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/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
+ }