Washing Machine State Machine

Thx all contributing to this thread - helped me a lot during the last days.
There I had some confusions changing the state model for a slightly different case, I swapped to a different pattern of coding.
I put the priority to the states and then evaluating thresholds.
I know it’ s not so efficient and contains more lines - but maybe it could help somebody else…

val Number STATE_OFF = 0
val Number STATE_STANDBY = 1
val Number STATE_ACTIVE = 2
val Number STATE_FINISHED = 3

val Number THRESHOLD_OFF = 5
val Number THRESHOLD_STANDBY = 20
val Number THRESHOLD_ACTIVE = 30

var java.util.concurrent.locks.ReentrantLock finishLock  = new java.util.concurrent.locks.ReentrantLock()

rule "Washingmachine_StateMachine"
when
    Item WashingMachine_Consumption changed
then
	switch WashingMachine_OpState.state	{
		case STATE_OFF: {
			 	if (WashingMachine_Consumption.state > THRESHOLD_STANDBY){
					WashingMachine_OpState.postUpdate(STATE_STANDBY)
				} 
				if (WashingMachine_Consumption.state > THRESHOLD_ACTIVE) {
					WashingMachine_OpState.postUpdate(STATE_ACTIVE)
				}
			}			
		case STATE_STANDBY: {
				if (WashingMachine_Consumption.state > THRESHOLD_ACTIVE) {
					WashingMachine_OpState.postUpdate(STATE_ACTIVE)
				}
				if (WashingMachine_Consumption.state < THRESHOLD_STANDBY) {
					WashingMachine_OpState.postUpdate(STATE_OFF)
				}
			}			
		case STATE_ACTIVE: {
				if (WashingMachine_Consumption.state < THRESHOLD_ACTIVE)	{
					finishLock.lock()
		            try {
		                Thread::sleep(10000) // Debounce for 10 seconds
		                if (WashingMachine_Consumption.state < THRESHOLD_ACTIVE) {
		                	 WashingMachine_OpState.postUpdate(STATE_FINISHED)
		               	} 
		            } finally {
		                finishLock.unlock()
		            }
				}
			}				
		case STATE_FINISHED: {
				if (WashingMachine_Consumption.state < THRESHOLD_STANDBY){
					WashingMachine_OpState.postUpdate(STATE_OFF)
				} 
				if (WashingMachine_Consumption.state > THRESHOLD_ACTIVE) {
					WashingMachine_OpState.postUpdate(STATE_ACTIVE)
				}	
			}		
		default: WashingMachine_OpState.postUpdate(STATE_OFF)
	}
end

I’m interested to hear your opinions…

5 Likes

I have done it in a similar way and i like your Threshold values. I will user it in my rule, makes it more readable.

Thanks
Thomas

Finally managed to finish this with my self built amp reader. Needs a bit of finetuning with regard to the amp values but works fine with Thom’s original (simple) rule.
But I did encounter an odd phenomenon when I add the state to items file: the group that I add it to, opens extremely slow.
I use
Number Washingmachine_OpState "Washingmachine State [MAP(was.map):%d]" <washingmachine> (GF_Garage, Machines)

where the map basically translates numbers 1-3 to words.
Anyway, if I remove the map command, it seems to go well.
So this one opens very very very slow (5-10 minutes)

But this one opens normally:

The only difference is the map file that looks like this:

0=OFF
1=Standby
2=Active
3=Finished
-=Error

That doesnt seem like a map that would take for ages tp load or execute.
Am I missing something?

Hey congrats on the first part.

The second part though… :confused: This is not normal and I’ve never experienced anything like it.

Hahaha, yes, several times :wink:

Maybe OpenHab is trying to teach me patience

Hmmm. Seems to affect the phone app much more than the basicUI.
restarting/clearing phone had no effect

Hi All,

this is defenitely a great thread about things weare able to do with openhab. I build a state machine as a rule in openHAB and it worked like a charm, but then i found the article about NodeRed. Thanks to @rgerrans

Because i heared often about NodeRed as one of THE IoT tools, i decided to give it a try. Installed NodeRed on an fresh openHABian installation (Thanks @ThomDietrich) and startet.

It is really simple to work with NodeRed just open the broswer an goto http://NodeRedServer:1880/ and start. I searched around and found the FSM node that represents a Finite State Machine in one node. Perfect, but as we know we have a little timer issue to overcome this jitter problem with many of the washing machines and therefore i could not use the FSM node.

Ok, i had to build the FSM with timer support on my own. The standard time in NodeRed could be retriggered, but not stopped, so i had to find a silution on this → stoptimer node did the trick for me.

At the end i created a flow that receives the power consumption from an item and sets the surrent sate of the washing machine using a String item.

For all who are interested the flow to import it into node red

[{“id”:“b6da215f.92716”,“type”:“tab”,“label”:“Washing Machine State Machine”},{“id”:“329acfe5.fbe06”,“type”:“openhab2-in”,“z”:“b6da215f.92716”,“name”:“WashingMachinePower”,“controller”:“e0c90f4f.513a8”,“itemname”:“WashingMachinePower”,“x”:120,“y”:600,“wires”:[[“172bb3e6.e94fcc”],]},{“id”:“172bb3e6.e94fcc”,“type”:“switch”,“z”:“b6da215f.92716”,“name”:“evaluate power”,“property”:“payload”,“propertyType”:“msg”,“rules”:[{“t”:“lt”,“v”:“2”,“vt”:“num”},{“t”:“lt”,“v”:“4”,“vt”:“num”},{“t”:“gt”,“v”:“10”,“vt”:“num”}],“checkall”:“false”,“outputs”:3,“x”:320,“y”:600,“wires”:[[“b5c4128b.3c3e3”],[“83b083d2.51a1e”],[“4e5a7235.047f3c”]]},{“id”:“1cf011b8.ce5d8e”,“type”:“switch”,“z”:“b6da215f.92716”,“name”:“evaluate state on power below 2W”,“property”:“payload.state”,“propertyType”:“msg”,“rules”:[{“t”:“eq”,“v”:“STATE_OFF”,“vt”:“str”},{“t”:“eq”,“v”:“STATE_STANDBY”,“vt”:“str”},{“t”:“eq”,“v”:“STATE_ACTIVE”,“vt”:“str”},{“t”:“eq”,“v”:“STATE_FINISHED”,“vt”:“str”},{“t”:“else”}],“checkall”:“false”,“outputs”:5,“x”:860,“y”:340,“wires”:[[“c270265e.13e1f8”],[“c270265e.13e1f8”],[“2a38ca8.538d236”],[“c270265e.13e1f8”],[“c270265e.13e1f8”]]},{“id”:“b5c4128b.3c3e3”,“type”:“openhab2-get”,“z”:“b6da215f.92716”,“name”:“WashingMachineState”,“controller”:“e0c90f4f.513a8”,“itemname”:“WashingMachineState”,“x”:540,“y”:540,“wires”:[[“1cf011b8.ce5d8e”]]},{“id”:“35249b23.f02864”,“type”:“openhab2-out”,“z”:“b6da215f.92716”,“name”:“Set WashingMachineState”,“controller”:“e0c90f4f.513a8”,“itemname”:“WashingMachineState”,“topic”:“ItemUpdate”,“payload”:“”,“x”:1880,“y”:580,“wires”:},{“id”:“2a38ca8.538d236”,“type”:“stoptimer”,“z”:“b6da215f.92716”,“duration”:“150”,“units”:“Second”,“payloadtype”:“num”,“payloadval”:“0”,“name”:“”,“x”:1130,“y”:440,“wires”:[[“c270265e.13e1f8”],]},{“id”:“c270265e.13e1f8”,“type”:“change”,“z”:“b6da215f.92716”,“name”:“set STATE_OFF”,“rules”:[{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“STATE_OFF”,“tot”:“str”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:1380,“y”:400,“wires”:[[“fc76d58.c9a6c28”]]},{“id”:“83b083d2.51a1e”,“type”:“openhab2-get”,“z”:“b6da215f.92716”,“name”:“WashingMachineState”,“controller”:“e0c90f4f.513a8”,“itemname”:“WashingMachineState”,“x”:540,“y”:600,“wires”:[[“ec78584d.73ef78”]]},{“id”:“ec78584d.73ef78”,“type”:“switch”,“z”:“b6da215f.92716”,“name”:“evaluate state on power below 4W”,“property”:“payload.state”,“propertyType”:“msg”,“rules”:[{“t”:“eq”,“v”:“STATE_OFF”,“vt”:“str”},{“t”:“eq”,“v”:“STATE_STANDBY”,“vt”:“str”},{“t”:“eq”,“v”:“STATE_ACTIVE”,“vt”:“str”},{“t”:“eq”,“v”:“STATE_FINISHED”,“vt”:“str”},{“t”:“else”}],“checkall”:“false”,“outputs”:5,“x”:860,“y”:640,“wires”:[[“ac335bda.d55018”],[“ac335bda.d55018”],[“d4d30b61.0754d8”],[“e2463e68.5343d”],[“ac335bda.d55018”]]},{“id”:“ac335bda.d55018”,“type”:“change”,“z”:“b6da215f.92716”,“name”:“set STATE_STANDBY”,“rules”:[{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“STATE_STANDBY”,“tot”:“str”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:1400,“y”:620,“wires”:[[“fc76d58.c9a6c28”]]},{“id”:“e2463e68.5343d”,“type”:“change”,“z”:“b6da215f.92716”,“name”:“set STATE_FINISHED”,“rules”:[{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“STATE_FINISHED”,“tot”:“str”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:1400,“y”:520,“wires”:[[“fc76d58.c9a6c28”]]},{“id”:“d4d30b61.0754d8”,“type”:“stoptimer”,“z”:“b6da215f.92716”,“duration”:“150”,“units”:“Second”,“payloadtype”:“num”,“payloadval”:“0”,“name”:“”,“x”:1130,“y”:500,“wires”:[[“e2463e68.5343d”],]},{“id”:“4e5a7235.047f3c”,“type”:“openhab2-get”,“z”:“b6da215f.92716”,“name”:“WashingMachineState”,“controller”:“e0c90f4f.513a8”,“itemname”:“WashingMachineState”,“x”:540,“y”:660,“wires”:[[“2ee8f606.cf76fa”,“9a4f86d0.2018a8”]]},{“id”:“2ee8f606.cf76fa”,“type”:“switch”,“z”:“b6da215f.92716”,“name”:“evaluate state on power above 10W”,“property”:“payload.state”,“propertyType”:“msg”,“rules”:[{“t”:“eq”,“v”:“STATE_OFF”,“vt”:“str”},{“t”:“eq”,“v”:“STATE_STANDBY”,“vt”:“str”},{“t”:“eq”,“v”:“STATE_ACTIVE”,“vt”:“str”},{“t”:“eq”,“v”:“STATE_FINISHED”,“vt”:“str”},{“t”:“else”}],“checkall”:“false”,“outputs”:5,“x”:860,“y”:780,“wires”:[[“2f9848db.0c1c58”],[“2f9848db.0c1c58”],[“2f9848db.0c1c58”],[“2f9848db.0c1c58”],[“2f9848db.0c1c58”]]},{“id”:“9a4f86d0.2018a8”,“type”:“change”,“z”:“b6da215f.92716”,“name”:“send STOP”,“rules”:[{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“STOP”,“tot”:“str”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:850,“y”:480,“wires”:[[“d4d30b61.0754d8”,“2a38ca8.538d236”]]},{“id”:“2f9848db.0c1c58”,“type”:“change”,“z”:“b6da215f.92716”,“name”:“set STATE_ACTIVE”,“rules”:[{“t”:“set”,“p”:“payload”,“pt”:“msg”,“to”:“STATE_ACTIVE”,“tot”:“str”}],“action”:“”,“property”:“”,“from”:“”,“to”:“”,“reg”:false,“x”:1400,“y”:720,“wires”:[[“fc76d58.c9a6c28”]]},{“id”:“7c4f6915.4e48e8”,“type”:“debug”,“z”:“b6da215f.92716”,“name”:“Debug Info”,“active”:true,“console”:“false”,“complete”:“payload”,“x”:1830,“y”:640,“wires”:},{“id”:“fc76d58.c9a6c28”,“type”:“rbe”,“z”:“b6da215f.92716”,“name”:“”,“func”:“rbei”,“gap”:“”,“start”:“”,“inout”:“out”,“x”:1670,“y”:580,“wires”:[[“35249b23.f02864”,“7c4f6915.4e48e8”]]},{“id”:“e0c90f4f.513a8”,“type”:“openhab2-controller”,“z”:“”,“name”:“openHAB”,“protocol”:“http”,“host”:“localhost”,“port”:“8080”,“path”:“”,“username”:“”,“password”:“”}]

Based on this experience, i this NodeRed is in minimum a perfect addon to the rule engine of openHAB and with openHABian it is a piece of cake to set it up.

Any comments, optimisations and and and are welcome.

Thomas

8 Likes

That looks really awesome. Thanks for sharing. :slight_smile:

Thanks for sharing @Dibbler42!

To be honest, I’m still not sure about NodeRED for my own use. Your picture looks cool for sure but is that supposed to be easier to write, read and modify than the ten lines of clear source code in my first posting? :upside_down:

2 Likes

@ThomDietrich

I’m not sure about that. For me it was a try and i transfered my “a little bite more than 10 lines” to node red just to try it. I hink it depends on programming skills and flow, rule or what ever to realise. A contact operated light is very simple to implement and leeds to quick results especially for beginners. But i am in doubt if it possible to tranfer my takerkoenig rule with item sorting and so on to node red.

Looking from my point it is annother option to work with and bring openHAB a little bit forward.

Thomas

That’s of course correct. That’s why we added NodeRED to openHABian and that’s why I’ve already linked your solution in the first posting here :wink:

1 Like

:+1:

I can´t read the power consumption, voltage etc. from a Sonoff POW flashed with Sonoff-Tasmota. The information page on the device says “Program version 5.0.6”

I have tried a few MQTT lines, such as:

Number nWama_Energy "Energy [%.1f]"  { mqtt="<[mosquitto:tele/sonoff-wama/ENERGY:state:default]" }

Number nWama_Energy "Energy [%.1f]"  { mqtt="<[mosquitto:tele/sonoff-wama/Power:state:default]" }

From the device console I see the following messages

01:10:22 MQTT: tele/sonoff-wama/STATE = {"Time":"2017-07-25T01:10:22", "Uptime":2, "Vcc":3.189, "POWER":"ON", "Wifi":{"AP":1, "SSID":"Home Zone", "RSSI":100, "APMac":"34:31:C4:5F:AC:8A"}}
01:10:22 MQTT: tele/sonoff-wama/ENERGY = {"Time":"2017-07-25T01:10:22", "Total":0.040, "Yesterday":0.015, "Today":0.025, "Period":2, "Power":30, "Factor":0.91, "Voltage":230, "Current":0.143}

I either see a dash or 0.0 as the item value.

Can somebody please give me a hint or share his items configuration?

Switch		box_heater				"Heater [%s]"				<radiator>	(gILeft)	{ mqtt="<[mqtt-loc:stat/box-heater/POWER:state:default],
																								<[mqtt-loc:tele/box-heater/STATE:state:JSONPATH($.POWER)],
																								>[mqtt-loc:cmnd/box-heater/power:command:*:default]"}
Number		box_heater_voltage		"Voltage [%d V]"			<energy>				{ mqtt="<[mqtt-loc:tele/box-heater/ENERGY:state:JSONPATH($.Voltage)]"}
Number		box_heater_current		"Current [%.3f А]"			<energy>				{ mqtt="<[mqtt-loc:tele/box-heater/ENERGY:state:JSONPATH($.Current)]"}
Number		box_heater_power		"Power [%.1f Wt]"			<energy>				{ mqtt="<[mqtt-loc:tele/box-heater/ENERGY:state:JSONPATH($.Power)]"}
Number		box_heater_today		"Today [%.3f kWt]"			<line>					{ mqtt="<[mqtt-loc:tele/box-heater/ENERGY:state:JSONPATH($.Today)]"}
Number		box_heater_yesterday	"Yesterday [%.3f кВт]"		<line>					{ mqtt="<[mqtt-loc:tele/box-heater/ENERGY:state:JSONPATH($.Yesterday)]"}

DateTime	box_heater_update		"Update [%1$ta %1$tR]"		<clock>					{ mqtt="<[mqtt-loc:tele/box-heater/STATE:state:JSONPATH($.Time)]"}
Number		box_heater_uptime		"Uptime [%d]"				<clock>					{ mqtt="<[mqtt-loc:tele/box-heater/STATE:state:JSONPATH($.Uptime)]"}
String		box_heater_state		"State [%s]"				<switch>				{ mqtt="<[mqtt-loc:tele/box-heater/STATE:state:JSONPATH($.POWER)]"}
Number		box_heater_rssi			"RSSI [%d %%]"				<signal>				{ mqtt="<[mqtt-loc:tele/box-heater/STATE:state:JSONPATH($.Wifi.RSSI)]"}
String		box_heater_lwt			"LWT [%s]"					<signal>				{ mqtt="<[mqtt-loc:tele/box-heater/LWT:state:default]"}

Thank you so much for sharing.
In order for that JSONPATH thing to work, I would need a rule, correct? If yes, would you also share your rule, please?

Rule is not necessary, you need to establish a transformation.

Bingo, thank you!!!

Also check out: https://github.com/arendst/Sonoff-Tasmota/wiki/openHAB#mandatory-topics--items

@Olymp feel free to add your items to the wiki article (in the right place)

1 Like

When I use the command

grep "Washingmachine_Power changed" /var/log/openhab2/events.log

on a Linux machine the output is only

Binary file /var/log/openhab2/events.log matches

instead of that nice listing . How can I extract the lines "nWama_Current changed " from the log file?

That does not seem to be the active log file but rather a compressed historical logfile.
You could do ‘zcat logfile | grep pattern’.
But if you’re looking for recent events you habe to Check the active logfile.

1 Like

Short question:

This values

val Number MODE_OFF = 0
val Number MODE_STANDBY = 1
val Number MODE_ACTIVE = 2
val Number MODE_FINISHED = 3

Can i use them inside my sitemap to make some visibility-switches too?

Or can i use this only inside the one rule rules-file, in that this is declared?