Announcement

Collapse
No announcement yet.

[C#] Occupancy based multizone HVAC control

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    [C#] Occupancy based multizone HVAC control

    Hello,

    I didn't quite want to spend $30+ on any of the plugins because none of them really seemed impressive, and I thought I could get the basic functionality myself along with a feature none of them provided. Below is a simple C# script I wrote that will take the value of several counters that expect a value of 0 or 1 which act as switches and performs some logic based on the occupancy status of the building or the floor.

    My Condo has 3 stories and is controlled by 2 zone HVAC, and my electricity is tiered, so any use between 3-8pm is really expensive. I found myself wondering how much it was costing me to keep my living room at 80 degrees while I'm spending all day in my Office, and the Nest units I had frequently would be cooling my house down while I was out of town because the presence detection was broken with some update.

    My Goal with this script is to combine my requirements of detecting if I'm home or not and setting the "Away" temperature, but also increasing the thermostat set points a few degrees up when no-one is in a particular zone.
    All of the lifting for managing the scheduling, and changing devices is done by the HomeSeer engine to keep the script simple, so adding more rooms, floors, and schedule triggers is as easy as copy/paste.

    I'll detail some examples of the room triggers and schedule triggers in the next post, but I'd imagine the test points could be re-worked to validate against device strings. I hate any GPS or 3rd party cloud services often used for arrival, so I'm working with motion detectors and Z-wave thermostats (alarm.com t2000 /Building36 T10)

    I Updated this to support a phone Ping status and deal with a roommate occupying the guest room so there could be a separate schedule.

    Code:
    using System;
    
    public object Main(object[] Parms) {
    
        //Temp Schedule
        Double thermostatMorning = hs.CounterValue("ThermostatMorning");
        Double thermostatDay = hs.CounterValue("ThermostatDay");
        Double thermostatEvening = hs.CounterValue("ThermostatEvening");
        Double thermostatNight = hs.CounterValue("ThermostatNight");
        Double thermostatPeakDay = hs.CounterValue("ThermostatPeakDay");
        Double Scene1HourChillDown = hs.CounterValue("Scene1HourChillDown");
        Double SceneGuestPresence = hs.CounterValue("SceneGuestPresence");
    
        //Room Occupancy
        Double occupancyF1Hallway = hs.CounterValue("OccupancyF1Hallway");
        Double occupancyF1Garage = hs.CounterValue("OccupancyF1Garage");
        Double occupancyF1GuestRoom = hs.CounterValue("OccupancyF1GuestRoom");
        Double occupancyF2Atrium = hs.CounterValue("OccupancyF2Atrium");
        Double occupancyF3MasterRoom = hs.CounterValue("OccupancyF3MasterRoom");
        Double occupancyF3LeftRoom = hs.CounterValue("OccupancyF3LeftRoom");
        Double occupancyF3RightRoom = hs.CounterValue("OccupancyF3RightRoom");
        Double occupancyPingable = hs.CounterValue("OccupancyPing");
    
        //Floor Occupancy
        Boolean occupancyG = false;
        Boolean occupancyF1 = false;
        Boolean occupancyF2 = false;
        Boolean occupancyF3 = false;
    
        //hs.WriteLog("HVAC Script Debug", "occupancyF1Hallway " + occupancyF1Hallway);
        //hs.WriteLog("HVAC Script Debug", "occupancyF1Garage " + occupancyF1Garage);
        //hs.WriteLog("HVAC Script Debug", "occupancyF1GuestRoom " + occupancyF1GuestRoom);
        if ( occupancyF1GuestRoom == 1 ) {
            occupancyG = true;
        } else {
            occupancyG = false;
        }
    
        if ( occupancyF1Hallway == 1 || occupancyF1Garage == 1 ) {
            occupancyF1 = true;
        } else {
            occupancyF1 = false;
        }
        //hs.WriteLog("HVAC Script Debug", "occupancyF1 " + occupancyF1);
    
        //hs.WriteLog("HVAC Script Debug", "occupancyF2Atrium " + occupancyF2Atrium);
        if ( occupancyF2Atrium == 1 ) {
            occupancyF2 = true;
        } else {
            occupancyF2 = false;
        }
        //hs.WriteLog("HVAC Script Debug", "occupancyF2 " + occupancyF2);
    
    
        //hs.WriteLog("HVAC Script Debug", "occupancyF3MasterRoom " + occupancyF3MasterRoom);
        //hs.WriteLog("HVAC Script Debug", "occupancyF3LeftBedroom " + occupancyF3LeftRoom);
        //hs.WriteLog("HVAC Script Debug", "occupancyF3RightBedroom " + occupancyF3RightRoom);
        if ( occupancyF3MasterRoom == 1 || occupancyF3LeftRoom == 1 || occupancyF3RightRoom == 1 ) {
            occupancyF3 = true;
        } else {
            occupancyF3 = false;
        }
        //hs.WriteLog("HVAC Script Debug", "occupancyF3 " + occupancyF3);
    
    
        //PingOccupancy
        Boolean occupancyPing = false;
        //hs.WriteLog("HVAC Script Debug", "occupancyPingable " + occupancyPingable);
        if ( occupancyPingable == 1 ) {
            occupancyPing = true;
        } else {
            occupancyPing = false;
        }
        //hs.WriteLog("HVAC Script Debug", "occupancyPing " + occupancyPing);
    
        //Building Occupancy    
        Boolean occupancyBuilding = false;
        if ( occupancyF1 || occupancyF2 || occupancyF3 || occupancyPing) {
            occupancyBuilding = true;
        } else if ( !occupancyF1 && !occupancyF2 && !occupancyF3 && !occupancyPing ) {
            occupancyBuilding = false;
        }
        //hs.WriteLog("HVAC Script Debug", "occupancyBuilding " + occupancyBuilding);
    
        //Away Schedule
        if ( !occupancyBuilding && !occupancyG) {
            hs.WriteLog("HVAC Script", "Trigger Away Temperature");
            hs.TriggerEvent("Thermostat Control AwayTemperature");
            return 0;
        }
    
        if ( Scene1HourChillDown == 1 ) {
            hs.WriteLog("HVAC Script", "Trigger Chill Down Temperature");
            hs.TriggerEvent("Thermostat Control ChillDownTemperature");
            return 0;
        }
    
        //PeakStagger
        //String s = hs.DeviceString(155);
        //hs.WriteLog("HVAC Script", "Atrium thermostat value is " + s);
        //String p = hs.DeviceString(327);
        //hs.WriteLog("HVAC Script", "Hallway thermostat value is " + p);
    
    //Floor 3 Schedule
        if ( occupancyF3 && occupancyBuilding ) {
            if ( SceneGuestPresence == 1 ) {
                hs.WriteLog("HVAC Script", "Trigger Guest Presence Temperature");
                hs.TriggerEvent("Thermostat Control F3-NightTemperature");
            } else {
                if ( thermostatPeakDay == 1 ) {
                    if ( occupancyG ) {
                        hs.WriteLog("HVAC Script", "Trigger Guest Peak Stagger Off");
                        hs.TriggerEvent("Thermostat Control F1_2-PeakDayStagger_Off");
                    } else {
                        hs.WriteLog("HVAC Script", "Trigger Guest Peak Stagger On");
                        hs.TriggerEvent("Thermostat Control F1_2-PeakDayStagger_On");
                    }
                } else {
                    hs.WriteLog("HVAC Script", "Trigger Guest Peak Stagger Off");
                    hs.TriggerEvent("Thermostat Control F1_2-PeakDayStagger_On");
                }
                //hs.WriteLog("HVAC Script Debug", "F3 occupied, Building occupied");
                if ( thermostatMorning == 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F3 Morning Temperature");
                    hs.TriggerEvent("Thermostat Control F3-MorningTemperature");
                } else if ( thermostatDay == 1 && thermostatPeakDay != 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F3 Day Temperature");
                    hs.TriggerEvent("Thermostat Control F3-DayTemperature");
                } else if ( thermostatDay == 1 && thermostatPeakDay == 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F3 PeakDay Temperature");
                    hs.TriggerEvent("Thermostat Control F3-PeakDayTemperature");
                } else if ( thermostatEvening == 1 && thermostatPeakDay == 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F3 Evening Temperature");
                    hs.TriggerEvent("Thermostat Control F3-EveningTemperature");
                } else if ( thermostatEvening == 1 && thermostatPeakDay == 0 ) {
                    hs.WriteLog("HVAC Script", "Trigger F3 Evening Temperature");
                    hs.TriggerEvent("Thermostat Control F3-EveningTemperature");
                } else if  ( thermostatNight == 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F3 Night Temperature");
                    hs.TriggerEvent("Thermostat Control F3-NightTemperature");
                } else {
                    hs.WriteLog("HVAC Script", "Trigger F3 Failsafe Temperature - F3occupied");
                    hs.TriggerEvent("Thermostat Control AwayTemperature");
                }
            }
        } else if ( !occupancyF3 && occupancyF2 ) {
            if ( SceneGuestPresence == 1 ) {
                hs.WriteLog("HVAC Script", "Trigger Guest Presence Temperature");
                hs.TriggerEvent("Thermostat Control F3-NightTemperature");
            } else {
                //hs.WriteLog("HVAC Script Debug", "F3 unoccupied, Building occupied");
                if ( thermostatPeakDay != 1 && thermostatEvening != 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F3 Hold Temperature");
                    hs.TriggerEvent("Thermostat Control F3-HoldTemperature");
                } else if ( thermostatEvening == 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F3 Evening Temperature");
                    hs.TriggerEvent("Thermostat Control F3-EveningTemperature");
                } else {
                    hs.WriteLog("HVAC Script", "Trigger F3 PeakDay Temperature");
                    hs.TriggerEvent("Thermostat Control F3-PeakDayTemperature");
                }
            }
        } else if ( occupancyG ) {
            hs.WriteLog("HVAC Script", "Guest Presance, no action");
        } else {
            hs.WriteLog("HVAC Script", "Trigger F3 Failsafe Temperature");
            hs.TriggerEvent("Thermostat Control AwayTemperature");
        }
    
    
        //Guest Room Schedule
        if ( occupancyG ) {
            if ( thermostatMorning == 1 ) {
                hs.WriteLog("HVAC Script", "Trigger Guest Morning Temperature");
                hs.TriggerEvent("Thermostat Control Guest-MorningTemperature");
            } else if ( thermostatDay == 1 && thermostatPeakDay != 1 ) {
                hs.WriteLog("HVAC Script", "Trigger Guest Day Temperature");
                hs.TriggerEvent("Thermostat Control Guest-DayTemperature");
            } else if ( thermostatDay == 1 && thermostatPeakDay == 1 ) {
                hs.WriteLog("HVAC Script", "Trigger Guest PeakDay Temperature");
                hs.TriggerEvent("Thermostat Control Guest-PeakDayTemperature");
            } else if ( thermostatEvening == 1 && thermostatPeakDay == 1 ) {
                hs.WriteLog("HVAC Script", "Trigger Guest Evening Temperature");
                hs.TriggerEvent("Thermostat Control Guest-EveningTemperature");
            } else if ( thermostatEvening == 1 && thermostatPeakDay == 0 ) {
                hs.WriteLog("HVAC Script", "Trigger Guest Evening Temperature");
                hs.TriggerEvent("Thermostat Control Guest-EveningTemperature");
            } else if  ( thermostatNight == 1 ) {
                hs.WriteLog("HVAC Script", "Trigger Guest Night Temperature");
                hs.TriggerEvent("Thermostat Control Guest-NightTemperature");
            } else {
                hs.WriteLog("HVAC Script", "Trigger Guest Failsafe Temperature");
                hs.TriggerEvent("Thermostat Control AwayTemperature");
            }
            return 0;
        }
    
    
        //Floor 1/2 Schedule
        if ( (occupancyF1 || occupancyF2) && occupancyBuilding ) {
            if ( SceneGuestPresence == 1 ) {
                hs.WriteLog("HVAC Script", "Trigger Guest Presence Temperature");
                hs.TriggerEvent("Thermostat Control Guest-PeakDayTemperature");
            } else {
                //hs.WriteLog("HVAC Script Debug", "F1_F2 occupied, Building occupied");
                if ( thermostatMorning == 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F1_2 Morning Temperature");
                    hs.TriggerEvent("Thermostat Control F1_2-MorningTemperature");
                } else if ( thermostatDay == 1 && thermostatPeakDay != 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F1/2 Day Temperature");
                    hs.TriggerEvent("Thermostat Control F1_2-DayTemperature");
                } else if ( thermostatDay == 1 && thermostatPeakDay == 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F1/2 PeakDay Temperature");
                    hs.TriggerEvent("Thermostat Control F1_2-PeakDayTemperature");
                } else if ( thermostatEvening == 1 && thermostatPeakDay == 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F1/2 Evening Temperature");
                    hs.TriggerEvent("Thermostat Control F1_2-EveningTemperature");
                } else if ( thermostatEvening == 1 && thermostatPeakDay == 0 ) {
                    hs.WriteLog("HVAC Script", "Trigger F1/2 Evening Temperature");
                    hs.TriggerEvent("Thermostat Control F1_2-EveningTemperature");
                } else if  ( thermostatNight == 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F1/2 Night Temperature");
                    hs.TriggerEvent("Thermostat Control F1_2-NightTemperature");
                } else {
                    hs.WriteLog("HVAC Script", "Trigger F1/2 Failsafe Temperature - F1/2occupied");
                    hs.TriggerEvent("Thermostat Control AwayTemperature");
                }
            }
        } else if ( (!occupancyF1 && !occupancyF2) && occupancyBuilding ) {
            if ( SceneGuestPresence == 1 ) {
                hs.WriteLog("HVAC Script", "Trigger Guest Presence Temperature");
                hs.TriggerEvent("Thermostat Control Guest-PeakDayTemperature");
            } else {
                //hs.WriteLog("HVAC Script Debug", "F1_F2 unoccupied, Building occupied");
                if ( thermostatPeakDay != 1 && thermostatEvening != 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F1_2 Hold Temperature");
                    hs.TriggerEvent("Thermostat Control F1_2-HoldTemperature");
                } else if ( thermostatEvening == 1 ) {
                    hs.WriteLog("HVAC Script", "Trigger F1_2 Evening Temperature");
                    hs.TriggerEvent("Thermostat Control F1_2-EveningTemperature");
                } else {
                    hs.WriteLog("HVAC Script", "Trigger F1_2 PeakDay Temperature");
                    hs.TriggerEvent("Thermostat Control F1_2-PeakDayTemperature");
                }
            }
        } else {
            hs.WriteLog("HVAC Script", "Trigger F1/2 Failsafe Temperature");
            hs.TriggerEvent("Thermostat Control AwayTemperature");
        }
    
        return 0;
    }
    The basic functionality:
    • Floor Boolean values are true if at least 1 room in each floor is occupied and false if all rooms are occupied
    • A building Boolean is true if at least one floor is true, and false if all rooms are false
    • I added a Ping occupancy into the building occupancy test as an example of testing if a device is online and on the network. This doesn't work well for Phones, as the wifi sleep prevents this from being reliable.
    • Several schedule conditions are considered depending if the zone is occupied, or the zone is unoccupied while another is occupied Failsafe sets the Away temperature to prevent any value combinations from accidentally cooling the house during peak hours.


    I have my schedule broken into several time frames:
    • Day time, which is during standard rate hours, including all day weekends.
    • PeakDay, peak rate hours from 3p-8p. Typically I'm not home, but if I am I want a compromise between cost and comfort.
    • Evening, starts 1 hour from the end of the peak rate. This is when I'm typically coming home so another compromise
    • Night, when I'm usually getting ready for bed and want a cooler temperature
    • Hold, I've personally determined that allowing the temperature to rise 2 degrees if a zone should reduce costs without being self defeating
    • Away, I set the temperatures as high as possible without causing issues. I also set one zone a bit more reasonable for the cat.


    Let me know what you think, I'll appreciate any feedback or criticism as this is my first attempt at c#, or any programming language.
    My ADD has taken over so I won't be actively supporting this if there are bugs, I'm just hoping it helps someone and welcome any input to consider when I revisit this.

    I have some other ideas for schedules to add to the logic such as an over-ride for when guests are visiting, but I'm probably going to make them suffer with the PeakDay schedule. >
    Also, I would like to get some Z-Wave controlled Vents, like the discontinued EcoNet EV100, and further expand on the Hold temp/occupied temp concept by room. The EV200 is apparently going to be available in 2019, so if I can get my C#/VB.NET by then, I may make a plugin that opens and closes vents depending on room temperature.

    The alarm.com thermostats I have are awesome, I highly recommend if you're familiar with reading the zwave alliance documentation on the parameters and are willing to take a bit of a risk (they're unsupported if you aren't a subscriber). They can be highly tuned via the parameters and work just fine with and without batteries.
    Supposedly there's a parameter to control if either the onboard thermostat is used to monitor the temperature or if a remote device is used which is a static 0 value. I'm trying to identify if any of the undocumented parameters are linked to that device. I'll update this script if that turns out to be possible.

    ====

    Since it appears i can't make a followup post, here's some info on how I setup my occupancy triggers, schedules, and thermostat events

    Occupancy trigger:
    One set of is created for each room. Some tuning on the end time is needed to keep the occupancy consistent. 30 minutes seems to be good for rooms, and 10 minutes is good for hallways and in this case, the garage.
    I also link to lights and zwave outlets, but you know how to do that
    I've also found that setting the motion sensors to use the most sensitive is needed.
    The trigger will keep resetting the counter every-time motion is re-detected.
    I've found that setting the "re-detect" time to the max of 60 seconds to save battery is sufficient in my case with the Zooz multi sensor



    Schedule:
    These are pretty simple and self explanatory. I found that the HomeSeer event engine is buggy when it comes to triggers and order, so the time must be before the day condition
    I'd like to be able to use a csv to set schedules wider than 7 days, but for now this works well


    Thermostat Events:
    A separate Event is needed for each thermostat for each schedule time.
    The Away event sets the away setpoints for both thermostats since they aren't independent in my case
    Don't mind the heating setpoints, I'm not sure what they should be yet.
    I have circulate tasks to start and stop the auto circulation around the peak times, these are specific to my thermostat models


    Script Trigger:
    I currently run the trigger every minute. Also eliminates the need to lock the thermostat because the temps will get enforced with the correct value every run. Some handling of temporary overrides could be in the future
    Last edited by ; July 13, 2018, 12:32 AM.
Working...
X