Printer power control via serial port's lines

Klipper has been the biggest game changer in my 3D printing journey. One of things I've wanted to implement for a long time was printer power control.
The main reason why for adding power control is to automatically the printer off after long prints. Also it may be handy if you see flames in printer's webcam feed.
Because I use thin client instead of something like raspberry pi, I can't just connect GPIO to SSR and be happy.
Fortunately RS-232 serial port is quite common for thin clients and it means that I have at least 2 "GPIOs". It's one more than I need to control SSR.

To make it work I had 2 problems to solve:
1. RS-232 uses differential signals with voltage up to ±15V.
2. Moonraker don't support control of serial port lines.

The first one relatively simple to solve. Typicaly SSRs have wide range of input signal. My SSR-25 clone specifies an input range of 3-32VDC, so a simple diode enough to make it work.
In theory input is somehow connected to a LED inside of optocoupler, which is diode by itself, so it may work without external diode. But since I don't know its reverse voltage characteristic, I decided to play safe.

The second problem is trickier. There are two output lines which may be used - DTR and RTS, but it's not possible to do something like

echo 1 > /sys/class/gpio/gpio42/value

There is no simple lines control exposed, also port must remain open. As soon as it's closed, lines states are cleared.

It's why I decided that python script which exposes control of DTR/RTS state over http should do the trick.
You can find script here: https://github.com/IvanBayan/dtr-rts-http-service
It has minimal dependency (pyserial) and also available as container image: https://github.com/IvanBayan/dtr-rts-http-service/pkgs/container/ivanbayan%2Fdtr-rts-http-service (I use prind so I run it in container for easier integration).
Serial port and HTTP port may be configured via command-line arguments or environment variables.
When service is started it opens serial port and keeps it open to maintain lines signals states.
Three exposed endpoints are /dtr, /rts and /status.
Each endpoint supports parameter `action` which can take values 'on', 'off' or 'status'
First two endpoints support POST method and the last one GET.

All of them return json object with schema:

{
"type": "object",
"properties": {
"result": {
"type": "string"
}
},
"required": [
"result"
]
}

The result value is "ON" or "OFF".
Here is example of moonraker configuration:

[power printer]
initial_state: off
restart_klipper_when_powered: True
restart_delay: 2
locked_while_printing: False
type: http
on_url: http://serial-server:8080/dtr?action=on
off_url: http://serial-server:8080/dtr?action=off
status_url: http://serial-server:8080/dtr?action=status
request_template:
  {% if command in ["on", "off"] %}
    {% do http_request.set_method("POST") %}
    {% do http_request.set_body("") %}
  {% endif %}
  {% do http_request.send() %}
response_template:
  {% set resp = http_request.last_response().json() %}
  {resp["result"]}

Replace "serial-server" with address where this script is listening.
Happy printing.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>