mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-08-22 10:39:58 +00:00
* Start on group support. #15 * Implement publishing to zigbee groups. https://github.com/Koenkk/zigbee2mqtt/issues/15 * Complete first version of group support. * Fix tests.
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
# Groups
|
||||
Zigbee2mqtt has support for Zigbee groups. By using Zigbee groups you can control multiple devices simultaneously.
|
||||
|
||||
## Configuration
|
||||
Add the following to your `configuration.yaml`.
|
||||
|
||||
```yaml
|
||||
groups:
|
||||
# ID, each group should have a different numerical ID
|
||||
'1':
|
||||
# Name which will be used to control the group
|
||||
friendly_name: group_1
|
||||
```
|
||||
|
||||
## Adding a device to a group
|
||||
Send an MQTT message to `zigbee2mqtt/bridge/groups/[GROUP_FRIENDLY_NAME]/add` with payload `DEVICE_FRIENDLY_NAME`
|
||||
|
||||
## Remove a device from a group
|
||||
Send an MQTT message to `zigbee2mqtt/bridge/groups/[GROUP_FRIENDLY_NAME]/remove` with payload `DEVICE_FRIENDLY_NAME`
|
||||
|
||||
## Controlling
|
||||
To control a group the following topic should be used. The payload is the same as is used for controlling devices.
|
||||
|
||||
```
|
||||
zigbee2mqtt/group/[GROUP_FRIENDLY_NAME]/set
|
||||
```
|
||||
|
||||
@@ -16,6 +16,7 @@ const ExtensionDeviceConfigure = require('./extension/deviceConfigure');
|
||||
const ExtensionDeviceReceive = require('./extension/deviceReceive');
|
||||
const ExtensionMarkOnlineXiaomi = require('./extension/markOnlineXiaomi');
|
||||
const ExtensionBridgeConfig = require('./extension/bridgeConfig');
|
||||
const ExtensionGroups = require('./extension/groups');
|
||||
|
||||
class Controller {
|
||||
constructor() {
|
||||
@@ -38,6 +39,7 @@ class Controller {
|
||||
new ExtensionRouterPollXiaomi(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
|
||||
new ExtensionMarkOnlineXiaomi(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
|
||||
new ExtensionBridgeConfig(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
|
||||
new ExtensionGroups(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
|
||||
];
|
||||
|
||||
if (settings.get().homeassistant) {
|
||||
|
||||
@@ -3,11 +3,20 @@ const settings = require('../util/settings');
|
||||
const zigbeeShepherdConverters = require('zigbee-shepherd-converters');
|
||||
const Queue = require('queue');
|
||||
const logger = require('../util/logger');
|
||||
const utils = require('../util/utils');
|
||||
|
||||
const topicRegex = new RegExp(`^${settings.get().mqtt.base_topic}/.+/(set|get)$`);
|
||||
const postfixes = ['left', 'right', 'center', 'bottom_left', 'bottom_right', 'top_left', 'top_right'];
|
||||
const maxDepth = 20;
|
||||
|
||||
const groupConverters = [
|
||||
zigbeeShepherdConverters.toZigbeeConverters.on_off,
|
||||
zigbeeShepherdConverters.toZigbeeConverters.light_brightness,
|
||||
zigbeeShepherdConverters.toZigbeeConverters.light_colortemp,
|
||||
zigbeeShepherdConverters.toZigbeeConverters.light_color,
|
||||
zigbeeShepherdConverters.toZigbeeConverters.ignore_transition,
|
||||
];
|
||||
|
||||
class DevicePublish {
|
||||
constructor(zigbee, mqtt, state, publishDeviceState) {
|
||||
this.zigbee = zigbee;
|
||||
@@ -47,10 +56,10 @@ class DevicePublish {
|
||||
topic = topic.replace(`${settings.get().mqtt.base_topic}/`, '');
|
||||
|
||||
// Parse type from topic
|
||||
const type = topic.substr(topic.lastIndexOf('/') + 1, topic.length);
|
||||
const cmdType = topic.substr(topic.lastIndexOf('/') + 1, topic.length);
|
||||
|
||||
// Remove type from topic
|
||||
topic = topic.replace(`/${type}`, '');
|
||||
topic = topic.replace(`/${cmdType}`, '');
|
||||
|
||||
// Check if we have to deal with a postfix.
|
||||
let postfix = '';
|
||||
@@ -61,9 +70,15 @@ class DevicePublish {
|
||||
topic = topic.replace(`/${postfix}`, '');
|
||||
}
|
||||
|
||||
const deviceID = topic;
|
||||
let entityType = 'device';
|
||||
if (topic.startsWith('group/')) {
|
||||
topic = topic.replace('group/', '');
|
||||
entityType = 'group';
|
||||
}
|
||||
|
||||
return {type: type, deviceID: deviceID, postfix: postfix};
|
||||
const ID = topic;
|
||||
|
||||
return {cmdType: cmdType, ID: ID, postfix: postfix, entityType: entityType};
|
||||
}
|
||||
|
||||
onMQTTMessage(topic, message) {
|
||||
@@ -73,22 +88,51 @@ class DevicePublish {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Map friendlyName to ieeeAddr if possible.
|
||||
const ieeeAddr = settings.getIeeeAddrByFriendlyName(topic.deviceID) || topic.deviceID;
|
||||
|
||||
// Get device
|
||||
const device = this.zigbee.getDevice(ieeeAddr);
|
||||
if (!device) {
|
||||
logger.error(`Failed to find device with ieeAddr: '${ieeeAddr}'`);
|
||||
return;
|
||||
// Map friendlyName (ID) to entityID if possible.
|
||||
let entityID = null;
|
||||
if (topic.entityType === 'group') {
|
||||
const groupID = settings.getGroupIDByFriendlyName(topic.ID);
|
||||
if (groupID) {
|
||||
entityID = Number(groupID);
|
||||
} else if (utils.isNumeric(topic.ID)) {
|
||||
entityID = Number(topic.ID);
|
||||
} else {
|
||||
logger.error(`Cannot find group '${topic.ID}'`);
|
||||
return;
|
||||
}
|
||||
} else if (topic.entityType === 'device') {
|
||||
entityID = settings.getIeeeAddrByFriendlyName(topic.ID) || topic.ID;
|
||||
}
|
||||
|
||||
// Map device to a model
|
||||
const model = zigbeeShepherdConverters.findByZigbeeModel(device.modelId);
|
||||
if (!model) {
|
||||
logger.warn(`Device with modelID '${device.modelId}' is not supported.`);
|
||||
logger.warn(`Please see: https://koenkk.github.io/zigbee2mqtt/how_tos/how_to_support_new_devices.html`);
|
||||
return;
|
||||
// Get entity details
|
||||
let endpoint = null;
|
||||
let converters = null;
|
||||
let device = null;
|
||||
|
||||
if (topic.entityType === 'device') {
|
||||
device = this.zigbee.getDevice(entityID);
|
||||
if (!device) {
|
||||
logger.error(`Failed to find device with ieeAddr: '${entityID}'`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Map device to a model
|
||||
const model = zigbeeShepherdConverters.findByZigbeeModel(device.modelId);
|
||||
if (!model) {
|
||||
logger.warn(`Device with modelID '${device.modelId}' is not supported.`);
|
||||
logger.warn(`Please see: https://koenkk.github.io/zigbee2mqtt/how_tos/how_to_support_new_devices.html`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine endpoint to publish to.
|
||||
if (model.hasOwnProperty('ep')) {
|
||||
const eps = model.ep(device);
|
||||
endpoint = eps.hasOwnProperty(topic.postfix) ? eps[topic.postfix] : null;
|
||||
}
|
||||
|
||||
converters = model.toZigbee;
|
||||
} else if (topic.entityType === 'group') {
|
||||
converters = groupConverters;
|
||||
}
|
||||
|
||||
// Convert the MQTT message to a Zigbee message.
|
||||
@@ -100,13 +144,6 @@ class DevicePublish {
|
||||
json = {state: message.toString()};
|
||||
}
|
||||
|
||||
// Determine endpoint to publish to.
|
||||
let endpoint = null;
|
||||
if (model.hasOwnProperty('ep')) {
|
||||
const eps = model.ep(device);
|
||||
endpoint = eps.hasOwnProperty(topic.postfix) ? eps[topic.postfix] : null;
|
||||
}
|
||||
|
||||
// When brightness is present skip state; brightness also handles state.
|
||||
if (json.hasOwnProperty('brightness') && json.hasOwnProperty('state')) {
|
||||
logger.debug(`Skipping 'state' because of 'brightness'`);
|
||||
@@ -115,14 +152,14 @@ class DevicePublish {
|
||||
|
||||
// For each key in the JSON message find the matching converter.
|
||||
Object.keys(json).forEach((key) => {
|
||||
const converter = model.toZigbee.find((c) => c.key.includes(key));
|
||||
const converter = converters.find((c) => c.key.includes(key));
|
||||
if (!converter) {
|
||||
logger.error(`No converter available for '${key}' (${json[key]})`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Converter didn't return a result, skip
|
||||
const converted = converter.convert(key, json[key], json, topic.type);
|
||||
const converted = converter.convert(key, json[key], json, topic.cmdType);
|
||||
if (!converted) {
|
||||
return;
|
||||
}
|
||||
@@ -130,7 +167,8 @@ class DevicePublish {
|
||||
// Add job to queue
|
||||
this.queue.push((queueCallback) => {
|
||||
this.zigbee.publish(
|
||||
ieeeAddr,
|
||||
entityID,
|
||||
topic.entityType,
|
||||
converted.cid,
|
||||
converted.cmd,
|
||||
converted.cmdType,
|
||||
@@ -139,7 +177,8 @@ class DevicePublish {
|
||||
endpoint,
|
||||
(error, rsp) => {
|
||||
// Devices do not report when they go off, this ensures state (on/off) is always in sync.
|
||||
if (topic.type === 'set' && !error && (key.startsWith('state') || key === 'brightness')) {
|
||||
if (topic.entityType === 'device' && topic.cmdType === 'set' &&
|
||||
!error && (key.startsWith('state') || key === 'brightness')) {
|
||||
const msg = {};
|
||||
const _key = topic.postfix ? `state_${topic.postfix}` : 'state';
|
||||
msg[_key] = key === 'brightness' ? 'ON' : json['state'];
|
||||
@@ -153,14 +192,14 @@ class DevicePublish {
|
||||
|
||||
// When there is a transition in the message the state of the device gets out of sync.
|
||||
// Therefore; at the end of the transition, read the new state from the device.
|
||||
if (topic.type === 'set' && converted.zclData.transtime) {
|
||||
if (topic.cmdType === 'set' && converted.zclData.transtime && topic.entityType === 'device') {
|
||||
const time = converted.zclData.transtime * 100;
|
||||
const getConverted = converter.convert(key, json[key], json, 'get');
|
||||
setTimeout(() => {
|
||||
// Add job to queue
|
||||
this.queue.push((queueCallback) => {
|
||||
this.zigbee.publish(
|
||||
ieeeAddr, getConverted.cid, getConverted.cmd, getConverted.cmdType,
|
||||
entityID, topic.entityType, getConverted.cid, getConverted.cmd, getConverted.cmdType,
|
||||
getConverted.zclData, getConverted.cfg, endpoint, () => queueCallback()
|
||||
);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
const settings = require('../util/settings');
|
||||
const logger = require('../util/logger');
|
||||
|
||||
const topicRegex = new RegExp(`^${settings.get().mqtt.base_topic}/bridge/groups/.+/(remove|add)$`);
|
||||
|
||||
class Groups {
|
||||
constructor(zigbee, mqtt, state, publishDeviceState) {
|
||||
this.zigbee = zigbee;
|
||||
this.mqtt = mqtt;
|
||||
this.state = state;
|
||||
this.publishDeviceState = publishDeviceState;
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.queue.stop();
|
||||
}
|
||||
|
||||
onMQTTConnected() {
|
||||
this.mqtt.subscribe(`${settings.get().mqtt.base_topic}/bridge/groups/+/remove`);
|
||||
this.mqtt.subscribe(`${settings.get().mqtt.base_topic}/bridge/groups/+/add`);
|
||||
}
|
||||
|
||||
parseTopic(topic) {
|
||||
if (!topic.match(topicRegex)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Remove base from topic
|
||||
topic = topic.replace(`${settings.get().mqtt.base_topic}/bridge/groups/`, '');
|
||||
|
||||
// Parse type from topic
|
||||
const type = topic.substr(topic.lastIndexOf('/') + 1, topic.length);
|
||||
|
||||
// Remove type from topic
|
||||
topic = topic.replace(`/${type}`, '');
|
||||
|
||||
return {friendly_name: topic, type: type};
|
||||
}
|
||||
|
||||
onMQTTMessage(topic, message) {
|
||||
topic = this.parseTopic(topic);
|
||||
|
||||
if (!topic) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find ID of this group.
|
||||
const groupID = settings.getGroupIDByFriendlyName(topic.friendly_name);
|
||||
if (!groupID) {
|
||||
logger.error(`Group with friendly_name '${topic.friendly_name}' doesn't exist`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Map message to ieeeAddr and check if device exist.
|
||||
message = message.toString();
|
||||
const ieeeAddr = settings.getIeeeAddrByFriendlyName(message) || message;
|
||||
if (!this.zigbee.getDevice(ieeeAddr)) {
|
||||
logger.error(`Failed to find device '${message}'`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Send command to the device.
|
||||
let payload = null;
|
||||
if (topic.type === 'add') {
|
||||
payload = {groupid: groupID, groupname: topic.friendly_name};
|
||||
} else if (topic.type === 'remove') {
|
||||
payload = {groupid: groupID};
|
||||
}
|
||||
|
||||
const callback = (error, rsp) => {
|
||||
if (error) {
|
||||
logger.error(`Failed to ${topic.type} ${ieeeAddr} from ${topic.friendly_name}`);
|
||||
} else {
|
||||
logger.error(`Succesfully ${topic.type} ${ieeeAddr} to ${topic.friendly_name}`);
|
||||
}
|
||||
};
|
||||
|
||||
this.zigbee.publish(
|
||||
ieeeAddr, 'device', 'genGroups', topic.type, 'functional',
|
||||
payload, null, null, callback,
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Groups;
|
||||
@@ -10,6 +10,7 @@ const defaults = {
|
||||
mqtt: {
|
||||
include_device_information: false,
|
||||
},
|
||||
groups: {},
|
||||
device_options: {},
|
||||
advanced: {
|
||||
log_directory: path.join(data.getPath(), 'log', '%TIMESTAMP%'),
|
||||
@@ -73,6 +74,16 @@ function getIeeeAddrByFriendlyName(friendlyName) {
|
||||
);
|
||||
}
|
||||
|
||||
function getGroupIDByFriendlyName(friendlyName) {
|
||||
if (!settings.groups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Object.keys(settings.groups).find((ID) =>
|
||||
settings.groups[ID].friendly_name === friendlyName
|
||||
);
|
||||
}
|
||||
|
||||
function changeFriendlyName(old, new_) {
|
||||
const ieeeAddr = getIeeeAddrByFriendlyName(old);
|
||||
|
||||
@@ -94,5 +105,6 @@ module.exports = {
|
||||
removeDevice: (ieeeAddr) => removeDevice(ieeeAddr),
|
||||
|
||||
getIeeeAddrByFriendlyName: (friendlyName) => getIeeeAddrByFriendlyName(friendlyName),
|
||||
getGroupIDByFriendlyName: (friendlyName) => getGroupIDByFriendlyName(friendlyName),
|
||||
changeFriendlyName: (old, new_) => changeFriendlyName(old, new_),
|
||||
};
|
||||
|
||||
@@ -5,4 +5,5 @@ module.exports = {
|
||||
millisecondsToSeconds: (milliseconds) => milliseconds / 1000,
|
||||
secondsToMilliseconds: (seconds) => seconds * 1000,
|
||||
isXiaomiDevice: (device) => xiaomiManufacturerID.includes(device.manufId),
|
||||
isNumeric: (string) => /^\d+$/.test(string),
|
||||
};
|
||||
|
||||
+27
-10
@@ -18,6 +18,11 @@ const shepherdSettings = {
|
||||
},
|
||||
};
|
||||
|
||||
const defaultCfg = {
|
||||
manufSpec: 0,
|
||||
disDefaultRsp: 0,
|
||||
};
|
||||
|
||||
logger.debug(`Using zigbee-shepherd with settings: '${JSON.stringify(shepherdSettings)}'`);
|
||||
|
||||
class Zigbee {
|
||||
@@ -187,22 +192,34 @@ class Zigbee {
|
||||
return this.shepherd.find(device.ieeeAddr, 1);
|
||||
}
|
||||
|
||||
publish(ieeAddr, cid, cmd, cmdType, zclData, cfg, ep, callback) {
|
||||
const device = this.findDevice(ieeAddr, ep);
|
||||
if (!device) {
|
||||
logger.error(`Zigbee cannot publish message to device because '${ieeAddr}' not known by zigbee-shepherd`);
|
||||
getGroup(ID) {
|
||||
return this.shepherd.getGroup(ID);
|
||||
}
|
||||
|
||||
publish(entityID, entityType, cid, cmd, cmdType, zclData, cfg=defaultCfg, ep, callback) {
|
||||
let entity = null;
|
||||
if (entityType === 'device') {
|
||||
entity = this.findDevice(entityID, ep);
|
||||
} else if (entityType === 'group') {
|
||||
entity = this.getGroup(entityID);
|
||||
}
|
||||
|
||||
if (!entity) {
|
||||
logger.error(
|
||||
`Zigbee cannot publish message to ${entityType} because '${entityID}' not known by zigbee-shepherd`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`Zigbee publish to '${ieeAddr}', ${cid} - ${cmd} - ` +
|
||||
`Zigbee publish to ${entityType} '${entityID}', ${cid} - ${cmd} - ` +
|
||||
`${JSON.stringify(zclData)} - ${JSON.stringify(cfg)} - ${ep}`
|
||||
);
|
||||
|
||||
const callback_ = (error, rsp) => {
|
||||
if (error) {
|
||||
logger.error(
|
||||
`Zigbee publish to '${ieeAddr}', ${cid} - ${cmd} - ${JSON.stringify(zclData)} ` +
|
||||
`Zigbee publish to ${entityType} '${entityID}', ${cid} - ${cmd} - ${JSON.stringify(zclData)} ` +
|
||||
`- ${JSON.stringify(cfg)} - ${ep} ` +
|
||||
`failed with error ${error}`);
|
||||
}
|
||||
@@ -210,10 +227,10 @@ class Zigbee {
|
||||
callback(error, rsp);
|
||||
};
|
||||
|
||||
if (cmdType === 'functional') {
|
||||
device.functional(cid, cmd, zclData, cfg, callback_);
|
||||
} else if (cmdType === 'foundation') {
|
||||
device.foundation(cid, cmd, zclData, cfg, callback_);
|
||||
if (cmdType === 'functional' && entity.functional) {
|
||||
entity.functional(cid, cmd, zclData, cfg, callback_);
|
||||
} else if (cmdType === 'foundation' && entity.foundation) {
|
||||
entity.foundation(cid, cmd, zclData, cfg, callback_);
|
||||
} else {
|
||||
logger.error(`Unknown zigbee publish cmdType ${cmdType}`);
|
||||
}
|
||||
|
||||
Generated
+13
-13
@@ -67,9 +67,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/parser": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.2.2.tgz",
|
||||
"integrity": "sha512-UNTmQ5cSLDeBGBl+s7JeowkqIHgmFAGBnLDdIzFmUNSuS5JF0XBcN59jsh/vJO/YjfsBqMxhMjoFGmNExmf0FA==",
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.2.3.tgz",
|
||||
"integrity": "sha512-0LyEcVlfCoFmci8mXx8A5oIkpkOgyo8dRHtxBnK9RRBwxO2+JZPNsqtVEZQ7mJFPxnXF9lfmU24mHOPI0qnlkA==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/template": {
|
||||
@@ -84,16 +84,16 @@
|
||||
}
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"version": "7.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.2.tgz",
|
||||
"integrity": "sha512-E5Bn9FSwHpSkUhthw/XEuvFZxIgrqb9M8cX8j5EUQtrUG5DQUy6bFyl7G7iQ1D1Czudor+xkmp81JbLVVM0Sjg==",
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.2.3.tgz",
|
||||
"integrity": "sha512-Z31oUD/fJvEWVR0lNZtfgvVt512ForCTNKYcJBGbPb1QZfve4WGH8Wsy7+Mev33/45fhP/hwQtvgusNdcCMgSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"@babel/generator": "^7.2.2",
|
||||
"@babel/helper-function-name": "^7.1.0",
|
||||
"@babel/helper-split-export-declaration": "^7.0.0",
|
||||
"@babel/parser": "^7.2.2",
|
||||
"@babel/parser": "^7.2.3",
|
||||
"@babel/types": "^7.2.2",
|
||||
"debug": "^4.1.0",
|
||||
"globals": "^11.1.0",
|
||||
@@ -838,7 +838,7 @@
|
||||
},
|
||||
"concat-stream": {
|
||||
"version": "1.6.2",
|
||||
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||
"resolved": "http://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
@@ -4763,8 +4763,8 @@
|
||||
}
|
||||
},
|
||||
"zigbee-shepherd": {
|
||||
"version": "git+https://github.com/Koenkk/zigbee-shepherd.git#ce52ac4131e2a505af6197b4a26d2b5360e4eb80",
|
||||
"from": "git+https://github.com/Koenkk/zigbee-shepherd.git#ce52ac4131e2a505af6197b4a26d2b5360e4eb80",
|
||||
"version": "git+https://github.com/Koenkk/zigbee-shepherd.git#081227b1789a6b416a5ef4a61162d805272f1ef3",
|
||||
"from": "git+https://github.com/Koenkk/zigbee-shepherd.git#081227b1789a6b416a5ef4a61162d805272f1ef3",
|
||||
"requires": {
|
||||
"areq": "^0.2.0",
|
||||
"busyman": "^0.3.0",
|
||||
@@ -4792,9 +4792,9 @@
|
||||
}
|
||||
},
|
||||
"zigbee-shepherd-converters": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/zigbee-shepherd-converters/-/zigbee-shepherd-converters-7.0.4.tgz",
|
||||
"integrity": "sha512-yFgF+TTQ5j6fjf0GG6JxIM5KsrKdlGnXM9wpJPR7W48WEwUwGAlB4x9ioRYCjWWEvX03ngR5RoOqTdGyr8P8Gw==",
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/zigbee-shepherd-converters/-/zigbee-shepherd-converters-7.0.5.tgz",
|
||||
"integrity": "sha512-wXjWbtJzBpttRtDAS/sDT6KEOPjc6Zi19BIDNClb2K0TQbVmlIwpe3nZk5CsEXC1AtKzzyReO6VAUIa1zX8o+A==",
|
||||
"requires": {
|
||||
"debounce": "*",
|
||||
"debug": "3.2.6",
|
||||
|
||||
+2
-2
@@ -45,8 +45,8 @@
|
||||
"semver": "*",
|
||||
"winston": "2.4.2",
|
||||
"ziee": "*",
|
||||
"zigbee-shepherd": "git+https://github.com/Koenkk/zigbee-shepherd.git#ce52ac4131e2a505af6197b4a26d2b5360e4eb80",
|
||||
"zigbee-shepherd-converters": "7.0.4",
|
||||
"zigbee-shepherd": "git+https://github.com/Koenkk/zigbee-shepherd.git#081227b1789a6b416a5ef4a61162d805272f1ef3",
|
||||
"zigbee-shepherd-converters": "7.0.5",
|
||||
"zive": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
+172
-101
@@ -11,7 +11,7 @@ const mqtt = {
|
||||
|
||||
const zigbee = {
|
||||
getDevice: null,
|
||||
publish: sandbox.stub().callsFake((ieeAddr, cid, cmd, cmdType, zclData, cfg, ep, callback) => {
|
||||
publish: sandbox.stub().callsFake((entityID, entityType, cid, cmd, cmdType, zclData, cfg, ep, callback) => {
|
||||
callback(false, null);
|
||||
}),
|
||||
};
|
||||
@@ -42,12 +42,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({brightness: '200'}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'genLevelCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'moveToLevelWithOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {level: '200', transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], null);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'genLevelCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'moveToLevelWithOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {level: '200', transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee devices when brightness is in %', () => {
|
||||
@@ -56,12 +57,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({brightness_percent: '92'}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'genLevelCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'moveToLevelWithOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {level: '235', transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], null);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'genLevelCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'moveToLevelWithOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {level: '235', transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee devices when brightness is in number', () => {
|
||||
@@ -70,12 +72,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({brightness: 230}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'genLevelCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'moveToLevelWithOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {level: 230, transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], null);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'genLevelCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'moveToLevelWithOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {level: 230, transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee devices with color_temp', () => {
|
||||
@@ -84,12 +87,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({color_temp: '222'}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'lightingColorCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'moveToColorTemp');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {colortemp: '222', transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], null);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'lightingColorCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'moveToColorTemp');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {colortemp: '222', transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee devices with color_temp in %', () => {
|
||||
@@ -98,12 +102,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({color_temp_percent: '100'}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'lightingColorCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'moveToColorTemp');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {colortemp: '500', transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], null);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'lightingColorCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'moveToColorTemp');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {colortemp: '500', transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee devices with non-default ep', () => {
|
||||
@@ -112,12 +117,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({state: 'OFF'}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'genOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'off');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[6], 2);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'genOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'off');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[7], 2);
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee devices with non-default ep and postfix', () => {
|
||||
@@ -126,12 +132,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/right/set', JSON.stringify({state: 'OFF'}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'genOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'off');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[6], 3);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'genOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'off');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[7], 3);
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee gledopto with [11,13]', () => {
|
||||
@@ -140,12 +147,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({state: 'OFF'}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'genOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'off');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[6], null);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'genOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'off');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee gledopto with [11,12,13]', () => {
|
||||
@@ -154,12 +162,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({state: 'OFF'}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'genOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'off');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[6], 12);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'genOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'off');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[7], 12);
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee devices with color xy', () => {
|
||||
@@ -168,12 +177,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({color: {x: 100, y: 50}}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'lightingColorCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'moveToColor');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {colorx: 6553500, colory: 3276750, transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], null);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'lightingColorCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'moveToColor');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {colorx: 6553500, colory: 3276750, transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee devices with color rgb', () => {
|
||||
@@ -182,12 +192,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({color: {r: 100, g: 200, b: 10}}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'lightingColorCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'moveToColor');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {colorx: 17085, colory: 44000, transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], null);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'lightingColorCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'moveToColor');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {colorx: 17085, colory: 44000, transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
|
||||
it('Should publish messages to zigbee devices with color rgb string', () => {
|
||||
@@ -196,12 +207,13 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({color: {rgb: '100,200,10'}}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'lightingColorCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'moveToColor');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {colorx: 17085, colory: 44000, transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], null);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'lightingColorCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'moveToColor');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {colorx: 17085, colory: 44000, transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
|
||||
it('Should publish 1 message when brightness with state is send', () => {
|
||||
@@ -210,12 +222,42 @@ describe('DevicePublish', () => {
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/0x12345678/set', JSON.stringify({state: 'ON', brightness: '50'}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], '0x12345678');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'genLevelCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'moveToLevelWithOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[4], {level: '50', transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], null);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'device');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'genLevelCtrl');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'moveToLevelWithOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {level: '50', transtime: 0});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
|
||||
it('Should publish messages to groups', () => {
|
||||
sandbox.stub(settings, 'getGroupIDByFriendlyName').callsFake(() => '1');
|
||||
zigbee.publish.resetHistory();
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/group/group_1/set', JSON.stringify({state: 'ON'}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], 1);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'group');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'genOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'on');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
|
||||
it('Should publish messages to groups by ID', () => {
|
||||
zigbee.publish.resetHistory();
|
||||
devicePublish.onMQTTMessage('zigbee2mqtt/group/2/set', JSON.stringify({state: 'ON'}));
|
||||
chai.assert.isTrue(zigbee.publish.calledOnce);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[0], 2);
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[1], 'group');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[2], 'genOnOff');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[3], 'on');
|
||||
chai.assert.strictEqual(zigbee.publish.getCall(0).args[4], 'functional');
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[5], {});
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[6], cfg.default);
|
||||
chai.assert.deepEqual(zigbee.publish.getCall(0).args[7], null);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -253,16 +295,18 @@ describe('DevicePublish', () => {
|
||||
it('Should parse set topic', () => {
|
||||
const topic = 'zigbee2mqtt/my_device_id/set';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.type, 'set');
|
||||
chai.assert.strictEqual(parsed.deviceID, 'my_device_id');
|
||||
chai.assert.strictEqual(parsed.cmdType, 'set');
|
||||
chai.assert.strictEqual(parsed.entityType, 'device');
|
||||
chai.assert.strictEqual(parsed.ID, 'my_device_id');
|
||||
chai.assert.strictEqual(parsed.postfix, '');
|
||||
});
|
||||
|
||||
it('Should parse get topic', () => {
|
||||
const topic = 'zigbee2mqtt/my_device_id2/get';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.type, 'get');
|
||||
chai.assert.strictEqual(parsed.deviceID, 'my_device_id2');
|
||||
chai.assert.strictEqual(parsed.cmdType, 'get');
|
||||
chai.assert.strictEqual(parsed.entityType, 'device');
|
||||
chai.assert.strictEqual(parsed.ID, 'my_device_id2');
|
||||
chai.assert.strictEqual(parsed.postfix, '');
|
||||
});
|
||||
|
||||
@@ -277,16 +321,18 @@ describe('DevicePublish', () => {
|
||||
|
||||
const topic = 'zigbee2mqtt/at/my/home/my_device_id2/get';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.type, 'get');
|
||||
chai.assert.strictEqual(parsed.deviceID, 'my_device_id2');
|
||||
chai.assert.strictEqual(parsed.cmdType, 'get');
|
||||
chai.assert.strictEqual(parsed.entityType, 'device');
|
||||
chai.assert.strictEqual(parsed.ID, 'my_device_id2');
|
||||
chai.assert.strictEqual(parsed.postfix, '');
|
||||
});
|
||||
|
||||
it('Should parse topic with when deviceID has multiple slashes', () => {
|
||||
const topic = 'zigbee2mqtt/floor0/basement/my_device_id2/set';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.type, 'set');
|
||||
chai.assert.strictEqual(parsed.deviceID, 'floor0/basement/my_device_id2');
|
||||
chai.assert.strictEqual(parsed.cmdType, 'set');
|
||||
chai.assert.strictEqual(parsed.entityType, 'device');
|
||||
chai.assert.strictEqual(parsed.ID, 'floor0/basement/my_device_id2');
|
||||
chai.assert.strictEqual(parsed.postfix, '');
|
||||
});
|
||||
|
||||
@@ -301,48 +347,54 @@ describe('DevicePublish', () => {
|
||||
|
||||
const topic = 'zigbee2mqtt/at/my/basement/floor0/basement/my_device_id2/set';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.type, 'set');
|
||||
chai.assert.strictEqual(parsed.deviceID, 'floor0/basement/my_device_id2');
|
||||
chai.assert.strictEqual(parsed.cmdType, 'set');
|
||||
chai.assert.strictEqual(parsed.entityType, 'device');
|
||||
chai.assert.strictEqual(parsed.ID, 'floor0/basement/my_device_id2');
|
||||
chai.assert.strictEqual(parsed.postfix, '');
|
||||
});
|
||||
|
||||
it('Should parse set with ieeAddr topic', () => {
|
||||
const topic = 'zigbee2mqtt/0x12345689/set';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.type, 'set');
|
||||
chai.assert.strictEqual(parsed.deviceID, '0x12345689');
|
||||
chai.assert.strictEqual(parsed.cmdType, 'set');
|
||||
chai.assert.strictEqual(parsed.entityType, 'device');
|
||||
chai.assert.strictEqual(parsed.ID, '0x12345689');
|
||||
chai.assert.strictEqual(parsed.postfix, '');
|
||||
});
|
||||
|
||||
it('Should parse set with postfix topic', () => {
|
||||
const topic = 'zigbee2mqtt/0x12345689/left/set';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.type, 'set');
|
||||
chai.assert.strictEqual(parsed.deviceID, '0x12345689');
|
||||
chai.assert.strictEqual(parsed.cmdType, 'set');
|
||||
chai.assert.strictEqual(parsed.entityType, 'device');
|
||||
chai.assert.strictEqual(parsed.ID, '0x12345689');
|
||||
chai.assert.strictEqual(parsed.postfix, 'left');
|
||||
});
|
||||
|
||||
it('Should parse set with postfix topic', () => {
|
||||
const topic = 'zigbee2mqtt/0x12345689/right/set';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.type, 'set');
|
||||
chai.assert.strictEqual(parsed.deviceID, '0x12345689');
|
||||
chai.assert.strictEqual(parsed.cmdType, 'set');
|
||||
chai.assert.strictEqual(parsed.entityType, 'device');
|
||||
chai.assert.strictEqual(parsed.ID, '0x12345689');
|
||||
chai.assert.strictEqual(parsed.postfix, 'right');
|
||||
});
|
||||
|
||||
it('Should parse set with postfix topic', () => {
|
||||
const topic = 'zigbee2mqtt/0x12345689/bottom_left/set';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.type, 'set');
|
||||
chai.assert.strictEqual(parsed.deviceID, '0x12345689');
|
||||
chai.assert.strictEqual(parsed.cmdType, 'set');
|
||||
chai.assert.strictEqual(parsed.entityType, 'device');
|
||||
chai.assert.strictEqual(parsed.ID, '0x12345689');
|
||||
chai.assert.strictEqual(parsed.postfix, 'bottom_left');
|
||||
});
|
||||
|
||||
it('Shouldnt parse set with invalid postfix topic', () => {
|
||||
const topic = 'zigbee2mqtt/0x12345689/invalid/set';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.type, 'set');
|
||||
chai.assert.strictEqual(parsed.deviceID, '0x12345689/invalid');
|
||||
chai.assert.strictEqual(parsed.cmdType, 'set');
|
||||
chai.assert.strictEqual(parsed.entityType, 'device');
|
||||
chai.assert.strictEqual(parsed.ID, '0x12345689/invalid');
|
||||
chai.assert.strictEqual(parsed.postfix, '');
|
||||
});
|
||||
|
||||
@@ -357,9 +409,28 @@ describe('DevicePublish', () => {
|
||||
|
||||
const topic = 'zigbee2mqtt/at/my/home/my/device/in/basement/sensor/bottom_left/get';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.type, 'get');
|
||||
chai.assert.strictEqual(parsed.deviceID, 'my/device/in/basement/sensor');
|
||||
chai.assert.strictEqual(parsed.cmdType, 'get');
|
||||
chai.assert.strictEqual(parsed.entityType, 'device');
|
||||
chai.assert.strictEqual(parsed.ID, 'my/device/in/basement/sensor');
|
||||
chai.assert.strictEqual(parsed.postfix, 'bottom_left');
|
||||
});
|
||||
|
||||
it('Should parse group topics', () => {
|
||||
const topic = 'zigbee2mqtt/group/group_1/set';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.cmdType, 'set');
|
||||
chai.assert.strictEqual(parsed.entityType, 'group');
|
||||
chai.assert.strictEqual(parsed.ID, 'group_1');
|
||||
chai.assert.strictEqual(parsed.postfix, '');
|
||||
});
|
||||
|
||||
it('Should parse group topics with mutiple slashes', () => {
|
||||
const topic = 'zigbee2mqtt/group/master/child/set';
|
||||
const parsed = devicePublish.parseTopic(topic);
|
||||
chai.assert.strictEqual(parsed.cmdType, 'set');
|
||||
chai.assert.strictEqual(parsed.entityType, 'group');
|
||||
chai.assert.strictEqual(parsed.ID, 'master/child');
|
||||
chai.assert.strictEqual(parsed.postfix, '');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user