Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
15b1a9e
Add numato integration (#33816)
clssn Apr 30, 2020
a65edc8
Fix crash in NAD integration (#34571)
gladhorn Apr 30, 2020
29a05a6
Add fortigate deprecation message (#34854)
kifeo Apr 30, 2020
55bf551
Add overlay options wrapper to rpi_camera (#34461)
alxrdn Apr 30, 2020
d43617c
Bump brother to 0.1.14 (#34930)
bieniu Apr 30, 2020
bf5cc22
Fix preservation of homekit fan speed on toggle (#34971)
bdraco Apr 30, 2020
435a886
Address new issues flagged by flake8 3.8.0a2 (#34964)
scop Apr 30, 2020
d4b6671
Remove panasonic_viera from legacy discovery (#34909)
Apr 30, 2020
6b16c34
Improve logging for unregistered webhooks (#34882)
danielperna84 Apr 30, 2020
ec47216
Use built-in test helpers on 3.8 (#34901)
balloob Apr 30, 2020
6fe0049
Fix webhook imports sorting (#34988)
MartinHjelmare Apr 30, 2020
928d9ec
Fix not condition validation and entity/device extraction (#34959)
frenck Apr 30, 2020
799d98e
Cleanup homekit callbacks and jobs (#34975)
bdraco Apr 30, 2020
ba73915
Add unique id to esphome config flow (#34753)
ctalkington Apr 30, 2020
76f3924
Use a future for mock coro (#34989)
balloob Apr 30, 2020
6056753
Introduce a singleton decorator (#34803)
balloob Apr 30, 2020
bd72ddd
[ci skip] Translation update
homeassistant May 1, 2020
4e55fa6
Refactor Remote class in panasonic_viera (#34911)
May 1, 2020
208fa84
Update excess powerwall logging to be debug (#34994)
bdraco May 1, 2020
cfc0edf
Log the rachio webhook url (#34992)
bdraco May 1, 2020
a2efc07
Add battery sensors to hunterdouglas_powerview (#34917)
bdraco May 1, 2020
5699cb8
Add allow extra to totalconnect config schema (#34993)
austinmroczek May 1, 2020
793592b
Config flow for homekit (#34560)
bdraco May 1, 2020
3e06e6b
Don't attempt to set Vizio is_volume_muted property if Vizio API does…
raman325 May 1, 2020
7b90cbd
UniFi - Disconnected clients wrongfully marked as wired not created (…
Kane610 May 1, 2020
1f66821
Support num_repeats for directv remote (#34982)
ctalkington May 1, 2020
bb08959
Support num_repeats for roku remote (#34981)
ctalkington May 1, 2020
225059f
Fix roomba not reporting error (#34996)
shenxn May 1, 2020
8f94674
Remove some passings of loop (#34995)
balloob May 1, 2020
03bb2a6
Lint roomba (#35000)
balloob May 1, 2020
72e7bee
UniFi - Add simple options flow (#34990)
Kane610 May 1, 2020
82a478e
Fix MQTT debug info for same topic (#34952)
emontnemery May 1, 2020
af62660
Attempt to fix flapping august lock test (#34998)
bdraco May 1, 2020
e7157f2
Fix restoring isy994 brightness with no previous state (#34972)
bdraco May 1, 2020
850b5cb
Config flow for ONVIF (#34520)
hunterjm May 1, 2020
a2896b4
Add flow and return sensors for MELCloud ATW device (#34693)
May 1, 2020
8ec5e53
Add full options to serial sensor platform (#34962)
guiguid May 1, 2020
66d3832
Fix MELCloud temperature unit (#35003)
May 1, 2020
be58c4f
Fix unknown exception being caught (#35005)
shenxn May 1, 2020
1cfa46d
Fix CI, incomplete change in melcloud (#35016)
frenck May 1, 2020
f3d7910
Rename WaterHeaterDevice to WaterHeaterEntity (#34675)
emontnemery May 1, 2020
8c65062
Several optimizations to automations (#35007)
frenck May 1, 2020
ea70d71
Use pulsectl library for PulseAudio connection (#34965)
breiti May 1, 2020
2b13a8c
Include QoS and retain in MQTT debug info (#35011)
emontnemery May 1, 2020
e6be297
Bump HAP-python to 2.8.3 (#35023)
bdraco May 1, 2020
8661cf4
Update AirVisual to use DataUpdateCoordinator (#34796)
bachya May 1, 2020
a65e656
Add more SNMP variable types (#33426)
Mich-b May 1, 2020
9436645
Fix songpal on devices where source!=uri (#34699)
rytilahti May 1, 2020
b320152
Fix translation merging for custom components without translations (#…
balloob May 1, 2020
e1ae455
Fix ONVIF YAML import (#35035)
frenck May 1, 2020
ecdcfb8
Add yeelight meteorite (YLDL01YL, ceiling10) (#35018)
rytilahti May 1, 2020
dff2ee2
Bump python-synology to 0.7.4 (#35052)
Quentame May 1, 2020
f4f2aff
[ci skip] Translation update
homeassistant May 2, 2020
842e099
Cleanup homekit strings spacing (#35056)
bdraco May 2, 2020
187392d
Bump hass-nabucasa to 0.34.2 (#35046)
balloob May 2, 2020
9632369
Fix another race in august tests (#35054)
bdraco May 2, 2020
d9b9a00
Fix Canary doing I/O in the event loop (#35039)
bachya May 2, 2020
0519b96
Add scene to default config (#35058)
balloob May 2, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 3 additions & 2 deletions .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ omit =
homeassistant/components/hue/light.py
homeassistant/components/hunterdouglas_powerview/__init__.py
homeassistant/components/hunterdouglas_powerview/scene.py
homeassistant/components/hunterdouglas_powerview/sensor.py
homeassistant/components/hunterdouglas_powerview/cover.py
homeassistant/components/hunterdouglas_powerview/entity.py
homeassistant/components/hydrawise/*
Expand Down Expand Up @@ -506,6 +507,7 @@ omit =
homeassistant/components/ombi/*
homeassistant/components/onewire/sensor.py
homeassistant/components/onkyo/media_player.py
homeassistant/components/onvif/__init__.py
homeassistant/components/onvif/camera.py
homeassistant/components/opencv/*
homeassistant/components/openevse/sensor.py
Expand All @@ -531,7 +533,6 @@ omit =
homeassistant/components/osramlightify/light.py
homeassistant/components/otp/sensor.py
homeassistant/components/panasonic_bluray/media_player.py
homeassistant/components/panasonic_viera/__init__.py
homeassistant/components/panasonic_viera/media_player.py
homeassistant/components/pandora/media_player.py
homeassistant/components/pcal9535a/*
Expand Down Expand Up @@ -611,7 +612,7 @@ omit =
homeassistant/components/roomba/vacuum.py
homeassistant/components/route53/*
homeassistant/components/rova/sensor.py
homeassistant/components/rpi_camera/camera.py
homeassistant/components/rpi_camera/*
homeassistant/components/rpi_gpio/*
homeassistant/components/rpi_gpio/cover.py
homeassistant/components/rpi_gpio_pwm/light.py
Expand Down
3 changes: 3 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ homeassistant/components/ipp/* @ctalkington
homeassistant/components/iqvia/* @bachya
homeassistant/components/irish_rail_transport/* @ttroy50
homeassistant/components/islamic_prayer_times/* @engrbm87
homeassistant/components/isy994/* @bdraco
homeassistant/components/izone/* @Swamp-Ig
homeassistant/components/jewish_calendar/* @tsvi
homeassistant/components/juicenet/* @jesserockz
Expand Down Expand Up @@ -267,6 +268,7 @@ homeassistant/components/nsw_fuel_station/* @nickw444
homeassistant/components/nsw_rural_fire_service_feed/* @exxamalte
homeassistant/components/nuheat/* @bdraco
homeassistant/components/nuki/* @pvizeli
homeassistant/components/numato/* @clssn
homeassistant/components/nut/* @bdraco
homeassistant/components/nws/* @MatthewFlamm
homeassistant/components/nzbget/* @chriscla
Expand All @@ -275,6 +277,7 @@ homeassistant/components/ohmconnect/* @robbiet480
homeassistant/components/ombi/* @larssont
homeassistant/components/onboarding/* @home-assistant/core
homeassistant/components/onewire/* @garbled1
homeassistant/components/onvif/* @hunterjm
homeassistant/components/openerz/* @misialq
homeassistant/components/opentherm_gw/* @mvn23
homeassistant/components/openuv/* @bachya
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/adguard/translations/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"username": "\u041b\u043e\u0433\u0438\u043d",
"verify_ssl": "AdGuard Home \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442"
},
"description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 \u044d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0434\u043b\u044f \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f AdGuard Home.",
"description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 Home Assistant \u0434\u043b\u044f \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f AdGuard Home.",
"title": "AdGuard Home"
}
}
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/airly/translations/ca.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"longitude": "Longitud",
"name": "Nom de la integraci\u00f3"
},
"description": "Configura una integraci\u00f3 de qualitat d\u2019aire Airly. Per generar la clau API, v\u00e9s a https://developer.airly.eu/register",
"description": "Configura una integraci\u00f3 de qualitat d'aire Airly. Per generar la clau API, v\u00e9s a https://developer.airly.eu/register",
"title": "Airly"
}
}
Expand Down
171 changes: 64 additions & 107 deletions homeassistant/components/airvisual/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,23 @@
)
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client, config_validation as cv
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect,
async_dispatcher_send,
)
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import (
CONF_CITY,
CONF_COUNTRY,
CONF_GEOGRAPHIES,
CONF_INTEGRATION_TYPE,
DATA_CLIENT,
DATA_COORDINATOR,
DOMAIN,
INTEGRATION_TYPE_GEOGRAPHY,
INTEGRATION_TYPE_NODE_PRO,
LOGGER,
TOPIC_UPDATE,
)

PLATFORMS = ["air_quality", "sensor"]

DATA_LISTENER = "listener"

DEFAULT_ATTRIBUTION = "Data provided by AirVisual"
DEFAULT_GEOGRAPHY_SCAN_INTERVAL = timedelta(minutes=10)
DEFAULT_NODE_PRO_SCAN_INTERVAL = timedelta(minutes=1)
Expand Down Expand Up @@ -97,7 +90,7 @@ def async_get_geography_id(geography_dict):

async def async_setup(hass, config):
"""Set up the AirVisual component."""
hass.data[DOMAIN] = {DATA_CLIENT: {}, DATA_LISTENER: {}}
hass.data[DOMAIN] = {DATA_COORDINATOR: {}}

if DOMAIN not in config:
return True
Expand Down Expand Up @@ -167,35 +160,71 @@ async def async_setup_entry(hass, config_entry):

if CONF_API_KEY in config_entry.data:
_standardize_geography_config_entry(hass, config_entry)
airvisual = AirVisualGeographyData(

client = Client(api_key=config_entry.data[CONF_API_KEY], session=websession)

async def async_update_data():
"""Get new data from the API."""
if CONF_CITY in config_entry.data:
api_coro = client.api.city(
config_entry.data[CONF_CITY],
config_entry.data[CONF_STATE],
config_entry.data[CONF_COUNTRY],
)
else:
api_coro = client.api.nearest_city(
config_entry.data[CONF_LATITUDE], config_entry.data[CONF_LONGITUDE],
)

try:
return await api_coro
except AirVisualError as err:
raise UpdateFailed(f"Error while retrieving data: {err}")

coordinator = DataUpdateCoordinator(
hass,
Client(api_key=config_entry.data[CONF_API_KEY], session=websession),
config_entry,
LOGGER,
name="geography data",
update_interval=DEFAULT_GEOGRAPHY_SCAN_INTERVAL,
update_method=async_update_data,
)

# Only geography-based entries have options:
config_entry.add_update_listener(async_update_options)
else:
_standardize_node_pro_config_entry(hass, config_entry)
airvisual = AirVisualNodeProData(hass, Client(session=websession), config_entry)

await airvisual.async_update()
client = Client(session=websession)

hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id] = airvisual
async def async_update_data():
"""Get new data from the API."""
try:
return await client.node.from_samba(
config_entry.data[CONF_IP_ADDRESS],
config_entry.data[CONF_PASSWORD],
include_history=False,
include_trends=False,
)
except NodeProError as err:
raise UpdateFailed(f"Error while retrieving data: {err}")

coordinator = DataUpdateCoordinator(
hass,
LOGGER,
name="Node/Pro data",
update_interval=DEFAULT_NODE_PRO_SCAN_INTERVAL,
update_method=async_update_data,
)

await coordinator.async_refresh()

hass.data[DOMAIN][DATA_COORDINATOR][config_entry.entry_id] = coordinator

for component in PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, component)
)

async def refresh(event_time):
"""Refresh data from AirVisual."""
await airvisual.async_update()

hass.data[DOMAIN][DATA_LISTENER][config_entry.entry_id] = async_track_time_interval(
hass, refresh, airvisual.scan_interval
)

return True


Expand Down Expand Up @@ -248,28 +277,31 @@ async def async_unload_entry(hass, config_entry):
)
)
if unload_ok:
hass.data[DOMAIN][DATA_CLIENT].pop(config_entry.entry_id)
remove_listener = hass.data[DOMAIN][DATA_LISTENER].pop(config_entry.entry_id)
remove_listener()
hass.data[DOMAIN][DATA_COORDINATOR].pop(config_entry.entry_id)

return unload_ok


async def async_update_options(hass, config_entry):
"""Handle an options update."""
airvisual = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id]
airvisual.async_update_options(config_entry.options)
coordinator = hass.data[DOMAIN][DATA_COORDINATOR][config_entry.entry_id]
await coordinator.async_request_refresh()


class AirVisualEntity(Entity):
"""Define a generic AirVisual entity."""

def __init__(self, airvisual):
def __init__(self, coordinator):
"""Initialize."""
self._airvisual = airvisual
self._attrs = {ATTR_ATTRIBUTION: DEFAULT_ATTRIBUTION}
self._icon = None
self._unit = None
self.coordinator = coordinator

@property
def available(self):
"""Return if entity is available."""
return self.coordinator.last_update_success

@property
def device_state_attributes(self):
Expand All @@ -295,86 +327,11 @@ def update():
self.update_from_latest_data()
self.async_write_ha_state()

self.async_on_remove(
async_dispatcher_connect(self.hass, self._airvisual.topic_update, update)
)
self.async_on_remove(self.coordinator.async_add_listener(update))

self.update_from_latest_data()

@callback
def update_from_latest_data(self):
"""Update the entity from the latest data."""
raise NotImplementedError


class AirVisualGeographyData:
"""Define a class to manage data from the AirVisual cloud API."""

def __init__(self, hass, client, config_entry):
"""Initialize."""
self._client = client
self._hass = hass
self.data = {}
self.geography_data = config_entry.data
self.geography_id = config_entry.unique_id
self.integration_type = INTEGRATION_TYPE_GEOGRAPHY
self.options = config_entry.options
self.scan_interval = DEFAULT_GEOGRAPHY_SCAN_INTERVAL
self.topic_update = TOPIC_UPDATE.format(config_entry.unique_id)

async def async_update(self):
"""Get new data for all locations from the AirVisual cloud API."""
if CONF_CITY in self.geography_data:
api_coro = self._client.api.city(
self.geography_data[CONF_CITY],
self.geography_data[CONF_STATE],
self.geography_data[CONF_COUNTRY],
)
else:
api_coro = self._client.api.nearest_city(
self.geography_data[CONF_LATITUDE], self.geography_data[CONF_LONGITUDE],
)

try:
self.data[self.geography_id] = await api_coro
except AirVisualError as err:
LOGGER.error("Error while retrieving data: %s", err)
self.data[self.geography_id] = {}

LOGGER.debug("Received new geography data")
async_dispatcher_send(self._hass, self.topic_update)

@callback
def async_update_options(self, options):
"""Update the data manager's options."""
self.options = options
async_dispatcher_send(self._hass, self.topic_update)


class AirVisualNodeProData:
"""Define a class to manage data from an AirVisual Node/Pro."""

def __init__(self, hass, client, config_entry):
"""Initialize."""
self._client = client
self._hass = hass
self._password = config_entry.data[CONF_PASSWORD]
self.data = {}
self.integration_type = INTEGRATION_TYPE_NODE_PRO
self.ip_address = config_entry.data[CONF_IP_ADDRESS]
self.scan_interval = DEFAULT_NODE_PRO_SCAN_INTERVAL
self.topic_update = TOPIC_UPDATE.format(config_entry.data[CONF_IP_ADDRESS])

async def async_update(self):
"""Get new data from the Node/Pro."""
try:
self.data = await self._client.node.from_samba(
self.ip_address, self._password, include_history=False
)
except NodeProError as err:
LOGGER.error("Error while retrieving Node/Pro data: %s", err)
self.data = {}
return

LOGGER.debug("Received new Node/Pro data")
async_dispatcher_send(self._hass, self.topic_update)
Loading