core/tests/components/awair/test_sensor.py

344 lines
9.9 KiB
Python
Raw Normal View History

Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
"""Tests for the Awair sensor platform."""
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
from homeassistant.components.awair.const import (
API_CO2,
API_HUMID,
API_LUX,
API_PM10,
API_PM25,
API_SCORE,
API_SPL_A,
API_TEMP,
API_VOC,
ATTR_UNIQUE_ID,
DOMAIN,
SENSOR_TYPES,
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
from homeassistant.const import (
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
ATTR_ICON,
ATTR_UNIT_OF_MEASUREMENT,
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
CONCENTRATION_PARTS_PER_BILLION,
CONCENTRATION_PARTS_PER_MILLION,
LIGHT_LUX,
PERCENTAGE,
STATE_UNAVAILABLE,
TEMP_CELSIUS,
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
from .const import (
AWAIR_UUID,
CONFIG,
DEVICES_FIXTURE,
GEN1_DATA_FIXTURE,
GEN2_DATA_FIXTURE,
GLOW_DATA_FIXTURE,
MINT_DATA_FIXTURE,
OFFLINE_FIXTURE,
OMNI_DATA_FIXTURE,
UNIQUE_ID,
USER_FIXTURE,
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
from tests.async_mock import patch
from tests.common import MockConfigEntry
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
async def setup_awair(hass, fixtures):
"""Add Awair devices to hass, using specified fixtures for data."""
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
entry = MockConfigEntry(domain=DOMAIN, unique_id=UNIQUE_ID, data=CONFIG)
with patch("python_awair.AwairClient.query", side_effect=fixtures):
entry.add_to_hass(hass)
await hass.config_entries.async_setup(entry.entry_id)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
await hass.async_block_till_done()
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
def assert_expected_properties(
hass, registry, name, unique_id, state_value, attributes
):
"""Assert expected properties from a dict."""
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
entry = registry.async_get(name)
assert entry.unique_id == unique_id
state = hass.states.get(name)
assert state
assert state.state == state_value
for attr, value in attributes.items():
assert state.attributes.get(attr) == value
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
async def test_awair_gen1_sensors(hass):
"""Test expected sensors on a 1st gen Awair."""
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
fixtures = [USER_FIXTURE, DEVICES_FIXTURE, GEN1_DATA_FIXTURE]
await setup_awair(hass, fixtures)
registry = await hass.helpers.entity_registry.async_get_registry()
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_awair_score",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_SCORE][ATTR_UNIQUE_ID]}",
"88",
{ATTR_ICON: "mdi:blur"},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_temperature",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_TEMP][ATTR_UNIQUE_ID]}",
"21.8",
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, "awair_index": 1.0},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_humidity",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_HUMID][ATTR_UNIQUE_ID]}",
"41.59",
{ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, "awair_index": 0.0},
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_carbon_dioxide",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_CO2][ATTR_UNIQUE_ID]}",
"654.0",
{
ATTR_ICON: "mdi:cloud",
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_MILLION,
"awair_index": 0.0,
},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_volatile_organic_compounds",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_VOC][ATTR_UNIQUE_ID]}",
"366",
{
ATTR_ICON: "mdi:cloud",
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_PARTS_PER_BILLION,
"awair_index": 1.0,
},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_pm2_5",
# gen1 unique_id should be awair_12345-DUST, which matches old integration behavior
f"{AWAIR_UUID}_DUST",
"14.3",
{
ATTR_ICON: "mdi:blur",
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
"awair_index": 1.0,
},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_pm10",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_PM10][ATTR_UNIQUE_ID]}",
"14.3",
{
ATTR_ICON: "mdi:blur",
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
"awair_index": 1.0,
},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
# We should not have a dust sensor; it's aliased as pm2.5
# and pm10 sensors.
assert hass.states.get("sensor.living_room_dust") is None
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
# We should not have sound or lux sensors.
assert hass.states.get("sensor.living_room_sound_level") is None
assert hass.states.get("sensor.living_room_illuminance") is None
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
async def test_awair_gen2_sensors(hass):
"""Test expected sensors on a 2nd gen Awair."""
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
fixtures = [USER_FIXTURE, DEVICES_FIXTURE, GEN2_DATA_FIXTURE]
await setup_awair(hass, fixtures)
registry = await hass.helpers.entity_registry.async_get_registry()
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_awair_score",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_SCORE][ATTR_UNIQUE_ID]}",
"97",
{ATTR_ICON: "mdi:blur"},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_pm2_5",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_PM25][ATTR_UNIQUE_ID]}",
"2.0",
{
ATTR_ICON: "mdi:blur",
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
"awair_index": 0.0,
},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
# The Awair 2nd gen reports specifically a pm2.5 sensor,
# and so we don't alias anything. Make sure we didn't do that.
assert hass.states.get("sensor.living_room_pm10") is None
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
async def test_awair_mint_sensors(hass):
"""Test expected sensors on an Awair mint."""
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
fixtures = [USER_FIXTURE, DEVICES_FIXTURE, MINT_DATA_FIXTURE]
await setup_awair(hass, fixtures)
registry = await hass.helpers.entity_registry.async_get_registry()
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_awair_score",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_SCORE][ATTR_UNIQUE_ID]}",
"98",
{ATTR_ICON: "mdi:blur"},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_pm2_5",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_PM25][ATTR_UNIQUE_ID]}",
"1.0",
{
ATTR_ICON: "mdi:blur",
ATTR_UNIT_OF_MEASUREMENT: CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
"awair_index": 0.0,
},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_illuminance",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_LUX][ATTR_UNIQUE_ID]}",
"441.7",
{ATTR_UNIT_OF_MEASUREMENT: LIGHT_LUX},
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
# The Mint does not have a CO2 sensor.
assert hass.states.get("sensor.living_room_carbon_dioxide") is None
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
async def test_awair_glow_sensors(hass):
"""Test expected sensors on an Awair glow."""
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
fixtures = [USER_FIXTURE, DEVICES_FIXTURE, GLOW_DATA_FIXTURE]
await setup_awair(hass, fixtures)
registry = await hass.helpers.entity_registry.async_get_registry()
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_awair_score",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_SCORE][ATTR_UNIQUE_ID]}",
"93",
{ATTR_ICON: "mdi:blur"},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
# The glow does not have a particle sensor
assert hass.states.get("sensor.living_room_pm2_5") is None
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
async def test_awair_omni_sensors(hass):
"""Test expected sensors on an Awair omni."""
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
fixtures = [USER_FIXTURE, DEVICES_FIXTURE, OMNI_DATA_FIXTURE]
await setup_awair(hass, fixtures)
registry = await hass.helpers.entity_registry.async_get_registry()
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_awair_score",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_SCORE][ATTR_UNIQUE_ID]}",
"99",
{ATTR_ICON: "mdi:blur"},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_sound_level",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_SPL_A][ATTR_UNIQUE_ID]}",
"47.0",
{ATTR_ICON: "mdi:ear-hearing", ATTR_UNIT_OF_MEASUREMENT: "dBa"},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_illuminance",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_LUX][ATTR_UNIQUE_ID]}",
"804.9",
{ATTR_UNIT_OF_MEASUREMENT: LIGHT_LUX},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
async def test_awair_offline(hass):
"""Test expected behavior when an Awair is offline."""
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
fixtures = [USER_FIXTURE, DEVICES_FIXTURE, OFFLINE_FIXTURE]
await setup_awair(hass, fixtures)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
# The expected behavior is that we won't have any sensors
# if the device is not online when we set it up. python_awair
# does not make any assumptions about what sensors a device
# might have - they are created dynamically.
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
# We check for the absence of the "awair score", which every
# device *should* have if it's online. If we don't see it,
# then we probably didn't set anything up. Which is correct,
# in this case.
assert hass.states.get("sensor.living_room_awair_score") is None
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
async def test_awair_unavailable(hass):
"""Test expected behavior when an Awair becomes offline later."""
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
fixtures = [USER_FIXTURE, DEVICES_FIXTURE, GEN1_DATA_FIXTURE]
await setup_awair(hass, fixtures)
registry = await hass.helpers.entity_registry.async_get_registry()
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
assert_expected_properties(
hass,
registry,
"sensor.living_room_awair_score",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_SCORE][ATTR_UNIQUE_ID]}",
"88",
{ATTR_ICON: "mdi:blur"},
)
Add Awair sensor platform (#18570) * Awair Sensor Platform This commit adds a sensor platform for Awair devices, by accessing their beta API. Awair heavily rate-limits this API, so we throttle updates based on the number of devices found. We also allow for the user to bypass API device listing entirely, because the device list endpoint is limited to only 6 calls per day. A crashing or restarting server would quickly hit that limit. This sensor platform uses the python_awair library (also written as part of this PR), which is available for async usage. * Disable pylint warning for broad try/catch It's true that this is generally not a great idea, but we really don't want to crash here. If we can't set up the platform, logging it and continuing is the right answer. * Add space to satisfy the linter * Awair platform PR feedback - Bump python_awair to 0.0.2, which has support for more granular exceptions - Ensure we have python_awair available in test - Raise PlatformNotReady if we can't set up Awair - Make the 'Awair score' its own sensor, rather than exposing it other ways - Set the platform up as polling, and set a sensible default - Pass in throttling parameters to the underlying data class, rather than use hacky global variable access to dynamically set the interval - Switch to dict access for required variables - Use pytest coroutines, set up components via async_setup_component, and test/modify/assert in generally better ways - Commit test data as fixtures * Awair PR feedback, volume 2 - Don't force updates in test, instead modify time itself and let homeassistant update things "normally". - Remove unneeded polling attribute - Rename timestamp attribute to 'last_api_update', to better reflect that it is the timestamp of the last time the Awair API servers received data from this device. - Use that attribute to flag the component as unavailable when data is stale. My own Awair device periodically goes offline and it really hardly indicates that at all. - Dynamically set fixture timestamps to the test run utcnow() value, so that we don't have to worry about ancient timestamps in tests blowing up down the line. - Don't assert on entities directly, for the most part. Find desired attributes in ... the attributes dict. * Patch an instance of utcnow I overlooked * Switch to using a context manager for timestream modification Honestly, it's just a lot easier to keep track of patches. Moreover, the ones I seem to have missed are now caught, and tests seem to consistently pass. Also, switch test_throttle_async_update to manipulating time more explicitly. * Missing blank line, thank you hound * Fix pydocstyle error I very much need to set up a script to do this quickly w/o tox, because running flake8 is not enough! * PR feedback * PR feedback
2018-11-25 08:01:19 +00:00
Refactor / update Awair integration (#34394) * Refactor / update Awair integration This commit does a few things, all in service of making the Awair integration more modern and reliable. Specifically we do the following: - Update to python_awair 0.1.1 - Begin using config entries / flow for setting up the integration. - YAML support is completely removed. - The integration now allows adding multiple Awair accounts, should a user wish to do so (I found it _very_ useful in development). - Group various Awair sensors into devices, using the device registry. - Renames various sensors and treats the "dust" sensor as a particulate sensor. - Device update rate-limits are no longer dynamically calculated; the Awair API now separates rate-limits on a per-device basis. - Supports sound pressure and illuminance sensors found on some Awair devices. - We report the "awair index" for certain sensors as part of device_state_attributes. The "index" is a subjective measure of whether or not a sensor reading is "good" or "bad" (and to what extent). It's a component of the Awair score, and it is useful on its own as an input for those who wish to do things like "display this color if the value is 'bad'". This is a breaking change, and requires updates to documentation and a warning in the README. The breaking changes in detail, are: - Support for all YAML configuration is removed, and users will need to re-add the integration via the UI. - We no longer support overriding device discovery via manual configuration of device UUIDs. This was previously supported because the Awair API had severe limits on the device list endpoints; however those have since been removed. - Gen 1 devices no longer show a "dust" sensor; rather we create a PM2.5 sensor and a PM10 sensor and just keep the values in sync. This better reflects the sensor capabilities: it can detect particles in a range from 2.5 -> 10, but cannot differentiate between sizes. - Sensors are renamed as follows: - "sensor.devicename_co2" -> "sensor.devicename_carbon_dioxide" - "sensor.devicename_voc" -> "sensor.devicename_volatile_organic_compounds" - "sensor.devicename_score" -> "sensor.devicename_air_quality_index" - I've chosen to call the "Awair Score" an "air quality index" sensor, because fundamentally the "Awair Score" and other air quality indices (such as CAQI) do the same thing: they calculate a value based on a variety of other inputs. Under the hood, the integration has seen some improvements: - We use the DataUpdateCoordinator class to handle updates, rather than rolling our own update class. - The code no longer tracks availability based on a timestamp returned from the Awair service; we assert that if we have received a response and the response has data for our device, then we are available (and otherwise, not available). We don't need to test the actual Awair API so heavily. - Test coverage has been expanded to handle a variety of products that Awair produces, not just the one I happen to own. - Test coverage no longer concerns itself with testing behavior that is now handled by the DataUpdateCoordinator; nor is it concerned with ensuring that the overall component sets up and registers properly. These are assumed to be well-tested functionaity of the core and not things we need to re-test ourselves. Finally - between library updates and integration updates, this integration is well-positioned to support future updates. I have a proof-of-concept patch for device automations, and the underlying library now supports subclassing authentication (which clears the way for us to use OAuth authentication for Awair). * Wrap test fixture in mock_coro Truthfully I'm not sure why this was passing on my local dev environment, but I was developing with python 3.8 before. After installing python 3.7, I was able to reproduce the CI failures and fix them. * Fix broken tests after #34901 and/or #34989 * Do not rename sensors so broadly We're going to keep the sensors named as they were before, pending the outcome of any decisions around the air_quality component and what names should be standardized for air-quality-like devices. If standardized names are selected (which does seem likely), then we will update this integration to match them - at which point, it would be a breaking change. But for now, we'll keep names mostly identical to what users had before. Notable in this commit is that we generate the entity_id ourselves, rather than just allowing it to be auto-generated from the name attribute. This allows us to provide more human friendly names, while keeping the old format for entity ids. For example, given an Awair device called "Living Room", we'll generate an entity id of "sensor.living_room_voc" but show set the name of the device to "Living Room Volatile organic compounds". * Support import from config.yaml We'll create a config entry from config.yaml the first time we're loaded, and then defer to it from then on. We ignore all keys other than the access_token, since we no longer need to deal with per-account rate-limits (rather, everything is per-device now). * Add myself to CODEOWNERS Since I wrote the initial integration, and now this re-write, it feels appropriate for me to take care of the integration along with `danielsjf`. * Remove name mangling * Update homeassistant/components/awair/manifest.json Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/config_flow.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/awair/sensor.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Address some review feedback * Set up reauth flow in a job, rather than awaiting * Remove unnecessary title string * Remove unnecessary config schema checking As pointed out in review, because this comes in via import from `configuration.yaml`, we can rely on the `PLATFORM_SCHEMA` validation instead. * Fix tests * Set unique_id appropriately for legacy devices For users who have had this integration already installed (and who have updated their home assistant installation sometime in recent history), we want to ensure that unique_id's are set to the same thing as before, to facilitate the upgrade process. To do that, we add an additional property to the `SENSOR_TYPES` dict (`ATTR_UNIQUE_ID`) which allows us to map modern sensor names from python_awair to what older versions called them - ie: `humidity` -> `HUMID`. We then use that value when constructing the unique ID. This should allow users to upgrade and not lose configuration even if entity IDs would otherwise change (because we have changed the name format that generates entity IDs). One note is that for the gen1 `DUST` sensor, we have to treat it differently. This integration used to call that a "PM2.5" sensor, but the unique_id generated would be something like `awair_12345_DUST`. So we special-case that sensor, and do the same thing. We do not need to special-case the PM10 sensor for gen1 devices, because we didn't create a PM10 sensor in the past (we do now, because the "DUST" sensor is really a hybrid PM2.5/PM10 sensor). * Patch async_setup_entry for two tests * Update awair config_flow to require / use an email address for unique_id Also, only start one re-auth flow. * Add a few more tests, try to get coverage up. * Add another test * Move attribution to device_state_attributes * Don't require email * Switch from Union[dict, None] to Optional[dict] * Use a mock where requested * Fix missing constant rename * Use async_create_task * Bump test coverage a bit for config_flow * s/CONF_UNIQUE_ID/UNIQUE_ID/g * Add warning about deprecated platform config Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2020-06-21 19:46:07 +00:00
with patch("python_awair.AwairClient.query", side_effect=OFFLINE_FIXTURE):
await hass.helpers.entity_component.async_update_entity(
"sensor.living_room_awair_score"
)
assert_expected_properties(
hass,
registry,
"sensor.living_room_awair_score",
f"{AWAIR_UUID}_{SENSOR_TYPES[API_SCORE][ATTR_UNIQUE_ID]}",
STATE_UNAVAILABLE,
{ATTR_ICON: "mdi:blur"},
)