Skip to content

Commit

Permalink
Code formatting and comments
Browse files Browse the repository at this point in the history
  • Loading branch information
dan-r committed Dec 7, 2024
1 parent 43e4a70 commit 7f50106
Show file tree
Hide file tree
Showing 21 changed files with 177 additions and 100 deletions.
29 changes: 18 additions & 11 deletions custom_components/ohme/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
"""The ohme integration."""

import logging
from homeassistant import core
from homeassistant.helpers.entity_registry import RegistryEntry, async_migrate_entries
from .const import *
from .utils import get_option
from .const import (
DOMAIN,
CONFIG_VERSION,
ENTITY_TYPES,
DATA_CLIENT,
DATA_COORDINATORS,
DATA_OPTIONS,
LEGACY_MAPPING,
)
from ohme import OhmeApiClient
from .coordinator import (
OhmeChargeSessionsCoordinator,
Expand All @@ -21,7 +30,7 @@ async def async_setup(hass: core.HomeAssistant, config: dict) -> bool:


async def async_setup_dependencies(hass, entry):
"""Instantiate client and refresh session"""
"""Instantiate client and refresh session."""
client = OhmeApiClient(entry.data["email"], entry.data["password"])
account_id = entry.data["email"]

Expand All @@ -41,18 +50,15 @@ async def async_update_listener(hass, entry):


async def async_setup_entry(hass, entry):
"""This is called from the config flow."""
"""Called from the config flow."""

def _update_unique_id(entry: RegistryEntry) -> dict[str, str] | None:
"""Update unique IDs from old format."""
if entry.unique_id.startswith("ohme_"):
parts = entry.unique_id.split("_")
legacy_id = "_".join(parts[2:])

if legacy_id in LEGACY_MAPPING:
new_id = LEGACY_MAPPING[legacy_id]
else:
new_id = legacy_id
new_id = LEGACY_MAPPING.get(legacy_id, legacy_id)

new_id = f"{parts[1]}_{new_id}"

Expand Down Expand Up @@ -90,7 +96,7 @@ def _update_unique_id(entry: RegistryEntry) -> dict[str, str] | None:
# Catch failures if this is an 'optional' coordinator
try:
await coordinator.async_config_entry_first_refresh()
except ConfigEntryNotReady as ex:
except ConfigEntryNotReady:
allow_failure = False
for optional in coordinators_optional:
allow_failure = (
Expand All @@ -99,10 +105,11 @@ def _update_unique_id(entry: RegistryEntry) -> dict[str, str] | None:

if allow_failure:
_LOGGER.error(
f"{coordinator.__class__.__name__} failed to setup. This coordinator is optional so the integration will still function, but please raise an issue if this persists."
"%s failed to setup. This coordinator is optional so the integration will still function, but please raise an issue if this persists.",
coordinator.__class__.__name__,
)
else:
raise ex
raise

hass.data[DOMAIN][account_id][DATA_COORDINATORS] = coordinators

Expand Down
2 changes: 2 additions & 0 deletions custom_components/ohme/base.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Base class for entities."""

from homeassistant.helpers.entity import Entity
from homeassistant.core import callback

Expand Down
26 changes: 16 additions & 10 deletions custom_components/ohme/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
"""Platform for sensor integration."""
"""Platform for binary_sensor."""

from __future__ import annotations
import logging
from homeassistant.components.binary_sensor import (
BinarySensorDeviceClass,
BinarySensorEntity,
)
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import generate_entity_id
from homeassistant.util.dt import utcnow
from .const import (
DOMAIN,
Expand All @@ -18,15 +17,16 @@
COORDINATOR_ADVANCED,
DATA_CLIENT,
)
from .coordinator import OhmeChargeSessionsCoordinator
from .utils import in_slot
from .base import OhmeEntity

_LOGGER = logging.getLogger(__name__)


async def async_setup_entry(
hass: core.HomeAssistant,
config_entry: config_entries.ConfigEntry,
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities,
):
"""Setup sensors and configure coordinator."""
Expand Down Expand Up @@ -59,6 +59,8 @@ class ConnectedBinarySensor(OhmeEntity, BinarySensorEntity):

@property
def is_on(self) -> bool:
"""Calculate state."""

if self.coordinator.data is None:
self._state = False
else:
Expand Down Expand Up @@ -88,10 +90,13 @@ def __init__(

@property
def is_on(self) -> bool:
"""Return state."""

return self._state

def _calculate_state(self) -> bool:
"""Some trickery to get the charge state to update quickly."""

power = self.coordinator.data["power"]["watt"]

# If no last reading or no batterySoc/power, fallback to power > 0
Expand Down Expand Up @@ -176,6 +181,7 @@ def _calculate_state(self) -> bool:
@callback
def _handle_coordinator_update(self) -> None:
"""Update data."""

# Don't accept updates if 5s hasnt passed
# State calculations use deltas that may be unreliable to check if requests are too often
if self._last_updated and (
Expand Down Expand Up @@ -229,11 +235,7 @@ class CurrentSlotBinarySensor(OhmeEntity, BinarySensorEntity):
def extra_state_attributes(self):
"""Attributes of the sensor."""
now = utcnow()
slots = (
self._hass.data[DOMAIN][self._client.email][DATA_SLOTS]
if DATA_SLOTS in self._hass.data[DOMAIN][self._client.email]
else []
)
slots = self._hass.data[DOMAIN][self._client.email].get(DATA_SLOTS, [])

return {
"planned_dispatches": [x for x in slots if not x["end"] or x["end"] > now],
Expand All @@ -242,6 +244,8 @@ def extra_state_attributes(self):

@property
def is_on(self) -> bool:
"""Return state."""

return self._state

@callback
Expand All @@ -268,6 +272,8 @@ class ChargerOnlineBinarySensor(OhmeEntity, BinarySensorEntity):

@property
def is_on(self) -> bool:
"""Calculate state."""

if self.coordinator.data and self.coordinator.data["online"]:
return True
elif self.coordinator.data:
Expand Down
6 changes: 4 additions & 2 deletions custom_components/ohme/button.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"""Platform for button."""

from __future__ import annotations
import logging
import asyncio

from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import generate_entity_id
from homeassistant.config_entries import ConfigEntry
from homeassistant.components.button import ButtonEntity

from .const import DOMAIN, DATA_CLIENT, DATA_COORDINATORS, COORDINATOR_CHARGESESSIONS
Expand All @@ -13,7 +15,7 @@


async def async_setup_entry(
hass: HomeAssistant, config_entry: config_entries.ConfigEntry, async_add_entities
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
):
"""Setup switches."""
account_id = config_entry.data["email"]
Expand Down
12 changes: 10 additions & 2 deletions custom_components/ohme/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""UI configuration flow."""

import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, OptionsFlow
from .const import (
Expand All @@ -20,6 +22,8 @@ class OhmeConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = CONFIG_VERSION

async def async_step_user(self, info):
"""First config step."""

errors = {}

if info is not None:
Expand All @@ -35,17 +39,21 @@ async def async_step_user(self, info):
step_id="user", data_schema=USER_SCHEMA, errors=errors
)

def async_get_options_flow(entry):
return OhmeOptionsFlow(entry)
def async_get_options_flow(self):
"""Return options flow."""
return OhmeOptionsFlow(self)


class OhmeOptionsFlow(OptionsFlow):
"""Options flow."""

def __init__(self, entry) -> None:
"""Initialize options flow and store config entry."""
self._config_entry = entry

async def async_step_init(self, options):
"""First step of options flow."""

errors = {}
# If form filled
if options is not None:
Expand Down
4 changes: 1 addition & 3 deletions custom_components/ohme/const.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"""Component constants"""
"""Component constants."""

DOMAIN = "ohme"
USER_AGENT = "dan-r-homeassistant-ohme"
INTEGRATION_VERSION = "1.1.0"
CONFIG_VERSION = 1
ENTITY_TYPES = ["sensor", "binary_sensor", "switch", "button", "number", "time"]

Expand Down
19 changes: 11 additions & 8 deletions custom_components/ohme/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
"""Ohme coordinators."""

from datetime import timedelta
import logging

from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from ohme import ApiException

from .const import (
DOMAIN,
Expand Down Expand Up @@ -41,8 +44,8 @@ async def _async_update_data(self):
try:
return await self._client.async_get_charge_sessions()

except BaseException:
raise UpdateFailed("Error communicating with API")
except ApiException as e:
raise UpdateFailed("Error communicating with API") from e


class OhmeAccountInfoCoordinator(DataUpdateCoordinator):
Expand Down Expand Up @@ -70,8 +73,8 @@ async def _async_update_data(self):
try:
return await self._client.async_get_account_info()

except BaseException:
raise UpdateFailed("Error communicating with API")
except ApiException as e:
raise UpdateFailed("Error communicating with API") from e


class OhmeAdvancedSettingsCoordinator(DataUpdateCoordinator):
Expand All @@ -96,8 +99,8 @@ async def _async_update_data(self):
try:
return await self._client.async_get_advanced_settings()

except BaseException:
raise UpdateFailed("Error communicating with API")
except ApiException as e:
raise UpdateFailed("Error communicating with API") from e


class OhmeChargeSchedulesCoordinator(DataUpdateCoordinator):
Expand All @@ -122,5 +125,5 @@ async def _async_update_data(self):
try:
return await self._client.async_get_schedule()

except BaseException:
raise UpdateFailed("Error communicating with API")
except ApiException as e:
raise UpdateFailed("Error communicating with API") from e
19 changes: 13 additions & 6 deletions custom_components/ohme/number.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"""Platform for number."""

from __future__ import annotations
import asyncio
from homeassistant.components.number import NumberEntity, NumberDeviceClass
from homeassistant.components.number.const import NumberMode, PERCENTAGE
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfTime
from homeassistant.helpers.entity import generate_entity_id
from homeassistant.core import callback, HomeAssistant
from .const import (
DOMAIN,
Expand All @@ -18,7 +20,7 @@


async def async_setup_entry(
hass: HomeAssistant, config_entry: config_entries.ConfigEntry, async_add_entities
hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities
):
"""Setup switches and configure coordinator."""
account_id = config_entry.data["email"]
Expand Down Expand Up @@ -59,6 +61,7 @@ class TargetPercentNumber(OhmeEntity, NumberEntity):
_attr_suggested_display_precision = 0

def __init__(self, coordinator, coordinator_schedules, hass: HomeAssistant, client):
"""Initialise the entity and set up a second coordinator."""
super().__init__(coordinator, hass, client)
self.coordinator_schedules = coordinator_schedules

Expand All @@ -85,7 +88,7 @@ async def async_set_native_value(self, value: float) -> None:

@callback
def _handle_coordinator_update(self) -> None:
"""Get value from data returned from API by coordinator"""
"""Get value from data returned from API by coordinator."""
# Set with the same logic as reading
if session_in_progress(self.hass, self._client.email, self.coordinator.data):
target = round(self.coordinator.data["appliedRule"]["targetPercent"])
Expand All @@ -96,6 +99,7 @@ def _handle_coordinator_update(self) -> None:

@property
def native_value(self):
"""Return the state of the entity."""
return self._state


Expand All @@ -111,6 +115,7 @@ class PreconditioningNumber(OhmeEntity, NumberEntity):
_attr_native_max_value = 60

def __init__(self, coordinator, coordinator_schedules, hass: HomeAssistant, client):
"""Initialise the entity and set up a second coordinator."""
super().__init__(coordinator, hass, client)
self.coordinator_schedules = coordinator_schedules

Expand Down Expand Up @@ -147,7 +152,7 @@ async def async_set_native_value(self, value: float) -> None:

@callback
def _handle_coordinator_update(self) -> None:
"""Get value from data returned from API by coordinator"""
"""Get value from data returned from API by coordinator."""
precondition = None
# Set with the same logic as reading
if session_in_progress(self.hass, self._client.email, self.coordinator.data):
Expand Down Expand Up @@ -175,6 +180,7 @@ def _handle_coordinator_update(self) -> None:

@property
def native_value(self):
"""Return the state of the entity."""
return self._state


Expand Down Expand Up @@ -206,16 +212,17 @@ def native_unit_of_measurement(self):

@callback
def _handle_coordinator_update(self) -> None:
"""Get value from data returned from API by coordinator"""
"""Get value from data returned from API by coordinator."""
if self.coordinator.data is not None:
try:
self._state = self.coordinator.data["userSettings"]["chargeSettings"][
0
]["value"]
except:
except (IndexError, KeyError):
self._state = None
self.async_write_ha_state()

@property
def native_value(self):
"""Return the state of the entity."""
return self._state
Loading

0 comments on commit 7f50106

Please sign in to comment.