iobroker.lorawan 1.18.62 → 1.19.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 +7 -0
- package/admin/jsonConfig.json +1 -2
- package/io-package.json +27 -27
- package/lib/modules/bridge.js +59 -53
- package/lib/modules/bridgeDeviceHandler.js +373 -0
- package/main.js +3 -18
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,13 @@ 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.19.0 (2026-01-03)
|
|
27
|
+
* (BenAhrdt) remove Bridgetype Smarthome
|
|
28
|
+
* (BenAhrdt) add firt possibility to generate devices from Bridge to Iob
|
|
29
|
+
|
|
30
|
+
### 1.18.63 (2026-01-01)
|
|
31
|
+
* (BenAhrdt) return to await calls in checkAll (bridge)
|
|
32
|
+
|
|
26
33
|
### 1.18.62 (2026-01-01)
|
|
27
34
|
* (BenAhrdt) Promise the foreign functions in Promise.all
|
|
28
35
|
|
package/admin/jsonConfig.json
CHANGED
|
@@ -751,8 +751,7 @@
|
|
|
751
751
|
"tooltip": "BridgeTypeTooltip",
|
|
752
752
|
"options": [
|
|
753
753
|
{"label":"BridgeTypeOff","value":"off"},
|
|
754
|
-
{"label":"BridgeTypeHA","value":"HA"}
|
|
755
|
-
{"label":"BridgeTypeSH","value":"SH"}
|
|
754
|
+
{"label":"BridgeTypeHA","value":"HA"}
|
|
756
755
|
],
|
|
757
756
|
"default": "off",
|
|
758
757
|
"xs": 12,
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "lorawan",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.19.0",
|
|
5
5
|
"news": {
|
|
6
|
+
"1.19.0": {
|
|
7
|
+
"en": "remove Bridgetype Smarthome\nadd firt possibility to generate devices from Bridge to Iob",
|
|
8
|
+
"de": "bridgetype Smarthome entfernen\nfügen Sie firt Möglichkeit, Geräte von Bridge zu Iob zu generieren",
|
|
9
|
+
"ru": "скачать Bridgetype Smarthome\nдобавьте возможность создания устройств от Bridge до Iob",
|
|
10
|
+
"pt": "remover o tipo de ponte Smarthome\nadicionar a possibilidade inicial de gerar dispositivos de Bridge para Iob",
|
|
11
|
+
"nl": "verwijderen Bridgetype Smarthome\nfirt mogelijkheid toevoegen om apparaten van brug aan Iob te genereren",
|
|
12
|
+
"fr": "supprimer Bridgetype Smarthome\najouter la possibilité de firt pour générer des appareils de Bridge à Iob",
|
|
13
|
+
"it": "rimuovere Bridgetype Smarthome\naggiungere firt possibilità di generare dispositivi da Bridge a Iob",
|
|
14
|
+
"es": "eliminar Bridgetype Smarthome\nañadir firt posibilidad de generar dispositivos desde Bridge a Iob",
|
|
15
|
+
"pl": "usuń Bridgetype Smarthome\ndodać firt możliwość generowania urządzeń z Bridge do Iob",
|
|
16
|
+
"uk": "видалити Bridgetype Smarthome\nдо Iob",
|
|
17
|
+
"zh-cn": "删除桥型 Smarthome\n从 Bridge 添加 firt 生成设备的可能性"
|
|
18
|
+
},
|
|
19
|
+
"1.18.63": {
|
|
20
|
+
"en": "return to await calls in checkAll (bridge)",
|
|
21
|
+
"de": "zurück zu warten Anrufe im Check Alle (Brücke)",
|
|
22
|
+
"ru": "возвращение в ожидании звонков в чек Все (мост)",
|
|
23
|
+
"pt": "retornar para aguardar chamadas em cheque Todos (ponte)",
|
|
24
|
+
"nl": "terug te keren naar wachten gesprekken in check Alle (brug)",
|
|
25
|
+
"fr": "retour à attendre les appels en contrôle Tous (pont)",
|
|
26
|
+
"it": "ritorno in attesa chiamate in controllo Tutti (ponte)",
|
|
27
|
+
"es": "volver a esperar llamadas en cheque Todo (puente)",
|
|
28
|
+
"pl": "powrót czekać rozmowy w czeku Wszystkie (most)",
|
|
29
|
+
"uk": "поверніть на чек дзвінків Всі (місто)",
|
|
30
|
+
"zh-cn": "返回等待呼叫检查 全部(桥梁)"
|
|
31
|
+
},
|
|
6
32
|
"1.18.62": {
|
|
7
33
|
"en": "Promise the foreign functions in Promise.all",
|
|
8
34
|
"de": "Versprechen Sie die ausländischen Funktionen in Promise.all",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "serializuj i buforuj wiadomości konfiguracyjne",
|
|
68
94
|
"uk": "послідовність і кешування конфігураційних повідомлень",
|
|
69
95
|
"zh-cn": "序列化和缓存配置信件"
|
|
70
|
-
},
|
|
71
|
-
"1.18.57": {
|
|
72
|
-
"en": "cache Infos in config for more performance",
|
|
73
|
-
"de": "cache Infos in config für mehr Leistung",
|
|
74
|
-
"ru": "cache Infos in Config для повышения производительности",
|
|
75
|
-
"pt": "informações de cache em configuração para mais desempenho",
|
|
76
|
-
"nl": "cache-informatie in configuratie voor meer prestaties",
|
|
77
|
-
"fr": "cache Infos en configuration pour plus de performances",
|
|
78
|
-
"it": "cache Infos in config per maggiori prestazioni",
|
|
79
|
-
"es": "cache Infos en config para más rendimiento",
|
|
80
|
-
"pl": "cache Infos w konfiguracji dla większej wydajności",
|
|
81
|
-
"uk": "cache Infos в конфігурації для більшої продуктивності",
|
|
82
|
-
"zh-cn": "为更多性能在配置中缓存信息"
|
|
83
|
-
},
|
|
84
|
-
"1.18.56": {
|
|
85
|
-
"en": "remoove namespace twice remooved\nserialize getConfigStates",
|
|
86
|
-
"de": "remoove namespace zweimal remooved\nserialisieren getConfigStates",
|
|
87
|
-
"ru": "remoove namespace дважды удаляется\nсерийный GetConfigStates",
|
|
88
|
-
"pt": "remoove namespace duas vezes remooved\nserialize getConfigStates",
|
|
89
|
-
"nl": "naamruimte twee keer verplaatsen\nserialiseren getConfigStates",
|
|
90
|
-
"fr": "remove namespace deux fois removed\nsérialiser getConfigStates",
|
|
91
|
-
"it": "rimoove namespace due volte rimuovi\nserializzare ottenereConfigStates",
|
|
92
|
-
"es": "remoove namespace dos remooved\nserialize getConfigStates",
|
|
93
|
-
"pl": "remoove namespace two remooved\nserialize getConfigurations",
|
|
94
|
-
"uk": "remoove namespace двічі remooved\nсертифіковано getConfigStates",
|
|
95
|
-
"zh-cn": "两次重新移动命名空间\n序列化获取配置状态"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
package/lib/modules/bridge.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const bridgeMqttClientClass = require('./bridgeMqttclient');
|
|
2
|
+
const bridgeDeviceHandlerClass = require('./bridgeDeviceHandler');
|
|
2
3
|
const schedule = require('node-schedule');
|
|
3
4
|
/*
|
|
4
5
|
Also er published irgendwie nicht den Mode => und es kommt virtual_Mode nicht subcribed....
|
|
@@ -18,6 +19,7 @@ class bridgeClass {
|
|
|
18
19
|
* ******************************************************************/
|
|
19
20
|
|
|
20
21
|
this.bridgeMqttClient = new bridgeMqttClientClass(this.adapter, this.adapter.config);
|
|
22
|
+
this.bridgeDeviceHandler = new bridgeDeviceHandlerClass(this.adapter);
|
|
21
23
|
|
|
22
24
|
// Structure of actual vaulues in Bridge (till las start of Adapter)
|
|
23
25
|
this.CheckedIds = {};
|
|
@@ -29,7 +31,6 @@ class bridgeClass {
|
|
|
29
31
|
this.Notifications = {};
|
|
30
32
|
this.BridgeDiscoveryPrefix = {
|
|
31
33
|
HA: 'homeassistant/',
|
|
32
|
-
SH: 'smarthome/',
|
|
33
34
|
};
|
|
34
35
|
this.ForeignBridgeMembers = {};
|
|
35
36
|
this.MinTime = 100; // ms between publish and subscribe same value
|
|
@@ -289,6 +290,9 @@ class bridgeClass {
|
|
|
289
290
|
// Special DataExchange
|
|
290
291
|
if (this.SubscribedTopics[topic].dataExchange) {
|
|
291
292
|
if (typeof message === 'object') {
|
|
293
|
+
// Call the BridgeDeviceHandler
|
|
294
|
+
await this.bridgeDeviceHandler.generateDeviceStructure(message);
|
|
295
|
+
// Stringify for set State
|
|
292
296
|
message = JSON.stringify(message);
|
|
293
297
|
}
|
|
294
298
|
await this.adapter.setState(
|
|
@@ -1749,6 +1753,59 @@ class bridgeClass {
|
|
|
1749
1753
|
*
|
|
1750
1754
|
* @param options options to special functions
|
|
1751
1755
|
*/
|
|
1756
|
+
async checkAllStatesForBridgeWork(options) {
|
|
1757
|
+
const activeFunction = 'bridge.js - checkAllStatesForBridgeWork';
|
|
1758
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
1759
|
+
try {
|
|
1760
|
+
// get old Discovered ids
|
|
1761
|
+
this.OldDiscoveredIds = JSON.parse((await this.adapter.getStateAsync('info.discoveredIds')).val);
|
|
1762
|
+
this.oldDiscoveredDevices = this.generateOldDevices(this.OldDiscoveredIds);
|
|
1763
|
+
// Clear object of all subscribed Ids and published Topics
|
|
1764
|
+
this.SubscribedTopics = {};
|
|
1765
|
+
this.PublishedIds = {};
|
|
1766
|
+
this.Notifications = {};
|
|
1767
|
+
|
|
1768
|
+
//this.adapter.log.error(JSON.stringify(this.oldDiscoveredDevices));
|
|
1769
|
+
await this.discoverGeneralNotification();
|
|
1770
|
+
|
|
1771
|
+
await this.discoverDataExchange();
|
|
1772
|
+
|
|
1773
|
+
// Get all ids in adapterfolder
|
|
1774
|
+
// Generate Infos of all devices and decoded folders
|
|
1775
|
+
const adapterObjects = await this.adapter.getAdapterObjectsAsync();
|
|
1776
|
+
for (const adapterObject of Object.values(adapterObjects)) {
|
|
1777
|
+
if (
|
|
1778
|
+
adapterObject._id.includes(
|
|
1779
|
+
`${this.adapter.messagehandler.directoryhandler.reachableSubfolders.uplinkDecoded}.`,
|
|
1780
|
+
) ||
|
|
1781
|
+
adapterObject._id.includes(
|
|
1782
|
+
`${this.adapter.messagehandler.directoryhandler.reachableSubfolders.downlinkControl}.`,
|
|
1783
|
+
)
|
|
1784
|
+
) {
|
|
1785
|
+
if (adapterObject.type === 'state') {
|
|
1786
|
+
const localOptions = {
|
|
1787
|
+
...(options || {}),
|
|
1788
|
+
common: adapterObject.common,
|
|
1789
|
+
};
|
|
1790
|
+
|
|
1791
|
+
await this.work(adapterObject._id, undefined, localOptions);
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
await this.discoverClimate();
|
|
1796
|
+
await this.getForeignStatesForStandardEntities();
|
|
1797
|
+
await this.getForeignClimateConfig();
|
|
1798
|
+
await this.getForeignHumidifierConfig();
|
|
1799
|
+
await this.getForeignLightConfig();
|
|
1800
|
+
await this.getForeignCoverConfig();
|
|
1801
|
+
await this.getForeignLockConfig();
|
|
1802
|
+
await this.checkDiscoveries();
|
|
1803
|
+
} catch (error) {
|
|
1804
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
/*
|
|
1752
1809
|
async checkAllStatesForBridgeWork(options) {
|
|
1753
1810
|
const activeFunction = 'bridge.js - checkAllStatesForBridgeWork';
|
|
1754
1811
|
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
@@ -1819,59 +1876,8 @@ class bridgeClass {
|
|
|
1819
1876
|
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
1820
1877
|
}
|
|
1821
1878
|
}
|
|
1822
|
-
|
|
1823
|
-
/* Alte Version
|
|
1824
|
-
async checkAllStatesForBridgeWork(options) {
|
|
1825
|
-
const activeFunction = 'bridge.js - checkAllStatesForBridgeWork';
|
|
1826
|
-
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
1827
|
-
try {
|
|
1828
|
-
// get old Discovered ids
|
|
1829
|
-
this.OldDiscoveredIds = JSON.parse((await this.adapter.getStateAsync('info.discoveredIds')).val);
|
|
1830
|
-
this.oldDiscoveredDevices = this.generateOldDevices(this.OldDiscoveredIds);
|
|
1831
|
-
// Clear object of all subscribed Ids and published Topics
|
|
1832
|
-
this.SubscribedTopics = {};
|
|
1833
|
-
this.PublishedIds = {};
|
|
1834
|
-
this.Notifications = {};
|
|
1835
|
-
|
|
1836
|
-
//this.adapter.log.error(JSON.stringify(this.oldDiscoveredDevices));
|
|
1837
|
-
await this.discoverGeneralNotification();
|
|
1838
|
-
|
|
1839
|
-
await this.discoverDataExchange();
|
|
1840
|
-
|
|
1841
|
-
// Get all ids in adapterfolder
|
|
1842
|
-
// Generate Infos of all devices and decoded folders
|
|
1843
|
-
const adapterObjects = await this.adapter.getAdapterObjectsAsync();
|
|
1844
|
-
for (const adapterObject of Object.values(adapterObjects)) {
|
|
1845
|
-
if (
|
|
1846
|
-
adapterObject._id.includes(
|
|
1847
|
-
`${this.adapter.messagehandler.directoryhandler.reachableSubfolders.uplinkDecoded}.`,
|
|
1848
|
-
) ||
|
|
1849
|
-
adapterObject._id.includes(
|
|
1850
|
-
`${this.adapter.messagehandler.directoryhandler.reachableSubfolders.downlinkControl}.`,
|
|
1851
|
-
)
|
|
1852
|
-
) {
|
|
1853
|
-
if (adapterObject.type === 'state') {
|
|
1854
|
-
if (!options) {
|
|
1855
|
-
options = {};
|
|
1856
|
-
}
|
|
1857
|
-
options.common = adapterObject.common;
|
|
1858
|
-
await this.work(adapterObject._id, undefined, options);
|
|
1859
|
-
}
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
|
-
await this.discoverClimate();
|
|
1863
|
-
await this.getForeignStatesForStandardEntities();
|
|
1864
|
-
await this.getForeignClimateConfig();
|
|
1865
|
-
await this.getForeignHumidifierConfig();
|
|
1866
|
-
await this.getForeignLightConfig();
|
|
1867
|
-
await this.getForeignCoverConfig();
|
|
1868
|
-
await this.getForeignLockConfig();
|
|
1869
|
-
await this.checkDiscoveries();
|
|
1870
|
-
} catch (error) {
|
|
1871
|
-
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
1872
|
-
}
|
|
1873
|
-
}
|
|
1874
1879
|
*/
|
|
1880
|
+
|
|
1875
1881
|
/**
|
|
1876
1882
|
* @param oldDiscoveredIds Ids wiche are discovered last time that Adapter runs
|
|
1877
1883
|
*/
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* class to handle incomming messages from Bridge
|
|
3
|
+
*/
|
|
4
|
+
class bridgeDeviceHandlerClass {
|
|
5
|
+
/**
|
|
6
|
+
* @param adapter data of the adapter (eg. for logging)
|
|
7
|
+
*/
|
|
8
|
+
constructor(adapter) {
|
|
9
|
+
this.adapter = adapter;
|
|
10
|
+
this.basefolder = 'bridge.devices';
|
|
11
|
+
this.adapter.extendObject(this.basefolder, {
|
|
12
|
+
type: 'folder',
|
|
13
|
+
common: { name: 'Devices recieved from Bridge' },
|
|
14
|
+
native: {},
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Generate Structure of incomming Data
|
|
19
|
+
/**
|
|
20
|
+
* @param message message from bridge to generate devices (eg.)
|
|
21
|
+
*/
|
|
22
|
+
async generateDeviceStructure(message) {
|
|
23
|
+
const activeFunction = 'bridgeDeviceHandler.js - generateDeviceStructure';
|
|
24
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
25
|
+
try {
|
|
26
|
+
// Query for Entity
|
|
27
|
+
if (message.entities) {
|
|
28
|
+
for (const entity of Object.values(message.entities)) {
|
|
29
|
+
const entityInfo = this.generateStructure(entity);
|
|
30
|
+
await this.adapter.extendObject(entityInfo?.device.id, {
|
|
31
|
+
type: 'device',
|
|
32
|
+
common: { name: entity.device.name },
|
|
33
|
+
native: entity.device,
|
|
34
|
+
});
|
|
35
|
+
const channel = entity.entity_id.substring(0, entity.entity_id.indexOf('.'));
|
|
36
|
+
await this.adapter.extendObject(entityInfo?.channel.id, {
|
|
37
|
+
type: 'channel',
|
|
38
|
+
common: { name: 'Channel of Entity' },
|
|
39
|
+
native: {},
|
|
40
|
+
});
|
|
41
|
+
let unique_id = entity.unique_id;
|
|
42
|
+
if (entity.unique_id.startsWith(channel)) {
|
|
43
|
+
unique_id = unique_id.substring(channel.length + 1, unique_id.length);
|
|
44
|
+
}
|
|
45
|
+
unique_id.replace('.', '_');
|
|
46
|
+
await this.adapter.extendObject(entityInfo?.state.id, {
|
|
47
|
+
type: 'state',
|
|
48
|
+
common: {
|
|
49
|
+
name: entityInfo?.state.name,
|
|
50
|
+
type: entityInfo?.state.type,
|
|
51
|
+
role: entityInfo?.state.role,
|
|
52
|
+
read: entityInfo?.state.read,
|
|
53
|
+
write: entityInfo?.state.write,
|
|
54
|
+
unit: entityInfo?.state.unit,
|
|
55
|
+
},
|
|
56
|
+
native: { entity: entity, entityInfo: entityInfo },
|
|
57
|
+
});
|
|
58
|
+
let state = entity.state;
|
|
59
|
+
if (entityInfo?.state.type === 'boolean') {
|
|
60
|
+
state = entity.state === 'on';
|
|
61
|
+
} else if (entityInfo?.state.type === 'number') {
|
|
62
|
+
state = Number(entity.state);
|
|
63
|
+
}
|
|
64
|
+
await this.adapter.setState(entityInfo?.state.id, state, true);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Periodic discovery
|
|
68
|
+
if (message.discovery) {
|
|
69
|
+
const id = `${this.basefolder}.discoveredEntities`;
|
|
70
|
+
await this.adapter.extendObject(id, {
|
|
71
|
+
type: 'state',
|
|
72
|
+
common: {
|
|
73
|
+
name: 'Discovered Entities',
|
|
74
|
+
type: 'string',
|
|
75
|
+
role: 'json',
|
|
76
|
+
read: true,
|
|
77
|
+
write: false,
|
|
78
|
+
def: '',
|
|
79
|
+
},
|
|
80
|
+
native: {},
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Read current data
|
|
84
|
+
const discoveredEntities = await this.adapter.getStateAsync(id);
|
|
85
|
+
const checkDevices = {};
|
|
86
|
+
if (discoveredEntities.val) {
|
|
87
|
+
const entities = JSON.parse(discoveredEntities.val);
|
|
88
|
+
for (const entityId of Object.keys(entities)) {
|
|
89
|
+
if (!Object.keys(message.entities).includes(entityId)) {
|
|
90
|
+
const entityInfo = this.generateStructure(entities[entityId]);
|
|
91
|
+
await this.adapter.delObjectAsync(entityInfo?.state.id);
|
|
92
|
+
checkDevices[entityInfo?.device.id] = {};
|
|
93
|
+
if (entityInfo?.channel.id) {
|
|
94
|
+
checkDevices[entityInfo?.device.id][entityInfo?.channel.id] = {};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Check for delete channels and devices
|
|
100
|
+
for (const deviceId of Object.keys(checkDevices)) {
|
|
101
|
+
let foundStateInAnyChannel = false;
|
|
102
|
+
|
|
103
|
+
// Check channel
|
|
104
|
+
for (const channelId of Object.keys(checkDevices[deviceId])) {
|
|
105
|
+
const channelParams = {
|
|
106
|
+
startkey: `${channelId}.`,
|
|
107
|
+
endkey: `${channelId}.\u9999`,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const channelStates = await this.adapter.getObjectViewAsync(
|
|
111
|
+
'system',
|
|
112
|
+
'state',
|
|
113
|
+
channelParams,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
if (channelStates.rows.length > 0) {
|
|
117
|
+
// State found
|
|
118
|
+
foundStateInAnyChannel = true;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// No state
|
|
123
|
+
await this.adapter.delObjectAsync(channelId, { recursive: true });
|
|
124
|
+
this.adapter.log.debug(`Deleted empty channel: ${channelId}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Check device
|
|
128
|
+
if (!foundStateInAnyChannel) {
|
|
129
|
+
const deviceParams = {
|
|
130
|
+
startkey: `${deviceId}.`,
|
|
131
|
+
endkey: `${deviceId}.\u9999`,
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const deviceStates = await this.adapter.getObjectViewAsync('system', 'state', deviceParams);
|
|
135
|
+
|
|
136
|
+
if (deviceStates.rows.length === 0) {
|
|
137
|
+
await this.adapter.delObjectAsync(deviceId, { recursive: true });
|
|
138
|
+
this.adapter.log.debug(`Deleted empty device: ${deviceId}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
await this.adapter.setState(id, JSON.stringify(message.entities), true);
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* @param entity entity wich contains the desired informations
|
|
152
|
+
*/
|
|
153
|
+
generateStructure(entity) {
|
|
154
|
+
const activeFunction = 'bridgeDeviceHandler.js - generateStructure';
|
|
155
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
156
|
+
try {
|
|
157
|
+
if (!entity || !entity.entity_id) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const [domain] = entity.entity_id.split('.');
|
|
162
|
+
|
|
163
|
+
const stateId = this.buildSafeStateId(entity);
|
|
164
|
+
if (!stateId) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
const type = this.detectType(entity);
|
|
168
|
+
const assign = this.detectAssign(entity);
|
|
169
|
+
|
|
170
|
+
const device = {
|
|
171
|
+
id: `${this.basefolder}.${entity.device?.id ?? 'unknown_device'}`,
|
|
172
|
+
name: entity.device?.name || 'Unknown Device',
|
|
173
|
+
manufacturer: entity.device?.manufacturer || '',
|
|
174
|
+
model: entity.device?.model || '',
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
const channel = {
|
|
178
|
+
id: `${this.basefolder}.${entity.device?.id}.${domain}`,
|
|
179
|
+
name: domain,
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const state = {
|
|
183
|
+
id: `${this.basefolder}.${entity.device?.id}.${domain}.${stateId}`,
|
|
184
|
+
name: entity.friendly_name || stateId,
|
|
185
|
+
type: type,
|
|
186
|
+
role: this.detectRole(entity, domain, type),
|
|
187
|
+
unit: entity.unit_of_measurement || undefined,
|
|
188
|
+
read: true,
|
|
189
|
+
write: this.isWritable(domain),
|
|
190
|
+
};
|
|
191
|
+
if (assign) {
|
|
192
|
+
state.assign = assign;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const meta = {
|
|
196
|
+
entity_id: entity.entity_id,
|
|
197
|
+
unique_id: entity.unique_id,
|
|
198
|
+
device_class: entity.device_class,
|
|
199
|
+
state_class: entity.state_class,
|
|
200
|
+
};
|
|
201
|
+
return {
|
|
202
|
+
device: device,
|
|
203
|
+
channel: channel,
|
|
204
|
+
state: state,
|
|
205
|
+
meta: meta,
|
|
206
|
+
};
|
|
207
|
+
} catch (error) {
|
|
208
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @param entity entity wich contains the deired informations
|
|
214
|
+
*/
|
|
215
|
+
detectType(entity) {
|
|
216
|
+
const activeFunction = 'bridgeDeviceHandler.js - detectType';
|
|
217
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
218
|
+
try {
|
|
219
|
+
const s = entity.state;
|
|
220
|
+
|
|
221
|
+
if (['on', 'off', 'true', 'false'].includes(s)) {
|
|
222
|
+
return 'boolean';
|
|
223
|
+
}
|
|
224
|
+
if (!isNaN(s) && s !== '') {
|
|
225
|
+
return 'number';
|
|
226
|
+
}
|
|
227
|
+
return 'string';
|
|
228
|
+
} catch (error) {
|
|
229
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* @param entity entity wich contains the deired informations
|
|
235
|
+
*/
|
|
236
|
+
detectAssign(entity) {
|
|
237
|
+
const activeFunction = 'bridgeDeviceHandler.js - detectAssign';
|
|
238
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
239
|
+
try {
|
|
240
|
+
const s = entity.state;
|
|
241
|
+
if (['on', 'off'].includes(s)) {
|
|
242
|
+
return { true: 'on', false: 'off' };
|
|
243
|
+
}
|
|
244
|
+
if (['true', 'false'].includes(s)) {
|
|
245
|
+
return { true: 'true', false: 'false' };
|
|
246
|
+
}
|
|
247
|
+
return null;
|
|
248
|
+
} catch (error) {
|
|
249
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* @param domain domain, wich contains the type of entity
|
|
255
|
+
*/
|
|
256
|
+
isWritable(domain) {
|
|
257
|
+
const activeFunction = 'bridgeDeviceHandler.js - isWritable';
|
|
258
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
259
|
+
try {
|
|
260
|
+
return [
|
|
261
|
+
'switch',
|
|
262
|
+
'light',
|
|
263
|
+
'input_boolean',
|
|
264
|
+
'input_number',
|
|
265
|
+
'input_select',
|
|
266
|
+
'climate',
|
|
267
|
+
'cover',
|
|
268
|
+
'lock',
|
|
269
|
+
].includes(domain);
|
|
270
|
+
} catch (error) {
|
|
271
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* @param entity entity wich contains the desired informations
|
|
277
|
+
* @param domain domain wich contains the type of the entity
|
|
278
|
+
* @param type type wich contains the type of ioBroker state
|
|
279
|
+
*/
|
|
280
|
+
detectRole(entity, domain, type) {
|
|
281
|
+
const activeFunction = 'bridgeDeviceHandler.js - detectRole';
|
|
282
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
283
|
+
try {
|
|
284
|
+
if (domain === 'switch') {
|
|
285
|
+
return 'switch';
|
|
286
|
+
}
|
|
287
|
+
if (domain === 'light') {
|
|
288
|
+
return 'light';
|
|
289
|
+
}
|
|
290
|
+
if (domain === 'binary_sensor') {
|
|
291
|
+
return 'indicator';
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (entity.device_class) {
|
|
295
|
+
const map = {
|
|
296
|
+
temperature: 'value.temperature',
|
|
297
|
+
humidity: 'value.humidity',
|
|
298
|
+
power: 'value.power',
|
|
299
|
+
energy: 'value.energy',
|
|
300
|
+
window: 'sensor.window',
|
|
301
|
+
door: 'sensor.door',
|
|
302
|
+
};
|
|
303
|
+
if (map[entity.device_class]) {
|
|
304
|
+
return map[entity.device_class];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (type === 'number') {
|
|
309
|
+
return 'value';
|
|
310
|
+
}
|
|
311
|
+
if (type === 'boolean') {
|
|
312
|
+
return 'indicator';
|
|
313
|
+
}
|
|
314
|
+
return 'state';
|
|
315
|
+
} catch (error) {
|
|
316
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* @param entity entity wich contains the deired informations
|
|
322
|
+
*/
|
|
323
|
+
buildSafeStateId(entity) {
|
|
324
|
+
const activeFunction = 'bridgeDeviceHandler.js - buildSafeStateId';
|
|
325
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
326
|
+
try {
|
|
327
|
+
// 1. Basis: unique_id oder entity_id
|
|
328
|
+
const baseId = entity.unique_id || entity.entity_id;
|
|
329
|
+
|
|
330
|
+
if (!baseId) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// if eg. switch in front => remove
|
|
335
|
+
const parts = baseId.split('.');
|
|
336
|
+
const raw =
|
|
337
|
+
parts.length > 1 && parts[0] === entity.entity_id?.split('.')[0] ? parts.slice(1).join('.') : baseId;
|
|
338
|
+
|
|
339
|
+
// 3. remove ".
|
|
340
|
+
return raw.replace(/\./g, '_');
|
|
341
|
+
} catch (error) {
|
|
342
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/************************************************************************************
|
|
347
|
+
*
|
|
348
|
+
************************************************************************************/
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* @param id id wich is to send
|
|
352
|
+
* @param state state of the id
|
|
353
|
+
*/
|
|
354
|
+
async sendData(id, state) {
|
|
355
|
+
const activeFunction = 'bridgeDeviceHandler.js - sendData';
|
|
356
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
357
|
+
try {
|
|
358
|
+
const idObject = await this.adapter.getObjectAsync(id);
|
|
359
|
+
const sendInfo = {};
|
|
360
|
+
if (idObject.native.entityInfo.state.assign) {
|
|
361
|
+
sendInfo[idObject.native.entity.entity_id] = idObject.native.entityInfo.state.assign[state.val];
|
|
362
|
+
} else {
|
|
363
|
+
sendInfo[idObject.native.entity.entity_id] = state.val;
|
|
364
|
+
}
|
|
365
|
+
await this.adapter.bridge.publishId(`${this.adapter.namespace}.bridge.dataFromIob`, sendInfo, {});
|
|
366
|
+
await this.adapter.setState(`${this.adapter.namespace}.bridge.dataFromIob`, JSON.stringify(sendInfo), true);
|
|
367
|
+
} catch (error) {
|
|
368
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
module.exports = bridgeDeviceHandlerClass;
|
package/main.js
CHANGED
|
@@ -846,24 +846,6 @@ class Lorawan extends utils.Adapter {
|
|
|
846
846
|
native: {},
|
|
847
847
|
});
|
|
848
848
|
await this.setState(id, '', true);
|
|
849
|
-
} else if (words[1] === 'chunk') {
|
|
850
|
-
this.extendObject('bridge.debug', {
|
|
851
|
-
type: 'folder',
|
|
852
|
-
common: { name: 'Debugfunctions of bridge' },
|
|
853
|
-
native: {},
|
|
854
|
-
});
|
|
855
|
-
this.extendObject('bridge.debug.chunk', {
|
|
856
|
-
type: 'state',
|
|
857
|
-
common: {
|
|
858
|
-
name: 'chunk of parallel works',
|
|
859
|
-
type: 'number',
|
|
860
|
-
read: true,
|
|
861
|
-
write: true,
|
|
862
|
-
def: 32,
|
|
863
|
-
},
|
|
864
|
-
native: {},
|
|
865
|
-
});
|
|
866
|
-
await this.setState(id, '', true);
|
|
867
849
|
}
|
|
868
850
|
} else {
|
|
869
851
|
let notificationId = `${this.namespace}.${this.bridge?.Words.notification}${this.bridge?.GeneralId}`;
|
|
@@ -894,6 +876,9 @@ class Lorawan extends utils.Adapter {
|
|
|
894
876
|
await this.setState(id, state.val, true);
|
|
895
877
|
await this.bridge.publishId(id, state.val, {});
|
|
896
878
|
}
|
|
879
|
+
} else if (id.startsWith(`${this.namespace}.bridge.devices.`)) {
|
|
880
|
+
await this.bridge?.bridgeDeviceHandler.sendData(id, state);
|
|
881
|
+
await this.setState(id, state.val, true);
|
|
897
882
|
}
|
|
898
883
|
} else {
|
|
899
884
|
// Query for 0_userdata or alias => states also publish with ack = false
|