first commit

This commit is contained in:
douboer@gmail.com
2026-03-15 09:30:40 +08:00
commit 3d19c4d34f
145 changed files with 11623 additions and 0 deletions

122
dash/src/dash.sh Executable file
View File

@@ -0,0 +1,122 @@
#!/usr/bin/env sh
DEBUG=${DEBUG:-false}
[ "$DEBUG" = true ] && set -x
DIR="$(dirname "$0")"
DASH_PNG="$DIR/dash.png"
FETCH_DASHBOARD_CMD="$DIR/local/fetch-dashboard.sh"
LOW_BATTERY_CMD="$DIR/local/low-battery.sh"
REFRESH_SCHEDULE=${REFRESH_SCHEDULE:-"2,32 8-17 * * MON-FRI"}
FULL_DISPLAY_REFRESH_RATE=${FULL_DISPLAY_REFRESH_RATE:-0}
SLEEP_SCREEN_INTERVAL=${SLEEP_SCREEN_INTERVAL:-3600}
RTC=/sys/devices/platform/mxc_rtc.0/wakeup_enable
LOW_BATTERY_REPORTING=${LOW_BATTERY_REPORTING:-false}
LOW_BATTERY_THRESHOLD_PERCENT=${LOW_BATTERY_THRESHOLD_PERCENT:-10}
num_refresh=0
init() {
if [ -z "$TIMEZONE" ] || [ -z "$REFRESH_SCHEDULE" ]; then
echo "Missing required configuration."
echo "Timezone: ${TIMEZONE:-(not set)}."
echo "Schedule: ${REFRESH_SCHEDULE:-(not set)}."
exit 1
fi
echo "Starting dashboard with $REFRESH_SCHEDULE refresh..."
/etc/init.d/framework stop
initctl stop webreader >/dev/null 2>&1
echo powersave >/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
lipc-set-prop com.lab126.powerd preventScreenSaver 1
}
prepare_sleep() {
echo "Preparing sleep"
/usr/sbin/eips -f -g "$DIR/sleeping.png"
# Give screen time to refresh
sleep 2
# Ensure a full screen refresh is triggered after wake from sleep
num_refresh=$FULL_DISPLAY_REFRESH_RATE
}
refresh_dashboard() {
echo "Refreshing dashboard"
"$DIR/wait-for-wifi.sh" "$WIFI_TEST_IP"
"$FETCH_DASHBOARD_CMD" "$DASH_PNG"
fetch_status=$?
if [ "$fetch_status" -ne 0 ]; then
echo "Not updating screen, fetch-dashboard returned $fetch_status"
return 1
fi
if [ "$num_refresh" -eq "$FULL_DISPLAY_REFRESH_RATE" ]; then
num_refresh=0
# trigger a full refresh once in every 4 refreshes, to keep the screen clean
echo "Full screen refresh"
/usr/sbin/eips -f -g "$DASH_PNG"
else
echo "Partial screen refresh"
/usr/sbin/eips -g "$DASH_PNG"
fi
num_refresh=$((num_refresh + 1))
}
log_battery_stats() {
battery_level=$(gasgauge-info -c)
echo "$(date) Battery level: $battery_level."
if [ "$LOW_BATTERY_REPORTING" = true ]; then
battery_level_numeric=${battery_level%?}
if [ "$battery_level_numeric" -le "$LOW_BATTERY_THRESHOLD_PERCENT" ]; then
"$LOW_BATTERY_CMD" "$battery_level_numeric"
fi
fi
}
rtc_sleep() {
duration=$1
if [ "$DEBUG" = true ]; then
sleep "$duration"
else
# shellcheck disable=SC2039
[ "$(cat "$RTC")" -eq 0 ] && echo -n "$duration" >"$RTC"
echo "mem" >/sys/power/state
fi
}
main_loop() {
while true; do
log_battery_stats
next_wakeup_secs=$("$DIR/next-wakeup" --schedule="$REFRESH_SCHEDULE" --timezone="$TIMEZONE")
if [ "$next_wakeup_secs" -gt "$SLEEP_SCREEN_INTERVAL" ]; then
action="sleep"
prepare_sleep
else
action="suspend"
refresh_dashboard
fi
# take a bit of time before going to sleep, so this process can be aborted
sleep 10
echo "Going to $action, next wakeup in ${next_wakeup_secs}s"
rtc_sleep "$next_wakeup_secs"
done
}
init
main_loop

23
dash/src/local/env.sh Normal file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env sh
# Export environment variables here
export WIFI_TEST_IP=${WIFI_TEST_IP:-1.1.1.1}
# 测试配置:全天每分钟刷新一次,便于验证图片拉取与屏幕刷新是否正常。
export REFRESH_SCHEDULE=${REFRESH_SCHEDULE:-"* * * * *"}
export TIMEZONE=${TIMEZONE:-"Asia/Shanghai"}
# By default, partial screen updates are used to update the screen,
# to prevent the screen from flashing. After a few partial updates,
# the screen will start to look a bit distorted (due to e-ink ghosting).
# 测试阶段强制每次都做一次全刷,避免首页残影和局部刷新的旧内容干扰验证。
# 等图片尺寸与刷新逻辑确认无误后,再改回 4 之类的值以节省功耗。
export FULL_DISPLAY_REFRESH_RATE=${FULL_DISPLAY_REFRESH_RATE:-0}
# When the time until the next wakeup is greater or equal to this number,
# the dashboard will not be refreshed anymore, but instead show a
# 'kindle is sleeping' screen. This can be useful if your schedule only runs
# during the day, for example.
export SLEEP_SCREEN_INTERVAL=3600
export LOW_BATTERY_REPORTING=${LOW_BATTERY_REPORTING:-false}
export LOW_BATTERY_THRESHOLD_PERCENT=10

View File

@@ -0,0 +1,4 @@
#!/usr/bin/env sh
# Fetch a new dashboard image, make sure to output it to "$1".
# For example:
"$(dirname "$0")/../xh" -d -q -o "$1" get https://raw.githubusercontent.com/pascalw/kindle-dash/master/example/example.png

View File

@@ -0,0 +1,17 @@
#!/usr/bin/env sh
battery_level_percentage=$1
last_battery_report_state="$(dirname "$0")/state/last_battery_report"
previous_report_timestamp=$(cat "$last_battery_report_state" 2>/dev/null || echo '-1')
now=$(date +%s)
# Implement desired logic here. The example below for example only reports low
# battery every 24 hours.
if [ "$previous_report_timestamp" -eq -1 ] ||
[ $((now - previous_report_timestamp)) -gt 86400 ]; then
# Replace this with for example an HTTP call via curl, or xh
echo "Reporting low battery: $battery_level_percentage%"
echo "$now" >"$last_battery_report_state"
fi

1
dash/src/next-wakeup/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/target

143
dash/src/next-wakeup/Cargo.lock generated Normal file
View File

@@ -0,0 +1,143 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "chrono"
version = "0.4.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
dependencies = [
"libc",
"num-integer",
"num-traits",
"time",
"winapi",
]
[[package]]
name = "chrono-tz"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2554a3155fec064362507487171dcc4edc3df60cb10f3a1fb10ed8094822b120"
dependencies = [
"chrono",
"parse-zoneinfo",
]
[[package]]
name = "cron-parser"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8446d1ce86096fd2260e732c6f5dffc752cbfa6cb14371d057bc1de3a1831b6"
dependencies = [
"chrono",
]
[[package]]
name = "kindle-dash-next-wakeup"
version = "0.1.0"
dependencies = [
"chrono",
"chrono-tz",
"cron-parser",
"pico-args",
]
[[package]]
name = "libc"
version = "0.2.82"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
[[package]]
name = "num-integer"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]]
name = "parse-zoneinfo"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41"
dependencies = [
"regex",
]
[[package]]
name = "pico-args"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d70072c20945e1ab871c472a285fc772aefd4f5407723c206242f2c6f94595d6"
[[package]]
name = "regex"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
[[package]]
name = "time"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
dependencies = [
"libc",
"wasi",
"winapi",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@@ -0,0 +1,15 @@
[package]
name = "kindle-dash-next-wakeup"
version = "0.1.0"
authors = ["Pascal Widdershoven <hello@pascalw.me>"]
edition = "2018"
[dependencies]
cron-parser = "0.7.7"
chrono = "0.4.19"
chrono-tz = "0.5.3"
pico-args = "0.4.0"
[[bin]]
name = "next-wakeup"
path = "src/main.rs"

View File

@@ -0,0 +1,54 @@
use chrono::Utc;
use chrono_tz::Tz;
const HELP: &str = "\
USAGE:
next-wakeup --schedule '2,32 8-17 * * MON-FRI' --timezone 'Europe/Amsterdam'
next-wakeup -s='2,32 8-17 * * MON-FRI' -tz='Europe/Amsterdam'
OPTIONS:
-tz, --timezone STRING Timezone used to interpret the cron schedule
-s, --schedule STRING Cron schedule to calculate next wakeup
-h, --help Prints help information
";
#[derive(Debug)]
struct Args {
timezone: Tz,
schedule: String,
}
fn main() {
let args = match parse_args() {
Ok(v) => v,
Err(e) => {
eprintln!("Error: {}.", e);
std::process::exit(1);
}
};
let schedule = args.schedule;
let now = Utc::now().with_timezone(&args.timezone);
let next = cron_parser::parse(&schedule, &now).expect("Invalid cron schedule");
let diff = next - now;
println!("{}", diff.num_seconds());
}
fn parse_args() -> Result<Args, pico_args::Error> {
let mut pargs = pico_args::Arguments::from_env();
if pargs.contains(["-h", "--help"]) {
print!("{}", HELP);
std::process::exit(1);
}
let args = Args {
timezone: pargs.value_from_str(["-tz", "--timezone"])?,
schedule: pargs.value_from_str(["-s", "--schedule"])?
};
Ok(args)
}

BIN
dash/src/sleeping.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

18
dash/src/start.sh Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/env sh
DEBUG=${DEBUG:-false}
[ "$DEBUG" = true ] && set -x
DIR="$(dirname "$0")"
ENV_FILE="$DIR/local/env.sh"
LOG_FILE="$DIR/logs/dash.log"
mkdir -p "$(dirname "$LOG_FILE")"
# shellcheck disable=SC1090
[ -f "$ENV_FILE" ] && . "$ENV_FILE"
if [ "$DEBUG" = true ]; then
"$DIR/dash.sh"
else
"$DIR/dash.sh" >>"$LOG_FILE" 2>&1 &
fi

2
dash/src/stop.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/usr/bin/env sh
pkill -f dash.sh

26
dash/src/wait-for-wifi.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/usr/bin/env sh
test_ip=$1
if [ -z "$test_ip" ]; then
echo "No test ip specified"
exit 1
fi
wait_for_wifi() {
max_retry=30
counter=0
ping -c 1 "$test_ip" >/dev/null 2>&1
# shellcheck disable=SC2181
while [ $? -ne 0 ]; do
[ $counter -eq $max_retry ] && echo "Couldn't connect to Wi-Fi" && exit 1
counter=$((counter + 1))
sleep 1
ping -c 1 "$test_ip" >/dev/null 2>&1
done
}
wait_for_wifi
echo "Wi-Fi connected"