diff --git a/db18b20.py b/db18b20.py deleted file mode 100755 index 11f1b35..0000000 --- a/db18b20.py +++ /dev/null @@ -1,55 +0,0 @@ -from time import sleep, time -from devtimer import CURRENT_TEMP - -''' - This is based on the widely available DS18B20 temperature probe. - It is a 1-wire protocol device that returns temperature directly - degrees C. The dataline must go on the Pi GPIO 4 (pin 7) which - should be pulled up to VCC with a 4.7K resistor. - - You have to do several thingsto make this work: - - 1) Enable 1-wire support in the Pi: - - edit /boot/config.txt set: dtoverlay=w1-gpio - reboot - - 2) Each 1-wire device is connected to the same pin (7) - on the Pi. It distinguishes between them by a uniq - address. You have to find that address *for your specific - device*. You do this by looking at: - - ls -l /sys/bus/w1/devices - - You'll see the ID of your device there. That needs to - be set in the line below for this code to work with - your device. -''' - - - -DS18B20_ID = "28-0416840ac6ff" - - -# This function is called on it's own thread by __main__ -# so that it runs continuously in background. - -def read_temp_probe(): - - try: - probe = open("/sys/bus/w1/devices/%s/w1_slave" % DS18B20_ID) - while True: - probe.seek(0) # Ensure we are at beginning-of-file to read latest probe sample - temp = float(probe.readlines()[-1].split()[-1].split("=")[-1])/1000 # Parse probe output - CURRENT_TEMP = int(round((temp * 9/5) +32)) # Convert C-F and round into an integer - if DEBUG: - print(CURRENT_TEMP) - except: - pass - - finally: - probe.close() - -if __name__ == "__main__": - DEBUG = 1 - read_temp_probe() diff --git a/devtimer.py b/devtimer.py index fcb9cd4..a7afd09 100755 --- a/devtimer.py +++ b/devtimer.py @@ -1,23 +1,34 @@ #!/usr/bin/env python3 - # devtimer.py - Temperature Controlled Photographic Darkroom Timer # Targeted for RaspberryPi # Copyright (c) 2018 TundraWare Inc. # Permission Hereby Granted For Unrestricted Personal Or Commercial Use +##### +# Imports +##### + +# General Imports from threading import Thread from time import time, sleep + +# Hardware Support + +from ds18b20 import * from tm1637 import * from wiringpi import wiringPiSetupGpio +import globals + + ##### # Constants ##### # Display -BRIGHTNESS0 = 0x09 +BRIGHTNESS0 = 0x0a CLK0 = 21 DIO0 = 20 @@ -28,22 +39,6 @@ BEEP = 15 # Beep interval CALIBRATION_OFFSET = 0.003 # Compensate for program overhead in master loop -# Profile Constants - -REALTIME = 0 -PAPER = 1 -FILM = 2 - - -# Globals - -# These get updated by the threads that read the switches and -# thermocouple. On a slow machine like the Pi Zero, we want to avoid -# unnecessary function calls, so we make these globally RW. -# So, shoot me ... - -CURRENT_PROFILE = FILM -CURRENT_TEMP = 20 # Stored as index relative to 60F ##### # Lookup Table For Compensating Factors @@ -52,7 +47,7 @@ ''' There are 3 tables in the list below. In order: - Realtime + Realtime - never actually used, just there as a placeholder Paper Film @@ -102,11 +97,14 @@ ##### ''' + We start a perpetual thread to read the current temperature + and update the relevant global variable. + Notice that the actual updating of the display gets run on its own - thread. That's because - on a Pi Zero, at least - it takes over - 250ms to do this. We don't want that time added to our timing loop, - so we send it off on a parallel thread, and initiate timing for - the next round in this thread. + thread as well. That's because - on a Pi Zero, at least - it takes + over 250ms to do this. We don't want that time added to our timing + loop, so we send it off on a parallel thread, and initiate timing + for the next round in this thread. ''' if __name__ == "__main__": @@ -116,9 +114,16 @@ wiringPiSetupGpio() display0 = TM1637(CLK0, DIO0, BRIGHTNESS0) + # Start measuring temperature + + get_temps = Thread(name="Temperatures", target=read_temp_probe) + get_temps.start() + # Start timing, using the selected profile and measured temperature elapsed_time = 0 + compensation_factor = 1 + while True: # Beep periodically @@ -129,13 +134,29 @@ if DEBUG: last = time() - update_thread = Thread(None, show_elapsed, None, (display0, elapsed_time)) - sleep(compensate[CURRENT_PROFILE][CURRENT_TEMP] - CALIBRATION_OFFSET) + # Update the display on a separate thread + + update_thread = Thread(name="Timer", target=show_elapsed, args=(display0, elapsed_time)) + update_thread.start() + + # For temperatures in-range, look up the compensating factor + + current_temp = globals.CURRENT_TEMP + if (globals.CURRENT_PROFILE == globals.REALTIME): + compensation_factor = 1 # Realtime requires no compensation + + elif globals.TEMP_LOW <= globals.CURRENT_TEMP <= globals.TEMP_HIGH: + compensation_factor = compensate[globals.CURRENT_PROFILE][current_temp-globals.TEMP_LOW] + + # Temperature is out of range for our correction table + # This implictly uses the last known compensation factor so we can keep running + + else: + print("Display Out-Of-Range Message Here") + + sleep(compensation_factor - CALIBRATION_OFFSET) elapsed_time += 1 elapsed_time %= 6000 - update_thread = Thread(None, show_elapsed, None, (display0, elapsed_time)) if DEBUG: - print("Current Temp: %s Inter-update Time: %s" % (CURRENT_TEMP, str(time()-last))) - - update_thread.start() + print("Current Temp: %s Factor: %s Inter-update Time: %s" % (current_temp, compensation_factor, str(time()-last))) diff --git a/ds18b20.py b/ds18b20.py new file mode 100755 index 0000000..96188e5 --- /dev/null +++ b/ds18b20.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +from select import select +import sys +from time import sleep, time +import globals + + +''' + This is based on the widely available DS18B20 temperature probe. + It is a 1-wire protocol device that returns temperature directly + degrees C. The dataline must go on the Pi GPIO 4 (pin 7) which + should be pulled up to VCC with a 4.7K resistor. + + You have to do several thingsto make this work: + + 1) Enable 1-wire support in the Pi: + + edit /boot/config.txt set: dtoverlay=w1-gpio + reboot + + 2) Each 1-wire device is connected to the same pin (7) + on the Pi. It distinguishes between them by a uniq + address. You have to find that address *for your specific + device*. You do this by looking at: + + ls -l /sys/bus/w1/devices + + You'll see the ID of your device there. That needs to + be set in the line below for this code to work with + your device. +''' + + + +DS18B20_ID = "28-0416840ac6ff" + + +# This function is called on it's own thread by __main__ +# so that it runs continuously in background. + + +def read_temp_probe(): + + try: + probe = open("/sys/bus/w1/devices/%s/w1_slave" % DS18B20_ID) + while True: + probe.seek(0) # Ensure we are at beginning-of-file to read latest probe sample + temp = float(probe.readlines()[-1].split()[-1].split("=")[-1])/1000 # Parse probe output + globals.CURRENT_TEMP = int(round((temp * 9/5) +32)) # Convert C-F and round into an integer + + if DEBUG: + sys.stdout.write("Temp: %sF\n" % globals.CURRENT_TEMP) + + except: + pass + + finally: + probe.close() + f.close() + +# Run this from the command line + +if __name__ == "__main__": + DEBUG = 1 + read_temp_probe() diff --git a/globals.py b/globals.py new file mode 100644 index 0000000..2f16a46 --- /dev/null +++ b/globals.py @@ -0,0 +1,23 @@ +# Global Constants + +# Timing profiles + +REALTIME = 0 +PAPER = 1 +FILM = 2 + +# Range of compensated timing + +TEMP_LOW=60 +TEMP_HIGH=80 + +# Global Variables + + +# These get updated by the threads that read the switches and +# thermocouple. On a slow machine like the Pi Zero, we want to avoid +# unnecessary function calls, so we make these globally RW. +# So, shoot me ... + +CURRENT_PROFILE = REALTIME +CURRENT_TEMP = 68