Donnerstag, 8. April 2021

PV-Anlagedaten in Home Assistant auswerten

 

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

 

 



 

Keine Kommentare:

Kommentar veröffentlichen