NEWS
"On" Subscripton: Funktionsaufruf mit Parameter
-
Hallo Leute,
ich habe folgendes Problem. Ich möchte auf die Änderung eines Datenpunktes reagieren und nutze die "on"-Subscription im Javascript Adapter. Ich möchte je nachdem welcher Datenpunkt geändert wurde, der aufzurufenden Funktion einen Parameter übergeben.
Wenn ich das so mache stürzt der Javascript Adapter aber ab und folgende Fehlermeldungen erscheinen im Log:
host.iobroker 2024-05-16 06:39:20.796 error Caught by controller[16]: 14: 0x16820ec [io.javascript.0] host.iobroker 2024-05-16 06:39:20.796 error Caught by controller[15]: 13: 0xdd1ef0 v8::internal::Builtin_JsonParse(int, unsigned long*, v8::internal::Isolate*) [io.javascript.0] host.iobroker 2024-05-16 06:39:20.796 error Caught by controller[14]: 12: 0x11b9170 v8::internal::String::SlowFlatten(v8::internal::Isolate*, v8::internal::Handle<v8::internal::ConsString>, v8::internal::AllocationType) [io.javascript.0] host.iobroker 2024-05-16 06:39:20.796 error Caught by controller[13]: 11: 0xeef85c v8::internal::FactoryBase<v8::internal::Factory>::NewRawOneByteString(int, v8::internal::AllocationType) [io.javascript.0] host.iobroker 2024-05-16 06:39:20.796 error Caught by controller[12]: 10: 0xeed4cc v8::internal::FactoryBase<v8::internal::Factory>::AllocateRawWithImmortalMap(int, v8::internal::AllocationType, v8::internal::Map, v8::internal::AllocationAlignment) [io.javascript.0] host.iobroker 2024-05-16 06:39:20.796 error Caught by controller[11]: 9: 0xef6254 v8::internal::Factory::AllocateRaw(int, v8::internal::AllocationType, v8::internal::AllocationAlignment) [io.javascript.0] host.iobroker 2024-05-16 06:39:20.796 error Caught by controller[10]: 8: 0xf140a0 v8::internal::HeapAllocator::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [io.javascript.0] host.iobroker 2024-05-16 06:39:20.796 error Caught by controller[9]: 7: 0xf130c8 v8::internal::HeapAllocator::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [io.javascript.0] host.iobroker 2024-05-16 06:39:20.795 error Caught by controller[8]: 6: 0xf36f44 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [io.javascript.0] host.iobroker 2024-05-16 06:39:20.795 error Caught by controller[7]: 5: 0xf24fac [io.javascript.0] host.iobroker 2024-05-16 06:39:20.795 error Caught by controller[6]: 4: 0xd468c0 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [io.javascript.0] host.iobroker 2024-05-16 06:39:20.795 error Caught by controller[5]: 3: 0xd466f0 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [io.javascript.0] host.iobroker 2024-05-16 06:39:20.795 error Caught by controller[4]: 2: 0xa9df08 [io.javascript.0] host.iobroker 2024-05-16 06:39:20.795 error Caught by controller[3]: 1: 0xb84c6c node::Abort() [io.javascript.0] host.iobroker 2024-05-16 06:39:20.795 error Caught by controller[2]: FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory host.iobroker 2024-05-16 06:39:20.795 error Caught by controller[1]: <--- JS stacktrace ---> host.iobroker 2024-05-16 06:39:20.795 error Caught by controller[1]: [736721:0x1294d850] 70354 ms: Mark-sweep 1995.6 (2096.3) -> 1994.1 (2096.5) MB, 202.1 / 0.0 ms (average mu = 0.079, current mu = 0.023) allocation failure; scavenge might not succeed host.iobroker 2024-05-16 06:39:20.795 error Caught by controller[1]: [736721:0x1294d850] 70148 ms: Mark-sweep 1995.1 (2096.5) -> 1993.5 (2095.7) MB, 216.3 / 0.0 ms (average mu = 0.133, current mu = 0.027) allocation failure; scavenge might not succeed host.iobroker 2024-05-16 06:39:20.795 error Caught by controller[1]: <--- Last few GCs --->
Das ist mein "on"-Definition:
const ventile=[ { "name": "Rasensprenger", "nr": 1, "on": "0_userdata.0.Garten.Rasensprenger_Ein", "left": "0_userdata.0.Garten.Rasensprenger_Restzeit" }, { "name": "Hecke+Steinbeet", "nr": 2, "on": "0_userdata.0.Garten.Hecke+Steinbeet_Ein", "left": "0_userdata.0.Garten.Hecke+Steinbeet_Restzeit" }, { "name": "Vorgarten+Kübel", "nr": 3, "on": "0_userdata.0.Garten.Vorgaten+Kübel_Ein", "left": "0_userdata.0.Garten.Vorgarten+Kübel_Restzeit" }, { "name": "Hochbeete", "nr": 4, "on": "0_userdata.0.Garten.Hochbeete_Ein", "left": "0_userdata.0.Garten.Hochbeete_Restzeit" }, { "name": "Oli-Seite", "nr": 5, "on": "0_userdata.0.Garten.Oli-Seite_Ein", "left": "0_userdata.0.Garten.Oli-Seite_Restzeit" }, { "name": "Dachterrasse", "nr": 6, "on": "0_userdata.0.Garten.Dachterrasse_Ein", "left": "0_userdata.0.Garten.Dachterrasse_Restzeit" } ] on ({id: ventile[0].on, change: 'ne'}, function(){Einschalten(ventile[0])}) on ({id: ventile[1].on, change: 'ne'}, function(){Einschalten(ventile[1])}) on ({id: ventile[2].on, change: 'ne'}, function(){Einschalten(ventile[2])}) on ({id: ventile[3].on, change: 'ne'}, function(){Einschalten(ventile[3])}) on ({id: ventile[4].on, change: 'ne'}, function(){Einschalten(ventile[4])}) on ({id: ventile[5].on, change: 'ne'}, function(){Einschalten(ventile[5])}) function Einschalten(ventil){ console.log("Schalte Ventil "+ventil.name+" ein.") var ein = getState(ventil.on).val; var min = toInt(getState("0_userdata.0.Garten.Einschalten_min").val); var s = min * 60 if (ein==true){ var duration_value=getState(root+ventil.nr+".duration_value").val var i=1 while (duration_value==null || duration_value=="null"){ my_log(dp_log, "Starte Bewässerung "+ventil.name+"."+i+"-ter Versuch...") setState(root+ventil.nr+".duration_value", `${s}`) sleep(10000) i+=1 } } if (ein==false){ setState(root+ventil.nr+".duration_value", "STOP_UNTIL_NEXT_TASK") my_log(dp_log, "Stoppe Bewässerung "+ventil.name) } }
Wo ist mein Fehler?
-
@vippis du verwendest var um deine variablen zu deklarieren, damit sind sie global. Das kann zu unerwarteten Fehlern führen weil damit schon vorhandene variablen überschrieben werden.
Verwende statt dessen let und const. -
Zunächst mal vorweg: JS ist nicht unbedingt meine Kernkompetenz
Aber mir fallen da ein paar Dinge auf:
@vippis sagte in "On" Subscripton: Funktionsaufruf mit Parameter:
der aufzurufenden Funktion einen Parameter übergeben
Das machst Du aber nicht.
Du rufts - wie eigentlich üblich - eine anonyme Funktion auf. Ohne Parameter - das könnte man nämlich auch so formatieren:on ({id: ventile[5].on, change: 'ne'}, function() { Einschalten(ventile[5]); });
Deine Formatierung ist lediglich "mimified".
Wie gesagt: Nicht meine Kernkompetenz, aber ich würde da ein Semikolon ans Ende der Zeile setzen.Auch den Vergleich würde ich anders formulieren:
if (ein) { ... } else { ... }
Und hinter
console.log("Schalte Ventil "+ventil.name+" ein.")
und
var s = min * 60
und einigen anderen Zeilen fehlt ein Semikolon,
-
@vippis sagte in "On" Subscripton: Funktionsaufruf mit Parameter:
Wo ist mein Fehler?
Sleep liefert ein Promise zurück: https://github.com/ioBroker/ioBroker.javascript/blob/master/docs/en/javascript.md#wait
Damit wartet Dein Script an der Stelle nie, sondern die Schleife läuft mit voller Rechenleistung. Ansonsten könntest Du das Script deutlich vereinfachen (es fehlt zwar die Hälfte vom Script, aber hier ein Beispiel):
const ventile = { '0_userdata.0.Garten.Rasensprenger_Ein': { name: 'Rasensprenger', nr: 1, left: '0_userdata.0.Garten.Rasensprenger_Restzeit', }, '0_userdata.0.Garten.Hecke+Steinbeet_Ein': { name: 'Hecke+Steinbeet', nr: 2, left: '0_userdata.0.Garten.Hecke+Steinbeet_Restzeit', }, '0_userdata.0.Garten.Vorgaten+Kübel_Ein': { name: 'Vorgarten+Kübel', nr: 3, left: '0_userdata.0.Garten.Vorgarten+Kübel_Restzeit', }, '0_userdata.0.Garten.Hochbeete_Ein': { name: 'Hochbeete', nr: 4, left: '0_userdata.0.Garten.Hochbeete_Restzeit', }, '0_userdata.0.Garten.Oli-Seite_Ein': { name: 'Oli-Seite', nr: 5, left: '0_userdata.0.Garten.Oli-Seite_Restzeit', }, '0_userdata.0.Garten.Dachterrasse_Ein': { name: 'Dachterrasse', nr: 6, left: '0_userdata.0.Garten.Dachterrasse_Restzeit', }, }; on ({ id: Object.keys(ventile), change: 'ne' }, async (obj) => { const ventil = ventile[obj.id]; const isOn = obj.state.val; const durationStateId = `${root}${ventil.nr}.duration_value`; console.log(`Schalte Ventil ${ventil.name} ein.`); const min = parseInt(getState('0_userdata.0.Garten.Einschalten_min').val); const s = min * 60; if (isOn) { const duration_value = getState(durationStateId).val; let i = 1; while (duration_value == null || duration_value == "null") { log(`Starte Bewässerung ${ventil.name}. ${i}-ter Versuch...`); setState(durationStateId, String(s), true); await sleep(10000); i += 1; } } else { setState(durationStateId, 'STOP_UNTIL_NEXT_TASK', true); log(`Stoppe Bewässerung ${ventil.name}`); } });
(so richtig verstehe ich die Logik dahinter noch nicht. Nur im Forum programmiert - daher kein Anspruch auf Vollständigkeit)
-
Vielen Dank für Euren Input, werde es umsetzen.
Zurzeit macht der smartgarden Adapter aber Ärger und daher kann ich die Verbesserungen nicht überprüfen. Ich bekomme jetzt error 429 Rückmeldungen von der API, wahrscheinlich weil die while Schleife zu viele API Calls generiert hat...
-
-
@vippis sagte in "On" Subscripton: Funktionsaufruf mit Parameter:
Ich bekomme jetzt error 429
Heißt:
429 Too Many Requests
-
Ja genau, das habe ich auch schon herausgefunden. Weißt du wie man da rauskommt oder hilft nur warten?
Hab schon eine Anfrage an feedback@developer.husqvarnagroup.cloud gesendet
-
@vippis sagte in "On" Subscripton: Funktionsaufruf mit Parameter:
Weißt du wie man da rauskommt oder hilft nur warten?
Das weiß nur der Serverbetreiber. Normalerweise sind die Rate Limits für so eine API öffentlich dokumentiert. Gibt es da nix?
-
bei der Automower Connect API gilt:
Limits
The following limitations currently apply to the Automower Connect API:
Max 1 request per second and appKey.
Max 10 000 request per month and appKey.
Any additional requests above these limits will be throttled.https://developer.husqvarnagroup.cloud/apis/automower-connect-api?tab=readme
ist ggf. bei Gardena gleich/ähnlich.
-
On average one call every fifteen minutes.
700 requests per week.
10 requests per 10-second interval.
https://developer.husqvarnagroup.cloud/apis/gardena-smart-system-api?tab=readme
-
Wie könnte man effektiv die API calls monitoren, damit ich die Limits nicht reiße?
Die Calls sollen dann entsprechend delayed werden und eine Ausgabe erfolgen?
Ist das eher was für mein Anwenderskript oder für @jpgorganizer Adapter?
-
@vippis sagte in "On" Subscripton: Funktionsaufruf mit Parameter:
Wie könnte man effektiv die API calls monitoren, damit ich die Limits nicht reiße?
Die meisten APIs liefern in jedem Response auch die restlichen rateLimits mit. Dann weiß man schon, ob man noch Luft hat und wieviele Anfragen verbleiben.
Ist aber sehr individuell. Ich würde einfach mal einen Response genauer anschauen, ob etwas in die Richtung enthalten ist.
-
Ich hab mir unter https://developer.husqvarnagroup.cloud einen frischen API Key erzeugt und bekomme jetzt keinen error 429 mehr