// Integrierte Heizungsthermostatsteuerung // Autor: Looxer01 ---------- Initiale Version: Datum 12.04.2017 // Version 0.7 12.04.2017 - Initialversion // Version 0.71 13.04.2017 - Korrektur: bei Raumnamen mit blanks wurden die Räume nicht beplant //...........................Ein Statement, dass zum Testen gedacht war wurde entfernt - Beim Anlegen der DPs führte das zu vielen Fehlermeldungen (Anlegen von DP und sofortiges Schreiben) // Version 0.72 14.04.2017 - Feiertag wurde nicht korrekt erkannt // ..........................Datumsformat für die Anzeige "letzter Programmlauf im View" wurde auf DDMMYYYY umgestellt // ..........................Das Feiertagsflag vom Feiertagsadapter wird synchronisiert mit dem Feiertagsflag der Heizungssteuerung //...........................Das Anwesenheitsflag von der Anwesenheitsfunktion wird synchronisiert mit dem Feiertagsflag der Heizungssteuerung // Version 0.73 14.04.2017 - Ueberfluessige LogEintraege entfernt // Version 0.74 15.04.2017 - Voreinstellung geaendert - annahme ist, dass mit direkten Verknuepfungen gearbeitet wird. Wenn nicht, dann muss die ThermostatTypeTab angepasst werden (Flag zentrale Steuerung) // Version 0.75 15.04.2017 - UserExit - Hinzugefügt //........................ - undefined Zustand Source_CurrentSollTemp abgefangen in writelog //........................ - Sensoren 'HM-Sec-RHS und 'HM-Sec-SC-2 aufgenommen // Version 0.76 18.05.2017 - Fehler Heizperiode - falscher control tab index in loop devices // Version 0.81 11,11.2017 - Fehler bei Create States - falscher type // beim view manually adjusted auf number gestellt und text korrigiert. // Fehler in der Roomlist: es wurden auch Geraete aus anderen Raeumen eingelesen // IP - Konfiguration angepasst fuer Wand und Heizkoerperthermostat // IP Geräte können jetzt auf den manuellen Modus gesetzt werden // Funktion: Nicht HM-Sensoren hinzugefügt // Userexit Datenpunkte bei den Experteneinstellungen auf initial gesetzt // Die Abfrage des GeraeteTypes fuer Thermostate wurde angepasst und checked ob der angegebene Type als Substring enthalten ist // und die Vergleichsstrings werden in Grossschrift verglichen (sensoren und Thermostate) // Nicht HM-Sensoren hinzugefügt mit subscription // Selektion der Geräte ohne ID Laenge // Das Programm dient zur Steuerung von Heizungsthermostaten. (siehe Funktionsliste in der Doku) // Es synchronisiert alle Thermostate eines Raumes - aehnlich zur Gruppenfunktion der Homematic // Direktverknüpfungen bzw Gruppen werden unterstützt. Letztendlich funktionieren die Thermostate aber auch ohne DV und Gruppen, so als wären sie mit DV bzw Gruppen gesteuert // Empfehlung: Modus des thermostates auf MANU setzen. "AUTO" ist zwar auchmoeglich, führt aber zur Erkennung einer manuellen Temperatur // Ein Thermostat/Sensor darf nicht mehreren Raeumen zugeordnet sein // Alle Sensoren und Thermostate muessen je 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 manuell geloescht werden - Restart Adapter REGA 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 und Sensoren muessen dem angegebenen Gewerk zugeordnet sein // 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 unbedingt 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] = ['MeinRaum']; // Liste der Raeume die gesteuert werden soll zum Testen RoomList[1] = ['Raum2']; RoomList[2] = ['Raumx']; RoomList[3] = ['Raum3']; 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 = false; // 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 = false; // 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 - var UseAnwesenheitserkennung = false; // wenn true, dann wird die o.g. Anwesenheitsvariable genutzt - Empfehlung erst im zweiten Schritt aktivieren var StateAnwesenheitFunction = JSPath + "Anwesenheitssteuerung.Userlist.JemandDa"; // Wenn UseAnwesenheitserkennung = true, dann muss der Pfad angepasst werden // Integration zum Feiertagskalender - var UseFeiertagskalender = false; // wenn der Kalender genutzt wird bitte auf true setzen - Empfehlung: Feiertagsadapter installieren und auf true setzen var StateFeiertagHeuteAdapter = "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 //------------------------------------------------------------------------------ // Pfad zum Anwesenheitsflag der Hz-Steuerung - wird parallel zum Adapter gehalten var StateAnwesenheit = JSPath + "Heizung.Heizplan.GlobaleParameter.Anwesenheit"; // Pfad zum Feiertagskennzeichen der Hz-Steuerung - wird parallel zum Adapter gehalten var 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 // Wenn mit Direktverbindungen gearbeitet wird dann MUSS zentrale Steuerung auf true stehen var ThermostatTypeTab = []; // 0.RPC-Pfad 1.GeraeteType 2. Beschreibung, 3. Type 4.DP-SollTemp 5.nicht verwendet ID 6.DP MANU/AUTO Schaltung 7.Steuerung DV 8. IstTemp 9-Check-MANU-Mode 10-Ventilstellung wenn nicht Heizperiode 11. Delay nach Verschluss zu ThermostatTypeTab[0] = ['hm-rpc.0.', 'HM-TC-IT-WM-W-EU', 'Wandthermostat (neu)' ,'WT', '2.SET_TEMPERATURE' , false, '2.MANU_MODE', true, '1.TEMPERATURE', '2.CONTROL_MODE', 12, 0]; ThermostatTypeTab[1] = ['hm-rpc.0.', 'HM-CC-TC' , 'Wandthermostat (alt)' ,'WT', '2.SETPOINT' , false, false, false, '1.TEMPERATURE', false, 12, 2]; ThermostatTypeTab[2] = ['hm-rpc.0.', 'HM-CC-RT-DN' , 'Heizkoerperthermostat(neu)' ,'HT', '4.SET_TEMPERATURE' , false, '4.MANU_MODE', true, '4.ACTUAL_TEMPERATURE', '4.CONTROL_MODE', 12, 0]; ThermostatTypeTab[3] = ['hm-rpc.1.', 'HmIP-eTRV' , 'Heizkoerperthermostat(HMIP)','IPHT', '1.SET_POINT_TEMPERATURE', false, '1.CONTROL_MODE', true, '1.ACTUAL_TEMPERATURE', '1.CONTROL_MODE', 12, 0]; ThermostatTypeTab[4] = ['hm-rpc.1.', 'HmIP-WTH' , 'Wandthermostat(HMIP)' ,'IPWT', '1.SET_POINT_TEMPERATURE', false, '1.CONTROL_MODE', false, '1.ACTUAL_TEMPERATURE', '1.CONTROL_MODE', 12, 0]; // 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', 12]; NoneHMTab[1] = ['initial', 'ZWAVE.0', 'zwa0183xxx', '4.SET_TEMPERATURE', 12]; NoneHMTab[2] = ['initial', 'ZWAVE.0', 'zwa0183xxx', '4.SET_TEMPERATURE', 12]; // Typen-Tabelle der Verschlusssensoren fuer Homematic Geräte // 6 = Verschlussstatus = false ist gechlossen var SensorTypeTab = []; // 0.RPC-Pfad 1.GeraeteType 2. Beschreibung, 3.Type 4.DP Status 5.nicht verwendet 6. Verschlussstatus 7. direktverknuepft SensorTypeTab[0] = ['hm-rpc.0.', 'HM-Sec-SCo' , 'Fenstersensor (neu)' , 'HM', '1.STATE' , false, false, true]; SensorTypeTab[1] = ['hm-rpc.0.', 'HM-Sec-SC' , 'Fenstersensor (alt)' , 'HM', '1.STATE' , false, false, true]; SensorTypeTab[3] = ['hm-rpc.0.', 'HM-Sec-RHS' , 'Fenster-Drehgriffkontakt', 'HM', '1.STATE' , false, false, true]; SensorTypeTab[4] = ['hm-rpc.0.', 'HM-Sec-SC-2', 'Fenstersensor-2 (alt)' , 'HM', '1.STATE' , false, false, true]; SensorTypeTab[5] = ['hm-rpc.1.', 'HMIP-SWDO' , 'Fenstersensor (HMIP )' , 'IPSE', '1.STATE' , false, false, true]; // Tabelle der Verschlusssensoren fuer NichtHomematic Geräte // 5 = wenn script die Absenktemperatur setzen soll, dann false var NoneHMSenorTab = []; // 0= Raum 1 = Datenpunkt vis vor Geraet 0.RPC-Pfad 2. Datenpunkt Geraet 3. Datenpunkt FensterstatusGeraeteType 4.Verschlussstatus bei geschlossen 5. TempAbsenkung automatisch, NoneHMSenorTab[0] = ['initial', 'javascript.0.Heizung', 'zwave1' , '1.State' , 0, false]; NoneHMSenorTab[1] = ['initial', 'javascript.0.Heizung', 'zwave2' , '1.STATE' , false, true]; NoneHMSenorTab[2] = ['initial', 'javascript.0.Heizung', 'zwav31' , '1.STATE' , 0, false]; // 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"; // UserExit Einstellungen // UserExits koennen genutzt werden, um die manuelle Temperatur von selbstdefinierten Abhängigkeiten zu steuern // Beipiel Steuerung von ElektroKonvektoren abhängig vom Energieertrag einer PV // Es koennen beliebig viele Eintragungen gemacht werden // // Die Datenpunkte werden nicht angelegt sondern muessen separat angelegt wreden // UserEexitTab Tabellendefinition: // 0 = Datenpunkt = Pfad Datenpunkt aufgrund dessen eine Reaktion erfolgen soll und Definition bei welchem Ereignis eine Reaktion erfolgen soll // 1 = Name der Routine - Routine muss im Userexit definiert sein // 2 = Operand - zulaessige Operanden sind // groesser = "valGt" // groesser gleich = "valGe" // kleiner = "valLt" // kleiner gleich = "valLe" // gleich = "val" // ungleich = "valNe" // beliebiege Aenderung = "Any" // 3 = Wert - Vergleichswert der die Routine auslöst (im Zusammenhang mit dem Operanden // Sobald eine Bedingung zutrifft wird der UserExit aufgerufen. Die zugehoerige Routine wird zu anfang des UserExits ermittelt und kann dann weiterverarbeitet werden // Rueckgabe des UserExits ist ein Raumname sowie eine manuelle Temperatur und Gueltigkeit in Minuten. Die Temperatur wird dann entsprechend mit der Gueltigkeit gesetzt // ist die manuelle Temperatur = 0 wird eine evt. vorher eingestellte manuelle Temperatur gelöscht und die neue SollTemperatur wird anhand des schedules ermittelt var UserExitTab = []; // 0 = Datenpunkt 1= Routine 2=Operand 3= Vergleichswert UserExitTab[0] = ['initial', 'TriggerHeatingOn', 'valGt', 100 ]; UserExitTab[1] = ['initial', 'TriggerHeatingOff', 'valLt', 0 ]; // es sind 5 globale Tabellen vordefiniert. Werden diese im UserExit befuellt bleiben die Werte erhalten für den nächsten Aufruf var UserExitValueTab1 = []; var UserExitValueTab2 = []; var UserExitValueTab3 = []; var UserExitValueTab4 = []; var UserExitValueTab5 = []; //------------------------------------------------------------------------------ // Ende Experteneinstellungen //------------------------------------------------------------------------------ // Variablendefinition var ControlTab = []; // Zentrale Tabelle der Thermostate var SensorList = []; // Liste der Verschlusssensoren var DelayAfterClose = []; // Liste fuer Thermostate, die einen Delay nachdem die Verschluesse geschlossen werden, benötigen (z.B. alte HM Thermostate) 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 // LoopRooms(); // nur zum testen fuer alle Raeume //----------------------------------------------------------------------------------------------------- // Job zur Ausfuehrung der Kernfunktion (Temperatur Setting) //----------------------------------------------------------------------------------------------------- schedule(cronjob, function() { LoopRooms(); // Ablauflogik entlang der gefundenen Thermostate fuer alle Raeume log("Heizungsscript verarbeitung durchgelaufen" ,"info"); }); // Ende Job //----------------------------------------------------------------------------------------------------- // Subscriptions zum UserExit // Alle Datenpunkte werden mit einer Subscription versehen. //----------------------------------------------------------------------------------------------------- for(var x in UserExitTab ) { if(UserExitTab[x][0] === "initial" ) { continue; } if(UserExitTab[x][2] === "valNe" ) { on({id: UserExitTab[x][0], valNe : UserExitTab[x][3] }, function(obj) { UserExitPrep(obj.id, obj.state.val); }); // ende on id } if(UserExitTab[x][2] === "valGt" ) { on({id: UserExitTab[x][0], valGt : UserExitTab[x][3] }, function(obj) { UserExitPrep(obj.id, obj.state.val); }); // ende on id } if(UserExitTab[x][2] === "valGe" ) { on({id: UserExitTab[x][0], valGe : UserExitTab[x][3] }, function(obj) { UserExitPrep(obj.id, obj.state.val); }); // ende on id } if(UserExitTab[x][2] === "valLt" ) { on({id: UserExitTab[x][0], valLt : UserExitTab[x][3] }, function(obj) { UserExitPrep(obj.id, obj.state.val); }); // ende on id } if(UserExitTab[x][2] === "valLe" ) { on({id: UserExitTab[x][0], valLe : UserExitTab[x][3] }, function(obj) { UserExitPrep(obj.id, obj.state.val); }); // ende on id } if(UserExitTab[x][2] === "val" ) { on({id: UserExitTab[x][0], val : UserExitTab[x][3] }, function(obj) { UserExitPrep(obj.id, obj.state.val); }); // ende on id } if(UserExitTab[x][2] === "any" ) { on({id: UserExitTab[x][0], any }, function(obj) { UserExitPrep(obj.id, obj.state.val); }); // ende on id } } // Endfor //----------------------------------------------------------------------------------------------------- // Funktion UserExit- // Es stehen 5 globale Tabellen zur Verfügung Die Werte dieser Tabellen gehen nicht verloren für den nächsten aufruf // UserExitValueTab1 // UserExitValueTab2 // UserExitValueTab3 // UserExitValueTab4 // UserExitValueTab5 // Rückgabe: // USerExitCallBack(Raum,Solltemperatur,Gueltigkeit) //----------------------------------------------------------------------------------------------------- function UserExit (id,value,routine) { if(routine === "TriggerHeatingOn") { log("Routine UserExit UserExit aufgerufen " + id + " " + value + " " + routine); } } // endfunction //----------------------------------------------------------------------------------------------------- //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 roomNoSpace; var idExtract; var fullname; var devtype; var FinishRoom = false; var y = 0; var SelectorVerschluss; var SelectorThermostat; var hmprc; var devTypeThermTab var sensortype; var StateDP // jetzt Thermostate einlesen // Lade alle Raeume for (var i in rooms){ // loop ueber alle Raeume roomName = rooms[i].name; if (debug) { log("Gibt es ein zugeordnetes Gerät für den Raum " + roomName + " wird jetzt ueberprueft","info"); } for (var x in ThermostatTypeTab){ // loop ueber die moeglichen Thermostattypen hmrpc = ThermostatTypeTab[x][0]; devTypeThermTab = ThermostatTypeTab[x][1].toUpperCase(); StateDP = ThermostatTypeTab[x][4];; $('channel[state.id=*.'+ThermostatTypeTab[x][4]+'] (rooms='+roomName+') (functions='+HeizungGewerk+') ').each(function (id, i) { idExtract = id.substr(0,id.length-StateDP.length-1); fullname = getObject(id).common.name; devtype = getObject(idExtract).native.TYPE.toUpperCase(); if(devtype.includes( devTypeThermTab) && RoomListUsage(roomName)) { // wenn die Raumliste genutzt wird ist und der Raum in der Liste enthalten ist SelectorThermostat = $('channel[state.id='+id+'] '); SelectorThermostat.on(function(obj) { // erstelle subscription if (obj.state.ack) { ThermostatChange(id); } }); // endon roomNoSpace = roomName.replace(/\s/g, "_"); ControlTab[y] = [roomNoSpace,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],ThermostatTypeTab[x][11]]; // 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 12= Delay nach Verschluss zu y = y +1; if(debug ) {log("Routine getdevice fuer " + roomNoSpace,"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 } log("Routine GetDevices fuer HM Thermostate " + ThermostatTypeTab[x],"info"); } }); // 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]; roomName.replace(/\s/g, "_"); if(roomName !== "initial" && RoomListUsage(roomName)) { id = NoneHMTab[b][1] + '.' + NoneHMTab[b][2] + '.' + NoneHMTab[b][3]; FullName = getObject(id).common.name; devtype = "NoneHM"; if(debug ) {log("Routine 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], NoneHMTab[b][6] ]; // 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 12= Delay nach Verschluss zu 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 //SensorTypeTab[5] = ['hm-rpc.1.', 'HMIP-SWDO' , 'Fenstersensor (HMIP )' , 'IPSE', '1.STATE' , 14, false, true]; // right string id.substr(-SensorTypeTab[x][5].length); y=0; for (var i in rooms){ roomName = rooms[i].name; for (var x in SensorTypeTab){ hmrpc = SensorTypeTab[x][0]; sensortype = SensorTypeTab[x][1]; StateDP = SensorTypeTab[x][4]; $('channel[state.id=*.'+SensorTypeTab[x][4]+'] (rooms='+roomName+') (functions='+SensorGewerk+') ').each(function (id, i) { idExtract = id.substr(0,id.length-StateDP.length-1); fullname = getObject(id).common.name; devtype = getObject(idExtract).native.TYPE; if(devtype === sensortype && RoomListUsage(roomName) ) { // wenn die Raumliste genutzt wird ist und der Raum in der Liste enthalten ist roomNoSpace = roomName.replace(/\s/g, "_"); SensorList[y] = [roomNoSpace,id,devtype,fullname,idExtract,SensorTypeTab[x][3],SensorTypeTab[x][4],SensorTypeTab[x][5],SensorTypeTab[x][6],SensorTypeTab[x][7] ]; SensorList[y][7] = getState( SensorList[y][1]).val; // Status des Sensors log("Routine GetDevices fuer HM Sensoren " + SensorList[y],"info"); 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 // Fuellen der Nicht-Homematic Sensoren in die SensorTab // Map-Dokumentation: // Sensortypetab = 0.RPC-Pfad 1.GeraeteType 2. Beschreibung, 3.Type 4.DP Status 5.Laenge ID 6. Verschlussstatus 7. direktverknuepft // NonHM-SensorTab 0= Raum 1 = Datenpunkt vis vor Geraet 0.RPC-Pfad 2. Datenpunkt Geraet 3. Datenpunkt FensterstatusGeraeteType 4.Verschlussstatus bei geschlossen 5. TempAbsenkung automatisch, // // Sensorlist SensorList[y] = [roomNoSpace, id, devtype, fullname, idExtract, SensorTypeTab[x][3],SensorTypeTab[x][4],SensorTypeTab[x][5],SensorTypeTab[x][6],SensorTypeTab[x][7] ]; // Füllen der sensorlist raum=0 komplette id=1 NoneHM=2 Name aus getobject(id)=3 NoneHMSenorTab(1)=4 "NoneHM"=5 NoneHMSenorTab(2)=6 laenge ID=7 verschlussstatus=8 direktverknüpft=9 , y = SensorList.length; // letzter Eintrag der Sensorlist for (var x in NoneHMSenorTab) { roomName = NoneHMSenorTab[x][0]; roomName.replace(/\s/g, "_"); if(roomName !== "initial" && RoomListUsage(roomName)) { // wenn die Raumliste genutzt wird ist und der Raum in der Liste enthalten ist. y = y +1; roomNoSpace = roomName.replace(/\s/g, "_"); id = NoneHMSenorTab[x][1] + '.' + NoneHMSenorTab[x][2] + '.' + NoneHMSenorTab[x][3]; FullName = getObject(id).common.name; devtype = "NoneHM"; if(debug ) {log("Routine getdevice fuer NoneHMSenorTab " + roomName,"info");} SensorList[y] = [roomNoSpace, id, devtype, FullName, NoneHMSenorTab[x][1], NoneHMSenorTab[x][3], FullName, false, getState(id).val, NoneHMSenorTab[x][5] ]; //Füllen der sensorlist raum=0 komplette id=1 NoneHM=2 Name aus getobject(id)=3 Datenpunkt bis vor Geraet=4 "NoneHM"=5 Beschreibung=6 frei=7 verschlussstatuss, direktverknuepft=9 log("Routine GetDevices NoneHM Sensoren: " + SensorList[y],"info"); on({id: SensorList[y][1], change: 'ne'}, function(obj) { //if (obj.state.val !== obj.oldState.val) { // nur bei Aenderungen SensorChange(obj.id); //} // End - react on change }); // ende on id } // endif roomName war nicht initial } // endfor Nicht Homematic Geraete // Ausgabe der Devices - Thermostate und Sensoren if (debug) { for (var d in rooms){ log ("Liste der gefundenen Räume " +rooms[d].name,"info"); } } // ende debug log("Routine GetDevices Devices initialisiert","info"); } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion LoopRooms - Abarbeiten der Raeume //----------------------------------------------------------------------------------------------------- function LoopRooms () { var roomName; var RoomRelevant = true; Source_last_Program_Run = formatDate(new Date(),"DD/MM/JJJJ SS:mm:ss"); setState(Gparameterpath + ".Source_last_Program_Run",Source_last_Program_Run); // Feiertagsflag synchronisieren if(UseFeiertagskalender) { // Feiertagskalender Adapter aktiv ? if(getState(StateFeiertagHeuteAdapter).val && StateFeiertagHeute !== true ) { // Feiertagsflag setzen setState(StateFeiertagHeute,true) } if(getState(StateFeiertagHeuteAdapter).val === false && StateFeiertagHeute !== false ) { // Feiertagsflag ruecksetzen setState(StateFeiertagHeute,false) } } // Anwesenheitsflag synchronisieren if(UseAnwesenheitserkennung) { if(getState(StateAnwesenheitFunction).val && StateAnwesenheit !== true ) { // Feiertagsflag setzen setState(StateAnwesenheit,true) } if(getState(StateAnwesenheitFunction).val === false && StateAnwesenheit !== false ) { // Feiertagsflag ruecksetzen setState(StateAnwesenheit,false) } } 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("Routine LoopRooms Starte Abarbeitung fuer Raum " + roomName,"info"); } ClearSources(); SetEventGlobalParameter(); // checken of ICAL events als global parameter vorliegen LoopDevices(roomName) if(debug) { log("Routine LoopRooms Ende Abarbeitung fuer Raum " + roomName,"info"); } if(debug) { log("","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; var ThermoType; // zum checken um welchen Thermostatypen es hier handelt aus der ControlTab(5) 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; ThermoType = ControlTab[x][5]; // log("Raum " + ControlTab[x][0] + " Geraet " + idExtract + " in Controltab next ist check on Modus") // 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; // Feststellen ob das Thermostat auf Auto oder MANU steht // Check CC und DN Thermostate (nicht IP) if( (ThermoType === "WT" || ThermoType === "HT") && (ThermMode === 0 || ThermMode === 2) ) { // Pruefen ob der manuelle Modus oder Party Mode eingeschaltet ist fuer CC and DN Thermostate log("Routine LoopDevices: 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 // check IP Thermostate if( (ThermoType === "IPHT" || ThermoType === "IPWT") && (ThermMode === 0 || ThermMode === 2) ) { // Pruefen ob der manuelle Modus oder Party Mode eingeschaltet ist fuer CC and DN Thermostate log("Routine LoopDevices: Geraet " + idExtract +" Raum: " + roomName + " in den Manuellen Modus gesetzt ","info"); log("Thermotype ist " + ThermoType + " ThermMode ist "+ ThermMode,"info"); setState(idExtract + "." + ControlTab[x][7], 1); // 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[x][11]; Source_GlobalParameter = "Heizperiode" + "_" + false; SetTemp (roomName,ScheduledSollTemp,id,false); writelog(roomName,id,"keine Heizperiode") continue; } Sensor = VerschlussRaumStatus (roomName); if(debug) {log("Routine LoopDevices: Sensorstatus fuer raum " + roomName + " ist " + Sensor,"info"); } // 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 ? // SetRoomOpen( roomName ); // in der delay tab werden evt Zeitstempel geloescht Source_GlobalParameter = "Verschluss offen TemperaturAbsenkung gesetzt"; if(debug) { log("Routine LoopDevices:" + Source_GlobalParameter,"info") } if(Check_SensorDV(roomName) === false) { // ist der Sensor direktverknuepft ? SetTemp (roomName,VerschlussAbsenkungsGrenze,id,false); } writelog(roomName,id,"") continue; } else { SetRoomClosed( roomName,ControlTab[x][12] ); // zeitstempel setzen fuer delay wenn erforderlich Source_GlobalParameter = "Raum " + roomName + " jetzt geschlossen "; if(getState(path + "." + roomName +".Source_TimeStamp").val === "init" && getState(id).val !== VerschlussAbsenkungsGrenze ) { // Wenn keine manuelle Temp gesetzt war Source_GlobalParameter = "Verschluss geschlossen TemperaturAbsenkung zurueck gesetzt"; if(debug) { log("Routine LoopDevices:" + Source_GlobalParameter,"info") } ExecuteTempDetermination (roomName,id); writelog(roomName,id,"") continue; } // kein TimeStamp gesetzt }// endif sensor status true } // endif Sensor ausgeloest if (Sensor) { // Wenn ein Sensor offen ist, dann mache nix 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(Source_ManTempSet === null) { return; // es gibt keine manuelle Temperatur } if(Check_ThermDV(roomName) ) { // sind die Thermostate direktverknuepft ? true heisst nein if(debug) {log("Routine LoopDevices: Starte Sync fuer Manuelle Temperatur fuer " + id,"info")} 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 for (x in ControlTab ) { if (ControlTab[x][1] === id ) { room = ControlTab[x][0]; if(debug) {log("Routine ThermostatChange: Thermostat " + id + " Raum " + room + " Thermostat Solltemperatur-Aenderung erkannt","info") } source_ManTempSet = getState(id).val; if(source_ManTempSet !== VerschlussAbsenkungsGrenze ) { ManAdj = ManAdjustments(room,id); } writelog(room,id,"") ; if(Source_ManTempSet === null) { // log("Routine ThermostatChange: ACHTUNG Fall 1 ThermostatChange in Temperatur Source_ManTempSet hat keinen Wert - kann nicht synchen") return; } if(debug) {log("Routine ThermostatChange: Starte Sync fuer Manuelle Temperatur fuer " + id + " Temperatur = " + Source_ManTempSet,"info")} 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("Routine SensorChange: Sensor " + id + " nicht in Sensorliste gefunden","info") return; // Sensor nicht in Sensorlist gefunden } SensorList[tabNo][7] = SensorStatCalc(id,SensorList[tabNo][2]); // id des Sensors und device type - Der Status des Sensors wird ermittelt und in die sensorliste eingetragen // Status des Verschlusses in Tabelle updaten 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("Routine SensorChange: Fenster "+ id + " status geaendert fuer "+ SensorList[tabNo][1] + " " + SensorList[tabNo][0] + " " +SensorList[tabNo][7],"info" ); log("Routine SensorChange: Raum " + SensorList[tabNo][1],"info") log("Routine SensorChange: Sensor ist dv ? " + SensorList[tabNo][9] ) log("Routine SensorChange: Sensor status ist ? "+ SensorList[tabNo][7] ) } if(SensorList[tabNo][9] && SensorList[tabNo][7]) { // Sensor ist direktverknuepft und wurde geoeffnet return; // nichts machen, da die Absenkung automatisch passiert } sensorausgeloest = true; LoopDevices(room); sensorausgeloest = false; } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion SensorStatCalc Setzt den Sensorsatus um in true oder false fuer Geraete die mehr Status zur Verfuegung stellen //----------------------------------------------------------------------------------------------------- function SensorStatCalc (id,devtype) { var SensorStatus = getState(id).val; if(SensorStatus === true || SensorStatus === false ) { return SensorStatus; } // Sensor HM-Sec-RHS ist ein Fenster Kipp Sensor mit Status 0 = geschlossen 1 = gekippt 2 = geoeffnet if(devtype === "HM-Sec-RHS" ) { if(SensorStatus > 0 ) { return true; // Sensor geoeffnet } else { return false; // Sensor geschlossen } // endif es ist ein HM-Sec-RHS } // jetzt checken ob der NoneHM Sensor geschlossen oder geöffnet ist if(devtype === "NoneHM") { for (var x in NoneHMSenorTab ) { if (id === NoneHMSenorTab[x][1]+"."+NoneHMSenorTab[x][2]+"."+NoneHMSenorTab[x][3]) { if(SensorStatus == NoneHMSenorTab[x][4] ) { return false; } else { return true; } } } } // Ende NoneHM check log("Routine SensorStatCalc: Sensorstatus fuer Sensor " + id + " nicht ermittelbar - Logik nicht implementiert","info"); return false; // fall back wenn keine Bedingung zutrifft = nicht implementierte Logik } // endfunction //----------------------------------------------------------------------------------------------------- //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(),"YYYY/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) { // return false; 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("Routine ManAdjustments: " + 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; } // 0.Fall Ein Delay wurde erkannt. Warten auf Ablauf Delay // Delay laut ThermostagTab Tabelle var DelayTime = CheckDelay(room); // gibt es einen delay ? 0 = kein Delay if(debug) { log("Routine ManAdjustments: DelayTime fuer Raum " + room + " ist " + DelayTime) log("aktuelle Millisekunden " +ActTimeMilliSek,"info") ; } if (DelayTime > ActTimeMilliSek ) { Source_ManualAdjustment = "Zeit noch nicht abgelaufen fuer Delay der Rueckstellung - noch warten"; return true; } if (DelayTime > 0 && DelayTime < ActTimeMilliSek && ChckAbsenkung !== true) { // delay time abgelaufen ? if(ManAdjTimeStamp !== "init" ) { SetRoomOpen(room); // Reset delay time Source_ManualAdjustment = "Manuelle Temperatur wird zurückgestellt nachdem der Raum jetzt geschlossen ist auf " + SourceManValue + " " + "erkannt"; if(debug) { log(Source_ManualAdjustment); } SetTemp (room,SourceManValue,id,false); Source_ManTempSet = SourceManValue; if(debug) { log("0.Fall " + Source_ManualAdjustment,"info"); } return true; } else { return false; } // endif es wurde eine manuelle Temp gesetzt } // endif delay time abgelaufen if (DelayTime > 0) { // Delay noch nicht abgelaufen return true; // mache nix } // 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,"YYYY/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,"YYYY/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("Routine ExecuteTempDetermination: 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("Routine ExecuteTempDetermination: 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("Routine ExecuteTempDetermination: Source_ManualAdjustment " + 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("Routine SelectSwichTime: 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 //----------------------------------------------------------------------------------------------------- // 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(getState(StateFeiertagHeute).val ) { // Heute ist Feiertag 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("Routine DetermineSchedule: 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("Routine DetermineSchedule: 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("Routine DetermineSchedule: Heute ist = " + Wochentag(currentday) + " Tag fuer den Schedule ist = " + Wochentag(i),"info"); } return(i); // Sonntagschedule ist richtig } } } // 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) { SetDetData(room); // Speichere Findungsdaten if (getState(id).val !== SollTemp) { // ist die SET-Temperature unterschiedlich zur errechneten Solltemperatur ? setState(id,SollTemp); if(debug) { log ("Routine SetTemp: ID updated " + id+" Raum " + room + " SollTemp = " + SollTemp,"info"); } Source_CurrentSollTemp = SollTemp; } if(AdjustLastTemp ) { // LastSollTemp synhronisieren setState(path + "." + room +".Source_Last_Temp",SollTemp); } // endif } // 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("Routine SyncThermostat: 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("Routine SyncThermostat: 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: 'number', name: 'Minimale Temperatur fuer Absenkung' , desc: 'Minimale Temperatur fuer Absenkung'}); } // endfor y // Daten je Profil // RaumParameter State = RoomPath + "AktivesRaumProfil"; createState(State, 1, {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, 0, {read: true, write: true, type: 'number', name: 'Im View manuell eingestellte Temperatur - 0=reset' , desc: 'Im View manuell eingestellte Temperatur - 0=reset'}); 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 SetRoomOpen loescht evt Zeitstempel //----------------------------------------------------------------------------------------------------- function SetRoomOpen ( room ) { for (x in DelayAfterClose ) { if ( DelayAfterClose[x][0] === room) { DelayAfterClose[x][1] =0; // Zeitstempel setzen if(debug) { log("Routine SetRoomOpen: Zeitstempel geloescht offenen Raum " + room,"info"); } return; } // endif room gefunden } // endfor // Eintrag gibt es noch nicht also hinzufügen DelayAfterClose.push( [room, 0 ] ); for (x in DelayAfterClose ) { if( debug) { log("Routine SetRoomOpen: Liste der Zeitstempel Raum " + room); } } } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion SetRoomClosed setzt einen Zeitstempel, wenn der letzte Sensor geschlossen meldet //----------------------------------------------------------------------------------------------------- function SetRoomClosed (room, delay) { if(delay === 0 ) { // delay in Minuten aus ThermTabType Tabelle return; } for (x in DelayAfterClose ) { if ( DelayAfterClose[x][0] === room) { DelayAfterClose[x][1] = new Date().getTime()+ delay*60000 ; // Zeitstempel setzen und die gewünschte anzahl Minuten hinzurechnen aus ThermTabType Tabelle if(debug) { log("Routine SetRoomClosed: Zeitstempel gesetzt für geschlossenen Raum " + room,"info"); } return; } // endif room gefunden } // endfor // Eintrag gibt es noch nicht also hinzufügen DelayAfterClose.push( [room, new Date().getTime()] ); for (x in DelayAfterClose ) { if(debug) { log("Routine SetRoomClosed: room " + DelayAfterClose[x][0] + " zeitstempel " + DelayAfterClose[x][1],"info" ); } } } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion CheckDelay checked ob ein Delay erforderlich ist für eine evt Anpassung der SollTemp //----------------------------------------------------------------------------------------------------- function CheckDelay (room) { for (x in DelayAfterClose ) { if ( DelayAfterClose[x][0] === room) { if(debug) { log("Routine CheckDelay: delay für Raum " + room +" ist vorhanden bis " +DelayAfterClose[x][1] + " millisekunden ","info" ); } return DelayAfterClose[x][1] ; // melde die Ablaufzeit } // endif room gefunden } // endfor return 0; // kein Delay } // ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion Check_SensorDV checkt ob eine Direktvernuepfung von Sensor zu Thermostat vorliegt im Raum //----------------------------------------------------------------------------------------------------- function Check_SensorDV (room) { for (var i in SensorList ) { if ( SensorList[i][0] === room && SensorList[i][0] === true ) { // Sensor ist direktverknuepft return true; } } return false; } //ende Funktion //----------------------------------------------------------------------------------------------------- // Funktion Check_ThermDV checkt ob eine Direktvernuepfung von Thermostat zu Thermostat (Gruppen) vorliegt im Raum //----------------------------------------------------------------------------------------------------- function Check_ThermDV(room) { for (var i in ControlTab ) { if (ControlTab[i][0] === room && ControlTab[i][7] === true) { // Thermostat ist direktverknuepft return true; } } return false; } //ende Funktion //----------------------------------------------------------------------------------------------------- // 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 ) { if(debug) {log("Routine ChckRoom - Dem Raum " + room + " ist ein Gerät zugeordnet ","info"); } return true; } } for (var z in NoneHMTab) { // auch nicht HM checken if ( NoneHMTab[z][0] === room ) { if(debug) {log("Routine ChckRoom - Dem Raum " + room + " ist ein Gerät zugeordnet ","info"); } return true; } } for (var z in NoneHMSenorTab) { // auch nicht HM checken if ( NoneHMSenorTab[z][0] === room ) { if(debug) {log("Routine ChckRoom - Dem Raum " + room + " ist ein Gerät zugeordnet ","info"); } return true; } } return false; } // ende funktion //----------------------------------------------------------------------------------------------------- // Funktion SensorFind Sucht den Sensor aus der SensorTabelle //----------------------------------------------------------------------------------------------------- function SensorFind (id) { for (var i in SensorList ) { if(debug) { log("Routine SensorFind ID = " + SensorList[i][1] + " Raum = " + SensorList[i][0],"info"); } if ( SensorList[i][1] === id) { return i; } } log("Routine SensorFind: sensor nicht gefunden " + id) 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(typeof(Source_ICALEvent) === "undefined" ) { Source_ICALEvent = ""; } if(typeof(Source_Profil) === "undefined" ) { Source_Profil = 99; } if(typeof(Source_GlobalParameter) === "undefined" ) { Source_GlobalParameter = ""; } if(typeof(Source_SchedulePoint) === "undefined" ) { Source_SchedulePoint = ""; } 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 //----------------------------------------------------------------------------------------------------- // Function UserExitPrep - hat nur die Aufgabe die Routine fuer den Userexit zu ermitteln. //----------------------------------------------------------------------------------------------------- function UserExitPrep (id,value) { if(debug) {log("Routine UserExitPrep aufgerufen " + id + " " + value,"info"); } for(var x in UserExitTab ) { if(UserExitTab[x][0] === id ) { UserExit(id,value,UserExitTab[x][1]) ; // uebergabe id, wert und Routine zum eigentlichen UserExit return; // eine ID darf nur einmal aufgerufen werden } // endif } // endfor } // Endfunction //----------------------------------------------------------------------------------------------------- // 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(typeof(Source_CurrentSollTemp) === "undefined" ) { Source_CurrentSollTemp = 0; } if(typeof(Source_ManualAdjustment) === "undefined" ) { Source_ManualAdjustment = 0; } 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("Routine writelog: 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