zigbee-herdsman-converters 14.0.349 → 14.0.350
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 +11 -0
- package/converters/toZigbee.js +0 -6
- package/devices/dawon_dns.js +34 -0
- package/devices/ecosmart.js +1 -1
- package/devices/heiman.js +2 -17
- package/devices/lellki.js +60 -0
- package/devices/moes.js +3 -4
- package/devices/robb.js +14 -0
- package/devices/sinope.js +14 -3
- package/devices/sprut.js +96 -0
- package/devices/tuya.js +8 -39
- package/lib/exposes.js +3 -0
- package/lib/tuya.js +19 -0
- package/npm-shrinkwrap.json +369 -397
- package/package.json +2 -2
package/converters/fromZigbee.js
CHANGED
|
@@ -7590,6 +7590,17 @@ const converters = {
|
|
|
7590
7590
|
}
|
|
7591
7591
|
},
|
|
7592
7592
|
},
|
|
7593
|
+
dawon_card_holder: {
|
|
7594
|
+
cluster: 'ssIasZone',
|
|
7595
|
+
type: 'commandStatusChangeNotification',
|
|
7596
|
+
convert: (model, msg, publish, options, meta) => {
|
|
7597
|
+
const zoneStatus = msg.data.zonestatus;
|
|
7598
|
+
return {
|
|
7599
|
+
card: (zoneStatus & 1) > 0,
|
|
7600
|
+
battery_low: (zoneStatus & 1<<3) > 0,
|
|
7601
|
+
};
|
|
7602
|
+
},
|
|
7603
|
+
},
|
|
7593
7604
|
// #endregion
|
|
7594
7605
|
|
|
7595
7606
|
// #region Ignore converters (these message dont need parsing).
|
package/converters/toZigbee.js
CHANGED
|
@@ -2739,12 +2739,6 @@ const converters = {
|
|
|
2739
2739
|
await tuya.sendDataPointBool(entity, tuya.dataPoints.moesSboostHeating, value === 'ON');
|
|
2740
2740
|
},
|
|
2741
2741
|
},
|
|
2742
|
-
moesS_thermostat_boost_heating_countdown: {
|
|
2743
|
-
key: ['boost_heating_countdown'],
|
|
2744
|
-
convertSet: async (entity, key, value, meta) => {
|
|
2745
|
-
await tuya.sendDataPointValue(entity, tuya.dataPoints.moesSboostHeatingCountdown, value);
|
|
2746
|
-
},
|
|
2747
|
-
},
|
|
2748
2742
|
moesS_thermostat_window_detection: {
|
|
2749
2743
|
key: ['window_detection'],
|
|
2750
2744
|
convertSet: async (entity, key, value, meta) => {
|
package/devices/dawon_dns.js
CHANGED
|
@@ -4,6 +4,7 @@ const tz = require('../converters/toZigbee');
|
|
|
4
4
|
const reporting = require('../lib/reporting');
|
|
5
5
|
const extend = require('../lib/extend');
|
|
6
6
|
const e = exposes.presets;
|
|
7
|
+
const ea = exposes.access;
|
|
7
8
|
|
|
8
9
|
module.exports = [
|
|
9
10
|
{
|
|
@@ -272,4 +273,37 @@ module.exports = [
|
|
|
272
273
|
},
|
|
273
274
|
exposes: [e.battery(), e.switch()],
|
|
274
275
|
},
|
|
276
|
+
{
|
|
277
|
+
zigbeeModel: ['KB-HD100-ZB'],
|
|
278
|
+
model: 'KB-HD100-ZB',
|
|
279
|
+
vendor: 'Dawon DNS',
|
|
280
|
+
description: 'IOT Card holder',
|
|
281
|
+
fromZigbee: [fz.dawon_card_holder],
|
|
282
|
+
toZigbee: [],
|
|
283
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
284
|
+
const endpoint = device.getEndpoint(1);
|
|
285
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['ssIasZone']);
|
|
286
|
+
const payload = [{
|
|
287
|
+
attribute: 'zoneState', minimumReportInterval: 0, maximumReportInterval: 3600, reportableChange: 0}];
|
|
288
|
+
await endpoint.configureReporting('ssIasZone', payload);
|
|
289
|
+
},
|
|
290
|
+
exposes: [exposes.binary('card', ea.STATE, true, false)
|
|
291
|
+
.withDescription('Indicates if the card is inserted (= true) or not (= false)'), e.battery_low()],
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
zigbeeModel: ['KB-B540R-ZB'],
|
|
295
|
+
model: 'KB-B540R-ZB',
|
|
296
|
+
vendor: 'Dawon DNS',
|
|
297
|
+
description: 'IOT smart plug 16A',
|
|
298
|
+
fromZigbee: [fz.on_off, fz.metering],
|
|
299
|
+
toZigbee: [tz.on_off],
|
|
300
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
301
|
+
const endpoint = device.getEndpoint(1);
|
|
302
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'seMetering']);
|
|
303
|
+
await reporting.onOff(endpoint);
|
|
304
|
+
await reporting.readMeteringMultiplierDivisor(endpoint);
|
|
305
|
+
await reporting.instantaneousDemand(endpoint);
|
|
306
|
+
},
|
|
307
|
+
exposes: [e.switch(), e.power(), e.energy()],
|
|
308
|
+
},
|
|
275
309
|
];
|
package/devices/ecosmart.js
CHANGED
|
@@ -55,7 +55,7 @@ module.exports = [
|
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
// eslint-disable-next-line
|
|
58
|
-
zigbeeModel: ['\u0000\u0002\u0000\u0004�V\u0000\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000e', '\u0000\u0002\u0000\u0004��\"�\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000e','\u0000\u0002\u0000\u0004�\u0003\"�\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000e'],
|
|
58
|
+
zigbeeModel: ['\u0000\u0002\u0000\u0004�V\u0000\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000e', '\u0000\u0002\u0000\u0004��\"�\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000e','\u0000\u0002\u0000\u0004�\u0003\"�\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000e','\u0000\u0002\u0000\u0004r �P\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000e','\u0000\u0002\u0000\u0004b �P\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u000e'],
|
|
59
59
|
model: 'D1523',
|
|
60
60
|
vendor: 'EcoSmart',
|
|
61
61
|
description: 'A19 soft white bulb',
|
package/devices/heiman.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
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
|
-
const globalStore = require('../lib/store');
|
|
5
4
|
const constants = require('../lib/constants');
|
|
6
5
|
const reporting = require('../lib/reporting');
|
|
7
6
|
const extend = require('../lib/extend');
|
|
8
7
|
const e = exposes.presets;
|
|
9
8
|
const ea = exposes.access;
|
|
9
|
+
const tuya = require('../lib/tuya');
|
|
10
10
|
|
|
11
11
|
module.exports = [
|
|
12
12
|
{
|
|
@@ -66,22 +66,7 @@ module.exports = [
|
|
|
66
66
|
await reporting.onOff(endpoint);
|
|
67
67
|
await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
|
|
68
68
|
},
|
|
69
|
-
onEvent:
|
|
70
|
-
const endpoint = device.getEndpoint(1);
|
|
71
|
-
if (type === 'stop') {
|
|
72
|
-
clearInterval(globalStore.getValue(device, 'interval'));
|
|
73
|
-
globalStore.clearValue(device, 'interval');
|
|
74
|
-
} else if (!globalStore.hasValue(device, 'interval')) {
|
|
75
|
-
const seconds = options && options.measurement_poll_interval ? options.measurement_poll_interval : 60;
|
|
76
|
-
if (seconds === -1) return;
|
|
77
|
-
const interval = setInterval(async () => {
|
|
78
|
-
try {
|
|
79
|
-
await endpoint.read('haElectricalMeasurement', ['rmsVoltage', 'rmsCurrent', 'activePower']);
|
|
80
|
-
} catch (error) {/* Do nothing*/}
|
|
81
|
-
}, seconds*1000);
|
|
82
|
-
globalStore.putValue(device, 'interval', interval);
|
|
83
|
-
}
|
|
84
|
-
},
|
|
69
|
+
onEvent: tuya.onEventMeasurementPoll,
|
|
85
70
|
exposes: [e.switch(), e.power(), e.current(), e.voltage()],
|
|
86
71
|
},
|
|
87
72
|
{
|
package/devices/lellki.js
CHANGED
|
@@ -5,6 +5,7 @@ const reporting = require('../lib/reporting');
|
|
|
5
5
|
const extend = require('../lib/extend');
|
|
6
6
|
const e = exposes.presets;
|
|
7
7
|
const ea = exposes.access;
|
|
8
|
+
const tuya = require('../lib/tuya');
|
|
8
9
|
|
|
9
10
|
module.exports = [
|
|
10
11
|
{
|
|
@@ -82,4 +83,63 @@ module.exports = [
|
|
|
82
83
|
description: 'Circuit switch',
|
|
83
84
|
extend: extend.switch(),
|
|
84
85
|
},
|
|
86
|
+
{
|
|
87
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_z6fgd73r'}],
|
|
88
|
+
model: 'XF-EU-S100-1-M',
|
|
89
|
+
description: 'Touch switch 1 gang (with power monitoring)',
|
|
90
|
+
vendor: 'LELLKI',
|
|
91
|
+
extend: extend.switch(),
|
|
92
|
+
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, fz.tuya_switch_power_outage_memory],
|
|
93
|
+
toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory],
|
|
94
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
95
|
+
const endpoint = device.getEndpoint(1);
|
|
96
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
97
|
+
endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acCurrentDivisor: 1000, acCurrentMultiplier: 1});
|
|
98
|
+
endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
|
|
99
|
+
device.save();
|
|
100
|
+
},
|
|
101
|
+
options: [exposes.options.measurement_poll_interval()],
|
|
102
|
+
exposes: [e.switch().withEndpoint('l1'), e.power(), e.current(), e.voltage().withAccess(ea.STATE),
|
|
103
|
+
e.energy(), exposes.enum('power_outage_memory', ea.STATE_SET, ['on', 'off', 'restore'])
|
|
104
|
+
.withDescription('Recover state after power outage')],
|
|
105
|
+
onEvent: tuya.onEventMeasurementPoll,
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_bppxj3sf'}],
|
|
109
|
+
model: 'WP34-EU',
|
|
110
|
+
vendor: 'LELLKI',
|
|
111
|
+
description: 'Outlet power cord with 4 sockets and 2 USB',
|
|
112
|
+
exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'), e.switch().withEndpoint('l3'),
|
|
113
|
+
e.switch().withEndpoint('l4'), e.switch().withEndpoint('l5')],
|
|
114
|
+
extend: extend.switch(),
|
|
115
|
+
meta: {multiEndpoint: true},
|
|
116
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
117
|
+
for (const ID of [1, 2, 3, 4, 5]) {
|
|
118
|
+
await reporting.bind(device.getEndpoint(ID), coordinatorEndpoint, ['genOnOff']);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
endpoint: (device) => {
|
|
122
|
+
return {'l1': 1, 'l2': 2, 'l3': 3, 'l4': 4, 'l5': 5};
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_0yxeawjt'}],
|
|
127
|
+
model: 'WK34-EU',
|
|
128
|
+
description: 'Power socket EU (with power monitoring)',
|
|
129
|
+
vendor: 'LELLKI',
|
|
130
|
+
fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, fz.tuya_switch_power_outage_memory],
|
|
131
|
+
toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory],
|
|
132
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
133
|
+
const endpoint = device.getEndpoint(1);
|
|
134
|
+
await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
|
|
135
|
+
endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acCurrentDivisor: 1000, acCurrentMultiplier: 1});
|
|
136
|
+
endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
|
|
137
|
+
device.save();
|
|
138
|
+
},
|
|
139
|
+
options: [exposes.options.measurement_poll_interval()],
|
|
140
|
+
exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE),
|
|
141
|
+
e.energy(), exposes.enum('power_outage_memory', ea.STATE_SET, ['on', 'off', 'restore'])
|
|
142
|
+
.withDescription('Recover state after power outage')],
|
|
143
|
+
onEvent: tuya.onEventMeasurementPoll,
|
|
144
|
+
},
|
|
85
145
|
];
|
package/devices/moes.js
CHANGED
|
@@ -200,18 +200,17 @@ module.exports = [
|
|
|
200
200
|
fromZigbee: [fz.ignore_basic_report, fz.ignore_tuya_set_time, fz.moesS_thermostat],
|
|
201
201
|
toZigbee: [tz.moesS_thermostat_current_heating_setpoint, tz.moesS_thermostat_child_lock,
|
|
202
202
|
tz.moesS_thermostat_window_detection, tz.moesS_thermostat_temperature_calibration,
|
|
203
|
-
tz.moesS_thermostat_boost_heating_countdown, tz.moesS_thermostat_system_mode,
|
|
204
203
|
tz.moesS_thermostat_boost_heating, tz.moesS_thermostat_boostHeatingCountdownTimeSet,
|
|
205
204
|
tz.moesS_thermostat_eco_temperature, tz.moesS_thermostat_max_temperature,
|
|
206
205
|
tz.moesS_thermostat_min_temperature, tz.moesS_thermostat_moesSecoMode,
|
|
207
|
-
tz.moesS_thermostat_schedule_programming],
|
|
206
|
+
tz.moesS_thermostat_system_mode, tz.moesS_thermostat_schedule_programming],
|
|
208
207
|
exposes: [
|
|
209
208
|
e.battery(), e.child_lock(), e.eco_mode(), e.eco_temperature(), e.max_temperature(), e.min_temperature(),
|
|
210
209
|
e.position(), e.window_detection(),
|
|
211
210
|
exposes.binary('window', ea.STATE, 'CLOSED', 'OPEN').withDescription('Window status closed or open '),
|
|
212
211
|
exposes.climate()
|
|
213
212
|
.withLocalTemperature(ea.STATE).withSetpoint('current_heating_setpoint', 5, 35, 0.5, ea.STATE_SET)
|
|
214
|
-
.withLocalTemperatureCalibration(-
|
|
213
|
+
.withLocalTemperatureCalibration(-9, 9, 1, ea.STATE_SET)
|
|
215
214
|
.withPreset(['programming', 'manual', 'temporary_manual', 'holiday'],
|
|
216
215
|
'MANUAL MODE ☝ - In this mode, the device executes manual temperature setting. '+
|
|
217
216
|
'When the set temperature is lower than the "minimum temperature", the valve is closed (forced closed). ' +
|
|
@@ -225,7 +224,7 @@ module.exports = [
|
|
|
225
224
|
'You can set up to 4 stages of temperature every for WEEKDAY ➀➁➂➃➄, SATURDAY ➅ and SUNDAY ➆.'),
|
|
226
225
|
exposes.binary('boost_heating', ea.STATE_SET, 'ON', 'OFF').withDescription('Boost Heating: press and hold "+" for 3 seconds, ' +
|
|
227
226
|
'the device will enter the boost heating mode, and the ▷╵◁ will flash. The countdown will be displayed in the APP'),
|
|
228
|
-
exposes.numeric('boost_heating_countdown', ea.
|
|
227
|
+
exposes.numeric('boost_heating_countdown', ea.STATE).withUnit('Min').withDescription('Countdown in minutes')
|
|
229
228
|
.withValueMin(0).withValueMax(15),
|
|
230
229
|
exposes.numeric('boost_heating_countdown_time_set', ea.STATE_SET).withUnit('second')
|
|
231
230
|
.withDescription('Boost Time Setting 100 sec - 900 sec, (default = 300 sec)').withValueMin(100).withValueMax(900)],
|
package/devices/robb.js
CHANGED
|
@@ -184,4 +184,18 @@ module.exports = [
|
|
|
184
184
|
},
|
|
185
185
|
exposes: [e.power(), e.current(), e.voltage().withAccess(ea.STATE), e.switch(), e.energy(), e.temperature()],
|
|
186
186
|
},
|
|
187
|
+
{
|
|
188
|
+
zigbeeModel: ['ROB_200-016-0'],
|
|
189
|
+
model: 'ROB_200-016-0',
|
|
190
|
+
vendor: 'ROBB smart',
|
|
191
|
+
description: 'RGB CCT DIM 3 in 1 Zigbee Remote',
|
|
192
|
+
fromZigbee: [fz.battery, fz.command_move_to_color, fz.command_move_to_color_temp, fz.command_move_hue,
|
|
193
|
+
fz.command_step, fz.command_recall, fz.command_on, fz.command_off, fz.command_toggle, fz.command_stop,
|
|
194
|
+
fz.command_move, fz.command_color_loop_set, fz.command_ehanced_move_to_hue_and_saturation],
|
|
195
|
+
toZigbee: [],
|
|
196
|
+
exposes: [e.battery(), e.action([
|
|
197
|
+
'color_move', 'color_temperature_move', 'hue_move', 'brightness_step_up', 'brightness_step_down',
|
|
198
|
+
'recall_*', 'on', 'off', 'toggle', 'brightness_stop', 'brightness_move_up', 'brightness_move_down',
|
|
199
|
+
'color_loop_set', 'enhanced_move_to_hue_and_saturation', 'hue_stop'])],
|
|
200
|
+
},
|
|
187
201
|
];
|
package/devices/sinope.js
CHANGED
|
@@ -113,8 +113,8 @@ module.exports = [
|
|
|
113
113
|
model: 'TH1300ZB',
|
|
114
114
|
vendor: 'Sinopé',
|
|
115
115
|
description: 'Zigbee smart floor heating thermostat',
|
|
116
|
-
fromZigbee: [fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.
|
|
117
|
-
fz.legacy.sinope_thermostat_state, fz.sinope_TH1300ZB_specific],
|
|
116
|
+
fromZigbee: [fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.electrical_measurement,
|
|
117
|
+
fz.ignore_temperature_report, fz.legacy.sinope_thermostat_state, fz.sinope_TH1300ZB_specific],
|
|
118
118
|
toZigbee: [tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
|
|
119
119
|
tz.thermostat_temperature_display_mode, tz.thermostat_keypad_lockout, tz.thermostat_system_mode, tz.thermostat_running_state,
|
|
120
120
|
tz.sinope_thermostat_occupancy, tz.sinope_thermostat_backlight_autodim_param, tz.sinope_thermostat_time,
|
|
@@ -128,7 +128,7 @@ module.exports = [
|
|
|
128
128
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
129
129
|
const endpoint = device.getEndpoint(1);
|
|
130
130
|
const binds = ['genBasic', 'genIdentify', 'genGroups', 'hvacThermostat', 'hvacUserInterfaceCfg',
|
|
131
|
-
'msTemperatureMeasurement', 'manuSpecificSinope'];
|
|
131
|
+
'haElectricalMeasurement', 'msTemperatureMeasurement', 'manuSpecificSinope'];
|
|
132
132
|
await reporting.bind(endpoint, coordinatorEndpoint, binds);
|
|
133
133
|
await reporting.thermostatTemperature(endpoint);
|
|
134
134
|
await reporting.thermostatPIHeatingDemand(endpoint);
|
|
@@ -138,6 +138,17 @@ module.exports = [
|
|
|
138
138
|
await reporting.thermostatRunningState(endpoint);
|
|
139
139
|
} catch (error) {/* Not all support this */}
|
|
140
140
|
|
|
141
|
+
await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
|
|
142
|
+
try {
|
|
143
|
+
await reporting.activePower(endpoint, {min: 10, max: 305, change: 1}); // divider 1: 1W
|
|
144
|
+
} catch (error) {/* Do nothing*/}
|
|
145
|
+
try {
|
|
146
|
+
await reporting.rmsCurrent(endpoint, {min: 10, max: 306, change: 100}); // divider 1000: 0.1Arms
|
|
147
|
+
} catch (error) {/* Do nothing*/}
|
|
148
|
+
try {
|
|
149
|
+
await reporting.rmsVoltage(endpoint, {min: 10, max: 307, change: 5}); // divider 10: 0.5Vrms
|
|
150
|
+
} catch (error) {/* Do nothing*/}
|
|
151
|
+
|
|
141
152
|
try {
|
|
142
153
|
await reporting.thermostatKeypadLockMode(endpoint);
|
|
143
154
|
} catch (error) {
|
package/devices/sprut.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const exposes = require('../lib/exposes');
|
|
2
|
+
const fz = require('../converters/fromZigbee');
|
|
3
|
+
const tz = require('../converters/toZigbee');
|
|
4
|
+
const reporting = require('../lib/reporting');
|
|
5
|
+
const e = exposes.presets;
|
|
6
|
+
const {calibrateAndPrecisionRoundOptions} = require('../lib/utils');
|
|
7
|
+
|
|
8
|
+
const fzLocal = {
|
|
9
|
+
temperature: {
|
|
10
|
+
cluster: 'msTemperatureMeasurement',
|
|
11
|
+
type: ['attributeReport', 'readResponse'],
|
|
12
|
+
options: [exposes.options.precision('temperature'), exposes.options.calibration('temperature')],
|
|
13
|
+
convert: (model, msg, publish, options, meta) => {
|
|
14
|
+
const temperature = parseFloat(msg.data['measuredValue']) / 100.0;
|
|
15
|
+
return {temperature: calibrateAndPrecisionRoundOptions(temperature, options, 'temperature')};
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
occupancy: {
|
|
19
|
+
cluster: 'msOccupancySensing',
|
|
20
|
+
type: ['readResponse', 'attributeReport'],
|
|
21
|
+
convert: (model, msg, publish, options, meta) => {
|
|
22
|
+
if (msg.data.hasOwnProperty('sprutOccupancyLevel')) {
|
|
23
|
+
return {occupancy_level: msg.data['sprutOccupancyLevel']};
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
voc: {
|
|
28
|
+
cluster: 'sprutVoc',
|
|
29
|
+
type: ['readResponse', 'attributeReport'],
|
|
30
|
+
convert: (model, msg, publish, options, meta) => {
|
|
31
|
+
if (msg.data.hasOwnProperty('voc')) {
|
|
32
|
+
return {voc: msg.data['voc']};
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
noise: {
|
|
37
|
+
cluster: 'sprutNoise',
|
|
38
|
+
type: ['readResponse', 'attributeReport'],
|
|
39
|
+
convert: (model, msg, publish, options, meta) => {
|
|
40
|
+
if (msg.data.hasOwnProperty('noise')) {
|
|
41
|
+
return {noise: msg.data['noise'].toFixed(2)};
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
noise_detected: {
|
|
46
|
+
cluster: 'sprutNoise',
|
|
47
|
+
type: ['readResponse', 'attributeReport'],
|
|
48
|
+
convert: (model, msg, publish, options, meta) => {
|
|
49
|
+
if (msg.data.hasOwnProperty('noise_detected')) {
|
|
50
|
+
return {noise_detected: msg.data['noise_detected'] === 1};
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
module.exports = [
|
|
57
|
+
{
|
|
58
|
+
zigbeeModel: ['WBMSW3'],
|
|
59
|
+
model: 'WB-MSW-ZIGBEE v.3',
|
|
60
|
+
vendor: 'Sprut.device',
|
|
61
|
+
description: 'Wall-mounted Zigbee sensor',
|
|
62
|
+
fromZigbee: [fzLocal.temperature, fz.illuminance, fz.humidity, fz.occupancy, fzLocal.occupancy, fz.co2, fzLocal.voc,
|
|
63
|
+
fzLocal.noise, fzLocal.noise_detected, fz.on_off],
|
|
64
|
+
toZigbee: [tz.on_off],
|
|
65
|
+
exposes: [e.temperature(), e.illuminance(), e.illuminance_lux(), e.humidity(),
|
|
66
|
+
e.occupancy(), e.occupancy_level(), e.co2(), e.voc(), e.noise(), e.noise_detected(), e.switch().withEndpoint('l1'),
|
|
67
|
+
e.switch().withEndpoint('l2'), e.switch().withEndpoint('default')],
|
|
68
|
+
configure: async (device, coordinatorEndpoint, logger) => {
|
|
69
|
+
const endpoint1 = device.getEndpoint(1);
|
|
70
|
+
const binds = ['genBasic', 'msTemperatureMeasurement', 'msIlluminanceMeasurement', 'msRelativeHumidity',
|
|
71
|
+
'msOccupancySensing', 'msCO2', 'sprutVoc', 'sprutNoise'];
|
|
72
|
+
await reporting.bind(endpoint1, coordinatorEndpoint, binds);
|
|
73
|
+
|
|
74
|
+
// led_red
|
|
75
|
+
await device.getEndpoint(2).read('genOnOff', ['onOff']);
|
|
76
|
+
|
|
77
|
+
// led_green
|
|
78
|
+
await device.getEndpoint(3).read('genOnOff', ['onOff']);
|
|
79
|
+
|
|
80
|
+
// buzzer
|
|
81
|
+
await device.getEndpoint(4).read('genOnOff', ['onOff']);
|
|
82
|
+
|
|
83
|
+
// Read data at start
|
|
84
|
+
await endpoint1.read('msTemperatureMeasurement', ['measuredValue']);
|
|
85
|
+
await endpoint1.read('msIlluminanceMeasurement', ['measuredValue']);
|
|
86
|
+
await endpoint1.read('msRelativeHumidity', ['measuredValue']);
|
|
87
|
+
await endpoint1.read('msOccupancySensing', ['occupancy']);
|
|
88
|
+
await endpoint1.read('sprutNoise', ['noise']);
|
|
89
|
+
await endpoint1.read('sprutNoise', ['noise_detected']);
|
|
90
|
+
},
|
|
91
|
+
endpoint: (device) => {
|
|
92
|
+
return {'system': 1, 'l1': 2, 'l2': 3, 'default': 4};
|
|
93
|
+
},
|
|
94
|
+
meta: {multiEndpoint: true},
|
|
95
|
+
},
|
|
96
|
+
];
|
package/devices/tuya.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
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
|
-
const globalStore = require('../lib/store');
|
|
5
4
|
const ota = require('../lib/ota');
|
|
6
5
|
const tuya = require('../lib/tuya');
|
|
7
6
|
const reporting = require('../lib/reporting');
|
|
@@ -554,7 +553,9 @@ module.exports = [
|
|
|
554
553
|
configure: async (device, coordinatorEndpoint, logger) => {
|
|
555
554
|
const endpoint = device.getEndpoint(1);
|
|
556
555
|
await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
|
|
557
|
-
|
|
556
|
+
try {
|
|
557
|
+
await reporting.batteryPercentageRemaining(endpoint);
|
|
558
|
+
} catch (error) {/* Fails for some*/}
|
|
558
559
|
},
|
|
559
560
|
},
|
|
560
561
|
{
|
|
@@ -852,7 +853,7 @@ module.exports = [
|
|
|
852
853
|
e.battery_low(), e.child_lock(), e.open_window(), e.open_window_temperature().withValueMin(0).withValueMax(30),
|
|
853
854
|
e.holiday_temperature().withValueMin(0).withValueMax(30), e.comfort_temperature().withValueMin(0).withValueMax(30),
|
|
854
855
|
e.eco_temperature().withValueMin(0).withValueMax(30),
|
|
855
|
-
exposes.climate().withPreset(['auto', 'manual', 'holiday']).withLocalTemperatureCalibration(-
|
|
856
|
+
exposes.climate().withPreset(['auto', 'manual', 'holiday']).withLocalTemperatureCalibration(-5, 5, 0.1, ea.STATE_SET)
|
|
856
857
|
.withLocalTemperature(ea.STATE).withSetpoint('current_heating_setpoint', 0, 30, 0.5, ea.STATE_SET),
|
|
857
858
|
exposes.numeric('boost_timeset_countdown', ea.STATE_SET).withUnit('second').withDescription('Setting '+
|
|
858
859
|
'minimum 0 - maximum 465 seconds boost time. The boost (♨) function is activated. The remaining '+
|
|
@@ -864,9 +865,8 @@ module.exports = [
|
|
|
864
865
|
' by switching the heating off. To achieve this, the valve is closed fully. To activate the '+
|
|
865
866
|
'heating stop, the device display "HS" ‚press the pair button to cancel.'),
|
|
866
867
|
exposes.binary('online', ea.STATE_SET, 'ON', 'OFF').withDescription('Is the device online'),
|
|
867
|
-
exposes.
|
|
868
|
-
'automatically start at the set time starting point and run the holiday temperature.')
|
|
869
|
-
.withValueMin(0).withValueMax(1000),
|
|
868
|
+
exposes.text('holiday_mode_date', ea.STATE_SET).withDescription('The holiday mode( ⛱ ) will '+
|
|
869
|
+
'automatically start at the set time starting point and run the holiday temperature.'),
|
|
870
870
|
exposes.composite('programming').withDescription('Auto Mode ⏱ - In this mode,'+
|
|
871
871
|
' the device executes a preset week programming temperature time and temperature. ')
|
|
872
872
|
.withFeature(exposes.text('schedule_monday', ea.STATE))
|
|
@@ -995,22 +995,7 @@ module.exports = [
|
|
|
995
995
|
exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE),
|
|
996
996
|
e.energy(), exposes.enum('power_outage_memory', ea.STATE_SET, ['on', 'off', 'restore'])
|
|
997
997
|
.withDescription('Recover state after power outage')],
|
|
998
|
-
onEvent:
|
|
999
|
-
const endpoint = device.getEndpoint(1);
|
|
1000
|
-
if (type === 'stop') {
|
|
1001
|
-
clearInterval(globalStore.getValue(device, 'interval'));
|
|
1002
|
-
globalStore.clearValue(device, 'interval');
|
|
1003
|
-
} else if (!globalStore.hasValue(device, 'interval')) {
|
|
1004
|
-
const seconds = options && options.measurement_poll_interval ? options.measurement_poll_interval : 60;
|
|
1005
|
-
if (seconds === -1) return;
|
|
1006
|
-
const interval = setInterval(async () => {
|
|
1007
|
-
try {
|
|
1008
|
-
await endpoint.read('haElectricalMeasurement', ['rmsVoltage', 'rmsCurrent', 'activePower']);
|
|
1009
|
-
} catch (error) {/* Do nothing*/}
|
|
1010
|
-
}, seconds*1000);
|
|
1011
|
-
globalStore.putValue(device, 'interval', interval);
|
|
1012
|
-
}
|
|
1013
|
-
},
|
|
998
|
+
onEvent: tuya.onEventMeasurementPoll,
|
|
1014
999
|
},
|
|
1015
1000
|
{
|
|
1016
1001
|
fingerprint: [{modelID: 'TS0111', manufacturerName: '_TYZB01_ymcdbl3u'}],
|
|
@@ -1084,23 +1069,7 @@ module.exports = [
|
|
|
1084
1069
|
exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE),
|
|
1085
1070
|
e.energy(), exposes.enum('power_outage_memory', ea.STATE_SET, ['on', 'off', 'restore'])
|
|
1086
1071
|
.withDescription('Recover state after power outage')],
|
|
1087
|
-
onEvent:
|
|
1088
|
-
const endpoint = device.getEndpoint(1);
|
|
1089
|
-
if (type === 'stop') {
|
|
1090
|
-
clearInterval(globalStore.getValue(device, 'interval'));
|
|
1091
|
-
globalStore.clearValue(device, 'interval');
|
|
1092
|
-
} else if (!globalStore.hasValue(device, 'interval')) {
|
|
1093
|
-
const seconds = options && options.measurement_poll_interval ? options.measurement_poll_interval : 60;
|
|
1094
|
-
if (seconds === -1) return;
|
|
1095
|
-
const interval = setInterval(async () => {
|
|
1096
|
-
try {
|
|
1097
|
-
await endpoint.read('haElectricalMeasurement', ['rmsVoltage', 'rmsCurrent', 'activePower']);
|
|
1098
|
-
await endpoint.read('seMetering', ['currentSummDelivered']);
|
|
1099
|
-
} catch (error) {/* Do nothing*/}
|
|
1100
|
-
}, seconds*1000);
|
|
1101
|
-
globalStore.putValue(device, 'interval', interval);
|
|
1102
|
-
}
|
|
1103
|
-
},
|
|
1072
|
+
onEvent: tuya.onEventMeasurementPoll,
|
|
1104
1073
|
},
|
|
1105
1074
|
{
|
|
1106
1075
|
zigbeeModel: ['5p1vj8r'],
|
package/lib/exposes.js
CHANGED
|
@@ -560,7 +560,10 @@ module.exports = {
|
|
|
560
560
|
max_temperature: () => new Numeric('max_temperature', access.STATE_SET).withUnit('°C').withDescription('Maximum temperature').withValueMin(-10).withValueMax(35),
|
|
561
561
|
max_temperature_limit: () => new Numeric('max_temperature_limit', access.STATE_SET).withUnit('°C').withDescription('Maximum temperature limit').withValueMin(-10).withValueMax(35),
|
|
562
562
|
min_temperature: () => new Numeric('min_temperature', access.STATE_SET).withUnit('°C').withDescription('Minimum temperature').withValueMin(-10).withValueMax(35),
|
|
563
|
+
noise: () => new Numeric('noise', access.STATE).withUnit('dBA').withDescription('The measured noise value'),
|
|
564
|
+
noise_detected: () => new Binary('noise_detected', access.STATE, true, false).withDescription('Indicates whether the device detected noise'),
|
|
563
565
|
occupancy: () => new Binary('occupancy', access.STATE, true, false).withDescription('Indicates whether the device detected occupancy'),
|
|
566
|
+
occupancy_level: () => new Numeric('occupancy_level', access.STATE).withDescription('The measured occupancy value'),
|
|
564
567
|
open_window: () => new Binary('open_window', access.STATE_SET, 'ON', 'OFF').withDescription('Enables/disables the status on the device'),
|
|
565
568
|
open_window_temperature: () => new Numeric('open_window_temperature', access.STATE_SET).withUnit('°C').withDescription('Open window temperature').withValueMin(-10).withValueMax(35),
|
|
566
569
|
pm10: () => new Numeric('pm10', access.STATE).withUnit('µg/m³').withDescription('Measured PM10 (particulate matter) concentration'),
|
package/lib/tuya.js
CHANGED
|
@@ -62,6 +62,24 @@ function convertDecimalValueTo2ByteHexArray(value) {
|
|
|
62
62
|
return [chunk1, chunk2].map((hexVal) => parseInt(hexVal, 16));
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
async function onEventMeasurementPoll(type, data, device, options) {
|
|
66
|
+
const endpoint = device.getEndpoint(1);
|
|
67
|
+
if (type === 'stop') {
|
|
68
|
+
clearInterval(globalStore.getValue(device, 'interval'));
|
|
69
|
+
globalStore.clearValue(device, 'interval');
|
|
70
|
+
} else if (!globalStore.hasValue(device, 'interval')) {
|
|
71
|
+
const seconds = options && options.measurement_poll_interval ? options.measurement_poll_interval : 60;
|
|
72
|
+
if (seconds === -1) return;
|
|
73
|
+
const interval = setInterval(async () => {
|
|
74
|
+
try {
|
|
75
|
+
await endpoint.read('haElectricalMeasurement', ['rmsVoltage', 'rmsCurrent', 'activePower']);
|
|
76
|
+
await endpoint.read('seMetering', ['currentSummDelivered']);
|
|
77
|
+
} catch (error) {/* Do nothing*/}
|
|
78
|
+
}, seconds*1000);
|
|
79
|
+
globalStore.putValue(device, 'interval', interval);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
65
83
|
async function onEventSetTime(type, data, device) {
|
|
66
84
|
// FIXME: Need to join onEventSetTime/onEventSetLocalTime to one command
|
|
67
85
|
|
|
@@ -683,6 +701,7 @@ module.exports = {
|
|
|
683
701
|
convertDecimalValueTo2ByteHexArray,
|
|
684
702
|
onEventSetTime,
|
|
685
703
|
onEventSetLocalTime,
|
|
704
|
+
onEventMeasurementPoll,
|
|
686
705
|
convertStringToHexArray,
|
|
687
706
|
isCoverInverted,
|
|
688
707
|
getCoverStateEnums,
|