Die LaMetric Anzeige eignet sich hervorragend, um weitere Informationen zum Stromverbrauch und Batterieladestand von HomeAssistant anzeigen zu lassen. Auch in diesem Fall unterstützt mich die NodeRed Integration hier.
In HomeAssistant gibt es auch eine direkte Intgeration (LaMetric – Home Assistant (home-assistant.io)). Diese kann aber nur Notfications anzeigen. Und das war mir ein bisschen zu wenig.
Als Vorbereitung habe ich folgende Grundlagen sichergestellt:
- Developer Account für LaMetric erstellt und eine neue Indicator Poll App angelegt
(alternativ kann die App My Data (DIY) App on LaMetric Market | LaMetric Time clock for smart home verwendet werden – allerdings kann man da keine Authentifizierung einbauen). - Sichergestellt, dass NodeRed Endpoints auch mit HomeAssistant sauber funktionieren.
Dann habe ich den folgenden Flow erstellt:
Dieser Flow gibt beim Aufruf des definierten Endpoints die korrekte JSON Antwort zurück. Er ist dynamisch und ergänzt mir je nach Verbraucher die entsprechenden „Frames“. Wie so eine JSON Antwort aussehen kann, ist übrigens hier ausgezeichnet beschrieben. Die Icons findet ihr am Besten jeweils hier.
Hier das komplette Beispiel:
[{"id":"7b9046f8e332ea49","type":"tab","label":"LaMetric","disabled":false,"info":"","env":[]},{"id":"2b0554fccc7c10b9","type":"function","z":"7b9046f8e332ea49","name":"Tesla","func":"let obj = \n{\n \"text\": msg.data + \"W\", \n \"icon\": 7421,\n};\nmsg.payload.frames[msg.counter] = obj;\nmsg.counter = msg.counter + 1;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1030,"y":320,"wires":[["4f7f181fb616955b"]]},{"id":"1f9cfe2d528de7da","type":"api-current-state","z":"7b9046f8e332ea49","name":"","server":"145b1a79.688086","version":3,"outputs":2,"halt_if":"0","halt_if_type":"num","halt_if_compare":"gt","entity_id":"sensor.easee_consumption_w","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":530,"y":340,"wires":[["2b0554fccc7c10b9"],["4f7f181fb616955b"]]},{"id":"4f7f181fb616955b","type":"api-current-state","z":"7b9046f8e332ea49","name":"","server":"145b1a79.688086","version":3,"outputs":2,"halt_if":"090","halt_if_type":"num","halt_if_compare":"gt","entity_id":"sensor.heatpump_consumption_w","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":540,"y":420,"wires":[["938991cf2cacc5e4"],["2b4c726e81ee01eb"]]},{"id":"2b4c726e81ee01eb","type":"api-current-state","z":"7b9046f8e332ea49","name":"","server":"145b1a79.688086","version":3,"outputs":2,"halt_if":"0","halt_if_type":"num","halt_if_compare":"gt","entity_id":"sensor.whirlpool_heater_power","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":530,"y":500,"wires":[["2af5fabed15389e9"],["945e48d42d335a9a"]]},{"id":"938991cf2cacc5e4","type":"function","z":"7b9046f8e332ea49","name":"Wärmepumpe","func":"let obj = \n{\n \"text\": msg.data + \"W\", \n \"icon\": 24564,\n};\nmsg.payload.frames[msg.counter] = obj;\nmsg.counter = msg.counter + 1;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1060,"y":400,"wires":[["2b4c726e81ee01eb"]]},{"id":"2af5fabed15389e9","type":"function","z":"7b9046f8e332ea49","name":"Whirlpool","func":"let obj = \n{\n \"text\": msg.data + \"W\", \n \"icon\": 9196,\n};\nmsg.payload.frames[msg.counter] = obj;\nmsg.counter = msg.counter + 1;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1040,"y":480,"wires":[["945e48d42d335a9a"]]},{"id":"64593cef4cb3d57c","type":"api-current-state","z":"7b9046f8e332ea49","name":"","server":"145b1a79.688086","version":3,"outputs":2,"halt_if":"0","halt_if_type":"num","halt_if_compare":"gt","entity_id":"sensor.solar_power_w","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":510,"y":260,"wires":[["ebed37c27d4822ec"],["1f9cfe2d528de7da"]]},{"id":"ebed37c27d4822ec","type":"function","z":"7b9046f8e332ea49","name":"Solarstrom","func":"let obj = \n{\n \"text\": msg.data + \"W\", \n \"icon\": 34921,\n};\nmsg.payload.frames[msg.counter] = obj;\nmsg.counter = msg.counter + 1;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1050,"y":240,"wires":[["1f9cfe2d528de7da"]]},{"id":"78ec095a22620f33","type":"http in","z":"7b9046f8e332ea49","name":"","url":"/meinlametric","method":"get","upload":false,"swaggerDoc":"","x":100,"y":60,"wires":[["2662394f2ee325a9"]]},{"id":"4d833c547c3a9433","type":"http response","z":"7b9046f8e332ea49","name":"","statusCode":"200","headers":{},"x":1220,"y":760,"wires":[]},{"id":"2662394f2ee325a9","type":"change","z":"7b9046f8e332ea49","name":"","rules":[{"t":"set","p":"counter","pt":"msg","to":"0","tot":"num"},{"t":"set","p":"payload","pt":"msg","to":"{\"frames\":[]}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":330,"y":60,"wires":[["b6d84d81997e56e6"]]},{"id":"f04cc3ddeb847126","type":"function","z":"7b9046f8e332ea49","name":"Battery SOC Anzeige","func":"let icon = 2741;\nif (msg.data2>10) \n{\n icon = 10892;\n} else if (msg.data2<-10) {\n icon = 45705;\n} else if (msg.data>95) \n{\n icon = 2741;\n} else if (msg.data>75) \n{\n icon = 2740;\n} else if (msg.data>50) \n{\n icon = 2739;\n} else if (msg.data>25) \n{\n icon = 2738;\n} else {\n icon = 2737;\n}\nlet obj = \n{\n \"goalData\": \n {\n \"start\": 0,\n \"end\": 100,\n \"current\": msg.data,\n \"unit\": \"%\"\n },\n \"icon\": icon\n};\nmsg.payload.frames[msg.counter] = obj;\nmsg.counter = msg.counter + 1;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1080,"y":120,"wires":[["f83ec808ed1613d0"]]},{"id":"8c713f3eade9052d","type":"function","z":"7b9046f8e332ea49","name":"Hausverbrauch","func":"let obj = \n{\n \"text\": msg.data + \"W\", \n \"icon\": 8441,\n};\nmsg.payload.frames[msg.counter] = obj;\nmsg.counter = msg.counter + 1;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1060,"y":180,"wires":[["64593cef4cb3d57c"]]},{"id":"945e48d42d335a9a","type":"api-current-state","z":"7b9046f8e332ea49","name":"","server":"145b1a79.688086","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.rocket_launch_1","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"entity"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":510,"y":580,"wires":[["e2981eb637336a2e"]]},{"id":"e2981eb637336a2e","type":"switch","z":"7b9046f8e332ea49","name":"","property":"data.attributes.launch_24h_warning","propertyType":"msg","rules":[{"t":"eq","v":"true","vt":"str"},{"t":"neq","v":"true","vt":"str"}],"checkall":"false","repair":false,"outputs":2,"x":730,"y":580,"wires":[["94d51672bb225a17"],["4d833c547c3a9433"]]},{"id":"94d51672bb225a17","type":"function","z":"7b9046f8e332ea49","name":"Rocket Launch - Vehicle","func":"let obj = \n{\n \"text\": msg.data.attributes.vehicle, \n \"icon\": 35531,\n};\nmsg.payload.frames[msg.counter] = obj;\nmsg.counter = msg.counter + 1;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1090,"y":560,"wires":[["1f83d96b5aa5a8c1"]]},{"id":"f83ec808ed1613d0","type":"api-current-state","z":"7b9046f8e332ea49","name":"","server":"145b1a79.688086","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.house_consumption","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":520,"y":180,"wires":[["8c713f3eade9052d"]]},{"id":"b6d84d81997e56e6","type":"api-current-state","z":"7b9046f8e332ea49","name":"","server":"145b1a79.688086","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.battery_soc","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"data","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":600,"y":60,"wires":[["b4191f61db6d8824"]]},{"id":"b4191f61db6d8824","type":"api-current-state","z":"7b9046f8e332ea49","name":"","server":"145b1a79.688086","version":3,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"sensor.battery_consumption_production_diff","state_type":"num","blockInputOverrides":false,"outputProperties":[{"property":"data2","propertyType":"msg","value":"","valueType":"entityState"}],"for":"0","forType":"num","forUnits":"minutes","override_topic":false,"state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","x":1000,"y":60,"wires":[["f04cc3ddeb847126"]]},{"id":"1f83d96b5aa5a8c1","type":"function","z":"7b9046f8e332ea49","name":"Rocket Launch - Coundtdown","func":"let seconds = Math.floor((Date.parse(msg.data.attributes.launch_target) - Date.now())/1000);\nlet hours = Math.floor(seconds/(60*60),0);\nseconds -= (hours * 60 * 60);\nlet minutes = Math.floor(seconds/60,0);\nseconds -= (minutes * 60);\nlet obj = \n{\n \"text\": hours + \"h \" + minutes + \"m\", \n \"icon\": 42127,\n};\nmsg.payload.frames[msg.counter] = obj;\nmsg.counter = msg.counter + 1;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1110,"y":620,"wires":[["4d833c547c3a9433"]]},{"id":"145b1a79.688086","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30"}]
Besonderheiten:
- Battery SOC Anzeige: Steuert auch das anzuzeigende Icon
- Einige Statusabfragen haben Konditionen und werden nur weiterbearbeitet, falls als ein „sinnvoller“ Wert vorhanden.
- Rocket Launch – Countdown: Berechnet den Zeitpunkt zum Start
In der eigenen LaMetric App setze ich dann auf die URL http://meinhomeassistant:1880/endpoint/meinlametric und eine Aktualisierung alle 30 Sekunden. Bei meiner Integration war zudem noch eine Basic Authentication notwendig.
Dann installiere ich meine eigene App auf der LaMetric und los gehts.