99from powersensor_local import PlugApi , VirtualHousehold
1010
1111from custom_components .powersensor .AsyncSet import AsyncSet
12- from custom_components .powersensor .const import POWER_SENSOR_UPDATE_SIGNAL , DOMAIN
12+ from custom_components .powersensor .const import (
13+ CREATE_PLUG_SIGNAL ,
14+ CREATE_SENSOR_SIGNAL ,
15+ DATA_UPDATE_SIGNAL_FMT_MAC_EVENT ,
16+ PLUG_ADDED_TO_HA_SIGNAL ,
17+ ROLE_UPDATE_SIGNAL ,
18+ SENSOR_ADDED_TO_HA_SIGNAL ,
19+ ZEROCONF_ADD_PLUG_SIGNAL ,
20+ ZEROCONF_REMOVE_PLUG_SIGNAL ,
21+ ZEROCONF_UPDATE_PLUG_SIGNAL ,
22+ )
1323
1424_LOGGER = logging .getLogger (__name__ )
1525class PowersensorMessageDispatcher :
@@ -25,28 +35,23 @@ def __init__(self, hass: HomeAssistant, entry: ConfigEntry, vhh: VirtualHousehol
2535 self ._pending_removals = {}
2636 self ._debounce_seconds = debounce_timeout
2737 self .has_solar = False
28- self ._virtual_household_has_been_setup = False
29- self ._last_request_to_notify_about_solar = datetime .datetime (1970 ,1 ,1 ,0 ,0 ,0 )
3038 self ._solar_request_limit = datetime .timedelta (seconds = 10 )
3139 self ._unsubscribe_from_signals = [
3240 async_dispatcher_connect (self ._hass ,
33- f"{ DOMAIN } _sensor_added_to_homeassistant" ,
34- self ._acknowledge_sensor_added_to_homeassistant ),
35- async_dispatcher_connect (self ._hass ,
36- f"{ DOMAIN } _zeroconf_add_plug" ,
41+ ZEROCONF_ADD_PLUG_SIGNAL ,
3742 self ._plug_added ),
3843 async_dispatcher_connect (self ._hass ,
39- f" { DOMAIN } _zeroconf_update_plug" ,
44+ ZEROCONF_UPDATE_PLUG_SIGNAL ,
4045 self ._plug_updated ),
4146 async_dispatcher_connect (self ._hass ,
42- f" { DOMAIN } _zeroconf_remove_plug" ,
47+ ZEROCONF_REMOVE_PLUG_SIGNAL ,
4348 self ._schedule_plug_removal ),
4449 async_dispatcher_connect (self ._hass ,
45- f" { DOMAIN } _plug_added_to_homeassistant" ,
50+ PLUG_ADDED_TO_HA_SIGNAL ,
4651 self ._acknowledge_plug_added_to_homeassistant ),
4752 async_dispatcher_connect (self ._hass ,
48- f" { DOMAIN } _solar_added_to_virtual_household" ,
49- self ._acknowledge_solar_added_to_virtual_household ),
53+ SENSOR_ADDED_TO_HA_SIGNAL ,
54+ self ._acknowledge_sensor_added_to_homeassistant ),
5055 ]
5156
5257 self ._monitor_add_plug_queue = None
@@ -78,7 +83,7 @@ async def _monitor_plug_queue(self):
7883 for mac_address , host , port , name in queue_snapshot :
7984 #@todo: maybe better to query the entity registry?
8085 if not self ._plug_has_been_seen (mac_address , name ):
81- async_dispatcher_send (self ._hass , f" { DOMAIN } _create_plug" ,
86+ async_dispatcher_send (self ._hass , CREATE_PLUG_SIGNAL ,
8287 mac_address , host , port , name )
8388 elif mac_address in self ._known_plugs and not mac_address in self .plugs :
8489 _LOGGER .info (f"Plug with mac { mac_address } is known, but API is missing."
@@ -135,62 +140,72 @@ def _create_api(self, mac_address, ip, port, name):
135140 self ._known_plugs .add (mac_address )
136141 self ._known_plug_names [name ] = mac_address
137142 known_evs = [
138- 'exception' ,
143+ # 'exception',
139144 'average_flow' ,
140145 'average_power' ,
141146 'average_power_components' ,
142147 'battery_level' ,
143- 'now_relaying_for' ,
144148 'radio_signal_quality' ,
145149 'summation_energy' ,
146150 'summation_volume' ,
147- 'uncalibrated_instant_reading' ,
151+ # 'uncalibrated_instant_reading',
148152 ]
149153
150154 for ev in known_evs :
151- api .subscribe (ev , lambda event , message : self .handle_message ( event , message ))
155+ api .subscribe (ev , self .handle_message )
156+ api .subscribe ('now_relaying_for' , self .handle_relaying_for )
152157 api .connect ()
153158
154- def add_api (self , network_info ):
155- _LOGGER .debug ("Manually adding API, this could cause API's and entities to get out of sync" )
156- self ._create_api (mac_address = network_info ['mac' ], ip = network_info ['host' ],
157- port = network_info ['port' ], name = network_info ['name' ])
158-
159159 def cancel_any_pending_removal (self , mac , source ):
160160 task = self ._pending_removals .pop (mac , None )
161161 if task :
162162 task .cancel ()
163163 _LOGGER .debug (f"Cancelled pending removal for { mac } by { source } ." )
164164
165+ async def handle_relaying_for (self , event : str , message : dict ):
166+ """Handle a potentially new sensor being reported."""
167+ mac = message .get ('mac' , None )
168+ device_type = message .get ('device_type' , None )
169+ if mac is None or device_type != "sensor" :
170+ _LOGGER .warning (f"Ignoring relayed device with MAC \" { mac } \" and type { device_type } " )
171+ return
172+
173+ persisted_role = self ._entry .data .get ('roles' , {}).get (mac , None )
174+ role = message .get ('role' , None )
175+ _LOGGER .debug (f"Relayed sensor { mac } with role { role } found" )
176+
177+ if mac not in self .sensors :
178+ _LOGGER .debug (f"Reporting new sensor { mac } with role { role } " )
179+ self .on_start_sensor_queue [mac ] = role
180+ async_dispatcher_send (self ._hass , CREATE_SENSOR_SIGNAL , mac , role )
181+ if role != persisted_role :
182+ _LOGGER .debug (f"Restoring role for { mac } from { role } to { persisted_role } " )
183+ async_dispatcher_send (self ._hass , ROLE_UPDATE_SIGNAL , mac , persisted_role )
184+
165185 async def handle_message (self , event : str , message : dict ):
166186 mac = message ['mac' ]
167- role = message .get ('role' , None )
168- if role is None :
169- role = self ._entry .data .get ('roles' , {}).get (mac , None )
170- self .cancel_any_pending_removal (mac , "new message received from plug" )
187+ persisted_role = self ._entry .data .get ('roles' , {}).get (mac , None )
188+ role = message .get ('role' , persisted_role )
189+ message ['role' ] = role
171190
172- if mac not in self .plugs .keys ():
173- if mac not in self .sensors :
174- if role is not None :
175- self .on_start_sensor_queue [mac ] = role
176- async_dispatcher_send (self ._hass , f"{ DOMAIN } _create_sensor" , mac , role )
191+ if role != persisted_role :
192+ async_dispatcher_send (self ._hass , ROLE_UPDATE_SIGNAL , mac , role )
193+
194+ self .cancel_any_pending_removal (mac , "new message received from plug" )
177195
178196 # Feed the household calculations
179197 if event == 'average_power' :
180198 await self ._vhh .process_average_power_event (message )
181199 elif event == 'summation_energy' :
182200 await self ._vhh .process_summation_event (message )
183- if role == 'solar' :
184- self .has_solar = True
185- if not self ._virtual_household_has_been_setup :
186- new_time = datetime .datetime .now ()
187- if self ._last_request_to_notify_about_solar + self ._solar_request_limit < new_time :
188- self ._last_request_to_notify_about_solar = new_time
189- _LOGGER .debug ("Notifying integration that solar is present." )
190- async_dispatcher_send (self ._hass , f"{ DOMAIN } _solar_sensor_detected" )
191- async_dispatcher_send (self ._hass , f"{ POWER_SENSOR_UPDATE_SIGNAL } _{ mac } _{ event } " , event , message )
192- if role is not None :
193- async_dispatcher_send (self ._hass , f"{ POWER_SENSOR_UPDATE_SIGNAL } _{ mac } _role" , 'role' , { 'role' : role })
201+
202+ async_dispatcher_send (self ._hass ,
203+ DATA_UPDATE_SIGNAL_FMT_MAC_EVENT % (mac , event ), event , message )
204+
205+ # Synthesise a role type message for the role diagnostic entity
206+ async_dispatcher_send (
207+ self ._hass , DATA_UPDATE_SIGNAL_FMT_MAC_EVENT % (mac , role ),
208+ 'role' , { 'role' : role })
194209
195210 async def disconnect (self ):
196211 for _ in range (len (self .plugs )):
@@ -208,10 +223,6 @@ def _acknowledge_sensor_added_to_homeassistant(self,mac, role):
208223 self .sensors [mac ] = role
209224
210225 @callback
211- def _acknowledge_solar_added_to_virtual_household (self , success ):
212- _LOGGER .debug ("Solar has been added to virtual household." )
213- self ._virtual_household_has_been_setup = success
214-
215226 async def _acknowledge_plug_added_to_homeassistant (self , mac_address , host , port , name ):
216227 self ._create_api (mac_address , host , port , name )
217228 await self ._plug_added_queue .remove ((mac_address , host , port , name ))
0 commit comments