chickenhouse: add climate control
Signed-off-by: Thomas Klaehn <thomas.klaehn@u-blox.com>
This commit is contained in:
parent
35d1aa796c
commit
ef2582dfa7
@ -4,7 +4,7 @@ After=multi-user.target
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=idle
|
Type=idle
|
||||||
ExecStart=/usr/bin/python /usr/local/lib/python2.7/dist-packages/gate_guard/__init__.py
|
ExecStart=/usr/bin/python /usr/local/lib/python2.7/dist-packages/chickenhouse/__init__.py
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
31
chickenhouse/__init__.py
Normal file
31
chickenhouse/__init__.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
'''Created on Aug 30, 2018
|
||||||
|
@author: tkl
|
||||||
|
'''
|
||||||
|
|
||||||
|
import time
|
||||||
|
import sys
|
||||||
|
import logging
|
||||||
|
import gate_guard.gate
|
||||||
|
from climate_control import ClimateControl
|
||||||
|
|
||||||
|
LOGFILE = '/var/log/chickenhouse.log'
|
||||||
|
LOGLEVEL = logging.DEBUG
|
||||||
|
LOGFORMAT = '%(asctime)s %(message)s'
|
||||||
|
|
||||||
|
def main():
|
||||||
|
logging.basicConfig(filename=LOGFILE, level=LOGLEVEL, format=LOGFORMAT)
|
||||||
|
gate_state = gate_guard.gate.Gate()
|
||||||
|
climate_control = ClimateControl()
|
||||||
|
try:
|
||||||
|
climate_control.start()
|
||||||
|
while True:
|
||||||
|
gate_state.poll()
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
climate_control.stop()
|
||||||
|
print "key exit"
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
95
climate_control/__init__.py
Normal file
95
climate_control/__init__.py
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
'''
|
||||||
|
Created on Aug 30, 2018
|
||||||
|
|
||||||
|
@author: tkl
|
||||||
|
'''
|
||||||
|
import logging
|
||||||
|
import socket
|
||||||
|
import ssl
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import paho.mqtt.client as mqtt
|
||||||
|
from climate_control.sensors import Dht22
|
||||||
|
from climate_control.heat import Heat
|
||||||
|
|
||||||
|
MQTT_BROKER = "mqtt.blackfinn.de"
|
||||||
|
MQTT_PORT = 8883
|
||||||
|
MQTT_CERT = "/etc/ssl/certs/DST_Root_CA_X3.pem"
|
||||||
|
MQTT_TEMPERATURE_TOPIC = "outdoor/chickenhouse/temperature"
|
||||||
|
MQTT_HUMIDITY_TOPIC = "outdoor/chickenhouse/humidity"
|
||||||
|
MQTT_ROOM_HEAT_TOPIC = "outdoor/chickenhouse/heat/room"
|
||||||
|
MQTT_WATER_HEAT_TOPIC = "outdoor/chickenhouse/heat/water"
|
||||||
|
|
||||||
|
WATER_HEAT_THRESHOLD = {"on": 1.0, "off": 2.0}
|
||||||
|
ROOM_HEAT_THRESHOLD = {"on": 1.0, "off": 2.0}
|
||||||
|
|
||||||
|
STATE_OFF = "off"
|
||||||
|
STATE_ON = "ON"
|
||||||
|
|
||||||
|
class ClimateControl(threading.Thread):
|
||||||
|
__water_heat = Heat(20)
|
||||||
|
__room_heat = Heat(21)
|
||||||
|
__climate = Dht22(26)
|
||||||
|
__thread_condition = True
|
||||||
|
__now = time.time()
|
||||||
|
__interval = 15 * 60
|
||||||
|
__next = time.time()
|
||||||
|
__water_heat_state = STATE_OFF
|
||||||
|
__room_heat_state = STATE_OFF
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(ClimateControl, self).__init__()
|
||||||
|
|
||||||
|
def __check_switch_water_heat(self, temperature):
|
||||||
|
ret = False
|
||||||
|
if temperature >= WATER_HEAT_THRESHOLD["off"] and self.__water_heat_state == STATE_ON:
|
||||||
|
self.__water_heat.off()
|
||||||
|
self.__water_heat_state = STATE_OFF
|
||||||
|
ret = True
|
||||||
|
elif temperature <= WATER_HEAT_THRESHOLD["on"] and self.__water_heat_state == STATE_OFF:
|
||||||
|
self.__water_heat.on()
|
||||||
|
self.__water_heat_state = STATE_ON
|
||||||
|
ret = True
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def __check_switch_room_heat(self, temperature):
|
||||||
|
ret = False
|
||||||
|
if temperature >= ROOM_HEAT_THRESHOLD["off"] and self.__room_heat_state == STATE_ON:
|
||||||
|
self.__room_heat.off()
|
||||||
|
self.__room_heat_state = STATE_OFF
|
||||||
|
ret = True
|
||||||
|
elif temperature <= ROOM_HEAT_THRESHOLD["on"] and self.__room_heat_state == STATE_OFF:
|
||||||
|
self.__room_heat.on()
|
||||||
|
self.__room_heat_state = STATE_ON
|
||||||
|
ret = True
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while self.__thread_condition:
|
||||||
|
self.__now = time.time()
|
||||||
|
if self.__next <= self.__now:
|
||||||
|
humidity, temperature = self.__climate.read()
|
||||||
|
try:
|
||||||
|
client = mqtt.Client()
|
||||||
|
client.tls_set(MQTT_CERT)
|
||||||
|
client.connect(MQTT_BROKER, MQTT_PORT, 60)
|
||||||
|
client.loop_start()
|
||||||
|
msg = "{} {}".format(self.__now, temperature)
|
||||||
|
client.publish(MQTT_TEMPERATURE_TOPIC, msg, qos=2, retain=True)
|
||||||
|
msg = "{} {}".format(self.__now, humidity)
|
||||||
|
client.publish(MQTT_HUMIDITY_TOPIC, msg, qos=2, retain=True)
|
||||||
|
if self.__check_switch_water_heat(temperature):
|
||||||
|
msg = "{} {}".format(self.__now, self.__water_heat_state)
|
||||||
|
client.publish(MQTT_WATER_HEAT_TOPIC, msg, qos=2, retain=True)
|
||||||
|
if self.__check_switch_room_heat(temperature):
|
||||||
|
msg = "{} {}".format(self.__now, self.__room_heat_state)
|
||||||
|
client.publish(MQTT_ROOM_HEAT_TOPIC, msg, qos=2, retain=True)
|
||||||
|
client.loop_stop()
|
||||||
|
client.disconnect()
|
||||||
|
except(ValueError, TypeError, socket.error, ssl.CertificateError):
|
||||||
|
logging.info('unable to publish to mqtt')
|
||||||
|
self.__next = self.__now + self.__interval
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.__thread_condition = False
|
19
climate_control/heat.py
Normal file
19
climate_control/heat.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
try:
|
||||||
|
import gpio
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError("gpio not found.")
|
||||||
|
|
||||||
|
class Heat(object):
|
||||||
|
def __init__(self, pin):
|
||||||
|
self.pin = gpio.Gpio(pin)
|
||||||
|
|
||||||
|
self.pin.export()
|
||||||
|
self.pin.direction(gpio.Gpio.DIRECTION_OUT)
|
||||||
|
|
||||||
|
self.pin.write(0)
|
||||||
|
|
||||||
|
def on(self):
|
||||||
|
self.pin.write(1)
|
||||||
|
|
||||||
|
def off(self):
|
||||||
|
self.pin.write(0)
|
28
climate_control/sensors.py
Normal file
28
climate_control/sensors.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
'''Module for sensor implementations'''
|
||||||
|
try:
|
||||||
|
import Adafruit_DHT
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError('Adafruit_DHT library not found.')
|
||||||
|
|
||||||
|
def is_valid(temperature, humidity):
|
||||||
|
'''Check if temperature and humidity are valid.'''
|
||||||
|
return True if humidity <= 100.0 and humidity >= 0.0 and \
|
||||||
|
temperature <= 100.0 and temperature >= -50.0 else False
|
||||||
|
|
||||||
|
class Dht22(object):
|
||||||
|
'''DHT 22 temperature and Humidity sensor class.'''
|
||||||
|
sensor = 22
|
||||||
|
pin = int()
|
||||||
|
|
||||||
|
def __init__(self, pin):
|
||||||
|
self.pin = pin
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
'''Read temperature and humidity.'''
|
||||||
|
temperature = -200.0
|
||||||
|
humidity = -1.0
|
||||||
|
valid = False
|
||||||
|
while valid is False:
|
||||||
|
temperature, humidity = Adafruit_DHT.read_retry(self.sensor, self.pin)
|
||||||
|
valid = is_valid(temperature, humidity)
|
||||||
|
return temperature, humidity
|
@ -1,24 +0,0 @@
|
|||||||
'''
|
|
||||||
Created on Dec 19, 2016
|
|
||||||
|
|
||||||
@author: klaehn
|
|
||||||
'''
|
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
import logging
|
|
||||||
import gate_guard.gate
|
|
||||||
|
|
||||||
def main():
|
|
||||||
logging.basicConfig(filename='/var/log/gate_guard.log', level=logging.DEBUG, format='%(asctime)s %(message)s')
|
|
||||||
gate_state = gate_guard.gate.Gate()
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
gate_state.poll()
|
|
||||||
time.sleep(0.1)
|
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print "key exit"
|
|
||||||
return None
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
4
setup.py
4
setup.py
@ -6,11 +6,11 @@ import stat
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
NAME = 'chickenhouse'
|
NAME = 'chickenhouse'
|
||||||
VERSION = '1.0.0'
|
VERSION = '1.1.0'
|
||||||
AUTHOR = 'tkl'
|
AUTHOR = 'tkl'
|
||||||
EMAIL = 'tkl@blackfinn.de'
|
EMAIL = 'tkl@blackfinn.de'
|
||||||
URL = 'https://git.blackfinn.de/python/chickenhouse'
|
URL = 'https://git.blackfinn.de/python/chickenhouse'
|
||||||
PACKAGES = ['gate_guard']
|
PACKAGES = ['chickenhouse', 'climate_control', 'gate_guard']
|
||||||
SCRIPTS = ['chickenhouse.service']
|
SCRIPTS = ['chickenhouse.service']
|
||||||
|
|
||||||
if sys.argv[1] == 'install':
|
if sys.argv[1] == 'install':
|
||||||
|
Loading…
Reference in New Issue
Block a user