home-assistant / architecture

Repo to discuss Home Assistant architecture
310 stars 102 forks source link

Humidifier integration design #310

Closed Shulyaka closed 2 years ago

Shulyaka commented 4 years ago

Context

There is a demand to support humidifier and dehumidifier devices in HA. I expect that those devices will grow popularity. People try to use climate integration for the lack of a better alternative (see home-assistant/home-assistant#28690 as an example). Several versions of generic_hygrostat integrations are being around for a long time as custom components. I made an attempt to enhance the climate integration for better humidifier support (see #288), but the outcome was that humidifier devices need their own integration. I created a PR with a new humidifier integration (home-assistant/home-assistant#28693) which is in many aspects similar to the climate integration, however I see there is a demand to discuss other options. This issue is to start the discussion on how to make home smarter with respect to air humidity.

Proposal

Discuss the options

Consequences

Better support for humidifier and dehumidifier devices, improve well being and user satisfaction.

Roadmap

This is to track the development of the humidifier support in one place:

Shulyaka commented 4 years ago

@awarecan added the following comment on the PR:

How to build a really smart humidifier

Most humidifier is measuring current_humidity in relative humidity and display it to the user (or report it back via some sort API). However relative humidity is not something represent how people feel comfortable, dew point is. Basically, dew point is calculated by both temperature and humidity. Therefore if we want have a really smart humidifier, we should be able to adjust target_humidity with current_temperature to maintain dew point in comfortable zone.

So, I want to add following into current design:

  1. current_temperature, returned by device

  2. current_dew_point, calculated by current temperature, current humidity, and air pressure (or elevation)

  3. target_dew_point, read/write by user or script (for example, user may switch to "comfort" mode, actually means let HA control the target dew point in a comfortable level)

I have two concerns on that

  1. I believe the humidifier component should accurately represent the actual device's capabilities and not to be much smarter than the device behind it. Not all humidifiers measure temperature, for example, and the lack of temperature information will break the functionality. We can use what google assistant and homekit support for humidifiers as a reference of what the integration can support (see google, homekit)
  2. Targeting dew point is essentially the same as targeting absolute humidity (not relative), which I doubt is what humans really feel.

That said, I do see a rationale in controlling both temperature and humidity of the air (and CO2 level probably) together in one component, I just think it is out of scope of humidifier or climate domain. I see it as a brand new integration (say, air_comfort or life_support, I am not good at naming) that would have slave climate and humidifier devices to control, that would target apparent temperature (see Apparent_temperature, Humidex, Heat_index, Thermal_comfort). I would be happy to implement such component, I just don't know yet how to design it.

Some other things to consider:

  1. climate devices may affect humidity. Some of HVACs have special functionality for that. Some of them also have fans.
  2. humidifier devices may affect temperature as a side effect. Depending of its type, evaporating water will lower the temperature while those using hot steam will raise it.
  3. fan devices affect apparent temperature while not affecting actual temperature or humidity
  4. Ventilation systems or just an open window may affect temperature and humidity depending on the outside values. They might be or might be not under our control or observation. They might also have an aux heater.
  5. Each room may have more than one fan, humidifier or climate device. Or may lack some of them.
  6. Energy saving targeting is also important.
  7. There are recommended levels for temperature, humidity and CO2 levels.
awarecan commented 4 years ago

Oh man, we are going to use home-assitant to control our dome on Mars

All three attributes I am proposing should be optional, and we can have a support flag for them.

I am currently developing a "next-generation" humidifier which has temperature sensor on board.

Shulyaka commented 4 years ago

Oh man, we are going to use home-assitant to control our dome on Mars

Not until HA 1.0.

All three attributes I am proposing should be optional, and we can have a support flag for them.

I am currently developing a "next-generation" humidifier which has temperature sensor on board.

Well, I can add temperature attribute if there are humidifiers with temperature sensors. But still I do not believe targeting dew point makes sense. Quoting Wikipedia: "In technical terms, the dew point is the temperature at which the water vapor in a sample of air at constant barometric pressure condenses into liquid water at the same rate at which it evaporates". That means it does not depend on current temperature at all! It can be calculated using relative humidity and temperature, but essentially it's just a measurement of amount of water in the air. There is a point in targeting other combinations of temperature and relative humidity, but do majority of humidifiers out there support it by themselves?

Shulyaka commented 4 years ago

There is a dew point sensor already available as a custom component: https://github.com/miguelangel-nubla/home-assistant-dewpoint

Shulyaka commented 4 years ago

And a thermal comfort sensor: https://github.com/dolezsa/thermal_comfort

Hedda commented 4 years ago

Another related type of category of devices that I think does not either fall under "climate" or "humidifier" categories and has been growing in popularity is "air purifier" (a.k.a. "air cleaner").

Therefor a follow-up question/discussion for "air-purifier" is how to make a home smarter with respect to "air-quality" measured by AQI (Air Quality Index), instead of respect to "air humidity" as for humidifiers and dehumidifiers.

So I think a related question is if air purifier should also be its own standalone integration or not?

https://en.wikipedia.org/wiki/Air_purifier

https://en.wikipedia.org/wiki/Air_quality_index

For reference and current relevance to the integration with Home Assistant, today the most popular WiFi-connected air-purifying consumer devices are probably "Xiaomi Mi Air Purifier 2S", "Xiaomi Mi Air Purifier 2H", and "Xiaomi Mi Air Purifier 3H" models (H = HEPA-filter).

https://www.mi.com/global/mi-air-purifier-2h

https://www.mi.com/global/mi-air-purifier-3H

Maybe obvious but should be noted that most air purifiers for home just have an optic-based air monitor sensor that measure air-quality by particles per cubic-meter/cubic-feet and use air-filters and/or activated-carbon filters to filter small particles like dust, mold-spores, and pollen out of the air, so they do not normally measure of help improve CO2 or Oxygen levels, however, some have activated-carbon filters and just filtering the air can help lower radon levels as radon sticks to small particles which when you breath in does more damage.

PS: One related cool thing is that both Google Assistant now has support for air-purifiers that works with Google Home.

Shulyaka commented 4 years ago

My opinion is yes, air purifier should have its own integration. At least Google has separate device types for purifiers, humidifiers, and AC: https://developers.google.com/assistant/smarthome/guides

Hedda commented 4 years ago

@Shulyaka Is adding such new integration for "air purifiers" maybe something that you might be willing to take on after your PR for "adding new humidifier entity integration" for Home Assistant Core?

If so then please note that there are actually different types of "purifiers", as "water purifiers" are also relatively common after "air purifiers", (for example, some home/household water filters can remove over 90% of chlorine, iron and silver, which is great as communal water purification plants commonly add chlorine to kill most harmful microbes and sometimes also add iron to remove arsenic contamination of groundwater). Google also has "water softener" as its own device types but I would argue that water softeners are also a type of water purifier because water softening process is normally filtering to remove calcium and magnesium from the water.

Shulyaka commented 4 years ago

May be. But I would like to finish humidifiers first (and that PR is only a start, there are number of others to follow to support various voice assistants, generic hygrostats, device actions, etc). Let's see how it goes first. And I don't own a smart purifier device myself.

Hedda commented 4 years ago

@Shulyaka Cool! You should get one then ;) Myself I highly recommend "Xiaomi Mi Air Purifier 3H" :) ...if you have a bigger room/space then the larger version is "Xiaomi Mi Air Purifier Pro". The only difference between those as I understand is the size of the fan, otherwise, they have the same functions. Why should have one? See -> https://www.youtube.com/watch?v=VidZMqmTgJQ :D

Shulyaka commented 4 years ago

Here is my research on smart humidifiers.

Method: Google for "smart humidifier" and "smart dehumidifier", then search for manual or official specs of everything (or similar from same manufacturer) found on pages from the first page of results. Note: not all of the devices are actually smart (in terms of connectivity), but they do still serve the purpose of the recap of functionality.

Observation:

  1. Humidifiers usually don't have fan, instead they feature different levels of operation often called 'mist levels'.
  2. There are up to 7 of those levels. Normally 3. Sometimes they have names (like 'low' or 'medium'), sometimes it's just the number (counting from 1). Some include the Auto mode in this list (i.e. '1', '2', '3', 'Auto'). Sometimes only the name.
  3. Dehumidifiers always have a fan and its level usually only has name without number. Normally 2 or 3 modes, 'low', 'medium', and 'high' (but one manufacture refer to them as 'silent', 'medium', and 'turbo')
  4. Some feature sleep mode and a heated mist.
  5. Apart from warm mist, some feature other controls like 'Air refreshing', 'Baby mode', 'pump'.

Conclusion:

  1. The sleep mode could be covered by the preset mode
  2. For the heater I probably need to port the functionality from climate

References:

  1. Humidifiers: 1.1. Proscenic 807C 1.2. iTvanila Humidifier HU-S1A 1.3. Levoit LV550HH 1.4. Motorola MBP86SN 1.5. Xiaomi Mi Air Humidifier
  2. Dehumidifiers: 2.1. Frigidaire 70 Pint Dehumidifier 2.2. hOmeLabs Dehumidifier 2.3. GE APER70LW 2.4. Honeywell TP70 2.5. LG UD501KOJ5 2.6. Inventor EVA II PRO WiFi

Additional information:

  1. Google Assistant recommends the following trait for fan speed for both humidifiers and dehumidifiers: Smart Home FanSpeed Trait Schema. It supports arbitrary list of speed names (without assigning it a number).
  2. Homekit has the RotationSpeed characteristic for HumidifierDehumidifier HAP-python/pyhap/resources/characteristics.json, which is a float value without names.
  3. Python-miio defines both name and number for fan speed: python-miio/miio/airdehumidifier.py

Questions:

  1. Should we distinguish between 'mist level' and 'fan speed' at all or provide a single interface for both?
  2. Do we need names, numbers, or both (tuples?)
  3. Do we need other controls such as pump or leave it to individual integrations?

My personal preference is to pretend everything is fan speed (even when mist level is used instead of a fan) and use same interface as climate integration for the sake of maintainability.

balloob commented 4 years ago

From https://github.com/home-assistant/core/pull/28693#issuecomment-616155455:

HomeKit supports the following for humidifiers:

Shulyaka commented 4 years ago

For the reference, Google Assistant supports the following:

The above are the recommended traits. A device doesn't have to implement all of them, and it could also implement additional ones.

https://developers.google.com/assistant/smarthome/guides/humidifier

BradleyFord commented 4 years ago

Note that the SmartMI Evaporative Humidifier does use a fan. This is quite popular as part of the Xiaomi family.

The types of humidifiers are:

So back to the question of fan speed/mist rate; I feel these are both essentially controlling the "Output level" of the device. Hence would output level be a reasonable generalisation that covers both requirements?

Shulyaka commented 4 years ago

HomeKit supports the following for humidifiers:

Here is how the humidifier integration would support HomeKit on a high level:

* Current Relative Humidity

Available via ATTR_CURRENT_HUMIDITY state attribute

  • Current Humidifier Dehumidifier State The ATTR_HUMIDIFIER_ACTION state attribute mapped to the HomeKit-supported values
  • Target Humidifier Dehumidifier State This is just the state, mapped to the HomeKit-supported values
  • Relative Humidity Dehumidifier Threshold
  • Relative Humidity Humidifier Threshold The ATTR_HUMIDITY state attribute. The correct characteristic is chosen from the two of the above based on available operation modes.
  • Rotation Speed We can use the Fan mode for that. The characteristic is optional.
  • Swing Mode Please correct me if I'm wrong, but it is not something very common to the humidifiers or dehumidifiers. I don't plan to support it yet. The characteristic is optional.
  • Water Level Though the characteristic is optional, this is a good thing thing to support. I've added ATTR_WATER_LEVEL for this.
  • Lock Physical Controls Not implemented yet, but the feature looks more or less common. Do we need this? The characteristic is also optional.
Shulyaka commented 4 years ago

Hence would output level be a reasonable generalisation that covers both requirements?

Makes sense. Do you think it should be based on a predefined list of possible literal values (such as 'low', 'medium', and 'high') or a range of configurable numerical values (i.e. 1-3)?

BradleyFord commented 4 years ago

Just looking at the number of "Output Levels" on the list of devices you provided:

Humidifier:

Dehumidifier

So basically from everything I can see the range of options is quite variable between 2 and 3. With Levoit being an outlier.

Shulyaka commented 4 years ago

On the output levels.

Basically we have the following options for the output levels:

  1. Named levels (i.e. 'low', 'medium', and 'high') 1.a. Static list defined by the integration 1.b. List is defined by the individual platform
  2. Numeric discrete levels with an attribute of the maximum value
  3. Float percent value (0.0 - 100.0). This is what HomeKit supports.

I wouldn't exclude the support for the ones that provide more levels. We can also combine the approaches.

I suggest the following:

  1. The output level will be a float between 0 and 100. A platform for a device that supports it, will need to translate it into level by itself. It will be easy (i.e. two 'if's for 3 levels).
  2. For the platforms that wish to support it, there will be a way to define a list of possible discrete levels. The humidifier integration will define a list of constants (OUTPUT_LEVEL_LOW, OUTPUT_LEVEL_LOWENERGY, OUTPUT_LEVEL_MIN, OUTPUT_LEVEL_SILENT, OUTPUT_LEVEL_NORMAL, OUTPUT_LEVEL_MEDIUM, OUTPUT_LEVEL_TURBO, OUTPUT_LEVEL_MAX, OUTPUT_LEVEL_HIGH and so on). The platform will define ATTR_OUTPUT_LEVELS attribute with a list of several values consisting of those constants. The humidifier integration will have a service set_output_level that will accept those constants values as an aliases. The integration will translate the levels into percent values using a dictionary, that would be documented.

UPD: I think integer instead of float will better fit.

BradleyFord commented 4 years ago

I've got no idea which way to go in terms of how this project prefers to do things; I'm just helping collect the data to support a good decision :)

Shulyaka commented 4 years ago

The Proscenic one has 7 levels

Shulyaka commented 4 years ago

By the way, I have found no device so far capable of both humidifying and dehumidifying. Though I believe they may exist.

Jc2k commented 4 years ago

The fan entity has a fixed output speed list and it’s caused a few arch issues, so I’d personally prefer the idea of having a float/percentage.

BradleyFord commented 4 years ago

So it could be setup as a percentage, and then the individual devices can map the percentage to the modes on the specific implementation?

On Sat, 2 May 2020, 9:48 pm Jc2k, notifications@github.com wrote:

The fan entity has a fixed output speed list and it’s caused a few arch issues, so I’d personally prefer the idea of having a float/percentage.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/home-assistant/architecture/issues/310#issuecomment-622997681, or unsubscribe https://github.com/notifications/unsubscribe-auth/AACOZ72DL4PQIGSCML6I54LRPRTJBANCNFSM4JN4JPMA .

Shulyaka commented 4 years ago

Well, Xiaomi CJXJSQ02ZM can both humidify and dry, and Xiaomi CJJSQ01ZM has no humidity sensor and thus cannot set target humidity.

Shulyaka commented 4 years ago

So it could be setup as a percentage, and then the individual devices can map the percentage to the modes on the specific implementation?

My suggestion a few comments above was to use percentage, but allow to use a fixed set of names as aliases to some values. Though the set of possible names would be fixed, it could be extended.

Shulyaka commented 4 years ago

Well, Xiaomi CJXJSQ02ZM can both humidify and dry

No, that was a mistake, it's just a dry run, a mode to evaporate all remaining water

Shulyaka commented 4 years ago

I've tried to summarize the data in a table (with the valuable help of @BradleyFord):

  On/Off Operation Modes Preset Modes Output levels Target humidity Humidity sensor Temperature sensor Child lock LED On/Off Water level Heater Timer Additional smart features Comments
HomeKit Yes Dehumidifying, Humidifying, Idle, Inactive No 0% - 100% float 0% - 100% float Yes No Yes No 0% - 100% float No No Swing Mode  
Google Assistant Yes Humidifier and Dehumidifier device types Any list of modes Any list of fan speeds with optional support for percent values 0% - 100%, 1% step Yes Could be exposed via TemperatureControl Trait, but it is not among recommended traits for humidifiers Available via toggles Available via toggles No Available via toggles Exposable via Timer trait, which is not among recommended traits for humidifiers Any number of toggles (on/off switches)  
Proscenic 807C Yes Off, Humidifiying, Auto, Baby   7 unnamed levels 30% - 75%, 5% step Yes Yes No "Sleep mode" Low water level alert "Heating" 1-12 hours Anion generator It has two auto operation modes ("Auto" and "Baby") for which you can not set the target humidity
Motorola MBP86SN Yes Off, Humidifiying, Auto, Baby   A, 1, 2, 3 30% - 75%, 5% step Yes No No Night light Low water level alert "Warm Mist" 1-12 hours Air Refreshing, Water and Dust Filter Replacement Alert It has and "Auto" output level. You can still configure the target humidity on that level. Also has both "Auto" and "Baby" operation modes as above.
Xiaomi Mi Air Humidifier Yes Off, Humidifiying   Unnamed 1st, 2nd, 3rd, and "Maximum" modes No No No No Yes Low water level alert, Water is over alert No No   No humidity sensor and no target humidity
Xiaomi Mi Smart Humidifier Yes Off, Humidifiying   Low, Medium, High, Humidity Yes Yes Yes No Yes Low water alert No Sheduled on/off Notification sounds On/Off User can only set the target humidity on "Humidity" output level.
SmariMI Humidifier 2 Yes Off, Humidifiying, Auto   Silent, Medium, Turbo 30% - 80%, 10% step Yes Yes Yes 0, 1, 22 = off, 1 = Dim, 0 = Bright 0% - 125% float No   Buzzer On/Off Dry mode which dries the water out when it has not been used for a while
Inventor EVA II PRO WiFi Yes Off, Dryer, Continuous, Smart, Manual   Silent, Medium, Turbo 35% - 85%, 5% step Yes Yes No No Full Water Tank indicator No 1-24 hours Ionizer Only Manual operation mode allows setting target humidity
Xiaomi Widetech Dehumidifier Yes Off, Clothes Dryer, Continuous, Smart, Manual   3 levels in Chinese 40%-60%, 10% step Yes Yes No No Water Full Shutdown No No   Only Manual operation mode allows setting target humidity
KOIOS Humidier Yes Sleep   Low, Mid, High 45% - 65%, 5% step Yes     "Sleep mode"     1-12 hours Anion generator  
Habitat Yes Smart, Easy, Timer, Comfort, Flow               Yes     Water Freshness  
Levoit LV550 Yes Auto   1, 2, 3, 4, 5 30% - 80% Yes Yes No Yes (Display) Low water level alert Yes 1-12 hours    
Levoit LV600 Yes Auto   1, 2, 3 40% - 80% Yes No No No Low water level alert Yes 1-12 hours    
Shulyaka commented 4 years ago

As for the high level design for the integration, I now have a second thought on some of my implementation decisions.

Humidifiers vs Dehumidifiers Requirement: It is essential to distinguish between humidifiers and dehumidifiers. No device I've seen so far is capable of both humidifying and dehumidifying.

Solution: Integration should define a function is_dehumidifier that would return True for dehumidifiers and False for humidifiers. By default (if not redefined by platform) the function will return False. If the function returns True, it will be mapped to value 'Yes' of ATTR_DEHUMIDIFIER capability attribute.

Operation and preset modes: Requirement: Some humidifiers feature several modes of operation. Usually only one of the modes allows setting target humidity. The modes are in wide range (i.e. "Auto", "Baby", "Clothes Dryer", "Continuous", "Smart", "Easy", "Flow", etc) and it is not easy to comprise a comprehensive list.

Solution: There is no point in supporting both operation and preset modes. The state function will return either "on" or "off". There will be no 'operation modes'. There will be support for preset modes just like it is done for climate integration, but they will be called just 'modes', not 'preset modes'. The platform should define the turn_on and turn_off functions that will be exposed as a service. If platform supports any working mode beyond just On and Off, it should return SUPPORT_MODE within its supported features. it will also need to define modes function returning a list of supported modes (will be mapped into ATTR_MODES capability attribute), mode function returning the current mode from that list (will be mapped into ATTR_MODE state attribute), and set_mode or async_set_mode function to set the mode (will be exposed as a humidifier.set_mode service).

Output levels: Requirements: Most humidifiers and dehumidifiers feature several levels of fan speeds or mist levels. At least one of the devices (Motorola MBP86SN) also features an Auto level (adjusted automatically based on current humidity).

Solution: Some thoughts are here: https://github.com/home-assistant/architecture/issues/310#issuecomment-622455369 https://github.com/home-assistant/architecture/issues/310#issuecomment-622963323

If the device supports output levels, it will need to return SUPPORT_OUTPUT_LEVEL among the supported features. It should also define a set_output_level or async_set_output_level with an integer argument between 0 and 100. It will need to set the output level of the device to the closest available value. It will be exposed as humidifier.set_output_level service. It will also need to define the output_level function that returns the current output level as integer. It may be different to the last value set by set_output_level function due to device limitations or manual user control. It will be mapped to ATTR_OUTPUT_LEVEL state attribute. As an extension to the above flow for the platforms that wish to support named discrete output levels, the following features are available: The integration will maintain a comprehensive dictionary of constants (i.e. OUTPUT_LEVEL_MIN) and the associated output levels. The platform will define a output_levels function with the list of those constants that the device supports. It will be mapped into ATTR_OUTPUT_LEVELS capability attribute. The humidifier.set_output_level service will accept those level names as argument. When the service is called, the integration will translate the names into numeric values before calling the platform set_output_level function. The platform will also be allowed to return the output level name as the result of output_level function. In this case the integration will set an additional state attribute ATTR_OUTPUT_LEVEL_NAME and also translate it into number for the ATTR_OUTPUT_LEVEL attribute. Although the list of the output level names is static and not extensible by the platform, we may append additional mames to it when needed. The list will be documented. Not sure how to support auto level though...

Target humidity: Requirement: Most humidifiers (except Xiaomi Mi Air Humidifier) support setting target humidity and feature humidity sensors. For HomeKit it is mandatory to be able to set target humidity (aka threshold). Devices feature different range and different step. No device provide precision better than 1%.

Solution: We must make a decision whether to support devices without humidity sensors and target humidity settings. The current approach is to assume they are not supported, but a platform may try to emulate support for target humidity setting by blindly controlling output level instead. A platform will define its range with min_humidity and max_humidity functions and optionally a step with humidity_step function. The integration will map them to ATTR_MIN_HUMIDITY, ATTR_MAX_HUMIDITY, and ATTR_HUMIDITY_STEP capability attributes respectively. The platform must provide either set_humidity or async_set_humidity function with an integer argument (will be exposed as humidifier.set_humidity service). Upon the call, the platform must configure the humidity of the device to the closest supported value. If the current device mode does not allow that, the platform should switch the device to the appropriate mode first. It should also provide the target_humidity function that returns the target humidity configured o the device. The integration will map the value to the ATTR_HUMIDITY state attribute. It may be different to the last value set by set_humidity function due to device limitations or manual user control.

Humidity and temperature sensors: Requirement: Almost all devices (except same xiaomi humidifier) support humidity sensors. Some also support temperature sensors.

Solution: The platform should provide the current_humidity function that returns the ambient humidity readings of the built-in device sensor (will be exposed as ATTR_CURRENT_HUMIDITY state attribute). If supported, the platform should also provide current_temperature and temperature_unit functions. If they are provided, the integration will convert the temperature using the temperature_unit and map the value to the ATTR_CURRENT_TEMPERATURE state attribute.

Water level: Requirement: Some humidifiers and dehumidifiers feature water level sensors. Some of them measure in percent (including overfill up to 125%). Some only feature binary low water indicator. Already mentioned Xiaomi Mi Air Humidifier features both low water level and water is over indicators.

Solution: If supported, the platform should provide the water_level function that returns an integer value in percent. If the device only supports a low water level indicator, it can either provide one of two fixed values (i.e. 100 and 30, defined by the physical properties of the device) or try to estimate the level based on uptime and output level. It will be mapped to the ATTR_WATER_LEVEL state attribute if provided.

Child lock: Requirement: At least one of the humidifiers (SmariMI Humidifier 2) supports child lock. It is also a supported feature in HomeKit.

Solution: If platform supports it, it should provide the is_locked function returning boolean value whether controls are locked or not. The integration will map it to the ATTR_LOCK state attribute. It should also provide two functions turn_lock_on and turn_lock_off (or their async counterparts), which will be exposed as humidifier.turn_lock_on and humidifier.turn_lock_off services. The platform should also return SUPPORT_LOCK among the supported features.

LED On/Off: Requirement: Some humidifiers feature an option to turn off the light or display (e.g. for the night). One of the humidifiers (SmariMI Humidifier 2) also supports dim and bright levels

Solution: The integration will support only on/off functionality. If platform wants to support different brightness levels, it may expose a custom service to set those levels. Please also see "Additional features" below. If platform supports it, it should provide the is_led_on function returning boolean value whether the LED is on or off. The integration will map it to the ATTR_LED state attribute. It should also provide two functions turn_led_on and turn_led_off (or their async counterparts), which will be exposed as humidifier.turn_led_on and humidifier.turn_led_off services. The platform should also return SUPPORT_LED among the supported features.

Heater: Requirement: Some humidifiers feature a 'heated' or 'warm' mist which can be turned on or off.

Solution: If platform supports it, it should provide the is_heater_on function returning boolean value whether the heater is on or off. The integration will map it to the ATTR_HEATER state attribute. It should also provide two functions turn_heat_on and turn_heat_off (or their async counterparts), which will be exposed as humidifier.turn_heat_on and humidifier.turn_heat_off services. The platform should also return SUPPORT_HEATER among the supported features.

Timer: Requirement: Some humidifiers feature an on/off timer with 0.5 or 1 hour precision.

Solution: HA provides much more advanced way to schedule things. I do not see any reasons to support the device timers for humidifiers. It will be more confusing than useful.

Ionizer: Requirement: Some humidifiers feature ionizer.

Solution: Same as LED, Heater or Child lock. If platform supports it, it should provide the is_ionizer_on function returning boolean value whether the ionizer is on or off. The integration will map it to the ATTR_IONIZER state attribute. It should also provide two functions turn_ionizer_on and turn_ionizer_off (or their async counterparts), which will be exposed as humidifier.turn_ionizer_on and humidifier.turn_ionizer_off services. The platform should also return SUPPORT_IONIZER among the supported features.

Additional features: Requirement: Some devices feature other functions that are not usually met in other devices. They include sounds on/off, Air Refreshing, Dust Filter Replacement Alert, etc

Solution: Because those features are not common to other devices, there is no point to support them on integration level. The platform may provide their own services or attributes, but they will not be exposed to other smart assistants. The platform will need to redefine state_attributes, capability_attributes, and async_setup functions to do that (calling parent ones first). There is nothing from the point of integration to support.

Shulyaka commented 4 years ago

We don't need to support all of the above features from the day one. Just let me know which of them I should include into the initial PR. Please review and confirm the design.

Shulyaka commented 4 years ago

Short version.

Humidifiers vs Dehumidifiers: ATTR_DEHUMIDIFIER for dehumidifiers Operation and preset modes: state is "on" or "off". turn_on and turn_off services. SUPPORT_MODE flag, ATTR_MODES and ATTR_MODE attributes, set_mode service Output levels: SUPPORT_OUTPUT_LEVEL flag, set_output_level service with integer or string argument, ATTR_OUTPUT_LEVEL, ATTR_OUTPUT_LEVELS, ATTR_OUTPUT_LEVEL_NAME attributes, names to values mapping. Not sure how to support auto level. Target humidity: ATTR_HUMIDITY, ATTR_MIN_HUMIDITY, ATTR_MAX_HUMIDITY, ATTR_HUMIDITY_STEP attributes, set_humidity service with integer argument Humidity and temperature sensors: ATTR_CURRENT_HUMIDITY and ATTR_CURRENT_TEMPERATURE attributes Water level: ATTR_WATER_LEVEL attribute Child lock: SUPPORT_LOCK feature, ATTR_LOCK attribute, turn_lock_on and turn_lock_off services LED On/Off: SUPPORT_LED feature, ATTR_LED attribute, turn_led_on and turn_led_off services Heater: SUPPORT_HEATER feature, ATTR_HEATER attribute, turn_heat_on and turn_heat_off services Ionizer: SUPPORT_IONIZER feature, ATTR_IONIZER attribute, turn_ionizer_on and turn_ionizer_off services Timer: Not supported

May be should also include notification sounds on/off. Or may be not.

Jc2k commented 4 years ago

In other tickets the core team has expressed an interest in splitting some entities apart rather than putting too many attributes on a single entity. Examples include the AirQuality entity, where it has been suggested it would be better to have multiple sensors linked together by a device registry entry. Another is battery, which now has changged a seperate battery charging sensor (rather than having an is_charging attribute). It was sugggested that climate might have too much stuff in one entity too (here).

I don't know if that changes your thinking any? Maybe some of the optional on/off features are seperate switches. Maybe water level is a seperate sensor.

Shulyaka commented 4 years ago

Well, let's hear what core team says, but I would at least keep the modes, output levels, target humidity, humidity sensor, child lock, and water level, because they are exported to HomeKit and Google Assistant as a single device. Ok, the child lock is also optional because it is rarely supported. I think I understand why it is done by AirQuality, but humidifiers are different in a way, because different properties/attributes influence each other (well, except heater, LED, ionizer, child lock, and sounds, we may separate them from the humidifier entity). It is true that I based my design on the current climate integration, and I think it makes sense to keep them similar to each other.

Jc2k commented 4 years ago

I agree, would be good to get an ADR or something on when it is good to make a seperate entity or not. One example given was: would it be something that you would make an automation trigger on. I can kind of see that for water level, for example. Another is that it makes it harder to use the humidity data (e.g. the built in graphs) becuse the state is the mode, not the current humidity %. It's quite common to see users use template sensors to work around this with other platforms.

AIUI the device registry is supposed to be used to show that these different properties/attributes are related, but clarification would be good indeed.

Not an opinion either way, but just for reference in HomeKit, I tried to make a similiar argument about batteries. A battery is exported as a single device in HomeKit but it was decided to have 2 entities on the HomeAssistant side (current % and is_charging). Decision is here. Implemented here.

Shulyaka commented 4 years ago

When I think about this approach I must admit I like it even more. We can leave in scope of this integration nothing but the core functionality of humidifiers, which is on/off, modes, humidity sensor, and target humidity. Everything else could be in scope of their own integrations, i.e. fan, switch, sensor, etc, linked with the device registry. The only thing I want to mention is that we would need a new sensor device class for water level, or we wouldn't be able to properly export it to HomeKit. The approach and the included functionality is up to the core developers to decide. @balloob , please advise.

Shulyaka commented 4 years ago

Even modes could go to it's own integration if we have a suitable one.

balloob commented 4 years ago

Yes to the breaking up, that way it's a lot easier.

If something is a dehumidifier should not be an attribute but a device class.

Ok, the child lock is also optional because it is rarely supported.

Let's leave this out. We should focus on the bare minimum. It's already complicated enough. So let's also leave out water level, led, heater or ionizer.

is_active, preset, target_humidity should be a good start?

Jc2k commented 3 years ago

@adrum has done some excellent work adding support to homekit_controller for humidifiers and dehumidifiers here https://github.com/home-assistant/core/pull/42311.

As a reviewier I need a second opinion though. What should we do about combied humidifier/dehumidifiers? The HomeKit spec allows these as part of the same device, with a single set of controls. But I cannot see how you handle this case with the new humidifier entity.

@adrum has done his best to map the 2 and I think i think it's probably the best you can do in a single entity without changing the base entity design. The PR uses modes to select whether the device is humidifying or dehumidifying. But it has to use essentially heuristics to know whether to map set_humidity to the dehumidifier threshold or humidifier threshold and i'm worried that this might cause what seems like glitchy behaviour if you don't understand the model the code is using. And I think it doesn't round trip as well (HomeKit controller -> HomeKit bridge) because it is hiding one of the target humidity values HK would otherwise expose to iOS.

A counter proposal I made is to actually create seperate entities on the HA side. So a combined humidifier and dehumidifier would appear as 2 seperate entities, linked by the device registry. This would solve the impedence mismatches. (But of course now there are 2 sets of controls. I'd be fine with that, but i'm not a typical user so i don't trust my opinion on this).

Shulyaka commented 3 years ago

During my research I could not find any device that is both humidifier and dehumidifier. Do they actually exist?

Jc2k commented 3 years ago

A quick google says there are devices like this

https://hanwell.com/app/uploads/CCR30-UK.pdf

And there are others that lack any sort of radio control.

But if they do exist they are much less common than separate devices.

But HomeKit does support them regardless. It sounds like we should error out if we do encounter one rather than try and map it to the existing interface, which isn't designed for combo devices. Or we should do my idea of creating 2 entities.

Shulyaka commented 3 years ago

Well, let me summarize the options here. Currently the integration has either humidifier or dehumidifier device class, while there are possible devices that are both. Originally I thought they are too exotic and no one would use it, but now there is an integration that actually needs this - the homekit_controller. We currently have the following options:

  1. Enhance humidifier integration to support joint humidifier and dehumidifier devices. Pros: a more universal solution, to control the device as a whole Cons: possible issues with Google Assistant (and may be other), which does not support this device type. Basically, we are just moving the same problem to another level
  2. Implement a workaround, having the two humidifier entities, for humidifier and dehumidifier threshold each, controlling the humidifying and dehumidifying parts of the device separately. Pros: keeping the humidifier integration simpler Cons: additional work to keep the two entities in sync (i.e. may be propagate mode and on/off state)
  3. Other workarounds, like having one entity but switching between humidifying and dehumidifying threshold with a mode, or controlling just the middle point keeping the same dead zone between them.

I believe it is up to the core developers to decide. @balloob?

Jc2k commented 3 years ago

Fwiw, 2 separate entities would work quite naturally in the homekit_controller code base. There wouldn't be any cludges to synchronise/propagate state as the entities would be "views" of the same raw data pushed by the accessory. And those views have to exist anyway to support standalone humidifiers and dehumidifiers. So that's probably the least effortful approach / most maintainer friendly approach on my side.

I don't like 3 because it is more effortful than 2 whilst hiding functionality.

And I don't think we should try 1 without some real world device.

So tl;dr Given we are not aware of any actual combi devices, I'm inclined to stick with 2 as both entities are needed anyway and it's the easiest approach.

Shulyaka commented 3 years ago

I agree, I am personally also for the easiest approach, if it is also the easiest long term.

MartinHjelmare commented 2 years ago

Let's go with suggestion 2. That doesn't require any further changes to the base model.

Since the humidifier integration has been implemented I'm going to close this issue. Most things on the road map are solved and remaining things don't need to be tracked in an architecture discussion for the humidifier since they just concern other integrations.

gcormier commented 1 year ago

Context

One of the challenges with maintaining indoor humidity in cold climates is to balance condensation on the windows. Sometimes it is not possible to achieve an ideal humidity level, as this means there will be condensation (or worst, frost) on the windows. The older (typically less efficient) the windows, the worse the issue.

Ecobee has a "frost control" setting, and other manual hygrometer controls for humidifiers will often have an external temperature sensor to take this into consideration, and they can work well. They have an unknown multiplier; Ecobee calls it "window efficiency level", which is merely a number from 1-10, and will cause Ecobee to offset the desired humidity by an unknown formula.

Where they fall short is in a large drop in temperature, such as the transition from day to night. Humidity levels will be set per the warmer daytime temperature, and once the temperature begins to drop rapidly, while the humidifier will turn off, there is still too much residual humidity in the house and condensation/frost can form.

HA has access to this information via the hourly weather forecast from the weather component. HA could also have access to an external temp sensor, be it a true sensor or the weather component's current temperature.

Proposal

I'd like to add some optional intelligence to generic_hygrostat to

  1. Factor in a temperature sensor entity for basic "frost control"
  2. Add some "look-ahead" functionality

Another simpler option would be to have generic_hygrostat allow target_humidity to reference an entity which could then be manipulated by an automation completely outside the component. The component would then merely need to ensure it's aware of changes to that entity as the external logic makes changes.

I wasn't sure where to have this discussion. Would anyone care to chime in?

MartinHjelmare commented 1 year ago

Please start a new discussion thread in this repo instead.

https://github.com/home-assistant/architecture/discussions