#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Module managing temperature in an enclosed space via heater, turning relay on and off. Gets temperature from one wire sensor. Attempts to keep temperature between given min and max. Writes its own log as well as temperature data with timestamps to CSV file. """ import getpass import pigpio from math import isnan import logging import time from csv import writer __author__ = "Franek Ɓazarewicz-Muradyan" __licence__ = "GPL" __version__ = "0.0.1" __status__ = "Development" # One wire temperature sensor settings W1_SENSOR_ID = '28-0517c1b121ff' W1_SENSOR_F = f'/sys/devices/w1_bus_master1/{W1_SENSOR_ID}/w1_slave' # Heater settings HEATER_PIN = 5 # Other settings TIMEFORMAT = '%Y-%M-%d %H:%M:%S' TEMPERATURE_MIN = 20 TEMPERATURE_MAX = 24 # TEMPERATURE_MIN = 28 # TEMPERATURE_MAX = 32 USERNAME = getpass.getuser() LOGNAME = f'/var/log/{USERNAME}/shroombox.log' DATA_FILE = f'/var/log/{USERNAME}/shroombox.csv' pio = pigpio.pi() logging.basicConfig( filename=LOGNAME, encoding='utf-8', filemode='a', format='%(asctime)s,%(msecs)d %(name)s%(levelname)s %(message)s', datefmt='%H:%M:%S', level=logging.DEBUG, ) logging.info("Starting shroombox") logger = logging.getLogger() def read_temp_alt(retry=0) -> float: """ Function reading temperature. :param retry: int :return: float """ # If sensor is physically disconected, opening file will fail temperature = float('NaN') if retry > 3: return temperature try: with open(W1_SENSOR_F, 'r') as sensor: ok = sensor.readline()[-4:].strip('\n') if ok == 'YES': try: temperature = round(int(sensor.readline().split('=')[1])/1000, 1) except: return temperature else: retry+=1 read_temp_alt(retry=retry) except: return temperature return temperature def heater_on(temp, on=False) -> bool: """ Function turning heater on. :param temp: int :param on: bool :return: bool """ status = pio.read(HEATER_PIN) timestamp = time.strftime(TIMEFORMAT) # turning it off if not on: if status: retval = 0 else: try: pio.write(HEATER_PIN, 1) message = f"Turning off, temp: {temp}, {timestamp}" logger.info(message) retval = 0 except Exception as exc: logger.warning(exc) retval = 1 # turning it on else: if not status: retval = 0 else: try: pio.write(HEATER_PIN, 0) message = f"Turning on, temp: {temp}, {timestamp}" logger.info(message) retval = 0 except Exception as exc: logger.warning(exc) retval = 1 return retval def callback(): temp = read_temp_alt() # TODO: Add check ntp is running, else we may go back to the '70-ties timestamp = time.strftime(TIMEFORMAT) try: with open(DATA_FILE, 'a') as _file: wrtr = writer(_file) wrtr.writerow((timestamp, temp)) except OSError as exc: print(f"Error writing data to file: {exc}") print(temp) # TODO: Remove this line when done with testing. if temp <= TEMPERATURE_MIN: if temp < TEMPERATURE_MIN - 5: print(f"Temperature below minimum: {temp}. Heater not powerful enough?") logger.warning(f"Heater doesn't work, battery empty?") state = heater_on(temp, on=True) if state != 0: logger.warning(f"heater_on() method returned {state}, {timestamp}") elif temp >= TEMPERATURE_MAX: state = heater_on(temp, on=False) if state != 0: logger.warning(f"heater_on() method returned {state} {timestamp}") # Turn off in case can't get temperature reading: elif isnan(temp): state = heater_on(temp, on=False) if state != 0: logger.warning(f"heater_on() method returned {state} {timestamp}") logging.warning(f"Cannot read temperature, check your connections! {timestamp}") if __name__ == '__main__': while True: callback() time.sleep(30)