iobroker.sonoff 4.2.0 → 5.0.0
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/README.md +28 -9
- package/admin/i18n/de.json +1 -1
- package/admin/i18n/es.json +2 -2
- package/admin/i18n/fr.json +2 -2
- package/admin/i18n/it.json +3 -3
- package/admin/i18n/nl.json +2 -2
- package/admin/i18n/pl.json +2 -2
- package/admin/i18n/pt.json +2 -2
- package/admin/i18n/ru.json +3 -3
- package/admin/i18n/uk.json +3 -3
- package/admin/i18n/zh-cn.json +1 -1
- package/build/lib/datapoints.js +213 -114
- package/build/lib/datapoints.js.map +1 -1
- package/build/lib/deviceManager.js +85 -64
- package/build/lib/deviceManager.js.map +1 -1
- package/build/lib/mqttBase.js +105 -23
- package/build/lib/mqttBase.js.map +1 -1
- package/io-package.json +83 -27
- package/package.json +2 -2
package/build/lib/mqttBase.js
CHANGED
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
5
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
36
|
exports.FORBIDDEN_CHARS = void 0;
|
|
7
|
-
const datapoints_1 =
|
|
37
|
+
const datapoints_1 = __importStar(require("./datapoints"));
|
|
8
38
|
const hueCalc = true;
|
|
9
39
|
exports.FORBIDDEN_CHARS = /[\]\\[*,;'"`<>\\?]/g;
|
|
10
40
|
const NO_PREFIX = '';
|
|
@@ -214,9 +244,30 @@ class MQTTBase {
|
|
|
214
244
|
this.processTasks().catch(err => this.adapter.log.error(err));
|
|
215
245
|
}
|
|
216
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* Finds the device channel (the `iobId` of its client) a state belongs to. That is not simply the
|
|
249
|
+
* first segment after "<namespace>.": the state can be nested (e.g. "STATE.POWER1" with "Create
|
|
250
|
+
* object tree" on), and a client ID may contain dots itself, as `FORBIDDEN_CHARS` keeps them. So
|
|
251
|
+
* the longest leading path that belongs to a known client wins - the first segment is only the
|
|
252
|
+
* fallback for a client that is not connected.
|
|
253
|
+
*
|
|
254
|
+
* @param id full state ID, e.g. "sonoff.0.DVES_123456.STATE.POWER1"
|
|
255
|
+
*/
|
|
256
|
+
getChannelId(id) {
|
|
257
|
+
const parts = id.substring(this.adapter.namespace.length + 1).split('.');
|
|
258
|
+
// The last segment is the data point itself, never part of the channel
|
|
259
|
+
for (let i = parts.length - 1; i > 1; i--) {
|
|
260
|
+
const channelId = parts.slice(0, i).join('.');
|
|
261
|
+
if (this.mappingClients[channelId]) {
|
|
262
|
+
return channelId;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return parts[0];
|
|
266
|
+
}
|
|
217
267
|
async onStateChangedColors(id, state, channelId, stateId) {
|
|
218
268
|
if (!channelId) {
|
|
219
269
|
const parts = id.split('.');
|
|
270
|
+
channelId = this.getChannelId(id);
|
|
220
271
|
stateId = parts.pop() || '';
|
|
221
272
|
if (stateId === 'level' ||
|
|
222
273
|
stateId === 'state' ||
|
|
@@ -225,7 +276,6 @@ class MQTTBase {
|
|
|
225
276
|
stateId === 'green') {
|
|
226
277
|
stateId = `${parts.pop()}.${stateId}`;
|
|
227
278
|
}
|
|
228
|
-
channelId = parts.splice(2, parts.length).join('.');
|
|
229
279
|
}
|
|
230
280
|
const ledModeIdExor = `${this.adapter.namespace}.${channelId}.modeLedExor`;
|
|
231
281
|
if (this.cachedModeExor[ledModeIdExor] === undefined) {
|
|
@@ -555,9 +605,8 @@ class MQTTBase {
|
|
|
555
605
|
this.adapter.log.debug(`onStateChange ${id}: ${JSON.stringify(state)}`);
|
|
556
606
|
if (state && !state.ack) {
|
|
557
607
|
// find client.id
|
|
558
|
-
const
|
|
559
|
-
const stateId =
|
|
560
|
-
const channelId = parts.splice(2, parts.length).join('.');
|
|
608
|
+
const channelId = this.getChannelId(id);
|
|
609
|
+
const stateId = id.split('.').pop() || '';
|
|
561
610
|
// Check if this is a Zigbee device state change
|
|
562
611
|
// Pattern: ZbReceived_DEVICEID_ATTRIBUTE (e.g., ZbReceived_0x0856_Power)
|
|
563
612
|
const zbMatch = stateId.match(/^ZbReceived_([^_]+)_(Power|Dimmer)$/);
|
|
@@ -659,15 +708,31 @@ class MQTTBase {
|
|
|
659
708
|
this.adapter.log.warn(`New object creation error: ${err.message}`);
|
|
660
709
|
}
|
|
661
710
|
}
|
|
662
|
-
else
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
711
|
+
else {
|
|
712
|
+
const common = task.data.common;
|
|
713
|
+
// Objects created by older versions get the current role, so that the type-detector can
|
|
714
|
+
// recognize the device. A role changed by the user is never in the list and stays as it is.
|
|
715
|
+
const updateRole = !!common.role &&
|
|
716
|
+
obj.common.role !== common.role &&
|
|
717
|
+
!!task.legacyRoles?.includes(obj.common.role || '');
|
|
718
|
+
if (obj.common.type !== common.type || task.storeMap !== undefined || updateRole) {
|
|
719
|
+
obj.common.type = common.type;
|
|
720
|
+
if (updateRole) {
|
|
721
|
+
obj.common.role = common.role;
|
|
722
|
+
obj.common.write = common.write;
|
|
723
|
+
for (const attr of ['unit', 'min', 'max']) {
|
|
724
|
+
if (common[attr] !== undefined) {
|
|
725
|
+
obj.common[attr] = common[attr];
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
try {
|
|
730
|
+
await this.adapter.setForeignObjectAsync(task.id, obj);
|
|
731
|
+
this.adapter.log.info(`Object updated: ${task.id}`);
|
|
732
|
+
}
|
|
733
|
+
catch (err) {
|
|
734
|
+
this.adapter.log.warn(`Object update error: ${err.message}`);
|
|
735
|
+
}
|
|
671
736
|
}
|
|
672
737
|
}
|
|
673
738
|
}
|
|
@@ -797,6 +862,7 @@ class MQTTBase {
|
|
|
797
862
|
native: {},
|
|
798
863
|
type: 'state',
|
|
799
864
|
},
|
|
865
|
+
legacyRoles: datapoints_1.legacyRoles[typeKey],
|
|
800
866
|
};
|
|
801
867
|
}
|
|
802
868
|
async syncPowerState(powerId, val) {
|
|
@@ -1049,19 +1115,33 @@ class MQTTBase {
|
|
|
1049
1115
|
const attributes = {
|
|
1050
1116
|
role: 'value',
|
|
1051
1117
|
read: true,
|
|
1052
|
-
|
|
1118
|
+
// RESULT is the answer to a command, so it can be controlled
|
|
1119
|
+
write: parts[2] === 'RESULT',
|
|
1053
1120
|
type: typeof val,
|
|
1054
1121
|
name: `${client.id} ${prefix ? `${prefix} ` : ''}${path.length ? `${path.join(' ')} ` : ''} ${replaceAttr}`,
|
|
1055
1122
|
};
|
|
1056
|
-
if (parts[2] === 'RESULT') {
|
|
1057
|
-
// control
|
|
1058
|
-
attributes.write = true;
|
|
1059
|
-
attributes.role = 'level';
|
|
1060
|
-
}
|
|
1061
1123
|
if (!['number', 'string', 'boolean'].includes(attributes.type)) {
|
|
1062
1124
|
attributes.type = 'string';
|
|
1063
1125
|
val = (val || '').toString();
|
|
1064
1126
|
}
|
|
1127
|
+
const autoRole = datapoints_1.autoRoles[path.length ? `${path.join('_')}_${attr}` : attr];
|
|
1128
|
+
if (autoRole) {
|
|
1129
|
+
attributes.role = autoRole.role;
|
|
1130
|
+
if (autoRole.unit) {
|
|
1131
|
+
attributes.unit = autoRole.unit;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
else if (attributes.type === 'string') {
|
|
1135
|
+
attributes.role = 'text';
|
|
1136
|
+
}
|
|
1137
|
+
else if (attributes.type === 'boolean') {
|
|
1138
|
+
// "switch" and "state" would be taken by the type-detector for a light or a socket
|
|
1139
|
+
attributes.role = attributes.write ? 'switch.setting' : 'indicator';
|
|
1140
|
+
}
|
|
1141
|
+
else if (attributes.write) {
|
|
1142
|
+
// "level" would be taken by the type-detector for a dimmer or a blind
|
|
1143
|
+
attributes.role = 'state';
|
|
1144
|
+
}
|
|
1065
1145
|
const id = `${this.adapter.namespace}.${client.iobId}.${prefix ? `${prefix}.` : ''}${path.length ? `${path.join('_')}_` : ''}${replaceAttr}`;
|
|
1066
1146
|
const obj = {
|
|
1067
1147
|
id,
|
|
@@ -1071,6 +1151,7 @@ class MQTTBase {
|
|
|
1071
1151
|
native: {},
|
|
1072
1152
|
type: 'state',
|
|
1073
1153
|
},
|
|
1154
|
+
legacyRoles: datapoints_1.autoLegacyRoles,
|
|
1074
1155
|
};
|
|
1075
1156
|
obj.data.common.name =
|
|
1076
1157
|
`${client.id} ${prefix ? `${prefix} ` : ''}${path.length ? `${path.join(' ')} ` : ''} ${replaceAttr}`;
|
|
@@ -1262,6 +1343,7 @@ class MQTTBase {
|
|
|
1262
1343
|
native: {},
|
|
1263
1344
|
type: 'state',
|
|
1264
1345
|
},
|
|
1346
|
+
legacyRoles: datapoints_1.legacyRoles[stateId],
|
|
1265
1347
|
};
|
|
1266
1348
|
// push only new objects
|
|
1267
1349
|
this.updateState(obj, async () => {
|