This project documents some Java software we have been using for several years and some more recent updates as part of our Home Control System (HCS). The software controller described here is a generic and re-usable Java class created to provide automatic and intelligent control, based on real-time events, along with scheduled control of devices and services in our home. It is used to control things like the central heating, hot water and security and convenience lighting.
We don't expose the underlying technology discussed here in normal use. The use of controllers and the configuration of these controllers would be part of another project to model our house configuration in XML and we plan to have a nice graphical tool to enable this. This tool would then allow anyone to automate and configure the behaviour of their home, assuming they used our Home Control System (HCS) and the same technology abstraction.
An instance of the class is created for each item to be controlled. The controller loads a configuration file from local storage, which is currently written in XML. This is part of our XML Home Automation project.
At any time we can send a 'reload' message to our Home Control System (HCS) and it will reload all of the XML configuration files, including the controller data.
The constructor creates the controller object and calls the
Load() method (which loads the configuration file). The configuration file (examples) has a device name (which is used to load the configuration file), the zone for this device (used to filter events) and a default value. If the conditions mean that no rules match, then this default value is used as the target output.
Check(event) method passes an event to the controller, which then checks its target output value. To make this function as fast as possible, it runs some test to see if it needs to do anything at all, e.g. is the event zone relevant or are any conditions satisfied.
Load() method causes the controller to load/reload its configuration file from the associated XML file. If the load fails the controller is marked as inactive and generates a warning when the Check() function is called. To make the class more efficient and faster, the XML file is processed and cached into a number of arrays.
Extend(duration) method extends the timer by the defined number of minutes.
Schedules, Rules, Timers & Timer Extensions
The controller schedule is configured using a set of simple rules, that determine the target value at any given time. The rules are loaded from a configuration file and validated on loading. We currently generate these files manually but, the plan is that a nice graphical tool will generate them in XML in the future.
The rules are processed in order to work out the current target value. The target value is in 'free text' format and is validated for the device to which it relates. For a device like the 'Hot Water Heater' the target will be either 'On' or 'Off'. For devices like 'Bathroom Heating' the target value will be a temperature (in ºC).
The rules are basically a house status (for which this rule applies or a wildcard), start date/time, end date/time and a target value (comma separated). The start and end can be based on a specific dates, or days of the week and always includes a time in the 24-hour format, e.g.
16:00:00. Rules using days of the week are specified in a string of the form
S----F- equates to Sunday and Friday only.
The time element can also have one of the following values: Sunrise, Sunset, Dawn or Dusk. These have time values set by the wider and retrieved from the database. We also plan to implement delays on these values, e.g. 15 minutes after sunset. This would be done in the form:
Each rule has one or more associated house status values of 'In', 'Out' or 'Away', to enable different target values for each status. If this is set to '*', then it is not checked. This is not the value stored in the database (which also may have the value of 'Auto') but, the calculated value returned by a Status class. This is because this class also handles the 'Auto' value and takes thus into account detected presence.
Triggers are devices that cause a timer extension, e.g. a PIR detection event in a room. Each trigger has an associated delay used to extend the timer. We have implemented this such that all trigger target values are the same.
One limitation in our implementation so far is that triggers need to be global or come from objects in the same zone as the device being controlled. This allows us to massively simplify things and reduce the number of events each controller has to process. We plan to remove this limitation though and monitor the impact of doing this as it restricts things too much.
Conditions are name-value pairs that are checked before the controller checks the rules and is thus able to change the target value. Typically these are a device and value to be tested (e.g. 'Heating' = 'On') but, they could also be an environmental variable (e.g. 'Twilight' = 'Dusk'). The house status is not considered a valid condition, because it is also a condition required for each rule. Conditions can test for a positive (true) match (the default) or a negative (false) match (using a <match>false</match> element).
It should be possible to have conditions per trigger and this will enable a basic state machine capability but, we don't see a need for this (yet).
Something else we are looking at is, extending the <match> element to support >, >=, < and <=. This enables much more powerful control based on numeric values. For example we could heat the water until the hot water capacity equals 100%.
Everything discussed up till now is about determining the 'target' output value but, this in itself doesn't activate a device to turn on (for example) a heater or air-conditioning unit. We are merely setting the target temperature to be reached. For heating and cooling controllers, we also need to have something that converts this into a binary (on/off) or analogue (0-100%) action.
The actions in the XML configuration file determine how this happens. For some devices this will be simply a matter of using the new target value as the device output value (e.g. Safety Lights = On).
We currently use a
<actions>O>/actions> element where 'O' is one of a number of action flags.
- E = send this new target value as an event, back into the HCS.
- O = output this value to the device
These are some example implementations in our home:
This is a really simple example, which has two rules to provide different switch off times depending on the day of the week.
Kitchen Worktop Lighting
Our kitchen worktop lights are an example of convenience lighting that are currently driven by this software controller. They are also an example of a controller that doesn't have any scheduled 'On' time. The lights are basically off all the time, apart from when they are triggered by the 'Kitchen PIR' = 'On' or 'Kitchen Door' = 'Open' events. Through testing we have found the optimum timer delay to be 6 minutes. They have a single condition associated with them, which is 'Twilight' = 'Dusk', to ensure they only come when it is dark outside. During the winter, this means that they also come on in the morning as well as at night time.
This is still being documented and tested.
The default value is set to the minimum temperature we want the room reach if we were 'Away' (e.g. 16°C). Most of the year, this would mean the heating won't be switched on in this room and thus use no energy.
We then define a comfortable background temperature for the 'In' status, which we want at night time (e.g. 20°C). This is then followed by a rule that sets a target temperature (e.g. 22°C) for use in the normal day time hours (e.g. 08:30 to 21:00). We then have a rule for when we are 'Out', which is a lower target (e.g. 18°C).
There is no point in putting conditions in to ensure these values are used only when the 'Heating' = 'On', these are target temperatures only and the heating and cooling can be switched on and off independently.
House Status & Presence
This approach works very well with manual controls and interactions. For example, it is very easy to have a '+30min' switch next to a heated towel rail, which triggers the towel rail to come on for 30 minutes. The same approach could be used to add a '+1hr' button for the hot water heating. It could also be used to provide simple 'on' and 'off' buttons. Similarly, the approach can be used with HTML/AJAX web interfaces (hosted on our LAN).
On a related note, we also have a hardware project to do something very similar.
This project only really works because we have used technology abstraction in our Home Control System (HCS). There are no dependencies here on specific home automation technology or the addressing of technology and devices. Each device in our home has a friendly, human-readable name, which is also used through-out our Home Control System (HCS).