I wasn’t sure whether to post this in the Node Red subforum or the Home Assistant Companion App Subforum
I designed an automation in Node Red to give me a warning when mobile data usage is high.
This can be handy in some situations (e.g. if you’re abroad and you don’t realise you’re no longer on wifi, or sometimes I use a mobile hotspot so my son can play online games on his Nintendo Switch, but I don’t want him to download updates in such cases).
The Home Assistant Companion App enables two sensors showing mobile data usage:
- Total data receives in GB since last reboot
- Total data sent in GB since last reboot.
I’ve combined the two into a single sensor which sums data sent and received by adding this to configuration.yaml:
template:
- sensor:
- name: "Mobile Quizzical mobile data consumed since reboot"
unit_of_measurement: "GB"
state_class: "total_increasing" #Enables long term statistics
state: >
{% set sent = states('sensor.mobile_quizzical_mobile_tx_gb') | float %}
{% set received = states('sensor.mobile_quizzical_mobile_rx_gb') | float %}
{{ (sent + received) }}
The documentation says the sensor gets updated every 15 minutes, but I notice this is very variable, e.g. in case of low data use the frequency seems lower:
Combined | |
---|---|
Time | Total GB |
23:39:31 | 0.222 |
23:55:59 | 0.286 |
00:24:07 | 2.483 |
00:28:54 | 3.045 |
00:39:09 | 3.244 |
00:40:28 | 3.249 |
00:56:54 | 3.251 |
02:33:28 | 3.252 |
03:57:54 | 3.254 |
05:40:18 | 3.255 |
08:00:00 | 3.275 |
08:00:25 | 3.278 |
08:13:28 | 3.29 |
08:15:29 | 3.297 |
08:28:14 | 3.306 |
08:45:52 | 3.308 |
09:04:13 | 3.309 |
I’d want a warning if for example data usage reached 1 gigabyte and this in a timespan of less than one hour.
I’ve created an input helper in Home Assistant “input_number.warn_megabyte_per_hour_mobile_quizzical” so that in the UI I have a slider to dynamically adjust what should trigger a warning.
I’m using Node Red, and while I have made many dozens of automations I still don’t think I’m that good at it, but here’s what I came up with:
- Whenever there’s new data coming in, I fetch the last hour of history. Each value is checked and only the last fully ascending series is kept (to account for the fact that if the smartphone was rebooted the data usage gets reset).
- I check whether the difference between the lowest and highest value is larger than 1GB (in reality it’s comparing to a slider helper in Home Assistant so I can dynamically change the value for which I want to get a warning).
The main weakness is probably the limitation of how frequently it gets an update from the Home Assistant Companion App. Ideally the app would send an update very quickly when there is high data usage as it’s possible to use a lot of data in 15 minutes.
I’m sharing this as I haven’t seen anyone else who makes use of these sensors in the Home Assistant Companion App. And feel free to share a better version There might be bugs as I haven’t done a full testing of all scenario’s.
[{"id":"4bd548ba89f5a12b","type":"api-get-history","z":"34843a6c.50d986","name":"Get 1 hour of history","server":"5c29d263.09d2ac","version":0,"startdate":"","enddate":"","entityid":"sensor.mobile_quizzical_mobile_data_consumed_since_reboot","entityidtype":"is","useRelativeTime":true,"relativeTime":"60 minutes","flatten":true,"output_type":"array","output_location_type":"msg","output_location":"payload","x":480,"y":280,"wires":[["7cf5d5c69508d79d","b4f3382a9032435b"]]},{"id":"2f6f6d7ab36e7fd6","type":"change","z":"34843a6c.50d986","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"\"Quizzical you've used \"&difference&\"GB of mobile data in less than 1 hour\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1360,"y":280,"wires":[["90e2090f2265cbc1"]]},{"id":"90e2090f2265cbc1","type":"debug","z":"34843a6c.50d986","name":"debug 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1520,"y":280,"wires":[]},{"id":"60b4bef1336b7fbb","type":"server-state-changed","z":"34843a6c.50d986","name":"Mobile quizzical","server":"5c29d263.09d2ac","version":4,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"sensor.mobile_quizzical_mobile_data_consumed_since_reboot","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":false,"for":"0","forType":"num","forUnits":"minutes","ignorePrevStateNull":false,"ignorePrevStateUnknown":false,"ignorePrevStateUnavailable":false,"ignoreCurrentStateUnknown":false,"ignoreCurrentStateUnavailable":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"eventData"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":150,"y":280,"wires":[["10738e127024fb17"]]},{"id":"079391609e94d577","type":"switch","z":"34843a6c.50d986","name":"> warning limit?","property":"$globalContext(\"homeassistant.homeAssistant.states['input_number.warn_megabyte_per_hour_mobile_quizzical'].state\")","propertyType":"jsonata","rules":[{"t":"lte","v":"msg.differencemb","vt":"msg"}],"checkall":"true","repair":false,"outputs":1,"x":1180,"y":280,"wires":[["2f6f6d7ab36e7fd6","977e07e630b26f8d"]]},{"id":"b4f3382a9032435b","type":"function","z":"34843a6c.50d986","name":"Only keep last ascending series","func":"msg.payload = msg.payload.reduce((acc, obj) => {// iterates through \n //payload array setting each element in turn to obj\n // acc will be the output\n let value = Number(obj.state); // changes obj.state to a number\n if(value < acc.total){ // check to see if new state is lower than last\n acc = {total:0,arr:[obj]}; // sets acc to object, wiping values\n }else{// otherwise\n acc.total = value;// sets acc.total to save last value\n acc.arr.push(obj);// pushes obj to acc\n }\n return acc;// returns acc ready for next array element\n},{total:0,arr:[]}// initialises acc to an object with 2 properties\n).arr// output just the array from the object returned\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":730,"y":280,"wires":[["f16c8b60ae9f7587","1ca43fa4b2f30882"]]},{"id":"f16c8b60ae9f7587","type":"function","z":"34843a6c.50d986","name":"get Min & Max value","func":"const [min, max] = msg.payload.reduce((acc, current) => {\n if(isNaN(current.state)) return [acc[0], acc[1]];\n return [\n Math.min(current.state, acc[0]), \n Math.max(current.state, acc[1])\n ];\n}, [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY ]);\nmsg.difference = (max - min).toFixed(2);\nmsg.differencemb = (max - min) * 1000;\nmsg.payload = {min, max};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":980,"y":280,"wires":[["079391609e94d577"]]},{"id":"10738e127024fb17","type":"trigger","z":"34843a6c.50d986","name":"wait 5s","op1":"","op2":"","op1type":"nul","op2type":"pay","duration":"5","extend":false,"overrideDelay":false,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":300,"y":280,"wires":[["4bd548ba89f5a12b"]]},{"id":"5c29d263.09d2ac","type":"server","name":"Home Assistant","version":4,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30,"areaSelector":"friendlyName","deviceSelector":"friendlyName","entitySelector":"friendlyName","statusSeparator":"at: ","statusYear":"hidden","statusMonth":"short","statusDay":"numeric","statusHourCycle":"h23","statusTimeFormat":"h:m"}]
I end the automation here with the result. For you to see what you do with it (a simple message on your phone, a high priority message that sounds an alarm on your/your partners mobile device, automatically disconnect the mobile internet,…)