Skip to content

Commit 9ac2161

Browse files
authored
Merge pull request #2 from Yaosanqi137/main
电费提醒和网费提醒
2 parents 226f170 + 2b0070c commit 9ac2161

5 files changed

Lines changed: 530 additions & 0 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ systemctl start oucshell.service
7171
systemctl enable oucshell.service
7272
```
7373

74+
# 效果演示
75+
76+
![img.png](show.png)
77+
7478
## 🤝 贡献者
7579

7680
<!-- readme: contributors -start -->

main.sh

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
#!/bin/bash
2+
3+
# ==========================================
4+
# 主控脚本
5+
# ==========================================
6+
7+
# --- 1. 路径定义 ---
8+
BASE_DIR=$(cd $(dirname $0); pwd)
9+
SRC_DIR="$BASE_DIR/src"
10+
CONFIG_FILE="$BASE_DIR/config.toml"
11+
LOG_FILE="$BASE_DIR/service.log"
12+
13+
# 日志
14+
log() {
15+
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
16+
}
17+
18+
trap "log '服务停止'; exit" SIGTERM SIGINT
19+
20+
# 依赖检查和安装
21+
check_and_install_dependencies() {
22+
local dependencies=("curl" "jq" "bc")
23+
local missing_packages=()
24+
25+
for pkg in "${dependencies[@]}"; do
26+
if ! command -v "$pkg" &> /dev/null; then
27+
missing_packages+=("$pkg")
28+
fi
29+
done
30+
31+
if [ ${#missing_packages[@]} -eq 0 ]; then
32+
log "环境检查通过: 依赖已就绪。"
33+
return 0
34+
fi
35+
36+
log "检测到缺失依赖: ${missing_packages[*]},尝试自动安装..."
37+
38+
local install_cmd=""
39+
if command -v apt-get &> /dev/null; then
40+
install_cmd="apt-get update && apt-get install -y"
41+
elif command -v yum &> /dev/null; then
42+
install_cmd="yum install -y"
43+
elif command -v dnf &> /dev/null; then
44+
install_cmd="dnf install -y"
45+
elif command -v apk &> /dev/null; then
46+
install_cmd="apk add --no-cache"
47+
else
48+
log "无法自动安装,请手动安装: ${missing_packages[*]}"
49+
exit 1
50+
fi
51+
52+
if [ "$EUID" -ne 0 ] && command -v sudo &> /dev/null; then
53+
install_cmd="sudo $install_cmd"
54+
fi
55+
56+
# 这里也将安装日志通过管道传递给 log 函数,保持日志格式统一
57+
eval "$install_cmd ${missing_packages[*]}" 2>&1 | while IFS= read -r line; do
58+
log "[依赖安装] $line"
59+
done
60+
61+
# 二次检查
62+
for pkg in "${missing_packages[@]}"; do
63+
if ! command -v "$pkg" &> /dev/null; then
64+
log "依赖 $pkg 安装失败,请检查网络或源。"
65+
exit 1
66+
fi
67+
done
68+
log "依赖安装完成。"
69+
}
70+
71+
# 配置文件生成与检查
72+
check_and_create_config() {
73+
if [ ! -f "$CONFIG_FILE" ]; then
74+
log "配置文件不存在,正在生成默认配置..."
75+
cat > "$CONFIG_FILE" << EOF
76+
# ==========================================
77+
# OUCShell配置文件
78+
# ==========================================
79+
80+
[Global]
81+
# 接收通知的邮箱
82+
TargetEmail = "your_email@example.com"
83+
84+
[SMTP]
85+
# 发件人邮箱服务器配置
86+
Host = "smtp.qq.com"
87+
Port = "465"
88+
User = "your_smtp_email@qq.com"
89+
Password = "your_smtp_auth_code"
90+
91+
# 电费提醒模块
92+
[Electricity]
93+
Enabled = true # 是否启用本模块
94+
Campus = "xha" # 校区选择
95+
# xha = 西海岸
96+
97+
[Electricity.xha]
98+
StudentID = "XXX" # 学号
99+
Token = "9f7c6e76979c4cb9dd3828f8cc44a5ef" # MD5(Sd1234) 居然加密这么简单吗?
100+
# [照明警戒值, 空调警戒值]
101+
RemindTime = [30.0, 30.0]
102+
103+
# 网费提醒模块
104+
[Internet]
105+
Enabled = true # 是否启用本模块
106+
Campus = "xha" # 校区选择
107+
# xha = 西海岸
108+
109+
[Internet.xha]
110+
StudentID = "XXX" # 学号
111+
# [最低余额, 触发天数]
112+
# 触发天数: 离下个月1号还有几天时开始检测。
113+
# e.g.
114+
# 填 -1 表示忽略日期,只要余额低就提醒。
115+
# 填 5 表示只有余额低 且 离月底少于5天时才提醒。
116+
RemindTime = [10, -1]
117+
EOF
118+
log "配置文件已生成: $CONFIG_FILE"
119+
log "检测到第一次运行,脚本将自动退出,请编辑配置文件后重新启动"
120+
exit 0
121+
else
122+
log "加载配置文件: $CONFIG_FILE"
123+
fi
124+
}
125+
126+
# 主函数
127+
128+
log "服务启动..."
129+
130+
check_and_install_dependencies
131+
check_and_create_config
132+
133+
# 电费提醒任务间隔 (秒)
134+
INTERVAL_ELEC=7200 # 2小时
135+
LAST_RUN_ELEC=0
136+
137+
# 网费提醒任务间隔 (秒)
138+
INTERVAL_NET=43200 # 半天
139+
LAST_RUN_NET=0
140+
141+
log "进入循环调度模式..."
142+
143+
while true; do
144+
CURRENT_TIME=$(date +%s)
145+
146+
# 电费监控
147+
148+
# 计算时间差
149+
TIME_DIFF=$((CURRENT_TIME - LAST_RUN_ELEC))
150+
151+
if [ $TIME_DIFF -ge $INTERVAL_ELEC ]; then
152+
SCRIPT_PATH="$SRC_DIR/elec_monitor.sh"
153+
154+
if [ -f "$SCRIPT_PATH" ]; then
155+
chmod +x "$SCRIPT_PATH"
156+
log "调度任务: 电费监控..."
157+
158+
/bin/bash "$SCRIPT_PATH" "$CONFIG_FILE" 2>&1 | while IFS= read -r line; do
159+
log "[elec_monitor] $line"
160+
done
161+
162+
log "任务结束: 电费监控"
163+
else
164+
log "警告: 找不到脚本 $SCRIPT_PATH"
165+
fi
166+
167+
LAST_RUN_ELEC=$(date +%s)
168+
fi
169+
170+
# 网费监控
171+
172+
# 计算时间差
173+
TIME_DIFF=$((CURRENT_TIME - LAST_RUN_NET))
174+
175+
if [ $TIME_DIFF -ge $INTERVAL_NET ]; then
176+
SCRIPT_PATH="$SRC_DIR/internet_monitor.sh"
177+
178+
if [ -f "$SCRIPT_PATH" ]; then
179+
chmod +x "$SCRIPT_PATH"
180+
log "调度任务: 网费监控..."
181+
182+
/bin/bash "$SCRIPT_PATH" "$CONFIG_FILE" 2>&1 | while IFS= read -r line; do
183+
log "[net_monitor] $line"
184+
done
185+
186+
log "任务结束: 网费监控"
187+
else
188+
log "警告: 找不到脚本 $SCRIPT_PATH"
189+
fi
190+
191+
LAST_RUN_NET=$(date +%s)
192+
fi
193+
194+
# 其他任务(预留)
195+
# TODO
196+
197+
sleep 60
198+
done

show.png

83.9 KB
Loading

src/elec_monitor.sh

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
#!/bin/bash
2+
3+
# ==========================================
4+
# 电费提醒功能脚本
5+
# ==========================================
6+
7+
CONFIG_PATH="$1"
8+
9+
# 检查参数
10+
if [ -z "$CONFIG_PATH" ]; then
11+
echo "错误: 未传入配置文件路径。"
12+
exit 1
13+
fi
14+
15+
if [ ! -f "$CONFIG_PATH" ]; then
16+
echo "错误: 配置文件不存在 ($CONFIG_PATH)"
17+
exit 1
18+
fi
19+
20+
# 配置读取
21+
get_val() {
22+
local section=$1
23+
local key=$2
24+
local safe_section=$(echo "$section" | sed 's/\./\\./g')
25+
26+
sed -n "/^\[$safe_section\]/,/^\[/p" "$CONFIG_PATH" \
27+
| grep "^$key" \
28+
| head -n 1 \
29+
| awk -F'=' '{print $2}' \
30+
| tr -d ' "' \
31+
| sed 's/#.*//' \
32+
| tr -d '\r'
33+
}
34+
35+
# 邮件发送函数
36+
send_email() {
37+
local subject=$1
38+
local content=$2
39+
40+
local smtp_host=$(get_val "SMTP" "Host")
41+
local smtp_port=$(get_val "SMTP" "Port")
42+
local smtp_user=$(get_val "SMTP" "User")
43+
local smtp_pass=$(get_val "SMTP" "Password")
44+
local target_email=$(get_val "Global" "TargetEmail")
45+
46+
if [ -z "$smtp_user" ] || [ -z "$target_email" ]; then
47+
echo "错误: 邮箱配置不完整,跳过发送。"
48+
return
49+
fi
50+
51+
echo "正在发送邮件到 $target_email ..."
52+
53+
local curl_url="smtp://$smtp_host:$smtp_port"
54+
if [ "$smtp_port" == "465" ]; then
55+
curl_url="smtps://$smtp_host:$smtp_port"
56+
fi
57+
58+
local mail_data="From: \"电费助手\" <$smtp_user>
59+
To: <$target_email>
60+
Subject: $subject
61+
MIME-Version: 1.0
62+
Content-Type: text/html; charset=utf-8
63+
64+
$content"
65+
66+
echo "$mail_data" | curl --silent --ssl-reqd \
67+
--url "$curl_url" \
68+
--user "$smtp_user:$smtp_pass" \
69+
--mail-from "$smtp_user" \
70+
--mail-rcpt "$target_email" \
71+
--upload-file -
72+
}
73+
74+
# 西海岸电费获取
75+
check_xha() {
76+
local sno=$(get_val "Electricity.xha" "StudentID")
77+
local token=$(get_val "Electricity.xha" "Token")
78+
79+
local thresholds_raw=$(get_val "Electricity.xha" "RemindTime" | tr -d '[]' | tr ',' ' ')
80+
81+
local light_limit=$(echo $thresholds_raw | awk '{print $1}')
82+
local ac_limit=$(echo $thresholds_raw | awk '{print $2}')
83+
84+
# 如果解析失败默认设为0
85+
light_limit=${light_limit:-0}
86+
ac_limit=${ac_limit:-0}
87+
88+
if [ -z "$sno" ] || [ -z "$token" ]; then
89+
echo "错误: 学号或Token未配置,请修改 config.toml"
90+
return
91+
fi
92+
93+
echo "查询西海岸校区... (学号: $sno)"
94+
95+
local response=$(curl -s -X POST "http://10.128.13.25/hydxcas/getCadByNo" \
96+
-H "Token: $token" \
97+
-H "Content-Type: application/json" \
98+
-d "{\"sno\": \"$sno\"}")
99+
100+
local errcode=$(echo "$response" | jq -r '.errcode')
101+
102+
if [ "$errcode" != "0" ]; then
103+
echo "API 请求失败: $(echo "$response" | jq -r '.errmsg')"
104+
return
105+
fi
106+
107+
# 解析数据
108+
local light_val=$(echo "$response" | jq -r '.value | fromjson | .eqptData[] | select(.categoryEnergyName == "照明与插座") | .buyElec')
109+
local ac_val=$(echo "$response" | jq -r '.value | fromjson | .eqptData[] | select(.categoryEnergyName == "空调末端") | .buyElec')
110+
111+
light_val=${light_val:-0}
112+
ac_val=${ac_val:-0}
113+
114+
echo "当前电量 -> 照明: $light_val, 空调: $ac_val"
115+
echo "警戒阈值 -> 照明: $light_limit, 空调: $ac_limit"
116+
117+
local need_alert=0
118+
local msg="<h3>电费余额不足提醒</h3><ul>"
119+
120+
# 使用 bc 进行比较,增加 2>/dev/null 屏蔽非数字报错
121+
if (( $(echo "$light_val < $light_limit" | bc -l 2>/dev/null) )); then
122+
need_alert=1
123+
msg="${msg}<li><strong>照明:</strong> ${light_val} 度 (低于 ${light_limit})</li>"
124+
fi
125+
126+
if (( $(echo "$ac_val < $ac_limit" | bc -l 2>/dev/null) )); then
127+
need_alert=1
128+
msg="${msg}<li><strong>空调:</strong> ${ac_val} 度 (低于 ${ac_limit})</li>"
129+
fi
130+
131+
msg="${msg}</ul><p>请及时充值!</p>"
132+
133+
if [ $need_alert -eq 1 ]; then
134+
send_email "【紧急】宿舍电费余额不足" "$msg"
135+
else
136+
echo "电量充足,无需提醒。"
137+
fi
138+
}
139+
140+
# 主函数部分
141+
142+
ENABLED=$(get_val "Electricity" "Enabled")
143+
if [ "$ENABLED" != "true" ]; then
144+
echo "电费监控模块未启用。"
145+
exit 0
146+
fi
147+
148+
CAMPUS=$(get_val "Electricity" "Campus")
149+
150+
case "$CAMPUS" in
151+
"xha")
152+
check_xha
153+
;;
154+
*)
155+
echo "未知的校区配置: $CAMPUS"
156+
;;
157+
esac

0 commit comments

Comments
 (0)