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.
- package/converters/fromZigbee.js +20 -9
- package/converters/toZigbee.js +47 -17
- package/devices/hive.js +4 -122
- package/devices/ledvance.js +7 -0
- package/devices/philips.js +9 -0
- package/devices/popp.js +4 -130
- package/devices/rgb_genie.js +2 -1
- package/devices/skydance.js +20 -5
- package/devices/tuya.js +22 -14
- package/devices/xiaomi.js +4 -0
- package/index.js +1 -1
- package/lib/ota/zigbeeOTA.js +32 -7
- 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
|
@@ -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 /
|
|
1384
|
-
y: precisionRound(msg.data.colory /
|
|
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
|
-
|
|
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
|
},
|
|
@@ -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.
|
|
6451
|
-
|
|
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.
|
|
6476
|
-
|
|
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
|
-
|
|
6552
|
-
|
|
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
|
-
|
|
6558
|
-
|
|
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
|
|
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/philips.js
CHANGED
|
@@ -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
|
|
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/rgb_genie.js
CHANGED
|
@@ -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) => {
|
package/devices/skydance.js
CHANGED
|
@@ -5,7 +5,10 @@ const ea = exposes.access;
|
|
|
5
5
|
|
|
6
6
|
module.exports = [
|
|
7
7
|
{
|
|
8
|
-
fingerprint: [
|
|
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: [
|
|
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: [
|
|
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: [
|
|
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: [
|
|
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)',
|