torbennehmer / hacs-e3dc

Homeassistant E3DC Integration
GNU Affero General Public License v3.0
68 stars 8 forks source link

Service E3DC Remote Storage Control Protocol (Git): Set power limits #175

Open thobohoii opened 2 months ago

thobohoii commented 2 months ago

System Health details

System Information

version core-2024.8.3
installation_type Home Assistant OS
dev false
hassio true
docker true
user root
virtualenv false
python_version 3.12.4
os_name Linux
os_version 6.6.46-haos
arch x86_64
timezone Europe/Berlin
config_dir /config
Home Assistant Community Store GitHub API | ok -- | -- GitHub Content | ok GitHub Web | ok GitHub API Calls Remaining | 4996 Installed Version | 1.34.0 Stage | running Available Repositories | 1383 Downloaded Repositories | 6
Home Assistant Cloud logged_in | false -- | -- can_reach_cert_server | ok can_reach_cloud_auth | ok can_reach_cloud | ok
Home Assistant Supervisor host_os | Home Assistant OS 13.1 -- | -- update_channel | stable supervisor_version | supervisor-2024.08.0 agent_version | 1.6.0 docker_version | 26.1.4 disk_total | 30.8 GB disk_used | 19.3 GB healthy | true supported | true host_connectivity | true supervisor_connectivity | true ntp_synchronized | true virtualization | kvm board | ova supervisor_api | ok version_api | ok installed_addons | Samba share (12.3.2), Node-RED (18.0.5), evcc (0.130.6), File editor (5.8.0), Terminal & SSH (9.14.0), Mosquitto broker (6.4.1), EMHASS (0.10.6), modbus-proxy (1.0.18), InfluxDB (5.0.0), Grafana (10.0.0), UniFi Network Application (3.2.0), deCONZ (7.0.0), SQLite Web (4.2.0)
Dashboards dashboards | 2 -- | -- resources | 1 views | 7 mode | storage
Recorder oldest_recorder_run | 25. August 2024 um 09:01 -- | -- current_recorder_run | 27. August 2024 um 16:31 estimated_db_size | 910.36 MiB database_engine | sqlite database_version | 3.45.3

Checklist

Describe the issue

If the Maximum charge (w) value is changed via the Service E3DC Remote Storage Control Protocol (Git): Set power limits, the Minimum required discharge value is always reset to 100W.

Reproduction steps

  1. change the Minimum required discharge value (Untere Entladeschwelle) via E3DC Portal or RSCPGui for Exempel to 50W
  2. take the Home Assistant service E3DC Remote Storage Control Protocol (Git): Set power limits and set withe that the Maximum Charge (Maximale Ladeleistung) value to for expampel 3000W
  3. Now take a look back at the Minimum required discharge value (Untere Entladeschwelle) and it will be back at 100W

Debug logs

{
  "home_assistant": {
    "installation_type": "Home Assistant OS",
    "version": "2024.8.3",
    "dev": false,
    "hassio": true,
    "virtualenv": false,
    "python_version": "3.12.4",
    "docker": true,
    "arch": "x86_64",
    "timezone": "Europe/Berlin",
    "os_name": "Linux",
    "os_version": "6.6.46-haos",
    "supervisor": "2024.08.0",
    "host_os": "Home Assistant OS 13.1",
    "docker_version": "26.1.4",
    "chassis": "vm",
    "run_as_root": true
  },
  "custom_components": {
    "e3dc_rscp": {
      "documentation": "https://github.com/torbennehmer/hacs-e3dc",
      "version": "3.8.0-beta.5",
      "requirements": [
        "pye3dc==0.9.2"
      ]
    },
    "hacs": {
      "documentation": "https://hacs.xyz/docs/configuration/start",
      "version": "2.0.0",
      "requirements": [
        "aiogithubapi>=22.10.1"
      ]
    },
    "nodered": {
      "documentation": "https://zachowj.github.io/node-red-contrib-home-assistant-websocket/guide/custom_integration/",
      "version": "4.0.2",
      "requirements": []
    },
    "epex_spot": {
      "documentation": "https://github.com/mampfes/ha_epex_spot",
      "version": "2.3.8",
      "requirements": [
        "beautifulsoup4"
      ]
    },
    "apsystemsapi_local": {
      "documentation": "https://www.home-assistant.io/integrations/apsystemsapi_local",
      "version": "1.0.0",
      "requirements": [
        "apsystems-ez1==1.0.1"
      ]
    },
    "cupra_we_connect": {
      "documentation": "https://github.com/daernsinstantfortress/cupra_we_connect",
      "version": "0.8.4",
      "requirements": [
        "weconnect-cupra-daern==0.50.13",
        "ascii_magic==2.1.1"
      ]
    }
  },
  "integration_manifest": {
    "domain": "e3dc_rscp",
    "name": "E3DC Remote Storage Control Protocol (Git)",
    "codeowners": [
      "torbennehmer"
    ],
    "config_flow": true,
    "dependencies": [],
    "documentation": "https://github.com/torbennehmer/hacs-e3dc",
    "homekit": {},
    "integration_type": "device",
    "iot_class": "cloud_polling",
    "issue_tracker": "https://github.com/torbennehmer/hacs-e3dc/issues",
    "requirements": [
      "pye3dc==0.9.2"
    ],
    "ssdp": [],
    "version": "3.8.0-beta.5",
    "zeroconf": [],
    "is_built_in": false
  },
  "setup_times": {
    "null": {
      "setup": 2.6496010832488537e-05
    },
    "ceaeacc14ac5c86f9c6949448719b4ff": {
      "wait_import_platforms": -0.018843285972252488,
      "config_entry_setup": 0.7926063160412014
    }
  },
  "data": {
    "current_data": {
      "system-derate-percent": 69.9999988079071,
      "system-derate-power": 6720.0,
      "system-additional-source-available": false,
      "system-battery-installed-capacity": 33,
      "system-battery-installed-peak": 9600,
      "system-ac-maxpower": 0,
      "system-battery-charge-max": 4680,
      "system-battery-discharge-max": 4545,
      "system-mac": "68:<redacted>",
      "model": "S10X",
      "system-battery-discharge-minimum-default": 100,
      "e3dc_timezone": "Europe/Berlin",
      "additional-production": 0,
      "autarky": 99.99998474121094,
      "battery-charge": 0,
      "battery-discharge": 12,
      "battery-netchange": -12,
      "grid-consumption": 0,
      "grid-netchange": -2088,
      "grid-production": 2088,
      "house-consumption": 528,
      "selfconsumption": 13.615857124328613,
      "soc": 100,
      "solar-production": 2604,
      "wallbox-consumption": 0,
      "pset-limit-charge": 4000,
      "pset-limit-discharge": 4545,
      "pset-limit-discharge-minimum": 100,
      "pset-limit-enabled": true,
      "pset-powersaving-enabled": true,
      "pset-weatherregulationenabled": true,
      "manual-charge-active": false,
      "manual-charge-energy": 0,
      "db-day-autarky": 98.48247528076172,
      "db-day-battery-charge": 10519.75,
      "db-day-battery-discharge": 2052.25,
      "db-day-grid-consumption": 247.25,
      "db-day-grid-production": 6375.5,
      "db-day-house-consumption": 16293.0,
      "db-day-selfconsumption": 71.5649185180664,
      "db-day-solar-production": 34255.0,
      "db-day-startts": 1725321600,
      "d0:5f:64:41:80:b5-app-software": 0,
      "d0:5f:64:41:80:b5-battery-to-car": 0,
      "d0:5f:64:41:80:b5-charging": false,
      "d0:5f:64:41:80:b5-charging-canceled": false,
      "d0:5f:64:41:80:b5-consumption-net": 0,
      "d0:5f:64:41:80:b5-consumption-sun": 0,
      "d0:5f:64:41:80:b5-energy-all": 281126,
      "d0:5f:64:41:80:b5-energy-net": 4314,
      "d0:5f:64:41:80:b5-energy-sun": 276812,
      "d0:5f:64:41:80:b5-index": 0,
      "d0:5f:64:41:80:b5-key-state": 0,
      "d0:5f:64:41:80:b5-max-charge-current": 16,
      "d0:5f:64:41:80:b5-phases": 1,
      "d0:5f:64:41:80:b5-plug-lock": true,
      "d0:5f:64:41:80:b5-plug": true,
      "d0:5f:64:41:80:b5-schuko": false,
      "d0:5f:64:41:80:b5-soc": 100,
      "d0:5f:64:41:80:b5-sun-mode": true
    },
    "get_system_info": {
      "deratePercent": 69.9999988079071,
      "deratePower": 6720.0,
      "externalSourceAvailable": 0,
      "installedBatteryCapacity": 33,
      "installedPeakPower": 9600,
      "maxAcPower": 0,
      "macAddress": "68:<redacted>",
      "maxBatChargePower": 4680,
      "maxBatDischargePower": 4545,
      "model": "S10X",
      "release": "H20_2024_024",
      "serial": "822<redacted>"
    },
    "get_system_status": {
      "dcdcAlive": true,
      "powerMeterAlive": true,
      "batteryModuleAlive": true,
      "pvModuleAlive": true,
      "pvInverterInited": true,
      "serverConnectionAlive": true,
      "pvDerated": false,
      "emsAlive": true,
      "acModeBlocked": false,
      "sysConfChecked": false,
      "emergencyPowerStarted": false,
      "emergencyPowerOverride": false,
      "wallBoxAlive": true,
      "powerSaveEnabled": false,
      "chargeIdlePeriodActive": false,
      "dischargeIdlePeriodActive": false,
      "waitForWeatherBreakthrough": false,
      "rescueBatteryEnabled": false,
      "emergencyReserveReached": false,
      "socSyncRequested": false
    },
    "get_powermeters": [
      {
        "index": 6,
        "type": 1,
        "typeName": "PM_TYPE_ROOT"
      }
    ],
    "e3dc_config": {
      "powermeters": [
        {
          "index": 6,
          "type": 1,
          "typeName": "PM_TYPE_ROOT",
          "name": "Root PM",
          "key": "root-pm",
          "total-state-class": "total",
          "negate-measure": false
        }
      ]
    },
    "poll": {
      "autarky": 99.99998474121094,
      "consumption": {
        "battery": -12,
        "house": 589,
        "wallbox": 0
      },
      "production": {
        "solar": 2600,
        "add": 0,
        "grid": -2023
      },
      "selfConsumption": 14.539039611816406,
      "stateOfCharge": 100,
      "time": "2024-09-03T15:32:22.000983+00:00"
    },
    "switches": [],
    "get_pvis_data": [
      {
        "acMaxApparentPower": 3333.333251953125,
        "cosPhi": {
          "active": null,
          "value": null,
          "excited": null
        },
        "deviceState": {
          "connected": true,
          "working": true,
          "inService": false
        },
        "frequency": {
          "under": null,
          "over": null
        },
        "index": 0,
        "lastError": "1 0x1",
        "maxPhaseCount": 3,
        "maxStringCount": 2,
        "onGrid": true,
        "phases": {
          "0": {
            "power": 784.8001708984375,
            "voltage": 228.46934509277344,
            "current": 3.4540247917175293,
            "apparentPower": 786.2779541015625,
            "reactivePower": 1.477783203125,
            "energyAll": 404046.2776249892,
            "energyGridConsumption": 52.914308206689725
          },
          "1": {
            "power": 819.5938110351562,
            "voltage": 235.3514862060547,
            "current": 3.4859631061553955,
            "apparentPower": 818.1951293945312,
            "reactivePower": -1.398681640625,
            "energyAll": 413198.209430482,
            "energyGridConsumption": 50.432797118092765
          },
          "2": {
            "power": 798.1170043945312,
            "voltage": 232.29287719726562,
            "current": 3.425994396209717,
            "apparentPower": 818.1951293945312,
            "reactivePower": 20.078125,
            "energyAll": 409786.89846609,
            "energyGridConsumption": 51.813604322061884
          }
        },
        "powerMode": 1,
        "serialNumber": "769<redacted>",
        "state": "0x110",
        "strings": {
          "0": {
            "power": 329.443359375,
            "voltage": 325.4532775878906,
            "current": 1.0125110149383545,
            "energyAll": 646703.368527336
          },
          "1": {
            "power": 2271.406005859375,
            "voltage": 338.9555358886719,
            "current": 6.701037883758545,
            "energyAll": 731230.4032194684
          }
        },
        "systemMode": 2,
        "temperature": {
          "max": 100.0,
          "min": -30.0,
          "values": [
            55.80600357055664,
            53.64500427246094
          ]
        },
        "type": 5,
        "version": "MAIN: HMI 3.18.12;DHTS 2.2.40;PU 1.0.60;PAR 8.0.4;ENS 1.9.0",
        "voltageMonitoring": {
          "thresholdTop": null,
          "thresholdBottom": null,
          "slopeUp": null,
          "slopeDown": null
        }
      }
    ],
    "get_powermeters_data": [
      {
        "activePhases": "111",
        "energy": {
          "L1": -713235.66,
          "L2": -2138600.67,
          "L3": -2717130.71
        },
        "index": 6,
        "maxPhasePower": 24000.0,
        "mode": 1,
        "power": {
          "L1": -680.0,
          "L2": -578.0,
          "L3": -768.0
        },
        "type": 1,
        "voltage": {
          "L1": 227.6999969482422,
          "L2": 233.50999450683594,
          "L3": 233.49000549316406
        }
      }
    ],
    "get_wallbox_data": {
      "appSoftware": 0,
      "batteryToCar": 0,
      "chargingActive": false,
      "chargingCanceled": false,
      "consumptionNet": 0,
      "consumptionSun": 0,
      "energyAll": 281126,
      "energyNet": 4314,
      "energySun": 276812,
      "index": 0,
      "keyState": 0,
      "maxChargeCurrent": 16,
      "phases": 1,
      "plugLocked": false,
      "plugged": true,
      "schukoOn": false,
      "soc": 100,
      "sunModeOn": true
    },
    "get_batteries_data": {
      "exception": [
        "Traceback (most recent call last):\n",
        "  File \"/config/custom_components/e3dc_rscp/diagnostics.py\", line 111, in _query_data_for_dump\n    tmp = call()\n          ^^^^^^\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_e3dc.py\", line 1667, in get_batteries_data\n    self.get_battery_data(\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_e3dc.py\", line 1562, in get_battery_data\n    temperatures.append(temperatures_data[sensor][2])\n                        ~~~~~~~~~~~~~~~~~^^^^^^^^\n",
        "IndexError: list index out of range\n"
      ]
    },
    "get_idle_periods": null,
    "get_power_settings": {
      "dischargeStartPower": 100,
      "maxChargePower": 4000,
      "maxDischargePower": 4545,
      "powerLimitsUsed": true,
      "powerSaveEnabled": true,
      "weatherForecastMode": 1,
      "weatherRegulatedChargeEnabled": true
    },
    "EMS_REQ_GET_MANUAL_CHARGE": {
      "exception": [
        "Traceback (most recent call last):\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_e3dc_rscp_local.py\", line 102, in sendRequest\n    receive = self._receive()\n              ^^^^^^^^^^^^^^^\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_e3dc_rscp_local.py\", line 76, in _receive\n    decData = rscpDecode(self.encdec.decrypt(data))[0]\n              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_rscpLib.py\", line 263, in rscpDecode\n    return rscpDecode(rscpFrameDecode(data)[0])\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_rscpLib.py\", line 279, in rscpDecode\n    innerData, usedLength = rscpDecode(data[curByte:])\n                            ^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_rscpLib.py\", line 270, in rscpDecode\n    strTag = getStrRscpTag(hexTag)\n             ^^^^^^^^^^^^^^^^^^^^^\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_rscpTags.py\", line 3692, in getStrRscpTag\n    tag = RscpTag(tag)\n          ^^^^^^^^^^^^\n",
        "  File \"/usr/local/lib/python3.12/enum.py\", line 757, in __call__\n    return cls.__new__(cls, value)\n           ^^^^^^^^^^^^^^^^^^^^^^^\n",
        "  File \"/usr/local/lib/python3.12/enum.py\", line 1171, in __new__\n    raise ve_exc\n",
        "ValueError: 16777278 is not a valid RscpTag\n",
        "\nDuring handling of the above exception, another exception occurred:\n\n",
        "Traceback (most recent call last):\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_e3dc.py\", line 227, in sendRequest\n    result = self.rscp.sendRequest(request)\n             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_e3dc_rscp_local.py\", line 108, in sendRequest\n    raise CommunicationError\n",
        "e3dc._e3dc_rscp_local.CommunicationError\n",
        "\nDuring handling of the above exception, another exception occurred:\n\n",
        "Traceback (most recent call last):\n",
        "  File \"/config/custom_components/e3dc_rscp/diagnostics.py\", line 111, in _query_data_for_dump\n    tmp = call()\n          ^^^^^^\n",
        "  File \"/config/custom_components/e3dc_rscp/diagnostics.py\", line 80, in <lambda>\n    lambda: self.e3dc.sendRequestTag(\n            ^^^^^^^^^^^^^^^^^^^^^^^^^\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_e3dc.py\", line 264, in sendRequestTag\n    return self.sendRequest(\n           ^^^^^^^^^^^^^^^^^\n",
        "  File \"/usr/local/lib/python3.12/site-packages/e3dc/_e3dc.py\", line 238, in sendRequest\n    raise SendError(\"Max retries reached\")\n",
        "e3dc._e3dc.SendError: Max retries reached\n"
      ]
    },
    "DB_REQ_HISTORY_DATA_DAY": [
      "DB_HISTORY_DATA_DAY",
      "Container",
      [
        [
          "DB_SUM_CONTAINER",
          "Container",
          [
            [
              "DB_GRAPH_INDEX",
              "Float32",
              -1.0
            ],
            [
              "DB_BAT_POWER_IN",
              "Float32",
              10519.75
            ],
            [
              "DB_BAT_POWER_OUT",
              "Float32",
              2052.25
            ],
            [
              "DB_DC_POWER",
              "Float32",
              34255.0
            ],
            [
              "DB_GRID_POWER_IN",
              "Float32",
              6375.5
            ],
            [
              "DB_GRID_POWER_OUT",
              "Float32",
              247.25
            ],
            [
              "DB_CONSUMPTION",
              "Float32",
              16293.0
            ],
            [
              "DB_PM_0_POWER",
              "Float32",
              0.0
            ],
            [
              "DB_PM_1_POWER",
              "Float32",
              0.0
            ],
            [
              "DB_BAT_CHARGE_LEVEL",
              "Float32",
              100.0
            ],
            [
              "DB_BAT_CYCLE_COUNT",
              "Int32",
              0
            ],
            [
              "DB_CONSUMED_PRODUCTION",
              "Float32",
              71.5649185180664
            ],
            [
              "DB_AUTARKY",
              "Float32",
              98.48247528076172
            ]
          ]
        ],
        [
          "DB_VALUE_CONTAINER",
          "Container",
          [
            [
              "DB_GRAPH_INDEX",
              "Float32",
              0.729166567325592
            ],
            [
              "DB_BAT_POWER_IN",
              "Float32",
              601.1286010742188
            ],
            [
              "DB_BAT_POWER_OUT",
              "Float32",
              117.27143096923828
            ],
            [
              "DB_DC_POWER",
              "Float32",
              1957.4285888671875
            ],
            [
              "DB_GRID_POWER_IN",
              "Float32",
              364.3143005371094
            ],
            [
              "DB_GRID_POWER_OUT",
              "Float32",
              14.128571510314941
            ],
            [
              "DB_CONSUMPTION",
              "Float32",
              931.028564453125
            ],
            [
              "DB_PM_0_POWER",
              "Float32",
              0.0
            ],
            [
              "DB_PM_1_POWER",
              "Float32",
              0.0
            ],
            [
              "DB_BAT_CHARGE_LEVEL",
              "Float32",
              100.0
            ],
            [
              "DB_BAT_CYCLE_COUNT",
              "Int32",
              0
            ],
            [
              "DB_CONSUMED_PRODUCTION",
              "Float32",
              71.5649185180664
            ],
            [
              "DB_AUTARKY",
              "Float32",
              100.0
            ]
          ]
        ]
      ]
    ]
  }
}

Diagnostics dump

No response

bullitt186 commented 2 months ago

I was able to reproduce the issue. The Service (or now-called action since HA 2024.8) called the underlying pye3dc with "None" for the non-set / non-changed values. pye3dc writes the system default value to the limits (max_charge, max_discharge, min_discharge) when called with None. Meaning when only changing one of max_charge or max_discharge, the other one would be reset to the system value as well in addition to min_discharge.

To fix this, i changed the service that when the values of one of these three limits are not changed, the currently set value is taken and written (again) via pye3dc to the Hauskraftwerk to preserve the current values. (The only other option would be the re-implementation of pye3dc's set_power_limits() which seemed like overkill to me) This by the way introduces the option to change min_discharge as well via HA, which wasn't possible previously.

See PR https://github.com/torbennehmer/hacs-e3dc/pull/176

One implication of this bug fix is a change in behaviour of the service. previously, you could (mis)use this service to re-set limits to their default values. now you striclty have to use "clear power limits" to clear all three of them. However i think this fix makes sense and is more logical than it was before.

@torbennehmer - let's discuss if you think the issue raised by @thobohoii should be handled differently.

thobohoii commented 2 months ago

@bullitt186 thank you for your investigation. Something like that was also my thougth. But i am not the programing guy.

I also tright difrent variations of the Service. Just max_charge or just max_discharge or both. But always the min_discharge Value will be reset to 100W.