NEWS
State auslesen in Adapterentwicklung
-
Hallo Leute,
so langsam verzweifelt ich ... ich bin zu doof um einen State aus einem Objekt in meinem Adapter auszulesen.
Was ich benötige:
Beim Ändern eines States wird eine Funktion ausgelöst, der ich einen State eines anderen Objektes mitgeben möchte (Parameter).Dazu stellen sich mit folgende Fragen:
- welches ist der korrekte Aufruf von "getState" für einen State innerhalb meines Adapters und muss ich den namespace mitgeben?
- ich habe gelernt, dass der getState async ist, wie muss ich dann aufrufen?
Im Grunde brauche ich den korrekten Befehl, um "holde mir den Wert des states xyz (und schreibe in variable)"
Anders formuliert:
Wenn sich ein state X ändert (onStateChange), soll dieser und andere (nicht geänderte) Werte gelesen werden und als Parameter an eine Funktion übergeben werden.Vielleicht kann mir jemand mit einem Beispiel aushelfen?
Wahrscheinlich ist das Thema wird sehr einfach und ich stehe einfach auf dem Schlauch....
Danke im Voraus.
Gruss
-
@reutli
Hi reutli,das ist in dem Adapter-Template schon mit drin.
Unter dem Adapter-Constructor sollte die Zeile 12 gesetzt sein.
constructor(options) { // @ts-ignore super({ ...options, name: "openwrt", }); this.on("ready", this.onReady.bind(this)); this.on("stateChange", this.onStateChange.bind(this)); // <- Diese Wichtig this.on("message", this.onMessage.bind(this)); this.on("unload", this.onUnload.bind(this)); }
Und dann springt die Funktion onStateChange an sobald sich ein state in dem Objekt(unter)baum deines Adapter geändert hat:
onStateChange(id, state) { if (state) { // The state was changed this.log.info(`state ${id} changed: ${state.val} (ack = ${state.ack})`); //Hier dein Code: const state1 = state.val; //Wert von State der in deinem Adapter geändert wurde const state2 = getState("admin.0.info.lastUpdateCheck").val; // Wert von State xy, hier als beispiel lastupdatecheck vom admin adapter this.deineFunktion(state1,state2); } else { // The state was deleted this.log.info(`state ${id} deleted`); } } deineFunktion(sState1,sState2) { this.log.info("State1: " + sState1); this.log.info("State2: " + sState2); }
Code ist ungetestet, evtl. gibts Tippfehler
-
@Schnup89 :
hmmm, ok, dann will ich das mal testen und melde mich wieder!
Das heisst also, dass ich bei getState den ganzen Pfad angeben muss, auch wenn ich im Adapter bin?
Ich frage deshalb, weil ich mir den dann zusammen bauen muss...Danke für die schnelle Antwort!!!
-
@reutli
OK dann hast du zwei Möglichkeiten:getState(this.namespace + "deinstate"...
this.namespace ist Adapter Name + Instanz mit Punkt.
- Möglichkeit:
Zwei globale Variablen anlegen und diese bei Wertänderung schreiben.
- Möglichkeit:
-
@Schnup89 sagte in State auslesen in Adapterentwicklung:
Möglichkeit:
Zwei globale Variablen anlegen und diese bei Wertänderung schreiben.Hi,
der letzte Punkt interessiert mich speziell! Als JavaScript Anfänger hänge ich genau an solchen Punkten, vor allem weil ich mich im Adapter-Template im Class-Kontext bewege...
Wie kann ich also aus der 'onStateChange' heraus eine globale Variable schreiben, die ich 'main.js'-weit dann benutzen kann?
Die ganzen Fragen hängen natürlich damit zusammen, dass nicht ausreichend Erfahrung in der Programmierung vorliegt, um allfällige Problemstellungen mit Lösungen zu belegen, sorry dafür. Aber ich lerne jeden Tag massiv dazu.
Gruss
Reutli -
So ich habe mal getestet, es scheint aber etwas mit dem 'getState' nicht zu funktionieren?! Scheint als stehe die Funktion gar nicht zur Verfügung?
Hier mein Code (mit '.this' und ohne versucht):
onStateChange(id, state) { if (state) { let mid = id.split('.')[2]; let trigger = id.split('.').pop(); this.log.info(`state ${id} changed: ${state.val} (ack = ${state.ack})`); if (trigger == 'command') { // wenn Befehl an Maower verändert wurde const command = state.val; const time = this.getState("husqvarna_mowers.0.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.duration").val; this.log.info('Variablen für Funktionsaufruf : command: ' + command + ' time: ' + time + ' mid: ' + mid); //this.await.sendCommand(command, time, mid); } } else { // The state was deleted this.log.info(`state ${id} deleted`); } }
Dann kommt der Fehler:
husqvarna_mowers.0 2020-04-20 07:23:04.055 error at processImmediate (internal/timers.js:456:21) husqvarna_mowers.0 2020-04-20 07:23:04.055 error at Immediate.<anonymous> (/usr/local/iobroker/node_modules/iobroker.js-controller/lib/adapter.js:4855:34) husqvarna_mowers.0 2020-04-20 07:23:04.055 error at HusqvarnaMowers.emit (events.js:311:20) husqvarna_mowers.0 2020-04-20 07:23:04.055 error at HusqvarnaMowers.onStateChange (/usr/local/iobroker/node_modules/iobroker.husqvarna_mowers/main.js:521:107) husqvarna_mowers.0 2020-04-20 07:23:04.055 error (68987) TypeError: Cannot read property 'val' of undefined husqvarna_mowers.0 2020-04-20 07:23:04.055 error (68987) uncaught exception: Cannot read property 'val' of undefined
Soweit war ich mit dem 'getState' eigentlich schon einmal.
Er zeigt mir den getState in WebStorm auch "komisch" an: -
@reutli
Du musst auf die " und ' achten, das hast du normalerweise bei dem Adapter-Wizard eingestellt. Bitte nutze ' für den String dann sollte es funktionieren:const time = this.getState("husqvarna_mowers.0.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.duration").val; -> const time = this.getState('husqvarna_mowers.0.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.duration').val;
Beispiel:
[..] //Nach dieser Zeile const utils = require('@iobroker/adapter-core'); //Diese einfügen: let tTime = ''; let sCommand = '': [..] //Dann sobald einer der Werte sich ändert die Funktion erweitern onStateChange(id, state) { [..] this.log.info('onStateChange aufgerufen'); //this.namespace = 'husqvarna_mowers.0.' tTime = this.getState(this.namespace + '.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.duration'); sCommand = this.getState(this.namespace + '.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.command'); this.sendCommand(); [..] } [..] sendCommand() { this.log.info('sendCommand aufgerufen'); this.log.info('sendCommand sTime: ' + sTime); this.log.info('sendCommand sCommand: ' + sCommand); }
-
Danke für Deine Antwort, aber das ist es leider auch nicht...
Code:
onStateChange(id, state) { if (state) { let mid = id.split('.')[2]; let trigger = id.split('.').pop(); this.log.info(`state ${id} changed: ${state.val} (ack = ${state.ack})`); if (trigger == 'command') { // wenn Befehl an Mower verändert wurde const command = state.val; const time = this.getState('husqvarna_mowers.0.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.duration').val; this.log.info('Variablen für Funktionsaufruf : command: ' + command + ' time: ' + time + ' mid: ' + mid); //this.await.sendCommand(command, time, mid); } } else { // The state was deleted this.log.info(`state ${id} deleted`); } }
Fehler:
husqvarna_mowers.0 2020-04-20 08:52:54.205 error at processImmediate (internal/timers.js:456:21) husqvarna_mowers.0 2020-04-20 08:52:54.205 error at Immediate.<anonymous> (/usr/local/iobroker/node_modules/iobroker.js-controller/lib/adapter.js:4855:34) husqvarna_mowers.0 2020-04-20 08:52:54.205 error at HusqvarnaMowers.emit (events.js:311:20) husqvarna_mowers.0 2020-04-20 08:52:54.205 error at HusqvarnaMowers.onStateChange (/usr/local/iobroker/node_modules/iobroker.husqvarna_mowers/main.js:521:107) husqvarna_mowers.0 2020-04-20 08:52:54.205 error (71636) TypeError: Cannot read property 'val' of undefined husqvarna_mowers.0 2020-04-20 08:52:54.205 error (71636) uncaught exception: Cannot read property 'val' of undefined
und der State ist m.E. auch da und korrekter String:
{ "type": "state", "common": { "name": "Duration of Command", "def": "24", "type": "number", "role": "indicator", "read": true, "write": true }, "native": {}, "from": "system.adapter.husqvarna_mowers.0", "user": "system.user.admin", "ts": 1587365605661, "_id": "husqvarna_mowers.0.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.duration", "acl": { "object": 1638, "state": 1638 } }
-
@reutli sagte in State auslesen in Adapterentwicklung:
husqvarna_mowers.0 2020-04-20 08:52:54.205 error (71636) TypeError: Cannot read property 'val' of undefined
husqvarna_mowers.0 2020-04-20 08:52:54.205 error (71636) TypeError: Cannot read property 'val' of undefined
.val entfernen
const time = this.getState('husqvarna_mowers.0.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.duration').val; // zu ->>>> const time = this.getState('husqvarna_mowers.0.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.duration');
-
Versuch eines der folgenden. Das was du oben versuchst funktioniert nicht, das ist vom JS Adapter.
Await/Async
const state = await this.getStateAsync('Dein Dp');
oder
Callback
this.getState('Dein Dp', (error, state) => { });
Bin mir beim unteren gerade nicht sicher, welche Werte alle übergeben werden
-
Das habe ich auch bereits versucht.... dann bekomme ich zwar keinen Fehler, aber auch keinen Wert (time ist dann undefined):
(71874) Variablen für Funktionsaufruf : command: Pause time: undefined mid: 6dcad25a-39f7-4baf-9f44-877302c35c1f
-
@J-A-R-V-I-S sagte in State auslesen in Adapterentwicklung:
Versuch eines der folgenden. Das was du oben versuchst funktioniert nicht, das ist vom JS Adapter.
Await/Async
const state = await this.getStateAsync('Dein Dp');Dann müsste ich eine komplette ASYNC Funktion aufbauen, weil ich ja in der 'OnStateChange' keinen await aufrufen kann?!
-
@reutli du kannst die einfach zu einer Async machen, indem du async davor schreibst.
async onStateChange(id, state)
-
Hi,
nope leider nicht.
Erhalte mit '.val' einen undefined bei 'time' (und ohne '.val' natürlich ein Object):(72098) Variablen für Funktionsaufruf : command: Pause time: undefined mid: 6dcad25a-39f7-4baf-9f44-877302c35c1f
hier der code:
async onStateChange(id, state) { if (state) { let mid = id.split('.')[2]; let trigger = id.split('.').pop(); this.log.info(`state ${id} changed: ${state.val} (ack = ${state.ack})`); if (trigger == 'command') { // wenn Befehl an Mower verändert wurde const command = state.val; const time = await this.getStateAsync('husqvarna_mowers.0.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.duration').val; this.log.info('Variablen für Funktionsaufruf : command: ' + command + ' time: ' + time + ' mid: ' + mid); //this.await.sendCommand(command, time, mid); } } else { // The state was deleted this.log.info(`state ${id} deleted`); } }
-
@reutli lass dir mal den ganzen State ausgeben, ohne .val.
this.log.info(JSON.stringify(time));
Und mach mal einen try/catch Block drum. Damit fängst du die möglichen Fehler ab.
-
@J-A-R-V-I-S sagte in State auslesen in Adapterentwicklung:
this.log.info(JSON.stringify(time));
jetzt bekomme ich Werte zurück:
(72271) {"val":"24","ack":true,"ts":1587366996004,"q":0,"from":"system.adapter.husqvarna_mowers.0","user":"system.user.admin","lc":1587295118488}
Warum bekommen ich diesen nicht in die const?
-
@reutli dann schreib es in eine neue Zeile;
const state = await this.getStateAsync('husqvarna_mowers.0.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.duration'); const time = state.val;
-
ok, danke.
Jetzt bekomme ich einen Wert:(72584) Variablen für Funktionsaufruf : command: Pause time: 24 mid: 6dcad25a-39f7-4baf-9f44-877302c35c1f
mit dem Code:
async onStateChange(id, state) { if (state) { let mid = id.split('.')[2]; let trigger = id.split('.').pop(); this.log.info(`state ${id} changed: ${state.val} (ack = ${state.ack})`); if (trigger == 'command') { // wenn Befehl an Mower verändert wurde const command = state.val; const state_check = await this.getStateAsync('husqvarna_mowers.0.6dcad25a-39f7-4baf-9f44-877302c35c1f.Control.duration'); this.log.info(JSON.stringify(state_check)); const time = state_check.val; this.log.info('Variablen für Funktionsaufruf : command: ' + command + ' time: ' + time + ' mid: ' + mid); //this.await.sendCommand(command, time, mid); } } else { // The state was deleted this.log.info(`state ${id} deleted`); } }
Aber: Warum muss ich aus dem ganzen 'onStateChange' eine Async machen? Das habe ich nicht verstanden (und auch noch nirgendwo so gesehen....?
Ich frage noch anders: Wie muss ich sonst (außerhalb des 'on StateChange') dann einen State abfragen?
Sorry wenn ich so nachfrage, versuche eben zu lernen...
Danke!
PS: kannst Du mir für mein Beispiel ein sauberes "Try/Catch" zeigen, damit ich das korrekt in andere Bereich übernehmen kann? Habe hier schon einiges an Doku gelesen, aber noch nicht so ganz kapiert...
-
@reutli der Try/Catch sieht wie folgt aus:
try { /* Hier all der Code bei dem Fehler abgefangen werden sollen. Sollte ein Fehler geworfen werden, wird der Code, der im Try/Catch steht nicht weiter ausgeführt, Code nach dem Try/Catch wird aber weiter ausgeführt. */ } catch(error) { this.log.error(error); }
-
@reutli sagte in State auslesen in Adapterentwicklung:
Ich frage noch anders: Wie muss ich sonst (außerhalb des 'on StateChange') dann einen State abfragen?
Entweder du machst es dort auch mit Async Methoden oder du verwendest die Möglichkeit mit Callbacks.