feat: add SunEnergyXT 500 Series battery storage module#3387
feat: add SunEnergyXT 500 Series battery storage module#3387ChristophCaina wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Die device.vue hat in dem Modul nichts zu suchen, die wird nur übers UI Repo im entsprechenden UI Pfad erzeugt.
There was a problem hiding this comment.
Danke für den Hinweis.
Das ist vermutlich noch von meinem lokalen testen übrig geblieben.
Werde ich anpassen und entfernen & Sobald ich mit realer Hardware weitere Tests gemacht habe, wird der pr finalisiert.
There was a problem hiding this comment.
Pull request overview
Adds a new openWB device integration for the SunEnergyXT 500 Series battery storage via the device’s local HTTP API, including active power-limit control support.
Changes:
- Introduces a new
sunenergyxtvendor/device module with configuration schema and device descriptor wiring. - Implements a battery component that reads SoC/power from
/readand writes control parameters to/write. - Adds a device configuration Vue component (settings UI) for IP/port/timeout.
Reviewed changes
Copilot reviewed 5 out of 7 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/modules/devices/sunenergyxt/vendor.py | Registers the new vendor metadata and grouping. |
| packages/modules/devices/sunenergyxt/sunenergyxt/device.py | Wires the configurable device and battery component updater. |
| packages/modules/devices/sunenergyxt/sunenergyxt/config.py | Adds device + component configuration classes (IP/port/timeout). |
| packages/modules/devices/sunenergyxt/sunenergyxt/bat.py | Implements HTTP read/write logic, state parsing, and set_power_limit() control. |
| packages/modules/devices/sunenergyxt/sunenergyxt/device.vue | Adds a settings UI component for configuring the device connection. |
| packages/modules/devices/sunenergyxt/init.py | Package marker. |
| packages/modules/devices/sunenergyxt/sunenergyxt/init.py | Package marker. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import logging | ||
| from typing import Any, Optional | ||
| import requests | ||
| from modules.common.abstract_device import AbstractBat |
| def _read(self) -> dict: | ||
| url = f"{self._base_url}/read" | ||
| resp = requests.get(url, timeout=self._timeout) | ||
| resp.raise_for_status() | ||
| return resp.json() | ||
|
|
||
| def _write(self, **kwargs) -> None: | ||
| url = f"{self._base_url}/write" | ||
| payload = {"state": kwargs} | ||
| resp = requests.post(url, json=payload, timeout=self._timeout) | ||
| resp.raise_for_status() | ||
| log.debug("SunEnergyXT write %s → %s", kwargs, resp.text) |
| bat_state = BatState( | ||
| power=power, | ||
| soc=soc, | ||
| imported=imported, | ||
| exported=exported, | ||
| ) | ||
| bat_state.max_charge_power = max_power | ||
| bat_state.max_discharge_power = max_power | ||
| self.store.set(bat_state) |
| class SunEnergyXTConfiguration: | ||
| def __init__(self, | ||
| ip_address: Optional[str] = "192.168.1.100", | ||
| port: int = 80, | ||
| timeout: int = 5): |
| def set_power_limit(self, power_limit: Optional[int]) -> None: | ||
| if power_limit is None: | ||
| log.debug("SunEnergyXT: Automatik (MM=1, GS=0)") | ||
| self._write(MM=1, GS=0) | ||
| elif power_limit == 0: | ||
| log.debug("SunEnergyXT: Entladung gesperrt (MM=0, GS=0)") | ||
| self._write(MM=0, GS=0) | ||
| elif power_limit > 0: | ||
| p = int(min(power_limit, 9999)) | ||
| log.debug("SunEnergyXT: Entladen mit %dW", p) | ||
| self._write(MM=0, GS=p) | ||
| else: | ||
| p = int(min(abs(power_limit), 9999)) | ||
| log.debug("SunEnergyXT: Laden mit %dW", p) | ||
| self._write(MM=0, GS=-p) |
| import DeviceConfigMixin from "../../DeviceConfigMixin.vue"; | ||
| export default { | ||
| name: "DeviceSunEnergyXT", | ||
| mixins: [DeviceConfigMixin], | ||
| }; |
| return ConfigurableDevice( | ||
| device_config=device_config, | ||
| component_factory=ComponentFactoryByType( | ||
| bat=create_bat_component, | ||
| ), |
| def update(self) -> None: | ||
| data = self._read() | ||
| reported = data.get("state", {}).get("reported", data) | ||
|
|
||
| soc = int(float(reported.get("SC", 0))) |
| import logging | ||
| from typing import Iterable | ||
| from modules.common.abstract_device import DeviceDescriptor | ||
| from modules.common.component_context import SingleComponentUpdateContext | ||
| from modules.common.configurable_device import ComponentFactoryByType, ConfigurableDevice, MultiComponentUpdater | ||
| from modules.devices.sunenergyxt.sunenergyxt.bat import SunEnergyXTBat | ||
| from modules.devices.sunenergyxt.sunenergyxt.config import SunEnergyXT, SunEnergyXTBatSetup | ||
|
|
||
| log = logging.getLogger(__name__) |
Summary
This PR adds support for the SunEnergyXT 500 Series (including the 500 PRO) battery storage system to openWB.
Communication
The device exposes a local HTTP API — no cloud dependency, no Modbus:
http://<IP>/readhttp://<IP>/writeFeatures
Read (passive monitoring)
SC)PB)GP)PP)IS)Active control (
power_limit_controllable = True)The module supports full active battery control by openWB:
None— automaticMM=1, GS=00— stop dischargeMM=0, GS=0> 0— discharge N WMM=0, GS=+N< 0— charge N WMM=0, GS=-NConfiguration
805UI
A Vue configuration page is provided via a separate PR to
openwb-ui-settings: ChristophCaina/openwb-ui-settingsTesting
power_limit_controllable) recognized by openWBrequires a real charging session with physical hardware