-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
"""The Chuck Charger Control integration.""" | ||
from __future__ import annotations | ||
import voluptuous as vol | ||
|
||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import Platform | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.exceptions import ( | ||
ConfigEntryAuthFailed, | ||
ConfigEntryNotReady, | ||
PlatformNotReady, | ||
) | ||
from .const import DOMAIN, PHASE_ORDER_DICT, CONF_HAVE_NET_CURRENT_SENSOR | ||
import logging | ||
import asyncio | ||
from . import chuck_rest | ||
|
||
|
||
PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.BUTTON] | ||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Set up Chuck Charger Control from a config entry.""" | ||
hass.data.setdefault(DOMAIN, {}) | ||
chargebox_cfg = dict(entry.data) | ||
have_net_current_sensor = chargebox_cfg[CONF_HAVE_NET_CURRENT_SENSOR] | ||
|
||
chargebox = chuck_rest.ChuckChargeBox( | ||
hass=hass, | ||
base_url=chargebox_cfg["base_url"], | ||
auth_name=chargebox_cfg["auth_user"], | ||
auth_pass=chargebox_cfg["auth_pass"], | ||
friendly_name=chargebox_cfg["friendly_name"], | ||
have_net_current_sensor=have_net_current_sensor, | ||
phase_order=[ | ||
chargebox_cfg["cfg_phase_order_conn1"], | ||
chargebox_cfg["cfg_phase_order_conn2"], | ||
], | ||
) | ||
|
||
try: | ||
await hass.async_add_executor_job(chargebox.update) | ||
except chuck_rest.ChuckRestTimeout: | ||
raise PlatformNotReady( | ||
f"Could not connect to chargebox {chargebox_cfg['friendly_name']} at {chargebox_cfg['base_url']}" | ||
) | ||
except chuck_rest.ChuckAuthError: | ||
raise ConfigEntryAuthFailed( | ||
f"Wrong username or password supplied for chargebox {chargebox_cfg['friendly_name']} at {chargebox_cfg['base_url']}" | ||
) | ||
except: | ||
raise PlatformNotReady( | ||
f"Unknown error connecting to chargebox {chargebox_cfg['friendly_name']} at {chargebox_cfg['base_url']}" | ||
) | ||
|
||
# Registers update listener to update config entry when options are updated. | ||
unsub_options_update_listener = entry.add_update_listener(options_update_listener) | ||
# Store a reference to the unsubscribe function to cleanup if an entry is unloaded. | ||
chargebox_cfg["unsub_options_update_listener"] = unsub_options_update_listener | ||
chargebox_cfg.update({"chargebox": chargebox}) | ||
hass.data[DOMAIN][entry.entry_id] = chargebox_cfg | ||
|
||
# Forward the setup to the sensor platform. | ||
await asyncio.gather( | ||
*( | ||
hass.config_entries.async_forward_entry_setup(entry, platform) | ||
for platform in PLATFORMS | ||
) | ||
) | ||
|
||
return True | ||
|
||
|
||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Unload a config entry.""" | ||
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): | ||
hass.data[DOMAIN][entry.entry_id]["unsub_options_update_listener"]() | ||
hass.data[DOMAIN].pop(entry.entry_id) | ||
|
||
return unload_ok | ||
|
||
|
||
async def options_update_listener(hass: HomeAssistant, config_entry: ConfigEntry): | ||
"""Handle options update.""" | ||
await hass.config_entries.async_reload(config_entry.entry_id) | ||
|
||
|
||
async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry): | ||
"""Migrate old entry.""" | ||
_LOGGER.debug("Migrating from version %s", config_entry.version) | ||
|
||
if config_entry.version == 1: | ||
new = {**config_entry.data} | ||
|
||
new["cfg_phase_order_conn1"] = config_entry.data["cfg_phase_order"] | ||
new["cfg_phase_order_conn2"] = config_entry.data["cfg_phase_order"] | ||
|
||
del new["cfg_phase_order"] | ||
|
||
config_entry.version = 2 | ||
hass.config_entries.async_update_entry(config_entry, data=new) | ||
|
||
_LOGGER.info("Migration to version %s successful", config_entry.version) | ||
|
||
return True |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
from homeassistant.components.button import ButtonEntity, ButtonDeviceClass | ||
from homeassistant import config_entries, core | ||
from homeassistant.components.button import ButtonEntity, ButtonDeviceClass | ||
from homeassistant.const import * | ||
from homeassistant.helpers.entity import DeviceInfo | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
|
||
from datetime import timedelta | ||
import logging | ||
from .const import DOMAIN, PHASE_ORDER_DICT | ||
from .sensor import get_friendly_name | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
SCAN_INTERVAL = timedelta(seconds=2) | ||
|
||
|
||
async def async_setup_entry( | ||
hass: core.HomeAssistant, | ||
config_entry: config_entries.ConfigEntry, | ||
async_add_entities: AddEntitiesCallback, | ||
): | ||
_LOGGER.debug("ASYNC SETUP ENTRY") | ||
chargebox = hass.data[DOMAIN][config_entry.entry_id]["chargebox"] | ||
charger_connected_to_ocpp = config_entry.data.get("is_connected_to_ocpp") | ||
to_add = get_buttons_to_add(chargebox, charger_connected_to_ocpp) | ||
async_add_entities(to_add) | ||
|
||
|
||
def get_buttons_to_add(chargebox, charger_connected_to_ocpp) -> list[ButtonEntity]: | ||
"""Return HA button entities used to control the charger based on its configuration. | ||
Args: | ||
chargebox (ChuckChargeBox): Charger that is currently being added | ||
charger_connected_to_ocpp (bool): True if charger is configured to communicate with a OCPP server (more on that below) | ||
Returns: | ||
buttons_to_add (list[ButtonEntity]): List of button entites to add to HA | ||
For each connector two buttons are added - one is to start the charging, the other one will stop it. | ||
If the charger is not connected to ocpp gateway (chuck is configured to use LOCAL or LOCAL_WITH_AUTH profile) | ||
the start button will simply enable charging which will start immediately if a car is connected and wants to charge. | ||
If the charger is connected to ocpp gateway (and chuck is using the OCPP profile) the start button will enable | ||
the charger and sends a start transaction request to the ocpp server, which will result in charging if allowed | ||
by the server. | ||
""" | ||
buttons_to_add = [] | ||
for connector in range(chargebox.get_connectors_count()): | ||
if charger_connected_to_ocpp: | ||
buttons_to_add.append( | ||
StartTransactionButton(chargebox=chargebox, connector_id=connector + 1) | ||
) | ||
|
||
buttons_to_add.extend( | ||
[ | ||
EnableChargingButton(chargebox=chargebox, connector_id=connector + 1), | ||
DisableChargingButton(chargebox=chargebox, connector_id=connector + 1), | ||
] | ||
) | ||
return buttons_to_add | ||
|
||
|
||
class DisableChargingButton(ButtonEntity): | ||
def __init__(self, chargebox, connector_id) -> None: | ||
super().__init__() | ||
self.chargebox = chargebox | ||
self.connector_id = connector_id | ||
self.friendly_name_appendix = "Disable charging" | ||
self.friendly_name = get_friendly_name(self) | ||
|
||
async def async_press(self): | ||
await self.chargebox.set_connector_enable_charging( | ||
connectorId=self.connector_id, state=False | ||
) | ||
|
||
@property | ||
def unique_id(self) -> str: | ||
return f"{self.chargebox.info['serialNumber']}_connector_{self.connector_id}_disable_charging" | ||
|
||
@property | ||
def name(self) -> str: | ||
return self.friendly_name | ||
|
||
@property | ||
def device_info(self) -> DeviceInfo: | ||
return self.chargebox.get_device_info() | ||
|
||
|
||
class EnableChargingButton(ButtonEntity): | ||
def __init__(self, chargebox, connector_id) -> None: | ||
super().__init__() | ||
self.chargebox = chargebox | ||
self.connector_id = connector_id | ||
self.friendly_name_appendix = "Enable charging" | ||
self.friendly_name = get_friendly_name(self) | ||
|
||
async def async_press(self): | ||
await self.chargebox.set_connector_enable_charging( | ||
connectorId=self.connector_id, state=True | ||
) | ||
|
||
@property | ||
def unique_id(self) -> str: | ||
return f"{self.chargebox.info['serialNumber']}_connector_{self.connector_id}_enable_charging" | ||
|
||
@property | ||
def name(self) -> str: | ||
return self.friendly_name | ||
|
||
@property | ||
def device_info(self) -> DeviceInfo: | ||
return self.chargebox.get_device_info() | ||
|
||
|
||
class StartTransactionButton(ButtonEntity): | ||
def __init__(self, chargebox, connector_id) -> None: | ||
super().__init__() | ||
self.chargebox = chargebox | ||
self.connector_id = connector_id | ||
self.friendly_name_appendix = "Start transcation" | ||
self.friendly_name = get_friendly_name(self) | ||
|
||
async def async_press(self): | ||
await self.chargebox.set_connector_charging_start( | ||
action="Start", connector=self.connector_id | ||
) | ||
|
||
@property | ||
def unique_id(self) -> str: | ||
return f"{self.chargebox.info['serialNumber']}_connector_{self.connector_id}_transcation_start" | ||
|
||
@property | ||
def name(self) -> str: | ||
return self.friendly_name | ||
|
||
@property | ||
def device_info(self) -> DeviceInfo: | ||
return self.chargebox.get_device_info() |