number.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. """Number platform for Solar of Things integration."""
  2. from __future__ import annotations
  3. import logging
  4. from homeassistant.components.number import NumberDeviceClass, NumberEntity, NumberMode
  5. from homeassistant.config_entries import ConfigEntry
  6. from homeassistant.const import PERCENTAGE
  7. from homeassistant.core import HomeAssistant
  8. from homeassistant.helpers.entity_platform import AddEntitiesCallback
  9. from homeassistant.helpers.update_coordinator import CoordinatorEntity
  10. from .const import DOMAIN
  11. _LOGGER = logging.getLogger(__name__)
  12. async def async_setup_entry(
  13. hass: HomeAssistant,
  14. entry: ConfigEntry,
  15. async_add_entities: AddEntitiesCallback,
  16. ) -> None:
  17. """Set up number entities (controls) for each device."""
  18. data = hass.data[DOMAIN][entry.entry_id]
  19. api = data["api"]
  20. station_id: str = data["station_id"]
  21. device_coordinators = data["device_coordinators"]
  22. entities: list[NumberEntity] = []
  23. for device_id, coordinator in device_coordinators.items():
  24. device_name = (coordinator.device_meta or {}).get("name") or device_id
  25. entities.extend(
  26. [
  27. SolarOfThingsBatteryChargeLimitNumber(api, coordinator, station_id, device_id, device_name),
  28. SolarOfThingsBatteryDischargeLimitNumber(api, coordinator, station_id, device_id, device_name),
  29. SolarOfThingsGridChargeLimitNumber(api, coordinator, station_id, device_id, device_name),
  30. ]
  31. )
  32. async_add_entities(entities)
  33. class _BaseNumber(CoordinatorEntity, NumberEntity):
  34. def __init__(self, api, coordinator, station_id: str, device_id: str, device_name: str) -> None:
  35. super().__init__(coordinator)
  36. self._api = api
  37. self._station_id = station_id
  38. self._device_id = device_id
  39. self._device_name = device_name
  40. @property
  41. def device_info(self):
  42. return {
  43. "identifiers": {(DOMAIN, self._device_id)},
  44. "name": self._device_name,
  45. "manufacturer": "Siseli",
  46. "model": (self.coordinator.data.get("device_meta") or {}).get("model") if self.coordinator.data else None,
  47. "via_device": (DOMAIN, self._station_id),
  48. }
  49. class SolarOfThingsBatteryChargeLimitNumber(_BaseNumber):
  50. _setting_key = "batteryChargeLimit"
  51. def __init__(self, api, coordinator, station_id: str, device_id: str, device_name: str) -> None:
  52. super().__init__(api, coordinator, station_id, device_id, device_name)
  53. self._attr_name = f"{device_name} Battery Charge Limit"
  54. self._attr_unique_id = f"{DOMAIN}_{station_id}_{device_id}_battery_charge_limit"
  55. self._attr_native_min_value = 0
  56. self._attr_native_max_value = 100
  57. self._attr_native_step = 1
  58. self._attr_native_unit_of_measurement = PERCENTAGE
  59. self._attr_mode = NumberMode.SLIDER
  60. self._attr_icon = "mdi:battery-arrow-up"
  61. @property
  62. def native_value(self):
  63. return ((self.coordinator.data or {}).get("settings") or {}).get(self._setting_key)
  64. async def async_set_native_value(self, value: float) -> None:
  65. await self.hass.async_add_executor_job(self._api.set_battery_charge_limit, self._device_id, int(value))
  66. await self.coordinator.async_request_refresh()
  67. class SolarOfThingsBatteryDischargeLimitNumber(_BaseNumber):
  68. _setting_key = "batteryDischargeLimit"
  69. def __init__(self, api, coordinator, station_id: str, device_id: str, device_name: str) -> None:
  70. super().__init__(api, coordinator, station_id, device_id, device_name)
  71. self._attr_name = f"{device_name} Battery Discharge Limit"
  72. self._attr_unique_id = f"{DOMAIN}_{station_id}_{device_id}_battery_discharge_limit"
  73. self._attr_native_min_value = 0
  74. self._attr_native_max_value = 100
  75. self._attr_native_step = 1
  76. self._attr_native_unit_of_measurement = PERCENTAGE
  77. self._attr_mode = NumberMode.SLIDER
  78. self._attr_icon = "mdi:battery-arrow-down"
  79. @property
  80. def native_value(self):
  81. return ((self.coordinator.data or {}).get("settings") or {}).get(self._setting_key)
  82. async def async_set_native_value(self, value: float) -> None:
  83. await self.hass.async_add_executor_job(self._api.set_battery_discharge_limit, self._device_id, int(value))
  84. await self.coordinator.async_request_refresh()
  85. class SolarOfThingsGridChargeLimitNumber(_BaseNumber):
  86. _setting_key = "gridChargeLimit"
  87. def __init__(self, api, coordinator, station_id: str, device_id: str, device_name: str) -> None:
  88. super().__init__(api, coordinator, station_id, device_id, device_name)
  89. self._attr_name = f"{device_name} Grid Charge Limit"
  90. self._attr_unique_id = f"{DOMAIN}_{station_id}_{device_id}_grid_charge_limit"
  91. self._attr_native_min_value = 0
  92. self._attr_native_max_value = 5000
  93. self._attr_native_step = 100
  94. self._attr_native_unit_of_measurement = "W"
  95. self._attr_mode = NumberMode.SLIDER
  96. self._attr_device_class = NumberDeviceClass.POWER
  97. self._attr_icon = "mdi:transmission-tower-import"
  98. @property
  99. def native_value(self):
  100. return ((self.coordinator.data or {}).get("settings") or {}).get(self._setting_key)
  101. async def async_set_native_value(self, value: float) -> None:
  102. await self.hass.async_add_executor_job(self._api.set_grid_charge_limit, self._device_id, int(value))
  103. await self.coordinator.async_request_refresh()