zigbee-herdsman-converters 14.0.511 → 14.0.512
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/converters/toZigbee.js +87 -72
- package/devices/philips.js +9 -0
- package/package.json +1 -1
package/converters/toZigbee.js
CHANGED
|
@@ -798,7 +798,7 @@ const converters = {
|
|
|
798
798
|
const {message} = meta;
|
|
799
799
|
const transition = utils.getTransition(entity, 'brightness', meta);
|
|
800
800
|
const turnsOffAtBrightness1 = utils.getMetaValue(entity, meta.mapped, 'turnsOffAtBrightness1', 'allEqual', false);
|
|
801
|
-
let state = message.hasOwnProperty('state') ? message.state.toLowerCase() : undefined;
|
|
801
|
+
let state = message.hasOwnProperty('state') ? (message.state === null ? null : message.state.toLowerCase()) : undefined;
|
|
802
802
|
let brightness = undefined;
|
|
803
803
|
if (message.hasOwnProperty('brightness')) {
|
|
804
804
|
brightness = Number(message.brightness);
|
|
@@ -806,91 +806,106 @@ const converters = {
|
|
|
806
806
|
brightness = utils.mapNumberRange(Number(message.brightness_percent), 0, 100, 0, 255);
|
|
807
807
|
}
|
|
808
808
|
|
|
809
|
-
if (brightness
|
|
810
|
-
// Allow 255
|
|
809
|
+
if (brightness === 255) {
|
|
810
|
+
// Allow 255 for backwards compatibility.
|
|
811
|
+
brightness = 254;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
if (brightness !== undefined && (isNaN(brightness) || brightness < 0 || brightness > 254)) {
|
|
811
815
|
throw new Error(`Brightness value of message: '${JSON.stringify(message)}' invalid, must be a number >= 0 and =< 254`);
|
|
812
816
|
}
|
|
813
817
|
|
|
814
|
-
if (state !== undefined && ['on', 'off', 'toggle'].includes(state) === false) {
|
|
818
|
+
if (state !== undefined && state !== null && ['on', 'off', 'toggle'].includes(state) === false) {
|
|
815
819
|
throw new Error(`State value of message: '${JSON.stringify(message)}' invalid, must be 'ON', 'OFF' or 'TOGGLE'`);
|
|
816
820
|
}
|
|
817
821
|
|
|
818
|
-
if (state ===
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
//
|
|
860
|
-
//
|
|
861
|
-
if (
|
|
862
|
-
|
|
863
|
-
globalStore.putValue(entity, 'turnedOffWithTransition', false);
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
const result = await converters.on_off.convertSet(entity, 'state', state, meta);
|
|
867
|
-
result.readAfterWriteTime = 0;
|
|
868
|
-
if (result.state && result.state.state === 'ON' && meta.state.brightness === 0) {
|
|
869
|
-
result.state.brightness = 1;
|
|
822
|
+
if ((state === undefined || state === null) && brightness === undefined) {
|
|
823
|
+
throw new Error(`At least one of "brightness" or "state" must have a value: '${JSON.stringify(message)}'`);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// Infer state from desired brightness if unset. Ideally we'd want to keep it as it is, but this code has always
|
|
827
|
+
// used 'MoveToLevelWithOnOff' so that'd break backwards compatibility. To keep the state, the user
|
|
828
|
+
// has to explicitly set it to null.
|
|
829
|
+
if (state === undefined) {
|
|
830
|
+
// Also write to `meta.message.state` in case we delegate to the `on_off` converter.
|
|
831
|
+
state = meta.message.state = brightness === 0 ? 'off' : 'on';
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
const targetState = state === 'toggle' ? (meta.state.state === 'ON' ? 'off' : 'on') : state;
|
|
835
|
+
if (targetState === 'off') {
|
|
836
|
+
// Simulate 'Off' with transition via 'MoveToLevelWithOnOff', otherwise just use 'Off'.
|
|
837
|
+
// TODO: if this is a group where some members don't support Level Control, turning them off
|
|
838
|
+
// with transition may have no effect. (Some devices, such as Envilar ZG302-BOX-RELAY, handle
|
|
839
|
+
// 'MoveToLevelWithOnOff' despite not supporting the cluster; others, like the LEDVANCE SMART+
|
|
840
|
+
// plug, do not.)
|
|
841
|
+
brightness = transition.specified || brightness === 0 ? 0 : undefined;
|
|
842
|
+
if (meta.state.hasOwnProperty('brightness') && meta.state.state === 'ON') {
|
|
843
|
+
// The light's current level gets clobbered in two cases:
|
|
844
|
+
// 1. when 'Off' has a transition, in which case it is really 'MoveToLevelWithOnOff'
|
|
845
|
+
// https://github.com/Koenkk/zigbee-herdsman-converters/issues/1073
|
|
846
|
+
// 2. when 'OnLevel' is set: "If OnLevel is not defined, set the CurrentLevel to the stored level."
|
|
847
|
+
// https://github.com/Koenkk/zigbee2mqtt/issues/2850#issuecomment-580365633
|
|
848
|
+
// We need to remember current brightness in case the next 'On' does not provide it. `meta` is not reliable
|
|
849
|
+
// here, as it will get clobbered too if reporting is configured.
|
|
850
|
+
globalStore.putValue(entity, 'brightness', meta.state.brightness);
|
|
851
|
+
globalStore.putValue(entity, 'turnedOffWithTransition', brightness !== undefined);
|
|
852
|
+
}
|
|
853
|
+
} else if (targetState === 'on' && brightness === undefined) {
|
|
854
|
+
// Simulate 'On' with transition via 'MoveToLevelWithOnOff', or restore the level from before
|
|
855
|
+
// it was clobbered by a previous transition to off; otherwise just use 'On'.
|
|
856
|
+
// TODO: same problem as above.
|
|
857
|
+
// TODO: if transition is not specified, should use device default (OnTransitionTime), not 0.
|
|
858
|
+
if (transition.specified || globalStore.getValue(entity, 'turnedOffWithTransition') === true) {
|
|
859
|
+
const current = utils.getObjectProperty(meta.state, 'brightness', 254);
|
|
860
|
+
brightness = globalStore.getValue(entity, 'brightness', current);
|
|
861
|
+
try {
|
|
862
|
+
const attributeRead = await entity.read('genLevelCtrl', ['onLevel']);
|
|
863
|
+
// TODO: for groups, `read` does not wait for responses. If it did, we could still issue a single
|
|
864
|
+
// command if all values of `OnLevel` are equal, or split into one command per device if not.
|
|
865
|
+
if (attributeRead !== undefined && attributeRead['onLevel'] != 255) {
|
|
866
|
+
brightness = attributeRead['onLevel'];
|
|
870
867
|
}
|
|
871
|
-
|
|
872
|
-
|
|
868
|
+
} catch (e) {
|
|
869
|
+
// OnLevel not supported
|
|
873
870
|
}
|
|
874
871
|
}
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
if (brightness === undefined) {
|
|
875
|
+
const result = await converters.on_off.convertSet(entity, 'state', state, meta);
|
|
876
|
+
result.readAfterWriteTime = 0;
|
|
877
|
+
if (result.state && result.state.state === 'ON' && meta.state.brightness === 0) {
|
|
878
|
+
result.state.brightness = 1;
|
|
879
879
|
}
|
|
880
|
+
return result;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
if (brightness === 0 && (targetState === 'on' || state === null)) {
|
|
884
|
+
brightness = 1;
|
|
885
|
+
}
|
|
886
|
+
if (brightness === 1 && turnsOffAtBrightness1) {
|
|
887
|
+
brightness = 2;
|
|
888
|
+
}
|
|
880
889
|
|
|
890
|
+
if (targetState !== 'off') {
|
|
881
891
|
globalStore.putValue(entity, 'brightness', brightness);
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
)
|
|
892
|
+
globalStore.clearValue(entity, 'turnedOffWithTransition');
|
|
893
|
+
}
|
|
894
|
+
await entity.command(
|
|
895
|
+
'genLevelCtrl',
|
|
896
|
+
state === null ? 'moveToLevel' : 'moveToLevelWithOnOff',
|
|
897
|
+
{level: Number(brightness), transtime: transition.time},
|
|
898
|
+
utils.getOptions(meta.mapped, entity),
|
|
899
|
+
);
|
|
888
900
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
};
|
|
901
|
+
const result = {state: {}, readAfterWriteTime: transition.time * 100};
|
|
902
|
+
if (brightness !== 0) {
|
|
903
|
+
result.state.brightness = Number(brightness);
|
|
893
904
|
}
|
|
905
|
+
if (state !== null) {
|
|
906
|
+
result.state.state = brightness === 0 ? 'OFF' : 'ON';
|
|
907
|
+
}
|
|
908
|
+
return result;
|
|
894
909
|
},
|
|
895
910
|
convertGet: async (entity, key, meta) => {
|
|
896
911
|
if (key === 'brightness') {
|
package/devices/philips.js
CHANGED
|
@@ -2645,6 +2645,15 @@ module.exports = [
|
|
|
2645
2645
|
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
2646
2646
|
ota: ota.zigbeeOTA,
|
|
2647
2647
|
},
|
|
2648
|
+
{
|
|
2649
|
+
zigbeeModel: ['929003045601_01', '929003045601_02'],
|
|
2650
|
+
model: '8719514338142',
|
|
2651
|
+
vendor: 'Philips',
|
|
2652
|
+
description: 'Hue White ambiance Runner double spotlight',
|
|
2653
|
+
meta: {turnsOffAtBrightness1: true},
|
|
2654
|
+
extend: hueExtend.light_onoff_brightness_colortemp({colorTempRange: [153, 454]}),
|
|
2655
|
+
ota: ota.zigbeeOTA,
|
|
2656
|
+
},
|
|
2648
2657
|
{
|
|
2649
2658
|
zigbeeModel: ['5047230P6', '5047230P6'],
|
|
2650
2659
|
model: '5047230P6',
|