22
33from __future__ import annotations
44
5- from asyncio import CancelledError , Future , get_event_loop , wait_for
5+ from asyncio import CancelledError , Future , Task , get_event_loop , wait_for
66from collections .abc import Callable
77from datetime import datetime
88import logging
@@ -61,8 +61,8 @@ class NodeSED(PlugwiseNode):
6161 # Maintenance
6262 _maintenance_interval : int | None = None
6363 _maintenance_last_awake : datetime | None = None
64- _maintenance_future : Future | None = None
65-
64+ _awake_future : Future | None = None
65+ _awake_timer_task : Task | None = None
6666 _ping_at_awake : bool = False
6767
6868 _awake_subscription : Callable [[], None ] | None = None
@@ -80,8 +80,10 @@ def __init__(
8080
8181 async def unload (self ) -> None :
8282 """Deactivate and unload node features."""
83- if self ._maintenance_future is not None :
84- self ._maintenance_future .cancel ()
83+ if self ._awake_future is not None :
84+ self ._awake_future .set_result (True )
85+ if self ._awake_timer_task is not None or not self ._awake_timer_task .done ():
86+ await self ._awake_timer_task
8587 if self ._awake_subscription is not None :
8688 self ._awake_subscription ()
8789 await super ().unload ()
@@ -124,10 +126,10 @@ async def _awake_response(self, message: NodeAwakeResponse) -> bool:
124126 )
125127 if ping_response is not None :
126128 self ._ping_at_awake = False
127- await self .reset_maintenance_awake (message .timestamp )
129+ await self ._reset_awake (message .timestamp )
128130 return True
129131
130- async def reset_maintenance_awake (self , last_alive : datetime ) -> None :
132+ async def _reset_awake (self , last_alive : datetime ) -> None :
131133 """Reset node alive state."""
132134 if self ._maintenance_last_awake is None :
133135 self ._maintenance_last_awake = last_alive
@@ -136,33 +138,39 @@ async def reset_maintenance_awake(self, last_alive: datetime) -> None:
136138 last_alive - self ._maintenance_last_awake
137139 ).seconds
138140
139- # Finish previous maintenance timer
140- if self ._maintenance_future is not None :
141- self ._maintenance_future .set_result (True )
141+ # Finish previous awake timer
142+ if self ._awake_future is not None :
143+ self ._awake_future .set_result (True )
142144
143145 # Setup new maintenance timer
144- self ._maintenance_future = get_event_loop ().create_future ()
146+ current_loop = get_event_loop ()
147+ self ._awake_future = current_loop .create_future ()
148+ self ._awake_timer_task = current_loop .create_task (
149+ self ._awake_timer (),
150+ name = f"Node awake timer for { self ._mac_in_str } "
151+ )
145152
153+ async def _awake_timer (self ) -> None :
154+ """Task to monitor to get next awake in time. If not it sets device to be unavailable."""
146155 # wait for next maintenance timer
147156 try :
148157 await wait_for (
149- self ._maintenance_future ,
158+ self ._awake_future ,
150159 timeout = (self ._maintenance_interval * 1.05 ),
151160 )
152161 except TimeoutError :
153162 # No maintenance awake message within expected time frame
154163 # Mark node as unavailable
155164 if self ._available :
156165 _LOGGER .info (
157- "No maintenance awake message received for %s within expected %s seconds." ,
158- self .mac ,
166+ "No awake message received from %s within expected %s seconds." ,
167+ self .name ,
159168 str (self ._maintenance_interval * 1.05 ),
160169 )
161170 await self ._available_update_state (False )
162171 except CancelledError :
163172 pass
164-
165- self ._maintenance_future = None
173+ self ._awake_future = None
166174
167175 async def sed_configure (
168176 self ,
0 commit comments