├── __init__.py ├── manifest.json ├── README.md ├── sensor.py └── LICENSE /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "domain": "airthings", 3 | "name": "Airthings Wave+", 4 | "documentation": "https://github.com/gkreitz/homeassistant-airthings", 5 | "dependencies": [], 6 | "requirements": ["pygatt[GATTTOOL]==4.0.3"], 7 | "codeowners": ["@gkreitz"] 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # homeassistant-airthings 2 | Quick n' dirty hack to get Airthings Wave Plus sensor into Home Assistant. Beware, very untested. Only works with Airthings Wave Plus. 3 | 4 | I wanted something to read my Airthings Wave Plus, so I built this. Far from production quality. Magic hardcoded constants. Reads data the wrong way to work around a bug. Tested on a single device. Only supports a single Wave Plus. Does not construct a unique id for the sensor. Figured I may as well upload in case it's useful to someone else. 5 | 6 | ## Installation 7 | 1. Find out the MAC address of your Airthings Wave Plus. See https://airthings.com/us/raspberry-pi/ for how to find MAC address. 8 | 1. Put `__init__.py`, `sensor.py`, `manifest.json` into `/custom_components/airthings/` on your home assistant installation (where `` is the directory where your config file resides). 9 | 1. Add the following to your `configuration.yaml` (or modify your `sensor` heading, if you already have one): 10 | ```yaml 11 | sensor: 12 | - platform: airthings 13 | mac: 00:11:22:AA:BB:CC # replace with MAC of your Airthings Wave+ 14 | ``` 15 | 16 | Then restart home assistant and if everything works, you'll have some new sensors named `sensor.airthings_{co2,humidity,longterm_radon,pressure,shortterm_radon,temperature,voc}` 17 | -------------------------------------------------------------------------------- /sensor.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import struct 3 | import datetime 4 | 5 | from homeassistant.components.sensor import PLATFORM_SCHEMA 6 | import homeassistant.helpers.config_validation as cv 7 | import voluptuous as vol 8 | 9 | from homeassistant.helpers.entity import Entity 10 | from homeassistant.util import Throttle 11 | from homeassistant.const import (TEMP_CELSIUS, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_PRESSURE, STATE_UNKNOWN) 12 | 13 | _LOGGER = logging.getLogger(__name__) 14 | 15 | DOMAIN = 'airthings' 16 | CONF_MAC = 'mac' 17 | 18 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ 19 | vol.Required(CONF_MAC): cv.string, 20 | }) 21 | 22 | MIN_TIME_BETWEEN_UPDATES = datetime.timedelta(minutes=15) 23 | SENSOR_TYPES = [ 24 | ['temperature', 'Temperature', TEMP_CELSIUS, None, DEVICE_CLASS_TEMPERATURE], 25 | ['co2', 'CO2', 'ppm', 'mdi:cloud', None], 26 | ['pressure', 'Pressure', 'mbar', 'mdi:gauge', DEVICE_CLASS_PRESSURE], 27 | ['humidity', 'Humidity', '%', None, DEVICE_CLASS_HUMIDITY], 28 | ['voc', 'VOC', 'ppm', 'mdi:cloud', None], 29 | ['short_radon', 'Short-term Radon', 'Bq/m3', 'mdi:cloud', None], 30 | ['long_radon', 'Long-term Radon', 'Bq/m3', 'mdi:cloud', None], 31 | ] 32 | 33 | 34 | 35 | def setup_platform(hass, config, add_devices, discovery_info=None): 36 | """Setup the sensor platform.""" 37 | _LOGGER.debug("Starting airthings") 38 | reader = AirthingsWavePlusDataReader(config.get(CONF_MAC)) 39 | add_devices([ AirthingsSensorEntity(reader, key,name,unit,icon,device_class) for [key, name, unit, icon, device_class] in SENSOR_TYPES]) 40 | 41 | class AirthingsWavePlusDataReader: 42 | def __init__(self, mac): 43 | self._mac = mac 44 | self._state = { } 45 | 46 | def get_data(self, key): 47 | if key in self._state: 48 | return self._state[key] 49 | return STATE_UNKNOWN 50 | 51 | @property 52 | def mac(self): 53 | return self._mac 54 | 55 | @Throttle(MIN_TIME_BETWEEN_UPDATES) 56 | def update(self): 57 | _LOGGER.debug("Airthings updating data") 58 | import pygatt 59 | from pygatt.backends import Characteristic 60 | adapter = pygatt.backends.GATTToolBackend() 61 | char = 'b42e2a68-ade7-11e4-89d3-123b93f75cba' 62 | try: 63 | # reset_on_start must be false - reset is hardcoded to do sudo, which does not exist in the hass.io Docker container. 64 | adapter.start(reset_on_start=False) 65 | device = adapter.connect(self._mac) 66 | # Unclear why this does not work. Seems broken in the command line tool too. Hopefully handle is stable... 67 | #value = device.char_read(char,timeout=10) 68 | value = device.char_read_handle('0x000d',timeout=10) 69 | (humidity, light, sh_rad, lo_rad, temp, pressure, co2, voc) = struct.unpack('