Skip to content

Commit

Permalink
added support for multiple wallboxes (#155)
Browse files Browse the repository at this point in the history
Based on the first feedback, I added multi-wallbox capability rightaway.

According to E3DC RSCP spec, up to 8 Wallboxes are supported.

If there's only one wallbox, WB entities are names "Wallbox ...", if
there are more, they are numbered starting with 1.
WB name/key/index is kept in a central list of Dict, so more advanced
naming conventions could be introduced easily.

As this can become a very long list of wallbox entities, ideally each
wallbox would be a own device.
I explored this a little bit but i'm afraid this would be a bigger
refactoring of this integration or something, which requires a deeper
understanding of HA.

As i only have one wallbox at home, i could only verify, that the
behaviour of that one is still correct, for the other wallboxes, i could
just verify that namings, keys and calling python-e3dc works as intended
but of course i could not verify if correct data is returned.

However I'd suggest to update the Beta in order to get feedback from
e.g. @Thomansky to test the multi-wallbox-functions.
  • Loading branch information
torbennehmer authored Jul 2, 2024
2 parents 8073de2 + bb132a9 commit 01cf975
Show file tree
Hide file tree
Showing 11 changed files with 451 additions and 300 deletions.
149 changes: 87 additions & 62 deletions custom_components/e3dc_rscp/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,67 +55,6 @@ class E3DCBinarySensorEntityDescription(BinarySensorEntityDescription):
on_icon="mdi:electric-switch-closed",
off_icon="mdi:electric-switch",
),
E3DCBinarySensorEntityDescription(
key="wallbox-sun-mode",
translation_key="wallbox-sun-mode",
on_icon="mdi:weather-sunny",
off_icon="mdi:weather-sunny-off",
device_class=None,
),
E3DCBinarySensorEntityDescription(
key="wallbox-plug-lock",
translation_key="wallbox-plug-lock",
on_icon="mdi:lock-open",
off_icon="mdi:lock",
device_class=BinarySensorDeviceClass.LOCK,
entity_registry_enabled_default=False, # Disabled per default as only Wallbox easy connect provides this state

),
E3DCBinarySensorEntityDescription(
key="wallbox-plug",
translation_key="wallbox-plug",
on_icon="mdi:power-plug",
off_icon="mdi:power-plug-off",
device_class=BinarySensorDeviceClass.PLUG,
),
E3DCBinarySensorEntityDescription(
key="wallbox-schuko",
translation_key="wallbox-schuko",
on_icon="mdi:power-plug-outline",
off_icon="mdi:power-plug-off-outline",
device_class=BinarySensorDeviceClass.POWER,
entity_registry_enabled_default=False, # Disabled per default as only Wallbox multi connect I provides this feature
),
E3DCBinarySensorEntityDescription(
key="wallbox-charging",
translation_key="wallbox-charging",
on_icon="mdi:car-electric",
off_icon="mdi:car-electric-outline",
device_class=BinarySensorDeviceClass.BATTERY_CHARGING,
),
E3DCBinarySensorEntityDescription(
key="wallbox-charging-canceled",
translation_key="wallbox-charging-canceled",
on_icon="mdi:cancel",
off_icon="mdi:check-circle-outline",
device_class=None,
),
E3DCBinarySensorEntityDescription(
key="wallbox-battery-to-car",
translation_key="wallbox-battery-to-car",
on_icon="mdi:battery-charging",
off_icon="mdi:battery-off",
device_class=None,
entity_registry_enabled_default=False,
),
E3DCBinarySensorEntityDescription(
key="wallbox-key-state",
translation_key="wallbox-key-state",
on_icon="mdi:key-variant",
off_icon="mdi:key-remove",
device_class=BinarySensorDeviceClass.LOCK,
entity_registry_enabled_default=False,
),
)


Expand All @@ -128,8 +67,94 @@ async def async_setup_entry(
entities: list[E3DCBinarySensor] = [
E3DCBinarySensor(coordinator, description, entry.unique_id)
for description in SENSOR_DESCRIPTIONS
if coordinator.wallbox_installed or not description.key.startswith("wallbox-")
]

for wallbox in coordinator.wallboxes:

wallbox_sun_mode_description = E3DCBinarySensorEntityDescription(
key=wallbox["key"] + "-sun-mode",
translation_key="wallbox-sun-mode",
translation_placeholders = {"wallbox_name": wallbox["name"]},
on_icon="mdi:weather-sunny",
off_icon="mdi:weather-sunny-off",
device_class=None,
)
entities.append(E3DCBinarySensor(coordinator, wallbox_sun_mode_description, entry.unique_id))

wallbox_plug_lock_description = E3DCBinarySensorEntityDescription(
key=wallbox["key"] + "-plug-lock",
translation_key="wallbox-plug-lock",
translation_placeholders = {"wallbox_name": wallbox["name"]},
on_icon="mdi:lock-open",
off_icon="mdi:lock",
device_class=BinarySensorDeviceClass.LOCK,
entity_registry_enabled_default=False, # Disabled per default as only Wallbox easy connect provides this state
)
entities.append(E3DCBinarySensor(coordinator, wallbox_plug_lock_description, entry.unique_id))

wallbox_plug_description = E3DCBinarySensorEntityDescription(
key=wallbox["key"] + "-plug",
translation_key="wallbox-plug",
translation_placeholders = {"wallbox_name": wallbox["name"]},
on_icon="mdi:power-plug",
off_icon="mdi:power-plug-off",
device_class=BinarySensorDeviceClass.PLUG,
)
entities.append(E3DCBinarySensor(coordinator, wallbox_plug_description, entry.unique_id))

wallbox_schuko_description = E3DCBinarySensorEntityDescription(
key=wallbox["key"] + "-schuko",
translation_key="wallbox-schuko",
translation_placeholders = {"wallbox_name": wallbox["name"]},
on_icon="mdi:power-plug-outline",
off_icon="mdi:power-plug-off-outline",
device_class=BinarySensorDeviceClass.POWER,
entity_registry_enabled_default=False, # Disabled per default as only Wallbox multi connect I provides this feature
)
entities.append(E3DCBinarySensor(coordinator, wallbox_schuko_description, entry.unique_id))

wallbox_charging_description = E3DCBinarySensorEntityDescription(
key=wallbox["key"] + "-charging",
translation_key="wallbox-charging",
translation_placeholders = {"wallbox_name": wallbox["name"]},
on_icon="mdi:car-electric",
off_icon="mdi:car-electric-outline",
device_class=BinarySensorDeviceClass.BATTERY_CHARGING,
)
entities.append(E3DCBinarySensor(coordinator, wallbox_charging_description, entry.unique_id))

wallbox_charging_canceled_description = E3DCBinarySensorEntityDescription(
key=wallbox["key"] + "-charging-canceled",
translation_key="wallbox-charging-canceled",
translation_placeholders = {"wallbox_name": wallbox["name"]},
on_icon="mdi:cancel",
off_icon="mdi:check-circle-outline",
device_class=None,
)
entities.append(E3DCBinarySensor(coordinator, wallbox_charging_canceled_description, entry.unique_id))

wallbox_battery_to_car_description = E3DCBinarySensorEntityDescription(
key=wallbox["key"] + "-battery-to-car",
translation_key="wallbox-battery-to-car",
translation_placeholders = {"wallbox_name": wallbox["name"]},
on_icon="mdi:battery-charging",
off_icon="mdi:battery-off",
device_class=None,
entity_registry_enabled_default=False,
)
entities.append(E3DCBinarySensor(coordinator, wallbox_battery_to_car_description, entry.unique_id))

wallbox_key_state_description = E3DCBinarySensorEntityDescription(
key=wallbox["key"] + "-key-state",
translation_key="wallbox-key-state",
translation_placeholders = {"wallbox_name": wallbox["name"]},
on_icon="mdi:key-variant",
off_icon="mdi:key-remove",
device_class=BinarySensorDeviceClass.LOCK,
entity_registry_enabled_default=False,
)
entities.append(E3DCBinarySensor(coordinator, wallbox_key_state_description, entry.unique_id))

async_add_entities(entities)


Expand Down
37 changes: 22 additions & 15 deletions custom_components/e3dc_rscp/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,7 @@ class E3DCButtonEntityDescription(ButtonEntityDescription):
) = None


BUTTONS: Final[tuple[E3DCButtonEntityDescription, ...]] = (
E3DCButtonEntityDescription(
key="wallbox-toggle-wallbox-phases",
translation_key="wallbox-toggle-wallbox-phases",
icon="mdi:sine-wave",
async_press_action=lambda coordinator: coordinator.async_toggle_wallbox_phases(),
),
E3DCButtonEntityDescription(
key="wallbox-toggle_wallbox-charging",
translation_key="wallbox-toggle-wallbox-charging",
icon="mdi:car-electric",
async_press_action=lambda coordinator: coordinator.async_toggle_wallbox_charging(),
),
)
BUTTONS: Final[tuple[E3DCButtonEntityDescription, ...]] = () # None yet


async def async_setup_entry(
Expand All @@ -57,9 +44,29 @@ async def async_setup_entry(
entities: list[E3DCButton] = [
E3DCButton(coordinator, description, entry.unique_id)
for description in BUTTONS
if coordinator.wallbox_installed or not description.key.startswith("wallbox-")
]

for wallbox in coordinator.wallboxes:

wallbox_toggle_wallbox_phases_description = E3DCButtonEntityDescription(
key=wallbox["key"] + "-toggle-wallbox-phases",
translation_key="wallbox-toggle-wallbox-phases",
translation_placeholders = {"wallbox_name": wallbox["name"]},
icon="mdi:sine-wave",
async_press_action=lambda coordinator: coordinator.async_toggle_wallbox_phases(),
)
entities.append(E3DCButton(coordinator, wallbox_toggle_wallbox_phases_description, entry.unique_id))

wallbox_toggle_wallbox_charging_description = E3DCButtonEntityDescription(
key=wallbox["key"] + "-toggle-wallbox-charging",
translation_key="wallbox-toggle-wallbox-charging",
translation_placeholders = {"wallbox_name": wallbox["name"]},
icon="mdi:car-electric",
async_press_action=lambda coordinator: coordinator.async_toggle_wallbox_charging(),
)
entities.append(E3DCButton(coordinator, wallbox_toggle_wallbox_charging_description, entry.unique_id))


async_add_entities(entities)


Expand Down
1 change: 1 addition & 0 deletions custom_components/e3dc_rscp/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
SERVICE_MANUAL_CHARGE = "manual_charge"
SERVICE_SET_WALLBOX_MAX_CHARGE_CURRENT = "set_wallbox_max_charge_current"
MAX_CHARGE_CURRENT = 32 # Maximum allowed wallbox charging current in Amperes
MAX_WALLBOXES_POSSIBLE = 8 # 8 is the maximum according to RSCP Specification

PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR,
Expand Down
Loading

0 comments on commit 01cf975

Please sign in to comment.