|
3 | 3 | import busio |
4 | 4 | from digitalio import DigitalInOut, Direction, Pull |
5 | 5 | import adafruit_dotstar as dotstar |
6 | | -from adafruit_esp32spi import adafruit_esp32spi |
7 | | -from adafruit_esp32spi import adafruit_esp32spi_wifimanager |
8 | | -import adafruit_esp32spi.adafruit_esp32spi_socket as socket |
9 | | -import adafruit_minimqtt.adafruit_minimqtt as MQTT |
10 | | -from adafruit_io.adafruit_io import IO_MQTT |
11 | | -from adafruit_io.adafruit_io_errors import AdafruitIO_MQTTError |
| 6 | +from adafruit_esp32spi import adafruit_esp32spi, adafruit_esp32spi_wifimanager |
| 7 | +from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError |
12 | 8 | from simpleio import map_range |
13 | 9 |
|
14 | 10 | import adafruit_pm25 |
|
34 | 30 | status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) |
35 | 31 | wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) |
36 | 32 |
|
37 | | - |
38 | 33 | # Connect to a PM2.5 sensor over UART |
39 | 34 | uart = busio.UART(board.TX, board.RX, baudrate=9600) |
40 | 35 | pm25 = adafruit_pm25.PM25_UART(uart) |
|
43 | 38 | i2c = busio.I2C(board.SCL, board.SDA) |
44 | 39 | bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c) |
45 | 40 |
|
46 | | -### MiniMQTT Callback Functions ### |
47 | | -def connected(client): |
48 | | - # Connected function will be called when the client is connected to Adafruit IO. |
49 | | - # This is a good place to subscribe to feed changes. The client parameter |
50 | | - # passed to this function is the Adafruit IO MQTT client so you can make |
51 | | - # calls against it easily. |
52 | | - print("Connected to Adafruit IO!") |
53 | | - |
54 | | -# pylint: disable=unused-argument |
55 | | -def disconnected(client): |
56 | | - # Disconnected function will be called when the client disconnects. |
57 | | - print("Disconnected from Adafruit IO!") |
58 | | - |
59 | | -def message(client, topic, message): |
60 | | - pass |
61 | | - |
62 | | -def on_new_time(client, topic, message): |
63 | | - """Obtains new time from Adafruit IO time service |
64 | | - and parses the current_hour/current_minute |
65 | | - """ |
66 | | - global current_hour, current_minute |
67 | | - current_time = message.split("-")[2].split("T")[1] |
68 | | - current_time = current_time.split(".")[0] |
69 | | - current_hour = int(current_time.split(":")[0]) |
70 | | - current_minute = int(current_time.split(":")[1]) |
71 | | - |
72 | | - |
73 | | - |
74 | 41 | ### Sensor Functions ### |
75 | 42 | def calculate_aqi(pm_sensor_reading): |
76 | 43 | """Returns a calculated air quality index (AQI) |
@@ -151,127 +118,68 @@ def read_bme280(is_celsius=False): |
151 | 118 | return temperature, humidity |
152 | 119 |
|
153 | 120 |
|
154 | | -### CODE ### |
155 | | - |
156 | | -# Connect to WiFi |
157 | | -print("Connecting to WiFi...") |
158 | | -wifi.connect() |
159 | | -print("Connected!") |
160 | | - |
161 | | -# Initialize MQTT interface with the esp interface |
162 | | -MQTT.set_socket(socket, esp) |
163 | | - |
164 | | -# Initialize a new MQTT Client object |
165 | | -mqtt_client = MQTT.MQTT( |
166 | | - broker="io.adafruit.com", username=secrets["aio_user"], password=secrets["aio_key"], |
167 | | -) |
| 121 | +# Create an instance of the Adafruit IO HTTP client |
| 122 | +io = IO_HTTP(secrets['aio_user'], secrets['aio_key'], wifi) |
168 | 123 |
|
169 | | -# Initialize an Adafruit IO MQTT Client |
170 | | -io = IO_MQTT(mqtt_client) |
| 124 | +# Describes feeds used to hold Adafruit IO data |
| 125 | +feed_aqi = io.get_feed("air-quality-sensor.aqi") |
| 126 | +feed_aqi_category = io.get_feed("air-quality-sensor.category") |
| 127 | +feed_humidity = io.get_feed("air-quality-sensor.humidity") |
| 128 | +feed_temperature = io.get_feed("air-quality-sensor.temperature") |
171 | 129 |
|
172 | | -# Connect the callback methods defined above to Adafruit IO |
173 | | -io.on_connect = connected |
174 | | -io.on_disconnect = disconnected |
175 | | -io.on_message = message |
176 | | - |
177 | | -# Connect to Adafruit IO |
178 | | -print("Connecting to Adafruit IO...") |
179 | | -io.connect() |
180 | | - |
181 | | -# Subscribe to the air quality sensor group |
182 | | -group_air_quality = "air-quality-sensor" |
183 | | -io.subscribe(group_key=group_air_quality) |
184 | | - |
185 | | -# Feeds within the air quality sensor group |
186 | | -# Temperature |
187 | | -feed_temp = group_air_quality + ".temperature" |
188 | | -# Humidity |
189 | | -feed_humid = group_air_quality + ".humidity" |
190 | | -# Air quality index (AQI) |
191 | | -feed_aqi = group_air_quality + ".aqi" |
192 | | -# Air quality index category |
193 | | -feed_aqi_category = group_air_quality + ".category" |
194 | 130 |
|
195 | 131 | # Set up location metadata |
196 | | -# TODO: Use secrets.py |
| 132 | +# TODO: Use secrets.py instead! |
197 | 133 | location_metadata = "40.726190, -74.005334, -6" |
198 | 134 |
|
199 | | -# Call on_new_time to update the time from Adafruit IO |
200 | | -io._client.add_topic_callback("time/ISO-8601", on_new_time) |
201 | | -# Subscribe to the Adafruit IO UTC time service |
202 | | -io.subscribe_to_time("ISO-8601") |
203 | | - |
204 | | -initial_time = time.monotonic() |
205 | | - |
206 | | -current_hour = 0 |
207 | | -current_minute = 0 |
208 | | -prv_hour = 0 |
209 | | -prv_minute = 0 |
210 | | -time_elapsed = 0 |
211 | | - |
212 | | -average_aqi = 0 |
| 135 | +elapsed_minutes = 0 |
| 136 | +prv_mins = 0 |
| 137 | +aqi_readings = 0 |
213 | 138 |
|
214 | 139 | while True: |
215 | | - try: |
216 | | - # Keep device connected to io.adafruit.com |
217 | | - # and process any incoming data. |
218 | | - io.loop() |
219 | | - except (ValueError, RuntimeError, AdafruitIO_MQTTError) as e: |
220 | | - print("Failed to get data, retrying\n", e) |
221 | | - wifi.reset() |
222 | | - wifi.connect() |
223 | | - io.reconnect() |
224 | | - continue |
225 | | - |
226 | | - # Check current time against io.adafruit time service |
227 | | - if (current_hour - prv_hour >= 1): |
228 | | - print("new hour!") |
229 | | - # Reset prv_hour |
230 | | - prv_hour = current_hour |
231 | | - io.publish(feed_temp, current_minute) |
232 | | - time_elapsed = True |
233 | | - elif (current_minute - prv_minute >= 1): |
234 | | - print("new 1m increment!") |
235 | | - print(current_minute) |
236 | | - # Reset prv_minute |
237 | | - prv_minute = int(current_minute) |
238 | | - io.publish(feed_temp, current_minute) |
239 | | - time_elapsed = True |
240 | | - elif current_minute % 10 == 0: |
241 | | - print("new 10m increment!") |
242 | | - # Reset prv_minute |
243 | | - prv_minute = int(current_minute) |
244 | | - io.publish(feed_temp, current_minute) |
245 | | - time_elapsed = True |
246 | | - else: |
247 | | - # no difference in current time |
248 | | - continue |
| 140 | + print("Obtaining time") |
| 141 | + try: |
| 142 | + cur_time = io.receive_time() |
| 143 | + # print(cur_time) |
| 144 | + except (ValueError, RuntimeError) as e: |
| 145 | + print("Failed to get data, retrying\n", e) |
| 146 | + wifi.reset() |
| 147 | + continue |
249 | 148 |
|
250 | | - if time_elapsed: |
251 | | - aqi_reading = sample_aq_sensor() |
252 | | - aqi, aqi_category = calculate_aqi(aqi_reading) |
253 | | - # Average AQI readings over amount of readings |
254 | | - if current_minute > 0: |
255 | | - average_aqi += aqi |
256 | | - average_aqi /= current_minute |
| 149 | + if cur_time[4] > prv_mins: |
| 150 | + print("%d min elapsed.."%elapsed_minutes) |
| 151 | + # Sample the AQI every minute |
| 152 | + aqi_readings += sample_aq_sensor() |
| 153 | + prv_mins = cur_time[4] |
| 154 | + elapsed_minutes += 1 |
| 155 | + |
| 156 | + if elapsed_minutes >= 10: |
| 157 | + print("Sampling AQI...") |
| 158 | + # Average AQI over 10 individual readings |
| 159 | + aqi_readings /= 10 |
| 160 | + aqi, aqi_category = calculate_aqi(aqi_readings) |
| 161 | + print("AQI: %d"%aqi) |
| 162 | + print("Category: %s"%aqi_category) |
| 163 | + |
| 164 | + # temp and humidity |
| 165 | + print("Sampling environmental sensor...") |
| 166 | + temperature, humidity = read_bme280() |
| 167 | + print("Temperature: %0.1f F" % temperature) |
| 168 | + print("Humidity: %0.1f %%" % humidity) |
| 169 | + # TODO: Publish all values to Adafruit IO |
257 | 170 |
|
258 | | - print("AQI: %d"%aqi) |
259 | | - print("Category: %s"%aqi_category) |
| 171 | + try: |
| 172 | + io.send_data(feed_aqi["key"], str(aqi)) |
| 173 | + io.send_data(feed_aqi_category["key"], aqi_category) |
| 174 | + io.send_data(feed_temperature["key"], str(temperature)) |
| 175 | + io.send_data(feed_humidity["key"], str(humidity)) |
| 176 | + except (ValueError, RuntimeError) as e: |
| 177 | + print("Failed to get data, retrying\n", e) |
| 178 | + wifi.reset() |
| 179 | + continue |
260 | 180 |
|
261 | | - # temp and humidity |
262 | | - temperature, humidity = read_bme280() |
263 | | - print("Temperature: %0.1f F" % temperature) |
264 | | - print("Humidity: %0.1f %%" % humidity) |
265 | 181 |
|
266 | | - # Publish to IO |
267 | | - print("Publishing to Adafruit IO...") |
268 | | - # TODO: These need to be within a try/except block |
269 | | - io.publish(feed_aqi, int(aqi), location_metadata) |
270 | | - io.publish(feed_aqi_category, aqi_category) |
271 | | - io.publish(feed_humid, humidity) |
272 | | - io.publish(feed_temp, temperature) |
273 | | - print("Published!") |
274 | | - # Reset time_elapsed |
275 | | - time_elapsed = False |
| 182 | + # Reset timer |
| 183 | + elapsed_minutes = 0 |
| 184 | + time.sleep(30) |
276 | 185 |
|
277 | | - time.sleep(60) |
0 commit comments