Extra (status) information from patterns

Hi folks,

I need the creativity/experience/knowledge of this community.

Finally I am monitoring (with some Shelly plug S) some of my devices at home:

  • Washing machine:

image

  • Dryer:

image

  • ...

These devices also have a series of different modes: long washing, eco wash, and so on...
Which means there are multiple different patterns, even for each single device.

I am now wondering in which way(s) I could get useful information from these measured patterns. And what I could do with that information. Some examples that pop up in my mind:

  • When the initial peak of the washing machine is completed, you could send a notification in your dashboard so that you can start another appliance that uses lots of power (to keep your peak demand a bit under control).
  • When the entire pattern is completed, you could send a notification in your dashboard that the laundry is ready.
  • And so on...

I could of course write some quick and dirty javascript code to determine this kind of stuff. But I am now wondering if there are perhaps way to have some reusable algorithm that I could use to extra information from any kind of pattern.

Of course it should be something practical, something that can be implemented in a short amount of time. No time to read a bunch of theoretical papers :yum:

Thanks!!
Bart

2 Likes

I looked into this a while back. Not easy to implement from scratch. This company offers solutions (I have not tried any of their products):

I think AI would be great for this.

Yes indeed @ghayne I had a (quick) look at that direction. But in that case I needed a wrapper library that makes life easy for me. Otherwise it will never happen... But didn't find one at first sight. I assume because I am using the wrong keywords, since I am not confident in that area.

You don't need a very deep analysis or indeed javascript to achieve your first two thoughts.

Personally I'd value an e-paper display next to the device with "Cost of last run ÂŁ9.99"

1 Like

Hi @jbudd,
Thanks for joining!
If you still have that flow somewhere, it would be nice if you could share it.
That explains indeed in a visual way the logic.

Hmm interesting. Did you implement something like that already in Node-RED?
My collegue at work also had an interesting idea: if the first high peak of the washing machine (i.e. much more power) is being used, then you could send a notification about the fact that an ECO cycle is preferred...

The little flow above? Well it's not real, I just used Node-red to draw a flow chart.

But the switch and trigger nodes are named descriptively, should be simple to reproduce.

I picked 10W arbitrarily as "in use" because who knows how much power an idle washing machine consumes?
Well you do, because of your shelly!

As for the display, I have never done it because I only have smart switches rated for 16 Chinese amps and I'm not sure of the correction factor for UK electricity. So no data.

I have used a smart switch and NR dashboard with an old espresso machine which has a similar consumption pattern - on continuously to boil the water tank then intermittently to maintain pressure.
I store instantaneous consumption values in a database and use SQL to analyse it. Eg how long the initial heating time was last time round can be used to estimate when the tank is nearly empty.

1 Like

I had not seen this post until now, but I had the same issue on finding out when my dryer was finished with a Shelly Pro Plug.

The way I solved it was to use the /aenergy/by_minute values that are returned. This has three values that are the amount of energy used for the previous three minutes. I used this to see if they all were less than a set threshold and report finished if so.

[{"id":"5eb9edf0837f1d1f","type":"change","z":"48f70e83376cab74","name":"Set Shelly Power Details","rules":[{"t":"set","p":"shellyDevices","pt":"flow","to":"{\"fcb467bee8f8\":{\"name\":\"Dryer\",\"threshold\":350,\"type\":\"I\",\"alertrecip\":\"user1\"}}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":290,"y":40,"wires":[[]]},{"id":"4f381a724fdd8d5e","type":"link in","z":"48f70e83376cab74","name":"Trigger - Startup","links":["6c98517f4e521057"],"x":115,"y":40,"wires":[["5eb9edf0837f1d1f"]],"icon":"font-awesome/fa-thumb-tack"},{"id":"e9c51bcd0ea74790","type":"link in","z":"48f70e83376cab74","name":"Shelly Power Plug","links":["28c4ec9d0ee61629"],"x":35,"y":40,"wires":[["fe62ef257cfd476a"]],"icon":"font-awesome/fa-power-off"},{"id":"287d959b0926e5af","type":"switch","z":"48f70e83376cab74","name":"Device\\n Select","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"Dryer","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":350,"y":160,"wires":[["ef823703414f6ee5"]]},{"id":"ef823703414f6ee5","type":"link out","z":"48f70e83376cab74","name":"Dryer","mode":"link","links":["64390ea627f84088","7e621ecc334d4472","ac3601ddfd865bc6","e7d03d4fe4c40dc2","dccee15310f12204","1c22c361dc9976a5"],"x":570,"y":160,"wires":[],"icon":"font-awesome/fa-power-off","l":true},{"id":"cf03708640fd8d83","type":"rbe","z":"48f70e83376cab74","name":"Alerts","func":"rbei","gap":"","start":"","inout":"out","septopics":true,"property":"payload","topi":"topic","x":350,"y":280,"wires":[["71856f01b40aac56"]]},{"id":"fe62ef257cfd476a","type":"delay","z":"48f70e83376cab74","name":"1/1s","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":55,"y":160,"wires":[["564cb4447e1156e1"]],"l":false},{"id":"71856f01b40aac56","type":"link out","z":"48f70e83376cab74","name":"PushOver","mode":"link","links":["a750115b04e3749b"],"x":560,"y":280,"wires":[],"icon":"node-red-node-pushover/pushover.png","l":true},{"id":"564cb4447e1156e1","type":"function","z":"48f70e83376cab74","name":"Format Data","func":"var func = global.get(\"func\");\nconst state = {\n    \"0\": \"Powered Off\",\n    \"1\": \"Powered On\",\n    \"R\": \"Running\",\n    \"F\": \"Finished\",\n    \"X\": \"Unknown State\"\n}\n\nvar now = new Date();\nvar time = func.formatDate(now).split(\" - \")[1];\nvar deviceList = flow.get(\"shellyDevices\") || [];\nif (deviceList.length == 0) { return null }\n\nvar mac = (msg.topic.split(\"/\")[1]);\nvar device = deviceList[mac];\nvar deviceName = device.name;\nvar deviceType = device.type;\nvar threshold  = device.threshold;\nvar alertrecip = device.alertrecip;\n\nmsg = {\n    topic:     deviceName,\n    threshold: threshold,\n    history:   [0,0,0],\n    output:    msg.payload.output,\n    apower:    msg.payload.apower,    // will be renamed to msg.payload\n    payload:   msg.payload\n}\n\nif (msg.payload.aenergy && msg.payload.aenergy.by_minute) {\n    msg.history = msg.payload.aenergy.by_minute\n}\n\n// There are two possible deviceType values:\n//    \n//    I: Intermittent : Devices that are ONLY powered on when they are required (Dryer, Washer, TV)\n//    C: Constant     : Devices that are ALWAYS powered on and reporting usage (Freezer, Rack)\n//    \n// ###############################################\n\nif (deviceType == \"C\") {\n    // START DEVICETYPE == \"C\" //\n    msg = msg;\n    // END DEVICETYPE == \"C\" //\n}\nelse if (deviceType == \"I\") {\n    // START DEVICETYPE == \"I\" //\n    var deviceData = flow.get(`p${msg.topic}`) || {opState: state[\"X\"], startTime: \"\"};\n    msg.opState  = deviceData.opState;\n    msg.started  = deviceData.startTime;\n    msg.updated  = time;\n    msg.duration = \"-\";\n\n    // Calculate duration (which may be zero)\n    if ((msg.opState != state[\"0\"]) || (msg.started != \"\")) {\n        var tUpdated = new Date(\"1970-01-01T\" + msg.updated).getTime();\n        var tStarted = new Date(\"1970-01-01T\" + msg.started).getTime();\n        var tDuration = ((tUpdated - tStarted) / 1000);\n        msg.duration = (func.convertTime(tDuration, \"short\"))\n    }\n\n    if (msg.output == false) {\n        msg.started = \"\";\n        msg.opState = state[\"0\"]\n        flow.set(`p${msg.topic}`, {opState: msg.opState, startTime: \"\", date: now});\n    }\n    else if (msg.output == true) {\n        if (deviceData.startTime == \"\") {      // Newly Powered On\n            msg.started = time;\n            msg.opState = state[\"1\"]\n            flow.set(`p${msg.topic}`, {opState: msg.opState, startTime: msg.started, date: now});\n        }\n        else {\n            // Continuing Power Usage - what is the power output (apower)\n            var aMinute = msg.history;\n            if ((aMinute[0] > msg.threshold) && (aMinute[1] > msg.threshold) && (aMinute[2] > msg.threshold)) { msg.opState = state[\"R\"] }\n\n            if (msg.opState == state[\"1\"]) {\n                if (aMinute[0] > msg.threshold) { msg.opState = state[\"R\"] }\n            }\n            else if (tDuration > 3600) {\n                if ((aMinute[1] < msg.threshold) && (aMinute[2] < msg.threshold)) { msg.opState = state[\"F\"] }\n            }\n            else {\n                if ((aMinute[0] < msg.threshold) && (aMinute[1] < msg.threshold)) { msg.opState = state[\"F\"] }\n                if ((aMinute[0] < msg.threshold) && (aMinute[2] < msg.threshold)) { msg.opState = state[\"F\"] }\n                if ((aMinute[0] < msg.threshold) && (aMinute[1] < msg.threshold) && (aMinute[2] < msg.threshold)) { msg.opState = state[\"F\"] }\n            }\n\n            flow.set(`p${msg.topic}`, {opState: msg.opState, startTime: deviceData.startTime, date: now});\n        }\n    }\n\n    if (msg.started == \"\") { msg.started = \"--:--:--\" }\n    // END DEVICETYPE == \"I\" //\n}\nelse {\n    // START UNKNOWN DEVICETYPE //\n    msg.topic   = \"Power Error\"\n    msg.opState = `Unknown 'deviceType' Value: ${deviceType}`\n    //  END UNKNOWN DEVICETYPE //\n}\n\nmsg.payload = msg.apower;\n\nreturn [\n    msg,\n    {topic: msg.topic, payload: msg.opState, device: alertrecip}\n]\n","outputs":2,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":170,"y":160,"wires":[["287d959b0926e5af"],["cf03708640fd8d83"]]},{"id":"2a092c751585d595","type":"group","z":"48f70e83376cab74","name":"fcb467bee8f8 - Dryer","style":{"stroke":"#ffC000","fill":"#ffefbf","fill-opacity":"0.25","label":true,"color":"#000000"},"nodes":["8c3bb350d5c6e7b1","e8c28d583cb5bcad","9fb570b8f92cf4b1","64390ea627f84088","8377cf2e9b5c2f5a","028d04f6be5e8cd4","ee414198db5be446","9eefd1d93fb09536","91a83caff4e558df"],"x":14,"y":699,"w":612,"h":122},{"id":"8c3bb350d5c6e7b1","type":"ui_text","z":"48f70e83376cab74","g":"2a092c751585d595","group":"b3dc5ac5c3026ddc","order":2,"width":3,"height":1,"name":"Watts","label":"","format":"{{msg.payload}} W","layout":"row-center","className":"","style":false,"font":"","fontSize":16,"color":"#000000","x":530,"y":740,"wires":[]},{"id":"e8c28d583cb5bcad","type":"ui_text","z":"48f70e83376cab74","g":"2a092c751585d595","group":"b3dc5ac5c3026ddc","order":3,"width":2,"height":1,"name":"Started","label":"{{msg.started}}","format":"","layout":"row-center","className":"","style":false,"font":"","fontSize":16,"color":"#000000","x":540,"y":780,"wires":[]},{"id":"9fb570b8f92cf4b1","type":"ui_chart","z":"48f70e83376cab74","g":"2a092c751585d595","name":"Chart","group":"b3dc5ac5c3026ddc","order":6,"width":7,"height":5,"label":"","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"Powered Off","dot":false,"ymin":"0","ymax":"1000","removeOlder":"1","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"className":"","x":230,"y":780,"wires":[[]]},{"id":"64390ea627f84088","type":"link in","z":"48f70e83376cab74","g":"2a092c751585d595","name":"Dryer","links":["ef823703414f6ee5","d8840cb1b67a45d2"],"x":55,"y":760,"wires":[["e8c28d583cb5bcad","8c3bb350d5c6e7b1","8377cf2e9b5c2f5a","028d04f6be5e8cd4","ee414198db5be446","91a83caff4e558df"]],"icon":"font-awesome/fa-power-off"},{"id":"8377cf2e9b5c2f5a","type":"change","z":"48f70e83376cab74","g":"2a092c751585d595","name":"Set opState","rules":[{"t":"set","p":"payload","pt":"msg","to":"opState","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":135,"y":740,"wires":[["9eefd1d93fb09536"]],"l":false},{"id":"028d04f6be5e8cd4","type":"ui_text","z":"48f70e83376cab74","g":"2a092c751585d595","group":"b3dc5ac5c3026ddc","order":5,"width":2,"height":1,"name":"Updated","label":"{{msg.updated}}","format":"","layout":"row-center","className":"","style":false,"font":"","fontSize":16,"color":"#000000","x":380,"y":780,"wires":[]},{"id":"ee414198db5be446","type":"ui_text","z":"48f70e83376cab74","g":"2a092c751585d595","group":"b3dc5ac5c3026ddc","order":4,"width":3,"height":1,"name":"Duration","label":"{{msg.duration}}","format":"","layout":"row-center","className":"","style":false,"font":"","fontSize":16,"color":"#000000","x":380,"y":740,"wires":[]},{"id":"9eefd1d93fb09536","type":"ui_led","z":"48f70e83376cab74","g":"2a092c751585d595","order":1,"group":"b3dc5ac5c3026ddc","width":4,"height":1,"label":"{{msg.opState}}","labelPlacement":"left","labelAlignment":"left","colorForValue":[{"color":"#000000","value":"Off","valueType":"str"},{"color":"#007fff","value":"Ready","valueType":"str"},{"color":"#00ff00","value":"Running","valueType":"str"},{"color":"#ff0000","value":"Finished","valueType":"str"}],"allowColorForValueInMessage":false,"shape":"circle","showGlow":false,"name":"State","x":230,"y":740,"wires":[]},{"id":"91a83caff4e558df","type":"function","z":"48f70e83376cab74","g":"2a092c751585d595","name":"History & Status","func":"var aMinute = msg.history;\nvar data = `${msg.updated} | ${parseInt(aMinute[0])} / ${parseInt(aMinute[1])} / ${parseInt(aMinute[2])} | ${msg.opState}`;\n\nnode.status({\n    fill:  \"blue\",\n    shape: \"dot\",\n    text:  data\n});\n\nif (msg.opState == \"Powered Off\") { return {payload: []}; }\nreturn msg;\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":135,"y":780,"wires":[["9fb570b8f92cf4b1"]],"icon":"node-red-contrib-home-assistant-websocket/ha-current-state.svg","l":false},{"id":"b3dc5ac5c3026ddc","type":"ui_group","name":"Garage - Dryer","tab":"9777d11ed41b8896","order":2,"disp":true,"width":"7","collapse":false,"className":""},{"id":"9777d11ed41b8896","type":"ui_tab","name":"Shelly Power","icon":"power_settings_new","order":7,"disabled":false,"hidden":false}]

The input is from a MQTT-In node for the plug.

This is also modular in that you can add many more plugs and have them reporting correctly as well as different types of usage. "Intermediate" for things like washers/dryers or "Permanent" for things like servers.

Names, thresholds and alert recipients are all device specific in the top change node called "Set Shelly Power Details"

Hope this helps

1 Like

I don't have Shellies but other smart switches with Tasmota.

I'm interested to know it the low code approach in my post above is not applicable to a Shelly? Does it not provide regular "current consumption" values?

It does, however I found that it's not enough to monitor just that metric as it depends on the device that is using the power.

For example, my dryer will fluctuate it's power requirements as needed to dry the clothes, but once that cycle has finished, it will use minimal power for about 10 minutes, then keep the clothes warm and spin them again for a bit.

In this instance, using your low code option would result in multiple alerts saying it had finished.

1 Like

This has arisen many times over the years in the openenergymonitor.org forum.
However most of it is in relation to identifying devices from a common supply, so it knows whether it's a washing machine, dishwasher etc.
Whereas you seem to be monitoring just one device, which makes things easier.
Don't know if the forum link above will take you any further....

1 Like

Thanks both.

Yes, a low code approach requires careful selection of the running/finished power consumption, different for each device type.
For example a washing machine has very high consumption while it's heating the water (unless it fills in a smart manner from hot and cold inlets), then again relatively high consumption when spinning.
A tumble dryer has repeated consumption spikes, and as @MyRandomThoughts says, a pause followed by more short heat/tumble cycles for an extended period.

My coffee machine monitor is far from being a low code solution because it uses some very complicated SQL to identify from momentary consumption records the times when it is performing the initial heat-up rather than simply maintaining the temperature/pressure.
I can use this data to estimate when the water tank is almost empty.
Image below shows 8 heat up events, a refill and two more heat ups.
image

1 Like