├── unused ├── README.md ├── CreateVariable.hms ├── GuestsThermostat.hms ├── parsingspeediterate.hms ├── parsingspeedsplit.hms └── TemperatureTableParsing.hms ├── LICENSE ├── TurnBoilerOnAfterVacation.hms ├── WaterSensorProwl.hms ├── README.md ├── Inventory.hms ├── TurnHeatingOn.hms ├── presenceVariableAggregation.hms ├── InformationDump.hms ├── presencedetection.sh ├── MacUserPresence.perl ├── ThermostatModeSwitch.hms ├── README.de.md └── PresenceTriggersTemperature.hms /unused/README.md: -------------------------------------------------------------------------------- 1 | Here are scripts that are no longer in use. 2 | -------------------------------------------------------------------------------- /unused/CreateVariable.hms: -------------------------------------------------------------------------------- 1 | string systemvariablename = "testvariable"; 2 | boolean debug = false; ! if set, output what is done 3 | 4 | 5 | object systemvariable = dom.GetObject(systemvariablename); 6 | if( !systemvariable ) 7 | { if(debug){WriteLine("Variable:"#systemvariablename#" does not exist - creating");} 8 | object systemVariables =dom.GetObject(ID_SYSTEM_VARIABLES); 9 | systemvariable=dom.CreateObject(OT_VARDP); 10 | systemvariable.Name(systemvariablename); 11 | systemVariables.Add(systemvariable.ID()); 12 | systemvariable.ValueType(ivtString); !. dokumentation says: boolean = 1; integer 2; real 3 ;time 5; 4 string; 13 | systemvariable.ValueSubType(istChar8859); 14 | systemvariable.DPInfo("stores thermostat modeswitches"); 15 | systemvariable.State("testvalue"); 16 | dom.RTUpdate(0); 17 | } 18 | 19 | string value = systemvariable.Value(); if(debug){WriteLine("value:"#value);} 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jolly aka Patrick Stein 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /unused/GuestsThermostat.hms: -------------------------------------------------------------------------------- 1 | !https://github.com/jollyjinx/homematic/blob/master/GuestsThermostat.hms 2 | ! 3 | ! This script turns my guests thermostat to auto or off depending on guests presence 4 | 5 | string thermostatname = "BidCos-RF.KEQ1039045:4"; ! set this to the guests room thermostat 6 | string presencevariablename = "presence.guests"; ! set this to the variable name you use for detecting guests at home 7 | boolean debug = false; ! if set, only output what is done, don't do it 8 | 9 | !------ Execution 10 | 11 | boolean guestsarepresent = dom.GetObject(presencevariablename).Value(); if(debug){WriteLine("presence.guests:"#guestsarepresent);} 12 | real settemperature = dom.GetObject(thermostatname#".SET_TEMPERATURE").Value(); if(debug){WriteLine("settemperature:"#settemperature);} 13 | 14 | ! modes 15 | ! 0 = auto 16 | ! 1 = manu 17 | ! 2 = party 18 | ! 3 = boost 19 | 20 | integer modetoset = 0; 21 | 22 | if( !guestsarepresent ) 23 | { 24 | modetoset = 1; 25 | } 26 | 27 | if(debug){WriteLine("Mode to set : "#modetoset);} 28 | integer currentmode = dom.GetObject(thermostatname#".CONTROL_MODE").Value(); if(debug){WriteLine("Current mode: "#currentmode);} 29 | 30 | if( modetoset != currentmode ) 31 | { 32 | if( 0 == modetoset ) 33 | { 34 | dom.GetObject(thermostatname#".AUTO_MODE").State(1); if(debug){WriteLine("Setting thermostat to auto-mode");} 35 | } 36 | else 37 | { 38 | dom.GetObject(thermostatname#".MANU_MODE").State(0.0); if(debug){WriteLine("Setting thermostat to manual mode");} 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /TurnBoilerOnAfterVacation.hms: -------------------------------------------------------------------------------- 1 | !https://github.com/jollyjinx/homematic/blob/master/TurnBoilerOnAfterVacation.hms 2 | ! 3 | ! This script turns my boiler when someone arrives at home and the boiler has not 4 | ! been turned on for 24 hours. 5 | ! Usually that is the case after a vacation, then I want to make sure I can take a 6 | ! shower instantly. 7 | 8 | string boilerswitchname = "BidCos-RF.KEQ0768205:1"; ! set this to the switch your boiler uses 9 | string presencevariablename = "presence.any"; ! set this to the variable name you use for detecting someone at home 10 | integer timebetweenchanges = 24; ! hours someone has not been home 11 | boolean debug = false; ! if set, only output what is done, don't do it 12 | 13 | !------ Execution 14 | 15 | boolean someoneisathome = dom.GetObject(presencevariablename).Value(); 16 | 17 | if( !someoneisathome ) 18 | { 19 | if(debug){WriteLine("Nobody home. Nothing to do.");} 20 | quit; 21 | } 22 | 23 | 24 | ! check time the switch was last modified 25 | 26 | var boilerswitch = dom.GetObject(boilerswitchname#".STATE"); 27 | integer lasttimechanged = boilerswitch.Timestamp().ToInteger(); 28 | integer timenow = system.Date("%Y-%m-%d %H:%M:%S").ToTime().ToInteger(); 29 | 30 | integer lastchange = (timenow-lasttimechanged); if(debug){WriteLine("Seconds since last changing:"#lastchange);} 31 | 32 | if( lastchange < (timebetweenchanges*3600) ) 33 | { 34 | if(debug){WriteLine("Last change not long enough ago");} 35 | quit; 36 | } 37 | 38 | boolean turnonboiler = true; 39 | boolean currentboilerstate = boilerswitch.Value(); if(debug){WriteLine("currentstate:"#currentboilerstate#"\nturnonboiler:"#turnonboiler);} 40 | 41 | if( currentboilerstate != turnonboiler ) 42 | { if(debug){WriteLine("Would change boiler:"#turnonboiler);} 43 | if(!debug){boilerswitch.State(turnonboiler);} 44 | } 45 | -------------------------------------------------------------------------------- /WaterSensorProwl.hms: -------------------------------------------------------------------------------- 1 | !! https://github.com/jollyjinx/homematic/blob/master/WaterSensorProwl.hms 2 | !! 3 | !! This scrips creates a prowl message when watersensors detect water or humitidy 4 | !! 5 | !! The script uses the 'prowlapikey' system variable to read out the prowl api key 6 | !! the variable will be created if it does not exist when you start the script the 7 | !! first time and the default value will be stored in there. 8 | !! 9 | !! Change the defaultprowlapikey before you start the script the first time in 10 | !! case you don't have the prowlapikey variable yet. 11 | 12 | 13 | boolean debug = true; 14 | string systemvariablename = "prowlapikey"; 15 | string defaultprowlapikey = "01234567890abcdef01234567890abcdef012345"; 16 | 17 | 18 | 19 | object systemvariable = dom.GetObject(systemvariablename); 20 | 21 | if( (systemvariablename.Length()>0) && (!systemvariable) ) 22 | { if(debug){WriteLine("Variable:"#systemvariablename#" does not exist - creating");} 23 | object systemVariables =dom.GetObject(ID_SYSTEM_VARIABLES); 24 | systemvariable=dom.CreateObject(OT_VARDP); 25 | systemvariable.Name(systemvariablename); 26 | systemVariables.Add(systemvariable.ID()); 27 | systemvariable.ValueType(ivtString); !. dokumentation says: boolean = 1; integer 2; real 3 ;time 5; 4 string; 28 | systemvariable.ValueSubType(istChar8859); 29 | systemvariable.DPInfo("Prowl API key"); 30 | systemvariable.State(defaultprowlapikey); 31 | dom.RTUpdate(0); 32 | } 33 | 34 | string prowlapikey = systemvariable.Variable().ToString(); 35 | 36 | 37 | string deviceid; 38 | foreach(deviceid, dom.GetObject(ID_DEVICES).EnumUsedIDs()) 39 | { 40 | var device = dom.GetObject(deviceid); if(debug){WriteLine("Device:"#device#" (id:"#deviceid#")");} 41 | 42 | if( "HM-Sec-WDS-2" == device.HSSID() ) 43 | { 44 | string channelid; 45 | foreach(channelid,device.Channels().EnumUsedIDs()) 46 | { 47 | var channel = dom.GetObject(channelid); if(debug){WriteLine("\t Channel:"#channel#" (id:"#channelid#")");} 48 | 49 | if( "WATERDETECTIONSENSOR" == channel.HSSID() ) 50 | { 51 | var interface = dom.GetObject(channel.Interface()); 52 | var datapoint = interface#"."#channel.Address(); if(debug){WriteLine("\t Datapoint:"#datapoint);} 53 | integer currentstate= dom.GetObject(datapoint#".STATE").Value(); if(debug){WriteLine("\t State:"#currentstate);} 54 | 55 | if( 0 != currentstate ) 56 | { 57 | !! water deteced, send mail 58 | 59 | system.Exec("wget -q -O /dev/null --no-check-certificate 'https://prowlapp.com/publicapi/add?apikey="#prowlapikey#"&application=HomeMatic&description=WASSERALARM:%20"#channel#"' &"); 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | 67 | -------------------------------------------------------------------------------- /unused/parsingspeediterate.hms: -------------------------------------------------------------------------------- 1 | 2 | 3 | integer loops = 20; 4 | integer loopcounter = loops; 5 | 6 | 7 | string presencetable = " 8 | presence.test: hall 6:00,18.5C 7:30,19.5C 19:30,20C 22:30,17C 9 | 10 | presence.guests: hall 6:00,18.5C 7:30,19.5C 19:30,20C 22:30,17C 11 | living 7:30,19C 19:30,20C 22:30,17C 12 | kitchen 6:00,18.5C 7:30,20C 20:30,17C 13 | guests 0:00,17C 8:00:14C 19:00,16C 21:00,17.5C 14 | 15 | presence.patrick: hall 0:00,16C 7:30:17C 19:30,19C 22:00,17C 16 | living 0:00,16C 7:30:17C 20:30,18C 22:00,17C 17 | kitchen 0:00,16C 7:30,17C 18 | office 0:00,16C 7:30,20C 19:30,16.5C 19 | sleeping 8:00,10C 21:00,15C 20 | 21 | presence.isabel: hall 6:00,18.5C 7:30,20.0C 20:00,17C 22 | living 7:30,18.5C 20:00,17C 23 | kitchen 6:00,18.5C 7:30,19.5C 20:00,17C 24 | isabel 7:30,19.5C 19:30,17.5C 25 | presence.test: hall 6:00,18.5C 7:30,19.5C 19:30,20C 22:30,17C 26 | 27 | presence.guests: hall 6:00,18.5C 7:30,19.5C 19:30,20C 22:30,17C 28 | living 7:30,19C 19:30,20C 22:30,17C 29 | kitchen 6:00,18.5C 7:30,20C 20:30,17C 30 | guests 0:00,17C 8:00:14C 19:00,16C 21:00,17.5C 31 | 32 | presence.patrick: hall 0:00,16C 7:30:17C 19:30,19C 22:00,17C 33 | living 0:00,16C 7:30:17C 20:30,18C 22:00,17C 34 | kitchen 0:00,16C 7:30,17C 35 | office 0:00,16C 7:30,20C 19:30,16.5C 36 | sleeping 8:00,10C 21:00,15C 37 | 38 | presence.isabel: hall 6:00,18.5C 7:30,20.0C 20:00,17C 39 | living 7:30,18.5C 20:00,17C 40 | kitchen 6:00,18.5C 7:30,19.5C 20:00,17C 41 | isabel 7:30,19.5C 19:30,17.5C 42 | "; 43 | 44 | integer starttime = system.Date("%F %X").ToTime().ToInteger(); 45 | 46 | while( loopcounter > 0) 47 | { 48 | loopcounter = loopcounter -1; 49 | 50 | string persons; 51 | integer charindex = 0; 52 | integer presenttablelength = presencetable.Length(); 53 | boolean seperator = true; 54 | string onechar; 55 | 56 | while( charindex < presenttablelength ) 57 | { 58 | string onechar = presencetable.Substr(charindex,1); 59 | charindex = charindex+1; 60 | 61 | if( (" " == onechar) || ("\t" == onechar) || ("\n" == onechar) || ("\r" ==onechar) ) 62 | { 63 | if( !seperator ) 64 | { 65 | persons = persons # " "; 66 | } 67 | seperator = true; 68 | } 69 | else 70 | { 71 | persons = persons # onechar; 72 | seperator = false; 73 | } 74 | } 75 | ! WriteLine("presencetable:"#persons); 76 | 77 | } 78 | 79 | integer endtime = system.Date("%F %X").ToTime().ToInteger(); 80 | 81 | integer timeittook = endtime-starttime; 82 | integer msperloop = (1000*timeittook)/loops; 83 | integer mserror = 1000/loops; 84 | 85 | WriteLine("\n\nConversion took:"#timeittook#" seconds"); 86 | WriteLine(msperloop#" (+/-"#mserror#") mseconds per loop"); 87 | 88 | -------------------------------------------------------------------------------- /unused/parsingspeedsplit.hms: -------------------------------------------------------------------------------- 1 | 2 | 3 | integer loops = 20; 4 | integer loopcounter = loops; 5 | 6 | 7 | string presencetable = " 8 | presence.test: hall 6:00,18.5C 7:30,19.5C 19:30,20C 22:30,17C 9 | 10 | presence.guests: hall 6:00,18.5C 7:30,19.5C 19:30,20C 22:30,17C 11 | living 7:30,19C 19:30,20C 22:30,17C 12 | kitchen 6:00,18.5C 7:30,20C 20:30,17C 13 | guests 0:00,17C 8:00:14C 19:00,16C 21:00,17.5C 14 | 15 | presence.patrick: hall 0:00,16C 7:30:17C 19:30,19C 22:00,17C 16 | living 0:00,16C 7:30:17C 20:30,18C 22:00,17C 17 | kitchen 0:00,16C 7:30,17C 18 | office 0:00,16C 7:30,20C 19:30,16.5C 19 | sleeping 8:00,10C 21:00,15C 20 | 21 | presence.isabel: hall 6:00,18.5C 7:30,20.0C 20:00,17C 22 | living 7:30,18.5C 20:00,17C 23 | kitchen 6:00,18.5C 7:30,19.5C 20:00,17C 24 | isabel 7:30,19.5C 19:30,17.5C 25 | presence.test: hall 6:00,18.5C 7:30,19.5C 19:30,20C 22:30,17C 26 | 27 | presence.guests: hall 6:00,18.5C 7:30,19.5C 19:30,20C 22:30,17C 28 | living 7:30,19C 19:30,20C 22:30,17C 29 | kitchen 6:00,18.5C 7:30,20C 20:30,17C 30 | guests 0:00,17C 8:00:14C 19:00,16C 21:00,17.5C 31 | 32 | presence.patrick: hall 0:00,16C 7:30:17C 19:30,19C 22:00,17C 33 | living 0:00,16C 7:30:17C 20:30,18C 22:00,17C 34 | kitchen 0:00,16C 7:30,17C 35 | office 0:00,16C 7:30,20C 19:30,16.5C 36 | sleeping 8:00,10C 21:00,15C 37 | 38 | presence.isabel: hall 6:00,18.5C 7:30,20.0C 20:00,17C 39 | living 7:30,18.5C 20:00,17C 40 | kitchen 6:00,18.5C 7:30,19.5C 20:00,17C 41 | isabel 7:30,19.5C 19:30,17.5C 42 | "; 43 | 44 | integer starttime = system.Date("%F %X").ToTime().ToInteger(); 45 | 46 | while( loopcounter > 0) 47 | { 48 | loopcounter = loopcounter -1; 49 | 50 | string substring; 51 | string p1 = ""; 52 | string p2 = ""; 53 | string p3 = ""; 54 | string p4 = ""; 55 | string newline = "\n"; 56 | string carriagereturn = "\r"; 57 | 58 | foreach(substring, presencetable.Split(" ") ) 59 | { 60 | if( substring.Length() >0 ) { p1 = p1 # "\t" # substring; } 61 | } 62 | foreach(substring, p1.Split(newline) ) 63 | { 64 | if( substring.Length() >0 ) { p2 = p2 # "\t" # substring; } 65 | } 66 | foreach(substring, p2.Split(newline) ) 67 | { 68 | if( substring.Length() >0 ) { p3 = p3 # "\t" # substring; } 69 | } 70 | foreach(substring, p3 ) 71 | { 72 | if( substring.Length() >0 ) { p4 = p4 # "\t" # substring; } 73 | } 74 | ! WriteLine("presencetable:"#p4); 75 | 76 | } 77 | 78 | integer endtime = system.Date("%F %X").ToTime().ToInteger(); 79 | 80 | integer timeittook = endtime-starttime; 81 | integer msperloop = (1000*timeittook)/loops; 82 | integer mserror = 1000/loops; 83 | 84 | WriteLine("\n\nConversion took:"#timeittook#" seconds"); 85 | WriteLine(msperloop#" (+/-"#mserror#") mseconds per loop"); 86 | 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Homematic Scripts 2 | ----------------- 3 | 4 | The following are scripts I use in conjunction with my Homematic installation. I do tend not to use additional modules / software on my systems, so things should work without additions. 5 | 6 | 7 | WLAN Presence Script ([presencedetection.sh](presencedetection.sh)) 8 | ------------------------ 9 | 10 | A script for routers to detect presence of specific devices (by ethernetaddress) or IP ranges (e.g. guests). On detection it will call a URL with a presence flag. 11 | Presence is detected by using the arp table of the device and will call given URLs in the event a presence changes. Only changes will be transmitted so very low traffic is generated. No presence detections are lost as the script retries if the destination is not ready for reception. 12 | This script runs on my router (a fritz!box, but should work on any unix based router). Currently the script sets presence variables on a HomeMatic CCU2, but could be used for other systems as well. 13 | 14 | 15 | Presence Aggregation ([presenceVariableAggregation.hms](presenceVariableAggregation.hms)) 16 | ------------------------------- 17 | 18 | Not all persons have a WLAN device to track their presence in the house. So I have variables that can be manually set, or set via a calendar/timetable. Furthermore there is the possibilty to define kids as persons that are at home only if an adult person is at home. 19 | 20 | Lets assume the following variables are set: 21 | 22 | presence.wlan.guests: away 23 | presence.wlan.patrick: PRESENT 24 | presence.wlan.isabel: away 25 | 26 | presence.manual.guests: away 27 | presence.manual.patrick: away 28 | presence.manual.isabel: PRESENT 29 | 30 | presence.calender.guests: away 31 | presence.calender.patrick: away 32 | presence.calender.isabel: away 33 | . 34 | . 35 | . 36 | 37 | The [presenceVariableAggregation.hms](presenceVariableAggregation.hms) script creates then aggregated presence variables: 38 | 39 | presence.any: PRESENT 40 | presence.guests: away 41 | presence.patrick: PRESENT 42 | presence.isabel: PRESENT 43 | . 44 | . 45 | . 46 | 47 | Those variables are the ones I use in the different scripts. 48 | 49 | 50 | 51 | [PresenceTriggersTemperature.hms](PresenceTriggersTemperature.hms) 52 | ------------------------------- 53 | 54 | This is the main script for my heating system. It sets the SET_TEMPERATURE on the thermostats when they are in automode. The SET_TEMPERATURE is depended if and which person is in a room, if windows or doors are open or people are presumed to be in a room cause a switch (e.g. lights, plugs) is engaged. 55 | 56 | The script uses a table to know the preferences of the different person groups: 57 | 58 | presence.guests: hall 0:00,17C 6:00,18.5C 7:30,19.5C 19:30,20C 59 | living 0:00,17C 7:30,19C 19:30,20C 60 | kitchen 0:00,17C 6:00,18.5C 7:30,20C 20:30,17C 61 | guests 0:00,17C 8:00:16C 21:00,17.5C 62 | 63 | presence.patrick: hall 0:00,16C 7:30:18C 20:30,19C 64 | living 0:00,16C 7:30:17C 20:30,18C 65 | kitchen 0:00,16C 7:30,18C 20:30,17C 66 | office 0:00,16C 7:30,19.5C 19:30,16.5C 67 | sleeping 0:00,15C 8:00,10C 22:00,16C 68 | 69 | 70 | 71 | 72 | [TurnHeatingOn.hms](TurnHeatingOn.hms) 73 | ----------------------- 74 | This script automtically finds out all heating thermostats and turns the main switch for the heating system on depending on the actual and set temperatures as well as valve states of the thermostats. 75 | 76 | 77 | [ThermostatModeSwitch.hms](ThermostatModeSwitch.hms) 78 | ----------------------- 79 | This script finds out all heating thermostats and sets them all to manual off state or auto mode depending on a switch state. So a single main switch can turn off all thermostats. 80 | 81 | 82 | [TurnBoilerOnAfterVacation.hms](TurnBoilerOnAfterVacation.hms) 83 | ----------------------- 84 | This script turns my boiler when someone arrives at home and the boiler has not been turned on for 24 hours. 85 | Usually that is the case after a vacation, then I want to make sure I can take a shower instantly. 86 | 87 | 88 | [Inventory.hms](Inventory.hms) 89 | ------------- 90 | Creates a inventory of your devices (in english or german) like this: 91 | 92 | 212 Kanaele in 38 Geraeten, 13 Geraetetypen: 93 | 3x HM-LC-Sw1PBU-FM, 7x HM-ES-PMSw1-Pl, 7x HM-Sec-SCo, 5x HM-Sec-SD, 7x HM-CC-RT-DN, 1x HM-RCV-50, 1x HM-Sec-SC-2, 1x HM-ES-TX-WM, 2x HM-Sec-WDS-2, 1x HM-LC-Sw4-SM, 1x HmIP-RCV-50, 1x HM-Sec-SD-Team, 1x HM-PB-2-WM55 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /Inventory.hms: -------------------------------------------------------------------------------- 1 | ! https://github.com/jollyjinx/homematic/blob/master/Inventory.hms 2 | ! 3 | ! Run the script to get a nice inventory 4 | ! 5 | !----- User setable variables 6 | 7 | string language = "de"; ! either "en" for english or "de" for german; 8 | boolean debug = false; 9 | 10 | !------ Execution 11 | 12 | ! 13 | ! generate the device list 14 | ! 15 | 16 | integer devicecounter = 0; 17 | integer channelcount = 0; 18 | integer devicetypecount = 0; 19 | string devicetypes = ","; 20 | string devicesconcat; 21 | 22 | string deviceid; 23 | foreach(deviceid, dom.GetObject(ID_DEVICES).EnumUsedIDs()) 24 | { 25 | var device = dom.GetObject(deviceid); if(debug){WriteLine("Device:"#device#" (id:"#deviceid#")");} 26 | string devicetype = device.HssType(); if(debug){WriteLine("Devicetype:"#devicetype);} 27 | 28 | devicecounter = devicecounter + 1; 29 | devicesconcat = devicesconcat # "\t" # devicetype; 30 | 31 | if( -1 == devicetypes.Find(","# devicetype # ",") ) 32 | { 33 | devicetypes = devicetypes # devicetype # ","; 34 | devicetypecount = devicetypecount + 1; 35 | } 36 | 37 | string channelid; 38 | foreach(channelid,device.Channels().EnumUsedIDs()) 39 | { if(debug){var channel = dom.GetObject(channelid);WriteLine("\t Channel:"#channel#" (id:"#channelid#")");} 40 | channelcount = channelcount + 1; 41 | } 42 | } if(debug){WriteLine(channelcount # " channels " # devicecounter # " devices " # devicetypecount # " devicetypes");} 43 | 44 | if( "de" == language ) 45 | { 46 | WriteLine(channelcount # " Kanaele in " # devicecounter # " Geraeten, " # devicetypecount # " Geraetetypen:"); 47 | } 48 | else 49 | { 50 | WriteLine(channelcount # " channels in " # devicecounter # " devices, " # devicetypecount # " devicetypes:"); 51 | } 52 | 53 | string typenames; 54 | 55 | !. string input = "/bin/sh -c 'cat /www/webui/js/lang/"#language#"/translate.lang.deviceDescription.js|sed -r \"s/%DF/ss/g;s/%FC/ue/g;s/%E4/ae/g;s/%F6/oe/g;s/(^\s+|,\s*\$)//g;s/\\"\\s*:\\s*\\"/\\":\\"/g;s/\\"//g;s/^(HM\-RCV\-50:).*\$/\1CCU2 System/;\"|awk -F : -v ORS=, \"{if(length(\$1)>3 && length(\$2)>3) print \$1\\",\\"\$2;}\"|sed \"s/,\$//;\" "; 56 | !. string stderr; 57 | !. system.Exec(input, &typenames,&stderr); if(debug){WriteLine("Type to Name array:" #typenames)}; 58 | 59 | 60 | 61 | string outputstring; 62 | string devicetype; 63 | foreach(devicetype,devicetypes.Split(",")) 64 | { 65 | if( devicetype.Length() ) 66 | { if(debug){WriteLine("Device:"#devicetype);} 67 | devicecounter = 0; 68 | 69 | string counttype; 70 | foreach(counttype,devicesconcat) 71 | { 72 | if( counttype.Length() && (counttype == devicetype) ) 73 | { 74 | devicecounter = devicecounter + 1; 75 | } 76 | } 77 | 78 | string originaldevicetype = devicetype; 79 | boolean foundnicename=false; 80 | 81 | while( !foundnicename && devicetype.Length()>6 ) 82 | { 83 | string nicename; 84 | integer devicenameposition = typenames.Find(devicetype#","); if(debug){WriteLine("Searching nicename for:"#devicetype);} 85 | 86 | if( -1 != devicenameposition ) 87 | { 88 | integer length = devicetype.Length(); 89 | string remainingstring = typenames.Substr(devicenameposition,length-devicenameposition); 90 | 91 | nicename = "(" # remainingstring.StrValueByIndex(",",1) # ")"; 92 | foundnicename = true; 93 | } 94 | else 95 | { 96 | devicetype = devicetype.Substr(0,devicetype.Length()-1); 97 | } 98 | } 99 | 100 | outputstring = outputstring # devicecounter # "x " # originaldevicetype # nicename # ", "; 101 | } 102 | } 103 | WriteLine(outputstring.Substr(0, outputstring.Length() - 2)); 104 | WriteLine("--------------------------------------------"); 105 | WriteLine("https://github.com/jollyjinx/homematic/blob/master/Inventory.hms"); 106 | -------------------------------------------------------------------------------- /TurnHeatingOn.hms: -------------------------------------------------------------------------------- 1 | ! https://github.com/jollyjinx/homematic/blob/master/TurnHeatingOn.hms 2 | ! 3 | ! Turn main heating switch on when thermostats in house are below 4 | ! their set value or valves are open. Either one valve is open a lot 5 | ! or all valves together are above a level. 6 | ! 7 | !----- User settable variables 8 | 9 | 10 | string heatingmainswitch = "BidCos-RF.KEQ0768205:2"; ! set this to the switch your heating uses 11 | 12 | integer timebetweenchanges = 15; ! in minutes before another change to the main switch should be done 13 | real singlevalveturnonstate = 30.0; ! if one valve is above this point turn on heating 14 | real averagevalveturnonstate = 20.0; ! if all valves average is above this point turn heating on 15 | real overshoottemperature = 1.0; ! if actutal temperature is above this valve state will be ignored 16 | boolean debug = false; ! if set only output what is done, don't do it 17 | 18 | !------ Execution 19 | 20 | var heatingswitch = dom.GetObject(heatingmainswitch#".STATE"); 21 | 22 | ! check time the switch was last modified 23 | 24 | time lasttimechanged = heatingswitch.Timestamp(); 25 | time timenow = system.Date("%Y-%m-%d %H:%M:%S").ToTime(); 26 | 27 | integer lastchange = (timenow-lasttimechanged).ToInteger(); if(debug){WriteLine("Seconds since last changing:"#lastchange);} 28 | 29 | if( lastchange < (timebetweenchanges*60) ) 30 | { 31 | if(debug){WriteLine("Last change not long enough ago");} 32 | quit; 33 | } 34 | 35 | 36 | boolean turnonheating = false; 37 | string thermostat; 38 | real allvalvestate = 0.0; 39 | real allvalvecount = 0.0; 40 | 41 | 42 | string deviceid; 43 | foreach(deviceid, dom.GetObject(ID_DEVICES).EnumUsedIDs()) 44 | { 45 | var device = dom.GetObject(deviceid); if(debug){WriteLine("Device:"#device#" (id:"#deviceid#")");} 46 | 47 | if( (!turnonheating) && ("HM-CC-RT-DN" == device.HSSID()) ) 48 | { 49 | string channelid; 50 | foreach(channelid,device.Channels().EnumUsedIDs()) 51 | { 52 | var channel = dom.GetObject(channelid); if(debug){WriteLine("\t Channel:"#channel#" (id:"#channelid#")");} 53 | 54 | if( (!turnonheating) && ("CLIMATECONTROL_RT_TRANSCEIVER" == channel.HSSID()) ) 55 | { 56 | var interface = dom.GetObject(channel.Interface()); 57 | var datapoint = interface#"."#channel.Address(); if(debug){WriteLine("\t Datapoint:"#datapoint);} 58 | 59 | real actualtemperature = dom.GetObject(datapoint#".ACTUAL_TEMPERATURE").Value(); 60 | real settemperature = dom.GetObject(datapoint#".SET_TEMPERATURE").Value(); if(debug){WriteLine("\t\t actualtemperature:"#actualtemperature#"\tsettemperature:"#settemperature);} 61 | time lastsetvalue = dom.GetObject(datapoint#".SET_TEMPERATURE").LastValue(); if(debug){WriteLine("\t\t LastValue:"#lastsetvalue);} 62 | 63 | if( (lastsetvalue == settemperature) && (actualtemperature < (settemperature+overshoottemperature)) ) 64 | { 65 | real valvestate = dom.GetObject(datapoint#".VALVE_STATE").Value(); if(debug){WriteLine("\t\t valvestate:"#valvestate#"\tsettemperature:"#settemperature);} 66 | 67 | allvalvecount=allvalvecount+1; 68 | allvalvestate=allvalvestate+valvestate; 69 | 70 | if( (actualtemperature < settemperature) || (valvestate>singlevalveturnonstate) ) 71 | { if(debug){WriteLine("should be heating(single thermostat)");} 72 | turnonheating = true; 73 | } 74 | } 75 | } 76 | } 77 | } 78 | } 79 | 80 | if( (allvalvecount>0.0) && ((allvalvestate/allvalvecount)>averagevalveturnonstate) ) 81 | { 82 | turnonheating = true; if(debug){WriteLine("should be heating(average valves)"#(allvalvestate/allvalvecount)#">"#averagevalveturnonstate);} 83 | } 84 | 85 | 86 | 87 | boolean currentheatingstate = heatingswitch.Value(); if(debug){WriteLine("currentstate:"#currentheatingstate#"\nturnonheating:"#turnonheating);} 88 | 89 | if( currentheatingstate <> turnonheating ) 90 | { if(debug){WriteLine("Would change heating:"#turnonheating);} 91 | if(!debug){heatingswitch.State(turnonheating);} 92 | } 93 | -------------------------------------------------------------------------------- /presenceVariableAggregation.hms: -------------------------------------------------------------------------------- 1 | ! https://github.com/jollyjinx/homematic/blob/master/presenceVariableAggregation.hms 2 | ! 3 | ! Aggregates presence variables to ones that are used in scripts. 4 | ! 5 | ! Not all persons have a WLAN device to track their presence in the house. 6 | ! So I have variables that can be manually set, or set via a calendar/timetable. 7 | ! 8 | ! Presence variables have the form: presense.[presencetype].[personname] 9 | ! Aggregated variables have the form: presense.[personname] and presence.any 10 | ! 11 | ! Lets assume the following variables are set: 12 | ! 13 | ! presence.wlan.guests: away 14 | ! presence.wlan.patrick: PRESENT My phone is logged to the wlan 15 | ! presence.wlan.isabel: away 16 | ! 17 | ! presence.manual.guests: away 18 | ! presence.manual.patrick: away 19 | ! presence.manual.isabel: PRESENT manually set via a virtual ccu2 switch 20 | ! 21 | ! presence.calender.guests: away presence set via a timetable 22 | ! presence.calender.patrick: away 23 | ! presence.calender.isabel: away 24 | ! . 25 | ! . 26 | ! . 27 | ! Those variables are aggregated with this through variables named presence.type.personname 28 | ! This script creates then aggregated presence variables: 29 | ! 30 | ! presence.any: PRESENT 31 | ! presence.guests: away 32 | ! presence.patrick: PRESENT 33 | ! presence.isabel: PRESENT 34 | ! . 35 | ! . 36 | ! . 37 | ! 38 | ! As I have a timetable for my daughter isabel and she has no presence device 39 | ! she is set at home via a timetable or manually. As she is not at home alone 40 | ! her aggregated presence is only set when someone else is at home. 41 | ! 42 | ! Those persons, that are depending on the presence of a real person are called 43 | ! kids here, even though I use it for a my daughter and my office. 44 | ! When I'm at home and my office computer has a lit screen, then my office is 45 | ! getting warm. 46 | ! This can also be used for shift workers to have three depending users that have 47 | ! differrent work times an those are present depending on a calender and the presence 48 | ! of the real user. 49 | ! 50 | !----- User setable variables 51 | 52 | string presenceprefix = "presence"; 53 | string anyperson = "any"; 54 | string kids = "isabel,officeuser"; ! comma seperated list 55 | boolean debug = false; 56 | 57 | ! 58 | !------- nothing needs to be changed below. 59 | ! 60 | 61 | string allpersons = ","#anyperson#","; 62 | string allkids = ","#kids#","; 63 | string presentpersons = ","; 64 | boolean adultispresent = false; 65 | 66 | string variableID; 67 | 68 | foreach(variableID, dom.GetObject(ID_SYSTEM_VARIABLES).EnumUsedIDs()) 69 | { 70 | string variablename = dom.GetObject(variableID).Name(); if(debug){WriteLine("Variable:"#variablename);} 71 | 72 | if( presenceprefix == variablename.StrValueByIndex(".",0) ) 73 | { if(debug){WriteLine("\t is presence variable");} 74 | string personname = variablename.StrValueByIndex(".",2); 75 | 76 | if( (personname.Length() > 0) && (personname != anyperson) ) 77 | { if(debug){WriteLine("\t personname:"#personname);} 78 | if( -1 == allpersons.Find(","#personname#",") ) 79 | { 80 | allpersons = allpersons#personname#","; if(debug){WriteLine("\tAdding to all:"#personname);} 81 | } 82 | if( -1 == presentpersons.Find(","#personname#",") ) 83 | { 84 | boolean personispresent = dom.GetObject(variablename).Value(); if(debug){WriteLine("\t"#personname#" is present:"#personispresent);} 85 | 86 | if( personispresent ) 87 | { 88 | if( (!adultispresent) && (-1 == allkids.Find(","#personname#",")) ) 89 | { 90 | adultispresent = true; 91 | presentpersons = ","#anyperson#presentpersons; if(debug){WriteLine("\tadultispresent is present.");} 92 | } 93 | presentpersons = presentpersons#personname#","; if(debug){WriteLine("\tpresentpersons:"#presentpersons);} 94 | } 95 | } 96 | else 97 | { 98 | if(debug){WriteLine("\t"#personname#" already present");} 99 | } 100 | } 101 | } 102 | } 103 | 104 | 105 | if(debug) { WriteLine("\nallpersons:"#allpersons#"\n\tpresentpersons:"#presentpersons#"\n\tadultispresent:"#adultispresent); } 106 | 107 | 108 | string personname; 109 | 110 | foreach(personname,allpersons.Split(",")) 111 | { 112 | if( personname.Length() > 0 ) 113 | { 114 | boolean ispresent = false; 115 | 116 | if( (adultispresent) && (-1 != presentpersons.Find(","#personname#",")) ) 117 | { if(debug){WriteLine("\tpersonname found:"#personname);} 118 | ispresent = true; 119 | } 120 | 121 | var presencevariable = dom.GetObject(presenceprefix#"."#personname); 122 | if( ispresent != presencevariable.Value() ) 123 | { if(debug){WriteLine("\t"#presenceprefix#"."#personname#" has changed:"#ispresent);} 124 | if(!debug){presencevariable.State(ispresent);} 125 | } 126 | else 127 | { if(debug){WriteLine("\t"#presenceprefix#"."#personname#" has not changed:"#ispresent);} 128 | 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /InformationDump.hms: -------------------------------------------------------------------------------- 1 | !https://github.com/jollyjinx/homematic/blob/master/InformationDump.hms 2 | ! 3 | ! This script dumps information on Homematic CCU2 connected devices,functions,variables and more. 4 | ! It might help you in finding out how to find out things with homematic script. 5 | ! 6 | 7 | WriteLine("Executing HM Script now"); 8 | 9 | string itemID; 10 | 11 | foreach (itemID, dom.GetObject(ID_PROGRAMS).EnumUsedIDs()) 12 | { 13 | WriteLine("Program ID:"#itemID); 14 | var item = dom.GetObject(itemID); 15 | 16 | WriteLine("Program:"#item); 17 | WriteLine("Program Last Run:"#item.Variable()); 18 | } 19 | foreach (itemID, dom.GetObject(ID_SYSTEM_VARIABLES).EnumUsedIDs()) 20 | { 21 | WriteLine("Variable id:"#itemID); 22 | var item = dom.GetObject(itemID); 23 | 24 | WriteLine("Variable:"#item); 25 | } 26 | foreach (itemID, dom.GetObject(ID_FUNCTIONS).EnumUsedIDs()) 27 | { 28 | WriteLine("Function id:"#itemID); 29 | var item = dom.GetObject(itemID); 30 | 31 | WriteLine("Function name:"#item); 32 | } 33 | foreach (itemID, dom.GetObject(ID_CHANNELS).EnumUsedIDs()) 34 | { 35 | WriteLine("Channel id:"#itemID); 36 | var item = dom.GetObject(itemID); 37 | 38 | WriteLine("Channel:"#item); 39 | } 40 | foreach (itemID, dom.GetObject(ID_INTERFACES).EnumUsedIDs()) 41 | { 42 | WriteLine("Interface id:"#itemID); 43 | var item = dom.GetObject(itemID); 44 | 45 | WriteLine("Interface:"#item); 46 | } 47 | foreach (itemID, dom.GetObject(ID_DATAPOINTS).EnumUsedIDs()) 48 | { 49 | WriteLine("Datapoint id:"#itemID); 50 | var item = dom.GetObject(itemID); 51 | 52 | WriteLine("Datapoint:"#item); 53 | } 54 | foreach (itemID, dom.GetObject(ID_ROOMS).EnumUsedIDs()) 55 | { 56 | WriteLine("Room ID:"#dom.GetObject(itemID)); 57 | var item = dom.GetObject(itemID); 58 | 59 | WriteLine("Room:"#item); 60 | } 61 | foreach (itemID, dom.GetObject(ID_STRUCTURE).EnumUsedIDs()) 62 | { 63 | WriteLine("Structure ID:"#dom.GetObject(itemID)); 64 | var item = dom.GetObject(itemID); 65 | 66 | WriteLine("Structure:"#item); 67 | } 68 | 69 | 70 | string deviceid; 71 | 72 | foreach(deviceid, dom.GetObject(ID_DEVICES).EnumUsedIDs()) 73 | { 74 | WriteLine("DeviceID:"#deviceid); 75 | 76 | var device=dom.GetObject(deviceid); 77 | WriteLine("Device:"#device); 78 | WriteLine("\t device.Address:"#device.Address()); 79 | WriteLine("\t device.Name:"#device.Name()); 80 | WriteLine("\t device.DataValue:"#device.DataValue()); 81 | ! WriteLine("\t device.LastDPActionTime:"#device.LastDPActionTime()); 82 | ! WriteLine("\t device.ChnRoom:"#device.ChnRoom()); 83 | WriteLine("\t device.PrgInfo:"#device.PrgInfo()); 84 | WriteLine("\t device.PrgInfo:"#device.PrgInfo().Value()); 85 | WriteLine("\t device.DestinationChannel:"#device.DestinationChannel()); 86 | WriteLine("\t device.DPInfo:"#device.DPInfo()); 87 | WriteLine("\t device.HSSID:"#device.HSSID()); 88 | WriteLine("\t device.IsTypeOf:"#device.IsTypeOf()); 89 | 90 | WriteLine("\t device.Operations:"#device.Operations()); 91 | string operationid; 92 | foreach(operationid,device.Operations().EnumUsedIDs()) 93 | { 94 | var operation=dom.GetObject(operationid); 95 | WriteLine("\t\t device.operation:"#operation); 96 | } 97 | string dpid; 98 | foreach(dpid,device.DPs().EnumUsedIDs()) 99 | { 100 | var dp=dom.GetObject(dpid); 101 | WriteLine("\t\t device.dpids:"#dp); 102 | } 103 | 104 | string channelid; 105 | 106 | foreach(channelid,device.Channels().EnumUsedIDs()) 107 | { 108 | var channel=dom.GetObject(channelid); 109 | 110 | WriteLine("\t Channel:"#channel#"\t channel.Name:"#channel.Name()); 111 | WriteLine("\t\t channel.ChnFunction:"#channel.ChnFunction()); 112 | WriteLine("\t\t channel.Address:"#channel.Address()); 113 | WriteLine("\t\t channel.ChnLabel:"#channel.ChnLabel()); 114 | WriteLine("\t\t channel.ChnFunction:"#channel.ChnFunction()); 115 | WriteLine("\t\t channel.ChnArchive:"#channel.ChnArchive()); 116 | WriteLine("\t\t channel.ChnDirection:"#channel.ChnDirection()); 117 | WriteLine("\t\t channel.DPInfo:"#channel.DPInfo()); 118 | WriteLine("\t\t channel.LastDPActionTime:"#channel.LastDPActionTime()); 119 | WriteLine("\t\t channel.DestinationDP:"#channel.DestinationDP()); 120 | WriteLine("\t\t channel.DataValue:"#channel.DataValue()); 121 | WriteLine("\t\t channel.ChnGroupPartnerId:"#channel.ChnGroupPartnerId()); 122 | WriteLine("\t\t channel.DestinationChannel:"#channel.DestinationChannel()); 123 | WriteLine("\t\t channel.HSSID:"#channel.HSSID()); 124 | WriteLine("\t\t channel.IsTypeOf:"#channel.IsTypeOf()); 125 | 126 | 127 | var interface=dom.GetObject(channel.Interface()); 128 | 129 | WriteLine("\t\t channel.Interface:"#interface); 130 | WriteLine("\t\t channel.Interface.Name:"#interface.Name()); 131 | !WriteLine("\t\t channel.Interface.Operations:"#interface.Operations()); 132 | !WriteLine("\t\t channel.Interface.Operations.Value:"#interface.Operations().Value()); 133 | 134 | !WriteLine("\t\t channel.Operations:"#channel.Operations()); 135 | 136 | !string dpid; 137 | foreach(operationid,channel.DPs().EnumUsedIDs()) 138 | { 139 | var datapoint=dom.GetObject(operationid); 140 | Write("\t\t\t channel.datapoint:"#datapoint#"\t"#datapoint.ValueType()#"\t Value:"#datapoint.Value()#"\t LastValue:"#datapoint.LastValue()#"\t Timestamp:"#datapoint.Timestamp()#"\t"); 141 | 142 | if(OPERATION_READ & datapoint.Operations()) { Write("READ "); } 143 | if(OPERATION_WRITE & datapoint.Operations()) { Write("WRITE "); } 144 | if(OPERATION_EVENT & datapoint.Operations()) { Write("EVENT "); } 145 | WriteLine(""); 146 | } 147 | 148 | string rid; 149 | 150 | foreach(rid,channel.ChnRoom().EnumUsedIDs()) 151 | { 152 | var room=dom.GetObject(rid); 153 | WriteLine("\t\t roomid:"#rid#"\t room:"#room#"\t room.Name:"#room.Name()); 154 | } 155 | foreach(rid,channel.ChnFunction().EnumUsedIDs()) 156 | { 157 | var function=dom.GetObject(rid); 158 | WriteLine("\t\t functionid:"#rid#"\t function:"#function#"\t function.Name:"#function.Name()); 159 | } 160 | WriteLine(""); 161 | } 162 | 163 | 164 | var interface=dom.GetObject(device.Interface()); 165 | WriteLine("\t device.Interface:"#interface); 166 | WriteLine("\t device.Interface.Name:"#interface.Name()); 167 | 168 | } 169 | -------------------------------------------------------------------------------- /unused/TemperatureTableParsing.hms: -------------------------------------------------------------------------------- 1 | ! This script tests how to parse a temperature table 2 | !. 3 | 4 | string comfortname = "comforttemperatures"; ! name of the temperature table that should act as default comfort temperature 5 | 6 | boolean debug = true; 7 | 8 | 9 | string temperaturetable = " 10 | 11 | comforttemperatures: test 0:00,16C 12 | test 0:01,16C 13 | test 23:59,16C 14 | test 0:01,16C 0:02,17C 15 | test 0:00,16C 23:59,17C 16 | test 0:01,16C 0:02,17C 23:59,18C 17 | test 23:58,16C 23:59,17C 18 | test 0:00,16C 8:00,17C 23:58,18C 19 | 20 | presence.guests: hall 6:00,18.5C 7:30,19.5C 19:30,20C 22:30,17C 21 | living 7:30,19C 19:30,20C 22:30,17C 22 | kitchen 6:00,18.5C 7:30,20C 20:30,17C 23 | guests 0:00,17C 8:00,14C 19:00,16C 21:00,17.5C 24 | 25 | presence.patrick: hall 0:00,16C 7:30,17C 19:30,19C 22:00,17C 26 | living 0:00,16C 7:30,17C 20:30,18C 22:00,17C 27 | kitchen 0:00,16C 7:30,17C 28 | office 0:00,16C 7:30,20C 19:30,16.5C 29 | sleeping 8:00,10C 21:00,15C 30 | 31 | presence.isabel: hall 6:00,18.5C 7:30,20.0C 20:00,17C 32 | living 7:30,18.5C 20:00,17C 33 | kitchen 6:00,18.5C 7:30,19.5C 20:00,17C 34 | isabel 7:30,19.5C 19:30,17.5C 35 | "; 36 | 37 | 38 | !. 39 | !--- no user setable parts below this point 40 | !. 41 | string currentyearmonthday = system.Date("%F "); 42 | integer timenow = (currentyearmonthday#system.Date("%X")).ToTime().ToInteger(); 43 | integer timedaystart = (currentyearmonthday#"00:00:00").ToTime().ToInteger(); 44 | integer secondsthisday = timenow-timedaystart; 45 | if(debug){WriteLine("timenow:"#timenow#"\t secondsthisday:"#secondsthisday);} 46 | 47 | string ascii_space = " "; 48 | string ascii_tabular = "\t"; 49 | string ascii_newline = "\n"; 50 | string ascii_return = "\r"; 51 | string table_delimiter = "#"; 52 | string roomtabledelimiter = ascii_newline; 53 | !. 54 | !. create a tabulator seperated temperaturetable 55 | !. 56 | 57 | 58 | if(true) 59 | { 60 | string substring; 61 | string temporarytemperaturetable1; 62 | string temporarytemperaturetable2; 63 | 64 | foreach(substring, temperaturetable.Split(ascii_space) ) 65 | { 66 | if( substring.Length() >0 ) { temporarytemperaturetable1 = temporarytemperaturetable1 # table_delimiter # substring; } 67 | } 68 | foreach(substring, temporarytemperaturetable1.Split(ascii_return) ) 69 | { 70 | if( substring.Length() >0 ) { temporarytemperaturetable2 = temporarytemperaturetable2 # table_delimiter # substring; } 71 | } 72 | temperaturetable = ""; 73 | 74 | foreach(substring, temporarytemperaturetable2 ) 75 | { 76 | if( substring.Length() >0 ) { temperaturetable = temperaturetable # table_delimiter # substring; } 77 | } 78 | temperaturetable = temperaturetable # ascii_newline; 79 | 80 | if(debug) {WriteLine("temperaturetable:"#temperaturetable);} 81 | } 82 | 83 | 84 | 85 | 86 | !. 87 | !. go through every person that is present and add figure out hte room preferences 88 | !. 89 | 90 | string roomtemperatures; 91 | string comforttemperatures; 92 | 93 | if(true) 94 | { 95 | string currentperson; 96 | boolean personispresent; 97 | integer personchangedtime; 98 | 99 | string temperaturetableline; 100 | 101 | foreach( temperaturetableline, temperaturetable.Split(ascii_newline) ) 102 | { !. if(debug){WriteLine("Line:"#temperaturetableline);} 103 | string currentroom; 104 | integer currentchangetime; 105 | string currentchangetemp; 106 | integer lastchangetime; 107 | string lastchangetemp; 108 | 109 | string temperaturetablepart; 110 | 111 | foreach(temperaturetablepart,temperaturetableline.Split(table_delimiter)) 112 | { 113 | integer partlength = temperaturetablepart.Length(); 114 | 115 | if( partlength > 0 ) 116 | { !. if(debug){WriteLine("\nPart:"#temperaturetablepart#" length:"#partlength);} 117 | integer colonposition = temperaturetablepart.Find(":"); 118 | 119 | if( -1 == colonposition ) 120 | { 121 | currentroom = temperaturetablepart; if(debug){WriteLine("\tcurrentroom:"#temperaturetablepart);} 122 | currentchangetime = -1; 123 | currentchangetemp = "-1"; 124 | lastchangetime = -1; 125 | lastchangetemp = "-1"; 126 | } 127 | else 128 | { 129 | if( colonposition == (partlength-1) ) 130 | { 131 | currentperson = temperaturetablepart.Substr(0,partlength-1); if(debug){WriteLine("\nPerson:"#currentperson);} 132 | 133 | object personvariable = dom.GetObject(currentperson); 134 | 135 | if( personvariable ) 136 | { 137 | personispresent = personvariable.Value(); 138 | boolean personwaspresent = personvariable.LastValue(); 139 | 140 | if( personispresent != personwaspresent ) 141 | { 142 | personchangedtime = personvariable.Timestamp().ToInteger(); 143 | } 144 | else 145 | { 146 | personchangedtime = timedaystart-86400; 147 | } if(debug){WriteLine("\tpresence:"#personispresent#" since:"#personchangedtime.ToTime()#" waspresent:"#personwaspresent);} 148 | } 149 | } 150 | else 151 | { 152 | integer timeseconds = (currentyearmonthday#temperaturetablepart.StrValueByIndex(",",0)#":00").ToTime().ToInteger(); 153 | string temperature = temperaturetablepart.StrValueByIndex(",",1); 154 | 155 | if( timeseconds > timenow ) 156 | { 157 | timeseconds = timeseconds - 86400; 158 | } 159 | !.if(debug){WriteLine(" timeseconds:"#timeseconds#" temperature:"#temperature);} 160 | !.if(debug){WriteLine("\troom:"#currentroom#","#currentchangetime.ToTime()#","#currentchangetemp#","#lastchangetime.ToTime()#","#lastchangetemp);} 161 | 162 | if( -1 == currentchangetime ) 163 | { 164 | currentchangetime = timeseconds; 165 | currentchangetemp = temperature; 166 | lastchangetime = timeseconds-86400; 167 | lastchangetemp = temperature; 168 | } 169 | else 170 | { !.if(debug){WriteLine("\troom:"#currentroom#","#currentchangetime.ToTime()#","#currentchangetemp#","#lastchangetime.ToTime()#","#lastchangetemp);} 171 | if( timeseconds > currentchangetime ) 172 | { 173 | lastchangetime = currentchangetime; 174 | lastchangetemp = currentchangetemp; 175 | currentchangetime = timeseconds; 176 | currentchangetemp = temperature; 177 | } 178 | else 179 | { 180 | if( timeseconds > lastchangetime ) 181 | { 182 | lastchangetime = timeseconds; 183 | lastchangetemp = temperature; 184 | } 185 | } 186 | } 187 | !.if(debug){WriteLine("\troom:"#currentroom#","#currentchangetime.ToTime()#","#currentchangetemp#","#lastchangetime.ToTime()#","#lastchangetemp);} 188 | } 189 | } 190 | } 191 | } 192 | 193 | if( currentroom.Length() > 0) 194 | { if(debug){WriteLine("\tFinal:"#currentroom#","#currentchangetime.ToTime()#","#currentchangetemp#","#lastchangetime.ToTime()#","#lastchangetemp);} 195 | if( personispresent ) 196 | { 197 | roomtemperatures = roomtemperatures#roomtabledelimiter#currentroom#","#currentchangetime#","#currentchangetemp#","#lastchangetime#","#lastchangetemp; 198 | } 199 | else 200 | { 201 | if( comfortname == currentperson ) 202 | { 203 | comforttemperatures = comforttemperatures#roomtabledelimiter#currentroom#","#currentchangetime#","#currentchangetemp#","#lastchangetime#","#lastchangetemp; 204 | } 205 | } 206 | } 207 | } 208 | if(debug){WriteLine("\nRoomtemperatures:"#roomtemperatures#"\nComforttemperatures:"#comforttemperatures);} 209 | } 210 | -------------------------------------------------------------------------------- /presencedetection.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # presence detection for home router (e.g. Fritzbox) 4 | # It sets variables to true/falso on the CCU2 depending on the presence of that person/group 5 | # This script can be found on: https://github.com/jollyjinx/homematic 6 | # 7 | # You need to adjust the script to your network setup, so read on: 8 | # 9 | # 1. Adjust the network addresses and names for the persons in this script 10 | # 2. Install this script on your router, so it starts after reboot (on a fritzbox via debug.cfg) 11 | # 4. enjoy 12 | # 13 | # Ajusting this script 14 | # -------------------- 15 | # I'm using variables on the CCU2 for presence detection: 16 | # 17 | # presence.patrick is set to beeing present when his ethernet address shows up 18 | # presence.nightguests is set when their ethernet addresses show up or devices in a network range 19 | # presence.dayguests is set when their ethernet addresses show up or devices in a network range 20 | # presence.any is set when patrick or guests is set. 21 | # 22 | # My local network is set up to be in 192.168.0.0 - 192.168.0.255 23 | # Stationary devices are in the range 192.168.0.0-192.168.0.139 and 192.168.0.200-192.168.0.255 24 | # Guests are either in the guest network 192.168.179.* or in the range 192.168.0.140-192.168.0.199 25 | # 26 | # As my network setup is different than yours you have to adjust the variable regular expressions 27 | # to your needs 28 | # 29 | # 30 | # At the start of the script presence variables are created on the box in case they don't exist. 31 | # This script uses 'nc' for creating the presense variables on the CCU2 and wget to setting the variables 32 | # 33 | # 34 | # Variables for you to change: 35 | # 36 | ccu2address="hmccu2" # ip address or network name of CCU2 37 | set patrick nightguests dayguests # variables to set on the CCU2 and their presence check 38 | patrick="80:ea:96:94:5a:66" # patricks presence detection device (iphone) 39 | nightguests="192.168.0.1[4-9][0-9]" # overnight guests 192.168.140-199 40 | dayguests="192.168.0.2[2-4][0-9]|192.168.179.[1-2]?[0-9]+" # dayguests 192.168.0.220-249 , 192.168.179.* 41 | # 42 | # The next variables are usually nothing you need to change 43 | # 44 | ignore="|at[\t ]+(00:0c:29|00:50:56|00:1c:42):" # ignore incomplete, vmware and parallels addresses 45 | looptime=30 # how often we check in seconds 46 | maximumcounter=45 # how many loops of looptime until somebody is no longer present 47 | intialcounter=4 # default counter for each presence variable at start 48 | variableprefix="presence.wlan." # prefix for the variables on the ccu2 49 | someonename="any" # variable name if someone is present 50 | debug=false 51 | $debug && looptime=5 52 | 53 | # 54 | # There is nothing below this line that needs to be changed 55 | # 56 | # 57 | RETURN_FAILURE=1 58 | RETURN_SUCCESS=0 59 | 60 | 61 | getorsetpresenceVariableState() 62 | { 63 | local name=$1 64 | local setstate=$2 65 | 66 | if [ "$setstate" != "" ] 67 | then 68 | local currentstate=`getorsetpresenceVariableState $name` 69 | if [ "$currentstate" == "$setstate" ] 70 | then 71 | echo -n "$currentstate" 72 | return $RETURN_SUCCESS 73 | fi 74 | fi 75 | local wgetreturn=$(wget -q -O - "http://$ccu2address:8181/rega.exe?state=dom.GetObject('$variableprefix$name').State($setstate)"|egrep -o '(false|true)$') 76 | 77 | if [ "true" == "$wgetreturn" ] 78 | then 79 | echo -n "1" 80 | return $RETURN_SUCCESS 81 | fi 82 | 83 | if [ "false" == "$wgetreturn" ] 84 | then 85 | echo -n "0" 86 | return $RETURN_SUCCESS 87 | fi 88 | echo -n "-1" 89 | return $RETURN_FAILURE 90 | } 91 | 92 | createPresenceVariableOnCCUIfNeeded() 93 | { 94 | local name=$1 95 | 96 | getorsetpresenceVariableState $name >/dev/null && return $RETURN_SUCCESS 97 | 98 | if [ ! -f /usr/bin/nc ] 99 | then 100 | echo "WARNING: /usr/bin/nc does not exist you need to create $variableprefix$name on CCU2 manually" 101 | return $RETURN_FAILURE 102 | fi 103 | 104 | local postbody="string v='$variableprefix$name';boolean f=true;string i;foreach(i,dom.GetObject(ID_SYSTEM_VARIABLES).EnumUsedIDs()){if(v==dom.GetObject(i).Name()){f=false;}};if(f){object s=dom.GetObject(ID_SYSTEM_VARIABLES);object n=dom.CreateObject(OT_VARDP);n.Name(v);s.Add(n.ID());n.ValueType(ivtBinary);n.ValueSubType(2);n.DPInfo(v#' is at home');n.ValueName1('anwesend');n.ValueName0('abwesend');n.State(false);dom.RTUpdate(0);}" 105 | local postlength=$(echo "$postbody" | wc -c) 106 | echo -e "POST /tclrega.exe HTTP/1.0\r\nContent-Length: $postlength\r\n\r\n$postbody" |nc "$ccu2address" 80 >/dev/null 2>&1 107 | 108 | getorsetpresenceVariableState $name >/dev/null 109 | } 110 | 111 | 112 | # 113 | # main 114 | # 115 | 116 | for name in $@ $someonename 117 | do 118 | createPresenceVariableOnCCUIfNeeded $name 119 | eval personcounter$name=$intialcounter 120 | eval ccupersonstate$name=`getorsetpresenceVariableState $name` 121 | eval samestatecounter$name=1 122 | done 123 | 124 | 125 | # 126 | # This is the main loop to check if somebody is present 127 | # 128 | while true 129 | do 130 | anygrepoutput="" 131 | arpoutput=$(arp -an |egrep -vi "$ignore"|grep 'at') 132 | 133 | for name in $@ $someonename 134 | do 135 | $debug && echo "Name: $name" 136 | 137 | if [ $name != $someonename ] 138 | then 139 | eval addresstocheck=\$$name 140 | grepoutput=$(echo "$arpoutput"|egrep -io "$addresstocheck") 141 | else 142 | grepoutput=$anygrepoutput 143 | fi 144 | 145 | 146 | if [ -n "$grepoutput" ]; 147 | then 148 | $debug && echo " Found in grepoutput" 149 | anygrepoutput=$anygrepoutput','$name 150 | newcounter=$maximumcounter 151 | newstate="1" 152 | else 153 | $debug && echo " Did not find in grepoutput" 154 | eval currentcounter=\$personcounter$name 155 | newcounter=`expr $currentcounter - 1 \| 1` 156 | newstate="0" 157 | fi 158 | 159 | $debug && echo " newcounter:$newcounter newstate:$newstate" 160 | 161 | if [ $newcounter -eq 1 -o $newcounter -eq $maximumcounter ] 162 | then 163 | eval oldstate=\$ccupersonstate$name 164 | 165 | $debug && echo " oldstate: $oldstate" 166 | 167 | if [ "$newstate" != "$oldstate" ] 168 | then 169 | $debug && echo " State differs setting on CCU immediately" 170 | 171 | eval ccupersonstate$name=`getorsetpresenceVariableState $name $newstate` 172 | eval samestatecounter$name=$maximumcounter 173 | else 174 | $debug && echo " State same, counting 2nd Variable" 175 | 176 | eval samestatecounter=\$samestatecounter$name 177 | samestatecounter=`expr $samestatecounter - 1 \| 1` 178 | 179 | $debug && echo " samestatecounter:$samestatecounter" 180 | 181 | if [ $samestatecounter -eq 1 ] 182 | then 183 | $debug && echo " setting state:$newstate on CCU" 184 | 185 | eval ccupersonstate$name=`getorsetpresenceVariableState $name $newstate` 186 | eval samestatecounter$name=$maximumcounter 187 | else 188 | eval samestatecounter$name=$samestatecounter 189 | fi 190 | fi 191 | fi 192 | eval personcounter$name=$newcounter 193 | done 194 | 195 | sleep $looptime 196 | $debug && echo ; echo; 197 | done 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /MacUserPresence.perl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | # Description: Tell Homematc CCU that Mac is beeing used (in a specefic room). It finds that out by 4 | # - are the displays active 5 | # - which displays are connected 6 | # or - which ethernet addresses are visible on Thunderbolt Ethernet 7 | # 8 | # In my case that means that I'm in the office. 9 | # Background: If connected to ethernet the Mac is in the office 10 | # 11 | # 12 | # HowTo: 1. Set the $ccunetworkaddress variable to the ip-address/name your CCU has. 13 | # 2. Set the ccupresencevariable variable to the name the variable that presents 14 | # the status of the mac on the ccu. This variable will be created if needed. 15 | # 3. If your Mac is stationary skip 3.* 16 | # 3.1 If the presence variable should be set only when a specific display is 17 | # connected or ethernet addresses are seen on the ethernet ( wlan or other 18 | # networks will be ignored ) you need to set the $ethernetneighbours and 19 | # $knowndisplays accordingly. 20 | # Find out your ethernet partners via the 'arp -an' command line 21 | # Find out your displays edids with '/usr/sbin/ioreg -r -c IODisplay' 22 | # 4. Start the script in the command line with the $debug variable to 1 to see if it 23 | # works. 24 | # 5. Add the script to your crontab with an entry like: 25 | # SHELL=/bin/zsh 26 | # */3 * * * * /usr/bin/perl /Users/jolly/Binaries/MacUserPresence.perl >/dev/null 2>&1 27 | # 28 | # 6. Create a Visual script on the CCU to run reset the named variable to off state after 29 | # 15 Minutes as the Mac can't set the varible to off when sleeping or switched off. 30 | # That script shoold look like: 31 | # Condition If... 32 | # [System State] presence.mac.officeuser when [in use] [trigger when updated] 33 | # Activity: Then... [x] stop all current delays before performing the activity (e.g. retriggering). 34 | # [System State] presence.mac.officeuser [delayed] 15 [minutes] [not in use] 35 | # 36 | # 37 | # To see what's happening you can call the script with --debug option 38 | # 39 | use strict; 40 | 41 | my $ccunetworkaddress = "hausautomation.jinx.eu"; 42 | my $ccupresencevariable = "presence.mac.officeuser"; 43 | 44 | my $ethernetneighbours = undef; # will be checked if set 45 | my $knowndisplays = undef; # will be checked if set 46 | 47 | 48 | ### 49 | # examples for ethernet neighbours. Find out what to set with 'arp -an' 50 | # 51 | #my $ethernetneighbours = "(8:96:d7:25:f8:71|a8:20:66:1:3:42|0:f:6f:3:3:bf|28:37:37:42:8b:cd|0:1a:22:4:51:9a|14:10:9f:d8:99:ff)"; # plt 52 | #my $ethernetneighbours = "(5C:F9:38:C5:98:C1|00:1A:22:04:9D:C4|3C:77:E6:61:DC:9E|00:1B:63:A2:88:F9|00:1C:B3:7A:35:BD|C8:02:10:05:D6:04|C0:25:06:77:36:31)"; # bgb 53 | # 54 | # 55 | # examples for display edids. Find out what to set with '/usr/sbin/ioreg -r -c IODisplay' 56 | #my $knowndisplays = "(00ffffffffffff0006102192d96201020e1201038040287828fe85a3574a9c2513505400000001010101010101010101010101010101bc1b00a0502017303020360081912100001ab06800a0a0402e603020360081912100001a000000ff004359383134303056584d500a00000000fc0043696e656d6120484|00ffffffffffff0006101e926c00fe020e0f010380311f782ecfb5a355499925105054000000d1000101010101010101010101010101253c80a070b0234030203600ef361100001a000000fc0043696e656d6120484420446973000000fc00706c61790a0000000000000000000000000000000000000000000)"; 57 | # 58 | 59 | 60 | # 61 | # nothing needs to be changed below this line 62 | # 63 | my $debug = grep(/^\-?\-?debug$/i,@ARGV); 64 | my $macusedinoffice = 0; 65 | 66 | CCU2::createBoolVariableIfNeeded($ccunetworkaddress,$ccupresencevariable); 67 | 68 | if( displayisactive() ) 69 | { 70 | print "Display is active.\n" if $debug; 71 | 72 | 73 | if( $ethernetneighbours && $knowndisplays ) 74 | { 75 | print "Will check for known ethernet neighbours and known displays...\n" if $debug; 76 | $macusedinoffice = knownneighboursonethernet($ethernetneighbours) && knowndisplaysareconnected($knowndisplays); 77 | print "...".($macusedinoffice?"both found":"did not find them both")."\n" if $debug; 78 | } 79 | elsif( $ethernetneighbours ) 80 | { 81 | print "Will check for known ethernet neighbours ...\n" if $debug; 82 | $macusedinoffice = knownneighboursonethernet($ethernetneighbours); 83 | print "...".($macusedinoffice?"found":"did not find")." them.\n" if $debug; 84 | } 85 | elsif( $knowndisplays ) 86 | { 87 | print "Will check if known displays are attached ...\n" if $debug; 88 | $macusedinoffice = knowndisplaysareconnected($knowndisplays); 89 | print "...".($macusedinoffice?"found":"did not find")." them.\n" if $debug; 90 | } 91 | else 92 | { 93 | $macusedinoffice = 1; 94 | } 95 | } 96 | else 97 | { 98 | print "Display not active\n" if $debug; 99 | } 100 | 101 | print "Resulting mac office user state: is ".($macusedinoffice?'':' not ')."active \n" if $debug; 102 | 103 | 104 | print "Setting variable on ccu....\n" if $debug; 105 | 106 | my $setreturn = CCU2::setVariable($ccunetworkaddress,$ccupresencevariable,$macusedinoffice); 107 | 108 | print "...done. Variable now set to: ".$setreturn."\n" if $debug; 109 | 110 | exit; 111 | 112 | 113 | 114 | sub displayisactive 115 | { 116 | my $displayisactive = `/usr/sbin/ioreg -r -c IODisplayWrangler |grep -o '"CurrentPowerState"=4'`; 117 | return length $displayisactive == 0 ? 0: 1 118 | } 119 | 120 | sub knowndisplaysareconnected 121 | { 122 | 123 | my $connecteddisplays = `/usr/sbin/ioreg -r -c IODisplay |grep 'IODisplayEDID'`; 124 | 125 | print "\tdisplays:".$connecteddisplays."\n" if $debug>1; 126 | 127 | if( $connecteddisplays =~ /$knowndisplays/ ) 128 | { 129 | print "\tFound display\n" if $debug; 130 | return 1; 131 | } 132 | return 0; 133 | } 134 | 135 | 136 | sub knownneighboursonethernet 137 | { 138 | my ($ethernetneighbours) = @_; 139 | my $arpoutput = `/usr/sbin/arp -an`; 140 | 141 | if( $arpoutput =~ /$ethernetneighbours/i ) 142 | { 143 | my $networksetupoutput = `/usr/sbin/networksetup -listnetworkserviceorder`; 144 | 145 | $networksetupoutput =~ s/^(\(\d+\).*?)\n\(/\1\(/gm; 146 | 147 | foreach my $networksetupline (split(/\n+/,$networksetupoutput)) 148 | { 149 | #print "\t".'$networksetupline='.$networksetupline."\n" if $debug; 150 | 151 | if( $networksetupline =~ /^\((\d+)\)\s*(.*?)\s*\([^\(\)]+Device:\s*(\S+\d+)\s*\)/ ) 152 | { 153 | my($order,$networkinterfacename,$devicename) = ($1,$2,$3); 154 | 155 | print "\t".'($order,$networkport,$devicename)=',$order,$networkinterfacename,$devicename."\n" if $debug>1; 156 | if( $networkinterfacename =~ /Ethernet/i ) 157 | { 158 | print "Found \t".'($order,$networkport,$devicename)='.$order.','.$networkinterfacename.','.$devicename."\n" if $debug > 1; 159 | if( $arpoutput =~ /\s$ethernetneighbours\s+on\s+$devicename\s/i ) 160 | { 161 | print "\tFound Ethernet to be correct in office: $& $devicename\n" if $debug; 162 | return 1; 163 | } 164 | } 165 | } 166 | } 167 | } 168 | return 0; 169 | } 170 | 171 | 172 | package CCU2; 173 | 174 | 175 | sub setVariable 176 | { 177 | my($ccuaddress,$variablename,$value) = @_; 178 | 179 | my $curlresult = `/usr/bin/curl -D - "http://$ccuaddress:8181/rega.exe?state=dom.GetObject('$variablename').State($value)" 2>/dev/null`; 180 | 181 | if( $curlresult =~ m#(.*)$# ) 182 | { 183 | return undef if $1 =~ /^null$/i; 184 | return 1 if $1 =~/^true$/i; 185 | return 0 if $1 =~/^false$/i; 186 | return $1; 187 | } 188 | else 189 | { 190 | print STDERR "Did not get correct result from request to ccu: $curlresult\n" 191 | } 192 | return undef 193 | } 194 | 195 | sub getVariable 196 | { 197 | my($ccuaddress,$variablename) = @_; 198 | return CCU2::setVariable($ccuaddress,$variablename); 199 | } 200 | 201 | sub createBoolVariableIfNeeded() 202 | { 203 | my($ccuaddress,$variablename) = @_; 204 | 205 | my $value = CCU2::getVariable($ccuaddress,$variablename); 206 | if( undef == $value ) 207 | { 208 | my $postbody="string v='$variablename';boolean f=true;string i;foreach(i,dom.GetObject(ID_SYSTEM_VARIABLES).EnumUsedIDs()){if(v==dom.GetObject(i).Name()){f=false;}};if(f){object s=dom.GetObject(ID_SYSTEM_VARIABLES);object n=dom.CreateObject(OT_VARDP);n.Name(v);s.Add(n.ID());n.ValueType(ivtBinary);n.ValueSubType(2);n.DPInfo(v#' is ');n.ValueName1('in use');n.ValueName0('not in use');n.State(false);dom.RTUpdate(0);}"; 209 | 210 | system('/usr/bin/curl','--data',$postbody,"http://$ccuaddress/tclrega.exe","2>/dev/nulL") || die "Cant execute curl"; 211 | return CCU2::getVariable($ccuaddress,$variablename); 212 | } 213 | return $value; 214 | } 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /ThermostatModeSwitch.hms: -------------------------------------------------------------------------------- 1 | ! https://github.com/jollyjinx/homematic/blob/master/ThermostatModeSwitch.hms 2 | ! 3 | ! Script changes all Thermostats to either auto or manual mode depending on the automode variable 4 | ! 5 | ! If in automode the script also resets the thermostats to automode after some time (resettoautomodedelay) 6 | ! 7 | ! As the Thermostats do not rember the time they have switched their mode this script uses a 8 | ! variable to store the first time the thermostat had changed mode, this variable is created if not exists. 9 | ! 10 | !----- User setable variables 11 | 12 | boolean automode = true; !.Set to true to set all Thermostats to automode, if false all thermostats 13 | !.will be set to manu mode and off. 14 | !.I actually use the state of a hardware switch to set automode like 15 | !. dom.GetObject("BidCos-RF.KEQ0768205:4.STATE").Value(); 16 | 17 | integer resettoautomodedelay = 180; !.time in minutes after which to reset the thermostats to the given mode - 0 for off 18 | string systemvariablename = "thermostat.automode.store"; !.systemvariable that stores the state when to switch thermostats back to auto 19 | !.will be created if needed 20 | boolean debug = false; !.if set, output what is done 21 | 22 | ! 23 | !------ Execution nothing needs to be changed below this line ----------- 24 | ! 25 | if(debug){WriteLine("Automode:"#automode);} 26 | object systemvariable = dom.GetObject(systemvariablename); 27 | if( !systemvariable ) 28 | { if(debug){WriteLine("Variable:"#systemvariablename#" does not exist - creating");} 29 | object systemVariables =dom.GetObject(ID_SYSTEM_VARIABLES); 30 | systemvariable=dom.CreateObject(OT_VARDP); 31 | systemvariable.Name(systemvariablename); 32 | systemVariables.Add(systemvariable.ID()); 33 | systemvariable.ValueType(ivtString); !. dokumentation says: boolean = 1; integer 2; real 3 ;time 5; 4 string; 34 | systemvariable.ValueSubType(istChar8859); 35 | systemvariable.DPInfo("stores thermostat modeswitches"); 36 | systemvariable.State(""); 37 | dom.RTUpdate(0); 38 | } 39 | 40 | integer timenow = system.Date("%F %X").ToTime().ToInteger(); if(debug){WriteLine("Timenow:"#timenow);} 41 | integer timetoswitchback = (timenow + (resettoautomodedelay*60 )); if(debug){WriteLine("timetoswitchback:"#timetoswitchback);} 42 | string timetoswitchbackstring = timetoswitchback #":"#(timetoswitchback.ToTime().ToString().StrValueByIndex(" ",1)); if(debug){WriteLine("timetoswitchbackstring:"#timetoswitchbackstring);} 43 | string systemvariablestring = systemvariable.Value(); if(debug){WriteLine("systemvariablestring:"#systemvariablestring);} 44 | string objectsandtimes = systemvariablestring.StrValueByIndex("#",1); if(debug){WriteLine("objectsandtimes:"#objectsandtimes);} 45 | string newobjectsandtimes = "automode:"#automode.ToString()#"#"; 46 | 47 | string lasttimerunstring = (systemvariablestring.StrValueByIndex("#",0)).StrValueByIndex(":",1); if(debug){WriteLine("lasttimerunstring:"#lasttimerunstring);} 48 | boolean lasttimerunmode = !automode; 49 | 50 | if( "true" == lasttimerunstring ) 51 | { 52 | lasttimerunmode = true; 53 | } 54 | else 55 | { 56 | if( "false" == lasttimerunstring ) 57 | { 58 | lasttimerunmode = false; 59 | } 60 | } if(debug){WriteLine("lasttimerunmode:"#lasttimerunmode);} 61 | 62 | if(lasttimerunmode != automode) 63 | { 64 | resettoautomodedelay = 0; 65 | } 66 | 67 | string deviceid; 68 | foreach(deviceid, dom.GetObject(ID_DEVICES).EnumUsedIDs()) 69 | { 70 | var device = dom.GetObject(deviceid); if(debug){WriteLine("Device:"#device#" (id:"#deviceid#")");} 71 | 72 | if( "HM-CC-RT-DN" == device.HssType() ) 73 | { 74 | string channelid; 75 | foreach(channelid,device.Channels().EnumUsedIDs()) 76 | { 77 | var channel = dom.GetObject(channelid); if(debug){WriteLine("\t Channel:"#channel#" (id:"#channelid#")");} 78 | 79 | if( "CLIMATECONTROL_RT_TRANSCEIVER" == channel.HssType() ) 80 | { 81 | var interface = dom.GetObject(channel.Interface()); 82 | var datapoint = interface#"."#channel.Address(); if(debug){WriteLine("\t Datapoint:"#datapoint);} 83 | integer currentstate= dom.GetObject(datapoint#".CONTROL_MODE").Value(); if(debug){WriteLine("\t State before:"#currentstate);} 84 | 85 | !.modes: 0 = auto, 1 = manu, 2 = party, 3 = boost 86 | boolean thermostatinautomode = false; 87 | if( 0==currentstate) 88 | { 89 | thermostatinautomode = true; 90 | } 91 | 92 | if( automode != thermostatinautomode ) 93 | { if(debug){WriteLine("\t Device not in suggested mode");} 94 | if( automode && (resettoautomodedelay>0) ) 95 | { 96 | boolean hasbeenfound = false; 97 | 98 | string objectandtime; 99 | foreach( objectandtime, objectsandtimes.Split(",") ) 100 | { if(debug){WriteLine("\t found in systemvariable:"#objectandtime);} 101 | if( (!hasbeenfound) && (objectandtime.Length()>0) ) 102 | { 103 | string storeddevice = objectandtime.StrValueByIndex(":",0); if(debug){WriteLine("\t storeddevice in systemvariable:"#storeddevice#"\t device:"#device);} 104 | 105 | if( device.Name() == storeddevice ) 106 | { if(debug){WriteLine("\t Device found equals one in systemvariable:"#objectandtime);} 107 | integer timechanged = objectandtime.StrValueByIndex(":",1).ToInteger(); 108 | 109 | if( timechanged < timenow ) 110 | { if(debug){WriteLine("\t Setting back to auto mode.");} 111 | dom.GetObject(datapoint#".AUTO_MODE").State(1); 112 | } 113 | else 114 | { 115 | newobjectsandtimes = newobjectsandtimes # "," # objectandtime; 116 | } 117 | hasbeenfound = true; 118 | } 119 | } 120 | } 121 | if( !hasbeenfound ) 122 | { 123 | newobjectsandtimes = newobjectsandtimes # "," # device # ":" # timetoswitchbackstring; if(debug){WriteLine("newobjectsandtimes now:"#newobjectsandtimes);} 124 | } 125 | } 126 | else 127 | { 128 | if( 0!=currentstate) 129 | { 130 | dom.GetObject(datapoint#".AUTO_MODE").State(1); if(debug){WriteLine("\t Setting to auto mode");} 131 | } 132 | 133 | if( 1!=currentstate ) 134 | { 135 | dom.GetObject(datapoint#".MANU_MODE").State(0.0); if(debug){WriteLine("\t Setting to manual mode");} 136 | } 137 | } 138 | if(debug){WriteLine("\t State after:"#dom.GetObject(datapoint#".CONTROL_MODE").Value());} 139 | } 140 | } 141 | } 142 | } 143 | } 144 | if(debug){WriteLine("newobjectsandtimes now:"#newobjectsandtimes);} 145 | if(systemvariablestring!=newobjectsandtimes) 146 | { 147 | systemvariable.State(newobjectsandtimes); 148 | } 149 | -------------------------------------------------------------------------------- /README.de.md: -------------------------------------------------------------------------------- 1 | Hallo Miteinander, 2 | 3 | ich stelle hier mal meine Homematic Steuerung vor, vielleicht interessiert es ja den ein oder anderen. 4 | 5 | 6 | Überblick 7 | ---------- 8 | 9 | Angefangen habe ich mit Homematic, da ich eine gebrauchte Gasbrennwertheizung bei mir eingebaut habe. Ein ganz einfaches Modell mit Brenner und Warmwasserspeicher. Die Gasheizung hatte nur ein einziges Thermostat für einen Führungsraum. Das ist dafür vorgesehen um einen Raum (meist das Wohnzimmer) der Heizung mitzuteilen ob sie nun heizen soll oder nicht. 10 | 11 | Da ich zu Hause arbeite, trifft das mit dem Führungsraum aber auf mich nicht zu. Tagsüber bin ich im Büro und Abends im Wohnzimmer - kein einzelner Führungsraum. Ich habe mir daraufhin das original Thermostat der Heizung genauer angesehen. Das ist einfach nur ein potentialfreies Relais. Von da an war klar, dass ich die Heizung mit einer Hausautomationsanlage steuern könnte. 12 | 13 | Ich habe mir dann eine CCU2, ein paar Thermostate und einen potentialfreien Schalter (HM-LC-Sw4-SM) gekauft um damit die Heizung zu steuern. 14 | 15 | Am Anfang waren die Solltemperaturen der Thermostate noch einfach zeitbasiert. Ich habe alleridngs auch eine Fritzbox und ein Smartphone, so dass ich darauf kam das auf anwesenheitsbasiertes Heizen umzustellen. D.h. es wird versucht über die spärlichen Informationen zu schliessen ob und wer in welchen Räumen ist. 16 | 17 | Wenn mein Handy im WLAN eingebucht ist, bin ich wohl im Haus. Wird in einem Raum ein elektrischer Schalter (Licht, Zwischenstecker,...) ein geschaltet, ist wohl jemand im dem Raum. Ist eine Person zu Hause und zeitlich meist in einem Raum (z.B. Morgens in der Küche), dann wird die Heizung entsprechend gesteuert. Sind Gäste im Haus wird das Gästezimmer wärmer gemacht und auch sonst die Temperaturen auf gästefreundliche Niveaus angehoben. 18 | 19 | Die Scripte laufen auf einer unveränderten CCU2 - sowie die Anwesenheitserkennung des WLANs auf einer Fritzbox. Alle meine Scripte finden sich unter https://github.com/jollyjinx/homematic . 20 | 21 | 22 | 23 | Anwesenheitserkennung mit WLAN ([presencedetection.sh](presencedetection.sh)) 24 | ------------------------------- 25 | 26 | Auf meiner Fritzbox läuft ein Script [presencedetection.sh](presencedetection.sh), mit dem ich die Anwesenheit von Geräten in meinem WLAN feststelle. Moderne SmartPhones versuchen ständig eine Internetverbindung aufrecht zu erhalten (z.B. für Push-Nachrichten) und sind damit dem Router immer bekannt. Das Script schaut also nur die ARP Tabelle an und pingt die Geräte nicht an, dadurch ändert sich an der Batterielaufzeit der Geräte nichts ! 27 | 28 | Bestimmte Geräte sind bestimmten Leuten zugeordnet und somit werden Variblen auf der CCU2 durch das Script gesetzt. Also z.B. presence.wlan.patrick, oder presence.wlan.guests. 29 | 30 | 31 | 32 | Anwesenheitsaggregation ([presenceVariableAggregation.hms](presenceVariableAggregation.hms)) 33 | ------------------------------- 34 | 35 | Da nicht alle Leute mit einem Gerät im WLAN einbuchen, gibt es noch manuell setzbare Variablen in der CCU2 z.B. presence.manual.guests. Diese werden mit dem script [presenceVariableAggregation.hms](presenceVariableAggregation.hms) mit den anderen Anwesenheitserkennungen zusammengefasst in die Variablen: presence.any, presence.guests, presence.patrick, usw. 36 | Es gibt noch die Möglichkeit bestimmte personen als Kinder zu definieren, die nur im Haus sind, wenn Erwachsene im Haus sind. Meine Tochter hat kein Handy und wird über eine Zeittabelle , bzw. einen virtuellen Taster als an/abwesend markiert. Durch die Aggregation ist sie nun nur anwesend, wenn auch ein Erwachsener anwesend ist. 37 | 38 | 39 | Als Beispiel sind folgende Anwesenheitsvariablen gesetzt: 40 | 41 | presence.wlan.guests: abwesend 42 | presence.wlan.patrick: ANWESEND 43 | presence.wlan.isabel: abwesend 44 | 45 | presence.manual.guests: abwesend 46 | presence.manual.patrick: abwesend 47 | presence.manual.isabel: ANWESEND 48 | 49 | presence.calender.guests: abwesend 50 | presence.calender.patrick: abwesend 51 | presence.calender.isabel: abwesend 52 | . 53 | . 54 | . 55 | 56 | daraus setzt das [presenceVariableAggregation.hms](presenceVariableAggregation.hms) script dann: 57 | 58 | presence.any: ANWESEND 59 | presence.guests: abwesend 60 | presence.patrick: ANWESEND 61 | presence.isabel: ANWESEND 62 | . 63 | . 64 | . 65 | 66 | Diese zusammengefassten Anwesenheitsvariabelen werte ich dann in weiteren Scripten aus. 67 | 68 | 69 | 70 | Anwesenheits Thermostatsteuerung ([PresenceTriggersTemperature.hms](PresenceTriggersTemperature.hms)) 71 | ------------------------------- 72 | 73 | Die ganze Anwesenheitserkennung mache ich nur, damit ich die Solltemperaturen der Thermostate einstellen kann. So hängt die Solltemperatur der Räume von den Leuten ab die im Haus sind und deren Vorlieben, das habe ich einer Tabelle aus dem Script eingefügt: 74 | 75 | presence.guests: hall 0:00,17C 6:00,18.5C 7:30,19.5C 19:30,20C 76 | living 0:00,17C 7:30,19C 19:30,20C 77 | kitchen 0:00,17C 6:00,18.5C 7:30,20C 20:30,17C 78 | guests 0:00,17C 8:00:16C 21:00,17.5C 79 | 80 | presence.patrick: hall 0:00,16C 7:30:18C 20:30,19C 81 | living 0:00,16C 7:30:17C 20:30,18C 82 | kitchen 0:00,16C 7:30,18C 20:30,17C 83 | office 0:00,16C 7:30,19.5C 19:30,16.5C 84 | sleeping 0:00,15C 8:00,10C 22:00,16C 85 | 86 | 87 | Das Script [PresenceTriggersTemperature.hms](PresenceTriggersTemperature.hms) wertet diese Tabelle aus, überprüft die Anwesenheit der Personen im Haus und deren Temperaturwerte für die jeweiligen Räume. Es wertet aus ob ein Fenster oder eine Tür im Raum geöffnet ist oder ob Heizungsrelevante Schalter im Raum aktiv sind. So geht das Script davon aus, dass wenn Licht im Raum brennt, wohl auch jemand anwesend ist. 88 | 89 | Falls in einem Raum keine Fenster/Tür sensoren sind, wird eine Fenster-offen Erkennung des Thermostats berücksichtigt. D.h. wenn das Thermostat ein offenes Fenster durch einen Temperatursturz erkennt überschreibt das Script die Fenster-offen-temperatur nicht. Allerdings muss dafür die Fenster-offen-temperatur des Thermostats mit der im Fenster-offen-temperatur variable im Script (openwindowtemp) übereinstimmen. 90 | 91 | Das Script setzt dann die Solltemperatur falls die aktuelle Solltemperatur nicht der berechneten übereinstimmt und das Thermostat im Automatikmodus läuft. Man kann also durch Umstellen auf manuellen Thermostatmodus auch die Temperatur manuell verändern. 92 | 93 | Ergänzt habe ich die Möglichkeit der Termostate automatisch in den AUTO vom MANU Modus nach einer festgelegten Zeit zurückzuspringen. Man kann also mal für ein paar Stunden die Temperatur manuell verändern und danach läuft alles wie gewohnt. 94 | Die Temperaturtabelle habe ich um die Möglichkeit ergänzt Komfort Temperaturen für Räume und Zeiten mit anzugeben, ganz so wie bei Benutzern. Damit kann man also durch Licht einschalten je nach Raum und Zeit eine andere Komforttemperatur einstellen. 95 | 96 | Es gibt nun auch die Möglichkeit die Thermostate bis zur nächsten Umstellung - sei es durch die Zeittabelle der verschiedenen Personen oder Fensteröffnen oder Schalter betätigen - nicht zu verstellen. 97 | Allerdings muss man dann alle AUTO Schaltzeiten der Thermostate selbst auch in die Tabelle aufnehmen, weswegen ich diesen Teil optional gemacht habe. 98 | 99 | 100 | 101 | Heizungssteuerung Hauptschalter ([TurnHeatingOn.hms](TurnHeatingOn.hms)) 102 | ------------------------------- 103 | 104 | Angefangen habe ich mit Homematic, da ich eine gebrauchte Gasbrennwertheizung bei mir eingebaut habe. Ein ganz einfaches Modell mit Brenner und Boiler. Die Gasheizung hat natürlich keinen HomeMatic Anschluss ;-( und noch schlimmer die Gasheizung hat nur ein einziges Führungstermostat. Das ist dafür vorgesehen um einen Raum (meist das Wohnzimmer) der Heizung mitzuteilen ob sie nun heizen soll oder nicht. 105 | 106 | Da ich zu Hause arbeite, trifft das mit dem Führungsraum aber auf mich nicht zu. Tagsüber bin ich im Büro und Abends im Wohnzimmer - kein einzelner Führungsraum. Deshalb habe ich mir das original Thermostat der Heizung genauer angesehen. Das ist einfach nur ein potentialfreies Relais. Da wusste ich schon mal, dass ich mit einem HM-LC-Sw4-SM das Thermostat des Führungraums ersetzen kann. 107 | 108 | An die Heizköper habe ich die normalen HM-CC-RT-DN Thermostate angeschraubt. Mit einem einfachen Script [TurnHeatingOn.hms](TurnHeatingOn.hms) schalte ich nun seit letzten März die Heizung entsprechend ein oder aus. Die Heizung erkennt selbtständig an Vor- und Rücklauf und wieviel der Brenner brennen muss, da habe ich nichts geändert. Ich übernehme mit dem Script nur die Simulation des Führungsthermostaten. Das Script wertet die Soll/Ist Temperaturen sowie die Ventilstellung der HM-CC-RT-DN Thermostate aus um die Heizung ein oder auszustellen. 109 | 110 | 111 | 112 | Heizungssteuerung Warmwasserspeicher ([TurnBoilerOnAfterVacation.hms](TurnBoilerOnAfterVacation.hms)) 113 | ------------------------------- 114 | 115 | Ich habe mir dann auch noch den Warmwasserspeicher der Heizung angesehen. Die Heizung erkennt die Warmwassertemperatur über einen Heissleiter. Ich habe dann mal ausprobiert ob ein einfaches überbrücken des Widerstandes ausreicht der Heizung klar zu machen dass der Boiler heiss ist, aber da meldet die Heizung (korrekterweise) dass der Widerstand defekt sei. 116 | 117 | Zufälligerweise lagen der Heizung noch ein paar Widerstände bei, mit denen ich (parallel zum Heisswiderstand geschaltet) der Heizung eine rund 20 Grad höhere Temperatur vorgaukeln kann. Ich habe dann das zweite potentialfreie Relais vom HM-LC-Sw4-SM daran angeschlossen und kann damit den Boiler nun an und ausstellen. 118 | 119 | Da ich, um den Warmwasserspeicher auszustellen der Heizung eine 20 Grad höhere Temperatur im Warmwasserspeicher vorgaukle, ist klar, dass ich den Frostschutz der Heizung damit ausheble und die Heizung evtl. Frost nicht erkennen könnte. Da es bei mir im Reihenhauskeller nicht fröstelt, habe ich damit kein Problem. 120 | 121 | Wenn jemand zu Hause ist, wird der Warmwasserspeicher einmal am Tag um 6:15 Uhr angeschaltet. Wenn ich also übers Wochenende nicht da bin, wird der Warmwasserspeicher auch nicht erhitzt. 122 | 123 | Der Warmwasserspeicher wird über ein weiteres Script immer nach einer halben Stunde ausgeschaltet. So kann man den Warmwasserspeicher auch mal zwischendurch manuell anschalten und er schaltet automatisch nach einer halben Stunde aus. Für Gaeste gibt es noch einen Schalter (HM-Sec-SCo:Funk- Tuer-/Fensterkontakt) an der Dusche, der den Boiler automatisch anschaltet sobald Gäste im Haus sind und geduscht wird (damit ist für den nächsten Duschenden auch warmes Wasser bereit). Und zu guter letzt, da ich gerne, wenn ich nach einem Urlaub nach Hause komme, Dusche, habe ich noch ein kleines Script laufen, welches den Boiler einschaltet wenn ich nach einem Urlaub nach Hause komme. [TurnBoilerOnAfterVacation.hms](TurnBoilerOnAfterVacation.hms) 124 | 125 | 126 | --- 127 | Hoffe es gibt Euch Anregungen. Falls Ihr Sachen verbessert, könnt Ihr einfach einen Pull Request auf GitHub machen. 128 | -------------------------------------------------------------------------------- /PresenceTriggersTemperature.hms: -------------------------------------------------------------------------------- 1 | !https://github.com/jollyjinx/homematic/blob/master/PresenceTriggersTemperature.hms 2 | ! 3 | ! This script changes the SET_TEMPERATURE of thermostats depending if a person is present 4 | ! in a room. 5 | ! If there are persons present in the house hand have a location/time/temperature table 6 | ! It uses the function/Gewerk 'Heating' to find out switched in that room to deduce presence of someone 7 | ! If there are openings in the 'Heating' function/Gewerk so not to heat 8 | !. 9 | 10 | real miniumroomtemp = 14.0; 11 | real openwindowtemp = 5.0; !. needs to be the same as set on the device. That way this script 12 | !. can recgonize when the thermostat itself recognises a open window 13 | !. even though no windowsensors are present. 14 | 15 | string heatingfunctionname = "Heating"; !. name of the function/"Gewerk" heating objects are put in 16 | !. open doors and windows in a room will switch heating off 17 | !. light,plugs and other switches in a room will signal present persons 18 | !. and will change to comfort temperature if lower 19 | 20 | boolean letuserschangeinbetween = false; !. If the set temperature changes due to user interaction or other 21 | !. programming, it will be set the thermostat temperature only when 22 | !. switches/doors or the temperature table will change. 23 | 24 | integer resetfrommanumodeafter = 3*3600; !. resets manual mode thermostats after n-seconds. 0 means keep in manual mode 25 | 26 | string comfortname = "comforttemperatures"; !. name of the temperature table person that should act as default comfort temperature 27 | string defaultroomname = "anyroom"; !. name of a default room for the person 28 | string systemvariablename = "thermostatrun"; !. name of a system variable (string type) used to store the last used thermostat 29 | !. set temperature. if set to "" it's not used . If the variable does not exist 30 | !. it is created. 31 | integer howoftendowerun = 5*60; !. How often this script runs automatically in seconds 32 | boolean debug = false; !. debugging of script - if set no changes will be made 33 | 34 | 35 | string temperaturetable = " 36 | 37 | comforttemperatures: anyroom 0:00,19C 38 | Wohnzimmer 8:00,18.5C 16:00,19.0C 22:00,18C 39 | Büro 0:00,20C 40 | 41 | presence.any: Flur 0:00,16C 7:30,17C 19:30,18C 22:00,17C 42 | Wohnzimmer 0:00,16C 7:30,17C 20:00,18C 22:00,17C 43 | Küche 0:00,16C 7:30,17C 20:00,17C 44 | Wohnzimmer 0:00,16C 45 | 46 | presence.dayguests: Flur 6:00,18.0C 7:30,19.5C 11:30,20C 22:30,17C 47 | Wohnzimmer 7:30,19C 11:30,20C 22:30,17C 48 | Küche 6:00,18.0C 7:30,20C 21:30,17C 49 | 50 | presence.nightguests: Flur 6:00,18.0C 7:30,19.5C 15:00,20C 22:30,17C 51 | Wohnzimmer 7:30,19C 19:30,20C 22:30,17C 52 | Küche 6:00,18.0C 7:30,20.5C 21:30,17C 53 | Gästezimmer 0:00,17C 9:00,16C 19:00,17C 21:00,19.0C 54 | 55 | presence.patrick: Schlafzimmer 0:00,18C 56 | 57 | presence.isabel: Flur 7:00,18.5C 7:00,19.5C 20:00,17C 58 | Wohnzimmer 7:00,18.5C 20:00,17C 59 | Küche 7:00,20.5C 20:00,17C 60 | Isabel 7:00,20.5C 20:30,17.5C 61 | 62 | presence.officeuser: Büro 0:00,20C 63 | 64 | "; 65 | 66 | !. 67 | !. Temperature table format: [presencevariablename]:\s+(\s*[roomname]\s+(HH?:MM,\d+(.\d)?C)+\n)+ 68 | !. 69 | !. Isabel and officeuser are defined as kids. Those persons, that are depending on the presence of a real 70 | !. person are called kids in the presenceaggregation script, even though I use it for a my daughter and my officeuser. 71 | !. When I'm at home and my office computer has a lit screen, then my office is 72 | !. getting warm. 73 | !. This can also be used for shift workers to have three depending users that have 74 | !. differrent work times an those are present depending on a calender and the presence 75 | !. of the real user. 76 | 77 | !--- no user setable parts below this point 78 | !. 79 | string currentyearmonthday = system.Date("%F "); 80 | integer timenow = (currentyearmonthday#system.Date("%X")).ToTime().ToInteger(); 81 | integer timedaystart = (currentyearmonthday#"00:00:00").ToTime().ToInteger(); 82 | integer secondsthisday = timenow-timedaystart; 83 | integer lasttimerun = timenow-howoftendowerun; 84 | 85 | !. 86 | !. In case you have the system variable 87 | object systemvariable = dom.GetObject(systemvariablename); 88 | 89 | if( (systemvariablename.Length()>0) && (!systemvariable) ) 90 | { if(debug){WriteLine("Variable:"#systemvariablename#" does not exist - creating");} 91 | object systemVariables =dom.GetObject(ID_SYSTEM_VARIABLES); 92 | systemvariable=dom.CreateObject(OT_VARDP); 93 | systemvariable.Name(systemvariablename); 94 | systemVariables.Add(systemvariable.ID()); 95 | systemvariable.ValueType(ivtString); !. dokumentation says: boolean = 1; integer 2; real 3 ;time 5; 4 string; 96 | systemvariable.ValueSubType(istChar8859); 97 | systemvariable.DPInfo("current thermostat settings"); 98 | systemvariable.State(""); 99 | dom.RTUpdate(0); 100 | } 101 | 102 | string oldsystemvariablestring = ""; 103 | string newsystemvariablestring = ""; 104 | 105 | if( systemvariable ) 106 | { 107 | string laststring = systemvariable.Variable().ToString(); 108 | integer offset = laststring.Find("#"); 109 | 110 | if( -1 != offset ) 111 | { 112 | lasttimerun = laststring.StrValueByIndex("#",0).ToTime().ToInteger(); 113 | oldsystemvariablestring = laststring.Substr(offset+1,laststring.Length()-(offset+1)); 114 | } 115 | } 116 | if(debug){WriteLine("timenow:"#timenow#"\t secondsthisday:"#secondsthisday#"\tlasttimerun"#lasttimerun.ToTime());} 117 | 118 | string ascii_space = " "; 119 | string ascii_tabular = "\t"; 120 | string ascii_newline = "\n"; 121 | string ascii_return = "\r"; 122 | string table_delimiter = "#"; 123 | string roomtabledelimiter = ascii_newline; 124 | !. 125 | !. create a tabulator seperated temperaturetable 126 | !. 127 | 128 | 129 | if(true) 130 | { 131 | string substring; 132 | string temporarytemperaturetable1; 133 | string temporarytemperaturetable2; 134 | 135 | foreach(substring, temperaturetable.Split(ascii_space) ) 136 | { 137 | if( substring.Length() >0 ) { temporarytemperaturetable1 = temporarytemperaturetable1 # table_delimiter # substring; } 138 | } 139 | foreach(substring, temporarytemperaturetable1.Split(ascii_return) ) 140 | { 141 | if( substring.Length() >0 ) { temporarytemperaturetable2 = temporarytemperaturetable2 # table_delimiter # substring; } 142 | } 143 | temperaturetable = ""; 144 | 145 | foreach(substring, temporarytemperaturetable2 ) 146 | { 147 | if( substring.Length() >0 ) { temperaturetable = temperaturetable # table_delimiter # substring; } 148 | } 149 | temperaturetable = temperaturetable # ascii_newline; 150 | 151 | if(debug) {WriteLine("temperaturetable:"#temperaturetable);} 152 | } 153 | 154 | 155 | 156 | 157 | !. 158 | !. go through every person that is present and add figure out hte room preferences 159 | !. 160 | 161 | string roomtemperatures; 162 | 163 | if(true) 164 | { 165 | string currentperson; 166 | boolean personispresent; 167 | integer personchangedtime; 168 | 169 | string comforttemperatures; 170 | string temperaturetableline; 171 | 172 | foreach( temperaturetableline, temperaturetable.Split(ascii_newline) ) 173 | { !. if(debug){WriteLine("Line:"#temperaturetableline);} 174 | string currentroom; 175 | integer currentchangetime; 176 | string currentchangetemp; 177 | 178 | string temperaturetablepart; 179 | 180 | foreach(temperaturetablepart,temperaturetableline.Split(table_delimiter)) 181 | { 182 | integer partlength = temperaturetablepart.Length(); 183 | 184 | if( partlength > 0 ) 185 | { !. if(debug){WriteLine("\nPart:"#temperaturetablepart#" length:"#partlength);} 186 | integer colonposition = temperaturetablepart.Find(":"); 187 | 188 | if( -1 == colonposition ) 189 | { 190 | currentroom = temperaturetablepart; if(debug){WriteLine("\tcurrentroom:"#temperaturetablepart);} 191 | currentchangetime = -1; 192 | currentchangetemp = "-1"; 193 | } 194 | else 195 | { 196 | if( colonposition == (partlength-1) ) 197 | { 198 | currentperson = temperaturetablepart.Substr(0,partlength-1); if(debug){WriteLine("\nPerson:"#currentperson);} 199 | 200 | object personvariable = dom.GetObject(currentperson); 201 | 202 | if( personvariable ) 203 | { 204 | personispresent = personvariable.Value(); 205 | boolean personwaspresent = personvariable.LastValue(); 206 | 207 | if( personispresent != personwaspresent ) 208 | { 209 | personchangedtime = personvariable.Timestamp().ToInteger(); 210 | } 211 | else 212 | { 213 | personchangedtime = timedaystart-86400; 214 | } if(debug){WriteLine("\tpresence:"#personispresent#" since:"#personchangedtime.ToTime()#" waspresent:"#personwaspresent);} 215 | } 216 | } 217 | else 218 | { 219 | integer timeseconds = (currentyearmonthday#temperaturetablepart.StrValueByIndex(",",0)#":00").ToTime().ToInteger(); 220 | string temperature = temperaturetablepart.StrValueByIndex(",",1); 221 | 222 | if( timeseconds > timenow ) 223 | { 224 | timeseconds = timeseconds - 86400; 225 | } !.if(debug){WriteLine(" timeseconds:"#timeseconds#" temperature:"#temperature);} 226 | !.if(debug){WriteLine("\troom:"#currentroom#","#currentchangetime.ToTime()#","#currentchangetemp);} 227 | if( -1 == currentchangetime ) 228 | { 229 | currentchangetime = timeseconds; 230 | currentchangetemp = temperature; 231 | } 232 | else 233 | { !.if(debug){WriteLine("\troom:"#currentroom#","#currentchangetime.ToTime()#","#currentchangetemp);} 234 | if( timeseconds > currentchangetime ) 235 | { 236 | currentchangetime = timeseconds; 237 | currentchangetemp = temperature; 238 | } 239 | } !.if(debug){WriteLine("\troom:"#currentroom#","#currentchangetime.ToTime()#","#currentchangetemp);} 240 | } 241 | } 242 | } 243 | } 244 | 245 | if( currentroom.Length() > 0) 246 | { if(debug){WriteLine("\tFinal:"#currentroom#","#currentchangetime.ToTime()#","#currentchangetemp);} 247 | if( comfortname == currentperson ) 248 | { 249 | comforttemperatures = comforttemperatures#roomtabledelimiter#currentroom#","#currentchangetime.ToTime()#","#currentchangetemp#","#comfortname; 250 | } 251 | else 252 | { 253 | if( !personispresent ) 254 | { 255 | currentchangetemp = miniumroomtemp; 256 | } 257 | if( personchangedtime > currentchangetime ) 258 | { 259 | currentchangetime = personchangedtime; 260 | } 261 | roomtemperatures = roomtemperatures#roomtabledelimiter#currentroom#","#currentchangetime.ToTime()#","#currentchangetemp#","#currentperson; 262 | } 263 | } 264 | } 265 | roomtemperatures = roomtemperatures # comforttemperatures; 266 | if(debug){WriteLine("\nRoomtemperatures:"#roomtemperatures);} 267 | } 268 | 269 | 270 | string roomid; 271 | foreach( roomid, dom.GetObject(ID_ROOMS).EnumUsedIDs() ) 272 | { 273 | object room = dom.GetObject(roomid); if(debug){WriteLine("\n\nroom:"#room);} 274 | boolean windowordoorsensorpresent = false; 275 | boolean openwindowordoor = false; 276 | boolean somebodyispresent = false; 277 | integer somebodychangedtime = -1; 278 | string thermostatdevices; 279 | string channelid; 280 | 281 | foreach(channelid,dom.GetObject(room).EnumUsedIDs()) 282 | { !.if(debug){WriteLine("\t channelid:"#channelid);} 283 | object channel = dom.GetObject(channelid); if(debug){WriteLine("\t channel:"#channel);} 284 | string functionid; 285 | 286 | foreach(functionid,channel.ChnFunction()) 287 | { if(debug){WriteLine("\t functionid:"#functionid); } 288 | string functionname = dom.GetObject(functionid); if(debug){WriteLine("\t functionname:"#functionname); } 289 | 290 | if( heatingfunctionname == functionname ) 291 | { 292 | object device = dom.GetObject(channel.Device()); if(debug){WriteLine("\t device:"#device);} 293 | string devicehssid = device.HssType(); if(debug){WriteLine("\t devicehssid:"#devicehssid);} 294 | 295 | if( "HM-CC-RT-DN" == devicehssid ) 296 | { 297 | var interface=dom.GetObject(channel.Interface()); 298 | thermostatdevices = thermostatdevices # "\t" # interface # "." # channel.Address(); 299 | } 300 | else 301 | { 302 | if( !openwindowordoor ) 303 | { 304 | string datapointid; 305 | foreach(datapointid,channel.DPs().EnumUsedIDs()) 306 | { 307 | var datapoint = dom.GetObject(datapointid); 308 | 309 | if(OPERATION_READ & datapoint.Operations()) 310 | { 311 | string dpname = datapoint.Name(); 312 | 313 | if( (-1 != dpname.Find(".STATE")) || ( "HM-RCV-50" == devicehssid ) ) 314 | { if(debug){WriteLine("\t Datapoint:"#dpname);} 315 | if( 0 == devicehssid.Find("HM-Sec-") ) 316 | { if(debug){WriteLine("\t WindowOrDoor: state:"#datapoint.Value());} 317 | windowordoorsensorpresent = true; 318 | 319 | if( datapoint.Value() ) 320 | { 321 | openwindowordoor = true; 322 | } 323 | } 324 | else 325 | { 326 | if( datapoint.Value() ) 327 | { if(debug){WriteLine("\t Somebody is present in room:"#datapoint.Value());} 328 | somebodyispresent = true; 329 | } 330 | } 331 | integer lastactiontime = channel.LastDPActionTime().ToInteger(); if(debug){WriteLine("\t lastactiontime:"#lastactiontime.ToTime());} 332 | if( somebodychangedtime < lastactiontime ) 333 | { 334 | somebodychangedtime = lastactiontime; 335 | } 336 | } 337 | } 338 | } 339 | } 340 | } if(debug){WriteLine("");} 341 | } 342 | } 343 | } 344 | 345 | if(debug){ WriteLine("\tThermostats:"#thermostatdevices#"\tSomebodyispresent in room:"#somebodyispresent#" since:"#somebodychangedtime.ToTime()#"\twindow or door open:"#openwindowordoor);} 346 | 347 | if( thermostatdevices.Length() ) 348 | { 349 | real newtemp = miniumroomtemp; 350 | integer newtime = -1; 351 | 352 | if( openwindowordoor ) 353 | { 354 | newtemp = openwindowtemp; 355 | newtime = timenow; 356 | } 357 | else 358 | { 359 | string roomtemperatureset; 360 | foreach(roomtemperatureset,roomtemperatures.Split(roomtabledelimiter) ) 361 | { 362 | if( roomtemperatureset.Length() > 0 ) 363 | { !.if(debug){WriteLine("\t testing room:"#roomtemperatureset);} 364 | string roomnameset = roomtemperatureset.StrValueByIndex(",",0).ToString(); 365 | 366 | if( (roomnameset == room) || (roomnameset==defaultroomname) ) 367 | { !.if(debug){WriteLine("\t found room:"#roomtemperatureset);} 368 | integer newtemptime; 369 | real newtempset; 370 | string newtempperson = roomtemperatureset.StrValueByIndex(",",3).ToString(); 371 | 372 | if(newtempperson == comfortname) 373 | { 374 | if( !somebodyispresent ) 375 | { 376 | newtempset = miniumroomtemp; 377 | } 378 | else 379 | { 380 | newtempset = roomtemperatureset.StrValueByIndex(",",2).ToFloat(); 381 | } 382 | newtemptime = somebodychangedtime; 383 | } 384 | else 385 | { 386 | newtemptime = roomtemperatureset.StrValueByIndex(",",1).ToTime().ToInteger(); 387 | newtempset = roomtemperatureset.StrValueByIndex(",",2).ToFloat(); 388 | } 389 | if( newtempset > newtemp) 390 | { 391 | newtemp = newtempset; 392 | } 393 | if( newtemptime > newtime) 394 | { 395 | newtime = newtemptime; 396 | } if(debug){WriteLine("\t newtemp:"#newtemp#"\tTime:"#newtime.ToTime()#"\tperson:"#newtempperson);} 397 | } 398 | } 399 | } 400 | } !.if(debug){WriteLine("\n"#room#"\n\t newtemp:"#newtemp#"\tnewtime:"#newtime.ToTime());} 401 | 402 | 403 | if( (!letuserschangeinbetween) 404 | || (newtime > (lasttimerun-howoftendowerun)) ) 405 | { if(debug){WriteLine("WILL SET as it has changed. lastchange:"#newtime.ToTime()#" lasttime:"#lasttimerun.ToTime());}; 406 | newsystemvariablestring = newsystemvariablestring #room #":"# newtemp # ","; 407 | 408 | string thermostatchanneladdress; 409 | foreach(thermostatchanneladdress,thermostatdevices) 410 | { 411 | if( thermostatchanneladdress.Length() ) 412 | { if(debug){WriteLine("\t thermostatchanneladdress: "#thermostatchanneladdress);} 413 | object thermostatchannel = dom.GetObject(thermostatchanneladdress#".CONTROL_MODE"); 414 | integer currentmode = dom.GetObject(thermostatchannel).Value(); if(debug){WriteLine("\t Current mode: "#currentmode);} 415 | !.modes: 0 = auto, 1 = manu, 2 = party, 3 = boost 416 | if( 1 == currentmode ) 417 | { 418 | string thermostatdeviceid = thermostatchannel.Device(); 419 | integer thermostattimechanged = dom.GetObject(thermostatdeviceid).LastDPActionTime().ToInteger(); if(debug){WriteLine("\t manu mode:thermostattimechanged: "#thermostattimechanged.ToTime());} 420 | 421 | if( thermostattimechanged < (timenow-resetfrommanumodeafter) ) 422 | { if(debug){WriteLine("\t Would change Mode to Automatic");} 423 | if(!debug) { dom.GetObject(thermostatchanneladdress#".AUTO_MODE").State(1);} 424 | currentmode = 0; 425 | } 426 | } 427 | if( 0 == currentmode ) 428 | { 429 | real termostattempcurrent = dom.GetObject(thermostatchanneladdress#".SET_TEMPERATURE").Value(); if(debug){WriteLine("\t settemp: "#termostattempcurrent);} 430 | 431 | if( (!windowordoorsensorpresent) && (termostattempcurrent == openwindowtemp) ) 432 | { 433 | if(debug){WriteLine("\t no window or door present, but thermostat is set to openwindowtemp. Ignoring set temperature");} 434 | } 435 | else 436 | { 437 | if( newtemp != termostattempcurrent ) 438 | { if(debug){WriteLine("Would change Temperature to: "#newtemp);} 439 | if(!debug) { dom.GetObject(thermostatchanneladdress#".SET_TEMPERATURE").State(newtemp);} 440 | } 441 | } 442 | } 443 | } 444 | } 445 | } 446 | else 447 | { 448 | if(debug){WriteLine("NOTHING TO set as it has not changed. lastchange:"#newtime.ToTime()#" lasttime:"#lasttimerun.ToTime());}; 449 | } 450 | } 451 | } 452 | 453 | 454 | if( systemvariable && (oldsystemvariablestring != newsystemvariablestring) ) 455 | { if(debug){WriteLine("systemvariable changed\nfrom:\t" # oldsystemvariablestring # "\nto:\t:" # newsystemvariablestring);} 456 | if(!debug){systemvariable.State(system.Date("%F %X") #"#"# newsystemvariablestring);} 457 | } 458 | 459 | --------------------------------------------------------------------------------