seven-segment-max7219/kiln-logger.py

167 lines
5.1 KiB
Python
Executable file

#!/usr/bin/env python
import websocket
import json
import time
from datetime import datetime
import csv
import argparse
import sys
from luma.led_matrix.device import max7219
from luma.core.interface.serial import spi, noop
from luma.core.virtual import viewport, sevensegment
# import requests
STD_HEADER = [
'stamp',
'runtime',
'temperature',
'target',
'state',
'heat',
'totaltime',
'profile',
]
PID_HEADER = [
'pid_time',
'pid_timeDelta',
'pid_setpoint',
'pid_ispoint',
'pid_err',
'pid_errDelta',
'pid_p',
'pid_i',
'pid_d',
'pid_kp',
'pid_ki',
'pid_kd',
'pid_pid',
'pid_out',
]
def logger(hostname, csvfile, noprofilestats, pidstats, stdout):
status_ws = websocket.WebSocket()
csv_fields = []
if not noprofilestats:
csv_fields += STD_HEADER
if pidstats:
csv_fields += PID_HEADER
out = open(csvfile, 'w')
csv_out = csv.DictWriter(out, csv_fields, extrasaction='ignore')
csv_out.writeheader()
if stdout:
csv_stdout = csv.DictWriter(sys.stdout, csv_fields, extrasaction='ignore', delimiter='\t')
csv_stdout.writeheader()
else:
csv_stdout = None
# setup seven segment display
# remove comment on the next line if using SPI interface 0. currently using SPI interface 1
#serial = spi(port=0, device=0, gpio=noop())
serial = spi(port=1, device=0, gpio=noop())
device = max7219(serial, cascaded=2)
seg = sevensegment(device)
# end setup seven segment display
# store the current state, default to IDLE
prev_kiln_state = "IDLE"
kiln_state = "IDLE"
while True:
try:
msg = json.loads(status_ws.recv())
except websocket.WebSocketException:
try:
status_ws.connect(f'ws://{hostname}/status')
except Exception:
time.sleep(5)
continue
if msg.get('type') == 'backlog':
continue
# get the current state, if the state changes from RUNNING to IDLE
if msg.get('state') == 'RUNNING':
if kiln_state == 'IDLE':
kiln_state = 'RUNNING'
prev_kiln_state = 'IDLE'
continue
if msg.get('state') == 'IDLE':
if kiln_state == 'RUNNING':
kiln_state = 'IDLE'
prev_kiln_state = 'RUNNING'
continue
if not noprofilestats:
msg['stamp'] = time.time()
if pidstats and 'pidstats' in msg:
for k, v in msg.get('pidstats', {}).items():
msg[f"pid_{k}"] = v
csv_out.writerow(msg)
out.flush()
if stdout:
for k in list(msg.keys()):
v = msg[k]
if isinstance(v, float):
msg[k] = '{:5.3f}'.format(v)
csv_stdout.writerow(msg)
sys.stdout.flush()
# ADD THE TEMPERATURE HERE with requests library, however, this is redundant, as the
# websocket messaging already has the temp value.
# try:
# req = requests.get('http://127.0.0.1:8081/api/stats')
# except KeyError:
# try:
# req = requests.get('http://127.0.0.1:8081/api/stats')
# except Exception:
# time.sleep(25)
# continue
# TODO: temp needs to be error checked if using the requests library.
# expected value is a decimal/float value between -58 and 2372 deg F
# temp = round(req.json()['ispoint'])
temp = round(msg['temperature'])
# time remaining for the display, calculated for rounded seconds
time_rem = msg['totaltime'] - msg['runtime']
if time_rem == -1 or kiln_state == 'IDLE':
if prev_kiln_state == 'IDLE':
seg.text = f"READY....TEMP{temp:4.0f}"
else:
seg.text = f"DONE....TEMP{temp:4.0f}"
else:
hours = round(time_rem // 3600)
minutes = round((time_rem - (hours * 3600)) // 60)
seconds = round((time_rem - (hours * 3600) - (minutes * 60))) - 1
seg.text = f"{hours:2.0f}-{minutes:2.0f}-{seconds:2.0f}TEMP{temp:4.0f}"
# END ADD TEMP
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Log kiln data for analysis.')
parser.add_argument('--hostname', type=str, default="localhost:8081", help="The kiln-controller hostname:port")
# parser.add_argument('--csvfile', type=str, default="/tmp/kilnstats.csv", help="Where to write the kiln stats to")
parser.add_argument('--csvfile', type=str, default=f"/tmp/kilnstats-{datetime.today().strftime('%Y_%m_%d-%I_%M')}.csv", help="Where to write the kiln stats to")
parser.add_argument('--pidstats', action='store_true', help="Include PID stats")
parser.add_argument('--noprofilestats', action='store_true', help="Do not store profile stats (default is to store them)")
parser.add_argument('--stdout', action='store_true', help="Also print to stdout")
args = parser.parse_args()
logger(args.hostname, args.csvfile, args.noprofilestats, args.pidstats, args.stdout)