core/homeassistant/components/zha/number.py

340 lines
9.6 KiB
Python
Raw Normal View History

"""Support for ZHA AnalogOutput cluster."""
import functools
import logging
from homeassistant.components.number import DOMAIN, NumberEntity
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from .core import discovery
from .core.const import (
CHANNEL_ANALOG_OUTPUT,
DATA_ZHA,
DATA_ZHA_DISPATCHERS,
SIGNAL_ADD_ENTITIES,
SIGNAL_ATTR_UPDATED,
)
from .core.registries import ZHA_ENTITIES
from .entity import ZhaEntity
_LOGGER = logging.getLogger(__name__)
STRICT_MATCH = functools.partial(ZHA_ENTITIES.strict_match, DOMAIN)
UNITS = {
0: "Square-meters",
1: "Square-feet",
2: "Milliamperes",
3: "Amperes",
4: "Ohms",
5: "Volts",
6: "Kilo-volts",
7: "Mega-volts",
8: "Volt-amperes",
9: "Kilo-volt-amperes",
10: "Mega-volt-amperes",
11: "Volt-amperes-reactive",
12: "Kilo-volt-amperes-reactive",
13: "Mega-volt-amperes-reactive",
14: "Degrees-phase",
15: "Power-factor",
16: "Joules",
17: "Kilojoules",
18: "Watt-hours",
19: "Kilowatt-hours",
20: "BTUs",
21: "Therms",
22: "Ton-hours",
23: "Joules-per-kilogram-dry-air",
24: "BTUs-per-pound-dry-air",
25: "Cycles-per-hour",
26: "Cycles-per-minute",
27: "Hertz",
28: "Grams-of-water-per-kilogram-dry-air",
29: "Percent-relative-humidity",
30: "Millimeters",
31: "Meters",
32: "Inches",
33: "Feet",
34: "Watts-per-square-foot",
35: "Watts-per-square-meter",
36: "Lumens",
37: "Luxes",
38: "Foot-candles",
39: "Kilograms",
40: "Pounds-mass",
41: "Tons",
42: "Kilograms-per-second",
43: "Kilograms-per-minute",
44: "Kilograms-per-hour",
45: "Pounds-mass-per-minute",
46: "Pounds-mass-per-hour",
47: "Watts",
48: "Kilowatts",
49: "Megawatts",
50: "BTUs-per-hour",
51: "Horsepower",
52: "Tons-refrigeration",
53: "Pascals",
54: "Kilopascals",
55: "Bars",
56: "Pounds-force-per-square-inch",
57: "Centimeters-of-water",
58: "Inches-of-water",
59: "Millimeters-of-mercury",
60: "Centimeters-of-mercury",
61: "Inches-of-mercury",
62: "°C",
63: "°K",
64: "°F",
65: "Degree-days-Celsius",
66: "Degree-days-Fahrenheit",
67: "Years",
68: "Months",
69: "Weeks",
70: "Days",
71: "Hours",
72: "Minutes",
73: "Seconds",
74: "Meters-per-second",
75: "Kilometers-per-hour",
76: "Feet-per-second",
77: "Feet-per-minute",
78: "Miles-per-hour",
79: "Cubic-feet",
80: "Cubic-meters",
81: "Imperial-gallons",
82: "Liters",
83: "Us-gallons",
84: "Cubic-feet-per-minute",
85: "Cubic-meters-per-second",
86: "Imperial-gallons-per-minute",
87: "Liters-per-second",
88: "Liters-per-minute",
89: "Us-gallons-per-minute",
90: "Degrees-angular",
91: "Degrees-Celsius-per-hour",
92: "Degrees-Celsius-per-minute",
93: "Degrees-Fahrenheit-per-hour",
94: "Degrees-Fahrenheit-per-minute",
95: None,
96: "Parts-per-million",
97: "Parts-per-billion",
98: "%",
99: "Percent-per-second",
100: "Per-minute",
101: "Per-second",
102: "Psi-per-Degree-Fahrenheit",
103: "Radians",
104: "Revolutions-per-minute",
105: "Currency1",
106: "Currency2",
107: "Currency3",
108: "Currency4",
109: "Currency5",
110: "Currency6",
111: "Currency7",
112: "Currency8",
113: "Currency9",
114: "Currency10",
115: "Square-inches",
116: "Square-centimeters",
117: "BTUs-per-pound",
118: "Centimeters",
119: "Pounds-mass-per-second",
120: "Delta-Degrees-Fahrenheit",
121: "Delta-Degrees-Kelvin",
122: "Kilohms",
123: "Megohms",
124: "Millivolts",
125: "Kilojoules-per-kilogram",
126: "Megajoules",
127: "Joules-per-degree-Kelvin",
128: "Joules-per-kilogram-degree-Kelvin",
129: "Kilohertz",
130: "Megahertz",
131: "Per-hour",
132: "Milliwatts",
133: "Hectopascals",
134: "Millibars",
135: "Cubic-meters-per-hour",
136: "Liters-per-hour",
137: "Kilowatt-hours-per-square-meter",
138: "Kilowatt-hours-per-square-foot",
139: "Megajoules-per-square-meter",
140: "Megajoules-per-square-foot",
141: "Watts-per-square-meter-Degree-Kelvin",
142: "Cubic-feet-per-second",
143: "Percent-obscuration-per-foot",
144: "Percent-obscuration-per-meter",
145: "Milliohms",
146: "Megawatt-hours",
147: "Kilo-BTUs",
148: "Mega-BTUs",
149: "Kilojoules-per-kilogram-dry-air",
150: "Megajoules-per-kilogram-dry-air",
151: "Kilojoules-per-degree-Kelvin",
152: "Megajoules-per-degree-Kelvin",
153: "Newton",
154: "Grams-per-second",
155: "Grams-per-minute",
156: "Tons-per-hour",
157: "Kilo-BTUs-per-hour",
158: "Hundredths-seconds",
159: "Milliseconds",
160: "Newton-meters",
161: "Millimeters-per-second",
162: "Millimeters-per-minute",
163: "Meters-per-minute",
164: "Meters-per-hour",
165: "Cubic-meters-per-minute",
166: "Meters-per-second-per-second",
167: "Amperes-per-meter",
168: "Amperes-per-square-meter",
169: "Ampere-square-meters",
170: "Farads",
171: "Henrys",
172: "Ohm-meters",
173: "Siemens",
174: "Siemens-per-meter",
175: "Teslas",
176: "Volts-per-degree-Kelvin",
177: "Volts-per-meter",
178: "Webers",
179: "Candelas",
180: "Candelas-per-square-meter",
181: "Kelvins-per-hour",
182: "Kelvins-per-minute",
183: "Joule-seconds",
185: "Square-meters-per-Newton",
186: "Kilogram-per-cubic-meter",
187: "Newton-seconds",
188: "Newtons-per-meter",
189: "Watts-per-meter-per-degree-Kelvin",
}
ICONS = {
0: "mdi:temperature-celsius",
1: "mdi:water-percent",
2: "mdi:gauge",
3: "mdi:speedometer",
4: "mdi:percent",
5: "mdi:air-filter",
6: "mdi:fan",
7: "mdi:flash",
8: "mdi:current-ac",
9: "mdi:flash",
10: "mdi:flash",
11: "mdi:flash",
12: "mdi:counter",
13: "mdi:thermometer-lines",
14: "mdi:timer",
}
async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Zigbee Home Automation Analog Output from config entry."""
entities_to_create = hass.data[DATA_ZHA][DOMAIN]
unsub = async_dispatcher_connect(
hass,
SIGNAL_ADD_ENTITIES,
functools.partial(
discovery.async_add_entities,
async_add_entities,
entities_to_create,
update_before_add=False,
),
)
hass.data[DATA_ZHA][DATA_ZHA_DISPATCHERS].append(unsub)
@STRICT_MATCH(channel_names=CHANNEL_ANALOG_OUTPUT)
class ZhaNumber(ZhaEntity, NumberEntity):
"""Representation of a ZHA Number entity."""
def __init__(self, unique_id, zha_device, channels, **kwargs):
"""Init this entity."""
super().__init__(unique_id, zha_device, channels, **kwargs)
self._analog_output_channel = self.cluster_channels.get(CHANNEL_ANALOG_OUTPUT)
async def async_added_to_hass(self):
"""Run when about to be added to hass."""
await super().async_added_to_hass()
self.async_accept_signal(
self._analog_output_channel, SIGNAL_ATTR_UPDATED, self.async_set_state
)
@property
def value(self):
"""Return the current value."""
return self._analog_output_channel.present_value
@property
def min_value(self):
"""Return the minimum value."""
min_present_value = self._analog_output_channel.min_present_value
if min_present_value is not None:
return min_present_value
return 0
@property
def max_value(self):
"""Return the maximum value."""
max_present_value = self._analog_output_channel.max_present_value
if max_present_value is not None:
return max_present_value
return 1023
@property
def step(self):
"""Return the value step."""
resolution = self._analog_output_channel.resolution
if resolution is not None:
return resolution
return super().step
@property
def name(self):
"""Return the name of the number entity."""
description = self._analog_output_channel.description
if description is not None and len(description) > 0:
return f"{super().name} {description}"
return super().name
@property
def icon(self):
"""Return the icon to be used for this entity."""
application_type = self._analog_output_channel.application_type
if application_type is not None:
return ICONS.get(application_type >> 16, super().icon)
return super().icon
@property
def unit_of_measurement(self):
"""Return the unit the value is expressed in."""
engineering_units = self._analog_output_channel.engineering_units
return UNITS.get(engineering_units)
@callback
def async_set_state(self, attr_id, attr_name, value):
"""Handle value update from channel."""
self.async_write_ha_state()
async def async_set_value(self, value):
"""Update the current value from HA."""
num_value = float(value)
if await self._analog_output_channel.async_set_present_value(num_value):
self.async_write_ha_state()
async def async_update(self):
"""Attempt to retrieve the state of the entity."""
await super().async_update()
_LOGGER.debug("polling current state")
if self._analog_output_channel:
value = await self._analog_output_channel.get_attribute_value(
"present_value", from_cache=False
)
_LOGGER.debug("read value=%s", value)