Tried a couple different templates I found on the forums to do a simple stopwatch. Trying to do sensor showing a time of the current state of a sensor that is either “Drying” or “Door Open”, which turned out to be a mess of not working. Think I’ll just abandon and go with my original idea and just add it to my Nodered flow I have of dryer/washer notifications, have it push back a time in a loop every minute or something like that.
looks a bit complicated, but it works:
{{(as_timestamp(now()) - as_timestamp(states.sensor.upstairs_temperature.last_updated | default(0))) | timestamp_custom("%d")|int-1}} Days {{(as_timestamp(now()) - as_timestamp(states.sensor.upstairs_temperature.last_updated | default(0))) | timestamp_custom("%H")|int-1}} Hours {{(as_timestamp(now()) - as_timestamp(states.sensor.upstairs_temperature.last_updated | default(0))) | timestamp_custom("%M")|int}} Minutes ago
Think I recall finding another post of yours with that template but it was showing like 30 days for some odd reason when I threw it in the test template deal on the config page. I’ll give it a go in the yaml though and see what happens. On the list for tonight unless my Aliexpress package of goodies gets delivered…
Showing Unknown if I paste it into the sensor template config, but in the templates tester page it shows the 30 days thing. When check the actual trigger time it shows a few seconds ago.
- platform: template
sensors:
dryer_doortime:
friendly_name: "Door Open Time"
value_template: >
{{(as_timestamp(now()) - as_timestamp(states.automation.dryer_door_stopwatch.attributes.last_triggered | default(0))) | timestamp_custom("%d")|int-1}} Days {{(as_timestamp(now()) - as_timestamp(states.automation.dryer_door_stopwatch.attributes.last_triggered | default(0))) | timestamp_custom("%H")|int-1}} Hours {{(as_timestamp(now()) - as_timestamp(states.automation.dryer_door_stopwatch.attributes.last_triggered | default(0))) | timestamp_custom("%M")|int}} Minutes ago
Somehow I had to subtract 1 for the day. Try and replace int-1
with int
and see if it’s better
Sorry for the thread bump but google directs me here.
I used (parts of) the code above to detect the status of my washing machine and run a stopwatch.
The code above is unfortunatly not compatible anymore with the current home assistant.
So I want to give back to the community and post my endresult here. (it works stable for me for over a year now)
Setup:
I use a Sonoff power monitor with tasmota to monitor the current of the washing machine. But any power-sensor should do.
I want to see if the washing machine is currenly on, and if so for how long (so I could estimate if it was almost done or not)
And get a notification when it was done off course
I also have a dryer and to monitor that one I duplicated and renamed everything, You can do that too so I’m not going to post everything twice
Sensor setup
Add the following template sensor (the 10 and 18 values are watts and might need tuning for your device)
- platform: time_date
display_options:
- 'time_date'
- platform: mqtt
state_topic: "tele/sonoff-pow1/SENSOR"
name: "Washing machine power usage"
unit_of_measurement: 'W'
value_template: "{{value_json['ENERGY'].Power }}"
- platform: template
sensors:
washing_machine_power_down:
value_template: "{{ states('sensor.washing_machine_power_usage') | int < 10 }}"
washing_machine_power_up:
value_template: "{{ states('sensor.washing_machine_power_usage') | int > 18 }}"
washing_machine_stopwatch:
friendly_name: "Time Elapsed"
value_template: >-
{% if is_state('input_boolean.washing_machine_switch', 'on') and as_timestamp(strptime(states.sensor.time_date.state, "%H:%M, %Y-%m-%d")) > 0 %}
{{ (as_timestamp(now()) - as_timestamp(states.automation.washing_machine_start.attributes.last_triggered)) | timestamp_custom("%H:%M", false) }}
{% elif is_state('input_boolean.washing_machine_switch', 'off') %}
Idle
{% elif is_state('sensor.washing_machine_stopwatch', 'unknown') %}
Unknown
{% else %}
{{ states('sensor.washing_machine_stopwatch') }}
{% endif %}
Input boolean
Add the following input to make a simple on/off status.
input_boolean:
washing_machine_switch:
name: "Washer in Use"
icon: mdi:settings
Automation
The first automation is to detect a “start”, the second one is to detect the completion/stop of the washing machine.
In my case I use a telegram notification to notify me, but you could replace it with anything else.
# ----------- Notification when washing machine is done -----------
- alias: "Washing Machine Start"
trigger:
platform: state
entity_id: sensor.washing_machine_power_up
from: 'False'
to: 'True'
for: '00:01:00'
condition:
condition: state
entity_id: input_boolean.washing_machine_switch
state: 'off'
action:
- service: input_boolean.turn_on
entity_id: input_boolean.washing_machine_switch
- alias: "Washing Machine Finish Notification"
trigger:
- platform: state
entity_id: sensor.washing_machine_power_down
from: 'False'
to: 'True'
for: '00:03:00'
condition:
condition: state
entity_id: input_boolean.washing_machine_switch
state: 'on'
action:
- service: notify.TELEGRAM_NOTIFY_XXXXXXX
data:
title: "*Washing Done*"
message: "Please move laundry to dryer\r\nTime Taken: {{ states('sensor.washing_machine_stopwatch') }}"
- service: input_boolean.turn_off
entity_id: input_boolean.washing_machine_switch
Customize config
Hide some values we do not need to see (but need for coding)
sensor.washing_machine_power_down:
hidden: true
sensor.washing_machine_power_up:
hidden: true
Group config
Combine all values neatly together
laundry_room:
name: Laundry
view: no
control: hidden
entities:
- input_boolean.washing_machine_switch
- sensor.washing_machine_power_usage
- sensor.washing_machine_stopwatch
Really nice job on this one. I switched my automations to Node-Red a little while ago so this was a bit of a blast to see it re-coded. Looks nice and tidy compared to how I had it.
don’t forget to also add a date_time sensor.
- platform: time_date
display_options:- ‘time’
#- ‘date’
#- ‘date_time’ - ‘time_date’
#- ‘time_utc’
#- ‘beat’
- ‘time’
Good point! I’ve added it to the example.
How are you tracking run time in Node Red? I’m looking at setting this up myself but am quite stumped on this piece…
Can you post your flow by chance?
Sure, here ya go. It’s not perfect but it works. The way i’m tracking runtime is with the interval length function. I ping it when the washer starts and ping it again when it stops (which is relayed through my current sensing Wemo plug; tracking the power of the washer) and when the interval length receives the second ping it outputs the time between the two pings.
[{"id":"ad68cd41.9bebb","type":"api-call-service","z":"c28561a9.2237e","name":"Set status to idle","server":"e3f4406a.ed517","service_domain":"input_select","service":"select_option","data":"{ \"entity_id\": \"input_select.washer_status\"}","mergecontext":"","x":630,"y":60,"wires":[[]]},{"id":"9a6ec2f3.a8f05","type":"trigger-state","z":"c28561a9.2237e","name":"Is Wash Monitor off?","server":"e3f4406a.ed517","entityid":"binary_sensor.washing_machine","debugenabled":false,"constraints":[{"id":"haqv32bh5wd","targetType":"this_entity","targetValue":"","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":"is","comparatorValueDatatype":"str","comparatorValue":"off"},{"id":"hy1onrmeh1u","targetType":"entity_id","targetValue":"sensor.washer_current_power","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":"less_than","comparatorValueDatatype":"num","comparatorValue":"6"}],"constraintsmustmatch":"all","outputs":2,"customoutputs":[],"outputinitially":false,"x":160,"y":60,"wires":[["8d74354c.30f0d8"],[]]},{"id":"c31fd9b3.ef8198","type":"server-state-changed","z":"c28561a9.2237e","name":"Washer Running (Monitor On)","server":"e3f4406a.ed517","entityidfilter":"binary_sensor.washing_machine","entityidfiltertype":"substring","outputinitially":false,"haltifstate":"off","outputs":1,"x":130,"y":120,"wires":[["cdd3262.cafc1d8"]]},{"id":"1430c822.0d4418","type":"api-call-service","z":"c28561a9.2237e","name":"Set to Cleaning","server":"e3f4406a.ed517","service_domain":"input_select","service":"select_option","data":"{ \"entity_id\": \"input_select.washer_status\" }","mergecontext":"","x":620,"y":120,"wires":[["c50e3fff.17391"]]},{"id":"e1dd7c5d.f4ea3","type":"trigger-state","z":"c28561a9.2237e","name":"Is Wash Cycle Complete?","server":"e3f4406a.ed517","entityid":"input_select.washer_status","debugenabled":false,"constraints":[{"id":"8q74nfn2inn","targetType":"this_entity","targetValue":"","propertyType":"current_state","propertyValue":"new_state.state","comparatorType":"is","comparatorValueDatatype":"str","comparatorValue":"Idle"},{"id":"08p0f32evee","targetType":"this_entity","targetValue":"","propertyType":"previous_state","propertyValue":"old_state.state","comparatorType":"is","comparatorValueDatatype":"str","comparatorValue":"Cleaning"}],"constraintsmustmatch":"all","outputs":2,"customoutputs":[],"outputinitially":false,"x":110,"y":260,"wires":[["c33f7db1.e242d","f2ba219d.425f3","1e27b2dc.5186ad","c50e3fff.17391","a39f505d.b6a43","888b1ad.e5306e8","50aff492.f4c7bc"],[]]},{"id":"7c6720de.c6b78","type":"api-call-service","z":"c28561a9.2237e","name":"Set status to Complete","server":"e3f4406a.ed517","service_domain":"input_select","service":"select_option","data":"{ \"entity_id\": \"input_select.washer_status\"}","mergecontext":"","x":1020,"y":260,"wires":[[]]},{"id":"1f433ef2.78b991","type":"api-call-service","z":"c28561a9.2237e","name":"Apri's iPhone","server":"e3f4406a.ed517","service_domain":"notify","service":"ios_april_rockwells_iphone","data":"{}","mergecontext":"","x":990,"y":300,"wires":[[]]},{"id":"d6faf789.382608","type":"function","z":"c28561a9.2237e","name":"Format data for iOS","func":"msg.payload = {\n \"data\": \n {\n \"message\":\"Wash cycle completed in \" + msg.washtime\n }\n}\nreturn msg;","outputs":1,"noerr":0,"x":750,"y":300,"wires":[["1f433ef2.78b991"]]},{"id":"cdd3262.cafc1d8","type":"function","z":"c28561a9.2237e","name":"Format data for HA","func":"var newMsg = { \n payload:{ \n \"data\":{ \n \"entity_id\":\"input_select.washer_status\",\n \"option\":\"Cleaning\"\n}\n }\n}\nreturn newMsg;","outputs":1,"noerr":0,"x":370,"y":120,"wires":[["1430c822.0d4418"]]},{"id":"8d74354c.30f0d8","type":"function","z":"c28561a9.2237e","name":"Format data for HA","func":"var newMsg = { \n payload:{ \n \"data\":{ \n \"entity_id\":\"input_select.washer_status\",\n \"option\":\"Idle\"\n}\n }\n}\nreturn newMsg;","outputs":1,"noerr":0,"x":370,"y":60,"wires":[["ad68cd41.9bebb"]]},{"id":"c33f7db1.e242d","type":"function","z":"c28561a9.2237e","name":"Format data for HA","func":"var newMsg = { \n payload:{ \n \"data\":{ \n \"entity_id\":\"input_select.washer_status\",\n \"option\":\"Wash Cycle Complete\"\n}\n }\n}\nreturn newMsg;","outputs":1,"noerr":0,"x":550,"y":260,"wires":[["7c6720de.c6b78"]]},{"id":"f2ba219d.425f3","type":"function","z":"c28561a9.2237e","name":"Format data for Google TTS","func":"var newMsg = { \n payload:{ \n \"data\":{ \n \"message\":\"Wash cycle completed in \" + msg.washtime\n }\n }\n}\nreturn newMsg;","outputs":1,"noerr":0,"x":780,"y":420,"wires":[["ef19e7cd.5a5388"]]},{"id":"ef19e7cd.5a5388","type":"api-call-service","z":"c28561a9.2237e","name":"Man Cave Speakers","server":"e3f4406a.ed517","service_domain":"tts","service":"google_say","data":"{ \"entity_id\":\"media_player.man_cave_speakers\" }","mergecontext":"","x":1020,"y":420,"wires":[[]]},{"id":"1e27b2dc.5186ad","type":"api-call-service","z":"c28561a9.2237e","name":"Turn on Speakers","server":"e3f4406a.ed517","service_domain":"switch","service":"turn_on","data":"{ \"entity_id\": \"switch.logitech_speakers\" }","mergecontext":"","x":550,"y":220,"wires":[[]]},{"id":"85c16fc1.88219","type":"comment","z":"c28561a9.2237e","name":"Washing Machine Monitor","info":"","x":130,"y":20,"wires":[]},{"id":"c50e3fff.17391","type":"interval-length","z":"c28561a9.2237e","format":"human","bytopic":false,"minimum":"1","maximum":"60","window":"","timeout":false,"msgTimeout":"","minimumunit":"mins","maximumunit":"mins","windowunit":"secs","msgTimeoutUnit":"secs","reset":false,"startup":false,"msgField":"washtime","timestampField":"timestamp","repeatTimeout":false,"name":"","x":280,"y":200,"wires":[["f2ba219d.425f3","a39f505d.b6a43","888b1ad.e5306e8","50aff492.f4c7bc"],[]]},{"id":"888b1ad.e5306e8","type":"api-current-state","z":"c28561a9.2237e","name":"Is Derrick Home?","server":"e3f4406a.ed517","outputs":1,"halt_if":"not_home","override_topic":true,"entity_id":"device_tracker.galaxys9lan","override_payload":true,"override_data":true,"x":550,"y":340,"wires":[["dad14bcd.646908"]]},{"id":"50aff492.f4c7bc","type":"api-current-state","z":"c28561a9.2237e","name":"Is Xander Home?","server":"e3f4406a.ed517","outputs":1,"halt_if":"not_home","override_topic":true,"entity_id":"device_tracker.d8bb2c096eee","override_payload":true,"override_data":true,"x":550,"y":380,"wires":[["f9fbedea.60eac"]]},{"id":"f9fbedea.60eac","type":"function","z":"c28561a9.2237e","name":"Format data for iOS","func":"msg.payload = {\n \"data\": \n {\n \"message\":\"Wash cycle completed in \" + msg.washtime\n }\n}\nreturn msg;","outputs":1,"noerr":0,"x":750,"y":380,"wires":[["2e20710e.26456e"]]},{"id":"2e20710e.26456e","type":"api-call-service","z":"c28561a9.2237e","name":"Xanders iPhone","server":"e3f4406a.ed517","service_domain":"notify","service":"ios_xanders_iphone","data":"{}","mergecontext":"","x":1000,"y":380,"wires":[[]]},{"id":"a39f505d.b6a43","type":"api-current-state","z":"c28561a9.2237e","name":"Is April Home?","server":"e3f4406a.ed517","outputs":1,"halt_if":"not_home","override_topic":true,"entity_id":"device_tracker.aprilrolsiphonelan","override_payload":true,"override_data":true,"x":540,"y":300,"wires":[["d6faf789.382608"]]},{"id":"dad14bcd.646908","type":"function","z":"c28561a9.2237e","name":"Format Data for Pushover","func":"msg.payload =\n{ \n \"data\":{ \n \"message\":\"Wash cycle completed in\" +msg.washtime\n }\n}\nreturn msg;","outputs":1,"noerr":0,"x":770,"y":340,"wires":[["93c7f49e.7edd98"]]},{"id":"93c7f49e.7edd98","type":"api-call-service","z":"c28561a9.2237e","name":"Pushbullet Notification","server":"e3f4406a.ed517","service_domain":"notify","service":"derrick_pushbullet","data":"","render_data":false,"mergecontext":"","x":1020,"y":340,"wires":[[]]},{"id":"e3f4406a.ed517","type":"server","z":"","name":"Home Assistant","legacy":false,"hassio":true,"rejectUnauthorizedCerts":true}]
Awesome, thanks! This gives me a great reference to work from!
So I’m running into a weird issue with the interval length node…
I’m doing almost exactly what you’ve done here, but the interval length node appears to trigger whenever a start or stop of the washer occurs… this leads to some strange behavior where when it goes from a stopped to a started state… I get notified for the interval between the last time it was stopped and the new start time… which obviously tends to be a really long time…
Am I doing something wrong here? I attempted to reset the interval length node… but that doesn’t solve the issue either…
Nevermind… I think I realized I can’t do exactly what I want with the interval length node…
I switched to tracking everything with a counter and it resolved my issue.
Thanks again!
Hi!
The config works awesome, except the time estimate. I always receive an error in HA.
“Could not render template Time Elapsed, the state is unknown.”
The date_time sensor is created and I have no idea whats the problem.
Hi, I’m glad to see that people are (still) using my creation
I still use it in the latest home assistant and it is working for me so I suspect a some config error.
Can you check if the following line renders in on the template test page? /developer-tools/template
{{ (as_timestamp(now()) - as_timestamp(states.automation.washing_machine_start.attributes.last_triggered)) | timestamp_custom("%H:%M", false) }}
If you change any name of a switch/automation you need to update all references to it.
Oh and it is “time_date” sensor instead of “date_time” sensor. But I think you just mixed up that when typing your message.
Thank you for your answer. I renamed the automation states.automation.washing_machine_start and that is the problem.
Now works perfect. Thank you again!