Radon Sensor

I've got a couple of Airthings Wave radon sensors. Following their instructions and a bit of fiddling I have them posting their data via a Python script with a raspberry pi as an intermediary. My thought is to use the Maker API to have that script post the radon readings to Hubitat.

This means I need a custom device driver for a Radon sensor, but "Radon" doesn't appear to be one of the supported capabilities. What should I use instead? Is there a generic float value I can define as a capability to store the radon readings?

Use attribute "Radon" instead

1 Like

Thank you!

1 Like

Interesting. I just picked up one of these earlier this week. I may have to look into a way to do the same.

Are there any radon sensors that can work with HE without doing this kind of two step workaround?

Do you have this code published anywhere? I'm interested in getting one of these and wouldn't mind collaborating (or just not having to re-invent the wheel)!

No, but I can post it here when I get home.

1 Like

Great, thanks!

Sorry this took so long... I completely forgot to look it up when I got home. Nice thing with Hubitat is it's hard to access from off network... but that's also the hard thing.

Here is the driver code. It subscribes to the MQTT server that is collecting the data from the Airthings sensor and makes that data available. There's a lot more cleanup that could be done here to make this more usable to others, such as removing the hard coding to my MQTT scheme in the subscribe call. But... this has been working for me for a few months now so I'm hard pressed to find a reason to touch it.

/**
 *  MQTT Radon Sensor
 *
 *  Copyright 2016 Eric Rowe
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 */
metadata {
	definition (name: "MQTT Radon Sensor", namespace: "ericrowe", author: "Eric Rowe") {
        capability "Sensor"
        capability "Initialize"
        capability "Temperature Measurement"
		attribute "Radon_24h", "Double"
        attribute "Radon_LongTerm", "Double"
        attribute "Temperature", "Double"
        attribute "Humidity", "Double"
	}


	simulator {
		// TODO: define status and reply messages here
	}

	tiles {
		valueTile("radon", "device.radon", decoration: "flat", width: 2, height: 2) {
            state "radon", label:'${currentValue} Bq/m3' }

		main(["Radon_LongTerm"])
		details(["Radon_24h", "Radon_LongTerm", "Temperature", "Humidity"])

	}
}

preferences {
    section("URI") {
        input "host", "text", title: "Host URI", required: true
        input "port", "text", title: "Host Port", required: true
        input "clientId", "text", title: "Client ID", required: true
        input "sensorId", "text", title: "Sensor ID", required: true
    }
}

void installed() {
    initialize()
}

void uninstalled() {
    interfaces.mqtt.disconnect()
}

void updated() {
    initialize()
}

void initialize() {
    try {
        def mqttInt = interfaces.mqtt
        mqttInt.connect("tcp://" + host + ":" + port, clientId, null, null)
        pauseExecution(1000)
        log.debug "connection established"
        mqttInt.subscribe("house/AirWave/Data/#")
    } catch(e) {
        log.debug "initialize error: ${e.message}"
    }
}

// parse incoming messages into attributes
void parse(String description) {
    def data = interfaces.mqtt.parseMessage(description)
    def payload = data["payload"]
    def jsonSlurped = new groovy.json.JsonSlurper().parseText(payload)
    if (jsonSlurped.SensorID == sensorId) {
        def value = jsonSlurped.Value * jsonSlurped.Scale
        radon = value
        sendEvent(name: jsonSlurped.Name,value: value,descriptionText: "",unit: jsonSlurped.Unit)
    }
}
void mqttClientStatus(String message) {
    log.debug "Parsing Client Status '${message}"
}

And this one is really ugly. This is the python script running on a raspberry pi that requests the sensor data from the Airthings sensor via a bluetooth dongle. IIRC I just set it up with a cron job that passes in the MAC address of the sensor to pull the data from. It uses the name programmed into the sensor as the name it reports under via MQTT. The MQTT server address is hard coded about 1/2 the way down. I'm publishing it twice - once to an internal MQTT server, and once to IFTTT (replace the key with your own if you want to try that one). It's honestly not all that well thought out, and is obviously just hacked together from the example script provided by Airthings... but as I said before - it's been working for me for months so I'm not going to touch it now...

# MIT License
#
# Copyright (c) 2018 Airthings AS
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# https://airthings.com

from bluepy.btle import UUID, Peripheral
from datetime import datetime
import sys
from time import time, sleep
import struct
import re
import paho.mqtt.client as paho
import json
import requests

class Sensor:
    def __init__(self, name, uuid, format_type, unit, scale):
        self.name = name
        self.uuid = uuid
        self.format_type = format_type
        self.unit = unit
        self.scale = scale

if len(sys.argv) < 2:
    print "USAGE: read_wave.py \"MAC\"\n where MAC is the address of the Wave and on the format AA:BB:CC:DD:EE:FF"
    sys.exit(1)

if not re.match("[0-9a-f]{2}([:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", sys.argv[1].lower()):
    print "USAGE: read_wave.py \"MAC\"\n where MAC is the address of the Wave and on the format AA:BB:CC:DD:EE:FF"
    sys.exit(1)

try:
    sensors = []
    sensors.append(Sensor("DateTime", UUID(0x2A08), 'HBBBBB', "\t", 0))
    sensors.append(Sensor("Temperature", UUID(0x2A6E), 'h', "deg C\t", 1.0/100.0))
    sensors.append(Sensor("Humidity", UUID(0x2A6F), 'H', "%\t\t", 1.0/100.0))
    sensors.append(Sensor("Radon 24h avg", "b42e01aa-ade7-11e4-89d3-123b93f75cba", 'H', "Bq/m3\t", 1.0))
    sensors.append(Sensor("Radon long term", "b42e0a4c-ade7-11e4-89d3-123b93f75cba", 'H', "Bq/m3\t", 1.0))

    p = Peripheral(sys.argv[1])

    def on_publish(client, userdata, mid):
        print "Message Published...."

    client = paho.Client()
    client.connect("192.168.1.200", 1883, 45)

    # Print header row
    str_header = "\t"
    for s in sensors:
        str_header += s.name + "\t"
    print str_header


    # Get and print sensor data
    str_out = ""
    date = ""
    for s in sensors:
        ch  = p.getCharacteristics(uuid=s.uuid)[0]
        if (ch.supportsRead()):
            val = ch.read()
            val = struct.unpack(s.format_type, val)
            if s.name == "DateTime":
                date = str(datetime(val[0], val[1], val[2], val[3], val[4], val[5])) + s.unit
                str_out += date
                str_out += "  "
                str_out += sys.argv[2]
            else:
                str_out += str(val[0] * s.scale) + " " + s.unit
                data = {}
                data['SensorID'] = sys.argv[2]
                data['Name'] = s.name
                data['Value'] = val[0]
                data['Scale'] = s.scale
                data['Unit'] = s.unit
                data['Timestamp'] = date
                client.publish("house/AirWave/Data/" + s.name,json.dumps(data),qos=1,retain=True)
                URL = "https://maker.ifttt.com/trigger/airSensor_" + s.name + "/with/key/<yourkey>"
                r = requests.get(url = URL, params = {'value1':val[0],'value2':s.scale,'value3':s.unit})
    print str_out
    client.publish("house/AirWave/Summary", str_out,qos=1,retain=True)



finally:
    client.disconnect()

Hello,

I have been working on my own sensors. Lately I am expanding my work to get Bluetooth devices to my hub.

I am approaching this a bit different. Rather than using PI, I made a BLE gateway that talk to the hub. The gateway perform similar functionality to the PI in this case. However, I am trying to add discovery of the devices so that it is easier to use. If you have a chance, please take a look at below. I have a few other Bluetooth devices of my own that I have brought in into Hubitat.

I am here because I am interested to get it working with Airthings. I do not have the device. However, if I can get some help form member in this threads, I may be able to make the DTH for Airthings.

I will need some help to get some preliminary data so that I can pair the Airthings. Then, I will need help testing and troubleshooting issues. I do not have the device I would not be able to troubleshoot it myself. I will provide you with one of my module free of charge. I would appreciate donation on shipping cost (around $3 to $5). I hope by doing this will give future owner of Airthings a chance to integrate their device into hubitat. If you are interested on doing this please feel free to reach out and PM me.

Thanks
Iman

1 Like

I'm IN.
I have an Airthing Wave Radon sensor and I'll be glad to help you with this.
I'm in Canada and I'll pay the shipping fees without problems.
PM additional infos. If we agree, I'll PM my address
Mike

I can help too if you need more folks and more sensors. I have a variety of Airthing sensors: 2x Gen 1 Wave, 2x Gen 2 Wave Plus, and 1x Wave Mini. I also have the airthing hub, but no integration there that I know of. Shipping's no problem.

I am however having trouble with my Hubitat for the last 5 days. I have to do a restart on it twice daily to keep it from locking up. I haven't had the inclination to go through the arduous process of uninstalling stuff until it stops misbehaving yet. That may impact your data and invalidate testing and troubleshooting on my system. Your call.

EDIT: just noticed there's an update available with a lock up fix advertised as one of the patches... applying now...

Hi @PPz, Thank you for your offer. Since you are in Canada, the shipping will be more expensive. I hope you do not mind that I work with @ericrowespam. If things goes well, I will make more of the modules.

@ericrowespam would you mind downloading an app on your smart phone. The name of the app is NRF connect. It is made by reputable European Semiconductor company.. Nordic Semiconductor. In the android version, It can get Raw Data of the Airthings advertisment packet. I use it to match it where I can load the driver. Would you be able to get that information?

If you can PM me, we can work out a way for me to send you my module.

Thanks
Iman

I don't :smile:
good luck to you !

Thank you. I will make more of the module if they work well for us.

PM'ed the data to you via a share folder.

I too am an owner of the Airthings Wave Plus and wanted to integrate it via LOCAL network only without any Internet access.
How is this project coming along?
Will it include all 6 measurements the Wave Plus supports? It would be good and beneficial to report high CO2, TVOC, Radon levels along with Humidity, Temp and Air Pressure.
I would be integrating it with Echo Speak to notify us when certain levels are reached to allow us to air out the house. Please remember to add text description in there as well.

1 Like

Any new news ?

1 Like

Has anyone able to connect AirThings Radon detector via Node Red?