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.
@@ -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).
@@ -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) => {
@@ -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
  ];
@@ -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: (type, data, device, options) => {
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(-30, 30, 0.1, ea.STATE_SET)
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.STATE_SET).withUnit('min').withDescription('Countdown in minutes')
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.ignore_temperature_report,
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) {
@@ -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
- await reporting.batteryPercentageRemaining(endpoint);
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(-30, 30, 0.1, ea.STATE_SET)
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.numeric('holiday_mode_date', ea.STATE_SET).withDescription('The holiday mode( ⛱ ) will '+
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: (type, data, device, options) => {
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: (type, data, device, options) => {
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,