Heute wird es hier mal un-photographisch:
Seit einiger Zeit beschäftige ich mich mit der Smart Home Software Home Assistant, die ich auf einem Raspberry Pi 4 betreibe.
Das System ist in der Lage verschiedene Automatisierungs-Plattformen in einem System zu vereinen, so dass das System die Automatisierungskomponeneten der Fritzbox (Fritz!DECT – u.a. die Heizungsautomation die hier vor einigen Jahren beschrieben wurde) und vieles Andere zusammenführen kann (Z-Wave, ZigBee, WiFi).
Hier soll es jetzt im Detail darum gehen, wie ich an die Messwerte meiner Solaranlage im HA-System gekommen bin.
Unser 5kWh SENEC LI2.1 Batteriespeicher liefert die Daten über Web-Schnittstellen der Herstellers, was für die persönliche Information ok ist, aber für die Nutzung in Automatisierungen nichts nutzt.
Im ersten Schritt wurde über die Erweiterung HACS eine Datenintegration für den SENEC-Speicher installiert. Danach stehen die wesentlichen Daten zur Verfügung, wobei die Frequenz der Daten, wie in den Web-Interfaces eher gemächlich ist.
Erste praktische Nutzung war die Solargesteuerte Schaltung unseres 5l Warmwasser-Untertischgerätes in der Küche. Die Spannungsversorgung wird Abends um 22:00 ausgeschaltet und falls es nicht genug Solarstrom gibt spätestens um 10:00 Morgens wieder aktiviert. Die Restwärem reich in der Regel morgens aus solange man keinen großen Abwasch in der Zeit hat.
Solargesteuert wird der Speicher dann nach Sonnenaufgang eingeschaltet, sobald der Speicher mindestens einen Ladezustand von 5% hat und mindestens 500 Watt PV-Strom erzeugt werden.
Als zweite Anwendung wurde in einem bestimmten Zeitfensters am Morgen das Küchenrollo (über ein Shelly 2.5 WiFi Modul) zur Hälfte geschlossen wurde sobald die Sonne blendet ( > 3.000 Watt Energie erzeugt). Hier zeigte sich jedoch dass der Integral-Wert aus dem Senec-Speicher nicht präzise genug war, da unsere PV-Anlage nur 12 Module in Ost-Richtung (Küchenseite) hat und zusätzlich 20 Module auf der West-Seite so dass die „Störleistung“ vom Westen gegen Mittag deutlich zunimmt.
Der vorgeschaltete Wechselrichter von SMA weist über das Display Strom und Spannung über das eingebaute Display für Ost- & West-Seite separat aus. Nachdem ich festgestellt hatte, dass der Wechselrichter über eine ModBus-Schnittstelle verfügt habe ich mich auf die Suche nach Auslesemöglichkeiten gemacht und die Hypothese, dass sowas mit der grafischen Programmieroberfläche Node Red klappen könnte wurde nach einer kurzen Netz-Recherche bestätigt.
Also habe ich die Noder Red Erweiterung in Home Assistant installiert. Außerdem war die Installation einer Node Red Integration notwendig um die ausgelesenen Daten in das HA-System übergeben zu können.
Im Netz fand ich eine gut dokumentierte Umsetzung für so ein Problem (Hausbau Becker: Modbus Integration in Node-RED von SMA) wobei die Komplexität dieser Umsetzung deutlich reduziert werden konnte.
Meine abgespeckte Struktur, die tagsüber alle 60 Sekunden die Leitung von Ost- und West-Seite ausliest, sieht dann so aus – wobei die Abfrage bei ausgeschaltetem Wechselrichter (z.B.bei Dämmerung oder nachts) einen Messwert von -2,8 Mrd liefert, den ich dann abfangen musste.
Obwohl ich mittlerweile weitere Automatisierungen mit Node Red gebaut habe habe ich festgestellt, dass ich immer noch mit gefährlichem Halbwissen unterwegs bin, dann an der Aufgabe die beiden Messwerte für Ost und West zu einem gemeinsamen Total-Wert zu addieren und zu übergeben bin ich bisher gescheitert – wenn als da jemand bitte einen Tip für mich hätte……
Da der aktuelle Total-Wert noch aus der Senec-Anlage kommt führen Verluste und Unterschiede in der Aufzeichnungsfrequenz momentan dazu, dass der West-Messwert gelegentlich den Total-Wert überschreitet.
Die grafische Umsetzung in der Lovelace sieht dann so aus:
In der Garfana-Erweiterung lassen sich die Messwerte so darstellen:
----------------------------------------------------------------------------------------------------------------------------
Für Nerds und Nachahmer jetzt noch etwas Programm-Code:
Node Red:
[
{
"id": "d2d6601a.7125f8",
"type": "tab",
"label": "SMA-Gt",
"disabled": false,
"info": "Regelmäßiges Auslesen von Daten der Solaranlage \n\nSMA- Wechselrichter über ModBus"
},
{
"id": "929489d6.baa6b8",
"type": "inject",
"z": "d2d6601a.7125f8",
"name": "60s Abfrage",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "60",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"payload": "",
"payloadType": "date",
"x": 140,
"y": 100,
"wires": [
[
"875fd828.40cc58"
]
]
},
{
"id": "cca0add4.907ac8",
"type": "modbus-getter",
"z": "d2d6601a.7125f8",
"name": "30769 - 30774",
"showStatusActivities": false,
"showErrors": false,
"logIOActivities": false,
"unitid": "3",
"dataType": "InputRegister",
"adr": "30769",
"quantity": "6",
"server": "101bd986.8eac7e",
"useIOFile": false,
"ioFile": "",
"useIOForPayload": false,
"emptyMsgOnFail": false,
"keepMsgProperties": false,
"x": 280,
"y": 260,
"wires": [
[
"a18b0ca9.912008"
],
[]
]
},
{
"id": "a18b0ca9.912008",
"type": "buffer-parser",
"z": "d2d6601a.7125f8",
"name": "",
"data": "responseBuffer.buffer",
"dataType": "msg",
"specification": "spec",
"specificationType": "ui",
"items": [
{
"type": "int32be",
"name": "IDC1",
"offset": 0,
"length": 1,
"offsetbit": 0,
"scale": "0.001",
"mask": ""
},
{
"type": "int32be",
"name": "UDC1",
"offset": 4,
"length": 1,
"offsetbit": 0,
"scale": "0.01",
"mask": ""
},
{
"type": "int32be",
"name": "PDC1",
"offset": 8,
"length": 1,
"offsetbit": 0,
"scale": "1",
"mask": ""
}
],
"swap1": "",
"swap2": "",
"swap3": "",
"swap1Type": "swap",
"swap2Type": "swap",
"swap3Type": "swap",
"msgProperty": "payload",
"msgPropertyType": "str",
"resultType": "keyvalue",
"resultTypeType": "output",
"multipleResult": false,
"fanOutMultipleResult": false,
"setTopic": true,
"outputs": 1,
"x": 490,
"y": 260,
"wires": [
[
"955c6aca.99d25",
"57ae0485.de5dd4"
]
]
},
{
"id": "551b7111.b1355",
"type": "comment",
"z": "d2d6601a.7125f8",
"name": "STP 7000TL-20 711",
"info": "",
"x": 110,
"y": 20,
"wires": []
},
{
"id": "955c6aca.99d25",
"type": "function",
"z": "d2d6601a.7125f8",
"name": "P-DC1",
"func": "var temp = (msg.payload.PDC1)\nmsg.payload = temp;\nmsg.topic = \"PDC1\"\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 670,
"y": 260,
"wires": [
[
"8e18adba.7a6b08"
]
]
},
{
"id": "2da0ac02.2aa7cc",
"type": "function",
"z": "d2d6601a.7125f8",
"d": true,
"name": "Wirkungsgrad",
"func": "var temp = (msg.payload[\"PAC1\"] / msg.payload[\"PDC1\"]) * 100\nmsg.payload = temp; \nmsg.payload = msg.payload.toFixed(1).replace('.', ',');\nmsg.topic = \"W1\"\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 1720,
"y": 1480,
"wires": [
[
"f6c144b5.8804d8"
]
]
},
{
"id": "9d45249.2ec42d8",
"type": "join",
"z": "d2d6601a.7125f8",
"d": true,
"name": "",
"mode": "custom",
"build": "object",
"property": "payload",
"propertyType": "msg",
"key": "topic",
"joiner": "\\n",
"joinerType": "str",
"accumulate": false,
"timeout": "",
"count": "2",
"reduceRight": false,
"reduceExp": "",
"reduceInit": "",
"reduceInitType": "",
"reduceFixup": "",
"x": 1550,
"y": 1480,
"wires": [
[
"2da0ac02.2aa7cc"
]
]
},
{
"id": "f6c144b5.8804d8",
"type": "ui_text",
"z": "d2d6601a.7125f8",
"d": true,
"group": "bad4a5be.f7833",
"order": 6,
"width": 0,
"height": 0,
"name": "Wirkungsgrad1",
"label": "Wirkungsgrad",
"format": "{{msg.payload}} %",
"layout": "row-spread",
"x": 1720,
"y": 1520,
"wires": []
},
{
"id": "fde7ffd7.08bf28",
"type": "comment",
"z": "d2d6601a.7125f8",
"name": "Erklärung",
"info": "Einfache Procedur zum Auslesen der beiden Momentanleistungen (Ost=2, West=1) vom SMA Wechselrichter.\n\nTechnisch im Wesentlichen eine Abgespeckte Kopie von: \nhttp://hausbau-becker.blogspot.com/2020/09/modbus-integration-in-node-red-von-sma.html\n\n----------------------------------------------------\n\n\n\n\n\n\n\n\n\n\n\nErklärung Modbus Wert S32 / U32:\n\n1 Register besteht aus 2x 8bit = 2x 1 byte.\n1 Wert besteht aus 2 Registern = 32bit bzw. 4 byte.\n\nUm einen Wert abzufragen, fragt man immer 2 Register ab.\nAlso ist Quantity =2.\n\nOffset fängt bei 0 an.\nOffset 0 = 1. 8bit, 1 = 2. 8bit (1. Register)\nOffset 2 = 2. 8bit, 3 = 3. 8bit (2. Register)\n= ein 32bit Wert\n\nOffset für den nächsten Wert fängt bei 4 an.",
"x": 340,
"y": 60,
"wires": []
},
{
"id": "57ae0485.de5dd4",
"type": "modbus-getter",
"z": "d2d6601a.7125f8",
"name": "30957 - 30962",
"showStatusActivities": false,
"showErrors": false,
"logIOActivities": false,
"unitid": "3",
"dataType": "InputRegister",
"adr": "30957",
"quantity": "6",
"server": "101bd986.8eac7e",
"useIOFile": false,
"ioFile": "",
"useIOForPayload": false,
"emptyMsgOnFail": false,
"keepMsgProperties": false,
"x": 280,
"y": 360,
"wires": [
[
"408f41b.ad9324"
],
[]
]
},
{
"id": "408f41b.ad9324",
"type": "buffer-parser",
"z": "d2d6601a.7125f8",
"name": "",
"data": "responseBuffer.buffer",
"dataType": "msg",
"specification": "spec",
"specificationType": "ui",
"items": [
{
"type": "int32be",
"name": "IDC2",
"offset": 0,
"length": 1,
"offsetbit": 0,
"scale": "0.001",
"mask": ""
},
{
"type": "int32be",
"name": "UDC2",
"offset": 4,
"length": 1,
"offsetbit": 0,
"scale": "0.01",
"mask": ""
},
{
"type": "int32be",
"name": "PDC2",
"offset": 8,
"length": 1,
"offsetbit": 0,
"scale": "1",
"mask": ""
}
],
"swap1": "",
"swap2": "",
"swap3": "",
"swap1Type": "swap",
"swap2Type": "swap",
"swap3Type": "swap",
"msgProperty": "payload",
"msgPropertyType": "str",
"resultType": "keyvalue",
"resultTypeType": "output",
"multipleResult": false,
"fanOutMultipleResult": false,
"setTopic": true,
"outputs": 1,
"x": 490,
"y": 360,
"wires": [
[
"8e51436.29a97c"
]
]
},
{
"id": "8e51436.29a97c",
"type": "function",
"z": "d2d6601a.7125f8",
"name": "P-DC2",
"func": "var temp = (msg.payload.PDC2)\nmsg.payload = temp;\nmsg.topic = \"PDC2\"\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"x": 670,
"y": 360,
"wires": [
[
"31f909c7.6b172e"
]
]
},
{
"id": "69891463.07084c",
"type": "ha-entity",
"z": "d2d6601a.7125f8",
"name": "SMA Power West",
"server": "3ee43a18.3e87e6",
"version": 1,
"debugenabled": false,
"outputs": 1,
"entityType": "sensor",
"config": [
{
"property": "name",
"value": "sensor.pv_power_west"
},
{
"property": "device_class",
"value": "sensor"
},
{
"property": "icon",
"value": "mdi:solar-power"
},
{
"property": "unit_of_measurement",
"value": "W"
}
],
"state": "payload",
"stateType": "msg",
"attributes": [],
"resend": true,
"outputLocation": "",
"outputLocationType": "global",
"inputOverride": "allow",
"outputOnStateChange": false,
"outputPayload": "$entity().state ? \"on\": \"off\"",
"outputPayloadType": "jsonata",
"x": 1030,
"y": 280,
"wires": [
[]
]
},
{
"id": "7c127324.031a54",
"type": "ha-entity",
"z": "d2d6601a.7125f8",
"name": "SMA Power East",
"server": "3ee43a18.3e87e6",
"version": 1,
"debugenabled": false,
"outputs": 1,
"entityType": "sensor",
"config": [
{
"property": "name",
"value": "sensor.pv_power_east"
},
{
"property": "device_class",
"value": "sensor"
},
{
"property": "icon",
"value": "mdi:solar-power"
},
{
"property": "unit_of_measurement",
"value": "W"
}
],
"state": "payload",
"stateType": "msg",
"attributes": [],
"resend": true,
"outputLocation": "",
"outputLocationType": "global",
"inputOverride": "allow",
"outputOnStateChange": false,
"outputPayload": "$entity().state ? \"on\": \"off\"",
"outputPayloadType": "jsonata",
"x": 1030,
"y": 380,
"wires": [
[]
]
},
{
"id": "db32e83a.8f577",
"type": "ha-entity",
"z": "d2d6601a.7125f8",
"name": "SMA Power total",
"server": "3ee43a18.3e87e6",
"version": 1,
"debugenabled": false,
"outputs": 1,
"entityType": "sensor",
"config": [
{
"property": "name",
"value": "sensor.pv_power_total"
},
{
"property": "device_class",
"value": "sensor"
},
{
"property": "icon",
"value": "mdi:solar-power"
},
{
"property": "unit_of_measurement",
"value": "W"
}
],
"state": "payload",
"stateType": "msg",
"attributes": [],
"resend": true,
"outputLocation": "",
"outputLocationType": "global",
"inputOverride": "allow",
"outputOnStateChange": false,
"outputPayload": "$entity().state ? \"on\": \"off\"",
"outputPayloadType": "jsonata",
"x": 1030,
"y": 480,
"wires": [
[]
]
},
{
"id": "875fd828.40cc58",
"type": "within-time-switch",
"z": "d2d6601a.7125f8",
"name": "",
"nameInt": "",
"positionConfig": "7b813a32.05963c",
"startTime": "sunriseStart",
"startTimeType": "pdsTime",
"startOffset": "",
"startOffsetType": "none",
"startOffsetMultiplier": 60000,
"endTime": "sunsetEnd",
"endTimeType": "pdsTime",
"endOffset": "",
"endOffsetType": "none",
"endOffsetMultiplier": 60000,
"timeRestrictions": 0,
"timeRestrictionsType": "none",
"timeDays": "*",
"timeOnlyOddDays": false,
"timeOnlyEvenDays": false,
"timeMonths": "*",
"timedatestart": "",
"timedateend": "",
"propertyStart": "",
"propertyStartType": "none",
"propertyStartCompare": "true",
"propertyStartThreshold": "",
"propertyStartThresholdType": "num",
"startTimeAlt": "",
"startTimeAltType": "entered",
"startOffsetAlt": 0,
"startOffsetAltType": "none",
"startOffsetAltMultiplier": 60000,
"propertyEnd": "",
"propertyEndType": "none",
"propertyEndCompare": "true",
"propertyEndThreshold": "",
"propertyEndThresholdType": "num",
"endTimeAlt": "",
"endTimeAltType": "entered",
"endOffsetAlt": 0,
"endOffsetAltType": "none",
"endOffsetAltMultiplier": 60000,
"tsCompare": "0",
"x": 320,
"y": 180,
"wires": [
[
"cca0add4.907ac8"
],
[]
]
},
{
"id": "8e18adba.7a6b08",
"type": "switch",
"z": "d2d6601a.7125f8",
"name": "",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "lt",
"v": "0",
"vt": "str"
},
{
"t": "btwn",
"v": "0",
"vt": "num",
"v2": "9999",
"v2t": "num"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 830,
"y": 260,
"wires": [
[],
[
"69891463.07084c"
]
]
},
{
"id": "31f909c7.6b172e",
"type": "switch",
"z": "d2d6601a.7125f8",
"name": "",
"property": "payload",
"propertyType": "msg",
"rules": [
{
"t": "lt",
"v": "0",
"vt": "str"
},
{
"t": "btwn",
"v": "0",
"vt": "num",
"v2": "9999",
"v2t": "num"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 830,
"y": 360,
"wires": [
[],
[
"7c127324.031a54"
]
]
},
{
"id": "101bd986.8eac7e",
"type": "modbus-client",
"name": "SMA-Gt",
"clienttype": "tcp",
"bufferCommands": true,
"stateLogEnabled": false,
"queueLogEnabled": false,
"tcpHost": "192.168.1.149",
"tcpPort": "502",
"tcpType": "TPC-RTU-BUFFERED",
"serialPort": "/dev/ttyUSB",
"serialType": "RTU-BUFFERD",
"serialBaudrate": "9600",
"serialDatabits": "8",
"serialStopbits": "1",
"serialParity": "none",
"serialConnectionDelay": "100",
"unit_id": "3",
"commandDelay": "200",
"clientTimeout": "1000",
"reconnectOnTimeout": true,
"reconnectTimeout": "2000",
"parallelUnitIdsAllowed": true
},
{
"id": "bad4a5be.f7833",
"type": "ui_group",
"name": "Test2",
"tab": "",
"order": 3,
"disp": true,
"width": "6",
"collapse": false
},
{
"id": "3ee43a18.3e87e6",
"type": "server",
"name": "Home Assistant",
"legacy": false,
"addon": true,
"rejectUnauthorizedCerts": true,
"ha_boolean": "y|yes|true|on|home|open",
"connectionDelay": true,
"cacheJson": true
},
{
"id": "7b813a32.05963c",
"type": "position-config",
"name": "",
"isValide": "true",
"longitude": "0",
"latitude": "0",
"angleType": "deg",
"timeZoneOffset": "99",
"timeZoneDST": "0",
"stateTimeFormat": "3",
"stateDateFormat": "12"
}
]
------------------------------------------------------------------------------------------------------------------
Die YAML-Oberfläche für Lovelace:
type: vertical-stack
cards:
- type: gauge
entity: sensor.senec_battery_charge_percent
min: 0
max: 100
severity:
green: 40
yellow: 20
red: 0
- type: entities
entities:
- entity: sensor.senec_battery_state_power
- entity: sensor.senec_grid_exported_power
name: Netz Einspeisung
- entity: sensor.senec_grid_imported_power
name: Netz Bezug
- entity: sensor.senec_system_state
state_color: true
type: 'custom:mini-graph-card'
entities:
- entity: sensor.senec_house_power
name: Total
show_state: true
fill: true
points_per_hour: 6
line_width: 2
height: 200
smoothing: false
font_size: 60
hours_to_show: 24
show:
fill: true
labels: true
labels_secondary: false
name: Hausverbrauch
type: 'custom:mini-graph-card'
entities:
- entity: sensor.senec_solar_generated_power
name: Total
show_state: true
fill: true
- entity: sensor.sensor_pv_power_east
name: Ost
show_state: true
show: null
fill: false
- color: green
entity: sensor.sensor_pv_power_west
name: West
show_state: true
show: null
fill: false
- color: yellow
entity: sensor.senec_battery_charge_percent
name: Akku Beladung
show_state: true
decimals: 1
show_points: false
y_axis: secondary
upper_bound_secondary: 100
group_by: hour
align_icon: right
points_per_hour: 2
line_width: 2
height: 200
smoothing: false
font_size: 60
hours_to_show: 24
show:
fill: true
labels: true
labels_secondary: false
name: PV-Leistung