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