Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 32 additions & 6 deletions custom_components/entity_controller/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import homeassistant.util.yaml.objects as YamlObjects
import homeassistant.util.uuid as uuid_util
from transitions import Machine
from transitions.core import MachineError
from transitions.extensions import HierarchicalMachine as Machine
Comment on lines 45 to 47
from homeassistant.helpers.service import async_call_from_config

Expand Down Expand Up @@ -370,6 +371,13 @@ async def async_setup(hass, config):
)
# Enter blocked state when component is enabled and entity is on
machine.add_transition(trigger="blocked", source="constrained", dest="blocked", conditions=["is_block_enabled"])
# blocked must also be reachable from idle: start_time_callback fires while
# the machine is already idle (HA restarted inside the active window, or an
# override toggled off before start_time) and calls blocked() when state
# entities are on. Without this transition that raises MachineError and HA
# keeps re-firing the failed point-in-time callback (error storm). Mirrors
# the existing sensor_on: idle -> blocked rule.
machine.add_transition(trigger="blocked", source="idle", dest="blocked", conditions=["is_block_enabled"])

for myconfig in config[DOMAIN]:
_LOGGER.info("Domain Configuration: " + str(myconfig))
Expand Down Expand Up @@ -1261,14 +1269,32 @@ def start_time_callback(self, evt):

self.update(start_time=parsed_start)

if self.is_state_entities_on() and self.is_block_enabled():
self.blocked()
else:
# If the entity is on and block is disabled, we just transition from constrained
# to idle and leave the entity on. (Don't start a timer to turn it off.)
self.enable()
self._apply_start_time_transition()
self.do_transition_behaviour(CONF_ON_EXIT_CONSTRAINED)

Comment on lines +1272 to 1274
def _apply_start_time_transition(self):
"""Transition the machine when start_time is reached.

Must never raise: an exception escaping a point-in-time callback makes
HA re-fire it endlessly (error storm). States with no defined
transition from here (e.g. overridden/active after a mid-window HA
restart) are logged and left unchanged -- the next sensor/override
event resolves the controller normally.
"""
try:
if self.is_state_entities_on() and self.is_block_enabled():
self.blocked()
else:
# If the entity is on and block is disabled, we just transition from constrained
# to idle and leave the entity on. (Don't start a timer to turn it off.)
self.enable()
except MachineError as err:
self.log.warning(
"start_time_callback :: no transition from state '%s' (%s); leaving state unchanged",
self.state,
err,
)

# =====================================================
# H E L P E R F U N C T I O N S ( N E W )
# =====================================================
Expand Down