runtime.py (1460B)
1 """Pure state rules for bounded Hunter BTT manual watering.""" 2 3 from datetime import datetime, timedelta 4 5 6 class ManualControlError(Exception): 7 """Raised when a valve action is unsafe for the known state.""" 8 9 10 def command_end_time( 11 is_zone1_watering: bool, 12 now: datetime, 13 duration_seconds: int | None, 14 reported_end_time: datetime | None, 15 ) -> datetime | None: 16 """Return the End time after a start/stop command. 17 18 FF8A can retain the previous manual duration immediately after a start. 19 A requested duration is therefore more accurate after FF82 confirms the 20 newly started zone-1 run. 21 """ 22 if duration_seconds is not None and is_zone1_watering: 23 return now + timedelta(seconds=duration_seconds) 24 return reported_end_time 25 26 27 def ensure_manual_start_allowed(is_closed: bool | None) -> None: 28 """Reject a manual start unless the valve is confirmed closed.""" 29 if is_closed is True: 30 return 31 if is_closed is False: 32 msg = "Hunter BTT is already watering" 33 raise ManualControlError(msg) 34 msg = "Hunter BTT watering state is unknown" 35 raise ManualControlError(msg) 36 37 38 def should_send_manual_stop(is_closed: bool | None) -> bool: 39 """Return whether an early stop is needed for the known valve state.""" 40 if is_closed is False: 41 return True 42 if is_closed is True: 43 return False 44 msg = "Hunter BTT watering state is unknown" 45 raise ManualControlError(msg)