zigbee-herdsman-converters 14.0.374 → 14.0.378
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 +85 -23
- package/converters/toZigbee.js +61 -8
- package/devices/bticino.js +11 -8
- package/devices/evanell.js +29 -0
- package/devices/hive.js +4 -122
- package/devices/iris.js +2 -0
- package/devices/jasco.js +18 -0
- package/devices/ledvance.js +7 -0
- package/devices/moes.js +1 -1
- package/devices/philips.js +9 -0
- package/devices/popp.js +4 -130
- package/devices/tuya.js +22 -13
- package/devices/xiaomi.js +10 -6
- package/index.js +1 -1
- package/lib/exposes.js +2 -1
- package/lib/tuya.js +25 -4
- package/lib/utils.js +9 -0
- package/npm-shrinkwrap.json +844 -874
- package/package.json +2 -2
package/converters/fromZigbee.js
CHANGED
|
@@ -3672,7 +3672,7 @@ const converters = {
|
|
|
3672
3672
|
case tuya.dataPoints.moesSboostHeatingCountdown:
|
|
3673
3673
|
return {boost_heating_countdown: value};
|
|
3674
3674
|
case tuya.dataPoints.moesSreset:
|
|
3675
|
-
|
|
3675
|
+
return {valve_state: value ? 'CLOSED' : 'OPEN'};
|
|
3676
3676
|
case tuya.dataPoints.moesSwindowDetectionFunktion_A2:
|
|
3677
3677
|
return {window_detection: value ? 'ON' : 'OFF'};
|
|
3678
3678
|
case tuya.dataPoints.moesSwindowDetection:
|
|
@@ -4136,6 +4136,51 @@ const converters = {
|
|
|
4136
4136
|
}
|
|
4137
4137
|
},
|
|
4138
4138
|
},
|
|
4139
|
+
evanell_thermostat: {
|
|
4140
|
+
cluster: 'manuSpecificTuya',
|
|
4141
|
+
type: ['commandDataResponse', 'commandDataReport'],
|
|
4142
|
+
convert: (model, msg, publish, options, meta) => {
|
|
4143
|
+
const result = {};
|
|
4144
|
+
for (const dpValue of msg.data.dpValues) {
|
|
4145
|
+
const value = tuya.getDataValue(dpValue);
|
|
4146
|
+
switch (dpValue.dp) {
|
|
4147
|
+
case tuya.dataPoints.evanellChildLock:
|
|
4148
|
+
result.child_lock = value ? 'LOCK' : 'UNLOCK';
|
|
4149
|
+
break;
|
|
4150
|
+
case tuya.dataPoints.evanellBattery:
|
|
4151
|
+
result.battery = value;
|
|
4152
|
+
break;
|
|
4153
|
+
case tuya.dataPoints.evanellHeatingSetpoint:
|
|
4154
|
+
result.current_heating_setpoint = value/10;
|
|
4155
|
+
break;
|
|
4156
|
+
case tuya.dataPoints.evanellLocalTemp:
|
|
4157
|
+
result.local_temperature = value/10;
|
|
4158
|
+
break;
|
|
4159
|
+
case tuya.dataPoints.evanellMode:
|
|
4160
|
+
switch (value) {
|
|
4161
|
+
case 0: // manual
|
|
4162
|
+
result.system_mode = 'auto';
|
|
4163
|
+
break;
|
|
4164
|
+
case 2: // away
|
|
4165
|
+
result.system_mode = 'heat';
|
|
4166
|
+
break;
|
|
4167
|
+
case 3: // auto
|
|
4168
|
+
result.system_mode = 'off';
|
|
4169
|
+
break;
|
|
4170
|
+
default:
|
|
4171
|
+
meta.logger.warn('zigbee-herdsman-converters:evanell_thermostat: ' +
|
|
4172
|
+
`Mode ${value} is not recognized.`);
|
|
4173
|
+
break;
|
|
4174
|
+
}
|
|
4175
|
+
break;
|
|
4176
|
+
default:
|
|
4177
|
+
meta.logger.warn(`zigbee-herdsman-converters:evanell_thermostat: NOT RECOGNIZED ` +
|
|
4178
|
+
`DP #${dpValue.dp} with data ${JSON.stringify(dpValue)}`);
|
|
4179
|
+
}
|
|
4180
|
+
}
|
|
4181
|
+
return result;
|
|
4182
|
+
},
|
|
4183
|
+
},
|
|
4139
4184
|
etop_thermostat: {
|
|
4140
4185
|
cluster: 'manuSpecificTuya',
|
|
4141
4186
|
type: ['commandDataResponse', 'commandDataReport'],
|
|
@@ -5160,7 +5205,7 @@ const converters = {
|
|
|
5160
5205
|
if (msg.data.hasOwnProperty('0')) payload.detection_period = msg.data['0'];
|
|
5161
5206
|
if (msg.data.hasOwnProperty('4')) payload.mode_switch = {4: 'anti_flicker_mode', 1: 'quick_mode'}[msg.data['4']];
|
|
5162
5207
|
if (msg.data.hasOwnProperty('10')) payload.switch_type = {1: 'toggle', 2: 'momentary'}[msg.data['10']];
|
|
5163
|
-
if (msg.data.hasOwnProperty('258')) payload.
|
|
5208
|
+
if (msg.data.hasOwnProperty('258')) payload.detection_interval = msg.data['258'];
|
|
5164
5209
|
if (msg.data.hasOwnProperty('268')) payload.motion_sensitivity = {1: 'low', 2: 'medium', 3: 'high'}[msg.data['268']];
|
|
5165
5210
|
if (msg.data.hasOwnProperty('512')) {
|
|
5166
5211
|
if (['ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM'].includes(model.model)) {
|
|
@@ -5321,7 +5366,7 @@ const converters = {
|
|
|
5321
5366
|
if (msg.data.hasOwnProperty('illuminance')) {
|
|
5322
5367
|
// The occupancy sensor only sends a message when motion detected.
|
|
5323
5368
|
// Therefore we need to publish the no_motion detected by ourselves.
|
|
5324
|
-
const timeout = meta && meta.state && meta.state.hasOwnProperty('
|
|
5369
|
+
const timeout = meta && meta.state && meta.state.hasOwnProperty('detection_interval') ? meta.state.detection_interval : 60;
|
|
5325
5370
|
|
|
5326
5371
|
// Stop existing timers because motion is detected and set a new one.
|
|
5327
5372
|
globalStore.getValue(msg.endpoint, 'timers', []).forEach((t) => clearTimeout(t));
|
|
@@ -5355,7 +5400,7 @@ const converters = {
|
|
|
5355
5400
|
|
|
5356
5401
|
// The occupancy sensor only sends a message when motion detected.
|
|
5357
5402
|
// Therefore we need to publish the no_motion detected by ourselves.
|
|
5358
|
-
const timeout = meta && meta.state && meta.state.hasOwnProperty('
|
|
5403
|
+
const timeout = meta && meta.state && meta.state.hasOwnProperty('detection_interval') ? meta.state.detection_interval : 60;
|
|
5359
5404
|
|
|
5360
5405
|
// Stop existing timers because motion is detected and set a new one.
|
|
5361
5406
|
globalStore.getValue(msg.endpoint, 'timers', []).forEach((t) => clearTimeout(t));
|
|
@@ -7516,41 +7561,58 @@ const converters = {
|
|
|
7516
7561
|
const dpValue = tuya.firstDpValue(msg, meta, 'tuya_radar_sensor');
|
|
7517
7562
|
const dp = dpValue.dp;
|
|
7518
7563
|
const value = tuya.getDataValue(dpValue);
|
|
7564
|
+
let result = null;
|
|
7519
7565
|
switch (dp) {
|
|
7520
7566
|
case tuya.dataPoints.trsPresenceState:
|
|
7521
|
-
|
|
7567
|
+
result = {presence: {0: false, 1: true}[value]};
|
|
7568
|
+
break;
|
|
7522
7569
|
case tuya.dataPoints.trsMotionState:
|
|
7523
|
-
|
|
7570
|
+
result = {occupancy: {1: false, 2: true}[value]};
|
|
7571
|
+
break;
|
|
7524
7572
|
case tuya.dataPoints.trsMotionSpeed:
|
|
7525
|
-
|
|
7573
|
+
result = {motion_speed: value};
|
|
7574
|
+
break;
|
|
7526
7575
|
case tuya.dataPoints.trsMotionDirection:
|
|
7527
|
-
|
|
7576
|
+
result = {motion_direction: tuya.tuyaRadar.motionDirection[value]};
|
|
7577
|
+
break;
|
|
7528
7578
|
case tuya.dataPoints.trsScene:
|
|
7529
|
-
|
|
7579
|
+
result = {radar_scene: tuya.tuyaRadar.radarScene[value]};
|
|
7580
|
+
break;
|
|
7530
7581
|
case tuya.dataPoints.trsSensitivity:
|
|
7531
|
-
|
|
7582
|
+
result = {radar_sensitivity: value};
|
|
7583
|
+
break;
|
|
7532
7584
|
case tuya.dataPoints.trsIlluminanceLux:
|
|
7533
|
-
|
|
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)}`);
|
|
7534
7589
|
}
|
|
7590
|
+
return result;
|
|
7535
7591
|
},
|
|
7536
7592
|
},
|
|
7537
7593
|
tuya_smart_vibration_sensor: {
|
|
7538
7594
|
cluster: 'manuSpecificTuya',
|
|
7539
7595
|
type: ['commandGetData', 'commandDataResponse', 'raw'],
|
|
7540
7596
|
convert: (model, msg, publish, options, meta) => {
|
|
7541
|
-
const
|
|
7542
|
-
const
|
|
7543
|
-
|
|
7544
|
-
|
|
7545
|
-
|
|
7546
|
-
|
|
7547
|
-
|
|
7548
|
-
|
|
7549
|
-
|
|
7550
|
-
|
|
7551
|
-
|
|
7552
|
-
|
|
7597
|
+
const result = {};
|
|
7598
|
+
for (const dpValue of msg.data.dpValues) {
|
|
7599
|
+
const value = tuya.getDataValue(dpValue);
|
|
7600
|
+
switch (dpValue.dp) {
|
|
7601
|
+
case tuya.dataPoints.state:
|
|
7602
|
+
result.contact = Boolean(value);
|
|
7603
|
+
break;
|
|
7604
|
+
case tuya.dataPoints.thitBatteryPercentage:
|
|
7605
|
+
result.battery = value;
|
|
7606
|
+
break;
|
|
7607
|
+
case tuya.dataPoints.tuyaVibration:
|
|
7608
|
+
result.vibration = Boolean(value);
|
|
7609
|
+
break;
|
|
7610
|
+
default:
|
|
7611
|
+
meta.logger.warn(`zigbee-herdsman-converters:tuya_smart_vibration_sensor: NOT RECOGNIZED ` +
|
|
7612
|
+
`DP #${dpValue.dp} with data ${JSON.stringify(dpValue)}`);
|
|
7613
|
+
}
|
|
7553
7614
|
}
|
|
7615
|
+
return result;
|
|
7554
7616
|
},
|
|
7555
7617
|
},
|
|
7556
7618
|
moes_thermostat_tv: {
|
package/converters/toZigbee.js
CHANGED
|
@@ -2078,12 +2078,12 @@ const converters = {
|
|
|
2078
2078
|
await entity.read('aqaraOpple', [0x0000], manufacturerOptions.xiaomi);
|
|
2079
2079
|
},
|
|
2080
2080
|
},
|
|
2081
|
-
|
|
2082
|
-
key: ['
|
|
2081
|
+
aqara_detection_interval: {
|
|
2082
|
+
key: ['detection_interval'],
|
|
2083
2083
|
convertSet: async (entity, key, value, meta) => {
|
|
2084
2084
|
value *= 1;
|
|
2085
2085
|
await entity.write('aqaraOpple', {0x0102: {value: [value], type: 0x20}}, manufacturerOptions.xiaomi);
|
|
2086
|
-
return {state: {
|
|
2086
|
+
return {state: {detection_interval: value}};
|
|
2087
2087
|
},
|
|
2088
2088
|
convertGet: async (entity, key, meta) => {
|
|
2089
2089
|
await entity.read('aqaraOpple', [0x0102], manufacturerOptions.xiaomi);
|
|
@@ -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;
|
|
@@ -5411,6 +5433,35 @@ const converters = {
|
|
|
5411
5433
|
await tuya.sendDataPointValue(entity, tuya.dataPoints.saswellTempCalibration, value);
|
|
5412
5434
|
},
|
|
5413
5435
|
},
|
|
5436
|
+
evanell_thermostat_current_heating_setpoint: {
|
|
5437
|
+
key: ['current_heating_setpoint'],
|
|
5438
|
+
convertSet: async (entity, key, value, meta) => {
|
|
5439
|
+
const temp = Math.round(value * 10);
|
|
5440
|
+
await tuya.sendDataPointValue(entity, tuya.dataPoints.evanellHeatingSetpoint, temp);
|
|
5441
|
+
},
|
|
5442
|
+
},
|
|
5443
|
+
evanell_thermostat_system_mode: {
|
|
5444
|
+
key: ['system_mode'],
|
|
5445
|
+
convertSet: async (entity, key, value, meta) => {
|
|
5446
|
+
switch (value) {
|
|
5447
|
+
case 'off':
|
|
5448
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.evanellMode, 3 /* off */);
|
|
5449
|
+
break;
|
|
5450
|
+
case 'heat':
|
|
5451
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.evanellMode, 2 /* manual */);
|
|
5452
|
+
break;
|
|
5453
|
+
case 'auto':
|
|
5454
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.evanellMode, 0 /* auto */);
|
|
5455
|
+
break;
|
|
5456
|
+
}
|
|
5457
|
+
},
|
|
5458
|
+
},
|
|
5459
|
+
evanell_thermostat_child_lock: {
|
|
5460
|
+
key: ['child_lock'],
|
|
5461
|
+
convertSet: async (entity, key, value, meta) => {
|
|
5462
|
+
await tuya.sendDataPointBool(entity, tuya.dataPoints.evanellChildLock, value === 'LOCK');
|
|
5463
|
+
},
|
|
5464
|
+
},
|
|
5414
5465
|
silvercrest_smart_led_string: {
|
|
5415
5466
|
key: ['color', 'brightness', 'effect'],
|
|
5416
5467
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -6244,11 +6295,13 @@ const converters = {
|
|
|
6244
6295
|
convertSet: async (entity, key, value, meta) => {
|
|
6245
6296
|
switch (key) {
|
|
6246
6297
|
case 'radar_scene':
|
|
6247
|
-
await tuya.
|
|
6248
|
-
|
|
6298
|
+
await tuya.sendDataPointEnum(entity, tuya.dataPoints.trsScene, utils.getKey(tuya.tuyaRadar.radarScene, value));
|
|
6299
|
+
break;
|
|
6249
6300
|
case 'radar_sensitivity':
|
|
6250
6301
|
await tuya.sendDataPointValue(entity, tuya.dataPoints.trsSensitivity, value);
|
|
6251
|
-
|
|
6302
|
+
break;
|
|
6303
|
+
default: // Unknown Key
|
|
6304
|
+
meta.logger.warn(`toZigbee.tuya_radar_sensor: Unhandled Key ${key}`);
|
|
6252
6305
|
}
|
|
6253
6306
|
},
|
|
6254
6307
|
},
|
package/devices/bticino.js
CHANGED
|
@@ -30,19 +30,22 @@ module.exports = [
|
|
|
30
30
|
vendor: 'BTicino',
|
|
31
31
|
description: 'Dimmer switch with neutral',
|
|
32
32
|
extend: extend.light_onoff_brightness({noConfigure: true}),
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
fromZigbee: [fz.brightness, fz.identify, fz.on_off, fz.lighting_ballast_configuration],
|
|
34
|
+
toZigbee: [tz.light_onoff_brightness, tz.legrand_settingAlwaysEnableLed, tz.legrand_settingEnableLedIfOn,
|
|
35
|
+
tz.legrand_settingEnableDimmer, tz.legrand_identify, tz.ballast_config],
|
|
36
|
+
exposes: [e.light_brightness(),
|
|
37
|
+
exposes.numeric('ballast_minimum_level', ea.ALL).withValueMin(1).withValueMax(254)
|
|
38
|
+
.withDescription('Specifies the minimum brightness value'),
|
|
39
|
+
exposes.numeric('ballast_maximum_level', ea.ALL).withValueMin(1).withValueMax(254)
|
|
40
|
+
.withDescription('Specifies the maximum brightness value'),
|
|
35
41
|
exposes.binary('dimmer_enabled', ea.STATE_SET, 'ON', 'OFF').withDescription('Allow the device to change brightness'),
|
|
36
42
|
exposes.binary('permanent_led', ea.STATE_SET, 'ON', 'OFF').withDescription('Enable or disable the permanent blue LED'),
|
|
37
|
-
exposes.binary('led_when_on', ea.STATE_SET, 'ON', 'OFF').withDescription('Enables the LED when the light is on'),
|
|
38
|
-
],
|
|
39
|
-
fromZigbee: [fz.brightness, fz.identify, fz.on_off],
|
|
40
|
-
toZigbee: [tz.light_onoff_brightness, tz.legrand_settingAlwaysEnableLed, tz.legrand_settingEnableLedIfOn,
|
|
41
|
-
tz.legrand_settingEnableDimmer, tz.legrand_identify],
|
|
43
|
+
exposes.binary('led_when_on', ea.STATE_SET, 'ON', 'OFF').withDescription('Enables the LED when the light is on')],
|
|
42
44
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
43
45
|
await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
|
|
44
46
|
const endpoint = device.getEndpoint(1);
|
|
45
|
-
await reporting.bind(endpoint, coordinatorEndpoint, ['genIdentify', 'genOnOff', 'genLevelCtrl',
|
|
47
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genIdentify', 'genOnOff', 'genLevelCtrl',
|
|
48
|
+
'genBinaryInput', 'lightingBallastCfg']);
|
|
46
49
|
await reporting.onOff(endpoint);
|
|
47
50
|
await reporting.brightness(endpoint);
|
|
48
51
|
},
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const exposes = require('../lib/exposes');
|
|
2
|
+
const fz = require('../converters/fromZigbee');
|
|
3
|
+
const tz = require('../converters/toZigbee');
|
|
4
|
+
const tuya = require('../lib/tuya');
|
|
5
|
+
const reporting = require('../lib/reporting');
|
|
6
|
+
const e = exposes.presets;
|
|
7
|
+
const ea = exposes.access;
|
|
8
|
+
|
|
9
|
+
module.exports = [
|
|
10
|
+
{
|
|
11
|
+
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_dmfguuli'}],
|
|
12
|
+
model: 'EZ200',
|
|
13
|
+
vendor: 'Evanell',
|
|
14
|
+
description: 'Thermostatic radiator valve',
|
|
15
|
+
fromZigbee: [fz.evanell_thermostat],
|
|
16
|
+
toZigbee: [tz.evanell_thermostat_current_heating_setpoint, tz.evanell_thermostat_system_mode,
|
|
17
|
+
tz.evanell_thermostat_child_lock],
|
|
18
|
+
onEvent: tuya.onEventSetTime,
|
|
19
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
20
|
+
const endpoint = device.getEndpoint(1);
|
|
21
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic']);
|
|
22
|
+
},
|
|
23
|
+
exposes: [e.child_lock(), e.battery(),
|
|
24
|
+
exposes.climate()
|
|
25
|
+
.withSetpoint('current_heating_setpoint', 5, 30, 0.5, ea.STATE_SET).withLocalTemperature(ea.STATE)
|
|
26
|
+
.withSystemMode(['off', 'heat', 'auto'], ea.STATE_SET),
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
];
|
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/iris.js
CHANGED
|
@@ -19,6 +19,8 @@ module.exports = [
|
|
|
19
19
|
await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement', 'genPowerCfg']);
|
|
20
20
|
await reporting.temperature(endpoint);
|
|
21
21
|
await reporting.batteryVoltage(endpoint);
|
|
22
|
+
device.powerSource = 'Battery';
|
|
23
|
+
device.save();
|
|
22
24
|
},
|
|
23
25
|
exposes: [e.contact(), e.battery_low(), e.tamper(), e.temperature(), e.battery()],
|
|
24
26
|
},
|
package/devices/jasco.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const reporting = require('../lib/reporting');
|
|
2
|
+
const extend = require('../lib/extend');
|
|
3
|
+
|
|
4
|
+
module.exports = [
|
|
5
|
+
{
|
|
6
|
+
zigbeeModel: ['35938'],
|
|
7
|
+
model: 'ZB3102',
|
|
8
|
+
vendor: 'Jasco Products',
|
|
9
|
+
description: 'Zigbee plug-in smart dimmer',
|
|
10
|
+
extend: extend.light_onoff_brightness({noConfigure: true}),
|
|
11
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
12
|
+
await extend.light_onoff_brightness().configure(device, coordinatorEndpoint, logger);
|
|
13
|
+
const endpoint = device.getEndpoint(1);
|
|
14
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
15
|
+
await reporting.onOff(endpoint);
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
];
|
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/moes.js
CHANGED
|
@@ -206,7 +206,7 @@ module.exports = [
|
|
|
206
206
|
tz.moesS_thermostat_system_mode, tz.moesS_thermostat_schedule_programming],
|
|
207
207
|
exposes: [
|
|
208
208
|
e.battery(), e.child_lock(), e.eco_mode(), e.eco_temperature(), e.max_temperature(), e.min_temperature(),
|
|
209
|
-
e.position(), e.window_detection(),
|
|
209
|
+
e.valve_state(), e.position(), e.window_detection(),
|
|
210
210
|
exposes.binary('window', ea.STATE, 'CLOSED', 'OPEN').withDescription('Window status closed or open '),
|
|
211
211
|
exposes.climate()
|
|
212
212
|
.withLocalTemperature(ea.STATE).withSetpoint('current_heating_setpoint', 5, 35, 0.5, ea.STATE_SET)
|
package/devices/philips.js
CHANGED
|
@@ -2574,4 +2574,13 @@ module.exports = [
|
|
|
2574
2574
|
extend: hueExtend.light_onoff_brightness(),
|
|
2575
2575
|
ota: ota.zigbeeOTA,
|
|
2576
2576
|
},
|
|
2577
|
+
{
|
|
2578
|
+
zigbeeModel: ['LWA019'],
|
|
2579
|
+
model: '9290024691',
|
|
2580
|
+
vendor: 'Philips',
|
|
2581
|
+
description: 'Hue white single filament bulb A19 E26 with Bluetooth (1100 Lumen)',
|
|
2582
|
+
meta: {turnsOffAtBrightness1: true},
|
|
2583
|
+
extend: hueExtend.light_onoff_brightness(),
|
|
2584
|
+
ota: ota.zigbeeOTA,
|
|
2585
|
+
},
|
|
2577
2586
|
];
|