So... presence awareness.
I didn't like that the following schedule:
6:30-8:00 Mon-Fri 17:00-23:00 Mon-Fri - Living Room - 20C
would not account in anyway for me to be "out" during the evening. Nor did I like it would go off and not provide heating if I was working from home one day.
So I needed to know if I was home or not. My first thought was my phone. It always connects to my Wifi within seconds, so all I need to do is detect it there. First I tried pinging it, figuring I could give it a static IP. This worked until the phone went to sleep, then it stopped responding. So then I tried rumaging around with nmap and arping. Still no response when sleeping and it could sleep for 20-30 minutes without answering a single ping or probe. I then tried a Tasker profile to send a notification of presence every minute while connected to the Wifi, but ... the Android over ruled it and shut the network off so that it still couldn't send the notifications. Pheewww.
Finally on a long shot I used "SNMP" to scan the TP-Link router and BINGO I found a dynamic list of connected DHCP assignments. When my phone connects it is listed within 10 seconds. When my phone disconnects it is unlisted in 20 seconds or so. So I wrapped this in a bit of python, ran it as a service and it publishes (you should see a trend
) a notification of my presence, either 1 (in), or 0 (out).
Finally tying it all together with a MultiRoomTempSchedule and a PresenceCondition I have the following:
Code:
target_temps = {
"default": {"livingRoom":6, "bedroom":6, "garage":1, "office":6},
"eco": {"livingRoom": 18, "bedroom": 16, "garage": 2, "office": 18},
"preferred": {"livingRoom": 20, "bedroom": 18, "garage": 2, "office": 20},
"max": {"livingRoom": 30, "bedroom": 30, "garage": 30, "office": 30}
}
A maintenance schedule without presence detection, active 24/7, 365 is told to use "default" temps.
A routine schedule without presence detection, active when I am 'routinely home', is told to use "eco" temps.
Finally a presence aware schedule active "all day" only if I am present, that is told to use "preferred" temps.
Sample logging out put at key times:
Code:
Aug 27 06:25:46 raspberrypi python3.5[22639]: Maintenance Schedule Active - checking temps default
Aug 27 06:25:46 raspberrypi python3.5[22639]: office: 22.31 < 6
Aug 27 06:25:46 raspberrypi python3.5[22639]: garage: 16.5000 < 1
Aug 27 06:25:46 raspberrypi python3.5[22639]: livingRoom: 19.12 < 6
Aug 27 06:25:46 raspberrypi python3.5[22639]: bedroom: 21.56 < 6
Aug 27 06:25:46 raspberrypi python3.5[22639]: Active demands []
At 06:30 however....
Code:
Aug 27 06:30:30 raspberrypi python3.5[22639]: Weekday Morning Routine Active - checking temps eco
Aug 27 06:30:30 raspberrypi python3.5[22639]: office: 22.31 < 18
Aug 27 06:30:30 raspberrypi python3.5[22639]: garage: 16.5620 < 2
Aug 27 06:30:30 raspberrypi python3.5[22639]: livingRoom: 19.06 < 18
Aug 27 06:30:30 raspberrypi python3.5[22639]: bedroom: 21.50 < 16
Aug 27 06:30:30 raspberrypi python3.5[22639]: Presence Schedule Active - checking temps preferred
Aug 27 06:30:30 raspberrypi python3.5[22639]: office: 22.31 < 20
Aug 27 06:30:30 raspberrypi python3.5[22639]: garage: 16.5620 < 2
Aug 27 06:30:30 raspberrypi python3.5[22639]: livingRoom: 19.06 < 20
Aug 27 06:30:30 raspberrypi python3.5[22639]: bedroom: 21.50 < 18
Aug 27 06:30:30 raspberrypi python3.5[22639]: Maintenance Schedule Active - checking temps default
Aug 27 06:30:30 raspberrypi python3.5[22639]: office: 22.31 < 6
Aug 27 06:30:30 raspberrypi python3.5[22639]: garage: 16.5620 < 1
Aug 27 06:30:30 raspberrypi python3.5[22639]: livingRoom: 19.06 < 6
Aug 27 06:30:30 raspberrypi python3.5[22639]: bedroom: 21.50 < 6
Aug 27 06:30:30 raspberrypi python3.5[22639]: Active demands [HEATING livingRoom True 0 0]
Aug 27 06:30:30 raspberrypi python3.5[22639]: Existing heating demand NONE heating ON 1566805485.240631 300
Aug 27 06:30:30 raspberrypi python3.5[22639]: Raising demand: {"heating": {"key":"heating", "demandState":"ON", "expiry":"300", "category": "CONTROL"}}
Presence Schedule Active raised the demand for heating at the living room is under 20C.
The "expiry" 300 is important. The heating commands have a minimum ON time for 5 minutes. This prevents it toggling on, off a lot and works well. The expiry also means that nothing has to switch the heating off again, it's demand will simply expire, a schedule is of course free to demand it for another 5 minutes every 30 seconds to keep it on.
The heating controller ended up doing this:
Code:
Aug 27 06:30:56 raspberrypi Heating Controller[22859]: {"heating": {"category": "NONE", "key": "heating", "demandState": "ON", "timestamp": 1566883830.6425545, "expiry": "300"}, "presenceHome": {"category": "NONE", "key": "presenceHome", "demandState": "ON", "timestamp": 1566883735.8001761, "expiry": 120}}
Aug 27 06:30:56 raspberrypi Heating Controller[22859]: Heating demandState ON demandExpiry 300 timestamp 1566883830.6425545 currentTime 1566883856.7965205
Aug 27 06:30:56 raspberrypi Heating Controller[22859]: Demand state True current state False
Aug 27 06:30:56 raspberrypi Heating Controller[22859]: Commanding heating on http://10.0.0.9/on
Aug 27 06:30:57 raspberrypi Heating Controller[22859]: <Response [400]>
Aug 27 06:30:57 raspberrypi Heating Controller[22859]: <Response [400]>
Aug 27 06:30:57 raspberrypi Heating Controller[22859]: Sending JSON datum to 10.0.0.3: {"heating": {"name": "Heating", "value": 1, "units": " ", "key": "heating", "timestamp": 0, "shortName": "HT", "type": "bool"}}
Aug 27 06:31:27 raspberrypi Heating Controller[22859]: {"heating": {"category": "NONE", "key": "heating", "demandState": "ON", "timestamp": 1566883830.6425545, "expiry": "300"}, "presenceHome": {"category": "NONE", "key": "presenceHome", "demandState": "ON", "timestamp": 1566883735.8001761, "expiry": 120}}
Aug 27 06:31:27 raspberrypi Heating Controller[22859]: Heating demandState ON demandExpiry 300 timestamp 1566883830.6425545 currentTime 1566883887.8853893
Aug 27 06:31:27 raspberrypi Heating Controller[22859]: Demand state True current state True
Aug 27 06:31:27 raspberrypi Heating Controller[22859]: Commanding heating on http://10.0.0.9/on
Aug 27 06:31:27 raspberrypi Heating Controller[22859]: <Response [200]>
This shows a bug. Because there is a minimum "off time" on the boiler, and the fact the heating controller sends an off signal every minute if the heating is off.... the first "on" command is rejected with a Response <400>. The second one, 1 minute later works fine. The SOnOff is now "on".
Justification for this 'feature'... OFF means OFF. So the OFF is always accepted and resets the "offTime" for short cycle detection. I think I can work around it though.
Obviously it send "on" a few more times, but as the sun was rising to come in the living room window it was set back to OFF pretty quickly.
Note at 08:00 when I was supposed to be leaving for work this happens:
Code:
Aug 27 08:30:17 raspberrypi python3.5[22639]: Presence Schedule Active - checking temps preferred
Aug 27 08:30:17 raspberrypi python3.5[22639]: office: 22.44 < 20
Aug 27 08:30:17 raspberrypi python3.5[22639]: garage: 16.7500 < 2
Aug 27 08:30:17 raspberrypi python3.5[22639]: livingRoom: 20.06 < 20
Aug 27 08:30:17 raspberrypi python3.5[22639]: bedroom: 21.81 < 18
Aug 27 08:30:17 raspberrypi python3.5[22639]: Maintenance Schedule Active - checking temps default
Aug 27 08:30:17 raspberrypi python3.5[22639]: office: 22.44 < 6
Aug 27 08:30:17 raspberrypi python3.5[22639]: garage: 16.7500 < 1
Aug 27 08:30:17 raspberrypi python3.5[22639]: livingRoom: 20.06 < 6
Aug 27 08:30:17 raspberrypi python3.5[22639]: bedroom: 21.81 < 6
Aug 27 08:30:17 raspberrypi python3.5[22639]: Active demands []
The morning routine schedule has ended, but the presence aware schedule is keeping the "preferred" target temperatures active.
Next steps have changed a bit now that I have it "in service". What I badly need now is a UI. First up probably the most helpful will be on the monitoring side of things. The current 16x2 LCD is having issues showing things like the heating status and presence, so that needs fixed. Then it would be nice to see the target temps for the various "modes" and to change them. Also the ability to manually hack the active demands and other low level stuff from my phone would be nice.
Then I need to return to the over-ride problem. The schedules are fairly dynamic in terms of temperature, presence etc. but they are still fixed. Things change, routines change and while they are easy to edit or change via a UI I would prefer a way to "over ride" certain things until conditions are met or time has passed etc.
I can think of several ways to achieve these things at different layers in the system, but haven't exactly what yet. An emerging idea is basically "Profiles", which are a set of things like Schedules, Conditions, Target temps, Controller config etc. That can be switched manually and have an expiry set. Consider:
Profile NORMAL
Profile ALL OFF
Profile ECO
Profile HOLIDAY
Profile DEMO - this could be cool, especially with lighting 
They could be manually enabled and have a kind of exit condition, much like Tasker profiles on Android.