8000 Add Google Air Quality integration by Thomas55555 · Pull Request #145237 · home-assistant/core · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add Google Air Quality integration #145237

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 27 commits into
base: dev
Choose a base branch
from

Conversation

Thomas55555
Copy link
Contributor
@Thomas55555 Thomas55555 commented May 19, 2025

Breaking change

Proposed change

This PR introduces a new integration for the Google Air Quality API, allowing Home Assistant users to retrieve real-time air quality data based on geographic coordinates.
The integration uses this library: https://github.com/Thomas55555/python-google-air-quality-api
The documentation for the API can be found here: https://developers.google.com/maps/documentation/air-quality
image

Type of change

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

Additional information

Checklist

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

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

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

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • For the updated dependencies - a link to the changelog, or at minimum a diff between library versions is added to the PR description.

To help with the load of incoming pull requests:

@Thomas55555 Thomas55555 marked this pull request as ready for review May 19, 2025 20:50
return self.async_abort(
reason="access_not_configured",
description_placeholders={
"message": f"Missing required scope: {OAUTH2_SCOPE}"
Copy link
Member

Choose a reason for hiding this comment

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

why is this in a placeholder? How does one add this?

Comment on lines 71 to 113
async def async_step_coordinates(
self, user_input: dict[str, Any]
) -> ConfigFlowResult:
"""Handle coordinate input and create the config entry."""
session = aiohttp_client.async_get_clientsession(self.hass)
auth = api.AsyncConfigFlowAuth(
session, self._oauth_data[CONF_TOKEN][CONF_ACCESS_TOKEN]
)
client = GoogleAirQualityApi(auth)
location = user_input[CONF_LOCATION]
lat = location[CONF_LATITUDE]
lon = location[CONF_LONGITUDE]

try:
user_resource_info = await client.async_air_quality(lat, lon)
except NoDataForLocationError:
return self._show_form_user(
user_input,
errors={"base": "no_data_for_location"},
)
except GoogleAirQualityApiError as ex:
return self.async_abort(
reason="access_not_configured",
description_placeholders={"message": str(ex)},
)
except Exception:
self.logger.exception("Unknown error occurred")
return self.async_abort(reason="unknown")

unique_id = f"{lat}_{lon}"

await self.async_set_unique_id(unique_id)
self._oauth_data.update(
{
CONF_LATITUDE: lat,
CONF_LONGITUDE: lon,
"region_code": user_resource_info.region_code,
}
)
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=f"Coordinates {lat}, {lon}", data=self._oauth_data
)
Copy link
Member

Choose a reason for hiding this comment

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

Would it make sense to use subentries here? This way we can use the same account for multiple locations

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I have implemented it here.
I haven't used subentries before and didn't find any examples in combination with a coordinator. So I'm happy about feedback.

Comment on lines 4 to 15
"carbon_monoxide": {
"default": "mdi:molecule-co"
},
"nitrogen_dioxide": {
"default": "mdi:molecule"
},
"ozone": {
"default": "mdi:molecule"
},
"sulphur_dioxide": {
"default": "mdi:molecule"
}
Copy link
Member

Choose a reason for hiding this comment

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

aren't these all device classes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, they are, but the API delivers other units, than in the device classes allowed.

Copy link
Member

Choose a reason for hiding this comment

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

What do they provide?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

CO is now a device class.
The API provides ppb for NO2, O3 and SO2. But home assistant requires µg/m³

Comment on lines 58 to 62
"excellent_air_quality",
"good_air_quality",
"low_air_quality",
"moderate_air_quality",
"poor_air_quality",
Copy link
Member

Choose a reason for hiding this comment

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

strip _air_quality imo, easier to template with

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Some regions report for example moderate_air_quality and some moderate_air_pollution. So the stripped version can be confusing.

Comment on lines 179 to 181
self._attr_translation_placeholders = {
"local_aqi": coordinator.data.indexes[1].display_name
}
Copy link
Member

Choose a reason for hiding this comment

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

What's this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the local AQI for the country, in which the selected coordinates are.
For Dutch it would for example be: LKI (NL)
https://developers.google.com/maps/documentation/air-quality/laqis?hl=de

Comment on lines 68 to 132
"1_blue": "1 - Blue",
"1_green": "1 - Green",
"10_33_percent_of_guideline": "10-33% of guideline",
"1a_very_good_air_quality": "1A - Very good air quality",
"1b_good_air_quality": "1B - Good air quality",
"2_cyan": "2 - Cyan",
"2_light_green": "2 - Light green",
"2a_acceptable_air_quality": "2A - Acceptable air quality",
"2b_acceptable_air_quality": "2B - Acceptable air quality",
"3_green": "3 - Green",
"3_yellow": "3 - Yellow",
"33_66_percent_of_guideline": "33-66% of guideline",
"3a_aggravated_air_quality": "3A - Aggravated air quality",
"3b_bad_air_quality": "3B - Bad air quality",
"4_orange": "4 - Orange",
"4_yellow_watch": "4 - Yellow/Watch",
"5_orange_alert": "5 - Orange/Alert",
"5_red": "5 - Red",
"6_red_alert_plus": "6 - Red/Alert+",
"66_100_percent_of_guideline": "66-100% of guideline",
"above_average_air_pollution": "Above average air pollution",
"acceptable": "Acceptable",
"acceptable_air_quality": "Acceptable air quality",
"acutely_unhealthy_air_quality": "Acutely unhealthy air quality",
"alarm_level": "Alarm level",
"alert_level": "Alert level",
"alert_threshold": "Alert threshold",
"average_air_pollution": "Average air pollution",
"average_air_quality": "Average air quality",
"bad_air_quality": "Bad air quality",
"below_average_air_pollution": "Below average air pollution",
"caution": "Caution",
"clean": "Clean",
"considerable_air_pollution": "Considerable air pollution",
"degraded_air_quality": "Degraded air quality",
"desirable_air_quality": "Desirable air quality",
"emergency": "Emergency",
"emergency_level": "Emergency level",
"evident_air_pollution": "Evident air pollution",
"excellent": "Excellent",
"excellent_air_quality": "[%key:component::google_air_quality::entity::sensor::uaqi_category::state::excellent_air_quality%]",
"extremely_bad_air_quality": "Extremely bad air quality",
"extremely_poor_air_quality": "Extremely poor air quality",
"extremely_unfavorable_air_quality": "Extremely unfavorable air quality",
"extremely_unhealthy_air_quality": "Extremely unhealthy air quality",
"fair_air_quality": "Fair air quality",
"fairly_good_air_quality": "Fairly good air quality",
"good": "Good",
"good_air_quality": "[%key:component::google_air_quality::entity::sensor::uaqi_category::state::good_air_quality%]",
"greater_than_100_percent_of_guideline": "Greater than 100% of guideline",
"hazardous_air_quality": "Hazardous air quality",
"heavily_polluted": "Heavily Polluted",
"heavy_air_pollution": "Heavy air pollution",
"high_air_pollution": "High air pollution",
"high_health_risk": "High health risk",
"high_pollution": "High pollution",
"horrible_air_quality": "Horrible air quality",
"less_than_10_percent_of_guideline": "Less than 10% of guideline",
"light_air_pollution": "Light air pollution",
"low_air_pollution": "Low air pollution",
"low_air_quality": "[%key:component::google_air_quality::entity::sensor::uaqi_category::state::low_air_quality%]",
"low_health_risk": "Low health risk",
"low_pollution": "Low pollution",
"medium_air_pollution": "Medium air pollution",
"medium_air_quality": "Medium air quality",
Copy link
Member

Choose a reason for hiding this comment

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

What in the world does this mean

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are the different possible values for the air quality in all the countries.

@home-assistant home-assistant bot marked this pull request as draft May 22, 2025 21:21
@home-assistant
Copy link

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

Thomas55555 and others added 4 commits May 23, 2025 17:13
@Thomas55555 Thomas55555 marked this pull request as ready for review May 26, 2025 19:41
@home-assistant home-assistant bot requested a review from joostlek May 26, 2025 19:41
@Thomas55555
Copy link
Contributor Author

Test errors are unrelated

@Thomas55555 Thomas55555 marked this pull request as draft June 3, 2025 19:46
@Thomas55555 Thomas55555 marked this pull request as ready for review June 3, 2025 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
0