Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode/*
44 changes: 39 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ temperature, air pressure, humidity, TVOCs and CO2.
* [Usage](#usage)
* [Printing data to the terminal window](#printing-data-to-the-terminal-window)
* [Piping data to a text-file](#piping-data-to-a-text-file)
* [Posting regularly to MQTT Server](#posting-regularly-to-mqtt-server)
* [Sensor data description](#sensor-data-description)
* [Contribution](#contribution)
* [Release notes](#release-notes)
Expand All @@ -36,8 +37,8 @@ The following tables shows a compact overview of dependencies for this project.

| package | version | Comments |
|-------------|-------------|-------------|
| python | 2.7 | Tested with python 2.7.13
| python-pip | | pip for python2.7
| python | 2.7 or 3.6 | Tested with python 2.7.13 and 3.6.5
| python-pip | | pip for python 2.7 or python 3.6
| git | | To download this project
| libglib2.0-dev | | For bluepy module

Expand Down Expand Up @@ -104,11 +105,12 @@ or install git to be able to clone this repo.
pi@raspberrypi:~$ sudo apt-get install git
```

Additionally, the ```read_waveplus.py``` script depends on the ```tableprint``` module
to print nicely formated sensor data to the Raspberry Pi terminal at run-time.
Additionally, the ```read_waveplus.py``` script depends on the ```tableprint``` module to print nicely formated sensor data to the Raspberry Pi terminal at run-time and the ```paho.mqtt``` module for communication with an MQTT server.

```
pi@raspberrypi:~$ sudo pip2 install tableprint==0.8.0
pi@raspberrypi:~$ sudo pip install tableprint==0.8.0
pi@raspberrypi:~$ sudo pip install paho-mqtt

```

> **Note:** The ```read_waveplus.py``` script has been tested with bluepy==1.2.0 and tableprint==0.8.0. You may download the latest versions at your own risk.
Expand Down Expand Up @@ -182,6 +184,38 @@ where you change ```SN``` with the 10-digit serial number, and change ```SAMPLE-

Exit the script using ```Ctrl+C```.

## Posting regularly to MQTT Server

If you need the data available on an home automation system, you can set up the script to post data read from the Airthings Wave plus to an MQTT server (like mosquitto). Invoking the read_waveplus.py with
```
pi@raspberrypi:~/waveplus-reader $ sudo python3 read_waveplus.py SN SAMPLE-PERIOD mqtt SERVER_ADDRESS
```
will read values from Airthings Wave Plus and post all values on the given mqtt server, assuming there is no login required.
```SN``` should be the serial number of your device, ```SAMPLE_PERIOD``` is ignored and ```SERVER_ADDRESS``` is the ip-address of the mqtt server you want your data posted to.

The values wil be posted as the following topics:
```
waveplus/SN/MEASUREMENT_TYPE
```
```MEASUREMENT_TYPE``` would be modified name of the measurements. Examples of topics would be
```
waveplus/2930002359/Humidity
waveplus/2930002359/Radon_ST_avg
...
waveplus/2930002359/VOC_level
```

Practical setup would be to add a line to your cron table:
```
pi@raspberrypi:~ $ sudo crontab -e
```
The following line will make a read and post every 5 minutes from your Raspberry Pi to the mqtt server located at ```192.168.0.16```:

```
*/5 * * * * sudo python3 /home/pi/waveplus-reader/read_waveplus.py 2930002359 60 mqtt 192.168.0.16
```


# Sensor data description

| sensor | units | Comments |
Expand Down
119 changes: 70 additions & 49 deletions read_waveplus.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,46 +31,51 @@
import time
import struct
import tableprint
import paho.mqtt.client as mqtt

# ===============================
# Script guards for correct usage
# ===============================

if len(sys.argv) < 3:
print "ERROR: Missing input argument SN or SAMPLE-PERIOD."
print "USAGE: read_waveplus.py SN SAMPLE-PERIOD [pipe > yourfile.txt]"
print " where SN is the 10-digit serial number found under the magnetic backplate of your Wave Plus."
print " where SAMPLE-PERIOD is the time in seconds between reading the current values."
print " where [pipe > yourfile.txt] is optional and specifies that you want to pipe your results to yourfile.txt."
print ("ERROR: Missing input argument SN or SAMPLE-PERIOD.")
print ("USAGE: read_waveplus.py SN SAMPLE-PERIOD [pipe > yourfile.txt]")
print (" where SN is the 10-digit serial number found under the magnetic backplate of your Wave Plus.")
print (" where SAMPLE-PERIOD is the time in seconds between reading the current values.")
print (" where [pipe > yourfile.txt] is optional and specifies that you want to pipe your results to yourfile.txt.")
sys.exit(1)

if sys.argv[1].isdigit() is not True or len(sys.argv[1]) != 10:
print "ERROR: Invalid SN format."
print "USAGE: read_waveplus.py SN SAMPLE-PERIOD [pipe > yourfile.txt]"
print " where SN is the 10-digit serial number found under the magnetic backplate of your Wave Plus."
print " where SAMPLE-PERIOD is the time in seconds between reading the current values."
print " where [pipe > yourfile.txt] is optional and specifies that you want to pipe your results to yourfile.txt."
print ("ERROR: Invalid SN format.")
print ("USAGE: read_waveplus.py SN SAMPLE-PERIOD [pipe > yourfile.txt]")
print (" where SN is the 10-digit serial number found under the magnetic backplate of your Wave Plus.")
print (" where SAMPLE-PERIOD is the time in seconds between reading the current values.")
print (" where [pipe > yourfile.txt] is optional and specifies that you want to pipe your results to yourfile.txt.")
sys.exit(1)

if sys.argv[2].isdigit() is not True or int(sys.argv[2])<0:
print "ERROR: Invalid SAMPLE-PERIOD. Must be a numerical value larger than zero."
print "USAGE: read_waveplus.py SN SAMPLE-PERIOD [pipe > yourfile.txt]"
print " where SN is the 10-digit serial number found under the magnetic backplate of your Wave Plus."
print " where SAMPLE-PERIOD is the time in seconds between reading the current values."
print " where [pipe > yourfile.txt] is optional and specifies that you want to pipe your results to yourfile.txt."
print ("ERROR: Invalid SAMPLE-PERIOD. Must be a numerical value larger than zero.")
print ("USAGE: read_waveplus.py SN SAMPLE-PERIOD [pipe > yourfile.txt]")
print (" where SN is the 10-digit serial number found under the magnetic backplate of your Wave Plus.")
print (" where SAMPLE-PERIOD is the time in seconds between reading the current values.")
print (" where [pipe > yourfile.txt] is optional and specifies that you want to pipe your results to yourfile.txt.")
sys.exit(1)

if len(sys.argv) > 3:
Mode = sys.argv[3].lower()
if Mode == 'mqtt':
Broker = sys.argv[4]
else:
Broker = None
else:
Mode = 'terminal' # (default) print to terminal

if Mode!='pipe' and Mode!='terminal':
print "ERROR: Invalid piping method."
print "USAGE: read_waveplus.py SN SAMPLE-PERIOD [pipe > yourfile.txt]"
print " where SN is the 10-digit serial number found under the magnetic backplate of your Wave Plus."
print " where SAMPLE-PERIOD is the time in seconds between reading the current values."
print " where [pipe > yourfile.txt] is optional and specifies that you want to pipe your results to yourfile.txt."
if Mode!='pipe' and Mode!='terminal' and Mode!='mqtt':
print ("ERROR: Invalid piping method.")
print ("USAGE: read_waveplus.py SN SAMPLE-PERIOD [pipe > yourfile.txt]")
print (" where SN is the 10-digit serial number found under the magnetic backplate of your Wave Plus.")
print (" where SAMPLE-PERIOD is the time in seconds between reading the current values.")
print (" where [pipe > yourfile.txt] is optional and specifies that you want to pipe your results to yourfile.txt.")
sys.exit(1)

SerialNumber = int(sys.argv[1])
Expand Down Expand Up @@ -124,8 +129,8 @@ def connect(self):
break # exit for loop

if (deviceFound is not True):
print "ERROR: Could not find device."
print "GUIDE: (1) Please verify the serial number. (2) Ensure that the device is advertising. (3) Retry connection."
print ("ERROR: Could not find device.")
print ("GUIDE: (1) Please verify the serial number. (2) Ensure that the device is advertising. (3) Retry connection.")
sys.exit(1)
else:
self.periph = Peripheral(MacAddr)
Expand Down Expand Up @@ -172,8 +177,8 @@ def set(self, rawData):
self.sensor_data[SENSOR_IDX_CO2_LVL] = rawData[8]*1.0
self.sensor_data[SENSOR_IDX_VOC_LVL] = rawData[9]*1.0
else:
print "ERROR: Unknown sensor version.\n"
print "GUIDE: Contact Airthings for support.\n"
print ("ERROR: Unknown sensor version.\n")
print ("GUIDE: Contact Airthings for support.\n")
sys.exit(1)

def conv2radon(self, radon_raw):
Expand All @@ -194,39 +199,55 @@ def getUnit(self, sensor_index):
waveplus.connect()

if (Mode=='terminal'):
print "\nPress ctrl+C to exit program\n"
print ("\nPress ctrl+C to exit program\n")

print "Device serial number: %s" %(SerialNumber)
print ("Device serial number: %s" %(SerialNumber))

header = ['Humidity', 'Radon ST avg', 'Radon LT avg', 'Temperature', 'Pressure', 'CO2 level', 'VOC level']

if (Mode=='terminal'):
print tableprint.header(header, width=12)
print (tableprint.header(header, width=12))
elif (Mode=='pipe'):
print header

while True:

# read values
print (header)
elif Mode == 'mqtt':
sensors = waveplus.read()
client = mqtt.Client()
client.connect(Broker)
for i in range(NUMBER_OF_SENSORS):
topic = "waveplus/{0}/{1}".format(SerialNumber, header[i].replace(' ','_'))
info = client.publish(topic, sensors.getValue(i), retain=False)
info.wait_for_publish()
time.sleep(0.1)

client.disconnect()
exit(1)

# extract
humidity = str(sensors.getValue(SENSOR_IDX_HUMIDITY)) + " " + str(sensors.getUnit(SENSOR_IDX_HUMIDITY))
radon_st_avg = str(sensors.getValue(SENSOR_IDX_RADON_SHORT_TERM_AVG)) + " " + str(sensors.getUnit(SENSOR_IDX_RADON_SHORT_TERM_AVG))
radon_lt_avg = str(sensors.getValue(SENSOR_IDX_RADON_LONG_TERM_AVG)) + " " + str(sensors.getUnit(SENSOR_IDX_RADON_LONG_TERM_AVG))
temperature = str(sensors.getValue(SENSOR_IDX_TEMPERATURE)) + " " + str(sensors.getUnit(SENSOR_IDX_TEMPERATURE))
pressure = str(sensors.getValue(SENSOR_IDX_REL_ATM_PRESSURE)) + " " + str(sensors.getUnit(SENSOR_IDX_REL_ATM_PRESSURE))
CO2_lvl = str(sensors.getValue(SENSOR_IDX_CO2_LVL)) + " " + str(sensors.getUnit(SENSOR_IDX_CO2_LVL))
VOC_lvl = str(sensors.getValue(SENSOR_IDX_VOC_LVL)) + " " + str(sensors.getUnit(SENSOR_IDX_VOC_LVL))

# Print data
data = [humidity, radon_st_avg, radon_lt_avg, temperature, pressure, CO2_lvl, VOC_lvl]

if (Mode=='terminal'):
print tableprint.row(data, width=12)
elif (Mode=='pipe'):
print data
while True:
sensors = None
try:
# read values
sensors = waveplus.read()

# extract
humidity = str(sensors.getValue(SENSOR_IDX_HUMIDITY)) + " " + str(sensors.getUnit(SENSOR_IDX_HUMIDITY))
radon_st_avg = str(sensors.getValue(SENSOR_IDX_RADON_SHORT_TERM_AVG)) + " " + str(sensors.getUnit(SENSOR_IDX_RADON_SHORT_TERM_AVG))
radon_lt_avg = str(sensors.getValue(SENSOR_IDX_RADON_LONG_TERM_AVG)) + " " + str(sensors.getUnit(SENSOR_IDX_RADON_LONG_TERM_AVG))
temperature = str(sensors.getValue(SENSOR_IDX_TEMPERATURE)) + " " + str(sensors.getUnit(SENSOR_IDX_TEMPERATURE))
pressure = str(sensors.getValue(SENSOR_IDX_REL_ATM_PRESSURE)) + " " + str(sensors.getUnit(SENSOR_IDX_REL_ATM_PRESSURE))
CO2_lvl = str(sensors.getValue(SENSOR_IDX_CO2_LVL)) + " " + str(sensors.getUnit(SENSOR_IDX_CO2_LVL))
VOC_lvl = str(sensors.getValue(SENSOR_IDX_VOC_LVL)) + " " + str(sensors.getUnit(SENSOR_IDX_VOC_LVL))

# Print data
data = [humidity, radon_st_avg, radon_lt_avg, temperature, pressure, CO2_lvl, VOC_lvl]

if (Mode=='terminal'):
print (tableprint.row(data, width=12))
elif (Mode=='pipe'):
print (data)

except :
print("Exception when calling waveplus->read")

time.sleep(SamplePeriod)

finally:
Expand Down