diff --git a/custom_components/localthings/fan.py b/custom_components/localthings/fan.py index e552d73..46642f1 100644 --- a/custom_components/localthings/fan.py +++ b/custom_components/localthings/fan.py @@ -89,11 +89,13 @@ class LocalThingsRangeHoodFan(LocalThingsEntity, FanEntity): """ _enable_turn_on_off_backwards_compatibility = False - _attr_supported_features = ( - FanEntityFeature.SET_SPEED - | FanEntityFeature.TURN_ON - | FanEntityFeature.TURN_OFF - ) + + @property + def supported_features(self) -> FanEntityFeature: + features = FanEntityFeature.TURN_ON | FanEntityFeature.TURN_OFF + if self.speed_count > 0: + features |= FanEntityFeature.SET_SPEED + return features def __init__(self, coordinator: LocalThingsCoordinator, bound) -> None: super().__init__(coordinator, bound) @@ -119,7 +121,18 @@ class LocalThingsRangeHoodFan(LocalThingsEntity, FanEntity): def _all_speed_codes(self) -> list[str]: rep = self._rep(self._bound.href) - return [str(value) for value in rep.get(_SUPPORTED_FAN_SPEED_FIELD, ())] + supported = rep.get(_SUPPORTED_FAN_SPEED_FIELD) + if supported: + return [str(value) for value in supported] + min_s = rep.get(_MIN_FAN_SPEED_FIELD) + max_s = rep.get('x.com.samsung.da.hood.settableMaxFanSpeed') + if min_s is not None and max_s is not None: + try: + mn, mx = int(min_s), int(max_s) + return [str(i) for i in range(mn, mx + 1)] + except (ValueError, TypeError): + pass + return [] def _active_speed_codes(self) -> list[str]: codes = self._all_speed_codes() diff --git a/tests/test_range_hood_fan.py b/tests/test_range_hood_fan.py index b1c3e55..ec9b11f 100644 --- a/tests/test_range_hood_fan.py +++ b/tests/test_range_hood_fan.py @@ -224,3 +224,19 @@ async def test_microwave_vent_fan_set_percentage_zero_turns_off(): await entity.async_set_percentage(0) assert coordinator.commands[-1][1] == ('speed', '0') + + +def test_microwave_vent_fan_missing_supported_fan_speed_falls_back_to_settable_min_max(): + """Hardware omitting supportedFanSpeed (e.g. ME8000T / issue #172) falls back + to building speed codes from settableMinFanSpeed ('0') and settableMaxFanSpeed ('3').""" + resources = _load_device('microwave_me7500d') + resources['/hood/fanspeed/vs/0'].pop('x.com.samsung.da.hood.supportedFanSpeed', None) + resources['/hood/fanspeed/vs/0']['x.com.samsung.da.hood.settableMinFanSpeed'] = '0' + resources['/hood/fanspeed/vs/0']['x.com.samsung.da.hood.settableMaxFanSpeed'] = '3' + + entity = _microwave_entity(resources) + assert entity._all_speed_codes() == ['0', '1', '2', '3'] + assert entity._active_speed_codes() == ['1', '2', '3'] + assert entity.speed_count == 3 + assert entity.supported_features & 1 # FanEntityFeature.SET_SPEED is present +