Second part of one_device_only big merge

This commit is contained in:
rospogrigio
2020-09-22 11:31:04 +02:00
committed by rospogrigio
parent 0048ce6d5e
commit 3259a4f654
10 changed files with 76 additions and 181 deletions

View File

@@ -9,8 +9,9 @@ from homeassistant.const import (
CONF_ENTITIES, CONF_ENTITIES,
) )
from .const import DOMAIN from .const import DOMAIN, TUYA_DEVICE
from .config_flow import config_schema from .config_flow import config_schema
from .common import TuyaDevice
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -19,23 +20,17 @@ UNSUB_LISTENER = "unsub_listener"
CONFIG_SCHEMA = config_schema() CONFIG_SCHEMA = config_schema()
def import_from_yaml(hass, config, platform):
"""Import configuration from YAML."""
config[CONF_PLATFORM] = platform
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=config
)
)
return True
async def async_setup(hass: HomeAssistant, config: dict): async def async_setup(hass: HomeAssistant, config: dict):
"""Set up the LocalTuya integration component.""" """Set up the LocalTuya integration component."""
hass.data.setdefault(DOMAIN, {}) hass.data.setdefault(DOMAIN, {})
print("setup:", config.get(DOMAIN)) for host_config in config.get(DOMAIN, []):
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=host_config
)
)
return True return True
@@ -45,12 +40,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
hass.data[DOMAIN][entry.entry_id] = { hass.data[DOMAIN][entry.entry_id] = {
UNSUB_LISTENER: unsub_listener, UNSUB_LISTENER: unsub_listener,
TUYA_DEVICE: TuyaDevice(entry.data),
} }
for platform in set(entity[CONF_PLATFORM] for entity in entry.data[CONF_ENTITIES]): for entity in entry.data[CONF_ENTITIES]:
platform = entity[CONF_PLATFORM]
hass.async_create_task( hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, platform) hass.config_entries.async_forward_entry_setup(entry, platform)
) )
return True return True

View File

@@ -16,8 +16,6 @@ sensor:
device_class: current device_class: current
""" """
import logging import logging
from time import time, sleep
from threading import Lock
import voluptuous as vol import voluptuous as vol
@@ -26,11 +24,7 @@ from homeassistant.components.binary_sensor import (
DEVICE_CLASSES_SCHEMA, DEVICE_CLASSES_SCHEMA,
BinarySensorEntity, BinarySensorEntity,
) )
from homeassistant.const import ( from homeassistant.const import CONF_ID, CONF_DEVICE_CLASS
CONF_ID,
CONF_DEVICE_CLASS,
CONF_FRIENDLY_NAME,
)
from .common import LocalTuyaEntity, prepare_setup_entities from .common import LocalTuyaEntity, prepare_setup_entities
@@ -51,7 +45,9 @@ def flow_schema(dps):
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up a Tuya sensor based on a config entry.""" """Set up a Tuya sensor based on a config entry."""
device, entities_to_setup = prepare_setup_entities(config_entry, DOMAIN) tuyainterface, entities_to_setup = prepare_setup_entities(
hass, config_entry, DOMAIN
)
if not entities_to_setup: if not entities_to_setup:
return return
@@ -59,7 +55,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
for device_config in entities_to_setup: for device_config in entities_to_setup:
sensors.append( sensors.append(
LocaltuyaBinarySensor( LocaltuyaBinarySensor(
TuyaCache(device, config_entry.data[CONF_FRIENDLY_NAME]), tuyainterface,
config_entry, config_entry,
device_config[CONF_ID], device_config[CONF_ID],
) )
@@ -68,74 +64,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
async_add_entities(sensors, True) async_add_entities(sensors, True)
class TuyaCache:
"""Cache wrapper for pytuya.TuyaDevice."""
def __init__(self, device, friendly_name):
"""Initialize the cache."""
self._cached_status = ""
self._cached_status_time = 0
self._device = device
self._friendly_name = friendly_name
self._lock = Lock()
@property
def unique_id(self):
"""Return unique device identifier."""
return self._device.id
def __get_status(self):
for i in range(5):
try:
status = self._device.status()
return status
except Exception:
print(
"Failed to update status of device [{}]".format(
self._device.address
)
)
sleep(1.0)
if i + 1 == 3:
_LOGGER.error(
"Failed to update status of device %s", self._device.address
)
# return None
raise ConnectionError("Failed to update status .")
def set_dps(self, state, dps_index):
"""Change the Tuya sensor status and clear the cache."""
self._cached_status = ""
self._cached_status_time = 0
for i in range(5):
try:
return self._device.set_dps(state, dps_index)
except Exception:
print(
"Failed to set status of device [{}]".format(self._device.address)
)
if i + 1 == 3:
_LOGGER.error(
"Failed to set status of device %s", self._device.address
)
return
# raise ConnectionError("Failed to set status.")
def status(self):
"""Get state of Tuya sensor and cache the results."""
self._lock.acquire()
try:
now = time()
if not self._cached_status or now - self._cached_status_time > 15:
sleep(0.5)
self._cached_status = self.__get_status()
self._cached_status_time = time()
return self._cached_status
finally:
self._lock.release()
class LocaltuyaBinarySensor(LocalTuyaEntity, BinarySensorEntity): class LocaltuyaBinarySensor(LocalTuyaEntity, BinarySensorEntity):
"""Representation of a Tuya binary sensor.""" """Representation of a Tuya binary sensor."""

View File

@@ -15,12 +15,12 @@ from homeassistant.const import (
) )
from . import pytuya from . import pytuya
from .const import CONF_LOCAL_KEY, CONF_PROTOCOL_VERSION, DOMAIN from .const import CONF_LOCAL_KEY, CONF_PROTOCOL_VERSION, DOMAIN, TUYA_DEVICE
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
def prepare_setup_entities(config_entry, platform): def prepare_setup_entities(hass, config_entry, platform):
"""Prepare ro setup entities for a platform.""" """Prepare ro setup entities for a platform."""
entities_to_setup = [ entities_to_setup = [
entity entity
@@ -30,16 +30,7 @@ def prepare_setup_entities(config_entry, platform):
if not entities_to_setup: if not entities_to_setup:
return None, None return None, None
tuyainterface = pytuya.TuyaInterface( tuyainterface = hass.data[DOMAIN][config_entry.entry_id][TUYA_DEVICE]
config_entry.data[CONF_DEVICE_ID],
config_entry.data[CONF_HOST],
config_entry.data[CONF_LOCAL_KEY],
float(config_entry.data[CONF_PROTOCOL_VERSION]),
)
for entity_config in entities_to_setup:
# this has to be done in case the device type is type_0d
tuyainterface.add_dps_to_request(entity_config[CONF_ID])
return tuyainterface, entities_to_setup return tuyainterface, entities_to_setup
@@ -55,12 +46,20 @@ def get_entity_config(config_entry, dps_id):
class TuyaDevice: class TuyaDevice:
"""Cache wrapper for pytuya.TuyaInterface.""" """Cache wrapper for pytuya.TuyaInterface."""
def __init__(self, interface, friendly_name): def __init__(self, config_entry):
"""Initialize the cache.""" """Initialize the cache."""
self._cached_status = "" self._cached_status = ""
self._cached_status_time = 0 self._cached_status_time = 0
self._interface = interface self._interface = pytuya.TuyaInterface(
self._friendly_name = friendly_name config_entry[CONF_DEVICE_ID],
config_entry[CONF_HOST],
config_entry[CONF_LOCAL_KEY],
config_entry[CONF_PROTOCOL_VERSION],
)
for entity in config_entry[CONF_ENTITIES]:
# this has to be done in case the device type is type_0d
self._interface.add_dps_to_request(entity[CONF_ID])
self._friendly_name = config_entry[CONF_FRIENDLY_NAME]
self._lock = Lock() self._lock = Lock()
@property @property
@@ -90,7 +89,7 @@ class TuyaDevice:
def set_dps(self, state, dps_index): def set_dps(self, state, dps_index):
# _LOGGER.info("running def set_dps from cover") # _LOGGER.info("running def set_dps from cover")
"""Change the Tuya device status and clear the cache.""" """Change the Tuya switch status and clear the cache."""
self._cached_status = "" self._cached_status = ""
self._cached_status_time = 0 self._cached_status_time = 0
for i in range(5): for i in range(5):
@@ -111,7 +110,7 @@ class TuyaDevice:
# raise ConnectionError("Failed to set status.") # raise ConnectionError("Failed to set status.")
def status(self): def status(self):
"""Get state of Tuya device and cache the results.""" """Get state of Tuya switch and cache the results."""
_LOGGER.debug("running def status(self) from TuyaDevice") _LOGGER.debug("running def status(self) from TuyaDevice")
self._lock.acquire() self._lock.acquire()
try: try:

View File

@@ -13,7 +13,6 @@ from homeassistant.const import (
CONF_DEVICE_ID, CONF_DEVICE_ID,
CONF_FRIENDLY_NAME, CONF_FRIENDLY_NAME,
CONF_PLATFORM, CONF_PLATFORM,
CONF_SWITCHES,
) )
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
@@ -97,7 +96,6 @@ def schema_defaults(schema, dps_list=None, **defaults):
if field.schema in defaults: if field.schema in defaults:
field.default = vol.default_factory(defaults[field]) field.default = vol.default_factory(defaults[field])
return copy return copy
@@ -310,37 +308,21 @@ class LocaltuyaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Handle import from YAML.""" """Handle import from YAML."""
def _convert_entity(conf): def _convert_entity(conf):
converted = { for field in flow_schema(conf[CONF_PLATFORM], self.dps_strings).keys():
CONF_ID: conf[CONF_ID], if str(field) in conf:
CONF_FRIENDLY_NAME: conf[CONF_FRIENDLY_NAME], conf[str(field)] = str(conf[field])
CONF_PLATFORM: self.platform,
}
for field in flow_schema(self.platform, self.dps_strings).keys():
converted[str(field)] = conf[field]
return converted
await self.async_set_unique_id(user_input[CONF_DEVICE_ID]) await self.async_set_unique_id(user_input[CONF_DEVICE_ID])
self.platform = user_input[CONF_PLATFORM]
if len(user_input.get(CONF_SWITCHES, [])) > 0: for entity_conf in user_input[CONF_ENTITIES]:
for switch_conf in user_input[CONF_SWITCHES].values(): entity_conf[CONF_ID] = str(entity_conf[CONF_ID])
self.entities.append(_convert_entity(switch_conf)) _convert_entity(entity_conf)
else:
self.entities.append(_convert_entity(user_input))
# print('ENTITIES: [{}] '.format(self.entities)) user_input[CONF_YAML_IMPORT] = True
config = {
CONF_FRIENDLY_NAME: f"{user_input[CONF_FRIENDLY_NAME]}", self._abort_if_unique_id_configured(updates=user_input)
CONF_HOST: user_input[CONF_HOST],
CONF_DEVICE_ID: user_input[CONF_DEVICE_ID],
CONF_LOCAL_KEY: user_input[CONF_LOCAL_KEY],
CONF_PROTOCOL_VERSION: user_input[CONF_PROTOCOL_VERSION],
CONF_YAML_IMPORT: True,
CONF_ENTITIES: self.entities,
}
self._abort_if_unique_id_configured(updates=config)
return self.async_create_entry( return self.async_create_entry(
title=f"{config[CONF_FRIENDLY_NAME]} (YAML)", data=config title=f"{user_input[CONF_FRIENDLY_NAME]} (YAML)", data=user_input
) )

View File

@@ -26,3 +26,5 @@ DOMAIN = "localtuya"
# Platforms in this list must support config flows # Platforms in this list must support config flows
PLATFORMS = ["binary_sensor", "cover", "fan", "light", "sensor", "switch"] PLATFORMS = ["binary_sensor", "cover", "fan", "light", "sensor", "switch"]
TUYA_DEVICE = "tuya_device"

View File

@@ -31,17 +31,14 @@ from homeassistant.components.cover import (
SUPPORT_STOP, SUPPORT_STOP,
SUPPORT_SET_POSITION, SUPPORT_SET_POSITION,
) )
from homeassistant.const import ( from homeassistant.const import CONF_ID
CONF_ID,
CONF_FRIENDLY_NAME,
)
from .const import ( from .const import (
CONF_OPEN_CMD, CONF_OPEN_CMD,
CONF_CLOSE_CMD, CONF_CLOSE_CMD,
CONF_STOP_CMD, CONF_STOP_CMD,
) )
from .common import LocalTuyaEntity, TuyaDevice, prepare_setup_entities from .common import LocalTuyaEntity, prepare_setup_entities
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -61,7 +58,9 @@ def flow_schema(dps):
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up a Tuya cover based on a config entry.""" """Set up a Tuya cover based on a config entry."""
tuyainterface, entities_to_setup = prepare_setup_entities(config_entry, DOMAIN) tuyainterface, entities_to_setup = prepare_setup_entities(
hass, config_entry, DOMAIN
)
if not entities_to_setup: if not entities_to_setup:
return return
@@ -69,7 +68,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
for device_config in entities_to_setup: for device_config in entities_to_setup:
covers.append( covers.append(
LocaltuyaCover( LocaltuyaCover(
TuyaDevice(tuyainterface, config_entry.data[CONF_FRIENDLY_NAME]), tuyainterface,
config_entry, config_entry,
device_config[CONF_ID], device_config[CONF_ID],
) )
@@ -185,7 +184,7 @@ class LocaltuyaCover(LocalTuyaEntity, CoverEntity):
def stop_cover(self, **kwargs): def stop_cover(self, **kwargs):
"""Stop the cover.""" """Stop the cover."""
_LOGGER.debug("Laudebugching command %s to cover ", self._config[CONF_STOP_CMD]) _LOGGER.debug("Launching command %s to cover ", self._config[CONF_STOP_CMD])
self._device.set_dps(self._config[CONF_STOP_CMD], self._dps_id) self._device.set_dps(self._config[CONF_STOP_CMD], self._dps_id)
def status_updated(self): def status_updated(self):

View File

@@ -26,9 +26,9 @@ from homeassistant.components.fan import (
SUPPORT_SET_SPEED, SUPPORT_SET_SPEED,
SUPPORT_OSCILLATE, SUPPORT_OSCILLATE,
) )
from homeassistant.const import CONF_ID, CONF_FRIENDLY_NAME from homeassistant.const import CONF_ID
from .common import LocalTuyaEntity, TuyaDevice, prepare_setup_entities from .common import LocalTuyaEntity, prepare_setup_entities
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -40,7 +40,9 @@ def flow_schema(dps):
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up a Tuya fan based on a config entry.""" """Set up a Tuya fan based on a config entry."""
tuyainterface, entities_to_setup = prepare_setup_entities(config_entry, DOMAIN) tuyainterface, entities_to_setup = prepare_setup_entities(
hass, config_entry, DOMAIN
)
if not entities_to_setup: if not entities_to_setup:
return return
@@ -49,7 +51,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
for device_config in entities_to_setup: for device_config in entities_to_setup:
fans.append( fans.append(
LocaltuyaFan( LocaltuyaFan(
TuyaDevice(tuyainterface, config_entry.data[CONF_FRIENDLY_NAME]), tuyainterface,
config_entry, config_entry,
device_config[CONF_ID], device_config[CONF_ID],
) )

View File

@@ -13,10 +13,7 @@ light:
""" """
import logging import logging
from homeassistant.const import ( from homeassistant.const import CONF_ID
CONF_ID,
CONF_FRIENDLY_NAME,
)
from homeassistant.components.light import ( from homeassistant.components.light import (
LightEntity, LightEntity,
DOMAIN, DOMAIN,
@@ -27,7 +24,7 @@ from homeassistant.components.light import (
SUPPORT_COLOR, SUPPORT_COLOR,
) )
from .common import LocalTuyaEntity, TuyaDevice, prepare_setup_entities from .common import LocalTuyaEntity, prepare_setup_entities
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -49,18 +46,17 @@ def flow_schema(dps):
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up a Tuya light based on a config entry.""" """Set up a Tuya light based on a config entry."""
tuyainterface, entities_to_setup = prepare_setup_entities(config_entry, DOMAIN) tuyainterface, entities_to_setup = prepare_setup_entities(
hass, config_entry, DOMAIN
)
if not entities_to_setup: if not entities_to_setup:
return return
lights = [] lights = []
for device_config in entities_to_setup: for device_config in entities_to_setup:
# this has to be done in case the device type is type_0d
tuyainterface.add_dps_to_request(device_config[CONF_ID])
lights.append( lights.append(
LocaltuyaLight( LocaltuyaLight(
TuyaDevice(tuyainterface, config_entry.data[CONF_FRIENDLY_NAME]), tuyainterface,
config_entry, config_entry,
device_config[CONF_ID], device_config[CONF_ID],
) )

View File

@@ -22,13 +22,12 @@ from homeassistant.components.sensor import DOMAIN, DEVICE_CLASSES
from homeassistant.const import ( from homeassistant.const import (
CONF_ID, CONF_ID,
CONF_DEVICE_CLASS, CONF_DEVICE_CLASS,
CONF_FRIENDLY_NAME,
CONF_UNIT_OF_MEASUREMENT, CONF_UNIT_OF_MEASUREMENT,
STATE_UNKNOWN, STATE_UNKNOWN,
) )
from .const import CONF_SCALING from .const import CONF_SCALING
from .common import LocalTuyaEntity, TuyaDevice, prepare_setup_entities from .common import LocalTuyaEntity, prepare_setup_entities
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -48,7 +47,9 @@ def flow_schema(dps):
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up a Tuya sensor based on a config entry.""" """Set up a Tuya sensor based on a config entry."""
tuyainterface, entities_to_setup = prepare_setup_entities(config_entry, DOMAIN) tuyainterface, entities_to_setup = prepare_setup_entities(
hass, config_entry, DOMAIN
)
if not entities_to_setup: if not entities_to_setup:
return return
@@ -56,7 +57,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
for device_config in entities_to_setup: for device_config in entities_to_setup:
sensors.append( sensors.append(
LocaltuyaSensor( LocaltuyaSensor(
TuyaDevice(tuyainterface, config_entry.data[CONF_FRIENDLY_NAME]), tuyainterface,
config_entry, config_entry,
device_config[CONF_ID], device_config[CONF_ID],
) )

View File

@@ -32,10 +32,7 @@ from homeassistant.components.switch import (
SwitchEntity, SwitchEntity,
DOMAIN, DOMAIN,
) )
from homeassistant.const import ( from homeassistant.const import CONF_ID
CONF_ID,
CONF_FRIENDLY_NAME,
)
from .const import ( from .const import (
ATTR_CURRENT, ATTR_CURRENT,
@@ -45,12 +42,10 @@ from .const import (
CONF_CURRENT_CONSUMPTION, CONF_CURRENT_CONSUMPTION,
CONF_VOLTAGE, CONF_VOLTAGE,
) )
from .common import LocalTuyaEntity, TuyaDevice, prepare_setup_entities from .common import LocalTuyaEntity, prepare_setup_entities
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
DEFAULT_ID = "1"
def flow_schema(dps): def flow_schema(dps):
"""Return schema used in config flow.""" """Return schema used in config flow."""
@@ -63,24 +58,17 @@ def flow_schema(dps):
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up a Tuya switch based on a config entry.""" """Set up a Tuya switch based on a config entry."""
tuyainterface, entities_to_setup = prepare_setup_entities(config_entry, DOMAIN) tuyainterface, entities_to_setup = prepare_setup_entities(
hass, config_entry, DOMAIN
)
if not entities_to_setup: if not entities_to_setup:
return return
switches = [] switches = []
for device_config in entities_to_setup: for device_config in entities_to_setup:
if device_config.get(CONF_CURRENT, "-1") != "-1":
tuyainterface.add_dps_to_request(device_config.get(CONF_CURRENT))
if device_config.get(CONF_CURRENT_CONSUMPTION, "-1") != "-1":
tuyainterface.add_dps_to_request(
device_config.get(CONF_CURRENT_CONSUMPTION)
)
if device_config.get(CONF_VOLTAGE, "-1") != "-1":
tuyainterface.add_dps_to_request(device_config.get(CONF_VOLTAGE))
switches.append( switches.append(
LocaltuyaSwitch( LocaltuyaSwitch(
TuyaDevice(tuyainterface, config_entry.data[CONF_FRIENDLY_NAME]), tuyainterface,
config_entry, config_entry,
device_config[CONF_ID], device_config[CONF_ID],
) )