Skip to content

Commit

Permalink
Refactor publishDeviceState to publishEntityState (for future group s…
Browse files Browse the repository at this point in the history
…upport).
  • Loading branch information
Koenkk committed Feb 4, 2019
1 parent c0a87ff commit c9c599b
Show file tree
Hide file tree
Showing 20 changed files with 105 additions and 94 deletions.
62 changes: 32 additions & 30 deletions lib/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const logger = require('./util/logger');
const settings = require('./util/settings');
const zigbeeShepherdConverters = require('zigbee-shepherd-converters');
const objectAssignDeep = require('object-assign-deep');
const utils = require('./util/utils');

// Extensions
const ExtensionNetworkMap = require('./extension/networkMap');
Expand Down Expand Up @@ -33,40 +34,40 @@ class Controller {
this.onMQTTConnected = this.onMQTTConnected.bind(this);
this.onZigbeeMessage = this.onZigbeeMessage.bind(this);
this.onMQTTMessage = this.onMQTTMessage.bind(this);
this.publishDeviceState = this.publishDeviceState.bind(this);
this.publishEntityState = this.publishEntityState.bind(this);

// Initialize extensions.
this.extensions = [
new ExtensionDeviceReceive(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
new ExtensionDeviceConfigure(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
new ExtensionDevicePublish(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
new ExtensionNetworkMap(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
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),
new ExtensionBind(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
new ExtensionCoordinatorGroup(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
new ExtensionReporting(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
new ExtensionDeviceReceive(this.zigbee, this.mqtt, this.state, this.publishEntityState),
new ExtensionDeviceConfigure(this.zigbee, this.mqtt, this.state, this.publishEntityState),
new ExtensionDevicePublish(this.zigbee, this.mqtt, this.state, this.publishEntityState),
new ExtensionNetworkMap(this.zigbee, this.mqtt, this.state, this.publishEntityState),
new ExtensionRouterPollXiaomi(this.zigbee, this.mqtt, this.state, this.publishEntityState),
new ExtensionMarkOnlineXiaomi(this.zigbee, this.mqtt, this.state, this.publishEntityState),
new ExtensionBridgeConfig(this.zigbee, this.mqtt, this.state, this.publishEntityState),
new ExtensionGroups(this.zigbee, this.mqtt, this.state, this.publishEntityState),
new ExtensionBind(this.zigbee, this.mqtt, this.state, this.publishEntityState),
new ExtensionCoordinatorGroup(this.zigbee, this.mqtt, this.state, this.publishEntityState),
new ExtensionReporting(this.zigbee, this.mqtt, this.state, this.publishEntityState),
// https://github.com/Koenkk/zigbee2mqtt/issues/592
// new ExtensionPollLivoloSwitch(this.zigbee, this.mqtt, this.state, this.publishDeviceState),
// new ExtensionPollLivoloSwitch(this.zigbee, this.mqtt, this.state, this.publishEntityState),
];

if (settings.get().homeassistant) {
this.extensions.push(new ExtensionHomeAssistant(
this.zigbee, this.mqtt, this.state, this.publishDeviceState
this.zigbee, this.mqtt, this.state, this.publishEntityState
));
}

if (settings.get().advanced.soft_reset_timeout !== 0) {
this.extensions.push(new ExtensionSoftReset(
this.zigbee, this.mqtt, this.state, this.publishDeviceState
this.zigbee, this.mqtt, this.state, this.publishEntityState
));
}

if (settings.get().advanced.availability_timeout) {
this.extensions.push(new ExtensionAvailability(
this.zigbee, this.mqtt, this.state, this.publishDeviceState
this.zigbee, this.mqtt, this.state, this.publishEntityState
));
}
}
Expand Down Expand Up @@ -215,44 +216,45 @@ class Controller {
sendAllCachedStates() {
this.zigbee.getAllClients().forEach((device) => {
if (this.state.exists(device.ieeeAddr)) {
this.publishDeviceState(device, this.state.get(device.ieeeAddr), false);
this.publishEntityState(device.ieeeAddr, this.state.get(device.ieeeAddr), false);
}
});
}

publishDeviceState(device, payload, cache) {
const deviceID = device.ieeeAddr;
publishEntityState(entityID, payload, cache) {
const entity = utils.resolveEntity(entityID);
const appSettings = settings.get();
let messagePayload = {...payload};

if (appSettings.advanced.cache_state) {
// Add cached state to payload
if (this.state.exists(deviceID)) {
messagePayload = objectAssignDeep.noMutate(this.state.get(deviceID), payload);
if (this.state.exists(entityID)) {
messagePayload = objectAssignDeep.noMutate(this.state.get(entityID), payload);
}

// Update state cache with new state.
if (cache) {
this.state.set(deviceID, messagePayload);
this.state.set(entityID, messagePayload);
}
}

const deviceSettings = settings.getDevice(deviceID);
const friendlyName = deviceSettings ? deviceSettings.friendly_name : deviceID;
const entitySettings = entity.type === 'device' ? settings.getDevice(entityID) : settings.getGroup(entityID);
const friendlyName = entitySettings ? entitySettings.friendly_name : entityID;
const options = {
retain: deviceSettings ? deviceSettings.retain : false,
qos: deviceSettings && deviceSettings.qos ? deviceSettings.qos : 0,
retain: entitySettings ? entitySettings.retain : false,
qos: entitySettings && entitySettings.qos ? entitySettings.qos : 0,
};

if (appSettings.mqtt.include_device_information) {
messagePayload.device = this.getDeviceInfoForMqtt(device);
if (entity.type === 'device' && appSettings.mqtt.include_device_information) {
messagePayload.device = this.getDeviceInfoForMqtt(entityID);
}

this.mqtt.publish(friendlyName, JSON.stringify(messagePayload), options);
}

getDeviceInfoForMqtt(device) {
const {type, ieeeAddr, nwkAddr, manufId, manufName, powerSource, modelId, status} = device;
getDeviceInfoForMqtt(ieeeAddr) {
const device = this.zigbee.getDevice(ieeeAddr);
const {type, nwkAddr, manufId, manufName, powerSource, modelId, status} = device;
const deviceSettings = settings.getDevice(device.ieeeAddr);

return {
Expand Down
2 changes: 1 addition & 1 deletion lib/extension/availability.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const toZigbeeCandidates = ['state'];
* This extensions pings devices to check if they are online.
*/
class Availability {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.availability_timeout = settings.get().advanced.availability_timeout;
Expand Down
4 changes: 2 additions & 2 deletions lib/extension/bind.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ const allowedClusters = [
];

class Bind {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
this.publishDeviceState = publishDeviceState;
this.publishEntityState = publishEntityState;

// Setup queue
this.queue = new Queue();
Expand Down
4 changes: 2 additions & 2 deletions lib/extension/bridgeConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ const configRegex = new RegExp(`${settings.get().mqtt.base_topic}/bridge/config/
const allowedLogLevels = ['error', 'warn', 'info', 'debug'];

class BridgeConfig {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
this.publishDeviceState = publishDeviceState;
this.publishEntityState = publishEntityState;

// Bind functions
this.permitJoin = this.permitJoin.bind(this);
Expand Down
4 changes: 2 additions & 2 deletions lib/extension/coordinatorGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ const devices = [E1524];
* This extensions adds the coordinator to a group which is required for some devices to work properly.
*/
class CoordinatorGroup {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
this.publishDeviceState = publishDeviceState;
this.publishEntityState = publishEntityState;
}

onZigbeeStarted() {
Expand Down
2 changes: 1 addition & 1 deletion lib/extension/deviceConfigure.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const Queue = require('queue');
* This extensions handles configuration of devices.
*/
class DeviceConfigure {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.configured = [];
this.attempts = {};
Expand Down
6 changes: 3 additions & 3 deletions lib/extension/devicePublish.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ const groupConverters = [
];

class DevicePublish {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
this.publishDeviceState = publishDeviceState;
this.publishEntityState = publishEntityState;
}

onMQTTConnected() {
Expand Down Expand Up @@ -151,7 +151,7 @@ class DevicePublish {
const msg = {};
const _key = topic.postfix ? `state_${topic.postfix}` : 'state';
msg[_key] = key.startsWith('brightness') ? 'ON' : json['state'];
this.publishDeviceState(device, msg, true);
this.publishEntityState(device.ieeeAddr, msg, true);
}
}
);
Expand Down
6 changes: 3 additions & 3 deletions lib/extension/deviceReceive.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ const dontCacheProperties = ['action', 'button', 'button_left', 'button_right',
* This extensions handles messages received from devices.
*/
class DeviceReceive {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
this.publishDeviceState = publishDeviceState;
this.publishEntityState = publishEntityState;
this.coordinator = null;
this.elapsed = {};
}
Expand Down Expand Up @@ -132,7 +132,7 @@ class DeviceReceive {
this.elapsed[device.ieeeAddr] = now;
}

this.publishDeviceState(device, payload, cache);
this.publishEntityState(device.ieeeAddr, payload, cache);
};

let payload = {};
Expand Down
6 changes: 3 additions & 3 deletions lib/extension/extensionTemplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ class ExtensionTemplate {
* @param {Zigbee} zigbee Zigbee controller
* @param {MQTT} mqtt MQTT controller
* @param {State} state State controller
* @param {Function} publishDeviceState Method to publish device state to MQTT.
* @param {Function} publishEntityState Method to publish device state to MQTT.
*/
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
this.publishDeviceState = publishDeviceState;
this.publishEntityState = publishEntityState;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions lib/extension/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ const logger = require('../util/logger');
const topicRegex = new RegExp(`^${settings.get().mqtt.base_topic}/bridge/group/.+/(remove|add|remove_all)$`);

class Groups {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
this.publishDeviceState = publishDeviceState;
this.publishEntityState = publishEntityState;
}

onMQTTConnected() {
Expand Down
6 changes: 3 additions & 3 deletions lib/extension/homeassistant.js
Original file line number Diff line number Diff line change
Expand Up @@ -487,11 +487,11 @@ const mapping = {
* This extensions handles integration with HomeAssistant
*/
class HomeAssistant {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
this.publishDeviceState = publishDeviceState;
this.publishEntityState = publishEntityState;
this.zigbee2mqttVersion = zigbee2mqttVersion;

// A map of all discoverd devices
Expand Down Expand Up @@ -593,7 +593,7 @@ class HomeAssistant {
// Publish all device states.
this.zigbee.getAllClients().forEach((device) => {
if (this.state.exists(device.ieeeAddr)) {
this.publishDeviceState(device, this.state.get(device.ieeeAddr), false);
this.publishEntityState(device.ieeeAddr, this.state.get(device.ieeeAddr), false);
}
});

Expand Down
2 changes: 1 addition & 1 deletion lib/extension/markOnlineXiaomi.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const utils = require('../util/utils');
* This extensions marks Xiaomi devices as online.
*/
class MarkOnlineXiaomi {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/extension/networkMap.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const settings = require('../util/settings');
const zigbeeShepherdConverters = require('zigbee-shepherd-converters');

class NetworkMap {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
Expand Down
2 changes: 1 addition & 1 deletion lib/extension/pollLivoloSwitch.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const foundationCfg = {manufSpec: 0, disDefaultRsp: 0};
* Extension required for Livolo device support.
*/
class PollLivoloSwitch {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.timer = null;
this.configured = {};
Expand Down
4 changes: 2 additions & 2 deletions lib/extension/reporting.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ const reportInterval = {
const reportableChange = 0;

class Reporting {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.mqtt = mqtt;
this.state = state;
this.publishDeviceState = publishDeviceState;
this.publishEntityState = publishEntityState;
}

shouldReport(ieeeAddr) {
Expand Down
2 changes: 1 addition & 1 deletion lib/extension/routerPollXiaomi.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const interval = utils.secondsToMilliseconds(60);
* This extensions polls Xiaomi Zigbee routers to keep them awake.
*/
class RouterPollXiaomi {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.timer = null;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/extension/softReset.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const utils = require('../util/utils');
* This extensions soft resets the ZNP after a certain timeout.
*/
class SoftReset {
constructor(zigbee, mqtt, state, publishDeviceState) {
constructor(zigbee, mqtt, state, publishEntityState) {
this.zigbee = zigbee;
this.timer = null;
this.timeout = utils.secondsToMilliseconds(settings.get().advanced.soft_reset_timeout);
Expand Down
1 change: 1 addition & 0 deletions lib/util/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ module.exports = {
write: () => write(),

getDevice: (ieeeAddr) => settings.devices ? settings.devices[ieeeAddr] : null,
getGroup: (ID) => settings.groups ? settings.groups[ID]: null,
getDevices: () => settings.devices ? settings.devices : [],
addDevice: (ieeeAddr) => addDevice(ieeeAddr),
removeDevice: (ieeeAddr) => removeDevice(ieeeAddr),
Expand Down
10 changes: 9 additions & 1 deletion test/controller.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ describe('Controller', () => {
});
mqttPublish = sandbox.stub(mqtt.prototype, 'publish').callsFake(() => {});
controller = new Controller();
controller.zigbee = {
getDevice: () => {
return {
modelId: 'TRADFRI bulb E27 CWS opal 600lm',
manufName: 'IKEA',
};
},
};
});

afterEach(() => {
Expand Down Expand Up @@ -54,7 +62,7 @@ describe('Controller', () => {
chai.assert.strictEqual(
mqttPublish.getCall(0).args[1],
`{"state":"ON","device":{"ieeeAddr":"0x12345678","friendlyName":"test",` +
`"modelId":"TRADFRI bulb E27 CWS opal 600lm"}}`
`"manufName":"IKEA","modelId":"TRADFRI bulb E27 CWS opal 600lm"}}`
);
});
});
Expand Down
Loading

0 comments on commit c9c599b

Please sign in to comment.