diff --git a/custom_components/dyson_local/__init__.py b/custom_components/dyson_local/__init__.py index 3029d00f1..83235c11e 100644 --- a/custom_components/dyson_local/__init__.py +++ b/custom_components/dyson_local/__init__.py @@ -212,6 +212,8 @@ def _async_get_platforms(device: DysonDevice) -> List[str]: platforms.extend(["binary_sensor", "climate"]) if isinstance(device, DysonPurifierHumidifyCool): platforms.append("humidifier") + if hasattr(device, "filter_life") or hasattr(device, "carbon_filter_life") or hasattr(device, "hepa_filter_life"): + platforms.append("button") return platforms diff --git a/custom_components/dyson_local/fan.py b/custom_components/dyson_local/fan.py index ab1ca0de3..94f52abc2 100644 --- a/custom_components/dyson_local/fan.py +++ b/custom_components/dyson_local/fan.py @@ -49,8 +49,9 @@ } PRESET_MODE_AUTO = "Auto" +PRESET_MODE_NORMAL = "Normal" -SUPPORTED_PRESET_MODES = [PRESET_MODE_AUTO] +SUPPORTED_PRESET_MODES = [PRESET_MODE_AUTO, PRESET_MODE_NORMAL] SPEED_RANGE = (1, 10) @@ -130,12 +131,15 @@ def preset_mode(self) -> Optional[str]: """Return the current selected preset mode.""" if self._device.auto_mode: return PRESET_MODE_AUTO - return None + else: + return PRESET_MODE_NORMAL def set_preset_mode(self, preset_mode: str) -> None: """Configure the preset mode.""" if preset_mode == PRESET_MODE_AUTO: self._device.enable_auto_mode() + elif preset_mode == PRESET_MODE_NORMAL: + self._device.disable_auto_mode() else: raise NotValidPresetModeError(f"Invalid preset mode: {preset_mode}") diff --git a/custom_components/dyson_local/manifest.json b/custom_components/dyson_local/manifest.json index 89e72cc53..970bd0e7c 100644 --- a/custom_components/dyson_local/manifest.json +++ b/custom_components/dyson_local/manifest.json @@ -7,5 +7,5 @@ "documentation": "https://github.com/libdyson-wg/ha-dyson", "iot_class": "local_push", "issue_tracker": "https://github.com/libdyson-wg/ha-dyson/issues", - "version": "1.0.0" + "version": "1.3.0" } diff --git a/custom_components/dyson_local/sensor.py b/custom_components/dyson_local/sensor.py index 8e16e7683..84ee04edb 100644 --- a/custom_components/dyson_local/sensor.py +++ b/custom_components/dyson_local/sensor.py @@ -8,6 +8,7 @@ DysonDevice, DysonPureCoolLink, DysonPurifierHumidifyCool, + DysonBigQuiet, ) from .vendor.libdyson.const import MessageType @@ -18,6 +19,7 @@ from homeassistant.const import ( CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER, + CONCENTRATION_PARTS_PER_MILLION, CONF_NAME, PERCENTAGE, TEMP_CELSIUS, @@ -58,7 +60,10 @@ async def async_setup_entry( DysonParticulatesSensor(coordinator, device, name), ] ) - else: # DysonPureCool or DysonPurifierHumidifyCool + elif isinstance(device, DysonBigQuiet): + if hasattr(device, "carbon_dioxide") and device.carbon_dioxide is not None: + entities.append(DysonCarbonDioxideSensor(coordinator, device, name)) + else: entities.extend( [ DysonPM25Sensor(coordinator, device, name), @@ -386,3 +391,26 @@ def native_value(self) -> Optional[float]: def available(self) -> bool: """Return available only if device not in off, init or failed states.""" return isinstance(self._device.formaldehyde, (int, float)) + + +class DysonCarbonDioxideSensor(DysonSensorEnvironmental): + """Dyson sensor for Carbon Dioxide.""" + + _SENSOR_TYPE = "c02" + _SENSOR_NAME = "Carbon Dioxide" + + _attr_device_class = SensorDeviceClass.CO2 + _attr_native_unit_of_measurement = CONCENTRATION_PARTS_PER_MILLION + _attr_state_class = SensorStateClass.MEASUREMENT + + @property + def native_value(self) -> Optional[float]: + """Return the state of the sensor.""" + if (value := self._device.carbon_dioxide) >= 0: + return value + return None + + @property + def available(self) -> bool: + """Return available only if device not in off, init or failed states.""" + return isinstance(self._device.carbon_dioxide, (int, float)) diff --git a/custom_components/dyson_local/services.yaml b/custom_components/dyson_local/services.yaml index 0278fc1f0..e9d57776e 100644 --- a/custom_components/dyson_local/services.yaml +++ b/custom_components/dyson_local/services.yaml @@ -1,22 +1,29 @@ set_angle: + name: Set Angle description: Set the oscillation angle of the selected fan(s). fields: entity_id: + name: Entity ID description: Name(s) of the entities for which to set the angle example: "fan.living_room" angle_low: + name: Angle Low description: The angle at which the oscillation should start example: 1 angle_high: + name: Angle High description: The angle at which the oscillation should end example: 255 set_timer: + name: Set Timer description: Set the sleep timer. fields: entity_id: + name: Entity ID description: Name(s) of the entities to set the sleep timer for example: "fan.living_room" timer: + name: Timer description: The value in minutes to set the timer to, 0 to disable it example: 30 diff --git a/custom_components/dyson_local/vendor/libdyson/__init__.py b/custom_components/dyson_local/vendor/libdyson/__init__.py index 47f5665bd..1618ff40b 100644 --- a/custom_components/dyson_local/vendor/libdyson/__init__.py +++ b/custom_components/dyson_local/vendor/libdyson/__init__.py @@ -17,6 +17,7 @@ DEVICE_TYPE_PURE_HUMIDIFY_COOL, DEVICE_TYPE_PURIFIER_HUMIDIFY_COOL_E, DEVICE_TYPE_PURIFIER_HUMIDIFY_COOL_K, + DEVICE_TYPE_PURIFIER_BIG_QUIET, ) from .const import CleaningMode # noqa: F401 @@ -37,6 +38,7 @@ from .dyson_pure_hot_cool import DysonPureHotCool from .dyson_pure_hot_cool_link import DysonPureHotCoolLink from .dyson_pure_humidify_cool import DysonPurifierHumidifyCool +from .dyson_purifier_big_quiet import DysonBigQuiet from .utils import get_mqtt_info_from_wifi_info # noqa: F401 @@ -72,4 +74,8 @@ def get_device(serial: str, credential: str, device_type: str) -> Optional[Dyson DEVICE_TYPE_PURIFIER_HUMIDIFY_COOL_E, ]: return DysonPurifierHumidifyCool(serial, credential, device_type) + if device_type in { + DEVICE_TYPE_PURIFIER_BIG_QUIET, + }: + return DysonBigQuiet(serial, credential, device_type) return None diff --git a/custom_components/dyson_local/vendor/libdyson/const.py b/custom_components/dyson_local/vendor/libdyson/const.py index 038e735e4..259788854 100644 --- a/custom_components/dyson_local/vendor/libdyson/const.py +++ b/custom_components/dyson_local/vendor/libdyson/const.py @@ -16,6 +16,7 @@ DEVICE_TYPE_PURE_HOT_COOL = "527" # HP04 DEVICE_TYPE_PURIFIER_HOT_COOL_E = "527E" # HP07 AND HP09 DEVICE_TYPE_PURIFIER_HOT_COOL_K = "527K" # HP07 AND HP09 +DEVICE_TYPE_PURIFIER_BIG_QUIET = "664" # BP02, BP03, and BP04 DEVICE_TYPE_NAMES = { DEVICE_TYPE_360_EYE: "360 Eye robot vacuum", @@ -33,6 +34,7 @@ DEVICE_TYPE_PURIFIER_HUMIDIFY_COOL_K: "Purifier Humidify+Cool", DEVICE_TYPE_PURIFIER_HUMIDIFY_COOL_E: "Purifier Humidify+Cool", DEVICE_TYPE_PURIFIER_HOT_COOL_K: "Purifier Hot+Cool", + DEVICE_TYPE_PURIFIER_BIG_QUIET: "Purifier Big+Quiet Series" } ENVIRONMENTAL_OFF = -1 diff --git a/custom_components/plant/manifest.json b/custom_components/plant/manifest.json index c24eaba01..713362752 100644 --- a/custom_components/plant/manifest.json +++ b/custom_components/plant/manifest.json @@ -16,5 +16,5 @@ "requirements": [ "async-timeout>=4.0.2" ], - "version": "2023.8.0" + "version": "2023.10.0" } diff --git a/custom_components/plant/number.py b/custom_components/plant/number.py index f1d8ef0e5..1376189fe 100644 --- a/custom_components/plant/number.py +++ b/custom_components/plant/number.py @@ -24,7 +24,7 @@ ) from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.event import async_track_state_change_event -from homeassistant.util.temperature import convert as convert_temperature +from homeassistant.util.unit_conversion import TemperatureConverter from .const import ( ATTR_CONDUCTIVITY, @@ -350,7 +350,7 @@ def state_attributes_changed(self, old_attributes, new_attributes): and new_attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "°C" ): new_state = round( - convert_temperature( + TemperatureConerter.convert( temperature=float(self.state), from_unit=TEMP_FAHRENHEIT, to_unit=TEMP_CELSIUS, @@ -367,7 +367,7 @@ def state_attributes_changed(self, old_attributes, new_attributes): and new_attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "°F" ): new_state = round( - convert_temperature( + TemperatureConerter.convert( temperature=float(self.state), from_unit=TEMP_CELSIUS, to_unit=TEMP_FAHRENHEIT, @@ -422,7 +422,7 @@ def state_attributes_changed(self, old_attributes, new_attributes): and new_attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "°C" ): new_state = round( - convert_temperature( + TemperatureConerter.convert( temperature=float(self.state), from_unit=TEMP_FAHRENHEIT, to_unit=TEMP_CELSIUS, @@ -441,7 +441,7 @@ def state_attributes_changed(self, old_attributes, new_attributes): and new_attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "°F" ): new_state = round( - convert_temperature( + TemperatureConerter.convert( temperature=float(self.state), from_unit=TEMP_CELSIUS, to_unit=TEMP_FAHRENHEIT, diff --git a/script/sync-components b/script/sync-components index 5790e10da..a576f40e5 100755 --- a/script/sync-components +++ b/script/sync-components @@ -46,7 +46,7 @@ rm -rf custom_components/ember_mug mv $TMPDIR/$$-ember/custom_components/ember_mug custom_components # renovate: datasource=github-releases depName=libdyson-wg/ha-dyson -DYSON_LOCAL_VERSION=v1.0.1 +DYSON_LOCAL_VERSION=v1.3.1 git clone --depth 1 --branch $DYSON_LOCAL_VERSION https://github.com/libdyson-wg/ha-dyson $TMPDIR/$$-dyson-local rm -rf custom_components/dyson_local mv $TMPDIR/$$-dyson-local/custom_components/dyson_local custom_components