By following this tutorial, you will make your openHAB setup aware of the current operation state of your washing machine, dishwasher, dryer, toaster, doomsday machine, you name it. This solution is purely based on a power usage reading by one of the many available modules. The solution will allow you to react on certain state transition, e.g. sending a notification to your smartphone: “Washing machine is finished!”.
Requirements
- power consumption measuring device, e.g. Homematic HM-ES-PMSw1-Pl, Sonoff Pow, …
- this rule was tested with openHAB 1.8 and openHAB 2.0
- no additional addons/bindings are needed (other than the one for your module)
Before continuing, please make sure that the device is connected to openHAB and is correctly providing usage data (Watts or Amps). Please be aware, that many devices have internal settings on how often and when to send new data. You do not need to tweak these in order for this solution to work, the reaction time might however be improved by doing so.
Idea and State Details
The presented solution is build on the idea, that the power usage of most household devices will differ between their operation states. Let’s have a look at a typical washing machine. It’s easy to identify these three fundamental states: Off - Standby - Active. By taking the timely transition between these states into account, we can add one especially important state: Finished.
One could even go one step further and differentiate between washing phases. These or other additional states can only be added, if information retrieved from our device is clear enough to always decide on the right state. While thinking about your needed states, it also doesn’t hurt to remember which events are actually important to you.
First Measurements
The first thing you have to do is taking one complete measurement series. Only by knowing the specific power consumption behavior of your device, you can later parametrize your rule. Here are two examples, one showing one run of my washing machine, the other shows the consumption of my dishwasher.
As you can see, the diagrams are very different. While the dishwasher diagram follows some acceptable pattern, the washing machine seems to be very unpredictable but even this diagram seems to consist of certain phases, which one “could” analyze.
Sample Data and Diagrams
openHAB already collects all events received by registered items in the logging file events.log
. Have your (washing) machine go though one full process and extract the usage data from the log. One example on how to do this on Linux:
grep "Washingmachine_Power changed" /var/log/openhab2/events.log
......
[...] Washingmachine_Power changed from 0.06 to 0.07
[...] Washingmachine_Power changed from 0.07 to 0.06
[...] Washingmachine_Power changed from 0.06 to 0.07
[...] Washingmachine_Power changed from 0.07 to 1.34
[...] Washingmachine_Power changed from 1.34 to 1.33
[...] Washingmachine_Power changed from 1.33 to 1.34
[...] Washingmachine_Power changed from 1.34 to 160.99
[...] Washingmachine_Power changed from 160.99 to 4.59
[...] Washingmachine_Power changed from 4.59 to 157.92
[...] Washingmachine_Power changed from 157.92 to 2154.860001
[...] Washingmachine_Power changed from 2154.860001 to 2257.259998
[...] Washingmachine_Power changed from 2257.259998 to 2160.779999
[...] Washingmachine_Power changed from 2160.779999 to 2158.700001
[...] Washingmachine_Power changed from 2158.700001 to 2266.509998
[...] Washingmachine_Power changed from 2266.509998 to 2155.84
......
You could now already analyze the data. It’s probably easier to do this by looking at a graph in your favorite tool (the diagrams above were created using https://plot.ly). Before you can do that, you need to extract the data to be used. You can do this on your favorite editor like Notepad++.
Converting the events log file output above on the fly into a CSV format (readable by Plot.ly or Excel) can be done with the following command:
grep "Waschmaschine_Power changed" /var/log/openhab2/events.log | sed 's/.[0-9]* \[ItemStateChangedEvent.* to /;/'
......
2016-10-22 20:13:29.095;135.17
2016-10-22 20:13:37.095;76.98
......
Finding the Transition Points
Now you need to find consumption values to decide on, in which state the washing machine might be in. Judging by the log data above, it’s pretty obvious, that my washing machine is consuming little power when turned off (0.07W), a bit more when in Standby (1.34W) and way more when active. It’s important to find power values that are only measured when switching states but not when being in one state! Always leave some space for small deviation. Finding the right values is the tricky part of this solution!
The result for the washing machine from above is illustrated in the following state machine diagram:
openHAB Implementation
The shown state machine can now be transferred to openHAB in a simple and short way. No magic here
household-devices.items
Number Washingmachine_OpState "Washingmachine State [%d]"
household-devices.rules
val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_FINISHED = 3
rule "Washingmachine Consumption State Machine"
when
Item Washingmachine_Power changed
then
if (Washingmachine_Power.state < 0.2) Washingmachine_OpState.postUpdate(MODE_OFF)
else if (Washingmachine_Power.state > 10) Washingmachine_OpState.postUpdate(MODE_ACTIVE)
else if (Washingmachine_Power.state < 4.5) {
if (Washingmachine_OpState.state == MODE_OFF) Washingmachine_OpState.postUpdate(MODE_STANDBY)
else if (Washingmachine_OpState.state == MODE_ACTIVE) Washingmachine_OpState.postUpdate(MODE_FINISHED)
}
end
That is basically it. You can now present the OpState item on your sitemap or react on transitions in rules. Example:
rule "Washingmachine Notifications"
when
Item Washingmachine_OpState changed
then
if (Washingmachine_OpState.state == MODE_FINISHED) {
pushover("Washingmachine finished!")
}
end
State oriented control flow
The above solution acts on the current power consumption as the main control flow element. For some a states oriented algorithm might be more intuitive or better suited. @BigMountainSki proposed a state oriented control flow in the following comment:
Bouncy States and other Obstacles
The above solution can already be used. Depending on your machine you may see bouncing states, resulting in multiple state transitions with unwanted effects (e.g. multiple notifications). In this part we will look into a few ways to handle these smaller problems.
Bouncy State Elimination using Delay
In the given washing machine example, the power reading surpasses the defined 4.5 Watts boundary a few times in the middle of the wanted active state. This can be handled by a simple time-based de-bouncing, using a lock (ReentrantLock, similar to a “semaphore”) and a delay.
household-devices.rules
import java.util.concurrent.locks.ReentrantLock
val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_FINISHED = 3
var java.util.concurrent.locks.ReentrantLock finishLock = new java.util.concurrent.locks.ReentrantLock()
rule "Washingmachine Consumption State Machine (Extended)"
when
Item Washingmachine_Power changed
then
if (Washingmachine_Power.state < 0.2) Washingmachine_OpState.postUpdate(MODE_OFF)
else if (Washingmachine_Power.state > 10) Washingmachine_OpState.postUpdate(MODE_ACTIVE)
else if (Washingmachine_Power.state < 4.5) {
if (Washingmachine_OpState.state == MODE_OFF) Washingmachine_OpState.postUpdate(MODE_STANDBY)
else if (Washingmachine_OpState.state == MODE_ACTIVE) {
finishLock.lock()
try {
Thread::sleep(10000) // Debounce for 10 seconds
if (Washingmachine_Power.state < 4.5) Washingmachine_OpState.postUpdate(MODE_FINISHED)
} finally {
finishLock.unlock()
}
}
}
end
Bouncy State Elimination using Persistence
Continue reading at:
Node-RED Implementation
Outlook
An alternative solution would be an event-based instead of a delay-based rechecking. If you got such a solution working for you, please share in the comments and I’ll make sure to include it
Happy Hacking!