diff --git a/config/model_menu.conf b/config/model_menu.conf new file mode 100644 index 00000000..9392a73d --- /dev/null +++ b/config/model_menu.conf @@ -0,0 +1,2 @@ +CreatBot_F430NX +CreatBot_D600Pro2 diff --git a/ks_includes/ModelConfig.py b/ks_includes/ModelConfig.py new file mode 100644 index 00000000..12f2d280 --- /dev/null +++ b/ks_includes/ModelConfig.py @@ -0,0 +1,136 @@ +import subprocess +import os +import logging + + +class ModelConfig: + + def __init__(self): + home = os.path.expanduser("~/") + printer_data_config = os.path.join(home, "printer_data", "config") + self.moonraker_config_path = printer_data_config + "/moonraker.conf" + self.klipperscreen_config_path = printer_data_config + "/KlipperScreen.conf" + self.printer_config_path = printer_data_config + "/printer.cfg" + + def get_mac_address(self, interface): + try: + result = subprocess.run( + ["ip", "link", "show", interface], capture_output=True, text=True + ) + output = result.stdout + + for line in output.split("\n"): + if "link/ether" in line: + mac_address = line.split()[1] + return mac_address + + except Exception as e: + logging.error(f"get mac address error: {e}") + return None + + def generate_machine_name(self, model): + mac_address = self.get_mac_address("eth0") + if mac_address: + mac_address = mac_address.replace(":", "") + last_four = mac_address[-4:] + machine_name = f"{model}-{last_four.upper()}" + return machine_name + else: + return None + + def write_mdns_config(self, device_name): + if device_name: + try: + with open(self.moonraker_config_path, "r") as file: + lines = file.readlines() + + with open(self.moonraker_config_path, "w") as file: + found_zeroconf_section = False + modified = False + + for line in lines: + if line.strip().startswith("[zeroconf]"): + found_zeroconf_section = True + elif found_zeroconf_section and line.strip().startswith( + "mdns_hostname" + ): + file.write(f"mdns_hostname:{device_name}\n") + found_zeroconf_section = False + modified = True + continue + elif found_zeroconf_section and line.strip().startswith( + "enable_ssdp" + ): + file.write("enable_ssdp: True") + found_zeroconf_section = False + modified = True + continue + + file.write(line) + + if not modified: + file.write("\n[zeroconf]\n") + file.write(f"mdns_hostname:{device_name}\n") + file.write("enable_ssdp: True") + logging.info(f"Setting MDNS address to {device_name}") + except FileNotFoundError: + logging.error( + f"The configuration file {self.moonraker_config_path} not found" + ) + + def write_device_name_config(self, device_name): + if device_name: + try: + with open(self.klipperscreen_config_path, "r+") as file: + lines = file.readlines() + file.seek(0) + found_printer_section = False + for i, line in enumerate(lines): + if line.strip().startswith("[printer"): + lines[i] = f"[printer {device_name}]\n" + found_printer_section = True + break + if not found_printer_section: + lines.insert(0, f"[printer {device_name}]\n") + file.truncate(0) + file.writelines(lines) + logging.info(f"Setting device name to {device_name}") + except FileNotFoundError: + logging.error( + f"Configuration file {self.klipperscreen_config_path} not found." + ) + + def wirte_printer_config(self, device_name): + if device_name: + try: + with open(self.printer_config_path, "r+") as file: + lines = file.readlines() + file.seek(0) + found_printer_section = False + for i, line in enumerate(lines): + if line.strip().startswith("[include ../creatbot/"): + lines[i] = f"[include ../creatbot/{device_name}.cfg]\n" + found_printer_section = True + break + if not found_printer_section: + lines.insert(0, f"[include ../creatbot/{device_name}.cfg]\n") + file.truncate(0) + file.writelines(lines) + + logging.info(f"Setting printer config to {device_name}") + + except FileNotFoundError: + logging.error( + f"Configuration file {self.printer_config_path} not found." + ) + + def generate_config(self, model): + model_name = model + model_name = model_name.split("_")[1] + device_name = self.generate_machine_name(model_name) + self.write_mdns_config(device_name) + self.write_device_name_config(device_name) + self.wirte_printer_config(model) + os.system("systemctl restart klipper.service") + os.system("systemctl restart moonraker.service") + os.system("systemctl restart KlipperScreen.service") diff --git a/panels/system.py b/panels/system.py index a0ffa32c..b3a393e4 100644 --- a/panels/system.py +++ b/panels/system.py @@ -1,9 +1,13 @@ import logging import gi +import time +import os.path +import pathlib gi.require_version("Gtk", "3.0") from gi.repository import Gtk from ks_includes.screen_panel import ScreenPanel +from ks_includes.ModelConfig import ModelConfig class Panel(ScreenPanel): @@ -12,8 +16,14 @@ class Panel(ScreenPanel): super().__init__(screen, title) self.current_row = 0 self.mem_multiplier = None + self.model_config = None self.scales = {} self.labels = {} + self.models = {} + self.click_count = 0 + self.last_click_time = 0 + self.click_threshold = 0.2 + self.target_clicks = 10 self.grid = Gtk.Grid(column_spacing=10, row_spacing=5) sysinfo = screen.printer.system_info @@ -39,11 +49,46 @@ class Panel(ScreenPanel): self.grid.attach(Gtk.Separator(), 0, self.current_row, 2, 1) self.current_row += 1 + self.machine_info(sysinfo) + self.current_row += 1 self.populate_info(sysinfo) scroll = self._gtk.ScrolledWindow() scroll.add(self.grid) self.content.add(scroll) + if self.model_config is None: + self.model_config = ModelConfig() + self.labels["model_menu"] = self._gtk.ScrolledWindow() + self.labels["model"] = Gtk.Grid() + self.labels["model_menu"].add(self.labels["model"]) + klipperscreendir = pathlib.Path(__file__).parent.resolve().parent + self.model_list_path = os.path.join( + klipperscreendir, "config", "model_menu.conf" + ) + self.model_list = pathlib.Path(self.model_list_path).read_text() + with open(self.model_list_path) as file: + for line in file: + model_name = line.strip() + self.models[model_name] = { + "name": model_name, + "type": "button", + "callback": self.change_model, + } + self.add_option( + "model", self.models, model_name, self.models[model_name] + ) + def change_model(self, widget, event): + self.model_config.generate_config(event) + def on_model_click(self, widget, event): + current_time = time.time() + if (current_time - self.last_click_time) <= self.click_threshold: + self.click_count += 1 + else: + self.click_count = 0 + self.last_click_time = current_time + if self.click_count == self.target_clicks: + self.click_count = 0 + self.load_menu("system", _("model")) def set_mem_multiplier(self, data): memory_units = data.get("memory_units", "kB").lower() @@ -62,6 +107,18 @@ class Panel(ScreenPanel): label = Gtk.Label(label=text, use_markup=True, xalign=0, wrap=True) self.grid.attach(label, column, self.current_row, 1, 1) self.current_row += 1 + def machine_info(self, sysinfo): + self.add_label_to_grid(self.prettify("device"), 0, bold=True) + self.current_row -= 1 + self.add_label_to_grid("Maker: CreatBot", 1) + event_box = Gtk.EventBox() + event_box.connect("button-press-event", self.on_model_click) + mode = self._screen.connecting_to_printer.split("-")[0] + label = Gtk.Label(label=f"Model: {mode}", use_markup=True, xalign=0, wrap=True) + self.grid.attach(event_box, 1, self.current_row, 1, 1) + self.current_row += 1 + event_box.add(label) + self.add_label_to_grid(f"Name: {self._screen.connecting_to_printer}", 1) def populate_info(self, sysinfo): for category, data in sysinfo.items():