@@ -58,7 +58,13 @@ def _map_readings_to_devices(
5858 device_identifier : Union [int , str ] = reading .device_id
5959 if device_identifier == 0 :
6060 device_identifier = reading .hilo_id
61- if device := self .find_device (device_identifier ):
61+ device = self .find_device (device_identifier )
62+ # If device_id was 0 and hilo_id lookup failed, this is likely
63+ # a gateway reading that arrives before GatewayValuesReceived
64+ # assigns the real ID. Fall back to the gateway device.
65+ if device is None and reading .device_id == 0 :
66+ device = next ((d for d in self .devices if d .type == "Gateway" ), None )
67+ if device :
6268 device .update_readings (reading )
6369 LOG .debug ("%s Received %s" , device , reading )
6470 if device not in updated_devices :
@@ -93,27 +99,78 @@ def generate_device(self, device: dict) -> HiloDevice:
9399 return dev
94100
95101 async def update (self ) -> None :
96- fresh_devices = await self ._api .get_devices (self .location_id )
102+ """Update device list from websocket cache + gateway from REST."""
103+ # Get devices from websocket cache (already populated by DeviceListInitialValuesReceived)
104+ cached_devices = self ._api .get_device_cache (self .location_id )
97105 generated_devices = []
98- for raw_device in fresh_devices :
106+ for raw_device in cached_devices :
99107 LOG .debug ("Generating device %s" , raw_device )
100108 dev = self .generate_device (raw_device )
101109 generated_devices .append (dev )
102110 if dev not in self .devices :
103111 self .devices .append (dev )
112+
113+ # Append gateway from REST API (still available)
114+ try :
115+ gw = await self ._api .get_gateway (self .location_id )
116+ LOG .debug ("Generating gateway device %s" , gw )
117+ gw_dev = self .generate_device (gw )
118+ generated_devices .append (gw_dev )
119+ if gw_dev not in self .devices :
120+ self .devices .append (gw_dev )
121+ except Exception as err :
122+ LOG .error ("Failed to get gateway: %s" , err )
123+
124+ # Now add devices from external sources (e.g. unknown source tracker)
125+ for callback in self ._api ._get_device_callbacks :
126+ try :
127+ cb_device = callback ()
128+ dev = self .generate_device (cb_device )
129+ generated_devices .append (dev )
130+ if dev not in self .devices :
131+ self .devices .append (dev )
132+ except Exception as err :
133+ LOG .error ("Failed to generate callback device: %s" , err )
134+
104135 for device in self .devices :
105136 if device not in generated_devices :
106137 LOG .debug ("Device unpaired %s" , device )
107138 # Don't do anything with unpaired device for now.
108- # self.devices.remove(device)
109139
110140 async def update_devicelist_from_signalr (
111141 self , values : list [dict [str , Any ]]
112142 ) -> list [HiloDevice ]:
113- # ic-dev21 not sure if this is dead code?
143+ """Process device list received from SignalR websocket.
144+
145+ This is called when DeviceListInitialValuesReceived arrives.
146+ It populates the API device cache and generates HiloDevice objects.
147+ """
148+ # Populate the API cache so future update() calls use this data
149+ self ._api .set_device_cache (values )
150+
114151 new_devices = []
115- for raw_device in values :
116- LOG .debug ("Generating device %s" , raw_device )
152+ for raw_device in self ._api .get_device_cache (self .location_id ):
153+ LOG .debug ("Generating device from SignalR %s" , raw_device )
154+ dev = self .generate_device (raw_device )
155+ if dev not in self .devices :
156+ self .devices .append (dev )
157+ new_devices .append (dev )
158+
159+ return new_devices
160+
161+ async def add_device_from_signalr (
162+ self , values : list [dict [str , Any ]]
163+ ) -> list [HiloDevice ]:
164+ """Process individual device additions from SignalR websocket.
165+
166+ This is called when DeviceAdded arrives. It appends to the existing
167+ cache rather than replacing it.
168+ """
169+ self ._api .add_to_device_cache (values )
170+
171+ new_devices = []
172+ for raw_device in self ._api .get_device_cache (self .location_id ):
173+ LOG .debug ("Generating added device from SignalR %s" , raw_device )
117174 dev = self .generate_device (raw_device )
118175 if dev not in self .devices :
119176 self .devices .append (dev )
@@ -122,9 +179,16 @@ async def update_devicelist_from_signalr(
122179 return new_devices
123180
124181 async def async_init (self ) -> None :
125- """Initialize the Hilo "manager" class."""
126- LOG .info ("Initialising after websocket is connected" )
182+ """Initialize the Hilo "manager" class.
183+
184+ Gets location IDs from REST API, then waits for the websocket
185+ to deliver the device list via DeviceListInitialValuesReceived.
186+ The gateway is appended from REST.
187+ """
188+ LOG .info ("Initialising: getting location IDs" )
127189 location_ids = await self ._api .get_location_ids ()
128190 self .location_id = location_ids [0 ]
129191 self .location_hilo_id = location_ids [1 ]
130- await self .update ()
192+ # Device list will be populated when DeviceListInitialValuesReceived
193+ # arrives on the websocket. The hilo integration's async_init will
194+ # call wait_for_device_cache() and then update() after subscribing.
0 commit comments