diff --git a/lib/controller.js b/lib/controller.js index 0e15c2067..fa3647f62 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -4,7 +4,6 @@ const EventBus = require('./eventBus'); const State = require('./state'); const logger = require('./util/logger'); const settings = require('./util/settings'); -const objectAssignDeep = require('object-assign-deep'); const utils = require('./util/utils'); const stringify = require('json-stable-stringify-without-jsonify'); const assert = require('assert'); @@ -281,12 +280,9 @@ class Controller { } let messagePayload = {...payload}; - const currentState = this.state.exists(resolvedEntity.settings.ID) ? - this.state.get(resolvedEntity.settings.ID) : {}; - const newState = objectAssignDeep.noMutate(currentState, payload); // Update state cache with new state. - this.state.set(resolvedEntity.settings.ID, newState, stateChangeReason); + const newState = this.state.set(resolvedEntity.settings.ID, payload, stateChangeReason); if (settings.get().advanced.cache_state) { // Add cached state to payload diff --git a/lib/extension/groups.js b/lib/extension/groups.js index 511bcc506..806b83f77 100644 --- a/lib/extension/groups.js +++ b/lib/extension/groups.js @@ -86,7 +86,7 @@ class Groups extends Extension { const payload = {}; let endpointName; - for (let [prop, value] of Object.entries(data.changed)) { + for (let [prop, value] of Object.entries(data.update)) { const endpointNameMatch = utils.getEndpointNames().find((n) => prop.endsWith(`_${n}`)); if (endpointNameMatch) { prop = prop.substring(0, prop.length - endpointNameMatch.length - 1); diff --git a/lib/state.js b/lib/state.js index 022df262e..3ba34770c 100644 --- a/lib/state.js +++ b/lib/state.js @@ -75,23 +75,20 @@ class State { return this.state[ID]; } - set(ID, state, reason=null) { - const toState = objectAssignDeep.noMutate(state); - const fromState = this.state[ID]; - const changed = {}; + set(ID, update, reason=null) { + const fromState = this.state[ID] || {}; + const toState = objectAssignDeep.noMutate(fromState, update); + const result = {...toState}; for (const property of Object.keys(toState)) { if (dontCacheProperties.find((p) => property.match(p))) { delete toState[property]; } - - if (!fromState || toState[property] !== fromState[property]) { - changed[property] = toState[property]; - } } this.state[ID] = toState; - this.eventBus.emit('stateChange', {ID, from: fromState, to: state, reason, changed}); + this.eventBus.emit('stateChange', {ID, from: fromState, to: toState, reason, update}); + return result; } removeKey(ID, path) { diff --git a/test/publish.test.js b/test/publish.test.js index de898056b..3d0b1bb9b 100644 --- a/test/publish.test.js +++ b/test/publish.test.js @@ -1064,6 +1064,7 @@ describe('Publish', () => { it('Home Assistant: should not set state when color temperature is also set and device is already on', async () => { settings.set(['homeassistant'], true); const device = zigbeeHerdsman.devices.bulb_color; + controller.state.remove(device.ieeeAddr); controller.state.set(device.ieeeAddr, {state: 'ON'}) const endpoint = device.getEndpoint(1); const payload = {state: 'ON', color_temp: 100}; @@ -1079,6 +1080,7 @@ describe('Publish', () => { it('Home Assistant: should set state when color temperature is also set and device is off', async () => { settings.set(['homeassistant'], true); const device = zigbeeHerdsman.devices.bulb_color; + controller.state.remove(device.ieeeAddr); controller.state.set(device.ieeeAddr, {state: 'OFF'}) const endpoint = device.getEndpoint(1); const payload = {state: 'ON', color_temp: 100}; @@ -1097,6 +1099,7 @@ describe('Publish', () => { it('Home Assistant: should not set state when color is also set', async () => { settings.set(['homeassistant'], true); const device = zigbeeHerdsman.devices.bulb_color; + controller.state.remove(device.ieeeAddr); controller.state.set(device.ieeeAddr, {state: 'ON'}) const endpoint = device.getEndpoint(1); const payload = {state: 'ON', color: {x: 0.41, y: 0.25}}; @@ -1396,12 +1399,12 @@ describe('Publish', () => { ); expect(MQTT.publish).toHaveBeenNthCalledWith(4, 'zigbee2mqtt/bulb_2', - stringify({"brightness":100,"color":{"x":0.408707336668894,"y":0.39239142575868},"state":"ON"}), + stringify({"brightness":100,"state":"ON"}), {retain: false, qos: 0}, expect.any(Function) ); expect(MQTT.publish).toHaveBeenNthCalledWith(5, 'zigbee2mqtt/group_with_tradfri', - stringify({"brightness":100,"color":{"x":0.408707336668894,"y":0.39239142575868},"state":"ON"}), + stringify({"brightness":100,"state":"ON"}), {retain: false, qos: 0}, expect.any(Function) ); });