iobroker.ebus 3.2.4 → 3.2.6

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.
Files changed (47) hide show
  1. package/.eslintrc.json +34 -34
  2. package/.releaseconfig.json +3 -0
  3. package/LICENSE +20 -20
  4. package/README.md +147 -130
  5. package/admin/index_m.html +419 -419
  6. package/admin/style.css +18 -18
  7. package/admin/words.js +27 -27
  8. package/io-package.json +218 -192
  9. package/lib/support_tools.js +370 -370
  10. package/lib/tools.js +99 -99
  11. package/main.js +1232 -1232
  12. package/package.json +13 -11
  13. package/widgets/ebus/lib/js/flot/jquery.canvaswrapper.js +549 -549
  14. package/widgets/ebus/lib/js/flot/jquery.colorhelpers.js +199 -199
  15. package/widgets/ebus/lib/js/flot/jquery.flot.axislabels.js +212 -212
  16. package/widgets/ebus/lib/js/flot/jquery.flot.browser.js +98 -98
  17. package/widgets/ebus/lib/js/flot/jquery.flot.categories.js +202 -202
  18. package/widgets/ebus/lib/js/flot/jquery.flot.composeImages.js +330 -330
  19. package/widgets/ebus/lib/js/flot/jquery.flot.crosshair.js +202 -202
  20. package/widgets/ebus/lib/js/flot/jquery.flot.drawSeries.js +662 -662
  21. package/widgets/ebus/lib/js/flot/jquery.flot.errorbars.js +375 -375
  22. package/widgets/ebus/lib/js/flot/jquery.flot.fillbetween.js +254 -254
  23. package/widgets/ebus/lib/js/flot/jquery.flot.flatdata.js +47 -47
  24. package/widgets/ebus/lib/js/flot/jquery.flot.hover.js +361 -361
  25. package/widgets/ebus/lib/js/flot/jquery.flot.image.js +249 -249
  26. package/widgets/ebus/lib/js/flot/jquery.flot.js +2953 -2953
  27. package/widgets/ebus/lib/js/flot/jquery.flot.legend.js +437 -437
  28. package/widgets/ebus/lib/js/flot/jquery.flot.logaxis.js +298 -298
  29. package/widgets/ebus/lib/js/flot/jquery.flot.navigate.js +834 -834
  30. package/widgets/ebus/lib/js/flot/jquery.flot.pie.js +794 -794
  31. package/widgets/ebus/lib/js/flot/jquery.flot.resize.js +60 -60
  32. package/widgets/ebus/lib/js/flot/jquery.flot.saturated.js +43 -43
  33. package/widgets/ebus/lib/js/flot/jquery.flot.selection.js +527 -527
  34. package/widgets/ebus/lib/js/flot/jquery.flot.stack.js +220 -220
  35. package/widgets/ebus/lib/js/flot/jquery.flot.symbol.js +98 -98
  36. package/widgets/ebus/lib/js/flot/jquery.flot.threshold.js +143 -143
  37. package/widgets/ebus/lib/js/flot/jquery.flot.time.js +586 -586
  38. package/widgets/ebus/lib/js/flot/jquery.flot.touch.js +320 -320
  39. package/widgets/ebus/lib/js/flot/jquery.flot.touchNavigate.js +360 -360
  40. package/widgets/ebus/lib/js/flot/jquery.flot.uiConstants.js +10 -10
  41. package/widgets/ebus/lib/js/flot/jquery.js +9473 -9473
  42. package/widgets/ebus/lib/js/lib/globalize.culture.en-US.js +33 -33
  43. package/widgets/ebus/lib/js/lib/globalize.js +1601 -1601
  44. package/widgets/ebus/lib/js/lib/jquery.event.drag.js +145 -145
  45. package/widgets/ebus/lib/js/lib/jquery.mousewheel.js +86 -86
  46. package/widgets/ebus.html +2395 -2395
  47. package/readme.txt +0 -297
package/main.js CHANGED
@@ -1,1233 +1,1233 @@
1
- /*
2
- * ebus adapter für iobroker
3
- *
4
- * Created: 15.09.2016 21:31:28
5
- * Author: Rene
6
-
7
-
8
- */
9
-
10
- /* jshint -W097 */// jshint strict:false
11
- /*jslint node: true */
12
- "use strict";
13
-
14
-
15
-
16
-
17
- const utils = require("@iobroker/adapter-core");
18
- const ebusdMinVersion = [23, 2];
19
- let ebusdVersion = [0, 0];
20
- let ebusdUpdateVersion = [0, 0];
21
-
22
- let adapter;
23
- function startAdapter(options) {
24
- options = options || {};
25
- Object.assign(options, {
26
- name: "ebus",
27
- //#######################################
28
- //
29
- ready: function () {
30
- try {
31
- //adapter.log.debug('start');
32
- main();
33
- }
34
- catch (e) {
35
- adapter.log.error("exception catch after ready [" + e + "]");
36
- }
37
- },
38
- //#######################################
39
- // is called when adapter shuts down
40
- unload: function (callback) {
41
- try {
42
-
43
- if (intervalID != null) {
44
- clearInterval(intervalID);
45
- }
46
- if (updateTimerID != null) {
47
- clearTimeout(updateTimerID);
48
- }
49
- adapter && adapter.log && adapter.log.info && adapter.log.info("cleaned everything up...");
50
- //to do stop intervall
51
- callback();
52
- } catch (e) {
53
- callback();
54
- }
55
- },
56
-
57
- stateChange: async (id, state) => {
58
- await HandleStateChange(id, state);
59
- },
60
- //#######################################
61
- //
62
- message: async (obj) => {
63
- if (obj) {
64
- switch (obj.command) {
65
- case "findParams":
66
- // e.g. send email or pushover or whatever
67
- adapter.log.debug("findParams command");
68
- // Send response in callback if required
69
- await FindParams(obj);
70
- break;
71
- default:
72
- adapter.log.error("unknown message " + obj.command);
73
- break;
74
- }
75
- }
76
- }
77
- //#######################################
78
- //
79
- });
80
- adapter = new utils.Adapter(options);
81
-
82
- return adapter;
83
- }
84
-
85
-
86
- const axios = require('axios');
87
- const net = require("net");
88
- const { PromiseSocket } = require("promise-socket");
89
-
90
- let intervalID=null;
91
- let updateTimerID=null;
92
-
93
- async function main() {
94
-
95
- adapter.log.debug("start with interface ebusd ");
96
-
97
- FillPolledVars();
98
- FillHistoryVars();
99
-
100
- await checkVariables();
101
-
102
- await subscribeVars();
103
-
104
- let readInterval = 5;
105
- if (parseInt(adapter.config.readInterval) > 0) {
106
- readInterval = adapter.config.readInterval;
107
- }
108
- adapter.log.debug("read every " + readInterval + " minutes");
109
- intervalID = setInterval(Do, readInterval * 60 * 1000);
110
-
111
- //read at adapterstart
112
- await Do();
113
-
114
- }
115
-
116
- let requestRunning = false;
117
-
118
- async function DoRequest() {
119
-
120
- adapter.log.debug("DoRequest ");
121
-
122
- if (!requestRunning) {
123
- requestRunning = true;
124
- await ebusd_ReadValues();
125
-
126
- await ebusd_ReceiveData();
127
- }
128
- else {
129
- adapter.log.debug("DoRequest: do nothing already running ");
130
- }
131
- requestRunning = false;
132
- }
133
-
134
- async function Do() {
135
-
136
- adapter.log.debug("starting ... " );
137
-
138
- await ebusd_Command();
139
-
140
- await DoRequest();
141
-
142
- }
143
-
144
-
145
- async function HandleStateChange(id, state) {
146
-
147
-
148
- if (state != null && state.ack !== true) {
149
-
150
- adapter.log.debug("handle state change " + id);
151
- const ids = id.split(".");
152
-
153
- if (ids[2] === "cmd") {
154
- await ebusd_Command();
155
- StartDataRequest();
156
- //see issue #77: only one request possible
157
- //await Do();
158
- }
159
- //unhandled state change ebus.0.find
160
- else if (ids[2] === "find") {
161
- await ebusd_find();
162
- }
163
- else {
164
- adapter.log.warn("unhandled state change " + id);
165
- }
166
- }
167
- }
168
-
169
-
170
- function StartDataRequest() {
171
-
172
- if (updateTimerID != null) {
173
- //already running
174
- clearTimeout(updateTimerID);
175
- updateTimerID = null;
176
- }
177
- //start or restart
178
- updateTimerID = setTimeout(DataRequest, 500);
179
- adapter.log.debug("StartDataRequest");
180
- }
181
-
182
-
183
- async function DataRequest() {
184
- adapter.log.debug("get data after command and timeout");
185
- if (updateTimerID != null) {
186
- clearTimeout(updateTimerID);
187
- updateTimerID = null;
188
- }
189
- await DoRequest();
190
- }
191
-
192
-
193
- let oPolledVars = [];
194
- function FillPolledVars() {
195
-
196
- if ( adapter.config.PolledDPs !== undefined && adapter.config.PolledDPs != null && adapter.config.PolledDPs.length > 0) {
197
- adapter.log.debug("use new object list for polled vars");
198
-
199
- //2023-02-10 only active vars
200
- for (let i = 0; i < adapter.config.PolledDPs.length; i++) {
201
- if (adapter.config.PolledDPs[i].active) {
202
- oPolledVars.push(adapter.config.PolledDPs[i]);
203
- }
204
- }
205
-
206
- }
207
- else {
208
- //make it compatible to old versions
209
- adapter.log.debug("check old comma separeted list for polled vars");
210
- const oPolled = adapter.config.PolledValues.split(",");
211
-
212
- if (oPolled.length > 0) {
213
-
214
- for (let i = 0; i < oPolled.length; i++) {
215
- if (oPolled[i].length > 0) {
216
- //console.log('add ' + oPolled[i]);
217
- const value = {
218
- circuit: "",
219
- name: oPolled[i],
220
- parameter: ""
221
- }
222
- oPolledVars.push(value);
223
- }
224
- }
225
- }
226
- }
227
-
228
- adapter.log.info("list of polled vars " + JSON.stringify(oPolledVars));
229
-
230
- }
231
-
232
- let oHistoryVars = [];
233
- function FillHistoryVars() {
234
-
235
- if (adapter.config.HistoryDPs !== undefined && adapter.config.HistoryDPs != null && adapter.config.HistoryDPs.length > 0) {
236
- adapter.log.debug("use new object list for history vars");
237
- oHistoryVars = adapter.config.HistoryDPs;
238
- }
239
- else {
240
- //make it compatible to old versions
241
- adapter.log.debug("check old comma separeted list for history vars");
242
- const oHistory = adapter.config.HistoryValues.split(",");
243
-
244
- if (oHistory.length > 0) {
245
-
246
- for (let i = 0; i < oHistory.length; i++) {
247
- if (oHistory[i].length > 0) {
248
- console.log('add ' + oHistory[i]);
249
- const value = {
250
- name: oHistory[i],
251
- }
252
- oHistoryVars.push(value);
253
- }
254
- }
255
- }
256
- }
257
- }
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
- //===================================================================================================
266
- // ebusd interface
267
-
268
- async function ebusd_Command() {
269
- const obj = await adapter.getStateAsync("cmd");
270
-
271
- if (obj !== undefined && obj != null) {
272
- const cmds = obj.val;
273
- if (cmds !== "") {
274
- adapter.log.debug("got command(s): " + cmds);
275
-
276
- adapter.log.debug("connect telnet to IP " + adapter.config.targetIP + " port " + parseInt(adapter.config.targetTelnetPort));
277
-
278
- try {
279
- const socket = new net.Socket();
280
- const promiseSocket = new PromiseSocket(socket);
281
-
282
- await promiseSocket.connect(parseInt(adapter.config.targetTelnetPort), adapter.config.targetIP);
283
- adapter.log.debug("telnet connected for cmd");
284
- promiseSocket.setTimeout(5000);
285
-
286
- const oCmds = cmds.split(",");
287
-
288
- if (oCmds.length > 0) {
289
- let received = "";
290
- for (let n = 0; n < oCmds.length; n++) {
291
-
292
- adapter.log.debug("send " + oCmds[n]);
293
- await promiseSocket.write(oCmds[n] + "\n");
294
-
295
- const data = await promiseSocket.read();
296
-
297
- if (data.includes("ERR")) {
298
- adapter.log.warn("sent " + oCmds[n] + ", received " + data + " please check ebusd logs for details!");
299
- }
300
- else {
301
- adapter.log.debug("received " + data);
302
- }
303
- received += data.toString();
304
- received += ", ";
305
- }
306
-
307
- //see issue #78: remove CR, LF and last comma
308
- received = received.replace(/\r?\n|\r/g,"");
309
- received = received.slice(0, -2);
310
-
311
- //set result to cmdResult
312
- await adapter.setStateAsync("cmdResult", { ack: true, val: received });
313
- }
314
- else {
315
- adapter.log.warn("no commands in list " + cmds + " " + JSON.stringify(oCmds));
316
- }
317
- await adapter.setStateAsync("cmd", { ack: true, val: "" });
318
-
319
- promiseSocket.destroy();
320
-
321
- } catch (e) {
322
- adapter.log.error("exception from tcp socket" + "[" + e + "]");
323
- }
324
- }
325
- }
326
- else {
327
- adapter.log.debug("object cmd not found " + JSON.stringify(obj));
328
- }
329
- }
330
-
331
- async function ebusd_find(){
332
- try {
333
- const socket = new net.Socket();
334
- const promiseSocket = new PromiseSocket(socket);
335
-
336
- await promiseSocket.connect(parseInt(adapter.config.targetTelnetPort), adapter.config.targetIP);
337
- adapter.log.debug("telnet connected for cmd");
338
- promiseSocket.setTimeout(5000);
339
-
340
- await promiseSocket.write("find -F circuit,name,comment\n");
341
-
342
- const data = await promiseSocket.read();
343
-
344
- if (data.includes("ERR")) {
345
- adapter.log.warn("received error! sent find, received " + data + " please check ebusd logs for details!");
346
- }
347
- else {
348
- adapter.log.debug("received " + typeof data + " " + data);
349
- }
350
-
351
- let str = new TextDecoder().decode(data);
352
- let datas = str.split(/\r?\n/)
353
-
354
- for (let i = 0; i < datas.length; i++) {
355
-
356
- //adapter.log.debug(JSON.stringify(datas[i]));
357
-
358
- let names = datas[i].split(",");
359
-
360
- //circuit,name,comment
361
- await UpdateDP(names[0], names[1], names[2]);
362
-
363
- let cmd = "read -f -c " + names[0] + " " + names[1] ;
364
-
365
- adapter.log.debug("send cmd " + cmd);
366
-
367
- cmd += "\n";
368
- await promiseSocket.write(cmd);
369
-
370
- const result = await promiseSocket.read();
371
-
372
- adapter.log.debug("received " + typeof result + " " + result);
373
- }
374
-
375
-
376
- promiseSocket.destroy();
377
-
378
- } catch (e) {
379
- adapter.log.error("exception from tcp socket in ebusd_find" + "[" + e + "]");
380
- }
381
-
382
- }
383
-
384
-
385
-
386
- //just call http://192.168.0.123:8889/data
387
-
388
- async function subscribeVars() {
389
- adapter.subscribeStates("cmd");
390
-
391
- adapter.subscribeStates("find");
392
-
393
- await adapter.setStateAsync("cmdResult", { ack: true, val: "" });
394
- }
395
-
396
- async function CreateObject(key, obj) {
397
-
398
- const obj_new = await adapter.getObjectAsync(key);
399
- //adapter.log.warn("got object " + JSON.stringify(obj_new));
400
-
401
- if (obj_new != null) {
402
-
403
- if ((obj_new.common.role != obj.common.role
404
- || obj_new.common.type != obj.common.type
405
- || (obj_new.common.unit != obj.common.unit && obj.common.unit != null)
406
- || obj_new.common.read != obj.common.read
407
- || obj_new.common.write != obj.common.write
408
- || obj_new.common.name != obj.common.name)
409
- && obj.type === "state"
410
- ) {
411
- adapter.log.warn("change object " + JSON.stringify(obj) + " " + JSON.stringify(obj_new));
412
- await adapter.extendObject(key, {
413
- common: {
414
- name: obj.common.name,
415
- role: obj.common.role,
416
- type: obj.common.type,
417
- unit: obj.common.unit,
418
- read: obj.common.read,
419
- write: obj.common.write
420
- }
421
- });
422
- }
423
- }
424
- else {
425
- await adapter.setObjectNotExistsAsync(key, obj);
426
- }
427
- }
428
-
429
-
430
- //circuit,name,comment
431
- async function UpdateDP(circuit, name, comment) {
432
-
433
- let key = circuit + ".messages." + name;
434
- adapter.log.debug("update check for " + key);
435
-
436
-
437
- // ehp.messages.Injection
438
- //ebus.0.ehp.messages.Injection
439
-
440
- const obj = await adapter.getObjectAsync(key);
441
- adapter.log.debug("update check got " + JSON.stringify(obj));
442
-
443
-
444
- //update check got null
445
-
446
- if (obj != null) {
447
-
448
- if (obj.common.name != comment) {
449
- adapter.log.debug("update " + key + " " + comment);
450
- await adapter.extendObject(key, {
451
- common: {
452
- name: comment,
453
- read: true,
454
- write: false
455
- }
456
- });
457
- }
458
- }
459
- else {
460
- await adapter.setObjectNotExistsAsync(key, {
461
- type: "channel",
462
- common: {
463
- name: comment,
464
- read: true,
465
- write: false
466
- }
467
- });
468
- }
469
-
470
- }
471
-
472
-
473
-
474
- async function checkVariables() {
475
- adapter.log.debug("init variables ");
476
-
477
- let key;
478
- let obj;
479
-
480
- key = "cmd";
481
- obj= {
482
- type: "state",
483
- common: {
484
- name: "ebusd command",
485
- type: "string",
486
- role: "text",
487
- read: true,
488
- write: true
489
- }
490
- };
491
- await CreateObject(key, obj);
492
-
493
- key = "cmdResult";
494
- obj = {
495
- type: "state",
496
- common: {
497
- name: "ebusd command result",
498
- type: "string",
499
- role: "text",
500
- read: true,
501
- write: false
502
- }
503
- };
504
- await CreateObject(key, obj);
505
-
506
- key = "find";
507
- obj = {
508
- type: "state",
509
- common: {
510
- name: "find existing data points",
511
- type: "boolean",
512
- role: "button",
513
- read: false,
514
- write: true
515
- }
516
- };
517
- await CreateObject(key, obj);
518
-
519
-
520
-
521
- adapter.log.debug("init common variables and " + oHistoryVars.length + " history DP's");
522
-
523
- if (oHistoryVars.length > 0) {
524
-
525
- if (oHistoryVars.length > 4) {
526
- adapter.log.warn("too many history values " + oHistoryVars.length + " -> maximum is 4");
527
- }
528
-
529
- for (let n = 1; n <= oHistoryVars.length; n++) {
530
-
531
- if (oHistoryVars[n - 1].name.length > 0) {
532
- const name = "history value " + n + " as JSON " + oHistoryVars[n - 1].name;
533
- key = "history.value" + n;
534
- obj= {
535
- type: "state",
536
- common: {
537
- name: name,
538
- type: "string",
539
- role: "value",
540
- unit: "",
541
- read: true,
542
- write: false
543
- },
544
- native: { location: key }
545
- };
546
- await CreateObject(key, obj);
547
- }
548
- else {
549
- adapter.log.warn("ignoring history value " + n + " (invalid name)");
550
- }
551
- }
552
-
553
- key = "history.date";
554
- obj= {
555
- type: "state",
556
- common: {
557
- name: "ebus history date / time as JSON",
558
- type: "string",
559
- role: "value",
560
- unit: "",
561
- read: true,
562
- write: false
563
- },
564
- native: {
565
- location: key
566
- }
567
- };
568
- await CreateObject(key, obj);
569
- }
570
- key = "history.error";
571
- obj= {
572
- type: "state",
573
- common: {
574
- name: "ebus error",
575
- type: "string",
576
- role: "value",
577
- unit: "",
578
- read: true,
579
- write: false
580
- },
581
- native: { location: key }
582
- };
583
- await CreateObject(key, obj);
584
- }
585
-
586
-
587
- function VersionCheck() {
588
-
589
- if (ebusdVersion[0] > 0 ) {
590
- if (ebusdVersion[0] < ebusdMinVersion[0] || (ebusdVersion[0] == ebusdMinVersion[0] && ebusdVersion[1] < ebusdMinVersion[1])) {
591
- adapter.log.info("please update ebusd, old version found: " + ebusdVersion[0] + "." + ebusdVersion[1] + " supported version is " + ebusdMinVersion[0] + "." + ebusdMinVersion[1]);
592
- }
593
- if (ebusdVersion[0] > ebusdMinVersion[0] || (ebusdVersion[0] >= ebusdMinVersion[0] && ebusdVersion[1] > ebusdMinVersion[1])) {
594
- adapter.log.info("unsupported ebusd version found (too new): " + ebusdVersion[0] + "." + ebusdVersion[1] + " supported version is " + ebusdMinVersion[0] + "." + ebusdMinVersion[1]);
595
- }
596
- }
597
-
598
- if (ebusdUpdateVersion[0] > 0 && ebusdVersion[0] > 0) {
599
-
600
- if (ebusdUpdateVersion[0] > ebusdVersion[0] || (ebusdUpdateVersion[0] == ebusdVersion[0] && ebusdUpdateVersion[1] > ebusdVersion[1])) {
601
- adapter.log.info("new ebusd version found: " + ebusdUpdateVersion[0] + "." + ebusdUpdateVersion[1] + " supported version is " + ebusdMinVersion[0] + "." + ebusdMinVersion[1]);
602
-
603
- }
604
-
605
- }
606
- }
607
-
608
- //get data via https in json -> this is the main data receiver; telnet just triggers ebusd to read data;
609
- //https://github.com/john30/ebusd/wiki/3.2.-HTTP-client
610
-
611
- async function ebusd_ReceiveData() {
612
-
613
- const sUrl = "http://" + adapter.config.targetIP + ":" + parseInt(adapter.config.targetHTTPPort) + "/data";
614
- adapter.log.debug("request data from " + sUrl);
615
-
616
- try {
617
-
618
- const buffer = await axios.get(sUrl);
619
-
620
- adapter.log.debug("got data " + typeof buffer.data + " " + JSON.stringify(buffer.data));
621
-
622
- const oData = buffer.data;
623
-
624
- //adapter.log.debug("oData " + oData);
625
-
626
- const flatten = require("flat");
627
-
628
- const newData = flatten(oData);
629
-
630
- const keys = Object.keys(newData);
631
-
632
- //adapter.log.debug("history: " + options.historyValues);
633
-
634
- const historyvalues = [];
635
- const historydates = [];
636
-
637
- const oToday = new Date();
638
- const month = oToday.getMonth() + 1;
639
-
640
- historydates.push({
641
- "date": oToday.getDate() + "." + month + "." + oToday.getFullYear(),
642
- "time": oToday.getHours() + ":" + oToday.getMinutes() + ":" + oToday.getSeconds()
643
- });
644
- //adapter.log.debug(JSON.stringify(historydates));
645
-
646
- let name = "unknown";
647
- let sError = "none";
648
- for (let i = 0; i < keys.length; i++) {
649
- let key = keys[i];
650
- const org_key = key;
651
-
652
- if (key.includes("[") || key.includes("]")) {
653
- adapter.log.debug("found unsupported chars in " + key);
654
- const start = key.indexOf('[');
655
- const end = key.lastIndexOf(']');
656
-
657
- if (start > 0 && end > 0) {
658
- const toReplace = key.slice(start, end + 1);
659
- key = key.replace(toReplace, "");
660
- }
661
- //adapter.log.warn("new key is " + key);
662
- }
663
-
664
- const subnames = key.split(".");
665
- const temp = subnames.length;
666
- //adapter.log.debug('Key : ' + key + ', Value : ' + newData[key]);
667
-
668
- //
669
- //if (key.match(adapter.FORBIDDEN_CHARS)) { continue; }
670
-
671
-
672
- if (key.includes("global.version")) {
673
- const value = newData[org_key];
674
- //adapter.log.info("in version, value " + value);
675
- const versionInfo = value.split('.');
676
- if (versionInfo.length > 1) {
677
- adapter.log.info("installed ebusd version is " + versionInfo[0] + "." + versionInfo[1]);
678
-
679
- ebusdVersion[0] = versionInfo[0];
680
- ebusdVersion[1] = versionInfo[1];
681
-
682
- VersionCheck();
683
- }
684
- }
685
-
686
- if (key.includes("global.updatecheck")) {
687
- let value = newData[org_key];
688
- //adapter.log.info("in version, value " + value);
689
-
690
- //revision v21.2 available
691
- value = value.replace("revision v", "");
692
- value = value.replace(" available", "");
693
-
694
- const versionInfo = value.split('.');
695
- if (versionInfo.length > 1) {
696
- adapter.log.info("found ebusd update version " + versionInfo[0] + "." + versionInfo[1]);
697
-
698
- ebusdUpdateVersion[0] = versionInfo[0];
699
- ebusdUpdateVersion[1] = versionInfo[1];
700
-
701
- VersionCheck();
702
- }
703
- }
704
-
705
-
706
-
707
- if (subnames[temp - 1].includes("name")) {
708
- name = newData[org_key];
709
- }
710
- else if (subnames[temp - 1].includes("value")) {
711
- //adapter.log.debug('Key : ' + key + ', Value : ' + newData[key] + " name " + name);
712
-
713
- let value = newData[org_key];
714
-
715
- if (value == null || value === undefined) {
716
- adapter.log.debug('Key : ' + key + ', Value : ' + newData[org_key] + " name " + name);
717
- }
718
-
719
-
720
- if (name === "hcmode2") {
721
- if (parseInt(value) === 0) {
722
- adapter.log.info(key + "in hcmode2 with value 0: off");
723
- value = "off";
724
- }
725
- else if (parseInt(value) === 5) {
726
- adapter.log.info(key + " with value 5: EVU Sperrzeit");
727
- value = "EVU Sperrzeit";
728
- }
729
- else {
730
- adapter.log.debug("in hcmode2, value " + value);
731
- }
732
- }
733
-
734
- let type = typeof value;
735
-
736
- if (adapter.config.useBoolean4Onoff) {
737
- if (type == "string" && (value == "on" || value == "off")) {
738
- adapter.log.debug('Key ' + key + " change to boolean " + value);
739
- //Key mc.messages.Status.fields.1.value could be boolean off
740
-
741
- type = "boolean";
742
-
743
- if (value == "on") {
744
- value = true;
745
- }
746
- else {
747
- value = false;
748
- }
749
-
750
- }
751
- }
752
- //value, change type if necessary
753
- await AddObject(key, type);
754
- await UpdateObject(key, value);
755
-
756
- //name parallel to value: used for lists in admin...
757
- const keyname = key.replace("value", "name");
758
- await AddObject(keyname, "string");
759
-
760
- await UpdateObject(keyname, name);
761
-
762
- //push to history
763
- //ebus.0.bai.messages.ReturnTemp.fields.temp.value
764
- //ebus.0.bai.messages.ReturnTemp.fields.tempmirror.value
765
- if (!subnames[temp - 2].includes("sensor") //ignore sensor states
766
- && !subnames[temp - 2].includes("mirror") //ignore mirror-data
767
- ) {
768
- for (let ii = 0; ii < oHistoryVars.length; ii++) {
769
-
770
- if (name === oHistoryVars[ii].name) {
771
-
772
- const sTemp = '{"' + name + '": "' + value + '"}';
773
- //adapter.log.debug(sTemp);
774
- historyvalues[ii] = [];
775
- historyvalues[ii].push(JSON.parse(sTemp));
776
- //adapter.log.debug(JSON.stringify(historyvalues));
777
- }
778
- }
779
- }
780
- }
781
- else if (subnames[temp - 1].includes("lastup")) {
782
-
783
- const value = newData[org_key];
784
-
785
- if (parseInt(value) > 0) {
786
- //adapter.log.debug('Key : ' + key + ', Value : ' + newData[key] + " name " + name);
787
-
788
- //umrechnen...
789
- const oDate = new Date(value * 1000);
790
- //const nDate = oDate.getDate();
791
- //const nMonth = oDate.getMonth() + 1;
792
- //const nYear = oDate.getFullYear();
793
- //const nHours = oDate.getHours();
794
- //const nMinutes = oDate.getMinutes();
795
- //const nSeconds = oDate.getSeconds();
796
-
797
- const sDate = oDate.toLocaleString();
798
- await AddObject(key, "string");
799
- await UpdateObject(key, sDate);
800
-
801
- const oToday = new Date();
802
-
803
- let bSkip = false;
804
-
805
- if (subnames[0].includes("scan") ||
806
- subnames[0].includes("ehp") ||
807
- (subnames.length>2 && subnames[2].includes("currenterror"))
808
-
809
- ) {
810
- bSkip = true;
811
- }
812
- if (temp > 2) {
813
- //adapter.log.debug("_______________size " + temp);
814
- if (subnames[2].includes("Timer")) {
815
- bSkip = true;
816
- }
817
- }
818
-
819
- if (!bSkip && Math.abs(oDate.getTime() - oToday.getTime()) > 1 * 60 * 60 * 1000) {
820
-
821
- const sError1 = "no update since " + sDate + " " + key + " ";
822
- if (sError.includes("none")) {
823
- sError = "ebus: " + sError1;
824
- }
825
- else {
826
- sError += sError1;
827
- }
828
- adapter.log.warn(sError1);
829
- }
830
-
831
-
832
- }
833
- }
834
- else if (subnames[0].includes("global")) {
835
- //adapter.log.debug('Key : ' + key + ', Value : ' + newData[key] + " name " + name);
836
- const value = newData[org_key];
837
- await AddObject(key, typeof value);
838
- await UpdateObject(key, value);
839
- }
840
- }
841
- await adapter.setStateAsync("history.error", { ack: true, val: sError });
842
-
843
- //adapter.log.debug(JSON.stringify(historyvalues));
844
-
845
- adapter.log.info("all http done");
846
-
847
-
848
- await UpdateHistory(historyvalues, historydates);
849
-
850
-
851
- }
852
- catch (e) {
853
- adapter.log.error("exception in ebusd_ReceiveData [" + e + "]");
854
-
855
- await adapter.setStateAsync("history.error", { ack: true, val: "exception in receive" });
856
- }
857
- //});
858
- }
859
-
860
-
861
-
862
- async function UpdateHistory(values, dates) {
863
-
864
- if (oHistoryVars.length > 0) {
865
- //prüfen ob alle json gleich lang sind
866
- let NoOfDates = -1;
867
-
868
- const obj = await adapter.getStateAsync("history.date");
869
-
870
- if (obj !== undefined && obj != null) {
871
- try {
872
- let oEbusDates = [];
873
- //adapter.log.debug("before " + obj.val);
874
- oEbusDates = JSON.parse(obj.val);
875
- //adapter.log.debug("after parse " + JSON.stringify(oEbusDates));
876
-
877
-
878
-
879
- oEbusDates.push(dates);
880
- //adapter.log.debug("after push " + JSON.stringify(oEbusDates));
881
- //limit length of object...
882
- if (oEbusDates.length > 200) {
883
-
884
- for (let i = oEbusDates.length; i > 200; i--) {
885
- //adapter.log.debug("delete");
886
- oEbusDates.shift();
887
- }
888
- }
889
- NoOfDates = oEbusDates.length;
890
- await adapter.setStateAsync("history.date", { ack: true, val: JSON.stringify(oEbusDates) });
891
- }
892
- catch (e) {
893
- adapter.log.error("exception in UpdateHistory part1 [" + e + "]");
894
- await adapter.setStateAsync("history.date", { ack: true, val: "[]" });
895
- NoOfDates = 0;
896
- }
897
- }
898
- else {
899
- adapter.log.warn("history.date not found, creating DP ");
900
- await adapter.setStateAsync("history.date", { ack: true, val: "[]" });
901
- NoOfDates = 0;
902
- }
903
-
904
- if (oHistoryVars.length > 0) {
905
- for (let ctr = 1; ctr <= oHistoryVars.length; ctr++) {
906
-
907
- if (oHistoryVars[ctr - 1].name.length > 0) {
908
- const ctrOkay = await UpdateHistoryValues(values, ctr, NoOfDates);
909
-
910
- if (!ctrOkay) {
911
- await adapter.setStateAsync("history.date", { ack: true, val: "[]" });
912
- NoOfDates = 0;
913
- adapter.log.warn("reset history date too");
914
- }
915
- }
916
- else {
917
- adapter.log.debug("ignoring history value " + ctr);
918
- }
919
- }
920
-
921
- adapter.log.info("all history done");
922
- }
923
- }
924
- else {
925
- adapter.log.debug("nothing to do for history");
926
- }
927
- }
928
-
929
-
930
-
931
- async function UpdateHistoryValues(values, ctr, curDateCtr) {
932
-
933
-
934
- let bRet = true;
935
-
936
- const obj = await adapter.getStateAsync("history.value" + ctr);
937
-
938
- if (obj !== undefined && obj != null) {
939
- try {
940
- let oEbusValues = [];
941
- if (obj !== null) {
942
- //adapter.log.debug("before " + obj.val);
943
-
944
- oEbusValues = JSON.parse(obj.val);
945
-
946
- //adapter.log.debug("after parse " + JSON.stringify(oEbusValues));
947
-
948
- //adapter.log.debug("after parse cnt " + oEbusValues.length);
949
- }
950
-
951
- //adapter.log.debug("values " + ctr + ": " + JSON.stringify(values[ctr-1]));
952
-
953
- oEbusValues.push(values[ctr - 1]);
954
- //adapter.log.debug("after push " + JSON.stringify(oEbusValues));
955
- //adapter.log.debug("after push cnt " + oEbusValues.length);
956
- //limit length of object...
957
- if (oEbusValues.length > 200) {
958
-
959
- for (let i = oEbusValues.length; i > 200; i--) {
960
- //adapter.log.debug("delete");
961
- oEbusValues.shift();
962
- }
963
- }
964
-
965
- const key = "history.value" + ctr;
966
- adapter.log.debug("update history " + key);
967
-
968
- if (curDateCtr != oEbusValues.length) {
969
- bRet = false;
970
- await adapter.setStateAsync("history.value" + ctr, { ack: true, val: "[]" });
971
- adapter.log.warn("reset history " + key + " because number of values different to date values");
972
-
973
- }
974
- else {
975
- await adapter.setStateAsync(key, { ack: true, val: JSON.stringify(oEbusValues) });
976
- }
977
-
978
-
979
- }
980
- catch (e) {
981
- adapter.log.error("exception in UpdateHistory part2 [" + e + "]");
982
- await adapter.setStateAsync("history.value" + ctr, { ack: true, val: "[]" });
983
- if (curDateCtr > 0) {
984
- bRet = false;
985
- }
986
- }
987
- }
988
- else {
989
- adapter.log.warn("history.value" + ctr + " not found, creating DP " + JSON.stringify(obj));
990
- await adapter.setStateAsync("history.value" + ctr, { ack: true, val: "[]" });
991
- if (curDateCtr > 0) {
992
- bRet = false;
993
- }
994
- }
995
-
996
- return bRet;
997
- }
998
-
999
-
1000
-
1001
- async function AddObject(key, type) {
1002
- //adapter.log.debug("addObject " + key);
1003
-
1004
- try {
1005
- const obj = await adapter.getObjectAsync(key);
1006
-
1007
- if (obj != null) {
1008
- //adapter.log.debug(" got Object " + JSON.stringify(obj));
1009
- if (obj.common.role != "value"
1010
- || obj.common.type != type) {
1011
- adapter.log.debug(" !!! need to extend for " + key);
1012
- await adapter.extendObject(key, {
1013
- common: {
1014
- type: type,
1015
- role: "value",
1016
- }
1017
- });
1018
- }
1019
- }
1020
- else {
1021
- adapter.log.warn(" !!! does not exist, creating now " + key );
1022
-
1023
- await adapter.setObjectNotExistsAsync(key, {
1024
- type: "state",
1025
- common: {
1026
- name: "data",
1027
- type: type,
1028
- role: "value",
1029
- unit: "",
1030
- read: true,
1031
- write: false
1032
- },
1033
- native: {
1034
- location: key
1035
- }
1036
- });
1037
- }
1038
-
1039
- } catch (e) {
1040
- adapter.log.error("exception in AddObject " + "[" + e + "]");
1041
- }
1042
- }
1043
-
1044
- async function UpdateObject(key, value) {
1045
- try {
1046
- if (value === undefined) {
1047
- adapter.log.warn("updateObject: not updated " + key + " value: " + value + " " + typeof value);
1048
- }
1049
- else if (value == null ) {
1050
- adapter.log.debug("updateObject: update to null " + key + " value: " + value);
1051
- await adapter.setStateAsync(key, { ack: true, val: null });
1052
- }
1053
- else {
1054
- adapter.log.debug("updateObject " + key + " : " + value);
1055
- await adapter.setStateAsync(key, { ack: true, val: value });
1056
- }
1057
- } catch (e) {
1058
- adapter.log.error("exception in UpdateObject " + "[" + e + "]");
1059
- }
1060
- }
1061
-
1062
-
1063
- //telnet client to write to ebusd
1064
- //https://github.com/john30/ebusd/wiki/3.1.-TCP-client-commands
1065
- /*
1066
- telnet 192.168.3.144 8890
1067
-
1068
- find -f -c broadcast outsidetemp
1069
- find -f outsidetemp
1070
- find -f YieldTotal
1071
-
1072
- read -f YieldTotal
1073
- read LegioProtectionEnabled
1074
-
1075
- read -f YieldTotal,read LegioProtectionEnabled,read -f -c broadcast outsidetemp
1076
-
1077
- */
1078
-
1079
-
1080
- //this function just triggers ebusd to read data; result will not be parsed; we just take the values from http result
1081
- //here we need a loop over all configured read data in admin-page
1082
- async function ebusd_ReadValues() {
1083
-
1084
- if (oPolledVars.length > 0) {
1085
-
1086
- adapter.log.debug("to poll ctr " + oPolledVars.length + " vals: " + JSON.stringify(oPolledVars));
1087
-
1088
- try {
1089
- const socket = new net.Socket();
1090
- const promiseSocket = new PromiseSocket(socket);
1091
-
1092
- await promiseSocket.connect(parseInt(adapter.config.targetTelnetPort), adapter.config.targetIP);
1093
- adapter.log.debug("telnet connected to poll variables " + adapter.config.targetIP + " port " + adapter.config.targetTelnetPort);
1094
- promiseSocket.setTimeout(5000);
1095
-
1096
- let retries = 0;
1097
- for (let nCtr = 0; nCtr < oPolledVars.length; nCtr++) {
1098
-
1099
- let circuit = "";
1100
- let params = "";
1101
- if (oPolledVars[nCtr].circuit != null && oPolledVars[nCtr].circuit.length > 0) {
1102
- circuit = "-c " + oPolledVars[nCtr].circuit + " ";
1103
- }
1104
- if (oPolledVars[nCtr].parameter != null && oPolledVars[nCtr].parameter.length > 0) {
1105
- params = " " + oPolledVars[nCtr].parameter;
1106
- }
1107
- let cmd = "read -f " + circuit + oPolledVars[nCtr].name + params;
1108
-
1109
- adapter.log.debug("send cmd " + cmd);
1110
-
1111
- cmd += "\n";
1112
- await promiseSocket.write(cmd);
1113
-
1114
- const data = await promiseSocket.read();
1115
-
1116
- //received ERR: arbitration lost for YieldThisYear
1117
- if (data.includes("ERR")) {
1118
- adapter.log.warn("sent " + cmd + ", received " + data + " for " + JSON.stringify(oPolledVars[nCtr]) + " please check ebusd logs for details!");
1119
-
1120
- /*
1121
- * sent read -f YieldLastYear, received ERR: arbitration lost for {"circuit":"","name":"YieldLastYear","parameter":""}
1122
- * */
1123
- if (data.includes("arbitration lost")) {
1124
-
1125
- retries++;
1126
- if (retries > adapter.config.maxretries) {
1127
- adapter.log.error("max retries, skip cmd " + cmd);
1128
- retries = 0;
1129
- }
1130
- else {
1131
- nCtr--;
1132
- adapter.log.debug("retry to send data ");
1133
- }
1134
- }
1135
- }
1136
- else {
1137
- adapter.log.debug("received " + data + " for " + JSON.stringify(oPolledVars[nCtr]));
1138
- }
1139
- }
1140
- promiseSocket.destroy();
1141
- adapter.log.debug("telnet disonnected");
1142
-
1143
- } catch (e) {
1144
- adapter.log.error("exception from tcp socket in ebusd_ReadValues " + "[" + e + "]");
1145
- }
1146
-
1147
-
1148
- }
1149
- else {
1150
- adapter.log.debug("nothing to poll; skip telnet");
1151
- }
1152
-
1153
- }
1154
-
1155
-
1156
- async function FindParams(obj) {
1157
-
1158
- adapter.log.debug("FindParams " + JSON.stringify(obj));
1159
-
1160
- let list = [];
1161
-
1162
- try {
1163
- let circuit = obj.message;
1164
-
1165
- const socket = new net.Socket();
1166
- const promiseSocket = new PromiseSocket(socket);
1167
-
1168
- await promiseSocket.connect(parseInt(adapter.config.targetTelnetPort), adapter.config.targetIP);
1169
- adapter.log.debug("telnet connected for cmd");
1170
- promiseSocket.setTimeout(5000);
1171
-
1172
- await promiseSocket.write("find -c " + circuit + " -F circuit,name\n");
1173
-
1174
- const data = await promiseSocket.read();
1175
-
1176
- if (data.includes("ERR")) {
1177
- adapter.log.warn("received error! sent find, received " + data + " please check ebusd logs for details!");
1178
- }
1179
- else {
1180
- adapter.log.debug("received " + typeof data + " " + data);
1181
- }
1182
- /*
1183
- received object ehp,AccelerationTestModeehp,AccelerationTestModeehp,ActualEnvironmentPowerehp,ActualEnvironmentPowerehp,ActualEnvironmentPowerPercentageehp,ActualEnvironmentPowerPercentageehp,ApplianceCodeehp,ApplianceCodeehp,Backupehp,Backupehp,BackupHoursehp,BackupHoursHcehp,BackupHoursHwcehp,BackupHysteresisehp,BackupIntegralehp,BackupModeHcehp,BackupModeHwcehp,BackupPowerCutehp,BackupStartsehp,BackupStartsHcehp,BackupStartsHwcehp,BackupTypeehp,BivalentTempehp,Bleedingehp,Bleedingehp,CirPumpehp,CirPumpehp,Code1ehp,Code1Code2Validehp,Code2ehp,Compehp,Compehp,CompControlStateehp,CompCutPressHighCountehp,CompCutPressLowCountehp,CompCutTempCountehp,CompDemandehp,CompHoursehp,CompHoursHcehp,CompHoursHwcehp,CompHysteresisehp,CompIntegralehp,CompPressHighehp,CompPressHighehp,CompPressLowehp,CompPressLowehp,CompStartsehp,CompStartsHcehp,CompStartsHwcehp,CompStateehp,CondensorTempehp,CondensorTempehp,currenterrorehp,Dateehp,DateTimeehp,DeltaTempT6T7ehp,ElectricWiringDiagramehp,ElectricWiringDiagramehp,EnergyBalancingReleaseehp,errorhistoryehp,FlowTempehp,FlowTempehp,FlowtempCoolingMinehp,FlowTempOffsetehp,Hc1Pumpehp,Hc1Pumpehp,Hc1PumpHoursehp,Hc1PumpPortehp,Hc1PumpStartsehp,Hc2Pumpehp,Hc2PumpHoursehp,HcFlowTempehp,HcFlowTempOffsetehp,HcModeDemandHoursehp,HcModeFulfilledHoursehp,HcParallelStorageFillingEnabledehp,HcPressehp,HcReturnTempehp,HcReturnTempehp,HcReturnTempOffsetehp,HeatPumpStatusehp,HeatPumpStatusehp,HeatpumpTypeehp,HwcHcValveehp,HwcHcValveehp,HwcHcValveStartsehp,HwcLaggingTimeehp,HwcLoadingDelayehp,HwcModeDemandHoursehp,HwcModeFulfilledHoursehp,HwcPumpStartsehp,HwcSwitchehp,HwcTempehp,HwcTempehp,HwcTempOffsetehp,HydraulicSchemeehp,ICLOutehp,ICLOutehp,Injectionehp,Integralehp,Mixer1DutyCycleehp,NumberCompStartsehp,OutsideTempehp,OutsideTempOffsetehp,OverpressureThresholdehp,PhaseOrderehp,PhaseOrderehp,PhaseStatusehp,PhaseStatusehp,PowerCutehp,PowerCutPreloadingehp,PressSwitchehp,PressSwitchehp,RebootCounterehp,ReturnTempMaxehp,SetModeehp,SoftwareCodeehp,Source2PumpHoursehp,Sourceehp,Sourceehp,SourceHoursehp,SourcePortehp,SourcePressehp,SourcePumpPrerunTimeehp,SourceStartsehp,SourceSwitchehp,SourceSwitchehp,SourceTempInputehp,SourceTempInputehp,SourceTempInputOffsetehp,SourceTempOutputehp,SourceTempOutputehp,SourceTempOutputOffsetehp,SourceTempOutputT8Minehp,StateSoftwareCodeehp,StateSoftwareCodeehp,Status01ehp,Status02ehp,Status16ehp,Statusehp,StatusCirPumpehp,StorageTempBottomehp,StorageTempBottomehp,StorageTempBottomOffsetehp,StorageTempTopehp,StorageTempTopehp,StorageTempTopOffsetehp,Subcoolingehp,Superheatehp,T19MaxToCompOffehp,TempInputehp,TempInputehp,TempInputOffsetehp,TempOutputehp,TempOutputehp,TempOutputOffsetehp,Timeehp,TimeBetweenTwoCompStartsMinehp,TimeCompOffMinehp,TimeCompOnMinehp,TimeOfNextPredictedPowerCutehp,TimeOfNextPredictedPowerCutehp,Weekdayehp,YieldTotalehp,YieldTotal
1184
- */
1185
- let str = new TextDecoder().decode(data);
1186
- let datas = str.split(/\r?\n/)
1187
-
1188
- for (let i = 0; i < datas.length; i++) {
1189
-
1190
- //adapter.log.debug(JSON.stringify(datas[i]));
1191
-
1192
- let names = datas[i].split(",");
1193
-
1194
- //doppelte und leere herausfiltern
1195
- let add = true;
1196
-
1197
- if (names[0] == "" || names[1] == "") {
1198
- add = false;
1199
- }
1200
- else {
1201
-
1202
- for (let n = 0; n < list.length; n++) {
1203
-
1204
- if (list[n].circuit == names[0] && list[n].name == names[1]) {
1205
- add = false;
1206
- //already in list
1207
- }
1208
- }
1209
- }
1210
-
1211
- if (add) {
1212
- let entry = {
1213
- active: false,
1214
- circuit: names[0],
1215
- name: names[1]
1216
- }
1217
-
1218
- list.push(entry);
1219
- }
1220
- }
1221
- } catch (e) {
1222
- adapter.log.error("exception in FindParams " + "[" + e + "]");
1223
- }
1224
- adapter.sendTo(obj.from, obj.command, list, obj.callback);
1225
- }
1226
-
1227
- // If started as allInOne/compact mode => return function to create instance
1228
- if (module && module.parent) {
1229
- module.exports = startAdapter;
1230
- } else {
1231
- // or start the instance directly
1232
- startAdapter();
1
+ /*
2
+ * ebus adapter für iobroker
3
+ *
4
+ * Created: 15.09.2016 21:31:28
5
+ * Author: Rene
6
+
7
+
8
+ */
9
+
10
+ /* jshint -W097 */// jshint strict:false
11
+ /*jslint node: true */
12
+ "use strict";
13
+
14
+
15
+
16
+
17
+ const utils = require("@iobroker/adapter-core");
18
+ const ebusdMinVersion = [23, 3];
19
+ const ebusdVersion = [0, 0];
20
+ const ebusdUpdateVersion = [0, 0];
21
+
22
+ let adapter;
23
+ function startAdapter(options) {
24
+ options = options || {};
25
+ Object.assign(options, {
26
+ name: "ebus",
27
+ //#######################################
28
+ //
29
+ ready: function () {
30
+ try {
31
+ //adapter.log.debug('start');
32
+ main();
33
+ }
34
+ catch (e) {
35
+ adapter.log.error("exception catch after ready [" + e + "]");
36
+ }
37
+ },
38
+ //#######################################
39
+ // is called when adapter shuts down
40
+ unload: function (callback) {
41
+ try {
42
+
43
+ if (intervalID != null) {
44
+ clearInterval(intervalID);
45
+ }
46
+ if (updateTimerID != null) {
47
+ clearTimeout(updateTimerID);
48
+ }
49
+ adapter && adapter.log && adapter.log.info && adapter.log.info("cleaned everything up...");
50
+ //to do stop intervall
51
+ callback();
52
+ } catch (e) {
53
+ callback();
54
+ }
55
+ },
56
+
57
+ stateChange: async (id, state) => {
58
+ await HandleStateChange(id, state);
59
+ },
60
+ //#######################################
61
+ //
62
+ message: async (obj) => {
63
+ if (obj) {
64
+ switch (obj.command) {
65
+ case "findParams":
66
+ // e.g. send email or pushover or whatever
67
+ adapter.log.debug("findParams command");
68
+ // Send response in callback if required
69
+ await FindParams(obj);
70
+ break;
71
+ default:
72
+ adapter.log.error("unknown message " + obj.command);
73
+ break;
74
+ }
75
+ }
76
+ }
77
+ //#######################################
78
+ //
79
+ });
80
+ adapter = new utils.Adapter(options);
81
+
82
+ return adapter;
83
+ }
84
+
85
+
86
+ const axios = require("axios");
87
+ const net = require("net");
88
+ const { PromiseSocket } = require("promise-socket");
89
+
90
+ let intervalID=null;
91
+ let updateTimerID=null;
92
+
93
+ async function main() {
94
+
95
+ adapter.log.debug("start with interface ebusd ");
96
+
97
+ FillPolledVars();
98
+ FillHistoryVars();
99
+
100
+ await checkVariables();
101
+
102
+ await subscribeVars();
103
+
104
+ let readInterval = 5;
105
+ if (parseInt(adapter.config.readInterval) > 0) {
106
+ readInterval = adapter.config.readInterval;
107
+ }
108
+ adapter.log.debug("read every " + readInterval + " minutes");
109
+ intervalID = setInterval(Do, readInterval * 60 * 1000);
110
+
111
+ //read at adapterstart
112
+ await Do();
113
+
114
+ }
115
+
116
+ let requestRunning = false;
117
+
118
+ async function DoRequest() {
119
+
120
+ adapter.log.debug("DoRequest ");
121
+
122
+ if (!requestRunning) {
123
+ requestRunning = true;
124
+ await ebusd_ReadValues();
125
+
126
+ await ebusd_ReceiveData();
127
+ }
128
+ else {
129
+ adapter.log.debug("DoRequest: do nothing already running ");
130
+ }
131
+ requestRunning = false;
132
+ }
133
+
134
+ async function Do() {
135
+
136
+ adapter.log.debug("starting ... " );
137
+
138
+ await ebusd_Command();
139
+
140
+ await DoRequest();
141
+
142
+ }
143
+
144
+
145
+ async function HandleStateChange(id, state) {
146
+
147
+
148
+ if (state != null && state.ack !== true) {
149
+
150
+ adapter.log.debug("handle state change " + id);
151
+ const ids = id.split(".");
152
+
153
+ if (ids[2] === "cmd") {
154
+ await ebusd_Command();
155
+ StartDataRequest();
156
+ //see issue #77: only one request possible
157
+ //await Do();
158
+ }
159
+ //unhandled state change ebus.0.find
160
+ else if (ids[2] === "find") {
161
+ await ebusd_find();
162
+ }
163
+ else {
164
+ adapter.log.warn("unhandled state change " + id);
165
+ }
166
+ }
167
+ }
168
+
169
+
170
+ function StartDataRequest() {
171
+
172
+ if (updateTimerID != null) {
173
+ //already running
174
+ clearTimeout(updateTimerID);
175
+ updateTimerID = null;
176
+ }
177
+ //start or restart
178
+ updateTimerID = setTimeout(DataRequest, 500);
179
+ adapter.log.debug("StartDataRequest");
180
+ }
181
+
182
+
183
+ async function DataRequest() {
184
+ adapter.log.debug("get data after command and timeout");
185
+ if (updateTimerID != null) {
186
+ clearTimeout(updateTimerID);
187
+ updateTimerID = null;
188
+ }
189
+ await DoRequest();
190
+ }
191
+
192
+
193
+ const oPolledVars = [];
194
+ function FillPolledVars() {
195
+
196
+ if ( adapter.config.PolledDPs !== undefined && adapter.config.PolledDPs != null && adapter.config.PolledDPs.length > 0) {
197
+ adapter.log.debug("use new object list for polled vars");
198
+
199
+ //2023-02-10 only active vars
200
+ for (let i = 0; i < adapter.config.PolledDPs.length; i++) {
201
+ if (adapter.config.PolledDPs[i].active) {
202
+ oPolledVars.push(adapter.config.PolledDPs[i]);
203
+ }
204
+ }
205
+
206
+ }
207
+ else {
208
+ //make it compatible to old versions
209
+ adapter.log.debug("check old comma separeted list for polled vars");
210
+ const oPolled = adapter.config.PolledValues.split(",");
211
+
212
+ if (oPolled.length > 0) {
213
+
214
+ for (let i = 0; i < oPolled.length; i++) {
215
+ if (oPolled[i].length > 0) {
216
+ //console.log('add ' + oPolled[i]);
217
+ const value = {
218
+ circuit: "",
219
+ name: oPolled[i],
220
+ parameter: ""
221
+ };
222
+ oPolledVars.push(value);
223
+ }
224
+ }
225
+ }
226
+ }
227
+
228
+ adapter.log.info("list of polled vars " + JSON.stringify(oPolledVars));
229
+
230
+ }
231
+
232
+ let oHistoryVars = [];
233
+ function FillHistoryVars() {
234
+
235
+ if (adapter.config.HistoryDPs !== undefined && adapter.config.HistoryDPs != null && adapter.config.HistoryDPs.length > 0) {
236
+ adapter.log.debug("use new object list for history vars");
237
+ oHistoryVars = adapter.config.HistoryDPs;
238
+ }
239
+ else {
240
+ //make it compatible to old versions
241
+ adapter.log.debug("check old comma separeted list for history vars");
242
+ const oHistory = adapter.config.HistoryValues.split(",");
243
+
244
+ if (oHistory.length > 0) {
245
+
246
+ for (let i = 0; i < oHistory.length; i++) {
247
+ if (oHistory[i].length > 0) {
248
+ console.log("add " + oHistory[i]);
249
+ const value = {
250
+ name: oHistory[i],
251
+ };
252
+ oHistoryVars.push(value);
253
+ }
254
+ }
255
+ }
256
+ }
257
+ }
258
+
259
+
260
+
261
+
262
+
263
+
264
+
265
+ //===================================================================================================
266
+ // ebusd interface
267
+
268
+ async function ebusd_Command() {
269
+ const obj = await adapter.getStateAsync("cmd");
270
+
271
+ if (obj !== undefined && obj != null) {
272
+ const cmds = obj.val;
273
+ if (cmds !== "") {
274
+ adapter.log.debug("got command(s): " + cmds);
275
+
276
+ adapter.log.debug("connect telnet to IP " + adapter.config.targetIP + " port " + parseInt(adapter.config.targetTelnetPort));
277
+
278
+ try {
279
+ const socket = new net.Socket();
280
+ const promiseSocket = new PromiseSocket(socket);
281
+
282
+ await promiseSocket.connect(parseInt(adapter.config.targetTelnetPort), adapter.config.targetIP);
283
+ adapter.log.debug("telnet connected for cmd");
284
+ promiseSocket.setTimeout(5000);
285
+
286
+ const oCmds = cmds.split(",");
287
+
288
+ if (oCmds.length > 0) {
289
+ let received = "";
290
+ for (let n = 0; n < oCmds.length; n++) {
291
+
292
+ adapter.log.debug("send " + oCmds[n]);
293
+ await promiseSocket.write(oCmds[n] + "\n");
294
+
295
+ const data = await promiseSocket.read();
296
+
297
+ if (data.includes("ERR")) {
298
+ adapter.log.warn("sent " + oCmds[n] + ", received " + data + " please check ebusd logs for details!");
299
+ }
300
+ else {
301
+ adapter.log.debug("received " + data);
302
+ }
303
+ received += data.toString();
304
+ received += ", ";
305
+ }
306
+
307
+ //see issue #78: remove CR, LF and last comma
308
+ received = received.replace(/\r?\n|\r/g,"");
309
+ received = received.slice(0, -2);
310
+
311
+ //set result to cmdResult
312
+ await adapter.setStateAsync("cmdResult", { ack: true, val: received });
313
+ }
314
+ else {
315
+ adapter.log.warn("no commands in list " + cmds + " " + JSON.stringify(oCmds));
316
+ }
317
+ await adapter.setStateAsync("cmd", { ack: true, val: "" });
318
+
319
+ promiseSocket.destroy();
320
+
321
+ } catch (e) {
322
+ adapter.log.error("exception from tcp socket" + "[" + e + "]");
323
+ }
324
+ }
325
+ }
326
+ else {
327
+ adapter.log.debug("object cmd not found " + JSON.stringify(obj));
328
+ }
329
+ }
330
+
331
+ async function ebusd_find(){
332
+ try {
333
+ const socket = new net.Socket();
334
+ const promiseSocket = new PromiseSocket(socket);
335
+
336
+ await promiseSocket.connect(parseInt(adapter.config.targetTelnetPort), adapter.config.targetIP);
337
+ adapter.log.debug("telnet connected for cmd");
338
+ promiseSocket.setTimeout(5000);
339
+
340
+ await promiseSocket.write("find -F circuit,name,comment\n");
341
+
342
+ const data = await promiseSocket.read();
343
+
344
+ if (data.includes("ERR")) {
345
+ adapter.log.warn("received error! sent find, received " + data + " please check ebusd logs for details!");
346
+ }
347
+ else {
348
+ adapter.log.debug("received " + typeof data + " " + data);
349
+ }
350
+
351
+ const str = new TextDecoder().decode(data);
352
+ const datas = str.split(/\r?\n/);
353
+
354
+ for (let i = 0; i < datas.length; i++) {
355
+
356
+ //adapter.log.debug(JSON.stringify(datas[i]));
357
+
358
+ const names = datas[i].split(",");
359
+
360
+ //circuit,name,comment
361
+ await UpdateDP(names[0], names[1], names[2]);
362
+
363
+ let cmd = "read -f -c " + names[0] + " " + names[1] ;
364
+
365
+ adapter.log.debug("send cmd " + cmd);
366
+
367
+ cmd += "\n";
368
+ await promiseSocket.write(cmd);
369
+
370
+ const result = await promiseSocket.read();
371
+
372
+ adapter.log.debug("received " + typeof result + " " + result);
373
+ }
374
+
375
+
376
+ promiseSocket.destroy();
377
+
378
+ } catch (e) {
379
+ adapter.log.error("exception from tcp socket in ebusd_find" + "[" + e + "]");
380
+ }
381
+
382
+ }
383
+
384
+
385
+
386
+ //just call http://192.168.0.123:8889/data
387
+
388
+ async function subscribeVars() {
389
+ adapter.subscribeStates("cmd");
390
+
391
+ adapter.subscribeStates("find");
392
+
393
+ await adapter.setStateAsync("cmdResult", { ack: true, val: "" });
394
+ }
395
+
396
+ async function CreateObject(key, obj) {
397
+
398
+ const obj_new = await adapter.getObjectAsync(key);
399
+ //adapter.log.warn("got object " + JSON.stringify(obj_new));
400
+
401
+ if (obj_new != null) {
402
+
403
+ if ((obj_new.common.role != obj.common.role
404
+ || obj_new.common.type != obj.common.type
405
+ || (obj_new.common.unit != obj.common.unit && obj.common.unit != null)
406
+ || obj_new.common.read != obj.common.read
407
+ || obj_new.common.write != obj.common.write
408
+ || obj_new.common.name != obj.common.name)
409
+ && obj.type === "state"
410
+ ) {
411
+ adapter.log.warn("change object " + JSON.stringify(obj) + " " + JSON.stringify(obj_new));
412
+ await adapter.extendObject(key, {
413
+ common: {
414
+ name: obj.common.name,
415
+ role: obj.common.role,
416
+ type: obj.common.type,
417
+ unit: obj.common.unit,
418
+ read: obj.common.read,
419
+ write: obj.common.write
420
+ }
421
+ });
422
+ }
423
+ }
424
+ else {
425
+ await adapter.setObjectNotExistsAsync(key, obj);
426
+ }
427
+ }
428
+
429
+
430
+ //circuit,name,comment
431
+ async function UpdateDP(circuit, name, comment) {
432
+
433
+ const key = circuit + ".messages." + name;
434
+ adapter.log.debug("update check for " + key);
435
+
436
+
437
+ // ehp.messages.Injection
438
+ //ebus.0.ehp.messages.Injection
439
+
440
+ const obj = await adapter.getObjectAsync(key);
441
+ adapter.log.debug("update check got " + JSON.stringify(obj));
442
+
443
+
444
+ //update check got null
445
+
446
+ if (obj != null) {
447
+
448
+ if (obj.common.name != comment) {
449
+ adapter.log.debug("update " + key + " " + comment);
450
+ await adapter.extendObject(key, {
451
+ common: {
452
+ name: comment,
453
+ read: true,
454
+ write: false
455
+ }
456
+ });
457
+ }
458
+ }
459
+ else {
460
+ await adapter.setObjectNotExistsAsync(key, {
461
+ type: "channel",
462
+ common: {
463
+ name: comment,
464
+ read: true,
465
+ write: false
466
+ }
467
+ });
468
+ }
469
+
470
+ }
471
+
472
+
473
+
474
+ async function checkVariables() {
475
+ adapter.log.debug("init variables ");
476
+
477
+ let key;
478
+ let obj;
479
+
480
+ key = "cmd";
481
+ obj= {
482
+ type: "state",
483
+ common: {
484
+ name: "ebusd command",
485
+ type: "string",
486
+ role: "text",
487
+ read: true,
488
+ write: true
489
+ }
490
+ };
491
+ await CreateObject(key, obj);
492
+
493
+ key = "cmdResult";
494
+ obj = {
495
+ type: "state",
496
+ common: {
497
+ name: "ebusd command result",
498
+ type: "string",
499
+ role: "text",
500
+ read: true,
501
+ write: false
502
+ }
503
+ };
504
+ await CreateObject(key, obj);
505
+
506
+ key = "find";
507
+ obj = {
508
+ type: "state",
509
+ common: {
510
+ name: "find existing data points",
511
+ type: "boolean",
512
+ role: "button",
513
+ read: false,
514
+ write: true
515
+ }
516
+ };
517
+ await CreateObject(key, obj);
518
+
519
+
520
+
521
+ adapter.log.debug("init common variables and " + oHistoryVars.length + " history DP's");
522
+
523
+ if (oHistoryVars.length > 0) {
524
+
525
+ if (oHistoryVars.length > 4) {
526
+ adapter.log.warn("too many history values " + oHistoryVars.length + " -> maximum is 4");
527
+ }
528
+
529
+ for (let n = 1; n <= oHistoryVars.length; n++) {
530
+
531
+ if (oHistoryVars[n - 1].name.length > 0) {
532
+ const name = "history value " + n + " as JSON " + oHistoryVars[n - 1].name;
533
+ key = "history.value" + n;
534
+ obj= {
535
+ type: "state",
536
+ common: {
537
+ name: name,
538
+ type: "string",
539
+ role: "value",
540
+ unit: "",
541
+ read: true,
542
+ write: false
543
+ },
544
+ native: { location: key }
545
+ };
546
+ await CreateObject(key, obj);
547
+ }
548
+ else {
549
+ adapter.log.warn("ignoring history value " + n + " (invalid name)");
550
+ }
551
+ }
552
+
553
+ key = "history.date";
554
+ obj= {
555
+ type: "state",
556
+ common: {
557
+ name: "ebus history date / time as JSON",
558
+ type: "string",
559
+ role: "value",
560
+ unit: "",
561
+ read: true,
562
+ write: false
563
+ },
564
+ native: {
565
+ location: key
566
+ }
567
+ };
568
+ await CreateObject(key, obj);
569
+ }
570
+ key = "history.error";
571
+ obj= {
572
+ type: "state",
573
+ common: {
574
+ name: "ebus error",
575
+ type: "string",
576
+ role: "value",
577
+ unit: "",
578
+ read: true,
579
+ write: false
580
+ },
581
+ native: { location: key }
582
+ };
583
+ await CreateObject(key, obj);
584
+ }
585
+
586
+
587
+ function VersionCheck() {
588
+
589
+ if (ebusdVersion[0] > 0 ) {
590
+ if (ebusdVersion[0] < ebusdMinVersion[0] || (ebusdVersion[0] == ebusdMinVersion[0] && ebusdVersion[1] < ebusdMinVersion[1])) {
591
+ adapter.log.info("please update ebusd, old version found: " + ebusdVersion[0] + "." + ebusdVersion[1] + " supported version is " + ebusdMinVersion[0] + "." + ebusdMinVersion[1]);
592
+ }
593
+ if (ebusdVersion[0] > ebusdMinVersion[0] || (ebusdVersion[0] >= ebusdMinVersion[0] && ebusdVersion[1] > ebusdMinVersion[1])) {
594
+ adapter.log.info("unsupported ebusd version found (too new): " + ebusdVersion[0] + "." + ebusdVersion[1] + " supported version is " + ebusdMinVersion[0] + "." + ebusdMinVersion[1]);
595
+ }
596
+ }
597
+
598
+ if (ebusdUpdateVersion[0] > 0 && ebusdVersion[0] > 0) {
599
+
600
+ if (ebusdUpdateVersion[0] > ebusdVersion[0] || (ebusdUpdateVersion[0] == ebusdVersion[0] && ebusdUpdateVersion[1] > ebusdVersion[1])) {
601
+ adapter.log.info("new ebusd version found: " + ebusdUpdateVersion[0] + "." + ebusdUpdateVersion[1] + " supported version is " + ebusdMinVersion[0] + "." + ebusdMinVersion[1]);
602
+
603
+ }
604
+
605
+ }
606
+ }
607
+
608
+ //get data via https in json -> this is the main data receiver; telnet just triggers ebusd to read data;
609
+ //https://github.com/john30/ebusd/wiki/3.2.-HTTP-client
610
+
611
+ async function ebusd_ReceiveData() {
612
+
613
+ const sUrl = "http://" + adapter.config.targetIP + ":" + parseInt(adapter.config.targetHTTPPort) + "/data";
614
+ adapter.log.debug("request data from " + sUrl);
615
+
616
+ try {
617
+
618
+ const buffer = await axios.get(sUrl);
619
+
620
+ adapter.log.debug("got data " + typeof buffer.data + " " + JSON.stringify(buffer.data));
621
+
622
+ const oData = buffer.data;
623
+
624
+ //adapter.log.debug("oData " + oData);
625
+
626
+ const flatten = require("flat");
627
+
628
+ const newData = flatten(oData);
629
+
630
+ const keys = Object.keys(newData);
631
+
632
+ //adapter.log.debug("history: " + options.historyValues);
633
+
634
+ const historyvalues = [];
635
+ const historydates = [];
636
+
637
+ const oToday = new Date();
638
+ const month = oToday.getMonth() + 1;
639
+
640
+ historydates.push({
641
+ "date": oToday.getDate() + "." + month + "." + oToday.getFullYear(),
642
+ "time": oToday.getHours() + ":" + oToday.getMinutes() + ":" + oToday.getSeconds()
643
+ });
644
+ //adapter.log.debug(JSON.stringify(historydates));
645
+
646
+ let name = "unknown";
647
+ let sError = "none";
648
+ for (let i = 0; i < keys.length; i++) {
649
+ let key = keys[i];
650
+ const org_key = key;
651
+
652
+ if (key.includes("[") || key.includes("]")) {
653
+ adapter.log.debug("found unsupported chars in " + key);
654
+ const start = key.indexOf("[");
655
+ const end = key.lastIndexOf("]");
656
+
657
+ if (start > 0 && end > 0) {
658
+ const toReplace = key.slice(start, end + 1);
659
+ key = key.replace(toReplace, "");
660
+ }
661
+ //adapter.log.warn("new key is " + key);
662
+ }
663
+
664
+ const subnames = key.split(".");
665
+ const temp = subnames.length;
666
+ //adapter.log.debug('Key : ' + key + ', Value : ' + newData[key]);
667
+
668
+ //
669
+ //if (key.match(adapter.FORBIDDEN_CHARS)) { continue; }
670
+
671
+
672
+ if (key.includes("global.version")) {
673
+ const value = newData[org_key];
674
+ //adapter.log.info("in version, value " + value);
675
+ const versionInfo = value.split(".");
676
+ if (versionInfo.length > 1) {
677
+ adapter.log.info("installed ebusd version is " + versionInfo[0] + "." + versionInfo[1]);
678
+
679
+ ebusdVersion[0] = versionInfo[0];
680
+ ebusdVersion[1] = versionInfo[1];
681
+
682
+ VersionCheck();
683
+ }
684
+ }
685
+
686
+ if (key.includes("global.updatecheck")) {
687
+ let value = newData[org_key];
688
+ //adapter.log.info("in version, value " + value);
689
+
690
+ //revision v21.2 available
691
+ value = value.replace("revision v", "");
692
+ value = value.replace(" available", "");
693
+
694
+ const versionInfo = value.split(".");
695
+ if (versionInfo.length > 1) {
696
+ adapter.log.info("found ebusd update version " + versionInfo[0] + "." + versionInfo[1]);
697
+
698
+ ebusdUpdateVersion[0] = versionInfo[0];
699
+ ebusdUpdateVersion[1] = versionInfo[1];
700
+
701
+ VersionCheck();
702
+ }
703
+ }
704
+
705
+
706
+
707
+ if (subnames[temp - 1].includes("name")) {
708
+ name = newData[org_key];
709
+ }
710
+ else if (subnames[temp - 1].includes("value")) {
711
+ //adapter.log.debug('Key : ' + key + ', Value : ' + newData[key] + " name " + name);
712
+
713
+ let value = newData[org_key];
714
+
715
+ if (value == null || value === undefined) {
716
+ adapter.log.debug("Key : " + key + ", Value : " + newData[org_key] + " name " + name);
717
+ }
718
+
719
+
720
+ if (name === "hcmode2") {
721
+ if (parseInt(value) === 0) {
722
+ adapter.log.info(key + "in hcmode2 with value 0: off");
723
+ value = "off";
724
+ }
725
+ else if (parseInt(value) === 5) {
726
+ adapter.log.info(key + " with value 5: EVU Sperrzeit");
727
+ value = "EVU Sperrzeit";
728
+ }
729
+ else {
730
+ adapter.log.debug("in hcmode2, value " + value);
731
+ }
732
+ }
733
+
734
+ let type = typeof value;
735
+
736
+ if (adapter.config.useBoolean4Onoff) {
737
+ if (type == "string" && (value == "on" || value == "off")) {
738
+ adapter.log.debug("Key " + key + " change to boolean " + value);
739
+ //Key mc.messages.Status.fields.1.value could be boolean off
740
+
741
+ type = "boolean";
742
+
743
+ if (value == "on") {
744
+ value = true;
745
+ }
746
+ else {
747
+ value = false;
748
+ }
749
+
750
+ }
751
+ }
752
+ //value, change type if necessary
753
+ await AddObject(key, type);
754
+ await UpdateObject(key, value);
755
+
756
+ //name parallel to value: used for lists in admin...
757
+ const keyname = key.replace("value", "name");
758
+ await AddObject(keyname, "string");
759
+
760
+ await UpdateObject(keyname, name);
761
+
762
+ //push to history
763
+ //ebus.0.bai.messages.ReturnTemp.fields.temp.value
764
+ //ebus.0.bai.messages.ReturnTemp.fields.tempmirror.value
765
+ if (!subnames[temp - 2].includes("sensor") //ignore sensor states
766
+ && !subnames[temp - 2].includes("mirror") //ignore mirror-data
767
+ ) {
768
+ for (let ii = 0; ii < oHistoryVars.length; ii++) {
769
+
770
+ if (name === oHistoryVars[ii].name) {
771
+
772
+ const sTemp = '{"' + name + '": "' + value + '"}';
773
+ //adapter.log.debug(sTemp);
774
+ historyvalues[ii] = [];
775
+ historyvalues[ii].push(JSON.parse(sTemp));
776
+ //adapter.log.debug(JSON.stringify(historyvalues));
777
+ }
778
+ }
779
+ }
780
+ }
781
+ else if (subnames[temp - 1].includes("lastup")) {
782
+
783
+ const value = newData[org_key];
784
+
785
+ if (parseInt(value) > 0) {
786
+ //adapter.log.debug('Key : ' + key + ', Value : ' + newData[key] + " name " + name);
787
+
788
+ //umrechnen...
789
+ const oDate = new Date(value * 1000);
790
+ //const nDate = oDate.getDate();
791
+ //const nMonth = oDate.getMonth() + 1;
792
+ //const nYear = oDate.getFullYear();
793
+ //const nHours = oDate.getHours();
794
+ //const nMinutes = oDate.getMinutes();
795
+ //const nSeconds = oDate.getSeconds();
796
+
797
+ const sDate = oDate.toLocaleString();
798
+ await AddObject(key, "string");
799
+ await UpdateObject(key, sDate);
800
+
801
+ const oToday = new Date();
802
+
803
+ let bSkip = false;
804
+
805
+ if (subnames[0].includes("scan") ||
806
+ subnames[0].includes("ehp") ||
807
+ (subnames.length>2 && subnames[2].includes("currenterror"))
808
+
809
+ ) {
810
+ bSkip = true;
811
+ }
812
+ if (temp > 2) {
813
+ //adapter.log.debug("_______________size " + temp);
814
+ if (subnames[2].includes("Timer")) {
815
+ bSkip = true;
816
+ }
817
+ }
818
+
819
+ if (!bSkip && Math.abs(oDate.getTime() - oToday.getTime()) > 1 * 60 * 60 * 1000) {
820
+
821
+ const sError1 = "no update since " + sDate + " " + key + " ";
822
+ if (sError.includes("none")) {
823
+ sError = "ebus: " + sError1;
824
+ }
825
+ else {
826
+ sError += sError1;
827
+ }
828
+ adapter.log.warn(sError1);
829
+ }
830
+
831
+
832
+ }
833
+ }
834
+ else if (subnames[0].includes("global")) {
835
+ //adapter.log.debug('Key : ' + key + ', Value : ' + newData[key] + " name " + name);
836
+ const value = newData[org_key];
837
+ await AddObject(key, typeof value);
838
+ await UpdateObject(key, value);
839
+ }
840
+ }
841
+ await adapter.setStateAsync("history.error", { ack: true, val: sError });
842
+
843
+ //adapter.log.debug(JSON.stringify(historyvalues));
844
+
845
+ adapter.log.info("all http done");
846
+
847
+
848
+ await UpdateHistory(historyvalues, historydates);
849
+
850
+
851
+ }
852
+ catch (e) {
853
+ adapter.log.error("exception in ebusd_ReceiveData [" + e + "]");
854
+
855
+ await adapter.setStateAsync("history.error", { ack: true, val: "exception in receive" });
856
+ }
857
+ //});
858
+ }
859
+
860
+
861
+
862
+ async function UpdateHistory(values, dates) {
863
+
864
+ if (oHistoryVars.length > 0) {
865
+ //prüfen ob alle json gleich lang sind
866
+ let NoOfDates = -1;
867
+
868
+ const obj = await adapter.getStateAsync("history.date");
869
+
870
+ if (obj !== undefined && obj != null) {
871
+ try {
872
+ let oEbusDates = [];
873
+ //adapter.log.debug("before " + obj.val);
874
+ oEbusDates = JSON.parse(obj.val);
875
+ //adapter.log.debug("after parse " + JSON.stringify(oEbusDates));
876
+
877
+
878
+
879
+ oEbusDates.push(dates);
880
+ //adapter.log.debug("after push " + JSON.stringify(oEbusDates));
881
+ //limit length of object...
882
+ if (oEbusDates.length > 200) {
883
+
884
+ for (let i = oEbusDates.length; i > 200; i--) {
885
+ //adapter.log.debug("delete");
886
+ oEbusDates.shift();
887
+ }
888
+ }
889
+ NoOfDates = oEbusDates.length;
890
+ await adapter.setStateAsync("history.date", { ack: true, val: JSON.stringify(oEbusDates) });
891
+ }
892
+ catch (e) {
893
+ adapter.log.error("exception in UpdateHistory part1 [" + e + "]");
894
+ await adapter.setStateAsync("history.date", { ack: true, val: "[]" });
895
+ NoOfDates = 0;
896
+ }
897
+ }
898
+ else {
899
+ adapter.log.warn("history.date not found, creating DP ");
900
+ await adapter.setStateAsync("history.date", { ack: true, val: "[]" });
901
+ NoOfDates = 0;
902
+ }
903
+
904
+ if (oHistoryVars.length > 0) {
905
+ for (let ctr = 1; ctr <= oHistoryVars.length; ctr++) {
906
+
907
+ if (oHistoryVars[ctr - 1].name.length > 0) {
908
+ const ctrOkay = await UpdateHistoryValues(values, ctr, NoOfDates);
909
+
910
+ if (!ctrOkay) {
911
+ await adapter.setStateAsync("history.date", { ack: true, val: "[]" });
912
+ NoOfDates = 0;
913
+ adapter.log.warn("reset history date too");
914
+ }
915
+ }
916
+ else {
917
+ adapter.log.debug("ignoring history value " + ctr);
918
+ }
919
+ }
920
+
921
+ adapter.log.info("all history done");
922
+ }
923
+ }
924
+ else {
925
+ adapter.log.debug("nothing to do for history");
926
+ }
927
+ }
928
+
929
+
930
+
931
+ async function UpdateHistoryValues(values, ctr, curDateCtr) {
932
+
933
+
934
+ let bRet = true;
935
+
936
+ const obj = await adapter.getStateAsync("history.value" + ctr);
937
+
938
+ if (obj !== undefined && obj != null) {
939
+ try {
940
+ let oEbusValues = [];
941
+ if (obj !== null) {
942
+ //adapter.log.debug("before " + obj.val);
943
+
944
+ oEbusValues = JSON.parse(obj.val);
945
+
946
+ //adapter.log.debug("after parse " + JSON.stringify(oEbusValues));
947
+
948
+ //adapter.log.debug("after parse cnt " + oEbusValues.length);
949
+ }
950
+
951
+ //adapter.log.debug("values " + ctr + ": " + JSON.stringify(values[ctr-1]));
952
+
953
+ oEbusValues.push(values[ctr - 1]);
954
+ //adapter.log.debug("after push " + JSON.stringify(oEbusValues));
955
+ //adapter.log.debug("after push cnt " + oEbusValues.length);
956
+ //limit length of object...
957
+ if (oEbusValues.length > 200) {
958
+
959
+ for (let i = oEbusValues.length; i > 200; i--) {
960
+ //adapter.log.debug("delete");
961
+ oEbusValues.shift();
962
+ }
963
+ }
964
+
965
+ const key = "history.value" + ctr;
966
+ adapter.log.debug("update history " + key);
967
+
968
+ if (curDateCtr != oEbusValues.length) {
969
+ bRet = false;
970
+ await adapter.setStateAsync("history.value" + ctr, { ack: true, val: "[]" });
971
+ adapter.log.warn("reset history " + key + " because number of values different to date values");
972
+
973
+ }
974
+ else {
975
+ await adapter.setStateAsync(key, { ack: true, val: JSON.stringify(oEbusValues) });
976
+ }
977
+
978
+
979
+ }
980
+ catch (e) {
981
+ adapter.log.error("exception in UpdateHistory part2 [" + e + "]");
982
+ await adapter.setStateAsync("history.value" + ctr, { ack: true, val: "[]" });
983
+ if (curDateCtr > 0) {
984
+ bRet = false;
985
+ }
986
+ }
987
+ }
988
+ else {
989
+ adapter.log.warn("history.value" + ctr + " not found, creating DP " + JSON.stringify(obj));
990
+ await adapter.setStateAsync("history.value" + ctr, { ack: true, val: "[]" });
991
+ if (curDateCtr > 0) {
992
+ bRet = false;
993
+ }
994
+ }
995
+
996
+ return bRet;
997
+ }
998
+
999
+
1000
+
1001
+ async function AddObject(key, type) {
1002
+ //adapter.log.debug("addObject " + key);
1003
+
1004
+ try {
1005
+ const obj = await adapter.getObjectAsync(key);
1006
+
1007
+ if (obj != null) {
1008
+ //adapter.log.debug(" got Object " + JSON.stringify(obj));
1009
+ if (obj.common.role != "value"
1010
+ || obj.common.type != type) {
1011
+ adapter.log.debug(" !!! need to extend for " + key);
1012
+ await adapter.extendObject(key, {
1013
+ common: {
1014
+ type: type,
1015
+ role: "value",
1016
+ }
1017
+ });
1018
+ }
1019
+ }
1020
+ else {
1021
+ adapter.log.warn(" !!! does not exist, creating now " + key );
1022
+
1023
+ await adapter.setObjectNotExistsAsync(key, {
1024
+ type: "state",
1025
+ common: {
1026
+ name: "data",
1027
+ type: type,
1028
+ role: "value",
1029
+ unit: "",
1030
+ read: true,
1031
+ write: false
1032
+ },
1033
+ native: {
1034
+ location: key
1035
+ }
1036
+ });
1037
+ }
1038
+
1039
+ } catch (e) {
1040
+ adapter.log.error("exception in AddObject " + "[" + e + "]");
1041
+ }
1042
+ }
1043
+
1044
+ async function UpdateObject(key, value) {
1045
+ try {
1046
+ if (value === undefined) {
1047
+ adapter.log.warn("updateObject: not updated " + key + " value: " + value + " " + typeof value);
1048
+ }
1049
+ else if (value == null ) {
1050
+ adapter.log.debug("updateObject: update to null " + key + " value: " + value);
1051
+ await adapter.setStateAsync(key, { ack: true, val: null });
1052
+ }
1053
+ else {
1054
+ adapter.log.debug("updateObject " + key + " : " + value);
1055
+ await adapter.setStateAsync(key, { ack: true, val: value });
1056
+ }
1057
+ } catch (e) {
1058
+ adapter.log.error("exception in UpdateObject " + "[" + e + "]");
1059
+ }
1060
+ }
1061
+
1062
+
1063
+ //telnet client to write to ebusd
1064
+ //https://github.com/john30/ebusd/wiki/3.1.-TCP-client-commands
1065
+ /*
1066
+ telnet 192.168.3.144 8890
1067
+
1068
+ find -f -c broadcast outsidetemp
1069
+ find -f outsidetemp
1070
+ find -f YieldTotal
1071
+
1072
+ read -f YieldTotal
1073
+ read LegioProtectionEnabled
1074
+
1075
+ read -f YieldTotal,read LegioProtectionEnabled,read -f -c broadcast outsidetemp
1076
+
1077
+ */
1078
+
1079
+
1080
+ //this function just triggers ebusd to read data; result will not be parsed; we just take the values from http result
1081
+ //here we need a loop over all configured read data in admin-page
1082
+ async function ebusd_ReadValues() {
1083
+
1084
+ if (oPolledVars.length > 0) {
1085
+
1086
+ adapter.log.debug("to poll ctr " + oPolledVars.length + " vals: " + JSON.stringify(oPolledVars));
1087
+
1088
+ try {
1089
+ const socket = new net.Socket();
1090
+ const promiseSocket = new PromiseSocket(socket);
1091
+
1092
+ await promiseSocket.connect(parseInt(adapter.config.targetTelnetPort), adapter.config.targetIP);
1093
+ adapter.log.debug("telnet connected to poll variables " + adapter.config.targetIP + " port " + adapter.config.targetTelnetPort);
1094
+ promiseSocket.setTimeout(5000);
1095
+
1096
+ let retries = 0;
1097
+ for (let nCtr = 0; nCtr < oPolledVars.length; nCtr++) {
1098
+
1099
+ let circuit = "";
1100
+ let params = "";
1101
+ if (oPolledVars[nCtr].circuit != null && oPolledVars[nCtr].circuit.length > 0) {
1102
+ circuit = "-c " + oPolledVars[nCtr].circuit + " ";
1103
+ }
1104
+ if (oPolledVars[nCtr].parameter != null && oPolledVars[nCtr].parameter.length > 0) {
1105
+ params = " " + oPolledVars[nCtr].parameter;
1106
+ }
1107
+ let cmd = "read -f " + circuit + oPolledVars[nCtr].name + params;
1108
+
1109
+ adapter.log.debug("send cmd " + cmd);
1110
+
1111
+ cmd += "\n";
1112
+ await promiseSocket.write(cmd);
1113
+
1114
+ const data = await promiseSocket.read();
1115
+
1116
+ //received ERR: arbitration lost for YieldThisYear
1117
+ if (data.includes("ERR")) {
1118
+ adapter.log.warn("sent " + cmd + ", received " + data + " for " + JSON.stringify(oPolledVars[nCtr]) + " please check ebusd logs for details!");
1119
+
1120
+ /*
1121
+ * sent read -f YieldLastYear, received ERR: arbitration lost for {"circuit":"","name":"YieldLastYear","parameter":""}
1122
+ * */
1123
+ if (data.includes("arbitration lost")) {
1124
+
1125
+ retries++;
1126
+ if (retries > adapter.config.maxretries) {
1127
+ adapter.log.error("max retries, skip cmd " + cmd);
1128
+ retries = 0;
1129
+ }
1130
+ else {
1131
+ nCtr--;
1132
+ adapter.log.debug("retry to send data ");
1133
+ }
1134
+ }
1135
+ }
1136
+ else {
1137
+ adapter.log.debug("received " + data + " for " + JSON.stringify(oPolledVars[nCtr]));
1138
+ }
1139
+ }
1140
+ promiseSocket.destroy();
1141
+ adapter.log.debug("telnet disonnected");
1142
+
1143
+ } catch (e) {
1144
+ adapter.log.error("exception from tcp socket in ebusd_ReadValues " + "[" + e + "]");
1145
+ }
1146
+
1147
+
1148
+ }
1149
+ else {
1150
+ adapter.log.debug("nothing to poll; skip telnet");
1151
+ }
1152
+
1153
+ }
1154
+
1155
+
1156
+ async function FindParams(obj) {
1157
+
1158
+ adapter.log.debug("FindParams " + JSON.stringify(obj));
1159
+
1160
+ const list = [];
1161
+
1162
+ try {
1163
+ const circuit = obj.message;
1164
+
1165
+ const socket = new net.Socket();
1166
+ const promiseSocket = new PromiseSocket(socket);
1167
+
1168
+ await promiseSocket.connect(parseInt(adapter.config.targetTelnetPort), adapter.config.targetIP);
1169
+ adapter.log.debug("telnet connected for cmd");
1170
+ promiseSocket.setTimeout(5000);
1171
+
1172
+ await promiseSocket.write("find -c " + circuit + " -F circuit,name\n");
1173
+
1174
+ const data = await promiseSocket.read();
1175
+
1176
+ if (data.includes("ERR")) {
1177
+ adapter.log.warn("received error! sent find, received " + data + " please check ebusd logs for details!");
1178
+ }
1179
+ else {
1180
+ adapter.log.debug("received " + typeof data + " " + data);
1181
+ }
1182
+ /*
1183
+ received object ehp,AccelerationTestModeehp,AccelerationTestModeehp,ActualEnvironmentPowerehp,ActualEnvironmentPowerehp,ActualEnvironmentPowerPercentageehp,ActualEnvironmentPowerPercentageehp,ApplianceCodeehp,ApplianceCodeehp,Backupehp,Backupehp,BackupHoursehp,BackupHoursHcehp,BackupHoursHwcehp,BackupHysteresisehp,BackupIntegralehp,BackupModeHcehp,BackupModeHwcehp,BackupPowerCutehp,BackupStartsehp,BackupStartsHcehp,BackupStartsHwcehp,BackupTypeehp,BivalentTempehp,Bleedingehp,Bleedingehp,CirPumpehp,CirPumpehp,Code1ehp,Code1Code2Validehp,Code2ehp,Compehp,Compehp,CompControlStateehp,CompCutPressHighCountehp,CompCutPressLowCountehp,CompCutTempCountehp,CompDemandehp,CompHoursehp,CompHoursHcehp,CompHoursHwcehp,CompHysteresisehp,CompIntegralehp,CompPressHighehp,CompPressHighehp,CompPressLowehp,CompPressLowehp,CompStartsehp,CompStartsHcehp,CompStartsHwcehp,CompStateehp,CondensorTempehp,CondensorTempehp,currenterrorehp,Dateehp,DateTimeehp,DeltaTempT6T7ehp,ElectricWiringDiagramehp,ElectricWiringDiagramehp,EnergyBalancingReleaseehp,errorhistoryehp,FlowTempehp,FlowTempehp,FlowtempCoolingMinehp,FlowTempOffsetehp,Hc1Pumpehp,Hc1Pumpehp,Hc1PumpHoursehp,Hc1PumpPortehp,Hc1PumpStartsehp,Hc2Pumpehp,Hc2PumpHoursehp,HcFlowTempehp,HcFlowTempOffsetehp,HcModeDemandHoursehp,HcModeFulfilledHoursehp,HcParallelStorageFillingEnabledehp,HcPressehp,HcReturnTempehp,HcReturnTempehp,HcReturnTempOffsetehp,HeatPumpStatusehp,HeatPumpStatusehp,HeatpumpTypeehp,HwcHcValveehp,HwcHcValveehp,HwcHcValveStartsehp,HwcLaggingTimeehp,HwcLoadingDelayehp,HwcModeDemandHoursehp,HwcModeFulfilledHoursehp,HwcPumpStartsehp,HwcSwitchehp,HwcTempehp,HwcTempehp,HwcTempOffsetehp,HydraulicSchemeehp,ICLOutehp,ICLOutehp,Injectionehp,Integralehp,Mixer1DutyCycleehp,NumberCompStartsehp,OutsideTempehp,OutsideTempOffsetehp,OverpressureThresholdehp,PhaseOrderehp,PhaseOrderehp,PhaseStatusehp,PhaseStatusehp,PowerCutehp,PowerCutPreloadingehp,PressSwitchehp,PressSwitchehp,RebootCounterehp,ReturnTempMaxehp,SetModeehp,SoftwareCodeehp,Source2PumpHoursehp,Sourceehp,Sourceehp,SourceHoursehp,SourcePortehp,SourcePressehp,SourcePumpPrerunTimeehp,SourceStartsehp,SourceSwitchehp,SourceSwitchehp,SourceTempInputehp,SourceTempInputehp,SourceTempInputOffsetehp,SourceTempOutputehp,SourceTempOutputehp,SourceTempOutputOffsetehp,SourceTempOutputT8Minehp,StateSoftwareCodeehp,StateSoftwareCodeehp,Status01ehp,Status02ehp,Status16ehp,Statusehp,StatusCirPumpehp,StorageTempBottomehp,StorageTempBottomehp,StorageTempBottomOffsetehp,StorageTempTopehp,StorageTempTopehp,StorageTempTopOffsetehp,Subcoolingehp,Superheatehp,T19MaxToCompOffehp,TempInputehp,TempInputehp,TempInputOffsetehp,TempOutputehp,TempOutputehp,TempOutputOffsetehp,Timeehp,TimeBetweenTwoCompStartsMinehp,TimeCompOffMinehp,TimeCompOnMinehp,TimeOfNextPredictedPowerCutehp,TimeOfNextPredictedPowerCutehp,Weekdayehp,YieldTotalehp,YieldTotal
1184
+ */
1185
+ const str = new TextDecoder().decode(data);
1186
+ const datas = str.split(/\r?\n/);
1187
+
1188
+ for (let i = 0; i < datas.length; i++) {
1189
+
1190
+ //adapter.log.debug(JSON.stringify(datas[i]));
1191
+
1192
+ const names = datas[i].split(",");
1193
+
1194
+ //doppelte und leere herausfiltern
1195
+ let add = true;
1196
+
1197
+ if (names[0] == "" || names[1] == "") {
1198
+ add = false;
1199
+ }
1200
+ else {
1201
+
1202
+ for (let n = 0; n < list.length; n++) {
1203
+
1204
+ if (list[n].circuit == names[0] && list[n].name == names[1]) {
1205
+ add = false;
1206
+ //already in list
1207
+ }
1208
+ }
1209
+ }
1210
+
1211
+ if (add) {
1212
+ const entry = {
1213
+ active: false,
1214
+ circuit: names[0],
1215
+ name: names[1]
1216
+ };
1217
+
1218
+ list.push(entry);
1219
+ }
1220
+ }
1221
+ } catch (e) {
1222
+ adapter.log.error("exception in FindParams " + "[" + e + "]");
1223
+ }
1224
+ adapter.sendTo(obj.from, obj.command, list, obj.callback);
1225
+ }
1226
+
1227
+ // If started as allInOne/compact mode => return function to create instance
1228
+ if (module && module.parent) {
1229
+ module.exports = startAdapter;
1230
+ } else {
1231
+ // or start the instance directly
1232
+ startAdapter();
1233
1233
  }