temphum: support multiple temp/relhum sensors

This commit is contained in:
Evgeny Zinoviev 2022-04-29 16:41:59 +03:00
parent c412bf2ee0
commit e93ebaad0a
10 changed files with 122 additions and 26 deletions

View File

@ -10,7 +10,7 @@ endif
PROGRAMS = admin_bot inverter_bot pump_bot sensors_bot
PROGRAMS += inverter_mqtt_receiver inverter_mqtt_sender
PROGRAMS += sensors_mqtt_receiver sensors_mqtt_sender
PROGRAMS += si7021d
PROGRAMS += temphumd
PROGRAMS += gpiorelayd
PROGRAMS += gpiosensord
#PROGRAMS += web_api

View File

@ -0,0 +1,18 @@
from .base import SensorType, TempHumSensor
from .si7021 import Si7021
from .dht12 import DHT12
__all__ = [
'SensorType',
'TempHumSensor',
'create_sensor'
]
def create_sensor(type: SensorType, bus: int) -> TempHumSensor:
if type == SensorType.Si7021:
return Si7021(bus)
elif type == SensorType.DHT12:
return DHT12(bus)
else:
raise ValueError('unexpected sensor type')

25
src/home/temphum/base.py Normal file
View File

@ -0,0 +1,25 @@
import smbus
from abc import abstractmethod, ABC
from enum import Enum
class TempHumSensor:
@abstractmethod
def humidity(self) -> float:
pass
@abstractmethod
def temperature(self) -> float:
pass
class I2CTempHumSensor(TempHumSensor, ABC):
def __init__(self, bus: int):
super().__init__()
self.bus = smbus.SMBus(bus)
class SensorType(Enum):
Si7021 = 'si7021'
DHT12 = 'dht12'

22
src/home/temphum/dht12.py Normal file
View File

@ -0,0 +1,22 @@
from .base import I2CTempHumSensor
class DHT12(I2CTempHumSensor):
i2c_addr = 0x5C
def _measure(self):
raw = self.bus.read_i2c_block_data(self.i2c_addr, 0, 5)
if (raw[0] + raw[1] + raw[2] + raw[3]) & 0xff != raw[4]:
raise ValueError("checksum error")
return raw
def temperature(self) -> float:
raw = self._measure()
temp = raw[2] + (raw[3] & 0x7f) * 0.1
if raw[3] & 0x80:
temp *= -1
return temp
def humidity(self) -> float:
raw = self._measure()
return raw[0] + raw[1] * 0.1

View File

@ -0,0 +1,13 @@
from .base import I2CTempHumSensor
class Si7021(I2CTempHumSensor):
i2c_addr = 0x40
def temperature(self) -> float:
raw = self.bus.read_i2c_block_data(self.i2c_addr, 0xE3, 2)
return 175.72 * (raw[0] << 8 | raw[1]) / 65536.0 - 46.85
def humidity(self) -> float:
raw = self.bus.read_i2c_block_data(self.i2c_addr, 0xE5, 2)
return 125.0 * (raw[0] << 8 | raw[1]) / 65536.0 - 6.0

19
src/temphum.py Normal file
View File

@ -0,0 +1,19 @@
from argparse import ArgumentParser
from home.temphum import SensorType, create_sensor
if __name__ == '__main__':
parser = ArgumentParser()
parser.add_argument('-t', '--type', choices=[item.value for item in SensorType],
required=True,
help='Sensor type')
parser.add_argument('-b', '--bus', type=int, default=0,
help='I2C bus number')
arg = parser.parse_args()
sensor = create_sensor(SensorType(arg.type), arg.bus)
temp = sensor.temperature()
hum = sensor.humidity()
print(f'temperature: {temp}')
print(f'rel. humidity: {hum}')

View File

@ -1,29 +1,26 @@
#!/usr/bin/env python3
import smbus
import argparse
import asyncio
import json
import logging
from typing import Optional
from home.config import config
from home.util import parse_addr
from home.temphum import SensorType, create_sensor, TempHumSensor
logger = logging.getLogger(__name__)
bus = None
sensor: Optional[TempHumSensor] = None
lock = asyncio.Lock()
delay = 0.01
async def si7021_read():
async def get_measurements():
async with lock:
await asyncio.sleep(delay)
# these are still blocking... meh
raw = bus.read_i2c_block_data(0x40, 0xE3, 2)
temp = 175.72 * (raw[0] << 8 | raw[1]) / 65536.0 - 46.85
raw = bus.read_i2c_block_data(0x40, 0xE5, 2)
rh = 125.0 * (raw[0] << 8 | raw[1]) / 65536.0 - 6.0
temp = sensor.temperature()
rh = sensor.humidity()
return rh, temp
@ -41,7 +38,7 @@ async def handle_client(reader, writer):
if request == 'read':
try:
rh, temp = await asyncio.wait_for(si7021_read(), timeout=3)
rh, temp = await asyncio.wait_for(get_measurements(), timeout=3)
data = dict(humidity=rh, temp=temp)
except asyncio.TimeoutError as e:
logger.exception(e)
@ -68,12 +65,14 @@ async def run_server(host, port):
if __name__ == '__main__':
config.load()
host, port = parse_addr(config['server']['listen'])
if 'measure_delay' in config['sensor']:
delay = float(config['sensor']['measure_delay'])
delay = float(config['smbus']['delay'])
bus = smbus.SMBus(int(config['smbus']['bus']))
sensor = create_sensor(SensorType(config['sensor']['type']),
int(config['sensor']['bus']))
try:
host, port = parse_addr(config['server']['listen'])
asyncio.run(run_server(host, port))
except KeyboardInterrupt:
logging.info('Exiting...')

View File

@ -1,6 +1,6 @@
[Unit]
Description=Sensors MQTT sender
After=si7021d.service
After=temphumd.service
[Service]
User=user

View File

@ -1,10 +0,0 @@
[Unit]
Description=si7021 daemon
After=network-online.target
[Service]
Restart=on-failure
ExecStart=/home/user/homekit/src/si7021d.py --config /etc/si7021d.toml
[Install]
WantedBy=multi-user.target

10
systemd/temphumd.service Normal file
View File

@ -0,0 +1,10 @@
[Unit]
Description=temperature and humidity daemon
After=network-online.target
[Service]
Restart=on-failure
ExecStart=/home/user/homekit/src/temphumd.py --config /etc/temphumd.toml
[Install]
WantedBy=multi-user.target