From 5dfbd86f656527e63ff43066cf255d2d4e139c90 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 10 Jan 2024 00:10:31 +0100 Subject: [PATCH 01/76] start support for AMF765 and CX5120 --- .../philips_airpurifier_coap/const.py | 16 ++++++ .../philips_airpurifier_coap/philips.py | 55 ++++++++++++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 0c60da1..5a90162 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -113,6 +113,8 @@ class FanModel(StrEnum): AC4550 = "AC4550" AC4558 = "AC4558" AC5659 = "AC5659" + AMF765 = "AMF765" + CX5120 = "CX5120" class PresetMode: @@ -293,6 +295,7 @@ class PhilipsApi: SWITCH_ON: "1", SWITCH_OFF: "0", } + # the AC1715 seems to follow a new scheme, this should later be refactored NEW_NAME = "D01-03" NEW_MODEL_ID = "D01-05" @@ -304,6 +307,12 @@ class PhilipsApi: NEW_PM25 = "D03-33" NEW_PREFERRED_INDEX = "D03-42" + # there is a third generation of devices with yet another scheme + NEW2_NAME = "D01S03" + NEW2_MODEL_ID = "D01S05" + NEW2_POWER = "D03102" + NEW2_DISPLAY_BACKLIGHT = "D0312D" + PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), "1": ("PM2.5", ICON.PM25), @@ -506,6 +515,13 @@ class PhilipsApi: SWITCH_ON: 100, SWITCH_OFF: 0, }, + PhilipsApi.NEW2_DISPLAY_BACKLIGHT: { + ATTR_ICON: ICON.LIGHT_DIMMING_BUTTON, + FanAttributes.LABEL: FanAttributes.DISPLAY_BACKLIGHT, + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + SWITCH_ON: 100, + SWITCH_OFF: 0, + }, } SELECT_TYPES: dict[str, SelectDescription] = { diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 7784995..6e3f87a 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -537,6 +537,45 @@ class PhilipsNewGenericCoAPFan(PhilipsGenericCoAPFanBase): STATE_POWER_OFF = "OFF" +class PhilipsNew2GenericCoAPFan(PhilipsGenericCoAPFanBase): + """Class to manage another new generic CoAP fan.""" + + AVAILABLE_PRESET_MODES = {} + AVAILABLE_SPEEDS = {} + + AVAILABLE_ATTRIBUTES = [ + # device information + (FanAttributes.NAME, PhilipsApi.NEW2_NAME), + (FanAttributes.MODEL_ID, PhilipsApi.NEW2_MODEL_ID), + (FanAttributes.PRODUCT_ID, PhilipsApi.PRODUCT_ID), + (FanAttributes.DEVICE_ID, PhilipsApi.DEVICE_ID), + # (FanAttributes.SOFTWARE_VERSION, PhilipsApi.SOFTWARE_VERSION), + (FanAttributes.WIFI_VERSION, PhilipsApi.WIFI_VERSION), + # (FanAttributes.ERROR_CODE, PhilipsApi.ERROR_CODE), + # (FanAttributes.ERROR, PhilipsApi.ERROR_CODE, PhilipsApi.ERROR_CODE_MAP), + # device configuration + # ( + # FanAttributes.PREFERRED_INDEX, + # PhilipsApi.NEW_PREFERRED_INDEX, + # PhilipsApi.NEW_PREFERRED_INDEX_MAP, + # ), + # device sensors + # ( + # FanAttributes.RUNTIME, + # PhilipsApi.RUNTIME, + # lambda x, _: str(timedelta(seconds=round(x / 1000))), + # ), + ] + + AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT] + AVAILABLE_SWITCHES = [] + AVAILABLE_SELECTS = [] + + KEY_PHILIPS_POWER = PhilipsApi.NEW2_POWER + STATE_POWER_ON = 1 + STATE_POWER_OFF = 0 + + class PhilipsHumidifierMixin(PhilipsGenericCoAPFanBase): """Mixin for humidifiers.""" @@ -1153,9 +1192,9 @@ class PhilipsAC3836(PhilipsGenericCoAPFan): AVAILABLE_PRESET_MODES = { PresetMode.AUTO: { - PhilipsApi.POWER: "1", - PhilipsApi.MODE: "AG", - PhilipsApi.SPEED: "1" + PhilipsApi.POWER: "1", + PhilipsApi.MODE: "AG", + PhilipsApi.SPEED: "1", }, # make speeds available as preset PresetMode.SLEEP: { @@ -1469,6 +1508,14 @@ class PhilipsAC5659(PhilipsGenericCoAPFan): AVAILABLE_SELECTS = [PhilipsApi.PREFERRED_INDEX] +class PhilipsAMF765(PhilipsNew2GenericCoAPFan): + """AMF765.""" + + +class PhilipsCX5120(PhilipsNew2GenericCoAPFan): + """CX5120.""" + + model_to_class = { FanModel.AC0850: PhilipsAC0850, FanModel.AC1214: PhilipsAC1214, @@ -1495,4 +1542,6 @@ class PhilipsAC5659(PhilipsGenericCoAPFan): FanModel.AC4550: PhilipsAC4550, FanModel.AC4558: PhilipsAC4558, FanModel.AC5659: PhilipsAC5659, + FanModel.AMF765: PhilipsAMF765, + FanModel.CX5120: PhilipsCX5120, } From 92981a47be3a34082c257c1ef79e6a5030ce1f82 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 10 Jan 2024 00:11:58 +0100 Subject: [PATCH 02/76] start support for AMF765 and CX5120 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fb70b77..ce69d75 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ Note: `configuration.yaml` is no longer supported and your configuration is not - AC4550 - AC4558 - AC5659 +- AMF765 +- CX5120 ## Is your model not supported yet? From a3557e755fea538c835c74e427ec266958733de6 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 10 Jan 2024 11:00:07 +0100 Subject: [PATCH 03/76] debug model detection --- .../philips_airpurifier_coap/config_flow.py | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/config_flow.py b/custom_components/philips_airpurifier_coap/config_flow.py index 9d805a9..d591f00 100644 --- a/custom_components/philips_airpurifier_coap/config_flow.py +++ b/custom_components/philips_airpurifier_coap/config_flow.py @@ -215,16 +215,37 @@ async def async_step_user(self, user_input: dict[str, Any] = None) -> FlowResult _LOGGER.warning(r"Failed to connect: %s", ex) raise exceptions.ConfigEntryNotReady from ex - # autodetect model and name - self._model = list( - filter( - None, - map(status.get, [PhilipsApi.MODEL_ID, PhilipsApi.NEW_MODEL_ID]), - ) - )[0][:9] + # autodetect model + model_map = map( + status.get, + [ + PhilipsApi.MODEL_ID, + PhilipsApi.NEW_MODEL_ID, + PhilipsApi.NEW2_MODEL_ID, + ], + ) + _LOGGER.debug("model_map retrieved: %s", model_map) + model_filter = filter(None, model_map) + _LOGGER.debug("model_filter applied: %s", model_filter) + model_list = list(model_filter) + _LOGGER.debug("model_list built: %s", model_list) + first_model = model_list[0] + _LOGGER.debug("first model selected: %s", first_model) + self._model = first_model[:9] + _LOGGER.debug("model type extracted: %s", self._model) + + # autodetect name self._name = list( filter( - None, map(status.get, [PhilipsApi.NAME, PhilipsApi.NEW_NAME]) + None, + map( + status.get, + [ + PhilipsApi.NAME, + PhilipsApi.NEW_NAME, + PhilipsApi.NEW2_NAME, + ], + ), ) )[0] self._device_id = status[PhilipsApi.DEVICE_ID] From 84148c6c5d85eb67fa5953085a457aa8909b749e Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 10 Jan 2024 13:16:20 +0100 Subject: [PATCH 04/76] put debugging into DHCP discovery --- .../philips_airpurifier_coap/config_flow.py | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/config_flow.py b/custom_components/philips_airpurifier_coap/config_flow.py index d591f00..f3e7366 100644 --- a/custom_components/philips_airpurifier_coap/config_flow.py +++ b/custom_components/philips_airpurifier_coap/config_flow.py @@ -91,14 +91,34 @@ async def async_step_dhcp(self, discovery_info: dhcp.DhcpServiceInfo) -> FlowRes _LOGGER.warning(r"Failed to connect: %s", ex) raise exceptions.ConfigEntryNotReady from ex - # autodetect model and name - self._model = list( + # autodetect model + model_map = map( + status.get, + [ + PhilipsApi.MODEL_ID, + PhilipsApi.NEW_MODEL_ID, + PhilipsApi.NEW2_MODEL_ID, + ], + ) + _LOGGER.debug("model_map retrieved: %s", model_map) + model_filter = filter(None, model_map) + _LOGGER.debug("model_filter applied: %s", model_filter) + model_list = list(model_filter) + _LOGGER.debug("model_list built: %s", model_list) + first_model = model_list[0] + _LOGGER.debug("first model selected: %s", first_model) + self._model = first_model[:9] + _LOGGER.debug("model type extracted: %s", self._model) + + # autodetect name + self._name = list( filter( - None, map(status.get, [PhilipsApi.MODEL_ID, PhilipsApi.NEW_MODEL_ID]) + None, + map( + status.get, + [PhilipsApi.NAME, PhilipsApi.NEW_NAME, PhilipsApi.NEW2_NAME], + ), ) - )[0][:9] - self._name = list( - filter(None, map(status.get, [PhilipsApi.NAME, PhilipsApi.NEW_NAME])) )[0] self._device_id = status[PhilipsApi.DEVICE_ID] _LOGGER.debug( From 9024a3f0f0d16ae9dceaa106d43e01daa4335f91 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 10 Jan 2024 15:33:47 +0100 Subject: [PATCH 05/76] fix base class for new models --- custom_components/philips_airpurifier_coap/philips.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 6e3f87a..28500e5 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -183,7 +183,10 @@ def __init__(self, coordinator: Coordinator) -> None: # noqa: D107 self._name = list( filter( None, - map(coordinator.status.get, [PhilipsApi.NAME, PhilipsApi.NEW_NAME]), + map( + coordinator.status.get, + [PhilipsApi.NAME, PhilipsApi.NEW_NAME, PhilipsApi.NEW2_NAME], + ), ) )[0] # self._modelName = coordinator.status["modelid"] @@ -192,7 +195,11 @@ def __init__(self, coordinator: Coordinator) -> None: # noqa: D107 None, map( coordinator.status.get, - [PhilipsApi.MODEL_ID, PhilipsApi.NEW_MODEL_ID], + [ + PhilipsApi.MODEL_ID, + PhilipsApi.NEW_MODEL_ID, + PhilipsApi.NEW2_MODEL_ID, + ], ), ) )[0] From 497ae125ec8a4b912492196cccdc36a43196acf0 Mon Sep 17 00:00:00 2001 From: Jorim Tielemans Date: Wed, 10 Jan 2024 16:36:23 +0100 Subject: [PATCH 06/76] Allow user to adjust brightness --- custom_components/philips_airpurifier_coap/const.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 5a90162..8b95f65 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -521,6 +521,7 @@ class PhilipsApi: CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, SWITCH_ON: 100, SWITCH_OFF: 0, + DIMMABLE: True, }, } From b621ca0ee93654215b95296c061c743bdf8724dc Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 11 Jan 2024 00:40:19 +0100 Subject: [PATCH 07/76] add temperature sensor --- custom_components/philips_airpurifier_coap/const.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 8b95f65..44cb9bf 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -312,6 +312,7 @@ class PhilipsApi: NEW2_MODEL_ID = "D01S05" NEW2_POWER = "D03102" NEW2_DISPLAY_BACKLIGHT = "D0312D" + NEW2_TEMPERATURE = "D03224" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -401,6 +402,18 @@ class PhilipsApi: ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, FanAttributes.UNIT: UnitOfTemperature.CELSIUS, }, + PhilipsApi.NEW2_TEMPERATURE: { + ATTR_DEVICE_CLASS: SensorDeviceClass.TEMPERATURE, + FanAttributes.ICON_MAP: { + 0: "mdi:thermometer-low", + 17: "mdi:thermometer", + 23: "mdi:thermometer-high", + }, + FanAttributes.LABEL: ATTR_TEMPERATURE, + FanAttributes.VALUE: lambda value, _: int(value / 10), + ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + FanAttributes.UNIT: UnitOfTemperature.CELSIUS, + }, # diagnostic information PhilipsApi.WATER_LEVEL: { FanAttributes.ICON_MAP: {0: ICON.WATER_REFILL, 10: "mdi:water"}, From 5cd455af3ed6f78acfe411f28e02eb477725f7ad Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 11 Jan 2024 01:03:56 +0100 Subject: [PATCH 08/76] add firmware detection --- custom_components/philips_airpurifier_coap/const.py | 1 + custom_components/philips_airpurifier_coap/philips.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 44cb9bf..8900256 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -313,6 +313,7 @@ class PhilipsApi: NEW2_POWER = "D03102" NEW2_DISPLAY_BACKLIGHT = "D0312D" NEW2_TEMPERATURE = "D03224" + NEW2_SOFTWARE_VERSION = "D01S12" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 28500e5..41dd08f 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -556,7 +556,7 @@ class PhilipsNew2GenericCoAPFan(PhilipsGenericCoAPFanBase): (FanAttributes.MODEL_ID, PhilipsApi.NEW2_MODEL_ID), (FanAttributes.PRODUCT_ID, PhilipsApi.PRODUCT_ID), (FanAttributes.DEVICE_ID, PhilipsApi.DEVICE_ID), - # (FanAttributes.SOFTWARE_VERSION, PhilipsApi.SOFTWARE_VERSION), + (FanAttributes.SOFTWARE_VERSION, PhilipsApi.NEW2_SOFTWARE_VERSION), (FanAttributes.WIFI_VERSION, PhilipsApi.WIFI_VERSION), # (FanAttributes.ERROR_CODE, PhilipsApi.ERROR_CODE), # (FanAttributes.ERROR, PhilipsApi.ERROR_CODE, PhilipsApi.ERROR_CODE_MAP), From f283585cd9fd9f74ff40bc9d007f533e9ea1af5e Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 11 Jan 2024 01:05:14 +0100 Subject: [PATCH 09/76] adding runtime detection --- custom_components/philips_airpurifier_coap/philips.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 41dd08f..fcfbf21 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -567,11 +567,11 @@ class PhilipsNew2GenericCoAPFan(PhilipsGenericCoAPFanBase): # PhilipsApi.NEW_PREFERRED_INDEX_MAP, # ), # device sensors - # ( - # FanAttributes.RUNTIME, - # PhilipsApi.RUNTIME, - # lambda x, _: str(timedelta(seconds=round(x / 1000))), - # ), + ( + FanAttributes.RUNTIME, + PhilipsApi.RUNTIME, + lambda x, _: str(timedelta(seconds=round(x / 1000))), + ), ] AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT] From e6020cda530d580f4f0521b491d04013fecb4604 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 11 Jan 2024 01:10:15 +0100 Subject: [PATCH 10/76] add child lock for AMF --- custom_components/philips_airpurifier_coap/const.py | 8 ++++++++ custom_components/philips_airpurifier_coap/philips.py | 2 ++ 2 files changed, 10 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 8900256..9ef70e7 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -314,6 +314,7 @@ class PhilipsApi: NEW2_DISPLAY_BACKLIGHT = "D0312D" NEW2_TEMPERATURE = "D03224" NEW2_SOFTWARE_VERSION = "D01S12" + NEW2_CHILD_LOCK = "D03103" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -504,6 +505,13 @@ class PhilipsApi: SWITCH_ON: True, SWITCH_OFF: False, }, + PhilipsApi.NEW2_CHILD_LOCK: { + ATTR_ICON: ICON.CHILD_LOCK_BUTTON, + FanAttributes.LABEL: FanAttributes.CHILD_LOCK, + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + SWITCH_ON: 1, + SWITCH_OFF: 0, + }, } LIGHT_TYPES: dict[str, LightDescription] = { diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index fcfbf21..0ae500b 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1518,6 +1518,8 @@ class PhilipsAC5659(PhilipsGenericCoAPFan): class PhilipsAMF765(PhilipsNew2GenericCoAPFan): """AMF765.""" + AVAILABLE_SWITCHES = [PhilipsApi.NEW2_CHILD_LOCK] + class PhilipsCX5120(PhilipsNew2GenericCoAPFan): """CX5120.""" From 76e6c4cf2f57fc6325df94f73ed890c771310029 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 11 Jan 2024 01:13:31 +0100 Subject: [PATCH 11/76] add IAI and PM25 sensors --- .../philips_airpurifier_coap/const.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 9ef70e7..1146328 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -315,6 +315,8 @@ class PhilipsApi: NEW2_TEMPERATURE = "D03224" NEW2_SOFTWARE_VERSION = "D01S12" NEW2_CHILD_LOCK = "D03103" + NEW2_INDOOR_ALLERGEN_INDEX = "D03120" + NEW2_PM25 = "D03121" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -365,6 +367,11 @@ class PhilipsApi: FanAttributes.LABEL: FanAttributes.INDOOR_ALLERGEN_INDEX, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, }, + PhilipsApi.NEW2_INDOOR_ALLERGEN_INDEX: { + FanAttributes.ICON_MAP: {0: ICON.IAI}, + FanAttributes.LABEL: FanAttributes.INDOOR_ALLERGEN_INDEX, + ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + }, PhilipsApi.PM25: { ATTR_DEVICE_CLASS: SensorDeviceClass.PM25, FanAttributes.ICON_MAP: {0: ICON.PM25}, @@ -379,6 +386,13 @@ class PhilipsApi: FanAttributes.UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, }, + PhilipsApi.NEW2_PM25: { + ATTR_DEVICE_CLASS: SensorDeviceClass.PM25, + FanAttributes.ICON_MAP: {0: ICON.PM25}, + FanAttributes.LABEL: FanAttributes.PM25, + FanAttributes.UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + }, PhilipsApi.TOTAL_VOLATILE_ORGANIC_COMPOUNDS: { ATTR_DEVICE_CLASS: SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS, FanAttributes.ICON_MAP: {0: "mdi:blur"}, From 403737cc69d81208b8a69b1f04474c26f3dce294 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 11 Jan 2024 01:23:06 +0100 Subject: [PATCH 12/76] add humidity and beeping --- .../philips_airpurifier_coap/const.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 1146328..9b925e1 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -181,6 +181,7 @@ class FanAttributes(StrEnum): AIR_QUALITY_INDEX = "air_quality_index" CHILD_LOCK = "child_lock" + BEEP = "beep" DEVICE_ID = "device_id" DEVICE_VERSION = "device_version" DISPLAY_BACKLIGHT = "display_backlight" @@ -315,8 +316,10 @@ class PhilipsApi: NEW2_TEMPERATURE = "D03224" NEW2_SOFTWARE_VERSION = "D01S12" NEW2_CHILD_LOCK = "D03103" + NEW2_BEEP = "D03130" NEW2_INDOOR_ALLERGEN_INDEX = "D03120" NEW2_PM25 = "D03121" + NEW2_HUMIDITY = "D03125" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -407,6 +410,13 @@ class PhilipsApi: ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, FanAttributes.UNIT: PERCENTAGE, }, + PhilipsApi.NEW2_HUMIDITY: { + ATTR_DEVICE_CLASS: SensorDeviceClass.HUMIDITY, + FanAttributes.ICON_MAP: {0: "mdi:water-percent"}, + FanAttributes.LABEL: FanAttributes.HUMIDITY, + ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + FanAttributes.UNIT: PERCENTAGE, + }, PhilipsApi.TEMPERATURE: { ATTR_DEVICE_CLASS: SensorDeviceClass.TEMPERATURE, FanAttributes.ICON_MAP: { @@ -526,6 +536,13 @@ class PhilipsApi: SWITCH_ON: 1, SWITCH_OFF: 0, }, + PhilipsApi.NEW2_BEEP: { + ATTR_ICON: "mdi:volume-high", + FanAttributes.LABEL: FanAttributes.BEEP, + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + SWITCH_ON: 100, + SWITCH_OFF: 0, + }, } LIGHT_TYPES: dict[str, LightDescription] = { From 498d8a2a31854bdca5f9ceda6b0fdc7b9568b807 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 11 Jan 2024 01:29:37 +0100 Subject: [PATCH 13/76] add filter sensors --- .../philips_airpurifier_coap/const.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 9b925e1..c91e669 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -320,6 +320,10 @@ class PhilipsApi: NEW2_INDOOR_ALLERGEN_INDEX = "D03120" NEW2_PM25 = "D03121" NEW2_HUMIDITY = "D03125" + NEW2_FILTER_NANOPROTECT_PREFILTER = "D0520D" + NEW2_FILTER_NANOPROTECT = "D0540E" + NEW2_FILTER_NANOPROTECT_PREFILTER_TOTAL = "D05207" + NEW2_FILTER_NANOPROTECT_TOTAL = "D05408" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -519,6 +523,24 @@ class PhilipsApi: FanAttributes.TOTAL: PhilipsApi.FILTER_NANOPROTECT_CLEAN_TOTAL, FanAttributes.TYPE: "", }, + PhilipsApi.NEW2_FILTER_NANOPROTECT: { + FanAttributes.ICON_MAP: { + 0: ICON.FILTER_REPLACEMENT, + 10: ICON.NANOPROTECT_FILTER, + }, + FanAttributes.LABEL: FanAttributes.FILTER_NANOPROTECT, + FanAttributes.TOTAL: PhilipsApi.NEW2_FILTER_NANOPROTECT_TOTAL, + FanAttributes.TYPE: "", + }, + PhilipsApi.NEW2_FILTER_NANOPROTECT_PREFILTER: { + FanAttributes.ICON_MAP: { + 0: ICON.PREFILTER_CLEANING, + 10: ICON.NANOPROTECT_FILTER, + }, + FanAttributes.LABEL: FanAttributes.FILTER_NANOPROTECT_CLEAN, + FanAttributes.TOTAL: PhilipsApi.NEW2_FILTER_NANOPROTECT_CLEAN_TOTAL, + FanAttributes.TYPE: "", + }, } SWITCH_TYPES: dict[str, SwitchDescription] = { From 76b42abd77f2e2a5628aa5f8f543abde3823739f Mon Sep 17 00:00:00 2001 From: Jorim Tielemans Date: Thu, 11 Jan 2024 04:03:01 +0100 Subject: [PATCH 14/76] Fix pre-filter constant --- custom_components/philips_airpurifier_coap/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index c91e669..a27e4d9 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -538,7 +538,7 @@ class PhilipsApi: 10: ICON.NANOPROTECT_FILTER, }, FanAttributes.LABEL: FanAttributes.FILTER_NANOPROTECT_CLEAN, - FanAttributes.TOTAL: PhilipsApi.NEW2_FILTER_NANOPROTECT_CLEAN_TOTAL, + FanAttributes.TOTAL: PhilipsApi.NEW2_FILTER_NANOPROTECT_PREFILTER_TOTAL, FanAttributes.TYPE: "", }, } From 803784a3a1a4dbfb2e20ddd42600aea6c38fff1b Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 11 Jan 2024 07:39:33 +0100 Subject: [PATCH 15/76] use temperature decimals --- custom_components/philips_airpurifier_coap/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index a27e4d9..4a101eb 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -440,7 +440,7 @@ class PhilipsApi: 23: "mdi:thermometer-high", }, FanAttributes.LABEL: ATTR_TEMPERATURE, - FanAttributes.VALUE: lambda value, _: int(value / 10), + FanAttributes.VALUE: lambda value, _: value / 10, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, FanAttributes.UNIT: UnitOfTemperature.CELSIUS, }, From 28115c687f0cde9e07741122bf8b318a39c54b5e Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 11 Jan 2024 21:43:38 +0100 Subject: [PATCH 16/76] fix display backlight for CX --- .../philips_airpurifier_coap/const.py | 23 +++++++++++++++++++ .../philips_airpurifier_coap/philips.py | 5 +++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 4a101eb..4f42184 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -179,6 +179,7 @@ class FanService(StrEnum): class FanAttributes(StrEnum): """The attributes of a fan.""" + ACTUAL_FAN_SPEED = "actual_fan_speed" AIR_QUALITY_INDEX = "air_quality_index" CHILD_LOCK = "child_lock" BEEP = "beep" @@ -313,6 +314,7 @@ class PhilipsApi: NEW2_MODEL_ID = "D01S05" NEW2_POWER = "D03102" NEW2_DISPLAY_BACKLIGHT = "D0312D" + NEW2_DISPLAY_BACKLIGHT2 = "D03105" NEW2_TEMPERATURE = "D03224" NEW2_SOFTWARE_VERSION = "D01S12" NEW2_CHILD_LOCK = "D03103" @@ -324,6 +326,7 @@ class PhilipsApi: NEW2_FILTER_NANOPROTECT = "D0540E" NEW2_FILTER_NANOPROTECT_PREFILTER_TOTAL = "D05207" NEW2_FILTER_NANOPROTECT_TOTAL = "D05408" + NEW2_FAN_SPEED = "D0310D" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -444,6 +447,18 @@ class PhilipsApi: ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, FanAttributes.UNIT: UnitOfTemperature.CELSIUS, }, + PhilipsApi.NEW2_FAN_SPEED: { + ATTR_DEVICE_CLASS: SensorDeviceClass.SPEED, + FanAttributes.ICON_MAP: { + 0: "mdi:thermometer-low", + 17: "mdi:thermometer", + 23: "mdi:thermometer-high", + }, + FanAttributes.LABEL: ATTR_TEMPERATURE, + FanAttributes.VALUE: lambda value, _: value / 10, + ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + FanAttributes.UNIT: UnitOfTemperature.CELSIUS, + }, # diagnostic information PhilipsApi.WATER_LEVEL: { FanAttributes.ICON_MAP: {0: ICON.WATER_REFILL, 10: "mdi:water"}, @@ -598,6 +613,14 @@ class PhilipsApi: SWITCH_OFF: 0, DIMMABLE: True, }, + PhilipsApi.NEW2_DISPLAY_BACKLIGHT2: { + ATTR_ICON: ICON.LIGHT_DIMMING_BUTTON, + FanAttributes.LABEL: FanAttributes.DISPLAY_BACKLIGHT, + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + SWITCH_ON: 100, + SWITCH_OFF: 0, + DIMMABLE: True, + }, } SELECT_TYPES: dict[str, SelectDescription] = { diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 0ae500b..5e2daca 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -574,7 +574,7 @@ class PhilipsNew2GenericCoAPFan(PhilipsGenericCoAPFanBase): ), ] - AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT] + AVAILABLE_LIGHTS = [] AVAILABLE_SWITCHES = [] AVAILABLE_SELECTS = [] @@ -1518,12 +1518,15 @@ class PhilipsAC5659(PhilipsGenericCoAPFan): class PhilipsAMF765(PhilipsNew2GenericCoAPFan): """AMF765.""" + AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT] AVAILABLE_SWITCHES = [PhilipsApi.NEW2_CHILD_LOCK] class PhilipsCX5120(PhilipsNew2GenericCoAPFan): """CX5120.""" + AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT2] + model_to_class = { FanModel.AC0850: PhilipsAC0850, From 9927475b09dde5da6e557062576d196efcc02ff1 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 11 Jan 2024 23:48:03 +0100 Subject: [PATCH 17/76] add new icons --- custom_components/philips_airpurifier_coap/const.py | 5 +++++ .../philips_airpurifier_coap/icons/pap/circulate.svg | 4 ++++ .../philips_airpurifier_coap/icons/pap/clean.svg | 4 ++++ .../philips_airpurifier_coap/icons/pap/mode.svg | 4 ++++ .../philips_airpurifier_coap/icons/pap/pm25b.svg | 4 ++++ .../philips_airpurifier_coap/icons/pap/rotate.svg | 7 +++++++ 6 files changed, 28 insertions(+) create mode 100644 custom_components/philips_airpurifier_coap/icons/pap/circulate.svg create mode 100644 custom_components/philips_airpurifier_coap/icons/pap/clean.svg create mode 100644 custom_components/philips_airpurifier_coap/icons/pap/mode.svg create mode 100644 custom_components/philips_airpurifier_coap/icons/pap/pm25b.svg create mode 100644 custom_components/philips_airpurifier_coap/icons/pap/rotate.svg diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 4f42184..1a256a3 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -64,6 +64,11 @@ class ICON(StrEnum): PREFILTER_WICK_CLEANING = "pap:prefilter_wick_cleaning" PM25 = "pap:pm25" IAI = "pap:iai" + PM25B = "pap:pm25b" + CIRCULATE = "pap:circulate" + CLEAN = "pap:clean" + MODE = "pap:mode" + ROTATE = "pap:rotate" DATA_EXTRA_MODULE_URL = "frontend_extra_module_url" diff --git a/custom_components/philips_airpurifier_coap/icons/pap/circulate.svg b/custom_components/philips_airpurifier_coap/icons/pap/circulate.svg new file mode 100644 index 0000000..e2cc318 --- /dev/null +++ b/custom_components/philips_airpurifier_coap/icons/pap/circulate.svg @@ -0,0 +1,4 @@ + + + + diff --git a/custom_components/philips_airpurifier_coap/icons/pap/clean.svg b/custom_components/philips_airpurifier_coap/icons/pap/clean.svg new file mode 100644 index 0000000..ade5e26 --- /dev/null +++ b/custom_components/philips_airpurifier_coap/icons/pap/clean.svg @@ -0,0 +1,4 @@ + + + + diff --git a/custom_components/philips_airpurifier_coap/icons/pap/mode.svg b/custom_components/philips_airpurifier_coap/icons/pap/mode.svg new file mode 100644 index 0000000..7095a29 --- /dev/null +++ b/custom_components/philips_airpurifier_coap/icons/pap/mode.svg @@ -0,0 +1,4 @@ + + + + diff --git a/custom_components/philips_airpurifier_coap/icons/pap/pm25b.svg b/custom_components/philips_airpurifier_coap/icons/pap/pm25b.svg new file mode 100644 index 0000000..b7acf73 --- /dev/null +++ b/custom_components/philips_airpurifier_coap/icons/pap/pm25b.svg @@ -0,0 +1,4 @@ + + + + diff --git a/custom_components/philips_airpurifier_coap/icons/pap/rotate.svg b/custom_components/philips_airpurifier_coap/icons/pap/rotate.svg new file mode 100644 index 0000000..bf213ce --- /dev/null +++ b/custom_components/philips_airpurifier_coap/icons/pap/rotate.svg @@ -0,0 +1,7 @@ + + + + + + + From cd1d96ca5f618fdb1b21942651f671070eb9e313 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 11 Jan 2024 23:58:04 +0100 Subject: [PATCH 18/76] add swing for CX --- custom_components/philips_airpurifier_coap/const.py | 9 +++++++++ custom_components/philips_airpurifier_coap/philips.py | 1 + 2 files changed, 10 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 1a256a3..f30d49e 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -230,6 +230,7 @@ class FanAttributes(StrEnum): WARN_VALUE = "warn_value" WARN_ICON = "warn_icon" RSSI = "rssi" + SWING = "swing" class FanUnits(StrEnum): @@ -332,6 +333,7 @@ class PhilipsApi: NEW2_FILTER_NANOPROTECT_PREFILTER_TOTAL = "D05207" NEW2_FILTER_NANOPROTECT_TOTAL = "D05408" NEW2_FAN_SPEED = "D0310D" + NEW2_SWING = "D0320F" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -585,6 +587,13 @@ class PhilipsApi: SWITCH_ON: 100, SWITCH_OFF: 0, }, + PhilipsApi.NEW2_SWING: { + ATTR_ICON: ICON.ROTATE, + FanAttributes.LABEL: FanAttributes.SWING, + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + SWITCH_ON: 17920, + SWITCH_OFF: 0, + }, } LIGHT_TYPES: dict[str, LightDescription] = { diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 5e2daca..9c6b7f8 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1526,6 +1526,7 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): """CX5120.""" AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT2] + AVAILABLE_SWITCHES = [PhilipsApi.NEW2_SWING] model_to_class = { From 07dd64adec44da9f933a79fb0d02e13f5609ed5a Mon Sep 17 00:00:00 2001 From: kongo09 Date: Fri, 12 Jan 2024 00:10:09 +0100 Subject: [PATCH 19/76] add circulation function --- custom_components/philips_airpurifier_coap/const.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index f30d49e..5b46697 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -334,6 +334,7 @@ class PhilipsApi: NEW2_FILTER_NANOPROTECT_TOTAL = "D05408" NEW2_FAN_SPEED = "D0310D" NEW2_SWING = "D0320F" + NEW2_CIRCULATION = "D0310A" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -352,6 +353,10 @@ class PhilipsApi: "P": ("Purification", ICON.PURIFICATION_ONLY_MODE), "PH": ("Purification and Humidification", ICON.TWO_IN_ONE_MODE), } + CIRCULATION_MAP = { + "1": ("Purification", ICON.CLEAN), + "2": ("Circulation", ICON.CIRCULATE), + } HUMIDITY_TARGET_MAP = { 40: ("40%", ICON.HUMIDITY_BUTTON), 50: ("50%", ICON.HUMIDITY_BUTTON), @@ -668,4 +673,9 @@ class PhilipsApi: CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, OPTIONS: PhilipsApi.NEW_PREFERRED_INDEX_MAP, }, + PhilipsApi.NEW2_CIRCULATION: { + FanAttributes.LABEL: FanAttributes.FUNCTION, + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + OPTIONS: PhilipsApi.CIRCULATION_MAP, + }, } From d5cf0b5fbba1615afb86585015a76d3589e71834 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 15 Jan 2024 13:49:34 +0100 Subject: [PATCH 20/76] fix speed sensor --- .../philips_airpurifier_coap/const.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 5b46697..4416fe3 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -231,6 +231,7 @@ class FanAttributes(StrEnum): WARN_ICON = "warn_icon" RSSI = "rssi" SWING = "swing" + TURBO = "turbo" class FanUnits(StrEnum): @@ -460,16 +461,17 @@ class PhilipsApi: FanAttributes.UNIT: UnitOfTemperature.CELSIUS, }, PhilipsApi.NEW2_FAN_SPEED: { - ATTR_DEVICE_CLASS: SensorDeviceClass.SPEED, FanAttributes.ICON_MAP: { - 0: "mdi:thermometer-low", - 17: "mdi:thermometer", - 23: "mdi:thermometer-high", + 0: ICON.FAN_SPEED_BUTTON, + 1: ICON.SPEED_1, + 6: ICON.SPEED_2, + 18: ICON.SPEED_3, }, - FanAttributes.LABEL: ATTR_TEMPERATURE, - FanAttributes.VALUE: lambda value, _: value / 10, + FanAttributes.VALUE: lambda value, _: value + if int(value) < 18 + else FanAttributes.TURBO, + FanAttributes.LABEL: FanAttributes.ACTUAL_FAN_SPEED, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, - FanAttributes.UNIT: UnitOfTemperature.CELSIUS, }, # diagnostic information PhilipsApi.WATER_LEVEL: { From f19d92041d1a0d4ed9b180134dc35d88aa79b76b Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 15 Jan 2024 23:55:28 +0100 Subject: [PATCH 21/76] fix circulation select --- custom_components/philips_airpurifier_coap/philips.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 9c6b7f8..7b5fcbe 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1520,6 +1520,7 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT] AVAILABLE_SWITCHES = [PhilipsApi.NEW2_CHILD_LOCK] + AVAILABLE_SELECTS = [PhilipsApi.NEW2_CIRCULATION] class PhilipsCX5120(PhilipsNew2GenericCoAPFan): From edeb5d73bc8778403526ae22b90f8b806ae5d0ab Mon Sep 17 00:00:00 2001 From: kongo09 Date: Tue, 16 Jan 2024 01:44:28 +0100 Subject: [PATCH 22/76] added oscillation for AMF --- .../philips_airpurifier_coap/__init__.py | 2 +- .../philips_airpurifier_coap/const.py | 22 +++ .../icons/pap/oscillate.svg | 4 + .../philips_airpurifier_coap/model.py | 13 ++ .../philips_airpurifier_coap/number.py | 126 ++++++++++++++++++ .../philips_airpurifier_coap/philips.py | 2 + 6 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 custom_components/philips_airpurifier_coap/icons/pap/oscillate.svg create mode 100644 custom_components/philips_airpurifier_coap/number.py diff --git a/custom_components/philips_airpurifier_coap/__init__.py b/custom_components/philips_airpurifier_coap/__init__.py index ac48208..51b8e60 100644 --- a/custom_components/philips_airpurifier_coap/__init__.py +++ b/custom_components/philips_airpurifier_coap/__init__.py @@ -32,7 +32,7 @@ _LOGGER = logging.getLogger(__name__) -PLATFORMS = ["fan", "sensor", "switch", "light", "select"] +PLATFORMS = ["fan", "sensor", "switch", "light", "select", "number"] # icons code thanks to Thomas Loven: diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 4416fe3..bac3351 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -24,6 +24,7 @@ from .model import ( FilterDescription, LightDescription, + NumberDescription, SelectDescription, SensorDescription, SwitchDescription, @@ -69,6 +70,7 @@ class ICON(StrEnum): CLEAN = "pap:clean" MODE = "pap:mode" ROTATE = "pap:rotate" + OSCILLATE = "pap:oscillate" DATA_EXTRA_MODULE_URL = "frontend_extra_module_url" @@ -232,6 +234,12 @@ class FanAttributes(StrEnum): RSSI = "rssi" SWING = "swing" TURBO = "turbo" + OSCILLATION = "oscillation" + VALUE_LIST = "value_list" + OFF = "off" + MIN = "min" + MAX = "max" + STEP = "step" class FanUnits(StrEnum): @@ -336,6 +344,7 @@ class PhilipsApi: NEW2_FAN_SPEED = "D0310D" NEW2_SWING = "D0320F" NEW2_CIRCULATION = "D0310A" + NEW2_OSCILLATION = "D0320F" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -681,3 +690,16 @@ class PhilipsApi: OPTIONS: PhilipsApi.CIRCULATION_MAP, }, } + +NUMBER_TYPES: dict[str, NumberDescription] = { + PhilipsApi.NEW2_OSCILLATION: { + FanAttributes.LABEL: FanAttributes.OSCILLATION, + ATTR_ICON: ICON.OSCILLATE, + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + FanAttributes.UNIT: "°", + FanAttributes.OFF: 0, + FanAttributes.MIN: 45, + FanAttributes.MAX: 350, + FanAttributes.STEP: 5, + } +} diff --git a/custom_components/philips_airpurifier_coap/icons/pap/oscillate.svg b/custom_components/philips_airpurifier_coap/icons/pap/oscillate.svg new file mode 100644 index 0000000..ca7f6d3 --- /dev/null +++ b/custom_components/philips_airpurifier_coap/icons/pap/oscillate.svg @@ -0,0 +1,4 @@ + + + + diff --git a/custom_components/philips_airpurifier_coap/model.py b/custom_components/philips_airpurifier_coap/model.py index 069cefc..b43a0f4 100644 --- a/custom_components/philips_airpurifier_coap/model.py +++ b/custom_components/philips_airpurifier_coap/model.py @@ -65,3 +65,16 @@ class SelectDescription(TypedDict): label: str entity_category: str options: dict[Any, tuple[str, str]] + + +class NumberDescription(TypedDict): + """Number class.""" + + icon: str + label: str + entity_category: str + unit: str + off: int + min: int + max: int + step: int diff --git a/custom_components/philips_airpurifier_coap/number.py b/custom_components/philips_airpurifier_coap/number.py new file mode 100644 index 0000000..c7ba878 --- /dev/null +++ b/custom_components/philips_airpurifier_coap/number.py @@ -0,0 +1,126 @@ +"""Philips Air Purifier & Humidifier Numbers.""" +from __future__ import annotations + +from collections.abc import Callable +import logging +from typing import Any + +from homeassistant.components.number import NumberEntity +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ( + ATTR_DEVICE_CLASS, + ATTR_ICON, + CONF_ENTITY_CATEGORY, + CONF_HOST, + CONF_NAME, +) +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import PlatformNotReady +from homeassistant.helpers.entity import Entity + +from .const import ( + CONF_MODEL, + DATA_KEY_COORDINATOR, + DOMAIN, + NUMBER_TYPES, + FanAttributes, + PhilipsApi, +) +from .philips import Coordinator, PhilipsEntity, model_to_class + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: ConfigEntry, + async_add_entities: Callable[[list[Entity], bool], None], +) -> None: + """Set up the number platform.""" + _LOGGER.debug("async_setup_entry called for platform number") + + host = entry.data[CONF_HOST] + model = entry.data[CONF_MODEL] + name = entry.data[CONF_NAME] + + data = hass.data[DOMAIN][host] + + coordinator = data[DATA_KEY_COORDINATOR] + + model_class = model_to_class.get(model) + if model_class: + available_numbers = [] + + for cls in reversed(model_class.__mro__): + cls_available_numbers = getattr(cls, "AVAILABLE_NUMBERS", []) + available_numbers.extend(cls_available_numbers) + + numbers = [] + + for number in NUMBER_TYPES: + if number in available_numbers: + numbers.append(PhilipsNumber(coordinator, name, model, number)) + + async_add_entities(numbers, update_before_add=False) + + else: + _LOGGER.error("Unsupported model: %s", model) + return + + +class PhilipsNumber(PhilipsEntity, NumberEntity): + """Define a Philips AirPurifier number.""" + + def __init__( # noqa: D107 + self, coordinator: Coordinator, name: str, model: str, number: str + ) -> None: + super().__init__(coordinator) + self._model = model + self._description = NUMBER_TYPES[number] + self._attr_device_class = self._description.get(ATTR_DEVICE_CLASS) + label = FanAttributes.LABEL + label = label.partition("#")[0] + self._attr_name = f"{name} {self._description[label].replace('_', ' ').title()}" + self._attr_entity_category = self._description.get(CONF_ENTITY_CATEGORY) + self._attr_icon = self._description.get(ATTR_ICON) + self._attr_mode = "slider" # hardwired for now + self._attr_unit_of_measurement = self._description.get(FanAttributes.UNIT) + + self._attr_min = self._description.get(FanAttributes.OFF) + self._min = self._description.get(FanAttributes.MIN) + self._attr_max = self._description.get(FanAttributes.MAX) + self._attr_step = self._description.get(FanAttributes.STEP) + + try: + device_id = self._device_status[PhilipsApi.DEVICE_ID] + self._attr_unique_id = f"{self._model}-{device_id}-{number.lower()}" + except Exception as e: + _LOGGER.error("Failed retrieving unique_id: %s", e) + raise PlatformNotReady + self._attrs: dict[str, Any] = {} + self.kind = number + + @property + def native_value(self) -> float | None: + """Return the current number.""" + value = self._device_status.get(self.kind) + return value + + async def async_set_native_value(self, value: float) -> None: + """Select a number.""" + + _LOGGER.debug("async_set_native_value called with: %s", value) + + # Catch the boundaries + if value is None or value < 0: + value = 0 + if value % self._attr_step > 0: + value = value // self._attr_step * self._attr_step + if value > 0 and value < self._min: + value = self._min + if value > self._attr_max: + value = self._attr_max + + _LOGGER.debug("setting number with: %s", value) + + await self.coordinator.client.set_control_value(self.kind, int(value)) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 7b5fcbe..f408bc2 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -283,6 +283,7 @@ class PhilipsGenericCoAPFanBase(PhilipsGenericFan): AVAILABLE_ATTRIBUTES = [] AVAILABLE_SWITCHES = [] AVAILABLE_LIGHTS = [] + AVAILABLE_NUMBERS = [] KEY_PHILIPS_POWER = PhilipsApi.POWER STATE_POWER_ON = "1" @@ -1521,6 +1522,7 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT] AVAILABLE_SWITCHES = [PhilipsApi.NEW2_CHILD_LOCK] AVAILABLE_SELECTS = [PhilipsApi.NEW2_CIRCULATION] + AVAILABLE_NUMBERS = [PhilipsApi.NEW2_OSCILLATION] class PhilipsCX5120(PhilipsNew2GenericCoAPFan): From c0ce7354ee84be8445ab23cd17c371715e626b8c Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 17 Jan 2024 00:58:22 +0100 Subject: [PATCH 23/76] exclude unavailable sensor from CX --- .../philips_airpurifier_coap/philips.py | 1 + .../philips_airpurifier_coap/sensor.py | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index f408bc2..efc3dcd 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1530,6 +1530,7 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT2] AVAILABLE_SWITCHES = [PhilipsApi.NEW2_SWING] + UNAVAILABLE_SENSORS = [PhilipsApi.NEW2_FAN_SPEED] model_to_class = { diff --git a/custom_components/philips_airpurifier_coap/sensor.py b/custom_components/philips_airpurifier_coap/sensor.py index 5709a42..ca05c88 100644 --- a/custom_components/philips_airpurifier_coap/sensor.py +++ b/custom_components/philips_airpurifier_coap/sensor.py @@ -51,19 +51,22 @@ async def async_setup_entry( # noqa: D103 coordinator = data[DATA_KEY_COORDINATOR] status = coordinator.status - sensors = [] - - for sensor in SENSOR_TYPES: - if sensor in status: - sensors.append(PhilipsSensor(coordinator, name, model, sensor)) - model_class = model_to_class.get(model) unavailable_filters = [] + unavailable_sensors = [] if model_class: for cls in reversed(model_class.__mro__): cls_unavailable_filters = getattr(cls, "UNAVAILABLE_FILTERS", []) unavailable_filters.extend(cls_unavailable_filters) + cls_unavailable_sensors = getattr(cls, "UNAVAILABLE_SENSORS", []) + unavailable_sensors.extend(cls_unavailable_sensors) + + sensors = [] + + for sensor in SENSOR_TYPES: + if sensor in status and sensor not in unavailable_sensors: + sensors.append(PhilipsSensor(coordinator, name, model, sensor)) for _filter in FILTER_TYPES: if _filter in status and _filter not in unavailable_filters: From 37c722c115a165b09fec9901fc776c2ea3963f8b Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 17 Jan 2024 01:09:01 +0100 Subject: [PATCH 24/76] fix wording of circulation option --- custom_components/philips_airpurifier_coap/const.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index bac3351..8e3f62f 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -364,8 +364,8 @@ class PhilipsApi: "PH": ("Purification and Humidification", ICON.TWO_IN_ONE_MODE), } CIRCULATION_MAP = { - "1": ("Purification", ICON.CLEAN), - "2": ("Circulation", ICON.CIRCULATE), + "1": ("Fan", ICON.CLEAN), + "3": ("Circulation", ICON.CIRCULATE), } HUMIDITY_TARGET_MAP = { 40: ("40%", ICON.HUMIDITY_BUTTON), From 78e74c62f1e82e56f8251dd865cdb5bcc22ea475 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 17 Jan 2024 01:20:59 +0100 Subject: [PATCH 25/76] fix circulation setting --- custom_components/philips_airpurifier_coap/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 8e3f62f..e5e5849 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -365,7 +365,7 @@ class PhilipsApi: } CIRCULATION_MAP = { "1": ("Fan", ICON.CLEAN), - "3": ("Circulation", ICON.CIRCULATE), + "2": ("Circulation", ICON.CIRCULATE), } HUMIDITY_TARGET_MAP = { 40: ("40%", ICON.HUMIDITY_BUTTON), From a8f5adc0562ecc12512a91b68e5b3734f0184ca0 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 17 Jan 2024 01:24:47 +0100 Subject: [PATCH 26/76] fix number slider --- .../philips_airpurifier_coap/number.py | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/number.py b/custom_components/philips_airpurifier_coap/number.py index c7ba878..f3b5c9b 100644 --- a/custom_components/philips_airpurifier_coap/number.py +++ b/custom_components/philips_airpurifier_coap/number.py @@ -84,12 +84,14 @@ def __init__( # noqa: D107 self._attr_entity_category = self._description.get(CONF_ENTITY_CATEGORY) self._attr_icon = self._description.get(ATTR_ICON) self._attr_mode = "slider" # hardwired for now - self._attr_unit_of_measurement = self._description.get(FanAttributes.UNIT) + self._attr_native_unit_of_measurement = self._description.get( + FanAttributes.UNIT + ) - self._attr_min = self._description.get(FanAttributes.OFF) + self._attr_native_min = self._description.get(FanAttributes.OFF) self._min = self._description.get(FanAttributes.MIN) - self._attr_max = self._description.get(FanAttributes.MAX) - self._attr_step = self._description.get(FanAttributes.STEP) + self._attr_native_max = self._description.get(FanAttributes.MAX) + self._attr_native_step = self._description.get(FanAttributes.STEP) try: device_id = self._device_status[PhilipsApi.DEVICE_ID] @@ -112,14 +114,14 @@ async def async_set_native_value(self, value: float) -> None: _LOGGER.debug("async_set_native_value called with: %s", value) # Catch the boundaries - if value is None or value < 0: - value = 0 - if value % self._attr_step > 0: - value = value // self._attr_step * self._attr_step + if value is None or value < self._attr_native_min: + value = self._attr_native_min + if value % self._attr_native_step > 0: + value = value // self._attr_native_step * self._attr_native_step if value > 0 and value < self._min: value = self._min - if value > self._attr_max: - value = self._attr_max + if value > self._attr_native_max: + value = self._attr_native_max _LOGGER.debug("setting number with: %s", value) From 438725578338275c430fc7df88b58b654253d792 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 17 Jan 2024 23:43:14 +0100 Subject: [PATCH 27/76] add beep switch --- custom_components/philips_airpurifier_coap/philips.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index efc3dcd..33485e5 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1520,7 +1520,7 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): """AMF765.""" AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT] - AVAILABLE_SWITCHES = [PhilipsApi.NEW2_CHILD_LOCK] + AVAILABLE_SWITCHES = [PhilipsApi.NEW2_CHILD_LOCK, PhilipsApi.NEW2_BEEP] AVAILABLE_SELECTS = [PhilipsApi.NEW2_CIRCULATION] AVAILABLE_NUMBERS = [PhilipsApi.NEW2_OSCILLATION] @@ -1529,7 +1529,7 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): """CX5120.""" AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT2] - AVAILABLE_SWITCHES = [PhilipsApi.NEW2_SWING] + AVAILABLE_SWITCHES = [PhilipsApi.NEW2_SWING, PhilipsApi.NEW2_BEEP] UNAVAILABLE_SENSORS = [PhilipsApi.NEW2_FAN_SPEED] From ce16d167ee0f78efc5876adb5571e2948550c322 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 17 Jan 2024 23:57:18 +0100 Subject: [PATCH 28/76] add modes for CX --- .../philips_airpurifier_coap/const.py | 5 +++ .../philips_airpurifier_coap/philips.py | 35 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index e5e5849..3c52cf0 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -142,6 +142,9 @@ class PresetMode: TURBO = "turbo" GAS = "gas" POLLUTION = "pollution" + LOW = "low" + HIGH = "high" + VENTILATION = "ventilation" ICON_MAP = { ALLERGEN: ICON.ALLERGEN_MODE, @@ -345,6 +348,8 @@ class PhilipsApi: NEW2_SWING = "D0320F" NEW2_CIRCULATION = "D0310A" NEW2_OSCILLATION = "D0320F" + NEW2_MODE_A = "D0310A" + NEW2_MODE_B = "D0310C" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 33485e5..46b4d41 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1528,6 +1528,41 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): class PhilipsCX5120(PhilipsNew2GenericCoAPFan): """CX5120.""" + AVAILABLE_PRESET_MODES = { + PresetMode.AUTO: { + PhilipsApi.NEW2_POWER: 1, + PhilipsApi.NEW2_MODE_A: 3, + PhilipsApi.NEW2_MODE_B: 0, + }, + PresetMode.HIGH: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_A: 3, + PhilipsApi.NEW2_MODE_B: 65, + }, + PresetMode.LOW: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_A: 3, + PhilipsApi.NEW2_MODE_B: 66, + }, + PresetMode.VENTILATION: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_A: 1, + PhilipsApi.NEW2_MODE_B: -127, + }, + } + AVAILABLE_SPEEDS = { + PresetMode.HIGH: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_A: 3, + PhilipsApi.NEW2_MODE_B: 65, + }, + PresetMode.LOW: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_A: 3, + PhilipsApi.NEW2_MODE_B: 66, + }, + } + AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT2] AVAILABLE_SWITCHES = [PhilipsApi.NEW2_SWING, PhilipsApi.NEW2_BEEP] UNAVAILABLE_SENSORS = [PhilipsApi.NEW2_FAN_SPEED] From c9b3ad2dcca94ca4c298e59dc85eb12fff1cf62a Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 18 Jan 2024 00:28:05 +0100 Subject: [PATCH 29/76] add timer for CX --- .../philips_airpurifier_coap/const.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 3c52cf0..d0042a1 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -243,6 +243,7 @@ class FanAttributes(StrEnum): MIN = "min" MAX = "max" STEP = "step" + TIMER = "timer" class FanUnits(StrEnum): @@ -350,6 +351,7 @@ class PhilipsApi: NEW2_OSCILLATION = "D0320F" NEW2_MODE_A = "D0310A" NEW2_MODE_B = "D0310C" + NEW2_TIMER = "D03110" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -372,6 +374,21 @@ class PhilipsApi: "1": ("Fan", ICON.CLEAN), "2": ("Circulation", ICON.CIRCULATE), } + TIMER_MAP = { + 0: ("Off", "mdi:clock-plus"), + 2: ("1h", "mdi:clock-time-one"), + 3: ("2h", "mdi:clock-time-two"), + 4: ("3h", "mdi:clock-time-three"), + 5: ("4h", "mdi:clock-time-four"), + 6: ("5h", "mdi:clock-time-five"), + 7: ("6h", "mdi:clock-time-six"), + 8: ("7h", "mdi:clock-time-seven"), + 9: ("8h", "mdi:clock-time-eight"), + 10: ("9h", "mdi:clock-time-nine"), + 11: ("10h", "mdi:clock-time-ten"), + 12: ("11h", "mdi:clock-time-eleven"), + 13: ("12h", "mdi:clock-time-twelve"), + } HUMIDITY_TARGET_MAP = { 40: ("40%", ICON.HUMIDITY_BUTTON), 50: ("50%", ICON.HUMIDITY_BUTTON), @@ -694,6 +711,11 @@ class PhilipsApi: CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, OPTIONS: PhilipsApi.CIRCULATION_MAP, }, + PhilipsApi.NEW2_TIMER: { + FanAttributes.LABEL: FanAttributes.TIMER, + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + OPTIONS: PhilipsApi.TIMER_MAP, + }, } NUMBER_TYPES: dict[str, NumberDescription] = { From b5499b5aaa77e64e3d7ab16473be37e5a177c89e Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 18 Jan 2024 00:35:12 +0100 Subject: [PATCH 30/76] add missing select for CX --- custom_components/philips_airpurifier_coap/philips.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 46b4d41..501e03b 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1566,6 +1566,7 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT2] AVAILABLE_SWITCHES = [PhilipsApi.NEW2_SWING, PhilipsApi.NEW2_BEEP] UNAVAILABLE_SENSORS = [PhilipsApi.NEW2_FAN_SPEED] + AVAILABLE_SELECTS = [PhilipsApi.NEW2_TIMER] model_to_class = { From af79edd30edc06a6d839bc744eb3ddc1397cce18 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 18 Jan 2024 00:42:06 +0100 Subject: [PATCH 31/76] add target temp for CX --- .../philips_airpurifier_coap/const.py | 14 +++++++++++++- .../philips_airpurifier_coap/philips.py | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index d0042a1..d3e2d98 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -244,6 +244,7 @@ class FanAttributes(StrEnum): MAX = "max" STEP = "step" TIMER = "timer" + TARGET_TEMP = "target_temperature" class FanUnits(StrEnum): @@ -352,6 +353,7 @@ class PhilipsApi: NEW2_MODE_A = "D0310A" NEW2_MODE_B = "D0310C" NEW2_TIMER = "D03110" + NEW2_TARGET_TEMP = "D0310E" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -728,5 +730,15 @@ class PhilipsApi: FanAttributes.MIN: 45, FanAttributes.MAX: 350, FanAttributes.STEP: 5, - } + }, + PhilipsApi.NEW2_TARGET_TEMP: { + FanAttributes.LABEL: FanAttributes.TARGET_TEMP, + ATTR_ICON: "mdi:thermometer", + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + FanAttributes.UNIT: "°", + FanAttributes.OFF: 1, + FanAttributes.MIN: 1, + FanAttributes.MAX: 37, + FanAttributes.STEP: 1, + }, } diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 501e03b..ddeca08 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1567,6 +1567,7 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): AVAILABLE_SWITCHES = [PhilipsApi.NEW2_SWING, PhilipsApi.NEW2_BEEP] UNAVAILABLE_SENSORS = [PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_SELECTS = [PhilipsApi.NEW2_TIMER] + AVAILABLE_NUMBERS = [PhilipsApi.NEW2_TARGET_TEMP] model_to_class = { From ffeabf3247654baa6b5ce624d94406da77c84295 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 18 Jan 2024 21:53:21 +0100 Subject: [PATCH 32/76] change string to int for function --- custom_components/philips_airpurifier_coap/const.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index d3e2d98..cbc5a24 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -373,8 +373,8 @@ class PhilipsApi: "PH": ("Purification and Humidification", ICON.TWO_IN_ONE_MODE), } CIRCULATION_MAP = { - "1": ("Fan", ICON.CLEAN), - "2": ("Circulation", ICON.CIRCULATE), + 1: ("Fan", ICON.CLEAN), + 2: ("Circulation", ICON.CIRCULATE), } TIMER_MAP = { 0: ("Off", "mdi:clock-plus"), From ed3c8aa2b1299fdf57543c95314c2002c3e97018 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 18 Jan 2024 22:54:05 +0100 Subject: [PATCH 33/76] speed and presets for AMF --- .../philips_airpurifier_coap/const.py | 7 +++ .../philips_airpurifier_coap/philips.py | 61 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index cbc5a24..1ca2d6f 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -131,6 +131,13 @@ class PresetMode: SPEED_GENTLE_1 = "gentle/speed 1" SPEED_2 = "speed 2" SPEED_3 = "speed 3" + SPEED_4 = "speed 4" + SPEED_5 = "speed 5" + SPEED_6 = "speed 6" + SPEED_7 = "speed 7" + SPEED_8 = "spped 8" + SPEED_9 = "spped 9" + SPEED_10 = "speed 10" ALLERGEN = "allergen" AUTO = "auto" AUTO_GENERAL = "auto general" diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index ddeca08..35d739e 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1519,6 +1519,67 @@ class PhilipsAC5659(PhilipsGenericCoAPFan): class PhilipsAMF765(PhilipsNew2GenericCoAPFan): """AMF765.""" + AVAILABLE_PRESET_MODES = { + PresetMode.AUTO: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 0, + }, + PresetMode.SLEEP: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 17, + }, + PresetMode.TURBO: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 18, + }, + } + AVAILABLE_SPEEDS = { + PresetMode.SPEED_1: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 1, + }, + PresetMode.SPEED_2: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 2, + }, + PresetMode.SPEED_3: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 3, + }, + PresetMode.SPEED_4: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 4, + }, + PresetMode.SPEED_5: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 5, + }, + PresetMode.SPEED_6: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 6, + }, + PresetMode.SPEED_7: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 7, + }, + PresetMode.SPEED_8: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 8, + }, + PresetMode.SPEED_9: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 9, + }, + PresetMode.SPEED_10: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 10, + }, + PresetMode.TURBO: { + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 18, + }, + } + AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT] AVAILABLE_SWITCHES = [PhilipsApi.NEW2_CHILD_LOCK, PhilipsApi.NEW2_BEEP] AVAILABLE_SELECTS = [PhilipsApi.NEW2_CIRCULATION] From 872cd1cb021b9cee4ab681757d2ee7dc05096b60 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 18 Jan 2024 22:55:55 +0100 Subject: [PATCH 34/76] timer for AMF --- custom_components/philips_airpurifier_coap/const.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 1ca2d6f..ca5a433 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -385,6 +385,7 @@ class PhilipsApi: } TIMER_MAP = { 0: ("Off", "mdi:clock-plus"), + 1: ("0.5h", "mdi:clock-time-one"), 2: ("1h", "mdi:clock-time-one"), 3: ("2h", "mdi:clock-time-two"), 4: ("3h", "mdi:clock-time-three"), From af4d51ea5c7f0ca16c1363766e7711ecc06b6430 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 18 Jan 2024 22:57:43 +0100 Subject: [PATCH 35/76] timer for AMF --- custom_components/philips_airpurifier_coap/philips.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 35d739e..a699858 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1582,7 +1582,7 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT] AVAILABLE_SWITCHES = [PhilipsApi.NEW2_CHILD_LOCK, PhilipsApi.NEW2_BEEP] - AVAILABLE_SELECTS = [PhilipsApi.NEW2_CIRCULATION] + AVAILABLE_SELECTS = [PhilipsApi.NEW2_CIRCULATION, PhilipsApi.NEW2_TIMER] AVAILABLE_NUMBERS = [PhilipsApi.NEW2_OSCILLATION] From 910cacdff36b95752de151e6ccc91dea78b77b85 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 18 Jan 2024 23:02:09 +0100 Subject: [PATCH 36/76] add standby sensor switch for AMF --- custom_components/philips_airpurifier_coap/const.py | 8 ++++++++ custom_components/philips_airpurifier_coap/philips.py | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index ca5a433..907add6 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -252,6 +252,7 @@ class FanAttributes(StrEnum): STEP = "step" TIMER = "timer" TARGET_TEMP = "target_temperature" + STANDBY_SENSORS = "standby_sensors" class FanUnits(StrEnum): @@ -361,6 +362,7 @@ class PhilipsApi: NEW2_MODE_B = "D0310C" NEW2_TIMER = "D03110" NEW2_TARGET_TEMP = "D0310E" + NEW2_STANDBY_SENSORS = "D03134" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -642,6 +644,12 @@ class PhilipsApi: SWITCH_ON: 17920, SWITCH_OFF: 0, }, + PhilipsApi.NEW2_STANDBY_SENSORS: { + ATTR_ICON: "mdi:power-settings", + FanAttributes.LABEL: FanAttributes.STANDBY_SENSORS, + SWITCH_ON: 1, + SWITCH_OFF: 0, + }, } LIGHT_TYPES: dict[str, LightDescription] = { diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index a699858..6a9c36d 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1581,7 +1581,11 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): } AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT] - AVAILABLE_SWITCHES = [PhilipsApi.NEW2_CHILD_LOCK, PhilipsApi.NEW2_BEEP] + AVAILABLE_SWITCHES = [ + PhilipsApi.NEW2_CHILD_LOCK, + PhilipsApi.NEW2_BEEP, + PhilipsApi.NEW2_STANDBY_SENSORS, + ] AVAILABLE_SELECTS = [PhilipsApi.NEW2_CIRCULATION, PhilipsApi.NEW2_TIMER] AVAILABLE_NUMBERS = [PhilipsApi.NEW2_OSCILLATION] From b225bf2ae4648dc9f985c2ccb55f725a528bcfde Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 18 Jan 2024 23:12:50 +0100 Subject: [PATCH 37/76] add auto plus for AMF --- custom_components/philips_airpurifier_coap/const.py | 8 ++++++++ custom_components/philips_airpurifier_coap/philips.py | 1 + 2 files changed, 9 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 907add6..2a74cca 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -253,6 +253,7 @@ class FanAttributes(StrEnum): TIMER = "timer" TARGET_TEMP = "target_temperature" STANDBY_SENSORS = "standby_sensors" + AUTO_PLUS = "auto_plus" class FanUnits(StrEnum): @@ -363,6 +364,7 @@ class PhilipsApi: NEW2_TIMER = "D03110" NEW2_TARGET_TEMP = "D0310E" NEW2_STANDBY_SENSORS = "D03134" + NEW2_AUTO_PLUS_AI = "D03180" PREFERRED_INDEX_MAP = { "0": ("Indoor Allergen Index", ICON.IAI), @@ -650,6 +652,12 @@ class PhilipsApi: SWITCH_ON: 1, SWITCH_OFF: 0, }, + PhilipsApi.NEW2_AUTO_PLUS_AI: { + ATTR_ICON: "mdi:format-annotation-plus", + FanAttributes.LABEL: FanAttributes.AUTO_PLUS, + SWITCH_ON: 1, + SWITCH_OFF: 0, + }, } LIGHT_TYPES: dict[str, LightDescription] = { diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 6a9c36d..ee5a964 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1585,6 +1585,7 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): PhilipsApi.NEW2_CHILD_LOCK, PhilipsApi.NEW2_BEEP, PhilipsApi.NEW2_STANDBY_SENSORS, + PhilipsApi.NEW2_AUTO_PLUS_AI, ] AVAILABLE_SELECTS = [PhilipsApi.NEW2_CIRCULATION, PhilipsApi.NEW2_TIMER] AVAILABLE_NUMBERS = [PhilipsApi.NEW2_OSCILLATION] From 20ee14f75f55aabd8e34da6c4d44c06dfc16b9c4 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sat, 20 Jan 2024 17:53:34 +0100 Subject: [PATCH 38/76] fix timer for CX --- .../philips_airpurifier_coap/const.py | 20 +++++++++++++++++++ .../philips_airpurifier_coap/philips.py | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 2a74cca..37e14df 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -403,6 +403,21 @@ class PhilipsApi: 12: ("11h", "mdi:clock-time-eleven"), 13: ("12h", "mdi:clock-time-twelve"), } + TIMER2_MAP = { + 0: ("Off", "mdi:clock-plus"), + 2: ("1h", "mdi:clock-time-one"), + 3: ("2h", "mdi:clock-time-two"), + 4: ("3h", "mdi:clock-time-three"), + 5: ("4h", "mdi:clock-time-four"), + 6: ("5h", "mdi:clock-time-five"), + 7: ("6h", "mdi:clock-time-six"), + 8: ("7h", "mdi:clock-time-seven"), + 9: ("8h", "mdi:clock-time-eight"), + 10: ("9h", "mdi:clock-time-nine"), + 11: ("10h", "mdi:clock-time-ten"), + 12: ("11h", "mdi:clock-time-eleven"), + 13: ("12h", "mdi:clock-time-twelve"), + } HUMIDITY_TARGET_MAP = { 40: ("40%", ICON.HUMIDITY_BUTTON), 50: ("50%", ICON.HUMIDITY_BUTTON), @@ -742,6 +757,11 @@ class PhilipsApi: CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, OPTIONS: PhilipsApi.TIMER_MAP, }, + PhilipsApi.NEW2_TIMER2: { + FanAttributes.LABEL: FanAttributes.TIMER, + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + OPTIONS: PhilipsApi.TIMER2_MAP, + }, } NUMBER_TYPES: dict[str, NumberDescription] = { diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index ee5a964..46c1b1e 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1632,7 +1632,7 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT2] AVAILABLE_SWITCHES = [PhilipsApi.NEW2_SWING, PhilipsApi.NEW2_BEEP] UNAVAILABLE_SENSORS = [PhilipsApi.NEW2_FAN_SPEED] - AVAILABLE_SELECTS = [PhilipsApi.NEW2_TIMER] + AVAILABLE_SELECTS = [PhilipsApi.NEW2_TIMER2] AVAILABLE_NUMBERS = [PhilipsApi.NEW2_TARGET_TEMP] From 4964ae298acc1f8c155c0b7e3150b372ff0fc252 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sat, 20 Jan 2024 17:55:07 +0100 Subject: [PATCH 39/76] fix time for CX --- custom_components/philips_airpurifier_coap/const.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 37e14df..09aab45 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -362,6 +362,7 @@ class PhilipsApi: NEW2_MODE_A = "D0310A" NEW2_MODE_B = "D0310C" NEW2_TIMER = "D03110" + NEW2_TIMER2 = "D03110" NEW2_TARGET_TEMP = "D0310E" NEW2_STANDBY_SENSORS = "D03134" NEW2_AUTO_PLUS_AI = "D03180" From b225a4c8ce8a96cba6eb65d4e7882c7410c8994c Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sat, 20 Jan 2024 17:55:47 +0100 Subject: [PATCH 40/76] fix oscillation for AMF --- custom_components/philips_airpurifier_coap/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 09aab45..e470641 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -772,7 +772,7 @@ class PhilipsApi: CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, FanAttributes.UNIT: "°", FanAttributes.OFF: 0, - FanAttributes.MIN: 45, + FanAttributes.MIN: 30, FanAttributes.MAX: 350, FanAttributes.STEP: 5, }, From 8f79ab6d474f042df6afcf717ac8668151725f4f Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sat, 20 Jan 2024 18:57:41 +0100 Subject: [PATCH 41/76] remove speed sensor and change pm25 icon --- .../philips_airpurifier_coap/const.py | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index e470641..fda2803 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -63,9 +63,9 @@ class ICON(StrEnum): WATER_REFILL = "pap:water_refill" PREFILTER_CLEANING = "pap:prefilter_cleaning" PREFILTER_WICK_CLEANING = "pap:prefilter_wick_cleaning" - PM25 = "pap:pm25" + PM25 = "pap:pm25b" IAI = "pap:iai" - PM25B = "pap:pm25b" + # PM25B = "pap:pm25b" CIRCULATE = "pap:circulate" CLEAN = "pap:clean" MODE = "pap:mode" @@ -521,19 +521,19 @@ class PhilipsApi: ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, FanAttributes.UNIT: UnitOfTemperature.CELSIUS, }, - PhilipsApi.NEW2_FAN_SPEED: { - FanAttributes.ICON_MAP: { - 0: ICON.FAN_SPEED_BUTTON, - 1: ICON.SPEED_1, - 6: ICON.SPEED_2, - 18: ICON.SPEED_3, - }, - FanAttributes.VALUE: lambda value, _: value - if int(value) < 18 - else FanAttributes.TURBO, - FanAttributes.LABEL: FanAttributes.ACTUAL_FAN_SPEED, - ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, - }, + # PhilipsApi.NEW2_FAN_SPEED: { + # FanAttributes.ICON_MAP: { + # 0: ICON.FAN_SPEED_BUTTON, + # 1: ICON.SPEED_1, + # 6: ICON.SPEED_2, + # 18: ICON.SPEED_3, + # }, + # FanAttributes.VALUE: lambda value, _: value + # if int(value) < 18 + # else FanAttributes.TURBO, + # FanAttributes.LABEL: FanAttributes.ACTUAL_FAN_SPEED, + # ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + # }, # diagnostic information PhilipsApi.WATER_LEVEL: { FanAttributes.ICON_MAP: {0: ICON.WATER_REFILL, 10: "mdi:water"}, From 2519e4987033680f83a8a65d80156e4bee868fb0 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sat, 20 Jan 2024 18:57:58 +0100 Subject: [PATCH 42/76] fix speed setting for AMF --- custom_components/philips_airpurifier_coap/philips.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 46c1b1e..458bf8e 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -279,7 +279,9 @@ class PhilipsGenericCoAPFanBase(PhilipsGenericFan): """Class as basis to manage a generic Philips CoAP fan.""" AVAILABLE_PRESET_MODES = {} + REPLACE_PRESET = None AVAILABLE_SPEEDS = {} + REPLACE_SPEED = None AVAILABLE_ATTRIBUTES = [] AVAILABLE_SWITCHES = [] AVAILABLE_LIGHTS = [] @@ -386,6 +388,9 @@ def preset_mode(self) -> Optional[str]: """Return the selected preset mode.""" for preset_mode, status_pattern in self._available_preset_modes.items(): for k, v in status_pattern.items(): + # check if the speed sensor also used for presets is different from the setting field + if self.REPLACE_PRESET is not None and k == self.REPLACE_PRESET[0]: + k = self.REPLACE_PRESET[1] if self._device_status.get(k) != v: break else: @@ -407,6 +412,9 @@ def percentage(self) -> Optional[int]: """Return the speed percentages.""" for speed, status_pattern in self._available_speeds.items(): for k, v in status_pattern.items(): + # check if the speed sensor is different from the speed setting field + if self.REPLACE_SPEED is not None and k == self.REPLACE_SPEED[0]: + k = self.REPLACE_SPEED[1] if self._device_status.get(k) != v: break else: @@ -1519,6 +1527,7 @@ class PhilipsAC5659(PhilipsGenericCoAPFan): class PhilipsAMF765(PhilipsNew2GenericCoAPFan): """AMF765.""" + REPLACE_PRESET = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_PRESET_MODES = { PresetMode.AUTO: { PhilipsApi.POWER: 1, @@ -1533,6 +1542,7 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): PhilipsApi.NEW2_MODE_B: 18, }, } + REPLACE_SPEED = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_SPEEDS = { PresetMode.SPEED_1: { PhilipsApi.POWER: 1, From 5871c1c540df1f87c9e9a0bb3008ee7334a146ba Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sat, 20 Jan 2024 23:41:59 +0100 Subject: [PATCH 43/76] make osciallation a fan property --- .../philips_airpurifier_coap/const.py | 21 +++++++---- .../philips_airpurifier_coap/philips.py | 35 ++++++++++++++++++- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index fda2803..7e52be3 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -327,6 +327,11 @@ class PhilipsApi: SWITCH_OFF: "0", } + OSCILLATION_MAP = { + SWITCH_ON: 17920, + SWITCH_OFF: 0, + } + # the AC1715 seems to follow a new scheme, this should later be refactored NEW_NAME = "D01-03" NEW_MODEL_ID = "D01-05" @@ -655,13 +660,15 @@ class PhilipsApi: SWITCH_ON: 100, SWITCH_OFF: 0, }, - PhilipsApi.NEW2_SWING: { - ATTR_ICON: ICON.ROTATE, - FanAttributes.LABEL: FanAttributes.SWING, - CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, - SWITCH_ON: 17920, - SWITCH_OFF: 0, - }, + # Oscillation is part of the fan model, so the switch is removed here + # + # PhilipsApi.NEW2_SWING: { + # ATTR_ICON: ICON.ROTATE, + # FanAttributes.LABEL: FanAttributes.SWING, + # CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + # SWITCH_ON: 17920, + # SWITCH_OFF: 0, + # }, PhilipsApi.NEW2_STANDBY_SENSORS: { ATTR_ICON: "mdi:power-settings", FanAttributes.LABEL: FanAttributes.STANDBY_SENSORS, diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 458bf8e..6f42524 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -23,6 +23,7 @@ from .const import ( DOMAIN, ICON, + SWITCH_OFF, SWITCH_ON, FanAttributes, FanModel, @@ -291,6 +292,8 @@ class PhilipsGenericCoAPFanBase(PhilipsGenericFan): STATE_POWER_ON = "1" STATE_POWER_OFF = "0" + KEY_OSCILLATION = None + def __init__( # noqa: D107 self, coordinator: Coordinator, @@ -376,6 +379,8 @@ def supported_features(self) -> int: features = FanEntityFeature.PRESET_MODE if self._speeds: features |= FanEntityFeature.SET_SPEED + if self.KEY_OSCILLATION is not None: + features |= FanEntityFeature.OSCILLATE return features @property @@ -407,6 +412,31 @@ def speed_count(self) -> int: """Return the number of speed options.""" return len(self._speeds) + @property + def oscillating(self) -> bool | None: + """Return if the fan is oscillating.""" + if self.KEY_OSCILLATION is None: + return None + + key = next(iter(self.KEY_OSCILLATION)) + status = self._device_status.get(key) + on = self.KEY_OSCILLATION.get(key).get(SWITCH_ON) + return status is not None and status == on + + async def async_oscillate(self, oscillating: bool) -> None: + """Osciallate the fan.""" + if self.KEY_OSCILLATION is None: + return None + + key = next(iter(self.KEY_OSCILLATION)) + values = self.KEY_OSCILLATION.get(key) + on = values.get(SWITCH_ON) + off = values.get(SWITCH_OFF) + if oscillating: + await self.coordinator.client.set_control_value(key, on) + else: + await self.coordinator.client.set_control_value(key, off) + @property def percentage(self) -> Optional[int]: """Return the speed percentages.""" @@ -1638,9 +1668,12 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): PhilipsApi.NEW2_MODE_B: 66, }, } + KEY_OSCILLATION = { + PhilipsApi.NEW2_OSCILLATION: PhilipsApi.OSCILLATION_MAP, + } AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT2] - AVAILABLE_SWITCHES = [PhilipsApi.NEW2_SWING, PhilipsApi.NEW2_BEEP] + AVAILABLE_SWITCHES = [PhilipsApi.NEW2_BEEP] UNAVAILABLE_SENSORS = [PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_SELECTS = [PhilipsApi.NEW2_TIMER2] AVAILABLE_NUMBERS = [PhilipsApi.NEW2_TARGET_TEMP] From c8618ff4c211621f8ee35f3ff8c66d648f9dbc7f Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sat, 20 Jan 2024 23:54:34 +0100 Subject: [PATCH 44/76] prepare AMF870 --- custom_components/philips_airpurifier_coap/const.py | 2 +- custom_components/philips_airpurifier_coap/philips.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 7e52be3..86ecabf 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -17,7 +17,6 @@ PERCENTAGE, SIGNAL_STRENGTH_DECIBELS_MILLIWATT, UnitOfTemperature, - UnitOfTime, ) from homeassistant.helpers.entity import EntityCategory @@ -121,6 +120,7 @@ class FanModel(StrEnum): AC4558 = "AC4558" AC5659 = "AC5659" AMF765 = "AMF765" + AMF870 = "AMF870" CX5120 = "CX5120" diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 6f42524..0cc2e85 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1631,6 +1631,10 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): AVAILABLE_NUMBERS = [PhilipsApi.NEW2_OSCILLATION] +class PhilipsAMF870(PhilipsAMF765): + """AMF870.""" + + class PhilipsCX5120(PhilipsNew2GenericCoAPFan): """CX5120.""" @@ -1706,5 +1710,6 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): FanModel.AC4558: PhilipsAC4558, FanModel.AC5659: PhilipsAC5659, FanModel.AMF765: PhilipsAMF765, + FanModel.AMF870: PhilipsAMF870, FanModel.CX5120: PhilipsCX5120, } From 09ffbda37a7abf6576f62fb98d3a3402aca201db Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sat, 20 Jan 2024 23:55:48 +0100 Subject: [PATCH 45/76] start support for AMF870 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ce69d75..529a842 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ Note: `configuration.yaml` is no longer supported and your configuration is not - AC4558 - AC5659 - AMF765 +- AMF870 - CX5120 From 58d64a3e5d67a81758f5b79fe8b3049ae17e1b29 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 11:45:05 +0100 Subject: [PATCH 46/76] fix pm2.5 sensor for AMF --- custom_components/philips_airpurifier_coap/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 86ecabf..c5f5bc5 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -354,7 +354,7 @@ class PhilipsApi: NEW2_CHILD_LOCK = "D03103" NEW2_BEEP = "D03130" NEW2_INDOOR_ALLERGEN_INDEX = "D03120" - NEW2_PM25 = "D03121" + NEW2_PM25 = "D03221" NEW2_HUMIDITY = "D03125" NEW2_FILTER_NANOPROTECT_PREFILTER = "D0520D" NEW2_FILTER_NANOPROTECT = "D0540E" From 2d38799a1210704adf897916dd4f9500200b9d92 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 11:47:53 +0100 Subject: [PATCH 47/76] remove turbo from speed settings for AMF --- custom_components/philips_airpurifier_coap/philips.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 0cc2e85..0f0853d 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1614,10 +1614,10 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): PhilipsApi.POWER: 1, PhilipsApi.NEW2_MODE_B: 10, }, - PresetMode.TURBO: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 18, - }, + # PresetMode.TURBO: { + # PhilipsApi.POWER: 1, + # PhilipsApi.NEW2_MODE_B: 18, + # }, } AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT] From 5d37ce632852be64125ab7bfff855aa2b9508a78 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 11:51:51 +0100 Subject: [PATCH 48/76] try to fix speed and preset for AMF --- .../philips_airpurifier_coap/const.py | 1 + .../philips_airpurifier_coap/philips.py | 24 +++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index c5f5bc5..00f793a 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -366,6 +366,7 @@ class PhilipsApi: NEW2_OSCILLATION = "D0320F" NEW2_MODE_A = "D0310A" NEW2_MODE_B = "D0310C" + NEW2_MODE_C = "D0310D" NEW2_TIMER = "D03110" NEW2_TIMER2 = "D03110" NEW2_TARGET_TEMP = "D0310E" diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 0f0853d..ab21f25 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1557,7 +1557,7 @@ class PhilipsAC5659(PhilipsGenericCoAPFan): class PhilipsAMF765(PhilipsNew2GenericCoAPFan): """AMF765.""" - REPLACE_PRESET = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] + # REPLACE_PRESET = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_PRESET_MODES = { PresetMode.AUTO: { PhilipsApi.POWER: 1, @@ -1572,47 +1572,47 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): PhilipsApi.NEW2_MODE_B: 18, }, } - REPLACE_SPEED = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] + # REPLACE_SPEED = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_SPEEDS = { PresetMode.SPEED_1: { PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 1, + PhilipsApi.NEW2_MODE_C: 1, }, PresetMode.SPEED_2: { PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 2, + PhilipsApi.NEW2_MODE_C: 2, }, PresetMode.SPEED_3: { PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 3, + PhilipsApi.NEW2_MODE_C: 3, }, PresetMode.SPEED_4: { PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 4, + PhilipsApi.NEW2_MODE_C: 4, }, PresetMode.SPEED_5: { PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 5, + PhilipsApi.NEW2_MODE_C: 5, }, PresetMode.SPEED_6: { PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 6, + PhilipsApi.NEW2_MODE_C: 6, }, PresetMode.SPEED_7: { PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 7, + PhilipsApi.NEW2_MODE_C: 7, }, PresetMode.SPEED_8: { PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 8, + PhilipsApi.NEW2_MODE_C: 8, }, PresetMode.SPEED_9: { PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 9, + PhilipsApi.NEW2_MODE_C: 9, }, PresetMode.SPEED_10: { PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 10, + PhilipsApi.NEW2_MODE_C: 10, }, # PresetMode.TURBO: { # PhilipsApi.POWER: 1, From 4315385da731af37273e38a8d732ee6873b0e448 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 14:41:57 +0100 Subject: [PATCH 49/76] extend autodiscovery for AMF --- .../philips_airpurifier_coap/manifest.json | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/manifest.json b/custom_components/philips_airpurifier_coap/manifest.json index bac990c..44fd951 100644 --- a/custom_components/philips_airpurifier_coap/manifest.json +++ b/custom_components/philips_airpurifier_coap/manifest.json @@ -1,23 +1,26 @@ { - "domain": "philips_airpurifier_coap", - "name": "Philips AirPurifier (with CoAP)", - "codeowners": ["@kongo09"], - "config_flow": true, - "dependencies": ["frontend", "http"], - "dhcp": [ - { - "macaddress": "B0F893*" - }, - { - "macaddress": "047863*" - }, - { - "hostname": "mxchip*" - } - ], - "documentation": "https://github.com/kongo09/philips-airpurifier-coap", - "iot_class": "local_push", - "issue_tracker": "https://github.com/kongo09/philips-airpurifier-coap/issues", - "requirements": ["aioairctrl==0.2.5"], - "version": "0.10.9" + "domain": "philips_airpurifier_coap", + "name": "Philips AirPurifier (with CoAP)", + "codeowners": ["@kongo09"], + "config_flow": true, + "dependencies": ["frontend", "http"], + "dhcp": [ + { + "macaddress": "B0F893*" + }, + { + "macaddress": "047863*" + }, + { + "macaddress": "849DC2*" + }, + { + "hostname": "mxchip*" + } + ], + "documentation": "https://github.com/kongo09/philips-airpurifier-coap", + "iot_class": "local_push", + "issue_tracker": "https://github.com/kongo09/philips-airpurifier-coap/issues", + "requirements": ["aioairctrl==0.2.5"], + "version": "0.10.9" } From 19656fab0df40765226bc44347a1ff65b7a5cbea Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 19:57:44 +0100 Subject: [PATCH 50/76] add icons for heating and gas --- .../philips_airpurifier_coap/const.py | 22 ++++++++++++++----- .../icons/pap/gas.svg | 4 ++++ .../icons/pap/heating.svg | 4 ++++ .../philips_airpurifier_coap/philips.py | 2 ++ 4 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 custom_components/philips_airpurifier_coap/icons/pap/gas.svg create mode 100644 custom_components/philips_airpurifier_coap/icons/pap/heating.svg diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 00f793a..31b8272 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -70,6 +70,8 @@ class ICON(StrEnum): MODE = "pap:mode" ROTATE = "pap:rotate" OSCILLATE = "pap:oscillate" + GAS = "pap:gas" + HEATING = "pap:heating" DATA_EXTRA_MODULE_URL = "frontend_extra_module_url" @@ -355,6 +357,7 @@ class PhilipsApi: NEW2_BEEP = "D03130" NEW2_INDOOR_ALLERGEN_INDEX = "D03120" NEW2_PM25 = "D03221" + NEW2_GAS = "D03122" NEW2_HUMIDITY = "D03125" NEW2_FILTER_NANOPROTECT_PREFILTER = "D0520D" NEW2_FILTER_NANOPROTECT = "D0540E" @@ -372,15 +375,16 @@ class PhilipsApi: NEW2_TARGET_TEMP = "D0310E" NEW2_STANDBY_SENSORS = "D03134" NEW2_AUTO_PLUS_AI = "D03180" + NEW2_PREFERRED_INDEX = "D0312A" PREFERRED_INDEX_MAP = { - "0": ("Indoor Allergen Index", ICON.IAI), - "1": ("PM2.5", ICON.PM25), + 0: ("Indoor Allergen Index", ICON.IAI), + 1: ("PM2.5", ICON.PM25), } GAS_PREFERRED_INDEX_MAP = { - "0": ("Indoor Allergen Index", ICON.IAI), - "1": ("PM2.5", ICON.PM25), - "2": ("Gas", "mdi:air"), + 0: ("Indoor Allergen Index", ICON.IAI), + 1: ("PM2.5", ICON.PM25), + 2: ("Gas", ICON.GAS), } NEW_PREFERRED_INDEX_MAP = { "IAI": ("Indoor Allergen Index", ICON.IAI), @@ -483,6 +487,12 @@ class PhilipsApi: FanAttributes.UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, }, + PhilipsApi.NEW2_GAS: { + FanAttributes.ICON_MAP: {0: "mdi:air"}, + FanAttributes.LABEL: FanAttributes.PM25, + FanAttributes.UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, + ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + }, PhilipsApi.TOTAL_VOLATILE_ORGANIC_COMPOUNDS: { ATTR_DEVICE_CLASS: SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS, FanAttributes.ICON_MAP: {0: "mdi:blur"}, @@ -741,7 +751,7 @@ class PhilipsApi: CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, OPTIONS: PhilipsApi.PREFERRED_INDEX_MAP, }, - PhilipsApi.PREFERRED_INDEX: { + PhilipsApi.NEW2_PREFERRED_INDEX: { FanAttributes.LABEL: FanAttributes.PREFERRED_INDEX, CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, OPTIONS: PhilipsApi.PREFERRED_INDEX_MAP, diff --git a/custom_components/philips_airpurifier_coap/icons/pap/gas.svg b/custom_components/philips_airpurifier_coap/icons/pap/gas.svg new file mode 100644 index 0000000..1aa23ec --- /dev/null +++ b/custom_components/philips_airpurifier_coap/icons/pap/gas.svg @@ -0,0 +1,4 @@ + + + + diff --git a/custom_components/philips_airpurifier_coap/icons/pap/heating.svg b/custom_components/philips_airpurifier_coap/icons/pap/heating.svg new file mode 100644 index 0000000..d161a9e --- /dev/null +++ b/custom_components/philips_airpurifier_coap/icons/pap/heating.svg @@ -0,0 +1,4 @@ + + + + diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index ab21f25..4da1fe7 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1634,6 +1634,8 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): class PhilipsAMF870(PhilipsAMF765): """AMF870.""" + AVAILABLE_SELECTS = [PhilipsApi.NEW2_PREFERRED_INDEX] + class PhilipsCX5120(PhilipsNew2GenericCoAPFan): """CX5120.""" From 3deb12124bb95ab1b6aa30c9c6db9e270e849570 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 19:59:01 +0100 Subject: [PATCH 51/76] fix icon for gas sensor --- custom_components/philips_airpurifier_coap/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 31b8272..d96474d 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -488,7 +488,7 @@ class PhilipsApi: ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, }, PhilipsApi.NEW2_GAS: { - FanAttributes.ICON_MAP: {0: "mdi:air"}, + FanAttributes.ICON_MAP: {0: ICON.GAS}, FanAttributes.LABEL: FanAttributes.PM25, FanAttributes.UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, From 9102f8dcf6b9b7c17285fd59c2e0c9a57ac1c5a0 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 20:02:17 +0100 Subject: [PATCH 52/76] refactor AMF classes and introduce gas sensor --- .../philips_airpurifier_coap/philips.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 4da1fe7..b8f8760 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1554,8 +1554,8 @@ class PhilipsAC5659(PhilipsGenericCoAPFan): AVAILABLE_SELECTS = [PhilipsApi.PREFERRED_INDEX] -class PhilipsAMF765(PhilipsNew2GenericCoAPFan): - """AMF765.""" +class PhilipsAMFxxx(PhilipsNew2GenericCoAPFan): + """AMF family.""" # REPLACE_PRESET = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_PRESET_MODES = { @@ -1631,7 +1631,13 @@ class PhilipsAMF765(PhilipsNew2GenericCoAPFan): AVAILABLE_NUMBERS = [PhilipsApi.NEW2_OSCILLATION] -class PhilipsAMF870(PhilipsAMF765): +class PhilipsAMF765(PhilipsAMFxxx): + """AMF765.""" + + UNAVAILABLE_SENSORS = [PhilipsApi.NEW2_GAS] + + +class PhilipsAMF870(PhilipsAMFxxx): """AMF870.""" AVAILABLE_SELECTS = [PhilipsApi.NEW2_PREFERRED_INDEX] @@ -1680,7 +1686,7 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): AVAILABLE_LIGHTS = [PhilipsApi.NEW2_DISPLAY_BACKLIGHT2] AVAILABLE_SWITCHES = [PhilipsApi.NEW2_BEEP] - UNAVAILABLE_SENSORS = [PhilipsApi.NEW2_FAN_SPEED] + UNAVAILABLE_SENSORS = [PhilipsApi.NEW2_FAN_SPEED, PhilipsApi.NEW2_GAS] AVAILABLE_SELECTS = [PhilipsApi.NEW2_TIMER2] AVAILABLE_NUMBERS = [PhilipsApi.NEW2_TARGET_TEMP] From 9a4d1cdbb1223b20dac6feb28bfb530f315e3d01 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 20:19:36 +0100 Subject: [PATCH 53/76] fix timer and add gas sensor for AMF --- .../philips_airpurifier_coap/const.py | 16 +++++++++++----- .../philips_airpurifier_coap/philips.py | 5 ++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index d96474d..523a563 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -370,12 +370,13 @@ class PhilipsApi: NEW2_MODE_A = "D0310A" NEW2_MODE_B = "D0310C" NEW2_MODE_C = "D0310D" - NEW2_TIMER = "D03110" - NEW2_TIMER2 = "D03110" + NEW2_TIMER = "D03110#1" + NEW2_TIMER2 = "D03110#2" NEW2_TARGET_TEMP = "D0310E" NEW2_STANDBY_SENSORS = "D03134" NEW2_AUTO_PLUS_AI = "D03180" - NEW2_PREFERRED_INDEX = "D0312A" + NEW2_PREFERRED_INDEX = "D0312A#1" + NEW2_GAS_PREFERRED_INDEX = "D0312A#2" PREFERRED_INDEX_MAP = { 0: ("Indoor Allergen Index", ICON.IAI), @@ -751,6 +752,11 @@ class PhilipsApi: CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, OPTIONS: PhilipsApi.PREFERRED_INDEX_MAP, }, + PhilipsApi.NEW_PREFERRED_INDEX: { + FanAttributes.LABEL: FanAttributes.PREFERRED_INDEX, + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + OPTIONS: PhilipsApi.NEW_PREFERRED_INDEX_MAP, + }, PhilipsApi.NEW2_PREFERRED_INDEX: { FanAttributes.LABEL: FanAttributes.PREFERRED_INDEX, CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, @@ -761,10 +767,10 @@ class PhilipsApi: CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, OPTIONS: PhilipsApi.GAS_PREFERRED_INDEX_MAP, }, - PhilipsApi.NEW_PREFERRED_INDEX: { + PhilipsApi.NEW2_GAS_PREFERRED_INDEX: { FanAttributes.LABEL: FanAttributes.PREFERRED_INDEX, CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, - OPTIONS: PhilipsApi.NEW_PREFERRED_INDEX_MAP, + OPTIONS: PhilipsApi.GAS_PREFERRED_INDEX_MAP, }, PhilipsApi.NEW2_CIRCULATION: { FanAttributes.LABEL: FanAttributes.FUNCTION, diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index b8f8760..525e437 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1640,7 +1640,10 @@ class PhilipsAMF765(PhilipsAMFxxx): class PhilipsAMF870(PhilipsAMFxxx): """AMF870.""" - AVAILABLE_SELECTS = [PhilipsApi.NEW2_PREFERRED_INDEX] + AVAILABLE_SELECTS = [ + PhilipsApi.NEW2_PREFERRED_INDEX, + PhilipsApi.NEW2_GAS_PREFERRED_INDEX, + ] class PhilipsCX5120(PhilipsNew2GenericCoAPFan): From 82b9b41b82cbdf91acf51b409172bb68e00216e5 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 20:26:17 +0100 Subject: [PATCH 54/76] add heating function for AMF870 --- custom_components/philips_airpurifier_coap/const.py | 13 ++++++++++++- .../philips_airpurifier_coap/philips.py | 4 +++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 523a563..b36b427 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -365,7 +365,8 @@ class PhilipsApi: NEW2_FILTER_NANOPROTECT_TOTAL = "D05408" NEW2_FAN_SPEED = "D0310D" NEW2_SWING = "D0320F" - NEW2_CIRCULATION = "D0310A" + NEW2_CIRCULATION = "D0310A#1" + NEW2_HEATING = "D0310A#2" NEW2_OSCILLATION = "D0320F" NEW2_MODE_A = "D0310A" NEW2_MODE_B = "D0310C" @@ -399,6 +400,11 @@ class PhilipsApi: 1: ("Fan", ICON.CLEAN), 2: ("Circulation", ICON.CIRCULATE), } + HEATING_MAP = { + 1: ("Fan", ICON.CLEAN), + 2: ("Circulation", ICON.CIRCULATE), + 3: ("Heating", ICON.HEATING), + } TIMER_MAP = { 0: ("Off", "mdi:clock-plus"), 1: ("0.5h", "mdi:clock-time-one"), @@ -777,6 +783,11 @@ class PhilipsApi: CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, OPTIONS: PhilipsApi.CIRCULATION_MAP, }, + PhilipsApi.NEW2_HEATING: { + FanAttributes.LABEL: FanAttributes.FUNCTION, + CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, + OPTIONS: PhilipsApi.HEATING_MAP, + }, PhilipsApi.NEW2_TIMER: { FanAttributes.LABEL: FanAttributes.TIMER, CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 525e437..f06e406 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1627,13 +1627,14 @@ class PhilipsAMFxxx(PhilipsNew2GenericCoAPFan): PhilipsApi.NEW2_STANDBY_SENSORS, PhilipsApi.NEW2_AUTO_PLUS_AI, ] - AVAILABLE_SELECTS = [PhilipsApi.NEW2_CIRCULATION, PhilipsApi.NEW2_TIMER] + AVAILABLE_SELECTS = [PhilipsApi.NEW2_TIMER] AVAILABLE_NUMBERS = [PhilipsApi.NEW2_OSCILLATION] class PhilipsAMF765(PhilipsAMFxxx): """AMF765.""" + AVAILABLE_SELECTS = [PhilipsApi.NEW2_CIRCULATION] UNAVAILABLE_SENSORS = [PhilipsApi.NEW2_GAS] @@ -1643,6 +1644,7 @@ class PhilipsAMF870(PhilipsAMFxxx): AVAILABLE_SELECTS = [ PhilipsApi.NEW2_PREFERRED_INDEX, PhilipsApi.NEW2_GAS_PREFERRED_INDEX, + PhilipsApi.NEW2_HEATING, ] From ead88a81b5c153d3aeb0e69815941d6e4401091e Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 20:27:18 +0100 Subject: [PATCH 55/76] add target temp for AMF870 --- custom_components/philips_airpurifier_coap/philips.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index f06e406..ae0e901 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1646,6 +1646,7 @@ class PhilipsAMF870(PhilipsAMFxxx): PhilipsApi.NEW2_GAS_PREFERRED_INDEX, PhilipsApi.NEW2_HEATING, ] + AVAILABLE_NUMBERS = [PhilipsApi.NEW2_TARGET_TEMP] class PhilipsCX5120(PhilipsNew2GenericCoAPFan): From d677b9419e5fddf753d00ddc1f6b4ef14f9d81c2 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 20:29:15 +0100 Subject: [PATCH 56/76] add oscillation for AMF870 --- custom_components/philips_airpurifier_coap/philips.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index ae0e901..d478686 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1647,6 +1647,9 @@ class PhilipsAMF870(PhilipsAMFxxx): PhilipsApi.NEW2_HEATING, ] AVAILABLE_NUMBERS = [PhilipsApi.NEW2_TARGET_TEMP] + KEY_OSCILLATION = { + PhilipsApi.NEW2_OSCILLATION: PhilipsApi.OSCILLATION_MAP, + } class PhilipsCX5120(PhilipsNew2GenericCoAPFan): From e286a8b7ce02368f06b283457a0ed7f4ad0d8c5f Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 20:43:36 +0100 Subject: [PATCH 57/76] fix gas sensor label --- custom_components/philips_airpurifier_coap/const.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index b36b427..eb2ba86 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -230,6 +230,7 @@ class FanAttributes(StrEnum): MODEL_ID = "model_id" NAME = "name" PM25 = "PM2.5" + GAS = "gas_level" PREFERRED_INDEX = "preferred_index" PRODUCT_ID = "product_id" RUNTIME = "runtime" @@ -496,7 +497,7 @@ class PhilipsApi: }, PhilipsApi.NEW2_GAS: { FanAttributes.ICON_MAP: {0: ICON.GAS}, - FanAttributes.LABEL: FanAttributes.PM25, + FanAttributes.LABEL: FanAttributes.GAS, FanAttributes.UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, }, From 41f1e8820236767a468b63b0559b65e1cac56b72 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 20:47:47 +0100 Subject: [PATCH 58/76] remove wrong oscillation for AMF870 --- custom_components/philips_airpurifier_coap/philips.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index d478686..ae0e901 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1647,9 +1647,6 @@ class PhilipsAMF870(PhilipsAMFxxx): PhilipsApi.NEW2_HEATING, ] AVAILABLE_NUMBERS = [PhilipsApi.NEW2_TARGET_TEMP] - KEY_OSCILLATION = { - PhilipsApi.NEW2_OSCILLATION: PhilipsApi.OSCILLATION_MAP, - } class PhilipsCX5120(PhilipsNew2GenericCoAPFan): From ad5b740f819405781091afabbf7d6c396defecfa Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 21:36:55 +0100 Subject: [PATCH 59/76] add preferred index attribute --- .../philips_airpurifier_coap/philips.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index ae0e901..051f58f 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -450,6 +450,8 @@ def percentage(self) -> Optional[int]: else: return ordered_list_item_to_percentage(self._speeds, speed) + return None + async def async_set_percentage(self, percentage: int) -> None: """Return the selected speed percentage.""" if percentage == 0: @@ -600,11 +602,11 @@ class PhilipsNew2GenericCoAPFan(PhilipsGenericCoAPFanBase): # (FanAttributes.ERROR_CODE, PhilipsApi.ERROR_CODE), # (FanAttributes.ERROR, PhilipsApi.ERROR_CODE, PhilipsApi.ERROR_CODE_MAP), # device configuration - # ( - # FanAttributes.PREFERRED_INDEX, - # PhilipsApi.NEW_PREFERRED_INDEX, - # PhilipsApi.NEW_PREFERRED_INDEX_MAP, - # ), + ( + FanAttributes.PREFERRED_INDEX, + PhilipsApi.NEW2_GAS_PREFERRED_INDEX, + PhilipsApi.GAS_PREFERRED_INDEX_MAP, + ), # device sensors ( FanAttributes.RUNTIME, From 9e4c7f0fdb397acd3b8104ea730f075cd711f9ae Mon Sep 17 00:00:00 2001 From: kongo09 Date: Sun, 21 Jan 2024 22:11:07 +0100 Subject: [PATCH 60/76] try to fix presets and speed for AMF --- .../philips_airpurifier_coap/philips.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 051f58f..3217ee6 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1564,56 +1564,69 @@ class PhilipsAMFxxx(PhilipsNew2GenericCoAPFan): PresetMode.AUTO: { PhilipsApi.POWER: 1, PhilipsApi.NEW2_MODE_B: 0, + PhilipsApi.NEW2_MODE_C: 3, }, PresetMode.SLEEP: { PhilipsApi.POWER: 1, PhilipsApi.NEW2_MODE_B: 17, + PhilipsApi.NEW2_MODE_C: 1, }, PresetMode.TURBO: { PhilipsApi.POWER: 1, PhilipsApi.NEW2_MODE_B: 18, + PhilipsApi.NEW2_MODE_C: 18, }, } # REPLACE_SPEED = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_SPEEDS = { PresetMode.SPEED_1: { PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 1, PhilipsApi.NEW2_MODE_C: 1, }, PresetMode.SPEED_2: { PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 2, PhilipsApi.NEW2_MODE_C: 2, }, PresetMode.SPEED_3: { PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 3, PhilipsApi.NEW2_MODE_C: 3, }, PresetMode.SPEED_4: { PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 4, PhilipsApi.NEW2_MODE_C: 4, }, PresetMode.SPEED_5: { PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 5, PhilipsApi.NEW2_MODE_C: 5, }, PresetMode.SPEED_6: { PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 6, PhilipsApi.NEW2_MODE_C: 6, }, PresetMode.SPEED_7: { PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 7, PhilipsApi.NEW2_MODE_C: 7, }, PresetMode.SPEED_8: { PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 8, PhilipsApi.NEW2_MODE_C: 8, }, PresetMode.SPEED_9: { PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 9, PhilipsApi.NEW2_MODE_C: 9, }, PresetMode.SPEED_10: { PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 10, PhilipsApi.NEW2_MODE_C: 10, }, # PresetMode.TURBO: { From 84e54ecadac96f0c38d6ac44fbcd82d6371dcc64 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 22 Jan 2024 18:57:59 +0100 Subject: [PATCH 61/76] fix units of gas sensor --- custom_components/philips_airpurifier_coap/const.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index eb2ba86..6fbd278 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -498,7 +498,6 @@ class PhilipsApi: PhilipsApi.NEW2_GAS: { FanAttributes.ICON_MAP: {0: ICON.GAS}, FanAttributes.LABEL: FanAttributes.GAS, - FanAttributes.UNIT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, }, PhilipsApi.TOTAL_VOLATILE_ORGANIC_COMPOUNDS: { From 304f0e62ad8551703671bc5514becae7dfc0060f Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 22 Jan 2024 19:01:45 +0100 Subject: [PATCH 62/76] remove extra preferred index --- custom_components/philips_airpurifier_coap/philips.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 3217ee6..2715627 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1657,7 +1657,6 @@ class PhilipsAMF870(PhilipsAMFxxx): """AMF870.""" AVAILABLE_SELECTS = [ - PhilipsApi.NEW2_PREFERRED_INDEX, PhilipsApi.NEW2_GAS_PREFERRED_INDEX, PhilipsApi.NEW2_HEATING, ] From 518cad71a0c1572b2e38aa26764b0f09ed068329 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 22 Jan 2024 19:21:28 +0100 Subject: [PATCH 63/76] change ints to str in attempt to fix presets, speed and swing --- custom_components/philips_airpurifier_coap/const.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 6fbd278..062e5a9 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -331,8 +331,8 @@ class PhilipsApi: } OSCILLATION_MAP = { - SWITCH_ON: 17920, - SWITCH_OFF: 0, + SWITCH_ON: "17920", + SWITCH_OFF: "0", } # the AC1715 seems to follow a new scheme, this should later be refactored From 24a2bfd3c6801cccde98190154234ae5e66794f3 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 22 Jan 2024 19:22:02 +0100 Subject: [PATCH 64/76] change ints to str in an attempt to fix presets, speed and swing --- .../philips_airpurifier_coap/philips.py | 114 +++++++++--------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 2715627..ba01ec6 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1562,72 +1562,72 @@ class PhilipsAMFxxx(PhilipsNew2GenericCoAPFan): # REPLACE_PRESET = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_PRESET_MODES = { PresetMode.AUTO: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 0, - PhilipsApi.NEW2_MODE_C: 3, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "0", + PhilipsApi.NEW2_MODE_C: "3", }, PresetMode.SLEEP: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 17, - PhilipsApi.NEW2_MODE_C: 1, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "17", + PhilipsApi.NEW2_MODE_C: "1", }, PresetMode.TURBO: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 18, - PhilipsApi.NEW2_MODE_C: 18, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "18", + PhilipsApi.NEW2_MODE_C: "18", }, } # REPLACE_SPEED = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_SPEEDS = { PresetMode.SPEED_1: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 1, - PhilipsApi.NEW2_MODE_C: 1, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "1", + PhilipsApi.NEW2_MODE_C: "1", }, PresetMode.SPEED_2: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 2, - PhilipsApi.NEW2_MODE_C: 2, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "2", + PhilipsApi.NEW2_MODE_C: "2", }, PresetMode.SPEED_3: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 3, - PhilipsApi.NEW2_MODE_C: 3, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "3", + PhilipsApi.NEW2_MODE_C: "3", }, PresetMode.SPEED_4: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 4, - PhilipsApi.NEW2_MODE_C: 4, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "4", + PhilipsApi.NEW2_MODE_C: "4", }, PresetMode.SPEED_5: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 5, - PhilipsApi.NEW2_MODE_C: 5, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "5", + PhilipsApi.NEW2_MODE_C: "5", }, PresetMode.SPEED_6: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 6, - PhilipsApi.NEW2_MODE_C: 6, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "6", + PhilipsApi.NEW2_MODE_C: "6", }, PresetMode.SPEED_7: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 7, - PhilipsApi.NEW2_MODE_C: 7, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "7", + PhilipsApi.NEW2_MODE_C: "7", }, PresetMode.SPEED_8: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 8, - PhilipsApi.NEW2_MODE_C: 8, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "8", + PhilipsApi.NEW2_MODE_C: "8", }, PresetMode.SPEED_9: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 9, - PhilipsApi.NEW2_MODE_C: 9, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "9", + PhilipsApi.NEW2_MODE_C: "9", }, PresetMode.SPEED_10: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_B: 10, - PhilipsApi.NEW2_MODE_C: 10, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_B: "10", + PhilipsApi.NEW2_MODE_C: "10", }, # PresetMode.TURBO: { # PhilipsApi.POWER: 1, @@ -1668,36 +1668,36 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): AVAILABLE_PRESET_MODES = { PresetMode.AUTO: { - PhilipsApi.NEW2_POWER: 1, - PhilipsApi.NEW2_MODE_A: 3, - PhilipsApi.NEW2_MODE_B: 0, + PhilipsApi.NEW2_POWER: "1", + PhilipsApi.NEW2_MODE_A: "3", + PhilipsApi.NEW2_MODE_B: "0", }, PresetMode.HIGH: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_A: 3, - PhilipsApi.NEW2_MODE_B: 65, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_A: "3", + PhilipsApi.NEW2_MODE_B: "65", }, PresetMode.LOW: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_A: 3, - PhilipsApi.NEW2_MODE_B: 66, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_A: "3", + PhilipsApi.NEW2_MODE_B: "66", }, PresetMode.VENTILATION: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_A: 1, - PhilipsApi.NEW2_MODE_B: -127, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_A: "1", + PhilipsApi.NEW2_MODE_B: "-127", }, } AVAILABLE_SPEEDS = { PresetMode.HIGH: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_A: 3, - PhilipsApi.NEW2_MODE_B: 65, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_A: "3", + PhilipsApi.NEW2_MODE_B: "65", }, PresetMode.LOW: { - PhilipsApi.POWER: 1, - PhilipsApi.NEW2_MODE_A: 3, - PhilipsApi.NEW2_MODE_B: 66, + PhilipsApi.POWER: "1", + PhilipsApi.NEW2_MODE_A: "3", + PhilipsApi.NEW2_MODE_B: "66", }, } KEY_OSCILLATION = { From f925a35a133b1e8ba5417cc56a8dd4a014c1b59a Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 22 Jan 2024 19:49:51 +0100 Subject: [PATCH 65/76] fix temperature unit --- custom_components/philips_airpurifier_coap/const.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 062e5a9..566cc92 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -3,6 +3,7 @@ from enum import StrEnum +from homeassistant.components.number.const import NumberDeviceClass from homeassistant.components.sensor import ( ATTR_STATE_CLASS, SensorDeviceClass, @@ -815,7 +816,8 @@ class PhilipsApi: FanAttributes.LABEL: FanAttributes.TARGET_TEMP, ATTR_ICON: "mdi:thermometer", CONF_ENTITY_CATEGORY: EntityCategory.CONFIG, - FanAttributes.UNIT: "°", + ATTR_DEVICE_CLASS: NumberDeviceClass.TEMPERATURE, + FanAttributes.UNIT: "°C", FanAttributes.OFF: 1, FanAttributes.MIN: 1, FanAttributes.MAX: 37, From cfac2413ba95998fdea5df30e61c4973e9a466c2 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 22 Jan 2024 19:51:50 +0100 Subject: [PATCH 66/76] fix number ranges --- custom_components/philips_airpurifier_coap/number.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/number.py b/custom_components/philips_airpurifier_coap/number.py index f3b5c9b..2ee11a8 100644 --- a/custom_components/philips_airpurifier_coap/number.py +++ b/custom_components/philips_airpurifier_coap/number.py @@ -88,9 +88,9 @@ def __init__( # noqa: D107 FanAttributes.UNIT ) - self._attr_native_min = self._description.get(FanAttributes.OFF) + self._attr_native_min_value = self._description.get(FanAttributes.OFF) self._min = self._description.get(FanAttributes.MIN) - self._attr_native_max = self._description.get(FanAttributes.MAX) + self._attr_native_max_value = self._description.get(FanAttributes.MAX) self._attr_native_step = self._description.get(FanAttributes.STEP) try: @@ -114,14 +114,14 @@ async def async_set_native_value(self, value: float) -> None: _LOGGER.debug("async_set_native_value called with: %s", value) # Catch the boundaries - if value is None or value < self._attr_native_min: - value = self._attr_native_min + if value is None or value < self._attr_native_min_value: + value = self._attr_native_min_value if value % self._attr_native_step > 0: value = value // self._attr_native_step * self._attr_native_step if value > 0 and value < self._min: value = self._min - if value > self._attr_native_max: - value = self._attr_native_max + if value > self._attr_native_max_value: + value = self._attr_native_max_value _LOGGER.debug("setting number with: %s", value) From e34f2b63f4f3a5963ffba1419fff09eb788fd3e4 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 22 Jan 2024 19:57:05 +0100 Subject: [PATCH 67/76] fix import --- custom_components/philips_airpurifier_coap/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 566cc92..5038f87 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -3,7 +3,7 @@ from enum import StrEnum -from homeassistant.components.number.const import NumberDeviceClass +from homeassistant.components.number import NumberDeviceClass from homeassistant.components.sensor import ( ATTR_STATE_CLASS, SensorDeviceClass, From a73be34a79d154addfcd5253773c184765a1f284 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 22 Jan 2024 20:23:29 +0100 Subject: [PATCH 68/76] revert ints and introduce debugging --- .../philips_airpurifier_coap/philips.py | 93 +++++++++++-------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index ba01ec6..df3c7ba 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -391,16 +391,29 @@ def preset_modes(self) -> Optional[list[str]]: @property def preset_mode(self) -> Optional[str]: """Return the selected preset mode.""" + _LOGGER.debug("fan %s preset mode requested", self._attr_name) for preset_mode, status_pattern in self._available_preset_modes.items(): + _LOGGER.debug( + " testing preset mode '%s' with status pattern: %s", + preset_mode, + status_pattern, + ) for k, v in status_pattern.items(): + _LOGGER.debug(" checking key, value pair: %s - %s", k, v) # check if the speed sensor also used for presets is different from the setting field if self.REPLACE_PRESET is not None and k == self.REPLACE_PRESET[0]: k = self.REPLACE_PRESET[1] - if self._device_status.get(k) != v: + status = self._device_status.get(k) + _LOGGER.debug(" status is: %s", status) + if status != v: + _LOGGER.debug(" status doesn't match value, stop trying") break else: + _LOGGER.debug(" found preset mode: %s", preset_mode) return preset_mode + _LOGGER.debug(" nothing found, sorry") + async def async_set_preset_mode(self, preset_mode: str) -> None: """Set the preset mode of the fan.""" status_pattern = self._available_preset_modes.get(preset_mode) @@ -1562,72 +1575,72 @@ class PhilipsAMFxxx(PhilipsNew2GenericCoAPFan): # REPLACE_PRESET = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_PRESET_MODES = { PresetMode.AUTO: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "0", - PhilipsApi.NEW2_MODE_C: "3", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 0, + PhilipsApi.NEW2_MODE_C: 3, }, PresetMode.SLEEP: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "17", - PhilipsApi.NEW2_MODE_C: "1", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 17, + PhilipsApi.NEW2_MODE_C: 1, }, PresetMode.TURBO: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "18", - PhilipsApi.NEW2_MODE_C: "18", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 18, + PhilipsApi.NEW2_MODE_C: 18, }, } # REPLACE_SPEED = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_SPEEDS = { PresetMode.SPEED_1: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "1", - PhilipsApi.NEW2_MODE_C: "1", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 1, + PhilipsApi.NEW2_MODE_C: 1, }, PresetMode.SPEED_2: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "2", - PhilipsApi.NEW2_MODE_C: "2", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 2, + PhilipsApi.NEW2_MODE_C: 2, }, PresetMode.SPEED_3: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "3", - PhilipsApi.NEW2_MODE_C: "3", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 3, + PhilipsApi.NEW2_MODE_C: 3, }, PresetMode.SPEED_4: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "4", - PhilipsApi.NEW2_MODE_C: "4", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 4, + PhilipsApi.NEW2_MODE_C: 4, }, PresetMode.SPEED_5: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "5", - PhilipsApi.NEW2_MODE_C: "5", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 5, + PhilipsApi.NEW2_MODE_C: 5, }, PresetMode.SPEED_6: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "6", - PhilipsApi.NEW2_MODE_C: "6", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 6, + PhilipsApi.NEW2_MODE_C: 6, }, PresetMode.SPEED_7: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "7", - PhilipsApi.NEW2_MODE_C: "7", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 7, + PhilipsApi.NEW2_MODE_C: 7, }, PresetMode.SPEED_8: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "8", - PhilipsApi.NEW2_MODE_C: "8", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 8, + PhilipsApi.NEW2_MODE_C: 8, }, PresetMode.SPEED_9: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "9", - PhilipsApi.NEW2_MODE_C: "9", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 9, + PhilipsApi.NEW2_MODE_C: 9, }, PresetMode.SPEED_10: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_B: "10", - PhilipsApi.NEW2_MODE_C: "10", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_B: 10, + PhilipsApi.NEW2_MODE_C: 10, }, # PresetMode.TURBO: { # PhilipsApi.POWER: 1, From f9deb9b5edf3b37215e9ca1b530eed9da3ffe60d Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 22 Jan 2024 20:44:30 +0100 Subject: [PATCH 69/76] introduce more debugging --- custom_components/philips_airpurifier_coap/philips.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index df3c7ba..4559726 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -391,7 +391,7 @@ def preset_modes(self) -> Optional[list[str]]: @property def preset_mode(self) -> Optional[str]: """Return the selected preset mode.""" - _LOGGER.debug("fan %s preset mode requested", self._attr_name) + _LOGGER.debug("fan %s preset mode requested", self._name) for preset_mode, status_pattern in self._available_preset_modes.items(): _LOGGER.debug( " testing preset mode '%s' with status pattern: %s", @@ -400,14 +400,17 @@ def preset_mode(self) -> Optional[str]: ) for k, v in status_pattern.items(): _LOGGER.debug(" checking key, value pair: %s - %s", k, v) + _LOGGER.debug(" value is of type: %s", type(v)) # check if the speed sensor also used for presets is different from the setting field if self.REPLACE_PRESET is not None and k == self.REPLACE_PRESET[0]: k = self.REPLACE_PRESET[1] status = self._device_status.get(k) _LOGGER.debug(" status is: %s", status) + _LOGGER.debug(" status is of type: %s", type(status)) if status != v: _LOGGER.debug(" status doesn't match value, stop trying") break + _LOGGER.debug(" match!") else: _LOGGER.debug(" found preset mode: %s", preset_mode) return preset_mode From 10e5aaab88eaafa3d351026aed24948530cadf61 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 22 Jan 2024 21:37:03 +0100 Subject: [PATCH 70/76] fix power key --- .../philips_airpurifier_coap/philips.py | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 4559726..40c6a12 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1578,17 +1578,17 @@ class PhilipsAMFxxx(PhilipsNew2GenericCoAPFan): # REPLACE_PRESET = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_PRESET_MODES = { PresetMode.AUTO: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 0, PhilipsApi.NEW2_MODE_C: 3, }, PresetMode.SLEEP: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 17, PhilipsApi.NEW2_MODE_C: 1, }, PresetMode.TURBO: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 18, PhilipsApi.NEW2_MODE_C: 18, }, @@ -1596,57 +1596,57 @@ class PhilipsAMFxxx(PhilipsNew2GenericCoAPFan): # REPLACE_SPEED = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_SPEEDS = { PresetMode.SPEED_1: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 1, PhilipsApi.NEW2_MODE_C: 1, }, PresetMode.SPEED_2: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 2, PhilipsApi.NEW2_MODE_C: 2, }, PresetMode.SPEED_3: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 3, PhilipsApi.NEW2_MODE_C: 3, }, PresetMode.SPEED_4: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 4, PhilipsApi.NEW2_MODE_C: 4, }, PresetMode.SPEED_5: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 5, PhilipsApi.NEW2_MODE_C: 5, }, PresetMode.SPEED_6: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 6, PhilipsApi.NEW2_MODE_C: 6, }, PresetMode.SPEED_7: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 7, PhilipsApi.NEW2_MODE_C: 7, }, PresetMode.SPEED_8: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 8, PhilipsApi.NEW2_MODE_C: 8, }, PresetMode.SPEED_9: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 9, PhilipsApi.NEW2_MODE_C: 9, }, PresetMode.SPEED_10: { - PhilipsApi.POWER: 1, + PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 10, PhilipsApi.NEW2_MODE_C: 10, }, # PresetMode.TURBO: { - # PhilipsApi.POWER: 1, + # PhilipsApi.NEW2_POWER: 1, # PhilipsApi.NEW2_MODE_B: 18, # }, } From 1e8cc8fec5d5871e395c44817d1ca7a47256c3e0 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Mon, 22 Jan 2024 23:33:57 +0100 Subject: [PATCH 71/76] only try to set/read first register and consider auto+ --- .../philips_airpurifier_coap/const.py | 13 ++++---- .../philips_airpurifier_coap/philips.py | 33 +++++++++++-------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 5038f87..8939215 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -144,6 +144,7 @@ class PresetMode: ALLERGEN = "allergen" AUTO = "auto" AUTO_GENERAL = "auto general" + AUTO_PLUS = "auto+" BACTERIA = "bacteria" GENTLE = "gentle" NIGHT = "night" @@ -694,12 +695,12 @@ class PhilipsApi: SWITCH_ON: 1, SWITCH_OFF: 0, }, - PhilipsApi.NEW2_AUTO_PLUS_AI: { - ATTR_ICON: "mdi:format-annotation-plus", - FanAttributes.LABEL: FanAttributes.AUTO_PLUS, - SWITCH_ON: 1, - SWITCH_OFF: 0, - }, + # PhilipsApi.NEW2_AUTO_PLUS_AI: { + # ATTR_ICON: "mdi:format-annotation-plus", + # FanAttributes.LABEL: FanAttributes.AUTO_PLUS, + # SWITCH_ON: 1, + # SWITCH_OFF: 0, + # }, } LIGHT_TYPES: dict[str, LightDescription] = { diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 40c6a12..bd272cc 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1577,20 +1577,27 @@ class PhilipsAMFxxx(PhilipsNew2GenericCoAPFan): # REPLACE_PRESET = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_PRESET_MODES = { + PresetMode.AUTO_PLUS: { + PhilipsApi.NEW2_POWER: 1, + PhilipsApi.NEW2_MODE_B: 0, + PhilipsApi.NEW2_AUTO_PLUS_AI: 1, + # PhilipsApi.NEW2_MODE_C: 3, + }, PresetMode.AUTO: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 0, - PhilipsApi.NEW2_MODE_C: 3, + PhilipsApi.NEW2_AUTO_PLUS_AI: 0, + # PhilipsApi.NEW2_MODE_C: 3, }, PresetMode.SLEEP: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 17, - PhilipsApi.NEW2_MODE_C: 1, + # PhilipsApi.NEW2_MODE_C: 1, }, PresetMode.TURBO: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 18, - PhilipsApi.NEW2_MODE_C: 18, + # PhilipsApi.NEW2_MODE_C: 18, }, } # REPLACE_SPEED = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] @@ -1598,52 +1605,52 @@ class PhilipsAMFxxx(PhilipsNew2GenericCoAPFan): PresetMode.SPEED_1: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 1, - PhilipsApi.NEW2_MODE_C: 1, + # PhilipsApi.NEW2_MODE_C: 1, }, PresetMode.SPEED_2: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 2, - PhilipsApi.NEW2_MODE_C: 2, + # PhilipsApi.NEW2_MODE_C: 2, }, PresetMode.SPEED_3: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 3, - PhilipsApi.NEW2_MODE_C: 3, + # PhilipsApi.NEW2_MODE_C: 3, }, PresetMode.SPEED_4: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 4, - PhilipsApi.NEW2_MODE_C: 4, + # PhilipsApi.NEW2_MODE_C: 4, }, PresetMode.SPEED_5: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 5, - PhilipsApi.NEW2_MODE_C: 5, + # PhilipsApi.NEW2_MODE_C: 5, }, PresetMode.SPEED_6: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 6, - PhilipsApi.NEW2_MODE_C: 6, + # PhilipsApi.NEW2_MODE_C: 6, }, PresetMode.SPEED_7: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 7, - PhilipsApi.NEW2_MODE_C: 7, + # PhilipsApi.NEW2_MODE_C: 7, }, PresetMode.SPEED_8: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 8, - PhilipsApi.NEW2_MODE_C: 8, + # PhilipsApi.NEW2_MODE_C: 8, }, PresetMode.SPEED_9: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 9, - PhilipsApi.NEW2_MODE_C: 9, + # PhilipsApi.NEW2_MODE_C: 9, }, PresetMode.SPEED_10: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 10, - PhilipsApi.NEW2_MODE_C: 10, + # PhilipsApi.NEW2_MODE_C: 10, }, # PresetMode.TURBO: { # PhilipsApi.NEW2_POWER: 1, From 821aaa61dcfd72dce9d7f33d2d0cddc0b280d96f Mon Sep 17 00:00:00 2001 From: kongo09 Date: Tue, 23 Jan 2024 21:54:52 +0000 Subject: [PATCH 72/76] re-enable Auto+ switch and remove from preset --- .../philips_airpurifier_coap/const.py | 12 ++++++------ .../philips_airpurifier_coap/philips.py | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 8939215..607d08a 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -695,12 +695,12 @@ class PhilipsApi: SWITCH_ON: 1, SWITCH_OFF: 0, }, - # PhilipsApi.NEW2_AUTO_PLUS_AI: { - # ATTR_ICON: "mdi:format-annotation-plus", - # FanAttributes.LABEL: FanAttributes.AUTO_PLUS, - # SWITCH_ON: 1, - # SWITCH_OFF: 0, - # }, + PhilipsApi.NEW2_AUTO_PLUS_AI: { + ATTR_ICON: "mdi:format-annotation-plus", + FanAttributes.LABEL: FanAttributes.AUTO_PLUS, + SWITCH_ON: 1, + SWITCH_OFF: 0, + }, } LIGHT_TYPES: dict[str, LightDescription] = { diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index bd272cc..40530d4 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1577,16 +1577,16 @@ class PhilipsAMFxxx(PhilipsNew2GenericCoAPFan): # REPLACE_PRESET = [PhilipsApi.NEW2_MODE_B, PhilipsApi.NEW2_FAN_SPEED] AVAILABLE_PRESET_MODES = { - PresetMode.AUTO_PLUS: { - PhilipsApi.NEW2_POWER: 1, - PhilipsApi.NEW2_MODE_B: 0, - PhilipsApi.NEW2_AUTO_PLUS_AI: 1, - # PhilipsApi.NEW2_MODE_C: 3, - }, + # PresetMode.AUTO_PLUS: { + # PhilipsApi.NEW2_POWER: 1, + # PhilipsApi.NEW2_MODE_B: 0, + # PhilipsApi.NEW2_AUTO_PLUS_AI: 1, + # # PhilipsApi.NEW2_MODE_C: 3, + # }, PresetMode.AUTO: { PhilipsApi.NEW2_POWER: 1, PhilipsApi.NEW2_MODE_B: 0, - PhilipsApi.NEW2_AUTO_PLUS_AI: 0, + # PhilipsApi.NEW2_AUTO_PLUS_AI: 0, # PhilipsApi.NEW2_MODE_C: 3, }, PresetMode.SLEEP: { From 6568b82ed85d5b7eb2ca2537797c47e819db39a3 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Wed, 24 Jan 2024 13:32:51 +0000 Subject: [PATCH 73/76] remove debug output --- .../philips_airpurifier_coap/philips.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index 40530d4..dd1607e 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -391,32 +391,17 @@ def preset_modes(self) -> Optional[list[str]]: @property def preset_mode(self) -> Optional[str]: """Return the selected preset mode.""" - _LOGGER.debug("fan %s preset mode requested", self._name) for preset_mode, status_pattern in self._available_preset_modes.items(): - _LOGGER.debug( - " testing preset mode '%s' with status pattern: %s", - preset_mode, - status_pattern, - ) for k, v in status_pattern.items(): - _LOGGER.debug(" checking key, value pair: %s - %s", k, v) - _LOGGER.debug(" value is of type: %s", type(v)) # check if the speed sensor also used for presets is different from the setting field if self.REPLACE_PRESET is not None and k == self.REPLACE_PRESET[0]: k = self.REPLACE_PRESET[1] status = self._device_status.get(k) - _LOGGER.debug(" status is: %s", status) - _LOGGER.debug(" status is of type: %s", type(status)) if status != v: - _LOGGER.debug(" status doesn't match value, stop trying") break - _LOGGER.debug(" match!") else: - _LOGGER.debug(" found preset mode: %s", preset_mode) return preset_mode - _LOGGER.debug(" nothing found, sorry") - async def async_set_preset_mode(self, preset_mode: str) -> None: """Set the preset mode of the fan.""" status_pattern = self._available_preset_modes.get(preset_mode) From 306fb060501bb02108c72c1e0d76a6bd4e620f3d Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 25 Jan 2024 20:49:31 +0000 Subject: [PATCH 74/76] fix speeds and presets for CX family --- .../philips_airpurifier_coap/philips.py | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index f178779..cbcf80d 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1675,36 +1675,36 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): AVAILABLE_PRESET_MODES = { PresetMode.AUTO: { - PhilipsApi.NEW2_POWER: "1", - PhilipsApi.NEW2_MODE_A: "3", - PhilipsApi.NEW2_MODE_B: "0", + PhilipsApi.NEW2_POWER: 1, + PhilipsApi.NEW2_MODE_A: 3, + PhilipsApi.NEW2_MODE_B: 0, }, PresetMode.HIGH: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_A: "3", - PhilipsApi.NEW2_MODE_B: "65", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_A: 3, + PhilipsApi.NEW2_MODE_B: 65, }, PresetMode.LOW: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_A: "3", - PhilipsApi.NEW2_MODE_B: "66", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_A: 3, + PhilipsApi.NEW2_MODE_B: 66, }, PresetMode.VENTILATION: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_A: "1", - PhilipsApi.NEW2_MODE_B: "-127", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_A: 1, + PhilipsApi.NEW2_MODE_B: -127, }, } AVAILABLE_SPEEDS = { PresetMode.HIGH: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_A: "3", - PhilipsApi.NEW2_MODE_B: "65", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_A: 3, + PhilipsApi.NEW2_MODE_B: 65, }, PresetMode.LOW: { - PhilipsApi.POWER: "1", - PhilipsApi.NEW2_MODE_A: "3", - PhilipsApi.NEW2_MODE_B: "66", + PhilipsApi.POWER: 1, + PhilipsApi.NEW2_MODE_A: 3, + PhilipsApi.NEW2_MODE_B: 66, }, } KEY_OSCILLATION = { From 88ec17dd6cbd0ca62b03b3a65e89156c55c2be5a Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 25 Jan 2024 20:55:09 +0000 Subject: [PATCH 75/76] support AC3858/86 --- README.md | 1 + custom_components/philips_airpurifier_coap/const.py | 1 + custom_components/philips_airpurifier_coap/philips.py | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/README.md b/README.md index 529a842..9df8717 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ Note: `configuration.yaml` is no longer supported and your configuration is not - AC3854/51 - AC3858/50 - AC3858/51 +- AC3858/86 - AC4236 - AC4550 - AC4558 diff --git a/custom_components/philips_airpurifier_coap/const.py b/custom_components/philips_airpurifier_coap/const.py index 14116f2..e894310 100644 --- a/custom_components/philips_airpurifier_coap/const.py +++ b/custom_components/philips_airpurifier_coap/const.py @@ -118,6 +118,7 @@ class FanModel(StrEnum): AC3854_51 = "AC3854/51" AC3858_50 = "AC3858/50" AC3858_51 = "AC3858/51" + AC3858_86 = "AC3858/86" AC4236 = "AC4236" AC4550 = "AC4550" AC4558 = "AC4558" diff --git a/custom_components/philips_airpurifier_coap/philips.py b/custom_components/philips_airpurifier_coap/philips.py index cbcf80d..ae6f9fc 100644 --- a/custom_components/philips_airpurifier_coap/philips.py +++ b/custom_components/philips_airpurifier_coap/philips.py @@ -1398,6 +1398,10 @@ class PhilipsAC385851(PhilipsAC385x51): """AC3858/51.""" +class PhilipsAC385886(PhilipsAC385x51): + """AC3858/86.""" + + class PhilipsAC4236(PhilipsGenericCoAPFan): """AC4236.""" @@ -1740,6 +1744,7 @@ class PhilipsCX5120(PhilipsNew2GenericCoAPFan): FanModel.AC3854_51: PhilipsAC385451, FanModel.AC3858_50: PhilipsAC385850, FanModel.AC3858_51: PhilipsAC385851, + FanModel.AC3858_86: PhilipsAC385886, FanModel.AC4236: PhilipsAC4236, FanModel.AC4550: PhilipsAC4550, FanModel.AC4558: PhilipsAC4558, From 0e7b904ddf5857b885fcbfeb47f071c16de500b9 Mon Sep 17 00:00:00 2001 From: kongo09 Date: Thu, 25 Jan 2024 21:02:38 +0000 Subject: [PATCH 76/76] update icons --- README.md | 62 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 9df8717..f37acd1 100644 --- a/README.md +++ b/README.md @@ -174,31 +174,41 @@ The `fan` entity has some additional attributes not captured with sensors. Speci The integration also provides the original Philips icons for your use in the frontend. The icons can be accessed with the prefix `pap:` and should be visible in the icon picker. Credit for this part of the code goes to @thomasloven -![Preview](./custom_components/philips_airpurifier_coap/icons/pap/power_button.svg) power_button
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/child_lock_button.svg) child_lock_button
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/auto_mode_button.svg) auto_mode_button
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/fan_speed_button.svg) fan_speed_button
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/humidity_button.svg) humidity_button
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/light_dimming_button.svg) light_dimming_button
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/two_in_one_mode_button.svg) two_in_one_mode_button
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/timer_reset_button.svg) timer_reset_button
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/sleep_mode.svg) sleep_mode
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/auto_mode.svg) auto_mode
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/speed_1.svg) speed_1
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/speed_2.svg) speed_2
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/speed_3.svg) speed_3
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/allergen_mode.svg) allergen_mode
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/purification_only_mode.svg) purification_only_mode
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/two_in_one_mode.svg) two_in_one_mode
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/bacteria_virus_mode.svg) bacteria_virus_mode
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/nanoprotect_filter.svg) nanoprotect_filter
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/filter_replacement.svg) filter_replacement
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/water_refill.svg) water_refill
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/prefilter_cleaning.svg) prefilter_clearning
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/prefilter_wick_cleaning.svg) prefilter_wick_cleaning
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/pm25.svg) pm25
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/iai.svg) iai
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/wifi.svg) wifi
-![Preview](./custom_components/philips_airpurifier_coap/icons/pap/reset.svg) reset
+| icon | name | +|------------------------------------------------------------------------------------------------|-------------------------| +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/power_button.svg) | power_button | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/child_lock_button.svg) | child_lock_button | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/auto_mode_button.svg) | auto_mode_button | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/fan_speed_button.svg) | fan_speed_button | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/humidity_button.svg) | humidity_button | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/light_dimming_button.svg) | light_dimming_button | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/two_in_one_mode_button.svg) | two_in_one_mode_button | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/timer_reset_button.svg) | timer_reset_button | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/sleep_mode.svg) | sleep_mode | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/auto_mode.svg) | auto_mode | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/speed_1.svg) | speed_1 | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/speed_2.svg) | speed_2 | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/speed_3.svg) | speed_3 | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/allergen_mode.svg) | allergen_mode | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/purification_only_mode.svg) | purification_only_mode | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/two_in_one_mode.svg) | two_in_one_mode | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/bacteria_virus_mode.svg) | bacteria_virus_mode | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/nanoprotect_filter.svg) | nanoprotect_filter | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/filter_replacement.svg) | filter_replacement | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/water_refill.svg) | water_refill | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/prefilter_cleaning.svg) | prefilter_clearning | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/prefilter_wick_cleaning.svg) | prefilter_wick_cleaning | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/pm25.svg) | pm25 | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/iai.svg) | iai | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/wifi.svg) | wifi | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/reset.svg) | reset | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/circulate.svg) | circulate | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/clean.svg) | clean | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/mode.svg) | mode | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/pm25b.svg) | pm25b | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/rotate.svg) | rotate | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/oscillate.svg) | oscillate | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/heating.svg) | heating | +| ![Preview](./custom_components/philips_airpurifier_coap/icons/pap/gas.svg) | gas | Note: you might have to clear your browser cache after installation to see the icons.