Skip to content

Commit

Permalink
feat: support more devices
Browse files Browse the repository at this point in the history
- smart dial
- dual motion sensors on awareness switch
- illuminance sensor
  • Loading branch information
rxwen committed Feb 7, 2023
1 parent ce6c879 commit 9917275
Show file tree
Hide file tree
Showing 7 changed files with 272 additions and 114 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@ There is support for the following device type within Home Assistant:
- Light
- Switch
- Curtain Motor
- Wireless Switch
- Smart Plug
- Smart Dial
- Motion Sensor
- Door Sensor
- Temperature Sensor
- Humidity Sensor
- Illuminance Sensor

## Installation

Expand Down Expand Up @@ -70,7 +73,7 @@ default_config:
logger:
default: info
logs:
homeassistant.components.terncy: info
homeassistant.components.terncy: debug
```

Expand Down
5 changes: 4 additions & 1 deletion README.zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,14 @@
-
- 开关
- 窗帘电机
- 无线开关
- 智能插座
- 旋钮开关
- 人体传感器
- 门磁传感器
- 温度传感器
- 湿度传感器
- 照度传感器

## 安装方法

Expand Down Expand Up @@ -70,7 +73,7 @@ default_config:
logger:
default: info
logs:
homeassistant.components.terncy: info
homeassistant.components.terncy: debug
```

Expand Down
162 changes: 83 additions & 79 deletions terncy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
HA_CLIENT_ID,
PROFILE_COLOR_DIMMABLE_LIGHT,
PROFILE_YAN_BUTTON,
PROFILE_SMART_DIAL,
PROFILE_COLOR_LIGHT,
PROFILE_COLOR_TEMPERATURE_LIGHT,
PROFILE_DIMMABLE_COLOR_TEMPERATURE_LIGHT,
Expand All @@ -45,6 +46,11 @@
ACTION_TRIPLE_PRESS,
ACTION_LONG_PRESS,
TerncyHassPlatformData,
PLATFORM_LIGHT,
PLATFORM_COVER,
PLATFORM_SWITCH,
PLATFORM_BINARY_SENSOR,
PLATFORM_SENSOR,
)
from .hub_monitor import TerncyHubManager
from .light import (
Expand All @@ -69,14 +75,20 @@
)
from .sensor import (
TerncyTemperatureSensor,
TerncyHumiditySensor,
TerncyIlluminanceSensor,
)

EVENT_DATA_CLICK_TIMES = "click_times"
DEVID_EXT_TEMP = "_temp"
DEVID_EXT_HUMIDITY = "_himidity"
DEVID_EXT_ILLU = "_illu"
DEVID_EXT_MOTIONL = "_motionl"
DEVID_EXT_MOTIONR = "_motionr"

PLATFORM_SCHEMA = vol.Schema({DOMAIN: vol.Schema({})}, extra=vol.ALLOW_EXTRA)

PLATFORMS = ["light", "cover", "switch", "binary_sensor", "sensor"]
PLATFORMS = [PLATFORM_LIGHT, PLATFORM_COVER, PLATFORM_SWITCH, PLATFORM_BINARY_SENSOR, PLATFORM_SENSOR]

_LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -117,9 +129,18 @@ def terncy_event_handler(tern, ev):
continue
devid = ent["id"]
temperature = get_attr_value(ent["attributes"], "temperature")
if temperature is not None:
if get_attr_value(ent["attributes"], "temperature") is not None:
_LOGGER.info("got temperature")
devid = devid + DEVID_EXT_TEMP
if get_attr_value(ent["attributes"], "luminance") is not None:
_LOGGER.info("got luminance")
devid = devid + DEVID_EXT_ILLU
if get_attr_value(ent["attributes"], "motionL") is not None:
_LOGGER.info("got motionl")
devid = devid + DEVID_EXT_MOTIONL
if get_attr_value(ent["attributes"], "motionR") is not None:
_LOGGER.info("got motionr")
devid = devid + DEVID_EXT_MOTIONR

if devid in parsed_devices:
dev = parsed_devices[devid]
Expand Down Expand Up @@ -230,40 +251,45 @@ async def async_setup(hass: HomeAssistant, config: dict):
"""Set up the Terncy component."""
return True

async def add_entity_to_platform(tern, devid, device, attrs, domain):
if not devid in tern.hass_platform_data.parsed_devices:
for platform in async_get_platforms(tern.hass_platform_data.hass, DOMAIN):
if platform.config_entry.unique_id == tern.dev_id:
if platform.domain == domain:
_LOGGER.info("add device %s of %s to %s", device.name, domain, platform.domain)
await platform.async_add_entities([device])
break
tern.hass_platform_data.parsed_devices[devid] = device
device.update_state(attrs)
if device.hass:
device.schedule_update_ha_state()


async def update_or_create_entity_inner(svc, tern, model, version, available):
_LOGGER.info("Updating service %s, available=%s", svc, available)

isLight = False
isSwitch = False
profile = svc["profile"]
features = -1
if profile == PROFILE_ONOFF_LIGHT:
features = SUPPORT_TERNCY_ON_OFF
isLight = True
elif profile == PROFILE_SMART_DIAL:
features = SUPPORT_TERNCY_ON_OFF
elif profile == PROFILE_COLOR_LIGHT:
features = SUPPORT_TERNCY_COLOR
isLight = True
elif profile == PROFILE_EXTENDED_COLOR_LIGHT:
features = SUPPORT_TERNCY_EXTENDED
isLight = True
elif profile == PROFILE_COLOR_TEMPERATURE_LIGHT:
features = SUPPORT_TERNCY_CT
isLight = True
elif profile == PROFILE_DIMMABLE_COLOR_TEMPERATURE_LIGHT:
features = SUPPORT_TERNCY_CT
isLight = True
elif profile == PROFILE_DIMMABLE_LIGHT:
features = SUPPORT_TERNCY_DIMMABLE
isLight = True
elif profile == PROFILE_DIMMABLE_LIGHT2:
features = SUPPORT_TERNCY_DIMMABLE
isLight = True
elif profile == PROFILE_COLOR_DIMMABLE_LIGHT:
features = SUPPORT_TERNCY_EXTENDED
isLight = True
elif profile == PROFILE_EXTENDED_COLOR_LIGHT2:
features = SUPPORT_TERNCY_EXTENDED
isLight = True
elif profile == PROFILE_PLUG:
features = SUPPORT_TERNCY_ON_OFF
elif profile == PROFILE_CURTAIN:
Expand All @@ -281,92 +307,70 @@ async def update_or_create_entity_inner(svc, tern, model, version, available):
return

devid = svc["id"]
devidTemp = devid + DEVID_EXT_TEMP
if profile == PROFILE_HA_TEMPERATURE_HUMIDITY:
devid = devidTemp

disableRelay = get_attr_value(svc["attributes"], "disableRelay")
temperature = get_attr_value(svc["attributes"], "temperature")

name = devid
if "name" in svc and svc["name"] != "":
name = svc["name"]

device = None
deviceTemp = None
if devid in tern.hass_platform_data.parsed_devices:
device = tern.hass_platform_data.parsed_devices[devid]
if temperature is not None:
deviceTemp = tern.hass_platform_data.parsed_devices[devidTemp]
deviceTemp.update_state(svc["attributes"])
deviceTemp.is_available = available
else:
attrs = svc["attributes"]

disableRelay = get_attr_value(attrs, "disableRelay")
temperature = get_attr_value(attrs, "temperature")
if not devid in tern.hass_platform_data.parsed_devices:
_LOGGER.info("need to add dev %s %d %s to platform", name, profile, devid)
if profile == PROFILE_YAN_BUTTON or disableRelay == 1:
isLight = False
isSwitch = True
device = TerncyButton(tern, devid, name, model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid, device, attrs, PLATFORM_SWITCH)
elif model.find("TERNCY-WS") >= 0 or model.find("TERNCY-LF") >= 0:
isLight = False
isSwitch = True
device = TerncySwitch(tern, devid, name, model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid, device, attrs, PLATFORM_SWITCH)
elif profile == PROFILE_SMART_DIAL:
device = TerncyButton(tern, devid, name, model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid, device, attrs, PLATFORM_SWITCH)
elif profile == PROFILE_PLUG:
device = TerncySmartPlug(tern, devid, name, model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid, device, attrs, PLATFORM_SWITCH)
elif profile == PROFILE_CURTAIN:
device = TerncyCurtain(tern, devid, name, model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid, device, attrs, PLATFORM_COVER)
elif profile == PROFILE_DOOR_SENSOR:
device = TerncyDoorSensor(tern, devid, name, model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid, device, attrs, PLATFORM_BINARY_SENSOR)
if not temperature is None:
device = TerncyTemperatureSensor(tern, devid + DEVID_EXT_TEMP, name + "-T", model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid + DEVID_EXT_TEMP, device, attrs, PLATFORM_SENSOR)
elif profile == PROFILE_HA_TEMPERATURE_HUMIDITY:
device = TerncyTemperatureSensor(tern, devid, name + " temperature", model, version, features)
device = TerncyTemperatureSensor(tern, devid + DEVID_EXT_TEMP, name, model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid + DEVID_EXT_TEMP, device, attrs, PLATFORM_SENSOR)
elif profile == PROFILE_PIR:
device = TerncyMotionSensor(tern, devid, name, model, version, features)
device = TerncyButton(tern, devid, name, model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid, device, attrs, PLATFORM_SWITCH)
device = TerncyMotionSensor(tern, devid+DEVID_EXT_MOTIONL, name + "-L", model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid+DEVID_EXT_MOTIONL, device, attrs, PLATFORM_BINARY_SENSOR)
device = TerncyMotionSensor(tern, devid+DEVID_EXT_MOTIONR, name+"-R", model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid+DEVID_EXT_MOTIONR, device, attrs, PLATFORM_BINARY_SENSOR)
device = TerncyIlluminanceSensor(tern, devid + DEVID_EXT_ILLU, name + "-I", model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid + DEVID_EXT_ILLU, device, attrs, PLATFORM_SENSOR)
device = TerncyTemperatureSensor(tern, devid + DEVID_EXT_TEMP, name + "-T", model, version, features)
device.is_available = available
await add_entity_to_platform(tern, devid + DEVID_EXT_TEMP, device, attrs, PLATFORM_SENSOR)
else:
device = TerncyLight(tern, devid, name, model, version, features)

if profile != PROFILE_HA_TEMPERATURE_HUMIDITY and temperature is not None:
_LOGGER.info("create temperature sensor")
deviceTemp = TerncyTemperatureSensor(tern, devidTemp, name + " temperature", model, version, features)
deviceTemp.update_state(svc["attributes"])
deviceTemp.is_available = available
tern.hass_platform_data.parsed_devices[devidTemp] = deviceTemp
device.update_state(svc["attributes"])
device.is_available = available
if devid in tern.hass_platform_data.parsed_devices:
if device.hass:
device.schedule_update_ha_state()
else:
for platform in async_get_platforms(tern.hass_platform_data.hass, DOMAIN):
if platform.config_entry.unique_id == tern.dev_id:
if profile == PROFILE_PLUG and platform.domain == "switch":
await platform.async_add_entities([device])
break
if profile == PROFILE_YAN_BUTTON and platform.domain == "switch":
await platform.async_add_entities([device])
break
elif profile == PROFILE_CURTAIN and platform.domain == "cover":
await platform.async_add_entities([device])
break
elif (
profile == PROFILE_DOOR_SENSOR
and platform.domain == "binary_sensor"
):
await platform.async_add_entities([device])
break
elif profile == PROFILE_PIR and platform.domain == "binary_sensor":
await platform.async_add_entities([device])
break
elif deviceTemp is not None and platform.domain == "sensor":
await platform.async_add_entities([deviceTemp])
continue
elif profile == PROFILE_HA_TEMPERATURE_HUMIDITY and platform.domain == "sensor":
await platform.async_add_entities([device])
break
elif isLight and platform.domain == "light":
await platform.async_add_entities([device])
break
elif isSwitch and platform.domain == "switch":
await platform.async_add_entities([device])
break
tern.hass_platform_data.parsed_devices[devid] = device
device.is_available = available
await add_entity_to_platform(tern, devid, device, attrs, PLATFORM_LIGHT)


async def update_or_create_entity(dev, tern):
Expand Down
29 changes: 8 additions & 21 deletions terncy/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,16 @@ def __init__(self, api, devid, name, model, version, features):

def update_state(self, attrs):
"""Updateterncy state."""
_LOGGER.info("update state event to %s", attrs)
_LOGGER.info("update %s state event to %s", self.unique_id, attrs)
on = get_attr_value(attrs, "motion")
if on is not None:
self._on = on
on = get_attr_value(attrs, "motionL")
if on is not None:
self._on = on
on = get_attr_value(attrs, "motionR")
if on is not None:
self._on = on

@property
def unique_id(self):
Expand Down Expand Up @@ -195,23 +201,4 @@ def device_info(self):
}

def get_trigger(self, id):
return [
{
CONF_PLATFORM: "device",
CONF_DEVICE_ID: id,
CONF_DOMAIN: DOMAIN,
CONF_TYPE: ACTION_SINGLE_PRESS,
},
{
CONF_PLATFORM: "device",
CONF_DEVICE_ID: id,
CONF_DOMAIN: DOMAIN,
CONF_TYPE: ACTION_DOUBLE_PRESS,
},
{
CONF_PLATFORM: "device",
CONF_DEVICE_ID: id,
CONF_DOMAIN: DOMAIN,
CONF_TYPE: ACTION_TRIPLE_PRESS,
},
]
return []
6 changes: 6 additions & 0 deletions terncy/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@
CONF_IP = "ip"
CONF_PORT = "port"

PLATFORM_LIGHT = "light"
PLATFORM_COVER = "cover"
PLATFORM_SWITCH = "switch"
PLATFORM_BINARY_SENSOR = "binary_sensor"
PLATFORM_SENSOR = "sensor"

ACTION_SINGLE_PRESS = "single_press"
ACTION_DOUBLE_PRESS = "double_press"
ACTION_TRIPLE_PRESS = "triple_press"
Expand Down
5 changes: 3 additions & 2 deletions terncy/device_trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import logging
_LOGGER = logging.getLogger(__name__)
from typing import List
from homeassistant.helpers import device_registry as dr

import voluptuous as vol
from homeassistant.components.automation import AutomationActionType
Expand Down Expand Up @@ -62,7 +63,7 @@ async def async_validate_trigger_config(hass: HomeAssistant, config: ConfigType)
async def async_get_triggers(hass: HomeAssistant, device_id: str) -> List[dict]:
"""List device triggers for Terncy devices."""
triggers = []
device_registry = await hass.helpers.device_registry.async_get_registry()
device_registry = dr.async_get(hass)
device = device_registry.async_get(device_id)
devid = min(device.identifiers)[1]
for tern in hass.data[DOMAIN].values():
Expand All @@ -81,7 +82,7 @@ async def async_attach_trigger(
) -> CALLBACK_TYPE:
"""Attach a trigger."""
device_id = config[CONF_DEVICE_ID]
device_registry = await hass.helpers.device_registry.async_get_registry()
device_registry = dr.async_get(hass)
device = device_registry.async_get(device_id)
_LOGGER.info(device.identifiers)
devid = min(device.identifiers)[1]
Expand Down
Loading

0 comments on commit 9917275

Please sign in to comment.