zigbee-herdsman-converters 14.0.356 → 14.0.360

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.
@@ -89,6 +89,10 @@ const converters = {
89
89
  result[postfixWithEndpointName('control_sequence_of_operation', msg, model)] =
90
90
  constants.thermostatControlSequenceOfOperations[msg.data['ctrlSeqeOfOper']];
91
91
  }
92
+ if (msg.data.hasOwnProperty('programingOperMode')) {
93
+ result[postfixWithEndpointName('programming_operation_mode', msg, model)] =
94
+ constants.thermostatProgrammingOperationModes[msg.data['programingOperMode']];
95
+ }
92
96
  if (msg.data.hasOwnProperty('systemMode')) {
93
97
  result[postfixWithEndpointName('system_mode', msg, model)] = constants.thermostatSystemModes[msg.data['systemMode']];
94
98
  }
@@ -1798,7 +1802,7 @@ const converters = {
1798
1802
  },
1799
1803
  nous_lcd_temperature_humidity_sensor: {
1800
1804
  cluster: 'manuSpecificTuya',
1801
- type: ['commandGetData'],
1805
+ type: ['commandDataResponse'],
1802
1806
  options: [exposes.options.precision('temperature'), exposes.options.calibration('temperature'),
1803
1807
  exposes.options.precision('humidity'), exposes.options.calibration('humidity')],
1804
1808
  convert: (model, msg, publish, options, meta) => {
@@ -785,7 +785,7 @@ const converters = {
785
785
  const {message} = meta;
786
786
  const transition = utils.getTransition(entity, 'brightness', meta);
787
787
  const turnsOffAtBrightness1 = utils.getMetaValue(entity, meta.mapped, 'turnsOffAtBrightness1', 'allEqual', false);
788
- const state = message.hasOwnProperty('state') ? message.state.toLowerCase() : undefined;
788
+ let state = message.hasOwnProperty('state') ? message.state.toLowerCase() : undefined;
789
789
  let brightness = undefined;
790
790
  if (message.hasOwnProperty('brightness')) {
791
791
  brightness = Number(message.brightness);
@@ -803,7 +803,11 @@ const converters = {
803
803
  }
804
804
 
805
805
  if (state === 'toggle' || state === 'off' || (brightness === undefined && state === 'on')) {
806
- if (transition.specified && (state === 'off' || state === 'on')) {
806
+ if (transition.specified) {
807
+ if (state === 'toggle') {
808
+ state = meta.state.state === 'ON' ? 'OFF' : 'ON';
809
+ }
810
+
807
811
  if (state === 'off' && meta.state.brightness && meta.state.state === 'ON') {
808
812
  // https://github.com/Koenkk/zigbee2mqtt/issues/2850#issuecomment-580365633
809
813
  // We need to remember the state before turning the device off as we need to restore
@@ -1154,6 +1158,20 @@ const converters = {
1154
1158
  await entity.read('hvacThermostat', ['ctrlSeqeOfOper']);
1155
1159
  },
1156
1160
  },
1161
+ thermostat_programming_operation_mode: {
1162
+ key: ['programming_operation_mode'],
1163
+ convertSet: async (entity, key, value, meta) => {
1164
+ const val = utils.getKey(constants.thermostatProgrammingOperationModes, value, undefined, Number);
1165
+ if (val === undefined) {
1166
+ throw new Error('Programming operation mode invalid, must be one of: ' +
1167
+ Object.values(constants.thermostatProgrammingOperationModes).join(', '));
1168
+ }
1169
+ await entity.write('hvacThermostat', {programingOperMode: val});
1170
+ },
1171
+ convertGet: async (entity, key, meta) => {
1172
+ await entity.read('hvacThermostat', ['programingOperMode']);
1173
+ },
1174
+ },
1157
1175
  thermostat_temperature_display_mode: {
1158
1176
  key: ['temperature_display_mode'],
1159
1177
  convertSet: async (entity, key, value, meta) => {
package/devices/climax.js CHANGED
@@ -121,4 +121,18 @@ module.exports = [
121
121
  exposes: [e.battery_low(), e.tamper(), e.action(['emergency', 'panic', 'disarm', 'arm_all_zones', 'arm_day_zones']),
122
122
  ],
123
123
  },
124
+ {
125
+ zigbeeModel: ['PRL_00.00.03.04TC'],
126
+ model: 'PRL-1ZBS-12/24V',
127
+ vendor: 'Climax',
128
+ description: 'Zigbee 12-24V relay controller',
129
+ extend: extend.switch(),
130
+ configure: async (device, coordinatorEndpoint, logger) => {
131
+ const endpoint = device.getEndpoint(1);
132
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
133
+ await reporting.onOff(endpoint);
134
+ device.powerSource = 'Mains (single phase)';
135
+ device.save();
136
+ },
137
+ },
124
138
  ];
@@ -15,14 +15,15 @@ module.exports = [
15
15
  model: '014G2461',
16
16
  vendor: 'Danfoss',
17
17
  description: 'Ally thermostat',
18
- fromZigbee: [fz.battery, fz.thermostat, fz.hvac_user_interface, fz.danfoss_thermostat],
18
+ fromZigbee: [fz.battery, fz.thermostat, fz.thermostat_weekly_schedule, fz.hvac_user_interface, fz.danfoss_thermostat],
19
19
  toZigbee: [tz.danfoss_thermostat_occupied_heating_setpoint, tz.thermostat_local_temperature, tz.danfoss_mounted_mode_active,
20
20
  tz.danfoss_mounted_mode_control, tz.danfoss_thermostat_vertical_orientation, tz.danfoss_algorithm_scale_factor,
21
21
  tz.danfoss_heat_available, tz.danfoss_heat_required, tz.danfoss_day_of_week, tz.danfoss_trigger_time,
22
22
  tz.danfoss_window_open_internal, tz.danfoss_window_open_external, tz.danfoss_load_estimate,
23
23
  tz.danfoss_viewing_direction, tz.danfoss_external_measured_room_sensor, tz.danfoss_radiator_covered,
24
- tz.thermostat_keypad_lockout, tz.thermostat_system_mode, tz.danfoss_load_balancing_enable, tz.danfoss_load_room_mean],
25
- exposes: [e.battery(), e.keypad_lockout(),
24
+ tz.thermostat_keypad_lockout, tz.thermostat_system_mode, tz.danfoss_load_balancing_enable, tz.danfoss_load_room_mean,
25
+ tz.thermostat_weekly_schedule, tz.thermostat_clear_weekly_schedule, tz.thermostat_programming_operation_mode],
26
+ exposes: [e.battery(), e.keypad_lockout(), e.programming_operation_mode(),
26
27
  exposes.binary('mounted_mode_active', ea.STATE_GET, true, false)
27
28
  .withDescription('Is the unit in mounting mode. This is set to `false` for mounted (already on ' +
28
29
  'the radiator) or `true` for not mounted (after factory reset)'),
@@ -71,7 +72,7 @@ module.exports = [
71
72
  'thermostats in the room. The gateway must update load_room_mean if enabled.'),
72
73
  exposes.numeric('load_room_mean', ea.ALL)
73
74
  .withDescription('Mean radiator load for room calculated by gateway for load balancing purposes (-8000=undefined)')
74
- .withValueMin(-8000).withValueMax(100),
75
+ .withValueMin(-8000).withValueMax(2000),
75
76
  exposes.numeric('load_estimate', ea.STATE_GET)
76
77
  .withDescription('Load estimate on this radiator')],
77
78
  ota: ota.zigbeeOTA,
@@ -237,7 +237,7 @@ module.exports = [
237
237
  vendor: 'Gledopto',
238
238
  ota: ota.zigbeeOTA,
239
239
  description: 'Zigbee LED Controller RGB+CCT (pro)',
240
- extend: gledoptoExtend.light_onoff_brightness_colortemp_color(),
240
+ extend: gledoptoExtend.light_onoff_brightness_colortemp_color({colorTempRange: [158, 495]}),
241
241
  meta: {disableDefaultResponse: true},
242
242
  },
243
243
  {
package/devices/hive.js CHANGED
@@ -156,14 +156,15 @@ module.exports = [
156
156
  model: 'UK7004240',
157
157
  vendor: 'Hive',
158
158
  description: 'Radiator valve based on Danfos Ally',
159
- fromZigbee: [fz.battery, fz.thermostat, fz.hvac_user_interface, fz.danfoss_thermostat],
159
+ fromZigbee: [fz.battery, fz.thermostat, fz.thermostat_weekly_schedule, fz.hvac_user_interface, fz.danfoss_thermostat],
160
160
  toZigbee: [tz.danfoss_thermostat_occupied_heating_setpoint, tz.thermostat_local_temperature, tz.danfoss_mounted_mode_active,
161
161
  tz.danfoss_mounted_mode_control, tz.danfoss_thermostat_vertical_orientation, tz.danfoss_algorithm_scale_factor,
162
162
  tz.danfoss_heat_available, tz.danfoss_heat_required, tz.danfoss_day_of_week, tz.danfoss_trigger_time,
163
163
  tz.danfoss_window_open_internal, tz.danfoss_window_open_external, tz.danfoss_load_estimate,
164
164
  tz.danfoss_viewing_direction, tz.danfoss_external_measured_room_sensor, tz.thermostat_keypad_lockout,
165
- tz.thermostat_system_mode, tz.danfoss_load_balancing_enable, tz.danfoss_load_room_mean],
166
- exposes: [e.battery(), e.keypad_lockout(),
165
+ tz.thermostat_system_mode, tz.danfoss_load_balancing_enable, tz.danfoss_load_room_mean,
166
+ tz.thermostat_weekly_schedule, tz.thermostat_clear_weekly_schedule, tz.thermostat_programming_operation_mode],
167
+ exposes: [e.battery(), e.keypad_lockout(), e.programming_operation_mode(),
167
168
  exposes.binary('mounted_mode_active', ea.STATE_GET, true, false)
168
169
  .withDescription('Is the unit in mounting mode. This is set to `false` for mounted (already on ' +
169
170
  'the radiator) or `true` for not mounted (after factory reset)'),
@@ -205,7 +206,7 @@ module.exports = [
205
206
  'thermostats in the room. The gateway must update load_room_mean if enabled.'),
206
207
  exposes.numeric('load_room_mean', ea.ALL)
207
208
  .withDescription('Mean radiator load for room calculated by gateway for load balancing purposes (-8000=undefined)')
208
- .withValueMin(-8000).withValueMax(100),
209
+ .withValueMin(-8000).withValueMax(2000),
209
210
  exposes.numeric('load_estimate', ea.STATE_GET)
210
211
  .withDescription('Load estimate on this radiator')],
211
212
  configure: async (device, coordinatorEndpoint, logger) => {
package/devices/popp.js CHANGED
@@ -15,14 +15,15 @@ module.exports = [
15
15
  model: '701721',
16
16
  vendor: 'Popp',
17
17
  description: 'Smart thermostat',
18
- fromZigbee: [fz.battery, fz.thermostat, fz.hvac_user_interface, fz.danfoss_thermostat],
18
+ fromZigbee: [fz.battery, fz.thermostat, fz.thermostat_weekly_schedule, fz.hvac_user_interface, fz.danfoss_thermostat],
19
19
  toZigbee: [tz.danfoss_thermostat_occupied_heating_setpoint, tz.thermostat_local_temperature, tz.danfoss_mounted_mode_active,
20
20
  tz.danfoss_mounted_mode_control, tz.danfoss_thermostat_vertical_orientation, tz.danfoss_algorithm_scale_factor,
21
21
  tz.danfoss_heat_available, tz.danfoss_heat_required, tz.danfoss_day_of_week, tz.danfoss_trigger_time,
22
22
  tz.danfoss_window_open_internal, tz.danfoss_window_open_external, tz.danfoss_load_estimate,
23
23
  tz.danfoss_viewing_direction, tz.danfoss_external_measured_room_sensor, tz.thermostat_keypad_lockout,
24
- tz.thermostat_system_mode, tz.danfoss_load_balancing_enable, tz.danfoss_load_room_mean],
25
- exposes: [e.battery(), e.keypad_lockout(),
24
+ tz.thermostat_system_mode, tz.danfoss_load_balancing_enable, tz.danfoss_load_room_mean,
25
+ tz.thermostat_weekly_schedule, tz.thermostat_clear_weekly_schedule, tz.thermostat_programming_operation_mode],
26
+ exposes: [e.battery(), e.keypad_lockout(), e.programming_operation_mode(),
26
27
  exposes.binary('mounted_mode_active', ea.STATE_GET, true, false)
27
28
  .withDescription('Is the unit in mounting mode. This is set to `false` for mounted (already on ' +
28
29
  'the radiator) or `true` for not mounted (after factory reset)'),
@@ -64,7 +65,7 @@ module.exports = [
64
65
  'thermostats in the room. The gateway must update load_room_mean if enabled.'),
65
66
  exposes.numeric('load_room_mean', ea.ALL)
66
67
  .withDescription('Mean radiator load for room calculated by gateway for load balancing purposes (-8000=undefined)')
67
- .withValueMin(-8000).withValueMax(100),
68
+ .withValueMin(-8000).withValueMax(2000),
68
69
  exposes.numeric('load_estimate', ea.STATE_GET)
69
70
  .withDescription('Load estimate on this radiator')],
70
71
  ota: ota.zigbeeOTA,
package/devices/tuya.js CHANGED
@@ -7,11 +7,41 @@ const reporting = require('../lib/reporting');
7
7
  const extend = require('../lib/extend');
8
8
  const e = exposes.presets;
9
9
  const ea = exposes.access;
10
-
10
+ const libColor = require('../lib/color');
11
+ const utils = require('../lib/utils');
11
12
 
12
13
  const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak', '_TZ3000_ew3ldmgx', '_TZ3000_gjnozsaz',
13
14
  '_TZ3000_jvzvulen', '_TZ3000_mraovvmm', '_TZ3000_nfnmi125', '_TZ3000_ps3dmato', '_TZ3000_w0qqde0g', '_TZ3000_u5u4cakc',
14
- '_TZ3000_rdtixbnu'];
15
+ '_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_v1pdxuqq'];
16
+
17
+ const tzLocal = {
18
+ TS0504B_color: {
19
+ key: ['color'],
20
+ convertSet: async (entity, key, value, meta) => {
21
+ const color = libColor.Color.fromConverterArg(value);
22
+ console.log(color);
23
+ const enableWhite =
24
+ (color.isRGB() && (color.rgb.red === 1 && color.rgb.green === 1 && color.rgb.blue === 1)) ||
25
+ // Zigbee2MQTT frontend white value
26
+ (color.isXY() && (color.xy.x === 0.3125 || color.xy.y === 0.32894736842105265)) ||
27
+ // Home Assistant white color picker value
28
+ (color.isXY() && (color.xy.x === 0.323 || color.xy.y === 0.329));
29
+
30
+ if (enableWhite) {
31
+ await entity.command('lightingColorCtrl', 'tuyaRgbMode', {enable: false});
32
+ const newState = {color_mode: 'xy'};
33
+ if (color.isXY()) {
34
+ newState.color = color.xy;
35
+ } else {
36
+ newState.color = color.rgb.gammaCorrected().toXY().rounded(4);
37
+ }
38
+ return {state: libColor.syncColorState(newState, meta.state, entity, meta.options, meta.logger)};
39
+ } else {
40
+ return await tz.light_color.convertSet(entity, key, value, meta);
41
+ }
42
+ },
43
+ },
44
+ };
15
45
 
16
46
  module.exports = [
17
47
  {
@@ -103,7 +133,7 @@ module.exports = [
103
133
  {
104
134
  fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_rk2yzt0u'},
105
135
  {modelID: 'TS0001', manufacturerName: '_TZ3000_o4cjetlm'}, {manufacturerName: '_TZ3000_o4cjetlm'},
106
- {modelID: 'TS0001', manufacturerName: '_TZ3000_iedbgyxt'}],
136
+ {modelID: 'TS0001', manufacturerName: '_TZ3000_iedbgyxt'}, {modelID: 'TS0001', manufacturerName: '_TZ3000_h3noz0a5'}],
107
137
  model: 'ZN231392',
108
138
  vendor: 'TuYa',
109
139
  description: 'Smart water/gas valve',
@@ -156,6 +186,7 @@ module.exports = [
156
186
  vendor: 'TuYa',
157
187
  description: 'Zigbee RGBW light',
158
188
  extend: extend.light_onoff_brightness_color(),
189
+ toZigbee: utils.replaceInArray(extend.light_onoff_brightness_color().toZigbee, [tz.light_color], [tzLocal.TS0504B_color]),
159
190
  meta: {applyRedFix: true},
160
191
  },
161
192
  {
@@ -175,6 +206,7 @@ module.exports = [
175
206
  {modelID: 'TS0202', manufacturerName: '_TYZB01_dl7cejts'},
176
207
  {modelID: 'TS0202', manufacturerName: '_TYZB01_qjqgmqxr'},
177
208
  {modelID: 'TS0202', manufacturerName: '_TZ3000_mmtwjmaq'},
209
+ {modelID: 'TS0202', manufacturerName: '_TZ3000_kmh5qpmb'},
178
210
  {modelID: 'TS0202', manufacturerName: '_TZ3000_mcxw5ehu'},
179
211
  {modelID: 'TS0202', manufacturerName: '_TZ3000_msl6wxk9'},
180
212
  {modelID: 'TS0202', manufacturerName: '_TYZB01_hqbdru35'},
package/devices/xiaomi.js CHANGED
@@ -1724,7 +1724,7 @@ module.exports = [
1724
1724
  model: 'MCCGQ12LM',
1725
1725
  vendor: 'Xiaomi',
1726
1726
  description: 'Aqara T1 door & window contact sensor',
1727
- fromZigbee: [fz.ias_contact_alarm_1, fz.battery],
1727
+ fromZigbee: [fz.xiaomi_contact, fz.battery],
1728
1728
  toZigbee: [],
1729
1729
  meta: {battery: {voltageToPercentage: '3V_2100'}},
1730
1730
  exposes: [e.contact(), e.battery(), e.battery_voltage()],
@@ -0,0 +1,21 @@
1
+ const exposes = require('../lib/exposes');
2
+ const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
3
+ const reporting = require('../lib/reporting');
4
+ const e = exposes.presets;
5
+
6
+ module.exports = [
7
+ {
8
+ zigbeeModel: ['ZBT-DIMSwitch-D0000'],
9
+ model: '8718801528334',
10
+ vendor: 'Ynoa',
11
+ description: 'Remote control one button dimmer',
12
+ fromZigbee: [fz.command_on, fz.command_off, fz.command_move, fz.command_stop, fz.battery],
13
+ exposes: [e.action(['on', 'off', 'brightness_move_up', 'brightness_move_down', 'brightness_stop']), e.battery()],
14
+ toZigbee: [],
15
+ configure: async (device, coordinatorEndpoint, logger) => {
16
+ const endpoint = device.getEndpoint(1);
17
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
18
+ await reporting.batteryPercentageRemaining(endpoint);
19
+ },
20
+ },
21
+ ];
@@ -4,6 +4,21 @@ const tz = require('../converters/toZigbee');
4
4
  const reporting = require('../lib/reporting');
5
5
  const extend = require('../lib/extend');
6
6
  const e = exposes.presets;
7
+ const tuya = require('../lib/tuya');
8
+
9
+ const fzLocal = {
10
+ ZMRM02: {
11
+ cluster: 'manuSpecificTuya',
12
+ type: ['commandGetData', 'commandSetDataResponse'],
13
+ convert: (model, msg, publish, options, meta) => {
14
+ const button = msg.data.dp;
15
+ const actionValue = tuya.getDataValue(msg.data.datatype, msg.data.data);
16
+ const lookup = {0: 'single', 1: 'double', 2: 'hold'};
17
+ const action = lookup[actionValue];
18
+ return {action: `button_${button}_${action}`};
19
+ },
20
+ },
21
+ };
7
22
 
8
23
  module.exports = [
9
24
  {
@@ -66,4 +81,20 @@ module.exports = [
66
81
  await reporting.onOff(endpoint);
67
82
  },
68
83
  },
84
+ {
85
+ fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_zqtiam4u'}],
86
+ model: 'ZM-RM02',
87
+ vendor: 'Zemismart',
88
+ description: 'Smart 6 key scene switch',
89
+ fromZigbee: [fzLocal.ZMRM02],
90
+ toZigbee: [],
91
+ onEvent: tuya.onEventSetTime,
92
+ exposes: [e.battery(), e.action([
93
+ 'button_1_hold', 'button_1_single', 'button_1_double',
94
+ 'button_2_hold', 'button_2_single', 'button_2_double',
95
+ 'button_3_hold', 'button_3_single', 'button_3_double',
96
+ 'button_4_hold', 'button_4_single', 'button_4_double',
97
+ 'button_5_hold', 'button_5_single', 'button_5_double',
98
+ 'button_6_hold', 'button_6_single', 'button_6_double'])],
99
+ },
69
100
  ];
package/lib/constants.js CHANGED
@@ -21,6 +21,11 @@ const thermostatControlSequenceOfOperations = {
21
21
  5: 'cooling_and_heating_4-pipes_with_reheat',
22
22
  };
23
23
 
24
+ const thermostatProgrammingOperationModes = {
25
+ 0: 'setpoint',
26
+ 1: 'schedule',
27
+ };
28
+
24
29
  const thermostatSystemModes = {
25
30
  0: 'off',
26
31
  1: 'auto',
@@ -247,6 +252,7 @@ module.exports = {
247
252
  repInterval,
248
253
  defaultBindGroup,
249
254
  thermostatControlSequenceOfOperations,
255
+ thermostatProgrammingOperationModes,
250
256
  thermostatSystemModes,
251
257
  thermostatRunningStates,
252
258
  thermostatRunningMode,
package/lib/exposes.js CHANGED
@@ -574,6 +574,7 @@ module.exports = {
574
574
  power_outage_memory: () => new Binary('power_outage_memory', access.ALL, true, false).withDescription('Enable/disable the power outage memory, this recovers the on/off mode after power failure'),
575
575
  presence: () => new Binary('presence', access.STATE, true, false).withDescription('Indicates whether the device detected presence'),
576
576
  pressure: () => new Numeric('pressure', access.STATE).withUnit('hPa').withDescription('The measured atmospheric pressure'),
577
+ programming_operation_mode: () => new Enum('programming_operation_mode', access.ALL, ['setpoint', 'schedule']).withDescription('Controls how programming affects the thermostat. Possible values: setpoint (only use specified setpoint), schedule (follow programmed setpoint schedule). Changing this value does not clear programmed schedules.'),
577
578
  smoke: () => new Binary('smoke', access.STATE, true, false).withDescription('Indicates whether the device detected smoke'),
578
579
  soil_moisture: () => new Numeric('soil_moisture', access.STATE).withUnit('%').withDescription('Measured soil moisture value'),
579
580
  sos: () => new Binary('sos', access.STATE, true, false).withDescription('SOS alarm'),