def check_sensor(parent_sensor_id: str) -> None: resp = requests.get( "https://www.purpleair.com/json?show={}".format(parent_sensor_id)) if resp.status_code != 200: raise Exception("got {} responde code from purpleair".format( resp.status_code)) try: resp_json = resp.json() except ValueError: return for sensor in resp_json.get("results"): sensor_id = sensor.get("ID") name = sensor.get("Label") stats = sensor.get("Stats") temp_f = sensor.get("temp_f") humidity = sensor.get("humidity") pressure = sensor.get("pressure") if stats: stats = json.loads(stats) pm25_10min_raw = stats.get("v1") if pm25_10min_raw: pm25_10min = max(float(pm25_10min_raw), 0) i_aqi = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pm25_10min), algo=aqi.ALGO_EPA) aqi_g.labels(parent_sensor_id=parent_sensor_id, sensor_id=sensor_id, sensor_name=name).set(i_aqi) # https://www.aqandu.org/airu_sensor#calibrationSection pm25_10min_AQandU = 0.778 * float(pm25_10min) + 2.65 i_aqi_AQandU = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pm25_10min_AQandU), algo=aqi.ALGO_EPA) aqi_AQandU_g.labels(parent_sensor_id=parent_sensor_id, sensor_id=sensor_id, sensor_name=name).set(i_aqi_AQandU) # https://www.lrapa.org/DocumentCenter/View/4147/PurpleAir-Correction-Summary pm25_10min_LRAPA = max(0.5 * float(pm25_10min) - 0.66, 0) i_aqi_LRAPA = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pm25_10min_LRAPA), algo=aqi.ALGO_EPA) aqi_LRAPA_g.labels(parent_sensor_id=parent_sensor_id, sensor_id=sensor_id, sensor_name=name).set(i_aqi_LRAPA) if temp_f: temp_g.labels(parent_sensor_id=parent_sensor_id, sensor_id=sensor_id, sensor_name=name).set(float(temp_f)) if pressure: pressure_g.labels(parent_sensor_id=parent_sensor_id, sensor_id=sensor_id, sensor_name=name).set(float(pressure)) if humidity: humidity_g.labels(parent_sensor_id=parent_sensor_id, sensor_id=sensor_id, sensor_name=name).set(float(humidity))
def get_air_quality(): # sudo usermod -a -G dialout yourusername # https://cdn.sparkfun.com/assets/parts/1/2/2/7/5/Laser_Dust_Sensor_Control_Protocol_V1.3.pdf # Start in reporting mode : query/home/pi/.local/bin sensor = SDS011("/dev/ttyUSB0", use_query_mode=True) sensor.set_work_period(work_time=0) # work_time is continuous logging.debug('waking sensor') sensor.sleep(sleep=False) # wake sensor logging.debug('waiting 30 seconds') time.sleep(30) # capture 30 seconds of data logging.debug('running sensor query') result = sensor.query() logging.debug('sleeping sensor') sensor.sleep() # sleep sensor # print(f" PMT2.5: {pm25} μg/m3 PMT10 : {pm10} μg/m3") if result is None: logging.error("Sensor returned None") return None pm25, pm10 = result data = { 'pm25': str(pm25), 'pm10': str(pm10), 'aqipm25': str(aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pm25))), 'aqipm10': str(aqi.to_iaqi(aqi.POLLUTANT_PM10, str(pm10))) } return data
def get_reading(field: str, monitor_id: int): sql = """ SELECT ch_a.label, ch_a.""" + field + """, ch_b.""" + field + """, FROM_UNIXTIME(ch_a.recorded_at) FROM air_quality ch_a JOIN air_quality ch_b ON ch_a.recorded_at = ch_b.recorded_at AND ch_b.id = ch_a.id + 1 WHERE ch_a.id = %(monitor_id)s AND ch_a.LastSeen > UNIX_TIMESTAMP(NOW() - INTERVAL 20 MINUTE) ORDER BY ch_a.recorded_at DESC LIMIT 1 """ bind = {"field": field, "monitor_id": monitor_id} cur.execute(sql, bind) response = cur.fetchone() try: # If one channel or the other is malfunctioning and reading zero, take the AQI value of the good channel if response[1] == 0: myaqi = aqi.to_iaqi(aqi.POLLUTANT_PM25, response[2], algo=aqi.ALGO_EPA) if response[2] == 0: myaqi = aqi.to_iaqi(aqi.POLLUTANT_PM25, response[1], algo=aqi.ALGO_EPA) # If they both have values, average them if response[1] > 0 and response[2] > 0: myaqi = aqi.to_iaqi(aqi.POLLUTANT_PM25, (response[1] + response[2]) / 2, algo=aqi.ALGO_EPA) data = Reading(id=monitor_id, label=response[0], field=field, A=response[1], B=response[2], avg=(response[1] + response[2]) / 2, time=response[3], pct_diff=(response[1] - response[2]) / response[1], aqi=myaqi, aqi_level=get_aqi_level(myaqi)) except: data = None return data
def process_data(d): r = struct.unpack('<HHxxBB', d[2:]) # pm25 = r[0]/10.0 pm25 = aqi.to_iaqi(aqi.POLLUTANT_PM25, r[0] / 10.0, algo=aqi.ALGO_EPA) # pm10 = r[1]/10.0 pm10 = aqi.to_iaqi(aqi.POLLUTANT_PM10, r[1] / 10.0, algo=aqi.ALGO_EPA) checksum = sum(ord(v) for v in d[2:8]) % 256 return [pm25, pm10]
def predict(): """Predict tomorrow AQI value and PM2.5 value using XGBoost""" result = {"Yangon": {}, "Mandalay": {}} # load XGBoost model loaded_model = joblib.load("app/static/model.sav") # get current month month = datetime.now().month # get current season season = get_season(month) air = requests.get( 'https://www.purpleair.com/json?show=9578|33329|26359|9618|26285|31425|51727|20389|36553|29855|33255|34545' ) air = air.json() air = preprocessing_all(air) for a in air: r = {} data = {} # Yangon = 1, Mandalay = 0 city = 1 if a["City"] == "Yangon" else 0 temp = a["Temperature"] humd = a["Humidity"] center = 0 # convert center name into respective value center = get_center(a["Label"]) p_data = [[city, center, month, season, int(temp), int(humd)]] # convert into pandas DataFrame p_data = pd.DataFrame(p_data, columns=[ 'City', 'Center', 'Month', 'Season', 'Temperature_F', 'Humidity_%' ]) # predict aqi_p = loaded_model.predict(p_data) # convert into int value r["PM2.5"] = int(float(aqi_p.astype(str)[0])) # calculate AQI value r["AQI"] = int( aqi.to_iaqi(aqi.POLLUTANT_PM25, str(r["PM2.5"]), algo=aqi.ALGO_EPA)) data[a["Label"]] = r if city: result["Yangon"].update(data) else: result["Mandalay"].update(data) final = [] # calculate average AQI and PM2.5 values for key, values in result.items(): a = [] pm = [] for k, v in values.items(): a.append(v["AQI"]) pm.append(v["PM2.5"]) a = float("{:.2f}".format(sum(a) / len(a))) pm = float("{:.2f}".format(sum(pm) / len(pm))) final.append({"Label": key, "AQI": a, "PM2.5": pm}) final = jsonify(final) final.headers.add("Access-Control-Allow-Origin", "*") return final
def preprocessing_one(api_json): """Accept input json from purpleair API Return processed data in list format """ result = {} result["Label"] = api_json["results"][0]["Label"] result["Lat"] = api_json["results"][0]["Lat"] result["Lon"] = api_json["results"][0]["Lon"] result["PM1_0"] = api_json["results"][0]["pm1_0_atm"] result["PM2_5"] = api_json["results"][0]["pm2_5_atm"] result["PM10_0"] = api_json["results"][0]["pm10_0_atm"] result["Humidity"] = api_json["results"][0]["humidity"] result["Temperature"] = api_json["results"][0]["temp_f"] result["Pressure"] = api_json["results"][0]["pressure"] # separate Yangon an Mandalay if "Mandalay" in api_json["results"][0]["Label"]: result["City"] = "Mandalay" else: result["City"] = "Yangon" # calculate AQI using PM2.5 value result["AQI"] = int( aqi.to_iaqi(aqi.POLLUTANT_PM25, str(api_json["results"][0]["pm2_5_atm"]), algo=aqi.ALGO_EPA)) return result
def handler(self, connection, addr): pid = os.getpid() BUFFER = 1024 print(f"Handling connection {pid}.") received = bytes() while True: try: data = connection.recv(BUFFER) except SOCKET_TIMEOUT: break received += data # There is an extra 33 bytes that comes through the connection if sys.getsizeof(data) < (BUFFER + 33): break else: # Set a timeout. This is needed if the data is exactly the # length of the buffer - in that case without a timeout # we will get stuck in the recv part of the loop connection.settimeout(0.5) request = pickle.loads(data) if request.lower() == "time": response = pickle.dumps("{}".format(datetime.now())) elif request.lower() == "weather": response = self.get_weather() elif request.lower() == "airquality": myaqi = aqi.to_iaqi(aqi.POLLUTANT_PM25, '12', algo=aqi.ALGO_EPA) response = f"Air quality index is: {myaqi}" else: response = "Invalid command" connection.send(pickle.dumps(response)) print(f"Returning response {response} to requester.") connection.close()
def preprocessing_all(api_json): """Accept input json from purpleair API Return processed data in list format """ result = [] count = 1 # get data from 'result' key for apis in api_json["results"]: # get data only from parent Air Quality Meters if not "ParentID" in apis: one_res = {} one_res["Label"] = apis["Label"] one_res["Lat"] = apis["Lat"] one_res["Lon"] = apis["Lon"] one_res["PM1_0"] = apis["pm1_0_atm"] one_res["PM2_5"] = apis["pm2_5_atm"] one_res["PM10_0"] = apis["pm10_0_atm"] one_res["Humidity"] = apis["humidity"] one_res["Temperature"] = apis["temp_f"] one_res["Pressure"] = apis["pressure"] # calculate AQI using PM2.5 value one_res["AQI"] = int( aqi.to_iaqi(aqi.POLLUTANT_PM25, str(apis["pm2_5_atm"]), algo=aqi.ALGO_EPA)) one_res["ID"] = count count = count + 1 # separate Yangon an Mandalay if "Mandalay" in apis["Label"]: one_res["City"] = "Mandalay" else: one_res["City"] = "Yangon" result.append(one_res) return result
def epa_pm100_aqi(self): # CONSIDER: Instead of averaging the two # sensors, should we just pick one? try: pm100 = statistics.mean( filter(bool, (self.pm100_a_avg, self.pm100_b_avg))) return aqi.to_iaqi(aqi.POLLUTANT_PM10, pm100, algo=aqi.ALGO_EPA) except statistics.StatisticsError: pass
def apply_aqi(self, row, aqi_measure, column_name): try: return aqi.to_iaqi(aqi_measure, str(row[column_name]), algo=aqi.ALGO_EPA) except IndexError: # the value is too big for the calculator, will calculate the max value instead. return 501 except Exception as e: print(e)
def get_particle_measure(): port = "/dev/ttyS0" # Set this to your serial port. baudrate = 9600 # Prepare serial connection. ser = Serial(port, baudrate=baudrate, bytesize=EIGHTBITS, parity=PARITY_NONE, stopbits=STOPBITS_ONE) ser.flushInput() HEADER_BYTE = b"\xAA" COMMANDER_BYTE = b"\xC0" TAIL_BYTE = b"\xAB" byte, previousbyte = b"\x00", b"\x00" for i in range(10): previousbyte = byte byte = ser.read(size=1) # We got a valid packet header. if previousbyte == HEADER_BYTE and byte == COMMANDER_BYTE: packet = ser.read(size=8) # Read 8 more bytes # Decode the packet - little endian, 2 shorts for pm2.5 and pm10, 2 ID bytes, checksum. readings = struct.unpack('<HHcccc', packet) # Measurements. pm_25 = readings[0] / 10.0 pm_10 = readings[1] / 10.0 # ID id = packet[4:6] # Prepare checksums. checksum = readings[4][0] calculated_checksum = sum(packet[:6]) & 0xFF checksum_verified = (calculated_checksum == checksum) # Message tail. tail = readings[5] if tail == TAIL_BYTE and checksum_verified: aqi_2_5 = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pm_25)) aqi_10 = aqi.to_iaqi(aqi.POLLUTANT_PM10, str(pm_10)) return [(pm_25, aqi_2_5), (pm_10, aqi_10)] return [(None, None), (None, None)]
def get_outdoor_data(): # https://docs.google.com/document/d/15ijz94dXJ-YAZLi9iZ_RaBwrZ4KtYeCy08goGBwnbCU/edit result = requests.get( f"https://www.purpleair.com/json?key={config['PURPLE_AIR_KEY']}&show={config['PURPLE_AIR_DEVICE_ID']}" ) field_map = { 'pm2_5_atm': 'pm25', 'pm10_0_atm': 'pm10', 'LastSeen': 'LastSeen', 'humidity': 'humidity', 'temp_f': 'temp_f', 'pressure': 'pressure' } data = {} logging.debug(json.dumps(result.json(), indent=4)) for record in result.json().get('results', []): # https://github.com/MazamaScience/AirSensor/blob/master/documents/PurpleAir_CF=ATM_vs_CF=1.md for field in field_map.keys(): if field in record: if field_map[field] not in data: data[field_map[field]] = record[field] else: if field in ['pm2_5_atm', 'pm10_0_atm']: # Average the existing measurement in data with the new # second measurement in record data[field_map[field]] = "{:.2f}".format( sum([ float(data[field_map[field]]), float(record[field]) ]) / 2) # We'll assume LastSeen values are similar # TODO : Check for very old LastSeen values and error out or something data['aqipm25'] = str(aqi.to_iaqi(aqi.POLLUTANT_PM25, str(data['pm25']))) data['aqipm10'] = str(aqi.to_iaqi(aqi.POLLUTANT_PM10, str(data['pm10']))) data['temp_f'] = f"{float(data['temp_f']) + PURPLE_AIR_TEMP_OFFSET:.2f}" return data
def test_create_aqis_correctly(self): print("Testing aqis correctly") deriver = Derive() # create Cleaner object cleaner = Cleaner() # create Cleaner object df = cleaner.load_csv_data('data') cleaner.clean_data(df) df_group = deriver.group_data_by_day(df) deriver.create_date_from_string(df_group, 'month', 'day', 'year') deriver.calc_aqis(df) aqi_value = df.iloc[10]['aqi_PM10'] PM10_value = df.iloc[10]['PM10'] test_aqi_value = aqi.to_iaqi(aqi.POLLUTANT_PM10, PM10_value, algo=aqi.ALGO_EPA) self.assertEqual(aqi_value, test_aqi_value) # make sure the datframe has at least some rows.
def read_pm_sensor(self): if self.dummy_data == True: pm = (random.randrange(0, 400, 1) / 2, random.randrange(0, 400, 2) / 4, random.randrange(0, 250, 5), random.randrange(0, 250, 5)) return pm self.pm_sensor.sleep(sleep=False) pm25reads = [] pm10reads = [] time.sleep(self.measurement_delay) readcount = 0 while readcount < 3: data = self.pm_sensor.query() pm25reads.append(data[0]) pm10reads.append(data[1]) time.sleep(2) readcount += 1 self.pm_sensor.sleep() pm25raw = median(pm25reads) pm10raw = median(pm10reads) pm25aqi = aqi.to_iaqi(aqi.POLLUTANT_PM25, pm25raw, algo=aqi.ALGO_EPA) pm10aqi = aqi.to_iaqi(aqi.POLLUTANT_PM10, pm10raw, algo=aqi.ALGO_EPA) return (pm25raw, pm10raw, pm25aqi, pm10aqi)
def main(): while True: with open('/home/pi/shared/src/airquality/aqi.json') as f: data = json.load(f) pm25 = [] pm10 = [] for element in data: # print(element) pm25.append(element['pm25']) pm10.append(element['pm10']) # print(statistics.mean(pm25)) # print(statistics.median(pm25)) # print('') # print(statistics.mean(pm10)) # print(statistics.median(pm10)) cur_aqi = aqi.to_iaqi(aqi.POLLUTANT_PM25, statistics.mean(pm25), algo=aqi.ALGO_EPA) # format and display print("AQI:\t%d" % cur_aqi) out_text = "%d" % cur_aqi oled.fill(0) oled.show() image = Image.new("1", (oled.width, oled.height)) draw = ImageDraw.Draw(image) # oled.text(out_text, 5, 15, 1) # oled.show() (font_width, font_height) = font.getsize(out_text) draw.text((oled.width // 2 - font_width // 2, oled.height // 2 - font_height // 2), out_text, font=font, fill=255) oled.image(image) oled.show() time.sleep(300)
def get_reading(monitor): sql = """ SELECT (aq1.PM2_5Value + aq2.PM2_5Value) / 2 as channel_avg, aq1.label, from_unixtime(aq1.recorded_at), aq1.record_id FROM air_quality aq1 JOIN air_quality aq2 ON aq1.record_id + 1 = aq2.record_id WHERE aq1.ID = %s AND aq1.AQI IS NULL AND aq1.recorded_at - aq1.lastseen < 1000; """ cur.execute(sql, monitor) conn.commit() response = cur.fetchall() print("Processing ", len(response), " readings") sql2 = """ UPDATE air_quality aq SET AQI = %(aqi)s WHERE aq.record_id = %(record_id)s OR aq.record_id = %(record_id)s + 1 """ updates = [] for r in response: myaqi = aqi.to_iaqi(aqi.POLLUTANT_PM25, r[0], algo=aqi.ALGO_EPA) update = {"aqi": myaqi, "record_id": r[3]} print(update) updates.append(update) cur.execute(sql2, update) conn.commit()
def get_aqi(self): if self.data_type == 'NO2': constant = aqi.POLLUTANT_NO2_1H elif self.data_type == 'O3': constant = aqi.POLLUTANT_O3_8H elif self.data_type == 'CO': constant = aqi.POLLUTANT_CO_8H elif self.data_type == 'SO2': constant = aqi.POLLUTANT_SO2_1H elif self.data_type == 'PM25': constant = aqi.POLLUTANT_PM25 else: return 0 try: my_aqi = aqi.to_iaqi(constant, str(self.get_avg()), algo=aqi.ALGO_EPA) except Exception as e: print 'out of range' return 0 return my_aqi
def saveData(): while True: max_data = open('max_data_size.txt', 'r') max_size = max_data.readline() max_data.close() start = time.time() # takes unix time at start of using sensor to ensure stable readings try: ppm25 = sensor.query()[0] # Query the sensor and then grabs the pm25 result from the list # The below lines figure out if the number can be converted to a AQI number. Must be 500 or below if ppm25 < 500: iaqi = aqi.to_iaqi(aqi.POLLUTANT_PM25, ppm25, algo=aqi.ALGO_EPA) # Converts micrograms per m^3 to aqi else: iaqi = 500 # If ppm25 is bigger than 500 iaqi is automatically 500 except: ppm25 = 'NO_DATA' data_file_size = os.stat('data.csv').st_size / (1024*1024) while float(max_size) <= data_file_size: # While the size of the file is bigger than the max file size lines = list() # makes empty list with open('data.csv', 'r') as readFile: # Opens the data file reader = csv.reader(readFile) # reads file into variable for row in reader: # appends all lines into the list lines.append(row) for line in lines: # Deletes the first line from the list lines.remove(line) break # has to break out of loop so as only to delete the first line from the list with open('data.csv', 'w', newline='') as writeFile: # opens the file as write writer = csv.writer(writeFile) # makes csv writer object writer.writerows(lines) # writes the list to the file without the first item if ppm25 != 'NO_DATA': toappend = [iaqi, time.time()] # Data formatted ready to be appended to the data file with open('data.csv', 'a+', newline='') as appendFile: append = csv.writer(appendFile) append.writerow(toappend) end = time.time() # Takes time at end to ensure stable reading from sensor difference = 3 - (end - start) if difference > 0: time.sleep(difference) # Ensures that the readings from the sensor are equally spaced apart
def handle_client(conn, addr): print(f"[NEW CONNECTION] {addr} connected.\n") connected = True while connected: msg_length = conn.recv(HEADER).decode(FORMAT) if msg_length: msg_length = int(msg_length) msg = conn.recv(msg_length).decode(FORMAT) if msg == DISCONNECT_MESSAGE: print(f"[DISCONNECTING] {addr}") connected = False break print(f"[{addr}] {msg}\n") if "weather" in msg.lower(): conn.send( f"The temperature today will be: {Data.temperature('celsius')['temp']}C" .encode(FORMAT)) elif "time" in msg.lower(): now = datetime.now() current_time = now.strftime("%H:%M:%S") conn.send( f"The time right now is: {current_time}".encode(FORMAT)) elif "air quality" in msg.lower() or "aq" in msg.lower(): myaqi = python - aqi.to_iaqi(python - aqi.POLLUTANT_PM25, '12', algo=python - aqi.ALGO_EPA) conn.send(f"The AQI (Air Quality Index) is: {myaqi}AQI".encode( FORMAT)) else: conn.send( f"The command doesn't exist, please try again!".encode( FORMAT)) conn.close()
def conv_aqi(pm25, pm10): aqi25 = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pm25)) aqi10 = aqi.to_iaqi(aqi.POLLUTANT_PM10, str(pm10)) return aqi25, aqi10
#!/usr/bin/env python3 from sds011 import SDS011 import socket import time import aqi UDP_IP = "10.0.0.20" UDP_PORT = 1027 sock = socket.socket( socket.AF_INET, # Internet socket.SOCK_DGRAM) # UDP sensor = SDS011("/dev/ttyUSB0", use_query_mode=True) while True: sensor.sleep(sleep=False) time.sleep(30) data = sensor.query() #convert to AQI from micrograms/m^3 aqi_2_5 = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(data[0])) aqi_10 = aqi.to_iaqi(aqi.POLLUTANT_PM10, str(data[1])) aqi_data = (str(aqi_2_5).encode('utf-8'), str(aqi_10).encode('utf-8')) print(data) print(aqi_data) sensor.sleep() # sock.sendto(str(data.encode('utf-8')), (UDP_IP,UDP_PORT)) sock.sendto(str(aqi_data).encode('utf-8'), (UDP_IP, UDP_PORT)) time.sleep(300)
def conv_aqi(pmt_2_5, pmt_10): aqi_2_5 = aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pmt_2_5)) aqi_10 = aqi.to_iaqi(aqi.POLLUTANT_PM10, str(pmt_10)) return aqi_2_5, aqi_10
def getData(self): for sensorID, devID in self.sensorDevices.iteritems(): device = indigo.devices[devID] url = "https://www.purpleair.com/json?show={}".format(sensorID) try: response = requests.get(url) except requests.exceptions.RequestException as err: self.logger.error(u"{}: getData RequestException: {}".format( device.name, err)) else: self.logger.threaddebug( u"{}: getData for sensor {}:\n{}".format( device.name, sensorID, response.text)) sensorData = response.json()['results'][0] sensor_aqi = int( aqi.to_iaqi(aqi.POLLUTANT_PM25, sensorData['PM2_5Value'], algo=aqi.ALGO_EPA)) state_list = [{ 'key': 'sensorValue', 'value': sensor_aqi, 'uiValue': "{}".format(sensor_aqi) }, { 'key': 'Temperature', 'value': sensorData['temp_f'], 'decimalPlaces': 0 }, { 'key': 'Humidity', 'value': sensorData['humidity'], 'decimalPlaces': 0 }, { 'key': 'Pressure', 'value': sensorData['pressure'], 'decimalPlaces': 2 }, { 'key': 'Label', 'value': sensorData['Label'] }, { 'key': 'Latitude', 'value': sensorData['Lat'] }, { 'key': 'Longitude', 'value': sensorData['Lon'] }, { 'key': 'RSSI', 'value': sensorData['RSSI'] }, { 'key': 'Uptime', 'value': sensorData['Uptime'] }, { 'key': 'Version', 'value': sensorData['Version'] }, { 'key': 'Hardware', 'value': sensorData['DEVICE_HARDWAREDISCOVERED'] }, { 'key': 'p_0_3_um', 'value': sensorData['p_0_3_um'] }, { 'key': 'p_0_5_um', 'value': sensorData['p_0_5_um'] }, { 'key': 'p_10_0_um', 'value': sensorData['p_10_0_um'] }, { 'key': 'p_1_0_um', 'value': sensorData['p_1_0_um'] }, { 'key': 'p_2_5_um', 'value': sensorData['p_2_5_um'] }, { 'key': 'p_5_0_um', 'value': sensorData['p_5_0_um'] }, { 'key': 'pm10_0_atm', 'value': sensorData['pm10_0_atm'] }, { 'key': 'pm10_0_cf_1', 'value': sensorData['pm10_0_cf_1'] }, { 'key': 'pm1_0_atm', 'value': sensorData['pm1_0_atm'] }, { 'key': 'pm1_0_cf_1', 'value': sensorData['pm1_0_cf_1'] }, { 'key': 'pm2_5_atm', 'value': sensorData['pm2_5_atm'] }, { 'key': 'pm2_5_cf_1', 'value': sensorData['pm2_5_cf_1'] }] device.updateStatesOnServer(state_list)
# Monitoring AIR Quality with Raspberry, Adafruit and SDS sensor https://www.raspberrypi.org/blog/monitor-air-quality-with-a-raspberry-pi/ import serial, time import aqi from Adafruit_IO import Client aio = Client(ADAFRUIT_USER, ADAFRUIT_PW) ser = serial.Serial('/dev/ttyUSB0') while True: data = [] for index in range(0, 10): datum = ser.read() data.append(datum) pmtofive = int.from_bytes(b''.join(data[2:4]), byteorder='little') / 10 pmtofive_aqi = str( aqi.to_iaqi(aqi.POLLUTANT_PM25, pmtofive, algo=aqi.ALGO_EPA)) #print('PM 2.5: ', pmtofive) #print('PM 2.5 AQI', pmtofive_aqi) aio.send('air25', pmtofive) aio.send('air25-aqi', pmtofive_aqi) pmten = int.from_bytes(b''.join(data[4:6]), byteorder='little') / 10 pmten_aqi = str(aqi.to_iaqi(aqi.POLLUTANT_PM10, pmten, algo=aqi.ALGO_EPA)) #print('PM 10 AQI: ', pmten_aqi) aio.send('air10', pmten) aio.send('air10-aqi', pmten_aqi) #print('PM 10: ', pmten)
scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive'] # what you want to access credentials = ServiceAccountCredentials.from_json_keyfile_name('GSpreadPM25Peet-194a222ea2e4.json', scope) client = gspread.authorize(credentials) sheet = client.open("PM25_Peet").sheet1 # workbook.worksheet #%% Define Serial t = serial.Serial('com8',9600) # modify the serial #'/dev/ttyUSB0' #while True: for i in range(0,10): t.flushInput() time.sleep(0.5) retstr = t.read(10) if (len(retstr)==10): if(retstr[0]==0xaa and retstr[1]==0xc0): if sum(retstr[2:8]) % 256 == retstr[8]: # check if error occur from check-sum pm25 = (int(retstr[2])+int(retstr[3])*256) / 10 # in ug/m3 pm10 = (int(retstr[4])+int(retstr[5])*256) / 10 # in ug/m3 aqi25_us = int(aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pm25), aqi.ALGO_EPA)) aqi25_cn = int(aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pm25), aqi.ALGO_MEP)) print ("pm2.5:%.1f AQI_US: %d AQI_CN: %d"%(pm25,aqi25_us,aqi25_cn)) sheet.append_row([time.ctime(),pm25,aqi25_us,aqi25_cn])
def insert_reading(reading): channel1 = """ INSERT INTO air_quality(recorded_at, AGE, DEVICE_BRIGHTNESS, DEVICE_LOCATIONTYPE, \ Hidden, ID, Label, LastSeen, LastUpdateCheck, Lat, Lon, PM2_5Value, RSSI, Stats, \ THINGSPEAK_PRIMARY_ID, THINGSPEAK_PRIMARY_ID_READ_KEY, THINGSPEAK_SECONDARY_ID, THINGSPEAK_SECONDARY_ID_READ_KEY, \ Type, Uptime, Version, humidity, is_owner, pressure, temp_f, aqi, current_pm_2_5, 10_min_avg, 30_min_avg, 60_min_avg, 6_hr_avg, 24_hr_avg, 1_wk_avg) VALUES( UNIX_TIMESTAMP(NOW()), %(AGE)s, %(DEVICE_BRIGHTNESS)s, %(DEVICE_LOCATIONTYPE)s, %(Hidden)s, %(ID)s, %(Label)s, %(LastSeen)s, %(LastUpdateCheck)s, %(Lat)s, %(Lon)s, %(PM2_5Value)s, %(RSSI)s, %(Stats)s, %(THINGSPEAK_PRIMARY_ID)s, %(THINGSPEAK_PRIMARY_ID_READ_KEY)s, %(THINGSPEAK_SECONDARY_ID)s, %(THINGSPEAK_SECONDARY_ID_READ_KEY)s, %(Type)s, %(Uptime)s, %(Version)s, %(humidity)s, %(isOwner)s, %(pressure)s, %(temp_f)s, %(aqi)s, %(v)s, %(v1)s, %(v2)s, %(v3)s, %(v4)s, %(v5)s, %(v6)s ) """ channel2 = """ INSERT INTO air_quality(recorded_at, AGE, Hidden, ID, Label, LastSeen, Lat, Lon, PM2_5Value, ParentID, Stats, \ THINGSPEAK_PRIMARY_ID, THINGSPEAK_PRIMARY_ID_READ_KEY, THINGSPEAK_SECONDARY_ID, THINGSPEAK_SECONDARY_ID_READ_KEY, \ is_owner, aqi, current_pm_2_5, 10_min_avg, 30_min_avg, 60_min_avg, 6_hr_avg, 24_hr_avg, 1_wk_avg) VALUES( UNIX_TIMESTAMP(NOW()), %(AGE)s, %(Hidden)s, %(ID)s, %(Label)s, %(LastSeen)s, %(Lat)s, %(Lon)s, %(PM2_5Value)s, %(ParentID)s, %(Stats)s, %(THINGSPEAK_PRIMARY_ID)s, %(THINGSPEAK_PRIMARY_ID_READ_KEY)s, %(THINGSPEAK_SECONDARY_ID)s, %(THINGSPEAK_SECONDARY_ID_READ_KEY)s, %(isOwner)s, %(aqi)s, %(v)s, %(v1)s, %(v2)s, %(v3)s, %(v4)s, %(v5)s, %(v6)s ) """ for r in reading: try: stats = json.loads(r['Stats']) r['v'] = stats['v'] r['v1'] = stats['v1'] r['v2'] = stats['v2'] r['v3'] = stats['v3'] r['v4'] = stats['v4'] r['v5'] = stats['v5'] r['v6'] = stats['v6'] r['aqi']= aqi.to_iaqi(aqi.POLLUTANT_PM25, stats['v'], algo=aqi.ALGO_EPA) print(r['Label'], r['aqi']) # print(json.dumps(r, sort_keys=True, indent=4, separators=(',', ': '))) sql = channel2 if "ParentID" in r else channel1 try: cur.execute(sql, r) conn.commit() # print("Reading inserted") except Exception as e: print("Unable to insert reading") print(e) except Exception as e: print("Failed to insert readings") print(r) print(e)
def process_pm2(self, pm2): pm2['pm2_aqi'] = aqi.to_iaqi(aqi.POLLUTANT_PM25, pm2['pm25_standard']) pm2['pm100_aqi'] = aqi.to_iaqi(aqi.POLLUTANT_PM25, pm2['pm100_standard']) return pm2
# aqi library # https://media.readthedocs.org/pdf/python-aqi/latest/python-aqi.pdf # pip install python-aqi import serial # module to read data from sensor import time # time management import aqi # conversion to US, CN , AQI index t = serial.Serial('com8', 9600) # modify the serial #'/dev/ttyUSB0' #while True: for i in range(0, 10): t.flushInput() time.sleep(0.5) retstr = t.read(10) if (len(retstr) == 10): if (retstr[0] == 0xaa and retstr[1] == 0xc0): if sum(retstr[2:8] ) % 256 == retstr[8]: # check if error occur from check-sum pm25 = (int(retstr[2]) + int(retstr[3]) * 256) / 10 # in ug/m3 pm10 = (int(retstr[4]) + int(retstr[5]) * 256) / 10 # in ug/m3 aqi25_us = int( aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pm25), aqi.ALGO_EPA)) aqi25_cn = int( aqi.to_iaqi(aqi.POLLUTANT_PM25, str(pm25), aqi.ALGO_MEP)) print("pm2.5:%.1f AQI_US: %d AQI_CN: %d" % (pm25, aqi25_us, aqi25_cn))
# -*- coding: utf-8 -*- """ Created on Sun Feb 3 22:41:58 2019 @author: PeerapongE """ # # United States Environmental Protection Agency (EPA) --> aqi.ALGO_EPA # China Ministry of Environmental Protection (MEP) --> aqi.ALGO_MEP import aqi myaqi = int(aqi.to_iaqi(aqi.POLLUTANT_PM25, '12', aqi.ALGO_EPA)) print(myaqi)
def test_to_iaqi(self): """Test IAQI conversion""" self.assertEqual( aqi.to_iaqi(aqi.POLLUTANT_O3_8H, '0.08753333', algo=aqi.ALGO_EPA), 129)