hass-core/homeassistant/components/sensor/knx.py
Will W 88b9503962 add percentage (DPT_Scaling) KNX sensors (#8168)
* add percentage (DPT_Scaling) KNX sensors

1. moved basic functionality to KNXSensorBaseClass instead of
KNXSensorFloatClass
2. added "if" clause in setup for a "percentage" sensor type and added KNXSensorDPTScalingClass

* support-knx-percentage-sensor: lint correction

Updated convert method base sensor class to avoid lint warning
(R201 - Method could be a function)

* added PLATFORM_SCHEMA for configuration

1. added SCHEMA extension for defined keywords
2. moved fixed data for internal settings out of sensor logic
3. moved everything into standard KNXSensor object
4. added parsing of extra config parameters in __init__

* correct lint errors on support-knx-percentage-sensor
2017-06-26 22:25:54 -07:00

183 lines
5.2 KiB
Python

"""
Sensors of a KNX Device.
For more details about this platform, please refer to the documentation at
https://home-assistant.io/components/knx/
"""
from enum import Enum
import logging
import voluptuous as vol
from homeassistant.const import (
CONF_NAME, CONF_MAXIMUM, CONF_MINIMUM,
CONF_TYPE, TEMP_CELSIUS
)
from homeassistant.components.knx import (KNXConfig, KNXGroupAddress)
from homeassistant.components.sensor import PLATFORM_SCHEMA
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['knx']
DEFAULT_NAME = "KNX sensor"
CONF_TEMPERATURE = 'temperature'
CONF_ADDRESS = 'address'
CONF_ILLUMINANCE = 'illuminance'
CONF_PERCENTAGE = 'percentage'
CONF_SPEED_MS = 'speed_ms'
class KNXAddressType(Enum):
"""Enum to indicate conversion type for the KNX address."""
FLOAT = 1
PERCENT = 2
# define the fixed settings required for each sensor type
FIXED_SETTINGS_MAP = {
# Temperature as defined in KNX Standard 3.10 - 9.001 DPT_Value_Temp
CONF_TEMPERATURE: {
'unit': TEMP_CELSIUS,
'default_minimum': -273,
'default_maximum': 670760,
'address_type': KNXAddressType.FLOAT
},
# Speed m/s as defined in KNX Standard 3.10 - 9.005 DPT_Value_Wsp
CONF_SPEED_MS: {
'unit': 'm/s',
'default_minimum': 0,
'default_maximum': 670760,
'address_type': KNXAddressType.FLOAT
},
# Luminance(LUX) as defined in KNX Standard 3.10 - 9.004 DPT_Value_Lux
CONF_ILLUMINANCE: {
'unit': 'lx',
'default_minimum': 0,
'default_maximum': 670760,
'address_type': KNXAddressType.FLOAT
},
# Percentage(%) as defined in KNX Standard 3.10 - 5.001 DPT_Scaling
CONF_PERCENTAGE: {
'unit': '%',
'default_minimum': 0,
'default_maximum': 100,
'address_type': KNXAddressType.PERCENT
}
}
SENSOR_TYPES = set(FIXED_SETTINGS_MAP.keys())
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_TYPE): vol.In(SENSOR_TYPES),
vol.Required(CONF_ADDRESS): cv.string,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_MINIMUM): vol.Coerce(float),
vol.Optional(CONF_MAXIMUM): vol.Coerce(float)
})
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the KNX Sensor platform."""
add_devices([KNXSensor(hass, KNXConfig(config))])
class KNXSensor(KNXGroupAddress):
"""Representation of a KNX Sensor device."""
def __init__(self, hass, config):
"""Initialize a KNX Float Sensor."""
# set up the KNX Group address
KNXGroupAddress.__init__(self, hass, config)
device_type = config.config.get(CONF_TYPE)
sensor_config = FIXED_SETTINGS_MAP.get(device_type)
if not sensor_config:
raise NotImplementedError()
# set up the conversion function based on the address type
address_type = sensor_config.get('address_type')
if address_type == KNXAddressType.FLOAT:
self.convert = convert_float
elif address_type == KNXAddressType.PERCENT:
self.convert = convert_percent
else:
raise NotImplementedError()
# other settings
self._unit_of_measurement = sensor_config.get('unit')
default_min = float(sensor_config.get('default_minimum'))
default_max = float(sensor_config.get('default_maximum'))
self._minimum_value = config.config.get(CONF_MINIMUM, default_min)
self._maximum_value = config.config.get(CONF_MAXIMUM, default_max)
_LOGGER.debug(
"%s: configured additional settings: unit=%s, "
"min=%f, max=%f, type=%s",
self.name, self._unit_of_measurement,
self._minimum_value, self._maximum_value, str(address_type)
)
self._value = None
@property
def state(self):
"""Return the Value of the KNX Sensor."""
return self._value
@property
def unit_of_measurement(self):
"""Return the defined Unit of Measurement for the KNX Sensor."""
return self._unit_of_measurement
def update(self):
"""Update KNX sensor."""
super().update()
self._value = None
if self._data:
if self._data == 0:
value = 0
else:
value = self.convert(self._data)
if self._minimum_value <= value <= self._maximum_value:
self._value = value
@property
def cache(self):
"""We don't want to cache any Sensor Value."""
return False
def convert_float(raw_value):
"""Conversion for 2 byte floating point values.
2byte Floating Point KNX Telegram.
Defined in KNX 3.7.2 - 3.10
"""
from knxip.conversion import knx2_to_float
return knx2_to_float(raw_value)
def convert_percent(raw_value):
"""Conversion for scaled byte values.
1byte percentage scaled KNX Telegram.
Defined in KNX 3.7.2 - 3.10.
"""
summed_value = 0
try:
# convert raw value in bytes
for val in raw_value:
summed_value *= 256
summed_value += val
except TypeError:
# pknx returns a non-iterable type for unsuccessful reads
pass
return round(summed_value * 100 / 255)