I did something very similar. I used Adafruit_DHT instead of pigpio. It simplifies the code slightly. I hadnât realized that the paho.mqtt had a client class. I switched my code over to using that. Not using it causes a TCP connect every time one sends a message (I suspect). I also have a PIR on my Pi that fires an event in my script. I like to keep the lights on when there is someone in the garage, at least after sunset.
I thought this was an interesting article that I thought I might implement: http://rawmeat.org/python-exponential-smoothing.html. I have heard that the DHT22 can be a little jumpy and this will smooth the numbers.
My script with temperature smoothing (and PIR which is irrelevant to the subject but might be interesting to someone). Some of the code didnât really appear to format as it was written. Anyway, the smoothing algorithm worked well.
#!/usr/bin/python
import sys
import signal
import time
import json
import Adafruit_DHT
import RPi.GPIO as GPIO
import paho.mqtt.client as mqtt
from datetime import datetime
print('Version 0.03')
sensorType = Adafruit_DHT.DHT22
sensorPin = 4 # Connected to DHT22
occupiedPin = 22 # LED turned on when motion is detected
unoccupiedPin = 17 # LED turned on when motion is not detected
motionPin = 12 # Connected to HC-SR501
mqttServer = "<server>"
mqttTopicPrefix = "State/Garage/{0}"
mqttTopicOccupied = "Occupied"
mqttTopicTemperature = "Temperature"
mqttTopicHumity = "Humidity"
mqttUserId = "<userid>"
mqttPassword = "<password>"
jsonMotion = '{{ "status": {{ "occupied": "{0}", "timestamp": {1} }}}}'; # JSON for motion
jsonHumidity = '{{ "status": {{ "humidity": {0:0.2f}, "timestamp": {1} }}}}'; # JSON for humidity
jsonTemperature = '{{ "status": {{ "temperature": {0:0.2f}, "timestamp": {1} }}}}'; # JSON for temperature
motionStates = [ "OPEN", "CLOSED" ]
mqttc = mqtt.Client()
def getTime():
# Save a few key strokes
return datetime.now().strftime('%H:%M:%S')
def signalHandler(signal, frame):
# Clean up on CTRL-C
print '\r\n' + getTime() + ': Exiting...'
mqttc.loop_stop()
mqttc.disconnect()
GPIO.cleanup()
sys.exit(0)
def mqttPublish(topic, msg):
# Publish to MQTT server
thisTopic = mqttTopicPrefix.format(topic)
mqttc.publish(thisTopic, msg)
def motionHandler(channel):
# Called when motion sensor state changes
motionValue = GPIO.input(motionPin)
print("motionValue={0}".format(motionValue))
if (motionValue):
GPIO.output(occupiedPin, GPIO.HIGH)
GPIO.output(unoccupiedPin, GPIO.LOW)
else:
GPIO.output(unoccupiedPin, GPIO.HIGH)
GPIO.output(occupiedPin, GPIO.LOW)
msg = jsonMotion.format(motionStates[motionValue], getTime())
mqttPublish(mqttTopicOccupied, msg)
def smoothTemps(period=10):
"""
Exponential moving average. Smooths the values over the period. Send
in values - at first it'll return a simple average, but as soon as it's
gathered 'period' values, it'll start to use the Exponential Moving
Averge to smooth the values.
period: int - how many values to smooth over (default=1000).
Gratitude to Rikard Anglerud - http://rawmeat.org/python-exponential-smoothing.html
"""
multiplier = 2 / float(1 + period)
cumulative_temp = yield None # We are being primed
# Start by just returning the simple average until we have enough data.
for i in xrange(1, period + 1):
cumulative_temp += yield cumulative_temp / float(i)
# Grab the simple average,
ema = cumulative_temp / period
# and start calculating the exponentially smoothed average we want.
while True:
ema = (((yield ema) - ema) * multiplier) + ema
def CtoF(value):
return value * 9 / 5.0 + 32
signal.signal(signal.SIGINT, signalHandler)
GPIO.setmode(GPIO.BCM)
GPIO.setup(occupiedPin, GPIO.OUT)
GPIO.setup(unoccupiedPin, GPIO.OUT)
GPIO.setup(motionPin, GPIO.IN)
GPIO.add_event_detect(motionPin, GPIO.BOTH, callback=motionHandler)
GPIO.output(unoccupiedPin, GPIO.HIGH)
GPIO.output(occupiedPin, GPIO.LOW)
time.sleep(2)
mqttc.username_pw_set(mqttUserId, mqttPassword)
mqttc.connect(mqttServer, 1883)
mqttc.loop_start()
# Initialize and prime the temperature value smoother
st = smoothTemps()
next(st)
while True:
humidity, temperature = Adafruit_DHT.read_retry(sensorType, sensorPin)
if humidity is not None and temperature is not None:
temperature = CtoF(st.send(temperature))
timestamp = getTime()
msg = jsonHumidity.format(humidity, timestamp)
print(msg)
mqttPublish(mqttTopicHumity, msg)
msg = jsonTemperature.format(temperature, timestamp)
print(msg)
mqttPublish(mqttTopicTemperature, msg)
else:
print(getTime() + ': Error - Failed to get reading')
time.sleep(60 * 10) # Every ten minutes
I will try ro build on weekend Leds under my bed with PIR which should turn on if it detects my feeds. The LEDs will be SK6812 with Warmwhite LED and RGB.
Hmm, I used LinkSprite based ESP8266 with a HC-SR501 motion sensor. I used that particular board because it has a +5v out which is required by that particular sensor. Unfortunately I found that it threw a lot of false positives and I ended up replacing it with a Raspberry Pi. Let me know if you have better success.
Glad you found the issue. Sometimes stuff gets messed up when pasted into this box I am currently typing in. By the way the smoothing value is way too high. It will average the temperatures out over about a week. I should edit that.
I modified the post to smooth over ten. Iâm at work so I donât actually remember what value I settled on. Do you have any feedback on a good value for this?