iobroker.e3oncan 0.6.14 → 0.6.16
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 +12 -5
- package/admin/jsonConfig.json +1 -1
- package/io-package.json +27 -27
- package/lib/canCollect.js +4 -8
- package/lib/canUds.js +64 -68
- package/lib/codecs.js +17 -7
- package/lib/codecs.test.js +57 -1
- package/lib/storage.js +7 -11
- package/lib/udsScan.js +6 -6
- package/main.js +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ In parallel **reading of datapoints** (ReadByDid) is supported. Informations not
|
|
|
21
21
|
|
|
22
22
|
**Writing of datapoints** via UDSonCAN (WriteByDid) is supported as well. By writing to datapoints it's possible to change setpoints, schedules and so on. It's even possible to add new schedules e.g. for domestic hot water circulation pump.
|
|
23
23
|
|
|
24
|
-
Writing of data is triggered by storing the corresponding state with `Acknowledged` not checked (ack=false) - yes, it's that simple! The datapoint will be read again from device and stored in the state
|
|
24
|
+
Writing of data is triggered by storing the corresponding state with `Acknowledged` not checked (ack=false) - yes, it's that simple! The datapoint will be read again from device and stored in the state 2.5 seconds after writing. If state not get's acknowledged, please take a look to the logs.
|
|
25
25
|
|
|
26
26
|
Writing is restricted to a set of datapoints using a **white list**. The list is stored in the info section of each device, e.g. at `e3oncan.0.vitocal.info.udsDidsWritable`. You can add more datapoints by editing this state. Make sure, **not** to check `Acknowledged` when saving the state.
|
|
27
27
|
|
|
@@ -39,13 +39,13 @@ A python based implementation of a pure listening approach using MQTT messaging
|
|
|
39
39
|
* Currently only Linux based systems are supported.
|
|
40
40
|
* CAN adapter is up and visible in system, e.g. as "can0" (use ifconfig to check).
|
|
41
41
|
* Refer to open3e project for further details
|
|
42
|
-
* **Make sure,
|
|
42
|
+
* **Make sure, no other UDSonCAN client (e.g. Open3Eclient.py) is running during initial setup!** This could cause communication errors in both applications.
|
|
43
43
|
|
|
44
44
|
All services provided by this adapter are based on device list of your specific Viessmann E3 setup. Therefore you have to follow following steps for first setup:
|
|
45
45
|
|
|
46
46
|
**Configuration**
|
|
47
47
|
* When installation of adapter has finished a confuration dialog will show up to configure up to two CAN bus adapters (tab "CAN ADAPTER")
|
|
48
|
-
* Edit name of adapter and check the "Connect to adapter" checkbox at least the external adapter
|
|
48
|
+
* Edit name of adapter and check the "Connect to adapter" checkbox at least for the external adapter
|
|
49
49
|
* When you're done, press "SAVE" button to apply the changes. This step is **mandatory**. The instance will restart and connect to the CAN adapter.
|
|
50
50
|
* Go to tab "LIST OF UDS DEVICES" and do a scan for devices available on bus by pressing the scan button. **This will take a few seconds.** You may watch the activities in a 2nd browser tab by looking on the logging info of the adapter.
|
|
51
51
|
* You may change the naming of the devices at 2nd column. Those names will be used to store all collected data in ioBoker's object tree. Again press "SAVE" button when you did your changes.
|
|
@@ -65,11 +65,11 @@ You may use datapoints informations on tab "LIST OF DATAPOINTS" for reference (o
|
|
|
65
65
|
| ID | Data| Unit |
|
|
66
66
|
| ------|:--- |------|
|
|
67
67
|
| 0x250 | Active Power L1, L2, L3, Total | W |
|
|
68
|
-
| 0x252 | Reactive Power L1, L2, L3, Total |
|
|
68
|
+
| 0x252 | Reactive Power L1, L2, L3, Total | VA |
|
|
69
69
|
| 0x254 | Current, L1, L2, L3, cosPhi | A, - |
|
|
70
70
|
| 0x256 | Voltage, L1, L2, L3, Frequency | V, Hz |
|
|
71
71
|
| 0x258 | Cumulated Import, Export | kWh |
|
|
72
|
-
| 0x25A | Total Active Power, Total Reactive Power | W |
|
|
72
|
+
| 0x25A | Total Active Power, Total Reactive Power | W, VA |
|
|
73
73
|
| 0x25C | Cumulated Import | kWh |
|
|
74
74
|
|
|
75
75
|
# Hints and limitations
|
|
@@ -102,6 +102,13 @@ Yes, that is possible under certain conditions:
|
|
|
102
102
|
Placeholder for the next version (at the beginning of the line):
|
|
103
103
|
### **WORK IN PROGRESS**
|
|
104
104
|
-->
|
|
105
|
+
### 0.6.16 (2024-01-27)
|
|
106
|
+
* (MyHomeMyData) Improvements based on findings in review as of 2024-01-25
|
|
107
|
+
* (MyHomeMyData) Checkbox for data collectiton on internal bus is now checked per default
|
|
108
|
+
|
|
109
|
+
### 0.6.15 (2024-01-23)
|
|
110
|
+
* (MyHomeMyData) Fix for Utf8 codec for handling of special characters, e.g. umlauts
|
|
111
|
+
|
|
105
112
|
### 0.6.14 (2024-01-22)
|
|
106
113
|
* (MyHomeMyData) Replace '.' by '_' in datapoint ids to avoid unwanted sub structure in data states
|
|
107
114
|
* (MyHomeMyData) Added more informations about white list for writables in Readme.
|
package/admin/jsonConfig.json
CHANGED
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "e3oncan",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.16",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.6.16": {
|
|
7
|
+
"en": "Improvements based on findings in review as of 2024-01-25\nCheckbox for data collectiton on internal bus is now checked per default",
|
|
8
|
+
"de": "Verbesserungen auf der Grundlage der Ergebnisse in der Überprüfung ab 2024-01-25\nCheckbox für Datensammler im internen Bus wird nun standardmäßig überprüft",
|
|
9
|
+
"ru": "Совершенствование на основе результатов, рассмотренных на 2024-01-25 годы\nCheckbox для сбора данных на внутреннем автобусе теперь проверяется по умолчанию",
|
|
10
|
+
"pt": "Aperfeiçoamentos baseados em achados em revisão a partir de 2024-01-25\nCaixa de seleção para coleta de dados no ônibus interno é agora verificada por padrão",
|
|
11
|
+
"nl": "Verbeteringen op basis van de resultaten van het onderzoek per 2024-01-25\nCheckbox voor gegevensverzameling op interne bus is nu standaard aangevinkt",
|
|
12
|
+
"fr": "Améliorations fondées sur les conclusions de l'examen en 2024-01-25\nLa case à cocher pour les données collectiton sur le bus interne est maintenant cochée par défaut",
|
|
13
|
+
"it": "Miglioramenti basati sui risultati in esame a partire dal 2024-01-25\nLa casella di controllo per i dati collettivi sul bus interno è ora controllata per impostazione predefinita",
|
|
14
|
+
"es": "Mejoras basadas en los resultados examinados al 2024-01-25\nCheckbox for data collectiton on internal bus is now check per default",
|
|
15
|
+
"pl": "Poprawki oparte na ustaleniach w przeglądzie z 2024- 01- 25\nSkrzynka kontrolna dla kolekcji danych w autobusie wewnętrznym jest teraz sprawdzana na domyślnym",
|
|
16
|
+
"uk": "Удосконалення на основі пошуку в рецензії на 2024-01-25\nCheckbox для збору даних у внутрішньому автобусі тепер перевіряється за замовчуванням",
|
|
17
|
+
"zh-cn": "根据截至2024-01-25年审查结果作出的改进\n内部总线上数据集合的复选框现在按默认检查"
|
|
18
|
+
},
|
|
19
|
+
"0.6.15": {
|
|
20
|
+
"en": "Fix for Utf8 codec for handling of special characters, e.g. umlauts",
|
|
21
|
+
"de": "Fix für Utf8-Codec zum Umgang mit Sonderzeichen, z.B. umlauts",
|
|
22
|
+
"ru": "Fix for Utf8 codec для обработки специальных символов, например, umlauts",
|
|
23
|
+
"pt": "Fix para Codec Utf8 para manipulação de caracteres especiais, por exemplo, umlauts",
|
|
24
|
+
"nl": "Fix voor Utf8 codec voor het hanteren van speciale tekens, bijvoorbeeld umlauts",
|
|
25
|
+
"fr": "Correction pour Codec Utf8 pour la manipulation de caractères spéciaux, p.ex. umlauts",
|
|
26
|
+
"it": "Fissaggio per Codice Utf8 per la gestione di caratteri speciali, ad esempio umlauts",
|
|
27
|
+
"es": "Corrección Utf8 codec para el manejo de caracteres especiales, por ejemplo umlauts",
|
|
28
|
+
"pl": "Napraw dla Kod Utf8 do obsługi znaków specjalnych, np. umlautów",
|
|
29
|
+
"uk": "Фіксація Utf8 кодека для обробки спеціальних символів, наприклад, umlauts",
|
|
30
|
+
"zh-cn": "修复 Utf8 处理特殊字符的编码器, 例如 umlauts"
|
|
31
|
+
},
|
|
6
32
|
"0.6.14": {
|
|
7
33
|
"en": "Replace '.' by '_' in datapoint ids to avoid unwanted sub structure in data states\nAdded more informations about white list for writables in Readme.\nRecognize loss of CAN connection.\nImproved handling of info.connection.",
|
|
8
34
|
"de": "Ersetzen Sie '.' durch '_' in Datapoint ids, um unerwünschte Unterstruktur in Datenzuständen zu vermeiden\nWeitere Informationen zur Weißen Liste für schreibbare in Readme.\nErkennen Verlust der CAN-Verbindung.\nVerbesserte Handhabung von info.connection.",
|
|
@@ -67,32 +93,6 @@
|
|
|
67
93
|
"pl": "Usunięto kod dla Rawmode ponieważ nigdy nie jest aktywowany",
|
|
68
94
|
"uk": "Видалити код для Rawmode, тому що він ніколи не активований",
|
|
69
95
|
"zh-cn": "删除了Rawmode的代码,因为它从未被激活"
|
|
70
|
-
},
|
|
71
|
-
"0.6.9": {
|
|
72
|
-
"en": "Bugfix: Only Linux is supported",
|
|
73
|
-
"de": "Bugfix: Nur Linux wird unterstützt",
|
|
74
|
-
"ru": "Исправление: Только Linux поддерживается",
|
|
75
|
-
"pt": "Bugfix: Apenas o Linux é suportado",
|
|
76
|
-
"nl": "Bugfix: Alleen Linux wordt ondersteund",
|
|
77
|
-
"fr": "Correction : Seul Linux est pris en charge",
|
|
78
|
-
"it": "Bugfix: Solo Linux è supportato",
|
|
79
|
-
"es": "Bugfix: Sólo Linux es compatible",
|
|
80
|
-
"pl": "Bugfix: Tylko Linux jest obsługiwany",
|
|
81
|
-
"uk": "Помилки: Тільки Linux підтримується",
|
|
82
|
-
"zh-cn": "错误修正 : 仅支持 Linux"
|
|
83
|
-
},
|
|
84
|
-
"0.6.8": {
|
|
85
|
-
"en": "Initial npm version",
|
|
86
|
-
"de": "Ursprüngliche npm-Version",
|
|
87
|
-
"ru": "Первоначальная версия npm",
|
|
88
|
-
"pt": "Versão inicial npm",
|
|
89
|
-
"nl": "Eerste npm-versie",
|
|
90
|
-
"fr": "Version initiale npm",
|
|
91
|
-
"it": "Versione npm iniziale",
|
|
92
|
-
"es": "Versión inicial npm",
|
|
93
|
-
"pl": "Początkowa wersja npm",
|
|
94
|
-
"uk": "Початкова версія npm",
|
|
95
|
-
"zh-cn": "初始 npm 版本"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"title": "Viessmann E3 CAN do",
|
package/lib/canCollect.js
CHANGED
|
@@ -57,7 +57,7 @@ class collect {
|
|
|
57
57
|
await this.storage.setOpMode('standby');
|
|
58
58
|
|
|
59
59
|
// Stop Timeout:
|
|
60
|
-
if (this.timeoutHandle) await clearTimeout(this.timeoutHandle);
|
|
60
|
+
if (this.timeoutHandle) await ctx.clearTimeout(this.timeoutHandle);
|
|
61
61
|
this.timeoutHandle = null;
|
|
62
62
|
|
|
63
63
|
this.stat.state = 'stopped';
|
|
@@ -71,10 +71,6 @@ class collect {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
sleep(milliseconds) {
|
|
75
|
-
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
74
|
async msgCollect(ctx, msg) {
|
|
79
75
|
|
|
80
76
|
if (await this.storage.getOpMode() == 'standby') return; // No communication in mode 'standby'
|
|
@@ -109,7 +105,7 @@ class collect {
|
|
|
109
105
|
this.data.databytes = this.data.databytes.concat(candata.slice(1));
|
|
110
106
|
if (this.data.databytes.length >= this.data.len) {
|
|
111
107
|
// All data received
|
|
112
|
-
if (this.timeoutHandle) await clearTimeout(this.timeoutHandle);
|
|
108
|
+
if (this.timeoutHandle) await ctx.clearTimeout(this.timeoutHandle);
|
|
113
109
|
this.stat.cntCommOk += 1;
|
|
114
110
|
if (!(this.data.did in this.ts)) { this.ts[this.data.did] = tsNow; }
|
|
115
111
|
if ( (this.config.delay == 0) || ((tsNow >= this.ts[this.data.did])) ) {
|
|
@@ -162,7 +158,7 @@ class collect {
|
|
|
162
158
|
this.data.databytes = candata.slice(5);
|
|
163
159
|
this.data.len = candata[4];
|
|
164
160
|
}
|
|
165
|
-
this.timeoutHandle = setTimeout(this.onTimeout, this.config.timeout, ctx, this);
|
|
161
|
+
this.timeoutHandle = ctx.setTimeout(this.onTimeout, this.config.timeout, ctx, this);
|
|
166
162
|
this.data.collecting = true;
|
|
167
163
|
break;
|
|
168
164
|
case 0xb5:
|
|
@@ -181,7 +177,7 @@ class collect {
|
|
|
181
177
|
this.data.D0expected = candata[0]+1;
|
|
182
178
|
this.data.databytes = candata.slice(4);
|
|
183
179
|
this.data.len = D3-0xb0;
|
|
184
|
-
this.timeoutHandle = setTimeout(this.onTimeout, this.config.timeout, ctx, this);
|
|
180
|
+
this.timeoutHandle = ctx.setTimeout(this.onTimeout, this.config.timeout, ctx, this);
|
|
185
181
|
this.data.collecting = true;
|
|
186
182
|
break;
|
|
187
183
|
default:
|
package/lib/canUds.js
CHANGED
|
@@ -9,21 +9,21 @@ class scheduleLoop {
|
|
|
9
9
|
this.schedHandle = null;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
async startSchedule() {
|
|
12
|
+
async startSchedule(ctx) {
|
|
13
13
|
if (this.schedule == 0) {
|
|
14
14
|
await this.ctxGlobal.log.silly('UDS schedule one time: '+this.ctxLocal.canIDhex+'.'+JSON.stringify(this.dids));
|
|
15
15
|
await this.ctxLocal.pushCmnd(this.ctxGlobal, 'read', this.dids);
|
|
16
16
|
this.schedHandle = null;
|
|
17
17
|
} else {
|
|
18
|
-
this.schedHandle = setInterval(async () => {
|
|
18
|
+
this.schedHandle = ctx.setInterval(async () => {
|
|
19
19
|
await this.loop();
|
|
20
20
|
}, this.schedule*1000);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
async stopSchedule() {
|
|
24
|
+
async stopSchedule(ctx) {
|
|
25
25
|
try {
|
|
26
|
-
if (this.schedHandle) await clearInterval(this.schedHandle);
|
|
26
|
+
if (this.schedHandle) await ctx.clearInterval(this.schedHandle);
|
|
27
27
|
await this.ctxGlobal.log.silly('UDS schedule stopped: '+String(this.schedule)+' '+this.ctxLocal.canIDhex+'.'+JSON.stringify(this.dids));
|
|
28
28
|
} catch (e) {
|
|
29
29
|
// Dod nothing
|
|
@@ -110,7 +110,6 @@ class uds {
|
|
|
110
110
|
type: 'channel',
|
|
111
111
|
common: {
|
|
112
112
|
name: this.config.stateBase+' commands',
|
|
113
|
-
role: 'device'
|
|
114
113
|
},
|
|
115
114
|
native: {},
|
|
116
115
|
});
|
|
@@ -139,7 +138,7 @@ class uds {
|
|
|
139
138
|
if (opMode == 'normal') {
|
|
140
139
|
for (const sched of Object.values(this.schedules)) {
|
|
141
140
|
// Start schedules on startup and do one-time schedules
|
|
142
|
-
await sched.startSchedule();
|
|
141
|
+
await sched.startSchedule(ctx);
|
|
143
142
|
}
|
|
144
143
|
}
|
|
145
144
|
if (opMode == 'normal') {
|
|
@@ -147,7 +146,7 @@ class uds {
|
|
|
147
146
|
} else {
|
|
148
147
|
await ctx.log.silly('UDS worker started in mode '+opMode+' on '+this.config.stateBase);
|
|
149
148
|
}
|
|
150
|
-
this.cmndsHandle = setInterval(async () => {
|
|
149
|
+
this.cmndsHandle = ctx.setInterval(async () => {
|
|
151
150
|
await this.cmndsLoop(ctx);
|
|
152
151
|
}, this.cmndsUpdateTime);
|
|
153
152
|
}
|
|
@@ -164,18 +163,18 @@ class uds {
|
|
|
164
163
|
|
|
165
164
|
// Stop loops:
|
|
166
165
|
for (const sched of Object.values(this.schedules)) {
|
|
167
|
-
await sched.stopSchedule();
|
|
166
|
+
await sched.stopSchedule(ctx);
|
|
168
167
|
}
|
|
169
|
-
if (this.cmndsHandle) await clearInterval(this.cmndsHandle);
|
|
168
|
+
if (this.cmndsHandle) await ctx.clearInterval(this.cmndsHandle);
|
|
170
169
|
|
|
171
170
|
// Stop Timeout:
|
|
172
|
-
if (this.timeoutHandle) await clearTimeout(this.timeoutHandle);
|
|
171
|
+
if (this.timeoutHandle) await ctx.clearTimeout(this.timeoutHandle);
|
|
173
172
|
this.timeoutHandle = null;
|
|
174
173
|
|
|
175
174
|
// Stop worker:
|
|
176
175
|
this.callback = null;
|
|
177
176
|
if (opMode == 'normal') {
|
|
178
|
-
|
|
177
|
+
ctx.unsubscribeStates(ctx.namespace+'.'+this.config.stateBase+'.*');
|
|
179
178
|
await ctx.log.info('UDS worker stopped on '+this.config.stateBase);
|
|
180
179
|
} else {
|
|
181
180
|
await ctx.log.silly('UDS worker stopped in mode '+opMode+' on '+this.config.stateBase);
|
|
@@ -201,12 +200,12 @@ class uds {
|
|
|
201
200
|
this.data.state = comState;
|
|
202
201
|
}
|
|
203
202
|
|
|
204
|
-
async setDidDone(coolDownTime) {
|
|
203
|
+
async setDidDone(ctx, coolDownTime) {
|
|
205
204
|
// Finalize communication for recent did
|
|
206
205
|
this.coolDownTs = new Date().getTime()+coolDownTime;
|
|
207
206
|
if (this.cmndsQueue.length == 0) this.busy = false;
|
|
208
207
|
await this.setComState(0);
|
|
209
|
-
if (this.timeoutHandle) await clearTimeout(this.timeoutHandle);
|
|
208
|
+
if (this.timeoutHandle) await ctx.clearTimeout(this.timeoutHandle);
|
|
210
209
|
}
|
|
211
210
|
|
|
212
211
|
async setDidStart(ctx, did, mode, len) {
|
|
@@ -228,9 +227,9 @@ class uds {
|
|
|
228
227
|
}
|
|
229
228
|
const tsNow = new Date().getTime();
|
|
230
229
|
const minWaiting = this.coolDownTs - tsNow;
|
|
231
|
-
if (minWaiting > 0) await this.sleep(minWaiting);
|
|
230
|
+
if (minWaiting > 0) await this.sleep(ctx, minWaiting);
|
|
232
231
|
this.busy = true;
|
|
233
|
-
this.timeoutHandle = await setTimeout(this.onTimeout, this.config.timeout, ctx, this);
|
|
232
|
+
this.timeoutHandle = await ctx.setTimeout(this.onTimeout, this.config.timeout, ctx, this);
|
|
234
233
|
this.data.did = did;
|
|
235
234
|
this.data.tsRequest = tsNow;
|
|
236
235
|
}
|
|
@@ -269,8 +268,8 @@ class uds {
|
|
|
269
268
|
}
|
|
270
269
|
}
|
|
271
270
|
|
|
272
|
-
sleep(milliseconds) {
|
|
273
|
-
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
271
|
+
sleep(ctx, milliseconds) {
|
|
272
|
+
return new Promise(resolve => ctx.setTimeout(resolve, milliseconds));
|
|
274
273
|
}
|
|
275
274
|
|
|
276
275
|
async cmndsLoop(ctx) {
|
|
@@ -309,7 +308,7 @@ class uds {
|
|
|
309
308
|
ctxLocal.stat.cntCommTimeoutPerDid[did] = 1;
|
|
310
309
|
}
|
|
311
310
|
if (ctxLocal.callback) await ctxLocal.callback(ctxGlobal, ctxLocal, ['timeout', {'did':ctxLocal.data.did,'didInfo':{'id':'','len':0},'val':''}]);
|
|
312
|
-
await ctxLocal.setDidDone(0);
|
|
311
|
+
await ctxLocal.setDidDone(ctxGlobal, 0);
|
|
313
312
|
}
|
|
314
313
|
|
|
315
314
|
async onUdsStateChange(ctx, ctxWorker, id, state) {
|
|
@@ -365,20 +364,24 @@ class uds {
|
|
|
365
364
|
switch (dcs.channel) {
|
|
366
365
|
case 'json':
|
|
367
366
|
// Change in json data
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
367
|
+
try {
|
|
368
|
+
byteArr = await this.storage.encodeDataCAN(ctx, this, did, await JSON.parse(state.val));
|
|
369
|
+
if (byteArr) {
|
|
370
|
+
await this.pushCmnd(ctx, 'write', [[did,byteArr]]);
|
|
371
|
+
ctx.setTimeout(function(ctxWorker,did){ctxWorker.cmndsQueue.push({'mode':'read', 'did': did});},2500,this,did); // Read value after 2500 ms
|
|
372
|
+
} else {
|
|
373
|
+
ctx.log.error('User command UDS WriteByDid on '+this.config.stateBase+': Encoding of data failed.');
|
|
374
|
+
}
|
|
375
|
+
} catch(e) {
|
|
376
|
+
ctx.log.error('WriteByDid(): Encoding of data failed on '+this.config.stateBase+'.'+String(did)+'; err='+JSON.stringify(e));
|
|
374
377
|
}
|
|
375
378
|
break;
|
|
376
379
|
case 'raw':
|
|
377
380
|
// Change in raw data
|
|
378
|
-
byteArr = this.storage.toByteArray(JSON.parse(state.val));
|
|
381
|
+
byteArr = this.storage.toByteArray(await JSON.parse(state.val));
|
|
379
382
|
if (byteArr) {
|
|
380
383
|
await this.pushCmnd(ctx, 'write', [[did,byteArr]]);
|
|
381
|
-
setTimeout(function(ctxWorker,did){ctxWorker.cmndsQueue.push({'mode':'read', 'did': did});},2500,this,did); // Read value after 2500 ms
|
|
384
|
+
ctx.setTimeout(function(ctxWorker,did){ctxWorker.cmndsQueue.push({'mode':'read', 'did': did});},2500,this,did); // Read value after 2500 ms
|
|
382
385
|
} else {
|
|
383
386
|
ctx.log.error('User command UDS WriteByDid on '+this.config.stateBase+': Encoding of data failed.');
|
|
384
387
|
}
|
|
@@ -389,12 +392,16 @@ class uds {
|
|
|
389
392
|
lenBaseId = ctx.namespace.length+dcs.device.length+dcs.channel.length+dcs.state.length+3;
|
|
390
393
|
if (id.length == lenBaseId) {
|
|
391
394
|
// Scalar value w/o sub structure
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
395
|
+
try {
|
|
396
|
+
byteArr = await this.storage.encodeDataCAN(ctx, this, did, await JSON.parse(state.val));
|
|
397
|
+
if (byteArr) {
|
|
398
|
+
await this.pushCmnd(ctx, 'write', [[did,byteArr]]);
|
|
399
|
+
ctx.setTimeout(function(ctxWorker,did){ctxWorker.cmndsQueue.push({'mode':'read', 'did': did});},2500,this,did); // Read value after 2500 ms
|
|
400
|
+
} else {
|
|
401
|
+
ctx.log.error('User command UDS WriteByDid on '+this.config.stateBase+': Encoding of data failed.');
|
|
402
|
+
}
|
|
403
|
+
} catch(e) {
|
|
404
|
+
ctx.log.error('WriteByDid(): Encoding of data failed on '+this.config.stateBase+'.'+String(did)+'; err='+JSON.stringify(e));
|
|
398
405
|
}
|
|
399
406
|
break;
|
|
400
407
|
}
|
|
@@ -402,21 +409,6 @@ class uds {
|
|
|
402
409
|
// Build json object for complete object tree of changed did:
|
|
403
410
|
await ctx.getStatesOf(dcs.device,dcs.device+'.'+dcs.channel,async function(err,obj) {
|
|
404
411
|
// Get all states for changed device.channel
|
|
405
|
-
/*
|
|
406
|
-
// Probalby better solution based on numbers as marker for arrays. But not working yet.
|
|
407
|
-
function isNumber(value) { return /^\d+$/.test(value); }
|
|
408
|
-
function insertDictSubVal(dict, keyArr, isArray, val) {
|
|
409
|
-
if (keyArr.length == 1) {
|
|
410
|
-
const key = keyArr[0];
|
|
411
|
-
if (isArray) dict[key].push(val); else dict[key] = val;
|
|
412
|
-
} else {
|
|
413
|
-
const key = keyArr.shift();
|
|
414
|
-
const nextIsArray = (((keyArr.length) && (isNumber(keyArr[0]))) ? true : false);
|
|
415
|
-
if (!(key in dict)) if (nextIsArray) dict[key] = []; else dict[key] = {};
|
|
416
|
-
insertDictSubVal(dict[key],keyArr, nextIsArray, val);
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
*/
|
|
420
412
|
function insertDictSubVal(dict, keyArr, val) {
|
|
421
413
|
const listLabels = ['ListEntries','Schedules','TopologyElement'];
|
|
422
414
|
if (keyArr.length == 1) {
|
|
@@ -437,12 +429,16 @@ class uds {
|
|
|
437
429
|
insertDictSubVal(treeDict, label.split('.'), val);
|
|
438
430
|
}
|
|
439
431
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
432
|
+
try {
|
|
433
|
+
byteArr = await ctxWorker.storage.encodeDataCAN(ctx, ctxWorker, did, treeDict);
|
|
434
|
+
if (byteArr) {
|
|
435
|
+
await ctxWorker.pushCmnd(ctx, 'write', [[did,byteArr]]);
|
|
436
|
+
ctx.setTimeout(function(ctxWorker,did){ctxWorker.cmndsQueue.push({'mode':'read', 'did': did});},2500,ctxWorker,did); // Read value after 2500 ms
|
|
437
|
+
} else {
|
|
438
|
+
ctx.log.error('User command UDS WriteByDid on '+ctxWorker.config.stateBase+': Encoding of data failed.');
|
|
439
|
+
}
|
|
440
|
+
} catch(e) {
|
|
441
|
+
ctx.log.error('WriteByDid(): Encoding of data failed on '+ctxWorker.config.stateBase+'.'+String(did)+'; err='+JSON.stringify(e));
|
|
446
442
|
}
|
|
447
443
|
});
|
|
448
444
|
break;
|
|
@@ -543,7 +539,7 @@ class uds {
|
|
|
543
539
|
} else {
|
|
544
540
|
ctx.log.error('UDS worker error on '+this.config.stateBase+': Negative response reading did '+String(this.data.did)+'. Code=0x'+Number(candata[3]).toString(16));
|
|
545
541
|
}
|
|
546
|
-
await this.setDidDone(0);
|
|
542
|
+
await this.setDidDone(ctx, 0);
|
|
547
543
|
break;
|
|
548
544
|
}
|
|
549
545
|
if ( (candata.length == 8) && ((candata[0] >> 4) == 0) && (candata[1] == this.readByDidProt.SIDrx) ) {
|
|
@@ -557,7 +553,7 @@ class uds {
|
|
|
557
553
|
this.data.len = candata[0]-3;
|
|
558
554
|
this.data.databytes = candata.slice(4,4+this.data.len);
|
|
559
555
|
this.storage.decodeDataCAN(ctx, this, this.data.did, this.data.databytes.slice(0,this.data.len));
|
|
560
|
-
await this.setDidDone(0);
|
|
556
|
+
await this.setDidDone(ctx, 0);
|
|
561
557
|
break;
|
|
562
558
|
} else {
|
|
563
559
|
// Did does not match
|
|
@@ -567,7 +563,7 @@ class uds {
|
|
|
567
563
|
} else {
|
|
568
564
|
ctx.log.error('UDS worker on '+this.config.stateBase+': Did mismatch MF. Expected='+String(this.data.did)+'; Received='+String(didRx));
|
|
569
565
|
}
|
|
570
|
-
await this.setDidDone(1000);
|
|
566
|
+
await this.setDidDone(ctx, 1000);
|
|
571
567
|
break;
|
|
572
568
|
}
|
|
573
569
|
}
|
|
@@ -592,7 +588,7 @@ class uds {
|
|
|
592
588
|
} else {
|
|
593
589
|
ctx.log.error('UDS worker on '+this.config.stateBase+': Did mismatch MF. Expected='+String(this.data.did)+'; Received='+String(didRx));
|
|
594
590
|
}
|
|
595
|
-
await this.setDidDone(1000);
|
|
591
|
+
await this.setDidDone(ctx, 1000);
|
|
596
592
|
break;
|
|
597
593
|
}
|
|
598
594
|
}
|
|
@@ -603,7 +599,7 @@ class uds {
|
|
|
603
599
|
}
|
|
604
600
|
await this.calcStat();
|
|
605
601
|
this.stat.cntCommBadProtocol += 1;
|
|
606
|
-
await this.setDidDone(2500);
|
|
602
|
+
await this.setDidDone(ctx, 2500);
|
|
607
603
|
break;
|
|
608
604
|
|
|
609
605
|
case 2: // waitForCFrbd
|
|
@@ -617,7 +613,7 @@ class uds {
|
|
|
617
613
|
await this.calcStat();
|
|
618
614
|
ctx.log.silly('UDS worker on '+this.config.stateBase+': MF completed. candata: '+this.storage.arr2Hex(candata));
|
|
619
615
|
this.storage.decodeDataCAN(ctx, this, this.data.did, this.data.databytes.slice(0,this.data.len));
|
|
620
|
-
await this.setDidDone(0);
|
|
616
|
+
await this.setDidDone(ctx, 0);
|
|
621
617
|
} else {
|
|
622
618
|
// More data to come
|
|
623
619
|
this.data.D0 += 1;
|
|
@@ -631,7 +627,7 @@ class uds {
|
|
|
631
627
|
ctx.log.error('UDS worker on '+this.config.stateBase+': Bad frame. candata: '+this.storage.arr2Hex(candata));
|
|
632
628
|
}
|
|
633
629
|
this.stat.cntCommBadProtocol += 1;
|
|
634
|
-
await this.setDidDone(2500);
|
|
630
|
+
await this.setDidDone(ctx, 2500);
|
|
635
631
|
}
|
|
636
632
|
break;
|
|
637
633
|
|
|
@@ -640,7 +636,7 @@ class uds {
|
|
|
640
636
|
// Negative response
|
|
641
637
|
this.stat.cntCommNR += 1;
|
|
642
638
|
ctx.log.error('UDS worker error on '+this.config.stateBase+': Negative response writing did '+String(this.data.did)+'. Code=0x'+Number(candata[3]).toString(16));
|
|
643
|
-
await this.setDidDone(0);
|
|
639
|
+
await this.setDidDone(ctx, 0);
|
|
644
640
|
break;
|
|
645
641
|
}
|
|
646
642
|
if ( (candata.length == 8) && (candata[0] == 0x03) && (candata[1] == this.writeByDidProt.SIDrx) ) {
|
|
@@ -652,7 +648,7 @@ class uds {
|
|
|
652
648
|
ctx.log.silly('UDS worker on '+this.config.stateBase+': writeByDid SF confirmation received.');
|
|
653
649
|
await this.calcStat();
|
|
654
650
|
this.storage.storeStatistics(ctx, this, false);
|
|
655
|
-
await this.setDidDone(0);
|
|
651
|
+
await this.setDidDone(ctx, 0);
|
|
656
652
|
break;
|
|
657
653
|
} else {
|
|
658
654
|
// Did does not match
|
|
@@ -660,14 +656,14 @@ class uds {
|
|
|
660
656
|
ctx.log.error('UDS worker on '+this.config.stateBase+': Did mismatch writeByDid SF. Expected='+String(this.data.did)+'; Received='+String(didRx));
|
|
661
657
|
await this.calcStat();
|
|
662
658
|
this.storage.storeStatistics(ctx, this, true);
|
|
663
|
-
await this.setDidDone(1000);
|
|
659
|
+
await this.setDidDone(ctx, 1000);
|
|
664
660
|
break;
|
|
665
661
|
}
|
|
666
662
|
}
|
|
667
663
|
ctx.log.error('UDS worker on '+this.config.stateBase+': Bad frame for writeByDid SF. candata: '+this.storage.arr2Hex(candata));
|
|
668
664
|
this.stat.cntCommBadProtocol += 1;
|
|
669
665
|
await this.calcStat();
|
|
670
|
-
await this.setDidDone(2500);
|
|
666
|
+
await this.setDidDone(ctx, 2500);
|
|
671
667
|
break;
|
|
672
668
|
|
|
673
669
|
case 4: // waitForFFFwbd
|
|
@@ -675,7 +671,7 @@ class uds {
|
|
|
675
671
|
// Negative response
|
|
676
672
|
this.stat.cntCommNR += 1;
|
|
677
673
|
ctx.log.error('UDS worker error on '+this.config.stateBase+': Negative response writing did '+String(this.data.did)+'. Code=0x'+Number(candata[3]).toString(16));
|
|
678
|
-
await this.setDidDone(0);
|
|
674
|
+
await this.setDidDone(ctx, 0);
|
|
679
675
|
break;
|
|
680
676
|
}
|
|
681
677
|
if ( (candata.length == 8) && (candata[0] == 0x30) && (candata[1] == 0x00) ) {
|
|
@@ -685,7 +681,7 @@ class uds {
|
|
|
685
681
|
if ((ST<20) || (ST>127)) ST=50; // Accept ST 20 .. 127 ms. Default to 50 ms.
|
|
686
682
|
while (this.data.txPos < this.data.len) {
|
|
687
683
|
// More data to send
|
|
688
|
-
await this.sleep(ST);
|
|
684
|
+
await this.sleep(ctx, ST);
|
|
689
685
|
const frame = [this.data.D0].concat(this.data.databytes.slice(this.data.txPos,this.data.txPos+7));
|
|
690
686
|
await this.sendFrame(ctx, frame);
|
|
691
687
|
this.data.txPos += 7;
|
|
@@ -698,7 +694,7 @@ class uds {
|
|
|
698
694
|
ctx.log.error('UDS worker on '+this.config.stateBase+': Bad frame for writeByDid MF. candata: '+this.storage.arr2Hex(candata));
|
|
699
695
|
this.stat.cntCommBadProtocol += 1;
|
|
700
696
|
await this.calcStat();
|
|
701
|
-
await this.setDidDone(2500);
|
|
697
|
+
await this.setDidDone(ctx, 2500);
|
|
702
698
|
break;
|
|
703
699
|
|
|
704
700
|
default:
|
|
@@ -708,7 +704,7 @@ class uds {
|
|
|
708
704
|
} else {
|
|
709
705
|
ctx.log.error('UDS worker on '+this.config.stateBase+': Bad state value: '+String(await this.getComState()));
|
|
710
706
|
}
|
|
711
|
-
await this.setDidDone(2500);
|
|
707
|
+
await this.setDidDone(ctx, 2500);
|
|
712
708
|
}
|
|
713
709
|
this.commBusy = false;
|
|
714
710
|
}
|
package/lib/codecs.js
CHANGED
|
@@ -205,18 +205,28 @@ class O3EUtf8 {
|
|
|
205
205
|
this.id = idStr;
|
|
206
206
|
this.offset = _args.offset;
|
|
207
207
|
}
|
|
208
|
+
|
|
208
209
|
encode(data) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
210
|
+
let result;
|
|
211
|
+
try {
|
|
212
|
+
result = Object.values(new TextEncoder().encode(data));
|
|
213
|
+
} catch(e) {
|
|
214
|
+
throw new Error('O3EUtf8.encode(): Conversion from Utf8 failed '+this.id+'; err='+JSON.stringify(e));
|
|
215
|
+
}
|
|
216
|
+
if (result.length > this.string_len) throw new Error('O3EUtf8.encode(): Result too long: '+this.id+' - '+String(result.length)+' > '+String(this.string_len));
|
|
212
217
|
return result.concat(Array.from(Array(this.string_len-result.length), () => 0));
|
|
213
218
|
|
|
214
219
|
}
|
|
215
220
|
decode(string_bin) {
|
|
216
|
-
let
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
221
|
+
let i = string_bin.slice(this.offset).indexOf(0);
|
|
222
|
+
if (i == -1) { i = string_bin.length-this.offset; }
|
|
223
|
+
let result;
|
|
224
|
+
try {
|
|
225
|
+
result = new TextDecoder().decode(new Uint8Array(string_bin.slice(this.offset,i)));
|
|
226
|
+
} catch(e) {
|
|
227
|
+
throw new Error('O3EUtf8.decode(): Conversion to Utf8 failed '+this.id+'; err='+JSON.stringify(e));
|
|
228
|
+
}
|
|
229
|
+
return result;
|
|
220
230
|
}
|
|
221
231
|
|
|
222
232
|
__len__() {
|
package/lib/codecs.test.js
CHANGED
|
@@ -38,6 +38,62 @@ function codecEncode(descr, expected, codec, len, id, args, val) {
|
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// Utf8:
|
|
42
|
+
describe('codecs.js => O3EUtf8()', () => {
|
|
43
|
+
const raw_hex1 = '4865697a6bc3b6727065720000000000000000000000000000000000000000000000000000000000';
|
|
44
|
+
const raw1 = E3.toByteArray(raw_hex1);
|
|
45
|
+
const txt1 = 'Heizkörper';
|
|
46
|
+
it(`Decode ${JSON.stringify(txt1)}`, () => {
|
|
47
|
+
const f = new E3.O3Ecodecs.O3EUtf8(raw1.length,'test1Utf08', {offset:0});
|
|
48
|
+
const result = f.decode(raw1);
|
|
49
|
+
expect(JSON.stringify(result)).to.equal(JSON.stringify(txt1));
|
|
50
|
+
});
|
|
51
|
+
it(`Encode ${JSON.stringify(raw1)}`, () => {
|
|
52
|
+
const f = new E3.O3Ecodecs.O3EUtf8(raw1.length,'test2Utf08', {offset:0});
|
|
53
|
+
const result = f.encode(txt1);
|
|
54
|
+
expect(JSON.stringify(raw1)).to.equal(JSON.stringify(result));
|
|
55
|
+
});
|
|
56
|
+
const raw_hex2 = '4675c39f626f64656e6865697a756e67000000000000000000000000000000000000000000000000';
|
|
57
|
+
const raw2 = E3.toByteArray(raw_hex2);
|
|
58
|
+
const txt2 = 'Fußbodenheizung';
|
|
59
|
+
it(`Decode ${JSON.stringify(txt2)}`, () => {
|
|
60
|
+
const f = new E3.O3Ecodecs.O3EUtf8(raw2.length,'test3Utf08', {offset:0});
|
|
61
|
+
const result = f.decode(raw2);
|
|
62
|
+
expect(JSON.stringify(result)).to.equal(JSON.stringify(txt2));
|
|
63
|
+
});
|
|
64
|
+
it(`Encode ${JSON.stringify(raw2)}`, () => {
|
|
65
|
+
const f = new E3.O3Ecodecs.O3EUtf8(raw2.length,'test4Utf08', {offset:0});
|
|
66
|
+
const result = f.encode(txt2);
|
|
67
|
+
expect(JSON.stringify(raw2)).to.equal(JSON.stringify(result));
|
|
68
|
+
});
|
|
69
|
+
const raw_hex3 = '00000000000000000000000000000000000000000000000000000000000000000000000000000000';
|
|
70
|
+
const raw3 = E3.toByteArray(raw_hex3);
|
|
71
|
+
const txt3 = '';
|
|
72
|
+
it(`Decode ${JSON.stringify(txt3)}`, () => {
|
|
73
|
+
const f = new E3.O3Ecodecs.O3EUtf8(raw3.length,'test5Utf08', {offset:0});
|
|
74
|
+
const result = f.decode(raw3);
|
|
75
|
+
expect(JSON.stringify(result)).to.equal(JSON.stringify(txt3));
|
|
76
|
+
});
|
|
77
|
+
it(`Encode ${JSON.stringify(raw3)}`, () => {
|
|
78
|
+
const f = new E3.O3Ecodecs.O3EUtf8(raw3.length,'test5Utf08', {offset:0});
|
|
79
|
+
const result = f.encode(txt3);
|
|
80
|
+
expect(JSON.stringify(raw3)).to.equal(JSON.stringify(result));
|
|
81
|
+
});
|
|
82
|
+
const raw_hex4 = '4675c39f';
|
|
83
|
+
const raw4 = E3.toByteArray(raw_hex4);
|
|
84
|
+
const txt4 = 'Fuß';
|
|
85
|
+
it(`Decode ${JSON.stringify(txt4)}`, () => {
|
|
86
|
+
const f = new E3.O3Ecodecs.O3EUtf8(raw4.length,'test6Utf08', {offset:0});
|
|
87
|
+
const result = f.decode(raw4);
|
|
88
|
+
expect(JSON.stringify(result)).to.equal(JSON.stringify(txt4));
|
|
89
|
+
});
|
|
90
|
+
it(`Encode ${JSON.stringify(raw4)}`, () => {
|
|
91
|
+
const f = new E3.O3Ecodecs.O3EUtf8(raw4.length,'test6Utf08', {offset:0});
|
|
92
|
+
const result = f.encode(txt4);
|
|
93
|
+
expect(JSON.stringify(raw4)).to.equal(JSON.stringify(result));
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
41
97
|
// val2byteArray:
|
|
42
98
|
describe('codecs.js => val2byteArr()', () => {
|
|
43
99
|
let val = -1;
|
|
@@ -152,7 +208,7 @@ describe('codecs.js => O3EInt8().encode()', () => {
|
|
|
152
208
|
codecEncode('Positive Number, scale=10, signed=false', [0xfb], E3.O3Ecodecs.O3EInt8, 1, 'test5', {scale:10.0,signed:false,offset: 0}, 25.1);
|
|
153
209
|
});
|
|
154
210
|
|
|
155
|
-
describe('codecs.js => O3EInt16().
|
|
211
|
+
describe('codecs.js => O3EInt16().encode()', () => {
|
|
156
212
|
codecEncode('Positive Number, scale=10, signed=true ', [0x32,0x00], E3.O3Ecodecs.O3EInt16, 2, 'test1', {scale:10.0,signed:true, offset: 0}, 5);
|
|
157
213
|
codecEncode('Positive Number, scale=10, signed=true ', [0xff,0x7f], E3.O3Ecodecs.O3EInt16, 2, 'test2', {scale:10.0,signed:true, offset: 0}, (2**15-1)/10);
|
|
158
214
|
codecEncode('Negative Number, scale=10, signed=true ', [0x00,0x80], E3.O3Ecodecs.O3EInt16, 2, 'test3', {scale:10.0,signed:true, offset: 0}, -(2**15)/10);
|
package/lib/storage.js
CHANGED
|
@@ -136,7 +136,6 @@ class storage {
|
|
|
136
136
|
type: 'device',
|
|
137
137
|
common: {
|
|
138
138
|
name: this.config.stateBase,
|
|
139
|
-
role: 'device'
|
|
140
139
|
},
|
|
141
140
|
native: {},
|
|
142
141
|
});
|
|
@@ -145,7 +144,6 @@ class storage {
|
|
|
145
144
|
type: 'channel',
|
|
146
145
|
common: {
|
|
147
146
|
name: this.config.stateBase+' informations',
|
|
148
|
-
role: 'channel'
|
|
149
147
|
},
|
|
150
148
|
native: {},
|
|
151
149
|
});
|
|
@@ -154,7 +152,7 @@ class storage {
|
|
|
154
152
|
type: 'state',
|
|
155
153
|
common: {
|
|
156
154
|
name: this.config.stateBase+' statistics about communication',
|
|
157
|
-
role: '
|
|
155
|
+
role: 'info.status',
|
|
158
156
|
type: 'json',
|
|
159
157
|
read: true,
|
|
160
158
|
write: true,
|
|
@@ -169,7 +167,6 @@ class storage {
|
|
|
169
167
|
type: 'channel',
|
|
170
168
|
common: {
|
|
171
169
|
name: this.config.stateBase+' JSON',
|
|
172
|
-
role: 'channel for json data'
|
|
173
170
|
},
|
|
174
171
|
native: {},
|
|
175
172
|
});
|
|
@@ -178,7 +175,6 @@ class storage {
|
|
|
178
175
|
type: 'channel',
|
|
179
176
|
common: {
|
|
180
177
|
name: this.config.stateBase+' TREE',
|
|
181
|
-
role: 'channel for tree data'
|
|
182
178
|
},
|
|
183
179
|
native: {},
|
|
184
180
|
});
|
|
@@ -187,7 +183,6 @@ class storage {
|
|
|
187
183
|
type: 'channel',
|
|
188
184
|
common: {
|
|
189
185
|
name: this.config.stateBase+' RAW',
|
|
190
|
-
role: 'channel for raw data'
|
|
191
186
|
},
|
|
192
187
|
native: {},
|
|
193
188
|
});
|
|
@@ -230,7 +225,7 @@ class storage {
|
|
|
230
225
|
if (['standby','normal','udsDidScan'].includes(await this.getOpMode())) {
|
|
231
226
|
const ts = new Date().getTime();
|
|
232
227
|
if ( (!forceStore) && (ts < ctxWorker.stat.nextTs) ) return; // Min. time step not reached. Do not store.
|
|
233
|
-
if (ctxWorker.stat)
|
|
228
|
+
if (ctxWorker.stat) ctx.setStateAsync(ctxWorker.config.stateBase+'.info.'+this.config.statId, JSON.stringify(ctxWorker.stat), true);
|
|
234
229
|
ctxWorker.stat.nextTs = ts+ctxWorker.stat.tsMinStep;
|
|
235
230
|
}
|
|
236
231
|
}
|
|
@@ -262,7 +257,7 @@ class storage {
|
|
|
262
257
|
common: {
|
|
263
258
|
name: idStr,
|
|
264
259
|
type: 'string',
|
|
265
|
-
role: '
|
|
260
|
+
role: 'json',
|
|
266
261
|
read: true,
|
|
267
262
|
write: true,
|
|
268
263
|
},
|
|
@@ -280,8 +275,8 @@ class storage {
|
|
|
280
275
|
if (typeof(obj) == 'object') {
|
|
281
276
|
if (Object.keys(obj).length <= 100) {
|
|
282
277
|
for (const [key, itm] of Object.entries(obj)) {
|
|
283
|
-
await storeObjectTree(ctx, String(stateId)+'.'+String(key).replace('.','_'),itm);
|
|
284
|
-
// No '.' in state id allowed
|
|
278
|
+
await storeObjectTree(ctx, String(stateId)+'.'+String(key).replace(ctx.FORBIDDEN_CHARS,'_').replace('.','_'),itm);
|
|
279
|
+
// No FORBIDDEN_CHARS and no '.' in state id allowed
|
|
285
280
|
}
|
|
286
281
|
} else {
|
|
287
282
|
ctx.log.error('Did valuation aborted. Too many members ('+String(Object.keys(obj).length)+') '+stateId+'.'+String(did));
|
|
@@ -307,7 +302,8 @@ class storage {
|
|
|
307
302
|
ctx.log.warn('Could not retreive codec for '+ctxWorker.config.stateBase+'.'+String(did)+'. err='+e.message);
|
|
308
303
|
codec = 'RawCodec';
|
|
309
304
|
}
|
|
310
|
-
idStr = cdi.id.replace('.','_');
|
|
305
|
+
idStr = cdi.id.replace(ctx.FORBIDDEN_CHARS,'_').replace('.','_');
|
|
306
|
+
// No FORBIDDEN_CHARS and no '.' in state allowed
|
|
311
307
|
common = true;
|
|
312
308
|
try {
|
|
313
309
|
val = await codec.decode(data);
|
package/lib/udsScan.js
CHANGED
|
@@ -210,14 +210,14 @@ class udsScan {
|
|
|
210
210
|
for (const baseAddr of Object(this.udsScanAddrRange).values()) {
|
|
211
211
|
for (const addr of Object(range(Number(this.udsScanAddrSpan), Number(baseAddr))).values()) {
|
|
212
212
|
await this.startupScanUdsDevice(ctx, addr);
|
|
213
|
-
await this.sleep(50);
|
|
213
|
+
await this.sleep(ctx, 50);
|
|
214
214
|
}
|
|
215
215
|
}
|
|
216
216
|
// eslint-disable-next-line no-case-declarations
|
|
217
217
|
const tsAbort = new Date().getTime() + this.udsMaxTrialsDevScan*this.udsTimeoutDevScan+250;
|
|
218
218
|
await ctx.log.info('UDS device scan: Waiting for scans to complete.');
|
|
219
219
|
while ( (this.cntUdsScansActive > 0) && (new Date().getTime() < tsAbort) ) {
|
|
220
|
-
await this.sleep(100);
|
|
220
|
+
await this.sleep(ctx, 100);
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
// Stop all scan workers:
|
|
@@ -304,14 +304,14 @@ class udsScan {
|
|
|
304
304
|
const dids = range(udsMaxCntDids, 256);
|
|
305
305
|
for (const addr of Object(udsAddrs).values()) {
|
|
306
306
|
await this.startupScanUdsDids(ctx, addr, dids);
|
|
307
|
-
await this.sleep(50);
|
|
307
|
+
await this.sleep(ctx, 50);
|
|
308
308
|
}
|
|
309
309
|
let cntDoneLast = -1;
|
|
310
310
|
await logStatus(ctx, this);
|
|
311
311
|
let ts = new Date().getTime();
|
|
312
312
|
const tsAbort = ts + this.udsScanDidsCntTotal*500;
|
|
313
313
|
while ( (this.cntUdsScansActive > 0) && (new Date().getTime() < tsAbort) ) {
|
|
314
|
-
await this.sleep(100);
|
|
314
|
+
await this.sleep(ctx, 100);
|
|
315
315
|
if ((new Date().getTime() - ts) >= 10000) {
|
|
316
316
|
ts += 10000;
|
|
317
317
|
await logStatus(ctx, this);
|
|
@@ -342,8 +342,8 @@ class udsScan {
|
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
-
sleep(milliseconds) {
|
|
346
|
-
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
345
|
+
sleep(ctx, milliseconds) {
|
|
346
|
+
return new Promise(resolve => ctx.setTimeout(resolve, milliseconds));
|
|
347
347
|
}
|
|
348
348
|
|
|
349
349
|
}
|
package/main.js
CHANGED
|
@@ -257,6 +257,7 @@ class E3oncan extends utils.Adapter {
|
|
|
257
257
|
*/
|
|
258
258
|
async onUnload(callback) {
|
|
259
259
|
try {
|
|
260
|
+
const tStart = new Date().getTime();
|
|
260
261
|
this.stoppingInstance = true;
|
|
261
262
|
// Stop UDS workers:
|
|
262
263
|
for (const worker of Object.values(this.E3UdsWorkers)) await worker.stop(this);
|
|
@@ -273,6 +274,7 @@ class E3oncan extends utils.Adapter {
|
|
|
273
274
|
// @ts-ignore
|
|
274
275
|
await this.disconnectFromCan(this.channelInt,this.config.canIntName);
|
|
275
276
|
this.setState('info.connection', false, true);
|
|
277
|
+
this.log.debug('onUnload() took '+String(new Date().getTime()-tStart)+' ms to complete.');
|
|
276
278
|
|
|
277
279
|
callback();
|
|
278
280
|
} catch (e) {
|
|
@@ -320,7 +322,7 @@ class E3oncan extends utils.Adapter {
|
|
|
320
322
|
}
|
|
321
323
|
|
|
322
324
|
sleep(milliseconds) {
|
|
323
|
-
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
325
|
+
return new Promise(resolve => this.setTimeout(resolve, milliseconds));
|
|
324
326
|
}
|
|
325
327
|
|
|
326
328
|
// If you need to accept messages in your adapter, uncomment the following block and the corresponding line in the constructor.
|