forked from platypush/platypush
Implemented remaining supported entities for the smartthings
integration
This commit is contained in:
parent
334ccc35a2
commit
afdeb91f66
8 changed files with 650 additions and 73 deletions
|
@ -60,6 +60,8 @@ export default {
|
|||
|
||||
if (this.isBoolean)
|
||||
return this.parseBoolean(this.value)
|
||||
if (Array.isArray(this.value) || typeof(this.value) === 'object')
|
||||
return JSON.stringify(this.value)
|
||||
|
||||
let value = parseFloat(this.value)
|
||||
if (this.decimals != null)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
EnumSensor.vue
|
|
@ -0,0 +1 @@
|
|||
Sensor.vue
|
|
@ -7,6 +7,14 @@
|
|||
}
|
||||
},
|
||||
|
||||
"button": {
|
||||
"name": "Button",
|
||||
"name_plural": "Buttons",
|
||||
"icon": {
|
||||
"class": "fas fa-circle-dot"
|
||||
}
|
||||
},
|
||||
|
||||
"current_sensor": {
|
||||
"name": "Sensor",
|
||||
"name_plural": "Sensors",
|
||||
|
@ -143,6 +151,14 @@
|
|||
}
|
||||
},
|
||||
|
||||
"multi_value_sensor": {
|
||||
"name": "Sensor",
|
||||
"name_plural": "Sensors",
|
||||
"icon": {
|
||||
"class": "fas fa-thermometer"
|
||||
}
|
||||
},
|
||||
|
||||
"binary_sensor": {
|
||||
"name": "Sensor",
|
||||
"name_plural": "Sensors",
|
||||
|
|
27
platypush/entities/buttons.py
Normal file
27
platypush/entities/buttons.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
import logging
|
||||
|
||||
from sqlalchemy import (
|
||||
Column,
|
||||
ForeignKey,
|
||||
Integer,
|
||||
)
|
||||
|
||||
from platypush.common.db import Base
|
||||
|
||||
from .sensors import EnumSensor
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
if 'button' not in Base.metadata:
|
||||
|
||||
class Button(EnumSensor):
|
||||
__tablename__ = 'button'
|
||||
|
||||
id = Column(
|
||||
Integer, ForeignKey(EnumSensor.id, ondelete='CASCADE'), primary_key=True
|
||||
)
|
||||
|
||||
__mapper_args__ = {
|
||||
'polymorphic_identity': __tablename__,
|
||||
}
|
|
@ -66,9 +66,9 @@ if 'binary_sensor' not in Base.metadata:
|
|||
if isinstance(value, str):
|
||||
value = value.lower()
|
||||
|
||||
if value in {True, 1, '1', 't', 'true', 'on'}:
|
||||
if value in {True, 1, '1', 't', 'true', 'on', 'ON'}:
|
||||
value = True
|
||||
elif value in {False, 0, '0', 'f', 'false', 'off'}:
|
||||
elif value in {False, 0, '0', 'f', 'false', 'off', 'OFF'}:
|
||||
value = False
|
||||
elif value is not None:
|
||||
logger.warning(f'Unsupported value for BinarySensor type: {value}')
|
||||
|
@ -100,3 +100,18 @@ if 'enum_sensor' not in Base.metadata:
|
|||
__mapper_args__ = {
|
||||
'polymorphic_identity': __tablename__,
|
||||
}
|
||||
|
||||
|
||||
if 'multi_value_sensor' not in Base.metadata:
|
||||
|
||||
class MultiValueSensor(Sensor):
|
||||
__tablename__ = 'multi_value_sensor'
|
||||
|
||||
id = Column(
|
||||
Integer, ForeignKey(Device.id, ondelete='CASCADE'), primary_key=True
|
||||
)
|
||||
value = Column(JSON)
|
||||
|
||||
__mapper_args__ = {
|
||||
'polymorphic_identity': __tablename__,
|
||||
}
|
||||
|
|
|
@ -1,32 +1,30 @@
|
|||
import asyncio
|
||||
import aiohttp
|
||||
|
||||
from threading import RLock
|
||||
from typing import Optional, Dict, List, Tuple, Type, Union, Iterable
|
||||
from typing import Dict, Iterable, List, Optional, Tuple, Type, Union
|
||||
|
||||
import aiohttp
|
||||
from pysmartthings import (
|
||||
Attribute,
|
||||
Capability,
|
||||
Command,
|
||||
Device,
|
||||
DeviceEntity,
|
||||
DeviceStatus,
|
||||
SmartThings,
|
||||
)
|
||||
|
||||
from platypush.entities import Entity, manages
|
||||
|
||||
from platypush.entities.devices import Device as PDevice
|
||||
from platypush.entities.devices import Device
|
||||
from platypush.entities.dimmers import Dimmer
|
||||
from platypush.entities.lights import Light
|
||||
from platypush.entities.sensors import Sensor
|
||||
from platypush.entities.switches import Switch
|
||||
from platypush.entities.switches import EnumSwitch, Switch
|
||||
from platypush.plugins import RunnablePlugin, action
|
||||
from platypush.utils import camel_case_to_snake_case
|
||||
|
||||
from ._mappers import device_mappers
|
||||
from ._mappers import DeviceMapper, device_mappers
|
||||
|
||||
|
||||
@manages(PDevice, Dimmer, Sensor, Switch, Light)
|
||||
@manages(Device, Dimmer, EnumSwitch, Light, Sensor, Switch)
|
||||
class SmartthingsPlugin(RunnablePlugin):
|
||||
"""
|
||||
Plugin to interact with devices and locations registered to a Samsung SmartThings account.
|
||||
|
@ -316,7 +314,7 @@ class SmartthingsPlugin(RunnablePlugin):
|
|||
assert location, 'Location {} not found'.format(location_id or name)
|
||||
return self._location_to_dict(location)
|
||||
|
||||
def _get_device(self, device: str) -> Device:
|
||||
def _get_device(self, device: str) -> DeviceEntity:
|
||||
return self._get_devices(device)[0]
|
||||
|
||||
@staticmethod
|
||||
|
@ -328,7 +326,7 @@ class SmartthingsPlugin(RunnablePlugin):
|
|||
|
||||
def _get_existing_and_missing_devices(
|
||||
self, *devices: str
|
||||
) -> Tuple[List[Device], List[str]]:
|
||||
) -> Tuple[List[DeviceEntity], List[str]]:
|
||||
# Split the external_id:type indicators and always return the parent device
|
||||
devices = tuple(self._to_device_and_property(dev)[0] for dev in devices)
|
||||
|
||||
|
@ -341,7 +339,7 @@ class SmartthingsPlugin(RunnablePlugin):
|
|||
missing_devs = {dev for dev in devices if dev not in found_devs}
|
||||
return list(found_devs.values()), list(missing_devs) # type: ignore
|
||||
|
||||
def _get_devices(self, *devices: str) -> List[Device]:
|
||||
def _get_devices(self, *devices: str) -> List[DeviceEntity]:
|
||||
devs, missing_devs = self._get_existing_and_missing_devices(*devices)
|
||||
if missing_devs:
|
||||
self.refresh_info()
|
||||
|
@ -376,8 +374,8 @@ class SmartthingsPlugin(RunnablePlugin):
|
|||
}
|
||||
|
||||
"""
|
||||
device = self._get_device(device)
|
||||
return self._device_to_dict(device)
|
||||
dev = self._get_device(device)
|
||||
return self._device_to_dict(dev)
|
||||
|
||||
async def _execute(
|
||||
self,
|
||||
|
@ -457,58 +455,92 @@ class SmartthingsPlugin(RunnablePlugin):
|
|||
loop.stop()
|
||||
|
||||
@staticmethod
|
||||
def _property_to_entity_name(property: str) -> str:
|
||||
return ' '.join(
|
||||
[
|
||||
t[:1].upper() + t[1:]
|
||||
for t in camel_case_to_snake_case(property).split('_')
|
||||
]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _to_entity(
|
||||
device: Device, property: str, entity_type: Type[Entity], **kwargs
|
||||
cls, device: DeviceEntity, property: str, entity_type: Type[Entity], **kwargs
|
||||
) -> Entity:
|
||||
return entity_type(
|
||||
id=f'{device.device_id}:{property}',
|
||||
name=entity_type.__name__,
|
||||
name=cls._property_to_entity_name(property),
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _get_status_attr_info(device: Device, attr: str) -> dict:
|
||||
status = device.status.attributes.get(attr)
|
||||
@classmethod
|
||||
def _get_status_attr_info(cls, device: DeviceEntity, mapper: DeviceMapper) -> dict:
|
||||
status = device.status.attributes.get(mapper.attribute)
|
||||
info = {}
|
||||
if status:
|
||||
if getattr(status, 'unit', None) is not None:
|
||||
info['unit'] = status.unit
|
||||
if getattr(status, 'min', None) is not None:
|
||||
info['min'] = status.min
|
||||
if getattr(status, 'max', None) is not None:
|
||||
info['max'] = status.max
|
||||
info.update(
|
||||
{
|
||||
attr: getattr(status, attr, None)
|
||||
for attr in ('unit', 'min', 'max')
|
||||
if getattr(status, attr, None) is not None
|
||||
}
|
||||
)
|
||||
|
||||
supported_values = mapper.values
|
||||
if isinstance(mapper.value_type, str):
|
||||
# The list of supported values is actually contained on a
|
||||
# device attribute
|
||||
try:
|
||||
supported_values = getattr(
|
||||
device.status, mapper.value_type, mapper.values
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if supported_values:
|
||||
info['values'] = mapper.values
|
||||
|
||||
return info
|
||||
|
||||
@staticmethod
|
||||
def _merge_dicts(*dicts: dict) -> dict:
|
||||
ret = {}
|
||||
for d in dicts:
|
||||
ret.update(d)
|
||||
return ret
|
||||
|
||||
@classmethod
|
||||
def _get_supported_entities(
|
||||
cls,
|
||||
device: Device,
|
||||
device: DeviceEntity,
|
||||
entity_type: Optional[Type[Entity]] = None,
|
||||
entity_value_attr: str = 'value',
|
||||
**default_entity_args,
|
||||
) -> List[Entity]:
|
||||
mappers = [
|
||||
m
|
||||
for m in device_mappers
|
||||
if (entity_type is None or issubclass(m.entity_type, entity_type))
|
||||
and m.capability in device.capabilities
|
||||
mapper
|
||||
for mapper in device_mappers
|
||||
if (entity_type is None or issubclass(mapper.entity_type, entity_type))
|
||||
and mapper.capability in device.capabilities
|
||||
]
|
||||
|
||||
return [
|
||||
cls._to_entity(
|
||||
device,
|
||||
property=m.attribute,
|
||||
entity_type=m.entity_type,
|
||||
**{entity_value_attr: m.get_value(device)},
|
||||
**default_entity_args,
|
||||
**cls._get_status_attr_info(device, m.attribute),
|
||||
property=mapper.attribute,
|
||||
entity_type=mapper.entity_type,
|
||||
**cls._merge_dicts(
|
||||
{entity_value_attr: mapper.get_value(device)},
|
||||
default_entity_args,
|
||||
mapper.entity_args,
|
||||
cls._get_status_attr_info(device, mapper),
|
||||
),
|
||||
)
|
||||
for m in mappers
|
||||
for mapper in mappers
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _get_lights(cls, device: Device) -> Iterable[Light]:
|
||||
def _get_lights(cls, device: DeviceEntity) -> Iterable[Light]:
|
||||
if not (
|
||||
{Capability.color_control, Capability.color_temperature}.intersection(
|
||||
device.capabilities
|
||||
|
@ -517,33 +549,39 @@ class SmartthingsPlugin(RunnablePlugin):
|
|||
return []
|
||||
|
||||
light_attrs = {}
|
||||
status = device.status
|
||||
|
||||
if Capability.switch in device.capabilities:
|
||||
light_attrs['on'] = device.status.switch
|
||||
light_attrs['on'] = status.switch
|
||||
if Capability.switch_level in device.capabilities:
|
||||
light_attrs['brightness'] = device.status.level
|
||||
light_attrs['brightness'] = status.level
|
||||
light_attrs['brightness_min'] = 0
|
||||
light_attrs['brightness_max'] = 100
|
||||
if Capability.color_temperature in device.capabilities:
|
||||
light_attrs['temperature'] = device.status.color_temperature
|
||||
light_attrs['temperature'] = status.color_temperature
|
||||
light_attrs['temperature_min'] = 1
|
||||
light_attrs['temperature_max'] = 30000
|
||||
if getattr(device.status, 'hue', None) is not None:
|
||||
light_attrs['hue'] = device.status.hue
|
||||
if getattr(status, 'hue', None) is not None:
|
||||
light_attrs['hue'] = status.hue
|
||||
light_attrs['hue_min'] = 0
|
||||
light_attrs['hue_max'] = 100
|
||||
if getattr(device.status, 'saturation', None) is not None:
|
||||
light_attrs['saturation'] = device.status.saturation
|
||||
if getattr(status, 'saturation', None) is not None:
|
||||
light_attrs['saturation'] = status.saturation
|
||||
light_attrs['saturation_min'] = 0
|
||||
light_attrs['saturation_max'] = 100
|
||||
|
||||
return [cls._to_entity(device, 'light', Light, **light_attrs)]
|
||||
|
||||
@classmethod
|
||||
def _get_switches(cls, device: Device) -> Iterable[Switch]:
|
||||
def _get_switches(cls, device: DeviceEntity) -> Iterable[Switch]:
|
||||
return cls._get_supported_entities(device, Switch, entity_value_attr='state')
|
||||
|
||||
@classmethod
|
||||
def _get_dimmers(cls, device: Device) -> Iterable[Dimmer]:
|
||||
def _get_enum_switches(cls, device: DeviceEntity) -> Iterable[Switch]:
|
||||
return cls._get_supported_entities(device, EnumSwitch)
|
||||
|
||||
@classmethod
|
||||
def _get_dimmers(cls, device: DeviceEntity) -> Iterable[Dimmer]:
|
||||
return cls._get_supported_entities(device, Dimmer, min=0, max=100)
|
||||
|
||||
@classmethod
|
||||
|
@ -703,12 +741,21 @@ class SmartthingsPlugin(RunnablePlugin):
|
|||
if value is None:
|
||||
# Toggle case
|
||||
dev = self._get_device(device)
|
||||
assert hasattr(
|
||||
dev.status, property
|
||||
), f'No such property on device "{dev.label}": "{property}"'
|
||||
if property == 'light':
|
||||
property = 'switch'
|
||||
else:
|
||||
assert hasattr(
|
||||
dev.status, property
|
||||
), f'No such property on device "{dev.label}": "{property}"'
|
||||
|
||||
value = getattr(dev.status, property, None)
|
||||
assert value is not None, (
|
||||
f'Could not get the current value of "{property}" for the '
|
||||
f'device "{dev.device_id}"'
|
||||
)
|
||||
|
||||
value = not value # Toggle
|
||||
device = dev.device_id
|
||||
value = getattr(dev.status, property) is not True
|
||||
|
||||
return self.set_value(device, property, value)
|
||||
|
||||
|
@ -769,10 +816,10 @@ class SmartthingsPlugin(RunnablePlugin):
|
|||
)
|
||||
|
||||
assert mapper, f'No mappers found to set {property}={data} on device "{device}"'
|
||||
|
||||
assert (
|
||||
mapper.set_command
|
||||
), f'The property "{property}" on the device "{device}" cannot be set'
|
||||
|
||||
command = (
|
||||
mapper.set_command(data)
|
||||
if callable(mapper.set_command)
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
from enum import Enum
|
||||
from typing import Any, Callable, List, Optional, Type, Union
|
||||
|
||||
from pysmartthings import Attribute, Capability, Command, Device
|
||||
from pysmartthings import Attribute, Capability, Command, DeviceEntity
|
||||
|
||||
from platypush.entities import Entity
|
||||
|
||||
from platypush.entities.audio import Muted, Volume
|
||||
from platypush.entities.batteries import Battery
|
||||
from platypush.entities.dimmers import Dimmer
|
||||
from platypush.entities.electricity import EnergySensor, PowerSensor, VoltageSensor
|
||||
from platypush.entities.humidity import HumiditySensor
|
||||
from platypush.entities.illuminance import IlluminanceSensor
|
||||
from platypush.entities.linkquality import LinkQuality
|
||||
from platypush.entities.motion import MotionSensor
|
||||
from platypush.entities.switches import Switch
|
||||
from platypush.entities.sensors import (
|
||||
BinarySensor,
|
||||
EnumSensor,
|
||||
MultiValueSensor,
|
||||
NumericSensor,
|
||||
)
|
||||
from platypush.entities.switches import EnumSwitch, Switch
|
||||
from platypush.entities.temperature import TemperatureSensor
|
||||
|
||||
|
||||
class DeviceMapper:
|
||||
|
@ -22,10 +34,11 @@ class DeviceMapper:
|
|||
entity_type: Type[Entity],
|
||||
capability: str,
|
||||
attribute: str,
|
||||
value_type: Type,
|
||||
set_command: Optional[Union[str, Callable[[Any], List[Any]]]] = None,
|
||||
get_value: Optional[Callable[[Device], Any]] = None,
|
||||
value_type: Union[Type, str],
|
||||
set_command: Optional[Union[str, Callable[[Any], str]]] = None,
|
||||
get_value: Optional[Callable[[DeviceEntity], Any]] = None,
|
||||
set_value_args: Optional[Callable[..., Any]] = None,
|
||||
**kwargs
|
||||
):
|
||||
self.entity_type = entity_type
|
||||
self.capability = capability
|
||||
|
@ -33,31 +46,79 @@ class DeviceMapper:
|
|||
self.attribute = attribute
|
||||
self.value_type = value_type
|
||||
self.get_value = get_value if get_value else self._default_get_value
|
||||
self.values = []
|
||||
self.entity_args = kwargs
|
||||
|
||||
if isinstance(value_type, Enum):
|
||||
self.values = [v.name for v in entity_type] # type: ignore
|
||||
|
||||
self.set_value_args = (
|
||||
set_value_args if set_value_args else self._default_set_value_args
|
||||
)
|
||||
|
||||
def _default_get_value(self, device: Device) -> Any:
|
||||
def _cast_value(self, value: Any) -> Any:
|
||||
if not isinstance(self.value_type, (str, Enum)):
|
||||
try:
|
||||
value = self.value_type(value)
|
||||
except Exception:
|
||||
# Set the value to None in case of cast errors
|
||||
value = None
|
||||
|
||||
return value
|
||||
|
||||
def _default_get_value(self, device: DeviceEntity) -> Any:
|
||||
if hasattr(device.status, self.attribute):
|
||||
value = getattr(device.status, self.attribute)
|
||||
else:
|
||||
value = device.status.attributes[self.attribute].value
|
||||
|
||||
return self.value_type(value)
|
||||
return self._cast_value(value)
|
||||
|
||||
def _default_set_value_args(self, *values: Any) -> List[Any]:
|
||||
return [self.value_type(v) for v in values]
|
||||
return [self._cast_value(v) for v in values]
|
||||
|
||||
|
||||
device_mappers: List[DeviceMapper] = [
|
||||
# acceleration_sensor
|
||||
DeviceMapper(
|
||||
entity_type=Volume,
|
||||
capability=Capability.audio_volume,
|
||||
attribute=Attribute.volume,
|
||||
value_type=int,
|
||||
set_command=Command.set_volume,
|
||||
entity_type=BinarySensor,
|
||||
capability=Capability.acceleration_sensor,
|
||||
attribute=Attribute.acceleration,
|
||||
value_type=bool,
|
||||
),
|
||||
# air_conditioner_fan_mode
|
||||
DeviceMapper(
|
||||
entity_type=EnumSwitch,
|
||||
capability=Capability.air_conditioner_fan_mode,
|
||||
attribute=Attribute.fan_mode,
|
||||
value_type=Attribute.supported_ac_fan_modes,
|
||||
set_command=Command.set_fan_mode,
|
||||
),
|
||||
# air_conditioner_mode
|
||||
DeviceMapper(
|
||||
entity_type=EnumSwitch,
|
||||
capability=Capability.air_conditioner_mode,
|
||||
attribute=Attribute.air_conditioner_mode,
|
||||
value_type=Attribute.supported_ac_modes,
|
||||
set_command=Command.set_air_conditioner_mode,
|
||||
),
|
||||
# air_quality_sensor
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.air_quality_sensor,
|
||||
attribute=Attribute.air_quality,
|
||||
value_type=int,
|
||||
),
|
||||
# alarm
|
||||
DeviceMapper(
|
||||
entity_type=EnumSwitch,
|
||||
capability=Capability.alarm,
|
||||
attribute=Attribute.alarm,
|
||||
value_type=Enum('AlarmValues', ['both', 'off', 'siren', 'strobe']),
|
||||
set_command=lambda value: value,
|
||||
set_value_args=lambda *_: [],
|
||||
),
|
||||
# audio_mute
|
||||
DeviceMapper(
|
||||
entity_type=Muted,
|
||||
capability=Capability.audio_mute,
|
||||
|
@ -66,25 +127,285 @@ device_mappers: List[DeviceMapper] = [
|
|||
set_command=lambda value: Command.mute if value else Command.unmute,
|
||||
set_value_args=lambda *_: [],
|
||||
),
|
||||
# audio_volume
|
||||
DeviceMapper(
|
||||
entity_type=MotionSensor,
|
||||
capability=Capability.motion_sensor,
|
||||
attribute=Attribute.motion,
|
||||
value_type=bool,
|
||||
entity_type=Volume,
|
||||
capability=Capability.audio_volume,
|
||||
attribute=Attribute.volume,
|
||||
value_type=int,
|
||||
set_command=Command.set_volume,
|
||||
),
|
||||
# battery
|
||||
DeviceMapper(
|
||||
entity_type=Battery,
|
||||
capability=Capability.battery,
|
||||
attribute=Attribute.battery,
|
||||
value_type=int,
|
||||
),
|
||||
# body_mass_index_measurement
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.body_mass_index_measurement,
|
||||
attribute=Attribute.body_weight_measurement,
|
||||
value_type=float,
|
||||
),
|
||||
# body_weight_measurement
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.body_weight_measurement,
|
||||
attribute=Attribute.body_weight_measurement,
|
||||
value_type=float,
|
||||
),
|
||||
# button
|
||||
DeviceMapper(
|
||||
entity_type=EnumSensor,
|
||||
capability=Capability.button,
|
||||
attribute=Attribute.button,
|
||||
value_type=Enum(
|
||||
'ButtonValues',
|
||||
[
|
||||
'pushed',
|
||||
'held',
|
||||
'double',
|
||||
'pushed_2x',
|
||||
'pushed_3x',
|
||||
'pushed_4x',
|
||||
'pushed_5x',
|
||||
'pushed_6x',
|
||||
'down',
|
||||
'down_2x',
|
||||
'down_3x',
|
||||
'down_4x',
|
||||
'down_5x',
|
||||
'down_6x',
|
||||
'down_hold',
|
||||
'up',
|
||||
'up_2x',
|
||||
'up_3x',
|
||||
'up_4x',
|
||||
'up_5x',
|
||||
'up_6x',
|
||||
'up_hold',
|
||||
'swipe_up',
|
||||
'swipe_down',
|
||||
'swipe_left',
|
||||
'swipe_right',
|
||||
'unknown',
|
||||
],
|
||||
),
|
||||
),
|
||||
# carbon_dioxide_measurement
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.carbon_dioxide_measurement,
|
||||
attribute=Attribute.carbon_dioxide,
|
||||
value_type=float,
|
||||
),
|
||||
# carbon_monoxide_detector
|
||||
DeviceMapper(
|
||||
entity_type=EnumSensor,
|
||||
capability=Capability.carbon_monoxide_detector,
|
||||
attribute=Attribute.carbon_monoxide,
|
||||
value_type=Enum(
|
||||
'CarbonMonoxideValues', ['clear', 'detected', 'tested', 'unknown']
|
||||
),
|
||||
),
|
||||
# carbon_monoxide_measurement
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.carbon_monoxide_measurement,
|
||||
attribute=Attribute.carbon_monoxide_level,
|
||||
value_type=float,
|
||||
),
|
||||
# contact_sensor
|
||||
DeviceMapper(
|
||||
entity_type=BinarySensor,
|
||||
capability=Capability.contact_sensor,
|
||||
attribute=Attribute.contact,
|
||||
value_type=bool,
|
||||
),
|
||||
# dishwasher_operating_state
|
||||
DeviceMapper(
|
||||
entity_type=EnumSensor,
|
||||
capability=Capability.dishwasher_operating_state,
|
||||
attribute=Attribute.machine_state,
|
||||
value_type=Attribute.supported_machine_states,
|
||||
),
|
||||
# door_control
|
||||
DeviceMapper(
|
||||
entity_type=Switch,
|
||||
capability=Capability.door_control,
|
||||
attribute=Attribute.door,
|
||||
value_type=bool,
|
||||
get_value=lambda device: device.status.door in {'open', 'opening'},
|
||||
set_command=lambda value: Command.open if value else Command.close,
|
||||
),
|
||||
# dryer_operating_state
|
||||
DeviceMapper(
|
||||
entity_type=EnumSensor,
|
||||
capability=Capability.dryer_operating_state,
|
||||
attribute=Attribute.machine_state,
|
||||
value_type=Attribute.supported_machine_states,
|
||||
),
|
||||
# dust_sensor
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.dust_sensor,
|
||||
attribute=Attribute.dust_level,
|
||||
value_type=float,
|
||||
),
|
||||
# energy_meter
|
||||
DeviceMapper(
|
||||
entity_type=EnergySensor,
|
||||
capability=Capability.energy_meter,
|
||||
attribute=Attribute.energy,
|
||||
value_type=float,
|
||||
),
|
||||
# equivalent_carbon_dioxide_measurement
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.equivalent_carbon_dioxide_measurement,
|
||||
attribute=Attribute.equivalent_carbon_dioxide_measurement,
|
||||
value_type=float,
|
||||
),
|
||||
# fan_speed
|
||||
DeviceMapper(
|
||||
entity_type=Dimmer,
|
||||
capability=Capability.switch_level,
|
||||
attribute=Attribute.level,
|
||||
capability=Capability.fan_speed,
|
||||
attribute=Attribute.fan_speed,
|
||||
value_type=int,
|
||||
set_command=Command.set_level,
|
||||
set_command=Command.set_fan_speed,
|
||||
),
|
||||
# formaldehyde_measurement
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.formaldehyde_measurement,
|
||||
attribute=Attribute.formaldehyde_level,
|
||||
value_type=float,
|
||||
),
|
||||
# gas_meter
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.gas_meter,
|
||||
attribute=Attribute.gas_meter,
|
||||
value_type=float,
|
||||
),
|
||||
# illuminance_measurement
|
||||
DeviceMapper(
|
||||
entity_type=IlluminanceSensor,
|
||||
capability=Capability.illuminance_measurement,
|
||||
attribute=Attribute.illuminance,
|
||||
value_type=float,
|
||||
),
|
||||
# infrared_level
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.infrared_level,
|
||||
attribute=Attribute.infrared_level,
|
||||
value_type=int,
|
||||
min=0,
|
||||
max=100,
|
||||
),
|
||||
# lock
|
||||
DeviceMapper(
|
||||
entity_type=Switch,
|
||||
capability=Capability.lock,
|
||||
attribute=Attribute.lock,
|
||||
value_type=bool,
|
||||
get_value=lambda device: device.status.lock in {True, 'locked'},
|
||||
set_command=lambda value: Command.lock if value else Command.unlock,
|
||||
set_value_args=lambda *_: [],
|
||||
),
|
||||
# media_input_source
|
||||
DeviceMapper(
|
||||
entity_type=EnumSwitch,
|
||||
capability=Capability.media_input_source,
|
||||
attribute=Attribute.input_source,
|
||||
value_type=Attribute.supported_input_sources,
|
||||
set_command=Command.set_input_source,
|
||||
),
|
||||
# motion_sensor
|
||||
DeviceMapper(
|
||||
entity_type=MotionSensor,
|
||||
capability=Capability.motion_sensor,
|
||||
attribute=Attribute.motion,
|
||||
value_type=bool,
|
||||
),
|
||||
# odor_sensor
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.odor_sensor,
|
||||
attribute=Attribute.odor_level,
|
||||
value_type=int,
|
||||
),
|
||||
# oven_operating_state
|
||||
DeviceMapper(
|
||||
entity_type=EnumSensor,
|
||||
capability=Capability.oven_operating_state,
|
||||
attribute=Attribute.machine_state,
|
||||
value_type=Attribute.supported_machine_states,
|
||||
),
|
||||
# power_consumption_report
|
||||
DeviceMapper(
|
||||
entity_type=PowerSensor,
|
||||
capability=Capability.power_consumption_report,
|
||||
attribute=Attribute.power_consumption,
|
||||
value_type=float,
|
||||
),
|
||||
# power_meter
|
||||
DeviceMapper(
|
||||
entity_type=PowerSensor,
|
||||
capability=Capability.power_meter,
|
||||
attribute=Attribute.power,
|
||||
value_type=float,
|
||||
),
|
||||
# power_source
|
||||
DeviceMapper(
|
||||
entity_type=EnumSensor,
|
||||
capability=Capability.power_source,
|
||||
attribute=Attribute.power_source,
|
||||
value_type=Enum('PowerSourceValues', ['battery', 'dc', 'mains', 'unknown']),
|
||||
),
|
||||
# presence_sensor
|
||||
DeviceMapper(
|
||||
entity_type=BinarySensor,
|
||||
capability=Capability.presence_sensor,
|
||||
attribute=Attribute.presence,
|
||||
value_type=bool,
|
||||
),
|
||||
# relative_humidity_measurement
|
||||
DeviceMapper(
|
||||
entity_type=HumiditySensor,
|
||||
capability=Capability.relative_humidity_measurement,
|
||||
attribute=Attribute.humidity,
|
||||
value_type=int,
|
||||
min=0,
|
||||
max=100,
|
||||
),
|
||||
# signal_strength
|
||||
DeviceMapper(
|
||||
entity_type=LinkQuality,
|
||||
capability=Capability.signal_strength,
|
||||
attribute=Attribute.lqi,
|
||||
value_type=int,
|
||||
min=0,
|
||||
max=255,
|
||||
),
|
||||
# smoke_detector
|
||||
DeviceMapper(
|
||||
entity_type=EnumSensor,
|
||||
capability=Capability.smoke_detector,
|
||||
attribute=Attribute.smoke,
|
||||
value_type=Enum('SmokeDetectorValues', ['clear', 'detected', 'tested']),
|
||||
),
|
||||
# sound_sensor
|
||||
DeviceMapper(
|
||||
entity_type=BinarySensor,
|
||||
capability=Capability.sound_sensor,
|
||||
attribute=Attribute.sound,
|
||||
value_type=bool,
|
||||
),
|
||||
# switch
|
||||
DeviceMapper(
|
||||
entity_type=Switch,
|
||||
capability=Capability.switch,
|
||||
|
@ -93,6 +414,153 @@ device_mappers: List[DeviceMapper] = [
|
|||
set_command=lambda value: Command.on if value else Command.off,
|
||||
set_value_args=lambda *_: [],
|
||||
),
|
||||
# switch_level
|
||||
DeviceMapper(
|
||||
entity_type=Dimmer,
|
||||
capability=Capability.switch_level,
|
||||
attribute=Attribute.level,
|
||||
value_type=int,
|
||||
set_command=Command.set_level,
|
||||
),
|
||||
# tamper_alert
|
||||
DeviceMapper(
|
||||
entity_type=BinarySensor,
|
||||
capability=Capability.tamper_alert,
|
||||
attribute=Attribute.tamper,
|
||||
value_type=bool,
|
||||
),
|
||||
# temperature_measurement
|
||||
DeviceMapper(
|
||||
entity_type=TemperatureSensor,
|
||||
capability=Capability.temperature_measurement,
|
||||
attribute=Attribute.temperature,
|
||||
value_type=float,
|
||||
),
|
||||
# thermostat_cooling_setpoint
|
||||
DeviceMapper(
|
||||
entity_type=Dimmer,
|
||||
capability=Capability.thermostat_cooling_setpoint,
|
||||
attribute=Attribute.cooling_setpoint,
|
||||
value_type=float,
|
||||
min=-460,
|
||||
max=10000,
|
||||
set_command=Command.set_cooling_setpoint,
|
||||
),
|
||||
# thermostat_fan_mode
|
||||
DeviceMapper(
|
||||
entity_type=EnumSwitch,
|
||||
capability=Capability.thermostat_fan_mode,
|
||||
attribute=Attribute.thermostat_fan_mode,
|
||||
value_type=Attribute.supported_thermostat_fan_modes,
|
||||
set_command=Command.set_thermostat_fan_mode,
|
||||
),
|
||||
# thermostat_heating_setpoint
|
||||
DeviceMapper(
|
||||
entity_type=Dimmer,
|
||||
capability=Capability.thermostat_heating_setpoint,
|
||||
attribute=Attribute.heating_setpoint,
|
||||
value_type=float,
|
||||
min=-460,
|
||||
max=10000,
|
||||
set_command=Command.set_heating_setpoint,
|
||||
),
|
||||
# thermostat_mode
|
||||
DeviceMapper(
|
||||
entity_type=EnumSwitch,
|
||||
capability=Capability.thermostat_mode,
|
||||
attribute=Attribute.thermostat_mode,
|
||||
value_type=Attribute.supported_thermostat_modes,
|
||||
set_command=Command.set_thermostat_mode,
|
||||
),
|
||||
# thermostat_operating_state
|
||||
DeviceMapper(
|
||||
entity_type=EnumSensor,
|
||||
capability=Capability.thermostat_operating_state,
|
||||
attribute=Attribute.thermostat_operating_state,
|
||||
value_type=Enum(
|
||||
'ThermostatOperatingState',
|
||||
[
|
||||
'cooling',
|
||||
'fan only',
|
||||
'heating',
|
||||
'idle',
|
||||
'pending cool',
|
||||
'pending heat',
|
||||
'vent economizer',
|
||||
],
|
||||
),
|
||||
),
|
||||
# three_axis
|
||||
DeviceMapper(
|
||||
entity_type=MultiValueSensor,
|
||||
capability=Capability.three_axis,
|
||||
attribute=Attribute.three_axis,
|
||||
value_type=list,
|
||||
),
|
||||
# tv_channel
|
||||
DeviceMapper(
|
||||
entity_type=Dimmer,
|
||||
capability=Capability.tv_channel,
|
||||
attribute=Attribute.tv_channel,
|
||||
value_type=int,
|
||||
set_command=Command.set_tv_channel,
|
||||
min=1,
|
||||
max=1000,
|
||||
),
|
||||
# tvoc_measurement
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.tvoc_measurement,
|
||||
attribute=Attribute.tvoc_level,
|
||||
value_type=float,
|
||||
),
|
||||
# ultraviolet_index
|
||||
DeviceMapper(
|
||||
entity_type=NumericSensor,
|
||||
capability=Capability.ultraviolet_index,
|
||||
attribute=Attribute.ultraviolet_index,
|
||||
value_type=float,
|
||||
),
|
||||
# valve
|
||||
DeviceMapper(
|
||||
entity_type=Switch,
|
||||
capability=Capability.valve,
|
||||
attribute=Attribute.valve,
|
||||
value_type=bool,
|
||||
set_command=lambda value: Command.open if value else Command.close,
|
||||
set_value_args=lambda *_: [],
|
||||
),
|
||||
# voltage_measurement
|
||||
DeviceMapper(
|
||||
entity_type=VoltageSensor,
|
||||
capability=Capability.voltage_measurement,
|
||||
attribute=Attribute.voltage,
|
||||
value_type=float,
|
||||
),
|
||||
# washer_operating_state
|
||||
DeviceMapper(
|
||||
entity_type=EnumSensor,
|
||||
capability=Capability.washer_operating_state,
|
||||
attribute=Attribute.machine_state,
|
||||
value_type=Attribute.supported_machine_states,
|
||||
),
|
||||
# water_sensor
|
||||
DeviceMapper(
|
||||
entity_type=BinarySensor,
|
||||
capability=Capability.water_sensor,
|
||||
attribute=Attribute.water,
|
||||
value_type=bool,
|
||||
),
|
||||
# window_shade
|
||||
DeviceMapper(
|
||||
entity_type=Dimmer,
|
||||
capability=Capability.window_shade,
|
||||
attribute=Attribute.window_shade,
|
||||
value_type=int,
|
||||
set_command='setWindowShade',
|
||||
min=0,
|
||||
max=100,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue