Heizkörperthermostat Heizprogramme per WebFront einstellen

Hallo zusammen,

über Weihnachten hatte ich versucht die vorhandenen Scripte bei mir zu installieren, aber irgendwie wollte das alles nicht so wie ich und überhaupt … :wink:

Habe dann damit rumgespielt und gemerkt das es auch funktioniert mit den neuen WHT-2 und eTRV-2 Geräten und so fing das dann an …
Michael (@Nall-chan) wird sicher mit den Augen rollen, aber es ist wieder ein einzelnes Script geworden, wo die Variablen unterhalb des Scriptes liegen :banghead:

Ich habe versucht soviel wie nötig zu dokumentieren. Danke auch an @Marc der mir auf dem letzten Meter geholfen hat beim Testen und entsprechendes Feedback gegeben hat.

Trotzdem der HINWEIS - NUTZUNG AUF EIGENE GEFAHR!!


<?
################################################################################
# Scriptbezeichnung: HomeMatic.TempSchedule.ips.php
# Version: 1.1.20190222
# 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)
#
# ------------------------------ Konfiguration ---------------------------------
#
# RPC clients
$client = array();
#
# Service IP (CCUx)
$ip = 'xxx.xxx.xxx.xxx';
#
# 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-TC-IT-WM-W-EU - Kanal 2 - THERMALCONTROL_TRANSMIT (ungetestet!!!)
#
$room = array (  
	array(12, '1 - KG: Hoppyraum', '', -1, 50660 /*[Systeme\Homematic\Thermostat\000A98A9A4E0C6 (HmIP-WTH-2)\000A98A9A4E0C6:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/, 26857 /*[Systeme\Homematic\Stellantrieb\000A18A994402D (HmIP-eTRV-2)\000A18A994402D:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/),
	array(21, '2 - EG: Küche', '', -1, 21113 /*[Systeme\Homematic\Thermostat\000A98A9A4E0BE (HmIP-WTH-2)\000A98A9A4E0BE:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/, 23635 /*[Systeme\Homematic\Stellantrieb\000A18A9943FD9 (HmIP-eTRV-2)\000A18A9943FD9:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/, 11542 /*[Systeme\Homematic\Stellantrieb\000A18A994405C (HmIP-eTRV-2)\000A18A994405C:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/),
	array(22, '2 - EG: Wohnen', '', -1, 23498 /*[Systeme\Homematic\Thermostat\000A98A9A4E10D (HmIP-WTH-2)\000A98A9A4E10D:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/, 58916 /*[Systeme\Homematic\Stellantrieb\000A18A9944035 (HmIP-eTRV-2)\000A18A9944035:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/),
	array(31, '3 - OG: Bad', '', -1, 56832 /*[Systeme\Homematic\Thermostat\000A98A9A4E0F5 (HmIP-WTH-2)\000A98A9A4E0F5:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/, 33650 /*[Systeme\Homematic\Stellantrieb\000A18A9944068 (HmIP-eTRV-2)\000A18A9944068:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/),
	array(32, '3 - OG: Luise', '', -1, 20199 /*[Systeme\Homematic\Thermostat\000A98A9A4E110 (HmIP-WTH-2)\000A98A9A4E110:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/, 11234 /*[Systeme\Homematic\Stellantrieb\000A18A9944066 (HmIP-eTRV-2)\000A18A9944066:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/),
	array(33, '3 - OG: Pia', '', -1, 55797 /*[Systeme\Homematic\Thermostat\000A98A9A4E096 (HmIP-WTH-2)\000A98A9A4E096:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/, 56530 /*[Systeme\Homematic\Stellantrieb\000A18A9943FDB (HmIP-eTRV-2)\000A18A9943FDB:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/),
	array(34, '3 - OG: Schlafen', '', -1, 30734 /*[Systeme\Homematic\Thermostat\000A98A9A4E0F7 (HmIP-WTH-2)\000A98A9A4E0F7:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/, 43879 /*[Systeme\Homematic\Stellantrieb\000393C98D1395 (HmIP-eTRV)\000393C98D1395:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/, 52032 /*[Systeme\Homematic\Stellantrieb\000393C98D1380 (HmIP-eTRV)\000393C98D1380:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/),
	array(41, '4 - DG: Studio', '', -1, 20652 /*[Systeme\Homematic\Thermostat\000A9709A0D78D (HmIP-WTH-2)\000A9709A0D78D:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/, 52057 /*[Systeme\Homematic\Stellantrieb\000393C98D1313 (HmIP-eTRV)\000393C98D1313:1 - HEATING_CLIMATECONTROL_TRANSCEIVER]*/),
	array(42, '4 - DG: Bad', '', -1, 40693 /*[Systeme\Homematic\Thermostat\JEQ0194704 (HM-CC-TC)\JEQ0194704:2 - CLIMATECONTROL_REGULATOR]*/)
);
#
$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', '', 32768),
	array(1, 'Speichern', '', 16711680)
);
# Kopieren Profil 
$copy = array(
	array(0, ">", "", -1),
	array(1, "Kopieren", "", 0x008000),
);
# Übertragen Profil 
$move = array(
	array(0, ">", "", -1),
	array(1, "Übertragen", "", 0x008000),
);
#
$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)
);
#
$time = array(
	array(1, '-1 h', '', 65280),
	array(2, '-10 min', '', 65280),
	array(3, '+10 min', '', 16744448),
	array(4, '+1 h', '', 16744448)
);
#
$temperature = array(
	array(1, '-1 °C', '', 3368703),
	array(2, '-0,5 °C', '', 3368703),
	array(3, '+0,5 °C', '', 16711680),
	array(4, '+1 °C', '', 16711680)
);
#
$slot = array(
	array(1, 'Löschen', '', 16764057),
	array(2, 'Anfügen', '', 13434828)
);
#
$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 aktierten 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, $channel);
		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 ($rofile 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>
");
					$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
	$request = new xmlrpcmsg("getParamset",
		array(new xmlrpcval("$address:$channel", "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!
");
		}
	}
	return $messages;
}

// Erzeugt eine Variable unterhalb {id} mit dem Namen {name} vom Typ [type}
// Existiert die Variable schon wird diese zurückgeliefert.
// Types: 0 = Boolean, 1 = Integer, 2 = Float, 3 = String
function CreateVariableByName($id, $name, $type) {
	$vid = @IPS_GetVariableIDByName($name, $id); 
	if($vid===false) {
		$vid = IPS_CreateVariable($type); 
		IPS_SetParent($vid, $id); 
		IPS_SetName($vid, $name); 
	}
	return $vid; 
}

// Erzeugt ein Variablenprofil vom Typ {type} mit Name n{name} 
function CreateProfile($name, $type) {
	if(!IPS_VariableProfileExists($name)) {
		IPS_CreateVariableProfile($name, $type);
	} 
	else {
	  $profile = IPS_GetVariableProfile($name);
	  if($profile['ProfileType'] != $type)
	    throw new Exception("Variable profile type does not match for profile ".$name);
	}
}

// Erzeugt ein Integer-Variablenprofil
function CreateProfileInteger($name, $icon, $prefix, $suffix, $minvalue, $maxvalue, $step, $digits, $asso = NULL) {
	CreateProfile($name, 1);

	IPS_SetVariableProfileIcon($name, $icon);
	IPS_SetVariableProfileText($name, $prefix, $suffix);
	IPS_SetVariableProfileDigits($name, $digits);
	
	if(($asso !== NULL) && (sizeof($asso) !== 0)){
	  $minvalue = 0;
	  $maxvalue = 0;
	} 
	IPS_SetVariableProfileValues($name, $minvalue, $maxvalue, $step);
	
	if(($asso !== NULL) && (sizeof($asso) !== 0)){
	  foreach($asso as $ass) {
	    IPS_SetVariableProfileAssociation($name, $ass[0], $ass[1], $ass[2], $ass[3]);
	  }
	}         
}

// 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.'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 = "";	
	$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));		
}

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

Viel Erfolg
Heiko

2 „Gefällt mir“