Add the configuration and python files to the repo

This commit is contained in:
Charles Descamps 2025-11-16 15:26:29 -07:00
parent 6868e441fb
commit f9e3679da9
4 changed files with 548 additions and 0 deletions

189
config.py Normal file
View file

@ -0,0 +1,189 @@
import logging
import os
# uncomment this if using MAX-31856
#from lib.max31856 import MAX31856
########################################################################
#
# General options
### Logging
log_level = logging.INFO
log_format = '%(asctime)s %(levelname)s %(name)s: %(message)s'
### Server
listening_port = 8081
########################################################################
# Cost Information
#
# This is used to calculate a cost estimate before a run. It's also used
# to produce the actual cost during a run. My kiln has three
# elements that when my switches are set to high, consume 9460 watts.
kwh_rate = 0.1787 # cost per kilowatt hour per currency_type to calculate cost to run job
kw_elements = 4.60 # if the kiln elements are on, the wattage in kilowatts
currency_type = "$" # Currency Symbol to show when calculating cost to run job
########################################################################
#
# GPIO Setup (BCM SoC Numbering Schema)
#
# Check the RasPi docs to see where these GPIOs are
# connected on the P1 header for your board type/rev.
# These were tested on a Pi B Rev2 but of course you
# can use whichever GPIO you prefer/have available.
### Outputs
gpio_heat = 23 # Switches zero-cross solid-state-relay
### Thermocouple Adapter selection:
# max31855 - bitbang SPI interface
# max31856 - bitbang SPI interface. must specify thermocouple_type.
max31855 = 1
max31856 = 0
# see lib/max31856.py for other thermocouple_type, only applies to max31856
# uncomment this if using MAX-31856
#thermocouple_type = MAX31856.MAX31856_S_TYPE
### Thermocouple Connection (using bitbang interfaces)
gpio_sensor_cs = 27
gpio_sensor_clock = 22
gpio_sensor_data = 17
gpio_sensor_di = 10 # only used with max31856
########################################################################
#
# duty cycle of the entire system in seconds
#
# Every N seconds a decision is made about switching the relay[s]
# on & off and for how long. The thermocouple is read
# temperature_average_samples times during and the average value is used.
sensor_time_wait = 2
########################################################################
#
# PID parameters
#
# These parameters control kiln temperature change. These settings work
# well with the simulated oven. You must tune them to work well with
# your specific kiln. Note that the integral pid_ki is
# inverted so that a smaller number means more integral action.
pid_kp = 25 # Proportional 25,200,200
pid_ki = 10 # Integral
pid_kd = 200 # Derivative
########################################################################
#
# Initial heating and Integral Windup
#
# this setting is deprecated and is no longer used. this happens by
# default and is the expected behavior.
stop_integral_windup = True
########################################################################
#
# Simulation parameters
simulate = False
sim_t_env = 60.0 # deg C
sim_c_heat = 500.0 # J/K heat capacity of heat element
sim_c_oven = 5000.0 # J/K heat capacity of oven
sim_p_heat = 5450.0 # W heating power of oven
sim_R_o_nocool = 0.5 # K/W thermal resistance oven -> environment
sim_R_o_cool = 0.05 # K/W " with cooling
sim_R_ho_noair = 0.1 # K/W thermal resistance heat element -> oven
sim_R_ho_air = 0.05 # K/W " with internal air circulation
########################################################################
#
# Time and Temperature parameters
#
# If you change the temp_scale, all settings in this file are assumed to
# be in that scale.
temp_scale = "f" # c = Celsius | f = Fahrenheit - Unit to display
time_scale_slope = "h" # s = Seconds | m = Minutes | h = Hours - Slope displayed in temp_scale per time_scale_slope
time_scale_profile = "m" # s = Seconds | m = Minutes | h = Hours - Enter and view target time in time_scale_profile
# emergency shutoff the profile if this temp is reached or exceeded.
# This just shuts off the profile. If your SSR is working, your kiln will
# naturally cool off. If your SSR has failed/shorted/closed circuit, this
# means your kiln receives full power until your house burns down.
# this should not replace you watching your kiln or use of a kiln-sitter
emergency_shutoff_temp = 2264 #cone 7
# If the current temperature is outside the pid control window,
# delay the schedule until it does back inside. This allows for heating
# and cooling as fast as possible and not continuing until temp is reached.
kiln_must_catch_up = True
# This setting is required.
# This setting defines the window within which PID control occurs.
# Outside this window (N degrees below or above the current target)
# the elements are either 100% on because the kiln is too cold
# or 100% off because the kiln is too hot. No integral builds up
# outside the window. The bigger you make the window, the more
# integral you will accumulate. This should be a positive integer.
pid_control_window = 5 #degrees
# thermocouple offset
# If you put your thermocouple in ice water and it reads 36F, you can
# set set this offset to -4 to compensate. This probably means you have a
# cheap thermocouple. Invest in a better thermocouple.
thermocouple_offset=0
# number of samples of temperature to average.
# If you suffer from the high temperature kiln issue and have set
# honour_theromocouple_short_errors to False,
# you will likely need to increase this (eg I use 40)
temperature_average_samples = 40
# Thermocouple AC frequency filtering - set to True if in a 50Hz locale, else leave at False for 60Hz locale
ac_freq_50hz = False
########################################################################
# Emergencies - or maybe not
########################################################################
# There are all kinds of emergencies that can happen including:
# - temperature is too high (emergency_shutoff_temp exceeded)
# - lost connection to thermocouple
# - unknown error with thermocouple
# - too many errors in a short period from thermocouple
# but in some cases, you might want to ignore a specific error, log it,
# and continue running your profile.
ignore_temp_too_high = False
ignore_lost_connection_tc = False
ignore_unknown_tc_error = False
ignore_too_many_tc_errors = False
# some kilns/thermocouples start erroneously reporting "short"
# errors at higher temperatures due to plasma forming in the kiln.
# Set this to True to ignore these errors and assume the temperature
# reading was correct anyway
ignore_tc_short_errors = False
########################################################################
# automatic restarts - if you have a power brown-out and the raspberry pi
# reboots, this restarts your kiln where it left off in the firing profile.
# This only happens if power comes back before automatic_restart_window
# is exceeded (in minutes). The kiln-controller.py process must start
# automatically on boot-up for this to work.
# DO NOT put automatic_restart_state_file anywhere in /tmp. It could be
# cleaned up (deleted) by the OS on boot.
# The state file is written to disk every sensor_time_wait seconds (2s by default)
# and is written in the same directory as config.py.
automatic_restarts = True
automatic_restart_window = 15 # max minutes since power outage
automatic_restart_state_file = os.path.abspath(os.path.join(os.path.dirname( __file__ ),'state.json'))
########################################################################
# load kiln profiles from this directory
# created a repo where anyone can contribute profiles. The objective is
# to load profiles from this repository by default.
# See https://github.com/jbruce12000/kiln-profiles
kiln_profiles_directory = os.path.abspath(os.path.join(os.path.dirname( __file__ ),"storage", "profiles"))
#kiln_profiles_directory = os.path.abspath(os.path.join(os.path.dirname( __file__ ),'..','kiln-profiles','pottery'))

117
sevensegment_demo.py Normal file
View file

@ -0,0 +1,117 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2017-18 Richard Hull and contributors
# See LICENSE.rst for details.
"""
Example for seven segment displays.
"""
import time
from datetime import datetime
from luma.led_matrix.device import max7219
from luma.core.interface.serial import spi, noop
from luma.core.virtual import viewport, sevensegment
def date(seg):
"""
Display current date on device.
"""
now = datetime.now()
seg.text = now.strftime("%y-%m-%d")
def clock(seg, seconds):
"""
Display current time on device.
"""
interval = 0.5
for i in range(int(seconds / interval)):
now = datetime.now()
seg.text = now.strftime("%H-%M-%S")
# calculate blinking dot
if i % 2 == 0:
seg.text = now.strftime("%H-%M-%S")
else:
seg.text = now.strftime("%H %M %S")
time.sleep(interval)
def show_message_vp(device, msg, delay=0.1):
# Implemented with virtual viewport
width = device.width
padding = " " * width
msg = padding + msg + padding
n = len(msg)
virtual = viewport(device, width=n, height=8)
sevensegment(virtual).text = msg
for i in reversed(list(range(n - width))):
virtual.set_position((i, 0))
time.sleep(delay)
def show_message_alt(seg, msg, delay=0.1):
# Does same as above but does string slicing itself
width = seg.device.width
padding = " " * width
msg = padding + msg + padding
for i in range(len(msg)):
seg.text = msg[i:i + width]
time.sleep(delay)
def main():
# create seven segment device
serial = spi(port=0, device=0, gpio=noop())
device = max7219(serial, cascaded=1)
seg = sevensegment(device)
print('Simple text...')
for _ in range(8):
seg.text = "HELLO"
time.sleep(0.6)
seg.text = " GOODBYE"
time.sleep(0.6)
# Digit slicing
print("Digit slicing")
seg.text = "_" * seg.device.width
time.sleep(1.0)
for i, ch in enumerate([9, 8, 7, 6, 5, 4, 3, 2]):
seg.text[i] = str(ch)
time.sleep(0.6)
for i in range(len(seg.text)):
del seg.text[0]
time.sleep(0.6)
# Scrolling Alphabet Text
print('Scrolling alphabet text...')
show_message_vp(device, "HELLO EVERYONE!")
show_message_vp(device, "PI is 3.14159 ... ")
show_message_vp(device, "IP is 127.0.0.1 ... ")
show_message_alt(seg, "0123456789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ")
# Digit futzing
date(seg)
time.sleep(5)
clock(seg, seconds=10)
# Brightness
print('Brightness...')
for x in range(5):
for intensity in range(16):
seg.device.contrast(intensity * 16)
time.sleep(0.1)
device.contrast(0x7F)
if __name__ == '__main__':
main()

124
temp_kiln.py Normal file
View file

@ -0,0 +1,124 @@
#!/usr/bin/env python
"""
Message to inform the project manager this was done wrong.
"""
import time
from datetime import datetime
from luma.led_matrix.device import max7219
from luma.core.interface.serial import spi, noop
from luma.core.virtual import viewport, sevensegment
import requests, json
def date(seg):
"""
Display current date on device.
"""
now = datetime.now()
seg.text = now.strftime("%y-%m-%d")
def clock(seg, seconds):
"""
Display current time on device.
"""
interval = 0.5
for i in range(int(seconds / interval)):
now = datetime.now()
seg.text = now.strftime("%H-%M-%S")
# calculate blinking dot
if i % 2 == 0:
seg.text = now.strftime("%H-%M-%S")
else:
seg.text = now.strftime("%H %M %S")
time.sleep(interval)
def show_message_vp(device, msg, delay=0.1):
# Implemented with virtual viewport
width = device.width
padding = " " * width
msg = padding + msg + padding
n = len(msg)
virtual = viewport(device, width=n, height=8)
sevensegment(virtual).text = msg
for i in reversed(list(range(n - width))):
virtual.set_position((i, 0))
time.sleep(delay)
def show_message_alt(seg, msg, delay=0.1):
# Does same as above but does string slicing itself
width = seg.device.width
padding = " " * width
msg = padding + msg + padding
for i in range(len(msg)):
seg.text = msg[i:i + width]
time.sleep(delay)
def main():
# create seven segment device
serial = spi(port=0, device=0, gpio=noop())
device = max7219(serial, cascaded=1)
seg = sevensegment(device)
#print('Simple text...')
#for _ in range(8):
# seg.text = "HELLO"
# time.sleep(0.6)
# seg.text = " GOODBYE"
# time.sleep(0.6)
# Digit slicing
#print("Digit slicing")
#seg.text = "_" * seg.device.width
#time.sleep(1.0)
#for i, ch in enumerate([9, 8, 7, 6, 5, 4, 3, 2]):
# seg.text[i] = str(ch)
# time.sleep(0.6)
#for i in range(len(seg.text)):
# del seg.text[0]
# time.sleep(0.6)
# Scrolling Alphabet Text
#print('Scrolling alphabet text...')
#show_message_vp(device, "HELLO EVERYONE!")
#show_message_vp(device, "PI is 3.14159 ... ")
#show_message_vp(device, "IP is 127.0.0.1 ... ")
#show_message_alt(seg, "0123456789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ")
# Inform the manager that this was wired wrong.
while True:
# use the kiln api at /api/stats
req = requests.get('http://127.0.0.1:8081/api/stats')
# get the temp from the req
temp = round(req.json()['ispoint'])
#show_message_vp(device, f"TEMP: {temp}")
seg.text = f"TEMP{temp}"
time.sleep(1)
# Digit futzing
#date(seg)
#time.sleep(5)
#clock(seg, seconds=10)
# Brightness
#print('Brightness...')
#for x in range(5):
# for intensity in range(16):
# seg.device.contrast(intensity * 16)
# time.sleep(0.1)
#device.contrast(0x7F)
if __name__ == '__main__':
main()

118
wired_wrong.py Normal file
View file

@ -0,0 +1,118 @@
#!/usr/bin/env python
"""
Message to inform the project manager this was done wrong.
"""
import time
from datetime import datetime
from luma.led_matrix.device import max7219
from luma.core.interface.serial import spi, noop
from luma.core.virtual import viewport, sevensegment
def date(seg):
"""
Display current date on device.
"""
now = datetime.now()
seg.text = now.strftime("%y-%m-%d")
def clock(seg, seconds):
"""
Display current time on device.
"""
interval = 0.5
for i in range(int(seconds / interval)):
now = datetime.now()
seg.text = now.strftime("%H-%M-%S")
# calculate blinking dot
if i % 2 == 0:
seg.text = now.strftime("%H-%M-%S")
else:
seg.text = now.strftime("%H %M %S")
time.sleep(interval)
def show_message_vp(device, msg, delay=0.1):
# Implemented with virtual viewport
width = device.width
padding = " " * width
msg = padding + msg + padding
n = len(msg)
virtual = viewport(device, width=n, height=8)
sevensegment(virtual).text = msg
for i in reversed(list(range(n - width))):
virtual.set_position((i, 0))
time.sleep(delay)
def show_message_alt(seg, msg, delay=0.1):
# Does same as above but does string slicing itself
width = seg.device.width
padding = " " * width
msg = padding + msg + padding
for i in range(len(msg)):
seg.text = msg[i:i + width]
time.sleep(delay)
def main():
# create seven segment device
serial = spi(port=0, device=0, gpio=noop())
device = max7219(serial, cascaded=1)
seg = sevensegment(device)
#print('Simple text...')
#for _ in range(8):
# seg.text = "HELLO"
# time.sleep(0.6)
# seg.text = " GOODBYE"
# time.sleep(0.6)
# Digit slicing
#print("Digit slicing")
#seg.text = "_" * seg.device.width
#time.sleep(1.0)
#for i, ch in enumerate([9, 8, 7, 6, 5, 4, 3, 2]):
# seg.text[i] = str(ch)
# time.sleep(0.6)
#for i in range(len(seg.text)):
# del seg.text[0]
# time.sleep(0.6)
# Scrolling Alphabet Text
#print('Scrolling alphabet text...')
#show_message_vp(device, "HELLO EVERYONE!")
#show_message_vp(device, "PI is 3.14159 ... ")
#show_message_vp(device, "IP is 127.0.0.1 ... ")
#show_message_alt(seg, "0123456789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ")
# Inform the manager that this was wired wrong.
while True:
show_message_vp(device, "YOU WIRED THIS WRONG")
time.sleep(1)
# Digit futzing
#date(seg)
#time.sleep(5)
#clock(seg, seconds=10)
# Brightness
#print('Brightness...')
#for x in range(5):
# for intensity in range(16):
# seg.device.contrast(intensity * 16)
# time.sleep(0.1)
#device.contrast(0x7F)
if __name__ == '__main__':
main()