diff options
| author | Tim Keller <tjk@tjkeller.xyz> | 2026-06-03 13:54:18 -0500 |
|---|---|---|
| committer | Tim Keller <tjk@tjkeller.xyz> | 2026-06-03 13:54:18 -0500 |
| commit | 8264c4659dbdb8d98310414badf288f8200fe242 (patch) | |
| tree | d4e967cd63990a464e36b7754676a58379e0f871 /hosts/gnuslashprinter | |
| parent | a6d9a9de1defe2c39c9514c0de76d37dcf8a0576 (diff) | |
| download | nixos-8264c4659dbdb8d98310414badf288f8200fe242.tar.xz nixos-8264c4659dbdb8d98310414badf288f8200fe242.zip | |
aliases for printer and new power control relay. moonraker power control for printer enabled and accessible via mainsail. power control python script for power control via http in moonraker
Diffstat (limited to 'hosts/gnuslashprinter')
| -rw-r--r-- | hosts/gnuslashprinter/configuration.nix | 11 | ||||
| -rw-r--r-- | hosts/gnuslashprinter/flask-relay-ctl.nix | 37 | ||||
| -rw-r--r-- | hosts/gnuslashprinter/klipper.nix | 66 | ||||
| -rw-r--r-- | hosts/gnuslashprinter/resources/flaskrelayctl/pyproject.toml | 10 | ||||
| -rw-r--r-- | hosts/gnuslashprinter/resources/flaskrelayctl/server/__init__.py | 54 | ||||
| -rw-r--r-- | hosts/gnuslashprinter/resources/klipper/printer.cfg | 2 |
6 files changed, 159 insertions, 21 deletions
diff --git a/hosts/gnuslashprinter/configuration.nix b/hosts/gnuslashprinter/configuration.nix index 6af701a..9e1f734 100644 --- a/hosts/gnuslashprinter/configuration.nix +++ b/hosts/gnuslashprinter/configuration.nix @@ -1,5 +1,8 @@ { - imports = [ ./klipper.nix ]; + imports = [ + ./flask-relay-ctl.nix + ./klipper.nix + ]; boot._loader.enable = true; @@ -16,5 +19,11 @@ # Enable user timmy _users.timmy.enable = true; + # Name devices + services.udev.extraRules = '' + SUBSYSTEM=="tty", KERNELS=="3-9", SYMLINK+="gsp-power" + SUBSYSTEM=="tty", KERNELS=="3-10", SYMLINK+="gsp-control" + ''; + system.stateVersion = "25.11"; } diff --git a/hosts/gnuslashprinter/flask-relay-ctl.nix b/hosts/gnuslashprinter/flask-relay-ctl.nix new file mode 100644 index 0000000..27507b6 --- /dev/null +++ b/hosts/gnuslashprinter/flask-relay-ctl.nix @@ -0,0 +1,37 @@ +{ pkgs, ... }: let + flaskrelayctl = pkgs.python3Packages.buildPythonApplication { + pname = "flaskrelayctl"; + version = "1.0"; + src = ./resources/flaskrelayctl; + pyproject = true; + build-system = with pkgs.python3Packages; [ setuptools ]; + dependencies = with pkgs.python3Packages; [ + flask + pyserial + ]; + }; +in { + users.users.relay-api = { + isSystemUser = true; + group = "relay-api"; + extraGroups = [ "dialout" ]; + }; + users.groups.relay-api = {}; + + systemd.services.relay-api = let + RELAYCTL_DEV = "/dev/gsp-power"; + in { + description = "USB Relay Flask API"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + serviceConfig = { + User = "relay-api"; + Group = "relay-api"; + ExecStart = "${flaskrelayctl}/bin/flaskrelayctl"; + Restart = "always"; + DeviceAllow = [ "${RELAYCTL_DEV} rw" ]; + }; + }; + + environment.systemPackages = [ flaskrelayctl ]; +} diff --git a/hosts/gnuslashprinter/klipper.nix b/hosts/gnuslashprinter/klipper.nix index a19261c..331a0c7 100644 --- a/hosts/gnuslashprinter/klipper.nix +++ b/hosts/gnuslashprinter/klipper.nix @@ -6,7 +6,7 @@ mcu = { enable = true; # Serial port connected to the microcontroller - serial = "/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0"; + serial = "/dev/gsp-control"; # Klipper flash must be enabled in order to build mcu firmware # The resulting `klipper-flash-mcu` command will show the location of the firmware bin in the nix store enableKlipperFlash = true; @@ -22,29 +22,31 @@ #configDir = "/var/lib/moonraker/config"; # Accessible by moonraker # TODO # Moonraker web-api + security.polkit.enable = true; # required for services.moonraker.allowSystemControl services.moonraker = { user = "root"; enable = true; address = "0.0.0.0"; + allowSystemControl = true; settings = { - #authorization = { - # force_logins = true; - # cors_domains = [ - # "*.local" - # "*.lan" - # "*://app.fluidd.xyz" - # "*://my.mainsail.xyz" - # ]; - # trusted_clients = [ - # "10.0.0.0/8" - # "127.0.0.0/8" - # "169.254.0.0/16" - # "172.16.0.0/12" - # "192.168.0.0/16" - # "FE80::/10" - # "::1/128" - # ]; - #}; + authorization = { + force_logins = true; + cors_domains = [ + "*.local" + "*.lan" + "*://app.fluidd.xyz" + "*://my.mainsail.xyz" + ]; + trusted_clients = [ + "10.0.0.0/8" + "127.0.0.0/8" + "169.254.0.0/16" + "172.16.0.0/12" + "192.168.0.0/16" + "FE80::/10" + "::1/128" + ]; + }; #file_manager.check_klipper_config_path = false; # Disable warning when klipper config is not accessible by moonraker # mainsail.cfg #"update_manager mainsail-config" = { @@ -54,6 +56,31 @@ # origin = "https://github.com/mainsail-crew/mainsail-config.git"; # managed_services = "klipper"; #}; + + "power printer" = let + relayApiHost = "http://localhost:5050"; + in { + type = "http"; + on_url = "${relayApiHost}/on"; + off_url = "${relayApiHost}/off"; + status_url = "${relayApiHost}/status"; + response_template = '' + + # The module will perform the "GET" request using the appropriate url. + # We use the `last_response` method to fetch the result and decode the + # json response. + {% set resp = http_request.last_response().json() %} + # The expression below will render "on" or "off". + {resp["state"].lower()} + ''; + off_when_shutdown = true; + on_when_job_queued = true; + locked_while_printing = true; + restart_klipper_when_powered = true; + restart_delay = "1"; + bound_services = "klipper"; + initial_state = "off"; + }; }; }; @@ -67,6 +94,7 @@ networking.firewall.allowedTCPPorts = [ 80 ]; # Port for mainsail via nginx # Webcam support in mainsail + # TODO hook to restart ustreamer when webcam is connected services.ustreamer.enable = true; services.mainsail.nginx.locations."/webcam/".proxyPass = "http://localhost:8080/stream"; # Default location for ustreamer stream } diff --git a/hosts/gnuslashprinter/resources/flaskrelayctl/pyproject.toml b/hosts/gnuslashprinter/resources/flaskrelayctl/pyproject.toml new file mode 100644 index 0000000..b151b74 --- /dev/null +++ b/hosts/gnuslashprinter/resources/flaskrelayctl/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "flaskrelayctl" +version = "1.0" + +[project.scripts] +flaskrelayctl = "server:main" diff --git a/hosts/gnuslashprinter/resources/flaskrelayctl/server/__init__.py b/hosts/gnuslashprinter/resources/flaskrelayctl/server/__init__.py new file mode 100644 index 0000000..f2c0bc3 --- /dev/null +++ b/hosts/gnuslashprinter/resources/flaskrelayctl/server/__init__.py @@ -0,0 +1,54 @@ +from flask import Flask, jsonify +import serial +import os + +app = Flask(__name__) + +RELAY_DEV = os.environ.get("RELAYCTL_DEV", "/dev/ttyUSB0") +RELAY_HOST = os.environ.get("RELAYCTL_HOST", "127.0.0.1") +RELAY_PORT = os.environ.get("RELAYCTL_PORT", "5050") +RELAY_BAUD = 9600 +RELAY_ID = 1 # NOTE: multi relay boards are not supported (only relay id 1) + +def get_cmd(state: bool): + """ + LCUS relay 4-byte control command syntax is as follows: + start: always 0xA0 + relay: id of relay (counts from 1) + state: coil energized 0 or 1 + checksum: sum of previous 3 bytes + """ + start = 0xA0 + relay = RELAY_ID + state = int(state) + checksum = start + relay + state + return bytes((start, relay, state, checksum)) + +def get_serial(): + return serial.Serial(RELAY_DEV, RELAY_BAUD, timeout=1) + +@app.route("/on", methods=["GET", "POST"]) +def on(): + with get_serial() as ser: + ser.write(get_cmd(True)) + return jsonify({"state": "ON"}) + +@app.route("/off", methods=["GET", "POST"]) +def off(): + with get_serial() as ser: + ser.write(get_cmd(False)) + return jsonify({"state": "OFF"}) + +@app.route("/status", methods=["GET"]) +def status(): + with get_serial() as ser: + ser.write(bytes((0xFF,))) # write 0xFF to get status + r = ser.readline() + state = r.decode("utf-8").removeprefix("CH1: ").strip() + return jsonify({"state": state}) + +def main(): + app.run(host=RELAY_HOST, port=int(RELAY_PORT)) + +if __name__ == "__main__": + main() diff --git a/hosts/gnuslashprinter/resources/klipper/printer.cfg b/hosts/gnuslashprinter/resources/klipper/printer.cfg index 1e39048..4baba56 100644 --- a/hosts/gnuslashprinter/resources/klipper/printer.cfg +++ b/hosts/gnuslashprinter/resources/klipper/printer.cfg @@ -90,7 +90,7 @@ max_temp: 130 pin: PA0 [mcu] -serial: /dev/serial/by-id/usb-1a86_USB_Serial-if00-port0 +serial: /dev/gsp-control restart_method: command [printer] |
