zigbee-herdsman-converters 14.0.457 → 14.0.460
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 +27 -24
- package/converters/toZigbee.js +55 -2
- package/devices/danfoss.js +50 -16
- package/devices/innr.js +16 -0
- package/devices/namron.js +58 -0
- package/devices/niko.js +20 -7
- package/devices/schneider_electric.js +20 -0
- package/devices/tuya.js +7 -11
- package/devices/xiaomi.js +9 -7
- package/lib/constants.js +14 -0
- package/lib/light.js +17 -16
- package/lib/xiaomi.js +12 -0
- package/npm-shrinkwrap.json +180 -168
- package/package.json +1 -1
package/converters/fromZigbee.js
CHANGED
|
@@ -44,6 +44,9 @@ const converters = {
|
|
|
44
44
|
result[postfixWithEndpointName('local_temperature_calibration', msg, model)] =
|
|
45
45
|
precisionRound(msg.data['localTemperatureCalibration'], 2) / 10;
|
|
46
46
|
}
|
|
47
|
+
if (msg.data.hasOwnProperty('outdoorTemp')) {
|
|
48
|
+
result[postfixWithEndpointName('outdoor_temperature', msg, model)] = precisionRound(msg.data['outdoorTemp'], 2) / 100;
|
|
49
|
+
}
|
|
47
50
|
if (msg.data.hasOwnProperty('occupancy')) {
|
|
48
51
|
result[postfixWithEndpointName('occupancy', msg, model)] = (msg.data.occupancy % 2) > 0;
|
|
49
52
|
}
|
|
@@ -3389,6 +3392,23 @@ const converters = {
|
|
|
3389
3392
|
if (msg.data.hasOwnProperty('danfossLoadEstimate')) {
|
|
3390
3393
|
result[postfixWithEndpointName('load_estimate', msg, model)] = msg.data['danfossLoadEstimate'];
|
|
3391
3394
|
}
|
|
3395
|
+
if (msg.data.hasOwnProperty('danfossPreheatStatus')) {
|
|
3396
|
+
result[postfixWithEndpointName('preheat_status', msg, model)] = (msg.data['danfossPreheatStatus'] === 1);
|
|
3397
|
+
}
|
|
3398
|
+
if (msg.data.hasOwnProperty('danfossAdaptionRunStatus')) {
|
|
3399
|
+
result[postfixWithEndpointName('adaptation_run_status', msg, model)] =
|
|
3400
|
+
constants.danfossAdaptionRunStatus[msg.data['danfossAdaptionRunStatus']];
|
|
3401
|
+
}
|
|
3402
|
+
if (msg.data.hasOwnProperty('danfossAdaptionRunSettings')) {
|
|
3403
|
+
result[postfixWithEndpointName('adaptation_run_settings', msg, model)] = (msg.data['danfossAdaptionRunSettings'] === 1);
|
|
3404
|
+
}
|
|
3405
|
+
if (msg.data.hasOwnProperty('danfossAdaptionRunControl')) {
|
|
3406
|
+
result[postfixWithEndpointName('adaptation_run_control', msg, model)] =
|
|
3407
|
+
constants.danfossAdaptionRunControl[msg.data['danfossAdaptionRunControl']];
|
|
3408
|
+
}
|
|
3409
|
+
if (msg.data.hasOwnProperty('danfossRegulationSetpointOffset')) {
|
|
3410
|
+
result[postfixWithEndpointName('regulation_setpoint_offset', msg, model)] = msg.data['danfossRegulationSetpointOffset'];
|
|
3411
|
+
}
|
|
3392
3412
|
// Danfoss Icon Converters
|
|
3393
3413
|
if (msg.data.hasOwnProperty('danfossRoomStatusCode')) {
|
|
3394
3414
|
result[postfixWithEndpointName('room_status_code', msg, model)] =
|
|
@@ -4983,6 +5003,12 @@ const converters = {
|
|
|
4983
5003
|
case tuya.dataPoints.state:
|
|
4984
5004
|
result.smoke = value === 0;
|
|
4985
5005
|
break;
|
|
5006
|
+
case 14:
|
|
5007
|
+
// battery state, ignore
|
|
5008
|
+
break;
|
|
5009
|
+
case 15:
|
|
5010
|
+
result.battery = value;
|
|
5011
|
+
break;
|
|
4986
5012
|
default:
|
|
4987
5013
|
meta.logger.warn(`zigbee-herdsman-converters:tuya_smoke: Unrecognized DP #${ dp} with data ${JSON.stringify(dpValue)}`);
|
|
4988
5014
|
}
|
|
@@ -5653,38 +5679,15 @@ const converters = {
|
|
|
5653
5679
|
type: ['attributeReport', 'readResponse'],
|
|
5654
5680
|
options: [exposes.options.invert_cover()],
|
|
5655
5681
|
convert: (model, msg, publish, options, meta) => {
|
|
5656
|
-
let running = false;
|
|
5657
|
-
|
|
5658
5682
|
if (model.model === 'ZNCLDJ12LM' && msg.type === 'attributeReport' && [0, 2].includes(msg.data['presentValue'])) {
|
|
5659
5683
|
// Incorrect reports from the device, ignore (re-read by onEvent of ZNCLDJ12LM)
|
|
5660
5684
|
// https://github.com/Koenkk/zigbee-herdsman-converters/pull/1427#issuecomment-663862724
|
|
5661
5685
|
return;
|
|
5662
5686
|
}
|
|
5663
5687
|
|
|
5664
|
-
if (msg.data['61440']) {
|
|
5665
|
-
const value = msg.data['61440'];
|
|
5666
|
-
// 63025664 comes from https://github.com/Koenkk/zigbee2mqtt/issues/5155#issuecomment-753344248
|
|
5667
|
-
running = value !== 0 && value !== 63025664;
|
|
5668
|
-
}
|
|
5669
|
-
|
|
5670
5688
|
let position = precisionRound(msg.data['presentValue'], 2);
|
|
5671
5689
|
position = options.invert_cover ? 100 - position : position;
|
|
5672
|
-
return {position
|
|
5673
|
-
},
|
|
5674
|
-
},
|
|
5675
|
-
xiaomi_curtain_options: {
|
|
5676
|
-
cluster: 'genBasic',
|
|
5677
|
-
type: ['attributeReport', 'readResponse'],
|
|
5678
|
-
convert: (model, msg, publish, options, meta) => {
|
|
5679
|
-
const data = msg.data['1025'];
|
|
5680
|
-
if (data) {
|
|
5681
|
-
return {
|
|
5682
|
-
options: { // next values update only when curtain finished initial setup and knows current position
|
|
5683
|
-
reverse_direction: data[2]=='\u0001',
|
|
5684
|
-
hand_open: data[5]=='\u0000',
|
|
5685
|
-
},
|
|
5686
|
-
};
|
|
5687
|
-
}
|
|
5690
|
+
return {position};
|
|
5688
5691
|
},
|
|
5689
5692
|
},
|
|
5690
5693
|
xiaomi_curtain_acn002_position: {
|
package/converters/toZigbee.js
CHANGED
|
@@ -1242,6 +1242,12 @@ const converters = {
|
|
|
1242
1242
|
await entity.read('hvacThermostat', ['localTemp']);
|
|
1243
1243
|
},
|
|
1244
1244
|
},
|
|
1245
|
+
thermostat_outdoor_temperature: {
|
|
1246
|
+
key: ['outdoor_temperature'],
|
|
1247
|
+
convertGet: async (entity, key, meta) => {
|
|
1248
|
+
await entity.read('hvacThermostat', ['outdoorTemp']);
|
|
1249
|
+
},
|
|
1250
|
+
},
|
|
1245
1251
|
thermostat_local_temperature_calibration: {
|
|
1246
1252
|
key: ['local_temperature_calibration'],
|
|
1247
1253
|
convertSet: async (entity, key, value, meta) => {
|
|
@@ -2112,7 +2118,7 @@ const converters = {
|
|
|
2112
2118
|
xiaomi_switch_power_outage_memory: {
|
|
2113
2119
|
key: ['power_outage_memory'],
|
|
2114
2120
|
convertSet: async (entity, key, value, meta) => {
|
|
2115
|
-
if (['ZNCZ04LM', 'ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM',
|
|
2121
|
+
if (['SP-EUC01', 'ZNCZ04LM', 'ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM',
|
|
2116
2122
|
'WS-EUK01', 'WS-EUK02', 'WS-EUK03', 'WS-EUK04', 'QBKG19LM', 'QBKG20LM', 'QBKG25LM', 'QBKG26LM',
|
|
2117
2123
|
'QBKG31LM', 'QBKG34LM', 'QBKG38LM', 'QBKG39LM', 'QBKG40LM', 'QBKG41LM', 'ZNDDMK11LM'].includes(meta.mapped.model)) {
|
|
2118
2124
|
await entity.write('aqaraOpple', {0x0201: {value: value ? 1 : 0, type: 0x10}}, manufacturerOptions.xiaomi);
|
|
@@ -2135,7 +2141,7 @@ const converters = {
|
|
|
2135
2141
|
return {state: {power_outage_memory: value}};
|
|
2136
2142
|
},
|
|
2137
2143
|
convertGet: async (entity, key, meta) => {
|
|
2138
|
-
if (['ZNCZ04LM', 'ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM',
|
|
2144
|
+
if (['SP-EUC01', 'ZNCZ04LM', 'ZNCZ15LM', 'QBCZ14LM', 'QBCZ15LM', 'SSM-U01', 'SSM-U02', 'DLKZMK11LM', 'DLKZMK12LM',
|
|
2139
2145
|
'WS-EUK01', 'WS-EUK02', 'WS-EUK03', 'WS-EUK04', 'QBKG19LM', 'QBKG20LM', 'QBKG25LM', 'QBKG26LM',
|
|
2140
2146
|
'QBKG31LM', 'QBKG34LM', 'QBKG38LM', 'QBKG39LM', 'QBKG40LM', 'QBKG41LM', 'ZNDDMK11LM'].includes(meta.mapped.model)) {
|
|
2141
2147
|
await entity.read('aqaraOpple', [0x0201]);
|
|
@@ -2848,6 +2854,53 @@ const converters = {
|
|
|
2848
2854
|
await entity.read('hvacThermostat', ['danfossLoadEstimate'], manufacturerOptions.danfoss);
|
|
2849
2855
|
},
|
|
2850
2856
|
},
|
|
2857
|
+
danfoss_preheat_status: {
|
|
2858
|
+
key: ['preheat_status'],
|
|
2859
|
+
convertGet: async (entity, key, meta) => {
|
|
2860
|
+
await entity.read('hvacThermostat', ['danfossPreheatStatus'], manufacturerOptions.danfoss);
|
|
2861
|
+
},
|
|
2862
|
+
},
|
|
2863
|
+
danfoss_adaptation_status: {
|
|
2864
|
+
key: ['adaptation_run_status'],
|
|
2865
|
+
convertGet: async (entity, key, meta) => {
|
|
2866
|
+
await entity.read('hvacThermostat', ['danfossAdaptionRunStatus'], manufacturerOptions.danfoss);
|
|
2867
|
+
},
|
|
2868
|
+
},
|
|
2869
|
+
danfoss_adaptation_settings: {
|
|
2870
|
+
key: ['adaptation_run_settings'],
|
|
2871
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2872
|
+
await entity.write('hvacThermostat', {'danfossAdaptionRunSettings': value}, manufacturerOptions.danfoss);
|
|
2873
|
+
return {readAfterWriteTime: 200, state: {'adaptation_run_settings': value}};
|
|
2874
|
+
},
|
|
2875
|
+
|
|
2876
|
+
convertGet: async (entity, key, meta) => {
|
|
2877
|
+
await entity.read('hvacThermostat', ['danfossAdaptionRunSettings'], manufacturerOptions.danfoss);
|
|
2878
|
+
},
|
|
2879
|
+
},
|
|
2880
|
+
danfoss_adaptation_control: {
|
|
2881
|
+
key: ['adaptation_run_control'],
|
|
2882
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2883
|
+
const payload = {'danfossAdaptionRunControl': utils.getKey(constants.danfossAdaptionRunControl, value, value, Number)};
|
|
2884
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.danfoss);
|
|
2885
|
+
return {readAfterWriteTime: 250, state: {'adaptation_run_control': value}};
|
|
2886
|
+
},
|
|
2887
|
+
|
|
2888
|
+
convertGet: async (entity, key, meta) => {
|
|
2889
|
+
await entity.read('hvacThermostat', ['danfossAdaptionRunControl'], manufacturerOptions.danfoss);
|
|
2890
|
+
},
|
|
2891
|
+
},
|
|
2892
|
+
danfoss_regulation_setpoint_offset: {
|
|
2893
|
+
key: ['regulation_setpoint_offset'],
|
|
2894
|
+
convertSet: async (entity, key, value, meta) => {
|
|
2895
|
+
const payload = {'danfossRegulationSetpointOffset': value};
|
|
2896
|
+
await entity.write('hvacThermostat', payload, manufacturerOptions.danfoss);
|
|
2897
|
+
return {readAfterWriteTime: 250, state: {'regulation_setpoint_offset': value}};
|
|
2898
|
+
},
|
|
2899
|
+
|
|
2900
|
+
convertGet: async (entity, key, meta) => {
|
|
2901
|
+
await entity.read('hvacThermostat', ['danfossRegulationSetpointOffset'], manufacturerOptions.danfoss);
|
|
2902
|
+
},
|
|
2903
|
+
},
|
|
2851
2904
|
danfoss_output_status: {
|
|
2852
2905
|
key: ['output_status'],
|
|
2853
2906
|
convertGet: async (entity, key, meta) => {
|
package/devices/danfoss.js
CHANGED
|
@@ -24,7 +24,8 @@ module.exports = [
|
|
|
24
24
|
tz.danfoss_viewing_direction, tz.danfoss_external_measured_room_sensor, tz.danfoss_radiator_covered,
|
|
25
25
|
tz.thermostat_keypad_lockout, tz.thermostat_system_mode, tz.danfoss_load_balancing_enable, tz.danfoss_load_room_mean,
|
|
26
26
|
tz.thermostat_weekly_schedule, tz.thermostat_clear_weekly_schedule, tz.thermostat_programming_operation_mode,
|
|
27
|
-
tz.danfoss_window_open_feature
|
|
27
|
+
tz.danfoss_window_open_feature, tz.danfoss_preheat_status, tz.danfoss_adaptation_status, tz.danfoss_adaptation_settings,
|
|
28
|
+
tz.danfoss_adaptation_control, tz.danfoss_regulation_setpoint_offset],
|
|
28
29
|
exposes: [e.battery(), e.keypad_lockout(), e.programming_operation_mode(),
|
|
29
30
|
exposes.binary('mounted_mode_active', ea.STATE_GET, true, false)
|
|
30
31
|
.withDescription('Is the unit in mounting mode. This is set to `false` for mounted (already on ' +
|
|
@@ -78,7 +79,19 @@ module.exports = [
|
|
|
78
79
|
.withDescription('Mean radiator load for room calculated by gateway for load balancing purposes (-8000=undefined)')
|
|
79
80
|
.withValueMin(-8000).withValueMax(2000),
|
|
80
81
|
exposes.numeric('load_estimate', ea.STATE_GET)
|
|
81
|
-
.withDescription('Load estimate on this radiator')
|
|
82
|
+
.withDescription('Load estimate on this radiator'),
|
|
83
|
+
exposes.binary('preheat_status', ea.STATE_GET, true, false)
|
|
84
|
+
.withDescription('Specific for pre-heat running in Zigbee Weekly Schedule mode'),
|
|
85
|
+
exposes.enum('adaptation_run_status', ea.STATE_GET, ['none', 'in_progress', 'found', 'lost'])
|
|
86
|
+
.withDescription('Status of adaptation run: None (before first run), In Progress, Valve Characteristic Found, ' +
|
|
87
|
+
'Valve Characteristic Lost'),
|
|
88
|
+
exposes.binary('adaptation_run_settings', ea.ALL, true, false)
|
|
89
|
+
.withDescription('Automatic adaptation run enabled (the one during the night)'),
|
|
90
|
+
exposes.enum('adaptation_run_control', ea.ALL, ['initate_adaptation', 'cancel_adaptation'])
|
|
91
|
+
.withDescription('Adaptation run control: Initiate Adaptation Run or Cancel Adaptation Run'),
|
|
92
|
+
exposes.numeric('regulation_setpoint_offset', ea.ALL)
|
|
93
|
+
.withDescription('Regulation SetPoint Offset in range -2.5°C to 2.5°C in steps of 0.1°C. Value 2.5°C = 25.')
|
|
94
|
+
.withValueMin(-25).withValueMax(25)],
|
|
82
95
|
ota: ota.zigbeeOTA,
|
|
83
96
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
84
97
|
const endpoint = device.getEndpoint(1);
|
|
@@ -117,20 +130,41 @@ module.exports = [
|
|
|
117
130
|
reportableChange: 1,
|
|
118
131
|
}], options);
|
|
119
132
|
|
|
120
|
-
await endpoint.
|
|
121
|
-
'
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
'
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
133
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
134
|
+
attribute: 'danfossPreheatStatus',
|
|
135
|
+
minimumReportInterval: constants.repInterval.MINUTE,
|
|
136
|
+
maximumReportInterval: constants.repInterval.MAX,
|
|
137
|
+
reportableChange: 1,
|
|
138
|
+
}], options);
|
|
139
|
+
|
|
140
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
141
|
+
attribute: 'danfossAdaptionRunStatus',
|
|
142
|
+
minimumReportInterval: constants.repInterval.MINUTE,
|
|
143
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
144
|
+
reportableChange: 1,
|
|
145
|
+
}], options);
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
await endpoint.read('hvacThermostat', [
|
|
149
|
+
'danfossWindowOpenFeatureEnable',
|
|
150
|
+
'danfossWindowOpenExternal',
|
|
151
|
+
'danfossDayOfWeek',
|
|
152
|
+
'danfossTriggerTime',
|
|
153
|
+
'danfossAlgorithmScaleFactor',
|
|
154
|
+
'danfossHeatAvailable',
|
|
155
|
+
'danfossMountedModeControl',
|
|
156
|
+
'danfossMountedModeActive',
|
|
157
|
+
'danfossExternalMeasuredRoomSensor',
|
|
158
|
+
'danfossRadiatorCovered',
|
|
159
|
+
'danfossLoadBalancingEnable',
|
|
160
|
+
'danfossLoadRoomMean',
|
|
161
|
+
'danfossAdaptionRunControl',
|
|
162
|
+
'danfossAdaptionRunSettings',
|
|
163
|
+
'danfossRegulationSetpointOffset',
|
|
164
|
+
], options);
|
|
165
|
+
} catch (e) {
|
|
166
|
+
/* not supported by all https://github.com/Koenkk/zigbee2mqtt/issues/11872 */
|
|
167
|
+
}
|
|
134
168
|
|
|
135
169
|
// read systemMode to have an initial value
|
|
136
170
|
await endpoint.read('hvacThermostat', ['systemMode']);
|
package/devices/innr.js
CHANGED
|
@@ -95,6 +95,14 @@ module.exports = [
|
|
|
95
95
|
extend: extend.light_onoff_brightness(),
|
|
96
96
|
meta: {turnsOffAtBrightness1: true},
|
|
97
97
|
},
|
|
98
|
+
{
|
|
99
|
+
zigbeeModel: ['BY 266'],
|
|
100
|
+
model: 'BY 266',
|
|
101
|
+
vendor: 'Innr',
|
|
102
|
+
description: 'B22 (Bayonet) bulb, dimmable',
|
|
103
|
+
extend: extend.light_onoff_brightness(),
|
|
104
|
+
meta: {turnsOffAtBrightness1: true},
|
|
105
|
+
},
|
|
98
106
|
{
|
|
99
107
|
zigbeeModel: ['RB 266'],
|
|
100
108
|
model: 'RB 266',
|
|
@@ -288,6 +296,14 @@ module.exports = [
|
|
|
288
296
|
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [153, 555]}),
|
|
289
297
|
meta: {applyRedFix: true, turnsOffAtBrightness1: true},
|
|
290
298
|
},
|
|
299
|
+
{
|
|
300
|
+
zigbeeModel: ['RB 249 T'],
|
|
301
|
+
model: 'RB 249 T',
|
|
302
|
+
vendor: 'Innr',
|
|
303
|
+
description: 'E14 candle, dimmable with, color temp',
|
|
304
|
+
extend: extend.light_onoff_brightness_colortemp({colorTempRange: [200, 454]}),
|
|
305
|
+
meta: {turnsOffAtBrightness1: true},
|
|
306
|
+
},
|
|
291
307
|
{
|
|
292
308
|
zigbeeModel: ['RB 148 T'],
|
|
293
309
|
model: 'RB 148 T',
|
package/devices/namron.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
const exposes = require('../lib/exposes');
|
|
2
2
|
const fz = {...require('../converters/fromZigbee'), legacy: require('../lib/legacy').fromZigbee};
|
|
3
|
+
const tz = require('../converters/toZigbee');
|
|
4
|
+
const constants = require('../lib/constants');
|
|
3
5
|
const reporting = require('../lib/reporting');
|
|
4
6
|
const extend = require('../lib/extend');
|
|
7
|
+
const ea = exposes.access;
|
|
5
8
|
const e = exposes.presets;
|
|
6
9
|
|
|
7
10
|
module.exports = [
|
|
@@ -255,4 +258,59 @@ module.exports = [
|
|
|
255
258
|
meta: {turnsOffAtBrightness1: true},
|
|
256
259
|
extend: extend.light_onoff_brightness_colortemp_color(),
|
|
257
260
|
},
|
|
261
|
+
{
|
|
262
|
+
zigbeeModel: ['4512737'],
|
|
263
|
+
model: '4512737',
|
|
264
|
+
vendor: 'Namron',
|
|
265
|
+
description: 'Touch termostat',
|
|
266
|
+
fromZigbee: [fz.thermostat, fz.metering, fz.electrical_measurement, fz.hvac_user_interface],
|
|
267
|
+
toZigbee: [tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint, tz.thermostat_occupancy,
|
|
268
|
+
tz.thermostat_local_temperature_calibration, tz.thermostat_local_temperature, tz.thermostat_outdoor_temperature,
|
|
269
|
+
tz.thermostat_system_mode, tz.thermostat_control_sequence_of_operation, tz.thermostat_running_state,
|
|
270
|
+
tz.thermostat_keypad_lockout],
|
|
271
|
+
exposes: [
|
|
272
|
+
e.local_temperature(),
|
|
273
|
+
exposes.numeric('outdoor_temperature', ea.STATE_GET).withUnit('°C')
|
|
274
|
+
.withDescription('Current temperature measured from the floor sensor'),
|
|
275
|
+
e.keypad_lockout(),
|
|
276
|
+
exposes.climate()
|
|
277
|
+
.withSetpoint('occupied_heating_setpoint', 5, 50, 0.01)
|
|
278
|
+
.withLocalTemperature()
|
|
279
|
+
.withLocalTemperatureCalibration(-30, 30, 0.1)
|
|
280
|
+
.withSystemMode(['off', 'auto', 'heat'])
|
|
281
|
+
.withRunningState(['idle', 'heat']),
|
|
282
|
+
e.power(), e.current(), e.voltage(), e.energy(),
|
|
283
|
+
],
|
|
284
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
285
|
+
const endpoint = device.getEndpoint(1);
|
|
286
|
+
const binds = [
|
|
287
|
+
'genBasic', 'genIdentify', 'genGroups', 'genScenes', 'hvacThermostat',
|
|
288
|
+
'seMetering', 'haElectricalMeasurement', 'genAlarms', 'msOccupancySensing', 'genTime', 'hvacUserInterfaceCfg',
|
|
289
|
+
];
|
|
290
|
+
await reporting.bind(endpoint, coordinatorEndpoint, binds);
|
|
291
|
+
|
|
292
|
+
// standard ZCL attributes
|
|
293
|
+
await reporting.thermostatTemperature(endpoint);
|
|
294
|
+
await reporting.thermostatOccupiedHeatingSetpoint(endpoint);
|
|
295
|
+
await reporting.thermostatUnoccupiedHeatingSetpoint(endpoint);
|
|
296
|
+
await reporting.thermostatKeypadLockMode(endpoint);
|
|
297
|
+
|
|
298
|
+
await endpoint.configureReporting('hvacThermostat', [{
|
|
299
|
+
attribute: 'ocupancy',
|
|
300
|
+
minimumReportInterval: 0,
|
|
301
|
+
maximumReportInterval: constants.repInterval.HOUR,
|
|
302
|
+
reportableChange: null,
|
|
303
|
+
}]);
|
|
304
|
+
|
|
305
|
+
await reporting.activePower(endpoint);
|
|
306
|
+
await reporting.currentSummDelivered(endpoint);
|
|
307
|
+
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
308
|
+
await reporting.rmsCurrent(endpoint);
|
|
309
|
+
await reporting.rmsVoltage(endpoint);
|
|
310
|
+
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
311
|
+
|
|
312
|
+
// Trigger read
|
|
313
|
+
await endpoint.read('hvacThermostat', ['systemMode', 'runningState', 'occupied_heating_setpoint']);
|
|
314
|
+
},
|
|
315
|
+
},
|
|
258
316
|
];
|
package/devices/niko.js
CHANGED
|
@@ -11,17 +11,30 @@ module.exports = [
|
|
|
11
11
|
model: '170-33505',
|
|
12
12
|
vendor: 'Niko',
|
|
13
13
|
description: 'Connected socket outlet',
|
|
14
|
-
fromZigbee: [fz.on_off, fz.electrical_measurement],
|
|
15
|
-
toZigbee: [tz.on_off, tz.electrical_measurement_power],
|
|
14
|
+
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering],
|
|
15
|
+
toZigbee: [tz.on_off, tz.electrical_measurement_power, tz.currentsummdelivered],
|
|
16
16
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
17
17
|
const endpoint = device.getEndpoint(1);
|
|
18
|
-
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement']);
|
|
19
|
-
await reporting.
|
|
18
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
|
|
19
|
+
await reporting.onOff(endpoint);
|
|
20
|
+
|
|
21
|
+
// NOTE: we read them individually, acFrequency* is not supported
|
|
22
|
+
// so we cannot use readEletricalMeasurementMultiplierDivisors
|
|
23
|
+
await endpoint.read('haElectricalMeasurement', ['acPowerMultiplier', 'acPowerDivisor']);
|
|
20
24
|
await reporting.activePower(endpoint, {min: 5, max: 3600, change: 1000});
|
|
25
|
+
await endpoint.read('haElectricalMeasurement', ['acCurrentDivisor', 'acPowerMultiplier', 'acPowerDivisor']);
|
|
21
26
|
await reporting.rmsCurrent(endpoint, {min: 5, max: 3600, change: 100});
|
|
27
|
+
await endpoint.read('haElectricalMeasurement', ['acVoltageMultiplier', 'acVoltageDivisor', 'acCurrentMultiplier']);
|
|
22
28
|
await reporting.rmsVoltage(endpoint, {min: 5, max: 3600, change: 100});
|
|
29
|
+
|
|
30
|
+
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
31
|
+
await reporting.currentSummDelivered(endpoint, {min: 60, change: 1});
|
|
23
32
|
},
|
|
24
|
-
exposes: [
|
|
33
|
+
exposes: [
|
|
34
|
+
e.switch(),
|
|
35
|
+
e.power().withAccess(ea.STATE_GET), e.current(), e.voltage(),
|
|
36
|
+
e.energy().withAccess(ea.STATE_GET),
|
|
37
|
+
],
|
|
25
38
|
},
|
|
26
39
|
{
|
|
27
40
|
zigbeeModel: ['Smart plug Zigbee PE'],
|
|
@@ -29,7 +42,7 @@ module.exports = [
|
|
|
29
42
|
vendor: 'Niko',
|
|
30
43
|
description: 'Smart plug with earthing pin',
|
|
31
44
|
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.power_on_behavior],
|
|
32
|
-
toZigbee: [tz.on_off, tz.power_on_behavior, tz.electrical_measurement_power],
|
|
45
|
+
toZigbee: [tz.on_off, tz.power_on_behavior, tz.electrical_measurement_power, tz.currentsummdelivered],
|
|
33
46
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
34
47
|
const endpoint = device.getEndpoint(1);
|
|
35
48
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'haElectricalMeasurement', 'seMetering']);
|
|
@@ -41,7 +54,7 @@ module.exports = [
|
|
|
41
54
|
await reporting.currentSummDelivered(endpoint, {min: 60, change: 1});
|
|
42
55
|
},
|
|
43
56
|
exposes: [
|
|
44
|
-
e.switch(), e.power().withAccess(ea.STATE_GET), e.energy(),
|
|
57
|
+
e.switch(), e.power().withAccess(ea.STATE_GET), e.energy().withAccess(ea.STATE_GET),
|
|
45
58
|
exposes.enum('power_on_behavior', ea.ALL, ['off', 'previous', 'on'])
|
|
46
59
|
.withDescription('Controls the behaviour when the device is powered on'),
|
|
47
60
|
],
|
|
@@ -694,4 +694,24 @@ module.exports = [
|
|
|
694
694
|
},
|
|
695
695
|
exposes: [e.battery(), e.illuminance(), e.illuminance_lux(), e.occupancy()],
|
|
696
696
|
},
|
|
697
|
+
{
|
|
698
|
+
zigbeeModel: ['CH/Socket/2'],
|
|
699
|
+
model: '3025CSGZ',
|
|
700
|
+
vendor: 'Schneider Electric',
|
|
701
|
+
description: 'Dual connected smart socket',
|
|
702
|
+
extend: extend.switch(),
|
|
703
|
+
exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2')],
|
|
704
|
+
meta: {multiEndpoint: true},
|
|
705
|
+
endpoint: (device) => {
|
|
706
|
+
return {'l1': 1, 'l2': 2};
|
|
707
|
+
},
|
|
708
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
709
|
+
const endpoint1 = device.getEndpoint(1);
|
|
710
|
+
await reporting.bind(endpoint1, coordinatorEndpoint, ['genOnOff']);
|
|
711
|
+
await reporting.onOff(endpoint1);
|
|
712
|
+
const endpoint2 = device.getEndpoint(2);
|
|
713
|
+
await reporting.bind(endpoint2, coordinatorEndpoint, ['genOnOff']);
|
|
714
|
+
await reporting.onOff(endpoint2);
|
|
715
|
+
},
|
|
716
|
+
},
|
|
697
717
|
];
|
package/devices/tuya.js
CHANGED
|
@@ -12,7 +12,7 @@ const utils = require('../lib/utils');
|
|
|
12
12
|
|
|
13
13
|
const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak', '_TZ3000_ew3ldmgx', '_TZ3000_gjnozsaz',
|
|
14
14
|
'_TZ3000_jvzvulen', '_TZ3000_mraovvmm', '_TZ3000_nfnmi125', '_TZ3000_ps3dmato', '_TZ3000_w0qqde0g', '_TZ3000_u5u4cakc',
|
|
15
|
-
'_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_kx0pris5', '_TZ3000_amdymr7l', '_TZ3000_z1pnpsdo'];
|
|
15
|
+
'_TZ3000_rdtixbnu', '_TZ3000_typdpbpg', '_TZ3000_kx0pris5', '_TZ3000_amdymr7l', '_TZ3000_z1pnpsdo', '_TZ3000_ksw8qtmt'];
|
|
16
16
|
|
|
17
17
|
const tzLocal = {
|
|
18
18
|
TS0504B_color: {
|
|
@@ -97,13 +97,14 @@ module.exports = [
|
|
|
97
97
|
description: 'Door sensor',
|
|
98
98
|
fromZigbee: [fz.ias_contact_alarm_1, fz.battery, fz.ignore_basic_report, fz.ias_contact_alarm_1_report],
|
|
99
99
|
toZigbee: [],
|
|
100
|
-
exposes: [e.contact(), e.battery_low(), e.tamper(), e.battery()],
|
|
100
|
+
exposes: [e.contact(), e.battery_low(), e.tamper(), e.battery(), e.battery_voltage()],
|
|
101
101
|
whiteLabel: [{vendor: 'CR Smart Home', model: 'TS0203'}],
|
|
102
102
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
103
103
|
try {
|
|
104
104
|
const endpoint = device.getEndpoint(1);
|
|
105
105
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
106
106
|
await reporting.batteryPercentageRemaining(endpoint);
|
|
107
|
+
await reporting.batteryVoltage(endpoint);
|
|
107
108
|
} catch (error) {/* Fails for some*/}
|
|
108
109
|
},
|
|
109
110
|
},
|
|
@@ -234,6 +235,7 @@ module.exports = [
|
|
|
234
235
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_jmiuubkz'},
|
|
235
236
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_cmaky9gq'},
|
|
236
237
|
{modelID: 'TS0505B', manufacturerName: '_TZ3000_tza2vjxx'},
|
|
238
|
+
{modelID: 'TS0505B', manufacturerName: '_TZ3210_it1u8ahz'},
|
|
237
239
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_k1pe6ibm'},
|
|
238
240
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_bfwvfyx1'},
|
|
239
241
|
{modelID: 'TS0505B', manufacturerName: '_TZ3210_leyz4rju'},
|
|
@@ -1028,8 +1030,6 @@ module.exports = [
|
|
|
1028
1030
|
toZigbee: [tz.tuya_cover_control, tz.tuya_cover_options],
|
|
1029
1031
|
exposes: [
|
|
1030
1032
|
e.cover_position().setAccess('position', ea.STATE_SET),
|
|
1031
|
-
exposes.binary('running', ea.STATE, true, false)
|
|
1032
|
-
.withDescription('Whether the motor is moving or not'),
|
|
1033
1033
|
exposes.composite('options', 'options')
|
|
1034
1034
|
.withFeature(exposes.numeric('motor_speed', ea.STATE_SET)
|
|
1035
1035
|
.withValueMin(0)
|
|
@@ -1274,7 +1274,7 @@ module.exports = [
|
|
|
1274
1274
|
description: 'Smart plug (with power monitoring)',
|
|
1275
1275
|
vendor: 'TuYa',
|
|
1276
1276
|
whiteLabel: [{vendor: 'LELLKI', model: 'TS011F_plug'}, {vendor: 'NEO', model: 'NAS-WR01B'},
|
|
1277
|
-
{vendor: 'BlitzWolf', model: 'BW-SHP15'}],
|
|
1277
|
+
{vendor: 'BlitzWolf', model: 'BW-SHP15'}, {vendor: 'Nous', model: 'A1Z'}],
|
|
1278
1278
|
ota: ota.zigbeeOTA,
|
|
1279
1279
|
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, fz.tuya_switch_power_outage_memory,
|
|
1280
1280
|
fz.ts011f_plug_indicator_mode, fz.ts011f_plug_child_mode],
|
|
@@ -1355,11 +1355,7 @@ module.exports = [
|
|
|
1355
1355
|
description: 'Smoke sensor',
|
|
1356
1356
|
fromZigbee: [fz.tuya_smoke],
|
|
1357
1357
|
toZigbee: [],
|
|
1358
|
-
|
|
1359
|
-
const endpoint = device.getEndpoint(1);
|
|
1360
|
-
await reporting.bind(endpoint, coordinatorEndpoint, ['genBasic']);
|
|
1361
|
-
},
|
|
1362
|
-
exposes: [e.smoke(), e.battery_low()],
|
|
1358
|
+
exposes: [e.smoke(), e.battery()],
|
|
1363
1359
|
},
|
|
1364
1360
|
{
|
|
1365
1361
|
fingerprint: [{modelID: 'TS0601', manufacturerName: '_TZE200_byzdayie'},
|
|
@@ -1652,7 +1648,7 @@ module.exports = [
|
|
|
1652
1648
|
},
|
|
1653
1649
|
},
|
|
1654
1650
|
{
|
|
1655
|
-
zigbeeModel: ['HY0017'],
|
|
1651
|
+
zigbeeModel: ['HY0017', '005f0c3'],
|
|
1656
1652
|
model: 'U86KCJ-ZP',
|
|
1657
1653
|
vendor: 'TuYa',
|
|
1658
1654
|
description: 'Smart 6 key scene wall switch',
|
package/devices/xiaomi.js
CHANGED
|
@@ -1047,7 +1047,7 @@ module.exports = [
|
|
|
1047
1047
|
vendor: 'Xiaomi',
|
|
1048
1048
|
fromZigbee: [fz.on_off, fz.xiaomi_basic, fz.electrical_measurement, fz.metering,
|
|
1049
1049
|
fz.aqara_opple, fz.xiaomi_power, fz.device_temperature],
|
|
1050
|
-
toZigbee: [tz.on_off],
|
|
1050
|
+
toZigbee: [tz.on_off, tz.xiaomi_switch_power_outage_memory],
|
|
1051
1051
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
1052
1052
|
const endpoint = device.getEndpoint(1);
|
|
1053
1053
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
@@ -1096,7 +1096,7 @@ module.exports = [
|
|
|
1096
1096
|
globalStore.putValue(device, 'interval', interval);
|
|
1097
1097
|
}
|
|
1098
1098
|
},
|
|
1099
|
-
exposes: [e.switch(), e.power(), e.energy(),
|
|
1099
|
+
exposes: [e.switch(), e.power(), e.energy(), e.power_outage_memory(),
|
|
1100
1100
|
e.device_temperature().withDescription('Device temperature (polled every 30 min)')],
|
|
1101
1101
|
ota: ota.zigbeeOTA,
|
|
1102
1102
|
},
|
|
@@ -1236,11 +1236,13 @@ module.exports = [
|
|
|
1236
1236
|
model: 'ZNCLDJ11LM',
|
|
1237
1237
|
description: 'Aqara curtain motor',
|
|
1238
1238
|
vendor: 'Xiaomi',
|
|
1239
|
-
fromZigbee: [fz.
|
|
1239
|
+
fromZigbee: [fz.xiaomi_basic, fz.xiaomi_curtain_position, fz.cover_position_tilt],
|
|
1240
1240
|
toZigbee: [tz.xiaomi_curtain_position_state, tz.xiaomi_curtain_options],
|
|
1241
1241
|
exposes: [e.cover_position().setAccess('state', ea.ALL),
|
|
1242
1242
|
exposes.binary('running', ea.STATE, true, false)
|
|
1243
|
-
.withDescription('Whether the motor is moving or not')
|
|
1243
|
+
.withDescription('Whether the motor is moving or not'),
|
|
1244
|
+
exposes.enum('motor_state', ea.STATE, ['stopped', 'opening', 'closing'])
|
|
1245
|
+
.withDescription('Motor state')],
|
|
1244
1246
|
ota: ota.zigbeeOTA,
|
|
1245
1247
|
},
|
|
1246
1248
|
{
|
|
@@ -1248,7 +1250,7 @@ module.exports = [
|
|
|
1248
1250
|
model: 'SRSC-M01',
|
|
1249
1251
|
description: 'Aqara roller shade motor',
|
|
1250
1252
|
vendor: 'Xiaomi',
|
|
1251
|
-
fromZigbee: [fz.
|
|
1253
|
+
fromZigbee: [fz.xiaomi_basic, fz.xiaomi_curtain_position, fz.cover_position_tilt],
|
|
1252
1254
|
toZigbee: [tz.xiaomi_curtain_position_state, tz.xiaomi_curtain_options],
|
|
1253
1255
|
exposes: [e.cover_position().setAccess('state', ea.ALL),
|
|
1254
1256
|
exposes.binary('running', ea.STATE, true, false)
|
|
@@ -1259,8 +1261,8 @@ module.exports = [
|
|
|
1259
1261
|
zigbeeModel: ['lumi.curtain.hagl04'],
|
|
1260
1262
|
model: 'ZNCLDJ12LM',
|
|
1261
1263
|
vendor: 'Xiaomi',
|
|
1262
|
-
description: 'Aqara B1 curtain motor
|
|
1263
|
-
fromZigbee: [fz.
|
|
1264
|
+
description: 'Aqara B1 curtain motor',
|
|
1265
|
+
fromZigbee: [fz.xiaomi_basic, fz.xiaomi_curtain_position, fz.battery, fz.cover_position_tilt],
|
|
1264
1266
|
toZigbee: [tz.xiaomi_curtain_position_state, tz.xiaomi_curtain_options],
|
|
1265
1267
|
onEvent: async (type, data, device) => {
|
|
1266
1268
|
// The position (genAnalogOutput.presentValue) reported via an attribute contains an invaid value
|
package/lib/constants.js
CHANGED
|
@@ -97,6 +97,18 @@ const temperatureDisplayMode = {
|
|
|
97
97
|
1: 'fahrenheit',
|
|
98
98
|
};
|
|
99
99
|
|
|
100
|
+
const danfossAdaptationRunStatus= {
|
|
101
|
+
0: 'none',
|
|
102
|
+
1: 'in_progress',
|
|
103
|
+
2: 'found',
|
|
104
|
+
4: 'lost',
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const danfossAdaptationRunControl = {
|
|
108
|
+
1: 'initate_adaptation',
|
|
109
|
+
2: 'cancel_adaptation',
|
|
110
|
+
};
|
|
111
|
+
|
|
100
112
|
const danfossWindowOpen = {
|
|
101
113
|
0: 'quarantine',
|
|
102
114
|
1: 'closed',
|
|
@@ -267,6 +279,8 @@ module.exports = {
|
|
|
267
279
|
dayOfWeek,
|
|
268
280
|
fanMode,
|
|
269
281
|
temperatureDisplayMode,
|
|
282
|
+
danfossAdaptationRunControl,
|
|
283
|
+
danfossAdaptationRunStatus,
|
|
270
284
|
danfossWindowOpen,
|
|
271
285
|
danfossRoomStatusCode,
|
|
272
286
|
danfossOutputStatus,
|
package/lib/light.js
CHANGED
|
@@ -19,24 +19,25 @@ function readColorAttributes(entity, meta, additionalAttributes=[]) {
|
|
|
19
19
|
* Additionally when we get a get payload, only request the fields included.
|
|
20
20
|
*/
|
|
21
21
|
const attributes = ['colorMode'];
|
|
22
|
+
if (meta && meta.message) {
|
|
23
|
+
if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('x'))) {
|
|
24
|
+
attributes.push('currentX');
|
|
25
|
+
}
|
|
26
|
+
if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('y'))) {
|
|
27
|
+
attributes.push('currentY');
|
|
28
|
+
}
|
|
22
29
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
attributes.push('enhancedCurrentHue');
|
|
34
|
-
} else {
|
|
35
|
-
attributes.push('currentHue');
|
|
30
|
+
if (utils.getMetaValue(entity, meta.mapped, 'supportsHueAndSaturation', 'allEqual', true)) {
|
|
31
|
+
if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('hue'))) {
|
|
32
|
+
if (utils.getMetaValue(entity, meta.mapped, 'enhancedHue', 'allEqual', true)) {
|
|
33
|
+
attributes.push('enhancedCurrentHue');
|
|
34
|
+
} else {
|
|
35
|
+
attributes.push('currentHue');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('saturation'))) {
|
|
39
|
+
attributes.push('currentSaturation');
|
|
36
40
|
}
|
|
37
|
-
}
|
|
38
|
-
if (!meta.message.color || (typeof meta.message.color === 'object' && meta.message.color.hasOwnProperty('saturation'))) {
|
|
39
|
-
attributes.push('currentSaturation');
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
|