zigbee-herdsman-converters 14.0.376 → 14.0.377

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.
@@ -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
  },
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',
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
  ];
package/devices/tuya.js CHANGED
@@ -1658,7 +1658,7 @@ module.exports = [
1658
1658
  vendor: 'TuYa',
1659
1659
  description: 'Temperature & humidity & illuminance sensor with display',
1660
1660
  fromZigbee: [fz.battery, fz.illuminance, fz.temperature, fz.humidity, fz.ts0201_temperature_humidity_alarm],
1661
- toZigbee: [],
1661
+ toZigbee: [tz.ts0201_temperature_humidity_alarm],
1662
1662
  configure: async (device, coordinatorEndpoint, logger) => {
1663
1663
  const endpoint = device.getEndpoint(1);
1664
1664
  // Enables reporting of measurement state changes
@@ -1667,10 +1667,14 @@ module.exports = [
1667
1667
  'msTemperatureMeasurement', 'msIlluminanceMeasurement', 'msRelativeHumidity', 'manuSpecificTuya_2']);
1668
1668
  },
1669
1669
  exposes: [e.temperature(), e.humidity(), e.battery(), e.illuminance(), e.illuminance_lux(),
1670
- exposes.numeric('alarm_temperature_max', ea.STATE).withUnit('°C').withDescription('Alarm temperature max'),
1671
- exposes.numeric('alarm_temperature_min', ea.STATE).withUnit('°C').withDescription('Alarm temperature min'),
1672
- exposes.numeric('alarm_humidity_max', ea.STATE).withUnit('%').withDescription('Alarm humidity max'),
1673
- exposes.numeric('alarm_humidity_min', ea.STATE).withUnit('%').withDescription('Alarm humidity min'),
1670
+ exposes.numeric('alarm_temperature_max', ea.STATE_SET).withUnit('°C').withDescription('Alarm temperature max')
1671
+ .withValueMin(-20).withValueMax(80),
1672
+ exposes.numeric('alarm_temperature_min', ea.STATE_SET).withUnit('°C').withDescription('Alarm temperature min')
1673
+ .withValueMin(-20).withValueMax(80),
1674
+ exposes.numeric('alarm_humidity_max', ea.STATE_SET).withUnit('%').withDescription('Alarm humidity max')
1675
+ .withValueMin(0).withValueMax(100),
1676
+ exposes.numeric('alarm_humidity_min', ea.STATE_SET).withUnit('%').withDescription('Alarm humidity min')
1677
+ .withValueMin(0).withValueMax(100),
1674
1678
  exposes.enum('alarm_humidity', ea.STATE, ['below_min_humdity', 'over_humidity', 'off'])
1675
1679
  .withDescription('Alarm humidity status'),
1676
1680
  exposes.enum('alarm_temperature', ea.STATE, ['below_min_temperature', 'over_temperature', 'off'])
@@ -1708,17 +1712,16 @@ module.exports = [
1708
1712
  model: 'MIR-HE200-TY',
1709
1713
  vendor: 'TuYa',
1710
1714
  description: 'Human presence sensor',
1711
- fromZigbee: [fz.ignore_basic_report, fz.tuya_radar_sensor],
1715
+ fromZigbee: [fz.tuya_radar_sensor],
1712
1716
  toZigbee: [tz.tuya_radar_sensor],
1713
1717
  exposes: [
1714
- e.illuminance_lux(), e.presence(),
1715
- exposes.binary('motion', ea.STATE, [true, false]).withDescription('moving inside the range of the sensor'),
1718
+ e.illuminance_lux(), e.presence(), e.occupancy(),
1716
1719
  exposes.numeric('motion_speed', ea.STATE).withDescription('Speed of movement'),
1717
- exposes.enum('motion_direction', ea.STATE, ['standing_still', 'moving_forward', 'moving_backward'])
1720
+ exposes.enum('motion_direction', ea.STATE, Object.values(tuya.tuyaRadar.motionDirection))
1718
1721
  .withDescription('direction of movement from the point of view of the radar'),
1719
1722
  exposes.numeric('radar_sensitivity', ea.STATE_SET).withValueMin(0).withValueMax(10).withValueStep(1)
1720
1723
  .withDescription('sensitivity of the radar'),
1721
- exposes.enum('radar_scene', ea.STATE_SET, ['default', 'area', 'toilet', 'bedroom', 'parlour', 'office', 'hotel'])
1724
+ exposes.enum('radar_scene', ea.STATE_SET, Object.values(tuya.tuyaRadar.radarScene))
1722
1725
  .withDescription('presets for sensitivity for presence and movement'),
1723
1726
  ],
1724
1727
  },
package/devices/xiaomi.js CHANGED
@@ -923,6 +923,10 @@ module.exports = [
923
923
  fromZigbee: [fz.xiaomi_battery, fz.xiaomi_contact, fz.xiaomi_contact_interval],
924
924
  toZigbee: [],
925
925
  exposes: [e.battery(), e.contact(), e.temperature(), e.battery_voltage()],
926
+ configure: async (device) => {
927
+ device.powerSource = 'Battery';
928
+ device.save();
929
+ },
926
930
  },
927
931
  {
928
932
  zigbeeModel: ['lumi.sensor_wleak.aq1'],
package/lib/tuya.js CHANGED
@@ -600,6 +600,24 @@ const fanModes = {
600
600
  3: 'auto',
601
601
  };
602
602
 
603
+ // Radar sensor lookups
604
+ const tuyaRadar = {
605
+ radarScene: {
606
+ 0: 'default',
607
+ 1: 'area',
608
+ 2: 'toilet',
609
+ 3: 'bedroom',
610
+ 4: 'parlour',
611
+ 5: 'office',
612
+ 6: 'hotel',
613
+ },
614
+ motionDirection: {
615
+ 0: 'standing_still',
616
+ 1: 'moving_forward',
617
+ 2: 'moving_backward',
618
+ },
619
+ };
620
+
603
621
  // Motion sensor lookups
604
622
  const msLookups = {
605
623
  OSensitivity: {
@@ -781,4 +799,5 @@ module.exports = {
781
799
  msLookups,
782
800
  tvThermostatMode,
783
801
  tvThermostatPreset,
802
+ tuyaRadar,
784
803
  };
package/lib/utils.js CHANGED
@@ -376,6 +376,14 @@ function normalizeCelsiusVersionOfFahrenheit(value) {
376
376
  return ((roundedFahrenheit - 32)/1.8).toFixed(2);
377
377
  }
378
378
 
379
+ function extendDevice(deviceConfigs, modelName, adjustments) {
380
+ const baseDevice = deviceConfigs.find((device) => device.model === modelName);
381
+ if (typeof baseDevice !== 'object') {
382
+ throw Error(`Could not find model ${modelName} in provided device list`);
383
+ }
384
+ return {...baseDevice, ...adjustments};
385
+ }
386
+
379
387
  module.exports = {
380
388
  getOptions,
381
389
  isLegacyEnabled,
@@ -406,4 +414,5 @@ module.exports = {
406
414
  normalizeCelsiusVersionOfFahrenheit,
407
415
  deleteSceneState,
408
416
  getSceneState,
417
+ extendDevice,
409
418
  };