iobroker.zigbee 1.5.5 → 1.6.6

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/lib/states.js CHANGED
@@ -80,7 +80,7 @@ const states = {
80
80
  read: true,
81
81
  type: 'number',
82
82
  min: 0,
83
- max: 254
83
+ max: 255
84
84
  },
85
85
  available: {
86
86
  id: 'available',
@@ -103,6 +103,15 @@ const states = {
103
103
  type: 'boolean',
104
104
  isOption: true,
105
105
  },
106
+ from_zigbee: {
107
+ id: 'msg_from_zigbee',
108
+ name: 'Message from Zigbee',
109
+ icon: undefined,
110
+ role: 'state',
111
+ write: false,
112
+ read: true,
113
+ type: 'string',
114
+ },
106
115
  checking: { // press button for checking
107
116
  id: 'checking',
108
117
  name: 'Start checking process',
@@ -287,7 +296,7 @@ const states = {
287
296
  prop: 'battery',
288
297
  name: 'Battery percent',
289
298
  icon: 'img/battery_p.png',
290
- role: 'battery.percent',
299
+ role: 'value.battery',
291
300
  write: false,
292
301
  read: true,
293
302
  type: 'number',
@@ -738,7 +747,7 @@ const states = {
738
747
  prop: 'battery_low',
739
748
  name: 'Battery Status Low',
740
749
  icon: undefined,
741
- role: 'state',
750
+ role: 'indicator.lowbat',
742
751
  write: false,
743
752
  read: true,
744
753
  type: 'boolean'
@@ -2130,7 +2139,7 @@ const states = {
2130
2139
  prop: 'local_temperature_calibration',
2131
2140
  name: 'Temperature Calibration',
2132
2141
  icon: undefined,
2133
- role: 'value.temperature',
2142
+ role: 'level',
2134
2143
  write: true,
2135
2144
  read: true,
2136
2145
  type: 'number',
@@ -2343,7 +2352,7 @@ const states = {
2343
2352
  prop: 'pi_heating_demand',
2344
2353
  name: 'Auto Valve position',
2345
2354
  icon: undefined,
2346
- role: 'state',
2355
+ role: 'value.valve',
2347
2356
  write: false,
2348
2357
  read: true,
2349
2358
  type: 'number',
@@ -2355,7 +2364,7 @@ const states = {
2355
2364
  prop: 'eurotronic_valve_position',
2356
2365
  name: 'Manual Valve position',
2357
2366
  icon: undefined,
2358
- role: 'state',
2367
+ role: 'level.valve',
2359
2368
  write: true,
2360
2369
  read: true,
2361
2370
  type: 'number',
@@ -2370,7 +2379,7 @@ const states = {
2370
2379
  prop: 'current_heating_setpoint',
2371
2380
  name: 'Current Target Temperature',
2372
2381
  icon: undefined,
2373
- role: 'value.temperature',
2382
+ role: 'level.temperature',
2374
2383
  write: true,
2375
2384
  read: true,
2376
2385
  type: 'number',
@@ -2382,10 +2391,10 @@ const states = {
2382
2391
  // 1 = manual valve control
2383
2392
  // 2 = auto (default)
2384
2393
  id: 'spz_trv_mode',
2385
- name: 'TRV Mode',
2394
+ name: 'TRV Mode (1 = manual | 2 = auto)',
2386
2395
  prop: 'eurotronic_trv_mode',
2387
2396
  icon: undefined,
2388
- role: 'state',
2397
+ role: 'level',
2389
2398
  write: true,
2390
2399
  read: true,
2391
2400
  type: 'number',
@@ -2402,7 +2411,7 @@ const states = {
2402
2411
  name: 'Thermostat Mode',
2403
2412
  prop: 'eurotronic_system_mode',
2404
2413
  icon: undefined,
2405
- role: 'state',
2414
+ role: 'level',
2406
2415
  write: true,
2407
2416
  read: true,
2408
2417
  type: 'number',
@@ -2412,7 +2421,7 @@ const states = {
2412
2421
  name: 'Thermostat Error',
2413
2422
  prop: 'eurotronic_error_status',
2414
2423
  icon: undefined,
2415
- role: 'state',
2424
+ role: 'value',
2416
2425
  write: false,
2417
2426
  read: true,
2418
2427
  type: 'number',
@@ -2422,7 +2431,7 @@ const states = {
2422
2431
  name: 'Window Open / Off',
2423
2432
  prop: 'eurotronic_host_flags',
2424
2433
  icon: undefined,
2425
- role: 'state',
2434
+ role: 'switch',
2426
2435
  write: true,
2427
2436
  read: true,
2428
2437
  type: 'boolean',
@@ -2441,7 +2450,7 @@ const states = {
2441
2450
  name: 'Boost Mode',
2442
2451
  prop: 'eurotronic_host_flags',
2443
2452
  icon: undefined,
2444
- role: 'state',
2453
+ role: 'switch.mode.boost',
2445
2454
  write: true,
2446
2455
  read: true,
2447
2456
  type: 'boolean',
@@ -2460,7 +2469,7 @@ const states = {
2460
2469
  name: 'Child Protection',
2461
2470
  prop: 'eurotronic_host_flags',
2462
2471
  icon: undefined,
2463
- role: 'state',
2472
+ role: 'switch.lock',
2464
2473
  write: true,
2465
2474
  read: true,
2466
2475
  type: 'boolean',
@@ -2479,7 +2488,7 @@ const states = {
2479
2488
  name: 'Mirror Display',
2480
2489
  prop: 'eurotronic_host_flags',
2481
2490
  icon: undefined,
2482
- role: 'state',
2491
+ role: 'switch',
2483
2492
  write: true,
2484
2493
  read: true,
2485
2494
  type: 'boolean',
@@ -2932,6 +2941,56 @@ const states = {
2932
2941
  return {...options, reverse_direction: value};
2933
2942
  },
2934
2943
  },
2944
+ curtain_xiaomi_reverse_direction: {
2945
+ id: 'reverse_direction',
2946
+ prop: 'options',
2947
+ name: 'Reverse direction',
2948
+ icon: undefined,
2949
+ role: 'state',
2950
+ write: true,
2951
+ read: true,
2952
+ type: 'boolean',
2953
+ inOptions: true,
2954
+ getter: payload => (payload.options !== null) && payload.options.hasOwnProperty('reverse_direction') && !isNaN(payload.options.reverse_direction) ? payload.options.reverse_direction : undefined,
2955
+ setterOpt: (value, options) => {
2956
+ return {...options, reverse_direction: value};
2957
+ },
2958
+ setter: (value, options) => {
2959
+ return {...options, reverse_direction: value};
2960
+ },
2961
+ },
2962
+ curtain_xiaomi_hand_open: {
2963
+ id: 'hand_open',
2964
+ prop: 'options',
2965
+ name: 'Hand open',
2966
+ icon: undefined,
2967
+ role: 'state',
2968
+ write: true,
2969
+ read: true,
2970
+ type: 'boolean',
2971
+ inOptions: true,
2972
+ getter: payload => (payload.options !== null) && payload.options.hasOwnProperty('hand_open') && !isNaN(payload.options.hand_open) ? payload.options.hand_open : undefined,
2973
+ setterOpt: (value, options) => {
2974
+ return {...options, hand_open: value};
2975
+ },
2976
+ setter: (value, options) => {
2977
+ return {...options, hand_open: value};
2978
+ },
2979
+ },
2980
+ curtain_xiaomi_reset_limits: {
2981
+ id: 'reset_limits',
2982
+ prop: 'options',
2983
+ name: 'Reset limits',
2984
+ icon: undefined,
2985
+ write: true,
2986
+ read: true,
2987
+ type: 'boolean',
2988
+ getter: payload => (undefined),
2989
+ inOptions: true,
2990
+ setter: (value, options) => {
2991
+ return {...options, reset_limits: value};
2992
+ },
2993
+ },
2935
2994
  blind_position: {
2936
2995
  id: 'position',
2937
2996
  prop: 'position',
@@ -4011,7 +4070,7 @@ const states = {
4011
4070
  prop: 'current_heating_setpoint',
4012
4071
  name: 'Current Target Temperature',
4013
4072
  icon: undefined,
4014
- role: 'value.temperature',
4073
+ role: 'level.temperature',
4015
4074
  write: true,
4016
4075
  read: true,
4017
4076
  type: 'number',
@@ -4024,7 +4083,7 @@ const states = {
4024
4083
  name: 'Locked',
4025
4084
  prop: 'child_lock',
4026
4085
  icon: undefined,
4027
- role: 'state',
4086
+ role: 'switch.lock',
4028
4087
  write: true,
4029
4088
  read: true,
4030
4089
  type: 'boolean',
@@ -4036,7 +4095,7 @@ const states = {
4036
4095
  name: 'Window detected',
4037
4096
  prop: 'window_detection',
4038
4097
  icon: undefined,
4039
- role: 'state',
4098
+ role: 'value',
4040
4099
  write: false,
4041
4100
  read: true,
4042
4101
  type: 'boolean',
@@ -4047,7 +4106,7 @@ const states = {
4047
4106
  name: 'Valve detected',
4048
4107
  prop: 'valve_detection',
4049
4108
  icon: undefined,
4050
- role: 'state',
4109
+ role: 'value',
4051
4110
  write: false,
4052
4111
  read: true,
4053
4112
  type: 'boolean',
@@ -4058,7 +4117,7 @@ const states = {
4058
4117
  name: 'Auto lock',
4059
4118
  prop: 'auto_lock',
4060
4119
  icon: undefined,
4061
- role: 'state',
4120
+ role: 'value',
4062
4121
  write: false,
4063
4122
  read: true,
4064
4123
  type: 'boolean',
@@ -4069,7 +4128,7 @@ const states = {
4069
4128
  prop: 'min_temperature',
4070
4129
  name: 'Minimal Temperature',
4071
4130
  icon: undefined,
4072
- role: 'value.temperature',
4131
+ role: 'level',
4073
4132
  write: true,
4074
4133
  read: true,
4075
4134
  type: 'number',
@@ -4082,7 +4141,7 @@ const states = {
4082
4141
  prop: 'max_temperature',
4083
4142
  name: 'Maximal Temperature',
4084
4143
  icon: undefined,
4085
- role: 'value.temperature',
4144
+ role: 'level',
4086
4145
  write: true,
4087
4146
  read: true,
4088
4147
  type: 'number',
@@ -4095,7 +4154,7 @@ const states = {
4095
4154
  prop: 'boost_time',
4096
4155
  name: 'Boost time',
4097
4156
  icon: undefined,
4098
- role: 'state',
4157
+ role: 'level',
4099
4158
  write: true,
4100
4159
  read: true,
4101
4160
  type: 'number',
@@ -4108,7 +4167,7 @@ const states = {
4108
4167
  prop: 'comfort_temperature',
4109
4168
  name: 'Comfort Temperature',
4110
4169
  icon: undefined,
4111
- role: 'value.temperature',
4170
+ role: 'level',
4112
4171
  write: true,
4113
4172
  read: true,
4114
4173
  type: 'number',
@@ -4121,7 +4180,7 @@ const states = {
4121
4180
  prop: 'eco_temperature',
4122
4181
  name: 'ECO Temperature',
4123
4182
  icon: undefined,
4124
- role: 'value.temperature',
4183
+ role: 'level',
4125
4184
  write: true,
4126
4185
  read: true,
4127
4186
  type: 'number',
@@ -4134,7 +4193,7 @@ const states = {
4134
4193
  name: 'Mode',
4135
4194
  prop: 'system_mode',
4136
4195
  icon: undefined,
4137
- role: 'state',
4196
+ role: 'level.mode.thermostat',
4138
4197
  write: true,
4139
4198
  read: true,
4140
4199
  type: 'string', // valid: low, medium, high
@@ -4201,7 +4260,7 @@ const states = {
4201
4260
  prop: 'position',
4202
4261
  name: 'Valve position',
4203
4262
  icon: undefined,
4204
- role: 'state',
4263
+ role: 'value.valve',
4205
4264
  write: false,
4206
4265
  read: true,
4207
4266
  type: 'number',
@@ -31,6 +31,10 @@ class StatesController extends EventEmitter {
31
31
  this.emit('log', 'warn', message, data);
32
32
  }
33
33
 
34
+ sendError(error, message) {
35
+ this.adapter.sendError(error, message);
36
+ }
37
+
34
38
  getDebugDevices() {
35
39
  this.debugDevices = [];
36
40
  this.adapter.getState(this.adapter.namespace + '.info.debugmessages', (err, state) => {
@@ -54,6 +58,7 @@ class StatesController extends EventEmitter {
54
58
 
55
59
  }
56
60
  onStateChange(id, state){
61
+ if (!this.adapter.zbController || !this.adapter.zbController.connected()) return;
57
62
  if (this.debugDevices === undefined) this.getDebugDevices();
58
63
  if (state && !state.ack) {
59
64
  if (id.endsWith('pairingCountdown') || id.endsWith('pairingMessage') || id.endsWith('connection')) return;
@@ -137,9 +142,10 @@ class StatesController extends EventEmitter {
137
142
  stateModel = statesMapping.findModel(model);
138
143
  if (!stateModel) {
139
144
  this.error('Device ' + deviceId + ' "' + model + '" not described in statesMapping.');
140
- return;
145
+ states = statesMapping.commonStates;
146
+ } else {
147
+ states = stateModel.states;
141
148
  }
142
- states = stateModel.states;
143
149
  if (typeof states === 'function' && !states.prototype) {
144
150
  const entity = await this.adapter.zbController.resolveEntity(deviceId);
145
151
  if (entity)
@@ -148,6 +154,7 @@ class StatesController extends EventEmitter {
148
154
  }
149
155
  return {states: states, stateModel: stateModel};
150
156
  } catch (error) {
157
+ this.sendError(error);
151
158
  this.error(`Error getDevStates for ${deviceId}. Error: ${error.stack}`);
152
159
  }
153
160
  }
@@ -191,6 +198,7 @@ class StatesController extends EventEmitter {
191
198
  this.warn('publish from State - LinkedState is not a function ' + JSON.stringify(linkedFunct));
192
199
  }
193
200
  } catch (e) {
201
+ this.sendError(e);
194
202
  this.error('Exception caught in publishfromstate');
195
203
  }
196
204
 
package/lib/utils.js CHANGED
@@ -114,6 +114,24 @@ const forceEndDevice = flatten(
114
114
  const xiaomiManufacturerID = [4151, 4447];
115
115
  const ikeaTradfriManufacturerID = [4476];
116
116
 
117
+ function sanitizeImageParameter(parameter) {
118
+ const replaceByDash = [/\?/g, /&/g, /[^a-z\d\-_./:]/gi, /[/]/gi];
119
+ let sanitized = parameter;
120
+ replaceByDash.forEach((r) => sanitized = sanitized.replace(r, '-'));
121
+ return sanitized;
122
+ }
123
+
124
+ function getDeviceIcon(definition) {
125
+ let icon = definition.icon;
126
+ if (icon) {
127
+ icon = icon.replace('${model}', sanitizeImageParameter(definition.model));
128
+ }
129
+ if (!icon) {
130
+ icon = `https://www.zigbee2mqtt.io/images/devices/${sanitizeImageParameter(definition.model)}.jpg`;
131
+ }
132
+ return icon;
133
+ }
134
+
117
135
  exports.secondsToMilliseconds = (seconds) => seconds * 1000;
118
136
  exports.bulbLevelToAdapterLevel = bulbLevelToAdapterLevel;
119
137
  exports.adapterLevelToBulbLevel = adapterLevelToBulbLevel;
@@ -130,3 +148,4 @@ exports.isXiaomiDevice = (device) => {
130
148
  (!device.manufacturerName || !device.manufacturerName.startsWith('Trust'));
131
149
  };
132
150
  exports.isIkeaTradfriDevice = (device) => ikeaTradfriManufacturerID.includes(device.manufacturerID);
151
+ exports.getDeviceIcon = getDeviceIcon;
@@ -22,6 +22,10 @@ class BaseExtension {
22
22
  debug(message, data) {
23
23
  this.zigbee.debug(message, data);
24
24
  }
25
+
26
+ sendError(error, message) {
27
+ this.zigbee.sendError(error, message);
28
+ }
25
29
  }
26
30
 
27
31
  module.exports = BaseExtension;
@@ -49,6 +49,7 @@ class DelayedAction extends BaseExtension {
49
49
  // }
50
50
  // }
51
51
  } catch (error) {
52
+ this.sendError(error);
52
53
  this.error(
53
54
  `Failed to DelayedAction.onZigbeeStarted (${error.stack})`,
54
55
  );
@@ -62,6 +63,7 @@ class DelayedAction extends BaseExtension {
62
63
  this.doActions(device);
63
64
  // }
64
65
  } catch (error) {
66
+ this.sendError(error);
65
67
  this.error(
66
68
  `Failed to DelayedAction.onZigbeeEvent (${error.stack})`,
67
69
  );
@@ -80,6 +82,7 @@ class DelayedAction extends BaseExtension {
80
82
  this.debug(`Succesfully delay action for ${device.ieeeAddr} ${device.modelID}`);
81
83
  this.doActions(device);
82
84
  } catch (error) {
85
+ this.sendError(error);
83
86
  this.error(
84
87
  `Failed to DelayedAction.delayAction ${device.ieeeAddr} ${device.modelID} (${error.stack})`,
85
88
  );
@@ -119,6 +122,7 @@ class DelayedAction extends BaseExtension {
119
122
  this.info(`Do action succesfully ${device.ieeeAddr} ${device.modelID}`);
120
123
  toDelete.push(actionDef);
121
124
  } catch (error) {
125
+ this.sendError(error);
122
126
  this.error(
123
127
  `Failed to do action ${device.ieeeAddr} ${device.modelID}, ` +
124
128
  `attempt ${actionDef.attempts + 1} (${error.stack})`,
@@ -136,6 +140,7 @@ class DelayedAction extends BaseExtension {
136
140
  delete this.actions[device.ieeeAddr];
137
141
  }
138
142
  } catch (error) {
143
+ this.sendError(error);
139
144
  this.error(
140
145
  `Failed to DelayedAction.doAction ${device.ieeeAddr} ${device.modelID} (${error.stack})`,
141
146
  );
@@ -159,6 +159,7 @@ class DeviceAvailability extends BaseExtension {
159
159
  }
160
160
  }
161
161
  catch (error) {
162
+ this.sendError(error);
162
163
  this.debug(`Exception in readState of '${device.ieeeAddr}' - error : '${error}'`);
163
164
  // intentionally empty: Just present to ensure we cause no harm
164
165
  // when reading the state fails. => fall back on standard Ping function
@@ -236,6 +237,7 @@ class DeviceAvailability extends BaseExtension {
236
237
  }
237
238
  }
238
239
  } catch (error) {
240
+ this.sendError(error);
239
241
  this.debug(`Failed to read state of '${entity.device.ieeeAddr}' after reconnect`);
240
242
  }
241
243
  }
@@ -29,15 +29,13 @@ class DeviceConfigure extends BaseExtension {
29
29
  if (!device || !mappedDevice) {
30
30
  return false;
31
31
  }
32
- if (device.meta.hasOwnProperty('configured') &&
33
- zigbeeHerdsmanConverters.getConfigureKey(mappedDevice)) {
32
+ if (!mappedDevice || !mappedDevice.configure) {
34
33
  return false;
35
34
  }
36
-
37
- if (!mappedDevice || !mappedDevice.configure) {
35
+ if (device.meta.hasOwnProperty('configured') &&
36
+ zigbeeHerdsmanConverters.getConfigureKey(mappedDevice)) {
38
37
  return false;
39
38
  }
40
-
41
39
  if (device.interviewing === true) {
42
40
  return false;
43
41
  }
@@ -64,6 +62,7 @@ class DeviceConfigure extends BaseExtension {
64
62
  }
65
63
  }
66
64
  } catch (error) {
65
+ this.sendError(error);
67
66
  this.error(
68
67
  `Failed to DeviceConfigure.onZigbeeStarted (${error.stack})`,
69
68
  );
@@ -77,6 +76,7 @@ class DeviceConfigure extends BaseExtension {
77
76
  this.configure(device, mappedDevice);
78
77
  }
79
78
  } catch (error) {
79
+ this.sendError(error);
80
80
  this.error(
81
81
  `Failed to DeviceConfigure.onZigbeeEvent (${error.stack})`,
82
82
  );
@@ -93,6 +93,7 @@ class DeviceConfigure extends BaseExtension {
93
93
  delete this.attempts[device.ieeeAddr];
94
94
  }
95
95
  } catch (error) {
96
+ this.sendError(error);
96
97
  this.error(
97
98
  `Failed to DeviceConfigure.onDeviceRemove (${error.stack})`,
98
99
  );
@@ -126,6 +127,7 @@ class DeviceConfigure extends BaseExtension {
126
127
  device.meta.configured = zigbeeHerdsmanConverters.getConfigureKey(mappedDevice);
127
128
  device.save();
128
129
  } catch (error) {
130
+ this.sendError(error);
129
131
  this.warn(
130
132
  `DeviceConfigure failed ${device.ieeeAddr} ${device.modelID}, ` +
131
133
  `attempt ${this.attempts[device.ieeeAddr] + 1} (${error.stack})`,
@@ -135,6 +137,7 @@ class DeviceConfigure extends BaseExtension {
135
137
 
136
138
  this.configuring.delete(device.ieeeAddr);
137
139
  } catch (error) {
140
+ this.sendError(error);
138
141
  this.error(
139
142
  `Failed to DeviceConfigure.configure ${device.ieeeAddr} ${device.modelID} (${error.stack})`,
140
143
  );