iobroker.lorawan 1.15.8 → 1.16.1
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 +6 -0
- package/io-package.json +27 -27
- package/lib/modules/bridge.js +167 -15
- package/lib/modules/bridgeMqttclient.js +1 -1
- package/lib/modules/directorieshandler.js +2 -2
- package/lib/modules/messagehandler.js +2 -2
- package/main.js +130 -97
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,12 @@ For now there is documentation in English here: https://wiki.hafenmeister.de
|
|
|
23
23
|
Placeholder for the next version (at the beginning of the line):
|
|
24
24
|
### **WORK IN PROGRESS**
|
|
25
25
|
-->
|
|
26
|
+
### 1.16.1 (2025-09-16)
|
|
27
|
+
* (BenAhrdt) bugfix namespace also by notifications
|
|
28
|
+
|
|
29
|
+
### 1.16.0 (2025-09-16)
|
|
30
|
+
* (BenAhrdt) possibility to insert foreign states to bridge by using enum.functions.bridge
|
|
31
|
+
|
|
26
32
|
### 1.15.8 (2025-09-16)
|
|
27
33
|
* (BenAhrdt) remove await from some callings
|
|
28
34
|
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "lorawan",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.16.1",
|
|
5
5
|
"news": {
|
|
6
|
+
"1.16.1": {
|
|
7
|
+
"en": "bugfix namespace also by notifications",
|
|
8
|
+
"de": "Fehlerbehebung Namespace auch bei Benachrichtigungen",
|
|
9
|
+
"ru": "исправлена ошибка с пространством имён также для уведомлений",
|
|
10
|
+
"pt": "Correção de bug no namespace também por notificações.",
|
|
11
|
+
"nl": "bugfix namespace ook bij meldingen",
|
|
12
|
+
"fr": "Correction d'un bug concernant les notifications de namespace.",
|
|
13
|
+
"it": "Risolto bug anche per i namespace nelle notifiche",
|
|
14
|
+
"es": "Corrección de error en el espacio de nombres también por notificaciones.",
|
|
15
|
+
"pl": "naprawiono błąd z przestrzenią nazw również w powiadomieniach",
|
|
16
|
+
"uk": "виправлення помилки простору імен також за допомогою сповіщень",
|
|
17
|
+
"zh-cn": "修复命名空间通知问题"
|
|
18
|
+
},
|
|
19
|
+
"1.16.0": {
|
|
20
|
+
"en": "possibility to insert foreign states to bridge by using enum.functions.bridge",
|
|
21
|
+
"de": "Möglichkeit, externe Zustände über enum.functions.bridge in die Bridge einzufügen.",
|
|
22
|
+
"ru": "Возможность вставки внешних состояний в мост путем использования enum.functions.bridge",
|
|
23
|
+
"pt": "possibilidade de inserir estados estrangeiros na ponte usando enum.functions.bridge",
|
|
24
|
+
"nl": "Mogelijkheid om externe toestanden in de brug in te voegen door gebruik te maken van enum.functions.bridge.",
|
|
25
|
+
"fr": "possibilité d'insérer des états étrangers dans le pont en utilisant enum.functions.bridge",
|
|
26
|
+
"it": "Possibilità di inserire stati esterni al bridge utilizzando enum.functions.bridge",
|
|
27
|
+
"es": "Posibilidad de insertar estados extranjeros en el puente utilizando enum.functions.bridge",
|
|
28
|
+
"pl": "możliwość wstawienia stanów zewnętrznych do mostka za pomocą enum.functions.bridge",
|
|
29
|
+
"uk": "Можливість додавання зовнішніх станів до моста за допомогою enum.functions.bridge",
|
|
30
|
+
"zh-cn": "通过使用enum.functions.bridge功能,可以将外部状态插入到桥接器中。"
|
|
31
|
+
},
|
|
6
32
|
"1.15.8": {
|
|
7
33
|
"en": "remove await from some callings",
|
|
8
34
|
"de": "Entferne das „await“ aus einigen Aufrufen.",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "Naprawiono błąd z zachowaniem tematów stanów wysyłanych.\nPoprawka błędu dotycząca kończenia stanu",
|
|
68
94
|
"uk": "Виправлено помилку збереження тем для відправлення стану\nВиправлено помилку з порядком стану",
|
|
69
95
|
"zh-cn": "修复发送状态主题时的保留问题\n修复了和状态结尾相关的问题"
|
|
70
|
-
},
|
|
71
|
-
"1.15.3": {
|
|
72
|
-
"en": "dont translate the selected state in bridge config",
|
|
73
|
-
"de": "Nicht den ausgewählten Status in der Bridge-Konfiguration übersetzen.",
|
|
74
|
-
"ru": "Не переводите состояние \"selected\" в настройках моста",
|
|
75
|
-
"pt": "não traduzir o estado selecionado na configuração da ponte",
|
|
76
|
-
"nl": "'geselecteerde toestand' niet vertalen in de bridge-configuratie.",
|
|
77
|
-
"fr": "ne pas traduire l'état sélectionné dans la configuration du pont",
|
|
78
|
-
"it": "non tradurre lo stato selezionato nella configurazione del ponte",
|
|
79
|
-
"es": "no traducir el estado seleccionado en la configuración del puente",
|
|
80
|
-
"pl": "nie tłumacz stanu \"selected\" w konfiguracji mostu",
|
|
81
|
-
"uk": "не перекладайте обраний стан в конфігурації моста",
|
|
82
|
-
"zh-cn": "不要将“selected state”翻译成桥接配置"
|
|
83
|
-
},
|
|
84
|
-
"1.15.2": {
|
|
85
|
-
"en": "change wording of notifications\nimport diagnostic and config fpr entity_type\nchange extSernsorTemperature in ExtSernsorTemperature",
|
|
86
|
-
"de": "Änderung der Benachrichtigungen\nDiagnose und konfiguriere entity_type\nÄndern von extSernsorTemperature in ExtSernsorTemperature",
|
|
87
|
-
"ru": "изменить формулировку уведомлений\nИсправление диагностики и конфигурации для типа entity\nИзменено extSernsorTemperature на ExtSernsorTemperature",
|
|
88
|
-
"pt": "alterar a redação das notificações\nimportação de diagnóstico e configuração para o tipo de entidade\nAlterar extSernsorTemperature para ExtSernsorTemperature",
|
|
89
|
-
"nl": "wijziging van meldingen\nimport diagnose en configuratie voor entity_type\nVerander extSernsorTemperature in ExtSernsorTemperature",
|
|
90
|
-
"fr": "modifier le libellé des notifications\nImporter le diagnostic et la configuration pour le type d'entité\nChanger extSernsorTemperature en ExtSernsorTemperature",
|
|
91
|
-
"it": "modificare i testi delle notifiche\nimport diagnostiche e configurazioni per il tipo di entità\nModifica extSernsorTemperature in ExtSernsorTemperature",
|
|
92
|
-
"es": "cambiar la redacción de las notificaciones\nimportar diagnóstico y configuración para el tipo de entidad\nCambiar extSensorTemperature a ExtSensorTemperature",
|
|
93
|
-
"pl": "zmień sformułowanie powiadomień\nimport diagnostyka i konfiguracja dla entity_type\nzmień extSensorTemperature na ExtSensorTemperature",
|
|
94
|
-
"uk": "змінити формулювання сповіщень\nімпорт діагнострики та конфігурації для типу entity\nЗміна extSensorTemperature на ExtSensorTemperature",
|
|
95
|
-
"zh-cn": "更改通知内容\n为entity_type添加诊断和配置\n将\"extSensorTemperature\"更改为\"ExtSensorTemperature\""
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
package/lib/modules/bridge.js
CHANGED
|
@@ -70,7 +70,7 @@ class bridgeClass {
|
|
|
70
70
|
second: '2-digit',
|
|
71
71
|
},
|
|
72
72
|
};
|
|
73
|
-
|
|
73
|
+
this.ids = {};
|
|
74
74
|
// Unitmapping zur Zuweisung der passenden Unit, wenn diese falsch geschrieben ist
|
|
75
75
|
this.unitMap = {
|
|
76
76
|
'°C': { device_class: 'temperature' },
|
|
@@ -207,7 +207,12 @@ class bridgeClass {
|
|
|
207
207
|
await this.publishId(this.SubscribedTopics[topic].id, message, {});
|
|
208
208
|
return;
|
|
209
209
|
}
|
|
210
|
-
|
|
210
|
+
// Check for namespace and write own, oder foreign state
|
|
211
|
+
if (this.SubscribedTopics[topic].id.startsWith(this.adapter.namespace)) {
|
|
212
|
+
await this.adapter.setState(this.SubscribedTopics[topic].id, message);
|
|
213
|
+
} else {
|
|
214
|
+
await this.adapter.setForeignStateAsync(this.SubscribedTopics[topic].id, message);
|
|
215
|
+
}
|
|
211
216
|
await this.adapter.setState('info.subscribedTopics', JSON.stringify(this.DiscoveredIds), true);
|
|
212
217
|
} else {
|
|
213
218
|
this.adapter.log.debug(`The received Topic ${topic} is not subscribed`);
|
|
@@ -226,8 +231,6 @@ class bridgeClass {
|
|
|
226
231
|
const activeFunction = 'bridge.js - work';
|
|
227
232
|
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
228
233
|
try {
|
|
229
|
-
// First remove namespace from id
|
|
230
|
-
id = this.adapter.removeNamespace(id);
|
|
231
234
|
if (this.bridgeMqttClient.internalConnectionstate) {
|
|
232
235
|
const countBefore = Object.keys(this.DiscoveredIds).length;
|
|
233
236
|
await this.discovery(id, options);
|
|
@@ -293,7 +296,7 @@ class bridgeClass {
|
|
|
293
296
|
const activeFunction = 'discoverDeviceNotifications';
|
|
294
297
|
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
295
298
|
try {
|
|
296
|
-
const notificationId = `${changeInfo.objectStartDirectory}${this.NotificationId}${this.GeneralId}`;
|
|
299
|
+
const notificationId = `${this.adapter.namespace}.${changeInfo.objectStartDirectory}${this.NotificationId}${this.GeneralId}`;
|
|
297
300
|
if (!this.Notifications[notificationId]) {
|
|
298
301
|
const deviceIdentifier = this.getDeviceIdentifier(changeInfo, this.adapter.config.DeviceIdentifiers);
|
|
299
302
|
const normalizedDeviceIdentifier = this.normalizeString(deviceIdentifier);
|
|
@@ -319,7 +322,7 @@ class bridgeClass {
|
|
|
319
322
|
// offline
|
|
320
323
|
const offline = {
|
|
321
324
|
topic: `${this.bridgeMqttClient.BridgePrefix}${normalizedDeviceIdentifier}/${this.Words.notification}_${this.Words.offline}${this.EndingState}`.toLowerCase(),
|
|
322
|
-
notificationId: `${changeInfo.objectStartDirectory}${this.NotificationId}${this.OfflineId}`,
|
|
325
|
+
notificationId: `${this.adapter.namespace}.${changeInfo.objectStartDirectory}${this.NotificationId}${this.OfflineId}`,
|
|
323
326
|
};
|
|
324
327
|
discoveryobject = this.getNotificationDiscoveryObject(deviceIdentifier, this.Words.offline);
|
|
325
328
|
this.Notifications[offline.notificationId] = {};
|
|
@@ -339,7 +342,7 @@ class bridgeClass {
|
|
|
339
342
|
// online
|
|
340
343
|
const online = {
|
|
341
344
|
topic: `${this.bridgeMqttClient.BridgePrefix}${normalizedDeviceIdentifier}/${this.Words.notification}_${this.Words.online}${this.EndingState}`.toLowerCase(),
|
|
342
|
-
notificationId: `${changeInfo.objectStartDirectory}${this.NotificationId}${this.OnlineId}`,
|
|
345
|
+
notificationId: `${this.adapter.namespace}.${changeInfo.objectStartDirectory}${this.NotificationId}${this.OnlineId}`,
|
|
343
346
|
};
|
|
344
347
|
discoveryobject = this.getNotificationDiscoveryObject(deviceIdentifier, this.Words.online);
|
|
345
348
|
this.Notifications[online.notificationId] = {};
|
|
@@ -372,7 +375,7 @@ class bridgeClass {
|
|
|
372
375
|
const activeFunction = 'discoverGeneralNotification';
|
|
373
376
|
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
374
377
|
try {
|
|
375
|
-
const notificationId = `${this.Words.notification}${this.GeneralId}`;
|
|
378
|
+
const notificationId = `${this.adapter.namespace}.${this.Words.notification}${this.GeneralId}`;
|
|
376
379
|
if (!this.Notifications[notificationId]) {
|
|
377
380
|
const discoveryobject = this.getNotificationDiscoveryObject(this.adapter.namespace, this.Words.general);
|
|
378
381
|
this.Notifications[notificationId] = {};
|
|
@@ -638,12 +641,12 @@ class bridgeClass {
|
|
|
638
641
|
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
639
642
|
try {
|
|
640
643
|
const climateIds = { target: '', act: '', mode: '' };
|
|
641
|
-
climateIds.target = `${config.TargetApplication}.devices.${config.TargetDevice}.${config.TargetFolder}.${config.TargetState}`;
|
|
642
|
-
climateIds.act = `${config.ActApplication}.devices.${config.ActDevice}.${config.ActFolder}.${config.ActState}`;
|
|
644
|
+
climateIds.target = `${this.adapter.namespace}.${config.TargetApplication}.devices.${config.TargetDevice}.${config.TargetFolder}.${config.TargetState}`;
|
|
645
|
+
climateIds.act = `${this.adapter.namespace}.${config.ActApplication}.devices.${config.ActDevice}.${config.ActFolder}.${config.ActState}`;
|
|
643
646
|
if (config.ModeApplication === 'NotPresent') {
|
|
644
|
-
climateIds.mode = `${config.TargetApplication}.devices.${config.TargetDevice}.${config.TargetFolder}${this.EndingVirtualMode}`;
|
|
647
|
+
climateIds.mode = `${this.adapter.namespace}.${config.TargetApplication}.devices.${config.TargetDevice}.${config.TargetFolder}${this.EndingVirtualMode}`;
|
|
645
648
|
} else {
|
|
646
|
-
climateIds.mode = `${config.ModeApplication}.devices.${config.ModeDevice}.${config.ModeFolder}.${config.ModeState}`;
|
|
649
|
+
climateIds.mode = `${this.adapter.namespace}.${config.ModeApplication}.devices.${config.ModeDevice}.${config.ModeFolder}.${config.ModeState}`;
|
|
647
650
|
}
|
|
648
651
|
for (const id of Object.values(climateIds)) {
|
|
649
652
|
if (!(await this.adapter.objectExists(id)) && !id.endsWith(this.EndingVirtualMode)) {
|
|
@@ -724,7 +727,7 @@ class bridgeClass {
|
|
|
724
727
|
val = State.val;
|
|
725
728
|
}
|
|
726
729
|
}
|
|
727
|
-
// safe old values (
|
|
730
|
+
// safe old values (5 last values)
|
|
728
731
|
if (this.PublishedIds[id].values) {
|
|
729
732
|
if (!this.PublishedIds[id].oldValues) {
|
|
730
733
|
this.PublishedIds[id].oldValues = [];
|
|
@@ -786,7 +789,7 @@ class bridgeClass {
|
|
|
786
789
|
(changeInfo.applicationId === config.Application || config.Application === '*') &&
|
|
787
790
|
(changeInfo.deviceEUI === config.Device || config.Device === '*') &&
|
|
788
791
|
(id.includes(`.${config.Folder}.`) || config.Folder === '*') &&
|
|
789
|
-
(id.endsWith(
|
|
792
|
+
(id.endsWith(`.decoded.${config.State}`) || config.State === '*')
|
|
790
793
|
) {
|
|
791
794
|
Bridgestate.discover = !config.exclude;
|
|
792
795
|
Bridgestate.publish = config.publish;
|
|
@@ -852,7 +855,7 @@ class bridgeClass {
|
|
|
852
855
|
(changeInfo.applicationId === config.Application || config.Application === '*') &&
|
|
853
856
|
(changeInfo.deviceEUI === config.Device || config.Device === '*') &&
|
|
854
857
|
(id.includes(`.${config.Folder}.`) || config.Folder === '*') &&
|
|
855
|
-
(id.endsWith(
|
|
858
|
+
(id.endsWith(`.control.${config.State}`) || config.State === '*')
|
|
856
859
|
) {
|
|
857
860
|
Bridgestate.discover = !config.exclude;
|
|
858
861
|
Bridgestate.publish = config.publish;
|
|
@@ -1390,6 +1393,7 @@ class bridgeClass {
|
|
|
1390
1393
|
}
|
|
1391
1394
|
await this.discoverClimate();
|
|
1392
1395
|
await this.discoverGeneralNotification();
|
|
1396
|
+
await this.getForeignStatesForStandardEntities();
|
|
1393
1397
|
} catch (error) {
|
|
1394
1398
|
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
1395
1399
|
}
|
|
@@ -1441,5 +1445,153 @@ class bridgeClass {
|
|
|
1441
1445
|
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
1442
1446
|
}
|
|
1443
1447
|
}
|
|
1448
|
+
|
|
1449
|
+
/*****************************************************************
|
|
1450
|
+
* *********************** Foreign functions *********************
|
|
1451
|
+
* **************************************************************/
|
|
1452
|
+
/**
|
|
1453
|
+
* get Foreign states for Bridge
|
|
1454
|
+
*/
|
|
1455
|
+
async getForeignStatesForStandardEntities() {
|
|
1456
|
+
const activeFunction = 'bridge.js - getForeignStatesForStandardEntities';
|
|
1457
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
1458
|
+
try {
|
|
1459
|
+
const functions = await this.adapter.getEnums('functions');
|
|
1460
|
+
if (functions['enum.functions']['enum.functions.bridge']) {
|
|
1461
|
+
for (const member of functions['enum.functions']['enum.functions.bridge'].common.members) {
|
|
1462
|
+
const params = {
|
|
1463
|
+
startkey: member,
|
|
1464
|
+
endkey: `${member}.\u9999`,
|
|
1465
|
+
};
|
|
1466
|
+
const states = await this.adapter.getObjectViewAsync('system', 'state', params);
|
|
1467
|
+
for (const state of states.rows) {
|
|
1468
|
+
const common = state.value.common;
|
|
1469
|
+
await this.discoverForeignStandardEntity(state.id, { common: common });
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
} catch (error) {
|
|
1474
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
/**
|
|
1479
|
+
* @param id id to discover foreign state
|
|
1480
|
+
* @param options options of foreign state
|
|
1481
|
+
*/
|
|
1482
|
+
async discoverForeignStandardEntity(id, options) {
|
|
1483
|
+
const activeFunction = 'bridge.js - discoverForeignStandardEntity';
|
|
1484
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
1485
|
+
try {
|
|
1486
|
+
const state = await this.adapter.getForeignStateAsync(id);
|
|
1487
|
+
const parentObject = await this.getParentObject(id);
|
|
1488
|
+
let partentId = '';
|
|
1489
|
+
let parentName = '';
|
|
1490
|
+
if (typeof parentObject === 'object') {
|
|
1491
|
+
partentId = parentObject._id;
|
|
1492
|
+
parentName = parentObject.common.name;
|
|
1493
|
+
} else {
|
|
1494
|
+
partentId = parentObject;
|
|
1495
|
+
parentName = partentId;
|
|
1496
|
+
}
|
|
1497
|
+
const deviceIdentifier = parentName;
|
|
1498
|
+
const statename = id.substring(partentId.length + 1, id.length);
|
|
1499
|
+
options.Bridgestate = {
|
|
1500
|
+
publish: options.common.read,
|
|
1501
|
+
subscribe: options.common.write,
|
|
1502
|
+
};
|
|
1503
|
+
const normalizedStateName = this.normalizeString(statename);
|
|
1504
|
+
const normalizedDeviceIdentifier = this.normalizeString(deviceIdentifier);
|
|
1505
|
+
const topic =
|
|
1506
|
+
`${this.bridgeMqttClient.BridgePrefix}${normalizedDeviceIdentifier}/${normalizedStateName}`.toLowerCase();
|
|
1507
|
+
const EntityType = await this.getEntityType(options);
|
|
1508
|
+
const AdditionalAttributes = await this.getStateAttributes(options.common, EntityType);
|
|
1509
|
+
const discoveryTopic =
|
|
1510
|
+
`${this.BridgeDiscoveryPrefix[this.adapter.config.BridgeType]}${EntityType}/${normalizedDeviceIdentifier}/${normalizedStateName}/config`.toLowerCase();
|
|
1511
|
+
const discoveryPayload = {
|
|
1512
|
+
name: statename,
|
|
1513
|
+
unique_id: `${normalizedDeviceIdentifier}_${normalizedStateName}`.toLowerCase(),
|
|
1514
|
+
device: { identifiers: [normalizedDeviceIdentifier.toLowerCase()], name: deviceIdentifier },
|
|
1515
|
+
};
|
|
1516
|
+
// Add Topics
|
|
1517
|
+
if (options.Bridgestate.publish) {
|
|
1518
|
+
discoveryPayload.state_topic = `${topic}${this.EndingState}`;
|
|
1519
|
+
}
|
|
1520
|
+
if (options.Bridgestate.subscribe) {
|
|
1521
|
+
discoveryPayload.command_topic = `${topic}${this.EndingSet}`;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
// Assign Attibute to Payload
|
|
1525
|
+
for (const Attribute in AdditionalAttributes) {
|
|
1526
|
+
discoveryPayload[Attribute] = AdditionalAttributes[Attribute];
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
if (options.Bridgestate.publish) {
|
|
1530
|
+
if (!this.PublishedIds[id]) {
|
|
1531
|
+
this.PublishedIds[id] = { discovery: [] };
|
|
1532
|
+
}
|
|
1533
|
+
this.PublishedIds[id].discovery.push({
|
|
1534
|
+
topic: discoveryTopic,
|
|
1535
|
+
payload: structuredClone(discoveryPayload),
|
|
1536
|
+
});
|
|
1537
|
+
this.PublishedIds[id].state_topic = discoveryPayload.state_topic;
|
|
1538
|
+
}
|
|
1539
|
+
if (options.Bridgestate.subscribe) {
|
|
1540
|
+
if (!this.SubscribedTopics[discoveryPayload.command_topic]) {
|
|
1541
|
+
this.SubscribedTopics[discoveryPayload.command_topic] = { discovery: [] };
|
|
1542
|
+
}
|
|
1543
|
+
this.SubscribedTopics[discoveryPayload.command_topic].discovery.push({
|
|
1544
|
+
topic: discoveryTopic,
|
|
1545
|
+
payload: structuredClone(discoveryPayload),
|
|
1546
|
+
});
|
|
1547
|
+
this.SubscribedTopics[discoveryPayload.command_topic].id = id;
|
|
1548
|
+
}
|
|
1549
|
+
await this.publishDiscovery(id, {
|
|
1550
|
+
topic: discoveryTopic,
|
|
1551
|
+
payload: structuredClone(discoveryPayload),
|
|
1552
|
+
});
|
|
1553
|
+
// Delay for publish new entity
|
|
1554
|
+
setTimeout(async () => {
|
|
1555
|
+
await this.publishId(id, state.val, {});
|
|
1556
|
+
}, 1000);
|
|
1557
|
+
// Subscribe state for onStatechange mathode
|
|
1558
|
+
this.adapter.subscribeForeignStatesAsync(id);
|
|
1559
|
+
} catch (error) {
|
|
1560
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
/**
|
|
1565
|
+
* @param id id to get parent Object
|
|
1566
|
+
*/
|
|
1567
|
+
async getParentObject(id) {
|
|
1568
|
+
const activeFunction = 'bridge.js - getParentObject';
|
|
1569
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
1570
|
+
try {
|
|
1571
|
+
const firstIdexOfDot = id.indexOf('.');
|
|
1572
|
+
const lastIdexOfDot = id.lastIndexOf('.');
|
|
1573
|
+
if (lastIdexOfDot > firstIdexOfDot + 3) {
|
|
1574
|
+
id = id.substring(0, lastIdexOfDot);
|
|
1575
|
+
const firstObj = await this.adapter.getForeignObjectAsync(id);
|
|
1576
|
+
if (!firstObj) {
|
|
1577
|
+
return undefined;
|
|
1578
|
+
}
|
|
1579
|
+
if (firstObj?.type === 'device') {
|
|
1580
|
+
return firstObj;
|
|
1581
|
+
}
|
|
1582
|
+
if (firstObj.type === 'channel') {
|
|
1583
|
+
const secondObj = await this.getParentObject(id);
|
|
1584
|
+
if (secondObj !== undefined) {
|
|
1585
|
+
return secondObj;
|
|
1586
|
+
}
|
|
1587
|
+
return firstObj;
|
|
1588
|
+
}
|
|
1589
|
+
return await this.getParentObject(id);
|
|
1590
|
+
}
|
|
1591
|
+
return id.substring(0, lastIdexOfDot);
|
|
1592
|
+
} catch (error) {
|
|
1593
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1444
1596
|
}
|
|
1445
1597
|
module.exports = bridgeClass;
|
|
@@ -49,7 +49,7 @@ class bridgeMqttClientClass {
|
|
|
49
49
|
this.adapter.i18nTranslation['connection to bridge is activ'],
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
|
-
const notificationId = `${this.adapter.bridge.Words.notification}${this.adapter.bridge.GeneralId}`;
|
|
52
|
+
const notificationId = `${this.adapter.namespace}.${this.adapter.bridge.Words.notification}${this.adapter.bridge.GeneralId}`;
|
|
53
53
|
await this.adapter.bridge?.publishNotification(
|
|
54
54
|
notificationId,
|
|
55
55
|
this.adapter.i18nTranslation['connection to bridge is activ'],
|
|
@@ -302,14 +302,14 @@ class directorieshandlerClass {
|
|
|
302
302
|
'Lorawan device back online',
|
|
303
303
|
message,
|
|
304
304
|
);
|
|
305
|
-
let notificationId = `${changeInfo.applicationId}.devices.${changeInfo.deviceEUI}${this.adapter.bridge.NotificationId}${this.adapter.bridge.OnlineId}`;
|
|
305
|
+
let notificationId = `${this.adapter.namespace}.${changeInfo.applicationId}.devices.${changeInfo.deviceEUI}${this.adapter.bridge.NotificationId}${this.adapter.bridge.OnlineId}`;
|
|
306
306
|
await this.adapter.bridge?.publishNotification(
|
|
307
307
|
notificationId,
|
|
308
308
|
message,
|
|
309
309
|
this.adapter.bridge?.Notificationlevel.deviceState,
|
|
310
310
|
true,
|
|
311
311
|
);
|
|
312
|
-
notificationId = `${this.adapter.bridge.Words.notification}${this.adapter.bridge.GeneralId}`;
|
|
312
|
+
notificationId = `${this.adapter.namespace}.${this.adapter.bridge.Words.notification}${this.adapter.bridge.GeneralId}`;
|
|
313
313
|
await this.adapter.bridge?.publishNotification(
|
|
314
314
|
notificationId,
|
|
315
315
|
message,
|
|
@@ -84,14 +84,14 @@ class messagehandlerClass {
|
|
|
84
84
|
this.adapter.registerNotification('lorawan', 'LoRaWAN device offline', message);
|
|
85
85
|
|
|
86
86
|
// Notification to bridge
|
|
87
|
-
let notificationId = `${changeInfo.applicationId}.devices.${changeInfo.deviceEUI}${this.adapter.bridge.NotificationId}${this.adapter.bridge.OfflineId}`;
|
|
87
|
+
let notificationId = `${this.adapter.namespace}.${changeInfo.applicationId}.devices.${changeInfo.deviceEUI}${this.adapter.bridge.NotificationId}${this.adapter.bridge.OfflineId}`;
|
|
88
88
|
await this.adapter.bridge?.publishNotification(
|
|
89
89
|
notificationId,
|
|
90
90
|
message,
|
|
91
91
|
this.adapter.bridge?.Notificationlevel.deviceState,
|
|
92
92
|
true,
|
|
93
93
|
);
|
|
94
|
-
notificationId = `${this.adapter.bridge.Words.notification}${this.adapter.bridge.GeneralId}`;
|
|
94
|
+
notificationId = `${this.adapter.namespace}.${this.adapter.bridge.Words.notification}${this.adapter.bridge.GeneralId}`;
|
|
95
95
|
await this.adapter.bridge?.publishNotification(
|
|
96
96
|
notificationId,
|
|
97
97
|
message,
|
package/main.js
CHANGED
|
@@ -383,7 +383,7 @@ class Lorawan extends utils.Adapter {
|
|
|
383
383
|
async onUnload(callback) {
|
|
384
384
|
try {
|
|
385
385
|
// Ausgabe der Nachrichtg, dass der Adapter beendet wird
|
|
386
|
-
const notificationId = `${this.bridge?.Words.notification}${this.bridge?.GeneralId}`;
|
|
386
|
+
const notificationId = `${this.namespace}.${this.bridge?.Words.notification}${this.bridge?.GeneralId}`;
|
|
387
387
|
await this.bridge?.publishNotification(
|
|
388
388
|
notificationId,
|
|
389
389
|
this.i18nTranslation['Adapter will be stoped'],
|
|
@@ -448,118 +448,151 @@ class Lorawan extends utils.Adapter {
|
|
|
448
448
|
);
|
|
449
449
|
}
|
|
450
450
|
if (!state.ack) {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
try {
|
|
459
|
-
if (JSON.parse(state.val)) {
|
|
460
|
-
await this.sendDownlink(downlinkTopic, state.val, changeInfo);
|
|
461
|
-
await this.bridge?.publishId(this.removeNamespace(id), state.val, {});
|
|
462
|
-
await this.setState(id, state.val, true);
|
|
463
|
-
}
|
|
464
|
-
} catch (error) {
|
|
465
|
-
this.log.warn(`Cant send invalid downlinks. Error: ${error}`);
|
|
466
|
-
}
|
|
467
|
-
} else if (changeInfo?.changedState === 'CustomSend') {
|
|
468
|
-
if (state.val !== '') {
|
|
451
|
+
if (id.startsWith(this.namespace)) {
|
|
452
|
+
// Check for downlink in id
|
|
453
|
+
if (id.indexOf('.downlink.control.') !== -1) {
|
|
454
|
+
// get information of the changing state
|
|
455
|
+
const changeInfo = await this.getChangeInfo(id, { withBestMatch: true });
|
|
456
|
+
const suffix = this.downlinkConfighandler?.getDownlinkTopicSuffix(changeInfo?.changedState);
|
|
457
|
+
if (changeInfo?.changedState === 'push' || changeInfo?.changedState === 'replace') {
|
|
469
458
|
const downlinkTopic = this.downlinkConfighandler?.getDownlinkTopic(changeInfo, suffix);
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
changeInfo
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
Confirmed: Statevalues[2]
|
|
479
|
-
? Statevalues[2] === 'true'
|
|
480
|
-
? true
|
|
481
|
-
: false
|
|
482
|
-
: downlinkConfig.confirmed,
|
|
483
|
-
Priority: Statevalues[3] ? Statevalues[3] : downlinkConfig.priority,
|
|
484
|
-
};
|
|
485
|
-
// Query for righte type
|
|
486
|
-
this.log.debug('The following values are detected at input of custom send state');
|
|
487
|
-
for (const element of Object.values(StateElements)) {
|
|
488
|
-
this.log.debug(typeof element);
|
|
489
|
-
this.log.debug(element);
|
|
459
|
+
try {
|
|
460
|
+
if (JSON.parse(state.val)) {
|
|
461
|
+
await this.sendDownlink(downlinkTopic, state.val, changeInfo);
|
|
462
|
+
await this.bridge?.publishId(id, state.val, {});
|
|
463
|
+
await this.setState(id, state.val, true);
|
|
464
|
+
}
|
|
465
|
+
} catch (error) {
|
|
466
|
+
this.log.warn(`Cant send invalid downlinks. Error: ${error}`);
|
|
490
467
|
}
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
!changeInfo?.bestMatchForDeviceType ||
|
|
495
|
-
this.downlinkConfighandler?.activeDownlinkConfigs[changeInfo.bestMatchForDeviceType]
|
|
496
|
-
.sendWithUplink === 'disabled'
|
|
497
|
-
) {
|
|
498
|
-
const downlink = this.downlinkConfighandler?.getDownlink(
|
|
499
|
-
{
|
|
500
|
-
port: StateElements.Port,
|
|
501
|
-
confirmed: StateElements.Confirmed,
|
|
502
|
-
priority: StateElements.Priority,
|
|
503
|
-
},
|
|
504
|
-
StateElements.PayloadInHex,
|
|
468
|
+
} else if (changeInfo?.changedState === 'CustomSend') {
|
|
469
|
+
if (state.val !== '') {
|
|
470
|
+
const downlinkTopic = this.downlinkConfighandler?.getDownlinkTopic(
|
|
505
471
|
changeInfo,
|
|
472
|
+
suffix,
|
|
506
473
|
);
|
|
507
|
-
|
|
508
|
-
|
|
474
|
+
const downlinkConfig =
|
|
475
|
+
this.downlinkConfighandler?.activeDownlinkConfigs[
|
|
476
|
+
changeInfo.bestMatchForDeviceType
|
|
477
|
+
];
|
|
478
|
+
const Statevalues = state.val.split(',');
|
|
479
|
+
const StateElements = {
|
|
480
|
+
PayloadInHex: Statevalues[0].toUpperCase(),
|
|
481
|
+
Port: Statevalues[1] ? parseInt(Statevalues[1]) : downlinkConfig.port,
|
|
482
|
+
Confirmed: Statevalues[2]
|
|
483
|
+
? Statevalues[2] === 'true'
|
|
484
|
+
? true
|
|
485
|
+
: false
|
|
486
|
+
: downlinkConfig.confirmed,
|
|
487
|
+
Priority: Statevalues[3] ? Statevalues[3] : downlinkConfig.priority,
|
|
488
|
+
};
|
|
489
|
+
// Query for righte type
|
|
490
|
+
this.log.debug('The following values are detected at input of custom send state');
|
|
491
|
+
for (const element of Object.values(StateElements)) {
|
|
492
|
+
this.log.debug(typeof element);
|
|
493
|
+
this.log.debug(element);
|
|
494
|
+
}
|
|
495
|
+
// Write into nextSend
|
|
496
|
+
await this.writeNextSend(changeInfo, StateElements.PayloadInHex);
|
|
497
|
+
if (
|
|
498
|
+
!changeInfo?.bestMatchForDeviceType ||
|
|
499
|
+
this.downlinkConfighandler?.activeDownlinkConfigs[
|
|
500
|
+
changeInfo.bestMatchForDeviceType
|
|
501
|
+
].sendWithUplink === 'disabled'
|
|
502
|
+
) {
|
|
503
|
+
const downlink = this.downlinkConfighandler?.getDownlink(
|
|
504
|
+
{
|
|
505
|
+
port: StateElements.Port,
|
|
506
|
+
confirmed: StateElements.Confirmed,
|
|
507
|
+
priority: StateElements.Priority,
|
|
508
|
+
},
|
|
509
|
+
StateElements.PayloadInHex,
|
|
510
|
+
changeInfo,
|
|
511
|
+
);
|
|
512
|
+
if (downlink !== undefined) {
|
|
513
|
+
await this.sendDownlink(
|
|
514
|
+
downlinkTopic,
|
|
515
|
+
JSON.stringify(downlink),
|
|
516
|
+
changeInfo,
|
|
517
|
+
);
|
|
518
|
+
}
|
|
509
519
|
}
|
|
510
520
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
const payloadInHex = this.downlinkConfighandler?.calculatePayloadInHex(
|
|
519
|
-
downlinkParameter,
|
|
520
|
-
state,
|
|
521
|
+
await this.bridge?.publishId(id, state.val, {});
|
|
522
|
+
await this.setState(id, state.val, true);
|
|
523
|
+
} else {
|
|
524
|
+
const downlinkTopic = this.downlinkConfighandler?.getDownlinkTopic(changeInfo, suffix);
|
|
525
|
+
const downlinkParameter = this.downlinkConfighandler?.getDownlinkParameter(
|
|
526
|
+
changeInfo,
|
|
527
|
+
{},
|
|
521
528
|
);
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
!changeInfo?.bestMatchForDeviceType ||
|
|
525
|
-
this.downlinkConfighandler?.activeDownlinkConfigs[changeInfo.bestMatchForDeviceType]
|
|
526
|
-
.sendWithUplink === 'disabled'
|
|
527
|
-
) {
|
|
528
|
-
const downlink = this.downlinkConfighandler?.getDownlink(
|
|
529
|
+
if (downlinkParameter !== undefined) {
|
|
530
|
+
const payloadInHex = this.downlinkConfighandler?.calculatePayloadInHex(
|
|
529
531
|
downlinkParameter,
|
|
530
|
-
|
|
531
|
-
changeInfo,
|
|
532
|
+
state,
|
|
532
533
|
);
|
|
533
|
-
|
|
534
|
-
|
|
534
|
+
await this.writeNextSend(changeInfo, payloadInHex);
|
|
535
|
+
if (
|
|
536
|
+
!changeInfo?.bestMatchForDeviceType ||
|
|
537
|
+
this.downlinkConfighandler?.activeDownlinkConfigs[
|
|
538
|
+
changeInfo.bestMatchForDeviceType
|
|
539
|
+
].sendWithUplink === 'disabled'
|
|
540
|
+
) {
|
|
541
|
+
const downlink = this.downlinkConfighandler?.getDownlink(
|
|
542
|
+
downlinkParameter,
|
|
543
|
+
payloadInHex,
|
|
544
|
+
changeInfo,
|
|
545
|
+
);
|
|
546
|
+
if (downlink !== undefined) {
|
|
547
|
+
await this.sendDownlink(
|
|
548
|
+
downlinkTopic,
|
|
549
|
+
JSON.stringify(downlink),
|
|
550
|
+
changeInfo,
|
|
551
|
+
);
|
|
552
|
+
}
|
|
535
553
|
}
|
|
554
|
+
await this.bridge?.publishId(id, state.val, {});
|
|
555
|
+
await this.setState(id, state.val, true);
|
|
536
556
|
}
|
|
537
|
-
await this.bridge?.publishId(this.removeNamespace(id), state.val, {});
|
|
538
|
-
await this.setState(id, state.val, true);
|
|
539
557
|
}
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
this.messagehandler?.fillWithDownlinkConfig(changeInfo?.objectStartDirectory, {});
|
|
558
|
+
} else if (id.indexOf('.configuration.') !== -1) {
|
|
559
|
+
// State is from configuration path
|
|
560
|
+
const changeInfo = await this.getChangeInfo(id, { withBestMatch: true });
|
|
561
|
+
this.messagehandler?.fillWithDownlinkConfig(changeInfo?.objectStartDirectory, {});
|
|
545
562
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
563
|
+
// remove not configed states
|
|
564
|
+
const adapterObjects = await this.getAdapterObjectsAsync();
|
|
565
|
+
for (const adapterObject of Object.values(adapterObjects)) {
|
|
566
|
+
if (
|
|
567
|
+
adapterObject.type === 'state' &&
|
|
568
|
+
adapterObject._id.indexOf(
|
|
569
|
+
`${changeInfo?.objectStartDirectory}.downlink.control`,
|
|
570
|
+
) !== -1
|
|
571
|
+
) {
|
|
572
|
+
const changeInfo = await this.getChangeInfo(adapterObject._id);
|
|
573
|
+
const downlinkParameter = this.downlinkConfighandler?.getDownlinkParameter(
|
|
574
|
+
changeInfo,
|
|
575
|
+
{
|
|
576
|
+
startupCheck: true,
|
|
577
|
+
},
|
|
578
|
+
);
|
|
579
|
+
if (!downlinkParameter) {
|
|
580
|
+
await this.delObjectAsync(this.removeNamespace(adapterObject._id));
|
|
581
|
+
}
|
|
559
582
|
}
|
|
560
583
|
}
|
|
584
|
+
await this.setState(id, state.val, true);
|
|
585
|
+
}
|
|
586
|
+
} else {
|
|
587
|
+
// Query for 0_userdata or alias => states also publish with ack = false
|
|
588
|
+
if (id.startsWith('0_userdata') || id.startsWith('alias')) {
|
|
589
|
+
await this.bridge?.publishId(id, state.val, {});
|
|
561
590
|
}
|
|
562
|
-
|
|
591
|
+
}
|
|
592
|
+
} else {
|
|
593
|
+
// Query for Namespace => Just publish foreign States with ack = true
|
|
594
|
+
if (!id.startsWith(this.namespace)) {
|
|
595
|
+
await this.bridge?.publishId(id, state.val, {});
|
|
563
596
|
}
|
|
564
597
|
}
|
|
565
598
|
} else {
|