diff --git a/custom_components/anker_solix/coordinator.py b/custom_components/anker_solix/coordinator.py index 8709211..2aea547 100644 --- a/custom_components/anker_solix/coordinator.py +++ b/custom_components/anker_solix/coordinator.py @@ -147,9 +147,10 @@ async def async_refresh_device_details( if isinstance(categories, str) else None ) - if SolixDeviceType.VEHICLE.value in categories: - # Refresh only device details for user account - data = await self.client.async_get_data(vehicle_details=True) + if categories: + if SolixDeviceType.VEHICLE.value in categories: + # Refresh only device details for user account + data = await self.client.async_get_data(vehicle_details=True) else: data = await self.client.async_get_data( device_details=True, reset_cache=reset_cache diff --git a/custom_components/anker_solix/manifest.json b/custom_components/anker_solix/manifest.json index 7a6a1ea..418b73f 100644 --- a/custom_components/anker_solix/manifest.json +++ b/custom_components/anker_solix/manifest.json @@ -16,5 +16,5 @@ "aiofiles>=23.2.0", "cryptography>=3.4.8" ], - "version": "3.2.0" + "version": "3.2.1" } \ No newline at end of file diff --git a/custom_components/anker_solix/number.py b/custom_components/anker_solix/number.py index b521122..2517bca 100644 --- a/custom_components/anker_solix/number.py +++ b/custom_components/anker_solix/number.py @@ -348,24 +348,6 @@ def __init__( self._attr_device_info = get_AnkerSolixDeviceInfo( data, context, coordinator.client.api.apisession.email ) - # update number limits based on solarbank count in system or active max - if self._attribute_name == "preset_system_output_power": - if (data.get("generation") or 0) >= 2: - # SB2 has min limit of 0W, they are typically correctly set in the schedule depending on device settings - self.native_min_value = (data.get("schedule") or {}).get( - "min_load" - ) or 0 - self.native_max_value = (data.get("schedule") or {}).get( - "max_load" - ) or self.native_max_value - else: - self.native_max_value = int( - self.native_max_value * (data.get("solarbank_count") or 1) - ) - if self._attribute_name == "preset_device_output_power": - self.native_min_value = int( - self.native_min_value / (data.get("solarbank_count") or 1) - ) elif self.entity_type == AnkerSolixEntityType.ACCOUNT: # get the account data from account context entry of coordinator data data = coordinator.data.get(context) or {} @@ -428,6 +410,41 @@ def update_state_value(self): # get dynamic unit if defined if unit := self.entity_description.unit_fn(data): self._attr_native_unit_of_measurement = unit + # update number limits for presets based on solarbank count in system or active max + if self._attribute_name == "preset_system_output_power": + if (data.get("generation") or 0) >= 2: + # SB2 has min limit of 0W, they are typically correctly set in the schedule depending on device settings + self.native_min_value = (data.get("schedule") or {}).get( + "min_load" + ) or 0 + self.native_max_value = (data.get("schedule") or {}).get( + "max_load" + ) or self.native_max_value + else: + # Use minimum from schedule fields (depends on defined interter) + self.native_min_value = (data.get("schedule") or {}).get( + "min_load" + ) or self.native_min_value + # SB1 max must consider multiple devices with MI80 inverter + self.native_max_value = int( + ( + (data.get("schedule") or {}).get("max_load") + or self.native_max_value + ) + * (data.get("solarbank_count") or 1) + ) + elif self._attribute_name == "preset_device_output_power": + # Multiple SB1 with device setting only supported for MI80 whose limits apply + self.native_min_value = int( + ( + (data.get("schedule") or {}).get("min_load") + or self.native_min_value + ) + / (data.get("solarbank_count") or 1) + ) + self.native_max_value = (data.get("schedule") or {}).get( + "max_load" + ) or self.native_max_value else: self._native_value = None self._assumed_state = False diff --git a/custom_components/anker_solix/select.py b/custom_components/anker_solix/select.py index 37f704e..999317c 100644 --- a/custom_components/anker_solix/select.py +++ b/custom_components/anker_solix/select.py @@ -395,13 +395,8 @@ def __init__( self._attr_options = self.entity_description.options_fn( data, self.entity_description.json_key ) - # update options based on other devices configured in system - if self._attribute_name == "preset_usage_mode": - self._attr_options = list( - coordinator.client.api.solarbank_usage_mode_options(deviceSn=context) - ) - self._attr_options.sort() - elif self._attribute_name == "system_price_unit": + # Initial options update for static information not changed during Api session + if self._attribute_name == "system_price_unit": # merge currencies from entity description and from Api currency list options = set(self._attr_options) | { item.get("symbol") @@ -414,46 +409,8 @@ def __init__( ) } self._attr_options = list(options) - elif self._attribute_name == "system_price_type": - self._attr_options = list( - coordinator.client.api.price_type_options(siteId=context) - ) - self._attr_options.sort() - elif self._attribute_name == "dynamic_price_provider": - self._attr_options = list( - coordinator.client.api.price_provider_options(siteId=context) - # TODO(SB3): Add None as option only if the provider can ever be removed - # | {"none"} - ) - self._attr_options.sort() - elif self._attribute_name == "vehicle_brand": - self._attr_options = coordinator.client.api.get_vehicle_options() - self._attr_options.sort() - elif self._attribute_name == "vehicle_model": - self._attr_options = coordinator.client.api.get_vehicle_options( - vehicle=SolixVehicle(brand=data.get("brand")) - ) - self._attr_options.sort() - elif self._attribute_name == "vehicle_year": - self._attr_options = coordinator.client.api.get_vehicle_options( - vehicle=SolixVehicle(brand=data.get("brand"), model=data.get("model")) - ) self._attr_options.sort() - elif self._attribute_name == "vehicle_variant": - self._attr_options = ( - self.coordinator.client.api.get_vehicle_options( - vehicle=SolixVehicle( - brand=brand, model=model, productive_year=year - ), - extendAttributes=True, - ) - if (brand := data.get("brand")) - and (model := data.get("model")) - and (year := data.get("productive_year")) - else [] - ) - self._attr_options.sort() - # Make sure that options are limited to existing state if entity cannot be changed + # Make sure that options are set to existing state if no options defined if not self._attr_options and self._attr_current_option is not None: self._attr_options = [self._attr_current_option] @@ -492,6 +449,7 @@ def options(self) -> str | None: ) if options != set(self._attr_options): self._attr_options = list(options) + self._attr_options.sort() elif self._attribute_name == "dynamic_price_provider": options = self.coordinator.client.api.price_provider_options( siteId=self.coordinator_context @@ -553,7 +511,7 @@ def options(self) -> str | None: self._attr_options.sort() else: self._attr_options = [] - # Make sure that options are limited to existing state if entity cannot be changed + # Make sure that options are limited to existing state if no options defined if not self._attr_options and self._attr_current_option is not None: self._attr_options = [self._attr_current_option] return self._attr_options diff --git a/custom_components/anker_solix/solixapi/poller.py b/custom_components/anker_solix/solixapi/poller.py index 967c73c..d2358bc 100644 --- a/custom_components/anker_solix/solixapi/poller.py +++ b/custom_components/anker_solix/solixapi/poller.py @@ -362,7 +362,7 @@ async def poll_sites( # noqa: C901 if (charge_calc := power_in - power_out) > 0: # No discharging, use the bat charge value if available in response charge_calc = max(charge_calc, batt_charge) - elif batt_discharge >= 0: + elif batt_discharge > 0: # use new field preferably if discharge value available charge_calc = -1 * batt_discharge # allow negative values for the field being used as battery power diff --git a/hacs.json b/hacs.json index 689fa9a..d89be4d 100644 --- a/hacs.json +++ b/hacs.json @@ -1,6 +1,6 @@ { "name": "Anker Solix", - "homeassistant": "2024.11.2", + "homeassistant": "2025.3.0", "persistent_directory": "solixapi/authcache", "render_readme": true }