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 air pollutants component #18707

Merged
merged 9 commits into from Dec 14, 2018
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
172 changes: 172 additions & 0 deletions homeassistant/components/air_pollutants/__init__.py
@@ -0,0 +1,172 @@
"""
Component for handling Air Pollutants data for your location.

For more details about this component, please refer to the documentation at
https://home-assistant.io/components/air_pollutants/
"""
import logging

from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
from homeassistant.helpers.entity import Entity

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'air_pollutants'

ENTITY_ID_FORMAT = DOMAIN + '.{}'

ATTR_AIR_POLLUTANTS_AQI = 'air_quality_index'
ATTR_AIR_POLLUTANTS_ATTRIBUTION = 'attribution'
ATTR_AIR_POLLUTANTS_C02 = 'carbon_dioxide'
ATTR_AIR_POLLUTANTS_CO = 'carbon_monoxide'
ATTR_AIR_POLLUTANTS_N2O = 'nitrogen_oxide'
ATTR_AIR_POLLUTANTS_NO = 'nitrogen_monoxide'
ATTR_AIR_POLLUTANTS_NO2 = 'nitrogen_dioxide'
ATTR_AIR_POLLUTANTS_OZONE = 'ozone'
ATTR_AIR_POLLUTANTS_PM_0_1 = 'particulate_matter_0_1'
ATTR_AIR_POLLUTANTS_PM_10 = 'particulate_matter_10'
ATTR_AIR_POLLUTANTS_PM_2_5 = 'particulate_matter_2_5'
ATTR_AIR_POLLUTANTS_SO2 = 'sulphur_dioxide'


async def async_setup(hass, config):
"""Set up the air pollutants component."""
component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass)
Copy link
Member

Choose a reason for hiding this comment

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

Should we set the default scan interval to 30 seconds as for sensors, instead of 15 seconds as is the main default?

Copy link
Member Author

Choose a reason for hiding this comment

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

We should.

await component.async_setup(config)
return True


async def async_setup_entry(hass, entry):
"""Set up a config entry."""
return await hass.data[DOMAIN].async_setup_entry(entry)


async def async_unload_entry(hass, entry):
"""Unload a config entry."""
return await hass.data[DOMAIN].async_unload_entry(entry)


class AirPollutantsEntity(Entity):
"""ABC for air pollutants data."""

@property
def particulate_matter_2_5(self):
"""Return the particulate matter 2.5 level."""
raise NotImplementedError()

@property
def particulate_matter_10(self):
"""Return the particulate matter 10 level."""
return None

@property
def particulate_matter_0_1(self):
"""Return the particulate matter 0.1 level."""
return None

@property
def temperature_unit(self):
"""Return the unit of measurement of the temperature."""
return None

@property
def air_quality_index(self):
"""Return the Air Quality Index (AQI)."""
return None

@property
def ozone(self):
"""Return the O3 (ozone) level."""
return None

@property
def carbon_monoxide(self):
"""Return the CO (carbon monoxide) level."""
return None

@property
def carbon_dioxide(self):
"""Return the CO2 (carbon dioxide) level."""
return None

@property
def attribution(self):
"""Return the attribution."""
return None

@property
def sulphur_dioxide(self):
"""Return the SO2 (sulphur dioxide) level."""
return None

@property
def nitrogen_oxide(self):
"""Return the N2O (nitrogen oxide) level."""
return None

@property
def nitrogen_monoxide(self):
"""Return the NO (nitrogen monoxide) level."""
return None

@property
def nitrogen_dioxide(self):
"""Return the NO2 (nitrogen dioxide) level."""
return None

@property
def state_attributes(self):
"""Return the state attributes."""
data = {}

air_quality_index = self.air_quality_index
if air_quality_index is not None:
data[ATTR_AIR_POLLUTANTS_AQI] = air_quality_index

ozone = self.ozone
if ozone is not None:
data[ATTR_AIR_POLLUTANTS_OZONE] = ozone

particulate_matter_0_1 = self.particulate_matter_0_1
Copy link
Member

Choose a reason for hiding this comment

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

We've used a PROP_TO_ATTR dictionary before to prevent the repetition.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks

if particulate_matter_0_1 is not None:
data[ATTR_AIR_POLLUTANTS_PM_0_1] = particulate_matter_0_1

particulate_matter_10 = self.particulate_matter_10
if particulate_matter_10 is not None:
data[ATTR_AIR_POLLUTANTS_PM_10] = particulate_matter_10

sulphur_dioxide = self.sulphur_dioxide
if sulphur_dioxide is not None:
data[ATTR_AIR_POLLUTANTS_SO2] = sulphur_dioxide

nitrogen_oxide = self.nitrogen_oxide
if nitrogen_oxide is not None:
data[ATTR_AIR_POLLUTANTS_N2O] = nitrogen_oxide

nitrogen_monoxide = self.nitrogen_monoxide
if nitrogen_monoxide is not None:
data[ATTR_AIR_POLLUTANTS_NO] = nitrogen_monoxide

nitrogen_dioxide = self.nitrogen_dioxide
if nitrogen_dioxide is not None:
data[ATTR_AIR_POLLUTANTS_NO2] = nitrogen_dioxide

carbon_dioxide = self.carbon_dioxide
if carbon_dioxide is not None:
data[ATTR_AIR_POLLUTANTS_C02] = carbon_dioxide

carbon_monoxide = self.carbon_monoxide
if carbon_monoxide is not None:
data[ATTR_AIR_POLLUTANTS_CO] = carbon_monoxide

attribution = self.attribution
if attribution is not None:
data[ATTR_AIR_POLLUTANTS_ATTRIBUTION] = attribution

return data

@property
def state(self):
"""Return the current state."""
return self.particulate_matter_2_5
56 changes: 56 additions & 0 deletions homeassistant/components/air_pollutants/demo.py
@@ -0,0 +1,56 @@
"""
Demo platform that offers fake air pollutants data.

For more details about this platform, please refer to the documentation
https://home-assistant.io/components/demo/
"""
from homeassistant.components.air_pollutants import AirPollutantsEntity


def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Air Pollutants."""
add_entities([
DemoAirPollutants('Home', 14, 23, 100),
DemoAirPollutants('Office', 4, 16, None)
])


class DemoAirPollutants(AirPollutantsEntity):
"""Representation of Air Pollutants data."""

def __init__(self, name, pm_2_5, pm_10, n2o):
"""Initialize the Demo Air Pollutants."""
self._name = name
self._pm_2_5 = pm_2_5
self._pm_10 = pm_10
self._n2o = n2o

@property
def name(self):
"""Return the name of the sensor."""
return '{} {}'.format('Demo Air Pollutants', self._name)

@property
def should_poll(self):
"""No polling needed for Demo Air Pollutants."""
return False

@property
def particulate_matter_2_5(self):
"""Return the particulate matter 2.5 level."""
return self._pm_2_5

@property
def particulate_matter_10(self):
"""Return the particulate matter 10 level."""
return self._pm_10

@property
def nitrogen_oxide(self):
"""Return the nitrogen oxide (N2O) level."""
return self._n2o

@property
def attribution(self):
"""Return the attribution."""
return 'Powered by Home Assistant'
1 change: 1 addition & 0 deletions homeassistant/components/demo.py
Expand Up @@ -15,6 +15,7 @@
DOMAIN = 'demo'

COMPONENTS_WITH_DEMO_PLATFORM = [
'air_pollutants',
'alarm_control_panel',
'binary_sensor',
'calendar',
Expand Down
1 change: 1 addition & 0 deletions tests/components/air_pollutants/__init__.py
@@ -0,0 +1 @@
"""The tests for Air Pollutants platforms."""
42 changes: 42 additions & 0 deletions tests/components/air_pollutants/test_air_pollutants.py
@@ -0,0 +1,42 @@
"""The tests for the Air Pollutants component."""
from homeassistant.components.air_pollutants import (
ATTR_AIR_POLLUTANTS_ATTRIBUTION, ATTR_AIR_POLLUTANTS_N2O,
ATTR_AIR_POLLUTANTS_OZONE, ATTR_AIR_POLLUTANTS_PM_10)
from homeassistant.setup import async_setup_component


async def test_state(hass):
"""Test Air Pollutants state."""
config = {
'air_pollutants': {
'platform': 'demo',
}
}

assert await async_setup_component(hass, 'air_pollutants', config)

state = hass.states.get('air_pollutants.demo_air_pollutants_home')
assert state is not None

assert state.state == '14'


async def test_attributes(hass):
"""Test Air Pollutants attributes."""
config = {
'air_pollutants': {
'platform': 'demo',
}
}

assert await async_setup_component(hass, 'air_pollutants', config)

state = hass.states.get('air_pollutants.demo_air_pollutants_office')
assert state is not None

data = state.attributes
assert data.get(ATTR_AIR_POLLUTANTS_PM_10) == 16
assert data.get(ATTR_AIR_POLLUTANTS_N2O) is None
assert data.get(ATTR_AIR_POLLUTANTS_OZONE) is None
assert data.get(ATTR_AIR_POLLUTANTS_ATTRIBUTION) == \
'Powered by Home Assistant'