Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion PyViCare/PyViCareDeviceConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,28 @@ def asAutoDetectDevice(self):
for (creator_method, type_name, roles) in device_types:
if re.search(type_name, self.device_model) or self.service.hasRoles(roles):
logger.info("detected %s %s", self.device_model, creator_method.__name__)
return creator_method()
device = creator_method()
if isinstance(device, (GazBoiler, HeatPump)) and not isinstance(device, Hybrid):
if self._isHybridByFeatures():
logger.info("upgrading %s to Hybrid based on API features", self.device_model)
return self.asHybridDevice()
return device

logger.info("Could not auto detect %s. Use generic device.", self.device_model)
return self.asGeneric()

def _isHybridByFeatures(self):
"""Check API features to detect hybrid devices (both burners and compressors)."""
try:
features = self.service.fetch_all_features()
feature_names = [f["feature"] for f in features.get("data", [])]
has_burners = any(f.startswith("heating.burners") for f in feature_names)
has_compressors = any(f.startswith("heating.compressors") for f in feature_names)
return has_burners and has_compressors
except (KeyError, TypeError, AttributeError, OSError):
logger.debug("Could not fetch features for hybrid detection of %s", self.device_model)
return False

def get_raw_json(self):
return self.service.fetch_all_features()

Expand Down
45 changes: 45 additions & 0 deletions tests/test_PyViCareDeviceConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,51 @@ def test_e3_device(self):
self.assertEqual(device.isLegacyDevice(), False)
self.assertEqual(device.isE3Device(), True)

def test_autoDetect_CU401B_S_with_burners_and_compressors_asHybrid(self):
self.service.hasRoles = has_roles(["type:heatpump"])
self.service.fetch_all_features = Mock(return_value={"data": [
{"feature": "heating.burners"},
{"feature": "heating.burners.0"},
{"feature": "heating.compressors"},
{"feature": "heating.compressors.0"},
]})
c = PyViCareDeviceConfig(
self.service, "0", "CU401B_S", "Online")
device_type = c.asAutoDetectDevice()
self.assertEqual("Hybrid", type(device_type).__name__)

def test_autoDetect_HeatPump_without_burners_stays_HeatPump(self):
self.service.hasRoles = has_roles(["type:heatpump"])
self.service.fetch_all_features = Mock(return_value={"data": [
{"feature": "heating.compressors"},
{"feature": "heating.compressors.0"},
]})
c = PyViCareDeviceConfig(
self.service, "0", "Vitocal300", "Online")
device_type = c.asAutoDetectDevice()
self.assertEqual("HeatPump", type(device_type).__name__)

def test_autoDetect_GazBoiler_with_compressors_asHybrid(self):
self.service.hasRoles = has_roles(["type:boiler"])
self.service.fetch_all_features = Mock(return_value={"data": [
{"feature": "heating.burners"},
{"feature": "heating.burners.0"},
{"feature": "heating.compressors"},
{"feature": "heating.compressors.0"},
]})
c = PyViCareDeviceConfig(
self.service, "0", "Vitodens200", "Online")
device_type = c.asAutoDetectDevice()
self.assertEqual("Hybrid", type(device_type).__name__)

def test_autoDetect_feature_fetch_failure_keeps_original(self):
self.service.hasRoles = has_roles(["type:heatpump"])
self.service.fetch_all_features = Mock(side_effect=OSError("API error"))
c = PyViCareDeviceConfig(
self.service, "0", "CU401B_S", "Online")
device_type = c.asAutoDetectDevice()
self.assertEqual("HeatPump", type(device_type).__name__)

def test_getDeviceType_heating(self):
c = PyViCareDeviceConfig(self.service, "0", "Vitocal", "Online", "heating")
self.assertEqual(c.getDeviceType(), "heating")
Expand Down
Loading