-
Notifications
You must be signed in to change notification settings - Fork 2
/
wxchip.py
executable file
·245 lines (197 loc) · 7.74 KB
/
wxchip.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
#!/usr/bin/python
# MODULE IMPORTS
import Adafruit_BMP.BMP085 as BMP085 # ODDITY, HAVE TO DO IT THIS WAY
import Adafruit_ADS1x15
import Adafruit_IO
from am2315 import AM2315
import ConfigParser
import time
import signal
import sys
import math
import subprocess
import threading
import logging
import os
# GLOBAL VARIABLES
# - 2/3 = +/-6.144V
# - 2 = +/-2.048V
ADCGAIN6VDC = 2/3
ADCGAIN6VDCVOLTS = 6.144
ADCGAIN2VDC = 2
ADCGAIN2VDCVOLTS = 2.048
ADCRESOLUTION = 2048
# ADC CHANNEL SENSORS
PHOTOCELL = 0
ANEMOMETER = 1
# ATMOSPHERICS
CTOK = 273.15
R_AIR = 287.058
P_FLAT_MAX_DELTA = 20.0
P_FLAT_MIN_DELTA = -20.0
# DEFAULTS
LEDOFFTIMER = 5
SLEEPTIME = 120
DATASENDSLEEP = 0.01
# CONNECT/DISCONNECT EVENTS
connected = threading.Event()
disconnected = threading.Event()
# CLASSES
class WeatherStation:
def __init__(self, io_client_conf="/etc/wxchip.cfg", io_client_type="mqtt"):
# VARIABLES
self.io_client = None
self.io_client_conf = io_client_conf
self.io_client_type = io_client_type
self.io_key = None
self.io_user = None
self.io_update_rate = SLEEPTIME
self.data = [
["wxchip-BMP180-temp", -1],
["wxchip-BMP180-baro", -1],
["wxchip-lux", -1],
["wxchip-windspeed", -1],
["wxchip-AM2315-temp", -1],
["wxchip-AM2315-humidity", -1]]
self.dead = False
self.last_pres_avg = 0
self.pres_trending = "flat"
# READ OUR CONFIG
config = ConfigParser.ConfigParser()
config.read(self.io_client_conf)
self.io_key = config.get("aio", "key", None)
self.io_user = config.get("aio", "username", None)
# OVER-WRITE THE IO CLIENT TYPE WITH THE STUFF FROM THE CONFIG
self.io_client_type = config.get("aio", "type", self.io_client_type)
# GET THE UPDATE RATE FROM THE CONFIG
self.io_update_rate = config.get("aio", "update_rate", self.io_update_rate)
# GET THE BUS NUMBERS FOR THE DEVICES
self.bmp180_bus = config.get("devices", "bmp180_bus", 1)
self.ads1015_bus = config.get("devices", "ads1015_bus", 1)
self.am2315_bus = config.get("devices", "am2315_bus", 1)
if self.io_key == None:
text = "No AIO Key found in %s" % self.io_client_conf
raise ValueError(text)
if self.io_user == None and self.io_client_type == "mqtt":
text = "No AIO User found in %s" % self.io_client_conf
raise ValueError(text)
# NO ERROR CHECKING FOR THE TYPE AND UPDATE RATE AS THEY HAVE DEFAULTS
# CREATE OUR IO_CLIENT
if self.io_client_type == "mqtt":
self.io_client = Adafruit_IO.MQTTClient(self.io_user, self.io_key)
logging.debug('Setting up AIO callbacks')
self.io_client.on_connect = io_connected
self.io_client.on_disconnect = io_disconnected
elif self.io_client_type == "rest":
self.io_client = Adafruit_IO.Client(self.io_key)
# CREATE OUR DEVICE OBJECTS
logging.debug('Setting up objects')
self.bmp180 = BMP085.BMP085(busnum=self.bmp180_bus)
self.ads1015 = Adafruit_ADS1x15.ADS1015(busnum=self.ads1015_bus)
# TODO: RE-ENABLE THIS
#self.am2315 = AM2315.AM2315(busnum=self.am2315_bus)
def calc_lux(self,volts):
lux = 0.0
# GENERIC CURVE FIT FROM https://learn.adafruit.com/photocells/using-a-photocell
#lux = 0.1624 * math.exp(1.6482 * volts)
# AXEL BENZ CURVE FIT FROM https://learn.adafruit.com/photocells/using-a-photocell
lux = 1.833 * math.exp(1.8344 * volts)
return lux
def compute_density(self,pres,temp):
return pres / (R_AIR * (temp + CTOK))
def calc_windspeed(self,volts):
return -1
def status_led_off(self):
logging.debug('CHIP LED off')
# TODO: POSSIBLY HOOK UP EXTERNAL LED
pass
def status_led_on(self):
logging.debug('CHIP LED on')
# TODO: POSSIBLY HOOK UP EXTERNAL LED
pass
def do_connect(self):
logging.debug("In do_connect: type: %s",self.io_client_type)
if self.io_client_type == "mqtt":
self.io_client.connect()
self.io_client.loop_background()
while not connected.isSet():
continue
connected.clear()
def kill(self):
self.dead = True
def run(self):
self.do_connect()
while not self.dead:
try:
if disconnected.isSet():
self.do_connect()
logging.debug("Gathering data")
# GET BMP805 DATA - TEMP AND ALT
self.data[0][1] = self.bmp180.read_temperature() # C
# GET ADC CHANNEL 0: PHOTOCELL
photocell_volts = self.ads1015.read_adc(PHOTOCELL, gain=ADCGAIN6VDC) * (ADCGAIN6VDCVOLTS/ADCRESOLUTION)
self.data[2][1] = self.calc_lux(float(photocell_volts))
# GET BMP085 DATA - PRESSURE AND DENSITY
self.data[1][1] = self.bmp180.read_pressure() # Pa
# GET ADC CHANNEL 1: ANEMOMETER
anemometer_volts = self.ads1015.read_adc(ANEMOMETER, gain=ADCGAIN2VDC) * (ADCGAIN2VDCVOLTS/ADCRESOLUTION)
self.data[3][1] = self.calc_windspeed(float(anemometer_volts))
# GET AM2315 DATA
# TODO: RE-ENABLE THIS
#self.data[4][1], self.data[5][1] = self.am2315.read_humidity_temperature()
# TURN OFF THE LED
self.status_led_off()
# PUBLISH DATA
try:
logging.debug("Sending data: client type: %s", self.io_client_type)
for data in self.data:
tmp = "%.3f" % data[1]
if self.io_client_type == "mqtt":
self.io_client.publish(data[0], tmp)
else:
self.io_client.send(data[0], tmp)
time.sleep(DATASENDSLEEP)
logging.debug("Sending data complete")
except Exception, e:
logging.exception('** something broke in publish **')
raise
self.status_led_on()
logging.debug("Starting sleep: %d seconds",SLEEPTIME)
time.sleep(SLEEPTIME)
except Exception, e:
logging.exception('** something else broke **')
# FUNCTIONS
def signal_handler(signal, frame):
logging.critical('killing wx-chip program!')
sys.exit(1)
signal.signal(signal.SIGINT, signal_handler)
def io_connected(client):
logging.info('Connected to wx-chip data repo on io.adafruit.com')
ISCONNECTED = True
connected.set()
disconnected.clear()
def io_disconnected(client):
logging.info('Disconnected from wx-chip data repo')
connected.clear()
disconnected.set()
def Main():
# WRITE PID TO FILE
pid = os.getpid()
f = open("/tmp/wx-chip.pid","w")
f.write(str(pid))
f.close()
# SETUP LOGGING
logging.basicConfig(level=logging.INFO,
format='%(asctime)s\t%(levelname)s\t%(message)s',
datefmt='%m-%d %H:%M',
filename='/tmp/wx-chip-debug.log',
filemode='w')
# SETTING UP WEATHER STATION
logging.debug("Creating weather station")
connected.clear()
disconnected.clear()
wxstation = WeatherStation(io_client_type="mqtt")
# RUN THE WEATHER STATION
wxstation.run()
if __name__ == "__main__":
Main()