add py aqi_monitor implementation

This commit is contained in:
simon 2022-10-21 16:03:47 +07:00
parent 16236da58f
commit d3255b7abd
Signed by: simon
GPG Key ID: 2C15AA5E89985DD4
8 changed files with 240 additions and 0 deletions

7
aqi_monitor_py/README.md Normal file
View File

@ -0,0 +1,7 @@
# Python Sensor Application
Updated script running on a RaspberryPi. Pure python implementation.
## Install libraries
```
pip install -r requirements.txt
```

View File

@ -0,0 +1,7 @@
ipython
simple-sds011
requests
RPi.bme280
cffi
smbus-cffi

View File

@ -0,0 +1,5 @@
{
"url": "https://www.example.com/api/aqi",
"username": "username",
"password": "password"
}

View File

@ -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()

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,9 @@
[Unit]
Description=sensor main.py
[Timer]
OnBootSec=1min
OnUnitActiveSec=3min
[Install]
WantedBy=multi-user.target