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.
- package/converters/fromZigbee.js +18 -7
- package/converters/toZigbee.js +29 -5
- package/devices/hive.js +4 -122
- package/devices/ledvance.js +7 -0
- package/devices/popp.js +4 -130
- package/devices/tuya.js +13 -10
- package/devices/xiaomi.js +4 -0
- package/lib/tuya.js +19 -0
- package/lib/utils.js +9 -0
- package/npm-shrinkwrap.json +844 -874
- package/package.json +2 -2
package/converters/fromZigbee.js
CHANGED
|
@@ -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
|
-
|
|
7567
|
+
result = {presence: {0: false, 1: true}[value]};
|
|
7568
|
+
break;
|
|
7567
7569
|
case tuya.dataPoints.trsMotionState:
|
|
7568
|
-
|
|
7570
|
+
result = {occupancy: {1: false, 2: true}[value]};
|
|
7571
|
+
break;
|
|
7569
7572
|
case tuya.dataPoints.trsMotionSpeed:
|
|
7570
|
-
|
|
7573
|
+
result = {motion_speed: value};
|
|
7574
|
+
break;
|
|
7571
7575
|
case tuya.dataPoints.trsMotionDirection:
|
|
7572
|
-
|
|
7576
|
+
result = {motion_direction: tuya.tuyaRadar.motionDirection[value]};
|
|
7577
|
+
break;
|
|
7573
7578
|
case tuya.dataPoints.trsScene:
|
|
7574
|
-
|
|
7579
|
+
result = {radar_scene: tuya.tuyaRadar.radarScene[value]};
|
|
7580
|
+
break;
|
|
7575
7581
|
case tuya.dataPoints.trsSensitivity:
|
|
7576
|
-
|
|
7582
|
+
result = {radar_sensitivity: value};
|
|
7583
|
+
break;
|
|
7577
7584
|
case tuya.dataPoints.trsIlluminanceLux:
|
|
7578
|
-
|
|
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: {
|
package/converters/toZigbee.js
CHANGED
|
@@ -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.
|
|
6277
|
-
|
|
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
|
-
|
|
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
|
|
159
|
-
|
|
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',
|
package/devices/ledvance.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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.
|
|
1671
|
-
|
|
1672
|
-
exposes.numeric('
|
|
1673
|
-
|
|
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.
|
|
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,
|
|
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,
|
|
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
|
};
|