Benzinpreise mit Tankerkönig Binding

Für welche Projekte verwendet Ihr OpenHAB? Was habt Ihr automatisiert? Stellt eure Projekte hier vor.

Moderatoren: Cyrelian, seppy

Antworten
Benutzeravatar
alkaline
Beiträge: 173
Registriert: 20. Apr 2017 13:25

Benzinpreise mit Tankerkönig Binding

Beitrag von alkaline »

Ich lasse mir die Benzinpreise für E 10 für zwei Tankstellen in der zeit zwischen 15 Uhr bis 17 Uhr berechnen und sende bei Unterschreitung eines bestimmten Preises die günstigste Tankstelle als Info via OH Cloud auf das Handy zu.
tankerkoenig.Items:

Code: Alles auswählen

/* Gruppen */
Group gSprit		  	"Spritpreise"					(Whg)  
Group gAral				"Sprit Aral"	<aral>				(gSprit)
Group gShell			"Sprit Shell"	<shell>		  		(gSprit)
Group gTotal			"Sprit Total"	<total>		  	  	(gSprit)

Number 	NewInfoMsg_Aral 		"Neuer Preis [%s]" <neu> (gAral)
Number 	OldInfoMsg_Aral 		"Alter Preis [%s]" <alt> (gAral)
Number 	NewInfoMsg_Shell 		"Neuer Preis [%s]" <neu> (gShell)
Number 	OldInfoMsg_Shell 		"Alter Preis [%s]" <alt> (gShell)
Number 	NewInfoMsg_Total 		"Neuer Preis [%s]" <neu> (gTotal)
Number 	OldInfoMsg_Total 		"Alter Preis [%s]" <alt> (gTotal)

Number E10_Shell "E10 Shell [%.3f ]" <e10>(gShell)	{ channel="tankerkoenig:station:WebserviceName:StationName1:e10" }
Number E5_Shell "E5 Shell [%.3f ]" <e5> (gShell)	{ channel="tankerkoenig:station:WebserviceName:StationName1:e5" }

Number E10_Aral "E10 Aral [%.3f ]" <e10> (gAral)	{ channel="tankerkoenig:station:WebserviceName:StationName2:e10"}
Number E5_Aral "E5 Aral [%.3f ]" <e5> (gAral)	{ channel="tankerkoenig:station:WebserviceName:StationName2:e5"}

Number E10_Total "E10 Total [%.3f ]" <e10> (gTotal)	{ channel="tankerkoenig:station:WebserviceName:StationName3:e10"}
Number E5_Total "E5 Total [%.3f ]" <e5> (gTotal)	{ channel="tankerkoenig:station:WebserviceName:StationName3:e5"}
benzinpreise.rules:

Code: Alles auswählen

import org.joda.time.LocalTime

rule "Benzinpreise Info"
when
	Item E10_Aral received update or
	Item E10_Shell received update
then
	postUpdate(OldInfoMsg_Shell, E10_Shell.state)
    postUpdate(OldInfoMsg_Aral, E10_Aral.state)
    postUpdate(OldInfoMsg_Total, E10_Total.state)
	val LocalTime afternoon = new LocalTime(15, 0)  // 15pm every day
  	val LocalTime evening = new LocalTime(17, 0)  // 17pm every day


	if (now.toLocalTime().isAfter(afternoon) && now.toLocalTime().isBefore(evening)){ //zwischen 15 und 17 Uhr
    var double ShellNewPrice = (NewInfoMsg_Shell.state as DecimalType).doubleValue
    var double AralNewPrice = (NewInfoMsg_Aral.state as DecimalType).doubleValue
    var double ShellOldPrice = (OldInfoMsg_Shell.state as DecimalType).doubleValue
    var double AralOldPrice = (OldInfoMsg_Aral.state as DecimalType).doubleValue
   		if ((ShellOldPrice == ShellNewPrice )||(AralOldPrice == AralNewPrice )){ // Der Preis der gleiche ist
   			// do nothing
    		}
    	else if ((ShellNewPrice < 1.30) && (ShellNewPrice < AralNewPrice)){     
    	sendBroadcastNotification("Tanken? Shell: " + ShellNewPrice)
    		}
    	else if ((AralNewPrice < 1.30) && (AralNewPrice < ShellNewPrice)){     
    	sendBroadcastNotification("Tanken? Aral: " + AralNewPrice)
    		}
    	}
  end
Sitemap:
Da ich zwei Sitemaps nutze (eine für Admin Zwecke, eine für Anzeige der wichtigsten Info's) und auch, weil ich sehr stark Gruppen nutze (siehe items) zeige ich lediglich die Sprit-Hauptgruppe "gSprit" in meiner Hauptgruppe Whg an:

Code: Alles auswählen

Group item=Whg label="Alle Elemente" icon="house"
Sieht dann auf dem Handy so aus: (Neuer Preis ist noch leer, da noch nicht 15 Uhr)
sprit_1.png
sprit_2.png
Icons:
icons.zip
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Benutzeravatar
alkaline
Beiträge: 173
Registriert: 20. Apr 2017 13:25

Re: Benzinpreise mit Tankerkönig Binding

Beitrag von alkaline »

Habe das Scripting nochmals etwas umgebaut, die Tankstellen werden jetzt nach der günstigsten sortiert.
items:

Code: Alles auswählen

/* Gruppen */
Group gSprit		  	"Spritpreise"					(Whg)  
Group gAral				"Sprit Aral"	<aral>				(gSprit)
Group gShell			"Sprit Shell"	<shell>		  		(gSprit)

Number E10_Shell "E10 Shell [%.2f ]" <e10>(gShell)	{ channel="tankerkoenig:station:WebserviceName:StationName1:e10" }
Number E5_Shell "E5 Shell [%.2f ]" <e5> (gShell)	{ channel="tankerkoenig:station:WebserviceName:StationName1:e5" }

Number E10_Aral "E10 Aral [%.2f ]" <e10> (gAral)	{ channel="tankerkoenig:station:WebserviceName:StationName2:e10"}
Number E5_Aral "E5 Aral [%.2f ]" <e5> (gAral)	{ channel="tankerkoenig:station:WebserviceName:StationName2:e5"}

String    FuelStation1    "Billigste Tankstelle [%s]" <tankstelle>	(gSprit)
String    FuelStation2    "Zweitbeste [%s]" 	<tankstelle> 

String OldBest_Station	"Alte beste Tankstelle [%s]" <alt> (gSprit)
String NewBest_Station	"Neue beste Tankstelle [%s]" <neu> (gSprit)
rules:

Code: Alles auswählen

import org.joda.time.LocalTime
import java.util.ArrayList
import java.util.Map
import java.util.HashMap
import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.locks.Lock

var Map <String, Double> FuelPricesMap = new HashMap<String, Double>()    // Stationsnamen und Preise für den Kraftstoff
var ArrayList<StringItem> FuelPriceItems =  new ArrayList<StringItem>()

val String filename = "benzin.rules"

rule "Benzinpreise Info"
when
	Item FuelPricesMap received update
then
	val LocalTime afternoon = new LocalTime(15, 0)  // 15pm every day
  	val LocalTime evening = new LocalTime(19, 0)  // 19pm every day
  	
	if (now.toLocalTime().isAfter(afternoon) && now.toLocalTime().isBefore(evening)){ //zwischen 15 und 19 Uhr
		if (FuelStation1.state.toString.contains ("1,29")) {
			sendTelegram("Marcus", "Günstiger Sprit: " + FuelStation1)
			postUpdate(OldBest_Station, FuelStation1.state)
			}
			else if (FuelStation1.state.toString.contains ("1,28")) {
    		sendTelegram("Marcus", "Günstiger Sprit: " + FuelStation1) // Erste Tankstelle im Array = günstigste Tankstelle
	   		postUpdate(OldBest_Station, FuelStation1.state)
	   		}
	   		else if (FuelStation1.state.toString.contains ("1,27")) {
    		sendTelegram("Marcus", "Günstiger Sprit: " + FuelStation1) // Erste Tankstelle im Array = günstigste Tankstelle
	   		postUpdate(OldBest_Station, FuelStation1.state)
	   		}
	   		else if (FuelStation1.state.toString.contains ("0,00")) {
    		postUpdate(FuelStation1, "Geschlossen")
	   		}
	   		else if (FuelStation2.state.toString.contains ("0,00")) {
    		postUpdate(FuelStation1, "Geschlossen")
	   		}
	  }
  end

  
rule "Benzinpreise Update"
when
	Item E10_Aral received update or
	Item E10_Shell received update
then
    
        var Lock lock = new ReentrantLock()
       
        var i = 0
    
        lock.lock()
        
         logInfo(filename,"Benzinpreise -> Update der Werte")
        
        // Zuweisung der Display Items in das Array
        FuelPriceItems.add(0, FuelStation1)
        FuelPriceItems.add(1, FuelStation2)


        // aktuelle Preise aus den Items in die Map übernehmen    
        FuelPricesMap.put("Shell",    (E10_Shell.state as DecimalType).doubleValue())
        FuelPricesMap.put("Aral",    (E10_Aral.state as DecimalType).doubleValue())

        
        // Map nach Preisen sortieren und die Werte dann dem Anzeigearray zuweisen
        for (PriceEntry : FuelPricesMap.entrySet.sortBy[value]) {
            FuelPriceItems.get(i).postUpdate(String::format("%s - %.2f €", PriceEntry.getKey(), PriceEntry.getValue()))
             i = i+1
        }
	        lock.unlock()
			postUpdate(NewBest_Station, FuelStation1.state)
end


Benutzeravatar
OliverCJ
Beiträge: 404
Registriert: 29. Aug 2017 12:41
Answers: 3
Wohnort: Bergisch Gladbach

Re: Benzinpreise mit Tankerkönig Binding

Beitrag von OliverCJ »

Guten Morgen,

auch wenn der Thread schon ein wenig älter ist... Vielen Dank für die Denkanstösse und die rules! Habe mich gestern ein wenig damit beschäftigt und das Ganze versucht, mal auf meine Gegebenheiten hier in der Nähe von Köln anzupassen.

Ich habe drei Tankstellen im Ort, die ich gerne vergleichen möchte und zusätzlich eine in der Nähe der Arbeitsstelle. Die "normale" Darstellung der Tanken auf der sitemap funktioniert auch, bekomme von allen die Preise angezeigt.

Im nächsten Schritt, wollte ich zumindest von den ersten dreien die Preise vergleichen und die beiden günstigsten ebenfalls ausgeben lassen. Dafür habe ich deine zweite rule angepasst. Das funktioniert leider nicht so, wie ich mir das vorstelle, sprich es wird eben nicht immer die günstigste in das entsprechende item geschrieben. Im Log bekomme ich auch eine Meldung dazu.

Items:

Code: Alles auswählen

Number TK_Stat1_E10
    "E10 [%.3f €]"
    <e10>
    (gTankstellenHEM)
    {channel="tankerkoenig:station:WebserviceName:StationName1:e10"}
    
Number TK_Stat2_E10
    "E10 [%.3f €]"
    <e10>
    (gTankstellenESSO)
    {channel="tankerkoenig:station:WebserviceName:StationName2:e10"}
    
Number TK_Stat3_E10
    "E10 [%.3f €]"
    <e10>
    (gTankstellenARAL)
    {channel="tankerkoenig:station:WebserviceName:StationName3:e10"}
    
String TK_Tankstelle_1
    "Günstigste Tankstelle [%s]"
    <tankstelle>
    (gTankstellen)

String TK_Tankstelle_2
    "Zweitbeste [%s]"
    <tankstelle>
    (gTankstellen)

String OldBest_Station
    "Alte beste Tankstelle [%s]"
    <alt>
    (gTankstellen)

String NewBest_Station
    "Neue beste Tankstelle [%s]"
    <neu>
    (gTankstellen)
Edit: Habe noch die letzten 4 Items ergänzt, wobei ich OldBestStation und NewBestStation eigentlich nicht wirklich benötige. Da sie aber in der rule vorkommen.... ;-)

Rule:

Code: Alles auswählen

import org.joda.time.LocalTime
import java.util.ArrayList
import java.util.Map
import java.util.HashMap
import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.locks.Lock

var Map <String, Double> FuelPricesMap = new HashMap<String, Double>()    //Stationsnamen und Preise für den Kraftstoff
var ArrayList<StringItem> "BenFuelPriceItems =  new ArrayList<StringItem>()

val String filename = "Tankerkönig"

rule "Benzinpreise Update"

when
	Item TK_Stat1_E10 received update or
	Item TK_Stat2_E10 received update or
	Item TK_Stat3_E10 received update or
        Item Dummy1 changed
then
    
        var Lock lock = new ReentrantLock()
       
        var i = 0
    
        lock.lock()
        
        logInfo(filename,"Benzinpreise -> Update der Werte")
        
        // Zuweisung der Display Items in das Array
        FuelPriceItems.add(0, TK_Tankstelle_1)
        FuelPriceItems.add(1, TK_Tankstelle_2)


        // aktuelle Preise aus den Items in die Map übernehmen    
        FuelPricesMap.put("HEM", (TK_Stat1_E10.state as DecimalType).doubleValue())
        FuelPricesMap.put("ESSO", (TK_Stat2_E10.state as DecimalType).doubleValue())
        FuelPricesMap.put("ARAL", (TK_Stat3_E10.state as DecimalType).doubleValue())
        
        // Map nach Preisen sortieren und die Werte dann dem Anzeigearray zuweisen
        for (PriceEntry : FuelPricesMap.entrySet.sortBy[value]) {
            FuelPriceItems.get(i).postUpdate(String::format("%s: %.3f €", PriceEntry.getKey(), PriceEntry.getValue()))
             i = i+1
        }
	        lock.unlock()
			postUpdate(NewBest_Station, TK_Tankstelle_1.state)
end
Und die Meldung im Log dazu (mit der ich ehrlich gesagt nicht viel anfangen kann):

Code: Alles auswählen

2020-07-23 06:26:39.114 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'Benzinpreise Update': Index: 2, Size: 2
Wobei die LogInfo "Benzinpreise -> Update der Werte" noch im Log auftaucht...

Der Unterschied liegt natürlich darin, dass ich drei Werte aus den Items in die Map übernehmen möchte. Allerdings finde ich in der rule keine Stelle, die das auf zwei begrenzen würde.... Oder wo ist mein Denkfehler?

Danke und Grüße
Oliver

PS. zu der ersten rule mit den Telegram-Messages hätte ich auch noch ne Frage, aber immer schön nacheinander ;-)

_______________________________________________
Homematic IP Komponenten an CCU 3 (wächst stetig)
Innogy Smarthome System (verabschiedet sich langsam)
Philips Hue Beleuchtung
Fritz!Box
VU+ Solo SAT-Receiver
2 Squeezeboxen
Denon Heos System

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

Re: Benzinpreise mit Tankerkönig Binding

Beitrag von udo1toni »

Warum überhaupt? ;) ok, die Frage kann man nun missverstehen...

Mal andersrum:

Ein Lock soll verhindern, dass Code doppelt ausgeführt wird (also mehrmals zeitgleich)
Eine Variable ist immer und ausnahmslos nur dort gültig, wo sie definiert wurde.
Wenn man also innerhalb einer Rule ein Lock definiert, dann ist das auch nur innerhalb dieser Rule gültig. Wird die Rule zeitgleich ein zweites Mal gestartet, so hat diese zweite Instanz keine Kenntnis von diesem Lock und legt einfach einen eigenen Laock an - mit identischem Namen, aber in einem eigenen Namespace!!!

Ein Lock ist also nur als globale Variable sinnvoll.

Aber weiter: Wenn man ein Lock verwenden will, muss man das auch korrekt tun. einfach lock.lock und lock.unlock führt nur zu Exceptions, gerade das will man ja vermeiden. Der Code müsste also in einen try-Block.

Die Idee der Sortierung ist gut, aber die Umsetzung wird so nicht (fehlerfrei) funktionieren.
Grundsätzlich sollte man aber sowieso versuchen, locks zu vermeiden, die machen in openHAB nur Ärger :)
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

Benutzeravatar
OliverCJ
Beiträge: 404
Registriert: 29. Aug 2017 12:41
Answers: 3
Wohnort: Bergisch Gladbach

Re: Benzinpreise mit Tankerkönig Binding

Beitrag von OliverCJ »

Hallo Udo,

tja, warum überhaupt? Ehrlich gesagt: Keine Ahnung! :?

Ich hatte ja geschrieben, dass ich die Idee von alkaline ganz interessant fand und sie mal ausprobieren wollte (eigentlich nur, weil mir gestern aufgefallen war, dass es meine Spritpreis-App nicht mehr gibt). Da er das Ganze als Projekt hier vor ca 3 Jahren eingestellt hatte und es keine weiteren Ergänzungen mehr gab, war ich erstmal davon ausgegangen, dass die rule so funktioniert. Ich habe sie dann halt nur ein wenig angepasst.

Das lock hat mir bis gerade nicht viel gesagt (Daher Danke für Deine Erläuterungen) und ich habe es einfach mit kopiert. Den Rest der rule meine ich aber zu verstehen...

Wenn ich Dich nun richtig verstehe, sollte ich das Lock also entweder außerhalb der rule definieren oder besser noch, ganz weg lassen. Dann aber einen try-Block verwenden... ähm... ich habe auf die Schnelle das hier gefunden: https://javabeginners.de/Exceptions/Die ... eisung.php
Ist das was, wo ich mich dran lang hangeln kann oder hättest Du einen Tipp für mich?

_______________________________________________
Homematic IP Komponenten an CCU 3 (wächst stetig)
Innogy Smarthome System (verabschiedet sich langsam)
Philips Hue Beleuchtung
Fritz!Box
VU+ Solo SAT-Receiver
2 Squeezeboxen
Denon Heos System

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

Re: Benzinpreise mit Tankerkönig Binding

Beitrag von udo1toni »

Ja, das ist halt die Grundsatz Erklärung. Schau mal hier bzw. Im engliscjen forum nach rules, die .lock und try enthalten.

Im Zweifel ist das lock.lock aber unnötig, wenn man den Code etwas anpasst.

Gesendet von meinem SM-G973F mit Tapatalk

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

seppel07
Beiträge: 8
Registriert: 31. Jul 2020 20:09

Re: Benzinpreise mit Tankerkönig Binding

Beitrag von seppel07 »

Sehr interessant und eine coole Idee. Der Code sieht gut aus.

Antworten