Skip to content

Commit

Permalink
Split entity to base so reminders can work
Browse files Browse the repository at this point in the history
Update manifest
Implement reminder sensors
  • Loading branch information
gazoodle committed Mar 16, 2022
1 parent 4bbb649 commit adb746b
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 20 deletions.
57 changes: 42 additions & 15 deletions custom_components/gecko/entity.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@
"""GeckoEntity class"""
import logging

from geckolib import Observable, GeckoAutomationFacadeBase, GeckoAsyncSpaMan

from geckolib import Observable
from .spa_manager import GeckoSpaManager
from homeassistant.helpers.entity import Entity
from homeassistant.config_entries import ConfigEntry

from .const import DOMAIN

_LOGGER = logging.getLogger(__name__)


class GeckoEntity(Entity):
"""Entity base of Gecko items"""
class GeckoEntityBase(Entity):
"""Base for all Gecko entities"""

def __init__(self, spaman, config_entry, automation_entity):
def __init__(
self,
spaman: GeckoSpaManager,
config_entry: ConfigEntry,
unique_id: str,
name: str,
parent_name: str,
) -> None:
self.spaman = spaman
self.config_entry = config_entry
self._automation_entity = automation_entity
if isinstance(automation_entity, Observable):
self._automation_entity.watch(self._on_change)
self._unique_id = unique_id
self._name = name
self._parent_name = parent_name
_LOGGER.info("Setup entity %r", self)

@property
def unique_id(self):
def unique_id(self) -> str:
"""Return a unique ID to use for this entity."""
return f"{self._automation_entity.unique_id}"
return self._unique_id

@property
def name(self):
"""Return the name of the entity."""
return f"{self._automation_entity.parent_name}: {self._automation_entity.name}"
return f"{self._parent_name}: {self._name}"

@property
def device_info(self):
Expand Down Expand Up @@ -63,9 +71,28 @@ def should_poll(self) -> bool:
"""Return false as we're a push model!"""
return False

def __repr__(self):
return f"{self._name}/{self._unique_id}"


class GeckoEntity(GeckoEntityBase):
"""Entity base of Gecko items"""

def __init__(
self, spaman: GeckoSpaManager, config_entry: ConfigEntry, automation_entity
):
super().__init__(
spaman,
config_entry,
automation_entity.unique_id,
automation_entity.name,
automation_entity.parent_name,
)
self._automation_entity = automation_entity
if isinstance(automation_entity, Observable):
self._automation_entity.watch(self._on_change)

def _on_change(self, _sender, _old_value, _new_value):
"""Notify HA of the change"""
self.async_schedule_update_ha_state(force_refresh=True)

def __repr__(self):
return f"{self._automation_entity.name}/{self._automation_entity.unique_id}"
if self.hass is not None:
self.async_schedule_update_ha_state(force_refresh=True)
4 changes: 2 additions & 2 deletions custom_components/gecko/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"domain": "gecko",
"name": "Gecko",
"version": "0.1.1",
"version": "0.1.2",
"documentation": "https://github.com/gazoodle/gecko-home-assistant",
"issue_tracker": "https://github.com/gazoodle/gecko-home-assistant/issues",
"iot_class": "local_push",
Expand All @@ -11,6 +11,6 @@
"@gazoodle"
],
"requirements": [
"geckolib==0.4.0"
"geckolib==0.4.1"
]
}
71 changes: 68 additions & 3 deletions custom_components/gecko/sensor.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Sensor platform for Gecko."""
from datetime import date, datetime
from homeassistant.helpers.typing import StateType
from datetime import datetime, timezone, timedelta
from geckolib import GeckoReminderType
from homeassistant.components.sensor import SensorEntity
from homeassistant.config_entries import ConfigEntry
from .const import DOMAIN, ICON
from .entity import GeckoEntity
from .entity import GeckoEntity, GeckoEntityBase
from .spa_manager import GeckoSpaManager


Expand All @@ -18,6 +19,8 @@ async def async_setup_entry(hass, entry, async_add_entities):
if spaman.can_use_facade:
for sensor in spaman.facade.sensors:
sensors.append(GeckoSensor(spaman, entry, sensor))
for reminder in spaman.facade.reminders_manager.reminders:
sensors.append(GeckoReminderSensor(spaman, entry, reminder.type))
async_add_entities(sensors)


Expand All @@ -43,3 +46,65 @@ def aicon(self):
def device_class(self):
"""Return the device class of the sensor."""
return self._automation_entity.device_class


class GeckoReminderSensor(GeckoEntityBase, SensorEntity):
def __init__(
self,
spaman: GeckoSpaManager,
config_entry: ConfigEntry,
reminder_type: GeckoReminderType,
) -> None:
super().__init__(
spaman,
config_entry,
f"{spaman.unique_id}-{GeckoReminderType.to_string(reminder_type)}",
f"{GeckoReminderSensor.type_to_name(reminder_type)} due",
spaman.spa_name,
)
self._reminder_type = reminder_type

@property
def native_value(self):
if self.spaman.facade is None:
return None
reminder = self.spaman.facade.reminders_manager.get_reminder(
self._reminder_type
)
if reminder is None:
return None
today = datetime.utcnow().date()
midnight = datetime(
today.year, today.month, today.day, 0, 0, 0, 0, timezone.utc
)
return midnight + timedelta(reminder.days)

@property
def native_unit_of_measurement(self):
return None

@property
def device_class(self) -> str:
return "timestamp"

@property
def icon(self) -> str:
return "mdi:reminder"

@staticmethod
def type_to_name(type: GeckoReminderType) -> str:
# This should go via strings.json at some point
if type == GeckoReminderType.RINSE_FILTER:
return "Rinse filter"
elif type == GeckoReminderType.CLEAN_FILTER:
return "Clean filter"
elif type == GeckoReminderType.CHANGE_WATER:
return "Change water"
elif type == GeckoReminderType.CHECK_SPA:
return "Check Spa"
elif type == GeckoReminderType.CHANGE_OZONATOR:
return "Change Ozonator"
elif type == GeckoReminderType.CHANGE_VISION_CARTRIDGE:
return "Change Vision cartridge"
else:
return "Unknown"
5 changes: 5 additions & 0 deletions custom_components/gecko/spa_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,18 @@ async def _queue_loop(self) -> None:
try:
if self._event_queue.empty():
continue

event = self._event_queue.get()
if event == GeckoSpaEvent.CLIENT_FACADE_IS_READY:
# Wait for a single update so we have reminders and watercare
await self.facade.wait_for_one_update()
self._can_use_facade = True
await self.reload()

elif event == GeckoSpaEvent.CLIENT_FACADE_TEARDOWN:
self._can_use_facade = False
await self.reload()

finally:
await asyncio.sleep(0)

Expand Down

0 comments on commit adb746b

Please sign in to comment.