Add config entry and device support to Demo ()

* Add config entry and device support to Demo

* Some more devices

* Fix tests using demo

* Review comments

* Update config_flow.py

* Revert

* Disable pylint
pull/28754/head
Bram Kragten 2019-11-13 16:37:31 +01:00 committed by GitHub
parent 15ce738357
commit 15e6278a2e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 305 additions and 54 deletions

View File

@ -3,43 +3,51 @@ import asyncio
import logging
import time
from homeassistant import bootstrap
from homeassistant import bootstrap, config_entries
import homeassistant.core as ha
from homeassistant.const import ATTR_ENTITY_ID, EVENT_HOMEASSISTANT_START
DOMAIN = "demo"
_LOGGER = logging.getLogger(__name__)
COMPONENTS_WITH_DEMO_PLATFORM = [
COMPONENTS_WITH_CONFIG_ENTRY_DEMO_PLATFORM = [
"air_quality",
"alarm_control_panel",
"binary_sensor",
"calendar",
"camera",
"climate",
"cover",
"device_tracker",
"fan",
"image_processing",
"light",
"lock",
"media_player",
"notify",
"sensor",
"stt",
"switch",
"tts",
"mailbox",
"water_heater",
]
COMPONENTS_WITH_DEMO_PLATFORM = [
"tts",
"stt",
"mailbox",
"notify",
"image_processing",
"calendar",
"device_tracker",
]
async def async_setup(hass, config):
"""Set up the demo environment."""
if DOMAIN not in config:
return True
config.setdefault(ha.DOMAIN, {})
config.setdefault(DOMAIN, {})
if not hass.config_entries.async_entries(DOMAIN):
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, data={}
)
)
# Set up demo platforms
for component in COMPONENTS_WITH_DEMO_PLATFORM:
@ -47,6 +55,9 @@ async def async_setup(hass, config):
hass.helpers.discovery.async_load_platform(component, DOMAIN, {}, config)
)
config.setdefault(ha.DOMAIN, {})
config.setdefault(DOMAIN, {})
# Set up sun
if not hass.config.latitude:
hass.config.latitude = 32.87336
@ -176,6 +187,16 @@ async def async_setup(hass, config):
return True
async def async_setup_entry(hass, config_entry):
"""Set the config entry up."""
# Set up demo platforms with config entry
for component in COMPONENTS_WITH_CONFIG_ENTRY_DEMO_PLATFORM:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, component)
)
return True
async def finish_setup(hass, config):
"""Finish set up once demo platforms are set up."""
switches = None

View File

@ -2,13 +2,18 @@
from homeassistant.components.air_quality import AirQualityEntity
def setup_platform(hass, config, add_entities, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the Air Quality."""
add_entities(
async_add_entities(
[DemoAirQuality("Home", 14, 23, 100), DemoAirQuality("Office", 4, 16, None)]
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)
class DemoAirQuality(AirQualityEntity):
"""Representation of Air Quality data."""

View File

@ -57,3 +57,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
)
]
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)

View File

@ -1,26 +1,49 @@
"""Demo platform that has two fake binary sensors."""
from homeassistant.components.binary_sensor import BinarySensorDevice
from . import DOMAIN
def setup_platform(hass, config, add_entities, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the Demo binary sensor platform."""
add_entities(
async_add_entities(
[
DemoBinarySensor("Basement Floor Wet", False, "moisture"),
DemoBinarySensor("Movement Backyard", True, "motion"),
DemoBinarySensor("binary_1", "Basement Floor Wet", False, "moisture"),
DemoBinarySensor("binary_2", "Movement Backyard", True, "motion"),
]
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)
class DemoBinarySensor(BinarySensorDevice):
"""representation of a Demo binary sensor."""
def __init__(self, name, state, device_class):
def __init__(self, unique_id, name, state, device_class):
"""Initialize the demo sensor."""
self._unique_id = unique_id
self._name = name
self._state = state
self._sensor_type = device_class
@property
def device_info(self):
"""Return device info."""
return {
"identifiers": {
# Serial numbers are unique identifiers within a specific domain
(DOMAIN, self.unique_id)
},
"name": self.name,
}
@property
def unique_id(self):
"""Return the unique id."""
return self._unique_id
@property
def device_class(self):
"""Return the class of this sensor."""

View File

@ -12,6 +12,11 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
async_add_entities([DemoCamera("Demo camera")])
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)
class DemoCamera(Camera):
"""The representation of a Demo camera."""

View File

@ -1,4 +1,5 @@
"""Demo platform that offers a fake climate device."""
import logging
from homeassistant.components.climate import ClimateDevice
from homeassistant.components.climate.const import (
ATTR_TARGET_TEMP_HIGH,
@ -20,15 +21,18 @@ from homeassistant.components.climate.const import (
HVAC_MODE_AUTO,
)
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS, TEMP_FAHRENHEIT
from . import DOMAIN
SUPPORT_FLAGS = 0
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_entities, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the Demo climate devices."""
add_entities(
async_add_entities(
[
DemoClimate(
unique_id="climate_1",
name="HeatPump",
target_temperature=68,
unit_of_measurement=TEMP_FAHRENHEIT,
@ -46,6 +50,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
hvac_modes=[HVAC_MODE_HEAT, HVAC_MODE_OFF],
),
DemoClimate(
unique_id="climate_2",
name="Hvac",
target_temperature=21,
unit_of_measurement=TEMP_CELSIUS,
@ -63,6 +68,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
hvac_modes=[mode for mode in HVAC_MODES if mode != HVAC_MODE_HEAT_COOL],
),
DemoClimate(
unique_id="climate_3",
name="Ecobee",
target_temperature=None,
unit_of_measurement=TEMP_CELSIUS,
@ -84,11 +90,17 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo climate devices config entry."""
await async_setup_platform(hass, {}, async_add_entities)
class DemoClimate(ClimateDevice):
"""Representation of a demo climate device."""
def __init__(
self,
unique_id,
name,
target_temperature,
unit_of_measurement,
@ -107,6 +119,7 @@ class DemoClimate(ClimateDevice):
preset_modes=None,
):
"""Initialize the climate device."""
self._unique_id = unique_id
self._name = name
self._support_flags = SUPPORT_FLAGS
if target_temperature is not None:
@ -143,6 +156,22 @@ class DemoClimate(ClimateDevice):
self._target_temperature_high = target_temp_high
self._target_temperature_low = target_temp_low
@property
def device_info(self):
"""Return device info."""
return {
"identifiers": {
# Serial numbers are unique identifiers within a specific domain
(DOMAIN, self.unique_id)
},
"name": self.name,
}
@property
def unique_id(self):
"""Return the unique id."""
return self._unique_id
@property
def supported_features(self):
"""Return the list of supported features."""

View File

@ -0,0 +1,16 @@
"""Config flow to configure demo component."""
from homeassistant import config_entries
# pylint: disable=unused-import
from . import DOMAIN
class DemoConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Demo configuration flow."""
VERSION = 1
async def async_step_import(self, import_info):
"""Set the config entry up from yaml."""
return self.async_create_entry(title="Demo", data={})

View File

@ -8,17 +8,19 @@ from homeassistant.components.cover import (
SUPPORT_OPEN,
CoverDevice,
)
from . import DOMAIN
def setup_platform(hass, config, add_entities, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the Demo covers."""
add_entities(
async_add_entities(
[
DemoCover(hass, "Kitchen Window"),
DemoCover(hass, "Hall Window", 10),
DemoCover(hass, "Living Room Window", 70, 50),
DemoCover(hass, "cover_1", "Kitchen Window"),
DemoCover(hass, "cover_2", "Hall Window", 10),
DemoCover(hass, "cover_3", "Living Room Window", 70, 50),
DemoCover(
hass,
"cover_4",
"Garage Door",
device_class="garage",
supported_features=(SUPPORT_OPEN | SUPPORT_CLOSE),
@ -27,12 +29,18 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)
class DemoCover(CoverDevice):
"""Representation of a demo cover."""
def __init__(
self,
hass,
unique_id,
name,
position=None,
tilt_position=None,
@ -41,6 +49,7 @@ class DemoCover(CoverDevice):
):
"""Initialize the cover."""
self.hass = hass
self._unique_id = unique_id
self._name = name
self._position = position
self._device_class = device_class
@ -59,6 +68,22 @@ class DemoCover(CoverDevice):
else:
self._closed = self.current_cover_position <= 0
@property
def device_info(self):
"""Return device info."""
return {
"identifiers": {
# Serial numbers are unique identifiers within a specific domain
(DOMAIN, self.unique_id)
},
"name": self.name,
}
@property
def unique_id(self):
"""Return unique ID for cover."""
return self._unique_id
@property
def name(self):
"""Return the name of the cover."""

View File

@ -15,9 +15,9 @@ FULL_SUPPORT = SUPPORT_SET_SPEED | SUPPORT_OSCILLATE | SUPPORT_DIRECTION
LIMITED_SUPPORT = SUPPORT_SET_SPEED
def setup_platform(hass, config, add_entities_callback, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the demo fan platform."""
add_entities_callback(
async_add_entities(
[
DemoFan(hass, "Living Room Fan", FULL_SUPPORT),
DemoFan(hass, "Ceiling Fan", LIMITED_SUPPORT),
@ -25,6 +25,11 @@ def setup_platform(hass, config, add_entities_callback, discovery_info=None):
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)
class DemoFan(FanEntity):
"""A demonstration fan component."""

View File

@ -15,6 +15,8 @@ from homeassistant.components.light import (
Light,
)
from . import DOMAIN
LIGHT_COLORS = [(56, 86), (345, 75)]
LIGHT_EFFECT_LIST = ["rainbow", "none"]
@ -30,24 +32,33 @@ SUPPORT_DEMO = (
)
def setup_platform(hass, config, add_entities_callback, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the demo light platform."""
add_entities_callback(
async_add_entities(
[
DemoLight(
1,
"light_1",
"Bed Light",
False,
True,
effect_list=LIGHT_EFFECT_LIST,
effect=LIGHT_EFFECT_LIST[0],
),
DemoLight(2, "Ceiling Lights", True, True, LIGHT_COLORS[0], LIGHT_TEMPS[1]),
DemoLight(3, "Kitchen Lights", True, True, LIGHT_COLORS[1], LIGHT_TEMPS[0]),
DemoLight(
"light_2", "Ceiling Lights", True, True, LIGHT_COLORS[0], LIGHT_TEMPS[1]
),
DemoLight(
"light_3", "Kitchen Lights", True, True, LIGHT_COLORS[1], LIGHT_TEMPS[0]
),
]
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)
class DemoLight(Light):
"""Representation of a demo light."""
@ -76,6 +87,17 @@ class DemoLight(Light):
self._effect = effect
self._available = True
@property
def device_info(self):
"""Return device info."""
return {
"identifiers": {
# Serial numbers are unique identifiers within a specific domain
(DOMAIN, self.unique_id)
},
"name": self.name,
}
@property
def should_poll(self) -> bool:
"""No polling needed for a demo light."""

View File

@ -4,9 +4,9 @@ from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED
from homeassistant.components.lock import SUPPORT_OPEN, LockDevice
def setup_platform(hass, config, add_entities, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the Demo lock platform."""
add_entities(
async_add_entities(
[
DemoLock("Front Door", STATE_LOCKED),
DemoLock("Kitchen Door", STATE_UNLOCKED),
@ -15,6 +15,11 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)
class DemoLock(LockDevice):
"""Representation of a Demo lock."""

View File

@ -24,9 +24,9 @@ from homeassistant.const import STATE_OFF, STATE_PAUSED, STATE_PLAYING
import homeassistant.util.dt as dt_util
def setup_platform(hass, config, add_entities, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the media player demo platform."""
add_entities(
async_add_entities(
[
DemoYoutubePlayer(
"Living Room",
@ -43,6 +43,11 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)
YOUTUBE_COVER_URL_FORMAT = "https://img.youtube.com/vi/{}/hqdefault.jpg"
SOUND_MODE_LIST = ["Dummy Music", "Dummy Movie"]
DEFAULT_SOUND_MODE = "Dummy Music"

View File

@ -3,6 +3,11 @@ from homeassistant.components.remote import RemoteDevice
from homeassistant.const import DEVICE_DEFAULT_NAME
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
setup_platform(hass, {}, async_add_entities)
def setup_platform(hass, config, add_entities_callback, discovery_info=None):
"""Set up the demo remotes."""
add_entities_callback(

View File

@ -6,31 +6,63 @@ from homeassistant.const import (
DEVICE_CLASS_TEMPERATURE,
)
from homeassistant.helpers.entity import Entity
from . import DOMAIN
def setup_platform(hass, config, add_entities, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the Demo sensors."""
add_entities(
async_add_entities(
[
DemoSensor(
"Outside Temperature", 15.6, DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, 12
"sensor_1",
"Outside Temperature",
15.6,
DEVICE_CLASS_TEMPERATURE,
TEMP_CELSIUS,
12,
),
DemoSensor(
"sensor_2", "Outside Humidity", 54, DEVICE_CLASS_HUMIDITY, "%", None
),
DemoSensor("Outside Humidity", 54, DEVICE_CLASS_HUMIDITY, "%", None),
]
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)
class DemoSensor(Entity):
"""Representation of a Demo sensor."""
def __init__(self, name, state, device_class, unit_of_measurement, battery):
def __init__(
self, unique_id, name, state, device_class, unit_of_measurement, battery
):
"""Initialize the sensor."""
self._unique_id = unique_id
self._name = name
self._state = state
self._device_class = device_class
self._unit_of_measurement = unit_of_measurement
self._battery = battery
@property
def device_info(self):
"""Return device info."""
return {
"identifiers": {
# Serial numbers are unique identifiers within a specific domain
(DOMAIN, self.unique_id)
},
"name": self.name,
}
@property
def unique_id(self):
"""Return the unique id."""
return self._unique_id
@property
def should_poll(self):
"""No polling needed for a demo sensor."""

View File

@ -0,0 +1,5 @@
{
"config": {
"title": "Demo"
}
}

View File

@ -1,29 +1,52 @@
"""Demo platform that has two fake switches."""
from homeassistant.components.switch import SwitchDevice
from homeassistant.const import DEVICE_DEFAULT_NAME
from . import DOMAIN
def setup_platform(hass, config, add_entities_callback, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the demo switches."""
add_entities_callback(
async_add_entities(
[
DemoSwitch("Decorative Lights", True, None, True),
DemoSwitch("AC", False, "mdi:air-conditioner", False),
DemoSwitch("swith1", "Decorative Lights", True, None, True),
DemoSwitch("swith2", "AC", False, "mdi:air-conditioner", False),
]
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)
class DemoSwitch(SwitchDevice):
"""Representation of a demo switch."""
def __init__(self, name, state, icon, assumed, device_class=None):
def __init__(self, unique_id, name, state, icon, assumed, device_class=None):
"""Initialize the Demo switch."""
self._unique_id = unique_id
self._name = name or DEVICE_DEFAULT_NAME
self._state = state
self._icon = icon
self._assumed = assumed
self._device_class = device_class
@property
def device_info(self):
"""Return device info."""
return {
"identifiers": {
# Serial numbers are unique identifiers within a specific domain
(DOMAIN, self.unique_id)
},
"name": self.name,
}
@property
def unique_id(self):
"""Return the unique id."""
return self._unique_id
@property
def should_poll(self):
"""No polling needed for a demo switch."""

View File

@ -76,6 +76,11 @@ DEMO_VACUUM_NONE = "4_Fourth_floor"
DEMO_VACUUM_STATE = "5_Fifth_floor"
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
setup_platform(hass, {}, async_add_entities)
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Demo vacuums."""
add_entities(

View File

@ -13,9 +13,9 @@ SUPPORT_FLAGS_HEATER = (
)
def setup_platform(hass, config, add_entities, discovery_info=None):
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Set up the Demo water_heater devices."""
add_entities(
async_add_entities(
[
DemoWaterHeater("Demo Water Heater", 119, TEMP_FAHRENHEIT, False, "eco"),
DemoWaterHeater("Demo Water Heater Celsius", 45, TEMP_CELSIUS, True, "eco"),
@ -23,6 +23,11 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
)
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
await async_setup_platform(hass, {}, async_add_entities)
class DemoWaterHeater(WaterHeaterDevice):
"""Representation of a demo water_heater device."""

View File

@ -30,6 +30,11 @@ CONDITION_CLASSES = {
}
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Demo config entry."""
setup_platform(hass, {}, async_add_entities)
def setup_platform(hass, config, add_entities, discovery_info=None):
"""Set up the Demo weather."""
add_entities(

View File

@ -498,6 +498,7 @@ async def test_unavailable_state_doesnt_sync(hass):
async def test_device_class_switch(hass, device_class, google_type):
"""Test that a cover entity syncs to the correct device type."""
sensor = DemoSwitch(
None,
"Demo Sensor",
state=False,
icon="mdi:switch",
@ -545,7 +546,9 @@ async def test_device_class_switch(hass, device_class, google_type):
)
async def test_device_class_binary_sensor(hass, device_class, google_type):
"""Test that a binary entity syncs to the correct device type."""
sensor = DemoBinarySensor("Demo Sensor", state=False, device_class=device_class)
sensor = DemoBinarySensor(
None, "Demo Sensor", state=False, device_class=device_class
)
sensor.hass = hass
sensor.entity_id = "binary_sensor.demo_sensor"
await sensor.async_update_ha_state()
@ -585,7 +588,7 @@ async def test_device_class_binary_sensor(hass, device_class, google_type):
)
async def test_device_class_cover(hass, device_class, google_type):
"""Test that a binary entity syncs to the correct device type."""
sensor = DemoCover(hass, "Demo Sensor", device_class=device_class)
sensor = DemoCover(None, hass, "Demo Sensor", device_class=device_class)
sensor.hass = hass
sensor.entity_id = "cover.demo_sensor"
await sensor.async_update_ha_state()

View File

@ -24,24 +24,26 @@ async def prometheus_client(loop, hass, hass_client):
hass, climate.DOMAIN, {"climate": [{"platform": "demo"}]}
)
sensor1 = DemoSensor("Television Energy", 74, None, ENERGY_KILO_WATT_HOUR, None)
sensor1 = DemoSensor(
None, "Television Energy", 74, None, ENERGY_KILO_WATT_HOUR, None
)
sensor1.hass = hass
sensor1.entity_id = "sensor.television_energy"
await sensor1.async_update_ha_state()
sensor2 = DemoSensor(
"Radio Energy", 14, DEVICE_CLASS_POWER, ENERGY_KILO_WATT_HOUR, None
None, "Radio Energy", 14, DEVICE_CLASS_POWER, ENERGY_KILO_WATT_HOUR, None
)
sensor2.hass = hass
sensor2.entity_id = "sensor.radio_energy"
await sensor2.async_update_ha_state()
sensor3 = DemoSensor("Electricity price", 0.123, None, "SEK/kWh", None)
sensor3 = DemoSensor(None, "Electricity price", 0.123, None, "SEK/kWh", None)
sensor3.hass = hass
sensor3.entity_id = "sensor.electricity_price"
await sensor3.async_update_ha_state()
sensor4 = DemoSensor("Wind Direction", 25, None, "°", None)
sensor4 = DemoSensor(None, "Wind Direction", 25, None, "°", None)
sensor4.hass = hass
sensor4.entity_id = "sensor.wind_direction"
await sensor4.async_update_ha_state()