HA: Werte einer beliebigen Webseite als Entität verwenden

 

Nachdem mein Internetzugang von Zeit zu Zeit die Verbindung verloren hat, wollte ich die Signalqualität des Kabelrouters in Home-Assistant überwachen. Mangels API, verwende ich die Verwaltungsoberfläche des Routers für die Abfrage und parse die Ausgabe in Bash. Mit diesem Ansatz können die Werte aus fast jeder Web-GUI in Home Assistant verfügbar gemacht werden.

Beispiel 1: GUI -> curl ohne einer Anmeldung und mehrere Werte mit einem Aufruf

Zunächst werfe ich einen Blick auf die Web-GUI, von der ich die Daten abfragen will. Im einfachsten Fall stellt dieser die Daten ohne Benutzeranmeldung zur Verfügung: Was bei der Vorgängerversion meines aktuellen Routers der Fall war:

 

Das Ziel ist die Werte der GUI in Home-Assistant zur Verfügung zu stellen:

 

Schritt für Schritt

Als ersten Schritt habe ich versucht, ob die Daten generell heruntergeladen werden können. Dazu habe ich den gesamten HTML-Quellcode der Seite mittels des Bash-Befehls curl und der Router-URL heruntergeladen. Für das Testen und Zusammenstellen des Befehls kann ein Linux-PC, der Home-Assistant-Docker-Container oder Linux unter Windows: WSL verwendet werden.

Erster Versuch: Herunterladen der Startseite mittels Bash-Befehl: curl

curl http://192.168.0.1

Als Antwort bekomme ich den Quellcode der Startseite, dieser beinhaltet neben dem Layout der GUI auch die Statuswerte:

[+]
<td id="ch_snr" scope="col" class="stdbold" nowrap><script language="javascript" type="text/javascript">dw(vdsch_snr);</script></TD>
</tr>
<tr>
<td id="channel_1" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 1<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="channel_1 ch_pwr" scope="row" class="stdbold" nowrap> 13.6 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
<td headers="channel_1 ch_snr" class="stdbold" nowrap>40.2 <script language="javascript" type="text/javascript">dw(vdb);</script></td>
</tr>
<tr>
<td id="channel_2" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 2<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="channel_2 ch_pwr" scope="row" class="stdbold" nowrap> 13.1 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
<td headers="channel_2 ch_snr" class="stdbold" nowrap>39.9 <script language="javascript" type="text/javascript">dw(vdb);</script></td>
</tr>
<tr>
<td id="channel_3" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 3<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="channel_3 ch_pwr" scope="row" class="stdbold" nowrap> 12.8 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
<td headers="channel_3 ch_snr" class="stdbold" nowrap>39.9 <script language="javascript" type="text/javascript">dw(vdb);</script></td>
</tr>
<tr>
<td id="channel_4" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 4<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="channel_4 ch_pwr" scope="row" class="stdbold" nowrap> 11.8 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
<td headers="channel_4 ch_snr" class="stdbold" nowrap>40.0 <script language="javascript" type="text/javascript">dw(vdb);</script></td>
</tr>
<tr>
<td id="channel_5" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 5<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="channel_5 ch_pwr" scope="row" class="stdbold" nowrap> 14.0 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
<td headers="channel_5 ch_snr" class="stdbold" nowrap>40.0 <script language="javascript" type="text/javascript">dw(vdb);</script></td>
</tr>
<tr>
<td id="channel_6" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 6<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="channel_6 ch_pwr" scope="row" class="stdbold" nowrap> 13.8 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
<td headers="channel_6 ch_snr" class="stdbold" nowrap>40.4 <script language="javascript" type="text/javascript">dw(vdb);</script></td>
</tr>
<tr>
<td id="channel_7" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 7<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="channel_7 ch_pwr" scope="row" class="stdbold" nowrap> 13.1 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
<td headers="channel_7 ch_snr" class="stdbold" nowrap>40.0 <script language="javascript" type="text/javascript">dw(vdb);</script></td>
</tr>
<tr>
<td id="channel_8" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 8<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="channel_8 ch_pwr" scope="row" class="stdbold" nowrap> 12.2 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
<td headers="channel_8 ch_snr" class="stdbold" nowrap>39.9 <script language="javascript" type="text/javascript">dw(vdb);</script></td>
...
                    <td class="Item3">
                        <table class="std" summary="Upstream Channels">
                            <tr> 
<td id="up_empty" width="140" nowrap>&nbsp; </td>
<td id="up_pwr" scope="col" width="140" class="stdbold" nowrap><script language="javascript" type="text/javascript">dw(vch_pwr);</script></td>
</tr>
<tr> 
<td id="up_channel_1" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 1<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="up_channel_1 up_pwr" scope="row" class="stdbold" nowrap>38.3 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
</tr> 
<tr> 
<td id="up_channel_2" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 2<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="up_channel_2 up_pwr" scope="row" class="stdbold" nowrap> 0.0 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
</tr> 
<tr> 
<td id="up_channel_3" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 3<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="up_channel_3 up_pwr" scope="row" class="stdbold" nowrap> 0.0 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
</tr> 
<tr> 
<td id="up_channel_4" width="140" nowrap><script language="javascript" type="text/javascript">dw(vs_channel);</script> 4<script language="javascript" type="text/javascript">dw(vcolon);</script></td>
<td headers="up_channel_4 up_pwr" scope="row" class="stdbold" nowrap> 0.0 <script language="javascript" type="text/javascript">dw(vdbmv);</script></td>
</tr> 

Um die Werte aus dem Quellcode zu extrahieren, kann dieser an bestimmte Bash-Funktionen übergeben werden. Als Beispiel kann "grep" bestimmte Passagen aus dem Text mithilfe von Regex herauslösen. Dabei ist es auch möglich die Textblöcke zunächst grob und mittels einer näheren Definition ein weiteres Mal an "grep" zu übergeben. Die Werte aus dem dargestellten HTML-Quellcode können beispielsweise wie folgt abgerufen und extrahiert werden:

curl - Aufruf und Übergabe an grep, um die gewünschten Textpasssagen zu extrahieren:

[+]
root@DESKTOP-I9DEFGN:~# curl http://192.168.0.1/Docsis_system.asp -s | grep -iE "ch_snr|up_pwr" | grep -Po "nowrap>(.*?)\ <"  | grep -Po "[0-9.]{1,4}" | xargs |  grep -Po "[0-9.]{1,4}"
40.3
39.9
39.9
39.9
40.1
40.4
39.9
39.9
38.3
40.0
39.5
40.5

Um mit einem Aufruf mehrere Werte auszulesen, können diese zunächst über die command_line-Platform abgerufen und später mittels Template-Sensoren als einzelne Entitäten verwendet werden.

Home Assistant command_line Platform

command_line:
  - sensor:
      name: cablelink_channels
      command: curl http://192.168.0.1/Docsis_system.asp -s | grep -iE "ch_snr|up_pwr" | grep -Po "nowrap>(.*?)\ <"  | grep -Po "[0-9.]{1,4}" | xargs
      scan_interval: 30

Die Entität cablelink_channels sammelt alle Werte und trennt diese mit einem Leerzeichen.

Template-Sensoren, einzelne Werte extrahieren

Über Templates kann auf die einzelnen Werte zugegriffen werden, indem der String über dessen Leerzeichen in ein Array verwandelt wird. Die Werte des Arrays können dann über den jeweiigen Index [0], [1] ... verwendet werden:

[+]
  - platform: template
    sensors:      
      cablelink_channel_snr_1:
        friendly_name: 'cablelink_channel_snr_1'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[0] }}'
      cablelink_channel_snr_2:
        friendly_name: 'cablelink_channel_snr_2'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[1] }}'      
      cablelink_channel_snr_3:
        friendly_name: 'cablelink_channel_snr_3'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[2] }}'
      cablelink_channel_snr_4:
        friendly_name: 'cablelink_channel_snr_4'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[3] }}'
      cablelink_channel_snr_5:
        friendly_name: 'cablelink_channel_snr_5'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[4] }}'
      cablelink_channel_snr_6:
        friendly_name: 'cablelink_channel_snr_6'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[5] }}'
      cablelink_channel_snr_7:
        friendly_name: 'cablelink_channel_snr_7'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[6] }}'
      cablelink_channel_snr_8:
        friendly_name: 'cablelink_channel_snr_8'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[7] }}'
      cablelink_channel_up_1:
        friendly_name: 'cablelink_channel_up_1'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[8] }}'
      cablelink_channel_up_2:
        friendly_name: 'cablelink_channel_up_2'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[9] }}'      
      cablelink_channel_up_3:
        friendly_name: 'cablelink_channel_up_3'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[10] }}'
      cablelink_channel_up_4:
        friendly_name: 'cablelink_channel_up_4'        
        unit_of_measurement: 'dB'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[11] }}'
 

Durchschnitts- Minimal- oder Maximal-Werte

Die min_max Platform ermöglicht es die Durchschnitts-, Maximal- oder Minimal-Werte bestimmter Entitäten in einer eigenen Entität zur Verfügung zu stellen.

[+]
sensor:
  - platform: min_max
    name: cablelink_channels_mean
    type: mean
    round_digits: 2
    entity_ids:
      - sensor.cablelink_channel_snr_1
      - sensor.cablelink_channel_snr_2
      - sensor.cablelink_channel_snr_3
      - sensor.cablelink_channel_snr_4
      - sensor.cablelink_channel_snr_5
      - sensor.cablelink_channel_snr_6
      - sensor.cablelink_channel_snr_7
      - sensor.cablelink_channel_snr_8
      - sensor.cablelink_channel_up_1
      - sensor.cablelink_channel_up_2
      - sensor.cablelink_channel_up_3
      - sensor.cablelink_channel_up_4

Sollte die Statusseite der WebGui erst nach einer Benutzeranmeldung aufgerufen werden können, müssen wir uns die Anmeldung in den Entwicklertools (F12) mit einem Browser (z.B. Google Chrome) näher ansehen:

Der Reiter "Network" verrät uns, wie die Daten für den Anmeldevorgang übertragen werden:

Ein Blick in die Payload zeigt uns die mittels "POST" übertragenen Formulardaten:

Umgemünzt auf einen curl-Befehl, würde die Anmeldung wie folgt aussehen:

curl -X POST http://192.168.0.1/goform/logon -d "username_login=admin&password_login=mysupersecretpassword&language_selector=en" -c cookies.txt;

Natürlich muss in der Befehlszeile das Passwort entsprechend angepasst werden. Der Parameter "-c" erzeugt eine Datei mit den für die Session verwendeten Cookies, also die Information für die stattgefundene Anmeldung. Verwenden wir diesen Parameter bei einer weiteren Abfrage, ist curl an der GUI angemeldet.

Nun können wir die Details für unsere Überwachung aus der Statusseite holen: http://192.168.0.1/st_docsis.html

Ziel ist es wieder, die Werte der Statusseite in Home Assistant zur Verfügung zu stellen:

Die folgende Befehlszeile führt eine Anmeldung durch und lädt den kompletten HTML-Sourcecode der Statusseite herunter:

curl -X POST http://192.168.0.1/goform/logon -d "username_login=admin&password_login=???&language_selector=en" -c cookies.txt; curl http://192.168.0.1/st_docsis.html -b cookies.txt

Der HTML-Quellcode kann dann wieder mit Linux-Funktionen wie grep, awk und xargs geparst werden. Ziel ist es die gewünschten Werte zu extrahieren:

Zusammengefasst schaut der Aufruf inkl. Anmeldung und Parsen der Statusseite in der Homeassistant-Konfig wie folgt aus:

Datei: configuration.yml

...
command_line:
  - sensor:
      name: cablelink_channels
      command: curl -X POST http://192.168.0.1/goform/logon -d "username_login=admin&password_login=??&language_selector=en" -c cookies.txt; curl http://192.168.0.1/st_docsis.html -b cookies.txt | grep -Po "</td><td scope=\"col\">(.*?)</td></tr>" | awk '{print substr($NF,0,30)}' | grep -Po "[\-0-9]{1,3}[.][0-9]" | xargs
      scan_interval: 60
...

Der Befehl sammelt alle Channel-Daten in einem Sensor mit Namen cablelink_channels und trennt diese mit einem Leerzeichen, entsprechende Templates können die einzelnen Werte dann extrahieren:

[+]
...
sensor:
  - platform: template
    sensors:
      cablelink_channel_down_1:
        friendly_name: 'cablelink_channel_down_1'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[0] if states("sensor.cablelink_channels").split(" ") | count > 1 else 0 }}'
      cablelink_channel_down_2:
        friendly_name: 'cablelink_channel_down_2'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[1] if states("sensor.cablelink_channels").split(" ") | count > 1 else 0 }}'      
      cablelink_channel_down_3:
        friendly_name: 'cablelink_channel_down_3'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[2] if states("sensor.cablelink_channels").split(" ") | count > 2 else 0}}'
      cablelink_channel_down_4:
        friendly_name: 'cablelink_channel_down_4'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[3] if states("sensor.cablelink_channels").split(" ") | count > 3 else 0}}'
      cablelink_channel_down_5:
        friendly_name: 'cablelink_channel_down_5'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[4] if states("sensor.cablelink_channels").split(" ") | count > 4 else 0 }}'
      cablelink_channel_down_6:
        friendly_name: 'cablelink_channel_down_6'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[5] if states("sensor.cablelink_channels").split(" ") | count > 5 else 0 }}'      
      cablelink_channel_down_7:
        friendly_name: 'cablelink_channel_down_7'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[6] if states("sensor.cablelink_channels").split(" ") | count > 6 else 0}}'
      cablelink_channel_down_8:
        friendly_name: 'cablelink_channel_down_8'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[7] if states("sensor.cablelink_channels").split(" ") | count > 7 else 0}}'
      cablelink_channel_down_9:
        friendly_name: 'cablelink_channel_down_9'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[8] if states("sensor.cablelink_channels").split(" ") | count > 8 else 0 }}'
      cablelink_channel_down_10:
        friendly_name: 'cablelink_channel_down_10'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[9] if states("sensor.cablelink_channels").split(" ") | count > 9 else 0 }}'      
      cablelink_channel_down_11:
        friendly_name: 'cablelink_channel_down_11'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[10] if states("sensor.cablelink_channels").split(" ") | count > 10 else 0}}'
      cablelink_channel_down_12:
        friendly_name: 'cablelink_channel_down_12'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[11] if states("sensor.cablelink_channels").split(" ") | count > 11 else 0}}'
      cablelink_channel_down_13:
        friendly_name: 'cablelink_channel_down_13'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[12] if states("sensor.cablelink_channels").split(" ") | count > 12 else 0 }}'
      cablelink_channel_down_14:
        friendly_name: 'cablelink_channel_down_14'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[13] if states("sensor.cablelink_channels").split(" ") | count > 13 else 0 }}'      
      cablelink_channel_down_15:
        friendly_name: 'cablelink_channel_down_15'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[14] if states("sensor.cablelink_channels").split(" ") | count > 14 else 0}}'
      cablelink_channel_down_16:
        friendly_name: 'cablelink_channel_down_16'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[15] if states("sensor.cablelink_channels").split(" ") | count > 15 else 0}}'



      cablelink_channel_up_1:
        friendly_name: 'cablelink_channel_up_1'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[36] if states("sensor.cablelink_channels").split(" ") | count > 36 else 0 }}'
      cablelink_channel_up_2:
        friendly_name: 'cablelink_channel_up_2'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[37] if states("sensor.cablelink_channels").split(" ") | count > 37 else 0 }}'      
      cablelink_channel_up_3:
        friendly_name: 'cablelink_channel_up_3'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[38] if states("sensor.cablelink_channels").split(" ") | count > 38 else 0}}'
      cablelink_channel_up_4:
        friendly_name: 'cablelink_channel_up_4'        
        unit_of_measurement: 'dBmV'
        value_template: '{{states("sensor.cablelink_channels").split(" ")[39] if states("sensor.cablelink_channels").split(" ") | count > 39 else 0}}'
...

states("sensor.cablelink_channels").split(" ") erzeugt ein Array mit den einzelnen Werten. Die jeweiligen Werte können mit dessen Index [0], [1] extrahiert werden.

Entwicklerwerkzeuge: Template testen

Für das Testen und zusammenstellen der Templates, also das Extrahieren der einzelnen Werte helfen die Entwicklerwerkzeuge in Home-Assistant. 

Unter "TEMPLATE" können die in der configuration.yaml verwendeten "value_template"-Werte getestet werden:

Beispiel 3: Leistungsdaten, Deye SUN800G3-EU-230 

Ein weiteres Beispiel für das Auslesen einer Webgui habe ich mit dem Deye Wechselrichter getestet, siehe: Deye PV Balkonkraftwerk: Inbetriebnahme und HA Integration.

Beispiel 4: OeMAG - Marktpreis

Ein anderes Beispiel ist der Einspeisetarif für eine PV-Anlage in Österreich. Der OeMAG-Marktpreis für das Einspeisen kann der folgenden Webseite entnommen werden: https://www.oem-ag.at/de/marktpreis. Ein Blick in die Entwicklertools des Browsers verrät den HTML-Quellcode und hilft beim Zusammenstellen des Bash-Befehls:

 

Mit folgendem Befehl konnte ich den Tarif auslesen:

curl https://www.oem-ag.at/de/marktpreis/ | grep -Po "px\">(.*?) Cent/kWh" | grep -Po "[0-9,]{3,7}"

Über einen "echo"-Befehl und an "bc" übertragen, kann der Wert von Cent auf Euro umgerechnet werden:

Für den Oemag-Marktpreis habe ich den folgenden Sensor in der configuration.yaml-Datei hinterlegt:

command_line:
  - sensor:
      name: oemag_marktpreis
      command: echo $(curl https://www.oem-ag.at/de/marktpreis/ | grep -Po "px\">(.*?) Cent/kWh" | grep -Po "[0-9,]{3,7}" | sed 's/,/./g') / 100 | bc -l
      unit_of_measurement: 'EUR/kWh'
      scan_interval: 21600

Alternativ teste ich auf dieser Seite gerade die Werte von E-Control, siehe: aktueller Oemag-Marktpreis.

Der Wert kann jetzt im Energy-Dashboard verwendet werden und zeigt das Einspeiseguthaben in den Statistiken:

Wird der Sensor in einer Automation verwendet, kann bei einer Wertänderung zudem eine Meldung auf das Handy geschickt werden:

alias: Benachrichtigung OeMAG-Markpreis
description: ""
trigger:
  - platform: state
    entity_id:
      - sensor.oemag_marktpreis
    for:
      hours: 12
      minutes: 0
      seconds: 0
condition: []
action:
  - service: notify.mobile_app_???
    data:
      title: OeMAG-Marktpreis-Änderung
      message: "{{states('sensor.oemag_marktpreis') | round(6)}}€/kWh"
mode: single

Nähere Informationen zu Automations, siehe: Home Assistant Automatisierung - Möglichkeiten & Grundlagen

Integration: Scrape

Für einzelne Werte kann alternativ zum command_line-Senser die Integration "Scrape" verwendet werden. Scrape arbeitet mit CSS-Selektoren und kann damit einzelne Werte aus den Webseiten extrahieren:

Über die folgende Eingabemaske können die Details für den Aufruf der Webseite hinterlegt werden:

Auch wenn das Auslesen über CSS-Selektoren sicherlich einen Mehrwert bietet, können Bash-Befehle meiner Meinung nach dennoch wesentlich einfacher in einem Linux-OS getestet werden, bevor diese in Home-Assistant zum Einsatz kommen.

Fazit

Die Command-Line Platform in Home Assistant kann im Prinzip alles, was das Betriebssystem von Home Assistant zulässt. Unter anderem können Linux-Befehle bestimmte Webseiten herunterladen und deren Daten extrahieren, wodurch diese ohne entsprechenden Integration in Home Assistant zur Verfügung gestellt werden können. 

Aktueller OeMAG-Marktpreis

Aktueller OeMAG-Marktpreis

erstellt: 03.10.2023 von Bernhard

Nachdem der aktuelle Marktpreis auf www.oem-ag.at immer erst nach ein paar Tagen aktualisiert wird und die Berechnung über die E-Control ev. schon vor einem Wochenende für das nächste Quartal erfolgt, versuche ich hier die aktuellen Daten zu präsentieren: ... weiterlesen

positive Bewertung({{pro_count}})
Beitrag bewerten:
{{percentage}} % positiv
negative Bewertung({{con_count}})

DANKE für deine Bewertung!

Fragen / Kommentare


(sortiert nach Bewertung / Datum) [alle Kommentare(am besten bewertete zuerst)]

✍GmbH07
02.10.2024 15:48
Hallo,

ich versuche eine Preis von folgender Website auszulesen, mit Scrape funktioniert es nur leider kann ich diesen Wert nicht für das Energie Dashboard verwenden und bekomme eine Fehlermeldung: 
Entität hat einen nicht-numerischen Status
Die folgenden Entitäten haben einen Zustand, der nicht als Zahl geparst werden kann:
sensor.wasserpreis_je_m3 (2,67)

Mit dem Link von dir welcher mir den OeMAG Preis anzeigt funktioniert es wunderbar. Könntest du mir hier weiterhelfen?

Link zum Preis:
https://www.holding-graz.at/de/wasser/wasserpreise/

Durch die weitere Nutzung der Seite stimmst du der Verwendung von Cookies zu Mehr Details