// Integrierte Heizungsthermostatsteuerung // Autor: Looxer01 ---------- Datum 12.04.2017 // Version 0.5 // Das Programm synchronisiert alle Thermostate eines Raumes - aehnlich zur Gruppenfunktion der Homematic // Verschlusssensoren und Thermostate muessen nicht direktverknuepft sein, koennen aber. // Empfehlung: Modus des thermostates auf MANU setzen. "AUTO" ist zwar auchmoeglich, wuerde aber zu den Schaltzeiten des Thermostates zu kurfristigen Soll-Temperaturaenderungen fuehren // Ein Thermostat/Sensor darf nicht mehreren Raeumen zugeordnet sein // Alle Sensoren und Thermostate muessen einem Gewerke zugeordnet sein // Hinweis: bei aelteren Installationen sind u.U. Raumdefinitionen in ioBroker inkonsistent was zu Fehlern im Programm fuehrt // Falls das auftritt muessen die enum.rooms mit den Raeumen der CCU verglichen worden. Falsche Definitionen muessen aus iobroker manuelle geloescht werden - neustart erforderlich // Falls es keine eigenen Definition in ioBroker gibt koennen auch einfach die enums gelöscht und durch REGA Neusynch neu angelegt werden // Vorbereitungen // die relevanten Thermostate muessen alle dem angegebenen Gewerk zugeordnet sein (mit Ausnahme von NICHT-Homematic-Geraeten) // Checken, dass alle Raeume bei den Aufzaehlungen mit der Raumliste der CCU uebereinstimmen // Die Views muessen angelegt werden. Hierzu sind die folgenden Schritte notwendig // a. Ersetzen der folgenden Variablen aus dem mitgelieferten View. Das muss je Raum und Profil wiederholt werden // - Ersetze Schlafzimmer mit den eigenen jeweiligen Raumnamen entsprechend der eigenen Raumliste - Achtung Raumnamen duerfen keine Blanks enthalten - Blanks muessen mit "_" aufgefuellt werden // - Ersetze Profil-1 durch Profil-2 etc je anzulegendes Profil // b. Importieren der so geaenderten views in VIS (ueber VIS Funktionen) // c. Ordne die richtigen Datenpunkte fuer Solltemperatur und Isttemperatur zu // ACHTUNG: Im View muss das Raumprofil aktiviert werden. Es ist anfangs nicht aktiviert damit nicht alle Raeume mit dem Standardprofil beim ersten Programmlauf aktiviert sind. Daher manuelle notwendig // // Bitte die Dokumentation lesen - alle Konfigschritte und auch die Funktionsweise des Programmes sind dort erlaeutert //------------------------------------------------------------------------------ // Beginn Generelle Einstellungen // werden an dieser Stelle benoetigt - Einstellungen sind nur in Spezialfaellen notwendig //------------------------------------------------------------------------------ // Anpassung nur wenn unbeding notwendig. Hier ist der Ansatz um z.B. Einliegerwohnungen separat zu steuern var JSPath = "javascript.0."; // JS- Pfad var path = JSPath +'Heizung.Heizplan'; // Pfad fuer create states var Gparameterpath = path + ".GlobaleParameter"; // Pfad in die Globalen Parameter var ICALPath = "ical.0.events"; // Pfad zu den ICAL events zur Profilauswahl //------------------------------------------------------------------------------ // Ende Generelle Einstellungen // Usereinstellungen sind Einstellungen, die ueblicherweise gemacht werden //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Beginn USER Einstellungen //------------------------------------------------------------------------------ // // Gewerke - wichtige Einstellung, da nur die Geraete eingelesen werden, die im Gewerk vorhanden sind //Das Gewerk muss alle Thermostate bzw Sensoren enhalten var HeizungGewerk = "Heizung"; // diesem Gewerk muessen alle Thermostate zugeordnet sein. var SensorGewerk = "Verschluss"; // diesem Gewerk muessen alle Verschlusssensoren zugeordnet sein. // Alle x Minuten wird gecheckt ob die SollTemp angepasst werden muss - Empfehlung 5 var cron = 5; // Raumliste - empfohlen zu benutzen fuer kleine Systeme // UseRoomList heisst, dass die nur hier gelisteten Raeume angelegt und abgearbeitet werden - somit werden nicht sofort alle Datenpunkte aller Räume angelegt (ca. 100 pro Raum und Profil) // dies dient hauptsaechlich zur Anlage der Daten - So koennen Raum fuer Raum alle States angelegt wrden // Das sollte genutzt werden mit langsamen Rechnern wie Raspi mit SD karte var UseRoomList = false; // Wenn testmodus werden nur die Angegebenen Raeume abgearbeitet var RoomList = []; RoomList[0] = ['Schlafzimmer']; // Liste der Raeume die gesteuert werden soll zum Testen RoomList[1] = ['Elternbad']; RoomList[2] = ['Wohnzimmer']; RoomList[3] = ['Kueche']; RoomList[4] = ['Raum4']; RoomList[5] = ['Raum5']; RoomList[6] = ['Raum6']; RoomList[7] = ['Raum7']; RoomList[8] = ['Raum8']; RoomList[9] = ['Raum9']; // Anzahl der Profile. i.d.R. sollten maximal 3 Profile genuegen - Profile werden z.B. fuer Events aus ICAL verwendet var MaxProfile = 1; // Maximal genutzte Profile pro Raum (gering halten ) Zahl zwischen 1 und 9 // Das ist die Temperatur, die eingestellt wird, wenn erkannt wird, dass ein Verschluss eines Raumes geoeffnet ist (z.B bei nicht direktverknuepften Geraeten) var VerschlussAbsenkungsGrenze = 12; // erweitertetes Logging im ioBroker log bei true var debug = true; // Logging in externe Datei - Achtung der Pfad muss fuer MS-Windows bzw IOS angepasst werden var LogFlag = false; // logging enabled var LogPath = "/opt/iobroker/iobroker-data/HeizungsthermostatLOG.csv"; // Pfad und Dateiname des externen Logs var OnlyChanges = true; // bei true wird nur geloggt wennn eine neue Solltemperatur geschrieben wird // ICAL Einstellungen (erst nach Ersteinstellung Aktivieren) // Wenn keine Events genutzt werden, dann alles auf false setzen // die Events muessen entsprechend in ICAL angelegt werden, sonst gibt es Warnmeldungen im Log // Die Eventnamen koennen angepasst werden. Bitte die Logkik von ICAL unbeding beachten. (siehe Doku im Kapitel ICAL) var UseEventsGlobalParameter = true; // mit diesen Events koennen Urlaub Party etc geplant werden - Empfehlung erst im zweiten Schritt aktivieren var UseEventsGlobalProfilSelect = false; // Events mit denen das Profil umgeschaltet werden kann - fuer alle Raeume - Empfehlung erst im zweiten Schritt aktivieren var UseEventsRaumProfilSelect = false; // Events mit denen das Profil fuer einzelne Raeume umgeschaltet werden kann - Empfehlung erst im zweiten Schritt aktivieren var EventG_UrlaubAbwesend = "Urlaub_Abwesend"; // dieses Event muss in ICAL angelegt werden wenn UseEventsGlobalParameter = true ist var EventG_UrlaubAnwesend = "Urlaub_Anwesend"; // dieses Event muss in ICAL angelegt werden wenn UseEventsGlobalParameter = true ist var EventG_Party = "Party"; // dieses Event muss in ICAL angelegt werden wenn UseEventsGlobalParameter = true ist var EventG_Gaeste = "Gaeste"; // dieses Event muss in ICAL angelegt werden wenn UseEventsGlobalParameter = true ist var EventG_Abwesend = "Keiner_DA"; // dieses Event muss in ICAL angelegt werden wenn UseEventsGlobalParameter = true ist var EventG_Feiertag = "Feiertag"; // dieses Event muss in ICAL angelegt werden wenn UseEventsGlobalParameter = true ist // Die folgenden EVENT Texte muessen in ICAL angelegt werden. Sobald die Texte im google Kalender // aktiv sind wird das Event fuer die Heizungsthermostatsteuerung ausgewertet. // Achtung die Zeichen <> und der Text innerhalb dieser Klammer duerfen nicht geaendert werden // siehe Dokumentation fuer mehr infos var UseEventG_Profil = "Global_Profil_"; // Events mit denen das Profil umgeschaltet werden kann - muss in ICAL angelegt werden wenn UseEventP_Profil = true ist var UseEventR_Profil = "_Profil_"; // Events mit denen das Raumprofil umgeschaltet werden kann - muss in ICAL angelegt werden wenn UseEventsRaumProfilSelect = true ist // Integration zur Anwesenheitsermittlung - wenn nicht integriert werden soll dann wird der State umgewandelt: var UseAnwesenheitserkennung = false; // wenn true, dann wird die o.g. Anwesenheitsvariable genutzt - Empfehlung erst im zweiten Schritt aktivieren var StateAnwesenheit = JSPath + "Anwesenheitssteuerung.Userlist.JemandDa"; // Wenn UseAnwesenheitserkennung = true, dann muss der Pfad angepasst werden // Feiertagsintegration und Anwesenheitsintegration . Einstellungen // Integration zum Feiertagskalender - var UseFeiertagskalender = false; // wenn der Kalender genutzt wird bitte auf true setzen - Empfehlung: Feiertagsadapter installieren und auf true setzen var StateFeiertagHeute = "feiertage.0.heute.boolean"; //wenn UseFeiertagskalender, dann wird dieser Pfad verwendet //------------------------------------------------------------------------------ // Ende USER Einstellungen // Usereinstellungen sind Einstellungen, die ueblicherweise gemacht werden //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Beginn Experteneinstellungen // Experteneinstellungen sollten nur geamcht werden, wenn die Logik des Programmes bekannt ist //------------------------------------------------------------------------------ // Wenn Die Anwesenheitserkennung manuell z.B. über ICAL genutzt wird dann kann hier der Pfad geaendert werden - Empfehlung ist nicht zu aendern if(UseAnwesenheitserkennung ===false ) { StateAnwesenheit = JSPath + "Heizung.Heizplan.GlobaleParameter.Anwesenheit"; } // Wenn keine Feiertagsadapterintegration gewünscht ist wird hier das Feiertagsflag verwaltet - Empfehlung ist nicht zu aendern if(UseFeiertagskalender ===false ) { StateFeiertagHeute = JSPath +"Heizung.Heizplan.GlobaleParameter.Feiertag_Heute"; } // die States sollten moeglichst so belassen werden - das Programm laesst aber Aenderungen zu var StatePartyjetzt = Gparameterpath + ".Partyjetzt"; // ID Party Jetzt flag var StateGaesteDa = Gparameterpath + ".GaesteDa"; // ID Gaeste da flag var StateUrlaubAnwesend = Gparameterpath + ".Urlaub_Anwesend"; // Wenn kein Arbeitstag, dann wird der Tag wie ein Sonntag behandelt var StateUrlaubAbwesenheit = Gparameterpath + ".Urlaub_Abwesend"; // Temperaturabsenkung wenn laengerer Urlaub eingetragen ist var StateHeizperiode = Gparameterpath + ".Heizperiode"; // Wenn Heizperiode false werden alle Ventile geschlossen // Die ThermostatTypeTab definiert die Thermostat Typen. So sollte es moeglich sein auch z.B. HM-IP einzubinden // Achtung zentrale Steuerungen muessen immer zuerst eingetragen sein. // Steuerung zentral heisst, dass dieses Geraet evt abhaengige Geraete steuert, wenn false, dann werden abhaengige Geraete gleich behandelt var ThermostatTypeTab = []; // 0.RPC-Pfad 1.GeraeteType 2. Beschreibung, 3. Type 4.DP-SollTemp 5.Laenge ID 6.DP MANU/AUTO Schaltung 7.Steuerung zentral 8. IstTemp 9-Check-MANU-Mode 10-Ventilstellung wenn nicht Heizperiode ThermostatTypeTab[0] = ['hm-rpc.0.', 'HM-TC-IT-WM-W-EU', 'Wandthermostat (neu)' ,'WT', '2.SET_TEMPERATURE' , 10, '2.MANU_MODE', false, '1.TEMPERATURE', '2.CONTROL_MODE', 30]; ThermostatTypeTab[1] = ['hm-rpc.0.', 'HM-CC-TC' , 'Wandthermostat (alt)' ,'WT', '2.SETPOINT' , 10, false, false, '1.TEMPERATURE', false, 30]; ThermostatTypeTab[2] = ['hm-rpc.0.', 'HM-CC-RT-DN' , 'Heizkoerperthermostat(neu)' ,'HT', '4.SET_TEMPERATURE' , 10, '4.MANU_MODE', false, '4.ACTUAL_TEMPERATURE', '4.CONTROL_MODE', 30]; ThermostatTypeTab[3] = ['hm-rpc.0.', 'HMIP-eTRV' , 'Heizkoerperthermostat(HMIP)','HT', '4.SET_POINT_TEMPERATURE', 10, '2.MANU_MODE', false, '4.ACTUAL_TEMPERATURE', '4.CONTROL_MODE', 30]; // Tabelle fuer Nicht HM Thermostate - Details finden sich in der Dokumentation // wurde zum Testen verwendet, da auch virutelle Thermostate verwaltet werden koennen. // Wenn nicht HM Geraete korrekt in ioBroker angebunden sind sollten diese auch ueber die Tabelle ThermostatTypeTab konfigurierbar sein //Spalte 1 = Raumname wie in der CCU hinterlegt //Spalte 2 = Erster Teil des Datenpunktpfades mit Instance wie z.B. "hm-rpc.0" //Spalte 3 = Zweiter Teil des Datenpunktpfades mit der ID des Geraetes z.B. "MEQ0183268" //Spalte 4 = Dritter Teil des Datenpunktpfades mit dem Datenpunkt der die Solltemperatur des Geraetes einstellt z.B. "4.SET_TEMPERATUR" // var NoneHMTab = []; // 0 = Raum 1 = Datenpunkt bis vor Geraet 2=Datenpunkt Geraet 3=Datenpunkt SollTemp 4= Ventilstellung bei NichtHeizperiode NoneHMTab[0] = ['initial', 'javascript.0.Heizung', 'zwave1', '4.SET_TEMPERATURE', 30]; NoneHMTab[1] = ['initial', 'ZWAVE.0', 'zwa0183xxx', '4.SET_TEMPERATURE', 30]; NoneHMTab[2] = ['initial', 'ZWAVE.0', 'zwa0183xxx', '4.SET_TEMPERATURE', 30]; // Typen-Tabelle der Verschlusssensoren var SensorTypeTab = []; // 0.RPC-Pfad 1.GeraeteType 2. Beschreibung, 3.Type 4.DP Status 5.Laenge ID SensorTypeTab[0] = ['hm-rpc.0.', 'HM-Sec-SCo', 'Fenstersensor (neu)' , 'HM', '1.STATE' , 10 ]; SensorTypeTab[1] = ['hm-rpc.0.', 'HM-Sec-SC' , 'Fenstersensor (alt)' , 'HM', '1.STATE' , 10 ]; // Mit der Tabelle OverruleTab kann die Logik der Temperaturanpassungen beeinflusst werden (Sobald eine Anpassung erfolgt wird der Vorgang Overrule abgebrochen) // Die Tabelle kann als Prioritätenliste verstanden werden, wenn mehrere Parameter gleichzeitig zutreffen sollten. // Die Logik wird fuer jeden Raum ausgefuehrt var OverruleTab = []; OverruleTab[0] = ["Abwesenheit"]; //Bei Abwesenheit wird die Temperatur der entsprechend Eisntellung abgesenkt OverruleTab[1] = ["UrlaubAnwesend"]; //Urlaubsanwesenheit / beeinflusst nicht direkt die Solltemp - ist aber wichtig fuer die Schedule Findung OverruleTab[2] = ["UrlaubAbwesend"]; //Urlaubsabwesenheit - OverruleTab[3] = ["Gaeste"]; //Temperatur Anhebung OverruleTab[4] = ["Party"]; //Partyabsenkung // Bei Verwendung des Widgets Select-value List werden die Temperaturen nicht als Grad gespeichert var VerwendungSelectValue = true; // Weitere Pfade fuer die globalen Parameter - Empfehlung ist keine Aenderung vorzunehmen var StatePP_PartyAbsenkung = "ProfilParameter_PartyAbsenkung"; var StatePP_GaesteAnhebung = "ProfilParameter_GaesteAnhebung"; var StatePP_AbwesenheitAbsenkung = "ProfilParameter_AbwesenheitAbsenkung"; var StatePP_UrlaubAbsenkung = "ProfilParameter_UrlaubAbsenkung"; var StatePP_UrlaubWieFeiertag = "ProfilParameter_UrlaubWieFeiertag"; var StatePP_MinimaleTemperatur = "ProfilParameter_MinimaleTemperatur"; //------------------------------------------------------------------------------ // Ende Experteneinstellungen //------------------------------------------------------------------------------ // Variablendefinition var ControlTab = []; // Zentrale Tabelle der Thermostate var SensorList = []; // Liste der Verschlusssensoren var fs = require('fs'); // enable write fuer externes log var cronjob = "*/"+cron+" * * * *"; // CRON pattern aufgrund der Vorgabe in den Einstellungen var sensorausgeloest = false; // Wenn ein Verschluss ausgeloest wird, dann wird auf true gesetzt // Diese Variablen sind ein Findungsnachweis fuer die gesetzte Temperatur - Sie werden am Ende im Raum gespeichert und dienen auch zur ermittlung von manuell eingestellten Temperatur var Source_Profil; var Source_ICALEvent; var Source_ManualAdjustment; var Source_GlobalParameter; var Source_ProfilParameter; var Source_SchedulePoint; var Source_LastTemp; var Source_Timestamp; var Source_CurrentSollTemp; var Source_last_Program_Run; var Source_ManTempSet; // Auslesen aller Raeume rooms = getEnums('rooms'); // Lade alle Raeume // Devicetabellen aufbauen getDevices(); // Liste der Thermostate generieren und States anlegen //----------------------------------------------------------------------------------------------------- // Job zur Ausfuehrung der Kernfunktion (Temperatur Setting) //----------------------------------------------------------------------------------------------------- schedule(cronjob, function() { LoopRooms(); // Ablauflogik entlang der gefundenen Thermostate fuer alle Raeume }); // Ende Job //----------------------------------------------------------------------------------------------------- //ab hier Haupt-Routinen // 1. GetDevices --einlesen bei jedem Programm start -nicht schedule // 2. Loop Rooms --wird ausgeführt durch den schedule // 3. LoopDevices --wird durch LoopRooms ausgeführt // 5. ThermostatChange -- bei jeder manuellen Aenderung des Thermostats wird diese Routine aufgerufen // 6. SensorChange -- wird ausgeführt wenn ein Verschluss geoeffnet/geschlossen wird //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- // Funktion getDevices - Zentrale Funktionen zum Lesen von enum und objekt //----------------------------------------------------------------------------------------------------- function getDevices () { // jetzt alle zugehoerigen Thermostate finden und in Crontab speichern var roomName; var idExtract; var fullname; var devtype; var FinishRoom = false; var y = 0; var InTest= true; var SelectorVerschluss; var SelectorThermostat; // jetzt Thermostate einlesen // Lade alle Raeume for (var i in rooms){ // loop ueber alle Raeume roomName = rooms[i].name; for (var x in ThermostatTypeTab){ // loop ueber die moeglichen Thermostattypen $('channel[state.id=*.'+ThermostatTypeTab[x][4]+'] (rooms='+roomName+') (functions='+HeizungGewerk+') ').each(function (id, i) { // selektiere alle Thermostate fuer den Raum idExtract = ThermostatTypeTab[x][0] + id.substr(9, ThermostatTypeTab[x][5]); fullname = getObject(id).common.name; devtype = getObject(idExtract).native.TYPE; if(devtype === ThermostatTypeTab[x][1] ) { SelectorThermostat = $('channel[state.id='+id+'] '); SelectorThermostat.on(function(obj) { // bei Zustandaenderung if (obj.state.ack) { ThermostatChange(id); } }); // endon ControlTab[y] = [roomName,id,devtype,fullname,idExtract,ThermostatTypeTab[x][3],ThermostatTypeTab[x][4],ThermostatTypeTab[x][6],ThermostatTypeTab[x][7],ThermostatTypeTab[x][8],ThermostatTypeTab[x][9],ThermostatTypeTab[x][10]]; // 0 = roomName 1 = id 2 = devtype 3 = FullName 4 ID Extract 5 = Type des Geraetes 6 = DP SollTemp 7 = Manu/Auto 8 = Steuerung zentral 9 = DP Ist-Temperatur 10 = DP MANU Check 11=Ventil Offen y = y +1; if (RoomListUsage(roomName) === true) { // wenn die Raumliste genutzt wird ist und der Raum in der Liste enthalten ist. if(debug ) {log("getdevice fuer " + roomName,"info");} CreateStates(roomName,devtype); // Lege die states an } if( ThermostatTypeTab[x][7] === true) { // Das ist das zentrale Steuerthermostat FinishRoom = true; // gehe zum naechsten Raum // return; // das steuernde Thermostat wurde gefunden ensprechend prioritaet der ThermostatTypeTab } } }); // end Channel loop if (FinishRoom) { FinishRoom=false; break; } // gehe zum naechsten Raum } // End ThermostatTypeTab } // End rooms - Homematic Geraete bzw voll eingebundene Geraete // Fuellen der Nicht-Homematic Geraete in die ControlTab y = ControlTab.length; for (var b in NoneHMTab) { roomName = NoneHMTab[b][0]; if(roomName !== "initial" ) { id = NoneHMTab[b][1] + '.' + NoneHMTab[b][2] + '.' + NoneHMTab[b][3]; FullName = getObject(id).common.name; devtype = "NoneHM"; if (RoomListUsage(roomName) === true) { // wenn die Raumliste genutzt wird ist und der Raum in der Liste enthalten ist. if(debug ) {log("getdevice fuer " + roomName,"info");} CreateStates(roomName,devtype); // Lege die states an } ControlTab[y] = [roomName,id,devtype,FullName,NoneHMTab[b][2],'HT',NoneHMTab[b][3],false,false,false,false, NoneHMTab[b][4] ]; // 0 = roomName 1 = id 2 = devtype 3 = FullName 4 ID Extract 5 = Type des Geraetes 6 = DP SollTemp 7 = Manu/Auto 8 = Steuerung zentral 9 = DP Ist-Temperatur 10 = DP MANU Check 11=Ventil Offen y = y +1; } // endif roomName war nicht initial } // endfor Nicht Homematic Geraete // jetzt die Control Tab Sortieren nach Raumnamen ControlTab.sort(SortControlTab); // Verschluss sensoren einlesen und subscription buchen y=0; for (var i in rooms){ roomName = rooms[i].name; for (var x in SensorTypeTab){ $('channel[state.id=*.'+SensorTypeTab[x][4]+'] (rooms='+roomName+') (functions='+SensorGewerk+') ').each(function (id, i) { idExtract = SensorTypeTab[x][0] + id.substr(9, SensorTypeTab[x][5]); fullname = getObject(id).common.name; devtype = getObject(idExtract).native.TYPE; if(devtype === SensorTypeTab[x][1] ) { SensorList[y] = [roomName,id,devtype,fullname,idExtract,SensorTypeTab[x][3],SensorTypeTab[x][4] ]; SensorList[y][7] = getState( SensorList[y][1]).val; // Status des Sensors log(SensorList[y][0] + " " + SensorList[y][1] + " " + SensorList[y][2] + " " + SensorList[y][3] + " " + SensorList[y][4] + " " + SensorList[y][5] + " " + SensorList[y][6] + " " + SensorList[y][7] ); y = y +1;// // SelectorVerschluss = $('channel[state.id='+id+'] (rooms='+roomName+') (functions='+SensorGewerk+') '); SelectorVerschluss = $('channel[state.id='+id+'] '); SelectorVerschluss.on(function(obj) { // bei Zustandaenderung if (obj.state.ack) { SensorChange(id); } }); // endon } }); // end Channel loop } // Endfor SensorTypeTab } // Endfor rooms Verschlusssensoren // Ausgabe der Devices - Thermostate und Sensoren for (var z in ControlTab) { if(debug) { log(z +" ControlTab " + ControlTab[z][0] + " " + ControlTab[z][1]+ " " +ControlTab[z][2]+ " "+ControlTab[z][3]+ " "+ControlTab[z][4]+ " "+ControlTab[z][5]+ " "+ControlTab[z][6]+ " "+ " "+ControlTab[z][7]+ " "+ControlTab[z][8]+ " "+ControlTab[z][9]+ " "+ControlTab[z][10],"info"); } else { log(z + " " + ControlTab[z][0] + " " + ControlTab[z][1],"info"); } } // End ControlTab for (var c in SensorList) { if(debug) { log("Sensor " + SensorList[c][1] + " in Raum " + SensorList[c][0] + " Status " + SensorList[c][7],"info"); } } log("Devices initialisiert","info"); } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion LoopRooms - Abarbeiten der Raeume //----------------------------------------------------------------------------------------------------- function LoopRooms () { var roomName; var RoomRelevant = true; Source_last_Program_Run = formatDate(new Date(),"JJJJ/MM/DD SS:mm:ss"); setState(Gparameterpath + ".Source_last_Program_Run",Source_last_Program_Run); for (var x in rooms){ // loop ueber all Raeume RoomRelevant = true; roomName = rooms[x].name; roomName = roomName.replace(/\s/g, "_"); // Blanks durch unterstrich ersetzen if(ChckRoom(roomName) === false) { // gibt es Thermostate fuer den Raum ? RoomRelevant = false; } // endif der Raum hat keine devices if(RoomListUsage(roomName) === false) { RoomRelevant = false; }// endif roomlistusage if( RoomRelevant) { if ( getState(path + "." + roomName +".AktivesRaumProfil"). val > 0) { if(debug) { log("Starte Abarbeitung fuer Raum " + roomName,"info"); } ClearSources(); SetEventGlobalParameter(); // checken of ICAL events als global parameter vorliegen LoopDevices(roomName) log("Ende Abarbeitung fuer Raum " + roomName,"info"); } } } // Endfor rooms } // endfunction //----------------------------------------------------------------------------------------------------- // Funktion LoopDevices - Abarbeiten der Thermostate //----------------------------------------------------------------------------------------------------- function LoopDevices (roomName) { // var ActiveRoomProfile; var ScheduledSollTemp; var ManAdjDetected; var ThermMode var ManAdj; var ManAdjTimeStamp = getState(path + "." + roomName +".Source_TimeStamp").val; Source_ManTempSet = null ; // Variable zurücksetzen - wird gebraucht fuer das synchen von Thermostaten for (var x in ControlTab){ if ( ControlTab[x][0] === roomName ) { Source_CurrentSollTemp = 0; Source_SchedulePoint = ""; Source_GlobalParameter=""; idExtract = ControlTab[x][4]; deviceType = ControlTab[x][2]; id =ControlTab[x][1]; fullname = getObject( ControlTab[x][1]).common.name; // Setzen des Thermostates in den manuellen Modus - wenn moeglich / eingestellt if(ControlTab[x][7] !== false && getState(path + "." + ControlTab[x][0] + "." + "RaumParameter_ManuellModeForce").val === true ) { // Geraet laesst sich auf MANU Schalten - im raumparameter steht auch, dass geschaltet werden soll ThermMode = getState(idExtract + "." + ControlTab[x][10]).val; if(ThermMode === 0 || ThermMode === 2) { // Pruefen ob der manuelle Modus oder Party Mode eingeschaltet ist log("Geraet " + idExtract +" Raum: " + roomName + " in den Manuellen Modus gesetzt ","info"); setState(idExtract + "." + ControlTab[x][7], getState(id).val); // setzen auf manuell - native boost und party werden nicht beachtet writelog(roomName,id,"Thermostat in den manuellen Modus versetzt") } // endeif automode war eingeschaltet } // endif pruefe ob das Geraet in den manuellen Modus geschickt werden kann und soll // Wenn keine Heizperiode dann die Ventile oeffnen oder schliessen und abbrechen if(getState(StateHeizperiode).val === false) { ScheduledSollTemp = ControlTab[z][10]; Source_GlobalParameter = "Heizperiode" + "_" + false; SetTemp (roomName,ScheduledSollTemp,id,false); writelog(roomName,id,"keine Heizperiode") continue; } Sensor = VerschlussRaumStatus (roomName); // Check ob ein Verschlusssensor offen ist if(sensorausgeloest) { // ein nicht direkt verknuepfter Sensor hat im Raum ausgeloest // Wenn ein Verschluss des Raumes geoeffnet ist, dann wird die Temp Absenkung gemacht if (Sensor) { // steht einer der Sensoren auf offen ? Source_GlobalParameter = "Verschluss offen TemperaturAbsenkung gesetzt"; if(debug) { log(Source_GlobalParameter,"info") } SetTemp (roomName,VerschlussAbsenkungsGrenze,id,false); writelog(roomName,id,"") continue; }// endif sensor status true } // endif Sensor ausgeloest if (Sensor) { return; } // Handling einer evt manuellen Temperatur im Regler oder im view eingestellt ManAdj = ManAdjustments(roomName,id) // Finden ob es man adjustments gibt if(ManAdj === false ) {; // es gibt keine manuelle Anpassung ExecuteTempDetermination (roomName,id); writelog(roomName,id,"") } // endif keine manuellen Adjustments if(ManAdj === true ) {; // es liegt eine manuelle Korrektur vor writelog(roomName,id,"") if(debug) {log("Starte Sync fuer Manuelle Temperatur fuer " + id,"info")} if(Source_ManTempSet === null) { log("ACHTUNG Fall 2 LoopDevices Temperatur Source_ManTempSet hat keinen Wert - kann nicht synchen") return; } SyncThermostat(roomName,"ManualTemp",Source_ManTempSet,id) // jetzt manuelle Temp synchen return; } // endif Manuelle Anpassung erkannt } //endif abarbeitung des Raums } // End for } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion ThermostatChange erkennt die Veraenderung der Solltemperatur durch subsription //----------------------------------------------------------------------------------------------------- function ThermostatChange (id) { var ManAdj; var room; Source_CurrentSollTemp = 0; // Ruecksetzen der current SollTemp fuer nachfolgende Programme log("Thermostat " + id + " Aenderung erkannt") for (x in ControlTab ) { if (ControlTab[x][1] === id ) { room = ControlTab[x][0]; source_ManTempSet = getState(id).val; ManAdj = ManAdjustments(room,id); if(debug) {log("Starte Sync fuer Manuelle Temperatur fuer " + id + " Temperatur = " + Source_ManTempSet,"info")} writelog(room,id,"") ; if(Source_ManTempSet === null) { log("ACHTUNG Fall 1 ThermostatChange in Temperatur Source_ManTempSet hat keinen Wert - kann nicht synchen") return; } SyncThermostat(room,"ManualTemp",Source_ManTempSet,id) ; // jetzt manuelle Temp synchen return; } } } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion SensorChange erkennt die Verschlussstellung eines Sensors und stellt die Temperatur entsprechend ein //----------------------------------------------------------------------------------------------------- function SensorChange (id) { var tabNo; tabNo = SensorFind(id); if(tabNo === 999 ) { log("Sensor " + id + " nicht in Sensorliste gefunden") return; // Sensor nicht in Sensorlist gefunden } var room = SensorList[tabNo][0].toString(); // Wenn keine Heizperiode if(getState(StateHeizperiode).val === false) { return; // keine Heizperiode } if(getState(path + "." + room +".Source_Profil") === 0 ) { return; // es ist noch kein Profil dem Raum zugeordnet } if(debug) {log("Sensor gefunden " + id + " Raum " + SensorList[tabNo][0]) } SensorList[tabNo][7] = getState(id).val; // Status des Verschlusses in Tabelle updaten if(debug) { log(" Fenster "+ id + " status geaendert fuer "+ SensorList[tabNo][1] + " " + SensorList[tabNo][0] + " " +SensorList[tabNo][7] ); log("Ubergabewert " + SensorList[tabNo][1]) } sensorausgeloest = true; LoopDevices(room); sensorausgeloest = false; } // ende Funktion //----------------------------------------------------------------------------------------------------- //ab hier Hauptfunktionen // 1. Manual Adjustments -- erkennt manuelle Anpassungen der Temperatur oder setzt diese zurueck // 2. Overrule -- Behandelt globale Parameter und ggf davon abhaengige Temperaturanpassungen // 3 ExecuteTempDetermination -- Hauptroutine zur Findung und speichern der Solltemp abhängig vom schedule // 4. SelectSwichTime -- Ermittlung die gültige Zeit des schedules (nicht Planungstag) // 5. ActiveProfile -- Bestimmt das aktive Raumprofil // 6. SetEventGlobalParameter -- ermittelt aufugrund von ICAL ggf gueltige Events // 7. SetTemp -- Nur hier wird die Solltemperatur fuer die Thermostate gesetzt // 8. DetermineSchedule -- ist input fuer ExecuteTempDetermination und ermittelt den richtigen Planungstag (1 bis 8 ) SelectSwichTime ermittelt die Zeit // 9. SyncThermostat -- Synchronisiert andere im Raum befindliche Thermostate wenn kein anderes zentrales Thermostat vorhanden ist // 10.CreateStates -- legt alle relevanten States fuer Raeume und profile an //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- // Funktion ManAdjustments checkt ob eineThermostat/Raum Temperatur manuell angpasst wurde //----------------------------------------------------------------------------------------------------- function ManAdjustments (room,id) { var ViewManDuration = getState(path + "." + room +".View_Manual_Temp_Duration").val; // Dauer der manuellen Aenderung var ViewManValidity = getState(path + "." + room +".View_ManTemp_Validity").val; // Errechnete Gueltigkeit als Ende Zeit var ViewManValue = Calculate_SollTemp(getState(path + "." + room +".View_Manually_Adjusted").val, "SetTemp");// Check fuer eine manuelle Temp Aenderung aus dem view var SourceManValue = Calculate_SollTemp(getState(path + "." + room +".Source_Manually_Adjusted").val, "SetTemp");// Check fuer eine manuelle Temp Aenderung aus dem view var ManAdjTimeStamp = getState(path + "." + room +".Source_TimeStamp").val; // Zeitstempel fall eine manuelle korrektur schon aktiv ist var last_Soll_Temp = getState(path + "." + room +".Source_Last_Temp").val; // Letzte gespeicherte Soll Temperatur var currentSollTemp = getState(id).val; // Ist die Geraete SollTemp ungleich der zuletzt gespeicherten Soll Temp ? var ActTime = formatDate(new Date(),"JJJJ/MM/DD SS:mm:ss"); // Formatierte Aktuelle Zeit var ActTimeMilliSek = new Date(ActTime).getTime(); // Aktuelle Zeit in Millisekunden seit 1970 var bisTime = getState(path + "." + room +".View_ManTemp_Validity").val; // gespeicherte Bistime var bisSetTimeMilliSek; var lastSetTimeMilliSek; var ChckAbsenkung = false; if(currentSollTemp === VerschlussAbsenkungsGrenze) { ChckAbsenkung = true; } if(ViewManDuration <= 0 ) { // die Dauer der manuellen Aenderung ist auf null gesetzt Source_ManualAdjustment = "Manuelle Temperatur Erkennung ist ausgeschaltet"; if(ManAdjTimeStamp !== "init" || ViewManValidity !== "init" || ViewManValue > 0 || ViewManValue > 0 ) { InitilizeManChange(room); // Manuelle Aenderungen zuruecksetzen Source_ManualAdjustment = "Manuelle Temperatur Erkennung initialisiert und ausgeschaltet"; } if(debug) { log(Source_ManualAdjustment,"info") } return false; } if(ManAdjTimeStamp !== "init" ) { // eine manuelle Temperatur wurde bereits gespeichert lastSetTimeMilliSek = new Date(ManAdjTimeStamp).getTime(); // gespeicherte Von-Zeit der manuellen Aenderung in Millisekunden seit 1970 bisSetTimeMilliSek = lastSetTimeMilliSek + ViewManDuration * 60 * 1000; // Bis Zeit der Gueltigkeit der manuellen Aenderung in Millisekunen } else { lastSetTimeMilliSek = ActTimeMilliSek; bisSetTimeMilliSek = lastSetTimeMilliSek + ViewManDuration * 60 * 1000; } // 1. Fall eine manuelle Korrektur ist erkannt - Sie wurde gerade erst eingestellt if (currentSollTemp !== last_Soll_Temp && ManAdjTimeStamp === "init" && ChckAbsenkung !== true) { // Temperturdifferenz erkannt und Zeitstempel noch nicht gesetzt Source_ManualAdjustment = "Manuelle Temperatur Verstellung am Thermostat auf " + currentSollTemp + " " + "erkannt"; SetTemp (room,currentSollTemp,id,false); Source_ManTempSet = currentSollTemp; setState(path + "." + room +".Source_TimeStamp",ActTime ); // Zeitstempel mit der aktuellen Zeit versehen setState(path + "." + room +".View_ManTemp_Validity",formatDate(bisSetTimeMilliSek,"JJJJ/MM/DD SS:mm:ss") ); // Zeitstempel mit der aktuellen Zeit versehen setState(path + "." + room +".Source_Manually_Adjusted",Calculate_SelectValueWert(currentSollTemp,"SetTemp") ); setState(path + "." + room +".View_Manually_Adjusted",Calculate_SelectValueWert(currentSollTemp,"SetTemp") ); if(debug) { log("1.Fall " + Source_ManualAdjustment,"info") } return true; } // 2. Fall eine Temperatur wurde im View eingegeben - eine vorherige Manuelle Temp gibt es nicht if (ManAdjTimeStamp === "init" && ViewManValue > 0) { // Im View wurde eine manuelle Temperatur eingetragen Source_ManualAdjustment = "Manuelle Temperatur Verstellung im View auf " + ViewManValue + " " + "erkannt"; SetTemp (room,ViewManValue,id,false); Source_ManTempSet = ViewManValue; setState(path + "." + room +".Source_TimeStamp",ActTime ); // Zeitstempel mit der aktuellen Zeit versehen setState(path + "." + room +".View_ManTemp_Validity",formatDate(bisSetTimeMilliSek,"JJJJ/MM/DD SS:mm:ss") ); // Zeitstempel mit der aktuellen Zeit versehen setState(path + "." + room +".Source_Manually_Adjusted",Calculate_SelectValueWert(ViewManValue,"SetTemp") ); if(debug) { log("2.Fall " + Source_ManualAdjustment,"info") } return true; } // 3. Fall im View wurde eine Temperatur gesetzt die von der vorher gesetzten Temperatur abweicht - overrule durch view if (ManAdjTimeStamp !== "init" && SourceManValue !== ViewManValue && ViewManValue > 0) { // Im View wurde eine manuelle Temperatur eingetragen Source_ManualAdjustment = "Manuelle Temperatur wurde im View auf 0 gesetzt - Loeschen der manuellen Temperatur "; SetTemp (room,ViewManValue,id,false); Source_ManTempSet = ViewManValue; setState(path + "." + room +".Source_Manually_Adjusted",ViewManValue) ; setState(path + "." + room +".View_Manually_Adjusted",ViewManValue) ; if(debug) { log("3.Fall " + Source_ManualAdjustment,"info") } return true; } // 4. Fall im View wurde die Temperatur auf 0 gesetzt - das fuehrt zum reset der manuellen Temperatur if (ManAdjTimeStamp !== "init" && ViewManValue === 0 && SourceManValue > 0) { // Im View wurde eine manuelle Temperatur eingetragen Source_ManualAdjustment = "Manuelle Temperatur wurde im View auf Null gesetzt - Loeschen der manuellen Temperatur"; InitilizeManChange(room); // Manuelle Aenderungen zuruecksetzen if(debug) { log("4.Fall " + Source_ManualAdjustment,"info") } return false; } // 5. Fall Die Manuelle Temperatur wurde am Thermostat veraendert if (currentSollTemp !== SourceManValue && ManAdjTimeStamp !== "init" && ChckAbsenkung !== true) { Source_ManualAdjustment = "Manuelle Temperatur Verstellung im Termostat auf " + currentSollTemp + " " + "erkannt"; setState(path + "." + room +".Source_Manually_Adjusted",Calculate_SelectValueWert(currentSollTemp,"SetTemp") ); setState(path + "." + room +".View_Manually_Adjusted",Calculate_SelectValueWert(currentSollTemp,"SetTemp") ); Source_ManTempSet = currentSollTemp; if(debug) { log("5.Fall " + Source_ManualAdjustment,"info") } return true; } // 6. Fall - die Manuell gesetzte Temperatur wird auf abgelaufen ueberprueft if (currentSollTemp !== last_Soll_Temp && ManAdjTimeStamp !== "init" ) { // Die manuelle Temperatur ist - pruefen ob abgelauen // wenn abgelaufen, dann die manuelle Temperatur loeschen if(bisSetTimeMilliSek <= ActTimeMilliSek) { // die manuelle Zeit ist abgelaufen InitilizeManChange(room); // Manuelle Aenderungen zuruecksetzen Source_ManualAdjustment = "Manuelle Temperatur abgelaufen um: " + ViewManValidity + " - zurueck zum Schedule" if(debug) { log("6a.Fall " + Source_ManualAdjustment,"info"); } return false; } else { // Temperatur noch nicht abgelaufen if(ChckAbsenkung !== true ) { // wenn keine Temperaturabsenkung vorliegt Source_ManualAdjustment = "Manuelle Temperatur noch aktuell - warten bis " + ViewManValidity + " - Temperatur ist " + currentSollTemp; Source_ManTempSet = currentSollTemp; if(debug) { log("6b.Fall" + Source_ManualAdjustment,"info"); } return true; } else { SetTemp (room,SourceManValue,id,false); // alte manuelle Temperatur wieder einstellen Source_ManTempSet = SourceManValue; return true; } } // endif Die manuelle Zeit ist abgelaufen } // check ob die manuelle Zeit abgelaufen ist // 7. Fall - die Manuell gesetzte Temperatur ist abgelaufen- der schedule hat gewechselt und entspricht der vorherigen manuellen Temperatur (Ausnahmesituation) if (ManAdjTimeStamp !== "init" ) { // Die manuelle Temperatur ist - pruefen ob abgelauen if(bisSetTimeMilliSek + cron * 60 * 1000 < ActTimeMilliSek) { InitilizeManChange(room); // Manuelle Aenderungen zuruecksetzen Source_ManualAdjustment = "Manuelle Temperatur abgelaufen um: " + ViewManValidity + " - zurueck zum Schedule" if(debug) { log("7.Fall " + Source_ManualAdjustment,"info"); } return false; } } return false; } // Endfunction //----------------------------------------------------------------------------------------------------- // Funktion OverruleSollTemp arbeitet nach der vorgegebenen Reihenfolge die globalen und Profilparameter ab //----------------------------------------------------------------------------------------------------- function OverruleSollTemp (room,Profil,SollTempSched,id) { for (var x in OverruleTab) { if(OverruleTab[x][0] === "UrlaubAnwesend") { // Wenn Urlaub dann Absenkung bis Mindestemperatur if (getState(StateUrlaubAnwesend).val ) { if (getState( path + "." + room + "." + "Profil-" + Profil +"."+StatePP_UrlaubWieFeiertag).val ) { Source_ProfilParameter = "Urlaub Anwesend - Urlaub wie Feiertag"; } else { Source_GlobalParameter = "Urlaub Anwesend"; } // endif ist der Urlaub wie ein Feiertag ? } // endif Urlaubanwesend ist true } if(OverruleTab[x][0] === "UrlaubAbwesend" && getState(StateUrlaubAbwesenheit).val) { // Wenn Urlaub dann Absenkung bis Mindestemperatur if (Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "." + StatePP_UrlaubAbsenkung).val,"CorrectTemp") !== 0) { // Absenkung geplant ? SollTempSched = SollTempSched - Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "." + StatePP_UrlaubAbsenkung).val,"CorrectTemp"); Source_GlobalParameter = "Urlaub Absenkung"; if(SollTempSched < Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "." + StatePP_MinimaleTemperatur).val,"SetTemp")) { SollTempSched = Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "." + StatePP_MinimaleTemperatur).val,"SetTemp"); Source_GlobalParameter = "Urlaub Absenkung-MindestTemperatur"; } return SollTempSched; } } if(OverruleTab[x][0] === "Gaeste") { // Wenn Gaeste dann Anhebung um Profilparameter if (getState(StateGaesteDa).val && Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "."+StatePP_GaesteAnhebung).val,"CorrectTemp") !== 0) { // Gaeste Anhebung muess ungleich 0 sein // nur wenn einen Anhebung geplant ist SollTempSched = SollTempSched + Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "."+StatePP_GaesteAnhebung).val,"CorrectTemp"); Source_GlobalParameter = "Gaeste Anhebung"; if(SollTempSched < Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "." + StatePP_MinimaleTemperatur).val,"SetTemp")) { SollTempSched = Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "." + StatePP_MinimaleTemperatur).val,"SetTemp"); Source_GlobalParameter = "Gaeste-MindestTemperatur"; } return SollTempSched; } } if(OverruleTab[x][0] === "Abwesenheit") { // Wenn Abwesenheit dann Absenkung um Profilparameter if (getState(StateAnwesenheit).val === false && Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "."+StatePP_AbwesenheitAbsenkung).val,"CorrectTemp") !== 0) { // Gaeste Anhebung muess ungleich 0 sein // nur wenn einen Anhebung geplant ist SollTempSched = SollTempSched - Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "."+StatePP_AbwesenheitAbsenkung).val,"CorrectTemp"); Source_GlobalParameter = "Abwesenheit Absenkung"; if(SollTempSched < Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "." + StatePP_MinimaleTemperatur).val,"SetTemp")) { SollTempSched = Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "." + StatePP_MinimaleTemperatur).val,"SetTemp"); Source_GlobalParameter = "Abwesenheit Absenkung-MindestTemperatur"; } return SollTempSched; } } if(OverruleTab[x][0] === "Party") { // Wenn Party dann Absenkung um Profilparameter if (getState(StatePartyjetzt).val && Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "."+StatePP_PartyAbsenkung).val,"CorrectTemp") !== 0) { // Gaeste Anhebung muess ungleich 0 sein // nur wenn einen Anhebung geplant ist SollTempSched = SollTempSched - Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "."+StatePP_PartyAbsenkung).val,"CorrectTemp"); Source_GlobalParameter = "Party Absenkung"; if(SollTempSched < Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "." + StatePP_MinimaleTemperatur).val,"SetTemp")) { SollTempSched = Calculate_SollTemp(getState(path + "." + room + "." + "Profil-"+Profil + "." + StatePP_MinimaleTemperatur).val,"SetTemp"); Source_GlobalParameter = "Party Absenkung-MindestTemperatur"; } return SollTempSched; } } } return SollTempSched; } // Ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion ExecuteTempDetermination checkt ob eineThermostat/Raum Temperatur manuell angpasst wurde //----------------------------------------------------------------------------------------------------- function ExecuteTempDetermination (roomName,id) { var ActiveRoomProfile; var ScheduledSollTemp; // Findung des aktuellen RaumProfiles ActiveRoomProfile = ActiveProfile (roomName); // Ermittlung des aktiven Raumprofils //die geplante Soll Temperatur aus dem Raumschedule aus dem aktuellen Profil ermitteln ScheduledSollTemp = SelectSwichTime(roomName,deviceType,id,ActiveRoomProfile); // Ermittlung der geplanten Solltemperatur if(debug ) { log("raum " + roomName + "Solltemp nach Switchtime: " + ScheduledSollTemp+ " Findung " + Source_SchedulePoint,"info"); } // Schauen ob die ermittelte Temperatur angepasst werden muss z.B. party Gaeste etc ScheduledSollTemp = OverruleSollTemp(roomName,ActiveRoomProfile,ScheduledSollTemp,id); //Global und Profilparameter koennen den schedule uebersteuern if(debug ) { log("raum " + roomName + "Solltemp nach overrule: " + ScheduledSollTemp+ " Findung " + Source_GlobalParameter,"info"); } // jetzt nochmal schauen, ob die gefundene Temperatur evt gleich einer manuell angepassten Temperatur ist if(getState(id).val === ScheduledSollTemp && getState(path + "." + roomName +".Source_TimeStamp").val !== "init" ) { Source_ManualAdjustment = "Manuell gesetzte Temperatur ist identisch mit der geplanten SollTemp - wird zurueckgesetzt"; InitilizeManChange(roomName); // Manuelle Aenderungen zuruecksetzen if(debug) { log(Source_ManualAdjustment,"info") } } // jetzt die Temperatur dem Thermostat uebermitteln SetTemp (roomName,ScheduledSollTemp,id,true); // jetzt die Temperatur schalten } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion Finde Schaltzeit im schedule und geplante Solltemperatur //----------------------------------------------------------------------------------------------------- function SelectSwichTime (room,deviceType,id,RaumProfil) { room = room.replace(/\s/g, "_"); // Alle Leerzeichen aus der Raumbezeichnung entfernen var weekday = new Date().getDay(); var currTime = formatDate(new Date(),"SS:mm:ss"); var TimeBisScheduled = " "; var TemperatureScheduled; var lasttime; weekday = DetermineSchedule(room,weekday,RaumProfil); // weekday wird uebersteuert, wenn ein "WieVortag" vorkommt for (i = 1; i <= 6; i++) { // es gibt 6 schedules pro Tag lasttime = "00:00:00"; TimeBisScheduled = getState(path + "." + room + ".Profil-"+ RaumProfil + "." + Wochentag(weekday)+ "_" + i +"_" + "bis").val; if(isTimeInRange(lasttime, TimeBisScheduled)) { TemperatureScheduled = getState(path + "." + room + ".Profil-" + RaumProfil+ "." + Wochentag(weekday)+ "_" + i +"_" + "Temp").val; TemperatureScheduled = Calculate_SollTemp(TemperatureScheduled,"SetTemp"); if(debug) { log("Schedule verwendet " + Wochentag(weekday) + " Timeslot ist " + TimeBisScheduled + " Solltemp ist " + TemperatureScheduled+ " RaumProfil ist: "+ RaumProfil,"info"); } Source_SchedulePoint = Wochentag(weekday)+"_" + TimeBisScheduled; return TemperatureScheduled; //exakte Schaltzeit gefunden - also raus jetzt } // endif timeInRange lasttime = TemperatureScheduled; } // endfor return 0; // da ist was schiefgelaufen. es haette einen schedule geben sollen } // ende Funktion //----------------------------------------------------------------------------------------------------- //Globale Parameter aus ICAL Feiertagskalender und Anwesenheitserkennung setzen // Globale Parameter aus ICAL: Urlaub Anwesend, Urlaub Abwesend, Party, Gaeste, Feiertage // Wenn events genutzt werden, dann koennen globale Parameter nicht mehr manuell eingestellt werden //----------------------------------------------------------------------------------------------------- function SetEventGlobalParameter() { if(UseEventsGlobalParameter === false) { return; // global parameter events sind ausgeschaltet } if(getState(ICALPath + "."+ EventG_Party).val) { setState(StatePartyjetzt,true); Source_ICALEvent = EventG_Party; return; } else { setState(StatePartyjetzt,false); } if(getState(ICALPath + "."+ EventG_UrlaubAbwesend).val) { setState(StateUrlaubAbwesenheit,true); Source_ICALEvent = EventG_UrlaubAbwesend; return; } else { setState(StateUrlaubAbwesenheit,false); } if(getState(ICALPath + "."+ EventG_UrlaubAnwesend).val) { setState(StateUrlaubAnwesend,true); Source_ICALEvent = EventG_UrlaubAnwesend; return; } else { setState(StateUrlaubAnwesend,false); } if(getState(ICALPath + "."+ EventG_Gaeste).val) { setState(StateGaesteDa,true); Source_ICALEvent = EventG_Gaeste; return; } else { setState(StateGaesteDa,false); } if(UseFeiertagskalender === false) { // Wenn der Feiertagsadapter genutzt wird werden Events fuer Feiertage nicht genutzt if(getState(ICALPath + "."+ EventG_Feiertag).val) { setState(StateFeiertagHeute,true); Source_ICALEvent = EventG_Feiertag; return; } else { setState(StateFeiertagHeute,false); } // endif check ICAL } // endif feiertagskalender nicht aktiv } // Ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion Finde Aktives Raumprofil //----------------------------------------------------------------------------------------------------- function ActiveProfile (room,Profil) { var pathprofile = path+"."+room; var ProfileName; if (MaxProfile === 1) { Profil = 1; Source_Profil = 1; return Profil; } // Erst Raumprofil checken - prio1 if(UseEventsRaumProfilSelect === true) { for (i = 1; i <= MaxProfile; i++) { ProfilName = UseEventR_Profil; ProfilName = UseEventR_Profil .replace("",room); ProfilName = ProfilName .replace("",i); if(getState(ICALPath + "."+ ProfilName).val) { setState(pathprofile+".AktivesEventProfil",i); Source_Profil = i; Source_ICALEvent = ProfilName; return i; } } // ende for i } // ende if globalProfilSelect // Globales Profil ist prio2 if(UseEventsGlobalProfilSelect === true) { for (i = 1; i <= MaxProfile; i++) { ProfilName = UseEventG_Profil; ProfilName = UseEventG_Profil .replace("",i); if(getState(ICALPath + "."+ ProfilName).val) { setState(pathprofile+".AktivesEventProfil",i); Source_Profil = i; Source_ICALEvent = ProfilName; return i; } } // ende for i } // ende if globalProfilSelect if(getState(pathprofile+".AktivesEventProfil").val !== 0) { // falls vorher ein Eventprofil aktiv war jetzt deaktivieren setState(pathprofile+".AktivesEventProfil",0); } // Wenn kein anderes Profil vorliegt dann gilt das manuell eingstellte Profil Profil = getState(pathprofile + ".AktivesRaumProfil").val; if (Profil > 9 || Profil < 1) { Profil = 1; } Source_Profil = Profil; return Profil; } //----------------------------------------------------------------------------------------------------- // Funktion SetTemp zum setzen einer neuen Solltemperatur //----------------------------------------------------------------------------------------------------- function SetTemp (room,SollTemp,id,AdjustLastTemp) { //log ("SetTemp " + SollTemp) //log ("SetTemp " + id) if(debug) { log ("ID to be updated " + id+" Raum " + room + " SollTemp = " + SollTemp,"info"); } SetDetData(room); // Speichere Findungsdaten if (getState(id).val !== SollTemp) { // ist die SET-Temperature unterschiedlich zur errechneten Solltemperatur ? setState(id,SollTemp); Source_CurrentSollTemp = SollTemp; } if(AdjustLastTemp ) { // LastSollTemp synhronisieren setState(path + "." + room +".Source_Last_Temp",SollTemp); } // endif } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion um den richtigen Planungstag zu finden bei Verwendung von WieVortag im schedule //----------------------------------------------------------------------------------------------------- function DetermineSchedule(room,weekday,Profil) { var currentday = weekday; var prePath = path + "." + room + ".Profil-" + Profil+"."; StateUrlaubWieFeiertag = prePath + "ProfilParameter_UrlaubWieFeiertag"; // Profilparameter Urlaub = Feiertag gesetzt ? if(getState(StateUrlaubAnwesend).val && getState(StateUrlaubWieFeiertag).val ) { // Heute ist ein Urlaubstag und soll wie ein Feiertag behandelt werden weekday = 7; // Urlaub ist wie Feiertag also den Feiertagsschedule setzen } if (weekday === 1) { // der schedule fuer Montag hat nie einen "wie Vortag" return weekday; } var TempWieVortag = getState(prePath + Wochentag(weekday)+ "_" + "wieVortag").val; // Wenn es keinen "WieVortag gib, dann kann der Tag genommen werden" if(TempWieVortag === false) { return weekday; } if(weekday === 0 ) { // Sonntag TempWieVortag = getState(prePath + Wochentag(0)+ "_" + "wieVortag").val; if (TempWieVortag===false) { if(debug) {log("Heute ist = " + Wochentag(weekday) + " Tag fuer den Schedule ist = " + Wochentag(0),"info"); } return(0); // Sonntagschedule hat keinen "WieVortag"-tick } else { weekday = 6; // Sonntagschedule hat einen "WieVortag"-tick also ist geht es jetzt mit Samstag weiter } } // Erstmal bei Feiertag schauen ob der Sonntag-Schedule der richtige ist if(weekday === 7 ) { // Feiertag TempWieVortag = getState(prePath + Wochentag(0)+ "_" + "wieVortag").val; if (TempWieVortag===false) { if(debug) { log("Heute ist = " + Wochentag(weekday) + " Tag fuer den Schedule ist = " + Wochentag(0),"info"); } return(0); // Sonntagschedule hat keinen "WieVortag"-tick } else { weekday = 6; // Sonntagschedule hat einen "WieVortag"-tick also ist geht es jetzt mit Samstag weiter } } // da Feiertag und Sonntag schon klar sind koennen die Tage von Samstag bis Montag (6-1) abgearbeitet werden for (i = weekday; i >0; i--) { TempWieVortag = getState(prePath + Wochentag(i)+ "_" + "wieVortag").val; if (TempWieVortag===false) { if(debug) { log("Heute ist = " + Wochentag(currentday) + " Tag fuer den Schedule ist = " + Wochentag(i),"info"); } return(i); // Sonntagschedule ist richtig } } } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion SyncThermostat - bei manuellen Aenderungen werden alle Thermostate des Raumes gesynched //----------------------------------------------------------------------------------------------------- function SyncThermostat (room,Action,SollTemp,Source_id) { var id; for (var x in ControlTab){ id = ControlTab[x][1]; if(ControlTab[x][0] === room && Action === "ExecuteTemp" && Source_id !== id ) { // Raum selektieren und alle abhaengingen Thermostate (mit 1 gekennzeichnet) if(debug) {log("Temperatur wird nach schedule synchronisiert fuer id " +id ) } ExecuteTempDetermination (room,id); } // endif setzte Temp entsprechend schedule if(ControlTab[x][0] === room && Action === "ManualTemp" && Source_id !== id ) { // Raum selektieren und alle abhaengingen Thermostate (mit 1 gekennzeichnet) if(debug) {log("Temperatur " + SollTemp + " wird synchronisiert fuer id " + id ) } SetTemp (room,SollTemp,id,false); } // endif setze Manuelle Temperatur } // endfor } // Ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion CreateStates zum Anlegen der Datenpunkte //----------------------------------------------------------------------------------------------------- function CreateStates (room,DeviceType) { room = room.replace(/\s/g, "_"); // Alle Leerzeichen aus der Raumbezeichnung entfernen // Globale Parameter createState(StateAnwesenheit, false, {read: true, write: true, type: 'boolean', name: 'Anwesenheitsflag ' , desc: 'Anwesenheitsflag'}); createState(StateFeiertagHeute, false, {read: true, write: true, type: 'boolean', name: 'Feiertag Heute ' , desc: 'Feiertag Heute- zur Temperaturanpassung (wie Sonntag)'}); createState(StatePartyjetzt, false, {read: true, write: true, type: 'boolean', name: 'Party Jetzt ' , desc: 'Party Jetzt- zur Temperaturanpassung'}); createState(StateGaesteDa, false, {read: true, write: true, type: 'boolean', name: 'Gaeste da ' , desc: 'Gaeste da - zur Temperaturanpassung'}); createState(StateUrlaubAnwesend, false, {read: true, write: true, type: 'boolean', name: 'Urlaub Anwesend ' , desc: 'Urlaub Heute- zur Temperaturanpassung (wie Sonntag)'}); createState(StateUrlaubAbwesenheit, false, {read: true, write: true, type: 'boolean', name: 'Urlaub Abwesend ' , desc: 'Urlaub und nicht zu Hause)'}); createState(StateHeizperiode, true, {read: true, write: true, type: 'boolean', name: 'Wenn Heizperiode dann Aktivierung der Heizplaene' , desc: 'Ausserhalb der Heizperiode werden Ventile geschlossen'}); State = Gparameterpath + ".Source_last_Program_Run"; createState(State, "init", {read: true, write: true, type: 'string', name: 'Datum/Zeit des letzten Programmlaufes' , desc: 'Datum/Zeit des letzten Programmlaufes'}); // Anlegen der raumbezogenen/profilbezogenen Datenpunkte var State; var RoomPath = path + "." + room + "."; var Profilpath; var Vorgabewert1 = Calculate_SelectValueWert(1,"CorrectTemp"); var Vorgabewert2 = Calculate_SelectValueWert(2,"CorrectTemp"); var Vorgabewert17 =Calculate_SelectValueWert(17,"SetTemp"); for (y = 1; y <= MaxProfile; y++) { // es werden alle Daten je profil angelegt Profilpath = "Profil-" + y +"."; for (i = 1; i <= 6; i++) { // es werden 6 BIS Zeiten angelegt for (x = 0; x <= 7; x++) { // es wird ein Plan je Wochentag und ein Feiertag angelegt if(i <= 6 ) { // die 6. Zeit hat keine BIS Zeit - nur Temperatur erforderlich StateBis = RoomPath + Profilpath + Wochentag(x)+ "_" + i +"_" + "bis"; } StateTemp = RoomPath + Profilpath + Wochentag(x)+ "_"+ i +"_" + "Temp"; if(i===1) { bisTime = "06:00:00"; SollTemp = Calculate_SelectValueWert(17,"SetTemp");} if(i===2) { bisTime = "08:00:00"; SollTemp = Calculate_SelectValueWert(21,"SetTemp");} if(i===3) { bisTime = "16:00:00"; SollTemp = Calculate_SelectValueWert(18,"SetTemp");} if(i===4) { bisTime = "21:00:00"; SollTemp = Calculate_SelectValueWert(21,"SetTemp");} if(i===5) { bisTime = "23:30:00"; SollTemp = Calculate_SelectValueWert(19,"SetTemp");} if(i===6) { bisTime = "00:00:00"; SollTemp = Calculate_SelectValueWert(17,"SetTemp");} createState(StateBis ,bisTime , {read: true, write: true, type: 'string', name: 'Zeit ' + i + ' von' , desc: 'Zeit von'}); createState(StateTemp ,SollTemp , {read: true, write: true, type: 'number', name: 'Solltemperatur '+ i , desc: 'Solltemperatur'}); StateWieVortag = RoomPath + Profilpath + Wochentag(x)+ "_" + "wieVortag"; createState(StateWieVortag, false, {read: true, write: true, type: 'boolean', name: 'Wie Vortag ' , desc: 'Wie Vortag'}); } // endfor y 6 Zeiten bzw Temperatur je schedule } // endfor i 6 BIS Zeiten State = RoomPath + Profilpath + StatePP_PartyAbsenkung; createState(State, Vorgabewert2 , {read: true, write: true, type: 'number', name: 'Absenkung bei Party in Grad Celsius ' , desc: 'Absenkung bei Party - negativer Wert = Anhebung'}); State = RoomPath + Profilpath + StatePP_GaesteAnhebung; createState(State, Vorgabewert1 , {read: true, write: true, type: 'number', name: 'Anhebung, wenn Gaeste anwesend ' , desc: 'Anhebung bei Gaesten - negativer Wert = Absenkung'}); State = RoomPath + Profilpath + StatePP_AbwesenheitAbsenkung; createState(State, Vorgabewert1 , {read: true, write: true, type: 'number', name: 'Absenkung bei Abwesenheit in Grad Celsius' , desc: 'Absenkung bei Abwesenheit - negativer Wert = Anhebung'}); State = RoomPath + Profilpath + StatePP_UrlaubAbsenkung createState(State, Vorgabewert2 , {read: true, write: true, type: 'number', name: 'Absenkung bei Urlaubs-Abwesenheit in Grad Celsius' , desc: 'Absenkung bei Urlaubs-Abwesenheit - negativer Wert = Anhebung'}); State = RoomPath + Profilpath + StatePP_UrlaubWieFeiertag; createState(State, true, {read: true, write: true, type: 'boolean', name: 'bei Anwesenheit wg Urlaub Temperaturen laut Feiertagsplan' , desc: 'Temperaturen laut Feiertagsplan'}); State = RoomPath + Profilpath + "ProfilParameter_MinimaleTemperatur"; createState(State, Vorgabewert17 , {read: true, write: true, type: 'boolean', name: 'Minimale Temperatur fuer Absenkung' , desc: 'Minimale Temperatur fuer Absenkung'}); } // endfor y // Daten je Profil // RaumParameter State = RoomPath + "AktivesRaumProfil"; createState(State, 0, {read: true, write: true, type: 'number', name: 'Aktives EventProfil 1-9' , desc: 'Fuer jeden Raum koennen max 9 Profile verwendet werden'}); State = RoomPath + "AktivesEventProfil"; createState(State, 0, {read: true, write: true, type: 'number', name: 'Aktives EventProfil 1-9' , desc: 'Fuer jeden Raum koennen max 9 Profile verwendet werden'}); State = RoomPath + "Source_Profil"; createState(State, 0, {read: true, write: true, type: 'number', name: 'ermitteltes Profil fuer die letzte RaumTemperatur' , desc: 'Fuer jeden Raum koennen max 9 Profile verwendet werden'}); State = RoomPath + "Source_ICALEvent"; createState(State, "init", {read: true, write: true, type: 'string', name: 'ermitteltes ICAL Event fuer die Profilfindung / Parameterermittlung' , desc: 'Profil oder Parameteranpassung'}); State = RoomPath + "Source_Schedule"; createState(State, "init", {read: true, write: true, type: 'string', name: 'der Schedulepunkt fuer die Solltemperatur' , desc: 'Der Schedule ist die taegliche Temperaturplanung'}); State = RoomPath + "Source_Global_Parameter"; createState(State, "init", {read: true, write: true, type: 'string', name: 'Globaler Parameter, der die Temperaturfindung beeinflusst' , desc: 'Global Parameter wie Party, Urlaub, Gaeste etc'}); State = RoomPath + "Source_Manually_Adjusted"; createState(State, 0, {read: true, write: true, type: 'number', name: 'Manuell eingestellte Temperatur' , desc: 'Solltemperatur der manuellen Verstellung'}); State = RoomPath + "Source_Last_Temp"; createState(State, 0, {read: true, write: true, type: 'number', name: 'letzte eingestellte Temperatur' , desc: 'Letzte Solltemperatur'}); State = RoomPath + "Source_TimeStamp"; createState(State, "init", {read: true, write: true, type: 'string', name: 'Datum und Zeit der letzten Tempanpassung' , desc: 'Zeitstempel'}); State = RoomPath + "View_Manually_Adjusted"; createState(State, false, {read: true, write: true, type: 'boolean', name: 'Zeitstempel Temperatur Absenkung bei Verschluss offen' , desc: 'Zeitstempel wenn ein Raum durch Fensteroeffnung auf Absenkung gestellt wurde'}); State = RoomPath + "View_Manual_Temp_Duration"; createState(State, 120, {read: true, write: true, type: 'number', name: 'Gueltigkeit in Minuten fuer manuelle Temperatur Aenderung' , desc: 'Zeitgueltigkeit in Minuten'}); State = RoomPath + "View_ManTemp_Validity"; createState(State, "init", {read: true, write: true, type: 'string', name: 'Datum und Zeit der Gueltigkeit (bis) zur Rueckkehr zum Plan' , desc: 'Zeitgueltigkeit bis (Datum / Zeit'}); State = RoomPath + "RaumParameter_ManuellModeForce"; createState(State, true, {read: true, write: true, type: 'boolean', name: 'Immer Umschaltung auf manuell (nur neue Thermsotate)' , desc: 'Immer Umschaltung auf manuell (nur neue Thermsotate'}); } // ende Funktion //----------------------------------------------------------------------------------------------------- //ab hier Nebenfunktionen //----------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------- // Funktion InitilizeManChange - Ruecksetzen der manuellen Daten - Manuelle Temperatur //----------------------------------------------------------------------------------------------------- function InitilizeManChange(room) { setState(path + "." + room +".Source_TimeStamp","init" ); setState(path + "." + room +".View_ManTemp_Validity","init" ); setState(path + "." + room +".Source_Manually_Adjusted",0) ; setState(path + "." + room +".View_Manually_Adjusted",0) ; } // endfunction //----------------------------------------------------------------------------------------------------- // Funktion SortControlTab - Sortieren der ControlTab nach Raumnamen //----------------------------------------------------------------------------------------------------- function SortControlTab(a,b) { a = a[0]; b = b[0]; return a == b ? 0 : (a < b ? -1 : 1); } // endfunction //----------------------------------------------------------------------------------------------------- // Funktion check Room in roomlist - //----------------------------------------------------------------------------------------------------- function ChckRoom (room) { for (var z in ControlTab) { if ( ControlTab[z][0] === room ) { return true; } } return false; } // ende funktion //----------------------------------------------------------------------------------------------------- // Funktion SensorFind Sucht den Sensor aus der SensorTabelle //----------------------------------------------------------------------------------------------------- function SensorFind (id) { for (var i in SensorList ) { if ( SensorList[i][1] === id) { return i; } } return 999; } //----------------------------------------------------------------------------------------------------- //Function VerschlussRaumStatus // ermittelt ob irgend ein Verschluss auf offen steht //----------------------------------------------------------------------------------------------------- function VerschlussRaumStatus(room) { var count=0; for (var x in SensorList) { if (SensorList[x][0].toString() === room) { count = count + 1; if(SensorList[x][7] === true) { return true; // mindestens ein Sensor staht auf offen } } } return false; // alle Sensoren auf geschlossen } // Ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion SetDetData - Schreibt die Findungsdaten in die source states //----------------------------------------------------------------------------------------------------- function SetDetData (room) { if(getState(path + "." + room +".Source_Profil") !== Number(Source_Profil) ) { setState(path + "." + room +".Source_Profil",Source_Profil); } if(getState(path + "." + room +".Source_Global_Parameter") !== Source_GlobalParameter) { setState(path + "." + room +".Source_Global_Parameter",Source_GlobalParameter); } if(getState(path + "." + room +".Source_ICALEvent") !== Source_ICALEvent) { setState(path + "." + room +".Source_ICALEvent",Source_ICALEvent); } if(getState(path + "." + room +".Source_ICALEvent") !== Source_ICALEvent) { setState(path + "." + room +".Source_ICALEvent",Source_ICALEvent); } if(getState(path + "." + room +".Source_Schedule") !== Source_SchedulePoint) { setState(path + "." + room +".Source_Schedule",Source_SchedulePoint); } } // Ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion Calculate SollTemperatur Urechnung des Select Value Wertes in Gradzahlen //----------------------------------------------------------------------------------------------------- function Calculate_SollTemp(SollTemp,Calc_type) { // var MinVal; var StepVal; var MaxVal ; if (VerwendungSelectValue !== true) { return SollTemp; } if( SollTemp === 0 ) { return SollTemp; } if (Calc_type === "SetTemp") { MinVal = 12; // Liste faengt mit 12 an StepVal = 0.5; // Schrittwert ist 0.5 SollTemp = MinVal + ( SollTemp *StepVal); // Errechnung der SollTemp } if (Calc_type === "CorrectTemp") { MinVal = 0; // Liste faengt mit 0 an MaxVal = 5; // Der Maxvalue ist Positiv und Negativ StepVal = 0.5; SollTemp = SollTemp * StepVal // Errechnung der SollTemp fuer positive Werte if(SollTemp > (MaxVal - MinVal)) { SollTemp = (SollTemp * -1 +StepVal) + MaxVal ; // fuer Negative Werte } } //log("aus Calc_SollTemp Ausstieg "+ SollTemp) return SollTemp; } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion Wochentag zur ermittlung des Tages //----------------------------------------------------------------------------------------------------- function Wochentag (tag) { if(tag === 0) { tag = "So"; return tag } if(tag === 1) { tag = "Mo"; return tag } if(tag === 2) { tag = "Di"; return tag } if(tag === 3) { tag = "Mi"; return tag } if(tag === 4) { tag = "Do"; return tag } if(tag === 5) { tag = "Fr"; return tag } if(tag === 6) { tag = "Sa"; return tag } if(tag === 7) { tag = "Feiertag"; return tag } } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion Calculate SelectValueList Wert Urechnung des Sollwertes in SelectValue List Wert //----------------------------------------------------------------------------------------------------- function Calculate_SelectValueWert(SelValWert,Calc_type) { var MinVal; var StepVal; var MaxVal; if (VerwendungSelectValue !== true) { return SelValWert; } if (Calc_type === "SetTemp") { MinVal = 12; // Liste faengt mit 12 an StepVal = 0.5; // Schrittwert ist 0.5 SelValWert = (SelValWert- MinVal ) / StepVal; // Errechnung des Select Value Wertes } if (Calc_type === "CorrectTemp") { MinVal = 0; // Liste faengt mit 0 an StepVal = 0.5; // Schrittwert ist 0.5 MaxVal = 5; // Der Maxvalue ist Positiv und Negativ if(SelValWert > (MaxVal/StepVal) ) { SelValWert = (SelValWert * (1-StepVal) *-1) +10; // Negative Werte } else { // else SelValWert = (SelValWert / StepVal); // Errechnung des Select Value Wertes positive Werte } } // log ("SelValWert = " + SelValWert,"info"); return SelValWert; } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion Setzt den Findungsnachweis zurueck //----------------------------------------------------------------------------------------------------- function ClearSources () { Source_Profil = 99 ; Source_ICALEvent =""; Source_ManualAdjustment =""; Source_GlobalParameter =""; Source_ProfilParameter =""; Source_LastTemp =""; Source_Timestamp =""; Source_SchedulePoint=""; } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion listed die sources im log //----------------------------------------------------------------------------------------------------- function LogSources () { if(debug !== true) { return; } log("Source_Profil " + Source_Profil,"info"); log("Source_ICALEvent " + Source_ICALEvent,"info"); log("Source_ManualAdjustment " +Source_ManualAdjustment,"info"); log("Source_GlobalParameter " + Source_GlobalParameter,"info"); log("Source_ProfilParameter " + Source_ProfilParameter,"info"); log("Source_LastTemp " + Source_LastTemp,"info"); log("Source_Timestamp " + Source_Timestamp,"info"); log("Source_SchedulePoint " + Source_SchedulePoint,"info"); log("Source_last_Program_Run " + Source_last_Program_Run,"info"); } // Ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion schreibt einen Logeintrag in das Filesystem //----------------------------------------------------------------------------------------------------- function writelog(room,id,Text) { if(OnlyChanges && Source_CurrentSollTemp === 0 ) { return; } // jetzt evt Kommawerte fuer Excel aufbereiten - Excel mit Komma =, und iobroker = . var Form_CurrentSollTemp = Source_CurrentSollTemp.toString(); Form_CurrentSollTemp = Form_CurrentSollTemp .replace(".",","); var Form_Source_ManualAdjustment = Source_ManualAdjustment.toString(); Form_Source_ManualAdjustment = Form_Source_ManualAdjustment .replace(".",","); if (LogFlag === true) { var logdate = formatDate(new Date(),"TT.MM.JJJJ"); var logtime = formatDate(new Date(),"SS:mm:ss"); if (fs.existsSync(LogPath)) { fs.appendFileSync(LogPath, logdate+";"+logtime+";"+room+";"+ id +";"+Form_CurrentSollTemp+";" +Source_Profil+";"+Source_GlobalParameter+";"+Source_ICALEvent+";"+Form_Source_ManualAdjustment+";"+Source_SchedulePoint+";"+Text + "\n"); // Fuege Satz in Datei ein } else { log("Logfile nicht gefunden - wird angelegt"), "info"; var headerLine= "Datum;Uhrzeit;Raum;Geraete-ID;SollTemp gesetzt;Profil;Global-Parameter;Event;Manuelle Temp;Schedule-Point;Bemerkung"; fs.appendFileSync(LogPath, headerLine + "\n"); // Fuege Satz in Datei ein fs.appendFileSync(LogPath, logdate+";"+logtime+";"+room+";"+ id +";"+Form_CurrentSollTemp+";" +Source_Profil+";"+Source_GlobalParameter+";"+Source_ICALEvent+";"+Form_Source_ManualAdjustment+";"+Source_SchedulePoint+";"+Text + "\n"); // Fuege Satz in Datei ein } // endif Filecheck } // Ende check on logflag } // Ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion RoomListUsage - Ist der UseRoomList eingeschaltet und befindet sich der Raum in der Liste //----------------------------------------------------------------------------------------------------- function RoomListUsage (Room) { if(UseRoomList === false) { return true; } for (var i in RoomList ) { if(RoomList[i][0] === Room) { return true; } } // endfor return false; } // End Function //----------------------------------------------------------------------------------------------------- // 3 Funktionen zum Zeitrange check zur Pruefung ob die Schaltungszeiten erreicht sind // Autor ist Beatz - uebernommen aus: // viewtopic.php?f=21&t=1072&p=11167&hilit=isTimeInRange&sid=4dca8ea2c7f9337cdc73a1a9e4824a40#p11167 //----------------------------------------------------------------------------------------------------- function isTimeInRange(strLower, strUpper) { if (strLower === null || strUpper === null) { return; } // var now = new Date(); var lower = addTime(strLower); var upper = addTime(strUpper); var inRange = false; if (upper > lower) { // opens and closes in same day inRange = (now >= lower && now <= upper) ? true : false; } else { // closes in the following day inRange = (now >= upper && now <= lower) ? false : true; } return inRange; } function currentDate() { var d = new Date(); return new Date(d.getFullYear(), d.getMonth(), d.getDate()); } function addTime(strTime) { var time = strTime.split(':'); var d = currentDate(); d.setHours(time[0]); d.setMinutes(time[1]); d.setSeconds(time[2]); return d; } // Ende Funktion