diff --git a/lib/controller.js b/lib/controller.js index a4ea0b02..37cc0bd1 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -285,6 +285,11 @@ class Controller { attributes.forEach((a) => messagePayload.device[a] = device[a]); } + // filter mqtt message attributes + if (entity.settings.filtered_attributes) { + entity.settings.filtered_attributes.forEach((a) => delete messagePayload[a]); + } + this.eventBus.emit('publishEntityState', {payload: messagePayload, entity}); if (Object.entries(messagePayload).length) { diff --git a/lib/util/settings.js b/lib/util/settings.js index 55499b7e..d408a25d 100644 --- a/lib/util/settings.js +++ b/lib/util/settings.js @@ -232,6 +232,7 @@ const schema = { friendly_name: {type: 'string'}, retain: {type: 'boolean'}, qos: {type: 'number'}, + filtered_attributes: {type: 'array', items: {type: 'string'}}, }, required: ['friendly_name'], }, @@ -251,6 +252,7 @@ const schema = { devices: {type: 'array', items: {type: 'string'}}, optimistic: {type: 'boolean'}, qos: {type: 'number'}, + filtered_attributes: {type: 'array', items: {type: 'string'}}, }, required: ['friendly_name'], }, diff --git a/test/controller.test.js b/test/controller.test.js index f72954c5..ea33c879 100644 --- a/test/controller.test.js +++ b/test/controller.test.js @@ -413,6 +413,20 @@ describe('Controller', () => { expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb", '{"state":"ON","brightness":200,"color_temp":370,"linkquality":99}', {"qos": 0, "retain": true}, expect.any(Function)); }); + + it('Publish entity state attribute_json output filtered', async () => { + await controller.start(); + settings.set(['experimental', 'output'], 'attribute_and_json'); + settings.set(['devices', zigbeeHerdsman.devices.bulb.ieeeAddr, 'filtered_attributes'], ['color_temp', 'linkquality']); + MQTT.publish.mockClear(); + await controller.publishEntityState('bulb', {state: 'ON', brightness: 200, color_temp: 370, linkquality: 99}); + await flushPromises(); + expect(MQTT.publish).toHaveBeenCalledTimes(3); + expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb/state", "ON", {"qos": 0, "retain": true}, expect.any(Function)); + expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb/brightness", "200", {"qos": 0, "retain": true}, expect.any(Function)); + expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb", '{"state":"ON","brightness":200}', {"qos": 0, "retain": true}, expect.any(Function)); + }); + it('Publish entity state with device information', async () => { await controller.start(); settings.set(['mqtt', 'include_device_information'], true); diff --git a/test/group.test.js b/test/group.test.js index 744d12c4..e5967164 100644 --- a/test/group.test.js +++ b/test/group.test.js @@ -297,6 +297,23 @@ describe('Groups', () => { expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/group_1", '{"state":"ON"}', {"retain": false, qos: 0}, expect.any(Function)); }); + it('Should publish state change of all members when a group changes its state, filtered', async () => { + const device = zigbeeHerdsman.devices.bulb_color; + const endpoint = device.getEndpoint(1); + const group = zigbeeHerdsman.groups.group_1; + group.members.push(endpoint); + settings.set(['groups'], {'1': {friendly_name: 'group_1', retain: false, filtered_attributes: ['brightness'], devices: [device.ieeeAddr]}}); + await controller.start(); + await flushPromises(); + + MQTT.publish.mockClear(); + await MQTT.events.message('zigbee2mqtt/group_1/set', JSON.stringify({state: 'ON', brightness: 100})); + await flushPromises(); + expect(MQTT.publish).toHaveBeenCalledTimes(2); + expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/bulb_color", '{"state":"ON","brightness":100}', {"retain": false, qos: 0}, expect.any(Function)); + expect(MQTT.publish).toHaveBeenCalledWith("zigbee2mqtt/group_1", '{"state":"ON"}', {"retain": false, qos: 0}, expect.any(Function)); + }); + it('Shouldnt publish group state change when a group is not optimistic', async () => { const device = zigbeeHerdsman.devices.bulb_color; const endpoint = device.getEndpoint(1);