Skip to content

Commit

Permalink
Add attributes on the sensor with the next event
Browse files Browse the repository at this point in the history
  • Loading branch information
slashback100 committed Nov 13, 2020
1 parent 31189cb commit e774b0f
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 28 deletions.
29 changes: 7 additions & 22 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ async def async_setup_entry(hass, entry):
"""Set up this component using config flow."""
_LOGGER.debug("async setup entry %s", entry.data["entities"])
unsub = entry.add_update_listener(update_listener)
#if PresenceSimulationSwitch.instances == 0:
# async_add_entities([PresenceSimulationSwitch(hass)], True)

# Use `hass.async_create_task` to avoid a circular dependency between the platform and the component
hass.async_create_task(hass.config_entries.async_forward_entry_setup(entry, SENSOR_PLATFORM))
Expand All @@ -34,15 +32,13 @@ async def async_setup(hass, config):

async def async_mysetup(hass, entities, deltaStr):
"""Set up this component (YAML or UI)."""
#hass.states.async_set(DOMAIN+".running", "off") # replaced by the sensor
delta = int(deltaStr)
_LOGGER.debug("Entities for presence simulation: %s", entities)

async def stop_presence_simulation(err=None):
"""Stop the presence simulation, raising a potential error"""
entity = hass.data[DOMAIN][SENSOR_PLATFORM][SENSOR]
entity.turn_off()
#hass.states.async_set(DOMAIN+".running", "off")
if err is not None:
_LOGGER.debug("Error in presence simulation, exiting")
raise e
Expand All @@ -63,7 +59,6 @@ async def async_expand_entities(entities):
except Exception as e:
_LOGGER.error("Error when trying to identify entity %s: %s", entity, e)
else:
#await stop_presence_simulation(e)
group_entities_expanded = await async_expand_entities(group_entities)
_LOGGER.debug("State %s", group_entities_expanded)
for tmp in group_entities_expanded:
Expand All @@ -86,7 +81,6 @@ async def handle_presence_simulation(call):
return
running = True
entity.turn_on()
#hass.states.async_set(DOMAIN+".running", "on")
_LOGGER.debug("Started presence simulation")

current_date = datetime.now(timezone.utc)
Expand All @@ -98,8 +92,7 @@ async def handle_presence_simulation(call):
for entity_id in dic:
_LOGGER.debug('Entity %s', entity_id)
#launch a thread by entity_id
#put the tasks in a tab to be able to kill them when the service stops
hass.async_create_task(simulate_single_entity(entity_id, dic[entity_id])) #coroutine
hass.async_create_task(simulate_single_entity(entity_id, dic[entity_id]))

hass.async_create_task(restart_presence_simulation())
_LOGGER.debug("All async tasks launched")
Expand Down Expand Up @@ -131,43 +124,36 @@ async def simulate_single_entity(entity_id, hist):
for state in hist: #hypothsis: states are ordered chronologically
_LOGGER.debug("State %s", state.as_dict())
_LOGGER.debug("Switch of %s foreseen at %s", entity_id, state.last_changed+timedelta(delta))
entity = hass.data[DOMAIN][SENSOR_PLATFORM][SENSOR]
await entity.async_add_next_event(state.last_changed+timedelta(delta), entity_id, state.state)

while is_running():
minus_delta = datetime.now(timezone.utc) + timedelta(-delta)
#_LOGGER.debug("%s <= %s", state.last_changed, minus_delta)
if state.last_changed <= minus_delta:
break
#_LOGGER.debug("%s: will retry in 30 sec", entity_id)
await asyncio.sleep(30)
if not is_running():
return # exit if state is false
#call service to turn on/off the light
await update_entity(entity_id, state)
await entity.async_remove_event(entity_id)

async def update_entity(entity_id, state):
domain = entity_id.split('.')[0]
service_data = {"entity_id": entity_id}
if domain == "light":
_LOGGER.debug("Switching light %s to %s", entity_id, state.state)
try:
if state.attributes["brightness"]:
if "brightness" in state.attributes:
service_data["brightness"] = state.attributes["brightness"]
except:
#brightness not defined
pass
try:
if state.attributes["rgb_color"]:
if "rgb_color" in state.attributes:
service_data["rgb_color"] = state.attributes["rgb_color"]
except:
#rgb_color not defined
pass
await hass.services.async_call("light", "turn_"+state.state, service_data, blocking=False)
else:
_LOGGER.debug("Switching entity %s to %s", entity_id, state.state)
await hass.services.async_call("homeassistant", "turn_"+state.state, service_data, blocking=False)

def is_running():
"""Returns true if the simulation is running"""
#return hass.states.get(DOMAIN+'.running').state == "on"
entity = hass.data[DOMAIN][SENSOR_PLATFORM][SENSOR]
return entity.is_on

Expand All @@ -182,7 +168,6 @@ async def update_listener(hass, entry):
"""Update listener after an update in the UI"""
_LOGGER.debug("Updating listener");
# The OptionsFlow saves data to options.
# Move them back to data and clean options (dirty, but not sure how else to do that)
if len(entry.options) > 0:
entry.data = entry.options
entry.options = {}
Expand Down
37 changes: 31 additions & 6 deletions sensor.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from homeassistant.helpers.entity import ToggleEntity
from datetime import datetime, timezone, timedelta
import math
import logging
from .const import (
DOMAIN,
SENSOR_PLATFORM,
SENSOR
)

SCAN_INTERVAL = timedelta(seconds=5)
_LOGGER = logging.getLogger(__name__)

async def async_setup_platform(hass, _, async_add_entities, discovery_info=None):
Expand All @@ -23,9 +25,13 @@ async def async_setup_entry(hass, config_entry, async_add_devices):

class PresenceSimulationSwitch(ToggleEntity):
instances = 0

def __init__(self, hass):
self.turn_off()
self.hass = hass
self.attr={}
self.attr["friendly_name"] = "Presence Simulation Toggle"
self._next_events = []
PresenceSimulationSwitch.instances += 1
pass

Expand All @@ -46,18 +52,27 @@ def turn_on(self, **kwargs):

def turn_off(self, **kwargs):
self._state = "off"
self._next_events = []

async def async_update(self):
pass
if len(self._next_events) > 0:
self.attr["next_event_datetime"], self.attr["next_entity_id"], self.attr["next_entity_state"] = sorted(self._next_events)[0]
else:
for prop in ("next_event_datetime", "next_entity_id", "next_entity_state"):
if prop in self.attr:
del self.attr[prop]

def update(self):
pass
if len(self._next_events) > 0:
self.attr["next_event_datetime"], self.attr["next_entity_id"], self.attr["next_entity_state"] = sorted(self._next_events)[0]
else:
for prop in ("next_event_datetime", "next_entity_id", "next_entity_state"):
if prop in self.attr:
del self.attr[prop]

@property
def device_state_attributes(self):
attr={}
attr["friendly_name"] = "Presence Simulation Toggle"
return attr
return self.attr

async def async_added_to_hass(self):
"""When sensor is added to hassio."""
Expand All @@ -67,3 +82,13 @@ async def async_added_to_hass(self):
if SENSOR_PLATFORM not in self.hass.data[DOMAIN]:
self.hass.data[DOMAIN][SENSOR_PLATFORM] = {}
self.hass.data[DOMAIN][SENSOR_PLATFORM][SENSOR] = self

async def async_add_next_event(self, next_datetime, entity_id, state):
self._next_events.append((next_datetime, entity_id, state))

async def async_remove_event(self, entity_id):
i=0
for e in self._next_events:
if e[1] == entity_id:
del self._next_events[i]
i += 1

0 comments on commit e774b0f

Please sign in to comment.