Many many changes. Homing is working fully

This commit is contained in:
jruthe
2020-07-11 23:24:06 -04:00
parent 3bc9882266
commit 2e9efc1234
7 changed files with 620 additions and 87 deletions

49
KlipperScreen.config Normal file
View File

@@ -0,0 +1,49 @@
[
{
"name": "Home",
"icon": "home",
"items": [
{
"name": "Home All",
"icon": "home",
"method": "post_printer_gcode",
"params": {"script": "G28"}
},
{
"name": "Home X",
"icon": "home-x",
"method": "post_printer_gcode",
"params": {"script": "G28 X"}
},
{
"name": "Home Y",
"icon": "home-y",
"method": "post_printer_gcode",
"params": {"script": "G28 Y"}
},
{
"name": "Home Z",
"icon": "home-z",
"method": "post_printer_gcode",
"params": {"script": "G28 Z"}
}
]
},
{
"name": "Filament" ,
"icon": "filament"
},
{
"name": "Move",
"icon": "move"
},
{
"name": "Menu",
"icon": "actions"
},
{
"name": "Control",
"icon": "control"
}
]

46
KlippyGtk.py Normal file
View File

@@ -0,0 +1,46 @@
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib
class KlippyGtk:
labels = {}
#def __init__ (self):
@staticmethod
def ImageLabel(image_name, text):
box1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, relief=2)
image = Gtk.Image()
#TODO: update file reference
image.set_from_file("/opt/printer/OctoScreen/styles/z-bolt/images/" + str(image_name) + ".svg")
label = Gtk.Label()
label.set_text(text)
box1.add(image)
box1.add(label)
return box1
@staticmethod
def ButtonImage(image_name, label, style=False):
img = Gtk.Image.new_from_file("/opt/printer/OctoScreen/styles/z-bolt/images/" + str(image_name) + ".svg")
b = Gtk.Button(label=label)
#b.props.relief = Gtk.RELIEF_NONE
b.set_image(img)
b.set_hexpand(True)
b.set_vexpand(True)
b.set_can_focus(False)
b.set_image_position(Gtk.PositionType.TOP)
b.set_always_show_image(True)
if style != False:
ctx = b.get_style_context()
ctx.add_class(style)
return b
@staticmethod
def formatTemperatureString(temp, target):
if (target > temp-2 and target < temp+2) or round(target,0) == 0:
return str(round(temp,2)) + "C"
return str(round(temp,2)) + "C -> " + str(round(target,2)) + "C"

81
KlippyWebsocket.py Normal file
View File

@@ -0,0 +1,81 @@
#!/usr/bin/python
import gi
import time
import threading
import json
import requests
import websocket
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib
#f = open("/home/pi/.moonraker_api_key", "r")
api_key = "" #f.readline()
#f.close()
api = {
"printer_info": {
"url": "/printer/info",
"method": "get_printer_info"
},
"apikey": {
"url": "/access/api_key"
},
"oneshot_token": {
"url": "/access/oneshot_token"
}
}
class KlippyWebsocket(threading.Thread):
_req_id = 0
def __init__(self, callback):
threading.Thread.__init__(self)
self._callback = callback
self._url = "127.0.0.1:7125"
def connect (self):
r = requests.get("http://" + self._url + api['oneshot_token']['url'], headers={"x-api-key":api_key})
if r.status_code != 200:
print "Failed to retrieve oneshot token"
return
token = json.loads(r.content)['result']
self.ws_url = "ws://" + self._url + "/websocket?token=" + token
self.ws = websocket.WebSocketApp(self.ws_url,
on_open = self.on_open,
on_message = self.on_message,
on_error = self.on_error,
on_close = self.on_close,
)
self.ws.on_open = self.on_open
self._wst = threading.Thread(target=self.ws.run_forever)
self._wst.daemon = True
self._wst.start()
def on_message(self, message):
result = json.loads(message)
print json.dumps(result, indent=2)
GLib.idle_add(self._callback, result['method'], result['params'][0])
def send_method(self, method, params):
#print "{jsonrpc: \"2.0\", method: \"" + str(method) + "\", params: " + json.dumps(params) + ", id: \"2\"}"
data = {
"jsonrpc": "2.0",
"method": method,
"params": params,
"id": "2"
}
print json.dumps(data)
self.ws.send(json.dumps(data))
def on_open(self, ws):
print "### ws open ###"
self.ws.send('{jsonrpc: "2.0", method: "post_printer_objects_subscription", params: {extruder: ["temperature","target"], toolhead: ["position", "status"]}, id: "1"}')
def on_close(self, ws):
print "### ws closed ###"
def on_error(self, ws, error):
print(error)

1
panels/__init__.py Normal file
View File

@@ -0,0 +1 @@
from idle_status import *

48
panels/idle_status.py Normal file
View File

@@ -0,0 +1,48 @@
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib
from KlippyGtk import KlippyGtk
class IdleStatusPanel:
_screen = None
labels = {}
def __init__(self, screen):
self._screen = screen
print "init"
# def initialize(self):
# box1 = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
# image = Gtk.Image()
# #TODO: update file reference
# image.set_from_file("/opt/printer/OctoScreen/styles/z-bolt/images/bed.svg")
# label = Gtk.Label()
# label.set_text("0C / 0C")
# self.bed_temp_label = label
# box1.add(image)
# box1.add(self.bed_temp_label)
#
# return box1
def initialize(self):
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
grid = Gtk.Grid()
grid.set_row_homogeneous(True)
grid.set_column_homogeneous(True)
for i in range(self._screen.number_tools):
self.labels["tool" + str(i)] = KlippyGtk.ButtonImage("extruder-"+str(i+1), "0C / 0C")
grid.attach(self.labels["tool" + str(i)], 0, 0, 1, 1)
self.labels['bed'] = KlippyGtk.ButtonImage("bed", "0C / 0C")
grid.attach(self.labels['bed'], 0, 1, 1, 1)
#box.add(KlippyGtk.ButtonImage("bed", "0C / 0C"))
box.add(grid)
return box
def update_temp(self, dev, temp, target):
if self.labels.has_key(dev):
self.labels[dev].set_label(KlippyGtk.formatTemperatureString(temp, target))

234
screen.py
View File

@@ -1,42 +1,63 @@
#!/usr/bin/python
import gi
import time
import threading
import json
import requests
import websocket
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk
from gi.repository import Gtk, Gdk, GLib
from KlippyWebsocket import KlippyWebsocket
from KlippyGtk import KlippyGtk
from panels import IdleStatusPanel
config = "/opt/printer/KlipperScreen/KlipperScreen.config"
class KlipperScreen(Gtk.Window):
""" Class for creating a screen for Klipper via HDMI """
currentPanel = None
bed_temp_label = None
number_tools = 1
panels = {}
_cur_panels = []
def __init__(self):
self.read_config()
self.init_style()
Gtk.Window.__init__(self)
self.set_default_size(Gdk.Screen.get_width(Gdk.Screen.get_default()),Gdk.Screen.get_height(Gdk.Screen.get_default()))
self.set_default_size(Gdk.Screen.get_width(Gdk.Screen.get_default()), Gdk.Screen.get_height(Gdk.Screen.get_default()))
r = requests.get("http://127.0.0.1:7125/printer/info") #, headers={"x-api-key":api_key})
if r.status_code != 200:
self.printer_initializing()
self.create_websocket()
return
#self.splash_screen()
data = json.loads(r.content)
if data['result']['is_ready'] != True:
self.printer_initializing()
self.create_websocket()
return
self.create_websocket()
self.main_panel()
self.box = Gtk.Box(spacing=6)
#self.add(self.box)
self.button1 = Gtk.Button(label="Hello")
self.button1.connect("clicked", self.on_button1_clicked)
#self.box.pack_start(self.button1, True, True, 0)
def read_config (self):
with open(config) as config_file:
self._config = json.load(config_file)
self.button2 = Gtk.Button(label="Goodbye")
self.button2.connect("clicked", self.on_button2_clicked)
#self.box.pack_start(self.button2, True, True, 0)
def init_style(self):
cssdata = ""
with open ('/home/pi/style.css', 'r' ) as file:
cssdata = file.read()
style_provider = Gtk.CssProvider()
style_provider.load_from_path("/home/pi/style.css")
style_provider.load_from_path("/opt/printer/KlipperScreen/style.css")
Gtk.StyleContext.add_provider_for_screen(
Gdk.Screen.get_default(),
@@ -45,14 +66,15 @@ class KlipperScreen(Gtk.Window):
)
def splash_screen(self):
if "splash_screen" not in self.panels:
image = Gtk.Image()
#TODO: update file reference
image.set_from_file("/opt/printer/OctoScreen/styles/z-bolt/images/logo.png")
#label = Gtk.Label()
#label.set_text("Initializing printer...")
label = Gtk.Button(label="Initializing printer...")
label.connect("clicked", self.printer_initialize)
label = Gtk.Label()
label.set_text("Initializing printer...")
#label = Gtk.Button(label="Initializing printer...")
#label.connect("clicked", self.printer_initialize)
main = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=15)
main.pack_start(image, True, True, 10)
@@ -60,33 +82,163 @@ class KlipperScreen(Gtk.Window):
box = Gtk.VBox()
box.add(main)
self.add(box)
self.currentPanel = box
self.panels['splash_screen'] = box
self.add(self.panels['splash_screen'])
self.show_all()
self._cur_panels = ['splash_screen']
def create_websocket(self):
self._ws = KlippyWebsocket(self._websocket_callback)
self._ws.connect()
self._curr = 0
def main_panel (self):
box = Gtk.Box(spacing=6)
if "main_panel" not in self.panels:
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
box.add(self.gtk_ButtonImage("/opt/printer/OctoScreen/styles/z-bolt/images/home.svg", "Home"))
box.add(self.gtk_ButtonImage("/opt/printer/OctoScreen/styles/z-bolt/images/filament.svg", "Filament"))
self.add(box)
self.currentPanel = box
grid = Gtk.Grid()
grid.set_row_homogeneous(True)
grid.set_column_homogeneous(True)
self.panels['idle_status'] = IdleStatusPanel(self)
def gtk_ButtonImage (self, image, label):
img = Gtk.Image.new_from_file(image)
grid.attach(self.panels['idle_status'].initialize(), 0, 0, 1, 1)
#grid.attach(box2, 1, 0, 1, 1)
b = Gtk.Button(label=label)
b.set_image(img)
b.set_image_position(Gtk.PositionType.TOP)
b.set_always_show_image(True)
ctx = b.get_style_context()
ctx.add_class("color1")
#button.set_vertical_expand(True)
#button.set_h_expand(True)
return b
def printer_initialize(self, widget):
self.remove(self.currentPanel)
grid.attach(self.arrangeMenuItems(self._config,2), 1, 0, 1, 1)
self.panels['main_screen'] = grid
print ("### Adding main panel")
self.add(self.panels['main_screen'])
self.show_all()
self._cur_panels.append("main_screen")
def _go_to_submenu(self, widget, menu):
print "#### Go to submenu " + str(menu)
self._remove_current_panel(False)
# Find current menu item
panels = list(self._cur_panels)
cur_item = self._find_current_menu_item(menu, self._config, panels.pop(0))
menu = cur_item['items']
grid = self.arrangeMenuItems(menu, 4)
b = KlippyGtk.ButtonImage('back', 'Back')
b.connect("clicked", self._menu_go_back)
grid.attach(b, 4, 2, 1, 1)
self._cur_panels.append(cur_item['name']) #str(cur_item['name']))
self.panels[cur_item['name']] = grid
self.add(self.panels[cur_item['name']])
self.show_all()
def _find_current_menu_item(self, menu, items, names):
# TODO: Make recursive
return items[menu]
def _remove_all_panels(self):
while len(self._cur_panels) > 0:
self._remove_current_panel()
def _remove_current_panel(self, pop=True):
print "1 " + str(self._cur_panels)
print self.panels.keys()
if len(self._cur_panels) > 0:
self.remove(
self.panels[
self._cur_panels[-1]
]
)
if pop == True:
print "Popping _cur_panels"
self._cur_panels.pop()
if len(self._cur_panels) > 0:
self.add(self.panels[self._cur_panels[-1]])
self.show_all()
def _menu_go_back (self, widget):
print "#### Menu go back"
self._remove_current_panel()
def _websocket_callback(self, action, data):
if action == "notify_klippy_state_changed":
if data == "ready":
print "### Going to ready state"
self.printer_ready()
elif data == "disconnect" or data == "shutdown":
print "### Going to disconnected state"
self.printer_initializing()
elif action == "notify_status_update":
#print data
if "idle_status" in self.panels:
if "heater_bed" in data:
self.panels['idle_status'].update_temp(
"bed",
round(data['heater_bed']['temperature'],1),
round(data['heater_bed']['target'],1)
)
if "extruder" in data and data['extruder'] != "extruder":
self.panels['idle_status'].update_temp(
"tool0",
round(data['extruder']['temperature'],1),
round(data['extruder']['target'],1)
)
def set_bed_temp (self, num, target):
print str(num) + "C / " + str(target) + "C"
if self.bed_temp_label == None:
return
self.bed_temp_label.set_text(str(num) + "C / " + str(target) + "C")
def arrangeMenuItems (self, items, columns):
grid = Gtk.Grid()
grid.set_row_homogeneous(True)
grid.set_column_homogeneous(True)
l = len(items)
i = 0
print items
for i in range(l):
col = i % columns
row = round(i/columns, 0)
width = 1
#if i+1 == l and l%2 == 1:
# width = 2
b = KlippyGtk.ButtonImage(
items[i]['icon'], items[i]['name'], "color"+str((i%4)+1)
)
if "items" in items[i]:
b.connect("clicked", self._go_to_submenu, i)
elif "method" in items[i]:
params = items[i]['params'] if "params" in items[i] else {}
b.connect("clicked", self._send_action, items[i]['method'], params)
grid.attach(b, col, row, 1, width)
i += 1
return grid
def _send_action(self, widget, method, params):
self._ws.send_method(method, params)
def printer_initializing(self):
self._remove_all_panels()
self.splash_screen()
def printer_ready(self):
self._remove_all_panels()
self.main_panel()
def on_button1_clicked(self, widget):
@@ -101,9 +253,7 @@ win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
#win = KlipperScreen()
#win.connect("destroy", Gtk.main_quit)
#win.show_all()
#Gtk.main()

158
style.css Normal file
View File

@@ -0,0 +1,158 @@
/* * {
} */
window {
background-color: #13181C;
-gtk-icon-shadow: none;
font-size: 20px;
}
scrollbar, scrollbar button {
border: none;
background-color: #13181C;
}
scrollbar slider {
min-width: 88px;
border-radius: 15px;
background-color: #404E57;
}
progress, trough {
min-height: 20px;
font-size: 50px;
}
progress {
background-color: #00C9B4;
font-size: 50px;
font-weight: lighter;
}
.printing-progress-bar{
font-size: 60px;
color: #00C9B4;
}
.printing-state {
opacity: 0.5;
}
button {
background-image: none;
background-color: #13181C;
margin: 5px;
margin-bottom: 10px;
border-radius: 0;
border: 0px solid #000;
color: #fff;
-gtk-icon-shadow: none;
}
button:active {
background-color: #304C62;
}
button.color1 {
border-bottom: 8px solid #ED6500;
}
button.color2 {
border-bottom: 8px solid #B10080;
}
button.color3 {
border-bottom: 8px solid #009384;
}
button.color4 {
border-bottom: 8px solid #A7E100;
}
button.active {
background-color: #20303D;
}
button.file-list {
margin: 0px;
}
entry {
font-size: 30px;
background-color: #20292F;
border-radius: 0;
padding-left: 1em;
margin-left: 1em;
padding-right: 1em;
}
button.keyboard {
font-size: 30px;
margin: 0px;
/* margin-bottom:10px; */
}
.dialog {
border: 2px solid black;
font-size: 20px;
padding: 50px;
background-color: #000;
}
.dialog button {
padding: 30px 50px 30px 50px;
border-bottom: 8px solid #009384;
}
.dialog {
border: 2px solid black;
font-size: 20px;
padding: 50px;
background-color: #000;
}
.dialog button {
padding: 30px 50px 30px 50px;
border-bottom: 8px solid #009384;
}
.message {
border: 2px solid #981E1F;
font-size: 20px;
padding: 50px;
color: #FFF;
background-color: #981E1F;
}
.message button {
background-color: #FFF;
color: #000;
padding: 40px 50px 40px 50px;
}
.notification {
background-clip: padding-box;
padding: 5px;
border-radius: 0 0 5px 5px;
opacity: 0.8;
}
.warning {
background-color: rgba(30, 204, 39, 0.7);
}
.error {
background-color: rgba(204, 30, 30, 0.7);
}
.printing-status-label {
padding-top: 5px;
padding-bottom: 3px;
font-size: 24px;
}
.hidden {
opacity: 0;
}