zigbee-herdsman-converters 14.0.376 → 14.0.380

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.
@@ -1380,8 +1380,8 @@ const converters = {
1380
1380
  const payload = {
1381
1381
  action: postfixWithEndpointName(`color_move`, msg, model),
1382
1382
  action_color: {
1383
- x: precisionRound(msg.data.colorx / 65535, 3),
1384
- y: precisionRound(msg.data.colory / 65535, 3),
1383
+ x: precisionRound(msg.data.colorx / 65536, 3),
1384
+ y: precisionRound(msg.data.colory / 65536, 3),
1385
1385
  },
1386
1386
  action_transition_time: msg.data.transtime,
1387
1387
  };
@@ -7561,22 +7561,33 @@ const converters = {
7561
7561
  const dpValue = tuya.firstDpValue(msg, meta, 'tuya_radar_sensor');
7562
7562
  const dp = dpValue.dp;
7563
7563
  const value = tuya.getDataValue(dpValue);
7564
+ let result = null;
7564
7565
  switch (dp) {
7565
7566
  case tuya.dataPoints.trsPresenceState:
7566
- return {presence: {0: false, 1: true}[value]};
7567
+ result = {presence: {0: false, 1: true}[value]};
7568
+ break;
7567
7569
  case tuya.dataPoints.trsMotionState:
7568
- return {motion: {1: false, 2: true}[value]};
7570
+ result = {occupancy: {1: false, 2: true}[value]};
7571
+ break;
7569
7572
  case tuya.dataPoints.trsMotionSpeed:
7570
- return {motion_speed: value};
7573
+ result = {motion_speed: value};
7574
+ break;
7571
7575
  case tuya.dataPoints.trsMotionDirection:
7572
- return {motion_direction: {0: 'standing_still', 1: 'moving_forward', 2: 'moving_backward'}[value]};
7576
+ result = {motion_direction: tuya.tuyaRadar.motionDirection[value]};
7577
+ break;
7573
7578
  case tuya.dataPoints.trsScene:
7574
- return {radar_scene: {'default': 0, 'area': 1, 'toilet': 2, 'bedroom': 3, 'parlour': 4, 'office': 5, 'hotel': 6}[value]};
7579
+ result = {radar_scene: tuya.tuyaRadar.radarScene[value]};
7580
+ break;
7575
7581
  case tuya.dataPoints.trsSensitivity:
7576
- return {radar_sensitivity: value};
7582
+ result = {radar_sensitivity: value};
7583
+ break;
7577
7584
  case tuya.dataPoints.trsIlluminanceLux:
7578
- return {illuminance_lux: value};
7585
+ result = {illuminance_lux: value};
7586
+ break;
7587
+ default:
7588
+ meta.logger.warn(`fromZigbee.tuya_radar_sensor: NOT RECOGNIZED DP ${dp} with data ${JSON.stringify(dpValue)}`);
7579
7589
  }
7590
+ return result;
7580
7591
  },
7581
7592
  },
7582
7593
  tuya_smart_vibration_sensor: {
@@ -5029,6 +5029,28 @@ const converters = {
5029
5029
  }
5030
5030
  },
5031
5031
  },
5032
+ ts0201_temperature_humidity_alarm: {
5033
+ key: ['alarm_humidity_max', 'alarm_humidity_min', 'alarm_temperature_max', 'alarm_temperature_min'],
5034
+ convertSet: async (entity, key, value, meta) => {
5035
+ switch (key) {
5036
+ case 'alarm_temperature_max':
5037
+ case 'alarm_temperature_min':
5038
+ case 'alarm_humidity_max':
5039
+ case 'alarm_humidity_min': {
5040
+ // await entity.write('manuSpecificTuya_2', {[key]: value});
5041
+ // instead write as custom attribute to override incorrect herdsman dataType from uint16 to int16
5042
+ // https://github.com/Koenkk/zigbee-herdsman/blob/v0.13.191/src/zcl/definition/cluster.ts#L4235
5043
+ const keyToAttributeLookup = {'alarm_temperature_max': 0xD00A, 'alarm_temperature_min': 0xD00B,
5044
+ 'alarm_humidity_max': 0xD00D, 'alarm_humidity_min': 0xD00E};
5045
+ const payload = {[keyToAttributeLookup[key]]: {value: value, type: 0x29}};
5046
+ await entity.write('manuSpecificTuya_2', payload);
5047
+ break;
5048
+ }
5049
+ default: // Unknown key
5050
+ meta.logger.warn(`Unhandled key ${key}`);
5051
+ }
5052
+ },
5053
+ },
5032
5054
  heiman_ir_remote: {
5033
5055
  key: ['send_key', 'create', 'learn', 'delete', 'get_list'],
5034
5056
  convertSet: async (entity, key, value, meta) => {
@@ -5066,7 +5088,7 @@ const converters = {
5066
5088
  key: ['scene_store'],
5067
5089
  convertSet: async (entity, key, value, meta) => {
5068
5090
  const isGroup = entity.constructor.name === 'Group';
5069
- const groupid = isGroup ? entity.groupID : 0;
5091
+ const groupid = isGroup ? entity.groupID : value.hasOwnProperty('group_id') ? value.group_id : 0;
5070
5092
  let sceneid = value;
5071
5093
  let scenename = null;
5072
5094
  if (typeof value === 'object') {
@@ -5166,7 +5188,7 @@ const converters = {
5166
5188
  }
5167
5189
 
5168
5190
  const isGroup = entity.constructor.name === 'Group';
5169
- const groupid = isGroup ? entity.groupID : 0;
5191
+ const groupid = isGroup ? entity.groupID : value.hasOwnProperty('group_id') ? value.group_id : 0;
5170
5192
  const sceneid = value.ID;
5171
5193
  const scenename = value.name;
5172
5194
  const transtime = value.hasOwnProperty('transition') ? value.transition : 0;
@@ -6273,11 +6295,13 @@ const converters = {
6273
6295
  convertSet: async (entity, key, value, meta) => {
6274
6296
  switch (key) {
6275
6297
  case 'radar_scene':
6276
- await tuya.sendDataPointValue(entity, tuya.dataPoints.trsScene, value);
6277
- return {state: {radar_scene: value}};
6298
+ await tuya.sendDataPointEnum(entity, tuya.dataPoints.trsScene, utils.getKey(tuya.tuyaRadar.radarScene, value));
6299
+ break;
6278
6300
  case 'radar_sensitivity':
6279
6301
  await tuya.sendDataPointValue(entity, tuya.dataPoints.trsSensitivity, value);
6280
- return {state: {radar_sensitivity: value}};
6302
+ break;
6303
+ default: // Unknown Key
6304
+ meta.logger.warn(`toZigbee.tuya_radar_sensor: Unhandled Key ${key}`);
6281
6305
  }
6282
6306
  },
6283
6307
  },
@@ -6447,10 +6471,12 @@ const converters = {
6447
6471
  } else {
6448
6472
  throw new Error('Dimmer brightness is out of range 0..255');
6449
6473
  }
6450
- await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white);
6451
- await tuya.sendDataPointValue(entity, tuya.dataPoints.dimmerLevel, newValue);
6474
+ await tuya.sendDataPoints(entity, [
6475
+ tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white),
6476
+ tuya.dpValueFromIntValue(tuya.dataPoints.dimmerLevel, newValue),
6477
+ ], 'dataRequest', 1);
6452
6478
 
6453
- return {state: {white_brightness: value}};
6479
+ return {state: (key == 'white_brightness') ? {white_brightness: value} : {brightness: value}};
6454
6480
  } else if (key == 'color_temp') {
6455
6481
  const [colorTempMin, colorTempMax] = [250, 454];
6456
6482
  const preset = {
@@ -6472,8 +6498,10 @@ const converters = {
6472
6498
  }
6473
6499
  const data = utils.mapNumberRange(value, colorTempMax, colorTempMin, 0, 1000);
6474
6500
 
6475
- await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white);
6476
- await tuya.sendDataPointValue(entity, tuya.dataPoints.silvercrestSetColorTemp, data);
6501
+ await tuya.sendDataPoints(entity, [
6502
+ tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white),
6503
+ tuya.dpValueFromIntValue(tuya.dataPoints.silvercrestSetColorTemp, data),
6504
+ ], 'dataRequest', 1);
6477
6505
 
6478
6506
  return {state: {color_temp: value}};
6479
6507
  } else if (key == 'color' || (separateWhite && (key == 'brightness'))) {
@@ -6526,12 +6554,11 @@ const converters = {
6526
6554
  }
6527
6555
 
6528
6556
  // Scale 0-255 to 0-1000 what the device expects.
6529
- if (b) {
6557
+ if (b != null) {
6530
6558
  hsb.b = make4sizedString(utils.mapNumberRange(b, 0, 255, 0, 1000).toString(16));
6531
- } else if (state.brightness) {
6559
+ } else if (state.brightness != null) {
6532
6560
  hsb.b = make4sizedString(utils.mapNumberRange(state.brightness, 0, 255, 0, 1000).toString(16));
6533
6561
  }
6534
-
6535
6562
  return hsb;
6536
6563
  };
6537
6564
 
@@ -6548,15 +6575,18 @@ const converters = {
6548
6575
  data = data.concat(tuya.convertStringToHexArray(hsb.s));
6549
6576
  data = data.concat(tuya.convertStringToHexArray(hsb.b));
6550
6577
 
6551
- await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.color);
6552
- await tuya.sendDataPointStringBuffer(entity, tuya.dataPoints.silvercrestSetColor, data);
6578
+ const commands = [
6579
+ tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.color),
6580
+ tuya.dpValueFromStringBuffer(tuya.dataPoints.silvercrestSetColor, data),
6581
+ ];
6553
6582
 
6554
6583
  if (separateWhite && meta.state.white_brightness != undefined) {
6555
6584
  // restore white state
6556
6585
  const newValue = utils.mapNumberRange(meta.state.white_brightness, 0, 255, 0, 1000);
6557
- await tuya.sendDataPointEnum(entity, tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white);
6558
- await tuya.sendDataPointValue(entity, tuya.dataPoints.dimmerLevel, newValue);
6586
+ commands.push(tuya.dpValueFromEnum(tuya.dataPoints.silvercrestChangeMode, tuya.silvercrestModes.white));
6587
+ commands.push(tuya.dpValueFromIntValue(tuya.dataPoints.dimmerLevel, newValue));
6559
6588
  }
6589
+ await tuya.sendDataPoints(entity, commands, 'dataRequest', 1);
6560
6590
 
6561
6591
  return {state: newState};
6562
6592
  }
package/devices/hive.js CHANGED
@@ -2,9 +2,9 @@ const exposes = require('../lib/exposes');
2
2
  const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
3
3
  const tz = require('../converters/toZigbee');
4
4
  const globalStore = require('../lib/store');
5
- const constants = require('../lib/constants');
6
5
  const reporting = require('../lib/reporting');
7
6
  const extend = require('../lib/extend');
7
+ const {extendDevice} = require('../lib/utils');
8
8
  const e = exposes.presets;
9
9
  const ea = exposes.access;
10
10
 
@@ -149,130 +149,12 @@ module.exports = [
149
149
  }
150
150
  },
151
151
  },
152
- {
153
- // TRV001 is the same as Danfoss Ally (eTRV0100) and Popp eT093WRO. If implementing anything, please consider
154
- // changing those two too.
152
+ extendDevice(require('./danfoss'), '014G2461', {
155
153
  zigbeeModel: ['TRV001'],
156
154
  model: 'UK7004240',
157
155
  vendor: 'Hive',
158
- description: 'Radiator valve based on Danfos Ally',
159
- fromZigbee: [fz.battery, fz.thermostat, fz.thermostat_weekly_schedule, fz.hvac_user_interface, fz.danfoss_thermostat],
160
- toZigbee: [tz.danfoss_thermostat_occupied_heating_setpoint, tz.thermostat_local_temperature, tz.danfoss_mounted_mode_active,
161
- tz.danfoss_mounted_mode_control, tz.danfoss_thermostat_vertical_orientation, tz.danfoss_algorithm_scale_factor,
162
- tz.danfoss_heat_available, tz.danfoss_heat_required, tz.danfoss_day_of_week, tz.danfoss_trigger_time,
163
- tz.danfoss_window_open_internal, tz.danfoss_window_open_external, tz.danfoss_load_estimate,
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
- 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(),
168
- exposes.binary('mounted_mode_active', ea.STATE_GET, true, false)
169
- .withDescription('Is the unit in mounting mode. This is set to `false` for mounted (already on ' +
170
- 'the radiator) or `true` for not mounted (after factory reset)'),
171
- exposes.binary('mounted_mode_control', ea.ALL, true, false)
172
- .withDescription('Set the unit mounting mode. `false` Go to Mounted Mode or `true` Go to Mounting Mode'),
173
- exposes.binary('thermostat_vertical_orientation', ea.ALL, true, false)
174
- .withDescription('Thermostat Orientation. This is important for the PID in how it assesses temperature. ' +
175
- '`false` Horizontal or `true` Vertical'),
176
- exposes.binary('viewing_direction', ea.ALL, true, false)
177
- .withDescription('Viewing/Display Direction. `false` Horizontal or `true` Vertical'),
178
- exposes.binary('heat_available', ea.ALL, true, false)
179
- .withDescription('Not clear how this affects operation. `false` No Heat Available or `true` Heat Available'),
180
- exposes.binary('heat_required', ea.STATE_GET, true, false)
181
- .withDescription('Whether or not the unit needs warm water. `false` No Heat Request or `true` Heat Request'),
182
- exposes.enum('setpoint_change_source', ea.STATE, ['manual', 'schedule', 'externally'])
183
- .withDescription('Values observed are `0` (manual), `1` (schedule) or `2` (externally)'),
184
- exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 32, 0.5).withLocalTemperature().withPiHeatingDemand()
185
- .withSystemMode(['heat']).withRunningState(['idle', 'heat'], ea.STATE),
186
- exposes.numeric('external_measured_room_sensor', ea.ALL)
187
- .withDescription('Set at maximum 3 hours interval but not more often than every 30 minutes and 0.1 ' +
188
- 'degrees difference. Resets every 3hours to standard. e.g. 21C = 2100 (-8000=undefined).')
189
- .withValueMin(-8000).withValueMax(3500),
190
- exposes.numeric('window_open_internal', ea.STATE_GET).withValueMin(0).withValueMax(4)
191
- .withDescription('0=Quarantine, 1=Windows are closed, 2=Hold - Windows are maybe about to open, ' +
192
- '3=Open window detected, 4=In window open state from external but detected closed locally'),
193
- exposes.binary('window_open_external', ea.ALL, true, false)
194
- .withDescription('Set if the window is open or close. This setting will trigger a change in the internal ' +
195
- 'window and heating demand. `false` (windows are closed) or `true` (windows are open)'),
196
- exposes.enum('day_of_week', ea.ALL,
197
- ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'away_or_vacation'])
198
- .withDescription('Exercise day of week: 0=Sun...6=Sat, 7=undefined'),
199
- exposes.numeric('trigger_time', ea.ALL).withValueMin(0).withValueMax(65535)
200
- .withDescription('Exercise trigger time. Minutes since midnight (65535=undefined). Range 0 to 1439'),
201
- exposes.numeric('algorithm_scale_factor', ea.ALL).withValueMin(1).withValueMax(10)
202
- .withDescription('Scale factor of setpoint filter timeconstant ("aggressiveness" of control algorithm) '+
203
- '1= Quick ... 5=Moderate ... 10=Slow'),
204
- exposes.binary('load_balancing_enable', ea.ALL, true, false)
205
- .withDescription('Whether or not the thermostat acts as standalone thermostat or shares load with other ' +
206
- 'thermostats in the room. The gateway must update load_room_mean if enabled.'),
207
- exposes.numeric('load_room_mean', ea.ALL)
208
- .withDescription('Mean radiator load for room calculated by gateway for load balancing purposes (-8000=undefined)')
209
- .withValueMin(-8000).withValueMax(2000),
210
- exposes.numeric('load_estimate', ea.STATE_GET)
211
- .withDescription('Load estimate on this radiator')],
212
- configure: async (device, coordinatorEndpoint, logger) => {
213
- const endpoint = device.getEndpoint(1);
214
- const options = {manufacturerCode: 0x1246};
215
- await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'hvacThermostat']);
216
-
217
- // standard ZCL attributes
218
- await reporting.batteryPercentageRemaining(endpoint);
219
- await reporting.thermostatTemperature(endpoint);
220
- await reporting.thermostatPIHeatingDemand(endpoint);
221
- await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
222
-
223
- // danfoss attributes
224
- await endpoint.configureReporting('hvacThermostat', [{
225
- attribute: 'danfossMountedModeActive',
226
- minimumReportInterval: constants.repInterval.MINUTE,
227
- maximumReportInterval: constants.repInterval.MAX,
228
- reportableChange: 1,
229
- }], options);
230
- await endpoint.configureReporting('hvacThermostat', [{
231
- attribute: 'danfossWindowOpenInternal',
232
- minimumReportInterval: constants.repInterval.MINUTE,
233
- maximumReportInterval: constants.repInterval.HOUR,
234
- reportableChange: 1,
235
- }], options);
236
- await endpoint.configureReporting('hvacThermostat', [{
237
- attribute: 'danfossHeatRequired',
238
- minimumReportInterval: constants.repInterval.MINUTE,
239
- maximumReportInterval: constants.repInterval.HOUR,
240
- reportableChange: 1,
241
- }], options);
242
- await endpoint.configureReporting('hvacThermostat', [{
243
- attribute: 'danfossExternalMeasuredRoomSensor',
244
- minimumReportInterval: constants.repInterval.MINUTE,
245
- maximumReportInterval: constants.repInterval.MAX,
246
- reportableChange: 1,
247
- }], options);
248
-
249
- await endpoint.read('hvacThermostat', [
250
- 'danfossWindowOpenExternal',
251
- 'danfossDayOfWeek',
252
- 'danfossTriggerTime',
253
- 'danfossAlgorithmScaleFactor',
254
- 'danfossHeatAvailable',
255
- 'danfossMountedModeControl',
256
- 'danfossMountedModeActive',
257
- 'danfossExternalMeasuredRoomSensor',
258
- 'danfossLoadBalancingEnable',
259
- 'danfossLoadRoomMean',
260
- ], options);
261
-
262
- // read systemMode to have an initial value
263
- await endpoint.read('hvacThermostat', ['systemMode']);
264
-
265
- // read keypadLockout, we don't need reporting as it cannot be set physically on the device
266
- await endpoint.read('hvacUserInterfaceCfg', ['keypadLockout']);
267
-
268
- // Seems that it is bug in Danfoss, device does not asks for the time with binding
269
- // So, we need to write time during configure (same as for HEIMAN devices)
270
- const time = Math.round(((new Date()).getTime() - constants.OneJanuary2000) / 1000);
271
- // Time-master + synchronised
272
- const values = {timeStatus: 3, time: time, timeZone: ((new Date()).getTimezoneOffset() * -1) * 60};
273
- endpoint.write('genTime', values);
274
- },
275
- },
156
+ description: 'Radiator valve based on Danfoss Ally (014G2461)',
157
+ }),
276
158
  {
277
159
  zigbeeModel: ['SLR1'],
278
160
  model: 'SLR1',
@@ -3,6 +3,13 @@ const extend = require('../lib/extend');
3
3
  const reporting = require('../lib/reporting');
4
4
 
5
5
  module.exports = [
6
+ {
7
+ zigbeeModel: ['A60S TW'],
8
+ model: 'AC33898',
9
+ vendor: 'LEDVANCE',
10
+ description: ' Smart+ LED classic E27 Zigbee 10W/810lm',
11
+ extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
12
+ },
6
13
  {
7
14
  zigbeeModel: ['Outdoor Plug', 'Plug Value'],
8
15
  model: 'AC26940/AC31266',
@@ -29,6 +29,15 @@ const hueExtend = {
29
29
  };
30
30
 
31
31
  module.exports = [
32
+ {
33
+ zigbeeModel: ['LCX004'],
34
+ model: '929002994901',
35
+ vendor: 'Philips',
36
+ description: 'Hue gradient lightstrip',
37
+ meta: {turnsOffAtBrightness1: true},
38
+ extend: hueExtend.light_onoff_brightness_colortemp_color({colorTempRange: [153, 500]}),
39
+ ota: ota.zigbeeOTA,
40
+ },
32
41
  {
33
42
  zigbeeModel: ['929003047501'],
34
43
  model: '929003047501',
package/devices/popp.js CHANGED
@@ -1,136 +1,10 @@
1
- const exposes = require('../lib/exposes');
2
- const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
3
- const tz = require('../converters/toZigbee');
4
- const ota = require('../lib/ota');
5
- const constants = require('../lib/constants');
6
- const reporting = require('../lib/reporting');
7
- const e = exposes.presets;
8
- const ea = exposes.access;
1
+ const {extendDevice} = require('../lib/utils');
9
2
 
10
3
  module.exports = [
11
- {
12
- // eT093WRO is the same as Hive TRV001 and Danfoss Ally (eTRV0100). If implementing anything, please consider
13
- // changing those two too.
4
+ extendDevice(require('./danfoss'), '014G2461', {
14
5
  zigbeeModel: ['eT093WRO'],
15
6
  model: '701721',
16
7
  vendor: 'Popp',
17
- description: 'Smart thermostat',
18
- fromZigbee: [fz.battery, fz.thermostat, fz.thermostat_weekly_schedule, fz.hvac_user_interface, fz.danfoss_thermostat],
19
- toZigbee: [tz.danfoss_thermostat_occupied_heating_setpoint, tz.thermostat_local_temperature, tz.danfoss_mounted_mode_active,
20
- tz.danfoss_mounted_mode_control, tz.danfoss_thermostat_vertical_orientation, tz.danfoss_algorithm_scale_factor,
21
- tz.danfoss_heat_available, tz.danfoss_heat_required, tz.danfoss_day_of_week, tz.danfoss_trigger_time,
22
- tz.danfoss_window_open_internal, tz.danfoss_window_open_external, tz.danfoss_load_estimate,
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
- 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(),
27
- exposes.binary('mounted_mode_active', ea.STATE_GET, true, false)
28
- .withDescription('Is the unit in mounting mode. This is set to `false` for mounted (already on ' +
29
- 'the radiator) or `true` for not mounted (after factory reset)'),
30
- exposes.binary('mounted_mode_control', ea.ALL, true, false)
31
- .withDescription('Set the unit mounting mode. `false` Go to Mounted Mode or `true` Go to Mounting Mode'),
32
- exposes.binary('thermostat_vertical_orientation', ea.ALL, true, false)
33
- .withDescription('Thermostat Orientation. This is important for the PID in how it assesses temperature. ' +
34
- '`false` Horizontal or `true` Vertical'),
35
- exposes.binary('viewing_direction', ea.ALL, true, false)
36
- .withDescription('Viewing/Display Direction. `false` Horizontal or `true` Vertical'),
37
- exposes.binary('heat_available', ea.ALL, true, false)
38
- .withDescription('Not clear how this affects operation. `false` No Heat Available or `true` Heat Available'),
39
- exposes.binary('heat_required', ea.STATE_GET, true, false)
40
- .withDescription('Whether or not the unit needs warm water. `false` No Heat Request or `true` Heat Request'),
41
- exposes.enum('setpoint_change_source', ea.STATE, ['manual', 'schedule', 'externally'])
42
- .withDescription('Values observed are `0` (manual), `1` (schedule) or `2` (externally)'),
43
- exposes.climate().withSetpoint('occupied_heating_setpoint', 5, 32, 0.5).withLocalTemperature().withPiHeatingDemand()
44
- .withSystemMode(['heat']).withRunningState(['idle', 'heat'], ea.STATE),
45
- exposes.numeric('external_measured_room_sensor', ea.ALL)
46
- .withDescription('Set at maximum 3 hours interval but not more often than every 30 minutes and 0.1 ' +
47
- 'degrees difference. Resets every 3hours to standard. e.g. 21C = 2100 (-8000=undefined).')
48
- .withValueMin(-8000).withValueMax(3500),
49
- exposes.numeric('window_open_internal', ea.STATE_GET).withValueMin(0).withValueMax(4)
50
- .withDescription('0=Quarantine, 1=Windows are closed, 2=Hold - Windows are maybe about to open, ' +
51
- '3=Open window detected, 4=In window open state from external but detected closed locally'),
52
- exposes.binary('window_open_external', ea.ALL, true, false)
53
- .withDescription('Set if the window is open or close. This setting will trigger a change in the internal ' +
54
- 'window and heating demand. `false` (windows are closed) or `true` (windows are open)'),
55
- exposes.enum('day_of_week', ea.ALL,
56
- ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'away_or_vacation'])
57
- .withDescription('Exercise day of week: 0=Sun...6=Sat, 7=undefined'),
58
- exposes.numeric('trigger_time', ea.ALL).withValueMin(0).withValueMax(65535)
59
- .withDescription('Exercise trigger time. Minutes since midnight (65535=undefined). Range 0 to 1439'),
60
- exposes.numeric('algorithm_scale_factor', ea.ALL).withValueMin(1).withValueMax(10)
61
- .withDescription('Scale factor of setpoint filter timeconstant ("aggressiveness" of control algorithm) '+
62
- '1= Quick ... 5=Moderate ... 10=Slow'),
63
- exposes.binary('load_balancing_enable', ea.ALL, true, false)
64
- .withDescription('Whether or not the thermostat acts as standalone thermostat or shares load with other ' +
65
- 'thermostats in the room. The gateway must update load_room_mean if enabled.'),
66
- exposes.numeric('load_room_mean', ea.ALL)
67
- .withDescription('Mean radiator load for room calculated by gateway for load balancing purposes (-8000=undefined)')
68
- .withValueMin(-8000).withValueMax(2000),
69
- exposes.numeric('load_estimate', ea.STATE_GET)
70
- .withDescription('Load estimate on this radiator')],
71
- ota: ota.zigbeeOTA,
72
- configure: async (device, coordinatorEndpoint, logger) => {
73
- const endpoint = device.getEndpoint(1);
74
- const options = {manufacturerCode: 0x1246};
75
- await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg', 'hvacThermostat']);
76
-
77
- // standard ZCL attributes
78
- await reporting.batteryPercentageRemaining(endpoint);
79
- await reporting.thermostatTemperature(endpoint);
80
- await reporting.thermostatPIHeatingDemand(endpoint);
81
- await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
82
-
83
- // danfoss attributes
84
- await endpoint.configureReporting('hvacThermostat', [{
85
- attribute: 'danfossMountedModeActive',
86
- minimumReportInterval: constants.repInterval.MINUTE,
87
- maximumReportInterval: constants.repInterval.MAX,
88
- reportableChange: 1,
89
- }], options);
90
- await endpoint.configureReporting('hvacThermostat', [{
91
- attribute: 'danfossWindowOpenInternal',
92
- minimumReportInterval: constants.repInterval.MINUTE,
93
- maximumReportInterval: constants.repInterval.HOUR,
94
- reportableChange: 1,
95
- }], options);
96
- await endpoint.configureReporting('hvacThermostat', [{
97
- attribute: 'danfossHeatRequired',
98
- minimumReportInterval: constants.repInterval.MINUTE,
99
- maximumReportInterval: constants.repInterval.HOUR,
100
- reportableChange: 1,
101
- }], options);
102
- await endpoint.configureReporting('hvacThermostat', [{
103
- attribute: 'danfossExternalMeasuredRoomSensor',
104
- minimumReportInterval: constants.repInterval.MINUTE,
105
- maximumReportInterval: constants.repInterval.MAX,
106
- reportableChange: 1,
107
- }], options);
108
-
109
- await endpoint.read('hvacThermostat', [
110
- 'danfossWindowOpenExternal',
111
- 'danfossDayOfWeek',
112
- 'danfossTriggerTime',
113
- 'danfossAlgorithmScaleFactor',
114
- 'danfossHeatAvailable',
115
- 'danfossMountedModeControl',
116
- 'danfossMountedModeActive',
117
- 'danfossExternalMeasuredRoomSensor',
118
- 'danfossLoadBalancingEnable',
119
- 'danfossLoadRoomMean',
120
- ], options);
121
-
122
- // read systemMode to have an initial value
123
- await endpoint.read('hvacThermostat', ['systemMode']);
124
-
125
- // read keypadLockout, we don't need reporting as it cannot be set physically on the device
126
- await endpoint.read('hvacUserInterfaceCfg', ['keypadLockout']);
127
-
128
- // Seems that it is bug in Danfoss, device does not asks for the time with binding
129
- // So, we need to write time during configure (same as for HEIMAN devices)
130
- const time = Math.round(((new Date()).getTime() - constants.OneJanuary2000) / 1000);
131
- // Time-master + synchronised
132
- const values = {timeStatus: 3, time: time, timeZone: ((new Date()).getTimezoneOffset() * -1) * 60};
133
- endpoint.write('genTime', values);
134
- },
135
- },
8
+ description: 'Smart thermostat based on Danfoss Ally (014G2461)',
9
+ }),
136
10
  ];
@@ -71,7 +71,8 @@ module.exports = [
71
71
  fromZigbee: [fz.battery, fz.command_on, fz.command_off, fz.command_step, fz.command_move, fz.command_stop, fz.command_recall,
72
72
  fz.command_move_hue, fz.command_move_to_color, fz.command_move_to_color_temp],
73
73
  exposes: [e.battery(), e.action(['on', 'off', 'brightness_step_up', 'brightness_step_down', 'brightness_move_up',
74
- 'brightness_move_down', 'brightness_stop', 'recall_1', 'recall_2', 'recall_3'])],
74
+ 'brightness_move_down', 'brightness_stop', 'recall_1', 'recall_2', 'recall_3', 'hue_move', 'color_temperature_move',
75
+ 'color_move', 'hue_stop'])],
75
76
  toZigbee: [],
76
77
  meta: {multiEndpoint: true, battery: {dontDividePercentage: true}},
77
78
  configure: async (device, coordinatorEndpoint) => {
@@ -5,7 +5,10 @@ const ea = exposes.access;
5
5
 
6
6
  module.exports = [
7
7
  {
8
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_6qoazbre'}],
8
+ fingerprint: [
9
+ {modelID: 'TS0601', manufacturerName: '_TZE200_6qoazbre'},
10
+ {modelID: 'TS0601', manufacturerName: '_TZE200_fcooykb4'},
11
+ ],
9
12
  model: 'WZ5_dim',
10
13
  vendor: 'Skydance',
11
14
  description: 'Zigbee & RF 5 in 1 LED controller (DIM mode)',
@@ -17,7 +20,10 @@ module.exports = [
17
20
  ],
18
21
  },
19
22
  {
20
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_gz3n0tzf'}],
23
+ fingerprint: [
24
+ {modelID: 'TS0601', manufacturerName: '_TZE200_gz3n0tzf'},
25
+ {modelID: 'TS0601', manufacturerName: '_TZE200_nthosjmx'},
26
+ ],
21
27
  model: 'WZ5_cct',
22
28
  vendor: 'Skydance',
23
29
  description: 'Zigbee & RF 5 in 1 LED controller (CCT mode)',
@@ -29,7 +35,10 @@ module.exports = [
29
35
  ],
30
36
  },
31
37
  {
32
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_9hghastn'}],
38
+ fingerprint: [
39
+ {modelID: 'TS0601', manufacturerName: '_TZE200_9hghastn'},
40
+ {modelID: 'TS0601', manufacturerName: '_TZE200_9mt3kgn0'},
41
+ ],
33
42
  model: 'WZ5_rgb',
34
43
  vendor: 'Skydance',
35
44
  description: 'Zigbee & RF 5 in 1 LED controller (RGB mode)',
@@ -41,7 +50,10 @@ module.exports = [
41
50
  ],
42
51
  },
43
52
  {
44
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_3thxjahu'}],
53
+ fingerprint: [
54
+ {modelID: 'TS0601', manufacturerName: '_TZE200_3thxjahu'},
55
+ {modelID: 'TS0601', manufacturerName: '_TZE200_g9jdneiu'},
56
+ ],
45
57
  model: 'WZ5_rgbw',
46
58
  vendor: 'Skydance',
47
59
  description: 'Zigbee & RF 5 in 1 LED controller (RGBW mode)',
@@ -56,7 +68,10 @@ module.exports = [
56
68
  meta: {separateWhite: true},
57
69
  },
58
70
  {
59
- fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_mde0utnv'}],
71
+ fingerprint: [
72
+ {modelID: 'TS0601', manufacturerName: '_TZE200_mde0utnv'},
73
+ {modelID: 'TS0601', manufacturerName: '_TZE200_aa9awrng'},
74
+ ],
60
75
  model: 'WZ5_rgbcct',
61
76
  vendor: 'Skydance',
62
77
  description: 'Zigbee & RF 5 in 1 LED controller (RGB+CCT mode)',