iobroker.amtronwallbox 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,7 +28,10 @@ Attention:
28
28
 
29
29
  ## Changelog
30
30
 
31
-
31
+ ### 0.0.3 (2022-08-18)
32
+ * (René) some bug fixes
33
+ * (René) change to cron
34
+ * (René) update of dependencies
32
35
 
33
36
  ### 0.0.1 (2022-05-19)
34
37
  * (René) initial release
@@ -36,7 +39,7 @@ Attention:
36
39
  ## License
37
40
  MIT License
38
41
 
39
- Copyright (c) 2022 rg-engineering <info@rg-engineering.eu>
42
+ Copyright (c) 2022 rg-engineering info@rg-engineering.eu
40
43
 
41
44
  Permission is hereby granted, free of charge, to any person obtaining a copy
42
45
  of this software and associated documentation files (the "Software"), to deal
@@ -129,8 +129,9 @@
129
129
  <table id="table_systems" class="table-values" style="width: 100%;">
130
130
  <thead>
131
131
  <tr>
132
+ <th id="tableSystems_col5" data-name="IsActive" data-type="checkbox" style="background: #64b5f6 " class="translate">IsActive</th>
132
133
  <th id="tableSystems_col1" data-name="Name" style="width: 20%; background: #64b5f6 " class="translate">name</th>
133
- <th id="tableSystems_col2" data-name="URL" style=" background: #64b5f6 " class="translate">URL</th>
134
+ <th id="tableSystems_col2" data-name="IPAddress" style=" background: #64b5f6 " class="translate">IPAddress</th>
134
135
  <th id="tableSystems_col3" data-name="ApiKey" style=" background: #64b5f6 " class="translate">ApiKey</th>
135
136
  <th id="tableSystems_col4" data-name="Type" data-options="Compact;ChargeControl;Xtra" data-type="select" style="background: #64b5f6 " class="translate">Type</th>
136
137
  <th data-buttons="up down delete" style="width: 100px; background: #64b5f6"></th>
package/admin/words.js CHANGED
@@ -2,12 +2,12 @@
2
2
  'use strict';
3
3
 
4
4
  systemDictionary = {
5
- "ApiKey": { "en": "API key", "de": "API-Schlüssel", "ru": "ключ API", "pt": "Chave API", "nl": "API sleutel", "fr": "Clé API", "it": "Chiave API", "es": "Clave API", "pl": "Klucz API", "zh-cn": "API 密钥"},
6
- "IsDonated": { "en": "donation status", "de": "wird gespendet", "ru": "статус пожертвования", "pt": "status de doação", "nl": "donatiestatus", "fr": "état du don", "it": "stato di donazione", "es": "estado de donación", "pl": "status darowizny", "zh-cn": "捐赠状况"},
5
+ "ApiKey": { "en": "Api Key", "de": "API-Schlüssel", "ru": "API-ключ", "pt": "Chave API", "nl": "API sleutel", "fr": "Clé API", "it": "Chiave API", "es": "Clave API", "pl": "Klucz API", "zh-cn": "API 密钥"},
6
+ "IPAddress": { "en": "IP-Address", "de": "IP Adresse", "ru": "Айпи адрес", "pt": "Endereço de IP", "nl": "IP adres", "fr": "Adresse IP", "it": "Indirizzo IP", "es": "Dirección IP", "pl": "Adres IP", "zh-cn": "IP地址"},
7
+ "IsActive": { "en": "active", "de": "aktiv", "ru": "активный", "pt": "ativo", "nl": "actief", "fr": "actif", "it": "attivo", "es": "activo", "pl": "aktywny", "zh-cn": "积极的"},
7
8
  "Main settings": { "en": "Main settings", "de": "Haupteinstellungen", "ru": "Основные параметры", "pt": "Configurações principais", "nl": "Belangrijkste instellingen", "fr": "Réglages principaux", "it": "Impostazioni principali", "es": "Ajustes principales", "pl": "Ustawienia główne", "zh-cn": "主要设置"},
8
- "SystemId": { "en": "System ID", "de": "System-ID", "ru": "Идентификатор системы", "pt": "ID do sistema", "nl": "Systeem-ID", "fr": "ID système", "it": "ID di sistema", "es": "identificación del sistema", "pl": "Identyfikator systemu", "zh-cn": "系统编号"},
9
- "name": { "en": "Name", "de": "Name", "ru": "Имя", "pt": "Nome", "nl": "Naam", "fr": "Nom", "it": "Nome", "es": "Nombre", "pl": "Nazwać", "zh-cn": "姓名"},
10
- "pvoutputorg adapter settings": { "en": "Adapter settings for pvoutputorg", "de": "Adaptereinstellungen für pvoutputorg", "ru": "Настройки адаптера для pvoutputorg", "pt": "Configurações do adaptador para pvoutputorg", "nl": "Adapterinstellingen voor pvoutputorg", "fr": "Paramètres de l'adaptateur pour pvoutputorg", "it": "Impostazioni dell'adattatore per pvoutputorg", "es": "Configuración del adaptador para pvoutputorg", "pl": "Ustawienia adaptera dla pvoutputorg", "zh-cn": "pvoutputorg 的适配器设置"},
11
- "readInterval": { "en": "interval to read data [min]", "de": "Intervall zum Lesen von Daten [min]", "ru": "интервал чтения данных [мин]", "pt": "intervalo para ler os dados [min]", "nl": "interval om gegevens te lezen [min]", "fr": "intervalle de lecture des données [min]", "it": "intervallo di lettura dei dati [min]", "es": "intervalo para leer datos [min]", "pl": "interwał odczytu danych [min]", "zh-cn": "读取数据的间隔 [分钟]"},
12
- "systems": { "en": "System", "de": "System", "ru": "Система", "pt": "Sistema", "nl": "Systeem", "fr": "Système", "it": "Sistema", "es": "Sistema", "pl": "System", "zh-cn": "系统"},
9
+ "Type": { "en": "type", "de": "Typ", "ru": "тип", "pt": "modelo", "nl": "type", "fr": "taper", "it": "genere", "es": "escribe", "pl": "rodzaj", "zh-cn": "类型"},
10
+ "name": { "en": "name", "de": "Name", "ru": "имя", "pt": "nome", "nl": "naam", "fr": "Nom", "it": "nome", "es": "nombre", "pl": "Nazwa", "zh-cn": "姓名"},
11
+ "readInterval": { "en": "read intervall [min]", "de": "Leseintervall [min]", "ru": "интервал чтения [мин]", "pt": "intervalo de leitura [min]", "nl": "lees interval [min]", "fr": "intervalle de lecture [min]", "it": "intervallo di lettura [min]", "es": "intervalo de lectura [min]", "pl": "interwał odczytu [min]", "zh-cn": "读取间隔 [分钟]"},
12
+ "systems": { "en": "systems", "de": "Systeme", "ru": "системы", "pt": "sistemas", "nl": "systemen", "fr": "systèmes", "it": "sistemi", "es": "sistemas", "pl": "systemy", "zh-cn": "系统"},
13
13
  };
@@ -50,6 +50,9 @@
50
50
  <Content Include="test\package.js" />
51
51
  <Content Include="test\tsconfig.json" />
52
52
  <Content Include="test\unit.js" />
53
+ <Content Include="todo.txt">
54
+ <SubType>Code</SubType>
55
+ </Content>
53
56
  </ItemGroup>
54
57
  <ItemGroup>
55
58
  <Folder Include=".github\" />
package/io-package.json CHANGED
@@ -1,8 +1,20 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "amtronwallbox",
4
- "version": "0.0.1",
4
+ "version": "0.0.3",
5
5
  "news": {
6
+ "0.0.3": {
7
+ "en": "dependencies updated",
8
+ "de": "Abhängigkeiten aktualisiert",
9
+ "ru": "зависимости обновлены",
10
+ "pt": "dependências atualizadas",
11
+ "nl": "afhankelijkheden bijgewerkt",
12
+ "fr": "dépendances mises à jour",
13
+ "it": "dipendenze aggiornate",
14
+ "es": "dependencias actualizadas",
15
+ "pl": "zaktualizowano zależności",
16
+ "zh-cn": "已更新依赖项"
17
+ },
6
18
  "0.0.1": {
7
19
  "en": "initial release",
8
20
  "de": "Erstveröffentlichung",
package/main.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*
2
- * pvoutputorg adapter für iobroker
2
+ * AMTRON wallbox adapter für iobroker
3
3
  *
4
4
  * Created: 15.05.2022 18:39:28
5
5
  * Author: Rene
@@ -10,6 +10,9 @@
10
10
  const utils = require("@iobroker/adapter-core");
11
11
  const axios = require('axios');
12
12
 
13
+ const CronJob = require("cron").CronJob;
14
+
15
+ let cronJobs = [];
13
16
 
14
17
  /*
15
18
  * docu see
@@ -44,8 +47,10 @@ function startAdapter(options) {
44
47
  // is called when adapter shuts down
45
48
  unload: function (callback) {
46
49
  try {
50
+ CronStop();
51
+ //clearInterval(intervalID);
52
+ //intervalID = null;
47
53
  adapter && adapter.log && adapter.log.info && adapter.log.info("cleaned everything up...");
48
- //to do stop intervall
49
54
  callback();
50
55
  } catch (e) {
51
56
  callback();
@@ -53,12 +58,13 @@ function startAdapter(options) {
53
58
  },
54
59
  //#######################################
55
60
  //
56
- SIGINT: function () {
57
- clearInterval(intervalID);
58
- intervalID = null;
59
- adapter && adapter.log && adapter.log.info && adapter.log.info("cleaned everything up...");
60
- CronStop();
61
- },
61
+ //SIGINT: function () {
62
+ // CronStop();
63
+ // //clearInterval(intervalID);
64
+ // //intervalID = null;
65
+ // adapter && adapter.log && adapter.log.info && adapter.log.info("cleaned everything up...");
66
+ // CronStop();
67
+ //},
62
68
  //#######################################
63
69
  // is called if a subscribed object changes
64
70
  //objectChange: function (id, obj) {
@@ -82,7 +88,7 @@ function startAdapter(options) {
82
88
 
83
89
 
84
90
 
85
- let intervalID;
91
+ //let intervalID;
86
92
  async function main() {
87
93
 
88
94
  adapter.log.debug("start ");
@@ -101,7 +107,8 @@ async function main() {
101
107
  adapter.log.warn("read interval not defined");
102
108
  }
103
109
  adapter.log.debug("read every " + readInterval + " minutes");
104
- intervalID = setInterval(Do, readInterval * 60 * 1000);
110
+ //intervalID = setInterval(Do, readInterval * 60 * 1000);
111
+ CronCreate(readInterval, Do)
105
112
 
106
113
  }
107
114
 
@@ -200,13 +207,8 @@ async function read_rest(system) {
200
207
 
201
208
  */
202
209
 
210
+ let sURL = "http://" + system.IPAddress + "/rest/full_state";
203
211
 
204
-
205
-
206
-
207
-
208
-
209
- let sURL = "http://" + system.URL + "/rest/full_state";
210
212
  let header = {
211
213
  headers: {
212
214
  Accept: 'application/json '
@@ -231,33 +233,33 @@ async function read_rest(system) {
231
233
  await adapter.setStateAsync(system.Name + ".Connection.State", { ack: true, val: data[0].split(":")[1] });
232
234
  await adapter.setStateAsync(system.Name + ".Authorisation.State", { ack: true, val: data[1].split(":")[1] });
233
235
  await adapter.setStateAsync(system.Name + ".Authorisation.UID", { ack: true, val: data[2].split(":")[1] });
234
- await adapter.setStateAsync(system.Name + ".TimeSinceChargingStart", { ack: true, val: data[3].split(":")[1] });
235
- await adapter.setStateAsync(system.Name + ".Meter", { ack: true, val: data[4].split(":")[1] });
236
- await adapter.setStateAsync(system.Name + ".Power", { ack: true, val: data[5].split(":")[1] });
237
- await adapter.setStateAsync(system.Name + ".Transaction", { ack: true, val: data[6].split(":")[1] });
236
+ await adapter.setStateAsync(system.Name + ".TimeSinceChargingStart", { ack: true, val: Number(data[3].split(":")[1]) });
237
+ await adapter.setStateAsync(system.Name + ".Meter", { ack: true, val: Number(data[4].split(":")[1]) });
238
+ await adapter.setStateAsync(system.Name + ".Power", { ack: true, val: Number(data[5].split(":")[1]) });
239
+ await adapter.setStateAsync(system.Name + ".Transaction", { ack: true, val: Number(data[6].split(":")[1]) });
238
240
  await adapter.setStateAsync(system.Name + ".CP_ID", { ack: true, val: data[7].split(":")[1] });
239
241
  await adapter.setStateAsync(system.Name + ".OCPP.State", { ack: true, val: data[8].split(":")[1] });
240
242
  await adapter.setStateAsync(system.Name + ".Type2.State", { ack: true, val: data[9].split(":")[1] });
241
243
  await adapter.setStateAsync(system.Name + ".Type2.Proximity", { ack: true, val: data[10].split(":")[1] });
242
- await adapter.setStateAsync(system.Name + ".SigCurrent", { ack: true, val: data[11].split(":")[1] });
244
+ await adapter.setStateAsync(system.Name + ".SigCurrent", { ack: true, val: Number(data[11].split(":")[1]) });
243
245
  await adapter.setStateAsync(system.Name + ".Schuko.State", { ack: true, val: data[12].split(":")[1] });
244
246
  await adapter.setStateAsync(system.Name + ".Backend.ConnectionState", { ack: true, val: data[13].split(":")[1] });
245
- await adapter.setStateAsync(system.Name + ".FreeCharging", { ack: true, val: data[14].split(":")[1] });
247
+ await adapter.setStateAsync(system.Name + ".FreeCharging", { ack: true, val: Boolean( data[14].split(":")[1]) });
246
248
  await adapter.setStateAsync(system.Name + ".SlaveState", { ack: true, val: data[15].split(":")[1] });
247
249
  await adapter.setStateAsync(system.Name + ".OCPP.MeterConfig", { ack: true, val: data[16].split(":")[1] });
248
250
  await adapter.setStateAsync(system.Name + ".OCPP.MeterSerial", { ack: true, val: data[17].split(":")[1] });
249
- await adapter.setStateAsync(system.Name + ".Current", { ack: true, val: data[18].split(":")[1] });
250
- await adapter.setStateAsync(system.Name + ".EnergyManagerCurrent", { ack: true, val: data[19].split(":")[1] });
251
+ await adapter.setStateAsync(system.Name + ".Current", { ack: true, val: Number(data[18].split(":")[1]) });
252
+ await adapter.setStateAsync(system.Name + ".EnergyManagerCurrent", { ack: true, val: Number(data[19].split(":")[1]) });
251
253
  await adapter.setStateAsync(system.Name + ".AmbientTemperature", { ack: true, val: data[20].split(":")[1] });
252
254
  await adapter.setStateAsync(system.Name + ".FirmwareVersion", { ack: true, val: data[21].split(":")[1] });
253
255
  await adapter.setStateAsync(system.Name + ".SerialNumber", { ack: true, val: data[22].split(":")[1] });
254
- await adapter.setStateAsync(system.Name + ".ContactCyclesSchuko", { ack: true, val: data[23].split(":")[1] });
255
- await adapter.setStateAsync(system.Name + ".ContactcyclesType2", { ack: true, val: data[24].split(":")[1] });
256
- await adapter.setStateAsync(system.Name + ".MaxCurrent", { ack: true, val: data[25].split(":")[1] });
256
+ await adapter.setStateAsync(system.Name + ".ContactCyclesSchuko", { ack: true, val: Number(data[23].split(":")[1]) });
257
+ await adapter.setStateAsync(system.Name + ".ContactcyclesType2", { ack: true, val: Number(data[24].split(":")[1]) });
258
+ await adapter.setStateAsync(system.Name + ".MaxCurrent", { ack: true, val: Number(data[25].split(":")[1]) });
257
259
  await adapter.setStateAsync(system.Name + ".RCMB.State", { ack: true, val: data[26].split(":")[1] });
258
260
  await adapter.setStateAsync(system.Name + ".RCMB.MaxValues", { ack: true, val: data[27].split(":")[1] });
259
261
  await adapter.setStateAsync(system.Name + ".RCMB.CurrentValues", { ack: true, val: data[28].split(":")[1] });
260
- await adapter.setStateAsync(system.Name + ".CableAttached", { ack: true, val: data[29].split(":")[1] });
262
+ await adapter.setStateAsync(system.Name + ".CableAttached", { ack: true, val: Boolean(data[29].split(":")[1]) });
261
263
  await adapter.setStateAsync(system.Name + ".Schuko.Config", { ack: true, val: data[30].split(":")[1] });
262
264
  await adapter.setStateAsync(system.Name + ".RCD.State", { ack: true, val: data[31].split(":")[1] });
263
265
  await adapter.setStateAsync(system.Name + ".MCB.Type2State", { ack: true, val: data[32].split(":")[1] });
@@ -267,7 +269,22 @@ async function read_rest(system) {
267
269
  await adapter.setStateAsync(system.Name + ".CP_Model", { ack: true, val: data[36].split(":")[1] });
268
270
  await adapter.setStateAsync(system.Name + ".DisplayText", { ack: true, val: data[37].split(":")[1] });
269
271
 
270
-
272
+ /*
273
+ amtronwallbox.0 2022-05-20 12:20:53.613 info State value to set for "amtronwallbox.0.Wallbox.CableAttached" has to be type "boolean" but received type "string"
274
+ amtronwallbox.0 2022-05-20 12:20:53.594 info State value to set for "amtronwallbox.0.Wallbox.MaxCurrent" has to be type "number" but received type "string"
275
+ amtronwallbox.0 2022-05-20 12:20:53.545 info State value to set for "amtronwallbox.0.Wallbox.ContactcyclesType2" has to be type "number" but received type "string"
276
+ amtronwallbox.0 2022-05-20 12:20:53.486 info State value to set for "amtronwallbox.0.Wallbox.ContactCyclesSchuko" has to be type "number" but received type "string"
277
+ amtronwallbox.0 2022-05-20 12:20:53.449 info State value to set for "amtronwallbox.0.Wallbox.EnergyManagerCurrent" has to be type "number" but received type "string"
278
+ amtronwallbox.0 2022-05-20 12:20:53.406 info State value to set for "amtronwallbox.0.Wallbox.Current" has to be type "number" but received type "string"
279
+ amtronwallbox.0 2022-05-20 12:20:53.392 info State value to set for "amtronwallbox.0.Wallbox.FreeCharging" has to be type "boolean" but received type "string"
280
+ amtronwallbox.0 2022-05-20 12:20:53.342 info State value to set for "amtronwallbox.0.Wallbox.SigCurrent" has to be type "number" but received type "string"
281
+ amtronwallbox.0 2022-05-20 12:20:53.324 info State value to set for "amtronwallbox.0.Wallbox.Transaction" has to be type "number" but received type "string"
282
+ amtronwallbox.0 2022-05-20 12:20:53.319 info State value to set for "amtronwallbox.0.Wallbox.Power" has to be type "number" but received type "string"
283
+ amtronwallbox.0 2022-05-20 12:20:53.313 info State value to set for "amtronwallbox.0.Wallbox.Meter" has to be type "number" but received type "string"
284
+ amtronwallbox.0 2022-05-20 12:20:53.268 info State value to set for "amtronwallbox.0.Wallbox.TimeSinceChargingStart" has to be type "number" but received type "string"
285
+
286
+ */
287
+
271
288
 
272
289
  }
273
290
  else {
@@ -909,6 +926,102 @@ async function CreateObject(key, obj) {
909
926
  }
910
927
  }
911
928
 
929
+ //===============================================================================
930
+ //cron functions
931
+ function CronStop() {
932
+ if (cronJobs.length > 0) {
933
+ adapter.log.debug("delete " + cronJobs.length + " cron jobs");
934
+ //cancel all cron jobs...
935
+ const start = cronJobs.length - 1;
936
+ for (let n = start; n >= 0; n--) {
937
+ cronJobs[n].stop();
938
+ }
939
+ cronJobs = [];
940
+ }
941
+ }
942
+
943
+ function deleteCronJob(id) {
944
+
945
+ cronJobs[id].stop();
946
+
947
+ if (id === cronJobs.length - 1) {
948
+ cronJobs.pop(); //remove last
949
+ }
950
+ else {
951
+ delete cronJobs[id];
952
+ }
953
+ CronStatus();
954
+
955
+
956
+ }
957
+
958
+ function CronCreate(Minute, callback) {
959
+
960
+ try {
961
+
962
+ const timezone = adapter.config.timezone || "Europe/Berlin";
963
+
964
+ let cronString = "";
965
+ //https://crontab-generator.org/
966
+ if (Minute == -99) {
967
+ //every day late evening
968
+ cronString = "5 23 * * *";
969
+ //just for logging
970
+ Minute = "late evening";
971
+ }
972
+ else {
973
+
974
+ cronString = "*/" + Minute + " * * * * ";
975
+ }
976
+
977
+ const nextCron = cronJobs.length;
978
+
979
+ adapter.log.debug("create cron job #" + nextCron + " every " + Minute + " string: " + cronString + " " + timezone);
980
+
981
+ //details see https://www.npmjs.com/package/cron
982
+ cronJobs[nextCron] = new CronJob(cronString,
983
+ () => callback(),
984
+ () => adapter.log.debug("cron job stopped"), // This function is executed when the job stops
985
+ true,
986
+ timezone
987
+ );
988
+
989
+ }
990
+ catch (e) {
991
+ adapter.log.error("exception in CronCreate [" + e + "]");
992
+ }
993
+ }
994
+
995
+ function CronStatus() {
996
+ let n = 0;
997
+ let length = 0;
998
+ try {
999
+ if (typeof cronJobs !== undefined && cronJobs != null) {
1000
+
1001
+ length = cronJobs.length;
1002
+ //adapter.log.debug("cron jobs");
1003
+ for (n = 0; n < length; n++) {
1004
+ if (typeof cronJobs[n] !== undefined && cronJobs[n] != null) {
1005
+ adapter.log.debug("cron status = " + cronJobs[n].running + " next event: " + timeConverter("DE", cronJobs[n].nextDates()));
1006
+ }
1007
+ }
1008
+
1009
+ if (length > 500) {
1010
+ adapter.log.warn("more then 500 cron jobs existing for this adapter, this might be a configuration error! (" + length + ")");
1011
+ }
1012
+ else {
1013
+ adapter.log.info(length + " cron job(s) created");
1014
+ }
1015
+ }
1016
+ }
1017
+ catch (e) {
1018
+ adapter.log.error("exception in getCronStat [" + e + "] : " + n + " of " + length);
1019
+ }
1020
+ }
1021
+
1022
+
1023
+
1024
+
912
1025
  // If started as allInOne/compact mode => return function to create instance
913
1026
  if (module && module.parent) {
914
1027
  module.exports = startAdapter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.amtronwallbox",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "ioBroker Adapter for AMTRON wallboxes",
5
5
  "author": {
6
6
  "name": "René G.",
@@ -22,28 +22,28 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@iobroker/adapter-core": "2.6.0",
25
- "@sentry/node": "6.19.3",
26
- "axios": "0.26.1"
25
+ "axios": "0.27.2",
26
+ "cron": "2.1.0"
27
27
  },
28
28
  "devDependencies": {
29
- "@iobroker/testing": "2.6.0",
30
- "@types/chai": "4.3.1",
29
+ "@iobroker/testing": "3.0.2",
30
+ "@types/chai": "4.3.3",
31
31
  "@types/chai-as-promised": "7.1.5",
32
32
  "@types/gulp": "4.0.9",
33
33
  "@types/mocha": "9.1.1",
34
- "@types/node": "17.0.25",
34
+ "@types/node": "18.7.3",
35
35
  "@types/proxyquire": "1.3.28",
36
36
  "@types/request-promise-native": "1.0.18",
37
- "@types/sinon": "10.0.11",
37
+ "@types/sinon": "10.0.13",
38
38
  "@types/sinon-chai": "3.2.8",
39
- "axios": "0.26.1",
39
+ "axios": "0.27.2",
40
40
  "chai": "4.3.6",
41
41
  "chai-as-promised": "7.1.1",
42
- "eslint": "8.14.0",
42
+ "eslint": "8.22.0",
43
43
  "gulp": "4.0.2",
44
- "mocha": "9.2.2",
44
+ "mocha": "10.0.0",
45
45
  "proxyquire": "2.1.3",
46
- "sinon": "13.0.2",
46
+ "sinon": "14.0.0",
47
47
  "sinon-chai": "3.7.0"
48
48
  },
49
49
  "main": "main.js",
package/todo.txt ADDED
@@ -0,0 +1,11 @@
1
+
2
+
3
+ IsActive pr�fen
4
+ URL pr�fen, wenn leer fehler meldung
5
+
6
+
7
+ andere API verwenden
8
+
9
+ Schreiben von Ladestrom
10
+
11
+ remove key in log