zigbee-herdsman-converters 14.0.348 → 14.0.352

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
  {
@@ -6,8 +6,7 @@ module.exports = [
6
6
  zigbeeModel: ['Lamp_01'],
7
7
  model: 'KS-SM001',
8
8
  vendor: 'Ksentry Electronics',
9
- description: '[Zigbee OnOff Controller](http://ksentry.manufacturer.globalsources.com/si/6008837134660'+
10
- '/pdtl/ZigBee-module/1162731630/zigbee-on-off-controller-modules.htm)',
9
+ description: 'Zigbee on/off controller',
11
10
  extend: extend.switch(),
12
11
  configure: async (device, coordinatorEndpoint, logger) => {
13
12
  const endpoint = device.getEndpoint(11);
@@ -98,4 +98,12 @@ module.exports = [
98
98
  extend: extend.ledvance.light_onoff_brightness_colortemp_color({colorTempRange: [153, 526]}),
99
99
  ota: ota.ledvance,
100
100
  },
101
+ {
102
+ zigbeeModel: ['Tibea TW Z3'],
103
+ model: '4058075168572',
104
+ vendor: 'LEDVANCE',
105
+ description: 'SMART+ lamp E27 turntable white',
106
+ extend: extend.ledvance.light_onoff_brightness_colortemp({colorTempRange: [153, 370]}),
107
+ ota: ota.ledvance,
108
+ },
101
109
  ];
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,90 @@ 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
+ },
145
+ {
146
+ fingerprint: [{modelID: 'TS011F', manufacturerName: '_TZ3000_c7nc9w3c'}],
147
+ model: 'WP30-EU',
148
+ description: 'Power cord 4 sockets EU (with power monitoring)',
149
+ vendor: 'LELLKI',
150
+ extend: extend.switch(),
151
+ fromZigbee: [fz.on_off, fz.electrical_measurement, fz.metering, fz.ignore_basic_report, fz.tuya_switch_power_outage_memory],
152
+ toZigbee: [tz.on_off, tz.tuya_switch_power_outage_memory],
153
+ configure: async (device, coordinatorEndpoint, logger) => {
154
+ const endpoint = device.getEndpoint(1);
155
+ await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff']);
156
+ await reporting.bind(device.getEndpoint(2), coordinatorEndpoint, ['genOnOff']);
157
+ await reporting.bind(device.getEndpoint(3), coordinatorEndpoint, ['genOnOff']);
158
+ endpoint.saveClusterAttributeKeyValue('haElectricalMeasurement', {acCurrentDivisor: 1000, acCurrentMultiplier: 1});
159
+ endpoint.saveClusterAttributeKeyValue('seMetering', {divisor: 100, multiplier: 1});
160
+ device.save();
161
+ },
162
+ options: [exposes.options.measurement_poll_interval()],
163
+ exposes: [e.switch().withEndpoint('l1'), e.switch().withEndpoint('l2'),
164
+ e.switch().withEndpoint('l3'), e.power(), e.current(), e.voltage().withAccess(ea.STATE),
165
+ e.energy(), exposes.enum('power_outage_memory', ea.STATE_SET, ['on', 'off', 'restore'])
166
+ .withDescription('Recover state after power outage')],
167
+ endpoint: (device) => {
168
+ return {l1: 1, l2: 2, l3: 3};
169
+ },
170
+ onEvent: tuya.onEventMeasurementPoll,
171
+ },
85
172
  ];
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/owon.js CHANGED
@@ -102,4 +102,23 @@ module.exports = [
102
102
  device.save();
103
103
  },
104
104
  },
105
+ {
106
+ zigbeeModel: ['THS317-ET'],
107
+ model: 'THS317-ET',
108
+ vendor: 'OWON',
109
+ description: 'Temperature and humidity sensor',
110
+ fromZigbee: [fz.temperature, fz.humidity, fz.battery],
111
+ toZigbee: [],
112
+ exposes: [e.battery(), e.temperature(), e.humidity()],
113
+ configure: async (device, coordinatorEndpoint, logger) => {
114
+ const endpoint = device.getEndpoint(2);
115
+ await reporting.bind(endpoint, coordinatorEndpoint, ['msTemperatureMeasurement', 'msRelativeHumidity', 'genPowerCfg']);
116
+ await reporting.temperature(endpoint);
117
+ await reporting.humidity(endpoint);
118
+ await reporting.batteryVoltage(endpoint);
119
+ await reporting.batteryPercentageRemaining(endpoint);
120
+ device.powerSource = 'Battery';
121
+ device.save();
122
+ },
123
+ },
105
124
  ];
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
@@ -35,15 +35,28 @@ module.exports = [
35
35
 
36
36
  try {
37
37
  await reporting.thermostatSystemMode(endpoint);
38
+ } catch (error) {/* Not all support this */}
39
+
40
+ try {
38
41
  await reporting.thermostatRunningState(endpoint);
39
- await reporting.readMeteringMultiplierDivisor(endpoint);
40
- await reporting.currentSummDelivered(endpoint, {min: 10, max: 303, change: [1, 1]});
42
+ } catch (error) {/* Not all support this */}
43
+
44
+ await reporting.readMeteringMultiplierDivisor(endpoint);
45
+ await reporting.currentSummDelivered(endpoint, {min: 10, max: 303, change: [1, 1]});
46
+ try {
41
47
  await reporting.instantaneousDemand(endpoint, {min: 10, max: 304, change: 1});
42
- await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
48
+ } catch (error) {/* Do nothing*/}
49
+
50
+ await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
51
+ try {
43
52
  await reporting.activePower(endpoint, {min: 10, max: 305, change: 1});
53
+ } catch (error) {/* Do nothing*/}
54
+ try {
44
55
  await reporting.rmsCurrent(endpoint, {min: 10, max: 306, change: 100}); // divider 1000: 0.1Arms
56
+ } catch (error) {/* Do nothing*/}
57
+ try {
45
58
  await reporting.rmsVoltage(endpoint, {min: 10, max: 307, change: 5}); // divider 10: 0.5Vrms
46
- } catch (error) {/* Not all support this */}
59
+ } catch (error) {/* Do nothing*/}
47
60
 
48
61
  // Disable default reporting
49
62
  await reporting.temperature(endpoint, {min: 1, max: 0xFFFF});
@@ -113,22 +126,22 @@ module.exports = [
113
126
  model: 'TH1300ZB',
114
127
  vendor: 'Sinopé',
115
128
  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],
129
+ fromZigbee: [fz.legacy.sinope_thermostat_att_report, fz.legacy.hvac_user_interface, fz.electrical_measurement,
130
+ fz.ignore_temperature_report, fz.legacy.sinope_thermostat_state, fz.sinope_TH1300ZB_specific],
118
131
  toZigbee: [tz.thermostat_local_temperature, tz.thermostat_occupied_heating_setpoint, tz.thermostat_unoccupied_heating_setpoint,
119
132
  tz.thermostat_temperature_display_mode, tz.thermostat_keypad_lockout, tz.thermostat_system_mode, tz.thermostat_running_state,
120
133
  tz.sinope_thermostat_occupancy, tz.sinope_thermostat_backlight_autodim_param, tz.sinope_thermostat_time,
121
134
  tz.sinope_thermostat_enable_outdoor_temperature, tz.sinope_thermostat_outdoor_temperature, tz.sinope_floor_control_mode,
122
135
  tz.sinope_ambiant_max_heat_setpoint, tz.sinope_floor_min_heat_setpoint, tz.sinope_floor_max_heat_setpoint,
123
136
  tz.sinope_temperature_sensor, tz.sinope_time_format],
124
- exposes: [e.local_temperature(), e.keypad_lockout(),
137
+ exposes: [e.local_temperature(), e.keypad_lockout(), e.power(), e.current(), e.voltage(),
125
138
  exposes.climate().withSetpoint('occupied_heating_setpoint', 7, 30, 0.5).withLocalTemperature()
126
139
  .withSystemMode(['off', 'auto', 'heat']).withRunningState(['idle', 'heat']).withPiHeatingDemand(),
127
140
  exposes.enum('backlight_auto_dim', ea.SET, ['on demand', 'sensing']).withDescription('Control backlight dimming behavior')],
128
141
  configure: async (device, coordinatorEndpoint, logger) => {
129
142
  const endpoint = device.getEndpoint(1);
130
143
  const binds = ['genBasic', 'genIdentify', 'genGroups', 'hvacThermostat', 'hvacUserInterfaceCfg',
131
- 'msTemperatureMeasurement', 'manuSpecificSinope'];
144
+ 'haElectricalMeasurement', 'msTemperatureMeasurement', 'manuSpecificSinope'];
132
145
  await reporting.bind(endpoint, coordinatorEndpoint, binds);
133
146
  await reporting.thermostatTemperature(endpoint);
134
147
  await reporting.thermostatPIHeatingDemand(endpoint);
@@ -138,6 +151,17 @@ module.exports = [
138
151
  await reporting.thermostatRunningState(endpoint);
139
152
  } catch (error) {/* Not all support this */}
140
153
 
154
+ await reporting.readEletricalMeasurementMultiplierDivisors(endpoint);
155
+ try {
156
+ await reporting.activePower(endpoint, {min: 10, max: 305, change: 1}); // divider 1: 1W
157
+ } catch (error) {/* Do nothing*/}
158
+ try {
159
+ await reporting.rmsCurrent(endpoint, {min: 10, max: 306, change: 100}); // divider 1000: 0.1Arms
160
+ } catch (error) {/* Do nothing*/}
161
+ try {
162
+ await reporting.rmsVoltage(endpoint, {min: 10, max: 307, change: 5}); // divider 10: 0.5Vrms
163
+ } catch (error) {/* Do nothing*/}
164
+
141
165
  try {
142
166
  await reporting.thermostatKeypadLockMode(endpoint);
143
167
  } catch (error) {
package/devices/sonoff.js CHANGED
@@ -70,11 +70,11 @@ module.exports = [
70
70
  exposes: [e.battery(), e.action(['single', 'double', 'long'])],
71
71
  fromZigbee: [fz.ewelink_action, fz.battery],
72
72
  toZigbee: [],
73
- meta: {battery: {voltageToPercentage: '3V_2500'}},
74
73
  configure: async (device, coordinatorEndpoint, logger) => {
75
74
  const endpoint = device.getEndpoint(1);
76
75
  await reporting.bind(endpoint, coordinatorEndpoint, ['genOnOff', 'genPowerCfg']);
77
76
  await reporting.batteryVoltage(endpoint);
77
+ await reporting.batteryPercentageRemaining(endpoint);
78
78
  },
79
79
  },
80
80
  {
@@ -126,12 +126,12 @@ module.exports = [
126
126
  description: 'Motion sensor',
127
127
  fromZigbee: [fz.ias_occupancy_alarm_1, fz.battery],
128
128
  toZigbee: [],
129
- meta: {battery: {voltageToPercentage: '3V_2500'}},
130
129
  configure: async (device, coordinatorEndpoint, logger) => {
131
130
  const endpoint = device.getEndpoint(1);
132
131
  const bindClusters = ['genPowerCfg'];
133
132
  await reporting.bind(endpoint, coordinatorEndpoint, bindClusters);
134
133
  await reporting.batteryVoltage(endpoint);
134
+ await reporting.batteryPercentageRemaining(endpoint);
135
135
  },
136
136
  exposes: [e.occupancy(), e.battery_low(), e.tamper(), e.battery()],
137
137
  },
@@ -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');
@@ -10,7 +9,7 @@ const e = exposes.presets;
10
9
  const ea = exposes.access;
11
10
 
12
11
 
13
- const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak', '_TZ3000_ew3ldmgx',
12
+ const TS011Fplugs = ['_TZ3000_5f43h46b', '_TZ3000_cphmq0q7', '_TZ3000_dpo1ysak', '_TZ3000_ew3ldmgx', '_TZ3000_gjnozsaz',
14
13
  '_TZ3000_jvzvulen', '_TZ3000_mraovvmm', '_TZ3000_nfnmi125', '_TZ3000_ps3dmato', '_TZ3000_w0qqde0g', '_TZ3000_u5u4cakc'];
15
14
 
16
15
  module.exports = [
@@ -126,6 +125,7 @@ module.exports = [
126
125
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_x2fqbdun'},
127
126
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_589kq4ul'},
128
127
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_1mtktxdk'},
128
+ {modelID: 'TS0505B', manufacturerName: '_TZ3210_remypqqm'},
129
129
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_0rn9qhnu'},
130
130
  {modelID: 'TS0505B', manufacturerName: '_TZ3210_bicjqpg4'},
131
131
  {modelID: 'TS0505B', manufacturerName: '_TZ3000_cmaky9gq'},
@@ -554,7 +554,9 @@ module.exports = [
554
554
  configure: async (device, coordinatorEndpoint, logger) => {
555
555
  const endpoint = device.getEndpoint(1);
556
556
  await reporting.bind(endpoint, coordinatorEndpoint, ['genPowerCfg']);
557
- await reporting.batteryPercentageRemaining(endpoint);
557
+ try {
558
+ await reporting.batteryPercentageRemaining(endpoint);
559
+ } catch (error) {/* Fails for some*/}
558
560
  },
559
561
  },
560
562
  {
@@ -843,6 +845,7 @@ module.exports = [
843
845
  whiteLabel: [
844
846
  {vendor: 'Moes', model: 'TV01-ZB'},
845
847
  {vendor: 'Tesla Smart', model: 'TSL-TRV-TV01ZG'},
848
+ {vendor: 'Unknown/id3.pl', model: 'GTZ08'},
846
849
  ],
847
850
  ota: ota.zigbeeOTA,
848
851
  fromZigbee: [fz.ignore_basic_report, fz.ignore_tuya_set_time, fz.tvtwo_thermostat],
@@ -852,7 +855,7 @@ module.exports = [
852
855
  e.battery_low(), e.child_lock(), e.open_window(), e.open_window_temperature().withValueMin(0).withValueMax(30),
853
856
  e.holiday_temperature().withValueMin(0).withValueMax(30), e.comfort_temperature().withValueMin(0).withValueMax(30),
854
857
  e.eco_temperature().withValueMin(0).withValueMax(30),
855
- exposes.climate().withPreset(['auto', 'manual', 'holiday']).withLocalTemperatureCalibration(-30, 30, 0.1, ea.STATE_SET)
858
+ exposes.climate().withPreset(['auto', 'manual', 'holiday']).withLocalTemperatureCalibration(-5, 5, 0.1, ea.STATE_SET)
856
859
  .withLocalTemperature(ea.STATE).withSetpoint('current_heating_setpoint', 0, 30, 0.5, ea.STATE_SET),
857
860
  exposes.numeric('boost_timeset_countdown', ea.STATE_SET).withUnit('second').withDescription('Setting '+
858
861
  'minimum 0 - maximum 465 seconds boost time. The boost (♨) function is activated. The remaining '+
@@ -864,9 +867,8 @@ module.exports = [
864
867
  ' by switching the heating off. To achieve this, the valve is closed fully. To activate the '+
865
868
  'heating stop, the device display "HS" ‚press the pair button to cancel.'),
866
869
  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),
870
+ exposes.text('holiday_mode_date', ea.STATE_SET).withDescription('The holiday mode( ⛱ ) will '+
871
+ 'automatically start at the set time starting point and run the holiday temperature.'),
870
872
  exposes.composite('programming').withDescription('Auto Mode ⏱ - In this mode,'+
871
873
  ' the device executes a preset week programming temperature time and temperature. ')
872
874
  .withFeature(exposes.text('schedule_monday', ea.STATE))
@@ -995,22 +997,7 @@ module.exports = [
995
997
  exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE),
996
998
  e.energy(), exposes.enum('power_outage_memory', ea.STATE_SET, ['on', 'off', 'restore'])
997
999
  .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
- },
1000
+ onEvent: tuya.onEventMeasurementPoll,
1014
1001
  },
1015
1002
  {
1016
1003
  fingerprint: [{modelID: 'TS0111', manufacturerName: '_TYZB01_ymcdbl3u'}],
@@ -1084,23 +1071,7 @@ module.exports = [
1084
1071
  exposes: [e.switch(), e.power(), e.current(), e.voltage().withAccess(ea.STATE),
1085
1072
  e.energy(), exposes.enum('power_outage_memory', ea.STATE_SET, ['on', 'off', 'restore'])
1086
1073
  .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
- },
1074
+ onEvent: tuya.onEventMeasurementPoll,
1104
1075
  },
1105
1076
  {
1106
1077
  zigbeeModel: ['5p1vj8r'],