Skip to content

How to control a arbitrary power switch using shell command through http for 3d printer using moonraker

Notifications You must be signed in to change notification settings

Jaj0/moonraker-cli-switch-server

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 

Repository files navigation

moonraker-cli-switch-server

How to control power switch using cli command

image PrinterTurnOn

👎 There's no way to run cli command to switch on/off custom power supply device through moonraker (yet, but i've raised feature request: Arksine/moonraker#932).

👎 Klipper can run macros, but these only run if the MCU is connected, which requires the power to be on in the first place.

🍀 Luckily the power section of Moonraker's config allows arbitrary http requests (even if type: http is, confusingly, not explicitly called out as supported in the documentation), a Python script with a tiny HTTP server attached can be used to send correct shell commands:

image

Here's how:

  1. Save this script somewhere, for example /home/pi/switch/server.py, then edit the ON_COMMAND, OFF_COMMAND, STATUS_COMMAND fields appropriately. Also rework parsing of STATUS_COMMAND return value to match 'on'/'off' status value.

Note: this is the code for the custiom gpio library for NanoPi Neo Air (WiringNP).

#!/usr/bin/python3

import json
import signal
from http.server import SimpleHTTPRequestHandler, HTTPServer
import subprocess

# Align those commands to your usecase
ON_COMMAND = "gpio mode 7 output; gpio write 7 1"
OFF_COMMAND = "gpio write 7 0"
STATUS_COMMAND = "gpio read 7"

running = True

def exit_gracefully(*args, **kwargs):
    print("Terminating...")
    global running
    running = False

signal.signal(signal.SIGINT, exit_gracefully)
signal.signal(signal.SIGTERM, exit_gracefully)


class MyHttpRequestHandler(SimpleHTTPRequestHandler):

      def do_GET(self):
         self.send_response(200)
         self.send_header('Content-type', 'application/json')
         self.end_headers()

         if self.path == "/on":
             # using shell=True allows us to send multiple commands separated by ;
             subprocess.run(ON_COMMAND, shell=True)
         elif self.path == "/off":
             subprocess.run(OFF_COMMAND, shell=True)
         ret = subprocess.run(STATUS_COMMAND, capture_output=True, shell=True)
         # rework this part to align it to output of your command
         # it should return 'on' or 'off' for key 'status' in return dictionary 
         status = ret.stdout.decode().strip()
         status = 'on' if status == '1' else 'off'
         # send reponse with switch status
         self.wfile.write(json.dumps({'status': status}).encode("utf-8"))


if __name__ == '__main__':
    server_class = HTTPServer
    handler_class = MyHttpRequestHandler
    server_address = ('127.0.0.1', 56427)

    httpd = server_class(server_address, handler_class)
    # intentionally making it slow, it doesn't need to react quickly
    httpd.timeout = 1  # seconds

    try:
        while running:
            httpd.handle_request()
    except KeyboardInterrupt:
        pass
  1. Make the script executable chmod +x /home/pi/switch/server.py.
  2. Make the script autostart, create a service with your editor of choice, e.g. sudo nano /etc/systemd/system/switch.service
[Unit]
Description=CLI Switch server
Wants=network.target
After=network.target

[Service]
User=pi
Group=pi
ExecStartPre=/bin/sleep 10
ExecStart=/home/pi/switch/server.py
Restart=always

[Install]
WantedBy=multi-user.target
  1. Start your service by calling sudo systemctl daemon-reload then sudo systemctl start switch, if something goes wrong you can check status sudo systemctl status switch and logs journalctl -u switch. Then enable it so it autostarts sudo systemctl enable switch
  2. Open in Mainsail/Fluidd your Moonraker.cfg, add this at the end (and maybe customise the device name just after "power"):
[power printer]
type: http
on_url: http://localhost:56427/on
off_url: http://localhost:56427/off
status_url: http://localhost:56427/
response_template:
  {% set resp = http_request.last_response().json() %}
  {resp["status"]}
bound_services: klipper
  1. Restart Moonraker and that should be all.

Optional goodies for Moonraker.cfg, to add below [power printer]

off_when_shutdown: True
locked_while_printing: True
restart_klipper_when_powered: True
on_when_job_queued: True

Optional Klipper auto power off, courtesy of Arksine/moonraker#167 (comment)

Add to Printer.cfg or any Klipper config, adjust device name if needed:

[idle_timeout]
timeout: 600
gcode:
  MACHINE_IDLE_TIMEOUT

# Turn on PSU
[gcode_macro M80]
gcode:
  # Moonraker action
  {action_call_remote_method('set_device_power',
                             device='printer',
                             state='on')}

# Turn off PSU
[gcode_macro M81]
gcode:
  # Moonraker action
  {action_call_remote_method('set_device_power',
                             device='printer',
                             state='off')}

[gcode_macro MACHINE_IDLE_TIMEOUT]
gcode:
  M84
  TURN_OFF_HEATERS
  M81

Thanks to user https://github.com/mainde for original idea on which i've based my solution!

About

How to control a arbitrary power switch using shell command through http for 3d printer using moonraker

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 100.0%