Gemini 等主板比较完美的打完安全关机方案
前言
原创文章,转载引用请务必注明链接,水平有限,如有疏漏,欢迎交流指正。
文章如有更新请访问 DFRobot社区。
欢迎对 Klipper 固件感兴趣,以及对改版 CNC 加工的 Voron 三叉戟、v0、v2.4 感兴趣的朋友加群交流(QQ Group:490111638)
我们约定:主板 指 MCU 部分,上位机 指运行 Klippy 的 MPU Linux 部分。
看过前文 Klipper 温控风扇以及电源管理(部分) 的朋友,一定了解到了安全关闭上位机系统的重要性,当然如果你是平日自家电脑关机靠直接拔电的壮士,下面的文章可以不用看了。
由于 Gemini 二合一主板的 MCU 和 MPU 是不是独立供电的,此外越来越多朋友的 3D 打印机为了好看,选择把上位机和主板一起封在电气箱内,通过总电源开关进行控制,所以就有了如何打完自动 安全 关机的必要性。注意,这里的安全是先关闭上位机电脑的 Linux 操作系统,再关闭总电源。
【更新 2022年3月18日】合并自动化规则,添加状态同步规则
1、手动安全关机方法的优化 —— 调用 Method
前文介绍过,手动关闭上位机系统有四种方式:物理关机按钮,网页关机按钮、KlipperScreen 彩色触摸屏按钮和 12864 等 LCD 屏幕菜单。
其中 使用 Klipper 监听按钮状态
和 mini12864 屏幕菜单
两种方法都需要 shell_cmd 组件,而此组件的缺点也很明显:
- 需要 Klipper Python2 ,默认不支持中文 Gcode 文件
- shell_cmd 组件不支持需要输入用户密码的命令
- shell_cmd 造成系统安全性下降
- 该组件需要自行安装
那么有没有什么法子不安装额外的东西,即可以实现关闭系统吗?我们上面了解到 Moonraker (下文称 mrk) API 的 machine.shutdown
方法,而且 Fluidd 网页
/KlipperScreen 按钮
关机的方法就是创建用户组 mnrkrsudo、klipperscreensudo
,执行一些系统命令不需要密码,如下所示:
fly@flygemini:~$ sudo ls /etc/sudoers.d/
020-sudo-for-moonraker 021-sudo-for-klipperscreen README
fly@flygemini:~$ sudo cat /etc/sudoers.d/020-sudo-for-moonraker
### Elevate moonraker API rights
### Do NOT allow Command Parts only Full Commands
### for example
###
### /sbin/systemctl "reboot", /sbin/apt "update", .....
Defaults!/usr/bin/apt-get env_keep +="DEBIAN_FRONTEND"
Cmnd_Alias REBOOT = /sbin/shutdown -r now, /bin/systemctl "reboot"
Cmnd_Alias SHUTDOWN = /sbin/shutdown now, /sbin/shutdown -h now, /bin/systemctl "poweroff"
Cmnd_Alias APT = /usr/bin/apt-get
Cmnd_Alias SYSTEMCTL = /bin/systemctl
%mnrkrsudo ALL=(ALL) NOPASSWD: REBOOT, SHUTDOWN, APT, SYSTEMCTL
1.1 Klipper 全家桶 API 介绍
我们常见的有 Klipper API Server、Moonraker Client API ,具体可以查看链接内文档,而其中的 machine.shutdown 就是属于 mrk api 。由此 mrk client 可以调用 klippy 提供的 API,同时可以被用户调用其 api。那么 klippy 可以调用 mrk api 来实现执行关机命令吗?也是可以的,还记得之前我们从 Klipper 内关闭打印机电源的示例吗,其有一个命令:action_call_remote_method
,查看 Klipper 文档,是这么说的:
action_call_remote_method(method_name)
: Calls a method registered by a remote client. If the method takes parameters they should be provided via keyword arguments, ie: action_call_remote_method("print_stuff", my_arg="hello_world")
意思就是除了上面两种 API 之外,Moonraker 还可以在 Klippy 那注册一个方法,告诉它(Klippy):我(Mrk)这里有此方法,可以被调用。
我们以已知方法(method)set_device_power
为关键词搜索 mrk 源码,可知关键词为 register_remote_method
,再以此搜索即获得支持的方法如下:
- moonraker_test
- shutdown_machine
- reboot_machine
- process_gcode_response
- process_status_update
- pause_job_queue
- start_job_queue
- set_wled_state
- set_wled
- publish_mqtt_topic
- paneldue_beep
- set_device_power
至此我们找到了想要的两个可以被 Klipper 调用的方法。
【更新:2022年3月13日】
笔者测试时还没有相关文档,2022-02-26 官方更新了 此部分文档 ,并补充了注意事项,建议阅读。虽然如此,我们查找答案的方法还是有记录借鉴意义的。
1.2 调用 Method
实现关机
物理关机按钮:
# ~/klipper_config/printer.cfg
[gcode_macro SHUTDOWN]
gcode:
{action_call_remote_method("shutdown_machine")}
# 定义物理按钮 【监听引脚状态】
[gcode_button poweroff_button]
# 按钮信号连接引脚
pin: host:gpio
# 按下时执行 gcode 宏命令
#press_gcode:
# 松开时执行 gcode 宏命令
release_gcode:
SHUTDOWN
测试通过,控制台输入 SHUTDOWN
或者被调用即可以实现关闭系统指令。
12864 屏幕菜单关机:
# printer.cfg
### menu poweroff by 思兼 v2 ###
[menu __main __poweroff]
type: list
enable: {not printer.idle_timeout.state == "Printing"}
name: PowerOff
[menu __main __poweroff __no]
type: command
name: NO
enable: {not printer.idle_timeout.state == "Printing"}
gcode:
{menu.back()}
[menu __main __poweroff __yes]
type: command
name: YES
enable: {not printer.idle_timeout.state == "Printing"}
gcode:
SHUTDOWN
2、 传统打完关机方案
我们先说说传统的打完关机功能,适用于 【上位机独立供电的情况】,多数朋友借助原来 Marlin 上用的 打完关机模块/继电器
,或者使用 智能插座
,我们说说各自的优缺点:
2.1 打完关机模块
优点:
缺点:
- 接线麻烦
- 价格较高 (79 + 9元)
- 为了安全关闭上位机系统,需要上位机独立供电:
- 如果由上位机 GPIO 引脚控制,支持开、关机操作,上传打印任务后自动开机
- 如果由主板引脚控制,仅支持关机,且要求主板支持从上位机取电,但此时会造成 5v 和 VCC 混合供电,导致潜在的信号干扰
示例如下:
# 上位机独立供电打完关机方案,by 思兼
#####################################################################
# 方法1,打印机主板 PS_ON 接口
#####################################################################
# 使用主板 PS_ON 引脚,需要上位机通过 USB 接口为主板供电,但此时会出现 5v
# 和 12/24v 同时供电的问题
[output_pin mks_pwc]
pin: PS_ON
pwm: False
value: 1
shutdown_value: 0
[gcode_macro M81]
description: PowerOff
gcode:
M84
SET_PIN PIN=mks_pwc VALUE=0
#####################################################################
# 方法2,上位机 GPIO 接口【推荐】
#####################################################################
# 使用上位机 GPIO 接口控制,支持开/关机,尤其适合上位机内置。需要额外修改
# moonraker.cfg 配置文件,可以手动在右上角菜单控制开关机
[gcode_macro M81]
gcode:
{action_call_remote_method("set_device_power",
device="printer",
state="off")}
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# 以下为修改 moonraker.cfg内容,“printer”名称对应。以及不能使用 UART 等引脚
[power printer]
type: gpio
pin: gpio26
off_when_shutdown: True
initial_state: off
#####################################################################
# 延时(挤出头降温)自动关机
#####################################################################
[delayed_gcode delayed_printer_off]
# 判断当前为空闲状态,才执行断电操作
initial_duration: 0.
gcode:
{% if printer.idle_timeout.state == "Idle" %}
M81
{% endif %}
[idle_timeout]
# https://www.klipper3d.org/Command_Templates.html?h=update_delayed_gcode#delayed-gcodes
# https://github.com/Klipper3d/klipper/issues/3865 | Firmware Restart 之后,要先home之后才会进入空闲状态
# 空闲状态360s后关闭电机和加热头,60s后关闭电源
gcode:
M84
TURN_OFF_HEATERS
UPDATE_DELAYED_GCODE ID=delayed_printer_off DURATION=60
timeout: 360
2.2 智能插座
优点:
- 价格相对便宜(30~50元)
- 无需额外接线
- 支持电量统计(可选)
缺点:
使用方法有以下几种,各有其不足:
- 预估打印完成时间定时关机 —— 不准确
- 使用具有电量检测功能的插座,当打印机处于低耗电时,认为打印完成,实现关机 —— 相对准确,成本提高
- 使用 Home Assistant 等智能家居系统,Klipper 打印完成后,调用 Moonraker 向 HA 发送关闭智能插座命令 —— 准确,但是需要 HA
其他用法欢迎补充。前两种方法自己从 APP 里设置即可,第三种方法我们下面一起介绍。
3、Gemini 等主板打完自动安全关机方案
此类主板的问题就是上位机和主板供电一起的,无论使用 打完关机模块
还是 智能插座
:
- 先断电 | 导致系统意外断电关机
- 先关闭系统 | 导致模块无法收到断电指令
我们分析一下理想的关机断电方案(横轴为时间):
之前想过用 延时继电器
(加自锁?)实现,但是想想还是智能插座更方便。同样有三种方案:
3.1 TPLink 智能插座
无需烧录固件和搭建 HA 系统,可以直接被 mrk 调用,但是 TPLink 更新了固件 之后有无法在局域网使用的可能。
3.2 智能插座烧录 Tasmota 固件
优缺点:
- 不需要家里有 HA 智能家居系统
- 需要拆开智能插座烧录固件,需要额外的工具,且有破拆外壳风险
- 仅支持 ESP8266/ESP32 等方案的智能插座,实测 ESP8266 烧录成功,ESP32 不行,需要进一步测试。
目前了解到的是 gosund
和 全橙
的部分智能插座使用 ESP8266 芯片。tasmota 目前支持的设备列表可以在 这里 查看。
3.2.1 为 ESP8266 设备烧录 Tasmota 固件
烧录软件:
- ESP-Flasher - GUI flasher for Tasmota based on esptool.py for ESP82XX and ESP32. (Windows or Mac)
- Tasmotizer - flashing and firmware download tool for ESP82XX only. (Windows, Linux or Mac) | 只支持 ESP8266
- Tasmota Web Installer - flash Tasmota using a Chrome based browser for ESP82XX and ESP32 | 在线烧录页面
任选其一即可。
下载固件:
烧录固件:
有的 ESP8266 模块自带串口芯片(如 NodeMCU),如果没有(如 Weduino)则自备 USB串口模块进行烧录。ESP8266 模块仅支持 3.3v,务必不要接错,建议独立供电,不建议由串口模块供电,烧录时 GPIO0
置于低电平进入烧写模式,借用一下老图。
连接设置 Tasmota
烧录完成后,重新上电稍等片刻可以看到一个 tasmota_XXXXXX-####
的热点,连接上去并打开网址:http://192.168.4.1
即可进入 Tasmota 设置界面。
注意:
- 热点只会存在 3分钟,需要重启模块才会再次出现。
- 新界面会提示你输入当前无线网络的用户名和密码,注意是 2.4GHz 的,ESP8266 不支持 5GHz 无线网络。
- 连接无线网络后分配的地址可以在路由器管理页面内或者使用
Fing
等局域网扫描软件查看。
进入后可以进行一些设置,这里我就不演示了。
3.2.2 设置 Moonraker
# moonraker.cfg
[power tasmota_plug]
type: tasmota
address: 192.168.0.201 # 请设置正确的设备 IP 地址
initial_state: on
off_when_shutdown: True
timer: 10 # 请设置合适的延时时间,单位 秒
注意这里一个官方文档里没有提到的隐藏参数:timer
,可以实现发送断电命令后,插座延时断电的功能。具体参考 power.py add parameter timer 和源码。注意,这里的 timer
和 GPIO Device Configuration 里的作用不一样:
A time (in seconds) after which the device will power off after being. switched on. This effectively turns the device into a momentary switch. This option is available for gpio, klipper_device, tplink_smartplug, shelly, and tasmota devices. The timer may be a floating point value for gpio types, it should be an integer for all other types. The default is no timer is set.
后者实现的是类似开启后延时自动断开的功能,无法在触发条件后才断开。
- 灯珠发绿色光为开启状态,蓝色为断开状态
- 设置断开后,延时 5s 才断开
3.3 使用 Home Assistant 控制智能插座
优缺点:
- 需要 HA 智能家居系统,如果之前家里就有就很方便
- 兼容性强,支持多种智能插座,大多数天猫精灵、小爱同学的都支持
- 不需要额外烧录固件,不需要拆开智能插座
整体来说,此方案更优秀。
3.3.1 搭建 Home Assistant 系统
方法众多,此处略去不表。我使用 树莓派4 + 中文镜像 进行测试。后续会在家里的软路由上进行安装,感觉树莓派镜像还挺麻烦的,由于国内网络不好导致安装体验差。这个教程 也有帮助。
3.3.2 添加智能插座设备
这里我以天猫精灵赠送的 BroadLink SP mini 3
为例:
添加智能插座
-
下载 博联智能
APP,在其中可以连接配置此智能插座并看到设备 MAC 地址。同时点击右上角 ...
图标—— 属性
—— 关闭 设备上锁
。同时根据 MAC 地址确认设备 IP 地址。
-
打开 http://homeassistant.local:8123/ 管理页面,选择 配置
—— 设备与服务
—— 添加集成
(右下角)—— Broadlink
,输入设备 IP 即可连接。
如是即可在 HA 主面板控制智能插座开关了。
延时关闭智能插座思路
由于我也是半路出家,第一次用 HA,网上搜到的都是开启后定时自动关闭,不是我想要的功能。思索一番,能想到的延时方法就是创建一个中间开关实体命名为 Relay
,再为它创建一个自动化规则,当 Moonraker 发送关闭命令后:
- Condition:Relay 从 on 到 off
- Action:延时 10s,关闭智能插座
创建 HA 辅助元素
- 开关名称随便起,这里是
Gemini_Relay
- 图标随便选
创建自动化规则
同样界面选择 自动化
标签 —— 创建自动化
—— 从空的自动化开始
,右上角选择 以 YAML 编辑
,你也可以事后查看图形化过程。
输入以下内容:
alias: 延时关闭插座
description: '收到 mrk 关闭指令,延时关闭智能插座'
trigger:
- platform: state
entity_id: input_boolean.gemini_relay
from: 'on'
to: 'off'
condition: []
action:
- delay:
hours: 0
minutes: 0
seconds: 10
milliseconds: 0
- type: turn_off
device_id: cbd09a4013a7cba034a1e42090227354
entity_id: switch.wi_fizhi_neng_cha_zuo_switch
domain: switch
mode: single
注意 device_id
和 entity_id
可以从图形界面直接选择。对应的正常打开智能插座配置如下,虽然用不上:
alias: 正常打开智能插座
description: ''
trigger:
- platform: state
entity_id: input_boolean.gemini_relay
from: 'off'
to: 'on'
condition: []
action:
- type: turn_on
device_id: cbd09a4013a7cba034a1e42090227354
entity_id: switch.wi_fizhi_neng_cha_zuo_switch
domain: switch
mode: single
【V2】
alias: 延时关闭智能插座
description: 收到 mrk 关闭指令,延时关闭智能插座。正常打开插座
trigger:
- platform: state
entity_id: input_boolean.gemini_relay
condition: []
action:
- choose:
- conditions:
- condition: state
entity_id: input_boolean.gemini_relay
state: 'on'
sequence:
- type: turn_on
device_id: cbd09a4013a7cba034a1e42090227354
entity_id: switch.wi_fizhi_neng_cha_zuo_switch
domain: switch
- conditions:
- condition: state
entity_id: input_boolean.gemini_relay
state: 'off'
sequence:
- delay:
hours: 0
minutes: 0
seconds: 15
milliseconds: 0
- type: turn_off
device_id: cbd09a4013a7cba034a1e42090227354
entity_id: switch.wi_fizhi_neng_cha_zuo_switch
domain: switch
default: []
mode: single
再创建一个同步插座状态的规则,因为有时候会手动通过插座按钮关闭。
alias: 同步智能插座状态
description: ''
trigger:
- platform: device
type: changed_states
device_id: cbd09a4013a7cba034a1e42090227354
entity_id: switch.wi_fizhi_neng_cha_zuo_switch
domain: switch
condition: []
action:
- choose:
- conditions:
- condition: device
type: is_on
device_id: cbd09a4013a7cba034a1e42090227354
entity_id: switch.wi_fizhi_neng_cha_zuo_switch
domain: switch
sequence:
- service: input_boolean.turn_on
data: {}
target:
entity_id: input_boolean.gemini_relay
- conditions:
- condition: device
type: is_off
device_id: cbd09a4013a7cba034a1e42090227354
entity_id: switch.wi_fizhi_neng_cha_zuo_switch
domain: switch
sequence:
- service: input_boolean.turn_off
data: {}
target:
entity_id: input_boolean.gemini_relay
default: []
mode: single
创建 HA 长期访问令牌
注意:
- 此令牌无法再次查看,请妥善保存
- 此令牌非常长,复制的时候注意复制完全
创建 Moonraker 配置
想要控制 HA 设备,需要用到上面 HA 创建的令牌(Token),官方给的 HA 配置 直接控制智能插座,无法实现延时功能。我们照葫芦画瓢整一个:
# moonraker.cfg
[power homeassistant_switch]
type: homeassistant
address: 【HA IP】
port: 8123
device: input_boolean.Gemini_Relay
domain: input_boolean
token: 【TOKEN】
注意:
- [HA IP] 请设置为你 HA 所在的设备 IP 地址
- [TOKEN] 请设置为上面创建的令牌
homeassistant_switch
| 随便起,支持中文例如 智能插座
Gemini_Relay
| 请改为你创建的实体名称
至此,我们的智能插座通过一个虚拟中继,比较完美的实现了 Gemini 之类的主板安全关机,同时我关于 Klipper 电源管理方面的文章也告一段落。