NEWS
[gelöst]JSON parsen, bräuchte Hilfe
-
Hey Leute,
ich möchte gerne meinen 3d Drucker etwas in ioBroker einbinden. Dazu verwende ich die Repetier Server Software um den Drucker zu steuern, dazu gibt es auch eine komplette API.
Zum Beispiel liefert mir http://IP:PORT/printer/api/AM8?a=stateList&data&apikey=XXXXX dieses JSON
{"AM8":{"activeExtruder":0,"debugLevel":6,"extruder":[{"error":0,"output":0,"tempRead":15.000000000000000,"tempSet":0.0000000000000000}],"fan2On":false,"fan2Voltage":0,"fanOn":false,"fanVoltage":255,"firmware":"Marlin","firmwareURL":"","flowMultiply":100,"hasXHome":true,"hasYHome":true,"hasZHome":true,"heatedBed":{"error":0,"output":0,"tempRead":15.100000381469727,"tempSet":0.0000000000000000},"layer":64,"lights":0,"numExtruder":1,"powerOn":false,"rec":false,"sdcardMounted":true,"speedMultiply":100,"volumetric":false,"x":0.0000000000000000,"y":180.00000000000000,"z":22.579999923706055}}
In eine ioBroker Variable bekomme ich das JSON rein, nur schaffe ich es nicht einzelne Objekte heraus zu filtern. Wahrscheinlich ist es ganz einfach, ich weiß nur leider nicht wie.
Mein Ansatz war folgender:
var url = 'http://IP:PORT/printer/api/AM8?a=stateList&data&apikey=XXXXXX'; request(url, function (err, state, body){ if (body) { log('Request - alles ok'); log(body); setState("javascript.1.3dDrucker", body); } else { log('Request meldet Fehler: ' + err, 'error'); } }); var idJSON = "javascript.1.3dDrucker"; // Datenpunkt-ID mit JSON-String var test; function JSONtoTemp(json) { var obj = JSON.parse(json); test = obj.tempRead; log('Temperatur: ' + test + ' °C'); } JSONtoTemp(getState(idJSON).val); // Script start on(idJSON, function(dp) { // triggern bei Wertänderung JSONtoTemp(dp.state.val); });
tempRead ist hier ja auch 2 mal vorhanden, wie kann ich differenzieren, welches ich auslesen möchte.
Gruß Frank
-
Anstelle von
log(body);
schreib zuerst mal
log(JSON.stringify(Body));
Dann solltest du die Datenstruktur schon mal besser erkennen können.
Ja, im JSON gibt es 2mal tempRead - einmal für "Extruder" und einmal für "heatedBed" an die Werte rankommen müsstest Du ungefähr so:
var tempExtruder = Body.AM8.extruder.tempRead var tempHeatedBed = Body.AM8.heatedBed.tempRead
Ist aber jetzt nur ungetestet im Halbschlaf ins Blaue geschossen
-
Also damit````
log(JSON.stringify(Body));Wo müssen die Variablen (var tempExtruder = Body.AM8.extruder.tempRead) denn hin?
-
Ja, hast Recht - das war ja schon ein JSON. Hatte ich jetzt was verwechselt von wegen dem Log.
Die Variablen müssen irgendwo in deine Funktion… Ups -ich sehe gerade dass dir offensichtlich der ganze Ablauf noch nicht so sonnenklar ist
Ich versuche mal das Script komplett zu machen - wieder ungetestet im Halbschlaf...
createState('3dDrucker.Extruder.Temp', "", { desc: 'Extrudertemperatur, type: 'number', role: 'value' }); function HoleTemp3D(){ var url = 'http://IP:PORT/printer/api/AM8?a=stateList&data&apikey=XXXXXX'; request(url, function (err, state, body){ if (body) { log('Request - alles ok'); log(body); var tempExtruder = Body.AM8.extruder.tempRead; log(tempExtruder) setState("javascript.1.3dDrucker", tempExtruder); } else { log('Request meldet Fehler: ' + err, 'error'); } }); } schedule("*/30 * * * * *function(){ //Beispiel um Werte aller 30s auszulesen HoleTemp3D(); });
-
Da merkt man den Halbschlaf
Hab es mal noch etwas abgeändert, damit ich keine Fehler mehr angezeigt bekomme:
createState('javascript.1.3dDrucker', ""); function HoleTemp3D(){ var url = 'http://IP:PORT/printer/api/AM8?a=stateList&data&apikey=XXXXXX'; request(url, function (err, state, body){ if (body) { log('Request - alles ok'); log(body); var tempExtruder = body.AM8.extruder.tempRead; log(tempExtruder); setState("javascript.1.3dDrucker", tempExtruder); } else { log('Request meldet Fehler: ' + err, 'error'); } }); } schedule("*/30 * * * * *" , function(){ HoleTemp3D(); });
Aber bekomme Fehler im log und die Instanz stürzt ab, da stimmt irgendwas noch nicht.
host.cubietruck 2018-01-10 09:25:05.441 error instance system.adapter.javascript.1 terminated with code 6 (uncaught exception) Caught 2018-01-10 09:25:05.439 error by controller[0]: at emitNone (events.js:91:20) Caught 2018-01-10 09:25:05.438 error by controller[0]: at IncomingMessage.g (events.js:292:16) Caught 2018-01-10 09:25:05.436 error by controller[0]: at IncomingMessage. (/opt/iobroker/node_modules/iobroker.javascript/node_modules/request/request.js:1085:12) Caught 2018-01-10 09:25:05.435 error by controller[0]: at Request.emit (events.js:188:7) Caught 2018-01-10 09:25:05.434 error by controller[0]: at emitOne (events.js:96:13) Caught 2018-01-10 09:25:05.432 error by controller[0]: at Request. (/opt/iobroker/node_modules/iobroker.javascript/node_modules/request/request.js:1163:10) Caught 2018-01-10 09:25:05.431 error by controller[0]: at Request.emit (events.js:191:7) Caught 2018-01-10 09:25:05.430 error by controller[0]: at emitTwo (events.js:106:13) Caught 2018-01-10 09:25:05.428 error by controller[0]: at Request.self.callback (/opt/iobroker/node_modules/iobroker.javascript/node_modules/request/request.js:186:22) Caught 2018-01-10 09:25:05.427 error by controller[0]: at Request._callback (script.js.test:84:44) Caught 2018-01-10 09:25:05.423 error by controller[0]: TypeError: Cannot read property 'extruder' of undefined javascript.1 2018-01-10 09:25:01.602 error at emitNone (events.js:91:20) javascript.1 2018-01-10 09:25:01.602 error at IncomingMessage.g (events.js:292:16) javascript.1 2018-01-10 09:25:01.602 error at IncomingMessage. (/opt/iobroker/node_modules/iobroker.javascript/node_modules/request/request.js:1085:12) javascript.1 2018-01-10 09:25:01.602 error at Request.emit (events.js:188:7) javascript.1 2018-01-10 09:25:01.602 error at emitOne (events.js:96:13) javascript.1 2018-01-10 09:25:01.602 error at Request. (/opt/iobroker/node_modules/iobroker.javascript/node_modules/request/request.js:1163:10) javascript.1 2018-01-10 09:25:01.602 error at Request.emit (events.js:191:7) javascript.1 2018-01-10 09:25:01.602 error at emitTwo (events.js:106:13) javascript.1 2018-01-10 09:25:01.602 error at Request.self.callback (/opt/iobroker/node_modules/iobroker.javascript/node_modules/request/request.js:186:22) javascript.1 2018-01-10 09:25:01.602 error at Request._callback (script.js.test:84:44) javascript.1 2018-01-10 09:25:01.602 error TypeError: Cannot read property 'extruder' of undefined javascript.1 2018-01-10 09:25:01.600 error uncaught exception: Cannot read property 'extruder' of undefined
-
javascript.1 2018-01-10 09:25:01.602 error TypeError: Cannot read property 'extruder' of undefined javascript.1 2018-01-10 09:25:01.600 error uncaught exception: Cannot read property 'extruder' of undefined ```` `
body.AM8 ist nicht definiert und hat daher keine extruder-Eigenschaft. Sicher dass body bereits ein JSON-Objekt ist und kein string?
Sonst müsste vor
var tempExtruder = body.AM8.extruder.tempRead;
noch ein
body = JSON.parse(body);
-
Ok, hab ich gemacht. Jetzt bekomme ich kein Fehler mehr im log, aber tempExtruder ist immer noch "undefined"
Und body schein leer zu sein: "javascript.1 script.js.test: [object Object]"
Übrigens ist das hier die API Doku: https://www.repetier-server.com/manuals … index.html
-
Und body schein leer zu sein: "javascript.1 script.js.test: [object Object]" `
Loggst du vor oder nach dem JSON.parse? Vorher solltest du den Inhalt direkt ausgeben können. Danach ist es ein Objekt ("[object Object]"), das du erst wieder in einen String umwandeln musst zum Loggen:log(JSON.stringify(body));
oder (wenn du etwas schönere Formatierung willst):
log(JSON.stringify(body, null, 4));
-
tempExtruder ist immer noch "undefined" `
Wenn man sich das Objekt mal anschaut, sieht man warum:{ "AM8":{ "activeExtruder":0, "debugLevel":6, "extruder":[ { "error":0, "output":0, "tempRead":15.000000000000000, "tempSet":0.0000000000000000 } ], "fan2On":false, "fan2Voltage":0, "fanOn":false, "fanVoltage":255, "firmware":"Marlin", "firmwareURL":"", "flowMultiply":100, "hasXHome":true, "hasYHome":true, "hasZHome":true, "heatedBed":{ "error":0, "output":0, "tempRead":15.100000381469727, "tempSet":0.0000000000000000 }, "layer":64, "lights":0, "numExtruder":1, "powerOn":false, "rec":false, "sdcardMounted":true, "speedMultiply":100, "volumetric":false, "x":0.0000000000000000, "y":180.00000000000000, "z":22.579999923706055 } }
extruder ist ein Array (könnten mehrere sein), d.h. du musst den richtigen auswählen - in deinem Fall den 0ten.
var tempExtruder = body.AM8.extruder[0].tempRead;
-
Super, danke Dir funktioniert.
Kannst du mir vielleicht noch sagen, wie ich den Wert auf 2 Nachkommastellen kürze?
-
wie ich den Wert auf 2 Nachkommastellen kürze? `
var tempExtruder = Math.round(100 * body.AM8.extruder[0].tempRead) / 100;
-
Na seht ihr was aus einem Vorschlag im Halbschlaf alles werden kann
Da sieht man dass Javascript nur meine 5. Fremdsprache ist - ohne zu testen gerade da viele solche Fehlerchen rein…
Aber Deine Objektdefinition ist - auch wenn es jetzt funktioniert - sagen wir mal suboptimal. Ich würde den Wert der Temperatur jedenfalls nicht einfach in einen DP mit der Bezeichnung "3dDrucker" schreiben sondern die Struktur des DP an die der Daten die vom Drucker kommen "anlehnen". Das mag aber noch als persönliche Geschmackssache durchgehen - ist nur ein Hinweis.
Was du aber auf keinen Fall machen solltest ist die Typdeklaration des Datenpunkts zu "vermatschen". So wie du den jetzt anlegst (createState('javascript.1.3dDrucker', ""); ist der Typ zwar überhaupt nicht deklariert, wird also vermutlich "variabel" und dann gibst du als Defaultwert auch noch einen String an (""), also zumindest der Datentyp 'number' sollte für einen Zahlenwert schon definiert sein und als Default wenigstens 0.
Das mag zwar so wie du das jetzt hast funktionieren und für den Moment auch keine Probleme machen, aber erstens ist es programmiertechnischer 'Murks' und zweitens wird es dir schmerzlich auf die Füße fallen wenn du die Daten mal historisieren und vielleicht in einem Diagramm auswerten willst.
Aber ist nur ein Hinweis - ich mache auch manchmal gerne selbst die Fehler um dann aus Schmerzen zu lernen
-
> Aber Deine Objektdefinition ist - auch wenn es jetzt funktioniert - sagen wir mal suboptimal
Das war alles nur mal zum testen ob es überhaupt funktioniert. Natürlich habe ich jetzt eine Struktur drin z.B. für Extruder, Bett usw. und auch für 2 Drucker. Wie gesagt, der Datenpunkt war nur zum testen, deshalb lief es auch in der zweiten Javascript Instanz.
-
Na dann ist ja alles Bestens
-
Ich hoffe das Skript gibt es dann hier [emoji847]
Oder gar einen Repetier Adapter [emoji6]
-
Script kann ich mal posten wenn ich es fertig hab, da sollen noch paar mehr Sachen rein.
Adapter wäre cool, bin ich aber leider der falsche Ansprechpartner für, da hab ich zu wenig Kenntnisse mit Javascript.
-
Json parse geht mit dem Systeminfo Adapter andere dafür sind nicht geplant.
Also entweder den oder JavaScript
–-----------------------
Send from mobile device
Das schöne ios hat Auto Korrektur zum k****
Wer Schreibfehler findet darf sie behalten oder auf eBay verkaufen, mindest Umsatz 10% für die community
-
Json parse geht mit dem Systeminfo Adapter andere dafür sind nicht geplant.
Also entweder den oder JavaScript `
Nee, er meinte ja einen extra Adapter für die Repetier Server Software für den 3d Drucker
-
Hey,
leider muss ich nochmal nachfragen, da ich jetzt noch ein zweites JSON hab, bei dem ich Zeit und Status in Prozent lesen könnte. Funktioniert nur nicht so wie ich dachte.
[{"active":true,"analysed":1,"done":0.26915197043345518,"job":"Halter_rechts.","jobid":4,"linesSend":67,"name":"AM8","ofLayer":146,"online":1,"pauseState":0,"paused":false,"printTime":4266.7126891287853,"printedTimeComp":412.82550469314651,"slug":"AM8","start":1515704149,"totalLines":24893}]
Das ist das JSON und ich brauche "done", "printTime" und "printedTimeComp". Ok, dachte ich mir dann müsste "done" ja "body.done" sein, stimmt aber anscheinend nicht, der Datenpunkt wird nicht gefüllt. Leider verstehe ich nicht warum. Helft mir bitte mal auf die Sprünge.
-