add py aqi_monitor implementation
This commit is contained in:
parent
16236da58f
commit
d3255b7abd
|
@ -0,0 +1,7 @@
|
||||||
|
# Python Sensor Application
|
||||||
|
Updated script running on a RaspberryPi. Pure python implementation.
|
||||||
|
|
||||||
|
## Install libraries
|
||||||
|
```
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
|
@ -0,0 +1,7 @@
|
||||||
|
ipython
|
||||||
|
simple-sds011
|
||||||
|
requests
|
||||||
|
RPi.bme280
|
||||||
|
|
||||||
|
cffi
|
||||||
|
smbus-cffi
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"url": "https://www.example.com/api/aqi",
|
||||||
|
"username": "username",
|
||||||
|
"password": "password"
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
"""entry point to collect data from sensors"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from sensor_sds011 import SDS
|
||||||
|
from sensor_bme280 import BmeSensor
|
||||||
|
|
||||||
|
|
||||||
|
class PiSensor:
|
||||||
|
"""collect and send data"""
|
||||||
|
|
||||||
|
SENSOR_ID = 1
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.data = False
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
"""get all data from sensors"""
|
||||||
|
self.data = {}
|
||||||
|
self.get_sds011()
|
||||||
|
self.get_bme()
|
||||||
|
self.add_static()
|
||||||
|
|
||||||
|
def get_sds011(self):
|
||||||
|
"""get data dict from sds011"""
|
||||||
|
sds_data = SDS().collect()
|
||||||
|
self.data.update(sds_data)
|
||||||
|
|
||||||
|
def get_bme(self):
|
||||||
|
"""get data dict from bme"""
|
||||||
|
bme_data = BmeSensor().collect()
|
||||||
|
self.data.update(bme_data)
|
||||||
|
|
||||||
|
def add_static(self):
|
||||||
|
"""add static values to data"""
|
||||||
|
self.data.update(
|
||||||
|
{
|
||||||
|
"sensor_id": self.SENSOR_ID,
|
||||||
|
"uptime": self.get_uptime(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_uptime():
|
||||||
|
"""read uptime"""
|
||||||
|
with open("/proc/uptime", "r", encoding="utf-8") as f:
|
||||||
|
uptime_seconds = float(f.readline().split()[0])
|
||||||
|
|
||||||
|
return uptime_seconds
|
||||||
|
|
||||||
|
def send_data(self):
|
||||||
|
"""post data to api endpoint"""
|
||||||
|
config = self.read_config()
|
||||||
|
auth = (config["username"], config["password"])
|
||||||
|
response = requests.post(config["url"], json=self.data, auth=auth)
|
||||||
|
if not response.ok:
|
||||||
|
print(response.text)
|
||||||
|
|
||||||
|
def read_config(self):
|
||||||
|
"""read config file"""
|
||||||
|
# build path
|
||||||
|
root_folder = path.dirname(sys.argv[0])
|
||||||
|
if root_folder == '/sbin':
|
||||||
|
# running interactive
|
||||||
|
config_path = 'config.json'
|
||||||
|
else:
|
||||||
|
config_path = path.join(root_folder, 'config.json')
|
||||||
|
|
||||||
|
with open(config_path, "r", encoding="utf-8") as f:
|
||||||
|
config = json.loads(f.read())
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sensor = PiSensor()
|
||||||
|
sensor.get_data()
|
||||||
|
print(sensor.data)
|
||||||
|
sensor.send_data()
|
|
@ -0,0 +1,40 @@
|
||||||
|
"""interact with temperature sensor"""
|
||||||
|
# pylint: disable=import-error
|
||||||
|
|
||||||
|
import smbus2
|
||||||
|
import bme280
|
||||||
|
|
||||||
|
|
||||||
|
class BmeSensor:
|
||||||
|
"""interact with BME280 sensor on pi"""
|
||||||
|
|
||||||
|
PORT = 1
|
||||||
|
ADDRESS = 0x76
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.data = False
|
||||||
|
|
||||||
|
def collect(self):
|
||||||
|
"""collect"""
|
||||||
|
print("collect data from bme280")
|
||||||
|
self.get_data()
|
||||||
|
temperature_values = self.format_data()
|
||||||
|
print(f"bme280 data: {temperature_values}")
|
||||||
|
|
||||||
|
return temperature_values
|
||||||
|
|
||||||
|
def get_data(self):
|
||||||
|
"""read data from sensor"""
|
||||||
|
bus = smbus2.SMBus(self.PORT)
|
||||||
|
calibration_params = bme280.load_calibration_params(bus, self.ADDRESS)
|
||||||
|
self.data = bme280.sample(bus, self.ADDRESS, calibration_params)
|
||||||
|
|
||||||
|
def format_data(self):
|
||||||
|
"""build dict to send"""
|
||||||
|
temperature_values = {
|
||||||
|
"temperature": round(self.data.temperature, 2),
|
||||||
|
"pressure": round(self.data.pressure),
|
||||||
|
"humidity": round(self.data.humidity, 2),
|
||||||
|
}
|
||||||
|
|
||||||
|
return temperature_values
|
|
@ -0,0 +1,80 @@
|
||||||
|
"""interact with aqi and environment sensors on pi4"""
|
||||||
|
import os
|
||||||
|
from time import sleep
|
||||||
|
import simple_sds011 # pylint: disable=import-error
|
||||||
|
|
||||||
|
|
||||||
|
class SDS:
|
||||||
|
"""collect data from sds011 sensor"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.port = self.get_port()
|
||||||
|
self.pm = simple_sds011.SDS011(self.port)
|
||||||
|
|
||||||
|
def collect(self):
|
||||||
|
"""collect average values"""
|
||||||
|
print("start collect")
|
||||||
|
self.startup()
|
||||||
|
pm_values = self.query_sensor()
|
||||||
|
self.shutdown()
|
||||||
|
print(f"pm_values: {pm_values}")
|
||||||
|
print("finish collect")
|
||||||
|
|
||||||
|
return pm_values
|
||||||
|
|
||||||
|
def get_port(self):
|
||||||
|
"""find tty port for sds sensor"""
|
||||||
|
print("find usb port")
|
||||||
|
usbs = [i for i in os.listdir("/dev/") if i.startswith("ttyUSB")]
|
||||||
|
if len(usbs) > 1:
|
||||||
|
raise ValueError(f"too many ttyUSBs found: {usbs}")
|
||||||
|
|
||||||
|
port = f"/dev/{usbs[0]}"
|
||||||
|
|
||||||
|
return port
|
||||||
|
|
||||||
|
def startup(self):
|
||||||
|
"""activate and set mode"""
|
||||||
|
print("startup sensor")
|
||||||
|
self.pm.active = 1
|
||||||
|
sleep(0.5)
|
||||||
|
self.pm.mode = simple_sds011.MODE_PASSIVE
|
||||||
|
print("warm up")
|
||||||
|
sleep(20)
|
||||||
|
|
||||||
|
def query_sensor(self):
|
||||||
|
"""query 15 times"""
|
||||||
|
print("collect samples")
|
||||||
|
pm25_sample = []
|
||||||
|
pm10_sample = []
|
||||||
|
|
||||||
|
for _ in range(15):
|
||||||
|
response = self.pm.query()
|
||||||
|
pm25, pm10 = response.get("value").values()
|
||||||
|
|
||||||
|
pm25_sample.append(pm25)
|
||||||
|
pm10_sample.append(pm10)
|
||||||
|
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
print(pm25_sample)
|
||||||
|
print(pm10_sample)
|
||||||
|
pm25_avg = self.avg(pm25_sample)
|
||||||
|
pm10_avg = self.avg(pm10_sample)
|
||||||
|
|
||||||
|
pm_values = {
|
||||||
|
"pm25": pm25_avg,
|
||||||
|
"pm10": pm10_avg
|
||||||
|
}
|
||||||
|
|
||||||
|
return pm_values
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
"""deactivate"""
|
||||||
|
print("shutdown sensor")
|
||||||
|
self.pm.active = 0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def avg(lst):
|
||||||
|
"""calc average of list"""
|
||||||
|
return round(sum(lst) / len(lst), 1)
|
|
@ -0,0 +1,8 @@
|
||||||
|
[Unit]
|
||||||
|
Description=sensor main.py
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=simon
|
||||||
|
Group=simon
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=python /home/simon/aqi_monitor/aqi_monitor_py/sensor/main.py
|
|
@ -0,0 +1,9 @@
|
||||||
|
[Unit]
|
||||||
|
Description=sensor main.py
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=1min
|
||||||
|
OnUnitActiveSec=3min
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
Loading…
Reference in New Issue