|
| 1 | +import logging |
| 2 | +from homeassistant.components.select import SelectEntity |
| 3 | +from homeassistant.helpers.aiohttp_client import async_get_clientsession |
| 4 | + |
| 5 | +from .const import DOMAIN |
| 6 | + |
| 7 | +_LOGGER = logging.getLogger(__name__) |
| 8 | + |
| 9 | +# Mapping: API → UI |
| 10 | +MODE_MAP = { |
| 11 | + "eco": "Eco", |
| 12 | + "fast": "Full", |
| 13 | + "solar": "Solar", |
| 14 | +} |
| 15 | + |
| 16 | +# UI → API |
| 17 | +REVERSE_MODE_MAP = {v.lower(): k for k, v in MODE_MAP.items()} |
| 18 | + |
| 19 | +async def async_setup_entry(hass, config_entry, async_add_entities): |
| 20 | + if not config_entry.options.get("use_wallbox_addon", False): |
| 21 | + return |
| 22 | + |
| 23 | + async_add_entities([EnpalWallboxModeSelect(hass)], True) |
| 24 | + |
| 25 | +class EnpalWallboxModeSelect(SelectEntity): |
| 26 | + def __init__(self, hass): |
| 27 | + self._hass = hass |
| 28 | + self._attr_name = "Wallbox Mode" |
| 29 | + self._attr_unique_id = "enpal_wallbox_mode_select" |
| 30 | + self._attr_options = list(MODE_MAP.values()) |
| 31 | + self._current_option = None |
| 32 | + self._pending_change = None |
| 33 | + self._base_url = "http://localhost:36725/wallbox" |
| 34 | + |
| 35 | + @property |
| 36 | + def current_option(self): |
| 37 | + return self._pending_change or self._current_option |
| 38 | + |
| 39 | + @property |
| 40 | + def device_info(self): |
| 41 | + return { |
| 42 | + "identifiers": {(DOMAIN, "enpal_device")}, |
| 43 | + "name": "Enpal Webgerät", |
| 44 | + "manufacturer": "Enpal", |
| 45 | + "model": "Webparser", |
| 46 | + } |
| 47 | + |
| 48 | + async def async_update(self): |
| 49 | + mode_entity = self._hass.states.get("sensor.wallbox_lademodus") |
| 50 | + if not mode_entity: |
| 51 | + return |
| 52 | + |
| 53 | + mode = mode_entity.state.lower() |
| 54 | + new_option = MODE_MAP.get(mode) |
| 55 | + |
| 56 | + if not new_option: |
| 57 | + _LOGGER.warning("Unknown wallbox mode from sensor: %s", mode) |
| 58 | + return |
| 59 | + |
| 60 | + # Wenn gerade ein pending change aktiv ist, dann prüfen: |
| 61 | + if self._pending_change: |
| 62 | + if self._pending_change == new_option: |
| 63 | + # Auswahl wurde bestätigt → Pending löschen |
| 64 | + _LOGGER.debug("Pending wallbox mode %s confirmed by sensor.", new_option) |
| 65 | + self._current_option = new_option |
| 66 | + self._pending_change = None |
| 67 | + else: |
| 68 | + # Auswahl noch nicht bestätigt → Anzeige bleibt unverändert |
| 69 | + _LOGGER.debug("Wallbox mode change pending: %s (sensor reports %s)", self._pending_change, new_option) |
| 70 | + else: |
| 71 | + self._current_option = new_option |
| 72 | + |
| 73 | + async def async_select_option(self, option: str): |
| 74 | + key = REVERSE_MODE_MAP.get(option.lower()) |
| 75 | + if key: |
| 76 | + self._pending_change = option |
| 77 | + self.async_write_ha_state() |
| 78 | + |
| 79 | + await self._call_wallbox_api(f"/set_{key}") |
| 80 | + |
| 81 | + # Im Erfolgsfall übernehmen wir nicht direkt — wir warten auf Bestätigung durch Sensor |
| 82 | + else: |
| 83 | + _LOGGER.warning("Unknown selected option: %s", option) |
| 84 | + |
| 85 | + async def _call_wallbox_api(self, endpoint): |
| 86 | + url = f"{self._base_url}{endpoint}" |
| 87 | + try: |
| 88 | + session = async_get_clientsession(self._hass) |
| 89 | + async with session.post(url, timeout=5) as resp: |
| 90 | + if resp.status != 200: |
| 91 | + _LOGGER.warning("Wallbox API call failed: %s", url) |
| 92 | + except Exception as e: |
| 93 | + _LOGGER.error("Error calling wallbox API endpoint %s: %s", endpoint, e) |
0 commit comments