HTTPMOD Regex für wetter.com

Begonnen von GU!DO, 30 Juli 2020, 11:58:16

Vorheriges Thema - Nächstes Thema

GU!DO

Hallo zusammen,

ich wollte mir schon lange einen "Wetter Raum" einrichten. Darin hätte ich gerne den Graphen der "16 Tage Vorschau" von wetter.com integriert.

Meine Idee ist die Daten mittels HTTPMOD abzuholen und den Graphen dann in FHEM mittels Grafana zu erstellen. Leider scheitere ich bereits am Regex und möchte euch gerne um Hilfe bitten.

Im Source schauen die Daten wie folgt aus:

<h2 class="gamma">Wetterdiagramm Vejers Strand für die nächsten 16 Tage</h2>

<div data-WetterChart id="chartdiv-16" data-min-grid-distance="15" data-device="desk" style="height: 364px; width: 100%">
<script type="application/json" data-for="source" data-id="chartdiv-16">[
{"date":"2020-07-29","precipitation":0.2,"temperatureMax":15,"temperatureMin":14,"sunhours":2},
{"date":"2020-07-30","precipitation":0,"temperatureMax":17,"temperatureMin":15,"sunhours":5},
{"date":"2020-07-31","precipitation":0,"temperatureMax":18,"temperatureMin":14,"sunhours":10},
{"date":"2020-08-01","precipitation":0.2,"temperatureMax":23,"temperatureMin":14,"sunhours":7},
{"date":"2020-08-02","precipitation":0,"temperatureMax":18,"temperatureMin":16,"sunhours":6},
{"date":"2020-08-03","precipitation":0,"temperatureMax":18,"temperatureMin":16,"sunhours":4},
{"date":"2020-08-04","precipitation":0,"temperatureMax":16,"temperatureMin":14,"sunhours":14},
{"date":"2020-08-05","precipitation":0.1,"temperatureMax":18,"temperatureMin":18,"sunhours":1},
{"date":"2020-08-06","precipitation":2.7,"temperatureMax":18,"temperatureMin":15,"sunhours":0},
{"date":"2020-08-07","precipitation":0,"temperatureMax":17,"temperatureMin":15,"sunhours":14},
{"date":"2020-08-08","precipitation":0.2,"temperatureMax":16,"temperatureMin":14,"sunhours":7},
{"date":"2020-08-09","precipitation":0.2,"temperatureMax":17,"temperatureMin":16,"sunhours":1},
{"date":"2020-08-10","precipitation":0,"temperatureMax":16,"temperatureMin":14,"sunhours":3},
{"date":"2020-08-11","precipitation":0,"temperatureMax":16,"temperatureMin":15,"sunhours":8},
{"date":"2020-08-12","precipitation":0.2,"temperatureMax":17,"temperatureMin":14,"sunhours":0},
{"date":"2020-08-13","precipitation":3,"temperatureMax":16,"temperatureMin":13,"sunhours":2} ]</script>
<img class="loading-spinner" src="https://cs3.wettercomassets.com/wcomv5/images/sonne_drehend_weiss.png" alt="loading ...">
</div>


Lt. meinem Versuch in regex101.com kann ich die Daten mittels:

<script type="application\/json" data-for="source" data-id="chartdiv-16">\[(.*?)\]

und Single Line Option auslesen.

Mein Regex sieht wie folgt aus:

<script type="application\/json" data-for="source" data-id="chartdiv-16">\[(.*?)\]/s


Das Reading wird jedoch leider nicht gefüllt...

Habt Ihr vielleicht eine Idee für mich?!?

Vielen Dank & viele Grüße

Guido

amenomade

Du kannst nicht /s einfach am Ende hinzufügen
Entweder "in line": (?s) am Anfang der Regex
Oder mit Attribut readingXXRegOpt

Anmerkung dazu: wenn Du die eckige Klammern nicht mitfängst, hast am Ende kein gültiges JSON in deinem Reading, dass Du dann mit on-board Mittel oder mit standard json Funktionen parsen könntest.
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

GU!DO

Hallo amenomade,

vielen Dank für die Info!
Ich habe mich bisher noch keine Regex selbst erstellt. Hatte aber mit /s schon ein komisches Gefühl. Habe nur leider keine Erklärung gefunden.

Das (?s) gilt wahrscheinlich im gesamten FHEM und nicht nur für HTTOMOD - oder?!?

Hättest Du auch einen Tip für mich, wie ich das JSON am besten zerlege und in die Datenbank bekomme?

Ich vermute am besten lege ich userreadings an und lasse diese ins logfile (will ich auf mysql umstellen) schreiben. Dann kann ich die Daten in Grafana aus der Log-Datenbank einlesen.

Ich hatte mir schon JSONMOD, EXPANDJSON und JSONREADINGS angesehen, ist aber die für diese Struktur vermutlich nicht wirklich geeignet. 

Das Zerlegen wäre vermutlich mit perl innerhalb von 99_myUtils am besten?!?

Vielen Dank & viele Grüße

Guido

herrmannj

JsonMod wäre ideal wenn wetter.com ein reines JSON liefern würde. Wenn du einen Weg findest das json direkt zu adressieren und zu laden ist der Rest ein Kinderspiel

amenomade

Zitat von: herrmannj am 31 Juli 2020, 11:13:43
JsonMod wäre ideal wenn wetter.com ein reines JSON liefern würde. Wenn du einen Weg findest das json direkt zu adressieren und zu laden ist der Rest ein Kinderspiel
.
Das ist aber leider nicht der Fall. Das json Teil ist nur ein Teil von einer riesen grossen HTML Seite. Schon mit extratAllJSON in HTTPMOD kriegt man die Meldung, dass es kein gültiges JSON ist
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

amenomade

ZitatDas (?s) gilt wahrscheinlich im gesamten FHEM und nicht nur für HTTOMOD - oder?!?
Das gilt überall wo Regex benutzt werden.

ZitatHättest Du auch einen Tip für mich, wie ich das JSON am besten zerlege und in die Datenbank bekomme?
Modul expandJSON wäre was.

Oder json2nameValue() https://forum.fhem.de/index.php/topic,113068.msg1074099.html#msg1074099

ZitatDas Zerlegen wäre vermutlich mit perl innerhalb von 99_myUtils am besten?!?
Geht natürlich auch
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

GU!DO

Hallo amenomade,

nochmals vielen Dank für die Infos und den Link.

Meine erste Idee war, mein Logging auf SQL umzustellen, die Werte in Readings abzulegen welche dann in der Datenbank landen und von Grafana ausgelesen werden können. Dabei bekomme ich aber ein Problem:

Ich muß die Werte jeweils in Bezug zum Datum speichern. Außerdem vermute ich, dass Grafana die Werte in einer Tabelle erwartet also:
Datum1 | Temperatur1 | Sonnenstunden1 | Niederschlag1
Datum2 | Temperatur2 | Sonnenstunden2 | Niederschlag2
usw.

DBLog schreibt aber immer nur einen Wert. Den könnte ich zwar aus Datum und Wert zusammensetzten, das wäre aber wahrscheinlich für das Auslesen der Daten mittels Grafana ein Problem.

Daher wäre es, meinem Kenntnisstand nach, am Sinnvollsten alles in eine myUtils Funktion zu packen, und eine extra Wetter-Tabelle in mysql direkt aus myUtils zu füllen.

Sehe ich das richtig oder gibt es eine einfachere / bessere Möglichkeit?

amenomade

Man kann immer mit userReadings mehrere Readings in einem (und mit belibigem Format) zusammenfassen
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

GU!DO

Aber wie ich es in FEM auch anstelle, in der Datenbank wird doch immer nur ein Reading pro Datensatz abgelegt - oder?!?

Ich muss aber die Werte, oder zumindest einen der Werte pro Datenbankeintrag mit dem zugehörigen Datum "verknüpfen" und das am besten in Form einer Tabelle, damit ich die Werte später in Grafana wieder dem Datum zuordnen kann.

amenomade

Was willst Du mit Grafana darstellen? Die Vergangenheit bis heute, oder die zukünftige 16 Tage?
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

GU!DO

Die zukünftigen 16 Tage in etwa so aufbereitet wie das Wetterdiagramm (das unterhalb der Tagesvorschauen steht):

https://www.wetter.com/wetter_aktuell/wettervorhersage/16_tagesvorhersage/daenemark/vejers-strand/DK0RI0036.html

amenomade

Dann musst Du wahrscheinlich ja etwas spezielles in myUtils basteln, da die Beispiele mit Fhem / Grafana hier immer als Zeit (X-Achse) das ReadingsTimestamp nutzen.
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

GU!DO

OK. Das hatte ich schon vermutet, da ich ja, wie gesagt, den Werten immer auch das zugehörige Datum zuordnen muß.

Vielen Dank schon mal.

Melde mich wenn ich weiter bin.

amenomade

Ich würde das json in 16 Readings parsen, wie Du es geschrieben hattest: Datum1 | Temperatur1 | Sonnenstunden1 | Niederschlag1

Und dann die mySQL Request mit SUBSTRING_INDEX() so bauen, dass Grafana seine 3 Spalten kriegt.
Pi 3B, Alexa, CUL868+Selbstbau 1/2λ-Dipol-Antenne, USB Optolink / Vitotronic, Debmatic und HM / HmIP Komponenten, Rademacher Duofern Jalousien, Fritz!Dect Thermostaten, Proteus

GU!DO

Sorry Deinen letzten Thread habe ich grad erst gesehen.
Ich hatte eine extra Tabelle angelegt und überlegt ob ich die Datenbank doch noch auf Deinen Vorschlag hin ändere. Da mir aber grad nix einfällt, was FHEM mit den vagen 16 Tages Prognosen steuern sollte, werden die Daten IMHO von FHEM auch nicht benötigt.
Daher bleibe ich erstmal bei meiner separaten Tabelle.

Ich habe es nun folgender Maßen gelöst:
(Vielleicht kann es ja nochmal jemand gebrauchen)

Ich bin absoluter Anfänger und habe mir das Meiste zusammen Gesucht. Es geht bestimmt besser oder schöner...  8)

Separate Tabelle für die Wetterprognose angelegt:

CREATE TABLE `WetterCom16` (
`id` INT NOT NULL AUTO_INCREMENT,
`datum` date NOT NULL,
    `niederschlag` DECIMAL(2,1) NOT NULL,
    `temp_max` TINYINT NOT NULL,
    `temp_min` TINYINT NOT NULL,
    `sonnenstunden` TINYINT NOT NULL,
    PRIMARY KEY (id)
);


Perl Modul zum Zugriff auf die mySQL Datenbank installiert:

perl -MCPAN -e shell
cpan> install DBD::mysql
cpan> install DBI


Folgendes in der 99_myUtils.pm geändert:


use DBI;
use Data::Dumper;
use JSON;

sub wettercom16Tage() {
my $raw  = ReadingsVal("OUT.WetterCom16","Tage16","");
my $USER = "root";
my $PASS = "mysql";
my @dsn = ("DBI:mysql:database=fhem;" .
                "host=10.20.30.19", $USER, $PASS);

my $dbh = DBI->connect(@dsn,
{ PrintError => 0,
  AutoCommit => 1,
}
) or die $DBI::errstr;

my $data =  '{"items":' . $raw . '}';

my $obj = from_json( $data );

my @items = @{ $obj->{'items'} };

    foreach my $item ( @items ) {
  my $datum         = $item->{'date'};
  my $niederschlag  = $item->{'precipitation'};
  my $temp_max      = $item->{'temperatureMax'};
  my $temp_min      = $item->{'temperatureMin'};
  my $sonnenstunden = $item->{'sunhours'};

  $datum =~ s/[^0-9.]+//gs;

$dbh->do("INSERT INTO WetterCom16 (datum,niederschlag,temp_max,temp_min,sonnenstunden) VALUES ($datum,$niederschlag,$temp_max,$temp_min,$sonnenstunden) ")
            or die $dbh->errstr();

}

$dbh->disconnect();
}


Sofern Ihr Verbesserungsvorschläge habt nur her damit...

Viele Grüße & vielen Dank an amenomade

Guido