-
-
Notifications
You must be signed in to change notification settings - Fork 34.2k
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
base: dev
Are you sure you want to change the base?
Conversation
"""Set up Air Quality Sensors.""" | ||
super().__init__(coordinator) | ||
self.entity_description = description | ||
name = f"{subentry.data[CONF_LATITUDE]}_{subentry.data[CONF_LONGITUDE]}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we give the entities a nicer name, like the street name?
The problem would be, that we than could have duplicate names, if to locations in the same road.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here: c534957
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don’t allow user configurable names in the config flow, they can update that later if they want, I'd say it was fine before
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. I'm on mobile and just saw CONF_NAME
and assumed it was configurable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be changes to ATTR_NAME
?
"name": "Google Air Quality", | ||
"codeowners": ["@Thomas55555"], | ||
"config_flow": true, | ||
"dependencies": ["application_credentials"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just had a look at the Google Weather integration PR. There is just the API-Key used. This would also work. So we can avoid the complicated OAuth2 workflow. Is this wanted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only problem is, that we can make no title for the main entry with the user name. We would then have to give the entry title for example a partly redacted version of the API-Key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed it
743403d
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You forgot to remove the dependency here.
await self.async_set_unique_id(user_input[CONF_API_KEY]) | ||
self._abort_if_unique_id_configured() | ||
return self.async_create_entry( | ||
title=f"API-Key: {'*' * (len(user_input[CONF_API_KEY]) - 3)}{user_input[CONF_API_KEY][-3:]}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would just pick a default name than to add parts of the api key here
except Exception: | ||
_LOGGER.exception("Unknown error occurred") | ||
return self.async_abort(reason="unknown") | ||
await self.async_set_unique_id(user_input[CONF_API_KEY]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can the api key change? If we can't get something more specific like an user id I would thing _async_abort_entries_match would work better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can only delete it and create a new one. But I would suggest to trigger an reauth flow for that (in another PR).
In opposite to the OAuth2 authentication, there is no possibility to get personal information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reauth flow will change the api key and I don't think you can change the unique id.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This pull request adds a new integration for the Google Air Quality API, enabling Home Assistant users to retrieve real‐time air quality information based on geographic coordinates. Key changes include new sensor, coordinator, and configuration flow logic; comprehensive test coverage including snapshots and fixtures; and updates to the manifest, requirements, and branding.
Reviewed Changes
Copilot reviewed 21 out of 23 changed files in this pull request and generated 1 comment.
File | Description |
---|---|
tests/components/google_air_quality/ | New tests, fixtures, and snapshots for verifying integration functionalities |
homeassistant/components/google_air_quality/ | New integration code including sensors, config flow, coordinator, manifest, and related files |
requirements*.txt | Updated dependencies to include the google_air_quality_api package |
homeassistant/brands/google.json and CODEOWNERS | Updated branding and ownership information |
) | ||
|
||
|
||
class GoogleAirQaulityApiFlowHandler(ConfigFlow, domain=DOMAIN): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The class name 'GoogleAirQaulityApiFlowHandler' appears to contain a typo. Consider renaming it to 'GoogleAirQualityApiFlowHandler' to improve clarity and consistency.
Copilot uses AI. Check for mistakes.
"name": "Google Air Quality", | ||
"codeowners": ["@Thomas55555"], | ||
"config_flow": true, | ||
"dependencies": ["application_credentials"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You forgot to remove the dependency here.
@@ -0,0 +1,12 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add "integration_type": "service",
The default is hub.
|
||
# Gold | ||
docs-examples: todo | ||
discovery-update-info: todo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
exempt
@@ -0,0 +1,80 @@ | |||
rules: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason you re-ordered these? They were in alphabetical order.
( | ||
AirQualitySensorEntity(coordinator, description, subentry_id, subentry) | ||
for description in AIR_QUALITY_SENSOR_TYPES | ||
if description.exists_fn(coordinator.data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems only for the local_aqi this could be false. Since you only do this in setup, if it's false, is it guaranteed to stay false in subsequent requests?
_LOGGER.exception("Unknown error occurred") | ||
return self.async_abort(reason="unknown") | ||
await self.async_set_unique_id(user_input[CONF_API_KEY]) | ||
self._abort_if_unique_id_configured() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can abort for this reason before you validate the API key
for entry in hass.config_entries.async_entries(DOMAIN): | ||
for subentry in entry.subentries.values(): | ||
if subentry.unique_id == unique_id: | ||
return self.async_abort(reason="already_configured") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be done before calling the API
unique_id = f"{lat}_{lon}" | ||
for entry in hass.config_entries.async_entries(DOMAIN): | ||
for subentry in entry.subentries.values(): | ||
if subentry.unique_id == unique_id: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See other comment, if you want to allow reconfigure, the subentries shouldn't have unique_id.
Instead of exact equality, should we check here that coordinates are very close in proximity?
return self.async_abort(reason="unknown") | ||
|
||
unique_id = f"{lat}_{lon}" | ||
for entry in hass.config_entries.async_entries(DOMAIN): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the end of the loop this overrides the entry you define at line 114
await hass.async_block_till_done() | ||
await self.hass.config_entries.async_reload(entry.entry_id) | ||
|
||
self.hass.async_create_task(reload_later()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The correct way to do this is in async_setup_entry
to add:
entry.async_on_unload(entry.add_update_listener(async_update_options))
and in __init__.py
to add:
async def async_update_options(
hass: HomeAssistant, entry: GoogleWeatherConfigEntry
) -> None:
"""Update options."""
await hass.config_entries.async_reload(entry.entry_id)
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
Type of change
Additional information
Checklist
ruff format homeassistant tests
)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest
.requirements_all.txt
.Updated by running
python3 -m script.gen_requirements_all
.To help with the load of incoming pull requests: