From eb46020bc990f8b691abc2d8baf2c4a7f1222518 Mon Sep 17 00:00:00 2001 From: Stefan Rubner <stefan@whocares.de> Date: Sun, 19 Jan 2025 17:31:05 +0100 Subject: [PATCH 1/6] Updated README with more detailed installation instructions Signed-off-by: Stefan Rubner <stefan@whocares.de> --- README.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4840ff3..829ea4e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ +[![hacs_badge][hacsbadge]][hacs] [![hainstall][hainstallbadge]][hainstall] # ha_sonnenbatterie Homeassistant integration to show many stats of Sonnenbatterie that should work with current versions of Sonnenbatterie. @@ -5,10 +6,7 @@ that should work with current versions of Sonnenbatterie. [![Validate with hassfest](https://github.com/weltmeyer/ha_sonnenbatterie/actions/workflows/hassfest.yaml/badge.svg)](https://github.com/weltmeyer/ha_sonnenbatterie/actions/workflows/hassfest.yaml) [![Validate with HACS](https://github.com/weltmeyer/ha_sonnenbatterie/actions/workflows/validate.yaml/badge.svg)](https://github.com/weltmeyer/ha_sonnenbatterie/actions/workflows/validate.yaml) -## Installation -Easiest way to install is to add this repository via [HACS](https://hacs.xyz). - -## Tested working with +### Tested working with * eco 8.03 9010 ND * eco 8.0 DE 9010 ND * sonnenBatterie 10 performance @@ -16,6 +14,53 @@ Easiest way to install is to add this repository via [HACS](https://hacs.xyz). ### Won't work with older Batteries * ex. model 9.2 eco from 2014 not working +## Installation + +### 1) via HACS +1. Add a custom **integration** repository to HACS using this link: + [https://github.com/weltmeyer/hasonnenbatterie](https://github.com/weltmeyer/hasonnenbatterie) + > [!IMPORTANT] + > This is a **HACS _integration_**, not a **HASS-IO _AddOn_**, so you <ins>need to have [HACS](https://hacs.xyz) installed</ins>, + > and you need to add this repository as a custom **integration repository** to HACS. +2. Once the repository is added, use the search bar and type `sonnenbatterie` +3. Use the 3-dot menu to the right of the list entry (not the one at the top bar!) to download/install the integration. + The latest release is automatically selected. Only select a different version if you've been told to do so + by one of the maintainers. +4. After you press download and the process has completed, you have to __Restart Home Assistant__ to install the + dependencies required by the integration +5. Setup the `sonnenbatterie` custom integration + +### 2) Manual installation + +1. Using your tool of choice open the directory (folder) where your HA configuration resides, e.g. where the + `configuration.yaml` is +2. If you don't have a `custom_components` directory (folder) there, create it +3. In the `custom_components` directory (folder) create a new folder called `sonnenbatterie` +4. Download _all_ the files from the `custom_components/sonnenbatterie/` directory (folder) from this repository +5. Place the files you downloaded in the new directory (folder) `sonnenbatterie` you created +6. Restart Home Assistant +7. Setup the sonnenbatterie custom integration as described below (see [Adding or enabling the integration](#adding_or_enabling_the_integration)) + +## Adding or enabling the integration + +> [!IMPORTANT] +> The integration must be [installed](#installation) before you can start to add or enable it! + +### 1) My Home Assistant + +Just click the following Button to start the configuration automatically: + +[![Open your Home Assistant instance and start setting up a new integration.](https://my.home-assistant.io/badges/config_flow_start.svg)][hainstall] + +### 2) Manual + +- Open the Home Assistant we interface +- Go to `Configuration -> Integrations` and click the "Add Integration" button in the lower right corner +- Search for "sonnenbatterie", select the correct entry and click on it +- This starts the configuration of a new Sonnenbatterie instance. Make sure to + - provide the correct IP address of your Sonnenbatterie within your network + - set the update interval to a reasonable value + ## Sensors The main focus of the integration is to provide a comprehensive set of sensors for your SonnenBatterie. Right after installation the most relevant sensors @@ -233,3 +278,10 @@ Please put those logs along with the setting you want monitored into ## Screenshots :) ![image](https://user-images.githubusercontent.com/1668465/78452159-ed2d7d80-7689-11ea-9e30-3a66ecc2372a.png) + +--- +[hacs]: https://hacs.xyz +[hacsbadge]: https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge&logo=homeassistantcommunitystore&logoColor=ccc + +[hainstall]: https://my.home-assistant.io/redirect/config_flow_start/?domain=sonnenbatterie +[hainstallbadge]: https://img.shields.io/badge/dynamic/json?style=for-the-badge&logo=home-assistant&logoColor=ccc&label=usage&suffix=%20installs&cacheSeconds=15600&url=https://analytics.home-assistant.io/custom_integrations.json&query=$.sonnenbatterie.total \ No newline at end of file From 78728e685cf433a4a3028dcc7ded54166cb0e4a7 Mon Sep 17 00:00:00 2001 From: Stefan Rubner <stefan@whocares.de> Date: Sun, 19 Jan 2025 17:38:00 +0100 Subject: [PATCH 2/6] Updates description for actions, added explanation for device_id Signed-off-by: Stefan Rubner <stefan@whocares.de> --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 829ea4e..5c8755f 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,13 @@ are already activated. Since version 2025.01.01 this integration also supports actions you can use to set some variables that influence the behaviour of your SonnenBatterie. +> [!NOTE] +> All actions require you ro provide a `device_id` to correctly identify the +> Sonnenbatterie you want to talk to. To find the device id for your Sonnenbatterie +> use the developer tools provided by Home Assistant. Just open the "Actions" tab +> and select an action an a device. Then switch to YAML mode where instead of the +> user-friendly name the device id will be displayed. + Currently supported actions are: ### <a name="set_operatingmode"></a>`set_operating_mode(mode=<mode>)` @@ -88,6 +95,7 @@ Currently supported actions are: ``` yaml action: sonnenbatterie.set_operating_mode data: + device_id: "<your sb instance's device id>" mode: "automatic" ``` @@ -118,6 +126,7 @@ An `int` representing the mode that has been set: ``` yaml action: sonnenbatterie.charge_battery data: + device_id: "<your sb instance's device id>" power: 0 ``` @@ -148,6 +157,7 @@ otherwise. ``` yaml action: sonnenbatterie.discharge_battery data: + device_id: "<your sb instance's device id>" power: 0 ``` @@ -164,6 +174,7 @@ otherwise. ``` yaml action: sonnenbatterie.set_battery_reserve data: + device_id: "<your sb instance's device id>" value: 10 ``` @@ -203,6 +214,7 @@ An integer representing the current value of "battery reserve" ``` yaml action: sonnenbatterie.set_config_item data: + device_id: "<your sb instance's device id>" item: "EM_USOC" value: "10" ``` @@ -236,6 +248,7 @@ data: ``` yaml action: sonnenbatterie.set_tou_schedule_string data: + device_id: "<your sb instance's device id>" schedule: '[{"start":"10:00", "stop":"10:00", "threshold_p_max": 20000}]' ``` @@ -252,7 +265,8 @@ data: ##### Code snippet ``` yaml action: sonnenbatterie.get_tou_schedule -data: {} +data: + deviceid: "<your sb instance's device id>" ``` ##### Result From 4b789f0d60b0911631f4976728c0f02f61cb3965 Mon Sep 17 00:00:00 2001 From: Stefan Rubner <stefan@whocares.de> Date: Sun, 19 Jan 2025 17:43:31 +0100 Subject: [PATCH 3/6] Fix some minor formatting errors in the actions section Signed-off-by: Stefan Rubner <stefan@whocares.de> --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5c8755f..a058de1 100644 --- a/README.md +++ b/README.md @@ -220,7 +220,7 @@ data: ``` ##### Response ``` json -{'EM_USOC': '10'} +{"EM_USOC": "10"} ``` ### <a name="set_tou_schedule"></a>`set_tou_schedule(schedule=<schedule_array>)` @@ -255,7 +255,7 @@ data: ##### Result ``` json { - "schedule": '[{"start": "10:00", "stop": "10:00", "threshold_p_max": 20000}]' + "schedule": [{"start": "10:00", "stop": "10:00", "threshold_p_max": 20000}] } ``` @@ -270,8 +270,10 @@ data: ``` ##### Result -``` yaml -schedule: "[{\"start\":\"10:00\", \"stop\":\"10:00\", \"threshold_p_max\": 20000}]" +``` json +{ + "schedule": [{"start": "10:00", "stop": "10:00", "threshold_p_max": 20000}] +} ``` ## Problems and/or unused/unavailable sensors From 383819a64760bd95d44a6eda4abed012b87a201c Mon Sep 17 00:00:00 2001 From: stefan <stefan@whocares.de> Date: Fri, 24 Jan 2025 16:50:52 +0100 Subject: [PATCH 4/6] Change input type for charge/discharge actions to str, closes #78 Signed-off-by: stefan <stefan@whocares.de> --- custom_components/sonnenbatterie/__init__.py | 4 +++- custom_components/sonnenbatterie/manifest.json | 2 +- custom_components/sonnenbatterie/service.py | 2 ++ custom_components/sonnenbatterie/services.yaml | 6 ++++-- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/custom_components/sonnenbatterie/__init__.py b/custom_components/sonnenbatterie/__init__.py index 20f83df..b57667d 100644 --- a/custom_components/sonnenbatterie/__init__.py +++ b/custom_components/sonnenbatterie/__init__.py @@ -93,12 +93,14 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b hass.data[DOMAIN][config_entry.entry_id][CONF_COORDINATOR] = sb_coordinator inverter_power = sb_coordinator.latestData['battery_system']['battery_system']['system']['inverter_capacity'] + LOGGER.debug(f"inverter_power: {inverter_power}") # noinspection PyPep8Naming SCHEMA_CHARGE_BATTERY = vol.Schema( { **cv.ENTITY_SERVICE_FIELDS, - vol.Required(CONF_CHARGE_WATT): vol.Range(min=0, max=inverter_power), + # vol.Required(CONF_CHARGE_WATT): vol.Range(min=0, max=inverter_power), + vol.Required(CONF_CHARGE_WATT): str, } ) diff --git a/custom_components/sonnenbatterie/manifest.json b/custom_components/sonnenbatterie/manifest.json index d17e04d..455ad70 100644 --- a/custom_components/sonnenbatterie/manifest.json +++ b/custom_components/sonnenbatterie/manifest.json @@ -8,5 +8,5 @@ "iot_class": "local_polling", "issue_tracker": "https://github.com/weltmeyer/ha_sonnenbatterie/issues", "requirements": ["requests","sonnenbatterie>=0.5.2"], - "version": "2025.01.02" + "version": "2025.01.03" } diff --git a/custom_components/sonnenbatterie/service.py b/custom_components/sonnenbatterie/service.py index dc2931d..8076e28 100644 --- a/custom_components/sonnenbatterie/service.py +++ b/custom_components/sonnenbatterie/service.py @@ -49,6 +49,7 @@ def _get_sb_connection(self, call_data: ReadOnlyDict) -> AsyncSonnenBatterie: # service definitions async def charge_battery(self, call: ServiceCall) -> ServiceResponse: + LOGGER.debug(f"_charge_battery: {call.data}") power = int(call.data.get(CONF_CHARGE_WATT)) # Make sure we have an sb2 object sb_conn = self._get_sb_connection(call.data) @@ -60,6 +61,7 @@ async def charge_battery(self, call: ServiceCall) -> ServiceResponse: } async def discharge_battery(self, call: ServiceCall) -> ServiceResponse: + LOGGER.debug(f"_discharge_battery: {call.data}") power = int(call.data.get(CONF_CHARGE_WATT)) sb_conn = self._get_sb_connection(call.data) # await sb_conn.login() diff --git a/custom_components/sonnenbatterie/services.yaml b/custom_components/sonnenbatterie/services.yaml index 1ff6d88..b656298 100644 --- a/custom_components/sonnenbatterie/services.yaml +++ b/custom_components/sonnenbatterie/services.yaml @@ -22,7 +22,8 @@ charge_battery: required: true example: "1000" selector: - number: + text: + suffix: "W" discharge_battery: fields: device_id: @@ -34,7 +35,8 @@ discharge_battery: required: true example: "1000" selector: - number: + text: + suffix: "W" set_battery_reserve: fields: device_id: From eb988546ce8da480812ceabbab94e1f2e313a6f8 Mon Sep 17 00:00:00 2001 From: stefan <stefan@whocares.de> Date: Fri, 24 Jan 2025 16:57:42 +0100 Subject: [PATCH 5/6] Add trivial check for negative values to dis-/charge actions Signed-off-by: stefan <stefan@whocares.de> --- custom_components/sonnenbatterie/service.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/custom_components/sonnenbatterie/service.py b/custom_components/sonnenbatterie/service.py index 8076e28..2ee52a7 100644 --- a/custom_components/sonnenbatterie/service.py +++ b/custom_components/sonnenbatterie/service.py @@ -51,6 +51,8 @@ def _get_sb_connection(self, call_data: ReadOnlyDict) -> AsyncSonnenBatterie: async def charge_battery(self, call: ServiceCall) -> ServiceResponse: LOGGER.debug(f"_charge_battery: {call.data}") power = int(call.data.get(CONF_CHARGE_WATT)) + if power < 0: + power = 0 # Make sure we have an sb2 object sb_conn = self._get_sb_connection(call.data) # await sb_conn.login() @@ -63,6 +65,8 @@ async def charge_battery(self, call: ServiceCall) -> ServiceResponse: async def discharge_battery(self, call: ServiceCall) -> ServiceResponse: LOGGER.debug(f"_discharge_battery: {call.data}") power = int(call.data.get(CONF_CHARGE_WATT)) + if power < 0: + power = 0 sb_conn = self._get_sb_connection(call.data) # await sb_conn.login() response = await sb_conn.sb2.discharge_battery(power) From 9e0c78b71ac7dddd5378e8840b4b2aa418e7f85b Mon Sep 17 00:00:00 2001 From: stefan <stefan@whocares.de> Date: Fri, 24 Jan 2025 17:48:29 +0100 Subject: [PATCH 6/6] Add number service to set `battery reserve`, closes #80 Signed-off-by: stefan <stefan@whocares.de> --- custom_components/sonnenbatterie/entities.py | 21 ++++++++++++++++++- custom_components/sonnenbatterie/number.py | 8 ++++++- .../sonnenbatterie/translations/de.json | 3 +++ .../sonnenbatterie/translations/en.json | 4 ++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/custom_components/sonnenbatterie/entities.py b/custom_components/sonnenbatterie/entities.py index 9c6c4f8..f8a9fbb 100644 --- a/custom_components/sonnenbatterie/entities.py +++ b/custom_components/sonnenbatterie/entities.py @@ -56,6 +56,14 @@ def __str__(self) -> str: writable=True, ) + BATTERY_RESERVE = SelectEntry( + key="battery_reserve", + type=Platform.NUMBER, + section="status", + property="USOC", + writable=True, + ) + BTN_RESET_CHARGE = SelectEntry( key="button_reset_charge", type=Platform.BUTTON, @@ -131,7 +139,7 @@ def unique_id(self) -> str: class SonnenbatterieNumberEntityDescription(NumberEntityDescription): tag: Tag = None native_min_value = 0 - native_step = 100 + native_step = 1 class SonnenNumberEntity(CoordinatorEntity[SonnenbatterieCoordinator], Entity): @@ -204,6 +212,7 @@ def unique_id(self) -> str: tag=Tag.CHARGE_POWER, device_class=NumberDeviceClass.POWER, mode=NumberMode.SLIDER, + native_step=100, ), SonnenbatterieNumberEntityDescription( key=Tag.DISCHARGE_POWER.key, @@ -212,6 +221,16 @@ def unique_id(self) -> str: tag=Tag.DISCHARGE_POWER, device_class=NumberDeviceClass.POWER, mode=NumberMode.SLIDER, + native_step=100, + ), + SonnenbatterieNumberEntityDescription( + key=Tag.BATTERY_RESERVE.key, + icon="mdi:battery-unknown", + entity_category=EntityCategory.CONFIG, + tag=Tag.BATTERY_RESERVE, + device_class=NumberDeviceClass.BATTERY, + mode=NumberMode.SLIDER, + native_step=1, ) ] diff --git a/custom_components/sonnenbatterie/number.py b/custom_components/sonnenbatterie/number.py index 3b123a0..8033b04 100644 --- a/custom_components/sonnenbatterie/number.py +++ b/custom_components/sonnenbatterie/number.py @@ -27,7 +27,11 @@ class SonnenbatterieNumber(SonnenNumberEntity, NumberEntity): def __init__(self, coordinator: SonnenbatterieCoordinator, description: SonnenbatterieNumberEntityDescription, max_power: int) -> None: super().__init__(coordinator, description) - self._max_power = max_power + LOGGER.debug(f"SonnenbatterieNumberEntity: {description}") + if description.key == "battery_reserve": + self._max_power = 100 + else: + self._max_power = max_power @property def native_max_value(self) -> int: @@ -42,5 +46,7 @@ async def async_set_native_value(self, value): await self.coordinator.sbconn.sb2.charge_battery(int(value)) case "number_discharge": await self.coordinator.sbconn.sb2.discharge_battery(int(value)) + case "battery_reserve": + await self.coordinator.sbconn.sb2.set_battery_reserve(int(value)) await self.coordinator.async_request_refresh() return None diff --git a/custom_components/sonnenbatterie/translations/de.json b/custom_components/sonnenbatterie/translations/de.json index d128b76..8a4479b 100644 --- a/custom_components/sonnenbatterie/translations/de.json +++ b/custom_components/sonnenbatterie/translations/de.json @@ -51,6 +51,9 @@ }, "number_discharge": { "name": "Entladen erzwingen (W)" + }, + "battery_reserve": { + "name": "Batterie-Reserve einstellen (%)" } }, "select": { diff --git a/custom_components/sonnenbatterie/translations/en.json b/custom_components/sonnenbatterie/translations/en.json index 7d176d1..7730236 100644 --- a/custom_components/sonnenbatterie/translations/en.json +++ b/custom_components/sonnenbatterie/translations/en.json @@ -51,7 +51,11 @@ }, "number_discharge": { "name": "Force discharge (W)" + }, + "battery_reserve": { + "name": "Set battery reserve (%)" } + }, "select": { "select_operating_mode": {