Genau, ich habe einfach ein Script geschrieben das alles für mich macht. Es ist natürlich auf meine Umgebung zugeschnitten, aber ich setze es mal hier rein.
Hier das Skript (ist original fürs WebFront entstanden, macht jetzt aber auch Tile und openHASP) …
<?php
declare(strict_types=1);
################################################################################
# Script: Calendar.SortByDate.ips.php
# Version: 2.0.20230806
# Author: Heiko Wilknitz
#
# Sortiert nach Datum die Links für Entsorgungstermine
#
# ----------------------------------- ID´s -------------------------------------
#
# Nicht das Modul selbst sondern nur der Visualisierungs-'Vater'
$parentID = 18852;
#
# Variablen für openHASP
$wiID = 23198;
$wnID = 14562;
$wtID = 53047;
$wmID = 12125;
#
# Übersetzungstabelle
$TRANS_TABLE = array(
'Monday' => 'Montag',
'Tuesday' => 'Dienstag',
'Wednesday' => 'Mittwoch',
'Thursday' => 'Donnerstag',
'Friday' => 'Freitag',
'Saturday' => 'Samstag',
'Sunday' => 'Sonntag',
'Mon' => 'Mo',
'Tue' => 'Di',
'Wed' => 'Mi',
'Thu' => 'Do',
'Fri' => 'Fr',
'Sat' => 'Sa',
'Sun' => 'So',
'January' => 'Januar',
'February' => 'Februar',
'March' => 'März',
'May' => 'Mai',
'June' => 'Juni',
'July' => 'Juli',
'October' => 'Oktober',
'December' => 'Dezember',
);
$WASTE_TYPES = [
'blue' => ['Color'=> '#11A0F3', 'Match'=> 'papier|pappe|zeitung'],
'green' => ['Color'=> '#58A906', 'Match'=> 'bio|grün|garten|baum|schnittgut'],
'yellow'=> ['Color'=> '#FFC107', 'Match'=> 'gelb|plaste|pvc'],
'red' => ['Color'=> '#F35A2C', 'Match'=> 'schadstoff|sonder|sperr|problem'],
'gray' => ['Color'=> '#999A9C', 'Match'=> 'rest']
];
$WASTE_ICON_TEXT = '%s \uEA7A# ';
#
################################################################################
#
# Requires include of the global function script via autoload (__autoload.php)
# or direct in the script (uncomment next line)!
# require_once(IPS_GetKernelDir()."scripts".DIRECTORY_SEPARATOR.'System.Functions.ips.php');
# You can download it from here https://github.com/wilkware/ips-scripts
#
defined('WWX_FUNCTIONS') || die('Global function library not available!');
// String Params
$lookahead = false;
// get all Links
$childs = IPS_GetChildrenIDs($parentID);
// read the data
$table = array();
foreach($childs as $child) {
$link = IPS_GetLink($child);
$pos = IPS_GetObject($link['TargetID'])['ObjectPosition'];
$name = IPS_GetName($child);
$type = RecognizeWaste($name, $WASTE_TYPES);
$date = GetValue($link['TargetID']);
$days = CalcDaysToDate($date);
$table[] = array('date' => $date, 'link' => $child, 'pos' => $pos, 'name' => $name, 'type' => $type, 'days' => $days);
}
// sort by date
usort($table, 'SortByDate');
//var_dump($table);
$names = [];
// set the sorted positions and what happend tommorow?
for ($i = 0; $i < count($table); $i++) {
if (strtotime($table[$i]['date']) === strtotime('tomorrow')) {
$names[] = $table[$i]['name'];
}
IPS_SetPosition($table[$i]['link'], $i);
}
// tommorow overrule today
if (!empty($names)) {
IPS_RunScriptWaitEx(34026 , ['action' => 'add', 'text' => 'Morgen ' . implode(' und ', $names) . '!', 'expires' => time() + 86400, 'removable' => true, 'type' => 3, 'image' => 'Recycling']);
}
# ------------------------------ openHASP -------------------------------------
// look ahead update
$offset = 0;
if ($lookahead) {
foreach ($table as $row) {
if (strtotime($row['date']) == strtotime('today')) {
$offset++;
} else {
break;
}
}
}
// count how many pickups as next
$pickups = 0;
$pudays = $table[$offset]['days'];
foreach ($table as $pk => $row) {
if ($pk < $offset) {
continue;
}
if ($row['days'] == $pudays) {
$pickups++;
} else {
break;
}
}
// build icons & text
$wi = '';
$wn = '';
for ($i = $offset; $i < ($offset + $pickups); $i++) {
$wi .= sprintf($WASTE_ICON_TEXT, $WASTE_TYPES[$table[$i]['type']]['Color']);
$wn .= $table[$i]['name'];
if ($i != ($offset + $pickups - 1)) {
$wn .= ', ';
}
}
// build html texts
$next = '';
// show today only if no date tommorow
if (strtotime($table[$offset]['date']) === strtotime('today')) {
$next = 'Heute';
}
// tommorow overrule today
if (strtotime($table[$offset]['date']) === strtotime('tomorrow')) {
$next = 'Morgen';
}
// generate widget for tile visu
if ($next == '') {
$next = date('d.m.', strtotime($table[$offset]['date']));
$next = strtr(date('D', strtotime($table[$offset]['date'])), $TRANS_TABLE) . '. ' . $next;
}
$wt = '';
// date infos
$days = $table[$offset]['days'];
$day = strtotime($table[$offset]['date']);
$wd = strtr(date('l', $day),$TRANS_TABLE);
$sd = date('d.m.', $day);
if ($days > 1) {
$wt = "Nächste Abholung:\nin $days Tagen\nam $wd $sd";
} else {
$wt = "Nächste Abholung:\n$next\nam $wd $sd";
}
SetValue($wiID, $wi);
SetValue($wnID, $wn);
SetValue($wtID, $wt);
SetValue($wmID, $next == 'Morgen');
# ------------------------------ Functions -------------------------------------
function SortByDate( $a, $b) {
return strtotime($a['date']) - strtotime($b['date']);
}
function CalcDaysToDate($startDate, $endDate = null)
{
if (empty($endDate)) $endDate = date('Y-m-d');
return intval(round(abs(strtotime($endDate) - strtotime($startDate)) / (60 * 60 * 24)));
}
function RecognizeWaste($name, $matches)
{
foreach ($matches as $type => $match) {
$pm = '/(' . $match['Match'] . ')/i';
if (preg_match($pm, $name)) {
return $type;
}
}
// Rest or all others
return 'gray';
}
################################################################################
Hier die IDs, welche im Skript verwendet werden …
(Variablen für openHASP)
(parentID Variable)
Die $parentID zeigt auf das WebFront Dummy Modul (halt historisch gewachsen)
Man kann das bestimmt auch anders und einfacher machen, aber wie es immer ist - nerver touch a running system 
Viel Spaß Heiko