mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Add Dynalite switch platform (#32389)
* added presets for switch devices * added channel type to __init and const * ran pylint on library so needed a few changes in names * removed callback * bool -> cv.boolean
This commit is contained in:
parent
d216c1f2ac
commit
521cc7247d
@ -1,4 +1,7 @@
|
||||
"""Support for the Dynalite networks."""
|
||||
|
||||
import asyncio
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
@ -10,18 +13,26 @@ from homeassistant.helpers import config_validation as cv
|
||||
from .bridge import DynaliteBridge
|
||||
from .const import (
|
||||
CONF_ACTIVE,
|
||||
CONF_ACTIVE_INIT,
|
||||
CONF_ACTIVE_OFF,
|
||||
CONF_ACTIVE_ON,
|
||||
CONF_AREA,
|
||||
CONF_AUTO_DISCOVER,
|
||||
CONF_BRIDGES,
|
||||
CONF_CHANNEL,
|
||||
CONF_CHANNEL_TYPE,
|
||||
CONF_DEFAULT,
|
||||
CONF_FADE,
|
||||
CONF_NAME,
|
||||
CONF_NO_DEFAULT,
|
||||
CONF_POLLTIMER,
|
||||
CONF_PORT,
|
||||
CONF_PRESET,
|
||||
DEFAULT_CHANNEL_TYPE,
|
||||
DEFAULT_NAME,
|
||||
DEFAULT_PORT,
|
||||
DOMAIN,
|
||||
ENTITY_PLATFORMS,
|
||||
LOGGER,
|
||||
)
|
||||
|
||||
@ -35,16 +46,31 @@ def num_string(value):
|
||||
|
||||
|
||||
CHANNEL_DATA_SCHEMA = vol.Schema(
|
||||
{vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_FADE): vol.Coerce(float)}
|
||||
{
|
||||
vol.Optional(CONF_NAME): cv.string,
|
||||
vol.Optional(CONF_FADE): vol.Coerce(float),
|
||||
vol.Optional(CONF_CHANNEL_TYPE, default=DEFAULT_CHANNEL_TYPE): vol.Any(
|
||||
"light", "switch"
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
CHANNEL_SCHEMA = vol.Schema({num_string: CHANNEL_DATA_SCHEMA})
|
||||
|
||||
PRESET_DATA_SCHEMA = vol.Schema(
|
||||
{vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_FADE): vol.Coerce(float)}
|
||||
)
|
||||
|
||||
PRESET_SCHEMA = vol.Schema({num_string: vol.Any(PRESET_DATA_SCHEMA, None)})
|
||||
|
||||
|
||||
AREA_DATA_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
vol.Optional(CONF_FADE): vol.Coerce(float),
|
||||
vol.Optional(CONF_NO_DEFAULT): vol.Coerce(bool),
|
||||
vol.Optional(CONF_CHANNEL): CHANNEL_SCHEMA,
|
||||
vol.Optional(CONF_PRESET): PRESET_SCHEMA,
|
||||
},
|
||||
)
|
||||
|
||||
@ -62,7 +88,10 @@ BRIDGE_SCHEMA = vol.Schema(
|
||||
vol.Optional(CONF_POLLTIMER, default=1.0): vol.Coerce(float),
|
||||
vol.Optional(CONF_AREA): AREA_SCHEMA,
|
||||
vol.Optional(CONF_DEFAULT): PLATFORM_DEFAULTS_SCHEMA,
|
||||
vol.Optional(CONF_ACTIVE, default=False): vol.Coerce(bool),
|
||||
vol.Optional(CONF_ACTIVE, default=False): vol.Any(
|
||||
CONF_ACTIVE_ON, CONF_ACTIVE_OFF, CONF_ACTIVE_INIT, cv.boolean
|
||||
),
|
||||
vol.Optional(CONF_PRESET): PRESET_SCHEMA,
|
||||
}
|
||||
)
|
||||
|
||||
@ -120,14 +149,17 @@ async def async_setup_entry(hass, entry):
|
||||
"""Set up a bridge from a config entry."""
|
||||
LOGGER.debug("Setting up entry %s", entry.data)
|
||||
bridge = DynaliteBridge(hass, entry.data)
|
||||
# need to do it before the listener
|
||||
hass.data[DOMAIN][entry.entry_id] = bridge
|
||||
entry.add_update_listener(async_entry_changed)
|
||||
if not await bridge.async_setup():
|
||||
LOGGER.error("Could not set up bridge for entry %s", entry.data)
|
||||
hass.data[DOMAIN][entry.entry_id] = None
|
||||
raise ConfigEntryNotReady
|
||||
hass.data[DOMAIN][entry.entry_id] = bridge
|
||||
hass.async_create_task(
|
||||
hass.config_entries.async_forward_entry_setup(entry, "light")
|
||||
)
|
||||
for platform in ENTITY_PLATFORMS:
|
||||
hass.async_create_task(
|
||||
hass.config_entries.async_forward_entry_setup(entry, platform)
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
@ -135,5 +167,9 @@ async def async_unload_entry(hass, entry):
|
||||
"""Unload a config entry."""
|
||||
LOGGER.debug("Unloading entry %s", entry.data)
|
||||
hass.data[DOMAIN].pop(entry.entry_id)
|
||||
result = await hass.config_entries.async_forward_entry_unload(entry, "light")
|
||||
return result
|
||||
tasks = [
|
||||
hass.config_entries.async_forward_entry_unload(entry, platform)
|
||||
for platform in ENTITY_PLATFORMS
|
||||
]
|
||||
results = await asyncio.gather(*tasks)
|
||||
return False not in results
|
||||
|
@ -20,8 +20,8 @@ class DynaliteBridge:
|
||||
self.host = config[CONF_HOST]
|
||||
# Configure the dynalite devices
|
||||
self.dynalite_devices = DynaliteDevices(
|
||||
newDeviceFunc=self.add_devices_when_registered,
|
||||
updateDeviceFunc=self.update_device,
|
||||
new_device_func=self.add_devices_when_registered,
|
||||
update_device_func=self.update_device,
|
||||
)
|
||||
self.dynalite_devices.configure(config)
|
||||
|
||||
@ -31,7 +31,7 @@ class DynaliteBridge:
|
||||
LOGGER.debug("Setting up bridge - host %s", self.host)
|
||||
return await self.dynalite_devices.async_setup()
|
||||
|
||||
async def reload_config(self, config):
|
||||
def reload_config(self, config):
|
||||
"""Reconfigure a bridge when config changes."""
|
||||
LOGGER.debug("Reloading bridge - host %s, config %s", self.host, config)
|
||||
self.dynalite_devices.configure(config)
|
||||
|
@ -3,7 +3,7 @@ from homeassistant import config_entries
|
||||
from homeassistant.const import CONF_HOST
|
||||
|
||||
from .bridge import DynaliteBridge
|
||||
from .const import DOMAIN, LOGGER # pylint: disable=unused-import
|
||||
from .const import DOMAIN, LOGGER
|
||||
|
||||
|
||||
class DynaliteFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
@ -12,8 +12,6 @@ class DynaliteFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
VERSION = 1
|
||||
CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_POLL
|
||||
|
||||
# pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the Dynalite flow."""
|
||||
self.host = None
|
||||
|
@ -4,21 +4,28 @@ import logging
|
||||
LOGGER = logging.getLogger(__package__)
|
||||
DOMAIN = "dynalite"
|
||||
|
||||
ENTITY_PLATFORMS = ["light"]
|
||||
ENTITY_PLATFORMS = ["light", "switch"]
|
||||
|
||||
|
||||
CONF_ACTIVE = "active"
|
||||
CONF_ACTIVE_INIT = "init"
|
||||
CONF_ACTIVE_OFF = "off"
|
||||
CONF_ACTIVE_ON = "on"
|
||||
CONF_ALL = "ALL"
|
||||
CONF_AREA = "area"
|
||||
CONF_AUTO_DISCOVER = "autodiscover"
|
||||
CONF_BRIDGES = "bridges"
|
||||
CONF_CHANNEL = "channel"
|
||||
CONF_CHANNEL_TYPE = "type"
|
||||
CONF_DEFAULT = "default"
|
||||
CONF_FADE = "fade"
|
||||
CONF_HOST = "host"
|
||||
CONF_NAME = "name"
|
||||
CONF_NO_DEFAULT = "nodefault"
|
||||
CONF_POLLTIMER = "polltimer"
|
||||
CONF_PORT = "port"
|
||||
CONF_PRESET = "preset"
|
||||
|
||||
|
||||
DEFAULT_CHANNEL_TYPE = "light"
|
||||
DEFAULT_NAME = "dynalite"
|
||||
DEFAULT_PORT = 12345
|
||||
|
@ -1,6 +1,5 @@
|
||||
"""Support for Dynalite channels as lights."""
|
||||
from homeassistant.components.light import SUPPORT_BRIGHTNESS, Light
|
||||
from homeassistant.core import callback
|
||||
|
||||
from .dynalitebase import DynaliteBase, async_setup_entry_base
|
||||
|
||||
@ -8,12 +7,8 @@ from .dynalitebase import DynaliteBase, async_setup_entry_base
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Record the async_add_entities function to add them later when received from Dynalite."""
|
||||
|
||||
@callback
|
||||
def light_from_device(device, bridge):
|
||||
return DynaliteLight(device, bridge)
|
||||
|
||||
async_setup_entry_base(
|
||||
hass, config_entry, async_add_entities, "light", light_from_device
|
||||
hass, config_entry, async_add_entities, "light", DynaliteLight
|
||||
)
|
||||
|
||||
|
||||
|
@ -5,5 +5,5 @@
|
||||
"documentation": "https://www.home-assistant.io/integrations/dynalite",
|
||||
"dependencies": [],
|
||||
"codeowners": ["@ziv1234"],
|
||||
"requirements": ["dynalite_devices==0.1.30"]
|
||||
"requirements": ["dynalite_devices==0.1.32"]
|
||||
}
|
||||
|
29
homeassistant/components/dynalite/switch.py
Executable file
29
homeassistant/components/dynalite/switch.py
Executable file
@ -0,0 +1,29 @@
|
||||
"""Support for the Dynalite channels and presets as switches."""
|
||||
from homeassistant.components.switch import SwitchDevice
|
||||
|
||||
from .dynalitebase import DynaliteBase, async_setup_entry_base
|
||||
|
||||
|
||||
async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||
"""Record the async_add_entities function to add them later when received from Dynalite."""
|
||||
|
||||
async_setup_entry_base(
|
||||
hass, config_entry, async_add_entities, "switch", DynaliteSwitch
|
||||
)
|
||||
|
||||
|
||||
class DynaliteSwitch(DynaliteBase, SwitchDevice):
|
||||
"""Representation of a Dynalite Channel as a Home Assistant Switch."""
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
"""Return true if switch is on."""
|
||||
return self._device.is_on
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn the switch on."""
|
||||
await self._device.async_turn_on()
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn the switch off."""
|
||||
await self._device.async_turn_off()
|
@ -466,7 +466,7 @@ dsmr_parser==0.18
|
||||
dweepy==0.3.0
|
||||
|
||||
# homeassistant.components.dynalite
|
||||
dynalite_devices==0.1.30
|
||||
dynalite_devices==0.1.32
|
||||
|
||||
# homeassistant.components.rainforest_eagle
|
||||
eagle200_reader==0.2.1
|
||||
|
@ -174,7 +174,7 @@ distro==1.4.0
|
||||
dsmr_parser==0.18
|
||||
|
||||
# homeassistant.components.dynalite
|
||||
dynalite_devices==0.1.30
|
||||
dynalite_devices==0.1.32
|
||||
|
||||
# homeassistant.components.ee_brightbox
|
||||
eebrightbox==0.0.4
|
||||
|
@ -41,7 +41,7 @@ async def create_entity_from_device(hass, device):
|
||||
mock_dyn_dev().async_setup = CoroutineMock(return_value=True)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
new_device_func = mock_dyn_dev.mock_calls[1][2]["newDeviceFunc"]
|
||||
new_device_func = mock_dyn_dev.mock_calls[1][2]["new_device_func"]
|
||||
new_device_func([device])
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -20,7 +20,7 @@ async def test_update_device(hass):
|
||||
mock_dyn_dev().async_setup = CoroutineMock(return_value=True)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
# Not waiting so it add the devices before registration
|
||||
update_device_func = mock_dyn_dev.mock_calls[1][2]["updateDeviceFunc"]
|
||||
update_device_func = mock_dyn_dev.mock_calls[1][2]["update_device_func"]
|
||||
device = Mock()
|
||||
device.unique_id = "abcdef"
|
||||
wide_func = Mock()
|
||||
@ -50,7 +50,7 @@ async def test_add_devices_then_register(hass):
|
||||
mock_dyn_dev().async_setup = CoroutineMock(return_value=True)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
# Not waiting so it add the devices before registration
|
||||
new_device_func = mock_dyn_dev.mock_calls[1][2]["newDeviceFunc"]
|
||||
new_device_func = mock_dyn_dev.mock_calls[1][2]["new_device_func"]
|
||||
# Now with devices
|
||||
device1 = Mock()
|
||||
device1.category = "light"
|
||||
@ -73,7 +73,7 @@ async def test_register_then_add_devices(hass):
|
||||
mock_dyn_dev().async_setup = CoroutineMock(return_value=True)
|
||||
assert await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
new_device_func = mock_dyn_dev.mock_calls[1][2]["newDeviceFunc"]
|
||||
new_device_func = mock_dyn_dev.mock_calls[1][2]["new_device_func"]
|
||||
# Now with devices
|
||||
device1 = Mock()
|
||||
device1.category = "light"
|
||||
|
@ -83,5 +83,9 @@ async def test_unload_entry(hass):
|
||||
) as mock_unload:
|
||||
assert await hass.config_entries.async_unload(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
mock_unload.assert_called_once()
|
||||
assert mock_unload.mock_calls == [call(entry, "light")]
|
||||
assert mock_unload.call_count == len(dynalite.ENTITY_PLATFORMS)
|
||||
expected_calls = [
|
||||
call(entry, platform) for platform in dynalite.ENTITY_PLATFORMS
|
||||
]
|
||||
for cur_call in mock_unload.mock_calls:
|
||||
assert cur_call in expected_calls
|
||||
|
34
tests/components/dynalite/test_switch.py
Executable file
34
tests/components/dynalite/test_switch.py
Executable file
@ -0,0 +1,34 @@
|
||||
"""Test Dynalite switch."""
|
||||
|
||||
from dynalite_devices_lib.switch import DynalitePresetSwitchDevice
|
||||
import pytest
|
||||
|
||||
from .common import (
|
||||
ATTR_METHOD,
|
||||
ATTR_SERVICE,
|
||||
create_entity_from_device,
|
||||
create_mock_device,
|
||||
run_service_tests,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_device():
|
||||
"""Mock a Dynalite device."""
|
||||
return create_mock_device("switch", DynalitePresetSwitchDevice)
|
||||
|
||||
|
||||
async def test_switch_setup(hass, mock_device):
|
||||
"""Test a successful setup."""
|
||||
await create_entity_from_device(hass, mock_device)
|
||||
entity_state = hass.states.get("switch.name")
|
||||
assert entity_state.attributes["friendly_name"] == mock_device.name
|
||||
await run_service_tests(
|
||||
hass,
|
||||
mock_device,
|
||||
"switch",
|
||||
[
|
||||
{ATTR_SERVICE: "turn_on", ATTR_METHOD: "async_turn_on"},
|
||||
{ATTR_SERVICE: "turn_off", ATTR_METHOD: "async_turn_off"},
|
||||
],
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user