From a3ca3e878b614e116d47c28329174f806239a229 Mon Sep 17 00:00:00 2001
From: Open Home Automation <daniel@open-homeautomation.com>
Date: Sun, 7 Aug 2016 22:14:01 +0200
Subject: [PATCH] Added support for serial particulate matters sensors -
 serial_pm (#2571)

---
 .coveragerc                                  |  1 +
 homeassistant/components/sensor/serial_pm.py | 94 ++++++++++++++++++++
 requirements_all.txt                         |  3 +
 3 files changed, 98 insertions(+)
 create mode 100644 homeassistant/components/sensor/serial_pm.py

diff --git a/.coveragerc b/.coveragerc
index 8867a0837aa..d1db30522e9 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -206,6 +206,7 @@ omit =
     homeassistant/components/sensor/onewire.py
     homeassistant/components/sensor/openweathermap.py
     homeassistant/components/sensor/openexchangerates.py
+    homeassistant/components/sensor/serial_pm.py
     homeassistant/components/sensor/plex.py
     homeassistant/components/sensor/rest.py
     homeassistant/components/sensor/sabnzbd.py
diff --git a/homeassistant/components/sensor/serial_pm.py b/homeassistant/components/sensor/serial_pm.py
new file mode 100644
index 00000000000..0dd6259d083
--- /dev/null
+++ b/homeassistant/components/sensor/serial_pm.py
@@ -0,0 +1,94 @@
+"""
+Support for particulate matter sensors connected to a serial port.
+
+For more details about this platform, please refer to the documentation at
+https://home-assistant.io/components/sensor.particulate_matter/
+"""
+import logging
+import voluptuous as vol
+
+from homeassistant.const import CONF_NAME, CONF_PLATFORM
+from homeassistant.helpers.entity import Entity
+import homeassistant.helpers.config_validation as cv
+from homeassistant.components.sensor import PLATFORM_SCHEMA
+
+REQUIREMENTS = ['pmsensor==0.2']
+
+
+_LOGGER = logging.getLogger(__name__)
+
+CONF_SERIAL_DEVICE = "serial_device"
+CONF_BRAND = "brand"
+
+PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
+    vol.Required(CONF_PLATFORM): 'serial_pm',
+    vol.Optional(CONF_NAME, default=""): cv.string,
+    vol.Required(CONF_SERIAL_DEVICE): cv.string,
+    vol.Required(CONF_BRAND): cv.string,
+})
+
+
+def setup_platform(hass, config, add_devices, discovery_info=None):
+    """Setup the available PM sensors."""
+    from pmsensor import serial_data_collector as pm
+
+    try:
+        coll = pm.PMDataCollector(config.get(CONF_SERIAL_DEVICE),
+                                  pm.SUPPORTED_SENSORS[config.get(CONF_BRAND)])
+    except KeyError:
+        _LOGGER.error("Brand %s not supported\n supported brands: %s",
+                      config.get(CONF_BRAND), pm.SUPPORTED_SENSORS.keys())
+        return
+    except OSError as err:
+        _LOGGER.error("Could not open serial connection to %s (%s)",
+                      config.get(CONF_SERIAL_DEVICE), err)
+        return
+
+    dev = []
+
+    for pmname in coll.supported_values():
+        if config.get("name") != "":
+            name = "{} PM{}".format(config.get("name"), pmname)
+        else:
+            name = "PM{}".format(pmname)
+        dev.append(ParticulateMatterSensor(coll, name, pmname))
+
+    add_devices(dev)
+
+
+class ParticulateMatterSensor(Entity):
+    """Representation of an Particulate matter sensor."""
+
+    def __init__(self, pmDataCollector, name, pmname):
+        """Initialize a new PM sensor."""
+        self._name = name
+        self._pmname = pmname
+        self._state = None
+        self._collector = pmDataCollector
+
+    @property
+    def name(self):
+        """Return the name of the sensor."""
+        return self._name
+
+    @property
+    def state(self):
+        """Return the state of the sensor."""
+        return self._state
+
+    @property
+    def unit_of_measurement(self):
+        """Return the unit of measurement of this entity, if any."""
+        return "µg/m³"
+
+    def update(self):
+        """Read from sensor and update the state."""
+        _LOGGER.debug("Reading data from PM sensor")
+        try:
+            self._state = self._collector.read_data()[self._pmname]
+        except KeyError:
+            _LOGGER.error("Could not read PM%s value", self._pmname)
+
+    def should_poll(self):
+        """Sensor needs polling."""
+        return True
diff --git a/requirements_all.txt b/requirements_all.txt
index 3919024860a..9714c56a0f1 100644
--- a/requirements_all.txt
+++ b/requirements_all.txt
@@ -230,6 +230,9 @@ phue==0.8
 # homeassistant.components.sensor.plex
 plexapi==1.1.0
 
+# homeassistant.components.sensor.serial_pm
+pmsensor==0.2
+
 # homeassistant.components.thermostat.proliphix
 proliphix==0.2.0
 
-- 
GitLab