diff --git a/homeassistant/components/air_pollutants/__init__.py b/homeassistant/components/air_pollutants/__init__.py new file mode 100644 index 00000000000..7391e8c9975 --- /dev/null +++ b/homeassistant/components/air_pollutants/__init__.py @@ -0,0 +1,176 @@ +""" +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/ +""" +from datetime import timedelta +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__) + +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' + +DOMAIN = 'air_pollutants' + +ENTITY_ID_FORMAT = DOMAIN + '.{}' + +SCAN_INTERVAL = timedelta(seconds=30) + + +async def async_setup(hass, config): + """Set up the air pollutants component.""" + component = hass.data[DOMAIN] = EntityComponent( + _LOGGER, DOMAIN, hass, SCAN_INTERVAL) + 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 + 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 diff --git a/homeassistant/components/air_pollutants/demo.py b/homeassistant/components/air_pollutants/demo.py new file mode 100644 index 00000000000..06c407d8608 --- /dev/null +++ b/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' diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index 8999087a137..d1bca45400b 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -15,6 +15,7 @@ DEPENDENCIES = ['conversation', 'introduction', 'zone'] DOMAIN = 'demo' COMPONENTS_WITH_DEMO_PLATFORM = [ + 'air_pollutants', 'alarm_control_panel', 'binary_sensor', 'calendar', diff --git a/tests/components/air_pollutants/__init__.py b/tests/components/air_pollutants/__init__.py new file mode 100644 index 00000000000..98af2395a1f --- /dev/null +++ b/tests/components/air_pollutants/__init__.py @@ -0,0 +1 @@ +"""The tests for Air Pollutants platforms.""" diff --git a/tests/components/air_pollutants/test_air_pollutants.py b/tests/components/air_pollutants/test_air_pollutants.py new file mode 100644 index 00000000000..bbbd85b3a0c --- /dev/null +++ b/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'