#!/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 kiln_state != msg['state']: prev_kiln_state = kiln_state kiln_state = msg['state'] 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 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)