Skip to content

Commit

Permalink
Changes to schedule and session updating (#32)
Browse files Browse the repository at this point in the history
* Refactor target percent/time logic and fix pending approval bug

* Give OhmeChargeSchedulesCoordinator a kick to update
  • Loading branch information
dan-r authored Jan 3, 2024
1 parent 3675b08 commit ef838ba
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 27 deletions.
2 changes: 1 addition & 1 deletion custom_components/ohme/api_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ async def async_max_charge(self):
result = await self._put_request(f"/v1/chargeSessions/{self._serial}/rule?maxCharge=true")
return bool(result)

async def async_apply_charge_rule(self, max_price=None, target_time=None, target_percent=None, pre_condition=None, pre_condition_length=None):
async def async_apply_session_rule(self, max_price=None, target_time=None, target_percent=None, pre_condition=None, pre_condition_length=None):
"""Apply rule to ongoing charge/stop max charge."""
# Check every property. If we've provided it, use that. If not, use the existing.
if max_price is None:
Expand Down
2 changes: 1 addition & 1 deletion custom_components/ohme/const.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Component constants"""
DOMAIN = "ohme"
USER_AGENT = "dan-r-homeassistant-ohme"
INTEGRATION_VERSION = "0.3.0"
INTEGRATION_VERSION = "0.3.1"

DATA_CLIENT = "client"
DATA_COORDINATORS = "coordinators"
Expand Down
41 changes: 29 additions & 12 deletions custom_components/ohme/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from homeassistant.helpers.entity import generate_entity_id
from homeassistant.core import callback, HomeAssistant
from .const import DOMAIN, DATA_CLIENT, DATA_COORDINATORS, COORDINATOR_CHARGESESSIONS, COORDINATOR_SCHEDULES

from .utils import session_in_progress

async def async_setup_entry(
hass: HomeAssistant,
Expand Down Expand Up @@ -43,36 +43,53 @@ def __init__(self, coordinator, coordinator_schedules, hass: HomeAssistant, clie

self._attr_device_info = client.get_device_info()

async def async_added_to_hass(self) -> None:
"""When entity is added to hass."""
await super().async_added_to_hass()
self.async_on_remove(
self.coordinator.async_add_listener(
self._handle_coordinator_update, None
)
)
self.async_on_remove(
self.coordinator_schedules.async_add_listener(
self._handle_coordinator_update, None
)
)

@property
def unique_id(self):
"""The unique ID of the switch."""
return self._client.get_unique_id("target_percent")

async def async_set_native_value(self, value: float) -> None:
"""Update the current value."""
# If disconnected, update top rule. If not, apply rule to current session
if self.coordinator.data and self.coordinator.data['mode'] == "DISCONNECTED":
await self._client.async_update_schedule(target_percent=int(value))
# If session in progress, update this session, if not update the first schedule
if session_in_progress(self.coordinator.data):
await self._client.async_apply_session_rule(target_percent=int(value))
await asyncio.sleep(1)
await self.coordinator_schedules.async_refresh()
await self.coordinator.async_refresh()
else:
await self._client.async_apply_charge_rule(target_percent=int(value))
await self._client.async_update_schedule(target_percent=int(value))
await asyncio.sleep(1)
await self.coordinator.async_refresh()
await self.coordinator_schedules.async_refresh()

@property
def icon(self):
"""Icon of the sensor."""
return "mdi:battery-heart"

@property
def native_value(self):
@callback
def _handle_coordinator_update(self) -> None:
"""Get value from data returned from API by coordinator"""
if self.coordinator.data and self.coordinator.data['appliedRule'] and self.coordinator.data['mode'] != "PENDING_APPROVAL" and self.coordinator.data['mode'] != "DISCONNECTED":
target = round(
self.coordinator.data['appliedRule']['targetPercent'])
# Set with the same logic as reading
if session_in_progress(self.coordinator.data):
target = round(self.coordinator.data['appliedRule']['targetPercent'])
elif self.coordinator_schedules.data:
target = round(self.coordinator_schedules.data['targetPercent'])

self._state = target if target > 0 else None

@property
def native_value(self):
return self._state
2 changes: 1 addition & 1 deletion custom_components/ohme/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ async def async_turn_on(self):
async def async_turn_off(self):
"""Stop max charging.
We are not changing anything, just applying the last rule. No need to supply anything."""
await self._client.async_apply_charge_rule()
await self._client.async_apply_session_rule()

await asyncio.sleep(1)
await self.coordinator.async_refresh()
Expand Down
41 changes: 29 additions & 12 deletions custom_components/ohme/time.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from homeassistant.helpers.entity import generate_entity_id
from homeassistant.core import callback, HomeAssistant
from .const import DOMAIN, DATA_CLIENT, DATA_COORDINATORS, COORDINATOR_CHARGESESSIONS, COORDINATOR_SCHEDULES
from .utils import session_in_progress
from datetime import time as dt_time

_LOGGER = logging.getLogger(__name__)
Expand Down Expand Up @@ -44,6 +45,20 @@ def __init__(self, coordinator, coordinator_schedules, hass: HomeAssistant, clie
"number.{}", "ohme_target_time", hass=hass)

self._attr_device_info = client.get_device_info()

async def async_added_to_hass(self) -> None:
"""When entity is added to hass."""
await super().async_added_to_hass()
self.async_on_remove(
self.coordinator.async_add_listener(
self._handle_coordinator_update, None
)
)
self.async_on_remove(
self.coordinator_schedules.async_add_listener(
self._handle_coordinator_update, None
)
)

@property
def unique_id(self):
Expand All @@ -52,29 +67,27 @@ def unique_id(self):

async def async_set_value(self, value: dt_time) -> None:
"""Update the current value."""
# If disconnected, update top rule. If not, apply rule to current session
if self.coordinator.data and self.coordinator.data['mode'] == "DISCONNECTED":
await self._client.async_update_schedule(target_time=(int(value.hour), int(value.minute)))
# If session in progress, update this session, if not update the first schedule
if session_in_progress(self.coordinator.data):
await self._client.async_apply_session_rule(target_time=(int(value.hour), int(value.minute)))
await asyncio.sleep(1)
await self.coordinator_schedules.async_refresh()
await self.coordinator.async_refresh()
else:
await self._client.async_apply_charge_rule(target_time=(int(value.hour), int(value.minute)))
await self._client.async_update_schedule(target_time=(int(value.hour), int(value.minute)))
await asyncio.sleep(1)
await self.coordinator.async_refresh()


await self.coordinator_schedules.async_refresh()

@property
def icon(self):
"""Icon of the sensor."""
return "mdi:alarm-check"

@property
def native_value(self):
@callback
def _handle_coordinator_update(self) -> None:
"""Get value from data returned from API by coordinator"""
# If we are not pending approval or disconnected, return in progress charge rule
# Read with the same logic as setting
target = None
if self.coordinator.data and self.coordinator.data['appliedRule'] and self.coordinator.data['mode'] != "PENDING_APPROVAL" and self.coordinator.data['mode'] != "DISCONNECTED":
if session_in_progress(self.coordinator.data):
target = self.coordinator.data['appliedRule']['targetTime']
elif self.coordinator_schedules.data:
target = self.coordinator_schedules.data['targetTime']
Expand All @@ -85,4 +98,8 @@ def native_value(self):
minute=(target % 3600) // 60,
second=0
)
self.async_write_ha_state()

@property
def native_value(self):
return self._state
13 changes: 13 additions & 0 deletions custom_components/ohme/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,16 @@ def time_next_occurs(hour, minute):
target = target + timedelta(days=1)

return target

def session_in_progress(data):
"""Is there a session in progress?
Used to check if we should update the current session rather than the first schedule."""
# Default to False with no data
if not data:
return False

# Car disconnected or pending approval, we should update the schedule
if data['mode'] == "DISCONNECTED" or data['mode'] == "PENDING_APPROVAL":
return False

return True

0 comments on commit ef838ba

Please sign in to comment.