diff --git a/.style b/.style index ea67b89..fe04d92 160000 --- a/.style +++ b/.style @@ -1 +1 @@ -Subproject commit ea67b8910400936a6445e27f40d7e60ca79dc069 +Subproject commit fe04d922f53d36e19d91a7f8dfe4ca7c66ed62a4 diff --git a/AbfallNavi/README.md b/AbfallNavi/README.md index a1c878e..c6d09b8 100644 --- a/AbfallNavi/README.md +++ b/AbfallNavi/README.md @@ -1,10 +1,10 @@ # AbfallNavi [![Version](https://img.shields.io/badge/Symcon-PHP--Modul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Product](https://img.shields.io/badge/Symcon%20Version-6.0-blue.svg)](https://www.symcon.de/produkt/) -[![Version](https://img.shields.io/badge/Modul%20Version-1.0.20221020-orange.svg)](https://github.com/Wilkware/IPSymconAwido) +[![Product](https://img.shields.io/badge/Symcon%20Version-6.4-blue.svg)](https://www.symcon.de/produkt/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.0.20231119-orange.svg)](https://github.com/Wilkware/WasteManagement) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) -[![Actions](https://github.com/Wilkware/IPSymconAwido/workflows/Check%20Style/badge.svg)](https://github.com/Wilkware/IPSymconAwido/actions) +[![Actions](https://github.com/Wilkware/WasteManagement/workflows/Check%20Style/badge.svg)](https://github.com/Wilkware/WasteManagement/actions) IP-Symcon Modul für die Visualisierung von Entsorgungsterminen. @@ -27,13 +27,13 @@ Derzeit unterstützt das Modul rund 20 verschiedene Regionen. Wenn jemand noch w ### 2. Voraussetzungen -* IP-Symcon ab Version 6.0 +* IP-Symcon ab Version 6.4 ### 3. Installation * Über den Modul Store das Modul Abfallwirtschaft (ehem. Awido) installieren. * Alternativ Über das Modul-Control folgende URL hinzufügen. -`https://github.com/Wilkware/IPSymconAwido` oder `git://github.com/Wilkware/IPSymconAwido.git` +`https://github.com/Wilkware/WasteManagement` oder `git://github.com/Wilkware/WasteManagement.git` ### 4. Einrichten der Instanzen in IP-Symcon @@ -108,6 +108,12 @@ __Beispiel__: `REGIO_Update(12345);` ### 8. Versionshistorie +v2.0.20231119 + +* _NEU_: Kompatibilität auf IPS 6.4 hoch gesetzt +* _NEU_: Support für v7 Visualisierung +* _FIX_: Sortierreihenfolge der Daten korriegiert + v1.0.20221020 * _NEU_: Initialversion diff --git a/AbfallNavi/form.json b/AbfallNavi/form.json index 672ab08..3545fbe 100644 --- a/AbfallNavi/form.json +++ b/AbfallNavi/form.json @@ -287,6 +287,27 @@ "name": "settingsVariables", "caption": "Create variables for non-selected disposals?" }, + { + "type": "CheckBox", + "name": "settingsTileVisu", + "caption": "Activate support for Tile Visu?" + }, + { + "type": "Select", + "name": "settingsTileSkin", + "caption": "Theme to be used (design):", + "width": "450px", + "options": [ + { + "label": "Light Skin", + "value": "light" + }, + { + "label": "Dark Skin", + "value": "dark" + } + ] + }, { "type": "SelectScript", "name": "settingsScript", diff --git a/AbfallNavi/locale.json b/AbfallNavi/locale.json index 9f12f25..0915e6a 100644 --- a/AbfallNavi/locale.json +++ b/AbfallNavi/locale.json @@ -19,6 +19,27 @@ "... call the following scipt after update the dates:": "... nach Aktualisierung der Werte folgendes Script aufrufen:", "Subsequent execution of a script:": "Anschließendes Ausführen eines Skriptes:", "Script:": "Script:", + "Activate support for Tile Visu?": "Unterstützung für Tile Visu aktivieren?", + "Theme to be used (design):": "Zu verwendendes Theme (Design):", + "Dark": "Dunkel", + "Light": "Hell", + "Waste": "Abfall", + "Pickup": "Abholung", + "Removal": "Abfuhr", + "Date": "Termin", + "Today": "Heute", + "Tomorrow": "Morgen", + "days": "Tage", + "day": "Tag", + "Next pickup:": "Nächste Abholung:", + "on": "am", + "Monday": "Montag", + "Tuesday": "Dienstag", + "Wednesday": "Mittwoch", + "Thursday": "Donnerstag", + "Friday": "Freitag", + "Saturday": "Samstag", + "Sunday": "Sonntag", "Disposal data ...": "Entsorgungsdaten ...", "Update": "Aktualisieren", "Creating instance.": "Die Instanz wird erstellt.", diff --git a/AbfallNavi/module.php b/AbfallNavi/module.php index 436f625..4490551 100644 --- a/AbfallNavi/module.php +++ b/AbfallNavi/module.php @@ -12,6 +12,7 @@ class AbfallNavi extends IPSModule use DebugHelper; use ServiceHelper; use VariableHelper; + use VisualisationHelper; // Service Provider private const SERVICE_PROVIDER = 'regio'; @@ -76,6 +77,8 @@ public function Create() $this->RegisterPropertyBoolean('settingsActivate', true); $this->RegisterPropertyBoolean('settingsVariables', false); $this->RegisterPropertyInteger('settingsScript', 0); + $this->RegisterPropertyBoolean('settingsTileVisu', false); + $this->RegisterPropertyString('settingsTileSkin', 'dark'); // Attributes for dynamic configuration forms (> v3.0) $this->RegisterAttributeString('io', serialize($this->PrepareIO())); // Register daily update timer @@ -268,9 +271,12 @@ public function ApplyChanges() $sId = $this->ReadPropertyString('streetID'); $aId = $this->ReadPropertyString('addonID'); $activate = $this->ReadPropertyBoolean('settingsActivate'); + $tilevisu = $this->ReadPropertyBoolean('settingsTileVisu'); $this->SendDebug(__FUNCTION__, 'clientID=' . $cId . ', placeId=' . $pId . ', streetId=' . $sId . ', addonId=' . $aId); // Safty default $this->SetTimerInterval('UpdateTimer', 0); + // Support for Tile Viso (v7.x) + $this->MaintainVariable('Widget', $this->Translate('Pickup'), vtString, '~HTMLBox', 0, $tilevisu); // Set status $io = unserialize($this->ReadAttributeString('io')); $this->SendDebug(__FUNCTION__, $io); @@ -335,12 +341,12 @@ public function Update() return; } // fractions convert to name => ident - $vars = []; + $waste = []; foreach ($io[self::IO_NAMES] as $ident => $name) { $this->SendDebug(__FUNCTION__, 'Fraction ident: ' . $ident . ', Name: ' . $name); - $vars[$ident] = ''; + $waste[$ident] = ['ident' => $ident, 'date' => '']; } - $this->SendDebug(__FUNCTION__, $vars); + $this->SendDebug(__FUNCTION__, $waste); // Build timestamp $today = mktime(0, 0, 0); // Iterate dates @@ -350,19 +356,27 @@ public function Update() continue; } // find out disposal type - foreach ($vars as $key => $time) { + foreach ($waste as $key => $time) { if ($key == $day['id']) { - if ($time == '') { - $vars[$key] = date('d.m.Y', strtotime($day['date'])); + if ($time['date'] == '') { + $waste[$key]['date'] = date('d.m.Y', strtotime($day['date'])); } break; } } } - $this->SendDebug(__FUNCTION__, $vars); + $this->SendDebug(__FUNCTION__, $waste); // write data to variable - foreach ($vars as $key => $time) { - $this->SetValueString((string) $key, $time); + foreach ($waste as $key => $var) { + $this->SetValueString((string) $var['ident'], $var['date']); + } + + // build tile widget + $btw = $this->ReadPropertyBoolean('settingsTileVisu'); + $skin = $this->ReadPropertyString('settingsTileSkin'); + $this->SendDebug(__FUNCTION__, 'TileVisu: ' . $btw . '(' . $skin . ')'); + if ($btw == true) { + $this->BuildWidget($waste, $skin); } // execute Script @@ -861,6 +875,7 @@ protected function ExecuteAction(&$io) foreach ($json as $date) { $data[] = ['id' => $date['bezirk']['fraktionId'], 'date' => $date['datum']]; } + $data = $this->OrderData($data, 'date'); $io[self::IO_ACTION] = self::ACTION_DATES; } break; diff --git a/Abfall_IO/README.md b/Abfall_IO/README.md index 2a8c80a..1a2baa0 100644 --- a/Abfall_IO/README.md +++ b/Abfall_IO/README.md @@ -1,10 +1,10 @@ # Abfall.IO [![Version](https://img.shields.io/badge/Symcon-PHP--Modul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Product](https://img.shields.io/badge/Symcon%20Version-6.0-blue.svg)](https://www.symcon.de/produkt/) -[![Version](https://img.shields.io/badge/Modul%20Version-1.5.20221020-orange.svg)](https://github.com/Wilkware/IPSymconAwido) +[![Product](https://img.shields.io/badge/Symcon%20Version-6.4-blue.svg)](https://www.symcon.de/produkt/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.0.2023119-orange.svg)](https://github.com/Wilkware/WasteManagement) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) -[![Actions](https://github.com/Wilkware/IPSymconAwido/workflows/Check%20Style/badge.svg)](https://github.com/Wilkware/IPSymconAwido/actions) +[![Actions](https://github.com/Wilkware/WasteManagement/workflows/Check%20Style/badge.svg)](https://github.com/Wilkware/WasteManagement/actions) IP-Symcon Modul für die Visualisierung von Entsorgungsterminen. @@ -27,13 +27,13 @@ Derzeit unterstützt das Modul über 60 verschiedene Landkreise und Großstädte ### 2. Voraussetzungen -* IP-Symcon ab Version 6.0 +* IP-Symcon ab Version 6.4 ### 3. Installation * Über den Modul Store das Modul Abfallwirtschaft (ehem. Awido) installieren. * Alternativ Über das Modul-Control folgende URL hinzufügen. -`https://github.com/Wilkware/IPSymconAwido` oder `git://github.com/Wilkware/IPSymconAwido.git` +`https://github.com/Wilkware/WasteManagement` oder `git://github.com/Wilkware/WasteManagement.git` ### 4. Einrichten der Instanzen in IP-Symcon @@ -118,6 +118,13 @@ __Beispiel__: `ABPIO_FixWasteName(12345, 'Hausmüll', 'Hausmüll (2 wöchentlich ### 8. Versionshistorie +v2.0.20231119 + +* _NEU_: Kompatibilität auf IPS 6.4 hoch gesetzt +* _NEU_: Support für v7 Visualisierung +* _FIX_: Übersetzungsfehler korrigiert +* _FIX_: PHP Syle Check korrigiert + v1.5.20221020 * _FIX_: Code bereinigt (ungenutzte Funktionen entfernt) diff --git a/Abfall_IO/form.json b/Abfall_IO/form.json index 4a7df89..6d2b936 100644 --- a/Abfall_IO/form.json +++ b/Abfall_IO/form.json @@ -301,6 +301,27 @@ "name": "settingsVariables", "caption": "Create variables for non-selected disposals?" }, + { + "type": "CheckBox", + "name": "settingsTileVisu", + "caption": "Activate support for Tile Visu?" + }, + { + "type": "Select", + "name": "settingsTileSkin", + "caption": "Theme to be used (design):", + "width": "450px", + "options": [ + { + "label": "Light Skin", + "value": "light" + }, + { + "label": "Dark Skin", + "value": "dark" + } + ] + }, { "type": "CheckBox", "name": "settingsStartsWith", @@ -309,7 +330,7 @@ { "type": "Select", "name": "settingsFormat", - "caption": "Format, in welchem die Daten abgeholt werden:", + "caption": "Format in which the data is collected:", "width": "450px", "options": [ { diff --git a/Abfall_IO/locale.json b/Abfall_IO/locale.json index bee3290..e7cc1ee 100644 --- a/Abfall_IO/locale.json +++ b/Abfall_IO/locale.json @@ -24,6 +24,27 @@ "Comma Separated Values file (CSV)": "Trennzeichengetrennte Datei (CSV)", "Subsequent execution of a script:": "Anschließendes Ausführen eines Skriptes:", "Script:": "Script:", + "Activate support for Tile Visu?": "Unterstützung für Tile Visu aktivieren?", + "Theme to be used (design):": "Zu verwendendes Theme (Design):", + "Dark": "Dunkel", + "Light": "Hell", + "Waste": "Abfall", + "Pickup": "Abholung", + "Removal": "Abfuhr", + "Date": "Termin", + "Today": "Heute", + "Tomorrow": "Morgen", + "days": "Tage", + "day": "Tag", + "Next pickup:": "Nächste Abholung:", + "on": "am", + "Monday": "Montag", + "Tuesday": "Dienstag", + "Wednesday": "Mittwoch", + "Thursday": "Donnerstag", + "Friday": "Freitag", + "Saturday": "Samstag", + "Sunday": "Sonntag", "Disposal data ...": "Entsorgungsdaten ...", "Update": "Aktualisieren", "Creating instance.": "Die Instanz wird erstellt.", diff --git a/Abfall_IO/module.php b/Abfall_IO/module.php index 728084f..1161edc 100644 --- a/Abfall_IO/module.php +++ b/Abfall_IO/module.php @@ -17,6 +17,7 @@ class Abfall_IO extends IPSModule use DebugHelper; use ServiceHelper; use VariableHelper; + use VisualisationHelper; // Service Provider private const SERVICE_PROVIDER = 'abpio'; @@ -73,6 +74,8 @@ public function Create() $this->RegisterPropertyBoolean('settingsStartsWith', false); $this->RegisterPropertyInteger('settingsScript', 0); $this->RegisterPropertyString('settingsFormat', 'ics'); + $this->RegisterPropertyBoolean('settingsTileVisu', false); + $this->RegisterPropertyString('settingsTileSkin', 'dark'); // Attributes for dynamic configuration forms (> v3.0) $this->RegisterAttributeString('io', serialize($this->PrepareIO())); // Register daily update timer @@ -289,9 +292,12 @@ public function ApplyChanges() $sId = $this->ReadPropertyString('streetID'); $aId = $this->ReadPropertyString('addonID'); $activate = $this->ReadPropertyBoolean('settingsActivate'); + $tilevisu = $this->ReadPropertyBoolean('settingsTileVisu'); $this->SendDebug(__FUNCTION__, 'clientID=' . $cId . ', placeId=' . $pId . ', districtId=' . $dId . ', streetId=' . $sId . ', addonId=' . $aId); // Safty default $this->SetTimerInterval('UpdateTimer', 0); + // Support for Tile Viso (v7.x) + $this->MaintainVariable('Widget', $this->Translate('Pickup'), vtString, '~HTMLBox', 0, $tilevisu); // Set status if ($cId == 'null') { $status = 201; @@ -416,10 +422,10 @@ public function Update() } // fractions convert to name => ident - $vars = []; + $waste = []; foreach ($io[self::IO_NAMES] as $ident => $name) { $this->SendDebug(__FUNCTION__, 'Fraction ident: ' . $ident . ', Name: ' . $name); - $vars[$name] = ['ident' => $ident, 'date' => '']; + $waste[$name] = ['ident' => $ident, 'date' => '']; } // ICS format @@ -456,7 +462,7 @@ public function Update() // Update fraction $name = $event->summary; if ($ssw == true) { - foreach ($vars as $key => $var) { + foreach ($waste as $key => $var) { if ($this->StartsWith($name, $key)) { $this->SendDebug(__FUNCTION__, 'StartWith: ' . $name . ' = ' . $key); $name = $key; @@ -464,16 +470,15 @@ public function Update() } } } - if (isset($vars[$name]) && $vars[$name]['date'] == '') { - $vars[$name]['date'] = $day; + if (isset($waste[$name]) && $waste[$name]['date'] == '') { + $waste[$name]['date'] = $day; $this->SendDebug(__FUNCTION__, 'Fraction date: ' . $name . ' = ' . $day); } } } // CSV format else { - $csv = array_map(function ($v) - { + $csv = array_map(function ($v) { $data = str_getcsv($v, ';'); return $data; }, explode("\n", $res)); @@ -495,7 +500,7 @@ public function Update() } // Update fraction if ($ssw == true) { - foreach ($vars as $key => $var) { + foreach ($waste as $key => $var) { if ($this->StartsWith($name, $key)) { $this->SendDebug(__FUNCTION__, 'StartWith: ' . $name . ' = ' . $key); $name = $key; @@ -503,8 +508,8 @@ public function Update() } } } - if (isset($vars[$name]) && $vars[$name]['date'] == '') { - $vars[$name]['date'] = $waste[$i]; + if (isset($waste[$name]) && $waste[$name]['date'] == '') { + $waste[$name]['date'] = $waste[$i]; $this->SendDebug(__FUNCTION__, 'Fraction date: ' . $name . ' = ' . $waste[$i]); } } @@ -512,10 +517,18 @@ public function Update() } // write data to variable - foreach ($vars as $key => $var) { + foreach ($waste as $key => $var) { $this->SetValueString((string) $var['ident'], $var['date']); } + // build tile widget + $btw = $this->ReadPropertyBoolean('settingsTileVisu'); + $skin = $this->ReadPropertyString('settingsTileSkin'); + $this->SendDebug(__FUNCTION__, 'TileVisu: ' . $btw . '(' . $skin . ')'); + if ($btw == true) { + $this->BuildWidget($waste, $skin); + } + // execute Script $script = $this->ReadPropertyInteger('settingsScript'); if ($script != 0) { diff --git a/Awido/README.md b/Awido/README.md index 6e10e7e..888dc65 100644 --- a/Awido/README.md +++ b/Awido/README.md @@ -1,10 +1,10 @@ # Awido [![Version](https://img.shields.io/badge/Symcon-PHP--Modul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Product](https://img.shields.io/badge/Symcon%20Version-6.0-blue.svg)](https://www.symcon.de/produkt/) -[![Version](https://img.shields.io/badge/Modul%20Version-3.4.20230124-orange.svg)](https://github.com/Wilkware/IPSymconAwido) +[![Product](https://img.shields.io/badge/Symcon%20Version-6.4-blue.svg)](https://www.symcon.de/produkt/) +[![Version](https://img.shields.io/badge/Modul%20Version-4.0.20231119-orange.svg)](https://github.com/Wilkware/WasteManagement) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) -[![Actions](https://github.com/Wilkware/IPSymconAwido/workflows/Check%20Style/badge.svg)](https://github.com/Wilkware/IPSymconAwido/actions) +[![Actions](https://github.com/Wilkware/WasteManagement/workflows/Check%20Style/badge.svg)](https://github.com/Wilkware/WasteManagement/actions) IP-Symcon Modul für die Visualisierung von Entsorgungsterminen. @@ -45,13 +45,13 @@ Wenn jemand noch weitere kennt, bitte einfach bei mir melden! ### 2. Voraussetzungen -* IP-Symcon ab Version 6.0 +* IP-Symcon ab Version 6.4 ### 3. Installation * Über den Modul Store das Modul Abfallwirtschaft (ehem. Awido) installieren. * Alternativ Über das Modul-Control folgende URL hinzufügen. -`https://github.com/Wilkware/IPSymconAwido` oder `git://github.com/Wilkware/IPSymconAwido.git` +`https://github.com/Wilkware/WasteManagement` oder `git://github.com/Wilkware/WasteManagement.git` ### 4. Einrichten der Instanzen in IP-Symcon @@ -126,6 +126,11 @@ __Beispiel__: `AWIDO_Update(12345);` ### 8. Versionshistorie +v4.0.20231119 + +* _NEU_: Kompatibilität auf IPS 6.4 hoch gesetzt +* _NEU_: Support für v7 Visualisierung + v3.4.20230124 * _FIX_: Skripte in den erweiterten Einstellungen werden wieder gespeichert diff --git a/Awido/form.json b/Awido/form.json index 3e977e2..cffc315 100644 --- a/Awido/form.json +++ b/Awido/form.json @@ -286,6 +286,27 @@ "name": "createVariables", "caption": "Create variables for non-selected disposals?" }, + { + "type": "CheckBox", + "name": "settingsTileVisu", + "caption": "Activate support for Tile Visu?" + }, + { + "type": "Select", + "name": "settingsTileSkin", + "caption": "Theme to be used (design):", + "width": "450px", + "options": [ + { + "label": "Light Skin", + "value": "light" + }, + { + "label": "Dark Skin", + "value": "dark" + } + ] + }, { "type": "SelectScript", "name": "settingsScript", diff --git a/Awido/locale.json b/Awido/locale.json index 2e6aef2..3fd10c3 100644 --- a/Awido/locale.json +++ b/Awido/locale.json @@ -19,6 +19,27 @@ "... call the following scipt after update the dates:": "... nach Aktualisierung der Werte folgendes Script aufrufen:", "Subsequent execution of a script:": "Anschließendes Ausführen eines Skriptes:", "Script:": "Script:", + "Activate support for Tile Visu?": "Unterstützung für Tile Visu aktivieren?", + "Theme to be used (design):": "Zu verwendendes Theme (Design):", + "Dark": "Dunkel", + "Light": "Hell", + "Waste": "Abfall", + "Pickup": "Abholung", + "Removal": "Abfuhr", + "Date": "Termin", + "Today": "Heute", + "Tomorrow": "Morgen", + "days": "Tage", + "day": "Tag", + "Next pickup:": "Nächste Abholung:", + "on": "am", + "Monday": "Montag", + "Tuesday": "Dienstag", + "Wednesday": "Mittwoch", + "Thursday": "Donnerstag", + "Friday": "Freitag", + "Saturday": "Samstag", + "Sunday": "Sonntag", "Disposal data ...": "Entsorgungsdaten ...", "Update": "Aktualisieren", "Creating instance.": "Die Instanz wird erstellt.", diff --git a/Awido/module.php b/Awido/module.php index 9f4ce5f..49da07f 100644 --- a/Awido/module.php +++ b/Awido/module.php @@ -12,6 +12,7 @@ class Awido extends IPSModule use DebugHelper; use ServiceHelper; use VariableHelper; + use VisualisationHelper; // Service Provider private const SERVICE_PROVIDER = 'awido'; @@ -43,6 +44,8 @@ public function Create() $this->RegisterPropertyBoolean('createVariables', false); $this->RegisterPropertyBoolean('activateAWIDO', true); $this->RegisterPropertyInteger('settingsScript', 0); + $this->RegisterPropertyBoolean('settingsTileVisu', false); + $this->RegisterPropertyString('settingsTileSkin', 'dark'); // Attributes for dynamic configuration forms (> v2.0) $this->RegisterAttributeString('cID', 'null'); $this->RegisterAttributeString('pID', 'null'); @@ -143,6 +146,7 @@ public function ApplyChanges() $streetId = $this->ReadPropertyString('streetGUID'); $addonId = $this->ReadPropertyString('addonGUID'); $activate = $this->ReadPropertyBoolean('activateAWIDO'); + $tilevisu = $this->ReadPropertyBoolean('settingsTileVisu'); $fractions = []; for ($i = 1; $i <= static::$FRACTIONS; $i++) { if ($this->ReadPropertyBoolean('fractionID' . $i)) { @@ -153,6 +157,8 @@ public function ApplyChanges() $this->SendDebug(__FUNCTION__, 'clientID=' . $clientId . ', placeId=' . $placeId . ', streetId=' . $streetId . ', addonId=' . $addonId . ', fractIds=' . $fractIds); // Safty default $this->SetTimerInterval('UpdateTimer', 0); + // Support for Tile Viso (v7.x) + $this->MaintainVariable('Widget', $this->Translate('Pickup'), vtString, '~HTMLBox', 0, $tilevisu); //$status = 102; if ($clientId == 'null') { $status = 201; @@ -224,10 +230,10 @@ public function Update() $data = json_decode($json); // Fractions mit Kurzzeichen(Short Name)) in Array konvertieren - $array = []; + $waste = []; foreach ($data as $fract) { $fractID = $this->ReadPropertyBoolean('fractionID' . $fract->id); - $array[$fract->snm] = ['ident' => $fract->snm, 'value' => '', 'exist' => $fractID]; + $waste[$fract->snm] = ['ident' => $fract->snm, 'date' => '', 'exist' => $fractID]; } // update data @@ -249,20 +255,27 @@ public function Update() $tag = substr($day->dt, 6) . '.' . substr($day->dt, 4, 2) . '.' . substr($day->dt, 0, 4); // Entsorgungsart herausfinden foreach ($day->fr as $snm) { - if ($array[$snm]['value'] == '') { - $array[$snm]['value'] = $tag; + if ($waste[$snm]['date'] == '') { + $waste[$snm]['date'] = $tag; } } } // write data to variable - foreach ($array as $line) { - if ($line['exist'] == true) { - // falls haendich geloescht, dann eben nicht! - $this->SetValueString((string) $line['ident'], $line['value']); + foreach ($waste as $key => $var) { + if ($var['exist'] == true) { + $this->SetValueString((string) $var['ident'], $var['date']); } } + // build tile widget + $btw = $this->ReadPropertyBoolean('settingsTileVisu'); + $skin = $this->ReadPropertyString('settingsTileSkin'); + $this->SendDebug(__FUNCTION__, 'TileVisu: ' . $btw . '(' . $skin . ')'); + if ($btw == true) { + $this->BuildWidget($waste, $skin); + } + // execute Script if ($scriptId != 0) { if (IPS_ScriptExists($scriptId)) { diff --git a/MuellMax/README.md b/MuellMax/README.md new file mode 100644 index 0000000..3f68a3a --- /dev/null +++ b/MuellMax/README.md @@ -0,0 +1,131 @@ +# MüllMax + +[![Version](https://img.shields.io/badge/Symcon-PHP--Modul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) +[![Product](https://img.shields.io/badge/Symcon%20Version-6.4-blue.svg)](https://www.symcon.de/produkt/) +[![Version](https://img.shields.io/badge/Modul%20Version-1.0.20231119-orange.svg)](https://github.com/Wilkware/WasteManagement) +[![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) +[![Actions](https://github.com/Wilkware/WasteManagement/workflows/Check%20Style/badge.svg)](https://github.com/Wilkware/WasteManagement/actions) + +IP-Symcon Modul für die Visualisierung von Entsorgungsterminen. + +## Inhaltverzeichnis + +1. [Funktionsumfang](#user-content-1-funktionsumfang) +2. [Voraussetzungen](#user-content-2-voraussetzungen) +3. [Installation](#user-content-3-installation) +4. [Einrichten der Instanzen in IP-Symcon](#user-content-4-einrichten-der-instanzen-in-ip-symcon) +5. [Statusvariablen und Profile](#user-content-5-statusvariablen-und-profile) +6. [WebFront](#user-content-6-webfront) +7. [PHP-Befehlsreferenz](#user-content-7-php-befehlsreferenz) +8. [Versionshistorie](#user-content-8-versionshistorie) + +### 1. Funktionsumfang + +Das Modul nutzt die von MüllMax (www.muellmax.de) bereitgestellten Daten zur Berechnung der bevorstehenden Entsorgungstermine (Abfallentsorgung). + +Derzeit unterstützt das Modul 15 verschiedene Landkreise und Großstädte. Wenn jemand noch weitere kennt, bitte einfach bei mir melden! + +### 2. Voraussetzungen + +* IP-Symcon ab Version 6.4 + +### 3. Installation + +* Über den Modul Store das Modul Abfallwirtschaft (ehem. Awido) installieren. +* Alternativ Über das Modul-Control folgende URL hinzufügen. +`https://github.com/Wilkware/WasteManagement` oder `git://github.com/Wilkware/WasteManagement.git` + +### 4. Einrichten der Instanzen in IP-Symcon + +* Unter "Instanz hinzufügen" ist das _'MuellMax'_-Modul (Alias: _'Abfallwirtschaft (MüllMax)'_ oder _'Entsorgungskalender (MüllMax)'_) unter dem Hersteller _'(Geräte)'_ aufgeführt. + +__Konfigurationsseite__: + +Entsprechend der gewählten Auswahl verändert sich das Formular dynamisch. +Eine komplette Neuauswahl erreicht man durch Auswahl "Bitte wählen ..." an der gewünschten Stelle. + +VORSTICHT: eine Änderung der Auswahl bedingt ein Update bzw. ein Neuanlegen der Statusvariablen!!! +Alte Variablen, welche es im anderen Landkreis gab werden nicht gelöscht! Hat man diese in einem WF verlinkt muss man danach +selber aufräumen. Ich denke aber mal das ein Umzug nicht so häufig vorkommt ;-) + +_Einstellungsbereich:_ + +> Online Dienste ... + +Name | Beschreibung +----------------------- | ---------------------------------- +Anbieter | 'MüllMax (muellmax.de)' + +> Abfallwirtschaft ... + +Name | Beschreibung +----------------------- | --------------------------------- +Entsorgungsgebiet | Liste der verfügbaren Gebiete (siehe oben) +Stadt | Ort im Entsorgungsgebiet (kann identisch zum Gebiet sein) +Straße | Strasse im gewählten Ort +Hausnummer | Hausnummer in gewählter Strasse +Entsorgungen | Entsorgungsarten, d.h. was wird im Gebiet an Entsorgung angeboten + +> Erweiterte Einstellungen ... + +Name | Beschreibung +------------------------------------------------------- | --------------------------------- +Tägliche Aktualisierung aktivieren? | Status, ob das tägliche Update aktiv oder inaktiv ist +Variablen für nicht ausgewählte Entsorgungen erstellen? | Status, ob für nicht genutzte Entsorgungen auch Variablen angelegt werden sollen, standardmäßig nein +Skript | Skript, welches nach dem Update der Termine ausgeführt wird, z.B. für Sortierung usw. + +_Aktionsbereich:_ + +Aktion | Beschreibung +----------------------- | --------------------------------- +AKTUALISEREN | Werte werden neu ermittelt und geschrieben + +### 5. Statusvariablen und Profile + +Die Statusvariablen/Timer werden automatisch angelegt. Das Löschen einzelner kann zu Fehlfunktionen führen. + +Name | Typ | Beschreibung +-------------------| --------- | ---------------- +Entsorgungsart(en) | String | Abhängig vom Entsorgungsgebiet und den angebotenem Service mehrere Variablen, z.B.: Restmüll, Biotonne usw. + +Es werden keine zusätzlichen Profile benötigt. + +### 6. WebFront + +Man kann die Statusvariablen(Strings) direkt im WF verlinken. +Aber wie bei der Konfiguration beschrieben, muss man aufpassen wenn die Konfiguration geändert wird. Dann müssen gegebenenfalls die Links neu eingerichtet werden. + +### 7. PHP-Befehlsreferenz + +```php +void MAXDE_Update(int $InstanzID); +``` + +Holt die nächsten anstehenden Entsorgungstermine für die gewählten Entsorgungsarten. +Die Funktion liefert keinerlei Rückgabewert. + +__Beispiel__: `MAXDE_Update(12345);` + +### 8. Versionshistorie + +v1.0.20231119 + +* _NEU_: Initialversion + +## Entwickler + +Seit nunmehr über 10 Jahren fasziniert mich das Thema Haussteuerung. In den letzten Jahren betätige ich mich auch intensiv in der IP-Symcon Community und steuere dort verschiedenste Skript und Module bei. Ihr findet mich dort unter dem Namen @pitti ;-) + +[![GitHub](https://img.shields.io/badge/GitHub-@wilkware-181717.svg?style=for-the-badge&logo=github)](https://wilkware.github.io/) + +## Spenden + +Die Software ist für die nicht kommerzielle Nutzung kostenlos, über eine Spende bei Gefallen des Moduls würde ich mich freuen. + +[![PayPal](https://img.shields.io/badge/PayPal-spenden-00457C.svg?style=for-the-badge&logo=paypal)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8816166) + +## Lizenz + +Namensnennung - Nicht-kommerziell - Weitergabe unter gleichen Bedingungen 4.0 International + +[![Licence](https://img.shields.io/badge/License-CC_BY--NC--SA_4.0-EF9421.svg?style=for-the-badge&logo=creativecommons)](https://creativecommons.org/licenses/by-nc-sa/4.0/) diff --git a/MuellMax/form.json b/MuellMax/form.json new file mode 100644 index 0000000..906c688 --- /dev/null +++ b/MuellMax/form.json @@ -0,0 +1,397 @@ +{ + "elements": [ + { + "type": "RowLayout", + "items": [ + { + "type": "Image", + "image": "data:image/png;base64,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", + "link": true, + "onClick": "echo 'https://wilkware.de';" + }, + { + "type": "Label", + "label": "\nMuellMax – Disposal calendar\n ", + "link": false, + "bold": true + } + ] + }, + { + "type": "Label", + "label": "This module uses the data provided by the MuellMax online service to display upcoming disposal dates.", + "link": false + }, + { + "type": "ExpansionPanel", + "caption": "Online service ...", + "items": [ + { + "type": "Select", + "name": "serviceProvider", + "caption": "Provider:", + "width": "450px", + "enabled": false, + "options": [ + { + "label": "Please select ...", + "value": "null" + } + ] + } + ] + }, + { + "type": "ExpansionPanel", + "caption": "Waste management ...", + "items": [ + { + "type": "RowLayout", + "items": [ + { + "type": "Select", + "name": "disposalID", + "caption": "Disposal area:", + "width": "450px", + "onChange": "IPS_RequestAction($id,'OnChangeDisposal',$disposalID);", + "options": [ + { + "label": "Please select ...", + "value": "null" + } + ] + } + ] + }, + { + "type": "RowLayout", + "items": [ + { + "type": "Select", + "name": "cityID", + "caption": "City:", + "width": "450px", + "visible": false, + "onChange": "IPS_RequestAction($id,'OnChangeCity',$cityID);", + "options": [ + { + "label": "Please select ...", + "value": "null" + } + ] + } + ] + }, + { + "type": "RowLayout", + "items": [ + { + "type": "Select", + "name": "streetID", + "caption": "Street:", + "width": "450px", + "visible": false, + "onChange": "IPS_RequestAction($id,'OnChangeStreet',$streetID);", + "options": [ + { + "label": "Please select ...", + "value": "null" + } + ] + }, + { + "type": "Select", + "name": "addonID", + "caption": "Number:", + "width": "450px", + "visible": false, + "onChange": "IPS_RequestAction($id,'OnChangeAddon',$addonID);", + "options": [ + { + "label": "Please select ...", + "value": "null" + } + ] + } + ] + }, + { + "type": "Label", + "name": "fractionLabel", + "caption": "The following disposals are offered:", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID1", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID2", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID3", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID4", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID5", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID6", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID7", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID8", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID9", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID10", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID11", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID12", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID13", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID14", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID15", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID16", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID17", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID18", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID19", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID20", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID21", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID22", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID23", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID24", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID25", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID26", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID27", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID28", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID29", + "visible": false + }, + { + "type": "CheckBox", + "name": "fractionID30", + "visible": false + } + ] + }, + { + "type": "ExpansionPanel", + "caption": "Advanced settings ...", + "items": [ + { + "type": "CheckBox", + "name": "settingsActivate", + "caption": "Activate daily update?" + }, + { + "type": "CheckBox", + "name": "settingsVariables", + "caption": "Create variables for non-selected disposals?" + }, + { + "type": "CheckBox", + "name": "settingsTileVisu", + "caption": "Activate support for Tile Visu?" + }, + { + "type": "Select", + "name": "settingsTileSkin", + "caption": "Theme to be used (design):", + "width": "450px", + "options": [ + { + "label": "Light Skin", + "value": "light" + }, + { + "label": "Dark Skin", + "value": "dark" + } + ] + }, + { + "type": "SelectScript", + "name": "settingsScript", + "caption": "Subsequent execution of a script:", + "width": "450px" + } + ] + } + ], + "actions": [ + { + "type": "Label", + "name": "updateLabel", + "caption": "Disposal data ...", + "visible": true + }, + { + "type": "Button", + "name": "updateButton", + "caption": "Update", + "onClick": "MAXDE_Update($id);", + "visible": true + }, + { + "type": "Label", + "caption": "" + }, + { + "type": "ExpansionPanel", + "caption": "Source code, donation and licence ...", + "items": [ + { + "type": "Label", + "caption": "The software is free of charge for non-commercial use, I would appreciate a donation if you like the module.", + "bold": true + }, + { + "type": "RowLayout", + "items": [ + { + "type": "Image", + "image": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTk2Ljc1IiBoZWlnaHQ9IjI4IiByb2xlPSJpbWciIGFyaWEtbGFiZWw9IkdJVEhVQjogQFdJTEtXQVJFIj48dGl0bGU+R0lUSFVCOiBAV0lMS1dBUkU8L3RpdGxlPjxnIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyI+PHJlY3Qgd2lkdGg9Ijg3LjUiIGhlaWdodD0iMjgiIGZpbGw9IiM1NTUiLz48cmVjdCB4PSI4Ny41IiB3aWR0aD0iMTA5LjI1IiBoZWlnaHQ9IjI4IiBmaWxsPSIjMTgxNzE3Ii8+PC9nPjxnIGZpbGw9IiNmZmYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZvbnQtZmFtaWx5PSJWZXJkYW5hLEdlbmV2YSxEZWphVnUgU2FucyxzYW5zLXNlcmlmIiB0ZXh0LXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIiBmb250LXNpemU9IjEwMCI+PGltYWdlIHg9IjkiIHk9IjciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgeGxpbms6aHJlZj0iZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCbWFXeHNQU0ozYUdsMFpYTnRiMnRsSWlCeWIyeGxQU0pwYldjaUlIWnBaWGRDYjNnOUlqQWdNQ0F5TkNBeU5DSWdlRzFzYm5NOUltaDBkSEE2THk5M2QzY3Vkek11YjNKbkx6SXdNREF2YzNabklqNDhkR2wwYkdVK1IybDBTSFZpUEM5MGFYUnNaVDQ4Y0dGMGFDQmtQU0pOTVRJZ0xqSTVOMk10Tmk0Mk15QXdMVEV5SURVdU16Y3pMVEV5SURFeUlEQWdOUzR6TURNZ015NDBNemdnT1M0NElEZ3VNakExSURFeExqTTROUzQyTGpFeE15NDRNaTB1TWpVNExqZ3lMUzQxTnpjZ01DMHVNamcxTFM0d01TMHhMakEwTFM0d01UVXRNaTR3TkMwekxqTXpPQzQzTWpRdE5DNHdOREl0TVM0Mk1TMDBMakEwTWkweExqWXhRelF1TkRJeUlERTRMakEzSURNdU5qTXpJREUzTGpjZ015NDJNek1nTVRjdU4yTXRNUzR3T0RjdExqYzBOQzR3T0RRdExqY3lPUzR3T0RRdExqY3lPU0F4TGpJd05TNHdPRFFnTVM0NE16Z2dNUzR5TXpZZ01TNDRNemdnTVM0eU16WWdNUzR3TnlBeExqZ3pOU0F5TGpnd09TQXhMak13TlNBekxqUTVOUzQ1T1RndU1UQTRMUzQzTnpZdU5ERTNMVEV1TXpBMUxqYzJMVEV1TmpBMUxUSXVOalkxTFM0ekxUVXVORFkyTFRFdU16TXlMVFV1TkRZMkxUVXVPVE1nTUMweExqTXhMalEyTlMweUxqTTRJREV1TWpNMUxUTXVNakl0TGpFek5TMHVNekF6TFM0MU5DMHhMalV5TXk0eE1EVXRNeTR4TnpZZ01DQXdJREV1TURBMUxTNHpNaklnTXk0eklERXVNak11T1RZdExqSTJOeUF4TGprNExTNHpPVGtnTXkwdU5EQTFJREV1TURJdU1EQTJJREl1TURRdU1UTTRJRE1nTGpRd05TQXlMakk0TFRFdU5UVXlJRE11TWpnMUxURXVNak1nTXk0eU9EVXRNUzR5TXk0Mk5EVWdNUzQyTlRNdU1qUWdNaTQ0TnpNdU1USWdNeTR4TnpZdU56WTFMamcwSURFdU1qTWdNUzQ1TVNBeExqSXpJRE11TWpJZ01DQTBMall4TFRJdU9EQTFJRFV1TmpJMUxUVXVORGMxSURVdU9USXVOREl1TXpZdU9ERWdNUzR3T1RZdU9ERWdNaTR5TWlBd0lERXVOakEyTFM0d01UVWdNaTQ0T1RZdExqQXhOU0F6TGpJNE5pQXdJQzR6TVRVdU1qRXVOamt1T0RJMUxqVTNRekl3TGpVMk5TQXlNaTR3T1RJZ01qUWdNVGN1TlRreUlESTBJREV5TGpJNU4yTXdMVFl1TmpJM0xUVXVNemN6TFRFeUxURXlMVEV5SWk4K1BDOXpkbWMrIi8+PHRleHQgdHJhbnNmb3JtPSJzY2FsZSguMSkiIHg9IjUyMi41IiB5PSIxNzUiIHRleHRMZW5ndGg9IjQ2NSIgZmlsbD0iI2ZmZiI+R0lUSFVCPC90ZXh0Pjx0ZXh0IHRyYW5zZm9ybT0ic2NhbGUoLjEpIiB4PSIxNDIxLjI1IiB5PSIxNzUiIHRleHRMZW5ndGg9Ijg1Mi41IiBmaWxsPSIjZmZmIiBmb250LXdlaWdodD0iYm9sZCI+QFdJTEtXQVJFPC90ZXh0PjwvZz48L3N2Zz4=", + "onClick": "echo 'https://wilkware.github.io/';" + }, + { + "type": "Image", + "image": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMTcxLjI1IiBoZWlnaHQ9IjI4IiByb2xlPSJpbWciIGFyaWEtbGFiZWw9IlBBWVBBTDogU1BFTkRFTiI+PHRpdGxlPlBBWVBBTDogU1BFTkRFTjwvdGl0bGU+PGcgc2hhcGUtcmVuZGVyaW5nPSJjcmlzcEVkZ2VzIj48cmVjdCB3aWR0aD0iODUuNSIgaGVpZ2h0PSIyOCIgZmlsbD0iIzU1NSIvPjxyZWN0IHg9Ijg1LjUiIHdpZHRoPSI4NS43NSIgaGVpZ2h0PSIyOCIgZmlsbD0iIzAwNDU3YyIvPjwvZz48ZyBmaWxsPSIjZmZmIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LWZhbWlseT0iVmVyZGFuYSxHZW5ldmEsRGVqYVZ1IFNhbnMsc2Fucy1zZXJpZiIgdGV4dC1yZW5kZXJpbmc9Imdlb21ldHJpY1ByZWNpc2lvbiIgZm9udC1zaXplPSIxMDAiPjxpbWFnZSB4PSI5IiB5PSI3IiB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIHhsaW5rOmhyZWY9ImRhdGE6aW1hZ2Uvc3ZnK3htbDtiYXNlNjQsUEhOMlp5QjJhV1YzUW05NFBTSXdJREFnTWpRZ01qUWlJSGh0Ykc1elBTSm9kSFJ3T2k4dmQzZDNMbmN6TG05eVp5OHlNREF3TDNOMlp5SStQSEJoZEdnZ1pEMGlUVEU1TGpjeE5TQTJMakV6TTJNdU1qUTVMVEV1T0RZMklEQXRNeTR4TVMwdU9UazVMVFF1TWpZMlF6RTNMall6TkM0Mk1qSWdNVFV1TnpJeElEQWdNVE11TXpBM0lEQklOaTR5TXpWakxTNDBNVGdnTUMwdU9URTJMalEwTkMweElDNDRPRGxNTWk0ek1qTWdNakF1TmpJeVl6QWdMak0xTmk0eU5TNDRMalkyTlM0NGFEUXVNekk0YkMwdU1qVWdNUzQ1TlRaakxTNHdPRFF1TXpVMUxqRTJOaTQyTWpJdU5EazRMall5TW1nekxqWTJNMk11TkRFM0lEQWdMamd6TWkwdU1qWTNMamt4TlMwdU56RXhkaTB1TWpZM2JDNDNORGt0TkM0Mk1qSjJMUzR4TnpoakxqQTRNeTB1TkRRMExqVXRMamd1T1RFMUxTNDRhQzQxWXpNdU5UYzRJREFnTmk0ek1qVXRNUzQxTVNBM0xqRTFOaTAxTGprMU5TNDBNVGd0TVM0NE5qY3VNalV5TFRNdU16YzRMUzQzTkRjdE5DNDBORFV0TGpJMUxTNHpOVFV0TGpZMk5pMHVOakl5TFRFdExqZzRPU0lnWm1sc2JEMGlJekF3T1dOa1pTSXZQanh3WVhSb0lHUTlJazB4T1M0M01UVWdOaTR4TXpOakxqSTBPUzB4TGpnMk5pQXdMVE11TVRFdExqazVPUzAwTGpJMk5rTXhOeTQyTXpRdU5qSXlJREUxTGpjeU1TQXdJREV6TGpNd055QXdTRFl1TWpNMVl5MHVOREU0SURBdExqa3hOaTQwTkRRdE1TQXVPRGc1VERJdU16SXpJREl3TGpZeU1tTXdJQzR6TlRZdU1qVXVPQzQyTmpVdU9HZzBMak15T0d3eExqRTJOQzAzTGpNM09DMHVNRGd6TGpJMk4yTXVNRGcwTFM0MU16TXVOUzB1T0RnNUxqazVPQzB1T0RnNWFESXVNRGhqTkM0d056a2dNQ0EzTGpJME1TMHhMamMzT0NBNExqSTBMVFl1TnpVMUxTNHdPRE10TGpJMk55QXdMUzR6TlRZZ01DMHVOVE0wSWlCbWFXeHNQU0lqTURFeU1UWTVJaTgrUEhCaGRHZ2daRDBpVFRrdU5UWXpJRFl1TVRNell5NHdPREl0TGpJMk5pNHlOUzB1TlRNekxqUTVPQzB1TnpFdU1UWTJJREFnTGpJMUxTNHdPUzQwTVRZdExqQTVhRFV1TkRrMFl5NDJOallnTUNBeExqTXpMakE1SURFdU9ETXVNVGM0TGpFMk5pQXdJQzR6TXpNZ01DQXVORGs0TGpBNE9TNHhOamd1TURnNUxqTXpOQzR3T0RrdU5ERTRMakUzT0dndU1qVmpMakkwT0M0d09Ea3VORGszTGpJMk5pNDNORGd1TXpVMUxqSTBPQzB4TGpnMk5pQXdMVE11TVRFdExqazVPUzAwTGpNMU5VTXhOeTQzTVRjdU5UTXpJREUxTGpnd05DQXdJREV6TGpNNUlEQklOaTR5TXpWakxTNDBNVGdnTUMwdU9URTJMak0xTmkweElDNDRPRGxNTWk0ek1qTWdNakF1TmpJeVl6QWdMak0xTmk0eU5TNDRMalkyTlM0NGFEUXVNekk0YkRFdU1UWTBMVGN1TXpjNElERXVNRGcwTFRjdU9URjZJaUJtYVd4c1BTSWpNREF6TURnM0lpOCtQQzl6ZG1jKyIvPjx0ZXh0IHRyYW5zZm9ybT0ic2NhbGUoLjEpIiB4PSI1MTIuNSIgeT0iMTc1IiB0ZXh0TGVuZ3RoPSI0NDUiIGZpbGw9IiNmZmYiPlBBWVBBTDwvdGV4dD48dGV4dCB0cmFuc2Zvcm09InNjYWxlKC4xKSIgeD0iMTI4My43NSIgeT0iMTc1IiB0ZXh0TGVuZ3RoPSI2MTcuNSIgZmlsbD0iI2ZmZiIgZm9udC13ZWlnaHQ9ImJvbGQiPlNQRU5ERU48L3RleHQ+PC9nPjwvc3ZnPg==", + "onClick": "echo 'https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=8816166';" + }, + { + "type": "Image", + "image": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iMjI5LjUiIGhlaWdodD0iMjgiIHJvbGU9ImltZyIgYXJpYS1sYWJlbD0iTElDRU5TRTogQ0MgQlktTkMtU0EgNC4wIj48dGl0bGU+TElDRU5TRTogQ0MgQlktTkMtU0EgNC4wPC90aXRsZT48ZyBzaGFwZS1yZW5kZXJpbmc9ImNyaXNwRWRnZXMiPjxyZWN0IHdpZHRoPSI5Mi43NSIgaGVpZ2h0PSIyOCIgZmlsbD0iIzU1NSIvPjxyZWN0IHg9IjkyLjc1IiB3aWR0aD0iMTM2Ljc1IiBoZWlnaHQ9IjI4IiBmaWxsPSIjZWY5NDIxIi8+PC9nPjxnIGZpbGw9IiNmZmYiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZvbnQtZmFtaWx5PSJWZXJkYW5hLEdlbmV2YSxEZWphVnUgU2FucyxzYW5zLXNlcmlmIiB0ZXh0LXJlbmRlcmluZz0iZ2VvbWV0cmljUHJlY2lzaW9uIiBmb250LXNpemU9IjEwMCI+PGltYWdlIHg9IjkiIHk9IjciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgeGxpbms6aHJlZj0iZGF0YTppbWFnZS9zdmcreG1sO2Jhc2U2NCxQSE4yWnlCbWFXeHNQU0lqUlVZNU5ESXhJaUJ5YjJ4bFBTSnBiV2NpSUhacFpYZENiM2c5SWpBZ01DQXlOQ0F5TkNJZ2VHMXNibk05SW1oMGRIQTZMeTkzZDNjdWR6TXViM0puTHpJd01EQXZjM1puSWo0OGRHbDBiR1UrUTNKbFlYUnBkbVVnUTI5dGJXOXVjend2ZEdsMGJHVStQSEJoZEdnZ1pEMGlUVEV4TGprNE15QXdZeTB6TGpJNU1pQXdMVFl1TVRrZ01TNHlNVGN0T0M0ME1qZ2dNeTQwT0RWRE1TNHlOU0ExTGpneE9TQXdJRGd1T0RRMElEQWdNVEpqTUNBekxqRTRPU0F4TGpJeE55QTJMakUwT0NBekxqVXlNaUE0TGpRMVF6VXVPREkzSURJeUxqYzFJRGd1T0RJeUlESTBJREV4TGprNE15QXlOR016TGpFMklEQWdOaTR5TWpJdE1TNHlOU0E0TGpVNU15MHpMalU0TTBNeU1pNDRNVFVnTVRndU1qRTBJREkwSURFMUxqSTROeUF5TkNBeE1tTXdMVE11TWpVMUxURXVNVGcyTFRZdU1qRTBMVE11TkRVNExUZ3VORGd6UXpFNExqSXpPQ0F4TGpJeE55QXhOUzR5TnpVZ01DQXhNUzQ1T0RNZ01IcHRMakF6TXlBeUxqRTNZekl1TnlBd0lEVXVNVEF6SURFdU1ESWdOaTQ1T0NBeUxqZzVNeUF4TGpnME15QXhMamcwTVNBeUxqZ3pJRFF1TWpjMElESXVPRE1nTmk0NU16Y2dNQ0F5TGpZNU5pMHVPVFUwSURVdU1EWXpMVEl1TnprNElEWXVPRGN5TFRFdU9UUXpJREV1T1RBMkxUUXVORFEwSURJdU9USTJMVGN1TURFeUlESXVPVEkyTFRJdU5qQXhJREF0TlM0d016Z3RNUzR3TVRrdE5pNDVNVFF0TWk0NE9UTXRNUzQ0TnpjdE1TNDROelV0TWk0NU15MDBMak0wTFRJdU9UTXROaTQ1TURVZ01DMHlMalU1TnlBeExqQTFNeTAxTGpBMk15QXlMamt6TFRZdU9UY2dNUzQ0TkRRdE1TNDROelFnTkM0eU1UUXRNaTQ0TmlBMkxqa3hOQzB5TGpnMmVrMDRMalk0SURndU1qYzRRell1TnpJeklEZ3VNamM0SURVdU1UWTFJRGt1TmpZZ05TNHhOalVnTVRKak1DQXlMak00SURFdU5EWTFJRE11TnpJeUlETXVOVGd4SURNdU56SXlJREV1TXpVNElEQWdNaTQxTVRZdExqYzBOQ0F6TGpFMU5TMHhMamczTkd3dE1TNDBPVEV0TGpjMU9HTXRMak16TXk0M09UZ3RMamd6T1NBeExqQXpOeTB4TGpRM09DQXhMakF6TnkweExqRXdOU0F3TFRFdU5qRXRMamt4TnkweExqWXhMVEl1TVRJMklEQXRNUzR5TVM0ME1qWXRNaTR4TWpjZ01TNDJNUzB5TGpFeU55NHpNaUF3SUM0NU5pNHhOek1nTVM0ek16SXVPVGRzTVM0MU9UY3RMamd6T0dNdExqWTRMVEV1TWpNMkxURXVPRE0zTFRFdU56STRMVE11TVRneExURXVOekk0ZW0wMkxqa3pNaUF3WXkweExqazFOeUF3TFRNdU5URTBJREV1TXpneUxUTXVOVEUwSURNdU56SXlJREFnTWk0ek9DQXhMalEyTkNBekxqY3lNaUF6TGpVNElETXVOekl5SURFdU16VTVJREFnTWk0MU1UWXRMamMwTkNBekxqRTFOUzB4TGpnM05Hd3RNUzQwT1MwdU56VTRZeTB1TXpNekxqYzVPQzB1T0RRZ01TNHdNemN0TVM0ME56Z2dNUzR3TXpjdE1TNHhNRFVnTUMweExqWXhNUzB1T1RFM0xURXVOakV4TFRJdU1USTJJREF0TVM0eU1TNDBNall0TWk0eE1qY2dNUzQyTVMweUxqRXlOeTR6TWlBd0lDNDVOaTR4TnpNZ01TNHpNekl1T1Rkc01TNDFPVGN0TGpnek9HTXRMalk0TFRFdU1qTTJMVEV1T0RNM0xURXVOekk0TFRNdU1UZ3hMVEV1TnpJNGVpSXZQand2YzNablBnPT0iLz48dGV4dCB0cmFuc2Zvcm09InNjYWxlKC4xKSIgeD0iNTQ4Ljc1IiB5PSIxNzUiIHRleHRMZW5ndGg9IjUxNy41IiBmaWxsPSIjZmZmIj5MSUNFTlNFPC90ZXh0Pjx0ZXh0IHRyYW5zZm9ybT0ic2NhbGUoLjEpIiB4PSIxNjExLjI1IiB5PSIxNzUiIHRleHRMZW5ndGg9IjExMjcuNSIgZmlsbD0iI2ZmZiIgZm9udC13ZWlnaHQ9ImJvbGQiPkNDIEJZLU5DLVNBIDQuMDwvdGV4dD48L2c+PC9zdmc+", + "onClick": "echo 'https://creativecommons.org/licenses/by-nc-sa/4.0/';" + } + ] + } + ] + } + ], + "status": [ + { + "code": 101, + "icon": "inactive", + "caption": "Creating instance." + }, + { + "code": 102, + "icon": "active", + "caption": "Instance active." + }, + { + "code": 104, + "icon": "inactive", + "caption": "Instance inactive." + }, + { + "code": 201, + "icon": "inactive", + "caption": "Please select a valid refuse management!" + }, + { + "code": 202, + "icon": "inactive", + "caption": "Please select a offered disposals!" + } + ] +} \ No newline at end of file diff --git a/MuellMax/locale.json b/MuellMax/locale.json new file mode 100644 index 0000000..e8ebc02 --- /dev/null +++ b/MuellMax/locale.json @@ -0,0 +1,56 @@ +{ + "translations": { + "de": { + "\nMuellMax – Disposal calendar\n ": "\nMüllMax – Entsorgungskalender\n ", + "This module uses the data provided by the MuellMax online service to display upcoming disposal dates.": "Dieses Modul nutzt die vom Online-Dienst MüllMax bereitgestellten Daten zur Darstellung der bevorstehenden Entsorgungstermine.", + "Online service ...": "Online Dienst ...", + "Provider:": "Anbieter:", + "Waste management ...": "Abfallwirtschaft ...", + "Please select ...": "Bitte wählen ...", + "Disposal area:": "Entsorgungsgebiet:", + "City:": "Stadt:", + "Street:": "Straße:", + "Number:": "Hausnummer:", + "All": "Alle", + "The following disposals are offered:": "Folgende Entsorgungen werden angeboten:", + "Advanced settings ...": "Erweiterte Einstellungen ...", + "Create variables for non-selected disposals?": "Variablen für nicht ausgewählte Entsorgungen erstellen?", + "Activate daily update?": "Tägliche Aktualisierung aktivieren?", + "... call the following scipt after update the dates:": "... nach Aktualisierung der Werte folgendes Script aufrufen:", + "Subsequent execution of a script:": "Anschließendes Ausführen eines Skriptes:", + "Script:": "Script:", + "Activate support for Tile Visu?": "Unterstützung für Tile Visu aktivieren?", + "Theme to be used (design):": "Zu verwendendes Theme (Design):", + "Dark": "Dunkel", + "Light": "Hell", + "Waste": "Abfall", + "Pickup": "Abholung", + "Removal": "Abfuhr", + "Date": "Termin", + "Today": "Heute", + "Tomorrow": "Morgen", + "days": "Tage", + "day": "Tag", + "Next pickup:": "Nächste Abholung:", + "on": "am", + "Monday": "Montag", + "Tuesday": "Dienstag", + "Wednesday": "Mittwoch", + "Thursday": "Donnerstag", + "Friday": "Freitag", + "Saturday": "Samstag", + "Sunday": "Sonntag", + "Disposal data ...": "Entsorgungsdaten ...", + "Update": "Aktualisieren", + "Creating instance.": "Die Instanz wird erstellt.", + "Instance active.": "Instanz ist aktiv.", + "Instance inactive.": "Instanz ist inaktiv.", + "Please select a valid refuse management!": "Bitte eine Abfallwirtschaft auswählen!", + "Please select a correct configuration!": "Bitte wählen Sie ein korrekte Konfiguration aus!", + "Please select a offered disposals!": "Bitte die angebotenen Entsorgungen auswählen!", + "Could not load json data!": "Konnte JSON Daten nicht laden!", + "Source code, donation and licence ...": "Quellcode, Spende und Lizenz ...", + "The software is free of charge for non-commercial use, I would appreciate a donation if you like the module.": "Die Software ist für die nicht kommzerielle Nutzung kostenlos, über eine Spende bei Gefallen des Moduls würde ich mich sehr freuen." + } + } +} \ No newline at end of file diff --git a/MuellMax/module.json b/MuellMax/module.json new file mode 100644 index 0000000..ceac3a2 --- /dev/null +++ b/MuellMax/module.json @@ -0,0 +1,15 @@ +{ + "id": "{2EC7DFA0-62D9-2E92-ADB1-6B8201D142FA}", + "name": "MuellMax", + "type": 3, + "vendor": "", + "aliases": [ + "Abfallwirtschaft (MüllMax)", + "Entsorgungskalender (MüllMax)" + ], + "url": "https://wilkware.de/ip-symcon-module/abfallwirtschaft/", + "parentRequirements": [], + "childRequirements": [], + "implemented": [], + "prefix": "MAXDE" +} \ No newline at end of file diff --git a/MuellMax/module.php b/MuellMax/module.php new file mode 100644 index 0000000..4869ed3 --- /dev/null +++ b/MuellMax/module.php @@ -0,0 +1,1059 @@ +RegisterPropertyString('serviceProvider', self::SERVICE_PROVIDER); + // Waste Management + $this->RegisterPropertyString('disposalID', 'null'); + $this->RegisterPropertyString('cityID', 'null'); + $this->RegisterPropertyString('streetID', 'null'); + $this->RegisterPropertyString('addonID', 'null'); + for ($i = 1; $i <= static::$FRACTIONS; $i++) { + $this->RegisterPropertyBoolean('fractionID' . $i, false); + } + // Advanced Settings + $this->RegisterPropertyBoolean('settingsActivate', true); + $this->RegisterPropertyBoolean('settingsVariables', false); + $this->RegisterPropertyInteger('settingsScript', 0); + $this->RegisterPropertyBoolean('settingsTileVisu', false); + $this->RegisterPropertyString('settingsTileSkin', 'dark'); + // Attributes for dynamic configuration forms (> v3.0) + $this->RegisterAttributeString('io', serialize($this->PrepareIO())); + // Register daily update timer + $this->RegisterTimer('UpdateTimer', 0, 'MAXDE_Update(' . $this->InstanceID . ');'); + } + + /** + * Configuration Form. + * + * @return JSON configuration string. + */ + public function GetConfigurationForm() + { + // Settings + $activate = $this->ReadPropertyBoolean('settingsActivate'); + // IO Values + $dId = $this->ReadPropertyString('disposalID'); + $cId = $this->ReadPropertyString('cityID'); + $sId = $this->ReadPropertyString('streetID'); + $aId = $this->ReadPropertyString('addonID'); + // Debug output + $this->SendDebug(__FUNCTION__, 'disposalID=' . $dId . ', cityID=' . $cId . ', streetId=' . $sId . ', addonId=' . $aId); + + // Get Basic Form + $jsonForm = json_decode(file_get_contents(__DIR__ . '/form.json'), true); + // Service Provider + $jsonForm['elements'][self::ELEM_PROVI]['items'][0]['options'] = $this->GetProviderOptions(); + // Waste Management + $jsonForm['elements'][self::ELEM_WASTE]['items'][0]['items'][0]['options'] = $this->GetClientOptions(self::SERVICE_PROVIDER); + + // Prompt + $prompt = ['caption' => $this->Translate('Please select ...') . str_repeat(' ', 79), 'value' => 'null']; + // go throw the whole way + $args = []; + $next = true; + // Build io array + $io = $this->PrepareIO(); + // Disposal + if ($dId != 'null') { + $io[self::IO_DISPOSAL] = $dId; + $this->SendDebug(__FUNCTION__, 'ACTION: Init Disposl!'); + $this->ExecuteAction($io); + if ($io[self::IO_SECURE] == '') { + $this->SendDebug(__FUNCTION__, 'Init secure token failed!'); + $next = false; + } + } else { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + // City or Streets + if ($next) { + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'mm_aus_ort.x=1'; + $args[] = 'mm_aus_ort.y=1'; + $this->SendDebug(__FUNCTION__, 'ACTION: City or Street!'); + $options = $this->ExecuteAction($io, $args); + // no city only streets + if ($io[self::IO_ACTION] != self::ACTION_CITY) { + unset($args); + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_str_name='; + $args[] = 'mm_aus_str_txt_submit=suchen'; + $this->SendDebug(__FUNCTION__, 'ACTION: No city only streets!'); + $options = $this->ExecuteAction($io, $args); + } + if (($io[self::IO_ACTION] != self::ACTION_CITY) && ($io[self::IO_ACTION] != self::ACTION_STREET)) { + $this->SendDebug(__FUNCTION__, 'No city or street received: ' . $io[self::IO_ACTION]); + $next = false; + } + } + // City + if ($next) { + if ($io[self::IO_ACTION] == self::ACTION_CITY) { + if ($options != null) { + // Always add the selection prompt + array_unshift($options, $prompt); + $jsonForm['elements'][self::ELEM_WASTE]['items'][1]['items'][0]['options'] = $options; + $jsonForm['elements'][self::ELEM_WASTE]['items'][1]['items'][0]['visible'] = true; + } else { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + if ($cId != 'null') { + $io[self::IO_CITY] = $cId; + // than prepeare the next + unset($args); + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_ort_sel=' . $io[self::IO_CITY]; + $args[] = 'mm_aus_ort_submit=weiter'; + $this->SendDebug(__FUNCTION__, 'ACTION: City and now streets!'); + $options = $this->ExecuteAction($io, $args); + // prepeare street ? + if ($io[self::IO_ACTION] != self::ACTION_STREET) { + unset($args); + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_str_name='; + $args[] = 'mm_aus_str_txt_submit=suchen'; + $options = $this->ExecuteAction($io, $args); + } + if ($options == null) { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + } else { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + } else { + $data[] = ['caption' => $this->Translate('Please select ...') . str_repeat(' ', 79), 'value' => $cId]; + $jsonForm['elements'][self::ELEM_WASTE]['items'][1]['items'][0]['options'] = $data; + $jsonForm['elements'][self::ELEM_WASTE]['items'][1]['items'][0]['visible'] = false; + } + } + // Street + if ($next) { + if ($io[self::IO_ACTION] == self::ACTION_STREET) { + if ($options != null) { + // Always add the selection prompt + array_unshift($options, $prompt); + $jsonForm['elements'][self::ELEM_WASTE]['items'][2]['items'][0]['options'] = $options; + $jsonForm['elements'][self::ELEM_WASTE]['items'][2]['items'][0]['visible'] = true; + } else { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + if ($sId != 'null') { + $io[self::IO_STREET] = $sId; + // than prepeare the next + unset($args); + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_str_sel=' . $io[self::IO_STREET]; + $args[] = 'mm_aus_str_sel_submit=weiter'; + $this->SendDebug(__FUNCTION__, 'ACTION: Street selected!'); + $options = $this->ExecuteAction($io, $args); + // Get Fractions ? + if ($io[self::IO_ACTION] != self::ACTION_ADDON) { + $io[self::IO_ACTION] = self::ACTION_FRACTIONS; + unset($args); + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_ica_auswahl=iCalendar-Datei'; + $this->SendDebug(__FUNCTION__, 'ACTION: No Addon - get fractions!'); + $options = $this->ExecuteAction($io, $args); + } + if ($options == null) { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + } else { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + } else { + $data[] = ['caption' => $this->Translate('Please select ...') . str_repeat(' ', 79), 'value' => $sId]; + $jsonForm['elements'][self::ELEM_WASTE]['items'][2]['items'][0]['options'] = $data; + $jsonForm['elements'][self::ELEM_WASTE]['items'][2]['items'][0]['visible'] = false; + } + } + // Addon + if ($next) { + if ($io[self::IO_ACTION] == self::ACTION_ADDON) { + $this->SendDebug(__FUNCTION__, 'ADDON'); + if ($options != null) { + // Always add the selection prompt + array_unshift($options, $prompt); + $jsonForm['elements'][self::ELEM_WASTE]['items'][2]['items'][1]['options'] = $options; + $jsonForm['elements'][self::ELEM_WASTE]['items'][2]['items'][1]['visible'] = true; + } else { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + if ($aId != 'null') { + $io[self::IO_ADDON] = $aId; + unset($args); + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_hnr_sel=' . $io[self::IO_ADDON]; + $args[] = 'mm_aus_hnr_sel_submit=weiter'; + $this->SendDebug(__FUNCTION__, 'ACTION: Addon selected!'); + $options = $this->ExecuteAction($io, $args); + // Get Fractions + $io[self::IO_ACTION] = self::ACTION_FRACTIONS; + unset($args); + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_ica_auswahl=iCalendar-Datei'; + $this->SendDebug(__FUNCTION__, 'ACTION: And now fractions!'); + $options = $this->ExecuteAction($io, $args); + if ($options == null) { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + } else { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + } else { + $data[] = ['caption' => $this->Translate('Please select ...') . str_repeat(' ', 79), 'value' => $aId]; + $jsonForm['elements'][self::ELEM_WASTE]['items'][2]['items'][1]['options'] = $data; + $jsonForm['elements'][self::ELEM_WASTE]['items'][2]['items'][1]['visible'] = false; + } + } + // Fractions + if ($next) { + if ($io[self::IO_ACTION] == self::ACTION_FRACTIONS) { + if ($options != null) { + // Label + $jsonForm['elements'][self::ELEM_WASTE]['items'][3]['visible'] = true; + $i = 1; + foreach ($options as $fract) { + $jsonForm['elements'][self::ELEM_WASTE]['items'][$i + 3]['caption'] = $fract['caption']; + $jsonForm['elements'][self::ELEM_WASTE]['items'][$i + 3]['visible'] = true; + $i++; + } + } else { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + } else { + $this->SendDebug(__FUNCTION__, __LINE__); + $next = false; + } + } + + // Write IO array + $this->WriteAttributeString('io', serialize($io)); + + // Debug output + $this->SendDebug(__FUNCTION__, $io); + // Return Form + return json_encode($jsonForm); + } + + public function ApplyChanges() + { + //Never delete this line! + parent::ApplyChanges(); + $dId = $this->ReadPropertyString('disposalID'); + $cId = $this->ReadPropertyString('cityID'); + $sId = $this->ReadPropertyString('streetID'); + $aId = $this->ReadPropertyString('addonID'); + $activate = $this->ReadPropertyBoolean('settingsActivate'); + $tilevisu = $this->ReadPropertyBoolean('settingsTileVisu'); + $this->SendDebug(__FUNCTION__, 'disposalID=' . $dId . ', cityID=' . $cId . ', streetId=' . $sId . ', addonId=' . $aId); + // Safty default + $this->SetTimerInterval('UpdateTimer', 0); + // Support for Tile Viso (v7.x) + $this->MaintainVariable('Widget', $this->Translate('Pickup'), vtString, '~HTMLBox', 0, $tilevisu); + // Set status + if ($dId == 'null') { + $status = 201; + } elseif (($cId == 'null') && ($sId == 'null') && ($aId == 'null')) { + $status = 202; + } else { + $status = 102; + } + // All okay + if ($status == 102) { + $this->CreateVariables(); + if ($activate == true) { + // Time neu berechnen + $this->UpdateTimerInterval('UpdateTimer', 0, 10, 0); + $this->SendDebug(__FUNCTION__, 'Timer aktiviert!'); + } else { + $status = 104; + } + } + $this->SetStatus($status); + } + + /** + * RequestAction. + * + * @param string $ident Ident (function name). + * @param string $value Value. + */ + public function RequestAction($ident, $value) + { + // Debug output + $this->SendDebug(__FUNCTION__, $ident . ' => ' . $value); + eval('$this->' . $ident . '(\'' . $value . '\');'); + return true; + } + + /** + * This function will be available automatically after the module is imported with the module control. + * Using the custom prefix this function will be callable from PHP and JSON-RPC through:. + * + * MAXDE_Update($id); + */ + public function Update() + { + // Check instance state + if ($this->GetStatus() != 102) { + $this->SendDebug(__FUNCTION__, 'Status: Instance is not active.'); + return; + } + $io = unserialize($this->ReadAttributeString('io')); + $this->SendDebug(__FUNCTION__, $io); + + // (1) Build io array & init + $uio = $this->PrepareIO(); + $uio[self::IO_DISPOSAL] = $io[self::IO_DISPOSAL]; + $this->ExecuteAction($uio); + if ($uio[self::IO_SECURE] == '') { + $this->SendDebug(__FUNCTION__, 'Init secure token failed!'); + return; + } + // (2) Request city or an empty street search field + $args[] = 'mm_ses=' . $uio[self::IO_SECURE]; + $args[] = 'mm_aus_ort.x=1'; + $args[] = 'mm_aus_ort.y=1'; + $this->ExecuteAction($uio, $args); + // (3) We have a city - select it + if ($io[self::IO_CITY] != '') { + unset($args); + $args[] = 'mm_ses=' . $uio[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_ort_sel=' . $io[self::IO_CITY]; + $args[] = 'mm_aus_ort_submit=weiter'; + $options = $this->ExecuteAction($uio, $args); + } + // (4) Select street + if ($io[self::IO_STREET] != '') { + unset($args); + $args[] = 'mm_ses=' . $uio[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_str_name='; + $args[] = 'mm_aus_str_txt_submit=suchen'; + $this->ExecuteAction($uio, $args); + unset($args); + $args[] = 'mm_ses=' . $uio[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_str_sel=' . $io[self::IO_STREET]; + $args[] = 'mm_aus_str_sel_submit=weiter'; + $this->ExecuteAction($uio, $args); + } + // (5) Select street addon + if ($io[self::IO_ADDON] != '') { + unset($args); + $args[] = 'mm_ses=' . $uio[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_hnr_sel=' . $io[self::IO_ADDON]; + $args[] = 'mm_aus_hnr_sel_submit=weiter'; + $this->ExecuteAction($uio, $args); + } + // (6) Get Fractions + unset($args); + $args[] = 'mm_ses=' . $uio[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_ica_auswahl=iCalendar-Datei'; + $this->ExecuteAction($uio, $args); + // (7) Get ics file + unset($args); + $args[] = 'mm_ses=' . $uio[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_type=termine'; + // fractions convert to name => ident + $waste = []; + foreach ($io[self::IO_NAMES] as $ident => $name) { + $this->SendDebug(__FUNCTION__, 'Fraction ident: ' . $ident . ', Name: ' . $name); + $waste[$name] = ['ident' => $ident, 'date' => '']; + $args[] = 'mm_frm_fra_' . $ident . '=' . $ident; + } + $args[] = 'mm_ica_gen=iCalendar-Datei laden'; + // service request + $url = $this->BuildURL($io['key']); + $request = implode('&', $args); + $response = $this->ServiceRequest($url, $request); + try { + $ical = new ICal(false, [ + 'defaultSpan' => 2, // Default value + 'defaultTimeZone' => 'UTC', + 'defaultWeekStart' => 'MO', // Default value + 'disableCharacterReplacement' => false, // Default value + 'filterDaysAfter' => null, // Default value + 'filterDaysBefore' => null, // Default value + 'skipRecurrence' => false, // Default value + ]); + $ical->initString($response); + } catch (Exception $e) { + $this->SendDebug(__FUNCTION__, 'initICS: ' . $e); + return; + } + // get all events + $events = $ical->events(); + // go throw all events + $this->SendDebug(__FUNCTION__, 'ICS Events: ' . $ical->eventCount); + foreach ($events as $event) { + $this->SendDebug(__FUNCTION__, 'Event: ' . $event->summary . ' = ' . $event->dtstart); + // echo $event->printData('%s: %s'.PHP_EOL); + if ($event->dtstart < date('Ymd')) { + continue; + } + // YYYYMMDD umwandeln in DD.MM.YYYY + $day = substr($event->dtstart, 6) . '.' . substr($event->dtstart, 4, 2) . '.' . substr($event->dtstart, 0, 4); + // Update fraction + $name = $event->summary; + // Name could be prefix/suffix :( + foreach ($io[self::IO_NAMES] as $ident => $fname) { + if (strstr($name, $fname) !== false) { + $name = $fname; + break; + } + } + if (isset($waste[$name]) && $waste[$name]['date'] == '') { + $waste[$name]['date'] = $day; + $this->SendDebug(__FUNCTION__, 'Fraction date: ' . $name . ' = ' . $day); + } + } + + // write data to variable + foreach ($waste as $key => $var) { + $this->SetValueString((string) $var['ident'], $var['date']); + } + + // build tile widget + $btw = $this->ReadPropertyBoolean('settingsTileVisu'); + $skin = $this->ReadPropertyString('settingsTileSkin'); + $this->SendDebug(__FUNCTION__, 'TileVisu: ' . $btw . '(' . $skin . ')'); + if ($btw == true) { + $this->BuildWidget($waste, $skin); + } + + // execute Script + $script = $this->ReadPropertyInteger('settingsScript'); + if ($script != 0) { + if (IPS_ScriptExists($script)) { + $rs = IPS_RunScript($script); + $this->SendDebug(__FUNCTION__, 'Script Execute (Return Value): ' . $rs, 0); + } else { + $this->SendDebug(__FUNCTION__, 'Update: Script #' . $script . ' existiert nicht!'); + } + } + + // calculate next update interval + $activate = $this->ReadPropertyBoolean('settingsActivate'); + if ($activate == true) { + $this->UpdateTimerInterval('UpdateTimer', 0, 10, 0); + } + } + + /** + * User has selected a new waste management. + * + * @param string $id Disposal ID . + */ + protected function OnChangeDisposal($id) + { + // ACTION: 'init', KEY: $id + $io = $this->PrepareIO(self::ACTION_INIT, $id); + $this->SendDebug(__FUNCTION__, $io); + $data = null; + if ($id != 'null') { + // Init + $data = $this->ExecuteAction($io); + } + // City or Streets + $args = []; + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'mm_aus_ort.x=1'; + $args[] = 'mm_aus_ort.y=1'; + $data = $this->ExecuteAction($io, $args); + // no city only streets + if ($io[self::IO_ACTION] != 'city') { + unset($args); + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_str_name='; + $args[] = 'mm_aus_str_txt_submit=suchen'; + $data = $this->ExecuteAction($io, $args); + } + $this->SendDebug(__FUNCTION__, $io); + // Hide or Unhide properties + $this->UpdateForm($io, $data); + // Update attribute + $this->WriteAttributeString('io', serialize($io)); + } + + /** + * User has selected a new city. + * + * @param string $id City ID . + */ + protected function OnChangeCity($id) + { + $this->SendDebug(__FUNCTION__, $id); + $io = unserialize($this->ReadAttributeString('io')); + $this->UpdateIO($io, self::ACTION_CITY, $id); + $data = null; + if ($id != 'null') { + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_ort_sel=' . $io[self::IO_CITY]; + $args[] = 'mm_aus_ort_submit=weiter'; + $data = $this->ExecuteAction($io, $args); + } + if ($io[self::IO_ACTION] != self::ACTION_STREET) { + unset($args); + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_str_name='; + $args[] = 'mm_aus_str_txt_submit=suchen'; + $data = $this->ExecuteAction($io, $args); + } else { + $this->SendDebug(__FUNCTION__, 'No street for city!'); + $this->SendDebug(__FUNCTION__, $io); + } + // Hide or Unhide properties + $this->UpdateForm($io, $data); + // Update attribute + $this->WriteAttributeString('io', serialize($io)); + } + + /** + * Benutzer hat eine neue Straße ausgewählt. + * + * @param string $id Street ID . + */ + protected function OnChangeStreet($id) + { + $this->SendDebug(__FUNCTION__, $id); + $io = unserialize($this->ReadAttributeString('io')); + $this->UpdateIO($io, self::ACTION_STREET, $id); + $data = null; + if ($id != 'null') { + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_str_sel=' . $io[self::IO_STREET]; + $args[] = 'mm_aus_str_sel_submit=weiter'; + $data = $this->ExecuteAction($io, $args); + // Get Fractions ? + if ($io[self::IO_ACTION] != self::ACTION_ADDON) { + $io[self::IO_ACTION] = self::ACTION_FRACTIONS; + unset($args); + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_ica_auswahl=iCalendar-Datei'; + $data = $this->ExecuteAction($io, $args); + } + } + // Hide or Unhide properties + $this->UpdateForm($io, $data); + // Update attribute + $this->WriteAttributeString('io', serialize($io)); + } + + /** + * Benutzer hat eine neue Hausnummer ausgewählt. + * + * @param string $id Addon ID . + */ + protected function OnChangeAddon($id) + { + $this->SendDebug(__FUNCTION__, $id); + $io = unserialize($this->ReadAttributeString('io')); + $this->UpdateIO($io, self::ACTION_ADDON, $id); + $data = null; + if ($id != 'null') { + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_frm_hnr_sel=' . $io[self::IO_ADDON]; + $args[] = 'mm_aus_hnr_sel_submit=weiter'; + $data = $this->ExecuteAction($io, $args); + // Get Fractions + $io[self::IO_ACTION] = self::ACTION_FRACTIONS; + unset($args); + $args[] = 'mm_ses=' . $io[self::IO_SECURE]; + $args[] = 'xxx=1'; + $args[] = 'mm_ica_auswahl=iCalendar-Datei'; + $data = $this->ExecuteAction($io, $args); + } + $this->SendDebug(__FUNCTION__, $data); + // Hide or Unhide properties + $this->UpdateForm($io, $data); + // Update attribute + $this->WriteAttributeString('io', serialize($io)); + } + + /** + * Hide/unhide form fields. + * + */ + protected function UpdateForm($io, $options) + { + $this->SendDebug(__FUNCTION__, $io); + $this->SendDebug(__FUNCTION__, $options); + if (($options != null) && ($io[self::IO_ACTION] != self::ACTION_FRACTIONS)) { + // Always add the selection prompt + $prompt = ['caption' => $this->Translate('Please select ...') . str_repeat(' ', 79), 'value' => 'null']; + array_unshift($options, $prompt); + } + switch ($io[self::IO_ACTION]) { + // Disposal selected + case self::ACTION_INIT: + $this->UpdateFormField('cityID', 'visible', false); + $this->UpdateFormField('streetID', 'visible', false); + $this->UpdateFormField('addonID', 'visible', false); + $this->UpdateFormField('cityID', 'value', 'null'); + $this->UpdateFormField('streetID', 'value', 'null'); + $this->UpdateFormField('addonID', 'value', 'null'); + // Fraction Checkboxes + $this->UpdateFormField('fractionLabel', 'visible', false); + for ($i = 1; $i <= static::$FRACTIONS; $i++) { + $this->UpdateFormField('fractionID' . $i, 'visible', false); + $this->UpdateFormField('fractionID' . $i, 'value', false); + } + break; + // City selected + case self::ACTION_CITY: + $this->UpdateFormField('cityID', 'visible', true); + $this->UpdateFormField('cityID', 'value', 'null'); + if ($options != null) { + $this->UpdateFormField('cityID', 'options', json_encode($options)); + } + // Elements below + $this->UpdateFormField('streetID', 'visible', false); + $this->UpdateFormField('addonID', 'visible', false); + $this->UpdateFormField('streetID', 'value', 'null'); + $this->UpdateFormField('addonID', 'value', 'null'); + // Fraction Checkboxes + $this->UpdateFormField('fractionLabel', 'visible', false); + for ($i = 1; $i <= static::$FRACTIONS; $i++) { + $this->UpdateFormField('fractionID' . $i, 'visible', false); + $this->UpdateFormField('fractionID' . $i, 'value', false); + } + break; + // Street selected + case self::ACTION_STREET: + if ($io['mm_city'] == '') { + $this->UpdateFormField('cityID', 'visible', false); + $this->UpdateFormField('cityID', 'value', 'null'); + } + $this->UpdateFormField('streetID', 'visible', true); + $this->UpdateFormField('streetID', 'value', 'null'); + if ($options != null) { + $this->UpdateFormField('streetID', 'options', json_encode($options)); + } + // Elements below + $this->UpdateFormField('addonID', 'visible', false); + $this->UpdateFormField('addonID', 'value', 'null'); + // Fraction Checkboxes + $this->UpdateFormField('fractionLabel', 'visible', false); + for ($i = 1; $i <= static::$FRACTIONS; $i++) { + $this->UpdateFormField('fractionID' . $i, 'visible', false); + $this->UpdateFormField('fractionID' . $i, 'value', false); + } + break; + // Addon number selected + case self::ACTION_ADDON: + $this->UpdateFormField('addonID', 'visible', true); + $this->UpdateFormField('addonID', 'value', 'null'); + if ($options != null) { + $this->UpdateFormField('addonID', 'options', json_encode($options)); + } + // Fraction Checkboxes + $this->UpdateFormField('fractionLabel', 'visible', false); + for ($i = 1; $i <= static::$FRACTIONS; $i++) { + $this->UpdateFormField('fractionID' . $i, 'visible', false); + $this->UpdateFormField('fractionID' . $i, 'value', false); + } + break; + // Fractions selected + case self::ACTION_FRACTIONS: + $this->UpdateFormField('labelFraction', 'visible', true); + $f = 1; + foreach ($options as $fract) { + $this->UpdateFormField('fractionID' . $f, 'visible', true); + $this->UpdateFormField('fractionID' . $f, 'caption', $fract['caption']); + $f++; + } + // hide all others + for ($i = $f; $i <= static::$FRACTIONS; $i++) { + $this->UpdateFormField('fractionID' . $i, 'visible', false); + $this->UpdateFormField('fractionID' . $i, 'value', false); + } + break; + } + } + + /** + * Create the variables for the fractions. + * + */ + protected function CreateVariables() + { + $io = unserialize($this->ReadAttributeString('io')); + $this->SendDebug(__FUNCTION__, $io); + if (empty($io[self::IO_NAMES])) { + return; + } + // how to maintain? + $variable = $this->ReadPropertyBoolean('settingsVariables'); + $i = 1; + $ids = explode(',', $io[self::IO_FRACTIONS]); + foreach ($ids as $fract) { + if ($i <= static::$FRACTIONS) { + $enabled = $this->ReadPropertyBoolean('fractionID' . $i); + $this->MaintainVariable($fract, $io[self::IO_NAMES][$fract], vtString, '', $i, $enabled || $variable); + } + $i++; + } + } + + /** + * Serialize properties to IO interface array + * + * @param string $n next from action + * @param string $d disposal id value + * @param string $c city id value + * @param string $s street id value + * @param string $a addon id value + * @param string $f fraction id value + * @return array IO interface + */ + protected function PrepareIO($n = null, $d = 'null', $c = 'null', $s = 'null', $a = 'null', $f = 'null') + { + $io[self::IO_ACTION] = ($n != null) ? $n : self::ACTION_INIT; + $io[self::IO_DISPOSAL] = ($d != 'null') ? $d : ''; + $io[self::IO_CITY] = ($c != 'null') ? $c : ''; + $io[self::IO_STREET] = ($s != 'null') ? $s : ''; + $io[self::IO_ADDON] = ($a != 'null') ? $a : ''; + $io[self::IO_FRACTIONS] = ($f != 'null') ? $f : ''; + $io[self::IO_SECURE] = ''; + $io[self::IO_NAMES] = []; + // data2array + return $io; + } + + /** + * Everthing has changed - update the IO array + * + * @param array $io IO interface array + * @param string $action new form action + * @param string $id new selected form value + */ + protected function UpdateIO(&$io, $action, $id) + { + $this->SendDebug(__FUNCTION__, $action); + $this->SendDebug(__FUNCTION__, $id); + // tage over the action + $io[self::IO_ACTION] = $action; + + if ($action == self::ACTION_ADDON) { + $io[self::IO_ADDON] = ($id != 'null') ? $id : ''; + return; + } else { + $io[self::IO_ADDON] = ''; + $io[self::IO_FRACTIONS] = ''; + $io[self::IO_NAMES] = []; + } + + if ($action == self::ACTION_STREET) { + $io[self::IO_STREET] = ($id != 'null') ? $id : ''; + return; + } else { + $io[self::IO_STREET] = ''; + } + + if ($action == self::ACTION_CITY) { + $io[self::IO_CITY] = ($id != 'null') ? $id : ''; + return; + } else { + $io[self::IO_CITY] = ''; + } + + if ($action == self::ACTION_INIT) { + $io[self::IO_DISPOSAL] = ($id != 'null') ? $id : ''; + return; + } else { + $io[self::IO_DISPOSAL] = ''; + } + } + + /** + * Builds the POST/GET Url for the API CALLS + * + * @param string $key Disposal ID + * @param string $action Get parameter action. + */ + protected function BuildURL($key) + { + $url = '{{base}}{{key}}/res/{{start}}Start.php'; + $str = ['base' => self::SERVICE_BASEURL, 'key' => strtolower($key), 'start' => $key]; + // replace all + if (preg_match_all('/{{(.*?)}}/', $url, $m)) { + foreach ($m[1] as $i => $varname) { + $url = str_replace($m[0][$i], sprintf('%s', $str[$varname]), $url); + } + } + $this->SendDebug(__FUNCTION__, $url); + return $url; + } + + /** + * Sends the action url and data to the service provider + * + * @param $io service array + * @param $args forms array + * @return array New selecteable options or null. + */ + protected function ExecuteAction(&$io, $args = []) + { + $this->SendDebug(__FUNCTION__, $io); + // Build URL data + $url = $this->BuildURL($io['key']); + // GET or POST data + $request = null; + if (!empty($args)) { + $request = implode('&', $args); + } + $this->SendDebug(__FUNCTION__, 'Rerquest: ' . $request); + // Request FORM (xpath) + $res = $this->GetDocument($url, $request); + $data = null; + // Collect DATA + if ($res !== false) { + // INIT and all following + $inputs = $res->query("//input[@type='hidden']"); + foreach ($inputs as $input) { + $name = $input->getAttribute('name'); + $value = $input->getAttribute('value'); + if (array_key_exists($name, $io)) { + $io[$name] = $value; + } + $this->SendDebug(__FUNCTION__, 'Hidden: ' . $name . ':' . $value); + } + // INIT and disposal has cities + $select = $res->query("//select[@name='mm_frm_ort_sel']"); + if ($select->length > 0) { + $io[self::IO_ACTION] = 'city'; + $options = $res->query('.//option', $select[0]); + if ($options->length > 0) { + foreach ($options as $option) { + $value = $option->getAttribute('value'); + $name = $option->nodeValue; + if ($value == 0) { + continue; + } + $data[] = ['caption' => $name, 'value' => $value]; + //$this->SendDebug(__FUNCTION__, 'City: ' . $name . ':' . $value); + } + $this->SendDebug(__FUNCTION__, 'RETURN : City'); + return $data; + } + } + // streets + $select = $res->query("//select[@name='mm_frm_str_sel']"); + if ($select->length > 0) { + $io[self::IO_ACTION] = 'street'; + $options = $res->query('.//option', $select[0]); + if ($options->length > 0) { + foreach ($options as $option) { + $value = $option->getAttribute('value'); + $name = $option->nodeValue; + if ($value == 0) { + continue; + } + $data[] = ['caption' => $name, 'value' => $value]; + //$this->SendDebug(__FUNCTION__, 'Street: ' . $name . ':' . $value); + } + $this->SendDebug(__FUNCTION__, 'RETURN : Street'); + return $data; + } + } + // addon + $select = $res->query("//select[@name='mm_frm_hnr_sel']"); + if ($select->length > 0) { + $io[self::IO_ACTION] = 'addon'; + $options = $res->query('.//option', $select[0]); + if ($options->length > 0) { + foreach ($options as $option) { + $value = $option->getAttribute('value'); + $name = $option->nodeValue; + if ($value == 0) { + continue; + } + $data[] = ['caption' => $name, 'value' => $value]; + //$this->SendDebug(__FUNCTION__, 'Addon: ' . $name . ':' . $value); + } + $this->SendDebug(__FUNCTION__, 'RETURN : Addon'); + return $data; + } + } + // fraction + + $divs = $res->query("//div[@class='m_artsel_ical']"); + if ($divs->length > 0) { + $this->SendDebug(__FUNCTION__, 'Fractions: YES'); + $fractions = []; + $name = []; + foreach ($divs as $div) { + $inputs = $res->query(".//input[@type='checkbox']", $div); + $spans = $res->query(".//span[@class='m_artsel_text']/text()", $div); + $name = $spans->item(0)->nodeValue; // clear name + $value = $inputs->item(0)->getAttribute('value'); // value + // store + $data[] = ['caption' => $name, 'value' => $inputs->item(0)->getAttribute('value')]; + $fractions[] = $value; + $names[$value] = $name; + $this->SendDebug(__FUNCTION__, 'Fraction: ' . $name . ':' . $value); + } + $io[self::IO_FRACTIONS] = implode(',', array_unique($fractions)); + $io[self::IO_NAMES] = $names; + } + } + $this->SendDebug(__FUNCTION__, 'RETURN : Last'); + return $data; + } + + /** + * Sends the API call and transform it to a XPath Document + * + * @param string $url Request URL + * @param string $request Request parameters + * @return mixed DOM document + */ + protected function GetDocument($url, $request) + { + $response = $this->ServiceRequest($url, $request); + if ($response !== false) { + //$this->SendDebug(__FUNCTION__, $response); + $dom = new DOMDocument(); + // disable libxml errors + libxml_use_internal_errors(true); + $dom->loadHTML(mb_convert_encoding($response, 'HTML-ENTITIES', 'UTF-8')); + // remove errors for yucky html + libxml_clear_errors(); + $xpath = new DOMXpath($dom); + return $xpath; + } + return $response; + } + + /** + * Sends the API call + * + * @param string $url Rewquest URL + * @param string $request If $request not null, we will send a POST request, else a GET request. + * @param string $method Over the $method parameter can we force a POST or GET request! + * @return mixed False if the response is null, otherwise the response + */ + protected function ServiceRequest($url, $request, $method = 'GET') + { + // Return + $ret = false; + // CURL + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); + curl_setopt($curl, CURLOPT_USERAGENT, self::SERVICE_USERAGENT); + if ($request != null) { + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt($curl, CURLOPT_POSTFIELDS, $request); + } else { + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); + } + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + $response = curl_exec($curl); + curl_close($curl); + //$this->SendDebug(__FUNCTION__, $response); + if ($response != null) { + return $response; + } + return $ret; + } + + /** + * Checks if a string starts with a given substring + * + * @param string $haystack The string to search in. + * @param string $needle The substring to search for in the haystack. + * @param bool Returns true if haystack begins with needle, false otherwise. + */ + private function StartsWith($haystack, $needle) + { + return (string) $needle !== '' && strncmp($haystack, $needle, strlen($needle)) === 0; + } +} diff --git a/MyMuell/README.md b/MyMuell/README.md index 320ea87..e5a359b 100644 --- a/MyMuell/README.md +++ b/MyMuell/README.md @@ -1,10 +1,10 @@ # MyMüll [![Version](https://img.shields.io/badge/Symcon-PHP--Modul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Product](https://img.shields.io/badge/Symcon%20Version-6.0-blue.svg)](https://www.symcon.de/produkt/) -[![Version](https://img.shields.io/badge/Modul%20Version-2.0.20230102-orange.svg)](https://github.com/Wilkware/IPSymconAwido) +[![Product](https://img.shields.io/badge/Symcon%20Version-6.4-blue.svg)](https://www.symcon.de/produkt/) +[![Version](https://img.shields.io/badge/Modul%20Version-3.0.20231119-orange.svg)](https://github.com/Wilkware/WasteManagement) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) -[![Actions](https://github.com/Wilkware/IPSymconAwido/workflows/Check%20Style/badge.svg)](https://github.com/Wilkware/IPSymconAwido/actions) +[![Actions](https://github.com/Wilkware/WasteManagement/workflows/Check%20Style/badge.svg)](https://github.com/Wilkware/WasteManagement/actions) IP-Symcon Modul für die Visualisierung von Entsorgungsterminen. @@ -27,13 +27,13 @@ Derzeit unterstützt das Modul über 400 verschiedene Gebiete. Wenn jemand noch ### 2. Voraussetzungen -* IP-Symcon ab Version 6.0 +* IP-Symcon ab Version 6.4 ### 3. Installation * Über den Modul Store das Modul Abfallwirtschaft (ehem. Awido) installieren. * Alternativ Über das Modul-Control folgende URL hinzufügen. -`https://github.com/Wilkware/IPSymconAwido` oder `git://github.com/Wilkware/IPSymconAwido.git` +`https://github.com/Wilkware/WasteManagement` oder `git://github.com/Wilkware/WasteManagement.git` ### 4. Einrichten der Instanzen in IP-Symcon @@ -106,6 +106,11 @@ __Beispiel__: `MYMDE_Update(12345);` ### 8. Versionshistorie +v3.0.20231119 + +* _NEU_: Kompatibilität auf IPS 6.4 hoch gesetzt +* _NEU_: Support für v7 Visualisierung + v2.0.20230102 * _FIX_: Komplette Konfigurationsumstellung wegen wechselnden IDs diff --git a/MyMuell/form.json b/MyMuell/form.json index d3766e1..e192b12 100644 --- a/MyMuell/form.json +++ b/MyMuell/form.json @@ -254,6 +254,27 @@ "name": "settingsVariables", "caption": "Create variables for non-selected disposals?" }, + { + "type": "CheckBox", + "name": "settingsTileVisu", + "caption": "Activate support for Tile Visu?" + }, + { + "type": "Select", + "name": "settingsTileSkin", + "caption": "Theme to be used (design):", + "width": "450px", + "options": [ + { + "label": "Light Skin", + "value": "light" + }, + { + "label": "Dark Skin", + "value": "dark" + } + ] + }, { "type": "SelectScript", "name": "settingsScript", diff --git a/MyMuell/locale.json b/MyMuell/locale.json index b9d1892..446bb4a 100644 --- a/MyMuell/locale.json +++ b/MyMuell/locale.json @@ -17,6 +17,27 @@ "... call the following scipt after update the dates:": "... nach Aktualisierung der Werte folgendes Script aufrufen:", "Subsequent execution of a script:": "Anschließendes Ausführen eines Skriptes:", "Script:": "Script:", + "Activate support for Tile Visu?": "Unterstützung für Tile Visu aktivieren?", + "Theme to be used (design):": "Zu verwendendes Theme (Design):", + "Dark": "Dunkel", + "Light": "Hell", + "Waste": "Abfall", + "Pickup": "Abholung", + "Removal": "Abfuhr", + "Date": "Termin", + "Today": "Heute", + "Tomorrow": "Morgen", + "days": "Tage", + "day": "Tag", + "Next pickup:": "Nächste Abholung:", + "on": "am", + "Monday": "Montag", + "Tuesday": "Dienstag", + "Wednesday": "Mittwoch", + "Thursday": "Donnerstag", + "Friday": "Freitag", + "Saturday": "Samstag", + "Sunday": "Sonntag", "Disposal data ...": "Entsorgungsdaten ...", "Update": "Aktualisieren", "Creating instance.": "Die Instanz wird erstellt.", diff --git a/MyMuell/module.php b/MyMuell/module.php index 5ed5f87..4846df8 100644 --- a/MyMuell/module.php +++ b/MyMuell/module.php @@ -12,6 +12,7 @@ class MyMuell extends IPSModule use DebugHelper; use ServiceHelper; use VariableHelper; + use VisualisationHelper; // Service Provider private const SERVICE_PROVIDER = 'mymde'; @@ -42,6 +43,8 @@ public function Create() $this->RegisterPropertyBoolean('settingsActivate', true); $this->RegisterPropertyBoolean('settingsVariables', false); $this->RegisterPropertyInteger('settingsScript', 0); + $this->RegisterPropertyBoolean('settingsTileVisu', false); + $this->RegisterPropertyString('settingsTileSkin', 'dark'); // Register daily update timer $this->RegisterTimer('UpdateTimer', 0, 'MYMDE_Update(' . $this->InstanceID . ');'); } @@ -113,9 +116,12 @@ public function ApplyChanges() $cId = $this->ReadPropertyString('cityID'); $aId = $this->ReadPropertyString('areaID'); $activate = $this->ReadPropertyBoolean('settingsActivate'); + $tilevisu = $this->ReadPropertyBoolean('settingsTileVisu'); $this->SendDebug(__FUNCTION__, 'cityID=' . ', areaID=' . $aId); // Safty default $this->SetTimerInterval('UpdateTimer', 0); + // Support for Tile Viso (v7.x) + $this->MaintainVariable('Widget', $this->Translate('Pickup'), vtString, '~HTMLBox', 0, $tilevisu); // Set status if ($cId == 'null') { $status = 201; @@ -178,7 +184,7 @@ public function Update() $data = json_decode($json, true); foreach ($data as $entry) { if (!isset($waste[$entry['trash_name']])) { - $waste[$entry['trash_name']] = ['title' => $entry['title'], 'date' => strtotime($entry['day'])]; + $waste[$entry['trash_name']] = ['ident' => $entry['trash_name'], 'date' => date('d.m.Y', strtotime($entry['day'])), 'title' => $entry['title']]; } } } else { @@ -189,7 +195,15 @@ public function Update() // write data to variable foreach ($waste as $key => $var) { - $this->SetValueString((string) $key, date('d.m.Y', $var['date'])); + $this->SetValueString((string) $key, $var['date']); + } + + // build tile widget + $btw = $this->ReadPropertyBoolean('settingsTileVisu'); + $skin = $this->ReadPropertyString('settingsTileSkin'); + $this->SendDebug(__FUNCTION__, 'TileVisu: ' . $btw . '(' . $skin . ')'); + if ($btw == true) { + $this->BuildWidget($waste, $skin); } // execute Script diff --git a/README.md b/README.md index a6d5df6..e59b591 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Abfallwirtschaft [![Version](https://img.shields.io/badge/Symcon-PHP--Bibliothek-purple.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Product](https://img.shields.io/badge/Symcon%20Version-6.0-blue.svg)](https://www.symcon.de/produkt/) +[![Product](https://img.shields.io/badge/Symcon%20Version-6.4-blue.svg)](https://www.symcon.de/produkt/) [![Licence](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) IP-Symcon Modulbibliothek für die Visualisierung von Entsorgungsterminen. @@ -21,15 +21,21 @@ Folgende Module beinhaltet diese Bibliothek: - __Awido__ ([Dokumentation](Awido)) Der AWIDO (Alle wichtigen Daten online) - Service. +- __MuellMax__ ([Dokumentation](MuellMax)) + Müllmax Abfallkalender – barrierefrei online und gedruckt. + - __MyMuell__ ([Dokumentation](MyMuell)) MyMüll.de für die saubere Organisierung von Abfall und Wertstoffe. +__HINWEIS:__ Über diese [Suchseite](https://asmium.de) kann man ganz schnell herausfinden ob die eigene Stadt/Gemeinde von einem der aufgelisteten Dienste unterstützt wird! :+1: + ## Historie +- 2023-11-19: Modul MuellMax (MüllMax DE) - 2023-01-24: Modul Awido (Script-Fix) - 2022-10-20: Modul AbfallNavi (Regio IT) - 2022-03-09: Modul MyMuell Multi-Domain-Fähigkeit -- 2021-11-09: Modul MyMuell (MyMüll.de) +- 2021-11-09: Modul MyMuell (mymüll.de) - 2021-04-06: Modul Abfall_IO (Abfall+) - 2021-04-04: Modul Abfallwirtschaft Konfigurator (Waste Management Configurator) - 2017-01-03: Modul Awido diff --git a/WasteManagementConfigurator/README.md b/WasteManagementConfigurator/README.md index 7cc1e9a..7486ed8 100644 --- a/WasteManagementConfigurator/README.md +++ b/WasteManagementConfigurator/README.md @@ -1,10 +1,10 @@ # Abfallwirtschafts-Konfigurator (Waste Management Configutrator) [![Version](https://img.shields.io/badge/Symcon-PHP--Modul-red.svg)](https://www.symcon.de/service/dokumentation/entwicklerbereich/sdk-tools/sdk-php/) -[![Product](https://img.shields.io/badge/Symcon%20Version-6.0-blue.svg)](https://www.symcon.de/produkt/) -[![Version](https://img.shields.io/badge/Modul%20Version-1.3.20220309-orange.svg)](https://github.com/Wilkware/IPSymconAwido) +[![Product](https://img.shields.io/badge/Symcon%20Version-6.4-blue.svg)](https://www.symcon.de/produkt/) +[![Version](https://img.shields.io/badge/Modul%20Version-2.0.20231119-orange.svg)](https://github.com/Wilkware/WasteManagement) [![License](https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-green.svg)](https://creativecommons.org/licenses/by-nc-sa/4.0/) -[![Actions](https://github.com/Wilkware/IPSymconAwido/workflows/Check%20Style/badge.svg)](https://github.com/Wilkware/IPSymconAwido/actions) +[![Actions](https://github.com/Wilkware/WasteManagement/workflows/Check%20Style/badge.svg)](https://github.com/Wilkware/WasteManagement/actions) IP-Symcon Modul für die Verwaltung von Online Diensten zur Bestimmung von Entsorgungsterminen. @@ -29,18 +29,21 @@ Derzeit unterstützt der Konfigurator folgende Anbieter: * [Abfall+](https://abfallplus.de) - "Die Gesamtlösung für elektronische Bürgerdienste in der Abfallwirtschaft!" * [MyMüll.de](https://mymuell.de) - "Abfall und Wertstoffe sauber organisiert!" * [AbfallNavi](https://regioit.de) - "Der digitale Abfallkalender der regio IT für die Abfallentsorgung!" +* [MyMuell](https://muellmax.de) - Müllmax Abfallkalender – barrierefrei online und gedruckt. + +__HINWEIS:__ Über diese [Suchseite](https://asmium.de) kann man ganz schnell herausfinden ob die eigene Stadt/Gemeinde von einem der aufgelisteten Dienste unterstützt wird! :+1: Wenn jemand noch weitere kennt, bitte einfach bei mir melden! ### 2. Voraussetzungen -* IP-Symcon ab Version 6.0 +* IP-Symcon ab Version 6.4 ### 3. Installation * Über den Modul Store das Modul Abfallwirtschaft (ehem. Awido) installieren. * Alternativ Über das Modul-Control folgende URL hinzufügen. -`https://github.com/Wilkware/IPSymconAwido` oder `git://github.com/Wilkware/IPSymconAwido.git` +`https://github.com/Wilkware/WasteManagement` oder `git://github.com/Wilkware/WasteManagement.git` ### 4. Einrichten der Instanzen in IP-Symcon @@ -56,7 +59,7 @@ _Einstellungsbereich:_ Name | Beschreibung ----------------------- | --------------------------------- -Zielkategorie | Kategorie unter welcher neue Instanzen erzeugt werden (keine Auswahl im Root) +Zielkategorie | Kategorie unter welcher neue Instanzen erzeugt werden (keine Auswahl im Root). Nur bis Version 7! _Aktionsbereich:_ @@ -78,6 +81,11 @@ Das Modul bietet keine direkten Funktionsaufrufe. ### 8. Versionshistorie +v2.0.20231119 + +* _NEU_: Onlinedienst MuellMax (muellmax.de) hinzugefügt +* _NEU_: Unterstützung für neuen Konfigurator der Version 7 + v1.3.20220309 * _NEU_: Konfigurationsformular angepasst diff --git a/WasteManagementConfigurator/form.json b/WasteManagementConfigurator/form.json index 9c6af74..de03fec 100644 --- a/WasteManagementConfigurator/form.json +++ b/WasteManagementConfigurator/form.json @@ -24,7 +24,8 @@ { "type": "SelectCategory", "name": "TargetCategory", - "caption": "Target Category:" + "caption": "Target Category:", + "visible": false } ], "actions": [ diff --git a/WasteManagementConfigurator/module.php b/WasteManagementConfigurator/module.php index f4d5e10..09c1aad 100644 --- a/WasteManagementConfigurator/module.php +++ b/WasteManagementConfigurator/module.php @@ -40,8 +40,14 @@ public function ApplyChanges() public function GetConfigurationForm() { $form = json_decode(file_get_contents(__DIR__ . '/form.json'), true); + // Version check + $version = (float) IPS_GetKernelVersion(); // Save location $location = $this->GetPathOfCategory($this->ReadPropertyInteger('TargetCategory')); + // Enable or disable "TargetCategory" for 6.x + if ($version < 7) { + $form['elements'][2]['visible'] = true; + } // Build configuration list values foreach (static::$PROVIDERS as $key => $value) { $values[] = [ @@ -66,7 +72,7 @@ public function GetConfigurationForm() [ 'moduleID' => $value[1], 'configuration' => ['serviceProvider' => $key], - 'location' => $location, + 'location' => ($version < 7) ? $location : [], ], ], ]; @@ -81,7 +87,7 @@ public function GetConfigurationForm() [ 'moduleID' => $value[1], 'configuration' => ['serviceProvider' => $key], - 'location' => $location, + 'location' => ($version < 7) ? $location : [], ], ], ]; diff --git a/library.json b/library.json index 3ecfaf1..880ad55 100644 --- a/library.json +++ b/library.json @@ -3,10 +3,10 @@ "author": "Wilkware (@Pitti)", "url": "https://wilkware.de", "compatibility": { - "version": "6.0" + "version": "6.4" }, "name": "Abfallwirtschaft", - "version": "3.6", - "build": 20230102, - "date": 1672657200 + "version": "4.0", + "build": 20231119, + "date": 1700391600 } \ No newline at end of file diff --git a/libs/ServiceHelper.php b/libs/ServiceHelper.php index 65144a5..6b042a6 100644 --- a/libs/ServiceHelper.php +++ b/libs/ServiceHelper.php @@ -27,6 +27,7 @@ trait ServiceHelper 'abpio' => [2, '{53922265-6F58-E833-34A1-52D44D1C8D3F}', 'Abfall.IO', 'abfallplus.de', 'Abfall+ ist die Lösung für elektronische Bürgerdienste in der Abfallwirtschaft!'], 'mymde' => [3, '{BCB84068-9194-754C-436F-F10BDD8E51BE}', 'MyMüll', 'mymuell.de', 'Abfall und Wertstoffe sauber organisiert!'], 'regio' => [4, '{085BA8B2-118B-208D-3664-3C230C55952E}', 'AbfallNavi', 'regioit.de', 'Der digitale Abfallkalender der regio IT für die Abfallentsorgung.'], + 'maxde' => [5, '{2EC7DFA0-62D9-2E92-ADB1-6B8201D142FA}', 'MüllMax', 'muellmax.de', 'Abfallkalender – barrierefrei online und gedruckt!'], ]; /** @@ -107,4 +108,42 @@ private function ExtractClients(string $url): array // return the events return $data['data']['clients']; } -} + + /** + * Order assoziate array data + * + * @param array $arr + * @param string|null $key + * @param string $direction + */ + private function OrderData(array $arr, string $key = null, string $direction = 'ASC') + { + // Check "order by key" + if (!is_string($key) && !is_array($key)) { + throw new InvalidArgumentException('Order() expects the first parameter to be a valid key or array'); + } + // Build order-by clausel + $props = []; + if (is_string($key)) { + $props[$key] = strtolower($direction) == 'asc' ? 1 : -1; + } else { + $i = count($key); + foreach ($key as $k => $dir) { + $props[$k] = strtolower($dir) == 'asc' ? $i : -($i); + $i--; + } + } + // Sort by passed keys + usort($arr, function ($a, $b) use ($props) { + foreach ($props as $key => $val) { + if ($a[$key] == $b[$key]) { + continue; + } + return $a[$key] > $b[$key] ? $val : -($val); + } + return 0; + }); + // Return sorted array + return $arr; + } +} \ No newline at end of file diff --git a/libs/VisualisationHelper.php b/libs/VisualisationHelper.php new file mode 100644 index 0000000..c6f21ed --- /dev/null +++ b/libs/VisualisationHelper.php @@ -0,0 +1,205 @@ + + * @copyright 2021 Heiko Wilknitz + * @link https://wilkware.de + * @license https://creativecommons.org/licenses/by-nc-sa/4.0/ CC BY-NC-SA 4.0 + */ + +declare(strict_types=1); + +/** + * Helper class for support new tile visu. + */ +trait VisualisationHelper +{ + /** + * Build a html widget for waste dates. + * + * @param array $waste Array with waste names and the next pick-up date. + */ + protected function BuildWidget(array $waste, string $skin) + { + $this->SendDebug(__FUNCTION__, $waste); + // (0) tabel with all infos + $table = []; + // (1) build new data array + foreach($waste as $key => $value) { + $id = @$this->GetIDForIdent($value['ident']); + if ($id !== false) { + $name = IPS_GetName($id); + $type = $this->RecognizeWaste($name); + $date = $value['date']; + $days = $this->CalcDaysToDate($date); + $table[] = ['name' => $name, 'type' => $type, 'date' => $date, 'days' => $days ]; + } + } + // (2) sort waste by date + usort($table, function ($a, $b) { + return strtotime($a['date']) - strtotime($b['date']); + }); + // (3) build html texts + $next = ''; + // show today only if no date tommorow + if (strtotime($table[0]['date']) === strtotime('today')) { + $next = $this->Translate('Heute'); + } + // tommorow overrule today + if (strtotime($table[0]['date']) === strtotime('tomorrow')) { + $next = $this->Translate('Morgen'); + } + // generate widget for tile visu + if ($next == '') { + $next = date('d.m.', strtotime($table[0]['date'])); + $next = $this->Translate(date('D', strtotime($table[0]['date']))) . '. ' . $next; + } + $textS = ''; + $textM = ''; + $textL = ''; + // date infos + $days = $table[0]['days']; + $day = strtotime($table[0]['date']); + $wd = $this->Translate (date('l')); + $sd = date('d.m.', $day); + $wn = $table[0]['name']; + if($days > 1) { + $textS = "in $days " . $this->Translate('days'); + $textM = "$wn

" . $this->Translate('Next pickup:') . "
in $days " . $this->Translate('days') . '
' . $this->Translate('on') . " $wd $sd"; + } else { + $textS = $next; + $textM = "$wn

" . $this->Translate('Next pickup:') . "
$next
" . $this->Translate('on') . " $wd $sd"; + } + // table rows + $textL = ''; + foreach($table as $row) { + if ($row['days'] == 0) $text = $this->Translate('Today'); + if ($row['days'] == 1) $text = $this->Translate('Tomorrow'); + if ($row['days'] >= 2) $text = $row['days'] . ' ' . $this->Translate('days'); + $textL .= ''; + $textL .= ''; + $textL .= '' . $row['name'] . ''; + $textL .= '' . $row['date'] . ''; + $textL .= '' . $text . ''; + $textL .= ''; + } + // (4) assamble cards + $removal = $this->Translate('Removal'); + $pickup = $this->Translate('Pickup'); + $date = $this->Translate('Date'); + $tbc = ($skin == 'light') ? '#D7D6D6' : '#4A4B4D'; + $html = ' + + + +
+
+ +
' . $textS. '
+
+
+ +
+
+ +
' . $textM. '
+
+
+ +
+ + + + ' . + $textL .' +
' . $removal . '' . $date . '' . $pickup . '
+
+ + + +'; + $this->SetValueString('Widget', $html); + } + + /** + * Calculate days up to a date + * + * @param mixed $startDate + * @param null $endDate + * @return int Number of days + */ + private function CalcDaysToDate($startDate, $endDate = null) + { + if (empty($endDate)) $endDate = date('Y-m-d'); + return round(abs(strtotime($endDate) - strtotime($startDate)) / (60 * 60 * 24)); + } + + /** + * Recognize waste type for given name + * + * @param mixed $name + */ + private function RecognizeWaste($name) + { + if(preg_match("/(papier|pappe|zeitung)/i", $name)){ + return 'blue'; + } + if(preg_match("/(bio|grün|garten|baum|schnittgut)/i", $name)){ + return 'green'; + } + if(preg_match("/(gelb|plast|pvc)/i", $name)){ + return 'yellow'; + } + if(preg_match("/(schadstoff|sonder|sperr)/i", $name)){ + return 'red'; + } + // Rest or all others + return 'gray'; + } +} diff --git a/libs/_traits.php b/libs/_traits.php index 90777a9..a114d82 100644 --- a/libs/_traits.php +++ b/libs/_traits.php @@ -190,3 +190,4 @@ require_once __DIR__ . '/../libs/ProfileHelper.php'; require_once __DIR__ . '/../libs/ServiceHelper.php'; require_once __DIR__ . '/../libs/VariableHelper.php'; +require_once __DIR__ . '/../libs/VisualisationHelper.php';