Extract specific events from ics and save them in order

Hello all,

Following an advice I got I’m posting here a rule script with which I have challenges.

Purpose
I want to make sure that I don’t miss some municipal dates: We have several different types of trash and the city switches dates a couple times a year. I created a habpanel widget to show the extracted dates and highlight them when they’re due tomorrow.
The approach below should work but I’m trying to improve both my understanding of openhab rules as well as learn what better approaches exist.

What I already do
The script pulls an ics from a web server, searches for the appropriate strings within them and extracts the dates for the four types I’m currently handling. Those dates are written in appropriate items and then pulled in a hardcoded order. The items look like:

DateTime Bioabfall "%1$tm %1$te,%1$tY" 

This results in a list like this:

  • Trash 1: 5th of May 2019
  • Trash 2: 22nd of Feb 2019
  • Trash 3: 27th of Feb 2019
  • Trash 4: 8th of May 2019

This list gets populated on boot and once a day - this part works completely fine.

What I would LIKE to do
Instead of having a hardcoded order of elements I would like them to be ordered by date.
What I tried to achieve this is expand the items to

String trash1_label
DateTime trash1_date

etc. Then I wanted to populate them with trash1 having the next upcoming date and so forth.
My current approach is to put the dates in a HashMap and then create a sortedList with a manually implemented insertSort. But this seems so … wrong :smiley:
I’m looking now for advice or ideas or even completely different approaches to achieve the same thing. The only two aspects I can’t change:

  • The source is an ics
  • The target is a list of elements sorted by an associated date

The script I currently have (including everything - it runs like this and works.)

import java.text.SimpleDateFormat
import java.util.HashMap

rule "<Test>"
when
	Item test received update ON or
	Time cron "	0 0 4 1/1 * ? *" or
	System started

then
	var ft = new SimpleDateFormat ("yyyyMMdd")
	var http = sendHttpGetRequest("http://www.awsh.de/api_v2/collection_dates/1/ort/553/strasse/290/hausnummern/0/abfallarten/R02-B02-D02-P04-W0/kalender.ics")
	val lines = http.split("\r?\n")
	
	// the strings which are used within the ics.
	val trashIdentifier = newArrayList(
		"SUMMARY:Restabfall 40L-240L(2-wöchentlich)",
		"SUMMARY:Gelber Sack(2-wöchentlich)",
		"SUMMARY:Papiertonne(monatlich)",
		"SUMMARY:Bioabfall(2-wöchentlich)"
	)

       //human readable identifier used as item names
	val trashType = newArrayList(
		"Restabfall",
		"GelberSack",
		"Papierabfall",
		"Bioabfall"
	)

	var HashMap<String, DateTime> trashMap = new HashMap<String, DateTime>();

	for (var i = 0; i < trashIdentifier.size(); i++) {
		var dateRaw = lines.get(lines.indexOf(trashIdentifier.get(i))-3)
		var date = dateRaw.substring(dateRaw.length()-8)

		trashMap.put(trashType.get(i), new DateTime(ft.parse(date)))

                //original, working part: This gives me an unsorted list of items with the correct date.
//		postUpdate("trashName"+i, trashType.get(i))
//		postUpdate("trashDate"+i,  new DateTime(ft.parse(date)).toString)
//		postUpdate(trashType.get(i), new DateTime(ft.parse(date)).toString)
	}

	//proof that the hashmap is populated correctly. 
        logInfo("test2: ", ""+trashMap)


	var sortedList = newArrayList();

        //initialize with first item, then iterate over the rest and go over an if/else tree to insert them.
	sortedList.add(0, trashType.get(0).toString)
	for (var i = 1; i < trashIdentifier.size(); i++)
	{
		if (trashMap.get(trashType.get(i-1)).isBefore(trashMap.get(trashType.get(i)))) {
			logInfo("asd:_ ", "__ " + trashMap.get(trashType.get(i)).toString)
	       }
	}

end

Thanks for any comments, hints, critique and pointers!

What I am not fully understanding is why you want to sort them by date. What do you intend to gain from that?
If you just would want to find the one that is due tomorrow, as simple if-else or switch case will suffice.

I want to always show the upcoming events:

  • Type C: Tomorrow
  • Type D: 17th of April
  • Type A: 25th of April
  • Type B: 28th of April

And then the if-else comes into play for comparing if it’s below a threshold for highlighting purposes.
In addition, I want other rules to have access to a sorted list of dates (think: “LED which has a different color depending on what is up next”).

Thank you for taking your time for me! :slight_smile:

To me it merely sounds like an instance of the XY problem. There’s other approaches than sorting (as @RolfV points out, too), there’s little benefit in listing future events except the next one, and googling reveals there’s also others who have implemented their ‘Abfallkalender’ in a different way.

Or on a meta level: being flexible is a key to success in Home Automation.
Changing expectations just a little to match your state of knowledge is often the better idea than to insist on going after a specific solution.


https://klenzel.de/5444

Thanks, @mstormi for those links! I have a long backlog of things to learn :slight_smile:
I’ll take the meta-hint to heart as well on the implementation side.
Where I don’t want to make compromises though is the end user experience - that’s where I’m always starting (“How should this thing behave”) - I’ll try to become more flexible on how to get there though!

For example the Eidelsburger-Link uses exactly my approach - but they already have a calendar which only includes the data they need (unlike the one published by my area), while the klenzel-Link uses the transfomers you already hinted me towards - which I’ll have a look at :slight_smile:

They’re giving me some ideas how to tackle this question in a different way though. I’ll give it a shot to build the same solution two or three times completely different, just to broaden my horizon a bit.

Again, all the inputs are highly appreciated, especially the critical voices - I’m learning more in a day than in the last two months trying to figure out shit on my own!

Cheers,
Georg

If you want a list like that, I would make use of a Treemap , using the (properly formatted!) dates as keys and the types as values (or actually maybe already the fully formatted string “Type x: yth of Z”.
Subsequently you can iterate over that map to get your output.

I’ve used something like that to answer another topic related to sorting (in a slightly different context), see here:

1 Like

@RolfV should we ever meet I’ll buy you a beer, tea or other drink of your choice - you’ve given me a shitload to learn and read - and it’s exciting :slight_smile:

Thanks a ton!