From 712b9d8af4195fd5c8520e69673cac06e5f1cb8c Mon Sep 17 00:00:00 2001 From: Daniel Raper Date: Tue, 2 Jan 2024 22:17:29 +0000 Subject: [PATCH] Add schedule change function --- README.md | 6 +++--- custom_components/ohme/number.py | 36 ++++++++++++++++++-------------- custom_components/ohme/time.py | 33 ++++++++++++++++++++--------- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 219094b..fcf29c0 100644 --- a/README.md +++ b/README.md @@ -54,9 +54,9 @@ This integration exposes the following entities: * Switches (Charge state) - **These are only functional when a car is connected** * Max Charge - Forces the connected car to charge regardless of set schedule * Pause Charge - Pauses an ongoing charge -* Inputs - **Only available during a charge session** - * Number: Target Percentage - Change the target percentage of the ongoing charge - * Time: Target Time - Change the time target for the current charge +* Inputs - **If in a charge session, this will change the active charge. If disconnected, this will change your first schedule.** + * Number: Target Percentage - Change the target battery percentage + * Time: Target Time - Change the target time * Buttons * Approve Charge - Approves a charge when 'Pending Approval' is on diff --git a/custom_components/ohme/number.py b/custom_components/ohme/number.py index e740856..ef8ceb7 100644 --- a/custom_components/ohme/number.py +++ b/custom_components/ohme/number.py @@ -3,7 +3,7 @@ from homeassistant.components.number import NumberEntity, NumberDeviceClass 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_ACCOUNTINFO +from .const import DOMAIN, DATA_CLIENT, DATA_COORDINATORS, COORDINATOR_CHARGESESSIONS, COORDINATOR_SCHEDULES async def async_setup_entry( @@ -14,10 +14,10 @@ async def async_setup_entry( """Setup switches and configure coordinator.""" coordinators = hass.data[DOMAIN][DATA_COORDINATORS] - coordinator = coordinators[COORDINATOR_CHARGESESSIONS] client = hass.data[DOMAIN][DATA_CLIENT] - numbers = [TargetPercentNumber(coordinator, hass, client)] + numbers = [TargetPercentNumber( + coordinators[COORDINATOR_CHARGESESSIONS], coordinators[COORDINATOR_SCHEDULES], hass, client)] async_add_entities(numbers, update_before_add=True) @@ -28,12 +28,13 @@ class TargetPercentNumber(NumberEntity): _attr_device_class = NumberDeviceClass.BATTERY _attr_suggested_display_precision = 0 - def __init__(self, coordinator, hass: HomeAssistant, client): + def __init__(self, coordinator, coordinator_schedules, hass: HomeAssistant, client): self.coordinator = coordinator + self.coordinator_schedules = coordinator_schedules self._client = client - self._state = 0 + self._state = None self._last_updated = None self._attributes = {} @@ -49,10 +50,15 @@ def unique_id(self): async def async_set_native_value(self, value: float) -> None: """Update the current value.""" - await self._client.async_apply_charge_rule(target_percent=int(value)) - - await asyncio.sleep(1) - await self.coordinator.async_refresh() + # 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)) + await asyncio.sleep(1) + await self.coordinator_schedules.async_refresh() + else: + await self._client.async_apply_charge_rule(target_percent=int(value)) + await asyncio.sleep(1) + await self.coordinator.async_refresh() @property def icon(self): @@ -62,13 +68,11 @@ def icon(self): @property def native_value(self): """Get value from data returned from API by coordinator""" - if self.coordinator.data and self.coordinator.data['appliedRule']: + 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']) + elif self.coordinator_schedules.data: + target = round(self.coordinator_schedules.data['targetPercent']) - if target == 0: - return self._state - - self._state = target - return self._state - return None + self._state = target if target > 0 else None + return self._state diff --git a/custom_components/ohme/time.py b/custom_components/ohme/time.py index 19f406b..c8814f4 100644 --- a/custom_components/ohme/time.py +++ b/custom_components/ohme/time.py @@ -4,7 +4,7 @@ from homeassistant.components.time import TimeEntity 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_ACCOUNTINFO +from .const import DOMAIN, DATA_CLIENT, DATA_COORDINATORS, COORDINATOR_CHARGESESSIONS, COORDINATOR_SCHEDULES from datetime import time as dt_time _LOGGER = logging.getLogger(__name__) @@ -18,10 +18,10 @@ async def async_setup_entry( """Setup switches and configure coordinator.""" coordinators = hass.data[DOMAIN][DATA_COORDINATORS] - coordinator = coordinators[COORDINATOR_CHARGESESSIONS] client = hass.data[DOMAIN][DATA_CLIENT] - numbers = [TargetTime(coordinator, hass, client)] + numbers = [TargetTime(coordinators[COORDINATOR_CHARGESESSIONS], + coordinators[COORDINATOR_SCHEDULES], hass, client)] async_add_entities(numbers, update_before_add=True) @@ -30,8 +30,9 @@ class TargetTime(TimeEntity): """Target time sensor.""" _attr_name = "Target Time" - def __init__(self, coordinator, hass: HomeAssistant, client): + def __init__(self, coordinator, coordinator_schedules, hass: HomeAssistant, client): self.coordinator = coordinator + self.coordinator_schedules = coordinator_schedules self._client = client @@ -51,10 +52,17 @@ def unique_id(self): async def async_set_value(self, value: dt_time) -> None: """Update the current value.""" - await self._client.async_apply_charge_rule(target_time=(int(value.hour), int(value.minute))) - - await asyncio.sleep(1) - await self.coordinator.async_refresh() + # 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))) + await asyncio.sleep(1) + await self.coordinator_schedules.async_refresh() + else: + await self._client.async_apply_charge_rule(target_time=(int(value.hour), int(value.minute))) + await asyncio.sleep(1) + await self.coordinator.async_refresh() + + @property def icon(self): @@ -64,9 +72,14 @@ def icon(self): @property def native_value(self): """Get value from data returned from API by coordinator""" - # Make sure we're not pending approval, as this sets the target time to now - if self.coordinator.data and self.coordinator.data['appliedRule'] and self.coordinator.data['mode'] != "PENDING_APPROVAL": + # If we are not pending approval or disconnected, return in progress charge rule + target = None + if self.coordinator.data and self.coordinator.data['appliedRule'] and self.coordinator.data['mode'] != "PENDING_APPROVAL" and self.coordinator.data['mode'] != "DISCONNECTED": target = self.coordinator.data['appliedRule']['targetTime'] + elif self.coordinator_schedules.data: + target = self.coordinator_schedules.data['targetTime'] + + if target: self._state = dt_time( hour=target // 3600, minute=(target % 3600) // 60,