Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add Airly integration #26375

Merged
merged 42 commits into from Oct 4, 2019
Merged
Changes from 2 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
3fe4eb4
Add Airly integration
bieniu Sep 3, 2019
246deaf
Update .coveragerc file
bieniu Sep 3, 2019
756dcdf
Remove AVAILABLE_CONDITIONS and fix device_class
bieniu Sep 4, 2019
09f95a0
Don't create client on every update
bieniu Sep 5, 2019
4659cfe
Rename client to session
bieniu Sep 5, 2019
aba85f1
Rename state_attributes to device_state_attributes
bieniu Sep 5, 2019
46b5137
Remove log latitude and longitude
bieniu Sep 5, 2019
277fa45
Fix try...except
bieniu Sep 5, 2019
9c70f81
Change latitude and longitude to HA defaults
bieniu Sep 5, 2019
f27b0de
_show_config_form doesn't need coroutine
bieniu Sep 5, 2019
988a665
Simplify config_flow errors handlig
bieniu Sep 5, 2019
137299f
Preetier
bieniu Sep 5, 2019
5babee4
Remove unnecessary condition
bieniu Sep 5, 2019
1ac9ff2
Change sensor platform to air_quality
bieniu Sep 6, 2019
028810b
Remove PM1
bieniu Sep 13, 2019
f56b3d6
Make unique_id more unique
bieniu Sep 13, 2019
98080a5
Remove ,
bieniu Sep 13, 2019
d50d4c8
Add tests for config_flow
bieniu Sep 14, 2019
4ba2e2d
Move conf to CONFIG
bieniu Sep 14, 2019
7ad6a85
Merge branch 'dev' into airly
bieniu Sep 14, 2019
c784998
Remove domain from unique_id
bieniu Sep 15, 2019
08f7255
Change the way update of attrs
bieniu Sep 15, 2019
572b24e
Language and attrs
bieniu Sep 17, 2019
a620e85
Fix attrs
bieniu Sep 17, 2019
d6548cb
Merge branch 'airly' of https://github.com/bieniu/home-assistant into…
bieniu Sep 17, 2019
a8d1426
Add aiohttp error handling
bieniu Oct 1, 2019
38ad28d
Throttle as decorator
bieniu Oct 1, 2019
7681899
Suggested change
bieniu Oct 1, 2019
4b0457f
Suggested change
bieniu Oct 1, 2019
490ea7b
Invert condition
bieniu Oct 1, 2019
6354396
Cleaning
bieniu Oct 1, 2019
e475e02
Add tests
bieniu Oct 2, 2019
1f5eb77
Polish no sesnor error handling
bieniu Oct 2, 2019
bc76771
Better strings
bieniu Oct 2, 2019
8b2bff4
Fix test_invalid_api_key
bieniu Oct 2, 2019
c55f607
Fix documentation url
bieniu Oct 2, 2019
1dbb1aa
Remove unnecessary test
bieniu Oct 2, 2019
8834e72
Remove language option
bieniu Oct 2, 2019
cfaf576
Merge pull request #1 from home-assistant/dev
bieniu Oct 2, 2019
0b81c50
Fix test_invalid_api_key once again
bieniu Oct 3, 2019
703e9a8
Sort imports
bieniu Oct 3, 2019
c41d18e
Remove splits in strings
bieniu Oct 3, 2019
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -19,6 +19,7 @@ omit =
homeassistant/components/adguard/switch.py
homeassistant/components/ads/*
homeassistant/components/aftership/sensor.py
homeassistant/components/airly/*
homeassistant/components/airvisual/sensor.py
homeassistant/components/aladdin_connect/cover.py
homeassistant/components/alarm_control_panel/manual_mqtt.py
@@ -14,6 +14,7 @@ homeassistant/scripts/check_config.py @kellerza

# Integrations
homeassistant/components/adguard/* @frenck
homeassistant/components/airly/* @bieniu
homeassistant/components/airvisual/* @bachya
homeassistant/components/alarm_control_panel/* @colinodell
homeassistant/components/alpha_vantage/* @fabaff
@@ -0,0 +1,21 @@
"""The Airly component."""
from homeassistant.core import Config, HomeAssistant


async def async_setup(hass: HomeAssistant, config: Config) -> bool:
"""Set up configured Airly."""
return True


async def async_setup_entry(hass, config_entry):
"""Set up Airly as config entry."""
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, "sensor")
)
return True


async def async_unload_entry(hass, config_entry):
"""Unload a config entry."""
await hass.config_entries.async_forward_entry_unload(config_entry, "sensor")
return True
@@ -0,0 +1,125 @@
"""Adds config flow for Airly."""
from airly import Airly
This conversation was marked as resolved by MartinHjelmare

This comment has been minimized.

Copy link
@MartinHjelmare

MartinHjelmare Sep 3, 2019

Member

Please sort imports according to PEP8.

from airly.exceptions import AirlyError
import async_timeout
import voluptuous as vol

from homeassistant import config_entries
from homeassistant.const import CONF_API_KEY, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME
from homeassistant.core import callback
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv

from .const import (
CONF_LANGUAGE,
DEFAULT_LANGUAGE,
DEFAULT_NAME,
DOMAIN,
LANGUAGE_CODES,
NO_AIRLY_SENSORS,
)


@callback
def configured_instances(hass):
"""Return a set of configured Airly instances."""
return set(
entry.data[CONF_NAME] for entry in hass.config_entries.async_entries(DOMAIN)
)


class AirlyFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
"""Config flow for Airly."""

VERSION = 1
CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL

def __init__(self):
"""Initialize."""
self._errors = {}

async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
self._errors = {}

websession = async_get_clientsession(self.hass)

if user_input is not None:
api_key_valid = await self._test_api_key(websession, user_input["api_key"])
if api_key_valid:
location_valid = await self._test_location(
websession,
user_input["api_key"],
user_input["latitude"],
user_input["longitude"],
)
if location_valid:
if user_input[CONF_LANGUAGE] in LANGUAGE_CODES:
if user_input[CONF_NAME] not in configured_instances(self.hass):
return self.async_create_entry(
title=user_input[CONF_NAME], data=user_input
)
self._errors[CONF_NAME] = "name_exists"
else:
self._errors["base"] = "wrong_lang"
else:
self._errors["base"] = "wrong_location"
else:
self._errors["base"] = "auth"

return await self._show_config_form(
name=DEFAULT_NAME,
api_key="",
latitude=self.hass.config.latitude,
longitude=self.hass.config.longitude,
language=DEFAULT_LANGUAGE,
)

async def _show_config_form(
This conversation was marked as resolved by MartinHjelmare

This comment has been minimized.

Copy link
@MartinHjelmare

MartinHjelmare Sep 3, 2019

Member

This doesn't need to be a coroutine since we don't need to await inside.

self, name=None, api_key=None, latitude=None, longitude=None, language=None
):
"""Show the configuration form to edit data."""
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(CONF_API_KEY, default=api_key): str,
vol.Required(CONF_LATITUDE, default=latitude): cv.latitude,
This conversation was marked as resolved by MartinHjelmare

This comment has been minimized.

Copy link
@MartinHjelmare

MartinHjelmare Sep 3, 2019

Member

Default to the latitude and longitude configured in hass.config and make these optional items.

This comment has been minimized.

Copy link
@bieniu

bieniu Sep 3, 2019

Author Contributor

@MartinHjelmare Latitude and longitude are required to fetch data from Airly. Why they should be optional?

This comment has been minimized.

Copy link
@MartinHjelmare

MartinHjelmare Sep 3, 2019

Member

Because the user may have configured them already. If we have defaults the items are by definition not required anymore.

vol.Required(CONF_LONGITUDE, default=longitude): cv.longitude,
vol.Optional(CONF_NAME, default=name): str,
vol.Optional(CONF_LANGUAGE, default=language): str,
}
),
errors=self._errors,
)

async def _test_api_key(self, client, api_key):
"""Return true if api_key is valid."""

try:
with async_timeout.timeout(10):
airly = Airly(api_key, client)
measurements = airly.create_measurements_session_point(
latitude=52.24131, longitude=20.99101
)

await measurements.update()
return True
except AirlyError:
This conversation was marked as resolved by MartinHjelmare

This comment has been minimized.

Copy link
@MartinHjelmare

MartinHjelmare Sep 3, 2019

Member

Please wrap as narrowly as possible with the try... except.

Move the return True down out of the try...except and return False on error instead.

pass
return False

async def _test_location(self, client, api_key, latitude, longitude):
"""Return true if location is valid."""

with async_timeout.timeout(10):
airly = Airly(api_key, client)
measurements = airly.create_measurements_session_point(
latitude=latitude, longitude=longitude
)

await measurements.update()
current = measurements.current
if current["indexes"][0]["description"] == NO_AIRLY_SENSORS:
return False
return True
@@ -0,0 +1,8 @@
"""Constants for Airly integration."""

CONF_LANGUAGE = "language"
DEFAULT_LANGUAGE = "en"
DEFAULT_NAME = "Airly"
DOMAIN = "airly"
LANGUAGE_CODES = ["en", "pl"]
NO_AIRLY_SENSORS = "There are no Airly sensors in this area yet."
@@ -0,0 +1,11 @@
{
"domain": "airly",
"name": "Airly",
"documentation": "https://www.home-assistant.io/components/airly",
"dependencies": [],
"codeowners": [
"@bieniu"
],
"requirements": ["airly==0.0.2"],
"config_flow": true
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.