Examples of HABPanel Solutions

Hi Robert, sure, you can have all the snippets you want :smile:
I will explain the garbage stuff as it’s the more cpmplex one. I imported the dates to a google calendar and read them via caldavPersonal binding. In my case it’s called “Muellkalender”.
First, I only worked with a filter for each item, but then they are not sorted by date in my widget. If I just display the next 4 events, I have the ones with a weekly plan double and maybe “paper” with a monthly plan not shown in the list. Both is not what I want, I want each kind of garbage displaded once, but sorted by date. That’s why I introduced a “second layer” of items:

/* Abfall-Kalender */
DateTime Restmuell "RestmĂŒll [%1$td.%1$tm.%1$tY]" <calendar> (gAbfall) { caldavPersonal="calendar:Muellkalender type:EVENT eventNr:1 value:START filter-name:'Restmuelltonne'" }
DateTime Biomuell "BiomĂŒll [%1$td.%1$tm.%1$tY]" <calendar> (gAbfall) { caldavPersonal="calendar:Muellkalender type:EVENT eventNr:1 value:START filter-name:'Biotonne'" }
DateTime Papiermuell "Papier [%1$td.%1$tm.%1$tY]" <calendar> (gAbfall) { caldavPersonal="calendar:Muellkalender type:EVENT eventNr:1 value:START filter-name:'Papiertonne'" }
DateTime RaWeg "RaWeg [%1$td.%1$tm.%1$tY]" <calendar> (gAbfall) { caldavPersonal="calendar:Muellkalender type:EVENT eventNr:1 value:START filter-name:'RaWeg'" }
DateTime Abfall_1_Datum "Abfall 1 Datum [%1$td.%1$tm.%1$tY]" <calendar> (gAbfall)
DateTime Abfall_2_Datum "Abfall 2 Datum [%1$td.%1$tm.%1$tY]" <calendar> (gAbfall)
DateTime Abfall_3_Datum "Abfall 3 Datum [%1$td.%1$tm.%1$tY]" <calendar> (gAbfall)
DateTime Abfall_4_Datum "Abfall 4 Datum [%1$td.%1$tm.%1$tY]" <calendar> (gAbfall)
String Abfall_1_Art "Abfall 1 Art [%s]" (gAbfall)
String Abfall_2_Art "Abfall 2 Art [%s]" (gAbfall)
String Abfall_3_Art "Abfall 3 Art [%s]" (gAbfall)
String Abfall_4_Art "Abfall 4 Art [%s]" (gAbfall)
String RestmuellTage "RestmĂŒll [%s]" (gAbfall)
String BiomuellTage "BiomĂŒll [%s]" (gAbfall)
String PapiermuellTage "Papier [%s]" (gAbfall)
String RaWegTage "RaWeg [%s]" (gAbfall)
String Abfall_1_Tage "Abfall 1 Tage [%s]" (gAbfall)
String Abfall_2_Tage "Abfall 2 Tage [%s]" (gAbfall)
String Abfall_3_Tage "Abfall 3 Tage [%s]" (gAbfall)
String Abfall_4_Tage "Abfall 4 Tage [%s]" (gAbfall)
Switch Abfall_Steht_An "Abfall steht an" (gAbfall)

As you see, the last one is a switch (“Abfall steht an” means “garbage is pending”). I use this for the confirmation.
Of course, I need some rules. The first one is for calculating the days from today to the date (if it’s today it shows “heute”, if it’s tomorrow it shows “morgen”, otherwise the number of days).
Second one is my sorting algorithm - It’s maybe not the smartest algorithm, but it’s the one I think I understand :see_no_evil: :grinning:
3rd rule is switching the switch on at 17:00 if garbage is tomorrow (called “morgen”). This is set to off by a click on the icon in the widget.
4th rule is informing me, if switch is still on at 20:30.
5th rule is ultimative escalation level :wink: informing my wife and me again. Never used up to now :stuck_out_tongue_winking_eye:

rule "Tage bis Abfall berechnen"
when 
	Time cron "0 5 * 1/1 * ? *" or
	Item Restmuell changed or
	Item Biomuell changed or
	Item Papiermuell changed or
	Item RaWeg changed or
	Item DelayedStartup changed from OFF to ON
then
	logInfo("all.rules", "Tage bis Abfall berechnen")
	//Restmuell
	val DateTime varRestmuellDatum = new DateTime((Restmuell.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli).withTimeAtStartOfDay
	val Long varRestmuellDiff = Math::round((varRestmuellDatum.millis - now.withTimeAtStartOfDay.millis) / (86400000.0))
	if ( varRestmuellDiff == 0 ) {
		RestmuellTage.postUpdate("heute")
	} else if ( varRestmuellDiff == 1 ) {
		RestmuellTage.postUpdate("morgen")
	} else {
		RestmuellTage.postUpdate(String::format("(%1$d T.)", varRestmuellDiff))
	}
	//Biomuell
	val DateTime varBiomuellDatum = new DateTime((Biomuell.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli).withTimeAtStartOfDay
	val Long varBiomuellDiff = Math::round((varBiomuellDatum.millis - now.withTimeAtStartOfDay.millis) / (86400000.0))
	if ( varBiomuellDiff == 0 ) {
		BiomuellTage.postUpdate("heute")
	} else if ( varBiomuellDiff == 1 ) {
		BiomuellTage.postUpdate("morgen")
	} else {
		BiomuellTage.postUpdate(String::format("(%1$d T.)", varBiomuellDiff))
	}
	//Papiermuell
	val DateTime varPapiermuellDatum = new DateTime((Papiermuell.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli).withTimeAtStartOfDay
	val Long varPapiermuellDiff = Math::round((varPapiermuellDatum.millis - now.withTimeAtStartOfDay.millis) / (86400000.0))
	if ( varPapiermuellDiff == 0 ) {
		PapiermuellTage.postUpdate("heute")
	} else if ( varPapiermuellDiff == 1 ) {
		PapiermuellTage.postUpdate("morgen")
	} else {
		PapiermuellTage.postUpdate(String::format("(%1$d T.)", varPapiermuellDiff))
	}
	//RaWeg
	val DateTime varRaWegDatum = new DateTime((RaWeg.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli).withTimeAtStartOfDay
	val Long varRaWegDiff = Math::round((varRaWegDatum.millis - now.withTimeAtStartOfDay.millis) / (86400000.0))
	if ( varRaWegDiff == 0 ) {
		RaWegTage.postUpdate("heute")
	} else if ( varRaWegDiff == 1 ) {
		RaWegTage.postUpdate("morgen")
	} else {
		RaWegTage.postUpdate(String::format("(%1$d T.)", varRaWegDiff))
	}	
end

rule "Abfalltermine sortieren"
when
	Item Restmuell received update or
	Item Biomuell received update or
	Item Papiermuell received update or
	Item RaWeg received update or
	Item RestmuellTage changed or
	Item PapiermuellTage changed or
	Item BiomuellTage changed or
	Item RaWegTage changed or
	//Time cron "0 8 0 1/1 * ? *" or
	Item DelayedStartup changed from OFF to ON
then
	Thread::sleep(3000)
	var DateTime varTempDatum
	var DateTime varAbfall1Datum = new DateTime((Restmuell.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)
	var DateTime varAbfall2Datum = new DateTime((Biomuell.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)
	var DateTime varAbfall3Datum = new DateTime((Papiermuell.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)
	var DateTime varAbfall4Datum = new DateTime((RaWeg.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)
	var String varTempArt
	var String varAbfall1Art = "Restmuell"
	var String varAbfall2Art = "Biomuell"
	var String varAbfall3Art = "Papiermuell"
	var String varAbfall4Art = "RaWeg"
	var String varTempTage
	var String varAbfall1Tage = RestmuellTage.state.toString
	var String varAbfall2Tage = BiomuellTage.state.toString
	var String varAbfall3Tage = PapiermuellTage.state.toString
	var String varAbfall4Tage = RaWegTage.state.toString
	var i = 1
	while ((i=i+1) < 6) {
		if (varAbfall1Datum > varAbfall2Datum) {
			varTempDatum = varAbfall1Datum
			varAbfall1Datum = varAbfall2Datum
			varAbfall2Datum = varTempDatum
			varTempArt = varAbfall1Art
			varAbfall1Art = varAbfall2Art
			varAbfall2Art = varTempArt
			varTempTage = varAbfall1Tage
			varAbfall1Tage = varAbfall2Tage
			varAbfall2Tage = varTempTage
			if (varAbfall2Datum > varAbfall3Datum) {
				varTempDatum = varAbfall2Datum
				varAbfall2Datum = varAbfall3Datum
				varAbfall3Datum = varTempDatum
				varTempArt = varAbfall2Art
				varAbfall2Art = varAbfall3Art
				varAbfall3Art = varTempArt
				varTempTage = varAbfall2Tage
				varAbfall2Tage = varAbfall3Tage
				varAbfall3Tage = varTempTage
				if (varAbfall3Datum > varAbfall4Datum) {
					varTempDatum = varAbfall3Datum
					varAbfall3Datum = varAbfall4Datum
					varAbfall4Datum = varTempDatum
					varTempArt = varAbfall3Art
					varAbfall3Art = varAbfall4Art
					varAbfall4Art = varTempArt
					varTempTage = varAbfall3Tage
					varAbfall3Tage = varAbfall4Tage
					varAbfall4Tage = varTempTage
				}
			}
		}
		if (varAbfall2Datum > varAbfall3Datum) {
				varTempDatum = varAbfall2Datum
				varAbfall2Datum = varAbfall3Datum
				varAbfall3Datum = varTempDatum
				varTempArt = varAbfall2Art
				varAbfall2Art = varAbfall3Art
				varAbfall3Art = varTempArt
				varTempTage = varAbfall2Tage
				varAbfall2Tage = varAbfall3Tage
				varAbfall3Tage = varTempTage
				if (varAbfall3Datum > varAbfall4Datum) {
					varTempDatum = varAbfall3Datum
					varAbfall3Datum = varAbfall4Datum
					varAbfall4Datum = varTempDatum
					varTempArt = varAbfall3Art
					varAbfall3Art = varAbfall4Art
					varAbfall4Art = varTempArt
					varTempTage = varAbfall3Tage
					varAbfall3Tage = varAbfall4Tage
					varAbfall4Tage = varTempTage
				}
			}
		if (varAbfall3Datum > varAbfall4Datum) {
					varTempDatum = varAbfall3Datum
					varAbfall3Datum = varAbfall4Datum
					varAbfall4Datum = varTempDatum
					varTempArt = varAbfall3Art
					varAbfall3Art = varAbfall4Art
					varAbfall4Art = varTempArt
					varTempTage = varAbfall3Tage
					varAbfall3Tage = varAbfall4Tage
					varAbfall4Tage = varTempTage
				}
	}
	Abfall_1_Datum.postUpdate(varAbfall1Datum.toString)
	Abfall_2_Datum.postUpdate(varAbfall2Datum.toString)
	Abfall_3_Datum.postUpdate(varAbfall3Datum.toString)
	Abfall_4_Datum.postUpdate(varAbfall4Datum.toString)
	Abfall_1_Art.postUpdate(varAbfall1Art)
	Abfall_2_Art.postUpdate(varAbfall2Art)
	Abfall_3_Art.postUpdate(varAbfall3Art)
	Abfall_4_Art.postUpdate(varAbfall4Art)
	Abfall_1_Tage.postUpdate(varAbfall1Tage)
	Abfall_2_Tage.postUpdate(varAbfall2Tage)
	Abfall_3_Tage.postUpdate(varAbfall3Tage)
	Abfall_4_Tage.postUpdate(varAbfall4Tage)
end

rule "Abfall steht an - Blinkeding"
when
	Time cron "0 0 17 1/1 * ? *"
then
	if (Abfall_1_Tage.state.toString == "morgen") {
	Abfall_Steht_An.postUpdate(ON)
	}
end

rule "Abfall steht an - Informiere Jochen"
when
	Time cron "0 30 20 1/1 * ? *"
then
	if ((Abfall_Steht_An.state == ON) && (Abfall_1_Art != "RaWeg")) {
	sendTelegram("haus_an_mich_bot", "%s solltest du noch raus stellen", Abfall_1_Art.state.toString)
	}
end

rule "Abfall steht an - Informiere -Frau- und Jochen"
when
	Time cron "0 30 21 1/1 * ? *"
then
	if ((Abfall_Steht_An.state == ON) && (Abfall_1_Art != "RaWeg")) {
	sendTelegram("haus_an_mich_bot", "Oh je, jetzt gibt's Ärger... %s steht wohl immer noch nicht draußen und -Frau- tritt dir gleich in den Hintern!", Abfall_1_Art.state.toString)
	sendTelegram("haus_an_frau_bot", "%s steht wohl immer noch nicht draußen... So ein Schlumpf, der Jochen", Abfall_1_Art.state.toString)
	}
end

An finally, the sorted items are displayed in a widget, with the blinking icon and confirmation click:
abfall.widget.json (8.8 KB)
It’s working, but there still is some work to do, reducing the repeating style stuff by better usage of css e.g. But that’s cosmetic stuff :smiley:

Have fun :sunglasses:

11 Likes