From 717fceae8a9862b2c9efdd51a10cb5e78a6ece14 Mon Sep 17 00:00:00 2001
From: David Huss <dh@atoav.com>
Date: Tue, 5 Nov 2024 17:11:14 +0100
Subject: [PATCH] Power State changes now keep track of time

---
 src/mediactl/system.py | 38 ++++++++++++++++++++++++++------------
 1 file changed, 26 insertions(+), 12 deletions(-)

diff --git a/src/mediactl/system.py b/src/mediactl/system.py
index 056ef1a..94d9767 100644
--- a/src/mediactl/system.py
+++ b/src/mediactl/system.py
@@ -64,7 +64,11 @@ class System(mediactl.WithLogger):
         )
         self.screen = mediactl.AC123(gpio_numbers=[13, 6, 5], logger=logger)
         self.status = {
-            "system": {"power": PowerState.off, "health": SystemHealth.unknown},
+            "system": {
+                "power": PowerState.off,
+                "health": SystemHealth.unknown,
+                "power-time": datetime.now(),
+            },
             "projector": self.projector.status,
             "ahm": self.ahm.status,
             "kramer": self.kramer.status,
@@ -119,6 +123,10 @@ class System(mediactl.WithLogger):
         self.status["dante-on"] = False
         return Ok(None)
 
+    def set_power_state(self, state: PowerState):
+        self.status["system"]["power"] = state
+        self.status["system"]["power-time"] = datetime.now()
+
     async def get_status(self, initial=False) -> dict:
         self.status["projector"] = await self.projector.get_status()
         self.status["ahm"] = await self.ahm.get_status(name=initial)
@@ -129,14 +137,20 @@ class System(mediactl.WithLogger):
 
         if self.just_switched_on():
             self.log_info("System has been switched ONNNN")
-            self.status["system"]["power"] = PowerState.on
+            self.set_power_state(PowerState.on)
         elif self.just_switched_off():
             self.log_info("System has been switched OFFFF")
-            self.status["system"]["power"] = PowerState.off
+            self.set_power_state(PowerState.off)
 
         if initial:
             if self.is_on_in_principle:
-                self.status["system"]["power"] = PowerState.on
+                self.set_power_state(PowerState.on)
+
+        # Assume the system is off if it has been shutting down for >= 10s
+        if self.status["system"]["power"] == PowerState.shutting_down and (
+            datetime.now() - self.status["system"]["power-time"]
+        ) > timedelta(seconds=10):
+            self.set_power_state(PowerState.off)
 
         self.pstatus = copy.deepcopy(self.status)
         return self.status
@@ -155,7 +169,7 @@ class System(mediactl.WithLogger):
     async def power_off(self, source="Script"):
         # Set state to request powerdown and log
         requested_at = datetime.now()
-        self.status["system"]["power"] = PowerState.requested_powerdown
+        self.set_power_state(PowerState.requested_powerdown)
         self.log_info(
             f"Received Power-Off-Command from {source}, sending request to Projector.."
         )
@@ -166,14 +180,14 @@ class System(mediactl.WithLogger):
         # Mute Main Control Group
         ahm_response = await self.ahm.mute_control_group(3)
 
-        self.status["system"]["power"] = PowerState.shutting_down
+        self.set_power_state(PowerState.shutting_down)
         while not self.status["system"]["power"].is_off():
             if projector_response.is_ok() and ahm_response.is_ok():
-                self.status["system"]["power"] = PowerState.off
+                self.set_power_state(PowerState.off)
                 self.log_info("Shutdown nominal, all systems responded")
                 break
             if (datetime.now() - requested_at) > timedelta(seconds=5):
-                self.status["system"]["power"] = PowerState.on
+                self.set_power_state(PowerState.on)
                 self.log_error(
                     f"Could not reach projctl at {self.projector.addr} during powerup after 5 seconds. Starting anyways"
                 )
@@ -195,7 +209,7 @@ class System(mediactl.WithLogger):
     async def power_on(self, source="Script"):
         # Set state to request powerup and log
         requested_at = datetime.now()
-        self.status["system"]["power"] = PowerState.requested_powerup
+        self.set_power_state(PowerState.requested_powerup)
         self.log_info(
             f"Received Power-On-Command from {source}, sending request to Projector.."
         )
@@ -205,16 +219,16 @@ class System(mediactl.WithLogger):
         ahm_response = await self.ahm.preset_recall(1)
 
         # We are now starting up
-        self.status["system"]["power"] = PowerState.starting_up
+        self.set_power_state(PowerState.starting_up)
         projector_reached = False
         while not self.status["system"]["power"].is_on():
             if projector_response.is_ok() and ahm_response.is_ok():
-                self.status["system"]["power"] = PowerState.on
+                self.set_power_state(PowerState.on)
                 self.log_info("Startup nominal, all systems appear to be online")
                 projector_reached = True
                 break
             if (datetime.now() - requested_at) > timedelta(seconds=5):
-                self.status["system"]["power"] = PowerState.on
+                self.set_power_state(PowerState.on)
                 self.log_error(
                     f"Could not reach projctl at {self.projector.addr} during powerup after 5 seconds. Starting anyways"
                 )
-- 
GitLab