Skip to content

Commit

Permalink
Merge pull request #92 from Alexwijn/improvement/more-manufacturers
Browse files Browse the repository at this point in the history
Refactor Manufacturer Identification
  • Loading branch information
Alexwijn authored Feb 8, 2025
2 parents a3ce0d0 + 243693b commit 3545d11
Show file tree
Hide file tree
Showing 23 changed files with 85 additions and 54 deletions.
6 changes: 3 additions & 3 deletions custom_components/sat/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,14 +489,14 @@ async def async_step_manufacturer(self, _user_input: dict[str, Any] | None = Non

try:
manufacturers = ManufacturerFactory.resolve_by_member_id(coordinator.member_id)
default_manufacturer = manufacturers[0].name if len(manufacturers) > 0 else -1
default_manufacturer = manufacturers[0].friendly_name if len(manufacturers) > 0 else -1
finally:
await coordinator.async_will_remove_from_hass()

options = []
for name, _info in MANUFACTURERS.items():
for name in MANUFACTURERS:
manufacturer = ManufacturerFactory.resolve_by_name(name)
options.append({"value": name, "label": manufacturer.name})
options.append({"value": name, "label": manufacturer.friendly_name})

return self.async_show_form(
last_step=True,
Expand Down
2 changes: 1 addition & 1 deletion custom_components/sat/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def __init__(self, coordinator: SatDataUpdateCoordinator, config_entry: ConfigEn
def device_info(self):
manufacturer = "Unknown"
if self._coordinator.manufacturer is not None:
manufacturer = self._coordinator.manufacturer.name
manufacturer = self._coordinator.manufacturer.friendly_name

return DeviceInfo(
name=NAME,
Expand Down
65 changes: 37 additions & 28 deletions custom_components/sat/manufacturer.py
Original file line number Diff line number Diff line change
@@ -1,54 +1,63 @@
from abc import abstractmethod
from abc import ABC, abstractmethod
from typing import Optional, List, Type

from typing import List, Optional
from custom_components.sat.helpers import snake_case

MANUFACTURERS = {
"ATAG": {"module": "atag", "class": "ATAG", "id": 4},
"Baxi": {"module": "baxi", "class": "Baxi", "id": 4},
"Brotge": {"module": "brotge", "class": "Brotge", "id": 4},
"Geminox": {"module": "geminox", "class": "Geminox", "id": 4},
"Ideal": {"module": "ideal", "class": "Ideal", "id": 6},
"Ferroli": {"module": "ferroli", "class": "Ferroli", "id": 9},
"DeDietrich": {"module": "dedietrich", "class": "DeDietrich", "id": 11},
"Vaillant": {"module": "vaillant", "class": "Vaillant", "id": 24},
"Immergas": {"module": "immergas", "class": "Immergas", "id": 27},
"Sime": {"module": "sime", "class": "Sime", "id": 27},
"Viessmann": {"module": "viessmann", "class": "Viessmann", "id": 33},
"Radiant": {"module": "radiant", "class": "Radiant", "id": 41},
"Nefit": {"module": "nefit", "class": "Nefit", "id": 131},
"Intergas": {"module": "intergas", "class": "Intergas", "id": 173},
"Other": {"module": "other", "class": "Other", "id": -1},
"Atag": 4,
"Baxi": 4,
"Brotge": 4,
"DeDietrich": 4,
"Ferroli": 9,
"Geminox": 4,
"Ideal": 6,
"Immergas": 27,
"Intergas": 173,
"Itho": 29,
"Nefit": 131,
"Radiant": 41,
"Remeha": 11,
"Sime": 27,
"Vaillant": 24,
"Viessmann": 33,
"Worcester": 95,
"Other": -1,
}


class Manufacturer:
class Manufacturer(ABC):
def __init__(self):
self._member_id = MANUFACTURERS.get(type(self).__name__)

@property
def member_id(self) -> int:
return self._member_id

@property
@abstractmethod
def name(self) -> str:
def friendly_name(self) -> str:
pass


class ManufacturerFactory:
@staticmethod
def resolve_by_name(name: str) -> Optional[Manufacturer]:
"""Resolve a Manufacturer instance by its name."""
manufacturer = MANUFACTURERS.get(name)
if not manufacturer:
if not (member_id := MANUFACTURERS.get(name)):
return None

return ManufacturerFactory._import_class(manufacturer["module"], manufacturer["class"])()
return ManufacturerFactory._import_class(snake_case(name), name)()

@staticmethod
def resolve_by_member_id(member_id: int) -> List[Manufacturer]:
"""Resolve a list of Manufacturer instances by member ID."""
return [
ManufacturerFactory._import_class(info["module"], info["class"])()
for name, info in MANUFACTURERS.items()
if info["id"] == member_id
ManufacturerFactory._import_class(snake_case(name), name)()
for name, value in MANUFACTURERS.items()
if member_id == value
]

@staticmethod
def _import_class(module_name: str, class_name: str):
def _import_class(module_name: str, class_name: str) -> Type[Manufacturer]:
"""Dynamically import and return a Manufacturer class."""
module = __import__(f"custom_components.sat.manufacturers.{module_name}", fromlist=[class_name])
return getattr(module, class_name)
return getattr(__import__(f"custom_components.sat.manufacturers.{module_name}", fromlist=[class_name]), class_name)
4 changes: 2 additions & 2 deletions custom_components/sat/manufacturers/atag.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from ..manufacturer import Manufacturer


class ATAG(Manufacturer):
class Atag(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'ATAG'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/baxi.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Baxi(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Baxi'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/brotge.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Brotge(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'BRÖTGE'
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class DeDietrich(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'De Dietrich'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/ferroli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Ferroli(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Ferroli'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/geminox.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Geminox(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Geminox'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/ideal.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Ideal(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Ideal'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/immergas.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Immergas(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Immergas'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/intergas.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Intergas(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Intergas'
7 changes: 7 additions & 0 deletions custom_components/sat/manufacturers/itho.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from ..manufacturer import Manufacturer


class Itho(Manufacturer):
@property
def friendly_name(self) -> str:
return 'Itho'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/nefit.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Nefit(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Nefit'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/other.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Other(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Other'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/radiant.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Radiant(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Radiant'
7 changes: 7 additions & 0 deletions custom_components/sat/manufacturers/remeha.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from ..manufacturer import Manufacturer


class Remeha(Manufacturer):
@property
def friendly_name(self) -> str:
return 'Remeha'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/sime.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Sime(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Sime'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/vaillant.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Vaillant(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Vaillant'
2 changes: 1 addition & 1 deletion custom_components/sat/manufacturers/viessmann.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@

class Viessmann(Manufacturer):
@property
def name(self) -> str:
def friendly_name(self) -> str:
return 'Viessmann'
7 changes: 7 additions & 0 deletions custom_components/sat/manufacturers/worcester.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from ..manufacturer import Manufacturer


class Worcester(Manufacturer):
@property
def friendly_name(self) -> str:
return 'Worcester Bosch'
2 changes: 1 addition & 1 deletion custom_components/sat/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def name(self) -> str:

@property
def native_value(self) -> str:
return self._coordinator.manufacturer.name
return self._coordinator.manufacturer.friendly_name

@property
def available(self) -> bool:
Expand Down
11 changes: 6 additions & 5 deletions tests/test_manufacturer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def test_resolve_by_name():
# Test valid name
manufacturer = ManufacturerFactory.resolve_by_name(name)
assert manufacturer is not None, f"Manufacturer '{name}' should not be None"
assert manufacturer.__class__.__name__ == data["class"]
assert manufacturer.__class__.__name__ == name

# Test invalid name
manufacturer = ManufacturerFactory.resolve_by_name("InvalidName")
Expand All @@ -16,16 +16,17 @@ def test_resolve_by_name():

def test_resolve_by_member_id():
"""Test resolving manufacturers by member ID."""
member_id_to_names = {data["id"]: [] for data in MANUFACTURERS.values()}
for name, data in MANUFACTURERS.items():
member_id_to_names[data["id"]].append(name)
member_id_to_names = {member_id: [] for name, member_id in MANUFACTURERS.items()}
for name, member_id in MANUFACTURERS.items():
member_id_to_names[member_id].append(name)

for member_id, names in member_id_to_names.items():
manufacturers = ManufacturerFactory.resolve_by_member_id(member_id)
assert len(manufacturers) == len(names), f"Expected {len(names)} manufacturers for member ID {member_id}"

for manufacturer in manufacturers:
assert manufacturer.__class__.__name__ in names, f"Manufacturer name '{manufacturer.name}' not expected for member ID {member_id}"
assert manufacturer.member_id == member_id, f"Expected {manufacturer.member_id} for member ID {member_id}"
assert manufacturer.__class__.__name__ in names, f"Manufacturer name '{manufacturer.friendly_name}' not expected for member ID {member_id}"

# Test invalid member ID
manufacturers = ManufacturerFactory.resolve_by_member_id(999)
Expand Down

0 comments on commit 3545d11

Please sign in to comment.