Heizkörperthermostat Heizprogramme per WebFront einstellen

Kannst ja das hier mal versuchen, aber mehr kann ich dann wahrscheinlich auch nicht helfen …

<?php
################################################################################
# Script:   HomeMatic.TempSchedule.ips.php
# Version:  1.2.20200219
# Author:   Heiko Wilknitz (@Pitti)
#           Basierend auf Zapp (2011) for the IPS Community
#           Erweitert von Swifty (Heizungs_Scripte v 0.1 - 15.02.2014)
#
# Auslese, Modifizieren und Speichern von Temperatur-Wochenplan
# von HomeMatic(IP)-Themostaten.
#
# !!! KEINE ÜBERNAHME VON GARANTIEN - NUTZUNG AUF EIGENE GEFAHR !!!
#
# ------------------------------ Installation ----------------------------------
#
# Dieses Skript richtet automatisch alle nötigen Objekte bei manueller
# Ausführung ein. Eine weitere manuelle Ausführung setzt alle benötigten Objekte
# wieder auf den Ausgangszustand.
#
# - Neues Skript erstellen
# - Diesen PHP-Code hineinkopieren
# - Abschnitt 'Konfiguration' den eigenen Gegebenheiten anpassen 
# - Skript Abspeichern
# - Skript Ausführen
# - Visualisierung per Link auf entstandene Variablen erstellen
#
# ------------------------------ Visualisierung --------------------------------
#
# Kann natürlich jeder machen wie er möchte, hier ein schematischer Vorschlag
# wie man vorgehen könnte:
#
# Zweischpaltiges Splitpane Layout (Vertikal 50:50)
# 
#   LINKE SEITE                             RECHTE SEITE
# 1. Link auf "Zimmer"                   Dummy Modul "Profil editieren"
# 2. Link auf "Wochenprogramm"            1. Link auf "Tag"
# 3. Link auf "Profil"                    2. Link auf "Zeitabschnitt"
# 4. Link auf "Wochenprofil"              3. Link auf "Zeit"
# 5. Link auf "Tagesprofil"               4. Link auf "Temperatur"
#                                         5. Link auf "Abschnitt"
#                                        Dummy Modul "Tagesprofil kopieren"
#                                         1. Link auf "Tagesauswahl"
#                                         2.Link auf "Kopieren"
#                                        Dummy Modul "Wochenprofil übertragen"
#                                         1. Link auf "Zimmerauswahl"
#                                         2. Link auf "Programmauswahl"
#                                         1. Link auf "Übertragen"
#
# ------------------------------ Changelog -------------------------------------
#
# 02.01.2019 - Initalversion (v1.0)
# 22.02.2019 - Bugfixes, mehr Doku(Hinweise) und Speichern ermöglicht (v1.1)
# 19.02.2020 - Bugfixes, ReadParamSet erweitert für Request ohne "channel"
#
# ------------------------------ Konfiguration ---------------------------------
#
# RPC clients
$client = array();
#
# Service IP (CCUx)
$ip = 'xxx.xxx.x.x';
#
# Nach dem Übertragen eines Profils an die Geräte wird eine Meldung ausgegeben.
# Soll dafür WFC_SendNotification verwendet werden dann bitte die notwendige
# WebFront-ID hinterlegen, ansonsten erfolgt eine nicht ganz so schöne
# Echo-Ausgabe, welche leider die Überschrift "Fehler" hat :(
$wfc = 0;
#
# BidCos Service Port (true = vorhanden & aktiv) 
$service = array(
    array('ID' => 0, 'TYPE' =>'RF', 'PORT' =>2001, 'ACTIVE' => true),   // HM
    array('ID' => 1, 'TYPE' =>'IP', 'PORT' =>2010, 'ACTIVE' => true),   // HM IP
    array('ID' => 2, 'TYPE' =>'WD', 'PORT' =>2000, 'ACTIVE' => false)   // Wired
);
#
# Räume (siehe nachfolgende Elementbelegung) 
#  (0) Logische Id (einfach von 0 durchnummerieren, oder eigene Logik verwenden)
#  (1) Name des Raumes
#  (2) Icon (sollte leer bleiben)
#  (3) Farbe (RGB-Wert, default -1)
#  (4) Wandthermostat-ID (oder auch direkt ein Heizkörperthermostat möglich)
#  (5) 1.Heizkörperthermostat-ID [mit Wandtherostat gekoppelt] - optional
#  (6) 2.Heizkörperthermostat-ID [mit Wandtherostat gekoppelt] - optional
#  (+) x.Heizkörperthermostat-ID [mit Wandtherostat gekoppelt] - optional
#
# HINWEIS IDs:
#  HmIP-WTH-2       - Kanal:1 - HEATING_CLIMATECONTROL_TRANSCEIVER
#  HmIP-eTRV        - Kanal:1 - HEATING_CLIMATECONTROL_TRANSCEIVER
#  HmIP-eTRV-2      - Kanal:1 - HEATING_CLIMATECONTROL_TRANSCEIVER
#  HM-CC-TC         - Kanal:2 - CLIMATECONTROL_REGULATOR
#  HM-CC-RT-DN      - Kanal:2 - CLIMATECONTROL_RECEIVER (ungetestet!!!)
#  HM-TC-IT-WM-W-EU - Kanal:2 - THERMALCONTROL_TRANSMIT (ungetestet!!!)
$room = array (  
    array(12, '1 - KG: Hoppyraum', '', -1, 50660, 26857),
    array(21, '2 - EG: Küche', '', -1, 21113, 23635, 11542),
    array(22, '2 - EG: Wohnen', '', -1, 23498, 58689),
    array(31, '3 - OG: Bad', '', -1, 56832, 33650),
    array(32, '3 - OG: Gäste', '', -1, 20199, 11234),
    array(33, '3 - OG: Arbeit', '', -1, 55797, 56530),
    array(34, '3 - OG: Schlafen', '', -1, 30734, 43879, 52032),
    array(41, '4 - DG: Studio', '', -1, 20652, 52057),
    array(42, '4 - DG: Bad', '', -1, 50467, 13788),
);
# Wochenplan Profil
$program = array (
    array(1, 'Arbeitswoche', '', 255),  // oder Normal
    array(2, 'Zuhause', '', 255),       // oder Frei
    array(3, 'Aus', '', 255)            // oder Abwesend
);
# Auslesen/Speichern Profil
$readwrite = array(
    array(0, 'Auslesen', '', 0x008000),
    array(1, 'Speichern', '', 0xFF0000)
);
# Kopieren Profil 
$copy = array(
    array(0, ">", "", -1),
    array(1, "Kopieren", "", 0x008000),
);
# Übertragen Profil 
$move = array(
    array(0, ">", "", -1),
    array(1, "Übertragen", "", 0x008000),
);
# Wochentag Profil
$day = array(
    array(0, 'Mo', '', -1),
    array(1, 'Di', '', -1),
    array(2, 'Mi', '', -1),
    array(3, 'Do', '', -1),
    array(4, 'Fr', '', -1),
    array(5, 'Sa', '', -1),
    array(6, 'So', '', -1)
);
# Zeit Profil
$time = array(
    array(1, '-1 h', '', 0x00FF00),
    array(2, '-10 min', '', 0x00FF00),
    array(3, '+10 min', '', 0xFF8000),
    array(4, '+1 h', '', 0xFF8000)
);
# Temperatur Profil
$temperature = array(
    array(1, '-1 °C', '', 0x3366FF),
    array(2, '-0,5 °C', '', 0x3366FF),
    array(3, '+0,5 °C', '', 0xFF0000),
    array(4, '+1 °C', '', 0xFF0000)
);
# Abschnitt Profil
$slot = array(
    array(1, 'Löschen', '', 0xFFCC99),
    array(2, 'Anfügen', '', 0xCCFFCC)
);
# Wochentage
$weekday = array("MONDAY","TUESDAY","WEDNESDAY","THURSDAY","FRIDAY","SATURDAY","SUNDAY");
#
################################################################################

################################################################################
# HINWEIS: Ich arbeite mit einer alten Version der Xml-RPC API Datei,
#          welche ich extra patchen musste damit alles funktioniert.
#          Wer das nicht möchte kann auch die Version 4.3.0 installieren!
#          DANN die nachfolgende Zeile durch ...
#          require "phpxmlrpc-4.3.0/lib/xmlrpc.inc"; oder so ersetzen!!!
require "__xmlrpc.inc.php" ;
################################################################################

//Init XMLRPC clients
Init();
// wichtig, da sonst am Tag der Zeitumstellung WZ/SZ Konflikte auftreten.
date_default_timezone_set('UTC'); 

// INSTALLATION
    if ($_IPS['SENDER']=='Execute') {
    $pos = 0;
    // Zimmer
    $vpn = "HM.Heating.Room";
    $vid = CreateVariableByName($_IPS['SELF'], "Zimmer", 1);
    CreateProfileInteger($vpn, 'HouseRemote', '', '', 0, 0, 0, 0, $room);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    // Wochenprogramm
    $vpn = "HM.Heating.Program";
    $vid = CreateVariableByName($_IPS['SELF'], "Wochenprogramm", 1);
    CreateProfileInteger($vpn, 'Temperature', '', '', 0, 0, 0, 0, $program);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    SetValue($vid, 1);
    // Auslese/Speichern Button
    $vpn = "HM.Heating.ReadWrite";
    $vid = CreateVariableByName($_IPS['SELF'], "Profil", 1);
    CreateProfileInteger($vpn, 'Script', '', '', 0, 0, 0, 0, $readwrite);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    SetValue($vid, 0);
    // Wochen(Temperatur)profil
    $vid = CreateVariableByName($_IPS['SELF'], 'Wochenprofil', 3);
    IPS_SetIcon($vid, "Calendar");
    IPS_SetVariableCustomProfile($vid, '~HTMLBox');
    IPS_SetPosition($vid, $pos++);
    // Tages(Temperatur)profil
    $vid = CreateVariableByName($_IPS['SELF'], 'Tagesprofil', 3);
    IPS_SetIcon($vid, "Clock");
    IPS_SetVariableCustomProfile($vid, '~HTMLBox');
    IPS_SetPosition($vid, $pos++);
    // Tagesauswahl
    $vpn = "HM.Heating.Day";
    $vid = CreateVariableByName($_IPS['SELF'], "Tag", 1);
    CreateProfileInteger($vpn, 'Calendar', '', '', 0, 0, 0, 0, $day);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    // Zeitabschnitt auswählen
    $vpn = "HM.Heating.Slot";
    $vid = CreateVariableByName($_IPS['SELF'], "Zeitabschnitt", 1);
    CreateProfileInteger($vpn, 'Database', '', '. Zeitabschnitt', 1, 3, 1, 0);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    // Zeit editieren
    $vpn = "HM.Heating.Time";
    $vid = CreateVariableByName($_IPS['SELF'], "Zeit", 1);
    CreateProfileInteger($vpn, 'Clock', '', '', 0, 0, 0, 0, $time);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    // Temperatur editieren
    $vpn = "HM.Heating.Temperature";
    $vid = CreateVariableByName($_IPS['SELF'], "Temperatur", 1);
    CreateProfileInteger($vpn, 'Temperature', '', '', 0, 0, 0, 0, $temperature);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    // Abschnitt editieren
    $vpn = "HM.Heating.Edit";
    $vid = CreateVariableByName($_IPS['SELF'], "Abschnitt", 1);
    CreateProfileInteger($vpn, 'Edit', '', '', 0, 0, 0, 0, $slot);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    // Tagesauswahl kopieren
    $vpn = "HM.Heating.Day";
    $vid = CreateVariableByName($_IPS['SELF'], "Tagesauswahl", 1);
    CreateProfileInteger($vpn, 'Calendar', '', '', 0, 0, 0, 0, $day);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    // Kopieren
    $vpn = "HM.Heating.Copy";
    $vid = CreateVariableByName($_IPS['SELF'], "Kopieren", 1);
    CreateProfileInteger($vpn, 'Script', '', '', 0, 0, 0, 0, $copy);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    SetValue($vid, 0);
    // Zimmerauswahl
    $vpn = "HM.Heating.Room";
    $vid = CreateVariableByName($_IPS['SELF'], "Zimmerauswahl", 1);
    CreateProfileInteger($vpn, 'HouseRemote', '', '', 0, 0, 0, 0, $room);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    // Programmauswahl
    $vpn = "HM.Heating.Program";
    $vid = CreateVariableByName($_IPS['SELF'], "Programmauswahl", 1);
    CreateProfileInteger($vpn, 'Temperature', '', '', 0, 0, 0, 0, $program);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    SetValue($vid, 1);
    // Übertragen
    $vpn = "HM.Heating.Move";
    $vid = CreateVariableByName($_IPS['SELF'], "Übertragen", 1);
    CreateProfileInteger($vpn, 'Script', '', '', 0, 0, 0, 0, $move);
    IPS_SetVariableCustomProfile($vid, $vpn);
    IPS_SetVariableCustomAction($vid, $_IPS['SELF']);
    IPS_SetPosition($vid, $pos++);
    SetValue($vid, 0);
    // Profile Cache
    $vid = CreateVariableByName($_IPS['SELF'], "Profiles", 3);
    IPS_SetHidden($vid, true);
    IPS_SetPosition($vid, -1);
    // Types Cache
    $vid = CreateVariableByName($_IPS['SELF'], "Types", 3);
    IPS_SetHidden($vid, true);
    IPS_SetPosition($vid, -1);
    }
    // AKTION VIA WEBFRONT
    else if($_IPS['SENDER'] == "WebFront") {
    // Aktion
    $name = IPS_GetName($_IPS['VARIABLE']);
    // ZIMMER -------------------------------------------------------------------
    if($name == 'Zimmer') {
        // Welcher Raum?
        $rn = $_IPS['VALUE'];
        // Welches Wochenprogramm?
        $vid = CreateVariableByName($_IPS['SELF'], 'Wochenprogramm', 1);
        $wp = GetValue($vid);
        // Welcher Tag?
        $vid = CreateVariableByName($_IPS['SELF'], "Tag", 1);
        $wd = GetValue($vid);
        // Rendern
        RenderProfile($rn, $wp, $wd);
    }
    // WOCHENPROGRANN -----------------------------------------------------------
    if($name == 'Wochenprogramm') {
        // Welches Zimmer?
        $vid = CreateVariableByName($_IPS['SELF'], "Zimmer", 1);
        $rn = GetValue($vid);
        // Welches Wochenprogramm?
        $wp = $_IPS['VALUE'];	
        // Welcher Tag?
        $vid = CreateVariableByName($_IPS['SELF'], "Tag", 1);
        $wd = GetValue($vid);
        // Rendern
        RenderProfile($rn, $wp, $wd);
    }
    // AUSLESEN/SPEICHERN -------------------------------------------------------
    if( $name == 'Profil') {
        // Welches Zimmer?
        $vid = CreateVariableByName($_IPS['SELF'], "Zimmer", 1);
        $rn  = GetValue($vid);	
        // Welches Wochenprogramm?
        $vid = CreateVariableByName($_IPS['SELF'], 'Wochenprogramm', 1);
        $wp  = GetValue($vid);
        // Welcher Tag?
        $vid = CreateVariableByName($_IPS['SELF'], "Tag", 1);
        $wd = GetValue($vid);
        // AUSLESEN
        if($_IPS['VALUE'] == 0) {
            // Temperatur Profil vom Gerät auslesen
            foreach($room as $value) {
                if($value[0] == $rn) {
                    $profile = ReadTempProfile($value[4], false);
                    SetWeeklyProfile($rn, $profile);
                    break;
                }
            }
            // Rendern
            RenderProfile($rn, $wp, $wd);
        }
        // SPEICHERN
        if($_IPS['VALUE'] ==1) {
            // Wochenprofil ermitteln
            $profile = GetWeeklyProfile($rn, $wp);
            // Teste Integrität der Tagesprofile
            $check = CheckWeeklyProfile($profile);
            if($check == "OK") {
                foreach($room as $value) {
                    if($value[0] == $rn) {
                        // Profil zum Gerät übertragen
                        $count = count($value);
                        for($d = 4; $d < $count; $d++) {
                            //echo $value[$d].PHP_EOL;
                            $check = WriteTempProfile($value[$d], $profile, $wp);
                            // IPS_Sleep(2000); 
                        }
                    }
                }
                if ($check == true) {
                    $check ="Speichern Erfolgreich";
                }
            }
            // Erolgsmeldung?!
            if($wfc != 0) {
                WFC_SendNotification($wfc, 'HM Heizungsplan', $check, 'Information', 5);
            }
            else {
                echo $check;
            }
        }
        $_IPS['VALUE'] = 0;
    }
    // TAG ----------------------------------------------------------------------
    if( $name == 'Tag') {
        // Welches Zimmer?
        $vid = CreateVariableByName($_IPS['SELF'], "Zimmer", 1);
        $rn  = GetValue($vid);	
        // Welches Wochenprogramm?
        $vid = CreateVariableByName($_IPS['SELF'], 'Wochenprogramm', 1);
        $wp  = GetValue($vid);
        // Welcher Tag?
        $wd  = $_IPS['VALUE'];
        // Rendern
        RenderProfile($rn, $wp, $wd);
    }
    // ZEITABSCHNITT ------------------------------------------------------------
    if( $name == 'Zeitabschnitt') {
        // Welches Zimmer?
        $vid = CreateVariableByName($_IPS['SELF'], "Zimmer", 1);
        $rn  = GetValue($vid);	
        // Welches Wochenprogramm?
        $vid = CreateVariableByName($_IPS['SELF'], 'Wochenprogramm', 1);
        $wp  = GetValue($vid);
        // Welcher Tag?
        $vid = CreateVariableByName($_IPS['SELF'], "Tag", 1);
        $wd = GetValue($vid);
        // Profil extrahieren
        $profile = GetWeeklyProfile($rn, $wp);
        $profile = GetDailyProfile($profile, $wd);
        // Welcher Zeitabschnitt? 
        $ts = $_IPS['VALUE'];
        // Render Tagesprofil
        $vid = CreateVariableByName($_IPS['SELF'], 'Tagesprofil', 3);
        SetValue($vid, RenderDailyProfile($profile, $ts));		
    }
    // ZEIT EDITIEREN -----------------------------------------------------------
    if($name == 'Zeit') {
        // Welches Zimmer?
        $vid = CreateVariableByName($_IPS['SELF'], "Zimmer", 1);
        $rn = GetValue($vid);
        // Welches Wochenprogramm?
        $vid = CreateVariableByName($_IPS['SELF'], 'Wochenprogramm', 1);
        $wp  = GetValue($vid);
        // Welcher Tag?
        $vid = CreateVariableByName($_IPS['SELF'], "Tag", 1);
        $wd = GetValue($vid);
        // Welcher Zeitabschnitt? 
        $vid = CreateVariableByName($_IPS['SELF'], "Zeitabschnitt", 1);
        $ts = GetValue($vid);
        // Wochenprofil ermitteln
        $profile = GetWeeklyProfile($rn, $wp);
        // Tagesprofil ermitteln
        $profile = GetDailyProfile($profile, $wd);
        // Aktion nur für die ersten Zeitabschnitte
        if($ts < count($profile['EndTimes'])) {
            // Verhindert dass die Zeit des letzten Slots geändert wird (immer 24:00)
            if($ts == 1) {
                $start = "00:00";
            }
            else {
                $start = $profile['EndTimes'][$ts-2];
            }
            $end  = $profile['EndTimes'][$ts-1];
            $next = $profile['EndTimes'][$ts];
            // Welche Aktion?		
            switch($_IPS['VALUE']) {
                case 1: // -1h
                    if((strtotime($end)-(60*60))> strtotime($start)) {
                        $end = date("H:i", (strtotime($end)-(60*60)));
                    }
                    $profile['EndTimes'][$ts-1] = $end;
                    break;
                case 2: // -10min
                    if((strtotime($end)-(10*60))> strtotime($start)) {
                        $end = date("H:i", (strtotime($end)-(10*60)));
                    }
                    $profile['EndTimes'][$ts-1] = $end;
                    break;
                case 3: // +10min
                    if((strtotime($end)+(10*60))< strtotime($next)) {
                        $end = date("H:i", (strtotime($end)+(10*60)));
                    }
                    $profile['EndTimes'][$ts-1] = $end;
                    break;
                case 4: // +1h
                    if((strtotime($end)+(60*60))< strtotime($next)) {
                        $end = date("H:i", (strtotime($end)+(60*60)));
                    }
                    $profile['EndTimes'][$ts-1] = $end;
                    break;
            }
            // Schreiben
            SetDailyProfile($rn, $wp, $wd, $profile);
            // Rendern
            RenderProfile($rn, $wp, $wd, $ts);
        }
        // Keine Auswahl
        $_IPS['VALUE'] = 0;		 	   
    }
    // TEMPERATUR EDITIEREN -----------------------------------------------------
    if($name == 'Temperatur') {
        // Welches Zimmer?
        $vid = CreateVariableByName($_IPS['SELF'], "Zimmer", 1);
        $rn = GetValue($vid);
        // Welches Wochenprogramm?
        $vid = CreateVariableByName($_IPS['SELF'], 'Wochenprogramm', 1);
        $wp  = GetValue($vid);
        // Welcher Tag?
        $vid = CreateVariableByName($_IPS['SELF'], "Tag", 1);
        $wd = GetValue($vid);
        // Welcher Zeitabschnitt? 
        $vid = CreateVariableByName($_IPS['SELF'], "Zeitabschnitt", 1);
        $ts = GetValue($vid);
        // Wochenprofil ermitteln
        $profile = GetWeeklyProfile($rn, $wp);
        // Tagesprofil ermitteln
        $profile = GetDailyProfile($profile, $wd);
        // Welche Temperatur?
        $temperatur = $profile['Values'][$ts-1];
        // Welche Aktion?		
        switch($_IPS['VALUE']) {
            case 1: // -1°C
                if(($temperatur-1) >= 4.99) {
                    $temperatur = $temperatur-1;
                    $profile['Values'][$ts-1] = $temperatur;
                }
                break;
            case 2: // -0.5°C
                if(($temperatur-0.5) > 4.9) {
                    $temperatur = $temperatur-0.5;
                    $profile['Values'][$ts-1] = $temperatur;
                }
                break;
            case 3: // +0.5°C
                if(($temperatur+0.5) < 30.1) {
                    $temperatur = $temperatur+0.5;
                    $profile['Values'][$ts-1] = $temperatur;
                }
                break;
            case 4: // +1°C
                if(($temperatur+1) <= 30.01) {
                    $temperatur = $temperatur+1;
                    $profile['Values'][$ts-1] = $temperatur;
                }
                break;
        }
        // Schreiben
        SetDailyProfile($rn, $wp, $wd, $profile);
        // Rendern
        RenderProfile($rn, $wp, $wd, $ts);
        // Keine Auswahl
        $_IPS['VALUE'] = 0;
    }
    // ABSCHNITT EDITIEREN ------------------------------------------------------
    if( $name == 'Abschnitt') {
        // Welches Zimmer?
        $vid = CreateVariableByName($_IPS['SELF'], "Zimmer", 1);
        $rn = GetValue($vid);
        // Welches Wochenprogramm?
        $vid = CreateVariableByName($_IPS['SELF'], 'Wochenprogramm', 1);
        $wp  = GetValue($vid);
        // Welcher Tag?
        $vid = CreateVariableByName($_IPS['SELF'], "Tag", 1);
        $wd = GetValue($vid);
        // Welcher Zeitabschnitt? 
        $vid = CreateVariableByName($_IPS['SELF'], "Zeitabschnitt", 1);
        $ts = GetValue($vid);
        // Wochenprofil ermitteln
        $profile = GetWeeklyProfile($rn, $wp);
        // Tagesprofil ermitteln
        $profile = GetDailyProfile($profile, $wd);
        // Wieviel Zeitabschnitte?
        $count = count($profile['EndTimes']);
        // Welche Aktion?		
        switch($_IPS['VALUE']) {
            case 1: // Löschen
                // letzter TimeSlot darf nicht gelöscht werden
                if ($count >1) {
                    array_splice($profile['EndTimes'], $ts-1, 1);
                    array_splice($profile['Values'], $ts-1, 1);
                    // letzten TimeSlot Ende immer 24:00
                    $profile['EndTimes'][$count-2]="24:00";
                }
                break;
            case 2: // Anfügen
                // max 13 TimeSlots zulässig (manche können auch 24, aber das sollte reichen)
                If ($count <13)  
                {
                    array_splice($profile['EndTimes'], $count, 0, "24:00");
                    array_splice($profile['Values'], $count, 0, "17");
                    // minimaler TimeSlot ist 10 min
                    $profile['EndTimes'][$count-1]="23:50";
                }
                break;
        }
        // Wurde was geändert?
        if($count <> count($profile['EndTimes'])) {
            SetDailyProfile($rn, $wp, $wd, $profile);
            // Rendern
            RenderProfile($rn, $wp, $wd);
        }
        // Keine Auswahl
        $_IPS['VALUE'] = 0;
    }
    // TAGESPROFIL KOPIEREN -----------------------------------------------------
    if( $name == 'Kopieren') {
        if($_IPS['VALUE'] ==1) {
            // Welchem Zimmer?
            $vid = CreateVariableByName($_IPS['SELF'], "Zimmer", 1);
            $rn = GetValue($vid);
            // Welches Wochenprogramm?
            $vid = CreateVariableByName($_IPS['SELF'], 'Wochenprogramm', 1);
            $wp  = GetValue($vid);
            // Von welcher Tag?
            $vid = CreateVariableByName($_IPS['SELF'], "Tag", 1);
            $wd = GetValue($vid);
            // Nach Welchen Tag? 
            $vid = CreateVariableByName($_IPS['SELF'], "Tagesauswahl", 1);
            $ta = GetValue($vid);
            if($wd == $ta) {
                echo ('Bitte anderen Tag auswählen!');
            }
            else {
                // Wochenprofil ermitteln
                $profile = GetWeeklyProfile($rn, $wp);
                // Tagesprofil von 
                $profile = GetDailyProfile($profile, $wd);
                // kopieren nach
                SetDailyProfile($rn, $wp, $ta, $profile);
                // Rendern
                RenderProfile($rn, $wp, $wd);
            }
        }
        $_IPS['VALUE'] = 0;
    }
    // WOCHENPROFIL ÜBERTRAGEN --------------------------------------------------
    if( $name == 'Übertragen') {
        if($_IPS['VALUE'] ==1) {
            // Welchem Zimmer?
            $vid = CreateVariableByName($_IPS['SELF'], "Zimmer", 1);
            $rn = GetValue($vid);
            // Welches Wochenprogramm?
            $vid = CreateVariableByName($_IPS['SELF'], 'Wochenprogramm', 1);
            $wp  = GetValue($vid);
            // Nach welchen Zimmer?
            $vid = CreateVariableByName($_IPS['SELF'], "Zimmerauswahl", 1);
            $za = GetValue($vid);
            // Nach welchen Program? 
            $vid = CreateVariableByName($_IPS['SELF'], "Programmauswahl", 1);
            $pa = GetValue($vid);
            if(($rn == $za) and ($wp == $pa)) {
                echo ('Auf sich selber zu übertragen macht keinen Sinn!');
            }	
            else {
                // Wochenprofil holen
                $profile = GetWeeklyProfile($rn, $wp);
                // Übertragen
                SetWeeklyProfile($za, $profile, $pa);
            }
        }
        $_IPS['VALUE'] = 0;
    }
    // DATENÜBERNAHME ------------------------------------------------------
    SetValue($_IPS['VARIABLE'], $_IPS['VALUE']);
}

# ------------------------------ Funktionen ------------------------------------

// Erzeugt pro aktiven Interface ein Client.
function Init() {
    global $ip, $service, $client;
    # Return Code 
    $ret = true;
    # Check all Services
    foreach($service as $s) {
        if($s['ACTIVE'] == true) {
            if (!isset($client[$s['TYPE']]) || $client[$s['TYPE']] !== false) {
                $client[$s['TYPE']] = new xmlrpc_client("http://".$ip.":".$s['PORT']);
            if ($client[$s['TYPE']] !== false) {
                    $ret &= true;
                }
                else {
                    $ret = false;
                }
            }
        }
    }
    // client existieren schon
    return false;
}

// Liefert alle Geräte der aktivierten Interfaces 
function DevicesList() {
    global $service, $client;
    //	listDevices
    $request = new xmlrpcmsg('listDevices');
    // merge all together
    $devices = array();
    foreach($service as $s) {
        if($s['ACTIVE'] == true) {
            $ret = Send($request, $s['TYPE']);
            foreach($ret as $device) {
                $device['INTERFACE'] = $s['ID'];
                $devices[] = $device;
            }
            //$devices = array_merge($devices, Send($request, $s['TYPE']));
        }
    }
    return $devices;
}

// Ermittelt den Typ des HM Gerätes (HM terminology)
function DeviceType($device) {
    // Cache auslesen
    $cid = CreateVariableByName($_IPS['SELF'], "Types", 3);
    $types = unserialize(GetValue($cid));
    // HM Adresse vom Device
    $address = explode(":", IPS_GetProperty($device, 'Address'));
    $serial  = $address[0];
    $channel = $address[1];
    // schon mal gelesen
    if(!is_array($types) || array_key_exists($serial, $types) == false) {
        $type = false;
        $list = DevicesList();
        foreach($list as $dev) {
            if (strpos($dev['ADDRESS'], $serial) !== false) {
                $type = $dev['TYPE'].':'.$dev['INTERFACE'];
                $types[$serial] = $type;
                SetValue($cid, serialize($types));
                break;  // We stop at the first one we find
            }
        }
    }
    else
    {
        $type=$types[$serial];
    }
    return $type;
}

// Liest das Temperaturprofil von einem Thermostat für den übergebenen Tag.
// $device: IPS Instance ID
// $day: Name des Tages in English (not case-sensitive) oder false für alle Tage
// $weekprofil: nur für HM-TC-IT-WM-W-EU & HmIP-WTH-2; 
//   gültige Werte 1,2,3; bei -1 werden alle Profile (1-3) zurückgegeben
function ReadTempProfile($device, $day = false, $weekprofil =-1) {
    global $service, $weekday;
    // HM Adresse vom Device
    $address = explode(":", IPS_GetProperty($device, 'Address'));
    $serial  = $address[0];
    $channel = $address[1];

    $days = $weekday;
    $temp = array();

    if ($day != false) {
        if(!in_array($day, $weekday)) die("Error: Unknown Day parameter in function ReadTempProfile!");
        $days = array($day);
    }
    // Was für ein HM Gerätetyp & Interface
    $dt 	= explode(":", DeviceType($device));
    $type = $dt[0];
    $if	= $dt[1];
    // Konvert Interface
    foreach($service as $s) {
        if($s['ID'] == $if) {
            $if = $s['TYPE'];
            break;
        }
    }	
    // HM-CC-TC Profil auslesen (hat nur eins)
    if($type == "HM-CC-TC") {
        $params = ReadParamSet($if, $serial, $channel);
        foreach($days as $day) {
            $thisEndTimes 	= array();
            $thisValues		= array();
            $timePrevious 	= "00:00";
            for($index 	= 1; $index <= 24; $index++) {
                $keyTemp 	= "TEMPERATUR_".strtoupper($day)."_".$index;
                $keyTO 		= "TIMEOUT_".strtoupper($day)."_".$index;
                $thisTemp 	= $params[$keyTemp];
                $thisTO 		= $params[$keyTO];
                $thisTime 	= date('H:i', mktime(0, $thisTO)); // $timePassed + TO
                if($thisTO >= 1440) $thisTime = "24:00";
                $timePrevious = $thisTime;
                array_push($thisEndTimes,	$thisTime);
                array_push($thisValues,		$thisTemp);
                if($thisTO >= 1440) break;
            }
            $temp["P1"][$day]['EndTimes'] = $thisEndTimes;
            $temp["P1"][$day]['Values'] 	= $thisValues;
        }
        return $temp;
    }
    // HM-CC-RT-DN Profil auslesen (hat nur eins)	
    if($type == "HM-CC-RT-DN") {
        $params = ReadParamSet($if, $serial, null);
        foreach($days as $day) {
            $thisEndTimes 	= array();
            $thisValues		= array();
            $timePrevious  = "00:00";
            for($index = 1; $index <= 13; $index++) {
                $keyTemp 	= "TEMPERATURE_".strtoupper($day)."_".$index;
                $keyTO 		= "ENDTIME_".strtoupper($day)."_".$index;
                $thisTemp 	= $params[$keyTemp];
                $thisTO 		= $params[$keyTO];
                $thisTime = date('H:i', mktime(0, $thisTO)); // $timePassed + TO
                if($thisTO >= 1440) $thisTime = "24:00";
                $timePrevious = $thisTime;
                array_push($thisEndTimes,  $thisTime);
                array_push($thisValues,		$thisTemp);
                if($thisTO >= 1440) break;
            }
            $temp["P1"][$day]['EndTimes'] = $thisEndTimes;
            $temp["P1"][$day]['Values'] 	= $thisValues;
        }
        return $temp;
    }	
    // HM-TC-IT-WM-W-EU Profil auslesen (1-3)	
    if($type == "HM-TC-IT-WM-W-EU") {
        $params = ReadParamSet($if, $serial, $channel);
        // 3 Profile
        for ($p=1; $p<=3; $p++) {
            foreach($days as $day) {
                $thisEndTimes 	= array();
                $thisValues		= array();
                $timePrevious 	= "00:00";
                for($index 	= 1; $index <= 13; $index++) {
                    $keyTemp 	= "P". $p ."_TEMPERATURE_".strtoupper($day)."_".$index;
                    $keyTO 		= "P". $p ."_ENDTIME_".strtoupper($day)."_".$index;
                    //* notwendig da Firmeware beim LAN-Adapter abweicht und beim Profil 1 dort das Präfix "P1_" fehlt.
                    if(array_key_exists($keyTemp, $params)) {
                        $thisTemp 	= $params[$keyTemp];
                        $thisTO 		= $params[$keyTO];
                    }
                    else {
                        $keyTemp 	= "TEMPERATURE_".strtoupper($day)."_".$index;
                        $keyTO 		= "ENDTIME_".strtoupper($day)."_".$index;
                        $thisTemp 	= $params[$keyTemp];
                        $thisTO 		= $params[$keyTO];
                    }
                    $thisTime = date('H:i', mktime(0, $thisTO)); // $timePassed + TO
                    if ($thisTO >= 1440) $thisTime = "24:00";
                    $timePrevious = $thisTime;
                    array_push($thisEndTimes,	$thisTime);
                    array_push($thisValues,		$thisTemp);
                    if($thisTO >= 1440) break;
                }
                $temp["P".$p][$day]['EndTimes'] 	= $thisEndTimes;
                $temp["P".$p][$day]['Values'] 	= $thisValues;
            }
        }
        if($weekprofil > 0 and $weekprofil <= 3) {
            return $temp["P".$weekprofil];
        }
        else {
            return $temp;
        }
    }
    // HmIP-WTH-2 || 	HMIP-eTRV || HmIP-eTRV-2 Profil auslesen (1-3 von 6)	
    if($type == "HmIP-WTH-2" or $type =="HmIP-eTRV-2" or $type == "HMIP-eTRV") {
        $params = ReadParamSet($if, $serial, $channel);
        // 3 Profile
        for ($p=1; $p<=3; $p++) {
            foreach($days as $day) {
                $thisEndTimes 	= array();
                $thisValues		= array();
                $timePrevious 	= "00:00";
                for($index 	= 1; $index <= 13; $index++) {
                    $keyTemp 	= "P". $p ."_TEMPERATURE_".strtoupper($day)."_".$index;
                    $keyTO 		= "P". $p ."_ENDTIME_".strtoupper($day)."_".$index;
                    $thisTemp 	= $params[$keyTemp];
                    $thisTO 		= $params[$keyTO];
                    $thisTime 	= date('H:i', mktime(0, $thisTO)); // $timePassed + TO
                    if ($thisTO >= 1440) $thisTime = "24:00";
                    $timePrevious = $thisTime;
                    array_push($thisEndTimes,	$thisTime);
                    array_push($thisValues,		$thisTemp);
                    if($thisTO >= 1440) break;
                }
                $temp["P".$p][$day]['EndTimes'] 	= $thisEndTimes;
                $temp["P".$p][$day]['Values'] 	= $thisValues;
            }
        }
        if($weekprofil > 0 and $weekprofil <= 3) {
            return $temp["P".$weekprofil];
        }
        else {
            return $temp;
        }
    }
    echo $type;
    if($type != "HM-CC-RT-DN" and $type != "HM-CC-TC" and $type != "HM-TC-IT-WM-W-EU" and $type != "HmIP-WTH-2" and $type != "HMIP-eTRV" and $type != "HmIP-eTRV-2") {
        die("Error: ReadTempProfile() Device $device is not of Type HM-CC-TC,HM-CC-RT-DN, HM-TC-IT-WM-W-EU, HmIP-WTH-2, HMIP-eTRV or HmIP-eTRV-2!");
    }
}

// Schreibt das Temperaturprofil in ein Thermostat/Stellantrieb.
// $device: IPS Instance ID
// $profile: Temperaturprofil wie von ReadTempProfile() geliefert
// $weekprofil: nur für HM-TC-IT-WM-W-EU & HmIP-WTH-2; 
//   gültige Werte 1,2,3; bei -1 werden alle Profile (1-3) zurückgegeben
function WriteTempProfile(int $device, array $profile, int $weekprofile=0) {
    global $service, $weekday;
    // HM Adresse vom Device
    $address = explode(":", IPS_GetProperty($device, 'Address'));
    $serial  = $address[0];
    $channel = $address[1];
    // Was für ein HM Gerätetyp & Interface
    $dt 	= explode(":", DeviceType($device));
    $type = $dt[0];
    $if 	= $dt[1];
    // Konvert Interface
    foreach($service as $s) {if($s['ID'] == $if) {$if = $s['TYPE'];break;}}
    // HM-CC-TC Profil schreiben (hat nur eins)
    if($type == "HM-CC-TC") {
        $params = new xmlrpcval();
        foreach($profile as $day => $values) {
            $timePrevious = "00:00";
            for($index=1; $index <= count($values['EndTimes']); $index++) {
                $key = "TEMPERATUR_".strtoupper($day)."_".$index;
                $temp = array($key => new xmlrpcval($values['Values'][$index-1], "double"));
                $params->addStruct($temp);
                $key = "TIMEOUT_".strtoupper($day)."_".$index;
                if ($values['EndTimes'][$index-1] > $timePrevious) {
                    // Convert end time to Timeout
                    $thisDayStart = mktime(0, 0);
                    $timeEndArray = explode(":", $values['EndTimes'][$index-1]);
                    if ($timeEndArray[1] % 10) die("Error: Invalid End Time (must be 10mn increments) for $day at index $index in WriteTempProfile()!");
                    $timeEndts = mktime($timeEndArray[0], $timeEndArray[1]);
                    $timeout = (($timeEndts - $thisDayStart)/60); // TODO, works  ?
                    $paramTime = array($key => new xmlrpcval("$timeout", "int")); // i4
                    $params->addStruct($paramTime);
                }
                else {
                    die("Error: Invalid End Time for $day at index $index in WriteTempProfile()!");
                }
                $timePrevious = $values['EndTimes'][$index-1];
            }
        }
        $request = new xmlrpcmsg("putParamset",
            array(new xmlrpcval("$serial:2", "string"),
                    new xmlrpcval("MASTER", "string"), $params));
        $result = Send($request, $if);
        return true;
    }
    // HM-CC-RT-DN Profil schreiben (hat nur eins)	
    if($type == "HM-CC-RT-DN") {
        $params = new xmlrpcval();
        foreach ($profile as $day => $values) {
            $timePrevious = "00:00";
            for($index=1; $index <= count($values['EndTimes']); $index++) {
                $key = "TEMPERATURE_".strtoupper($day)."_".$index;
                $temp = array($key => new xmlrpcval($values['Values'][$index-1], "double"));
                $params->addStruct($temp);
                $key = "ENDTIME_".strtoupper($day)."_".$index;
                if ($index>13) break; // HM-CC-RT-DN hat nur 13 Tages - Timeslots
                if ($values['EndTimes'][$index-1] > $timePrevious) {
                    // Convert end time to Timeout
                    $thisDayStart = mktime(0, 0);
                    $timeEndArray = explode(":", $values['EndTimes'][$index-1]);
                    if ($timeEndArray[1] % 10) die("Error: Invalid End Time (must be 10mn increments) for $day at index $index in WriteTempProfile()!");
                    $timeEndts = mktime($timeEndArray[0], $timeEndArray[1]);
                    $timeout = (($timeEndts - $thisDayStart)/60); // TODO, works  ?
                    $paramTime = array($key => new xmlrpcval("$timeout", "int")); // i4
                    $params->addStruct($paramTime);
                }
                else {
                    die("Error: Invalid End Time for $day at index $index in WriteTempProfile()!");
                }
                $timePrevious = $values['EndTimes'][$index-1];
            }
        }
        $request = new xmlrpcmsg("putParamset",
            array(new xmlrpcval("$serial", "string"), // no channel NOT TESTED????
                    new xmlrpcval("MASTER", "string"), $params));
        $result = Send($request, $if);
        return true;
    }
    // HM-TC-IT-WM-W-EU Profil schreiben (1-3)	
    if ($type == "HM-TC-IT-WM-W-EU") {
        $prefix="P".$weekprofile."_";
        $params = new xmlrpcval();
        foreach ($profile as $day => $values) {
            $timePrevious = "00:00";
            for ($index=1; $index <= count($values['EndTimes']); $index++) {
                $key = $prefix ."TEMPERATURE_".strtoupper($day)."_".$index;
                $temp = array($key => new xmlrpcval($values['Values'][$index-1], "double"));
                $params->addStruct($temp);
                $key = $prefix ."ENDTIME_".strtoupper($day)."_".$index;
                if ($index>13) break; // HM-TC-IT-WM-W-EU hat nur 13 Tages - Timeslots
                if ($values['EndTimes'][$index-1] > $timePrevious) {
                    // Convert end time to Timeout
                    $thisDayStart = mktime(0, 0);
                    $timeEndArray = explode(":", $values['EndTimes'][$index-1]);
                    if ($timeEndArray[1] % 5) die("Error: Invalid End Time (must be 10mn increments) for $day at index $index in WriteTempProfile()!");
                    $timeEndts = mktime($timeEndArray[0], $timeEndArray[1]);
                    $timeout = (($timeEndts - $thisDayStart)/60); // TODO, works  ?
                    $paramTime = array($key => new xmlrpcval("$timeout", "int")); // i4
                    $params->addStruct($paramTime);
                }
                else {
                    die("Error: Invalid End Time for $day at index $index in WriteTempProfile()!");
                }
                $timePrevious = $values['EndTimes'][$index-1];
            }
        }
        $request = new xmlrpcmsg("putParamset",
            array(new xmlrpcval("$serial", "string"), // no channel NOT TESTED????
                    new xmlrpcval("MASTER", "string"), $params));
        $result = Send($request, $if);
        return true;
    }
    // HmIP-WTH-2 || 	HMIP-eTRV || HmIP-eTRV-2 Profil schreiben (1-3 von 6)	
    if($type == "HmIP-WTH-2" or $type =="HmIP-eTRV-2" or $type == "HMIP-eTRV") {
        $prefix="P".$weekprofile."_";
        $params = new xmlrpcval();
        foreach ($profile as $day => $values) {
            $timePrevious = "00:00";
            for ($index=1; $index <= count($values['EndTimes']); $index++) {
                $key = $prefix ."TEMPERATURE_".strtoupper($day)."_".$index;
                $temp = array($key => new xmlrpcval($values['Values'][$index-1], "double"));
                $params->addStruct($temp);
                $key = $prefix ."ENDTIME_".strtoupper($day)."_".$index;
                if ($index>13) break; // nur 13 Tages - Timeslots
                if ($values['EndTimes'][$index-1] > $timePrevious) {
                    // Convert end time to Timeout
                    $thisDayStart = mktime(0, 0);
                    $timeEndArray = explode(":", $values['EndTimes'][$index-1]);
                    if ($timeEndArray[1] % 5) die("Error: Invalid End Time (must be 10mn increments) for $day at index $index in HMXML_setTempProfile()<br>\n");
                    $timeEndts = mktime($timeEndArray[0], $timeEndArray[1]);
                    $timeout = (($timeEndts - $thisDayStart)/60); // TODO, works  ?
                    $paramTime = array($key => new xmlrpcval("$timeout", "int")); // i4
                    $params->addStruct($paramTime);
                }
                else {
                    die("Error: Invalid End Time for $day at index $index in WriteTempProfile()!");
                }
                $timePrevious = $values['EndTimes'][$index-1];
            }
        }
        $request = new xmlrpcmsg("putParamset",
            array(new xmlrpcval("$serial:$channel", "string"),
                    new xmlrpcval("MASTER", "string"), $params));
        //var_dump($params);
        $result = Send($request, $if);
        return true;
    }
    if($type != "HM-CC-RT-DN" and $type != "HM-CC-TC" and $type != "HM-TC-IT-WM-W-EU" and $type != "HmIP-WTH-2" and $type != "HMIP-eTRV" and $type != "HmIP-eTRV-2") {
        die("Error: WriteTempProfile() Device $device is not of Type HM-CC-TC,HM-CC-RT-DN, HM-TC-IT-WM-W-EU, HmIP-WTH-2, HMIP-eTRV or HmIP-eTRV-2!");
    }
}

// Liest die Parameter von einem Gerät aus.
// $if: HM Inteface
// $adress: HM adress
// $channel: HM device chanvel
// $param: Ein spezifischer Parameter wird ausgelesen (siehe HomeMatic Specficiation),sonst alle
function ReadParamSet($if, $address, $channel, $param = false) {
    // Build request
    $value = $address;
    if($channel != null) {
        $value .= ":".$channel;
    }
    $request = new xmlrpcmsg("getParamset",
        array(new xmlrpcval("$value", "string"), new xmlrpcval("MASTER", "string")));
    $messages = Send($request, $if);
    //var_dump($messages);
    if ($param !== false) return $messages[$param];
    return $messages;
}

// Creates XMLRPC Client Instance and sends request
function Send($request, $type) 
{
    global $client;
    // If the client does not exist, initialise it here
    if (isset($client[$type]) &&  $client[$type] !== false) {
        $response = $client[$type]->send($request);
        if ( $response->errno == 0 ) {
        $messages = php_xmlrpc_decode($response->value());
        }
        else {
            die("Error: Send() Request to $type Service failed -> $response->errstr!\n");
        }
    }
    return $messages;
}

// Extrahiert für den übergebenen Raum und Wochenprofil das entsprechende
// Temperaturprofil soweit es schon man ausgelesen und gecached wurde. 
function GetWeeklyProfile(int $rn, int $wp) {
    // Rückgabefeld
    $profil = array();
    // Cache auslesen
    $cid = CreateVariableByName($_IPS['SELF'], "Profiles", 3);
    $profiles = unserialize(GetValue($cid));
    // unseres dabei?
    if(isset($profiles[$rn])) {
        if(isset($profiles[$rn]["P".$wp])) {
            //	"HM-TC-IT-WM-W-EU" oder "HmIP-WTH-2"
            $profil = $profiles[$rn]["P".$wp];
        }
        else {
            //	Quickhack :( "HM-CC-TC" oder "HM-CC-RT-DN"
            $profil = $profiles[$rn]["P1"];
        }
    }
    return $profil;
}

// Speichert für den übergebenen Raum die Wochenprofil(e).
function SetWeeklyProfile(int $rn, array $profile, int $wp =-1) {
    // Cache auslesen
    $cid = CreateVariableByName($_IPS['SELF'], "Profiles", 3);
    $profiles = unserialize(GetValue($cid));
    if($wp > 0 and $wp <= 3) {
        $profiles[$rn]["P".$wp] = $profile;
    }
    else {
        $profiles[$rn] = $profile;
    }
    // Cache updaten
    SetValue($cid, serialize($profiles));
}

// Extrahiert für den übergebenen Tag das Tagesprofil
function GetDailyProfile(array $week, int $day) {
global $weekday;
    // Rückgabefeld
    $profil = array();
    // unseres dabei?
    if(isset($week[$weekday[$day]])) {
        $profil = $week[$weekday[$day]];
    }
    return $profil;
}

// Speichert für den übergebenen Raum die Wochenprofil(e).
function SetDailyProfile(int $rn, int $wp, int $day, array $dp) {
    global $weekday;
    // Cache auslesen
    $cid = CreateVariableByName($_IPS['SELF'], "Profiles", 3);
    $profiles = unserialize(GetValue($cid));
    // Tagesprofil austauschen
    if(isset($profiles[$rn]["P".$wp])) {
        //	"HM-TC-IT-WM-W-EU" oder "HmIP-WTH-2"
        $profiles[$rn]["P".$wp][$weekday[$day]] = $dp;
    }
    else {
        //	"HM-CC-TC" oder "HM-CC-RT-DN"
        $profiles[$rn][$weekday[$day]] = $dp;
    }
    // Cache updaten
    SetValue($cid, serialize($profiles));
}

// Prüfen ob Profil konsistent ist
function CheckWeeklyProfile($profile) {
    global $weekday;
    // Ergebniss
    $ret = "OK";
    foreach($weekday as $key => $day) {
        $time1='00:00';
        foreach($profile[$weekday[$key]]['EndTimes'] as $ts => $time2) {
            // Speicherslots des HM WT in min
            if(strtotime($time2) <= strtotime($time1)) {
                $slot = $ts+1;
                $ret="Fehler im Tagesprofil $weekday[$key] (Slot: $slot Start: $time1 - Ende: $time2 )";
                break;
            }
            $time1 = $time2;
        }
    }
    return $ret;
}

// Zeitabschnitt Auswahl im Webfront Anzeige auf Anzahl
// der belegten Slots im HM WT beschränken
function SetTimeSlotProfile($profile, $hl=99) {
    // Profilename
    $vpn = "HM.Heating.Slot";
    // Anzahl Slots
    $count = 0;
    if(!empty($profile)) {
        $count = count($profile['EndTimes']);
    }
    // Auswahl anpassen?!
    $vid = CreateVariableByName($_IPS['SELF'], "Zeitabschnitt", 1);
    if($count > 0) {
        IPS_SetVariableProfileValues ($vpn, 1, $count, 1);
        if($hl <= $count) {
            SetValue($vid, $hl);
            return $hl;
        }
        else {
            SetValue($vid, 1);
            return 1;
        }		
    }
    else {
        IPS_SetVariableProfileValues ($vpn, 1, 1, 1);
        SetValue($vid, 0);
    }
    return 99;
}

// Erzeugt vom übergebenen Wochen-Temperaturprofil das entsprechende HTML
function RenderWeeklyProfile(array $profile, $hl = 99) {
    global $day, $weekday;
    // Temeraturen => 15, 16, 17, 18, 19, 20, 21, 22
    if(!empty($profile)) {
        foreach ($weekday as $k => $d)	{
            $time1='00:00';
            foreach ($profile[$weekday[$k]]['EndTimes'] as $time2) {
                // Speicherslots des HM WT in min
                $times[$d][]=(strtotime("01.01.2001 ". $time2)-strtotime("01.01.2001 ". $time1))/60; 
                $time1=$time2;
            }
            foreach ($profile[$weekday[$k]]['Values'] as $v) {
                if($v <= 15) 		$temp[$d][] = 't15';	// sehr kalt
                elseif ($v <= 16)	$temp[$d][] = 't16';	// kalt
                elseif ($v <= 17)	$temp[$d][] = 't17';	// Kühl
                elseif ($v <= 18)	$temp[$d][] = 't18';	// normal
                elseif ($v <= 19)	$temp[$d][] = 't19';	// warm
                elseif ($v <= 20)	$temp[$d][] = 't20';	// sehr warm
                elseif ($v <= 21)	$temp[$d][] = 't21';	// heiß
                else 					$temp[$d][] = 't22';	// sehr heiß
            }
        }
    }
    else {
        // kein Profil kein Highlight!
        $hl = 99;
    }	
    // styles definieren
    $style = '';
    $style = $style.'<style type="text/css">';
    $style = $style.'body {margin: 0px;}';
    $style = $style.'table.tp {border-collapse: collapse; font-size: 11px; width: 100%; border-right: 1px solid rgba(255, 255, 255, 0.2);}';
    $style = $style.'td.fst {vertical-align: middle; text-align: center; width: 4%; padding: 2px; border-left: 1px solid rgba(255, 255, 255, 0.2); border-right: 1px solid rgba(255, 255, 255, 0.2); border-top: 1px solid rgba(255, 255, 255, 0.1); }';
    $style = $style.'td.mid {vertical-align: middle; text-align: center; width: 4%; padding: 2px; border-right: 1px solid rgba(255, 255, 255, 0.2); border-top: 1px solid rgba(255, 255, 255, 0.1); }';
    $style = $style.'td.lst {vertical-align: middle; text-align: center; width: 4%; padding: 2px; border-right: 1px solid rgba(255, 255, 255, 0.2); border-top: 1px solid rgba(255, 255, 255, 0.1); }';
    $style = $style.'tr:last-child {border-bottom: 1px solid rgba(255, 255, 255, 0.2); }';
    $style = $style.'.th { color: rgb(255, 255, 255); background-color: rgba(255, 255, 255,0.25); font-weight:bold; background-image: linear-gradient(top,rgba(0,0,0,0) 0,rgba(0,0,0,0.3) 28%,rgba(0,0,0,0.3) 100%); background-image: -o-linear-gradient(top,rgba(0,0,0,0) 0,rgba(0,0,0,0.3) 28%,rgba(0,0,0,0.3) 100%); background-image: -moz-linear-gradient(top,rgba(0,0,0,0) 0,rgba(0,0,0,0.3) 28%,rgba(0,0,0,0.3) 100%); background-image: -webkit-linear-gradient(top,rgba(0,0,0,0) 0,rgba(0,0,0,0.3) 28%,rgba(0,0,0,0.3) 100%); background-image: -ms-linear-gradient(top,rgba(0,0,0,0) 0,rgba(0,0,0,0.3) 28%,rgba(0,0,0,0.3) 100%); }';
    $style = $style.'.hl {background-color: black; opacity: 0.5;}';
    $style = $style.'.t15 {background-color: #6600CC; opacity: 0.9;}'; // lila (sehr kalt) <= 15
    $style = $style.'.t16 {background-color: #0000FF; opacity: 0.9;}'; // dunkelblau (kalt) = 16
    $style = $style.'.t17 {background-color: #0080FF; opacity: 0.9;}'; // hellblau (kühl) = 17
    $style = $style.'.t18 {background-color: #00FFFF; opacity: 0.9;}'; // türkis (normal) 18
    $style = $style.'.t19 {background-color: #00FF00; opacity: 0.9;}'; // grün (warm) =19
    $style = $style.'.t20 {background-color: #FFFF00; opacity: 0.9;}'; // gelb (sehr warm) = 20
    $style = $style.'.t21 {background-color: #FF8000; opacity: 0.9;}'; // orange (heiß) = 21
    $style = $style.'.t22 {background-color: #FF0000; opacity: 0.9;}'; // rot (sehr heiß) >= 22
    $style = $style.'</style>';
    // HTML Table erzeugen
    $html = $style;	
    $html = $html.'<table class="tp">';
    $html = $html.'<tr>';

    for($i=0; $i <= 24; $i++) {
        if($i == 0) {
            $html = $html.'<td class=""></td>';
        }
        elseif ($i == 24) {
            $html = $html.'<td class="lst th" colspan="12">'.sprintf("%02d", $i).'</td>';
        }
        else {
            $html = $html.'<td class="mid th" colspan="12">'.sprintf("%02d", $i).'</td>';
        }
    }
    $html = $html.'</tr>';

    foreach ($weekday as $k => $d)	{
        // wurde Wochentag mit übergeben (0=Mo, 1=Di ... 99=kein Wochentag vorgegeben)
        if($hl <> $k) {
            $html = $html.'<tr><td class="fst th">'. $day[$k][1] .'</td>';
        }
        else {
            $html = $html.'<tr class="hl"><td class="fst th">'. $day[$k][1] .'</td>';
        }
        if(isset($times)) {
            foreach ($times[$d] as $key => $time) {
                $html = $html.'<td colspan="'.($time/5).'" class="'.$temp[$d][$key].'"> </td>';
            }
        }
        else {
            for($i=0; $i < 24; $i++) {
                $html = $html.'<td colspan="12"> </td>';
            }
        }
        $html = $html.'</tr>';
    }
    $html = $html.'</table>';
    $html = $html.'<div style="height:8px;"><nbsp /></div>';
    // Index Tabelle (Temperatur-Spektrum)
    $html = $html.'<table style="border: 0px; font-size:11px; text-shadow:1px 1px #000000; width:100%; text-align: center">';
    $html = $html.'<tr>';
    $html = $html.'<td class="t15" style="width:12%"><= 15°C</td>';
    $html = $html.'<td class="t16" style="width:13%"><= 16°C</td>';
    $html = $html.'<td class="t17" style="width:12%"><= 17°C</td>';
    $html = $html.'<td class="t18" style="width:13%"><= 18°C</td>';
    $html = $html.'<td class="t19" style="width:12%"><= 19°C</td>';
    $html = $html.'<td class="t20" style="width:13%"><= 20°C</td>';
    $html = $html.'<td class="t21" style="width:12%"><= 21°C</td>';
    $html = $html.'<td class="t22" style="width:13%">>= 22°C</td>';
    $html = $html.'</tr></table>';
    // Rückgabe
    return $html;
}

// Erzeugt vom übergebenen Tages-Temperaturprofil das entsprechende HTML
function RenderDailyProfile(array $profile, int $hl=99) {
    // styles definieren
    $html = '<style>
    body {margin: 0px;}
    ::-webkit-scrollbar { width: 8px; }
    ::-webkit-scrollbar-track { background: transparent; }
    ::-webkit-scrollbar-thumb { background: #555; border-radius: 20px; }
    ::-webkit-scrollbar-thumb:hover { background: #555; }
    ul {font-size:12px;padding-left: 20px;}
    em {font-size: xx-small;}
    .time {font-size:12px;}
    .list {font-size:14px; font-weight: bold; padding-top: 10px;}
    </style>';	
    $html = $html.'<table class="tp">';
    $html = $html.'<tr><td class=""></td><td class="mid th">Startzeit</td><td class="mid th">Endzeit</td><td class="lst th">Temperatur</td></tr>';
    // rendern
    if(!empty($profile)) {
        $start="00:00";
        foreach($profile['EndTimes'] as $key => $end) {
            $temp = number_format($profile['Values'][$key], 1,",",".");
            if($key <> $hl-1) {
                $html = $html.'<tr><td class="fst th">'.($key+1) .'. Zeitabschnitt</td><td class="mid">'.$start.'</td><td class="mid">'.$end.'</td><td class="lst">'.$temp.' °C</td></tr>';
            }
            else {
                $html = $html.'<tr class ="hl"><td class="fst th">'.($key+1). '. Zeitabschnitt</td><td class="mid">'.$start.'</td><td class="mid">'.$end.'</td><td class="lst">'.$temp.' °C</td></tr>';
            }
            $start=$end;
        }
    }
    else {
        // kein Profil vorhanden!
        $html = $html.'<tr><td class="fst th">-<td class="mid">-</td><td class="mid">-</td><td class="lst">-</td></tr>';
    }
    $html = $html.'</table>';
    // Rückgabe
    return $html;
}

// Update HTML
function RenderProfile(int $rn, int $wp, int $wd, int $ts = 99) {
    // Profil extrahieren
    $profile = GetWeeklyProfile($rn, $wp);
    // Rendern Wochenprofil
    $vid = CreateVariableByName($_IPS['SELF'], 'Wochenprofil', 3);
    SetValue($vid, RenderWeeklyProfile($profile, $wd));		
    // Profil extrahieren
    $profile = GetDailyProfile($profile, $wd);
    $ts = SetTimeSlotProfile($profile, $ts);
    // Render Tagesprofil
    $vid = CreateVariableByName($_IPS['SELF'], 'Tagesprofil', 3);
    SetValue($vid, RenderDailyProfile($profile, $ts));		
}

################################################################################
?>

Musst natürlich die richtigen Geräte eintragen!

Viel Erfolg Heiko

Danke, ich versuch mal mein Glück.

Gruß

Jürgen

Hallo Heiko,

im Skript kommt jetzt dieser Fehler:

Fatal error: Uncaught TypeError: count(): Argument #1 ($value) must be of type Countable|array, int given in C:\ProgramData\Symcon\scripts\System.Functions.ips.php:713
Stack trace:
#0 C:\ProgramData\Symcon\scripts\31879.ips.php(178): CreateProfileInteger('HM.Heating.Room', 'HouseRemote', '', '', 0, 0, 0, 0, Array)
#1 {main}
  thrown in C:\ProgramData\Symcon\scripts\System.Functions.ips.php on line 713

In deiner „System.Functions“, „Version: 4.0.20231005“ fehlt nach $step das $digits. Hab mir diese direkt von GitHub geladen.
Dort im ChangeLog schreibst du " CreateProfilInteger korrigiert (ACHTUNG)". Was ist da zu beachten?

Gruß

Jürgen

Hallo Jürgen,

oh je - wie geschrieben alles schon sehr alt - lass mal sein.

Ich baue eine neue Version die dann auf der Höhe der Zeit seien sollte :slight_smile:
Stelle sie dann hier ein - sollte ich heute noch schaffen!

Gruß HEiko

Ahh super, freue mich drauf.

Danke

Gruß

Jürgen

Lief die nur für HM IP?

Ich stelle gerade fest, dass meine eingesetzte Swifty Version mit den Jahren einfach mitgewandert ist. Ist aber auch erst ein Jahrzehnt her. :smile:

Gruß

Nein, es gingen auch „ältere“ HM Geräte.

Ich meinte mehr das Script selbt mit Höhe der Zeit :smiley:

Gruß Heiko

Ok, ich wollte erst seit 10 oder 11 Jahren (irgendwo am Beginn dies Threads 2013) etwas umbauen und zentral steuern.

Aber wie es so läuft. Time goes by :grinning:

Gruß

So, war hoffentlich einfacher als erwartet …

FILE ENTFERNT WEIL FEHLERHAFT!!!

Jürgen, schau mal ob es läuft bei Dir!

Danke, aber ich habe glaube noch die falsche „__xmlrpc.inc.php“.
Du hattest doch eine von dir angepasste. Könntest du sie mir bitte zukommen lassen?

Gruß

jürgen

Ich verzweifle!
Im Skript ist ein „s“ zu viel → // INSTALLATION
if ($_IPS[‚SENDER‘]==‚Executes‘) {
Aber bekomme beim lesen diese Fehler:

Danke, mach ich immer wenn ich was teste :slight_smile:

Was für ein Thermostat hast Du nun eigentlich?

HM-TC-IT-WM-W-EU und als Steller HM-CC-RT-DN

Das Auslesen hatte ja gestern noch funktioniert :rofl:

Durch unterschiedliche Konfigurationswerte stimmen meine Zeilennummern wahrscheinlich mit Deinen nicht überein. Kannst mal Zeile 775 und 776 zeigen!

                        $thisTemp 	= $params[$keyTemp];
                        $thisTO 		= $params[$keyTO];
1 „Gefällt mir“

@jnicke schön das jetzt das alte Script dank der neuen xmlrpc Datei funktioniert!

Ich habe jetzt nochmal geschaut, aber eigentlich auch im neuen Script keinen gravierenden Unterschied gefunden, aber wenn es bei Dir läuft alles gut!

Never touch a running system :smiley:

Gruß HEiko

Hallo Heiko

Vielen lieben Dank für Deine Unterstützung!:+1:

Gruß

Jürgen

Hallo Heiko,

gibt es hier jetzt ein neues Skript?
Ich habe auch noch ein ganz ganz altes am laufen und würde gerne umsteigen denke ich.

Danke und Grüße
Stephan

Moin Stephan,

jein, ich habe ein neues Skript (eigentlich nur an meine Script-Bibo angepasstes) gebaut, aber das hat bei jnicke nicht funktioniert :frowning: leider wissen wir nicht warum. Bei mir läuft es dafür fehlerfrei :nerd_face:

Welche Version hast Du im Moment im Einsatz?
und
Welche Thermostate und Stellantriebe steuerst Du dabin (Bezeichnung)?

Gruß Heiko

PS: Wenn Lust kannst Du das neue auch mal testen?

Hallo Heiko,

ich habe auch noch eine Version von Swifty im Einsatz. Funktioniert auch noch.
Allerdings würde ich das gerne ändern.

Im Einsatz sind bei mir fast ausschließlich HM-CC-RT-DN, vereinzelt mit Raumthermostat ( HM-TC-IT-WM-W-EU). Nur in einem Raum habe ich noch ein altes Thermostat (HM-CC-TC) und einen alten Stellantrieb (HM-CC-VD).

Ist das aktuelle Skript dann in deiner Skript-Bibliothek zu finden?
Muss sehen wann ich dazu komme es zu testen.

Grüße
Stephan