commit
6fb103dd92
6 changed files with 83 additions and 7 deletions
|
@ -24,6 +24,14 @@ class Bme680Settings(BaseModel):
|
||||||
name: str = Field("Climate Sensor", description="The name of the sensor.")
|
name: str = Field("Climate Sensor", description="The name of the sensor.")
|
||||||
|
|
||||||
|
|
||||||
|
class Pms5003ModuleSettings(BaseModel):
|
||||||
|
enabled: bool = Field(True, description="If sensor should be enabled or not.")
|
||||||
|
device: str = Field("/dev/ttyUSB0", description="The TTY path of the sensor.")
|
||||||
|
baudrate: int = Field(9600, description="The baudrate of the serial port.")
|
||||||
|
pin_enable: str = Field("GPIO22", description="The pin enable.")
|
||||||
|
pin_reset: str = Field("GPIO27", description="The pin reset.")
|
||||||
|
|
||||||
|
|
||||||
class BridgeSettings(BaseModel):
|
class BridgeSettings(BaseModel):
|
||||||
display_name: str = Field(
|
display_name: str = Field(
|
||||||
"Bridge", description="The display name of the HAP bridge."
|
"Bridge", description="The display name of the HAP bridge."
|
||||||
|
@ -31,6 +39,7 @@ class BridgeSettings(BaseModel):
|
||||||
bme680: Bme680Settings = Field(
|
bme680: Bme680Settings = Field(
|
||||||
Bme680Settings(), description="Settings for the BME680 module."
|
Bme680Settings(), description="Settings for the BME680 module."
|
||||||
)
|
)
|
||||||
|
pms5003: Pms5003ModuleSettings = Field(Pms5003ModuleSettings(), description="Settings for the PMS5003 sensor.")
|
||||||
|
|
||||||
|
|
||||||
class HomekitAccessoryProtocolSettings(BaseModel):
|
class HomekitAccessoryProtocolSettings(BaseModel):
|
||||||
|
|
|
@ -8,6 +8,7 @@ from pyhap.accessory_driver import AccessoryDriver
|
||||||
|
|
||||||
from app.config import Settings
|
from app.config import Settings
|
||||||
from app.sensors.bme import Bme680Sensor
|
from app.sensors.bme import Bme680Sensor
|
||||||
|
from app.sensors.pms import Pms5003Sensor
|
||||||
|
|
||||||
|
|
||||||
def get_bridge(accessory_driver: AccessoryDriver, settings: Settings):
|
def get_bridge(accessory_driver: AccessoryDriver, settings: Settings):
|
||||||
|
@ -23,9 +24,13 @@ def get_bridge(accessory_driver: AccessoryDriver, settings: Settings):
|
||||||
if settings.hap.bridge.bme680.enabled:
|
if settings.hap.bridge.bme680.enabled:
|
||||||
bridge.add_accessory(
|
bridge.add_accessory(
|
||||||
Bme680Sensor(
|
Bme680Sensor(
|
||||||
accessory_driver, settings.hap.bridge.bme680.name, settings=settings
|
accessory_driver, settings=settings
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
if settings.hap.bridge.pms5003.enabled:
|
||||||
|
bridge.add_accessory(
|
||||||
|
Pms5003Sensor(accessory_driver, settings=settings)
|
||||||
|
)
|
||||||
return bridge
|
return bridge
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,5 +48,4 @@ if __name__ == "__main__":
|
||||||
)
|
)
|
||||||
driver.add_accessory(accessory=get_bridge(driver, settings))
|
driver.add_accessory(accessory=get_bridge(driver, settings))
|
||||||
signal.signal(signal.SIGTERM, driver.signal_handler)
|
signal.signal(signal.SIGTERM, driver.signal_handler)
|
||||||
signal.signal(signal.SIGINT, driver.signal_handler)
|
|
||||||
driver.start()
|
driver.start()
|
||||||
|
|
|
@ -15,12 +15,12 @@ class Bme680Sensor(Accessory):
|
||||||
|
|
||||||
category = CATEGORY_SENSOR # This is for the icon in the iOS Home app.
|
category = CATEGORY_SENSOR # This is for the icon in the iOS Home app.
|
||||||
|
|
||||||
def __init__(self, driver, display_name, *, aid=None, settings: Settings):
|
def __init__(self, driver, *, aid=None, settings: Settings):
|
||||||
"""Here, we just store a reference to the current temperature characteristic and
|
"""Here, we just store a reference to the current temperature characteristic and
|
||||||
add a method that will be executed every time its value changes.
|
add a method that will be executed every time its value changes.
|
||||||
"""
|
"""
|
||||||
# If overriding this method, be sure to call the super's implementation first.
|
# If overriding this method, be sure to call the super's implementation first.
|
||||||
super().__init__(driver, display_name, aid=aid)
|
super().__init__(driver, settings.hap.bridge.bme680.name, aid=aid)
|
||||||
|
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
self.sensor = bme680.BME680(
|
self.sensor = bme680.BME680(
|
||||||
|
|
56
app/sensors/pms.py
Normal file
56
app/sensors/pms.py
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from prometheus_client import Gauge
|
||||||
|
from pyhap.accessory import Accessory
|
||||||
|
from pyhap.const import CATEGORY_SENSOR
|
||||||
|
|
||||||
|
from app.config import Settings
|
||||||
|
from pms5003 import PMS5003
|
||||||
|
|
||||||
|
|
||||||
|
class Pms5003Sensor(Accessory):
|
||||||
|
category = CATEGORY_SENSOR
|
||||||
|
|
||||||
|
def __init__(self, driver, *, aid=None, settings: Settings):
|
||||||
|
super().__init__(driver, settings.hap.bridge.bme680.name, aid=aid)
|
||||||
|
|
||||||
|
self.settings = settings
|
||||||
|
self.sensor = PMS5003(
|
||||||
|
device=settings.hap.bridge.pms5003.device,
|
||||||
|
baudrate=settings.hap.bridge.pms5003.baudrate,
|
||||||
|
pin_enable=settings.hap.bridge.pms5003.pin_enable,
|
||||||
|
pin_reset=settings.hap.bridge.pms5003.pin_reset
|
||||||
|
)
|
||||||
|
|
||||||
|
self._pms5003_pm_ug_per_m3_1 = Gauge(
|
||||||
|
"pms5003_pm_ug_per_m3_1", "The PM1.0 ug/m3 (ultrafine particles)."
|
||||||
|
)
|
||||||
|
self._pms5003_pm_ug_per_m3_2 = Gauge(
|
||||||
|
"pms5003_pm_ug_per_m3_1", "PM2.5 ug/m3 (combustion particles, organic compounds, metals)."
|
||||||
|
)
|
||||||
|
self._pms5003_pm_ug_per_m3_10 = Gauge(
|
||||||
|
"pms5003_pm_ug_per_m3_1", "PM10 ug/m3 (dust, pollen, mould spores)"
|
||||||
|
)
|
||||||
|
|
||||||
|
@Accessory.run_at_interval(120)
|
||||||
|
def run(self):
|
||||||
|
"""
|
||||||
|
This function runs the accessory. It polls for data and updates prometheus metrics.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
data = self.sensor.read()
|
||||||
|
|
||||||
|
self._pms5003_pm_ug_per_m3_1.set(data.pm_ug_per_m3(1.0))
|
||||||
|
self._pms5003_pm_ug_per_m3_2.set(data.pm_ug_per_m3(2.5))
|
||||||
|
self._pms5003_pm_ug_per_m3_10.set(data.pm_ug_per_m3(10))
|
||||||
|
except IOError as e:
|
||||||
|
# This happens from time to time, best we stop and let systemd restart us.
|
||||||
|
logging.critical("Failed to read data from serial.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""We override this method to clean up any resources or perform final actions, as
|
||||||
|
this is called by the AccessoryDriver when the Accessory is being stopped.
|
||||||
|
"""
|
||||||
|
print("Stopping accessory.")
|
|
@ -3,10 +3,16 @@ prometheus:
|
||||||
port: 8000
|
port: 8000
|
||||||
hap:
|
hap:
|
||||||
port: 51826
|
port: 51826
|
||||||
persist_file: /home/denis/bme680-homekit/accessory.state
|
persist_file: accessory.state
|
||||||
bridge:
|
bridge:
|
||||||
display_name: Bridge
|
display_name: Bridge
|
||||||
bme680:
|
bme680:
|
||||||
enabled: yes
|
enabled: yes
|
||||||
address: 118 # Primary I2C Address
|
address: 118 # Primary I2C Address
|
||||||
name: "Climate Sensor"
|
name: "Climate Sensor"
|
||||||
|
pms5003:
|
||||||
|
enabled: yes
|
||||||
|
device: "/dev/ttyUSB0"
|
||||||
|
baudrate: 9600
|
||||||
|
pin_enable: "GPIO22"
|
||||||
|
pin_reset: "GPIO27"
|
|
@ -4,3 +4,4 @@ prometheus-client== 0.19.0
|
||||||
PyYAML==6.0.1
|
PyYAML==6.0.1
|
||||||
pydantic~=2.6.1
|
pydantic~=2.6.1
|
||||||
pydantic-settings==2.1.0
|
pydantic-settings==2.1.0
|
||||||
|
pms5003==1.0.0
|
Loading…
Reference in a new issue