2929 NONE ,
3030 OFF ,
3131 P1_MEASUREMENTS ,
32+ PRIORITY_DEVICE_CLASSES ,
3233 TEMP_CELSIUS ,
3334 THERMOSTAT_CLASSES ,
3435 TOGGLES ,
@@ -278,7 +279,11 @@ def __init__(self) -> None:
278279 SmileCommon .__init__ (self )
279280
280281 def _all_appliances (self ) -> None :
281- """Collect all appliances with relevant info."""
282+ """Collect all appliances with relevant info.
283+
284+ Also, collect the P1 smartmeter info from a location
285+ as this one is not available as an appliance.
286+ """
282287 self ._count = 0
283288 self ._all_locations ()
284289
@@ -330,55 +335,33 @@ def _all_appliances(self) -> None:
330335 if not (appl := self ._appliance_info_finder (appl , appliance )):
331336 continue
332337
333- # P1: for gateway and smartmeter switch entity_id - part 1
334- # This is done to avoid breakage in HA Core
335- if appl .pwclass == "gateway" and self .smile_type == "power" :
336- appl .entity_id = appl .location
337-
338338 self ._create_gw_entities (appl )
339339
340- # For P1 collect the connected SmartMeter info
341340 if self .smile_type == "power" :
342- self ._p1_smartmeter_info_finder (appl )
343- # P1: for gateway and smartmeter switch entity_id - part 2
344- for item in self .gw_entities :
345- if item != self .gateway_id :
346- self .gateway_id = item
347- # Leave for-loop to avoid a 2nd device_id switch
348- break
349-
350- # Place the gateway and optional heater_central devices as 1st and 2nd
351- for dev_class in ("heater_central" , "gateway" ):
352- for entity_id , entity in dict (self .gw_entities ).items ():
353- if entity ["dev_class" ] == dev_class :
354- tmp_entity = entity
355- self .gw_entities .pop (entity_id )
356- cleared_dict = self .gw_entities
357- add_to_front = {entity_id : tmp_entity }
358- self .gw_entities = {** add_to_front , ** cleared_dict }
341+ self ._get_p1_smartmeter_info ()
359342
360- def _all_locations (self ) -> None :
361- """Collect all locations."""
362- loc = Munch ()
363- locations = self ._domain_objects .findall ("./location" )
364- for location in locations :
365- loc .name = location .find ("name" ).text
366- loc .loc_id = location .attrib ["id" ]
367- if loc .name == "Home" :
368- self ._home_location = loc .loc_id
343+ # Sort the gw_entities
344+ self ._sort_gw_entities ()
369345
370- self ._loc_data [loc .loc_id ] = {"name" : loc .name }
346+ def _get_p1_smartmeter_info (self ) -> None :
347+ """For P1 collect the connected SmartMeter info from the Home/building location.
371348
372- def _p1_smartmeter_info_finder (self , appl : Munch ) -> None :
373- """Collect P1 DSMR SmartMeter info."""
349+ Note: For P1, the entity_id for the gateway and smartmeter are
350+ switched to maintain backward compatibility with existing implementations.
351+ """
352+ appl = Munch ()
374353 loc_id = next (iter (self ._loc_data .keys ()))
375- location = self ._domain_objects .find (f'./location[@id="{ loc_id } "]' )
354+ if (
355+ location := self ._domain_objects .find (f'./location[@id="{ loc_id } "]' )
356+ ) is None :
357+ return
358+
376359 locator = MODULE_LOCATOR
377360 module_data = self ._get_module_data (location , locator )
378361 if not module_data ["contents" ]:
379362 LOGGER .error ("No module data found for SmartMeter" ) # pragma: no cover
380- return None # pragma: no cover
381-
363+ return # pragma: no cover
364+ appl . available = None
382365 appl .entity_id = self .gateway_id
383366 appl .firmware = module_data ["firmware_version" ]
384367 appl .hardware = module_data ["hardware_version" ]
@@ -391,22 +374,49 @@ def _p1_smartmeter_info_finder(self, appl: Munch) -> None:
391374 appl .vendor_name = module_data ["vendor_name" ]
392375 appl .zigbee_mac = None
393376
377+ # Replace the entity_id of the gateway by the smartmeter location_id
378+ self .gw_entities [loc_id ] = self .gw_entities .pop (self .gateway_id )
379+ self .gateway_id = loc_id
380+
394381 self ._create_gw_entities (appl )
395382
383+ def _sort_gw_entities (self ) -> None :
384+ """Place the gateway and optional heater_central entities as 1st and 2nd."""
385+ for dev_class in PRIORITY_DEVICE_CLASSES :
386+ for entity_id , entity in dict (self .gw_entities ).items ():
387+ if entity ["dev_class" ] == dev_class :
388+ priority_entity = entity
389+ self .gw_entities .pop (entity_id )
390+ other_entities = self .gw_entities
391+ priority_entities = {entity_id : priority_entity }
392+ self .gw_entities = {** priority_entities , ** other_entities }
393+
394+ def _all_locations (self ) -> None :
395+ """Collect all locations."""
396+ loc = Munch ()
397+ locations = self ._domain_objects .findall ("./location" )
398+ for location in locations :
399+ loc .name = location .find ("name" ).text
400+ loc .loc_id = location .attrib ["id" ]
401+ if loc .name == "Home" :
402+ self ._home_location = loc .loc_id
403+
404+ self ._loc_data [loc .loc_id ] = {"name" : loc .name }
405+
396406 def _appliance_info_finder (self , appl : Munch , appliance : etree ) -> Munch :
397407 """Collect info for all appliances found."""
398408 match appl .pwclass :
399409 case "gateway" :
400- # Collect gateway device info
410+ # Collect gateway entity info
401411 return self ._appl_gateway_info (appl , appliance )
402412 case _ as dev_class if dev_class in THERMOSTAT_CLASSES :
403- # Collect thermostat device info
413+ # Collect thermostat entity info
404414 return self ._appl_thermostat_info (appl , appliance )
405415 case "heater_central" :
406- # Collect heater_central device info
416+ # Collect heater_central entity info
407417 self ._appl_heater_central_info (
408418 appl , appliance , False
409- ) # False means non-legacy device
419+ ) # False means non-legacy entity
410420 self ._dhw_allowed_modes = self ._get_appl_actuator_modes (
411421 appliance , "domestic_hot_water_mode_control_functionality"
412422 )
@@ -801,19 +811,23 @@ def _process_on_off_device_c_heating_state(self, data: GwEntityData) -> None:
801811 data ["binary_sensors" ]["heating_state" ] = data ["c_heating_state" ]
802812
803813 if self .smile (ADAM ):
814+ # First count when not present, then create and init to False.
815+ # When present init to False
804816 if "heating_state" not in data ["binary_sensors" ]:
805817 self ._count += 1
806818 data ["binary_sensors" ]["heating_state" ] = False
819+
807820 if "cooling_state" not in data ["binary_sensors" ]:
808821 self ._count += 1
809822 data ["binary_sensors" ]["cooling_state" ] = False
823+
810824 if self ._cooling_enabled :
811825 data ["binary_sensors" ]["cooling_state" ] = data ["c_heating_state" ]
812826 else :
813827 data ["binary_sensors" ]["heating_state" ] = data ["c_heating_state" ]
814828
815829 def _update_anna_cooling (self , entity_id : str , data : GwEntityData ) -> None :
816- """Update the Anna heater_central device for cooling.
830+ """Update the Anna heater_central entity for cooling.
817831
818832 Support added for Techneco Elga and Thercon Loria/Thermastage.
819833 """
0 commit comments