From 8a2134b3a8562b137ab650f0293a904763f95fec Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 18 Oct 2017 11:20:19 +0200 Subject: [PATCH] Add serial sensor (#9861) * Add serial sensor * Rename config variable and cancel --- .coveragerc | 1 + homeassistant/components/sensor/serial.py | 90 +++++++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 94 insertions(+) create mode 100644 homeassistant/components/sensor/serial.py diff --git a/.coveragerc b/.coveragerc index a65a9f4b861..a2055681f18 100644 --- a/.coveragerc +++ b/.coveragerc @@ -534,6 +534,7 @@ omit = homeassistant/components/sensor/sabnzbd.py homeassistant/components/sensor/scrape.py homeassistant/components/sensor/sensehat.py + homeassistant/components/sensor/serial.py homeassistant/components/sensor/serial_pm.py homeassistant/components/sensor/shodan.py homeassistant/components/sensor/skybeacon.py diff --git a/homeassistant/components/sensor/serial.py b/homeassistant/components/sensor/serial.py new file mode 100644 index 00000000000..ffa8bcc3070 --- /dev/null +++ b/homeassistant/components/sensor/serial.py @@ -0,0 +1,90 @@ +""" +Support for reading data from a serial port. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/sensor.serial/ +""" +import asyncio +import logging + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.sensor import PLATFORM_SCHEMA +from homeassistant.const import CONF_NAME, EVENT_HOMEASSISTANT_STOP +from homeassistant.helpers.entity import Entity + +REQUIREMENTS = ['pyserial-asyncio==0.4'] + +_LOGGER = logging.getLogger(__name__) + +CONF_SERIAL_PORT = 'serial_port' + +DEFAULT_NAME = "Serial Sensor" + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_SERIAL_PORT): cv.string, + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, +}) + + +@asyncio.coroutine +def async_setup_platform(hass, config, async_add_devices, discovery_info=None): + """Set up the Serial sensor platform.""" + name = config.get(CONF_NAME) + port = config.get(CONF_SERIAL_PORT) + + sensor = SerialSensor(name, port) + + hass.bus.async_listen_once( + EVENT_HOMEASSISTANT_STOP, sensor.stop_serial_read()) + async_add_devices([sensor], True) + + +class SerialSensor(Entity): + """Representation of a Serial sensor.""" + + def __init__(self, name, port): + """Initialize the Serial sensor.""" + self._name = name + self._state = None + self._port = port + self._serial_loop_task = None + + @asyncio.coroutine + def async_added_to_hass(self): + """Handle when an entity is about to be added to Home Assistant.""" + self._serial_loop_task = self.hass.loop.create_task( + self.serial_read(self._port)) + + @asyncio.coroutine + def serial_read(self, device, **kwargs): + """Read the data from the port.""" + import serial_asyncio + reader, _ = yield from serial_asyncio.open_serial_connection( + url=device, **kwargs) + while True: + line = yield from reader.readline() + self._state = line.decode('utf-8').strip() + self.async_schedule_update_ha_state() + + @asyncio.coroutine + def stop_serial_read(self): + """Close resources.""" + if self._serial_loop_task: + self._serial_loop_task.cancel() + + @property + def name(self): + """Return the name of the sensor.""" + return self._name + + @property + def should_poll(self): + """No polling needed.""" + return False + + @property + def state(self): + """Return the state of the sensor.""" + return self._state diff --git a/requirements_all.txt b/requirements_all.txt index 61d711d5fe2..028ee8e91c7 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -724,6 +724,9 @@ pyqwikswitch==0.4 # homeassistant.components.climate.sensibo pysensibo==1.0.1 +# homeassistant.components.sensor.serial +pyserial-asyncio==0.4 + # homeassistant.components.switch.acer_projector pyserial==3.1.1