From 6dc877d8def472b95bafbfc1385dbde891cc7639 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Sun, 13 Sep 2015 11:38:06 +0200 Subject: [PATCH] Add command sensor --- .../components/sensor/command_sensor.py | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 homeassistant/components/sensor/command_sensor.py diff --git a/homeassistant/components/sensor/command_sensor.py b/homeassistant/components/sensor/command_sensor.py new file mode 100644 index 00000000000..752b2e21a20 --- /dev/null +++ b/homeassistant/components/sensor/command_sensor.py @@ -0,0 +1,124 @@ +""" +homeassistant.components.sensor.command_sensor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Allows to configure custom shell commands to turn a value for a sensor. + +Configuration: + +To use the command_line sensor you will need to add something like the +following to your configuration.yaml file. + +sensor: + platform: command_sensor + name: "Command sensor" + command: sensor_command + unit_of_measurement: "°C" + correction_factor: 0.0001 + +Variables: + +name +*Optional +Name of the command sensor. + +command +*Required +The action to take to get the value. + +unit_of_measurement +*Optional +Defines the units of measurement of the sensor, if any. + +correction_factor +*Optional +A float value to do some basic calculations. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.command_sensor.html +""" +import logging +from subprocess import check_output, CalledProcessError +from datetime import timedelta + +from homeassistant.helpers.entity import Entity +from homeassistant.util import Throttle + + +_LOGGER = logging.getLogger(__name__) + +DEFAULT_NAME = "Command Sensor" + +# Return cached results if last scan was less then this time ago +MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=60) + + +# pylint: disable=unused-argument +def setup_platform(hass, config, add_devices_callback, discovery_info=None): + """ Add the Command Sensor. """ + + if config.get('command') is None: + _LOGGER.error('Missing required variable: "command"') + return False + + data = CommandSensorData(config.get('command')) + + add_devices_callback([CommandSensor( + data, + config.get('name', DEFAULT_NAME), + config.get('unit_of_measurement'), + config.get('correction_factor', 1.0) + )]) + + +class CommandSensor(Entity): + """ Represents a sensor that is returning a value of a shell commands. """ + def __init__(self, data, name, unit_of_measurement, corr_factor): + self.data = data + self._name = name + self._state = False + self._unit_of_measurement = unit_of_measurement + self._corr_factor = corr_factor + self.update() + + @property + def name(self): + """ The name of the sensor. """ + return self._name + + @property + def unit_of_measurement(self): + """ Unit the value is expressed in. """ + return self._unit_of_measurement + + @property + def state(self): + """ Returns the state of the device. """ + return self._state + + def update(self): + """ Gets the latest data and updates the state. """ + self.data.update() + value = self.data.value + + if value is not None: + self._state = int(round(float(value)) * self._corr_factor) + + +# pylint: disable=too-few-public-methods +class CommandSensorData(object): + """ Class for handling the data retrieval. """ + + def __init__(self, command): + self.command = command + self.value = None + + @Throttle(MIN_TIME_BETWEEN_UPDATES) + def update(self): + """ Gets the latest data with a shell command. """ + _LOGGER.info('Running command: %s', self.command) + + try: + return_value = check_output(self.command.split()) + self.value = return_value.strip().decode('utf-8') + except CalledProcessError: + _LOGGER.error('Command failed: %s', self.command)