Awattar

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Benutzeravatar
udo1toni
Beiträge: 13854
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Awattar

Beitrag von udo1toni »

Das Update Interval in der http.cfg bezieht sich auf das Füllen des Caches. Das heißt, wenn man hier eine Stunde einträgt, fragt openHAB einmal stündlich die Website ab und speichert die Daten im Cache. Die erste Abfrage geschieht, sobald das http Binding gestartet wird, also nicht etwa zur vollen Stunde. Entsprechend müsste man, damit die Daten auch "aktuell" sind, openHAB möglichst immer zur vollen Stunde neu starten.

Das Update in der Sitemap bezieht sich aber auf die Darstellung des Items. Es ist durchaus sinnvoll, hier eine Minute einzutragen, das hat keinen Einfluss auf die Anzahl der Abfragen bei Awattar.

Alle Rules gehören in eine (oder auch mehrere) Datei(en) *.rules unterhalb openhab2/rules/

Die Items sollten quasi unmittelbar gültige Werte zeigen, ansonsten hast Du irgendwo einen Fehler drin.
Schau mal in openhab.log, ob dort irgendwelche Fehler angezeigt werden.

Laut Dokumentation wird kein Token gebraucht, und es dürfen bis 60 Abfragen pro Minute gestellt werden (wobei das ja eher witzlos ist) https://www.awattar.de/services/api
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

tobi.wanka
Beiträge: 9
Registriert: 21. Sep 2019 22:02

Re: Awattar

Beitrag von tobi.wanka »

meinen http.cfg sieht so aus:

Code: Alles auswählen

awattar.url=https://api.awattar.de/v1/marketdata
awattar.updateInterval=1500000
Der Zeitintervall sollte ca 25 min sein. Was aber bedeutet, das mein "Awattar_Preis1" nicht immer den aktuellen Preis anzeigt.

meine Awattar.item:

Code: Alles auswählen

// awattar

Group Awattar "Strompreise " <Awattar>
Group AwattarZeitIn
Group AwattarZeitOut

Number Awattar_Preis1 "Preis1 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[0].marketprice)]"}
Number Awattar_Preis2 "Preis2 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[1].marketprice)]"}
Number Awattar_Preis3 "Preis3 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[2].marketprice)]"}
Number Awattar_Preis4 "Preis4 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[3].marketprice)]"}
Number Awattar_Preis5 "Preis5 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[4].marketprice)]"}
Number Awattar_Preis6 "Preis6 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[5].marketprice)]"}
Number Awattar_Preis7 "Preis7 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[6].marketprice)]"}
Number Awattar_Preis8 "Preis8 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[7].marketprice)]"}
Number Awattar_Preis9 "Preis9 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[8].marketprice)]"}
Number Awattar_Preis10 "Preis10 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[9].marketprice)]"}
Number Awattar_Preis11 "Preis11 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[10].marketprice)]"}
Number Awattar_Preis12 "Preis12 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[11].marketprice)]"}
Number Awattar_Preis13 "Preis13 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[12].marketprice)]"}
Number Awattar_Preis14 "Preis14 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[13].marketprice)]"}
Number Awattar_Preis15 "Preis15 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[14].marketprice)]"}
Number Awattar_Preis16 "Preis16 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[15].marketprice)]"}
Number Awattar_Preis17 "Preis17 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[16].marketprice)]"}
Number Awattar_Preis18 "Preis18 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[17].marketprice)]"}
Number Awattar_Preis19 "Preis19 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[18].marketprice)]"}
Number Awattar_Preis20 "Preis20 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[19].marketprice)]"}
Number Awattar_Preis21 "Preis21 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[20].marketprice)]"}
Number Awattar_Preis22 "Preis22 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[21].marketprice)]"}
Number Awattar_Preis23 "Preis23 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[22].marketprice)]"}
Number Awattar_Preis24 "Preis24 [%.2f €/MWh]" (Awattar) {http="<[awattar:30000:JSONPATH($.data[23].marketprice)]"}

Number AwattarIn_Zeit1 "Zeit1" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[0].start_timestamp)]"}
Number AwattarIn_Zeit2 "Zeit2" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[1].start_timestamp)]"}
Number AwattarIn_Zeit3 "Zeit3" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[2].start_timestamp)]"}
Number AwattarIn_Zeit4 "Zeit4" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[3].start_timestamp)]"}
Number AwattarIn_Zeit5 "Zeit5" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[4].start_timestamp)]"}
Number AwattarIn_Zeit6 "Zeit6" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[5].start_timestamp)]"}
Number AwattarIn_Zeit7 "Zeit7" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[6].start_timestamp)]"}
Number AwattarIn_Zeit8 "Zeit8" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[7].start_timestamp)]"}
Number AwattarIn_Zeit9 "Zeit9" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[8].start_timestamp)]"}
Number AwattarIn_Zeit10 "Zeit10" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[9].start_timestamp)]"}
Number AwattarIn_Zeit11 "Zeit11" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[10].start_timestamp)]"}
Number AwattarIn_Zeit12 "Zeit12" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[11].start_timestamp)]"}
Number AwattarIn_Zeit13 "Zeit13" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[12].start_timestamp)]"}
Number AwattarIn_Zeit14 "Zeit14" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[13].start_timestamp)]"}
Number AwattarIn_Zeit15 "Zeit15" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[14].start_timestamp)]"}
Number AwattarIn_Zeit16 "Zeit16" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[15].start_timestamp)]"}
Number AwattarIn_Zeit17 "Zeit17" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[16].start_timestamp)]"}
Number AwattarIn_Zeit18 "Zeit18" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[17].start_timestamp)]"}
Number AwattarIn_Zeit19 "Zeit19" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[18].start_timestamp)]"}
Number AwattarIn_Zeit20 "Zeit20" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[19].start_timestamp)]"}
Number AwattarIn_Zeit21 "Zeit21" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[20].start_timestamp)]"}
Number AwattarIn_Zeit22 "Zeit22" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[21].start_timestamp)]"}
Number AwattarIn_Zeit23 "Zeit23" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[22].start_timestamp)]"}
Number AwattarIn_Zeit24 "Zeit24" <time> (AwattarZeitIn) {http="<[awattar:30000:JSONPATH($.data[23].start_timestamp)]"}

DateTime Awattar_Zeit1 "Zeit1 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit2 "Zeit2 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit3 "Zeit3 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit4 "Zeit4 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit5 "Zeit5 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit6 "Zeit6 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit7 "Zeit7 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit8 "Zeit8 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit9 "Zeit9 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit10 "Zeit10 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit11 "Zeit11 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit12 "Zeit12 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit13 "Zeit13 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit14 "Zeit14 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit15 "Zeit15 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit16 "Zeit16 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit17 "Zeit17 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit18 "Zeit18 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit19 "Zeit19 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit20 "Zeit20 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit21 "Zeit21 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit22 "Zeit22 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit23 "Zeit23 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
DateTime Awattar_Zeit24 "Zeit24 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
Zum Umrechnen der Zeit noch die awattarzeit.rules:

Code: Alles auswählen

rule "Zeit rechnen"
when 
    Member of AwattarZeitIn changed 
then
    if(triggeringItem.state instanceof Number) {
        AwattarZeitOut.members.filter[m |
            m.name.contains(triggeringItem.name.split("_").get(1))
        ].head.postUpdate((new DateTime((triggeringItem.state as Number).longValue)).toString)
    }
end
Zum Anzeigen hab ich mir eine Awattar.sitemap

Code: Alles auswählen

sitemap Awattar label="Awattar" {
    Frame label="Strompreise" {

    Text item=Awattar_Preis1
    Text item=Awattar_Zeit1

    Text item=Awattar_Preis2
    Text item=Awattar_Zeit2

    Text item=Awattar_Preis3
    Text item=Awattar_Zeit3
    
    Text item=Awattar_Preis4
    Text item=Awattar_Zeit4
    
    Text item=Awattar_Preis5
    Text item=Awattar_Zeit5

    Text item=Awattar_Preis6
    Text item=Awattar_Zeit6
    
    Text item=Awattar_Preis7
    Text item=Awattar_Zeit7
    
    Text item=Awattar_Preis8
    Text item=Awattar_Zeit8

    Text item=Awattar_Preis9
    Text item=Awattar_Zeit9

    Text item=Awattar_Preis10
    Text item=Awattar_Zeit10

    Text item=Awattar_Preis11
    Text item=Awattar_Zeit11

    Text item=Awattar_Preis12
    Text item=Awattar_Zeit12

    Text item=Awattar_Preis13
    Text item=Awattar_Zeit13
    
    Text item=Awattar_Preis14
    Text item=Awattar_Zeit14
    
    Text item=Awattar_Preis15
    Text item=Awattar_Zeit15

    Text item=Awattar_Preis16
    Text item=Awattar_Zeit16
    
    Text item=Awattar_Preis17
    Text item=Awattar_Zeit17
    
    Text item=Awattar_Preis18
    Text item=Awattar_Zeit18

    Text item=Awattar_Preis19
    Text item=Awattar_Zeit19

    Text item=Awattar_Preis20
    Text item=Awattar_Zeit20
    
    Text item=Awattar_Preis21
    Text item=Awattar_Zeit21
    
    Text item=Awattar_Preis22
    Text item=Awattar_Zeit22

    Text item=Awattar_Preis23
    Text item=Awattar_Zeit23

    Text item=Awattar_Preis24
    Text item=Awattar_Zeit24    

    
    Chart item=Awattar_Preis24 label="Strompreis [%s €/MWH]" icon="Price" period=D
    Chart item=Awattar_Preis23 label="Strompreis [%s €/MWH]" icon="Price" period=D
    Chart item=Awattar_Preis13 label="Strompreis [%s €/MWH]" icon="Price" period=12h

      }
} 
Und zum grafisch darstellen experimeniere ich gerade mit rrd4j.persist (muss als Addon extra installiert werden)

Code: Alles auswählen

Strategies {
    everyMinute : "0 * * * * ?"
    everyHour : "0 0 * * * ?"
    everyDay : "0 0 0 * * ?"
    default = everyChange
}

Items
    {

Awattar_Preis24 : strategy = everyMinute
Awattar_Preis23 : strategy = everyMinute
Awattar_Preis13 : strategy = everyMinute

    }

Soweit bin ich schon super zufrieden.

Ich bin mir nicht sicher, ob es notwenig ist einen "aktuellen Preis" auszurechnen. Warscheinlich reicht es aus, den Abfrageintervall sehr kurz zu machen und denn den "Awattar_Preis1" zu verwenden. Elegant wäre ein "aktueller Preis" aber schon.

Ich hoffe die Infos machen es etwas einfacher.

@udo1toni: Deine "Awattar.rules" werde ich gerne ausprobieren und damit weiterentwickeln. Mal sehe wann ich dazu komme....

jb79
Beiträge: 7
Registriert: 29. Sep 2019 15:29

Re: Awattar

Beitrag von jb79 »

udo1toni hat geschrieben: 30. Sep 2019 16:30 Laut Dokumentation wird kein Token gebraucht, und es dürfen bis 60 Abfragen pro Minute gestellt werden (wobei das ja eher witzlos ist) https://www.awattar.de/services/api
Ach ja, ich vergaß: Ich wohne in Österreich, hier gilt Token nötig und 100 Abfragen/Tag => https://www.awattar.com/services/api/

So jetzt hab ich's aber. Für alle die Awattar in Österreich nutzen wollen hier die Anleitung wie es geht:

http.cfg:

Code: Alles auswählen

awattar.url=https://api.awattar.com/v1/marketdata{Authorization=Basic TokenXYZ}
awattar.updateInterval=1500000
Der Token braucht das Format "username:passwort", wobei der Username der Token ist, den man von Awattar erhalten hat, das Passwort ist egal (man kann 12345 nehmen). Der Token, gefolgt von : und sagen wir 12345, also Token:12345 oben in den Base64 Encoder kopieren und das Ergebis aus dem unteren Feld in der http.cfg anstelle von TokenXYZ einfügen.

Andere Frage: Wie schafft man es, daß die Preisabfrage jeden Tag immer zur selben Uhrzeit, sagen wir mal 18:00, stattfindet?
lg Jürgen

Benutzeravatar
udo1toni
Beiträge: 13854
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Awattar

Beitrag von udo1toni »

Abfrage um eine bestimmte Uhrzeit wäre eine Sache, die man mit einer Rule erschlägt. Das heißt, Du legst eine Rule an, in der Du direkt die http-Abfrage mittels sendHttpGetRequest(String url) schickst. Das Ergebnis speicherst Du dann in einer Variablen, die Du dann mittels JSONPATH auf die verschiedneen Items aufteilst. Die Items sind dann alle unbound, also ohne Channel.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

tobi.wanka
Beiträge: 9
Registriert: 21. Sep 2019 22:02

Re: Awattar

Beitrag von tobi.wanka »

Mein Ansatz ist gerade ein anderer. Ich habe mir ein Item erstellt, dass den aktuellen Strompreis aus ausweisen soll.

Code: Alles auswählen

Number Awattar_aktuell "Preis aktuell [%.2f €/MWh]" (Awattar) 
Jetzt vergleiche ich nur die Zeitangaben aus meiner Abfrage mit der aktuelle Zeit und Übergebe den Preis der entsprechenden Stunde in den aktuellen Wert.
Vielleicht war ich etwas umständlich aber es funktioniert:

1. Item mit der aktuellen Zeit erstellen:

Zeit.item

Code: Alles auswählen

// aktuelle Zeit


DateTime Zeitaktuell "Zeitaktuell [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> 
2. Item mit der aktuellen Zeit Zeit.rules

Code: Alles auswählen

//===============================================================================
rule "aktuelle Zeit"

when
Time cron "0/1 * * 1/1 * ? *"

then
        Zeitaktuell.sendCommand(new DateTimeType)
    
end

3. awattaraktuell.rules

Code: Alles auswählen

rule "Preisaktuell"

when 
   Time cron "0/1 * * 1/1 * ? *"
then

    if((Awattar_Zeit1.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli
     <
      (Zeitaktuell.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli
      &&
   (Awattar_Zeit2.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli
     >
      (Zeitaktuell.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli)  

    {
        Awattar_aktuell.sendCommand(Awattar_Preis1.state as Number)  
            Zeitpreisaktuell.sendCommand(new DateTimeType)           
      
             }
    if((Awattar_Zeit2.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli
     <
      (Zeitaktuell.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli
      &&
   (Awattar_Zeit3.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli
     >
      (Zeitaktuell.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli)  

    {
        Awattar_aktuell.sendCommand(Awattar_Preis2.state as Number)  
            Zeitpreisaktuell.sendCommand(new DateTimeType)           
      
             }

      if((Awattar_Zeit3.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli
     <
      (Zeitaktuell.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli
      &&
   (Awattar_Zeit4.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli
     >
      (Zeitaktuell.state as DateTimeType).getZonedDateTime.toInstant.toEpochMilli)  

    {
        Awattar_aktuell.sendCommand(Awattar_Preis2.state as Number)  
            Zeitpreisaktuell.sendCommand(new DateTimeType)           
      
             }

end
Meine Abfrage habe ich gerade auf 2 Stunden umgestellt.

Benutzeravatar
udo1toni
Beiträge: 13854
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: Awattar

Beitrag von udo1toni »

Diese Zeile:

Code: Alles auswählen

Time cron "0/1 * * 1/1 * ? *"
bewirkt das gleiche wie diese Zeile:

Code: Alles auswählen

Time cron "* * * * * ?"
womit beide Rules einmal pro Sekunde ausgeführt werden. Der letzte Stern steht für das Jahr, die Angabe ist optional, kann also entfallen.
Es kann sein, dass die Rule mit Deinem Trigger zwischen 0 Uhr und 1 Uhr gar nicht ausgeführt wird, da bin ich mir nicht so ganz sicher ("beginnend mit 1 Uhr").

Nicht nur ist das absoluter Overkill (der Wert ändert sich nur einmal pro Stunde), Du hast auch zwei voneinander unabhängige Rules, die beide mit dem selben Time cron Trigger ausgelöst werden.
openHAB hat default zwei Threads, die für Scheduler Events verwendet werden. Es ist also sehr wahrscheinlich, dass weitere Timer durch diese beiden Rules nachhaltig gestört werden.

Um die Zeit in einem Item zu speichern, benötigt man gar keine Rule, stattdessen greift man zum NTP Binding, welches "nebenher" auch dafür sorgt, dass die Zeit immer korrekt ist - vorausgesetzt, man hat NTP auch korrekt konfiguriert, natürlich.
new DateTimeType greift hingegen auf die Rechneruhr zurück, falls man also keinen NTP Client auf Betriebssystemebene eingerichtet hat, läuft diese Zeit abhängig von Temperatur und Rechner weg - durchaus auch mehr als eine Minute pro Tag.

Die Anzeige der Uhrzeit in der UI kann man realisieren, aber ob das sekundengenau funktioniert, wage ich zu bezweifeln, weil die UI dafür nicht ausgelegt ist.
Im Allgemeinen wird eine Auflösung von 30 Sekunden ausreichen, was man so im NTP Binding konfigurieren kann (Update des Items alle 30 Sekunden, Synchronisation mit dem Server z.B. nach 120 Aktualisierungen, also einmal pro Stunde).

Der exakte Zeitpunkt des Tarifwechsels wird vermutlich aus dem Vertrag ersichtlich sein, ich gehe jetzt mal von der vollen Stunde aus. Was dann bedeutet, dass man den aktuellen Tarif einmal stündlich umschalten muss, am besten einige Sekunden nach dem Stundenwechsel, entsprechend wäre der Time cron Ausdruck dann:

Code: Alles auswählen

Time cron "5 0 0 * * ?"
für stündlich, fünf Sekunden nach der vollen Stunde.

sendCommand() schickt ein Kommando an alle verlinkten Channel. Default wird anschließend auch ein postUpdate() auf das selbe Item ausgeführt (kann man abschalten). Sofern man den Preis nicht über ein Binding irgendwohin schickt (http, mqtt, knx... whatever), sollte ein postUpdate() ausreichen, um die Anzeige in der UI zu ändern (und man kann auch Rules darauf triggern lassen).

Die Vergleichszeilen schreien nach einer Optimierung mit Konstanten, weil bis auf zwei Werte alle Werte mindestens zweimal verwendet werden. Es trüge auch zur Lesbarkeit der Rule bei ;) mal abgesehen von der Tatsache, dass die Rule umgehend eine null-Pointer Exception verursacht, wenn auch nur eines der Items zum Zeitpunkt der Ausführung kein gültiges Datum enthält, weil dieser Fall nicht abgefangen wird.

Zu guter Letzt ist der Vergleich des Zeitstempels ebenfalls unnötig, sofern man sicherstellt, dass die Preise tatsächlich aktuell sind, es reicht in dem Fall, die korrekte Stunde zu suchen. das geht z.B. so:

Code: Alles auswählen

now.getHourOfDay // 0 - 23 
Es bietet sich dann an, gar nicht den genauen Zeitstempel zu speichern, sondern stattdessen die Stunde zu speichern oder gar immer den Preis für einen bestimmten Zeitraum im gleichen Item, dann kann man bei geschickter Namenswahl das betreffende Item direkt "errechnen". Also nicht den Preis in zwei Stunden in das Item Preis02 speichern, sondern den Preis für 2 Uhr in Preis02 speichern. alle Preise kommen in eine Gruppe gPreis. Dann reicht dies hier:

Code: Alles auswählen

aktuellerPreis.postUpdate(gPreis.members.filter[i|i.name.endsWith(String::format("%02d",now.getHourOfDay))].head.state as Number)
um immer den aktuellen Preis zu kopieren.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

sgp01
Beiträge: 1
Registriert: 20. Aug 2020 06:29

Re: Awattar

Beitrag von sgp01 »

Hallo,

vielleicht wenn es jemand braucht, hier meine Lösung. Angepasst von den Vorschlägen aus dem Thread hier!

Ziel ist die Ermittlung von Minimum und Maximum Preisen für diverse Zeitspannen. Also wann soll Warmwasser aufgewärmt werden. Wann ist der Strompreis hoch und ich schalte die Heizung für die Wärmepumpe ab etc. etc.

1.) Laut Homepage sind die Preise für den Folgetag ab 14:00 über die API zu downloaden. Der API kann als Parameter ein Timestamp als Startzeit übergeben werden. Also in diesem Fall, 0:00 des Folgetags um die Preise für die nächsten 24 Stunden zu erhalten.
2.) Die Items sollen darauf basierend nach Uhrzeit sortiert und befüllt sein. D.h. Item Preis0=0:00-1:00, Preis1=1:00-2:00, Preis3=2:00-3:00 etc.
3.) Um den günstigsten Preis für das Aufwärmen von Warmwasser am Vormittag und am Nachmittag zu finden
4.) Ich möchte darauf basierend auch die Wärmepumpe für die Heizung in den 10 teuersten Stunden am Tag ausschalten, das programmiere ich aber erst wenn die Heizsaison beginnt

1. Items können von Tobi.wanka übernommen werden. Wichtig ist dass folgende Items noch hinzugefügt werden. Also Preis0 für Preis von 0 - 1 Uhr. Preis24 kann gelöscht werden.

Code: Alles auswählen

Number Awattar_Preis0 "Preis0 [%.2f €/MWh]" (Awattar) 
...
Number AwattarIn_Zeit0 "Zeit0" <time> (AwattarZeitIn) 
...
DateTime Awattar_Zeit0 "Zeit0 [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM]" <time> (AwattarZeitOut)
2. Sitemap kann man von Tobi.wanka nehmen, bitte noch ein Item für Preis0 / Zeit0 hinzufügen

3. Rules

Code: Alles auswählen

import java.time.ZoneId
import java.time.Instant
import java.time.ZonedDateTime
import java.util.Map

rule "Awattarpreisupdate"
 when
     Time cron "0 30 14 ? * * *"
 then
    var Instant instant = Instant.now();                                                    //timestamp / epoch herausfinden für 0:00 des aktuellen Tags und 0:00 des folgetags
    var ZoneId zoneId = ZoneId.of( "Europe/Vienna" );			            //Lösung ist von hier: https://stackoverflow.com/questions/10308356/how-to-obtain-the-start-time-and-end-time-of-a-day/10308430
    var ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
    var ZonedDateTime zdtStart = zdt.toLocalDate().atStartOfDay( zoneId );
    var Number epoch_today = zdtStart.toEpochSecond() * 1000
    var Number epoch_tomorrow = epoch_today + 86400000                   //zum Timestamp vom aktuellen Tagesstart 24 Stunden hinzufügen um den Timestamp für die API abfrage zu erhalten

    logInfo("awattar", "Start Heute: "+zdtStart+" "+epoch_today+ " Morgen: "+epoch_tomorrow)
    logInfo("awattar", "Hole Daten von https://api.awattar.com/v1/marketdata?start="+epoch_tomorrow)

    var Map<Number, Double> awattar_map = newHashMap                                                        //Hashmap mit Preis0 --> xx EUR, Preis1 --> xx EUR                                                                                                            
    var String data = sendHttpGetRequest("https://api.awattar.com/v1/marketdata?start="+epoch_tomorrow)     //lade die Preise für den Folgetag ab 0:00 herunter, basierend auf den vorhin berechneten Timestamp
    var i = 0                                                                                               					//das heruntergeladene Json parsen
    while ( i <= 23) {        
        var String preis_str = transform("JSONPATH", "$.data["+i+"].marketprice", data)                     //parse das jeweilige Item
        var String zeit_str = transform("JSONPATH", "$.data["+i+"].start_timestamp", data)    
        var Number preis_float = Float::parseFloat(preis_str) as Number 
        postUpdate("Awattar_Preis"+i,preis_str)
        postUpdate("AwattarIn_Zeit"+i,zeit_str)                
        logInfo("awattar", "Preis"+i+"="+preis_str)
        awattar_map.put(i as Number,    preis_float.doubleValue())                                          //Füge den Preis plus Stunde der Hashmap hinzu
        i=i+1
    }

    i = 0                                                                                                   //Hashmap sortieren nach Preis und das Minimum herausfinden
    var Number min_morning = 0
    var Number min_afternoon = 0
    for (gPowerEntry : awattar_map.entrySet.sortBy[value]) {        
        logInfo("awattar","Key "+gPowerEntry.getKey() + " Value "+  gPowerEntry.getValue()  )
        if (min_morning == 0 && gPowerEntry.getKey() >=1 && gPowerEntry.getKey() <=6) {
            min_morning = gPowerEntry.getKey()
        }
        if (min_afternoon == 0 && gPowerEntry.getKey() >=12 && gPowerEntry.getKey() <=17) {
            min_afternoon = gPowerEntry.getKey()
        }
        i = i+1        
    }

    logInfo("awattar","Min Morning "+min_morning + " Min Afternoon "+  min_afternoon )                  // sind die Ergebnisse in Stunden, kann in Items gepostet werden
                                                                                                        // min_morning bedeutet zB um 3:00 ist der Preis zwischen 1:00 und 6:00 am günstigsten
end
Wie in den Kommentaren beschrieben, die Inhalte von min_morning und min_afternoon muss selbst weiterverarbeitet werden, zB für die Steuerung der Wärmepumpe oder anderer Verbraucher. Denkbar wäre zB auch wenn der Strompreis negativ ist schaltet man halt den Fön ein :mrgreen:

AutomateIT
Beiträge: 1
Registriert: 9. Sep 2020 09:53

Re: Awattar

Beitrag von AutomateIT »

Ich habe versucht das ganze zu übernehmen, bin mir aber nicht sicher was ich hier sehe:

Code: Alles auswählen

2020-09-09 14:30:00.434 [INFO ] [lipse.smarthome.model.script.awattar] - Start Tag heute: 2020-09-09T00:00+02:00[Europe/Berlin] 1599602400000 Start Tag morgen: 1599688800000
2020-09-09 14:30:00.435 [INFO ] [lipse.smarthome.model.script.awattar] - Hole Daten von https://api.awattar.com/v1/marketdata?start=1599688800000
Nach UTC ist das der 09.09. 22 Uhr. Die API Dokumentation sagt aber nicht ob sie UTC oder Localtime erwartet. Wenn ich mir die Preise anschaue finde ich keinen Zusammenhang zu den Preisen die ich per Webseite abrufen kann:

Code: Alles auswählen

2020-09-09 14:30:00.575 [INFO ] [lipse.smarthome.model.script.awattar] - Preis0=32.09
2020-09-09 14:30:00.583 [INFO ] [lipse.smarthome.model.script.awattar] - Preis1=31.2
2020-09-09 14:30:00.594 [INFO ] [lipse.smarthome.model.script.awattar] - Preis2=31.04
Online sehe ich für den 10.09. folgende Werte: 0=3.45 1=3.45 2=3.48, 4=3.48, 5=3.47

Zwei Punkte die mir noch aufgefallen sind:
In der Sitemap sind alle Zeiten leer. Laut Hilfe kann ich auch auch keine Epoch an ein DateTime Item schicken?
Mit dem Ansatz verliere ich ab 14:30 Uhr alle Daten für den aktuellen Tag - einen besseren Ansatz habe ich aber auch noch nicht. Hat hier jemand eine gute Idee?

tobi.wanka
Beiträge: 9
Registriert: 21. Sep 2019 22:02

Re: Awattar

Beitrag von tobi.wanka »

Ich hab nun für jede Stunde ein Item definiert (wie oben beschrieben):

Auszug aus meiner Awatt.item:

Code: Alles auswählen

// awatt

Group awatt "Strompreise" <Awattar>
Group:Number:MIN preisminnacht "durchs.Preis [%.2f €/MWh]" <Awattar>

Number awattar_akt "Preis aktuell [%.2f €/MWh]"  <Awattar>

Number awattar_pr0 "Preis0 [%.2f €/MWh]" (Awatt, preisminnacht) 
Number awattar_pr1 "Preis0 [%.2f €/MWh]" (Awatt, preisminnacht)
Number awattar_pr2 "Preis0 [%.2f €/MWh]" (Awatt, preisminnacht)
Nun möchte ich gerne das Item "awattar_akt" mit dem Preis der aktuellen Stunde füllen.

Meine Rule läuft aber leider auf Fehler:

Code: Alles auswählen

rule "awattaktuell"
// Ermittlung des aktuellen Preis aus wattabfrage

 when
   Time cron "52 1 0/1 1/1 * ? *" or
   Time cron "24 1 0/1 1/1 * ? *" or

   Item Preisaktualisieren changed

 then

var x = now.getHourOfDay()

sendCommand(awattar_akt, "awattar_pr"+x)

logInfo("awattaktuell", awattar_akt+"")
sendCommand(awattabfrage, "OFF")

end

Folgender Fehler:
==> /var/log/openhab2/openhab.log <==

2020-12-04 21:05:26.538 [WARN ] [rthome.model.script.actions.BusEvent] - Cannot convert 'awattar_pr21' to a command type which item 'awattar_akt' accepts: [DecimalType, QuantityType, RefreshType].

2020-12-04 21:05:26.546 [INFO ] [.smarthome.model.script.awattaktuell] - awattar_akt (Type=NumberItem, State=NULL, Label=Preis aktuell, Category=Awattar)

Wie kann ich ein Item aus einem Text und einer variable zusammensetzen?

Benutzeravatar
udo1toni
Beiträge: 13854
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Awattar

Beitrag von udo1toni »

So funktioniert das nicht.

x ist eine Integer Zahl. „Awattar_akt“ ist ein String.
Es geht also schon damit los, dass Du versuchst, einen String und eine Zahl zusammenzufügen.
Gehen wir davon aus, dass Du mit x.toString aus der Zahl einen String machst, so ist das Ergebnis der Operation aber immer noch ein String. Du versuchst also, einem Number Item einen String zuzuweisen. Selbst wenn der String ein reiner Zahlenwert wäre, ginge das schief. :)
In Wirklichkeit willst Du natürlich, dass der errechnete String als Itemname verstanden wird, und dann willst Du auch noch den Status dieses Items auslesen.

Auch das wird so nicht funktionieren.

Die korrekte Herangehensweise: Du erzeugst ein Group Item (das kann gerne vom Typ Number sein, der Typ spielt aber für die Rule keine Rolle) und ordnest alle Stundenitems diesem Group Item zu. Nehmen wir an, das Group Item heißt dann gAwattar. Es kommen nur die Stundenwerte da rein, keine anderen Items, die mit Awattar zu tun haben!

Der Zahlenwert (also 0 bis 23) sollte in diesem Fall mit einem eigenen Unterstrich im Namen abgetrennt sein, also Awattar_akt_0 bis Awattar_akt_23.

Nun kannst Du in einer Rule das korrekte Item bestimmen:

Code: Alles auswählen

val akt = gAwattar.members.filter[i|i.name.split(“_“).get(2) == (now.getHourOfDay.toString)].head
Die lokale Konstante akt steht nun für das Item mit der aktuellen Stunde im Namen. Du kannst mit akt.state auf den Inhalt des Items zugreifen und mit awattar_akt.postUpdate(akt.state) den Status direkt in das Item awattar_akt übernehmen.

.members ist eine Liste aller unmittelbaren Member des Group Items. .filter[] filtert die Liste nach den angegebenen Bedingungen.
i| bedeutet, dass i nach dem | als Substitution für jedes einzelne Item verwendet wird.
.name ist der NAme des Items.
.split(“_“) teilt den String an den Unterstrichen auf und liefert eine Liste.
.get(2) holt aus dieser Liste den 3. Teilstring (0 ist er erste Teil)
.head liefert den erster Treffer.

Gesendet von iPad mit Tapatalk
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Antworten