Extract smartthings switch energy attributes into sensors (#53719)
This commit is contained in:
parent
8972fae0ca
commit
2b2cddb5f0
5 changed files with 257 additions and 75 deletions
|
@ -9,6 +9,7 @@ import logging
|
||||||
from aiohttp.client_exceptions import ClientConnectionError, ClientResponseError
|
from aiohttp.client_exceptions import ClientConnectionError, ClientResponseError
|
||||||
from pysmartapp.event import EVENT_TYPE_DEVICE
|
from pysmartapp.event import EVENT_TYPE_DEVICE
|
||||||
from pysmartthings import Attribute, Capability, SmartThings
|
from pysmartthings import Attribute, Capability, SmartThings
|
||||||
|
from pysmartthings.device import DeviceEntity
|
||||||
|
|
||||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
@ -412,7 +413,7 @@ class DeviceBroker:
|
||||||
class SmartThingsEntity(Entity):
|
class SmartThingsEntity(Entity):
|
||||||
"""Defines a SmartThings entity."""
|
"""Defines a SmartThings entity."""
|
||||||
|
|
||||||
def __init__(self, device):
|
def __init__(self, device: DeviceEntity) -> None:
|
||||||
"""Initialize the instance."""
|
"""Initialize the instance."""
|
||||||
self._device = device
|
self._device = device
|
||||||
self._dispatcher_remove = None
|
self._dispatcher_remove = None
|
||||||
|
|
|
@ -3,18 +3,26 @@ from __future__ import annotations
|
||||||
|
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from pysmartthings import Attribute, Capability
|
from pysmartthings import Attribute, Capability
|
||||||
|
from pysmartthings.device import DeviceEntity
|
||||||
|
|
||||||
from homeassistant.components.sensor import SensorEntity
|
from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, SensorEntity
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
AREA_SQUARE_METERS,
|
AREA_SQUARE_METERS,
|
||||||
CONCENTRATION_PARTS_PER_MILLION,
|
CONCENTRATION_PARTS_PER_MILLION,
|
||||||
DEVICE_CLASS_BATTERY,
|
DEVICE_CLASS_BATTERY,
|
||||||
|
DEVICE_CLASS_CO,
|
||||||
|
DEVICE_CLASS_CO2,
|
||||||
|
DEVICE_CLASS_ENERGY,
|
||||||
DEVICE_CLASS_HUMIDITY,
|
DEVICE_CLASS_HUMIDITY,
|
||||||
DEVICE_CLASS_ILLUMINANCE,
|
DEVICE_CLASS_ILLUMINANCE,
|
||||||
|
DEVICE_CLASS_POWER,
|
||||||
|
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
DEVICE_CLASS_TIMESTAMP,
|
DEVICE_CLASS_TIMESTAMP,
|
||||||
|
DEVICE_CLASS_VOLTAGE,
|
||||||
ELECTRIC_POTENTIAL_VOLT,
|
ELECTRIC_POTENTIAL_VOLT,
|
||||||
ENERGY_KILO_WATT_HOUR,
|
ENERGY_KILO_WATT_HOUR,
|
||||||
LIGHT_LUX,
|
LIGHT_LUX,
|
||||||
|
@ -25,26 +33,27 @@ from homeassistant.const import (
|
||||||
TEMP_FAHRENHEIT,
|
TEMP_FAHRENHEIT,
|
||||||
VOLUME_CUBIC_METERS,
|
VOLUME_CUBIC_METERS,
|
||||||
)
|
)
|
||||||
|
from homeassistant.util.dt import utc_from_timestamp
|
||||||
|
|
||||||
from . import SmartThingsEntity
|
from . import SmartThingsEntity
|
||||||
from .const import DATA_BROKERS, DOMAIN
|
from .const import DATA_BROKERS, DOMAIN
|
||||||
|
|
||||||
Map = namedtuple("map", "attribute name default_unit device_class")
|
Map = namedtuple("map", "attribute name default_unit device_class state_class")
|
||||||
|
|
||||||
CAPABILITY_TO_SENSORS = {
|
CAPABILITY_TO_SENSORS = {
|
||||||
Capability.activity_lighting_mode: [
|
Capability.activity_lighting_mode: [
|
||||||
Map(Attribute.lighting_mode, "Activity Lighting Mode", None, None)
|
Map(Attribute.lighting_mode, "Activity Lighting Mode", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.air_conditioner_mode: [
|
Capability.air_conditioner_mode: [
|
||||||
Map(Attribute.air_conditioner_mode, "Air Conditioner Mode", None, None)
|
Map(Attribute.air_conditioner_mode, "Air Conditioner Mode", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.air_quality_sensor: [
|
Capability.air_quality_sensor: [
|
||||||
Map(Attribute.air_quality, "Air Quality", "CAQI", None)
|
Map(Attribute.air_quality, "Air Quality", "CAQI", None, STATE_CLASS_MEASUREMENT)
|
||||||
],
|
],
|
||||||
Capability.alarm: [Map(Attribute.alarm, "Alarm", None, None)],
|
Capability.alarm: [Map(Attribute.alarm, "Alarm", None, None, None)],
|
||||||
Capability.audio_volume: [Map(Attribute.volume, "Volume", PERCENTAGE, None)],
|
Capability.audio_volume: [Map(Attribute.volume, "Volume", PERCENTAGE, None, None)],
|
||||||
Capability.battery: [
|
Capability.battery: [
|
||||||
Map(Attribute.battery, "Battery", PERCENTAGE, DEVICE_CLASS_BATTERY)
|
Map(Attribute.battery, "Battery", PERCENTAGE, DEVICE_CLASS_BATTERY, None)
|
||||||
],
|
],
|
||||||
Capability.body_mass_index_measurement: [
|
Capability.body_mass_index_measurement: [
|
||||||
Map(
|
Map(
|
||||||
|
@ -52,57 +61,80 @@ CAPABILITY_TO_SENSORS = {
|
||||||
"Body Mass Index",
|
"Body Mass Index",
|
||||||
f"{MASS_KILOGRAMS}/{AREA_SQUARE_METERS}",
|
f"{MASS_KILOGRAMS}/{AREA_SQUARE_METERS}",
|
||||||
None,
|
None,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.body_weight_measurement: [
|
Capability.body_weight_measurement: [
|
||||||
Map(Attribute.body_weight_measurement, "Body Weight", MASS_KILOGRAMS, None)
|
Map(
|
||||||
|
Attribute.body_weight_measurement,
|
||||||
|
"Body Weight",
|
||||||
|
MASS_KILOGRAMS,
|
||||||
|
None,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
Capability.carbon_dioxide_measurement: [
|
Capability.carbon_dioxide_measurement: [
|
||||||
Map(
|
Map(
|
||||||
Attribute.carbon_dioxide,
|
Attribute.carbon_dioxide,
|
||||||
"Carbon Dioxide Measurement",
|
"Carbon Dioxide Measurement",
|
||||||
CONCENTRATION_PARTS_PER_MILLION,
|
CONCENTRATION_PARTS_PER_MILLION,
|
||||||
None,
|
DEVICE_CLASS_CO2,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.carbon_monoxide_detector: [
|
Capability.carbon_monoxide_detector: [
|
||||||
Map(Attribute.carbon_monoxide, "Carbon Monoxide Detector", None, None)
|
Map(Attribute.carbon_monoxide, "Carbon Monoxide Detector", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.carbon_monoxide_measurement: [
|
Capability.carbon_monoxide_measurement: [
|
||||||
Map(
|
Map(
|
||||||
Attribute.carbon_monoxide_level,
|
Attribute.carbon_monoxide_level,
|
||||||
"Carbon Monoxide Measurement",
|
"Carbon Monoxide Measurement",
|
||||||
CONCENTRATION_PARTS_PER_MILLION,
|
CONCENTRATION_PARTS_PER_MILLION,
|
||||||
None,
|
DEVICE_CLASS_CO,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.dishwasher_operating_state: [
|
Capability.dishwasher_operating_state: [
|
||||||
Map(Attribute.machine_state, "Dishwasher Machine State", None, None),
|
Map(Attribute.machine_state, "Dishwasher Machine State", None, None, None),
|
||||||
Map(Attribute.dishwasher_job_state, "Dishwasher Job State", None, None),
|
Map(Attribute.dishwasher_job_state, "Dishwasher Job State", None, None, None),
|
||||||
Map(
|
Map(
|
||||||
Attribute.completion_time,
|
Attribute.completion_time,
|
||||||
"Dishwasher Completion Time",
|
"Dishwasher Completion Time",
|
||||||
None,
|
None,
|
||||||
DEVICE_CLASS_TIMESTAMP,
|
DEVICE_CLASS_TIMESTAMP,
|
||||||
|
None,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
Capability.dryer_mode: [Map(Attribute.dryer_mode, "Dryer Mode", None, None)],
|
Capability.dryer_mode: [Map(Attribute.dryer_mode, "Dryer Mode", None, None, None)],
|
||||||
Capability.dryer_operating_state: [
|
Capability.dryer_operating_state: [
|
||||||
Map(Attribute.machine_state, "Dryer Machine State", None, None),
|
Map(Attribute.machine_state, "Dryer Machine State", None, None, None),
|
||||||
Map(Attribute.dryer_job_state, "Dryer Job State", None, None),
|
Map(Attribute.dryer_job_state, "Dryer Job State", None, None, None),
|
||||||
Map(
|
Map(
|
||||||
Attribute.completion_time,
|
Attribute.completion_time,
|
||||||
"Dryer Completion Time",
|
"Dryer Completion Time",
|
||||||
None,
|
None,
|
||||||
DEVICE_CLASS_TIMESTAMP,
|
DEVICE_CLASS_TIMESTAMP,
|
||||||
|
None,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
Capability.dust_sensor: [
|
Capability.dust_sensor: [
|
||||||
Map(Attribute.fine_dust_level, "Fine Dust Level", None, None),
|
Map(
|
||||||
Map(Attribute.dust_level, "Dust Level", None, None),
|
Attribute.fine_dust_level,
|
||||||
|
"Fine Dust Level",
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
Map(Attribute.dust_level, "Dust Level", None, None, STATE_CLASS_MEASUREMENT),
|
||||||
],
|
],
|
||||||
Capability.energy_meter: [
|
Capability.energy_meter: [
|
||||||
Map(Attribute.energy, "Energy Meter", ENERGY_KILO_WATT_HOUR, None)
|
Map(
|
||||||
|
Attribute.energy,
|
||||||
|
"Energy Meter",
|
||||||
|
ENERGY_KILO_WATT_HOUR,
|
||||||
|
DEVICE_CLASS_ENERGY,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
Capability.equivalent_carbon_dioxide_measurement: [
|
Capability.equivalent_carbon_dioxide_measurement: [
|
||||||
Map(
|
Map(
|
||||||
|
@ -110,6 +142,7 @@ CAPABILITY_TO_SENSORS = {
|
||||||
"Equivalent Carbon Dioxide Measurement",
|
"Equivalent Carbon Dioxide Measurement",
|
||||||
CONCENTRATION_PARTS_PER_MILLION,
|
CONCENTRATION_PARTS_PER_MILLION,
|
||||||
None,
|
None,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.formaldehyde_measurement: [
|
Capability.formaldehyde_measurement: [
|
||||||
|
@ -118,50 +151,94 @@ CAPABILITY_TO_SENSORS = {
|
||||||
"Formaldehyde Measurement",
|
"Formaldehyde Measurement",
|
||||||
CONCENTRATION_PARTS_PER_MILLION,
|
CONCENTRATION_PARTS_PER_MILLION,
|
||||||
None,
|
None,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.gas_meter: [
|
Capability.gas_meter: [
|
||||||
Map(Attribute.gas_meter, "Gas Meter", ENERGY_KILO_WATT_HOUR, None),
|
Map(
|
||||||
Map(Attribute.gas_meter_calorific, "Gas Meter Calorific", None, None),
|
Attribute.gas_meter,
|
||||||
Map(Attribute.gas_meter_time, "Gas Meter Time", None, DEVICE_CLASS_TIMESTAMP),
|
"Gas Meter",
|
||||||
Map(Attribute.gas_meter_volume, "Gas Meter Volume", VOLUME_CUBIC_METERS, None),
|
ENERGY_KILO_WATT_HOUR,
|
||||||
|
None,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
Map(Attribute.gas_meter_calorific, "Gas Meter Calorific", None, None, None),
|
||||||
|
Map(
|
||||||
|
Attribute.gas_meter_time,
|
||||||
|
"Gas Meter Time",
|
||||||
|
None,
|
||||||
|
DEVICE_CLASS_TIMESTAMP,
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
Map(
|
||||||
|
Attribute.gas_meter_volume,
|
||||||
|
"Gas Meter Volume",
|
||||||
|
VOLUME_CUBIC_METERS,
|
||||||
|
None,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
Capability.illuminance_measurement: [
|
Capability.illuminance_measurement: [
|
||||||
Map(Attribute.illuminance, "Illuminance", LIGHT_LUX, DEVICE_CLASS_ILLUMINANCE)
|
Map(
|
||||||
|
Attribute.illuminance,
|
||||||
|
"Illuminance",
|
||||||
|
LIGHT_LUX,
|
||||||
|
DEVICE_CLASS_ILLUMINANCE,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
Capability.infrared_level: [
|
Capability.infrared_level: [
|
||||||
Map(Attribute.infrared_level, "Infrared Level", PERCENTAGE, None)
|
Map(
|
||||||
|
Attribute.infrared_level,
|
||||||
|
"Infrared Level",
|
||||||
|
PERCENTAGE,
|
||||||
|
None,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
Capability.media_input_source: [
|
Capability.media_input_source: [
|
||||||
Map(Attribute.input_source, "Media Input Source", None, None)
|
Map(Attribute.input_source, "Media Input Source", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.media_playback_repeat: [
|
Capability.media_playback_repeat: [
|
||||||
Map(Attribute.playback_repeat_mode, "Media Playback Repeat", None, None)
|
Map(Attribute.playback_repeat_mode, "Media Playback Repeat", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.media_playback_shuffle: [
|
Capability.media_playback_shuffle: [
|
||||||
Map(Attribute.playback_shuffle, "Media Playback Shuffle", None, None)
|
Map(Attribute.playback_shuffle, "Media Playback Shuffle", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.media_playback: [
|
Capability.media_playback: [
|
||||||
Map(Attribute.playback_status, "Media Playback Status", None, None)
|
Map(Attribute.playback_status, "Media Playback Status", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.odor_sensor: [Map(Attribute.odor_level, "Odor Sensor", None, None)],
|
Capability.odor_sensor: [
|
||||||
Capability.oven_mode: [Map(Attribute.oven_mode, "Oven Mode", None, None)],
|
Map(Attribute.odor_level, "Odor Sensor", None, None, None)
|
||||||
|
],
|
||||||
|
Capability.oven_mode: [Map(Attribute.oven_mode, "Oven Mode", None, None, None)],
|
||||||
Capability.oven_operating_state: [
|
Capability.oven_operating_state: [
|
||||||
Map(Attribute.machine_state, "Oven Machine State", None, None),
|
Map(Attribute.machine_state, "Oven Machine State", None, None, None),
|
||||||
Map(Attribute.oven_job_state, "Oven Job State", None, None),
|
Map(Attribute.oven_job_state, "Oven Job State", None, None, None),
|
||||||
Map(Attribute.completion_time, "Oven Completion Time", None, None),
|
Map(Attribute.completion_time, "Oven Completion Time", None, None, None),
|
||||||
],
|
],
|
||||||
Capability.oven_setpoint: [
|
Capability.oven_setpoint: [
|
||||||
Map(Attribute.oven_setpoint, "Oven Set Point", None, None)
|
Map(Attribute.oven_setpoint, "Oven Set Point", None, None, None)
|
||||||
|
],
|
||||||
|
Capability.power_meter: [
|
||||||
|
Map(
|
||||||
|
Attribute.power,
|
||||||
|
"Power Meter",
|
||||||
|
POWER_WATT,
|
||||||
|
DEVICE_CLASS_POWER,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
Capability.power_source: [
|
||||||
|
Map(Attribute.power_source, "Power Source", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.power_meter: [Map(Attribute.power, "Power Meter", POWER_WATT, None)],
|
|
||||||
Capability.power_source: [Map(Attribute.power_source, "Power Source", None, None)],
|
|
||||||
Capability.refrigeration_setpoint: [
|
Capability.refrigeration_setpoint: [
|
||||||
Map(
|
Map(
|
||||||
Attribute.refrigeration_setpoint,
|
Attribute.refrigeration_setpoint,
|
||||||
"Refrigeration Setpoint",
|
"Refrigeration Setpoint",
|
||||||
None,
|
None,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.relative_humidity_measurement: [
|
Capability.relative_humidity_measurement: [
|
||||||
|
@ -170,6 +247,7 @@ CAPABILITY_TO_SENSORS = {
|
||||||
"Relative Humidity Measurement",
|
"Relative Humidity Measurement",
|
||||||
PERCENTAGE,
|
PERCENTAGE,
|
||||||
DEVICE_CLASS_HUMIDITY,
|
DEVICE_CLASS_HUMIDITY,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.robot_cleaner_cleaning_mode: [
|
Capability.robot_cleaner_cleaning_mode: [
|
||||||
|
@ -178,25 +256,43 @@ CAPABILITY_TO_SENSORS = {
|
||||||
"Robot Cleaner Cleaning Mode",
|
"Robot Cleaner Cleaning Mode",
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.robot_cleaner_movement: [
|
Capability.robot_cleaner_movement: [
|
||||||
Map(Attribute.robot_cleaner_movement, "Robot Cleaner Movement", None, None)
|
Map(
|
||||||
|
Attribute.robot_cleaner_movement, "Robot Cleaner Movement", None, None, None
|
||||||
|
)
|
||||||
],
|
],
|
||||||
Capability.robot_cleaner_turbo_mode: [
|
Capability.robot_cleaner_turbo_mode: [
|
||||||
Map(Attribute.robot_cleaner_turbo_mode, "Robot Cleaner Turbo Mode", None, None)
|
Map(
|
||||||
|
Attribute.robot_cleaner_turbo_mode,
|
||||||
|
"Robot Cleaner Turbo Mode",
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
Capability.signal_strength: [
|
Capability.signal_strength: [
|
||||||
Map(Attribute.lqi, "LQI Signal Strength", None, None),
|
Map(Attribute.lqi, "LQI Signal Strength", None, None, STATE_CLASS_MEASUREMENT),
|
||||||
Map(Attribute.rssi, "RSSI Signal Strength", None, None),
|
Map(
|
||||||
|
Attribute.rssi,
|
||||||
|
"RSSI Signal Strength",
|
||||||
|
None,
|
||||||
|
DEVICE_CLASS_SIGNAL_STRENGTH,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Capability.smoke_detector: [
|
||||||
|
Map(Attribute.smoke, "Smoke Detector", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.smoke_detector: [Map(Attribute.smoke, "Smoke Detector", None, None)],
|
|
||||||
Capability.temperature_measurement: [
|
Capability.temperature_measurement: [
|
||||||
Map(
|
Map(
|
||||||
Attribute.temperature,
|
Attribute.temperature,
|
||||||
"Temperature Measurement",
|
"Temperature Measurement",
|
||||||
None,
|
None,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.thermostat_cooling_setpoint: [
|
Capability.thermostat_cooling_setpoint: [
|
||||||
|
@ -205,10 +301,11 @@ CAPABILITY_TO_SENSORS = {
|
||||||
"Thermostat Cooling Setpoint",
|
"Thermostat Cooling Setpoint",
|
||||||
None,
|
None,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.thermostat_fan_mode: [
|
Capability.thermostat_fan_mode: [
|
||||||
Map(Attribute.thermostat_fan_mode, "Thermostat Fan Mode", None, None)
|
Map(Attribute.thermostat_fan_mode, "Thermostat Fan Mode", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.thermostat_heating_setpoint: [
|
Capability.thermostat_heating_setpoint: [
|
||||||
Map(
|
Map(
|
||||||
|
@ -216,10 +313,11 @@ CAPABILITY_TO_SENSORS = {
|
||||||
"Thermostat Heating Setpoint",
|
"Thermostat Heating Setpoint",
|
||||||
None,
|
None,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.thermostat_mode: [
|
Capability.thermostat_mode: [
|
||||||
Map(Attribute.thermostat_mode, "Thermostat Mode", None, None)
|
Map(Attribute.thermostat_mode, "Thermostat Mode", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.thermostat_operating_state: [
|
Capability.thermostat_operating_state: [
|
||||||
Map(
|
Map(
|
||||||
|
@ -227,6 +325,7 @@ CAPABILITY_TO_SENSORS = {
|
||||||
"Thermostat Operating State",
|
"Thermostat Operating State",
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.thermostat_setpoint: [
|
Capability.thermostat_setpoint: [
|
||||||
|
@ -235,12 +334,13 @@ CAPABILITY_TO_SENSORS = {
|
||||||
"Thermostat Setpoint",
|
"Thermostat Setpoint",
|
||||||
None,
|
None,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.three_axis: [],
|
Capability.three_axis: [],
|
||||||
Capability.tv_channel: [
|
Capability.tv_channel: [
|
||||||
Map(Attribute.tv_channel, "Tv Channel", None, None),
|
Map(Attribute.tv_channel, "Tv Channel", None, None, None),
|
||||||
Map(Attribute.tv_channel_name, "Tv Channel Name", None, None),
|
Map(Attribute.tv_channel_name, "Tv Channel Name", None, None, None),
|
||||||
],
|
],
|
||||||
Capability.tvoc_measurement: [
|
Capability.tvoc_measurement: [
|
||||||
Map(
|
Map(
|
||||||
|
@ -248,23 +348,39 @@ CAPABILITY_TO_SENSORS = {
|
||||||
"Tvoc Measurement",
|
"Tvoc Measurement",
|
||||||
CONCENTRATION_PARTS_PER_MILLION,
|
CONCENTRATION_PARTS_PER_MILLION,
|
||||||
None,
|
None,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
Capability.ultraviolet_index: [
|
Capability.ultraviolet_index: [
|
||||||
Map(Attribute.ultraviolet_index, "Ultraviolet Index", None, None)
|
Map(
|
||||||
|
Attribute.ultraviolet_index,
|
||||||
|
"Ultraviolet Index",
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
Capability.voltage_measurement: [
|
Capability.voltage_measurement: [
|
||||||
Map(Attribute.voltage, "Voltage Measurement", ELECTRIC_POTENTIAL_VOLT, None)
|
Map(
|
||||||
|
Attribute.voltage,
|
||||||
|
"Voltage Measurement",
|
||||||
|
ELECTRIC_POTENTIAL_VOLT,
|
||||||
|
DEVICE_CLASS_VOLTAGE,
|
||||||
|
STATE_CLASS_MEASUREMENT,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
Capability.washer_mode: [
|
||||||
|
Map(Attribute.washer_mode, "Washer Mode", None, None, None)
|
||||||
],
|
],
|
||||||
Capability.washer_mode: [Map(Attribute.washer_mode, "Washer Mode", None, None)],
|
|
||||||
Capability.washer_operating_state: [
|
Capability.washer_operating_state: [
|
||||||
Map(Attribute.machine_state, "Washer Machine State", None, None),
|
Map(Attribute.machine_state, "Washer Machine State", None, None, None),
|
||||||
Map(Attribute.washer_job_state, "Washer Job State", None, None),
|
Map(Attribute.washer_job_state, "Washer Job State", None, None, None),
|
||||||
Map(
|
Map(
|
||||||
Attribute.completion_time,
|
Attribute.completion_time,
|
||||||
"Washer Completion Time",
|
"Washer Completion Time",
|
||||||
None,
|
None,
|
||||||
DEVICE_CLASS_TIMESTAMP,
|
DEVICE_CLASS_TIMESTAMP,
|
||||||
|
None,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
@ -292,11 +408,34 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
||||||
sensors.extend(
|
sensors.extend(
|
||||||
[
|
[
|
||||||
SmartThingsSensor(
|
SmartThingsSensor(
|
||||||
device, m.attribute, m.name, m.default_unit, m.device_class
|
device,
|
||||||
|
m.attribute,
|
||||||
|
m.name,
|
||||||
|
m.default_unit,
|
||||||
|
m.device_class,
|
||||||
|
m.state_class,
|
||||||
)
|
)
|
||||||
for m in maps
|
for m in maps
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if broker.any_assigned(device.device_id, "switch"):
|
||||||
|
for capability in (Capability.energy_meter, Capability.power_meter):
|
||||||
|
maps = CAPABILITY_TO_SENSORS[capability]
|
||||||
|
sensors.extend(
|
||||||
|
[
|
||||||
|
SmartThingsSensor(
|
||||||
|
device,
|
||||||
|
m.attribute,
|
||||||
|
m.name,
|
||||||
|
m.default_unit,
|
||||||
|
m.device_class,
|
||||||
|
m.state_class,
|
||||||
|
)
|
||||||
|
for m in maps
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
async_add_entities(sensors)
|
async_add_entities(sensors)
|
||||||
|
|
||||||
|
|
||||||
|
@ -311,14 +450,21 @@ class SmartThingsSensor(SmartThingsEntity, SensorEntity):
|
||||||
"""Define a SmartThings Sensor."""
|
"""Define a SmartThings Sensor."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, device, attribute: str, name: str, default_unit: str, device_class: str
|
self,
|
||||||
):
|
device: DeviceEntity,
|
||||||
|
attribute: str,
|
||||||
|
name: str,
|
||||||
|
default_unit: str,
|
||||||
|
device_class: str,
|
||||||
|
state_class: str | None,
|
||||||
|
) -> None:
|
||||||
"""Init the class."""
|
"""Init the class."""
|
||||||
super().__init__(device)
|
super().__init__(device)
|
||||||
self._attribute = attribute
|
self._attribute = attribute
|
||||||
self._name = name
|
self._name = name
|
||||||
self._device_class = device_class
|
self._device_class = device_class
|
||||||
self._default_unit = default_unit
|
self._default_unit = default_unit
|
||||||
|
self._attr_state_class = state_class
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
|
@ -346,6 +492,13 @@ class SmartThingsSensor(SmartThingsEntity, SensorEntity):
|
||||||
unit = self._device.status.attributes[self._attribute].unit
|
unit = self._device.status.attributes[self._attribute].unit
|
||||||
return UNITS.get(unit, unit) if unit else self._default_unit
|
return UNITS.get(unit, unit) if unit else self._default_unit
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_reset(self) -> datetime | None:
|
||||||
|
"""Return the time when the sensor was last reset, if any."""
|
||||||
|
if self._attribute == Attribute.energy:
|
||||||
|
return utc_from_timestamp(0)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class SmartThingsThreeAxisSensor(SmartThingsEntity, SensorEntity):
|
class SmartThingsThreeAxisSensor(SmartThingsEntity, SensorEntity):
|
||||||
"""Define a SmartThings Three Axis Sensor."""
|
"""Define a SmartThings Three Axis Sensor."""
|
||||||
|
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Sequence
|
from collections.abc import Sequence
|
||||||
|
|
||||||
from pysmartthings import Attribute, Capability
|
from pysmartthings import Capability
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchEntity
|
from homeassistant.components.switch import SwitchEntity
|
||||||
|
|
||||||
|
@ -48,16 +48,6 @@ class SmartThingsSwitch(SmartThingsEntity, SwitchEntity):
|
||||||
# the entity state ahead of receiving the confirming push updates
|
# the entity state ahead of receiving the confirming push updates
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
@property
|
|
||||||
def current_power_w(self):
|
|
||||||
"""Return the current power usage in W."""
|
|
||||||
return self._device.status.attributes[Attribute.power].value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def today_energy_kwh(self):
|
|
||||||
"""Return the today total energy usage in kWh."""
|
|
||||||
return self._device.status.attributes[Attribute.energy].value
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self) -> bool:
|
def is_on(self) -> bool:
|
||||||
"""Return true if light is on."""
|
"""Return true if light is on."""
|
||||||
|
|
|
@ -6,7 +6,11 @@ real HTTP calls are not initiated during testing.
|
||||||
"""
|
"""
|
||||||
from pysmartthings import ATTRIBUTES, CAPABILITIES, Attribute, Capability
|
from pysmartthings import ATTRIBUTES, CAPABILITIES, Attribute, Capability
|
||||||
|
|
||||||
from homeassistant.components.sensor import DEVICE_CLASSES, DOMAIN as SENSOR_DOMAIN
|
from homeassistant.components.sensor import (
|
||||||
|
DEVICE_CLASSES,
|
||||||
|
DOMAIN as SENSOR_DOMAIN,
|
||||||
|
STATE_CLASSES,
|
||||||
|
)
|
||||||
from homeassistant.components.smartthings import sensor
|
from homeassistant.components.smartthings import sensor
|
||||||
from homeassistant.components.smartthings.const import DOMAIN, SIGNAL_SMARTTHINGS_UPDATE
|
from homeassistant.components.smartthings.const import DOMAIN, SIGNAL_SMARTTHINGS_UPDATE
|
||||||
from homeassistant.config_entries import ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
|
@ -33,6 +37,8 @@ async def test_mapping_integrity():
|
||||||
assert (
|
assert (
|
||||||
sensor_map.device_class in DEVICE_CLASSES
|
sensor_map.device_class in DEVICE_CLASSES
|
||||||
), sensor_map.device_class
|
), sensor_map.device_class
|
||||||
|
if sensor_map.state_class:
|
||||||
|
assert sensor_map.state_class in STATE_CLASSES, sensor_map.state_class
|
||||||
|
|
||||||
|
|
||||||
async def test_entity_state(hass, device_factory):
|
async def test_entity_state(hass, device_factory):
|
||||||
|
@ -95,6 +101,44 @@ async def test_entity_and_device_attributes(hass, device_factory):
|
||||||
assert entry.manufacturer == "Unavailable"
|
assert entry.manufacturer == "Unavailable"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_energy_sensors_for_switch_device(hass, device_factory):
|
||||||
|
"""Test the attributes of the entity are correct."""
|
||||||
|
# Arrange
|
||||||
|
device = device_factory(
|
||||||
|
"Switch_1",
|
||||||
|
[Capability.switch, Capability.power_meter, Capability.energy_meter],
|
||||||
|
{Attribute.switch: "off", Attribute.power: 355, Attribute.energy: 11.422},
|
||||||
|
)
|
||||||
|
entity_registry = er.async_get(hass)
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
# Act
|
||||||
|
await setup_platform(hass, SENSOR_DOMAIN, devices=[device])
|
||||||
|
# Assert
|
||||||
|
state = hass.states.get("sensor.switch_1_energy_meter")
|
||||||
|
assert state
|
||||||
|
assert state.state == "11.422"
|
||||||
|
entry = entity_registry.async_get("sensor.switch_1_energy_meter")
|
||||||
|
assert entry
|
||||||
|
assert entry.unique_id == f"{device.device_id}.{Attribute.energy}"
|
||||||
|
entry = device_registry.async_get_device({(DOMAIN, device.device_id)})
|
||||||
|
assert entry
|
||||||
|
assert entry.name == device.label
|
||||||
|
assert entry.model == device.device_type_name
|
||||||
|
assert entry.manufacturer == "Unavailable"
|
||||||
|
|
||||||
|
state = hass.states.get("sensor.switch_1_power_meter")
|
||||||
|
assert state
|
||||||
|
assert state.state == "355"
|
||||||
|
entry = entity_registry.async_get("sensor.switch_1_power_meter")
|
||||||
|
assert entry
|
||||||
|
assert entry.unique_id == f"{device.device_id}.{Attribute.power}"
|
||||||
|
entry = device_registry.async_get_device({(DOMAIN, device.device_id)})
|
||||||
|
assert entry
|
||||||
|
assert entry.name == device.label
|
||||||
|
assert entry.model == device.device_type_name
|
||||||
|
assert entry.manufacturer == "Unavailable"
|
||||||
|
|
||||||
|
|
||||||
async def test_update_from_signal(hass, device_factory):
|
async def test_update_from_signal(hass, device_factory):
|
||||||
"""Test the binary_sensor updates when receiving a signal."""
|
"""Test the binary_sensor updates when receiving a signal."""
|
||||||
# Arrange
|
# Arrange
|
||||||
|
|
|
@ -7,11 +7,7 @@ real HTTP calls are not initiated during testing.
|
||||||
from pysmartthings import Attribute, Capability
|
from pysmartthings import Attribute, Capability
|
||||||
|
|
||||||
from homeassistant.components.smartthings.const import DOMAIN, SIGNAL_SMARTTHINGS_UPDATE
|
from homeassistant.components.smartthings.const import DOMAIN, SIGNAL_SMARTTHINGS_UPDATE
|
||||||
from homeassistant.components.switch import (
|
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
|
||||||
ATTR_CURRENT_POWER_W,
|
|
||||||
ATTR_TODAY_ENERGY_KWH,
|
|
||||||
DOMAIN as SWITCH_DOMAIN,
|
|
||||||
)
|
|
||||||
from homeassistant.config_entries import ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
from homeassistant.const import STATE_UNAVAILABLE
|
from homeassistant.const import STATE_UNAVAILABLE
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
|
@ -72,8 +68,6 @@ async def test_turn_on(hass, device_factory):
|
||||||
state = hass.states.get("switch.switch_1")
|
state = hass.states.get("switch.switch_1")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == "on"
|
assert state.state == "on"
|
||||||
assert state.attributes[ATTR_CURRENT_POWER_W] == 355
|
|
||||||
assert state.attributes[ATTR_TODAY_ENERGY_KWH] == 11.422
|
|
||||||
|
|
||||||
|
|
||||||
async def test_update_from_signal(hass, device_factory):
|
async def test_update_from_signal(hass, device_factory):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue