Newer
Older
devtimer / devtimer.py
#!/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


from threading import Thread
from time import time, sleep
from tm1637 import *
from wiringpi import wiringPiSetupGpio

wiringPiSetupGpio()

#####
# Constants
#####

# Display

BRIGHTNESS = 0x09
CLK = 21
DIO = 20

# General Constants

DEBUG = True                  # Debugging switch

BEEP = 15                     # Beep interval
CALIBRATION_OFFSET = 0.0022   # Compensate for program overhead in master loop
NORMAL_TEMP = 68              # Reference temperature in degrees F


#####
# Lookup Table For Compensating Factors
#####

'''
  Each paper|film-developer combo has an entry here, expressed as:

    +- correction/degree

  68F is considered "normal".  Temperatures below this will cause the
  timer to run slower. Temperatures above it, will cause the timer to
  run faster.  This creates a "virtual second" that reflect time,
  material, and developer selected.

  WARNING: It takes about 250ms to update the display on a Pi Zero.
           So, if the "virtual second" falls at or below this, the
           code will be attempting to do updates faster than the
           display can handle. So the total amount of compensation
           cannot be smaller than about 0.300 to be on the safe side.
'''

compensate = (
               0.000,     # Normal
               0.010,     # Small temperature dependency
               0.040,     # Medium temperature dependency
               0.100,     # Large temperature dependency
             )

# Beep at the user at fixed intervals

def beep():
    print("Beep!")


# Return the current temperature in degrees F

def get_temp():
    return 72


# Update the display with elapsed time

def show_elapsed(display0, elapsed):

    min = elapsed // 60
    sec = elapsed % 60
    d0 = display0.digit_to_segment[min // 10]
    d1 = display0.digit_to_segment[min % 10]
    d2 = display0.digit_to_segment[sec // 10]
    d3 = display0.digit_to_segment[sec % 10]
    display0.set_segments([d0, 0x80 + d1, d2, d3])

# Program entry point

'''
  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.
'''

if __name__ == "__main__":

    display0 = TM1637(CLK, DIO, BRIGHTNESS)

    compensation_profile = 0
    elapsed_time = 0
    while True:

        # Beep periodically

        if elapsed_time and not elapsed_time%BEEP:
            beep()

        last = time()
        update_thread = Thread(None, show_elapsed, None, (display0, elapsed_time))
        sleep(1.000 + ((NORMAL_TEMP-get_temp()) * compensate[0]) - CALIBRATION_OFFSET)
        elapsed_time += 1
        elapsed_time %= 6000
        update_thread = Thread(None, show_elapsed, None, (display0, elapsed_time))

        if DEBUG:
            print("Inter-update Time: %s" % str(time()-last))

        update_thread.start()