iobroker.lorawan 1.13.3 → 1.13.5
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 +9 -0
- package/admin/i18n/de/translations.json +11 -3
- package/admin/i18n/en/translations.json +9 -1
- package/admin/jsonConfig.json +268 -1
- package/admin/jsonTab.json +69 -0
- package/io-package.json +39 -29
- package/lib/modules/bridge.js +280 -33
- package/lib/modules/bridgeMqttclient.js +11 -4
- package/lib/modules/deviceProfiles/Vicki.json +1 -1
- package/lib/modules/directorieshandler.js +1 -1
- package/lib/modules/messagehandler.js +8 -1
- package/main.js +69 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,15 @@ 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.13.5 (2025-09-06)
|
|
27
|
+
* (BenAhrdt) Show discovery topic(s) & messag(es) ind array
|
|
28
|
+
* (BenAhrdt) Add Tab to see Discovered, Published and Subscribed Ids.
|
|
29
|
+
* (BenAhrdt) Add Posibility to discover climate Entity
|
|
30
|
+
* (BenAhrdt) Retaining Discovery
|
|
31
|
+
|
|
32
|
+
### 1.13.4 (2025-09-04)
|
|
33
|
+
* (BenAhrdt) Bugfixing crc in Vicki Profile => ChildLock
|
|
34
|
+
|
|
26
35
|
### 1.13.3 (2025-09-04)
|
|
27
36
|
* (BenAhrdt) Add images to the new States
|
|
28
37
|
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"_NoLoRaWAN": "Der State ist nicht in der richtigen Lorawan - Instanz",
|
|
118
118
|
"publishTooltip": "Veröffentlichen Sie den State zur der Bridge",
|
|
119
119
|
"subscribeTooltip": "Abonnieren Sie den State von der Bridge",
|
|
120
|
-
"BridgeStateHeader": "Definieren Sie
|
|
120
|
+
"BridgeStateHeader": "Definieren Sie Zustände für das HA Discovery",
|
|
121
121
|
"BridgeStateInformation": "Hier können Sie ein Array von States definieren, die ein Topic für Discovery festlegen. (Wildcards sind auch möglich)",
|
|
122
122
|
"Application": "Anwendung",
|
|
123
123
|
"Device": "Gerät",
|
|
@@ -126,7 +126,15 @@
|
|
|
126
126
|
"BridgeType": "Bridge Typ",
|
|
127
127
|
"BridgeTypeTooltip": "Wählen Sie den Typ des Fremdsystems aus",
|
|
128
128
|
"BridgeTypeOff": "aus",
|
|
129
|
-
"BridgeTypeHA": "
|
|
129
|
+
"BridgeTypeHA": "Home Assistant",
|
|
130
130
|
"RefreshDiscoveryCronJob": "Discovery Zyklus",
|
|
131
|
-
"RefreshDiscoveryCronJobTooltip": "Stellen Sie den Cronjob für das Discovery ein"
|
|
131
|
+
"RefreshDiscoveryCronJobTooltip": "Stellen Sie den Cronjob für das Discovery ein",
|
|
132
|
+
"ClimateHeader": "Definieren Sie Zustände für eine Klima ENtität",
|
|
133
|
+
"ClimateInformation": "Hier können Sie ein Array von Klimaentitäten definieren",
|
|
134
|
+
"ClimateTargetTemperatureText": "Solltemperatur",
|
|
135
|
+
"ClimateActTemperatureText": "Isttemperatur",
|
|
136
|
+
"ClimateActModeText": "Mode",
|
|
137
|
+
"_DiscoveredIds": "Discoverd Ids",
|
|
138
|
+
"_PublishedIds": "Published Ids",
|
|
139
|
+
"_SubscribedTopics": "Subscribed Topics"
|
|
132
140
|
}
|
|
@@ -128,5 +128,13 @@
|
|
|
128
128
|
"BridgeTypeOff": "off",
|
|
129
129
|
"BridgeTypeHA": "Home Assistant",
|
|
130
130
|
"RefreshDiscoveryCronJob": "Discover Cycle",
|
|
131
|
-
"RefreshDiscoveryCronJobTooltip": "insert the cronjob for refreshing the discovery"
|
|
131
|
+
"RefreshDiscoveryCronJobTooltip": "insert the cronjob for refreshing the discovery",
|
|
132
|
+
"ClimateHeader": "Define States for Climate Entity",
|
|
133
|
+
"ClimateInformation": "Here you can define an array of Climate definitions",
|
|
134
|
+
"ClimateTargetTemperatureText": "Target Temperature",
|
|
135
|
+
"ClimateActTemperatureText": "Target Temperature",
|
|
136
|
+
"ClimateActModeText": "Target Temperature",
|
|
137
|
+
"_DiscoveredIds": "Discoverd Ids",
|
|
138
|
+
"_PublishedIds": "Published Ids",
|
|
139
|
+
"_SubscribedTopics": "Subscribed Topics"
|
|
132
140
|
}
|
package/admin/jsonConfig.json
CHANGED
|
@@ -1112,7 +1112,7 @@
|
|
|
1112
1112
|
"attr": "subscribe",
|
|
1113
1113
|
"label": "subscribe",
|
|
1114
1114
|
"hidden": "data.Folder !== 'downlink.control'",
|
|
1115
|
-
"default":
|
|
1115
|
+
"default": true,
|
|
1116
1116
|
"width": "5%"
|
|
1117
1117
|
},
|
|
1118
1118
|
{
|
|
@@ -1123,6 +1123,273 @@
|
|
|
1123
1123
|
"width": "5%"
|
|
1124
1124
|
}
|
|
1125
1125
|
]
|
|
1126
|
+
},
|
|
1127
|
+
"_ClimateHeader":{
|
|
1128
|
+
"newLine": true,
|
|
1129
|
+
"hidden": "data.BridgeType === 'off'",
|
|
1130
|
+
"type": "header",
|
|
1131
|
+
"text": "ClimateHeader",
|
|
1132
|
+
"size": 3,
|
|
1133
|
+
"xs": 12,
|
|
1134
|
+
"sm": 12,
|
|
1135
|
+
"md": 12,
|
|
1136
|
+
"lg": 12,
|
|
1137
|
+
"xl": 12
|
|
1138
|
+
},
|
|
1139
|
+
"_ClimateInformation":{
|
|
1140
|
+
"newLine":true,
|
|
1141
|
+
"hidden": "data.BridgeType === 'off'",
|
|
1142
|
+
"type": "staticText",
|
|
1143
|
+
"label": "ClimateInformation",
|
|
1144
|
+
"xs": 12,
|
|
1145
|
+
"sm": 12,
|
|
1146
|
+
"md": 12,
|
|
1147
|
+
"lg": 12,
|
|
1148
|
+
"xl": 12
|
|
1149
|
+
},
|
|
1150
|
+
"ClimateConfig":{
|
|
1151
|
+
"newLine": true,
|
|
1152
|
+
"hidden": "data.BridgeType === 'off'",
|
|
1153
|
+
"type":"accordion",
|
|
1154
|
+
"titleAttr": "ClimateName",
|
|
1155
|
+
"clone": true,
|
|
1156
|
+
"xs": 12,
|
|
1157
|
+
"sm": 12,
|
|
1158
|
+
"md": 12,
|
|
1159
|
+
"lg": 12,
|
|
1160
|
+
"xl": 12,
|
|
1161
|
+
"items":[
|
|
1162
|
+
{
|
|
1163
|
+
"type": "text",
|
|
1164
|
+
"attr": "ClimateName",
|
|
1165
|
+
"label": "ClimateNameText",
|
|
1166
|
+
"xs": 12,
|
|
1167
|
+
"sm": 4,
|
|
1168
|
+
"md": 4,
|
|
1169
|
+
"lg": 4,
|
|
1170
|
+
"xl": 4
|
|
1171
|
+
},
|
|
1172
|
+
{
|
|
1173
|
+
"newLine": true,
|
|
1174
|
+
"type": "staticText",
|
|
1175
|
+
"attr": "_statciTextTarget",
|
|
1176
|
+
"label": "ClimateTargetTemperatureText",
|
|
1177
|
+
"xs": 12,
|
|
1178
|
+
"sm": 12,
|
|
1179
|
+
"md": 12,
|
|
1180
|
+
"lg": 12,
|
|
1181
|
+
"xl": 12
|
|
1182
|
+
},
|
|
1183
|
+
{
|
|
1184
|
+
"newLine": true,
|
|
1185
|
+
"type": "selectSendTo",
|
|
1186
|
+
"attr": "TargetApplication",
|
|
1187
|
+
"label": "Application",
|
|
1188
|
+
"default": "No Application selected",
|
|
1189
|
+
"jsonData": "{}",
|
|
1190
|
+
"command": "getApplicationsForClimateConfig",
|
|
1191
|
+
"xs": 12,
|
|
1192
|
+
"sm": 3,
|
|
1193
|
+
"md": 3,
|
|
1194
|
+
"lg": 3,
|
|
1195
|
+
"xl": 3
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
"type": "selectSendTo",
|
|
1199
|
+
"attr": "TargetDevice",
|
|
1200
|
+
"label": "Device",
|
|
1201
|
+
"default": "No Device selected",
|
|
1202
|
+
"jsonData": "{\"application\":\"${data.TargetApplication}\"}",
|
|
1203
|
+
"command": "getDevicesForClimateConfig",
|
|
1204
|
+
"alsoDependsOn":[
|
|
1205
|
+
"TargetApplication"
|
|
1206
|
+
],
|
|
1207
|
+
"xs": 12,
|
|
1208
|
+
"sm": 3,
|
|
1209
|
+
"md": 3,
|
|
1210
|
+
"lg": 3,
|
|
1211
|
+
"xl": 3
|
|
1212
|
+
},
|
|
1213
|
+
{
|
|
1214
|
+
"type": "select",
|
|
1215
|
+
"attr": "TargetFolder",
|
|
1216
|
+
"label": "Folder",
|
|
1217
|
+
"default": "downlink.control",
|
|
1218
|
+
"options": [
|
|
1219
|
+
{"label":"downlink.control","value":"downlink.control"}
|
|
1220
|
+
],
|
|
1221
|
+
"xs": 12,
|
|
1222
|
+
"sm": 2,
|
|
1223
|
+
"md": 2,
|
|
1224
|
+
"lg": 2,
|
|
1225
|
+
"xl": 2
|
|
1226
|
+
},
|
|
1227
|
+
{
|
|
1228
|
+
"type": "selectSendTo",
|
|
1229
|
+
"attr": "TargetState",
|
|
1230
|
+
"label": "State",
|
|
1231
|
+
"default": "No State selected",
|
|
1232
|
+
"jsonData": "{\"application\":\"${data.TargetApplication}\",\"device\":\"${data.TargetDevice}\",\"folder\":\"${data.TargetFolder}\"}",
|
|
1233
|
+
"command": "getStatesForClimateConfig",
|
|
1234
|
+
"alsoDependsOn":[
|
|
1235
|
+
"TargetApplication",
|
|
1236
|
+
"TargetDevice",
|
|
1237
|
+
"TargetFolder"
|
|
1238
|
+
],
|
|
1239
|
+
"xs": 12,
|
|
1240
|
+
"sm": 4,
|
|
1241
|
+
"md": 4,
|
|
1242
|
+
"lg": 4,
|
|
1243
|
+
"xl": 4
|
|
1244
|
+
},
|
|
1245
|
+
{
|
|
1246
|
+
"type": "staticText",
|
|
1247
|
+
"attr": "_statciTextAct",
|
|
1248
|
+
"label": "ClimateActTemperatureText",
|
|
1249
|
+
"xs": 12,
|
|
1250
|
+
"sm": 12,
|
|
1251
|
+
"md": 12,
|
|
1252
|
+
"lg": 12,
|
|
1253
|
+
"xl": 12
|
|
1254
|
+
},
|
|
1255
|
+
{
|
|
1256
|
+
"newLine": true,
|
|
1257
|
+
"type": "selectSendTo",
|
|
1258
|
+
"attr": "ActApplication",
|
|
1259
|
+
"label": "Application",
|
|
1260
|
+
"default": "No Application selected",
|
|
1261
|
+
"jsonData": "{}",
|
|
1262
|
+
"command": "getApplicationsForClimateConfig",
|
|
1263
|
+
"xs": 12,
|
|
1264
|
+
"sm": 3,
|
|
1265
|
+
"md": 3,
|
|
1266
|
+
"lg": 3,
|
|
1267
|
+
"xl": 3
|
|
1268
|
+
},
|
|
1269
|
+
{
|
|
1270
|
+
"type": "selectSendTo",
|
|
1271
|
+
"attr": "ActDevice",
|
|
1272
|
+
"label": "Device",
|
|
1273
|
+
"default": "No Device selected",
|
|
1274
|
+
"jsonData": "{\"application\":\"${data.ActApplication}\"}",
|
|
1275
|
+
"command": "getDevicesForClimateConfig",
|
|
1276
|
+
"alsoDependsOn":[
|
|
1277
|
+
"ActApplication"
|
|
1278
|
+
],
|
|
1279
|
+
"xs": 12,
|
|
1280
|
+
"sm": 3,
|
|
1281
|
+
"md": 3,
|
|
1282
|
+
"lg": 3,
|
|
1283
|
+
"xl": 3
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
"type": "select",
|
|
1287
|
+
"attr": "ActFolder",
|
|
1288
|
+
"label": "Folder",
|
|
1289
|
+
"default": "uplink.decoded",
|
|
1290
|
+
"options": [
|
|
1291
|
+
{"label":"uplink.decoded","value":"uplink.decoded"}
|
|
1292
|
+
],
|
|
1293
|
+
"xs": 12,
|
|
1294
|
+
"sm": 2,
|
|
1295
|
+
"md": 2,
|
|
1296
|
+
"lg": 2,
|
|
1297
|
+
"xl": 2
|
|
1298
|
+
},
|
|
1299
|
+
{
|
|
1300
|
+
"type": "selectSendTo",
|
|
1301
|
+
"attr": "ActState",
|
|
1302
|
+
"label": "State",
|
|
1303
|
+
"default": "No State selected",
|
|
1304
|
+
"jsonData": "{\"application\":\"${data.ActApplication}\",\"device\":\"${data.ActDevice}\",\"folder\":\"${data.ActFolder}\"}",
|
|
1305
|
+
"command": "getStatesForClimateConfig",
|
|
1306
|
+
"alsoDependsOn":[
|
|
1307
|
+
"ActApplication",
|
|
1308
|
+
"ActDevice",
|
|
1309
|
+
"ActFolder"
|
|
1310
|
+
],
|
|
1311
|
+
"xs": 12,
|
|
1312
|
+
"sm": 4,
|
|
1313
|
+
"md": 4,
|
|
1314
|
+
"lg": 4,
|
|
1315
|
+
"xl": 4
|
|
1316
|
+
},
|
|
1317
|
+
{
|
|
1318
|
+
"type": "staticText",
|
|
1319
|
+
"attr": "_statciTextMode",
|
|
1320
|
+
"label": "ClimateModeTemperatureText",
|
|
1321
|
+
"xs": 12,
|
|
1322
|
+
"sm": 12,
|
|
1323
|
+
"md": 12,
|
|
1324
|
+
"lg": 12,
|
|
1325
|
+
"xl": 12
|
|
1326
|
+
},
|
|
1327
|
+
{
|
|
1328
|
+
"newLine": true,
|
|
1329
|
+
"type": "selectSendTo",
|
|
1330
|
+
"attr": "ModeApplication",
|
|
1331
|
+
"label": "Application",
|
|
1332
|
+
"default": "NotPresent",
|
|
1333
|
+
"jsonData": "{}",
|
|
1334
|
+
"command": "getApplicationsForClimateModeConfig",
|
|
1335
|
+
"xs": 12,
|
|
1336
|
+
"sm": 3,
|
|
1337
|
+
"md": 3,
|
|
1338
|
+
"lg": 3,
|
|
1339
|
+
"xl": 3
|
|
1340
|
+
},
|
|
1341
|
+
{
|
|
1342
|
+
"type": "selectSendTo",
|
|
1343
|
+
"attr": "ModeDevice",
|
|
1344
|
+
"label": "Device",
|
|
1345
|
+
"default": "*",
|
|
1346
|
+
"jsonData": "{\"application\":\"${data.ModeApplication}\"}",
|
|
1347
|
+
"command": "getDevicesForClimateConfig",
|
|
1348
|
+
"hidden": "data.ModeApplication === 'NotPresent'",
|
|
1349
|
+
"alsoDependsOn":[
|
|
1350
|
+
"ModeApplication"
|
|
1351
|
+
],
|
|
1352
|
+
"xs": 12,
|
|
1353
|
+
"sm": 3,
|
|
1354
|
+
"md": 3,
|
|
1355
|
+
"lg": 3,
|
|
1356
|
+
"xl": 3
|
|
1357
|
+
},
|
|
1358
|
+
{
|
|
1359
|
+
"type": "select",
|
|
1360
|
+
"attr": "ModeFolder",
|
|
1361
|
+
"label": "Folder",
|
|
1362
|
+
"default": "uplink.decoded",
|
|
1363
|
+
"options": [
|
|
1364
|
+
{"label":"uplink.decoded","value":"uplink.decoded"}
|
|
1365
|
+
],
|
|
1366
|
+
"hidden": "data.ModeApplication === 'NotPresent'",
|
|
1367
|
+
"xs": 12,
|
|
1368
|
+
"sm": 2,
|
|
1369
|
+
"md": 2,
|
|
1370
|
+
"lg": 2,
|
|
1371
|
+
"xl": 2
|
|
1372
|
+
},
|
|
1373
|
+
{
|
|
1374
|
+
"type": "selectSendTo",
|
|
1375
|
+
"attr": "ModeState",
|
|
1376
|
+
"label": "State",
|
|
1377
|
+
"default": "No State selected",
|
|
1378
|
+
"jsonData": "{\"application\":\"${data.ModeApplication}\",\"device\":\"${data.ActDevice}\",\"folder\":\"${data.ActFolder}\"}",
|
|
1379
|
+
"command": "getStatesForClimateConfig",
|
|
1380
|
+
"alsoDependsOn":[
|
|
1381
|
+
"ModeApplication",
|
|
1382
|
+
"ModeDevice",
|
|
1383
|
+
"ModeFolder"
|
|
1384
|
+
],
|
|
1385
|
+
"hidden": "data.ModeApplication === 'NotPresent'",
|
|
1386
|
+
"xs": 12,
|
|
1387
|
+
"sm": 4,
|
|
1388
|
+
"md": 4,
|
|
1389
|
+
"lg": 4,
|
|
1390
|
+
"xl": 4
|
|
1391
|
+
}
|
|
1392
|
+
]
|
|
1126
1393
|
}
|
|
1127
1394
|
}
|
|
1128
1395
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"i18n": true,
|
|
3
|
+
"type": "tabs",
|
|
4
|
+
"tabsStyle": {
|
|
5
|
+
"width": "calc(100% - 100px)"
|
|
6
|
+
},
|
|
7
|
+
"items":{
|
|
8
|
+
"_DiscoveredIds":{
|
|
9
|
+
"type": "panel",
|
|
10
|
+
"label": "_DiscoveredIds",
|
|
11
|
+
"items": {
|
|
12
|
+
"_DiscoveredIds":{
|
|
13
|
+
"type": "text",
|
|
14
|
+
"label": "_DiscoveredIds",
|
|
15
|
+
"defaultSendTo": "getDiscoveredIds",
|
|
16
|
+
"minRows": 10,
|
|
17
|
+
"readOnly": true,
|
|
18
|
+
"trim": false,
|
|
19
|
+
"noClearButton": true,
|
|
20
|
+
"xs": 12,
|
|
21
|
+
"sm": 12,
|
|
22
|
+
"md": 12,
|
|
23
|
+
"lg": 12,
|
|
24
|
+
"xl": 12
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"_PublishedIds":{
|
|
29
|
+
"type": "panel",
|
|
30
|
+
"label": "_PublishedIds",
|
|
31
|
+
"items": {
|
|
32
|
+
"_PublishedIds":{
|
|
33
|
+
"type": "text",
|
|
34
|
+
"label": "_PublishedIds",
|
|
35
|
+
"defaultSendTo": "getPublishedIds",
|
|
36
|
+
"minRows": 10,
|
|
37
|
+
"readOnly": true,
|
|
38
|
+
"trim": false,
|
|
39
|
+
"noClearButton": true,
|
|
40
|
+
"xs": 12,
|
|
41
|
+
"sm": 12,
|
|
42
|
+
"md": 12,
|
|
43
|
+
"lg": 12,
|
|
44
|
+
"xl": 12
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"_SubscribedTopics":{
|
|
49
|
+
"type": "panel",
|
|
50
|
+
"label": "_SubscribedTopics",
|
|
51
|
+
"items": {
|
|
52
|
+
"_SubscribedTopics":{
|
|
53
|
+
"type": "text",
|
|
54
|
+
"label": "_SubscribedTopics",
|
|
55
|
+
"defaultSendTo": "getSubscribedTopics",
|
|
56
|
+
"minRows": 10,
|
|
57
|
+
"readOnly": true,
|
|
58
|
+
"trim": false,
|
|
59
|
+
"noClearButton": true,
|
|
60
|
+
"xs": 12,
|
|
61
|
+
"sm": 12,
|
|
62
|
+
"md": 12,
|
|
63
|
+
"lg": 12,
|
|
64
|
+
"xl": 12
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "lorawan",
|
|
4
|
-
"version": "1.13.
|
|
4
|
+
"version": "1.13.5",
|
|
5
5
|
"news": {
|
|
6
|
+
"1.13.5": {
|
|
7
|
+
"en": "Show discovery topic(s) & messag(es) ind array\nAdd Tab to see Discovered, Published and Subscribed Ids.\nAdd Posibility to discover climate Entity\nRetaining Discovery",
|
|
8
|
+
"de": "Zeige Entdeckungsthemen & Messag(en) ind array\nFügen Sie Tab hinzu, um entdeckte, veröffentlichte und abgemeldete Ids zu sehen.\nMöglichkeit, das Klima zu entdecken\nRetaining Discovery",
|
|
9
|
+
"ru": "Показать тему(ы) обнаружения и мессенджер(ы) ind array\nДобавьте вкладку, чтобы увидеть обнаруженные, опубликованные и подписанные идентификаторы.\nДобавить возможность открыть климатическую организацию\nСохранение Discovery",
|
|
10
|
+
"pt": "Mostrar o( s) tópico( s) de descoberta & messag( es) ind array\nAdicionar aba para ver IDs descobertos, publicados e assinados.\nAdicionar Possibilidade de descobrir o clima Entidade\nManter a Descoberta",
|
|
11
|
+
"nl": "Ontdekkingsonderwerp(s) & messag(es) ind-array tonen\nTabblad toevoegen om Ontdekt, Gepubliceerd en Geabonneerd Ids te zien.\nMogelijkheid toevoegen om klimaat te ontdekken Entity\nOntdekking behouden",
|
|
12
|
+
"fr": "Afficher le(s) sujet(s) de découverte et le(s) tableau(s) ind\nAjouter un onglet pour voir les idées découvertes, publiées et enregistrées.\nAjouter la possibilité de découvrir le climat Entité\nConserver la découverte",
|
|
13
|
+
"it": "Mostra argomento(i) & messag(es) ind array\nAggiungi scheda per vedere Scoperto, Pubblicato e Abbonato Ids.\nAggiungi Posibilità per scoprire il clima\nRecuperare Discovery",
|
|
14
|
+
"es": "Mostrar el tema de descubrimiento(s) & messag(es) end array\nAñadir Tab para ver Ids descubiertos, publicados y suscritos.\nAñadir Posibilidad de descubrir la Entidad climática\nRetaining Discovery",
|
|
15
|
+
"pl": "Pokaż temat (y) & messag (y) ind array\nDodaj kartę, aby zobaczyć odkryte, opublikowane i subskrybowane identyfikatory.\nDodaj możliwość odkrywania podmiotu klimatu\nZachowanie Odkrycia",
|
|
16
|
+
"uk": "Показати тему відкриття (s) & mesag(es) ind array\nДодати вкладку, щоб побачити Discovered, Опубліковано та підписувати Ids.\nДодати можливість відкрити клімат\nПідтримка Discovery",
|
|
17
|
+
"zh-cn": "显示发现主题 & messag( es) ind 数组\n添加 Tab 以查看发现、 发布和订阅的 Ids .\n添加发现气候实体的可能性\n保留发现"
|
|
18
|
+
},
|
|
19
|
+
"1.13.4": {
|
|
20
|
+
"en": "Bugfixing crc in Vicki Profile => ChildLock",
|
|
21
|
+
"de": "Bugfixing crc in Vicki Profil => ChildLock",
|
|
22
|
+
"ru": "Bugfixing crc в профиле Вики => ChildLock",
|
|
23
|
+
"pt": "Bugfixing crc in Vicki Profile => ChildLock",
|
|
24
|
+
"nl": "Bugfixing crc in Vicki-profiel => ChildLock",
|
|
25
|
+
"fr": "Correction de bugs dans le profil Vicki => ChildLock",
|
|
26
|
+
"it": "Bugfixing crc in Vicki Profilo => ChildLock",
|
|
27
|
+
"es": "Crc de Bugfixing en Vicki Perfil = 75%Lock",
|
|
28
|
+
"pl": "Bugfining crc w profilu Vicki = > ChildLock",
|
|
29
|
+
"uk": "Виправлення кришки в Vicki Profile => Дитячий замок",
|
|
30
|
+
"zh-cn": "Vicki 配置中的错误修复 crc QQ ChildLock"
|
|
31
|
+
},
|
|
6
32
|
"1.13.3": {
|
|
7
33
|
"en": "Add images to the new States",
|
|
8
34
|
"de": "Bild hinzugefügt für die neuen Staaten",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "usunąć Błąd z obsługą folderu / stanu",
|
|
68
94
|
"uk": "видалення Помилки з папкою / державною обробкою",
|
|
69
95
|
"zh-cn": "删除 有文件夹/ 状态处理的错误"
|
|
70
|
-
},
|
|
71
|
-
"1.12.0": {
|
|
72
|
-
"en": "Custom Table for Config HA Bridge",
|
|
73
|
-
"de": "Benutzerdefinierte Tisch für Config HA Bridge",
|
|
74
|
-
"ru": "Настольный стол для моста Config HA",
|
|
75
|
-
"pt": "Mesa personalizada para configuração HA Bridge",
|
|
76
|
-
"nl": "Aangepaste tabel voor Config HA Bridge",
|
|
77
|
-
"fr": "Table personnalisée pour Config HA Bridge",
|
|
78
|
-
"it": "Tabella personalizzata per Config HA Bridge",
|
|
79
|
-
"es": "Tabla personalizada para el puente Config HA",
|
|
80
|
-
"pl": "Niestandardowa tabela dla Config HA Bridge",
|
|
81
|
-
"uk": "Спеціальна таблиця для Config HA Bridge",
|
|
82
|
-
"zh-cn": "配置 HA 桥的自定义表格"
|
|
83
|
-
},
|
|
84
|
-
"1.11.10": {
|
|
85
|
-
"en": "insert logging to object change",
|
|
86
|
-
"de": "einfügen von protokollierung zur objektänderung",
|
|
87
|
-
"ru": "вставить журналирование для изменения объекта",
|
|
88
|
-
"pt": "inserir o registro à mudança de objeto",
|
|
89
|
-
"nl": "loggen toevoegen aan objectverandering",
|
|
90
|
-
"fr": "insérer l'enregistrement dans le changement d'objet",
|
|
91
|
-
"it": "inserire logging per cambiare oggetto",
|
|
92
|
-
"es": "insertar logging to object change",
|
|
93
|
-
"pl": "wpisz logowanie do zmiany obiektu",
|
|
94
|
-
"uk": "вставити заголовок до зміни об'єкта",
|
|
95
|
-
"zh-cn": "插入日志到对象更改"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
|
@@ -146,7 +146,16 @@
|
|
|
146
146
|
"dataSource": "push",
|
|
147
147
|
"blockly": true,
|
|
148
148
|
"adminUI": {
|
|
149
|
-
"config": "json"
|
|
149
|
+
"config": "json",
|
|
150
|
+
"tab": "json"
|
|
151
|
+
},
|
|
152
|
+
"adminTab": {
|
|
153
|
+
"link": "jsonTab.json",
|
|
154
|
+
"singleton": false,
|
|
155
|
+
"name": {
|
|
156
|
+
"en": "LoRaWAN",
|
|
157
|
+
"de": "LoRaWAN"
|
|
158
|
+
}
|
|
150
159
|
},
|
|
151
160
|
"dependencies": [
|
|
152
161
|
{
|
|
@@ -376,7 +385,8 @@
|
|
|
376
385
|
"subscribe": false,
|
|
377
386
|
"exclude": false
|
|
378
387
|
}
|
|
379
|
-
]
|
|
388
|
+
],
|
|
389
|
+
"ClimateConfig": []
|
|
380
390
|
},
|
|
381
391
|
"objects": [],
|
|
382
392
|
"instanceObjects": [
|
package/lib/modules/bridge.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const bridgeMqttClientClass = require('./bridgeMqttclient');
|
|
2
2
|
const schedule = require('node-schedule');
|
|
3
|
-
|
|
3
|
+
/*
|
|
4
|
+
Also er published irgendwie nicht den Mode => und es kommt virtual_Mode nicht subcribed....
|
|
5
|
+
*/
|
|
4
6
|
/**
|
|
5
7
|
* this class handles the bridge to foreign system
|
|
6
8
|
*/
|
|
@@ -10,7 +12,7 @@ class bridgeClass {
|
|
|
10
12
|
*/
|
|
11
13
|
constructor(adapter) {
|
|
12
14
|
this.adapter = adapter;
|
|
13
|
-
|
|
15
|
+
this.InitDone = false; // Activates work
|
|
14
16
|
/*********************************************************************
|
|
15
17
|
* ************** Definition Assigns (externel Module) ***************
|
|
16
18
|
* ******************************************************************/
|
|
@@ -21,12 +23,16 @@ class bridgeClass {
|
|
|
21
23
|
this.CheckedIds = {};
|
|
22
24
|
this.DiscoveredIds = {};
|
|
23
25
|
this.SubscribedTopics = {};
|
|
24
|
-
this.
|
|
26
|
+
this.PublishedIds = {};
|
|
27
|
+
this.VitualIds = {};
|
|
25
28
|
this.BridgeDiscoveryPrefix = {
|
|
26
29
|
HA: 'homeassistant/',
|
|
27
30
|
};
|
|
28
31
|
this.MinTime = 100; // ms between publish and subscribe same value
|
|
29
32
|
this.DiscoveryCronjob = {};
|
|
33
|
+
this.EndingVirtualClimate = '.virtual_climate';
|
|
34
|
+
this.EndingVirtualMode = '.virtual_mode';
|
|
35
|
+
this.ClimateEntityType = 'climate';
|
|
30
36
|
}
|
|
31
37
|
|
|
32
38
|
/*********************************************************************
|
|
@@ -42,15 +48,25 @@ class bridgeClass {
|
|
|
42
48
|
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
43
49
|
try {
|
|
44
50
|
if (this.SubscribedTopics[topic]) {
|
|
45
|
-
this.SubscribedTopics[topic].val = message;
|
|
46
|
-
this.SubscribedTopics[topic].ts = Date.now();
|
|
47
51
|
if (
|
|
48
|
-
!this.
|
|
49
|
-
this.
|
|
50
|
-
Date.now() - this.
|
|
52
|
+
!this.PublishedIds[this.SubscribedTopics[topic].id] ||
|
|
53
|
+
this.PublishedIds[this.SubscribedTopics[topic].id].val !== message ||
|
|
54
|
+
Date.now() - this.PublishedIds[this.SubscribedTopics[topic].id].ts >= this.MinTime
|
|
51
55
|
) {
|
|
56
|
+
this.SubscribedTopics[topic].val = message;
|
|
57
|
+
this.SubscribedTopics[topic].ts = Date.now();
|
|
58
|
+
if (this.SubscribedTopics[topic].id.endsWith(this.EndingVirtualMode)) {
|
|
59
|
+
this.adapter.log.debug(
|
|
60
|
+
`The value ${message} is assigned to virtual id: ${this.SubscribedTopics[topic].id}`,
|
|
61
|
+
);
|
|
62
|
+
this.VitualIds[this.SubscribedTopics[topic].id] = message;
|
|
63
|
+
this.adapter.log.warn(`aaa${JSON.stringify(this.VitualIds)}`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
52
66
|
await this.adapter.setState(this.SubscribedTopics[topic].id, message);
|
|
53
67
|
}
|
|
68
|
+
} else {
|
|
69
|
+
this.adapter.log.debug(`The received Topic ${topic} is not subscribed`);
|
|
54
70
|
}
|
|
55
71
|
} catch (error) {
|
|
56
72
|
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
@@ -66,9 +82,13 @@ class bridgeClass {
|
|
|
66
82
|
const activeFunction = 'bridge.js - work';
|
|
67
83
|
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
68
84
|
try {
|
|
85
|
+
// First remove namespace from id
|
|
86
|
+
id = this.adapter.removeNamespace(id);
|
|
69
87
|
if (this.bridgeMqttClient.internalConnectionstate) {
|
|
70
88
|
await this.discovery(id, options);
|
|
71
89
|
await this.publishId(id, Stateval);
|
|
90
|
+
} else {
|
|
91
|
+
this.adapter.log.debug(`work called with id ${id}, but Bridge is not connected yet.`);
|
|
72
92
|
}
|
|
73
93
|
} catch (error) {
|
|
74
94
|
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
@@ -88,7 +108,11 @@ class bridgeClass {
|
|
|
88
108
|
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
89
109
|
try {
|
|
90
110
|
if (!this.CheckedIds[id] || (options && options.forceDiscovery)) {
|
|
111
|
+
this.CheckedIds[id] = {};
|
|
112
|
+
this.adapter.log.debug(`discover the id ${id}`);
|
|
91
113
|
await this.buildDiscovery(id, options);
|
|
114
|
+
} else {
|
|
115
|
+
this.adapter.log.debug(`${id} allready checked for discovery`);
|
|
92
116
|
}
|
|
93
117
|
} catch (error) {
|
|
94
118
|
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
@@ -96,7 +120,205 @@ class bridgeClass {
|
|
|
96
120
|
}
|
|
97
121
|
|
|
98
122
|
/*********************************************************************
|
|
99
|
-
*
|
|
123
|
+
* ********************** Discover Climate ***************************
|
|
124
|
+
* ******************************************************************/
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Discover Configed Climate Entities
|
|
128
|
+
*/
|
|
129
|
+
async discoverClimate() {
|
|
130
|
+
const activeFunction = 'discoverClimate';
|
|
131
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
132
|
+
try {
|
|
133
|
+
if (this.adapter.config.ClimateConfig) {
|
|
134
|
+
for (const config of this.adapter.config.ClimateConfig) {
|
|
135
|
+
if (!(await this.generateClimateIds(config))) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// All Ids ok
|
|
139
|
+
// Target
|
|
140
|
+
const target = {};
|
|
141
|
+
target.changeInfo = await this.adapter.getChangeInfo(config.climateIds.target);
|
|
142
|
+
target.DeviceIdentifier = this.getDeviceIdentifier(
|
|
143
|
+
target.changeInfo,
|
|
144
|
+
this.adapter.config.DeviceIdentifiers,
|
|
145
|
+
);
|
|
146
|
+
target.ReplacedDeviceIdentifier = await this.replaceGermanSpecific(target.DeviceIdentifier);
|
|
147
|
+
target.ReplacedWithoutSpace = await this.replaceSpace(target.ReplacedDeviceIdentifier);
|
|
148
|
+
target.ReplaceWithoutSlash = await this.replaceSlash(target.ReplacedWithoutSpace);
|
|
149
|
+
target.Topic = `${this.bridgeMqttClient.BridgePrefix}${target.ReplacedDeviceIdentifier}/${target.changeInfo.changedState}`;
|
|
150
|
+
|
|
151
|
+
//Min und Max holen
|
|
152
|
+
const targetObject = await this.adapter.getObjectAsync(config.climateIds.target);
|
|
153
|
+
if (targetObject.common.min) {
|
|
154
|
+
target.min = targetObject.common.min;
|
|
155
|
+
}
|
|
156
|
+
if (targetObject.common.max) {
|
|
157
|
+
target.max = targetObject.common.max;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Act
|
|
161
|
+
const act = {};
|
|
162
|
+
act.changeInfo = await this.adapter.getChangeInfo(config.climateIds.act);
|
|
163
|
+
act.DeviceIdentifier = this.getDeviceIdentifier(
|
|
164
|
+
act.changeInfo,
|
|
165
|
+
this.adapter.config.DeviceIdentifiers,
|
|
166
|
+
);
|
|
167
|
+
act.ReplacedDeviceIdentifier = await this.replaceGermanSpecific(act.DeviceIdentifier);
|
|
168
|
+
act.ReplacedWithoutSpace = await this.replaceSpace(act.ReplacedDeviceIdentifier);
|
|
169
|
+
act.ReplaceWithoutSlash = await this.replaceSlash(act.ReplacedWithoutSpace);
|
|
170
|
+
act.Topic = `${this.bridgeMqttClient.BridgePrefix}${act.ReplacedDeviceIdentifier}/${act.changeInfo.changedState}`;
|
|
171
|
+
|
|
172
|
+
// Mode
|
|
173
|
+
const mode = {};
|
|
174
|
+
mode.changeInfo = await this.adapter.getChangeInfo(config.climateIds.mode);
|
|
175
|
+
mode.DeviceIdentifier = this.getDeviceIdentifier(
|
|
176
|
+
mode.changeInfo,
|
|
177
|
+
this.adapter.config.DeviceIdentifiers,
|
|
178
|
+
);
|
|
179
|
+
mode.ReplacedDeviceIdentifier = await this.replaceGermanSpecific(mode.DeviceIdentifier);
|
|
180
|
+
mode.ReplacedWithoutSpace = await this.replaceSpace(mode.ReplacedDeviceIdentifier);
|
|
181
|
+
mode.ReplaceWithoutSlash = await this.replaceSlash(mode.ReplacedWithoutSpace);
|
|
182
|
+
mode.Topic = `${this.bridgeMqttClient.BridgePrefix}${mode.ReplacedDeviceIdentifier}/${mode.changeInfo.changedState}`;
|
|
183
|
+
|
|
184
|
+
const indexLastSlashTarget = target.Topic.lastIndexOf('/');
|
|
185
|
+
const Topic = target.Topic.substring(0, indexLastSlashTarget) + this.EndingVirtualClimate;
|
|
186
|
+
const DiscoveryTopic = `${this.BridgeDiscoveryPrefix[this.adapter.config.BridgeType]}${this.ClimateEntityType}/${target.ReplaceWithoutSlash}/${config.ClimateName}/config`;
|
|
187
|
+
const indexLastDotTarget = config.climateIds.target.lastIndexOf('.');
|
|
188
|
+
const Id = config.climateIds.target.substring(0, indexLastDotTarget) + this.EndingVirtualClimate;
|
|
189
|
+
const DiscoveryPayload = {
|
|
190
|
+
name: config.ClimateName,
|
|
191
|
+
unique_id: `${target.ReplaceWithoutSlash}_${config.ClimateName}`.toLowerCase(),
|
|
192
|
+
device: {
|
|
193
|
+
identifiers: [target.ReplaceWithoutSlash.toLowerCase()],
|
|
194
|
+
name: target.DeviceIdentifier,
|
|
195
|
+
},
|
|
196
|
+
mode_state_topic: mode.Topic,
|
|
197
|
+
mode_command_topic: mode.Topic,
|
|
198
|
+
temperature_state_topic: target.Topic,
|
|
199
|
+
temperature_command_topic: target.Topic,
|
|
200
|
+
current_temperature_topic: act.Topic,
|
|
201
|
+
min_temp: target.min ? target.min : 0,
|
|
202
|
+
max_temp: target.max ? target.max : 40,
|
|
203
|
+
modes: ['auto', 'heat', 'off'],
|
|
204
|
+
precision: 0.5,
|
|
205
|
+
temp_step: 0.5,
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// Assign Subscribed Topics
|
|
209
|
+
this.SubscribedTopics[target.Topic] = {};
|
|
210
|
+
this.SubscribedTopics[target.Topic].id = config.climateIds.target;
|
|
211
|
+
this.SubscribedTopics[target.Topic].val = await this.adapter.getState(config.climateIds.target).val;
|
|
212
|
+
this.SubscribedTopics[target.Topic].ts = Date.now() - this.MinTime;
|
|
213
|
+
|
|
214
|
+
this.SubscribedTopics[mode.Topic] = {};
|
|
215
|
+
this.SubscribedTopics[mode.Topic].id = config.climateIds.mode;
|
|
216
|
+
if (config.climateIds.mode.endsWith(this.EndingVirtualMode)) {
|
|
217
|
+
this.SubscribedTopics[mode.Topic].val = 'auto';
|
|
218
|
+
this.VitualIds[config.climateIds.mode] = this.SubscribedTopics[mode.Topic].val;
|
|
219
|
+
} else {
|
|
220
|
+
this.SubscribedTopics[mode.Topic].val = await this.adapter.getState(config.climateIds.mode).val;
|
|
221
|
+
}
|
|
222
|
+
this.SubscribedTopics[mode.Topic].ts = Date.now() - this.MinTime;
|
|
223
|
+
|
|
224
|
+
const DiscoveryObject = {
|
|
225
|
+
Topic: Topic,
|
|
226
|
+
topic: DiscoveryTopic,
|
|
227
|
+
payload: structuredClone(DiscoveryPayload),
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// Assign published Topics
|
|
231
|
+
// Target
|
|
232
|
+
if (!this.PublishedIds[config.climateIds.target]) {
|
|
233
|
+
this.PublishedIds[config.climateIds.target] = { discovery: [] };
|
|
234
|
+
}
|
|
235
|
+
this.PublishedIds[config.climateIds.target].Topic = target.Topic;
|
|
236
|
+
this.PublishedIds[config.climateIds.target].discovery.push({
|
|
237
|
+
topic: DiscoveryTopic,
|
|
238
|
+
payload: structuredClone(DiscoveryPayload),
|
|
239
|
+
});
|
|
240
|
+
this.PublishedIds[config.climateIds.target].val = 0;
|
|
241
|
+
this.PublishedIds[config.climateIds.target].ts = Date.now();
|
|
242
|
+
|
|
243
|
+
// Act
|
|
244
|
+
if (!this.PublishedIds[config.climateIds.act]) {
|
|
245
|
+
this.PublishedIds[config.climateIds.act] = { discovery: [] };
|
|
246
|
+
}
|
|
247
|
+
this.PublishedIds[config.climateIds.act].Topic = act.Topic;
|
|
248
|
+
this.PublishedIds[config.climateIds.act].discovery.push({
|
|
249
|
+
topic: DiscoveryTopic,
|
|
250
|
+
payload: structuredClone(DiscoveryPayload),
|
|
251
|
+
});
|
|
252
|
+
this.PublishedIds[config.climateIds.act].val = 0;
|
|
253
|
+
this.PublishedIds[config.climateIds.act].ts = Date.now();
|
|
254
|
+
|
|
255
|
+
// Mode
|
|
256
|
+
if (!this.PublishedIds[config.climateIds.mode]) {
|
|
257
|
+
this.PublishedIds[config.climateIds.mode] = { discovery: [] };
|
|
258
|
+
}
|
|
259
|
+
this.PublishedIds[config.climateIds.mode].Topic = mode.Topic;
|
|
260
|
+
this.PublishedIds[config.climateIds.mode].discovery.push({
|
|
261
|
+
topic: DiscoveryTopic,
|
|
262
|
+
payload: structuredClone(DiscoveryPayload),
|
|
263
|
+
});
|
|
264
|
+
this.PublishedIds[config.climateIds.mode].val = 0;
|
|
265
|
+
this.PublishedIds[config.climateIds.mode].ts = Date.now();
|
|
266
|
+
|
|
267
|
+
// Publishing the discover message
|
|
268
|
+
await this.publishDiscovery(Id, {
|
|
269
|
+
topic: DiscoveryObject?.topic,
|
|
270
|
+
payload: structuredClone(DiscoveryObject.payload),
|
|
271
|
+
});
|
|
272
|
+
await this.publishId(config.climateIds.target, this.SubscribedTopics[target.Topic].val);
|
|
273
|
+
await this.publishId(config.climateIds.act, await this.adapter.getState(config.climateIds.act).val);
|
|
274
|
+
await this.publishId(config.climateIds.mode, this.SubscribedTopics[mode.Topic].val);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
} catch (error) {
|
|
278
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/*********************************************************************
|
|
283
|
+
* ****************** generate Climate Ids ***************************
|
|
284
|
+
* ******************************************************************/
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* @param config Configuration of the climate entity, wich is to genereate
|
|
288
|
+
*/
|
|
289
|
+
async generateClimateIds(config) {
|
|
290
|
+
const activeFunction = 'generateClimateIds';
|
|
291
|
+
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
292
|
+
try {
|
|
293
|
+
const climateIds = { target: '', act: '', mode: '' };
|
|
294
|
+
climateIds.target = `${config.TargetApplication}.devices.${config.TargetDevice}.${config.TargetFolder}.${config.TargetState}`;
|
|
295
|
+
climateIds.act = `${config.ActApplication}.devices.${config.ActDevice}.${config.ActFolder}.${config.ActState}`;
|
|
296
|
+
if (config.ModeApplication === 'NotPresent') {
|
|
297
|
+
climateIds.mode = `${climateIds.target}${this.EndingVirtualMode}`;
|
|
298
|
+
} else {
|
|
299
|
+
climateIds.mode = `${config.ModeApplication}.devices.${config.ModeDevice}.${config.ModeFolder}.${config.ModeState}`;
|
|
300
|
+
}
|
|
301
|
+
for (const id of Object.values(climateIds)) {
|
|
302
|
+
if (!(await this.adapter.objectExists(id)) && !id.endsWith(this.EndingVirtualMode)) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (config.ClimateName === '') {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
const indexOfSpace = config.ClimateName.indexOf(' ');
|
|
310
|
+
if (indexOfSpace > 0) {
|
|
311
|
+
config.ClimateName = config.ClimateName.substring(0, indexOfSpace);
|
|
312
|
+
}
|
|
313
|
+
config.climateIds = climateIds;
|
|
314
|
+
return true;
|
|
315
|
+
} catch (error) {
|
|
316
|
+
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/*********************************************************************
|
|
321
|
+
* ********************* Publish zur Bridge **************************
|
|
100
322
|
* ******************************************************************/
|
|
101
323
|
|
|
102
324
|
/**
|
|
@@ -104,10 +326,10 @@ class bridgeClass {
|
|
|
104
326
|
* @param val Value of the used Id
|
|
105
327
|
*/
|
|
106
328
|
async publishId(id, val) {
|
|
107
|
-
const activeFunction = 'bridge.js -
|
|
329
|
+
const activeFunction = 'bridge.js - publishId';
|
|
108
330
|
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
109
331
|
try {
|
|
110
|
-
if (this.
|
|
332
|
+
if (this.PublishedIds[id]) {
|
|
111
333
|
if (val === undefined) {
|
|
112
334
|
const State = await this.adapter.getState(id);
|
|
113
335
|
if (State) {
|
|
@@ -115,16 +337,21 @@ class bridgeClass {
|
|
|
115
337
|
}
|
|
116
338
|
}
|
|
117
339
|
if (
|
|
118
|
-
!this.SubscribedTopics[this.
|
|
119
|
-
this.SubscribedTopics[this.
|
|
120
|
-
Date.now() - this.SubscribedTopics[this.
|
|
340
|
+
!this.SubscribedTopics[this.PublishedIds[id].Topic] ||
|
|
341
|
+
this.SubscribedTopics[this.PublishedIds[id].Topic].val !== val ||
|
|
342
|
+
Date.now() - this.SubscribedTopics[this.PublishedIds[id].Topic].ts >= this.MinTime
|
|
121
343
|
) {
|
|
122
|
-
this.
|
|
123
|
-
this.
|
|
124
|
-
|
|
344
|
+
this.PublishedIds[id].ts = Date.now();
|
|
345
|
+
this.PublishedIds[id].val = val;
|
|
346
|
+
if (typeof val !== 'string') {
|
|
347
|
+
val = JSON.stringify(val);
|
|
348
|
+
}
|
|
349
|
+
await this.bridgeMqttClient.publish(this.PublishedIds[id].Topic, val, {
|
|
125
350
|
retain: true,
|
|
126
351
|
});
|
|
127
352
|
}
|
|
353
|
+
} else {
|
|
354
|
+
this.adapter.log.debug(`Id not for publish used.`);
|
|
128
355
|
}
|
|
129
356
|
} catch (error) {
|
|
130
357
|
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
@@ -136,7 +363,7 @@ class bridgeClass {
|
|
|
136
363
|
* @param options Options for using spezial fuctions
|
|
137
364
|
*/
|
|
138
365
|
async buildDiscovery(id, options) {
|
|
139
|
-
const activeFunction = 'bridge.js -
|
|
366
|
+
const activeFunction = 'bridge.js - buildDiscovery';
|
|
140
367
|
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
141
368
|
try {
|
|
142
369
|
// Query for decoded Folder
|
|
@@ -170,17 +397,27 @@ class bridgeClass {
|
|
|
170
397
|
options.Bridgestate = Bridgestate;
|
|
171
398
|
const DiscoveryObject = await this.getDiscoveryObject(changeInfo, options);
|
|
172
399
|
if (Bridgestate.publish) {
|
|
173
|
-
this.
|
|
174
|
-
|
|
175
|
-
|
|
400
|
+
if (!this.PublishedIds[id]) {
|
|
401
|
+
this.PublishedIds[id] = { discovery: [] };
|
|
402
|
+
}
|
|
403
|
+
this.PublishedIds[id].Topic = DiscoveryObject?.Topic;
|
|
404
|
+
this.PublishedIds[id].discovery.push({
|
|
405
|
+
topic: DiscoveryObject?.topic,
|
|
406
|
+
payload: structuredClone(DiscoveryObject?.payload),
|
|
407
|
+
});
|
|
408
|
+
this.PublishedIds[id].val = 0;
|
|
409
|
+
this.PublishedIds[id].ts = Date.now();
|
|
176
410
|
}
|
|
177
411
|
if (Bridgestate.subscribe) {
|
|
178
412
|
this.SubscribedTopics[DiscoveryObject?.Topic] = {};
|
|
179
413
|
this.SubscribedTopics[DiscoveryObject?.Topic].id = id;
|
|
180
414
|
this.SubscribedTopics[DiscoveryObject?.Topic].val = 0;
|
|
181
|
-
this.SubscribedTopics[DiscoveryObject?.Topic].ts = Date.now();
|
|
415
|
+
this.SubscribedTopics[DiscoveryObject?.Topic].ts = Date.now() - this.MinTime;
|
|
182
416
|
}
|
|
183
|
-
await this.publishDiscovery(id,
|
|
417
|
+
await this.publishDiscovery(id, {
|
|
418
|
+
topic: DiscoveryObject?.topic,
|
|
419
|
+
payload: structuredClone(DiscoveryObject?.payload),
|
|
420
|
+
});
|
|
184
421
|
}
|
|
185
422
|
}
|
|
186
423
|
|
|
@@ -218,19 +455,30 @@ class bridgeClass {
|
|
|
218
455
|
options.Bridgestate = Bridgestate;
|
|
219
456
|
const DiscoveryObject = await this.getDiscoveryObject(changeInfo, options);
|
|
220
457
|
if (Bridgestate.publish) {
|
|
221
|
-
this.
|
|
458
|
+
if (!this.PublishedIds[id]) {
|
|
459
|
+
this.PublishedIds[id] = { discovery: [] };
|
|
460
|
+
}
|
|
461
|
+
this.PublishedIds[id].Topic = DiscoveryObject?.Topic;
|
|
462
|
+
this.PublishedIds[id].discovery.push({
|
|
463
|
+
topic: DiscoveryObject?.topic,
|
|
464
|
+
payload: structuredClone(DiscoveryObject?.payload),
|
|
465
|
+
});
|
|
466
|
+
this.PublishedIds[id].val = 0;
|
|
467
|
+
this.PublishedIds[id].ts = Date.now();
|
|
222
468
|
}
|
|
223
469
|
if (Bridgestate.subscribe) {
|
|
224
470
|
this.SubscribedTopics[DiscoveryObject?.Topic] = {};
|
|
225
471
|
this.SubscribedTopics[DiscoveryObject?.Topic].id = id;
|
|
226
472
|
this.SubscribedTopics[DiscoveryObject?.Topic].val = 0;
|
|
227
|
-
this.SubscribedTopics[DiscoveryObject?.Topic].ts = Date.now();
|
|
473
|
+
this.SubscribedTopics[DiscoveryObject?.Topic].ts = Date.now() - this.MinTime;
|
|
228
474
|
}
|
|
229
|
-
await this.publishDiscovery(id,
|
|
475
|
+
await this.publishDiscovery(id, {
|
|
476
|
+
topic: DiscoveryObject?.topic,
|
|
477
|
+
payload: structuredClone(DiscoveryObject?.payload),
|
|
478
|
+
});
|
|
230
479
|
}
|
|
231
480
|
}
|
|
232
481
|
}
|
|
233
|
-
this.CheckedIds[id] = {};
|
|
234
482
|
} catch (error) {
|
|
235
483
|
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
236
484
|
}
|
|
@@ -275,7 +523,7 @@ class bridgeClass {
|
|
|
275
523
|
for (const Attribute in AdditionalAttributes) {
|
|
276
524
|
DiscoveryPayload[Attribute] = AdditionalAttributes[Attribute];
|
|
277
525
|
}
|
|
278
|
-
return { Topic: Topic,
|
|
526
|
+
return { Topic: Topic, topic: DiscoveryTopic, payload: DiscoveryPayload };
|
|
279
527
|
} catch (error) {
|
|
280
528
|
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
281
529
|
}
|
|
@@ -294,11 +542,9 @@ class bridgeClass {
|
|
|
294
542
|
this.adapter.log.debug(`Function ${activeFunction} started.`);
|
|
295
543
|
try {
|
|
296
544
|
this.DiscoveredIds[id] = DiscoveryObject;
|
|
297
|
-
await this.bridgeMqttClient.publish(
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
{},
|
|
301
|
-
);
|
|
545
|
+
await this.bridgeMqttClient.publish(DiscoveryObject.topic, JSON.stringify(DiscoveryObject.payload), {
|
|
546
|
+
retain: true,
|
|
547
|
+
});
|
|
302
548
|
await this.adapter.setState('info.discoveredIds', JSON.stringify(this.DiscoveredIds), true);
|
|
303
549
|
} catch (error) {
|
|
304
550
|
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
@@ -617,6 +863,7 @@ class bridgeClass {
|
|
|
617
863
|
}
|
|
618
864
|
}
|
|
619
865
|
}
|
|
866
|
+
await this.discoverClimate();
|
|
620
867
|
} catch (error) {
|
|
621
868
|
this.adapter.log.error(`error at ${activeFunction}: ${error}`);
|
|
622
869
|
}
|
|
@@ -72,10 +72,17 @@ class bridgeMqttClientClass {
|
|
|
72
72
|
this.client.on('message', async (topic, message) => {
|
|
73
73
|
this.adapter.log.debug(`incomming bridge topic: ${topic}`);
|
|
74
74
|
this.adapter.log.debug(`incomming bridge message: ${message}`);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
//
|
|
78
|
-
|
|
75
|
+
|
|
76
|
+
let payload = message.toString('utf8');
|
|
77
|
+
// Message Parsen => Wenn nicht pasebar, dann string weitergeben
|
|
78
|
+
try {
|
|
79
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
80
|
+
// @ts-expect-error
|
|
81
|
+
payload = JSON.parse(message);
|
|
82
|
+
} catch {
|
|
83
|
+
this.adapter.log.debug(`The Message ${message} is not parsabele. Work with string`);
|
|
84
|
+
}
|
|
85
|
+
await this.adapter.bridge.handleMessage(topic, payload);
|
|
79
86
|
});
|
|
80
87
|
}
|
|
81
88
|
/**
|
|
@@ -480,7 +480,7 @@ class directorieshandlerClass {
|
|
|
480
480
|
});
|
|
481
481
|
// Add Bridged Funktion (MQTT auto discovery)
|
|
482
482
|
// Add for new state
|
|
483
|
-
await this.adapter.bridge
|
|
483
|
+
await this.adapter.bridge?.work(objectId, stateVal, { common: common });
|
|
484
484
|
if (typeof stateVal === 'object') {
|
|
485
485
|
stateVal = JSON.stringify(stateVal);
|
|
486
486
|
}
|
|
@@ -136,7 +136,9 @@ class messagehandlerClass {
|
|
|
136
136
|
const adapterObjectsAtStart = await this.adapter.getAdapterObjectsAsync();
|
|
137
137
|
for (const adapterObject of Object.values(adapterObjectsAtStart)) {
|
|
138
138
|
if (adapterObject.type === 'device') {
|
|
139
|
-
await this.fillWithDownlinkConfig(this.adapter.removeNamespace(adapterObject._id), {
|
|
139
|
+
await this.fillWithDownlinkConfig(this.adapter.removeNamespace(adapterObject._id), {
|
|
140
|
+
startup: true,
|
|
141
|
+
});
|
|
140
142
|
//await this.addDirectoriesToPresentDirectory(`${stateId}`); Not used yet (Maybe for thefuture with more folders)
|
|
141
143
|
}
|
|
142
144
|
}
|
|
@@ -524,6 +526,11 @@ class messagehandlerClass {
|
|
|
524
526
|
if (downlinkDevice !== this.adapter.downlinkConfighandler.internalDevices.baseDevice) {
|
|
525
527
|
foundLength[downlinkParameter.name] = downlinkDevice.length;
|
|
526
528
|
}
|
|
529
|
+
// Add Bridged Funktion (MQTT auto discovery) only in Message
|
|
530
|
+
if (!options?.startup) {
|
|
531
|
+
await this.adapter.bridge.work(stateId, undefined, { common: common });
|
|
532
|
+
}
|
|
533
|
+
|
|
527
534
|
//check for right type of data (after a possible change)
|
|
528
535
|
if (!options || !options.inMessage) {
|
|
529
536
|
const state = await this.adapter.getStateAsync(stateId);
|
package/main.js
CHANGED
|
@@ -77,8 +77,8 @@ class Lorawan extends utils.Adapter {
|
|
|
77
77
|
this.subscribeStatesAsync('*');
|
|
78
78
|
//this.subscribeObjectsAsync('*.uplink.decoded.*');
|
|
79
79
|
//this.subscribeObjectsAsync('*.downlink.control.*');
|
|
80
|
-
this.log.
|
|
81
|
-
this.log.
|
|
80
|
+
this.log.debug(`the adapter starts with downlinkconfigs: ${JSON.stringify(this.config.downlinkConfig)}.`);
|
|
81
|
+
this.log.debug(
|
|
82
82
|
`the active downlinkconfigs are: ${JSON.stringify(this.downlinkConfighandler.activeDownlinkConfigs)}`,
|
|
83
83
|
);
|
|
84
84
|
/*
|
|
@@ -409,12 +409,12 @@ class Lorawan extends utils.Adapter {
|
|
|
409
409
|
const activeFunction = 'onStateChange';
|
|
410
410
|
try {
|
|
411
411
|
if (state) {
|
|
412
|
-
//this.log.
|
|
412
|
+
//this.log.debug(`state ${id} changed: val: ${state.val} - ack: ${state.ack}`);
|
|
413
413
|
// The state was changed => only states with ack = false will be processed, others will be ignored
|
|
414
414
|
if (!state.ack) {
|
|
415
415
|
// Check for downlink in id
|
|
416
416
|
if (id.indexOf('.downlink.control.') !== -1) {
|
|
417
|
-
this.log.
|
|
417
|
+
this.log.debug(`the state ${id} has changed to ${state.val}.`);
|
|
418
418
|
// get information of the changing state
|
|
419
419
|
const changeInfo = await this.getChangeInfo(id, { withBestMatch: true });
|
|
420
420
|
const suffix = this.downlinkConfighandler?.getDownlinkTopicSuffix(changeInfo?.changedState);
|
|
@@ -538,7 +538,7 @@ class Lorawan extends utils.Adapter {
|
|
|
538
538
|
async checkSendDownlinkWithUplink(id) {
|
|
539
539
|
const activeFunction = 'checkSendDownlinkWithUplink';
|
|
540
540
|
try {
|
|
541
|
-
this.log.
|
|
541
|
+
this.log.debug(`Check for send downlink with uplink.`);
|
|
542
542
|
const changeInfo = await this.getChangeInfo(id, { withBestMatch: true });
|
|
543
543
|
if (
|
|
544
544
|
changeInfo &&
|
|
@@ -637,7 +637,7 @@ class Lorawan extends utils.Adapter {
|
|
|
637
637
|
async getChangeInfo(id, options) {
|
|
638
638
|
const activeFunction = 'getChangeInfo';
|
|
639
639
|
try {
|
|
640
|
-
this.log.
|
|
640
|
+
this.log.debug(`changeinfo of id ${id}, will be generated.`);
|
|
641
641
|
const changeInfo = this.getBaseDeviceInfo(id);
|
|
642
642
|
const myId = `${changeInfo?.objectStartDirectory}.${this.messagehandler?.directoryhandler.reachableSubfolders.configuration}.devicetype`;
|
|
643
643
|
// Check for changeInfo
|
|
@@ -672,7 +672,7 @@ class Lorawan extends utils.Adapter {
|
|
|
672
672
|
}
|
|
673
673
|
}
|
|
674
674
|
}
|
|
675
|
-
this.log.
|
|
675
|
+
this.log.debug(`changeinfo is ${JSON.stringify(changeInfo)}.`);
|
|
676
676
|
return changeInfo;
|
|
677
677
|
} catch (error) {
|
|
678
678
|
this.log.error(`error at ${activeFunction}: ${error}`);
|
|
@@ -681,7 +681,7 @@ class Lorawan extends utils.Adapter {
|
|
|
681
681
|
|
|
682
682
|
removeNamespace(id) {
|
|
683
683
|
if (id.indexOf(this.namespace) !== -1) {
|
|
684
|
-
this.log.
|
|
684
|
+
this.log.debug(`namespace will be removed from id ${id}.`);
|
|
685
685
|
id = id.substring(this.namespace.length + 1, id.length);
|
|
686
686
|
}
|
|
687
687
|
return id;
|
|
@@ -931,10 +931,21 @@ class Lorawan extends utils.Adapter {
|
|
|
931
931
|
}
|
|
932
932
|
|
|
933
933
|
// send application to config
|
|
934
|
-
} else if (
|
|
934
|
+
} else if (
|
|
935
|
+
obj.command === 'getApplicationsForConfig' ||
|
|
936
|
+
obj.command === 'getApplicationsForClimateConfig' ||
|
|
937
|
+
obj.command === 'getApplicationsForClimateModeConfig'
|
|
938
|
+
) {
|
|
935
939
|
try {
|
|
936
|
-
let myCount =
|
|
937
|
-
const applications = [
|
|
940
|
+
let myCount = 0;
|
|
941
|
+
const applications = [];
|
|
942
|
+
if (obj.command === 'getApplicationsForConfig') {
|
|
943
|
+
applications[myCount] = { label: '* (Wildcard)', value: '*' };
|
|
944
|
+
myCount++;
|
|
945
|
+
} else if (obj.command === 'getApplicationsForClimateModeConfig') {
|
|
946
|
+
applications[myCount] = { label: '* Not Present (Virtual)', value: 'NotPresent' };
|
|
947
|
+
myCount++;
|
|
948
|
+
}
|
|
938
949
|
const currentApplications = {};
|
|
939
950
|
const adapterObjects = await this.getAdapterObjectsAsync();
|
|
940
951
|
for (const adapterObject of Object.values(adapterObjects)) {
|
|
@@ -955,10 +966,14 @@ class Lorawan extends utils.Adapter {
|
|
|
955
966
|
} catch (error) {
|
|
956
967
|
this.log.error(error);
|
|
957
968
|
}
|
|
958
|
-
} else if (obj.command === 'getDevicesForConfig') {
|
|
969
|
+
} else if (obj.command === 'getDevicesForConfig' || obj.command === 'getDevicesForClimateConfig') {
|
|
959
970
|
try {
|
|
960
|
-
let myCount =
|
|
961
|
-
const devices = [
|
|
971
|
+
let myCount = 0;
|
|
972
|
+
const devices = [];
|
|
973
|
+
if (obj.command === 'getDevicesForConfig') {
|
|
974
|
+
devices[myCount] = { label: '* (Wildcard)', value: '*' };
|
|
975
|
+
myCount++;
|
|
976
|
+
}
|
|
962
977
|
const adapterObjects = await this.getAdapterObjectsAsync();
|
|
963
978
|
for (const adapterObject of Object.values(adapterObjects)) {
|
|
964
979
|
if (
|
|
@@ -991,10 +1006,14 @@ class Lorawan extends utils.Adapter {
|
|
|
991
1006
|
} catch (error) {
|
|
992
1007
|
this.log.error(error);
|
|
993
1008
|
}
|
|
994
|
-
} else if (obj.command === 'getStatesForConfig') {
|
|
1009
|
+
} else if (obj.command === 'getStatesForConfig' || obj.command === 'getStatesForClimateConfig') {
|
|
995
1010
|
try {
|
|
996
|
-
let myCount =
|
|
997
|
-
const states = [
|
|
1011
|
+
let myCount = 0;
|
|
1012
|
+
const states = [];
|
|
1013
|
+
if (obj.command === 'getDevicesForConfig') {
|
|
1014
|
+
states[myCount] = { label: '* (Wildcard)', value: '*' };
|
|
1015
|
+
myCount++;
|
|
1016
|
+
}
|
|
998
1017
|
const currentStates = {};
|
|
999
1018
|
const adapterObjects = await this.getAdapterObjectsAsync();
|
|
1000
1019
|
for (const adapterObject of Object.values(adapterObjects)) {
|
|
@@ -1035,6 +1054,39 @@ class Lorawan extends utils.Adapter {
|
|
|
1035
1054
|
} catch (error) {
|
|
1036
1055
|
this.log.error(error);
|
|
1037
1056
|
}
|
|
1057
|
+
} else if (obj.command === 'getDiscoveredIds') {
|
|
1058
|
+
try {
|
|
1059
|
+
this.sendTo(
|
|
1060
|
+
obj.from,
|
|
1061
|
+
obj.command,
|
|
1062
|
+
JSON.stringify(this.bridge?.DiscoveredIds, null, 2),
|
|
1063
|
+
obj.callback,
|
|
1064
|
+
);
|
|
1065
|
+
} catch (error) {
|
|
1066
|
+
this.log.error(error);
|
|
1067
|
+
}
|
|
1068
|
+
} else if (obj.command === 'getPublishedIds') {
|
|
1069
|
+
try {
|
|
1070
|
+
this.sendTo(
|
|
1071
|
+
obj.from,
|
|
1072
|
+
obj.command,
|
|
1073
|
+
JSON.stringify(this.bridge?.PublishedIds, null, 2),
|
|
1074
|
+
obj.callback,
|
|
1075
|
+
);
|
|
1076
|
+
} catch (error) {
|
|
1077
|
+
this.log.error(error);
|
|
1078
|
+
}
|
|
1079
|
+
} else if (obj.command === 'getSubscribedTopics') {
|
|
1080
|
+
try {
|
|
1081
|
+
this.sendTo(
|
|
1082
|
+
obj.from,
|
|
1083
|
+
obj.command,
|
|
1084
|
+
JSON.stringify(this.bridge?.SubscribedTopics, null, 2),
|
|
1085
|
+
obj.callback,
|
|
1086
|
+
);
|
|
1087
|
+
} catch (error) {
|
|
1088
|
+
this.log.error(error);
|
|
1089
|
+
}
|
|
1038
1090
|
} else {
|
|
1039
1091
|
const result = { error: true, message: 'No message matched', received: obj.message };
|
|
1040
1092
|
if (obj.callback) {
|