#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Module managing temperature in the shroombox. """ from os import getpid import pigpio from math import isnan import logging import time from simple_pid import PID __author__ = "Franek Ɓazarewicz-Muradyan" __licence__ = "GPL" __version__ = "0.0.1" __status__ = "Proof of concept" # ********************** # Hardware Settings # ********************** # 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 relay_pin = 5 mosfet_pin = 22 # ********************** # Software Settings # ********************** timeformat = '%Y-%M-%d %H:%M:%S' temperature_min = 20 temperature_max = 24 temperature_target = 20 read_retry = 3 logname = '/var/log/pipi/shroombox.log' data_file = '/var/log/pipi/shroombox.csv' # ********************** # PID Settings # ********************** Kp = 1 Ki = 0.2 Kd = 0 sample_time = 10 # ********************** # Code # ********************** 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( retry: int = 0, ) -> float: # If sensor is physically disconected, opening file will fail temperature = float('NaN') if retry > read_retry: return temperature 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 IndexError: # TODO: What other exceptions? return temperature else: retry += 1 read_temp(retry=retry) return temperature def heater_on( temp: float, on: bool = False, ) -> bool: status = pio.read(relay_pin) timestamp = time.strftime(timeformat) # turning it off if not on: if status == 1: return False else: try: pio.write(relay_pin, 1) message = f"Turning off, temp: {temp}, {timestamp}" logger.info(message) return False except: # TODO: documentation doesn't talk about exceptions on write return True # turning it on if on: if status == 0: return False else: try: pio.write(relay_pin, 0) message = f"Turning on, temp: {temp}, {timestamp}" logger.info(message) return False except: return True def temp_control( current_temperature: float ) -> int: pid = PID(Kp, Ki, Kd, setpoint=temperature_target) pid.output_limits = (0, 255) pid.sample_time = sample_time return pid(current_temperature) def main_alt(): temp = read_temp_alt() timestamp = time.strftime(timeformat) print(temp) with open(data_file, 'a') as dat: dat.write(temp) frequency = temp_control(temp) try: pio.set_PWM_frequency(mosfet_pin, frequency) except ( pio.PI_BAD_USER_GPIO, pio.PI_NOT_PERMITTED, ) as exc: logger.warning(f"Failed to set GPIO PWM frequency: {exc} {timestamp}") def main(): temp = read_temp() timestamp = time.strftime(timeformat) print(temp) if temp <= temperature_min: # if temp < temperature_min - 5: # print(f"Heater doesn't work, battery empty?") # logger.warning(f"Heater doesn't work, battery empty?") # state = heater_on(temp, on=False) 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}") elif isnan(temp): state = heater_on(temp, on=False) logging.warning(f"Cannot read temperature, check your connections! {timestamp}") if __name__ == '__main__': with open('/run/shroombox.pid', 'w') as f: f.write(str(getpid())) while True: pio = pigpio.pi() main() time.sleep(30)