Skip to content

Commit 9a468bb

Browse files
committed
Added select box for lademodus and switch to turn on/off
1 parent bab155e commit 9a468bb

4 files changed

Lines changed: 171 additions & 2 deletions

File tree

custom_components/enpal_webparser/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
2424
hass.data.setdefault(DOMAIN, {})
2525

2626
use_wallbox_addon = entry.options.get("use_wallbox_addon", False)
27-
platforms = ["sensor"] + (["button"] if use_wallbox_addon else [])
27+
28+
platforms = ["sensor"]
29+
if use_wallbox_addon:
30+
platforms.extend(["button", "switch", "select"])
2831

2932
hass.data[DOMAIN][entry.entry_id] = {
3033
"config": entry.data,

custom_components/enpal_webparser/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
"iot_class": "local_polling",
99
"issue_tracker": "https://github.com/derolli1976/enpal/issues",
1010
"requirements": [],
11-
"version": "2.0.2"
11+
"version": "2.1.0"
1212
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import logging
2+
from homeassistant.components.switch import SwitchEntity
3+
from homeassistant.helpers.aiohttp_client import async_get_clientsession
4+
5+
from .const import DOMAIN
6+
7+
_LOGGER = logging.getLogger(__name__)
8+
9+
async def async_setup_entry(hass, config_entry, async_add_entities):
10+
if not config_entry.options.get("use_wallbox_addon", False):
11+
return
12+
13+
async_add_entities([EnpalWallboxSwitch(hass)], True)
14+
15+
class EnpalWallboxSwitch(SwitchEntity):
16+
def __init__(self, hass):
17+
self._hass = hass
18+
self._attr_name = "Wallbox Charging"
19+
self._attr_unique_id = "enpal_wallbox_charging_switch"
20+
self._is_on = False
21+
self._pending_state = None
22+
self._base_url = "http://localhost:36725/wallbox"
23+
24+
@property
25+
def is_on(self):
26+
return self._pending_state if self._pending_state is not None else self._is_on
27+
28+
@property
29+
def device_info(self):
30+
return {
31+
"identifiers": {(DOMAIN, "enpal_device")},
32+
"name": "Enpal Webgerät",
33+
"manufacturer": "Enpal",
34+
"model": "Webparser",
35+
}
36+
37+
async def async_update(self):
38+
status_entity = self._hass.states.get("sensor.wallbox_status")
39+
if not status_entity:
40+
return
41+
42+
status = status_entity.state.lower()
43+
new_state = status == "loading"
44+
45+
if self._pending_state is not None:
46+
if self._pending_state == new_state:
47+
_LOGGER.debug("Wallbox switch state confirmed by sensor: %s", status)
48+
self._is_on = new_state
49+
self._pending_state = None
50+
else:
51+
_LOGGER.debug("Wallbox switch state pending: requested=%s, sensor=%s", self._pending_state, new_state)
52+
else:
53+
self._is_on = new_state
54+
55+
async def async_turn_on(self, **kwargs):
56+
await self._call_wallbox_api("/start")
57+
self._pending_state = True
58+
self.async_write_ha_state()
59+
60+
async def async_turn_off(self, **kwargs):
61+
await self._call_wallbox_api("/stop")
62+
self._pending_state = False
63+
self.async_write_ha_state()
64+
65+
async def _call_wallbox_api(self, endpoint):
66+
url = f"{self._base_url}{endpoint}"
67+
try:
68+
session = async_get_clientsession(self._hass)
69+
async with session.post(url, timeout=5) as resp:
70+
if resp.status != 200:
71+
_LOGGER.warning("Wallbox API call failed: %s", url)
72+
except Exception as e:
73+
_LOGGER.error("Error calling wallbox API endpoint %s: %s", endpoint, e)

0 commit comments

Comments
 (0)