Created
July 7, 2018 14:10
-
-
Save noahwilliamsson/cde6b9ea46ae075079f07576c10f510e to your computer and use it in GitHub Desktop.
Graph temperature logs from the klippy.log file with plot.ly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# | |
# Graph temperature logs from the klippy.log file generated by | |
# https://github.com/KevinOConnor/klipper | |
# | |
# You will need a free https://plot.ly account and an API key from: | |
# https://plot.ly/settings/api#/ | |
# | |
# Usage: | |
# pip install --user plotly cryptography cryptography nose tornado six | |
# python klipper-temp.py <username> <APIKey> klippy.log | |
# | |
import os, sys, time | |
from datetime import datetime | |
import plotly | |
import plotly.plotly as py | |
import plotly.graph_objs as go | |
import plotly.offline as offline | |
if len(sys.argv) < 4: | |
print('Usage: {} <plot.ly username> <API key> <klippy.log>'.format(sys.argv[0])) | |
sys.exit(0) | |
username = sys.argv[1] | |
api_key = sys.argv[2] | |
filename = sys.argv[3] | |
plotly.tools.set_credentials_file(username=username, api_key=api_key) | |
plotly.tools.set_config_file(world_readable=True, sharing='public') | |
data = '' | |
with open(filename, 'r') as f: | |
data = f.read().strip() | |
layout = {'shapes': []} | |
shape_titles = [] | |
shape_x = [] | |
shape_y = [] | |
objs = [] | |
time_base = prev_time = time.time() | |
for line in data.splitlines(): | |
if not line: | |
continue | |
tokens = line.split() | |
if tokens[0] == 'Start': | |
# Start printer at Thu Jul 5 10:56:23 2018 (1530788183.8 11292.7) | |
time_base = float(tokens[8][1:]) - float(tokens[9][:-1]) | |
prev_time = time_base + float(tokens[9][:-1]) | |
shape_titles.append('Start printer') | |
shape_x.append(datetime.fromtimestamp(prev_time)) | |
shape_y.append(5 * (len(shape_y) + 1)) | |
layout['shapes'].append({ | |
'type': 'line', | |
'yref': 'paper', | |
'x0': datetime.fromtimestamp(prev_time), 'y0': 0, | |
'x1': datetime.fromtimestamp(prev_time), 'y1': 1, | |
'line': { 'color': 'blue' } | |
}) | |
continue | |
elif tokens[0] == 'Extrude' or (tokens[0] == 'Heater' and tokens[:-1][0] == 'rate'): | |
# Extrude below minimum temp | |
# Heater extruder not heating at expected rate | |
shape_titles.append(line) | |
shape_x.append(datetime.fromtimestamp(prev_time)) | |
shape_y.append(100) | |
layout['shapes'].append({ | |
'type': 'line', | |
'yref': 'paper', | |
'x0': datetime.fromtimestamp(prev_time), 'y0':0, | |
'x1': datetime.fromtimestamp(prev_time), 'y1':1, | |
'line': { 'color': 'black' } | |
}) | |
elif tokens[0] == 'Shutdown': | |
# Shutdown due to M112 command | |
shape_titles.append(line) | |
shape_x.append(datetime.fromtimestamp(prev_time)) | |
shape_y.append(100) | |
layout['shapes'].append({ | |
'type': 'line', | |
'yref': 'paper', | |
'x0': datetime.fromtimestamp(prev_time), 'y0': 0, | |
'x1': datetime.fromtimestamp(prev_time), 'y1': 1, | |
'line': { 'color': 'red' } | |
}) | |
elif tokens[0] == 'Heater': | |
# Heater heater_bed approaching new target of 60.000 | |
# Heater heater_bed within range of 60.000 | |
# Heater extruder approaching new target of 170.000 | |
# Heater extruder within range of 170.000 | |
value = tokens[-1:][0] | |
if value.replace('.','',1).isdigit(): | |
value = float(value) | |
approaching = (tokens[2] == 'approaching') | |
color = 'yellow' if approaching else 'orange' | |
shape_titles.append(' '.join([tokens[1], tokens[2], str(value)])) | |
shape_x.append(datetime.fromtimestamp(prev_time)) | |
shape_y.append(value-10 if approaching else value) | |
layout['shapes'].append({ | |
'type': 'line', | |
'x0': datetime.fromtimestamp(prev_time), 'y0': 0, | |
'x1': datetime.fromtimestamp(prev_time), 'y1': value, | |
'line': { 'color': color } | |
}) | |
if not line or tokens[0] != 'Stats': | |
continue | |
# Stats 11259.9: gcodein=0 mcu: mcu_awake=0.000 mcu_task_avg=0.000000 mcu_task_stddev=0.000000 bytes_write=641 bytes_read=2724 bytes_retransmit=9 bytes_invalid=0 send_seq=74 receive_seq=74 retransmit_seq=2 srtt=0.001 rttvar=0.000 rto=0.025 ready_bytes=0 stalled_bytes=0 freq=25000231 heater_bed: target=0 temp=0.0 pwm=0.000 print_time=602.221 buffer_time=0.249 print_stall=0 extruder: target=0 temp=65.1 pwm=0.000 | |
obj = {} | |
for token in tokens: | |
if token[-1:] == ':': | |
part = token[:-1] | |
if part.replace('.','',1).isdigit(): | |
obj['time'] = time_base + float(part) | |
continue | |
temp = token.split('=') | |
if len(temp) != 2: | |
continue | |
(key, value) = temp | |
if key in ['temp', 'target']: | |
obj[part + '_' + key] = float(value) | |
prev_time = obj['time'] | |
objs.append(obj) | |
data = [] | |
if shape_titles: | |
data.append(go.Scatter(x=shape_x, y=shape_y, name='Events', mode='text', text=shape_titles)) | |
x = [] | |
extruder_temp = [] | |
bed_temp = [] | |
# Cumulative moving average | |
# https://github.com/KevinOConnor/klipper/commit/b0ee323e2e01ba2084bea8de733f16474f1167eb | |
extruder_temp_smoothed = [] | |
smooth_time = 2.0 | |
inv_smooth_time = 1. / smooth_time | |
last_temp_time = 0 | |
smoothed_temp = 0 | |
#extruder_temp_cma = [] | |
#cma = 0 | |
for obj in objs: | |
x.append(datetime.fromtimestamp(obj['time'])) | |
if 'extruder_temp' in obj: | |
extruder_temp.append(obj['extruder_temp']) | |
temp = obj['extruder_temp'] | |
read_time = obj['time'] | |
# https://github.com/KevinOConnor/klipper/commit/b0ee323e2e01ba2084bea8de733f16474f1167eb | |
time_diff = read_time - last_temp_time | |
last_temp = temp | |
last_temp_time = read_time | |
temp_diff = temp - smoothed_temp | |
adj_time = min(time_diff * inv_smooth_time, 1.) | |
smoothed_temp += temp_diff * adj_time | |
extruder_temp_smoothed.append(smoothed_temp) | |
#cma = (temp + (smooth_time-1)*cma) / (smooth_time) | |
#extruder_temp_cma.append(cma) | |
if 'heater_bed_temp' in obj: | |
bed_temp.append(obj['heater_bed_temp']) | |
if extruder_temp: | |
data.append(go.Scatter(x=x, y=extruder_temp, name='Extruder')) | |
if extruder_temp_smoothed: | |
data.append(go.Scatter(x=x, y=extruder_temp_smoothed, name='Extruder smoothed')) | |
#if extruder_temp_cma: | |
# data.append(go.Scatter(x=x, y=extruder_temp_cma, name='Extruder CMA')) | |
if bed_temp: | |
data.append(go.Scatter(x=x, y=bed_temp, name='Bed')) | |
fig = {'data': data, 'layout': layout} | |
# Online plot | |
py.plot(fig, filename=os.path.basename(filename) + '.html', auto_open=True) | |
# Offline plot | |
#offline.plot(fig, filename=os.path.basename(filename) + '.html', image='png', image_filename=os.path.basename(filename), auto_open=True) | |
#print('Image saved to', os.path.dirname(filename) + '.png') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment