Skip to content

Instantly share code, notes, and snippets.

@noahwilliamsson
Created July 7, 2018 14:10
Show Gist options
  • Save noahwilliamsson/cde6b9ea46ae075079f07576c10f510e to your computer and use it in GitHub Desktop.
Save noahwilliamsson/cde6b9ea46ae075079f07576c10f510e to your computer and use it in GitHub Desktop.
Graph temperature logs from the klippy.log file with plot.ly
#!/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