NEWS
Parser Adapter Timer/Solarview von website auslesen
-
Hallo,
ich habe auch mal eine Frage zum Parser Adapter.
ich würde unter anderem einen timer von einer Website (https://hub.warframestat.us/timer) abgreifen wollen. leider klappt das nicht wirklich
nach dem ich das Beispiel auf github, mit der Temperatur erfolgreich nachgebaut habe, habe ich mich mal ein bisschen eingelesen und folgenden regex erstellt und auf regex101.com (erfolgreich wie ich meine) getestet.
((\d+(\.\d+)?)\s*(h))?(\s*(\d+)\s*(m))?(\s*(\d+)\s*(s))
dieser sollte mir ja jetzt quasi alle werte von der website in diesem Format rausfiltern: XXh YYm ZZs
! https://www.pic-upload.de ~~leider scheint das nur theoretisch zu funktionieren, da der vom Adapter erstellte Datenpunkt leer bleibt.
–-------------------------------------------------------------------------------------------------------------------------------------------
genauso wie in meinem zweiten test.
Da ich https://forum.iobroker.net/viewtopic.php?f=21&t=6548&p=68067&hilit=solarview#p68067 im Forum schon gelesen hatte das es jemandem gelungen ist, mit dem Parser Adapter Daten von Solarview
! Solarview ist ein Photovoltaiklogger, der (bei mir) auf einem Raspberry läuft, den ich über http://192.168.178.101:88/ erreichen kann. in Iobroker zu bekommen, habe ich erstmal versucht das hinzubekommen.
Leider steht nicht dabei wie der Ersteller das Problem letztendlich gelöst hat
hier finde ich allerdings nichteinmal einen Ansatz, da keine einheit dahinter steht wonach ich filtern könnte.
! https://www.pic-upload.de ~~die seite sieht so aus: http://www.solarview.info/solarview_fb/
bin für jede hilfe dankbar~~~~
-
okay. habe meine Probleme jetzt gelöst. allerdings ohne das parsen von websites (auch wenn es schön wäre hierzu mal ein komplexeres beispiel als eine wetterseite zu sehen zu bekommen)
ich halte meine Lösungen hier mal für die Nachwelt fest.
1. Lösung Solarview
Hierfür habe ich mir ein kleines Script geschrieben. vorher muss allerdings noch das "node-netcat" modul installiert, und "setObjekt" aktiviert werden. Dafür einfach node-netcad im adapter eintragen und speichern:
Script:
createState("Solarview.W_actual", {unit: "W", read: true, write: false}); createState("Solarview.kWh_today", {unit: "kWh", read: true, write: false}); createState("Solarview.kWh_month", {unit: "kWh", read: true, write: false}); createState("Solarview.kWh_year", {unit: "kWh", read: true, write: false}); createState("Solarview.kWh_total", {unit: "kWh", read: true, write: false}); const ip_adress = "192.168.178.101"; const port = "15000"; const interval_time = 60000; //in ms const max_errors = 5; //danach error action /* ---Zeitraum in dem Anfragen gesendet werden--- */ const starttime = '05:00'; const endtime = '23:00'; /* ---Wird nach bei "max_errors" hintereinander folgenden errors ausgeführt---*/ function erroraction(){ console.error("ERROR. TCP-Server is not responding. Bad Wifi connection? "+ countedErrors +" errors in row"); //hier können beliebige aktionen ergänzt werden. Meldeleuchte einschalten o.ä. } /*-------------------------------------------------------------------------------------*/ /*---------------ab hier nichts mehr ändern--------------*/ var raw_data, W_actual, kWh_today, kWh_month, kWh_year, kWh_total, countedErrors = 0; setInterval (function() { //arbeitsschleife if (compareTime(starttime, endtime, "between")) { //Zeit zwischen der die Daten abgerufen werden sollen raw_data = ""; client.start(); //tcp server anfrage - springe in unterprogramm setTimeout(function () { //delay, damit die empfangenen daten in raw_data geschrieben werden können if (raw_data !== "") { countedErrors = 0; //errorcounter zurücksetzen raw_data = raw_data.replace (/[{]+/,""); // "{" entfernen raw_data = raw_data.replace (/[}]+/,""); // "}" entfernen raw_data = raw_data.split(","); // split von raw_data in array bei (,) W_actual = raw_data[10]; W_actual = del_0(W_actual); kWh_today = raw_data[6]; kWh_today = del_0(kWh_today); kWh_month = raw_data[7]; kWh_month = del_0(kWh_month); kWh_year = raw_data[8]; kWh_year = del_0(kWh_year); kWh_total = raw_data[9]; kWh_total = del_0(kWh_total); setState("Solarview.W_actual", W_actual); //status in Objekt schreiben setState("Solarview.kWh_today", kWh_today); setState("Solarview.kWh_month", kWh_month); setState("Solarview.kWh_year", kWh_year); setState("Solarview.kWh_total", kWh_total); console.debug("W_actual: " + W_actual); //Ausgabe im debug log console.debug("kWh_today: " + kWh_today); console.debug("kWh_month: " + kWh_month); console.debug("kWh_year: " + kWh_year); console.debug("kWh_total: " + kWh_total); } else{ errorcounter(); } }, 3000); // klammer timeout }//klammer if Logging time },interval_time); //klammer interval /*-------------------------------------------------------------------------------------*/ /*---------------Unterprogramme--------------*/ /* ########################## Errorcounter ########################## */ function errorcounter() { countedErrors = countedErrors + 1; if (countedErrors <= max_errors){ console.warn("TCP-Server not responding: " + countedErrors + " times"); }else { erroraction(); } } /* ########################## del_0 ########################## */ function del_0(input_del_0) //vorne stehenden 0en löschen { input_del_0 = input_del_0.replace (/^[0]+/,""); // um alle vorranstehenden 0en zu entfernen if (input_del_0 === "") //falls wert nun leer, setze wert auf 0 { input_del_0 = "0"; } else if (input_del_0.match (/^[.]+/)) //falls wert mit einem "." beginnt, setze "0" vor "." { input_del_0 = "0"+input_del_0; } return input_del_0; } /* ########################## TCP-retrieve ########################## */ var Netcat = require('node-netcat'); var client = Netcat.client(port, ip_adress); client.on('open', function () { console.debug('connect'); client.send('00*'); //cmd der nach dem connect ausgeführt wird }); client.on('data',function (data) { //empfangenden daten werden in variable "data" abgelegt raw_data = data.toString(); //daten in globale variable raw_data ablegen und in string formatieren (notwendig für replace funktion) console.debug("client.on: " + raw_data); //received data in debug log client.send(); //close connection }); client.on('error', function (err) { console.debug(err); }); client.on('close', function () { console.debug('close'); });
Bedingung hierfür ist das in Solarview@Fritzbox der TCP Server aktiviert ist. Wie das geht kann man der Solarview Anleitung nachlesen.
Danach einfach im Javascript Adapter einfügen, IP-Adresse, sowie Port anpassen und starten. danach sollte bei den Objekten der JS-Instanz ein neuer Unterordner "Solarview" auftauchen.
Anmerkung: das Script fragt nur die Gesamtanlage ab. also nicht jeden Wechselrichter für sich, falls mehrere vorhanden sind.
Lösung 2: Timer von der Website
Ich wurde darauf hingewiesen, das die Seite glücklicherweise über eine Api verfügt.
Diese habe ich auch per Script abgefragt:
createState("Warframe.Cetus_day/night_cycle", {unit: "", read: true, write: false}); const url = 'https://api.warframestat.us/pc/cetusCycle' var raw_data, time_till_night; try { require("request")(url, function (error, response, result) { raw_data = result.split(","); //raw_data splitten console.debug("incoming: " +raw_data); //raw_data gesamt anzeigen return raw_data; //raw_data aus der funktion in globale variable schieben }).on("error", function (e) {console.error(e);}); }catch (e) {console.error(e);} //######### String verarbeitung ######### timeout = setTimeout(function () { time_till_night = raw_data[5].split(':'); time_till_night[1] = time_till_night[1].replace (/[}]+/,""); time_till_night[1] = time_till_night[1].replace (/["]+/,""); time_till_night[1] = time_till_night[1].replace (/["]+/,""); console.debug("time_till_night: " +time_till_night[1]); setState("Warframe.Cetus_day/night_cycle", time_till_night[1]); }, 1500);
Edit: 27.5 19 | Eintrag angepasst, da durch die Forumumstellung wohl was durcheinander gekommen ist
-
Servus - vielen Dank für dein Script und die Infos!
Konnte es somit auch hinbekommen das in iobroker zu integrieren. Sind ja doch relativ wenig Infos zu SolarView oder auch PVOutput.org vorhanden.
Endlich kann man es auch schön mit direkten Werten im View ausgeben!
Grüße und nochmals Danke
-
kein Problem.
schön zu hören das meine mühen noch woanders Anwendung finden
mir ist allerdings aufgefallen, dass sich alle paar tage der tcp-server auf dem raspberry aufhängt? kannst du das bestätigen?
also die daten werden weiterhin geloggt und auf der vom webserver bereitgestellten website dargestellt.
nur der tcp-server gibt halt keinen datenstring mehr raus, was sich im iobroker-log mit einer error-meldung bemerkbar macht.
-
Servus,
ich werde das mal beobachten.. Ist mir so noch nicht aufgefallen….
-
meinst du so eine ?
Timer.listOnTimeout (timers.js:214:5) javascript.0 2019-01-14 15:30:25.449 error at tryOnTimeout (timers.js:250:5) javascript.0 2019-01-14 15:30:25.449 error at ontimeout (timers.js:399:34) javascript.0 2019-01-14 15:30:25.449 error at Timeout._onTimeout (/opt/iobroker/node_modules/iobroker.javascript/lib/sandbox.js:1762:34) javascript.0 2019-01-14 15:30:25.448 error at Object. <anonymous>(script.js.common.SolarView:19:24) javascript.0 2019-01-14 15:30:25.448 error Error in callback: TypeError: Cannot read property 'replace' of undefined</anonymous>
Diese bekomme ich nämlich rein….
-
meinst du so eine ?
Timer.listOnTimeout (timers.js:214:5) javascript.0 2019-01-14 15:30:25.449 error at tryOnTimeout (timers.js:250:5) javascript.0 2019-01-14 15:30:25.449 error at ontimeout (timers.js:399:34) javascript.0 2019-01-14 15:30:25.449 error at Timeout._onTimeout (/opt/iobroker/node_modules/iobroker.javascript/lib/sandbox.js:1762:34) javascript.0 2019-01-14 15:30:25.448 error at Object. <anonymous>(script.js.common.SolarView:19:24) javascript.0 2019-01-14 15:30:25.448 error Error in callback: TypeError: Cannot read property 'replace' of undefined</anonymous>
Diese bekomme ich nämlich rein…. `
Genau.. denke das lag bei mir an einer schlechten Wlan Verbindung des Pi im Keller.
Habe mittlerweile das Errorhandling etwas verbessert, sowie die Möglichkeit hinzugefügt einen Zeitraum festzulegen wann Anfragen an den Pi gesendet werden.
In der Funktion "errormsg()" können dann noch beliebige Aktionen (Telegram nachricht o.ä.) ,wenn gewollt, ergänzt werden.
Hatte zwischendurch auch mal den automatischen restart des Pi implementiert. Aber wieder rausgenommen, da mir das dann doch ein bisschen zu "overkill" war und es ja warscheinlich eh an der Verbindung liegt.
Hier Version "2.0":
! ````
createState("Solarview.W_actual", {unit: "W", read: true, write: false});
createState("Solarview.kWh_today", {unit: "kWh", read: true, write: false});
createState("Solarview.kWh_month", {unit: "kWh", read: true, write: false});
createState("Solarview.kWh_year", {unit: "kWh", read: true, write: false});
createState("Solarview.kWh_total", {unit: "kWh", read: true, write: false});
! const ip_adress = "192.168.178.101";
const port = "15000";
const interval_time = 45000; //in ms
const max_errors = 8; //danach erroraction
! /* ---Zeitraum in dem Anfragen gesendet werden--- /
const starttime = '05:00';
const endtime = '23:00';
! / ---Wird nach der bei "max_errors" festgelegten aufeinanderfolgenden errors ausgeführt---/
function erroraction(){
console.error("ERROR. TCP-Server is not responding. Bad Wifi connection? "+ countedErrors +" errors in row");
! //hier können beliebige aktionen ergänzt werden.
! }
! /-------------------------------------------------------------------------------------/
/---------------Hauptprogramm--------------*/
! var raw_data, W_actual, kWh_today, kWh_month, kWh_year, kWh_total, countedErrors = 0;
! setInterval (function() { //arbeitsschleife
! if (compareTime(starttime, endtime, "between")) { //Zeit zwischen der die Daten abgerufen werden sollenraw_data = ""; client.start(); //tcp server anfrage - springe in unterprogramm setTimeout(function () { //delay, damit die empfangenen daten in raw_data geschrieben werden können
! if (raw_data !== "") {
countedErrors = 0; //errorcounter zurücksetzenraw_data = raw_data.replace (/[{]+/,""); // "{" entfernen raw_data = raw_data.replace (/[}]+/,""); // "}" entfernen raw_data = raw_data.split(","); // split von raw_data in array bei (,) W_actual = raw_data[10]; W_actual = del_0(W_actual); kWh_today = raw_data[6]; kWh_today = del_0(kWh_today); kWh_month = raw_data[7]; kWh_month = del_0(kWh_month); kWh_year = raw_data[8]; kWh_year = del_0(kWh_year); kWh_total = raw_data[9]; kWh_total = del_0(kWh_total); setState("Solarview.W_actual", W_actual); //status in Objekt schreiben setState("Solarview.kWh_today", kWh_today); setState("Solarview.kWh_month", kWh_month); setState("Solarview.kWh_year", kWh_year); setState("Solarview.kWh_total", kWh_total); console.debug("W_actual: " + W_actual); //Ausgabe im debug log console.debug("kWh_today: " + kWh_today); console.debug("kWh_month: " + kWh_month); console.debug("kWh_year: " + kWh_year); console.debug("kWh_total: " + kWh_total);
!
} else{
errorcounter();
}
! }, 3000); // klammer timeout
}//klammer if Logging time
},interval_time); //klammer interval
! /-------------------------------------------------------------------------------------/
/---------------Unterprogramme--------------/
! /* ########################## Errorcounter ########################## /
! function errorcounter()
{
countedErrors = countedErrors + 1;
if (countedErrors <= max_errors){
console.warn("TCP-Server not responding: " + countedErrors + " times");
}else {
erroraction();
}
}
! / ########################## del_0 ########################## */
! function del_0(input_del_0) //vorne stehenden 0en löschen
{
input_del_0 = input_del_0.replace (/^[0]+/,""); // um alle vorranstehenden 0en zu entfernenif (input_del_0 === "") //falls wert nun leer, setze wert auf 0 { input_del_0 = "0"; } else if (input_del_0.match (/^[.]+/)) //falls wert mit einem "." beginnt, setze "0" vor "." { input_del_0 = "0"+input_del_0; } return input_del_0;
}
! /* ########################## TCP-retrieve ########################## /
! var Netcat = require('node-netcat');
var client = Netcat.client(port, ip_adress);
! client.on('open', function ()
{
console.debug('connect');
client.send('00'); //cmd der nach dem connect ausgeführt wird
});
! client.on('data',function (data) { //empfangenden daten werden in variable "data" abgelegt
raw_data = data.toString(); //daten in globale variable raw_data ablegen und in string formatieren (notwendig für replace funktion)
console.debug("client.on: " + raw_data); //received data in debug log
! client.send(); //close connection
});
! client.on('error', function (err) {
console.debug(err);
});
! client.on('close', function () {
console.debug('close');
});
! ````Falls dir sonst noch was auffällt, oder an Funktionen fehlt, lass es mich wissen
Edit 27.05.19 | Siehe zweiter Beitrag für das aktuelle script. bei der forum umstellung hat es wohl die darstellung zerschossen.
-
Sehr cool,
leider habe ich selber zu wenig Ahnung… um so tolller das du das mit uns teilst!
Ich danke dir!