iobroker.e3oncan 0.6.9
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/LICENSE +21 -0
- package/README.md +129 -0
- package/admin/e3oncan.png +0 -0
- package/admin/e3oncan_small.png +0 -0
- package/admin/i18n/de/translations.json +60 -0
- package/admin/i18n/en/translations.json +60 -0
- package/admin/i18n/es/translations.json +62 -0
- package/admin/i18n/fr/translations.json +62 -0
- package/admin/i18n/it/translations.json +62 -0
- package/admin/i18n/nl/translations.json +62 -0
- package/admin/i18n/pl/translations.json +62 -0
- package/admin/i18n/pt/translations.json +62 -0
- package/admin/i18n/ru/translations.json +62 -0
- package/admin/i18n/uk/translations.json +62 -0
- package/admin/i18n/zh-cn/translations.json +62 -0
- package/admin/jsonConfig.json +594 -0
- package/admin/udsDevices.json +37 -0
- package/io-package.json +164 -0
- package/lib/adapter-config.d.ts +19 -0
- package/lib/canCollect.js +199 -0
- package/lib/canUds.js +715 -0
- package/lib/codecs.js +709 -0
- package/lib/didsE3.json +29025 -0
- package/lib/didsE380.json +275 -0
- package/lib/didsE3Writables.json +396 -0
- package/lib/enums.js +2223 -0
- package/lib/storage.js +396 -0
- package/lib/udsScan.js +353 -0
- package/main.js +490 -0
- package/package.json +80 -0
package/main.js
ADDED
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Created with @iobroker/create-adapter v2.5.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// The adapter-core module gives you access to the core ioBroker functions
|
|
8
|
+
// you need to create an adapter
|
|
9
|
+
const utils = require('@iobroker/adapter-core');
|
|
10
|
+
|
|
11
|
+
// Load your modules here, e.g.:
|
|
12
|
+
// const fs = require("fs");
|
|
13
|
+
|
|
14
|
+
const can = require('socketcan');
|
|
15
|
+
const codecs = require('./lib/codecs');
|
|
16
|
+
const storage = require('./lib/storage');
|
|
17
|
+
const collect = require('./lib/canCollect');
|
|
18
|
+
const uds = require('./lib/canUds');
|
|
19
|
+
const udsScan = require('./lib/udsScan');
|
|
20
|
+
|
|
21
|
+
class E3oncan extends utils.Adapter {
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @param {Partial<utils.AdapterOptions>} [options={}]
|
|
25
|
+
*/
|
|
26
|
+
constructor(options) {
|
|
27
|
+
super({
|
|
28
|
+
...options,
|
|
29
|
+
name: 'e3oncan',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
this.e380Collect = null; // E380 alway is assigned to external bus
|
|
33
|
+
this.E3CollectInt = {}; // Dict of collect devices on internal bus
|
|
34
|
+
this.E3CollectExt = {}; // Dict of collect devices on external bus
|
|
35
|
+
this.collectTimeout = 1500; // Timeout (ms) for collecting data
|
|
36
|
+
this.E3UdsWorkers = {}; // Dict of uds devices on external bus
|
|
37
|
+
|
|
38
|
+
this.channelExt = null;
|
|
39
|
+
this.channelExtName = '';
|
|
40
|
+
this.channelInt = null;
|
|
41
|
+
this.channelIntName = '';
|
|
42
|
+
|
|
43
|
+
this.udsWorkers = {};
|
|
44
|
+
this.udsTimeout = 7500; // Timeout (ms) for normal UDS communication
|
|
45
|
+
this.udsDevices = []; // Confirmed & edited UDS devices
|
|
46
|
+
|
|
47
|
+
this.udsDidForScan = 256; // Busidentification is in this id
|
|
48
|
+
this.udsScanWorker = new udsScan.udsScan();
|
|
49
|
+
this.udsScanDevices = []; // UDS devices found during scan
|
|
50
|
+
this.doUdsDevScan = false;
|
|
51
|
+
this.udsDevAddrs = [];
|
|
52
|
+
this.udsDevStateNames = [];
|
|
53
|
+
this.udsDidsMaxNmbr = 3000; // Max. number of dids per device for scan
|
|
54
|
+
|
|
55
|
+
//this.on('install', this.onInstall.bind(this));
|
|
56
|
+
this.on('ready', this.onReady.bind(this));
|
|
57
|
+
this.on('stateChange', this.onStateChange.bind(this));
|
|
58
|
+
//this.on('objectChange', this.onObjectChange.bind(this));
|
|
59
|
+
this.on('message', this.onMessage.bind(this));
|
|
60
|
+
this.on('unload', this.onUnload.bind(this));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Is called when databases are connected and adapter received configuration.
|
|
65
|
+
*/
|
|
66
|
+
async onReady() {
|
|
67
|
+
// Initialize your adapter here
|
|
68
|
+
|
|
69
|
+
await this.log.info('Startup of instance '+this.namespace+': Starting.');
|
|
70
|
+
//await this.log.debug('this.config:');
|
|
71
|
+
//await this.log.debug(JSON.stringify(this.config));
|
|
72
|
+
|
|
73
|
+
// Reset the connection indicator during startup
|
|
74
|
+
this.setState('info.connection', false, true);
|
|
75
|
+
|
|
76
|
+
// Collect known devices adresses:
|
|
77
|
+
for (const dev of Object.values(this.config.tableUdsDevices)) {
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
this.udsDevAddrs.push(dev.devAddr);
|
|
80
|
+
// @ts-ignore
|
|
81
|
+
this.udsDevStateNames.push(dev.devStateName);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
codecs.rawmode.setOpMode(false);
|
|
85
|
+
|
|
86
|
+
// Check for required scan for UDS devices
|
|
87
|
+
this.doUdsDevScan = (this.config.tableUdsDevices.length == 0);
|
|
88
|
+
if (this.doUdsDevScan) await this.log.info('UDS device scan is required.');
|
|
89
|
+
|
|
90
|
+
// Setup external CAN bus if required
|
|
91
|
+
// ==================================
|
|
92
|
+
|
|
93
|
+
// @ts-ignore
|
|
94
|
+
if (this.config.canExtActivated) {
|
|
95
|
+
// @ts-ignore
|
|
96
|
+
[this.channelExt, this.channelExtName] = await this.connectToCan(this.channelExt, this.config.canExtName, this.onCanMsgExt);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Setup internal CAN bus if required
|
|
100
|
+
// ==================================
|
|
101
|
+
|
|
102
|
+
// @ts-ignore
|
|
103
|
+
if (this.config.canIntActivated) {
|
|
104
|
+
// @ts-ignore
|
|
105
|
+
[this.channelInt, this.channelIntName] = await this.connectToCan(this.channelInt, this.config.canIntName, this.onCanMsgInt);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Setup E380 collect worker:
|
|
109
|
+
if (this.channelExt) this.e380Collect = await this.setupE380CollectWorker(this.config);
|
|
110
|
+
|
|
111
|
+
// Setup all configured devices for collect:
|
|
112
|
+
// @ts-ignore
|
|
113
|
+
if (this.channelExt) await this.setupE3CollectWorkers(this.config.tableCollectCanExt, this.E3CollectExt, this.channelExt);
|
|
114
|
+
// @ts-ignore
|
|
115
|
+
if (this.channelInt) await this.setupE3CollectWorkers(this.config.tableCollectCanInt, this.E3CollectInt, this.channelInt);
|
|
116
|
+
|
|
117
|
+
// Initial setup all configured devices for UDS:
|
|
118
|
+
if (this.channelExt) await this.setupUdsWorkers();
|
|
119
|
+
|
|
120
|
+
await this.log.info('Startup of instance '+this.namespace+': Done.');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Setup CAN busses
|
|
124
|
+
|
|
125
|
+
async connectToCan(channel, name, onMsg) {
|
|
126
|
+
let chName = name;
|
|
127
|
+
if (!channel) {
|
|
128
|
+
try {
|
|
129
|
+
channel = can.createRawChannel(name, true);
|
|
130
|
+
await channel.addListener('onMessage', onMsg, this);
|
|
131
|
+
await channel.start();
|
|
132
|
+
await this.setState('info.connection', true, true);
|
|
133
|
+
await this.log.info('CAN-Adapter connected: '+name);
|
|
134
|
+
} catch (e) {
|
|
135
|
+
await this.log.error(`Could not connect to CAN-Adapter "${name}" - err=${e.message}`);
|
|
136
|
+
channel = null;
|
|
137
|
+
chName = '';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return([channel, chName]);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async disconnectFromCan(channel, name) {
|
|
144
|
+
if (channel) {
|
|
145
|
+
try {
|
|
146
|
+
await channel.stop();
|
|
147
|
+
await this.log.info('CAN-Adapter disconnected: '+name);
|
|
148
|
+
channel = null;
|
|
149
|
+
} catch (e) {
|
|
150
|
+
await this.log.error(`Could not disconnect from CAN "${name}" - err=${e.message}`);
|
|
151
|
+
channel = null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return([channel,'']);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Setup E380 collect worker:
|
|
158
|
+
|
|
159
|
+
async setupE380CollectWorker(conf) {
|
|
160
|
+
let e380Worker = null;
|
|
161
|
+
if (conf.e380Active) {
|
|
162
|
+
e380Worker = new collect.collect(
|
|
163
|
+
{ 'canID': [0x250,0x252,0x254,0x256,0x258,0x25A,0x25C],
|
|
164
|
+
'stateBase': conf.e380Name,
|
|
165
|
+
'device': 'e380',
|
|
166
|
+
'delay': conf.e380Delay,
|
|
167
|
+
'active': conf.e380Active});
|
|
168
|
+
await e380Worker.initStates(this,'standby');
|
|
169
|
+
}
|
|
170
|
+
if (e380Worker) await e380Worker.startup(this);
|
|
171
|
+
return e380Worker;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Setup E3 collect workers:
|
|
175
|
+
|
|
176
|
+
async setupE3CollectWorkers(conf, workers) {
|
|
177
|
+
if ( (conf) && (conf.length > 0) ) {
|
|
178
|
+
for (const workerConf of Object.values(conf)) {
|
|
179
|
+
if (workerConf.collectActive) {
|
|
180
|
+
// @ts-ignore
|
|
181
|
+
const devInfo = this.config.tableUdsDevices.filter(item => item.collectCanId == workerConf.collectCanId);
|
|
182
|
+
if (devInfo.length > 0) {
|
|
183
|
+
const worker = new collect.collect(
|
|
184
|
+
{ 'canID' : [Number(workerConf.collectCanId)],
|
|
185
|
+
'stateBase': devInfo[0].devStateName,
|
|
186
|
+
'device' : 'common',
|
|
187
|
+
'timeout' : this.collectTimeout,
|
|
188
|
+
'delay' : workerConf.collectDelayTime
|
|
189
|
+
});
|
|
190
|
+
await worker.initStates(this, 'standby');
|
|
191
|
+
if (worker) await worker.startup(this);
|
|
192
|
+
workers[Number(workerConf.collectCanId)] = worker;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Setup workers for collecting data and for communication via UDS
|
|
200
|
+
|
|
201
|
+
async setupUdsWorkers() {
|
|
202
|
+
// @ts-ignore
|
|
203
|
+
if ( (this.config.tableUdsSchedules) && (this.config.tableUdsSchedules.length > 0) ) {
|
|
204
|
+
// @ts-ignore
|
|
205
|
+
for (const dev of Object.values(this.config.tableUdsSchedules)) {
|
|
206
|
+
if (dev.udsScheduleActive) {
|
|
207
|
+
await this.sleep(50); // 50 ms pause to next schedule
|
|
208
|
+
const devTxAddr = Number(dev.udsSelectDevAddr);
|
|
209
|
+
const devRxAddr = devTxAddr + 16;
|
|
210
|
+
if (!(this.E3UdsWorkers[devRxAddr])) {
|
|
211
|
+
// Create new worker
|
|
212
|
+
// @ts-ignore
|
|
213
|
+
const devInfo = this.config.tableUdsDevices.filter(item => item.devAddr == dev.udsSelectDevAddr);
|
|
214
|
+
if (devInfo.length > 0) {
|
|
215
|
+
const dev_name = devInfo[0].devStateName;
|
|
216
|
+
await this.log.silly('New UDS device on '+String(dev.udsSelectDevAddr)+' with name '+String(dev_name));
|
|
217
|
+
this.E3UdsWorkers[devRxAddr] = new uds.uds(
|
|
218
|
+
{ 'canID' : devTxAddr,
|
|
219
|
+
'stateBase': dev_name,
|
|
220
|
+
'device' : 'common',
|
|
221
|
+
'delay' : 0,
|
|
222
|
+
'active' : dev.udsScheduleActive,
|
|
223
|
+
'channel' : this.channelExt,
|
|
224
|
+
'timeout' : this.udsTimeout
|
|
225
|
+
});
|
|
226
|
+
await this.E3UdsWorkers[devRxAddr].initStates(this,'standby');
|
|
227
|
+
await this.E3UdsWorkers[devRxAddr].addSchedule(this, dev.udsSchedule, dev.udsScheduleDids);
|
|
228
|
+
await this.log.silly('New Schedule ('+String(dev.udsSchedule)+'s) UDS device on '+String(dev.udsSelectDevAddr));
|
|
229
|
+
} else {
|
|
230
|
+
await this.log.error('Could not setup UDS device on address '+String(dev.udsSelectDevAddr)+' due to missing device name.');
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
await this.E3UdsWorkers[devRxAddr].addSchedule(this, dev.udsSchedule, dev.udsScheduleDids);
|
|
235
|
+
await this.log.silly('New Schedule ('+String(dev.udsSchedule)+'s) UDS device on '+String(dev.udsSelectDevAddr));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
for (const worker of Object.values(this.E3UdsWorkers)) {
|
|
240
|
+
await worker.startup(this, 'normal');
|
|
241
|
+
await this.subscribeStates(this.namespace+'.'+worker.config.stateBase+'.*',this.onStateChange);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Is called when adapter shuts down - callback has to be called under any circumstances!
|
|
249
|
+
* @param {() => void} callback
|
|
250
|
+
*/
|
|
251
|
+
async onUnload(callback) {
|
|
252
|
+
try {
|
|
253
|
+
// Stop UDS workers:
|
|
254
|
+
for (const worker of Object.values(this.E3UdsWorkers)) await worker.stop(this);
|
|
255
|
+
for (const worker of Object.values(this.udsScanWorker.workers)) await worker.stop(this);
|
|
256
|
+
|
|
257
|
+
// Stop Collect workers:
|
|
258
|
+
if (this.e380Collect) this.e380Collect.stop(this);
|
|
259
|
+
for (const worker of Object.values(this.E3CollectExt)) await worker.stop(this);
|
|
260
|
+
for (const worker of Object.values(this.E3CollectInt)) await worker.stop(this);
|
|
261
|
+
|
|
262
|
+
// Stop CAN communication:
|
|
263
|
+
// @ts-ignore
|
|
264
|
+
await this.disconnectFromCan(this.channelExt,this.config.canExtName);
|
|
265
|
+
// @ts-ignore
|
|
266
|
+
await this.disconnectFromCan(this.channelInt,this.config.canIntName);
|
|
267
|
+
|
|
268
|
+
callback();
|
|
269
|
+
} catch (e) {
|
|
270
|
+
this.log.error('unLoad() could not be completed. err='+e.message);
|
|
271
|
+
callback();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// If you need to react to object changes, uncomment the following block and the corresponding line in the constructor.
|
|
276
|
+
// You also need to subscribe to the objects with `this.subscribeObjects`, similar to `this.subscribeStates`.
|
|
277
|
+
// /**
|
|
278
|
+
// * Is called if a subscribed object changes
|
|
279
|
+
// * @param {string} id
|
|
280
|
+
// * @param {ioBroker.Object | null | undefined} obj
|
|
281
|
+
// */
|
|
282
|
+
// @ts-ignore
|
|
283
|
+
/*
|
|
284
|
+
onObjectChange(id, obj) {
|
|
285
|
+
if (obj) {
|
|
286
|
+
// The object was changed
|
|
287
|
+
this.log.info(`object ${id} changed: ${JSON.stringify(obj)}`);
|
|
288
|
+
} else {
|
|
289
|
+
// The object was deleted
|
|
290
|
+
this.log.info(`object ${id} deleted`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
*/
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Is called if a subscribed state changes
|
|
297
|
+
* @param {string} id
|
|
298
|
+
* @param {ioBroker.State | null | undefined} state
|
|
299
|
+
*/
|
|
300
|
+
onStateChange(id, state) {
|
|
301
|
+
if ( (state) && (!state.ack) ) {
|
|
302
|
+
// The state was changed and ack == false
|
|
303
|
+
this.log.silly(`state ${id} changed: ${state.val} (ack = ${state.ack})`);
|
|
304
|
+
for (const worker of Object.values(this.E3UdsWorkers)) {
|
|
305
|
+
if (id.includes(this.namespace+'.'+worker.config.stateBase)) {
|
|
306
|
+
this.log.silly(`Call worker for ${worker.config.stateBase}`);
|
|
307
|
+
worker.onUdsStateChange(this, worker, id, state);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
sleep(milliseconds) {
|
|
314
|
+
return new Promise(resolve => setTimeout(resolve, milliseconds));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// If you need to accept messages in your adapter, uncomment the following block and the corresponding line in the constructor.
|
|
318
|
+
// /**
|
|
319
|
+
// * Some message was sent to this instance over message box. Used by email, pushover, text2speech, ...
|
|
320
|
+
// * Using this method requires "common.messagebox" property to be set to true in io-package.json
|
|
321
|
+
// * @param {ioBroker.Message} obj
|
|
322
|
+
// */
|
|
323
|
+
async onMessage(obj) {
|
|
324
|
+
//await this.log.debug('this.config:');
|
|
325
|
+
//await this.log.debug(JSON.stringify(this.config));
|
|
326
|
+
if (typeof obj === 'object' && obj.message) {
|
|
327
|
+
this.log.silly(`command received ${obj.command}`);
|
|
328
|
+
|
|
329
|
+
if (obj.command === 'getUdsDevices') {
|
|
330
|
+
if (obj.callback) {
|
|
331
|
+
if (!this.udsDevScanIsRunning) {
|
|
332
|
+
if (this.doUdsDevScan) {
|
|
333
|
+
let success = false;
|
|
334
|
+
this.udsDevScanIsRunning = true;
|
|
335
|
+
await this.log.silly(`Received data - ${JSON.stringify(obj)}`);
|
|
336
|
+
//this.udsScanDevices = obj.message.udsDevices;
|
|
337
|
+
success = await this.udsScanWorker.scanUdsDevices(this);
|
|
338
|
+
await this.sendTo(obj.from, obj.command, this.udsDevices, obj.callback);
|
|
339
|
+
if (success) this.doUdsDevScan = false;
|
|
340
|
+
this.udsDevScanIsRunning = false;
|
|
341
|
+
} else {
|
|
342
|
+
// Scan not required. Do nothing
|
|
343
|
+
this.sendTo(obj.from, obj.command, obj.message, obj.callback);
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
await this.log.debug('Request "getUdsDevice" during running UDS scan!');
|
|
347
|
+
this.sendTo(obj.from, obj.command, obj.message, obj.callback);
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
350
|
+
this.sendTo(obj.from, obj.command, [], obj.callback);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (obj.command === 'getUdsDeviceSelect') {
|
|
355
|
+
if (obj.callback) {
|
|
356
|
+
this.log.silly(`Received data - ${JSON.stringify(obj)}`);
|
|
357
|
+
if (Array.isArray(obj.message) ) {
|
|
358
|
+
const selUdsDevices = obj.message.map(item => ({label: item.devStateName, value: item.devAddr}));
|
|
359
|
+
this.log.silly(`Data to send - ${JSON.stringify(selUdsDevices)}`);
|
|
360
|
+
if (selUdsDevices) {
|
|
361
|
+
this.sendTo(obj.from, obj.command, selUdsDevices, obj.callback);
|
|
362
|
+
}
|
|
363
|
+
} else {
|
|
364
|
+
this.sendTo(obj.from, obj.command, [{label: 'Not available', value: ''}], obj.callback);
|
|
365
|
+
}
|
|
366
|
+
} else {
|
|
367
|
+
this.sendTo(obj.from, obj.command, [{label: 'Not available', value: ''}], obj.callback);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (obj.command === 'getExtColDeviceSelect') {
|
|
372
|
+
if (obj.callback) {
|
|
373
|
+
this.log.silly(`Received data - ${JSON.stringify(obj)}`);
|
|
374
|
+
if (Array.isArray(obj.message) ) {
|
|
375
|
+
const selUdsDevices = obj.message.filter(item => item.collectCanId != '').map(item => ({label: item.devStateName, value: item.collectCanId}));
|
|
376
|
+
this.log.silly(`Data to send - ${JSON.stringify(selUdsDevices)}`);
|
|
377
|
+
if (selUdsDevices) {
|
|
378
|
+
this.sendTo(obj.from, obj.command, selUdsDevices, obj.callback);
|
|
379
|
+
}
|
|
380
|
+
} else {
|
|
381
|
+
this.sendTo(obj.from, obj.command, [{label: 'Not available', value: ''}], obj.callback);
|
|
382
|
+
}
|
|
383
|
+
} else {
|
|
384
|
+
this.sendTo(obj.from, obj.command, [{label: 'Not available', value: ''}], obj.callback);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
if (obj.command === 'getIntColDeviceSelect') {
|
|
389
|
+
if (obj.callback) {
|
|
390
|
+
this.log.silly(`Received data - ${JSON.stringify(obj)}`);
|
|
391
|
+
if (Array.isArray(obj.message) ) {
|
|
392
|
+
const selUdsDevices = obj.message.filter(item => item.collectCanId != '').map(item => ({label: item.devStateName, value: item.collectCanId}));
|
|
393
|
+
this.log.silly(`Data to send - ${JSON.stringify(selUdsDevices)}`);
|
|
394
|
+
if (selUdsDevices) {
|
|
395
|
+
this.sendTo(obj.from, obj.command, selUdsDevices, obj.callback);
|
|
396
|
+
}
|
|
397
|
+
} else {
|
|
398
|
+
this.sendTo(obj.from, obj.command, [{label: 'Not available', value: ''}], obj.callback);
|
|
399
|
+
}
|
|
400
|
+
} else {
|
|
401
|
+
this.sendTo(obj.from, obj.command, [{label: 'Not available', value: ''}], obj.callback);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (obj.command === 'startDidScan') {
|
|
406
|
+
if (obj.callback) {
|
|
407
|
+
if (!this.udsDidScanIsRunning) {
|
|
408
|
+
this.udsDidScanIsRunning = true;
|
|
409
|
+
this.log.silly(`Received data - ${JSON.stringify(obj)}`);
|
|
410
|
+
await this.udsScanWorker.scanUdsDids(this,this.udsDevAddrs,this.udsDidsMaxNmbr);
|
|
411
|
+
//await this.udsScanWorker.scanUdsDids(this,this.udsDevAddrs,300);
|
|
412
|
+
this.sendTo(obj.from, obj.command, this.udsDevices, obj.callback);
|
|
413
|
+
this.udsDidScanIsRunning = false;
|
|
414
|
+
} else {
|
|
415
|
+
this.log.silly('Request "startDidScan" during running UDS did scan!');
|
|
416
|
+
this.sendTo(obj.from, obj.command, obj.message, obj.callback);
|
|
417
|
+
}
|
|
418
|
+
} else {
|
|
419
|
+
this.sendTo(obj.from, obj.command, obj.message, obj.callback);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (obj.command === 'getUdsDids') {
|
|
424
|
+
if (obj.callback) {
|
|
425
|
+
this.log.silly(`Received data - ${JSON.stringify(obj)}`);
|
|
426
|
+
if ( (obj.message) && (this.udsDevStateNames.includes(obj.message)) ) {
|
|
427
|
+
const udsDids = new storage.storageDids({stateBase:obj.message, device:obj.message});
|
|
428
|
+
await udsDids.readKnownDids(this);
|
|
429
|
+
const udsDidsTable = [];
|
|
430
|
+
if (udsDids.didsDevSpecAvail) {
|
|
431
|
+
for (const [did, item] of Object.entries(udsDids.didsDictDevCom)) {
|
|
432
|
+
udsDidsTable.push({didId:Number(did), didLen:Number(item.len), didName:item.id, didCodec:item.codec});
|
|
433
|
+
//if (udsDidsTable.length >= 50) break;
|
|
434
|
+
}
|
|
435
|
+
for (const [did, item] of Object.entries(udsDids.didsDictDevSpec)) {
|
|
436
|
+
udsDidsTable.push({didId:Number(did), didLen:Number(item.len), didName:item.id, didCodec:item.codec});
|
|
437
|
+
//if (udsDidsTable.length >= 60) break;
|
|
438
|
+
}
|
|
439
|
+
udsDidsTable.sort((a,b) => a.didId-b.didId);
|
|
440
|
+
}
|
|
441
|
+
this.sendTo(obj.from, obj.command, {native: {tableUdsDids: udsDidsTable}}, obj.callback);
|
|
442
|
+
} else {
|
|
443
|
+
this.sendTo(obj.from, obj.command, {native: {tableUdsDids: []}}, obj.callback);
|
|
444
|
+
}
|
|
445
|
+
} else {
|
|
446
|
+
this.sendTo(obj.from, obj.command, {native: {tableUdsDids: []}}, obj.callback);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
if (obj.command === 'getUdsDidsDevSelect') {
|
|
451
|
+
if (obj.callback) {
|
|
452
|
+
this.log.silly(`Received data - ${JSON.stringify(obj)}`);
|
|
453
|
+
// @ts-ignore
|
|
454
|
+
const selUdsDevices = this.config.tableUdsDevices.map(item => ({ label: item.devStateName, value: item.devStateName }));
|
|
455
|
+
await this.log.silly(`Data to send - ${JSON.stringify(selUdsDevices)}`);
|
|
456
|
+
if (selUdsDevices) {
|
|
457
|
+
await this.sendTo(obj.from, obj.command, selUdsDevices, obj.callback);
|
|
458
|
+
}
|
|
459
|
+
} else {
|
|
460
|
+
await this.sendTo(obj.from, obj.command, [{label: 'Not available', value: ''}], obj.callback);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
onCanMsgExt(msg) {
|
|
469
|
+
if ( (this.e380Collect) && (this.e380Collect.config.canID.includes(msg.id)) ) { this.e380Collect.msgCollect(this, msg); }
|
|
470
|
+
if (this.E3CollectExt[msg.id]) this.E3CollectExt[msg.id].msgCollect(this, msg);
|
|
471
|
+
if (this.E3UdsWorkers[msg.id]) this.E3UdsWorkers[msg.id].msgUds(this, msg);
|
|
472
|
+
if (this.udsScanWorker.workers[msg.id]) this.udsScanWorker.workers[msg.id].msgUds(this, msg);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
onCanMsgInt(msg) {
|
|
476
|
+
if (this.E3CollectInt[msg.id]) this.E3CollectInt[msg.id].msgCollect(this, msg);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
if (require.main !== module) {
|
|
482
|
+
// Export the constructor in compact mode
|
|
483
|
+
/**
|
|
484
|
+
* @param {Partial<utils.AdapterOptions>} [options={}]
|
|
485
|
+
*/
|
|
486
|
+
module.exports = (options) => new E3oncan(options);
|
|
487
|
+
} else {
|
|
488
|
+
// otherwise start the instance directly
|
|
489
|
+
new E3oncan();
|
|
490
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "iobroker.e3oncan",
|
|
3
|
+
"version": "0.6.9",
|
|
4
|
+
"description": "Collect data on CAN bus for Viessmann E3 devices, e.g. Vitocal, Vitocharge, Energy Meter E380",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Juergen",
|
|
7
|
+
"email": "juergen.bonfert@gmail.com"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/MyHomeMyData/ioBroker.e3oncan",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"Viessmann",
|
|
13
|
+
"E3",
|
|
14
|
+
"CAN",
|
|
15
|
+
"Heating",
|
|
16
|
+
"PV",
|
|
17
|
+
"Energy Meter"
|
|
18
|
+
],
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git@github.com:MyHomeMyData/ioBroker.e3oncan.git"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">= 16"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@iobroker/adapter-core": "^3.0.4",
|
|
28
|
+
"Buffer": "^0.0.0",
|
|
29
|
+
"serialport": "^12.0.0",
|
|
30
|
+
"socketcan": "^4.0.4"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@alcalzone/release-script": "^3.7.0",
|
|
34
|
+
"@alcalzone/release-script-plugin-iobroker": "^3.7.0",
|
|
35
|
+
"@alcalzone/release-script-plugin-license": "^3.7.0",
|
|
36
|
+
"@alcalzone/release-script-plugin-manual-review": "^3.7.0",
|
|
37
|
+
"@iobroker/adapter-dev": "^1.2.0",
|
|
38
|
+
"@iobroker/testing": "^4.1.0",
|
|
39
|
+
"@tsconfig/node16": "^16.1.1",
|
|
40
|
+
"@types/chai": "^4.3.10",
|
|
41
|
+
"@types/chai-as-promised": "^7.1.8",
|
|
42
|
+
"@types/mocha": "^10.0.6",
|
|
43
|
+
"@types/node": "^20.9.0",
|
|
44
|
+
"@types/proxyquire": "^1.3.31",
|
|
45
|
+
"@types/sinon": "^17.0.2",
|
|
46
|
+
"@types/sinon-chai": "^3.2.12",
|
|
47
|
+
"chai": "^4.3.10",
|
|
48
|
+
"chai-as-promised": "^7.1.1",
|
|
49
|
+
"eslint": "^8.56.0",
|
|
50
|
+
"mocha": "^10.2.0",
|
|
51
|
+
"proxyquire": "^2.1.3",
|
|
52
|
+
"sinon": "^17.0.1",
|
|
53
|
+
"sinon-chai": "^3.7.0",
|
|
54
|
+
"typescript": "~5.3.3"
|
|
55
|
+
},
|
|
56
|
+
"main": "main.js",
|
|
57
|
+
"files": [
|
|
58
|
+
"admin{,/!(src)/**}/!(tsconfig|tsconfig.*|.eslintrc).{json,json5}",
|
|
59
|
+
"admin{,/!(src)/**}/*.{html,css,png,svg,jpg,js}",
|
|
60
|
+
"lib/",
|
|
61
|
+
"www/",
|
|
62
|
+
"io-package.json",
|
|
63
|
+
"LICENSE",
|
|
64
|
+
"main.js"
|
|
65
|
+
],
|
|
66
|
+
"scripts": {
|
|
67
|
+
"test:js": "mocha --config test/mocharc.custom.json \"{!(node_modules|test)/**/*.test.js,*.test.js,test/**/test!(PackageFiles|Startup).js}\"",
|
|
68
|
+
"test:package": "mocha test/package --exit",
|
|
69
|
+
"test:integration": "mocha test/integration --exit",
|
|
70
|
+
"test": "npm run test:js && npm run test:package",
|
|
71
|
+
"check": "tsc --noEmit -p tsconfig.check.json",
|
|
72
|
+
"lint": "eslint .",
|
|
73
|
+
"translate": "translate-adapter",
|
|
74
|
+
"release": "release-script"
|
|
75
|
+
},
|
|
76
|
+
"bugs": {
|
|
77
|
+
"url": "https://github.com/MyHomeMyData/ioBroker.e3oncan/issues"
|
|
78
|
+
},
|
|
79
|
+
"readmeFilename": "README.md"
|
|
80
|
+
}
|