Skip to content

Commit

Permalink
Reuse "type" mapping feature
Browse files Browse the repository at this point in the history
  • Loading branch information
atrovato committed Sep 16, 2022
1 parent 2cff872 commit af30069
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 136 deletions.
64 changes: 0 additions & 64 deletions server/services/zigbee2mqtt/exposes/coverType.js

This file was deleted.

77 changes: 44 additions & 33 deletions server/services/zigbee2mqtt/exposes/enumType.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
const { DEVICE_FEATURE_CATEGORIES, DEVICE_FEATURE_TYPES, BUTTON_STATUS } = require('../../../utils/constants');
const {
DEVICE_FEATURE_CATEGORIES,
DEVICE_FEATURE_TYPES,
BUTTON_STATUS,
COVER_STATE,
} = require('../../../utils/constants');

const WRITE_VALUE_MAPPING = {};
const READ_VALUE_MAPPING = {};

const addMapping = (exposeName, gladysValue, z2mValue) => {
const writeExposeMapping = WRITE_VALUE_MAPPING[exposeName] || {};
writeExposeMapping[gladysValue] = z2mValue;
WRITE_VALUE_MAPPING[exposeName] = writeExposeMapping;

const readExposeMapping = READ_VALUE_MAPPING[exposeName] || {};
readExposeMapping[z2mValue] = gladysValue;
READ_VALUE_MAPPING[exposeName] = readExposeMapping;
};

addMapping('action', BUTTON_STATUS.CLICK, 'single');
addMapping('action', BUTTON_STATUS.DOUBLE_CLICK, 'double');
addMapping('action', BUTTON_STATUS.HOLD_CLICK, 'hold');
addMapping('action', BUTTON_STATUS.LONG_CLICK, 'long');
addMapping('state', COVER_STATE.OPEN, 'OPEN');
addMapping('state', COVER_STATE.CLOSE, 'CLOSE');
addMapping('state', COVER_STATE.STOP, 'STOP');

module.exports = {
type: 'enum',
writeValue: (expose, value) => {
let relatedValue;

// Mapping is only for button click
switch (value) {
case BUTTON_STATUS.CLICK:
relatedValue = 'single';
break;
case BUTTON_STATUS.DOUBLE_CLICK:
relatedValue = 'double';
break;
case BUTTON_STATUS.HOLD_CLICK:
relatedValue = 'hold';
break;
case BUTTON_STATUS.LONG_CLICK:
relatedValue = 'long';
break;
default:
relatedValue = undefined;
}
const relatedValue = (WRITE_VALUE_MAPPING[expose.name] || {})[value];

if (relatedValue && expose.values.includes(relatedValue)) {
return relatedValue;
Expand All @@ -30,19 +38,11 @@ module.exports = {
return undefined;
},
readValue: (expose, value) => {
// Mapping is only for button click
switch (value) {
case 'single':
return BUTTON_STATUS.CLICK;
case 'double':
return BUTTON_STATUS.DOUBLE_CLICK;
case 'hold':
return BUTTON_STATUS.HOLD_CLICK;
case 'long':
return BUTTON_STATUS.LONG_CLICK;
default:
return undefined;
}
return (READ_VALUE_MAPPING[expose.name] || {})[value];
},
feature: {
min: 0,
max: 1,
},
names: {
action: {
Expand All @@ -51,5 +51,16 @@ module.exports = {
type: DEVICE_FEATURE_TYPES.BUTTON.CLICK,
},
},
state: {
types: {
cover: {
category: DEVICE_FEATURE_CATEGORIES.SHUTTER,
type: DEVICE_FEATURE_TYPES.SHUTTER.STATE,
min: -1,
max: 1,
forceOverride: true,
},
},
},
},
};
2 changes: 0 additions & 2 deletions server/services/zigbee2mqtt/exposes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@ const binaryType = require('./binaryType');
const numericType = require('./numericType');
const enumType = require('./enumType');
const compositeType = require('./compositeType');
const coverType = require('./coverType');

module.exports = {
[binaryType.type]: binaryType,
[numericType.type]: numericType,
[enumType.type]: enumType,
[compositeType.type]: compositeType,
[coverType.type]: coverType,
};
9 changes: 9 additions & 0 deletions server/services/zigbee2mqtt/exposes/numericType.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,15 @@ module.exports = {
forceOverride: true,
},
},
position: {
types: {
cover: {
category: DEVICE_FEATURE_CATEGORIES.SHUTTER,
type: DEVICE_FEATURE_TYPES.SHUTTER.POSITION,
unit: DEVICE_FEATURE_UNITS.PERCENT,
},
},
},
power: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.SWITCH,
Expand Down
2 changes: 1 addition & 1 deletion server/services/zigbee2mqtt/lib/findMatchingExpose.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const logger = require('../../../utils/logger');
const recursiveSearch = (expose, type, search) => {
const { property, features = [] } = expose;
if (property === search) {
return { ...expose, parent_type: type };
return expose;
}

for (let i = 0; i < features.length; i += 1) {
Expand Down
4 changes: 1 addition & 3 deletions server/services/zigbee2mqtt/lib/readValue.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ function readValue(deviceName, property, value) {
throw new Error(`Zigbee2mqqt expose not found on device "${deviceName}" with property "${property}".`);
}

const { parent_type: parentType, type: exposeType } = expose;
const mapper = exposesMap[parentType] || exposesMap[exposeType];
const matchingValue = mapper.readValue(expose, value);
const matchingValue = exposesMap[expose.type].readValue(expose, value);

if (matchingValue === undefined) {
throw new Error(`Zigbee2mqqt don't handle value "${value}" for property "${property}".`);
Expand Down
12 changes: 3 additions & 9 deletions server/services/zigbee2mqtt/utils/features/buildFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function buildByName(names = {}, name, parentType) {
*/
function buildFeature(deviceName, expose = {}, parentType) {
const { type, name, property, access, value_min: minValue, value_max: maxValue, unit: deviceUnit, values } = expose;
const { names = {}, feature } = exposesMap[parentType] || exposesMap[type] || {};
const { names = {}, feature } = exposesMap[type] || {};
const byName = buildByName(names, name, parentType);

if (!byName) {
Expand All @@ -61,13 +61,7 @@ function buildFeature(deviceName, expose = {}, parentType) {
// eslint-disable-next-line no-bitwise
const hasFeedback = !readOnly && (access & 1) === 1;

const createdFeature = {
min: 0,
read_only: readOnly,
has_feedback: hasFeedback,
...(feature || {}),
...(byName || {}),
};
const createdFeature = { read_only: readOnly, has_feedback: hasFeedback, ...(feature || {}), ...(byName || {}) };

// Min value
const min = minValue !== undefined ? minValue : createdFeature.min;
Expand All @@ -76,7 +70,7 @@ function buildFeature(deviceName, expose = {}, parentType) {
let { max } = createdFeature;
if (maxValue !== undefined) {
max = maxValue;
} else if (max === undefined && values !== undefined) {
} else if (values !== undefined) {
max = values.length;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ const { assert } = require('chai');
const enumType = require('../../../../services/zigbee2mqtt/exposes/enumType');
const { BUTTON_STATUS } = require('../../../../utils/constants');

describe('zigbee2mqtt enumType', () => {
describe('zigbee2mqtt action enumType', () => {
const expose = {
name: 'action',
values: ['single', 'long', 'short', 'double', 'triple', 'hold'],
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
const { assert } = require('chai');

const coverType = require('../../../../services/zigbee2mqtt/exposes/coverType');
const enumType = require('../../../../services/zigbee2mqtt/exposes/enumType');
const { COVER_STATE } = require('../../../../utils/constants');

describe('zigbee2mqtt coverType', () => {
describe('zigbee2mqtt cover enumType', () => {
const expose = {
name: 'state',
values: ['OPEN', 'CLOSE', 'STOP'],
};

Expand All @@ -16,12 +17,12 @@ describe('zigbee2mqtt coverType', () => {
const { enumValue, intValue } = mapping;

it(`should write ${enumValue} value as ${intValue} value`, () => {
const result = coverType.writeValue(expose, intValue);
const result = enumType.writeValue(expose, intValue);
assert.equal(result, enumValue);
});

it(`should read ${intValue} value as ${enumValue}`, () => {
const result = coverType.readValue(expose, enumValue);
const result = enumType.readValue(expose, enumValue);
assert.equal(result, intValue);
});
});
Expand All @@ -30,17 +31,17 @@ describe('zigbee2mqtt coverType', () => {
const missingEnumExpose = {
values: ['OPEN', 'CLOSE'],
};
const result = coverType.writeValue(missingEnumExpose, COVER_STATE.STOP);
const result = enumType.writeValue(missingEnumExpose, COVER_STATE.STOP);
assert.equal(result, undefined);
});

it('should write undefined value', () => {
const result = coverType.writeValue(expose, 7);
const result = enumType.writeValue(expose, 7);
assert.equal(result, undefined);
});

it('should read enum value', () => {
const result = coverType.readValue(expose, 'unknown');
const result = enumType.readValue(expose, 'unknown');
assert.equal(result, undefined);
});
});
16 changes: 0 additions & 16 deletions server/test/services/zigbee2mqtt/lib/findMatchingExpose.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,11 @@ describe('zigbee2mqtt findMatchingExpose', () => {
type: 'binary',
name: 'state',
property: 'state',
parent_type: 'switch',
access: 3,
value_on: 'ON',
value_off: 'OFF',
};
const result = zigbee2MqttService.device.findMatchingExpose('0x00158d00045b2740', 'state');
assert.deepEqual(result, expected);
});

it('expose dicovered on child features', () => {
const expected = {
access: 7,
description: 'Position of this cover',
name: 'position',
property: 'position',
type: 'numeric',
parent_type: 'cover',
value_max: 100,
value_min: 0,
};
const result = zigbee2MqttService.device.findMatchingExpose('0x00158d00045b2740', 'position');
assert.deepEqual(result, expected);
});
});
12 changes: 12 additions & 0 deletions server/test/services/zigbee2mqtt/utils/payloads/CCT5015.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@
"unit": "percent",
"read_only": false,
"has_feedback": true
},
{
"category": "signal",
"external_id": "zigbee2mqtt:CCT5015 device:signal:integer:linkquality",
"has_feedback": false,
"max": 5,
"min": 0,
"name": "Linkquality",
"read_only": true,
"selector": "zigbee2mqtt-cct5015-device-signal-integer-linkquality",
"type": "integer",
"unit": null
}
],
"name": "CCT5015 device",
Expand Down

0 comments on commit af30069

Please sign in to comment.