Skip to content

Commit

Permalink
initial test
Browse files Browse the repository at this point in the history
  • Loading branch information
sirkojon committed Feb 20, 2024
1 parent 4136b7f commit 7ee1b87
Show file tree
Hide file tree
Showing 39 changed files with 1,686 additions and 0 deletions.
8 changes: 8 additions & 0 deletions custom_components/chuck_control/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions custom_components/chuck_control/.idea/chuck_control.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions custom_components/chuck_control/.idea/chuck_powerbalancer.iml

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.

4 changes: 4 additions & 0 deletions custom_components/chuck_control/.idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions custom_components/chuck_control/.idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions custom_components/chuck_control/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

106 changes: 106 additions & 0 deletions custom_components/chuck_control/__init__.py
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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
137 changes: 137 additions & 0 deletions custom_components/chuck_control/button.py
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()
Loading

0 comments on commit 7ee1b87

Please sign in to comment.