224 lines
6.1 KiB
Bash
224 lines
6.1 KiB
Bash
#!/bin/sh
|
|
|
|
CONFIG="led-scheduler"
|
|
SECTION="main"
|
|
LED_ROOT="/sys/class/leds"
|
|
CRON_FILE="/etc/crontabs/root"
|
|
CRON_BEGIN="# BEGIN luci-app-led-scheduler"
|
|
CRON_END="# END luci-app-led-scheduler"
|
|
|
|
log() { logger -t led-scheduler "$*"; }
|
|
uci_get() { uci -q get "${CONFIG}.${SECTION}.$1" 2>/dev/null; }
|
|
|
|
valid_led_name() {
|
|
case "$1" in
|
|
""|*/*|*".."*|*[!A-Za-z0-9:_.-]*) return 1 ;;
|
|
esac
|
|
return 0
|
|
}
|
|
|
|
available_led() {
|
|
valid_led_name "$1" || return 1
|
|
[ -d "${LED_ROOT}/$1" ]
|
|
}
|
|
|
|
configured_leds() {
|
|
local section sysfs
|
|
uci -q show system 2>/dev/null |
|
|
sed -n 's/^system\.\([^=]*\)=led$/\1/p' |
|
|
while IFS= read -r section; do
|
|
sysfs="$(uci -q get "system.${section}.sysfs" 2>/dev/null)"
|
|
[ -n "$sysfs" ] || continue
|
|
available_led "$sysfs" || continue
|
|
printf '%s\n' "$sysfs"
|
|
done |
|
|
awk '!seen[$0]++'
|
|
}
|
|
|
|
selected_leds() {
|
|
local all selected led
|
|
all="$(uci_get all_system_leds)"
|
|
[ -n "$all" ] || all="1"
|
|
if [ "$all" = "1" ]; then
|
|
configured_leds
|
|
return 0
|
|
fi
|
|
selected="$(uci_get led)"
|
|
for led in $selected; do
|
|
available_led "$led" || continue
|
|
printf '%s\n' "$led"
|
|
done | awk '!seen[$0]++'
|
|
}
|
|
|
|
restore_native() {
|
|
if [ -x /etc/init.d/led ]; then
|
|
/etc/init.d/led restart >/dev/null 2>&1
|
|
return $?
|
|
fi
|
|
echo "OpenWrt LED service /etc/init.d/led not found" >&2
|
|
return 1
|
|
}
|
|
|
|
turn_off() {
|
|
local led path
|
|
restore_native >/dev/null 2>&1 || true
|
|
selected_leds | while IFS= read -r led; do
|
|
available_led "$led" || continue
|
|
path="${LED_ROOT}/${led}"
|
|
[ -w "${path}/trigger" ] && printf '%s\n' none > "${path}/trigger" 2>/dev/null
|
|
[ -w "${path}/brightness" ] && printf '%s\n' 0 > "${path}/brightness" 2>/dev/null
|
|
done
|
|
log "selected LEDs turned off"
|
|
}
|
|
|
|
turn_on() {
|
|
if restore_native; then
|
|
log "native OpenWrt LED configuration restored"
|
|
return 0
|
|
fi
|
|
log "failed to restore native LED configuration"
|
|
return 1
|
|
}
|
|
|
|
validate_time() {
|
|
local t="$1" h m
|
|
case "$t" in [0-9][0-9]:[0-9][0-9]) ;; *) return 1 ;; esac
|
|
h="${t%:*}"; m="${t#*:}"
|
|
h="${h#0}"; m="${m#0}"
|
|
[ -n "$h" ] || h=0; [ -n "$m" ] || m=0
|
|
[ "$h" -ge 0 ] 2>/dev/null || return 1
|
|
[ "$h" -le 23 ] 2>/dev/null || return 1
|
|
[ "$m" -ge 0 ] 2>/dev/null || return 1
|
|
[ "$m" -le 59 ] 2>/dev/null || return 1
|
|
return 0
|
|
}
|
|
|
|
time_parts() {
|
|
local t="$1" h m
|
|
h="${t%:*}"; m="${t#*:}"
|
|
h="${h#0}"; m="${m#0}"
|
|
[ -n "$h" ] || h=0; [ -n "$m" ] || m=0
|
|
printf '%s %s\n' "$h" "$m"
|
|
}
|
|
|
|
strip_cron_block() {
|
|
local tmp="/tmp/led-scheduler-cron.$$"
|
|
mkdir -p "$(dirname "$CRON_FILE")"
|
|
touch "$CRON_FILE"
|
|
awk -v begin="$CRON_BEGIN" -v end="$CRON_END" '
|
|
$0 == begin { skip=1; next }
|
|
$0 == end { skip=0; next }
|
|
!skip { print }
|
|
' "$CRON_FILE" > "$tmp"
|
|
cat "$tmp" > "$CRON_FILE"
|
|
rm -f "$tmp"
|
|
}
|
|
|
|
reload_cron() { [ -x /etc/init.d/cron ] && /etc/init.d/cron restart >/dev/null 2>&1; }
|
|
|
|
clear_cron() {
|
|
strip_cron_block
|
|
reload_cron
|
|
log "cron entries removed"
|
|
}
|
|
|
|
sync_cron() {
|
|
local enabled off_time on_time off_h off_m on_h on_m
|
|
enabled="$(uci_get enabled)"; [ -n "$enabled" ] || enabled="0"
|
|
off_time="$(uci_get off_time)"; on_time="$(uci_get on_time)"
|
|
[ -n "$off_time" ] || off_time="23:00"
|
|
[ -n "$on_time" ] || on_time="07:00"
|
|
strip_cron_block
|
|
if [ "$enabled" != "1" ]; then reload_cron; log "scheduler disabled; cron entries removed"; return 0; fi
|
|
validate_time "$off_time" || { echo "Invalid off_time: $off_time" >&2; return 1; }
|
|
validate_time "$on_time" || { echo "Invalid on_time: $on_time" >&2; return 1; }
|
|
set -- $(time_parts "$off_time"); off_h="$1"; off_m="$2"
|
|
set -- $(time_parts "$on_time"); on_h="$1"; on_m="$2"
|
|
{
|
|
printf '%s\n' "$CRON_BEGIN"
|
|
printf '%s %s * * * /usr/bin/led-control off\n' "$off_m" "$off_h"
|
|
printf '%s %s * * * /usr/bin/led-control on\n' "$on_m" "$on_h"
|
|
printf '%s\n' "$CRON_END"
|
|
} >> "$CRON_FILE"
|
|
reload_cron
|
|
log "cron synchronized: off=${off_time}, on=${on_time}"
|
|
}
|
|
|
|
minutes_from_time() {
|
|
local t="$1" h m
|
|
set -- $(time_parts "$t"); h="$1"; m="$2"
|
|
echo $((h * 60 + m))
|
|
}
|
|
|
|
apply_current_state() {
|
|
local enabled off_time on_time now_h now_m now off on
|
|
enabled="$(uci_get enabled)"
|
|
if [ "$enabled" != "1" ]; then turn_on; return $?; fi
|
|
off_time="$(uci_get off_time)"; on_time="$(uci_get on_time)"
|
|
[ -n "$off_time" ] || off_time="23:00"
|
|
[ -n "$on_time" ] || on_time="07:00"
|
|
validate_time "$off_time" || return 1
|
|
validate_time "$on_time" || return 1
|
|
off="$(minutes_from_time "$off_time")"; on="$(minutes_from_time "$on_time")"
|
|
if [ "$off" -eq "$on" ]; then turn_on; return $?; fi
|
|
now_h="$(date +%H)"; now_m="$(date +%M)"
|
|
now_h="${now_h#0}"; now_m="${now_m#0}"
|
|
[ -n "$now_h" ] || now_h=0; [ -n "$now_m" ] || now_m=0
|
|
now=$((now_h * 60 + now_m))
|
|
if [ "$off" -lt "$on" ]; then
|
|
if [ "$now" -ge "$off" ] && [ "$now" -lt "$on" ]; then turn_off; else turn_on; fi
|
|
else
|
|
if [ "$now" -ge "$off" ] || [ "$now" -lt "$on" ]; then turn_off; else turn_on; fi
|
|
fi
|
|
}
|
|
|
|
list_configured() {
|
|
local section name sysfs trigger
|
|
uci -q show system 2>/dev/null |
|
|
sed -n 's/^system\.\([^=]*\)=led$/\1/p' |
|
|
while IFS= read -r section; do
|
|
name="$(uci -q get "system.${section}.name" 2>/dev/null)"
|
|
sysfs="$(uci -q get "system.${section}.sysfs" 2>/dev/null)"
|
|
trigger="$(uci -q get "system.${section}.trigger" 2>/dev/null)"
|
|
[ -n "$sysfs" ] || continue
|
|
printf '%s %s %s\n' "${name:-$sysfs}" "$sysfs" "${trigger:-unknown}"
|
|
done
|
|
}
|
|
|
|
status() {
|
|
echo "enabled=$(uci_get enabled)"
|
|
echo "off_time=$(uci_get off_time)"
|
|
echo "on_time=$(uci_get on_time)"
|
|
echo "all_system_leds=$(uci_get all_system_leds)"
|
|
echo "selected sysfs LEDs:"
|
|
selected_leds | sed 's/^/ - /'
|
|
}
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: led-control COMMAND
|
|
|
|
Commands:
|
|
list List LEDs defined by OpenWrt System -> LED Configuration
|
|
selected List LEDs currently selected by LED Scheduler
|
|
off Turn selected LEDs off
|
|
on Restore OpenWrt native LED configuration
|
|
apply Apply the correct state for the current time
|
|
sync Synchronize cron entries from UCI configuration
|
|
clear-cron Remove this application's cron entries
|
|
status Show scheduler configuration
|
|
EOF
|
|
}
|
|
|
|
case "$1" in
|
|
list) list_configured ;;
|
|
selected) selected_leds ;;
|
|
off) turn_off ;;
|
|
on) turn_on ;;
|
|
apply) apply_current_state ;;
|
|
sync) sync_cron ;;
|
|
clear-cron) clear_cron ;;
|
|
status) status ;;
|
|
*) usage; exit 1 ;;
|
|
esac
|