Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes #5

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.DS_Store
22 changes: 17 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
# homeassistant-airthings
Quick n' dirty hack to get Airthings Wave Plus sensor into Home Assistant. Beware, very untested. Only works with Airthings Wave Plus.
# Airthings Wave Plus Environment Sensor for Home Assistant

This was developed by [@gkreitz](https://github.com/gkreitz) and forked from (https://github.com/gkreitz/homeassistant-airthings)

Quick n' dirty hack to get [Airthings Wave Plus](https://amazon.com/Airthings-2930-Quality-Detection-Dashboard/dp/B07JB8QWH6?tag=rynoshark-20) indoor air quality sensors into Home Assistant.

**Beware, very untested. Only works with Airthings Wave Plus.**

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.

## Installation

1. Find out the MAC address of your Airthings Wave Plus. See https://airthings.com/us/raspberry-pi/ for how to find MAC address.
1. Put `__init__.py`, `sensor.py`, `manifest.json` into `<config>/custom_components/airthings/` on your home assistant installation (where `<config>` is the directory where your config file resides).
1. This fork made for intergation through HACS.
1. Add the following to your `configuration.yaml` (or modify your `sensor` heading, if you already have one):

```yaml
sensor:
- platform: airthings
- platform: airthings_wave_plus
mac: 00:11:22:AA:BB:CC # replace with MAC of your Airthings Wave+
```

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}`
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}`

### See Also

* [Airthings Wave Plus discussion forum on Home Assistant](https://community.home-assistant.io/t/air-quality-monitor-radon-meter-airthings-wave-plus/102836)
* [Airthings for Home Assistant](https://github.com/custom-components/sensor.airthings_wave) (does not support Wave Plus)
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"domain": "airthings",
"name": "Airthings Wave+",
"domain": "airthings_wave_plus",
"name": "Airthings Wave Plus",
"documentation": "https://github.com/gkreitz/homeassistant-airthings",
"dependencies": [],
"requirements": ["pygatt[GATTTOOL]==4.0.3"],
Expand Down
57 changes: 33 additions & 24 deletions sensor.py → ..._components/airthings_wave_plus/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,41 @@

_LOGGER = logging.getLogger(__name__)

DOMAIN = 'airthings'
DOMAIN = 'airthings_wave_plus'

CONF_MAC = 'mac'

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Required(CONF_MAC): cv.string,
})

MIN_TIME_BETWEEN_UPDATES = datetime.timedelta(minutes=15)

SENSOR_TYPES = [
['temperature', 'Temperature', TEMP_CELSIUS, None, DEVICE_CLASS_TEMPERATURE],
['co2', 'CO2', 'ppm', 'mdi:cloud', None],
['pressure', 'Pressure', 'mbar', 'mdi:gauge', DEVICE_CLASS_PRESSURE],
['humidity', 'Humidity', '%', None, DEVICE_CLASS_HUMIDITY],
['voc', 'VOC', 'ppm', 'mdi:cloud', None],
['short_radon', 'Short-term Radon', 'Bq/m3', 'mdi:cloud', None],
['long_radon', 'Long-term Radon', 'Bq/m3', 'mdi:cloud', None],
# key name unit icon device class
[ 'temperature', 'Temperature', TEMP_CELSIUS, None, DEVICE_CLASS_TEMPERATURE ],
[ 'co2', 'CO2', 'ppm', 'mdi:cloud', None ],
[ 'pressure', 'Pressure', 'mbar', 'mdi:gauge', DEVICE_CLASS_PRESSURE ],
[ 'humidity', 'Humidity', '%', None, DEVICE_CLASS_HUMIDITY ],
[ 'voc', 'VOC', 'ppm', 'mdi:cloud', None ],
[ 'short_radon', 'Short-term Radon', 'Bq/m3', 'mdi:cloud', None ],
[ 'long_radon', 'Long-term Radon', 'Bq/m3', 'mdi:cloud', None ],
]



def setup_platform(hass, config, add_devices, discovery_info=None):
"""Setup the sensor platform."""
_LOGGER.debug("Starting airthings")
reader = AirthingsWavePlusDataReader(config.get(CONF_MAC))
add_devices([ AirthingsSensorEntity(reader, key,name,unit,icon,device_class) for [key, name, unit, icon, device_class] in SENSOR_TYPES])

sensors = []
for [key, name, unit, icon, device_class] in SENSOR_TYPES:
sensors.append( AirthingsSensorEntity(reader, key, name, unit, icon, device_class) )
add_devices(sensors)

class AirthingsWavePlusDataReader:
def __init__(self, mac):
self._mac = mac
self._state = { }
self._state = {}

def get_data(self, key):
if key in self._state:
Expand All @@ -54,27 +59,32 @@ def mac(self):

@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
_LOGGER.debug("Airthings updating data")
_LOGGER.debug(f"Updating data from Airthings Wave Plus {self._mac}")

import pygatt
from pygatt.backends import Characteristic
adapter = pygatt.backends.GATTToolBackend()
char = 'b42e2a68-ade7-11e4-89d3-123b93f75cba'
#char = 'b42e2a68-ade7-11e4-89d3-123b93f75cba'

try:
# reset_on_start must be false - reset is hardcoded to do sudo, which does not exist in the hass.io Docker container.
# reset_on_start must be false - reset is hardcoded to execute sudo, which doesn't exist
# in the hass.io Docker container.
adapter.start(reset_on_start=False)
device = adapter.connect(self._mac)

# Unclear why this does not work. Seems broken in the command line tool too. Hopefully handle is stable...
#value = device.char_read(char,timeout=10)
value = device.char_read_handle('0x000d',timeout=10)
(humidity, light, sh_rad, lo_rad, temp, pressure, co2, voc) = struct.unpack('<xbxbHHHHHHxxxx', value)
self._state['humidity'] = humidity / 2.0
self._state['light'] = light * 1.0

self._state['humidity'] = humidity / 2.0
self._state['light'] = light * 1.0
self._state['short_radon'] = sh_rad
self._state['long_radon'] = lo_rad
self._state['temperature'] = temp / 100.
self._state['pressure'] = pressure / 50.
self._state['co2'] = co2 * 1.
self._state['voc'] = voc * 1.
self._state['long_radon'] = lo_rad
self._state['temperature'] = temp / 100.0
self._state['pressure'] = pressure / 50.0
self._state['co2'] = co2 * 1.0
self._state['voc'] = voc * 1.0
finally:
adapter.stop()

Expand All @@ -93,7 +103,7 @@ def __init__(self, reader, key, name, unit, icon, device_class):
@property
def name(self):
"""Return the name of the sensor."""
return 'Airthings {}'.format(self._name)
return 'Airthings Wave Plus {}'.format(self._name)

@property
def icon(self):
Expand Down Expand Up @@ -121,7 +131,6 @@ def unique_id(self):

def update(self):
"""Fetch new state data for the sensor.

This is the only method that should fetch new data for Home Assistant.
"""
self._reader.update()
5 changes: 5 additions & 0 deletions hacs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Airthings Wave Plus",
"domains": [ "sensor" ],
"render_readme": true,
}