Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sensor platform for Xiaomi Miio fans #54564

Merged
merged 14 commits into from
Aug 15, 2021
Merged

Add sensor platform for Xiaomi Miio fans #54564

merged 14 commits into from
Aug 15, 2021

Conversation

bieniu
Copy link
Member

@bieniu bieniu commented Aug 12, 2021

Breaking change

The following fan entity attributes temperature, humidity, aqi, purify volume, filter life remaining, filter hours used, co2, illuminance, motor speed and motor2 speed has been migrated to the senor entity.
Users need to update their automations.

The filter_rfid_product_id and filter_rfid_tag fan entity attributes has been removed as they are of little use to users.

Proposed change

This PR migrates the existing fan attributes to the sensor entities.

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

Checklist

  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • The code has been formatted using Black (black --fast homeassistant tests)
  • Tests have been added to verify that the new code works.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • Untested files have been added to .coveragerc.

The integration reached or maintains the following Integration Quality Scale:

  • No score or internal
  • 🥈 Silver
  • 🥇 Gold
  • 🏆 Platinum

To help with the load of incoming pull requests:

@probot-home-assistant
Copy link

This pull request needs to be manually signed off by @home-assistant/core before it can get merged.
(message by ReviewEnforcer)

@probot-home-assistant
Copy link

Hey there @rytilahti, @syssi, @starkillerOG, mind taking a look at this pull request as it has been labeled with an integration (xiaomi_miio) you are listed as a code owner for? Thanks!
(message by CodeOwnersMention)

@bieniu
Copy link
Member Author

bieniu commented Aug 12, 2021

@jbouwh Please have a look.

Copy link
Contributor

@jbouwh jbouwh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look good overall a few suggestions.

MODELS_HUMIDIFIER_MIIO,
MODELS_HUMIDIFIER_MIOT,
MODELS_HUMIDIFIER_MJJSQ,
MODELS_PURIFIER_MIIO,
MODELS_PURIFIER_MIOT,
)
from .device import XiaomiCoordinatedMiioEntity, XiaomiMiioEntity
from .gateway import XiaomiGatewayDevice
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constant in line 64->78 does no seem to be reference anymore.

UNIT_LUMEN = "lm"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UNIT_LUMEN is used in the line 180.

@@ -238,13 +362,34 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
elif model in MODELS_HUMIDIFIER_MIIO:
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assignment of device is all the same perhaps we can do the check for the condition in the else statement first.
Just get the value for KEY_DEVICE if key if it is available (perhaps use get).

Background:
AIR_MONITOR_PLATFORMS (MODELS_AIR_MONITOR) (flow_type == CONF_DEVICE) and GATEWAY_PLATFORMS (flow_type == CONF_GATEWAY) are initializing then sensor platform too.

sensors = PURIFIER_MIIO_SENSORS
elif model in MODELS_PURIFIER_MIOT:
device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
sensors = PURIFIER_MIOT_SENSORS
else:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a next PR we should also move there sensors to a coordinated context

sensors = HUMIDIFIER_MIIO_SENSORS
elif model == MODEL_AIRPURIFIER_V2:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we could do the model to sensors translation using a constant dict

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea.

),
ATTR_AQI: XiaomiMiioSensorDescription(
key=ATTR_AQI,
name="Air Quality Index",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed that in the Xiaomi Home app this value is specified as PM2.5 and not AQI. I wonder if we should not treat it as a PM2.5 sensor.

Screenshot_20210813-124553__01

Copy link
Contributor

@jbouwh jbouwh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@jbouwh jbouwh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good

homeassistant/components/xiaomi_miio/sensor.py Outdated Show resolved Hide resolved
state_class=STATE_CLASS_MEASUREMENT,
attributes=(
"filter_hours_used",
"filter_rfid_product_id",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like it's static info. We only want to have dynamic info related to the entity state in the state attributes. There are only some exceptions like attribution or if the info is essential for automations.

Copy link
Member

@syssi syssi Aug 14, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This filter_rfid_product_id looks like this : 0:0:30:33. It could change if you use a different filter product. The filter_type is extracted/is part of the product id.

Copy link
Member

@MartinHjelmare MartinHjelmare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@MartinHjelmare
Copy link
Member

We should mention that filter product id and rf id tag were removed in the breaking changes paragraph.

@jbouwh
Copy link
Contributor

jbouwh commented Aug 14, 2021

Please have a look at the error at #54625. The water_level sensor seems to create a an error when the cover is removed.

@jbouwh
Copy link
Contributor

jbouwh commented Aug 14, 2021

2021-08-14 13:35:24 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/workspaces/core/homeassistant/helpers/update_coordinator.py", line 134, in _handle_refresh_interval
    await self._async_refresh(log_failures=True, scheduled=True)
  File "/workspaces/core/homeassistant/helpers/update_coordinator.py", line 265, in _async_refresh
    update_callback()
  File "/workspaces/core/homeassistant/helpers/update_coordinator.py", line 325, in _handle_coordinator_update
    self.async_write_ha_state()
  File "/workspaces/core/homeassistant/helpers/entity.py", line 464, in async_write_ha_state
    self._async_write_ha_state()
  File "/workspaces/core/homeassistant/helpers/entity.py", line 498, in _async_write_ha_state
    state = self._stringify_state()
  File "/workspaces/core/homeassistant/helpers/entity.py", line 470, in _stringify_state
    state = self.state
  File "/workspaces/core/homeassistant/components/xiaomi_miio/sensor.py", line 450, in state
    and self._state > self.entity_description.valid_max_value
TypeError: '>' not supported between instances of 'NoneType' and 'float'

I merged this pull to sync the code base.

@jbouwh
Copy link
Contributor

jbouwh commented Aug 14, 2021

This issue is caused here:

self._state = self._extract_value_from_attribute(
self.coordinator.data, self.entity_description.key
)
if (
self.entity_description.valid_min_value
and self._state < self.entity_description.valid_min_value
) or (
self.entity_description.valid_max_value
and self._state > self.entity_description.valid_max_value
):

When state is None. No further checks should be performed. When the cover is removed the backend returns None.

Suggestion is to insert one line of code...

@property
def state(self):
"""Return the state of the device."""
self._state = self._extract_value_from_attribute(
self.coordinator.data, self.entity_description.key
)

        if self._state is None:
          return None

if (
self.entity_description.valid_min_value
and self._state < self.entity_description.valid_min_value
) or (
self.entity_description.valid_max_value
and self._state > self.entity_description.valid_max_value
):

@bieniu
Copy link
Member Author

bieniu commented Aug 15, 2021

We should mention that filter product id and rf id tag were removed in the breaking changes paragraph.

Done

@bieniu
Copy link
Member Author

bieniu commented Aug 15, 2021

This issue is caused here

Great catch. Fixed.

@MartinHjelmare
Copy link
Member

Why did we have the valid max and min value checks? Don't we need them anymore?

@bieniu
Copy link
Member Author

bieniu commented Aug 15, 2021

Why did we have the valid max and min value checks? Don't we need them anymore?

With earlier versions of python-miio than 0.5.7 the integration had to check that the value of water_level was not greater than 100% (with water tank detached the value of water_level was 127/1.2), now python-miio does this, please look here.

Copy link
Member

@MartinHjelmare MartinHjelmare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good!

@MartinHjelmare
Copy link
Member

MartinHjelmare commented Aug 15, 2021

@jbouwh please confirm we can merge here.

@jbouwh
Copy link
Contributor

jbouwh commented Aug 15, 2021

@jbouwh please confirm we can merge here.

I'll check within a few hours

@jbouwh
Copy link
Contributor

jbouwh commented Aug 15, 2021

Tested. All seems ok. The water_level sensor turn to unknown when the cover is removed. This is expected.
Alto tested together with PR #54625. All seems right now. Now exceptions.

@MartinHjelmare
Copy link
Member

Thanks!

@MartinHjelmare MartinHjelmare merged commit ebaae8d into home-assistant:dev Aug 15, 2021
@bieniu bieniu deleted the xiaomi-miio-fan-sensor branch August 16, 2021 07:23
@github-actions github-actions bot locked and limited conversation to collaborators Aug 17, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants