Replace Docker-based zigbee2mqtt with a KISS LXC approach using Alpine Linux container with Node.js + zigbee2mqtt, matching the HAProxy LXC pattern. Adds USB serial passthrough for Sonoff Dongle Lite MG21. - zigbee2mqttctl: Full LXC lifecycle (install, update, check, shell) - RPCD: LXC diagnostics (lxc, cp210x, serial, container, service) - api.js: Fix callApply missing params (payload was silently dropped) - overview.js: Match new LXC diagnostics, fix applyConfig call - Makefiles: Replace +dockerd +docker +containerd with +lxc +kmod-usb-serial-cp210x Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
180 lines
5.1 KiB
Bash
Executable File
180 lines
5.1 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
. /usr/share/libubox/jshn.sh
|
|
|
|
CONFIG="zigbee2mqtt"
|
|
SERVICE="/etc/init.d/zigbee2mqtt"
|
|
CTL="/usr/sbin/zigbee2mqttctl"
|
|
LXC_NAME="zigbee2mqtt"
|
|
|
|
case "$1" in
|
|
list)
|
|
cat <<'JSON'
|
|
{
|
|
"status": {},
|
|
"apply": {},
|
|
"logs": {},
|
|
"control": {},
|
|
"update": {},
|
|
"install": {},
|
|
"check": {}
|
|
}
|
|
JSON
|
|
;;
|
|
call)
|
|
handle_call() {
|
|
case "$1" in
|
|
status)
|
|
local serial_port=$(uci -q get ${CONFIG}.main.serial_port)
|
|
serial_port=${serial_port:-/dev/ttyUSB0}
|
|
|
|
json_init
|
|
|
|
# Config
|
|
json_add_string "serial_port" "$serial_port"
|
|
json_add_string "mqtt_host" "$(uci -q get ${CONFIG}.main.mqtt_host)"
|
|
json_add_string "base_topic" "$(uci -q get ${CONFIG}.main.base_topic)"
|
|
json_add_string "frontend_port" "$(uci -q get ${CONFIG}.main.frontend_port)"
|
|
json_add_string "channel" "$(uci -q get ${CONFIG}.main.channel)"
|
|
json_add_string "data_path" "$(uci -q get ${CONFIG}.main.data_path)"
|
|
json_add_string "permit_join" "$(uci -q get ${CONFIG}.main.permit_join)"
|
|
json_add_boolean "enabled" "$([ "$(uci -q get ${CONFIG}.main.enabled)" = "1" ] && echo 1 || echo 0)"
|
|
|
|
# Service state
|
|
json_add_object "service"
|
|
json_add_boolean "enabled" "$("$SERVICE" enabled >/dev/null 2>&1 && echo 1 || echo 0)"
|
|
local running=0
|
|
lxc-info -n "$LXC_NAME" -s 2>/dev/null | grep -q "RUNNING" && running=1
|
|
json_add_boolean "running" "$running"
|
|
json_close_object
|
|
|
|
# Diagnostics
|
|
json_add_object "diagnostics"
|
|
json_add_boolean "lxc" "$(command -v lxc-start >/dev/null 2>&1 && echo 1 || echo 0)"
|
|
json_add_boolean "serial_device" "$([ -c "$serial_port" ] && echo 1 || echo 0)"
|
|
json_add_boolean "cp210x_module" "$(lsmod 2>/dev/null | grep -q 'cp210x' && echo 1 || echo 0)"
|
|
json_add_boolean "container_exists" "$([ -d "/srv/lxc/$LXC_NAME/rootfs" ] && echo 1 || echo 0)"
|
|
json_add_boolean "service_file" "$([ -x "$SERVICE" ] && echo 1 || echo 0)"
|
|
json_close_object
|
|
|
|
json_dump
|
|
;;
|
|
apply)
|
|
local input
|
|
read input
|
|
json_load "$input"
|
|
|
|
local serial_port mqtt_host mqtt_username mqtt_password
|
|
local base_topic frontend_port channel data_path permit_join enabled
|
|
json_get_var serial_port serial_port
|
|
json_get_var mqtt_host mqtt_host
|
|
json_get_var mqtt_username mqtt_username
|
|
json_get_var mqtt_password mqtt_password
|
|
json_get_var base_topic base_topic
|
|
json_get_var frontend_port frontend_port
|
|
json_get_var channel channel
|
|
json_get_var data_path data_path
|
|
json_get_var permit_join permit_join
|
|
json_get_var enabled enabled
|
|
|
|
[ -n "$serial_port" ] && uci set ${CONFIG}.main.serial_port="$serial_port"
|
|
[ -n "$mqtt_host" ] && uci set ${CONFIG}.main.mqtt_host="$mqtt_host"
|
|
uci set ${CONFIG}.main.mqtt_username="${mqtt_username}"
|
|
uci set ${CONFIG}.main.mqtt_password="${mqtt_password}"
|
|
[ -n "$base_topic" ] && uci set ${CONFIG}.main.base_topic="$base_topic"
|
|
[ -n "$frontend_port" ] && uci set ${CONFIG}.main.frontend_port="$frontend_port"
|
|
[ -n "$channel" ] && uci set ${CONFIG}.main.channel="$channel"
|
|
[ -n "$data_path" ] && uci set ${CONFIG}.main.data_path="$data_path"
|
|
[ -n "$permit_join" ] && uci set ${CONFIG}.main.permit_join="$permit_join"
|
|
[ -n "$enabled" ] && uci set ${CONFIG}.main.enabled="$enabled"
|
|
uci commit ${CONFIG}
|
|
|
|
if [ "$enabled" = "1" ]; then
|
|
"$SERVICE" enable >/dev/null 2>&1
|
|
else
|
|
"$SERVICE" disable >/dev/null 2>&1
|
|
fi
|
|
|
|
"$SERVICE" restart >/dev/null 2>&1 &
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_dump
|
|
;;
|
|
logs)
|
|
local input tail
|
|
read input
|
|
json_load "$input"
|
|
json_get_var tail tail
|
|
tail=${tail:-200}
|
|
|
|
json_init
|
|
local logfile="/srv/zigbee2mqtt/data/zigbee2mqtt.log"
|
|
if [ -f "$logfile" ]; then
|
|
json_add_string "log" "$(tail -n "$tail" "$logfile" 2>/dev/null)"
|
|
else
|
|
json_add_string "log" "No log file found"
|
|
fi
|
|
json_dump
|
|
;;
|
|
control)
|
|
local input action
|
|
read input
|
|
json_load "$input"
|
|
json_get_var action action
|
|
|
|
case "$action" in
|
|
start) "$SERVICE" start >/dev/null 2>&1 & ;;
|
|
stop) "$SERVICE" stop >/dev/null 2>&1 ;;
|
|
restart) "$SERVICE" restart >/dev/null 2>&1 & ;;
|
|
*)
|
|
json_init
|
|
json_add_boolean "success" 0
|
|
json_add_string "error" "invalid action"
|
|
json_dump
|
|
return
|
|
;;
|
|
esac
|
|
|
|
json_init
|
|
json_add_boolean "success" 1
|
|
json_dump
|
|
;;
|
|
update)
|
|
local output rc
|
|
output=$("$CTL" update 2>&1)
|
|
rc=$?
|
|
json_init
|
|
json_add_boolean "success" "$([ "$rc" -eq 0 ] && echo 1 || echo 0)"
|
|
[ -n "$output" ] && json_add_string "output" "$output"
|
|
json_dump
|
|
;;
|
|
install)
|
|
local output rc
|
|
output=$("$CTL" install 2>&1)
|
|
rc=$?
|
|
json_init
|
|
json_add_boolean "success" "$([ "$rc" -eq 0 ] && echo 1 || echo 0)"
|
|
[ -n "$output" ] && json_add_string "output" "$output"
|
|
json_dump
|
|
;;
|
|
check)
|
|
local output rc
|
|
output=$("$CTL" check 2>&1)
|
|
rc=$?
|
|
json_init
|
|
json_add_boolean "success" "$([ "$rc" -eq 0 ] && echo 1 || echo 0)"
|
|
[ -n "$output" ] && json_add_string "output" "$output"
|
|
json_dump
|
|
;;
|
|
*)
|
|
json_init
|
|
json_add_string "error" "unknown method"
|
|
json_dump
|
|
;;
|
|
esac
|
|
}
|
|
handle_call "$2"
|
|
;;
|
|
esac
|