41 Commits

Author SHA1 Message Date
星光-k
2c2de32b57 Update clock.py 2025-01-23 12:24:18 +08:00
星光-k
4e7cceaa72 Update clock.py 2025-01-23 12:20:25 +08:00
星光-k
1f00376e90 Update main.py 2025-01-23 12:13:22 +08:00
星光-k
41bf67d6fe Update weather.py 2025-01-23 11:10:15 +08:00
星光-k
d932daedd4 Update main.py 2025-01-23 10:55:42 +08:00
星光-k
ce705c6dd5 更新 main.py 2025-01-21 14:04:07 +00:00
星光-k
e420aa23a2 更新 main.py 2025-01-21 13:49:10 +00:00
星光-k
c0d776da36 更新 clean.sh 2025-01-21 00:53:36 +00:00
星光-k
7a76aef402 更新 e-Paper_clean.servic 2025-01-20 23:19:27 +00:00
星光-k
c3666059ce 更新 clean.sh 2025-01-20 23:16:51 +00:00
星光-k
dfae4181cb 更新 e-Paper_clean.service 2025-01-20 23:16:32 +00:00
星光-k
0085656d20 更新 weather.py 2025-01-20 18:26:50 +00:00
星光-k
f8857cbd17 更新 weather.py 2025-01-20 18:20:54 +00:00
星光-k
90b6ae1403 更新 main.py 2025-01-20 17:19:47 +00:00
星光-k
e9b284a9b3 更新 main.py 2025-01-20 15:23:38 +00:00
星光-k
7405aabf2c 更新 raspi_e-Paper.service 2025-01-20 13:38:04 +00:00
星光-k
ca450afb14 更新 raspi_e-Paper.service 2025-01-20 13:28:20 +00:00
星光-k
c82aadd4e7 更新 raspi_e-Paper.service 2025-01-20 13:27:31 +00:00
星光-k
0a96f265f7 更新 raspi_e-Paper.service 2025-01-20 12:33:21 +00:00
星光-k
298a3f43f1 更新 main.py 2025-01-19 06:51:43 +00:00
星光-k
17544b607a 更新 main.py 2025-01-19 06:41:04 +00:00
星光-k
99780f1bf9 Update main.py 2025-01-19 10:35:23 +08:00
星光-k
118cc0a2ee Update main.py 2025-01-19 06:35:24 +08:00
星光-k
3155088921 Update weather.py 2025-01-19 06:11:12 +08:00
星光-k
28f0a9d37d Update main.py 2025-01-19 06:10:35 +08:00
星光-k
fc1678aa95 Update install.sh 2025-01-19 05:48:39 +08:00
星光-k
f0eb8dc53e Update start.sh 2025-01-19 05:47:35 +08:00
星光-k
9e5114b7bd Update start.sh 2025-01-19 05:47:17 +08:00
星光-k
bb44237caa Delete webui directory 2025-01-19 05:46:48 +08:00
星光-k
e82fd225f5 Update main.py 2025-01-19 05:44:46 +08:00
星光-k
c67ae6bd78 Update main.py 2025-01-19 04:11:49 +08:00
星光-k
72c2b23566 Update main.py 2025-01-19 04:02:43 +08:00
星光-k
590494d734 Update start.sh 2025-01-19 01:20:53 +08:00
星光-k
8a29bf9110 Update main.py 2025-01-19 01:20:15 +08:00
星光-k
ab6abaf2e3 Update weather.py 2025-01-19 01:19:21 +08:00
星光-k
5436cba3d0 Update install.sh 2025-01-18 09:38:47 +08:00
星光-k
70d1b3d710 Delete webui/1 2025-01-18 09:11:52 +08:00
星光-k
6fa3fe1407 Add files via upload 2025-01-18 01:11:29 +00:00
星光-k
cd6fc91cda Create 1 2025-01-18 09:10:49 +08:00
星光-k
60272f75ea Delete app directory 2025-01-18 09:09:51 +08:00
星光-k
faf0e2f505 Add files via upload 2025-01-18 01:09:34 +00:00
13 changed files with 475 additions and 1807 deletions

View File

@@ -1,79 +0,0 @@
from flask import Flask, render_template, request, send_from_directory, redirect, url_for, jsonify
import os
import re
import subprocess
app = Flask(__name__, template_folder='webui', static_url_path='', static_folder='webui')
FONT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'pic') # 字体文件夹路径
MAIN_PY_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'bin', 'main.py')
def list_font_files(font_dir):
try:
return os.listdir(font_dir)
except Exception as e:
print(f"Error listing font files: {e}")
return [] # 返回空列表以避免迭代错误
@app.route('/execute-shell')
def execute_shell():
# 替换以下命令为您想要执行的Shell命令
command = "sudo reboot now"
result = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
if result.returncode == 0:
return jsonify({'status': 'success', 'output': result.stdout})
else:
return jsonify({'status': 'error', 'output': result.stderr})
@app.route('/edit_main_py')
def edit_main_py():
try:
with open(MAIN_PY_PATH, 'r') as file:
content = file.read()
except Exception as e:
return f"Error reading main.py: {e}", 500
return render_template('edit_main_py.html', content=content)
@app.route('/save_main_py', methods=['POST'])
def save_main_py():
new_content = request.form.get('content')
if new_content is None:
return "No content provided", 400
try:
with open(MAIN_PY_PATH, 'w') as file:
file.write(new_content)
except Exception as e:
return f"Error saving main.py: {e}", 500
return redirect(url_for('index'))
@app.route('/')
def index():
font_files = list_font_files(FONT_DIR)
return render_template('index.html', font_files=font_files)
@app.route('/upload', methods=['POST'])
def upload():
if 'font_file' not in request.files:
return '没有文件部分'
file = request.files['font_file']
if file.filename == '':
return '没有选择文件'
if file:
filename = os.path.join(FONT_DIR, file.filename)
file.save(filename)
return '文件已上传成功'
@app.route('/update_font_names')
def update_font_names():
font_files = list_font_files(FONT_DIR)
return render_template('update_font_names.html', font_files=font_files)
@app.route('/fonts/<filename>')
def fonts(filename):
return send_from_directory(FONT_DIR, filename)
if not os.path.exists(FONT_DIR):
os.makedirs(FONT_DIR)
if __name__ == '__main__':
# 绑定到0.0.0.0,允许远程访问
app.run(host='0.0.0.0', port=80, debug=False)

View File

@@ -1,9 +0,0 @@
/*!
Theme: Default
Description: Original highlight.js style
Author: (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
Maintainer: @highlightjs/core-team
Website: https://highlightjs.org/
License: see project LICENSE
Touched: 2021
*/pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{background:#f3f3f3;color:#444}.hljs-comment{color:#697070}.hljs-punctuation,.hljs-tag{color:#444a}.hljs-tag .hljs-attr,.hljs-tag .hljs-name{color:#444}.hljs-attribute,.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-name,.hljs-selector-tag{font-weight:700}.hljs-deletion,.hljs-number,.hljs-quote,.hljs-selector-class,.hljs-selector-id,.hljs-string,.hljs-template-tag,.hljs-type{color:#800}.hljs-section,.hljs-title{color:#800;font-weight:700}.hljs-link,.hljs-operator,.hljs-regexp,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-symbol,.hljs-template-variable,.hljs-variable{color:#ab5656}.hljs-literal{color:#695}.hljs-addition,.hljs-built_in,.hljs-bullet,.hljs-code{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta .hljs-string{color:#38a}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}

View File

@@ -1,59 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>编辑 main.py</title>
<!-- 引用本地的highlight.js CSS -->
<link rel="stylesheet" href="{{ url_for('static', filename='default.min.css') }}">
</head>
<body>
<h1>编辑 main.py</h1>
<!-- 添加一个表单来提交编辑后的代码 -->
<form method="post" action="{{ url_for('save_main_py') }}">
<pre style="background-color: black !important;"><code class="python" id="code">{{ content }}</code></pre>
<input type="hidden" name="content" id="hidden-content">
<input type="submit" value="保存">
</form>
<!-- 引用本地的highlight.js JavaScript -->
<script src="{{ url_for('static', filename='highlight.min.js') }}"></script>
<script>
// 初始化highlight.js
document.addEventListener('DOMContentLoaded', (event) => {
hljs.highlightAll();
});
</script>
<script>
document.addEventListener('DOMContentLoaded', function() {
var preElements = document.querySelectorAll('pre.code-editor');
preElements.forEach(function(pre) {
pre.style.backgroundColor = 'black';
});
});
</script>
<h2>重启</h2>
</head>
<body>
<button id="executeShellBtn">重启</button>
<script>
document.getElementById('executeShellBtn').addEventListener('click', function() {
fetch('/execute-shell')
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
alert('Command executed successfully:\n' + data.output);
} else {
alert('Error executing command:\n' + data.output);
}
})
.catch(error => {
alert('Error: ' + error);
});
});
</script>
</body>
</html>
 

File diff suppressed because one or more lines are too long

View File

@@ -1,27 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>字体上传和管理</title>
</head>
<body>
<h1>上传字体文件</h1>
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="font_file">
<input type="submit" value="上传">
</form>
<h2>已上传的字体文件:</h2>
<ul>
{% for font_file in font_files %}
<li>{{ font_file }}</li>
{% else %}
<li>没有找到字体文件。</li>
{% endfor %}
</ul>
<!-- 添加跳转到edit_main_py的按钮 -->
<a href="/edit_main_py"><button>编辑main.py</button></a>
</body>
</html>

View File

@@ -1,26 +0,0 @@
<!-- update_font_names.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>更新字体文件名</title>
</head>
<body>
<h1>更新字体文件名</h1>
<form method="post" action="/save_font_names">
<label for="font01">字体文件名 01:</label>
<input type="text" id="font01" name="font01"><br>
<label for="font02">字体文件名 02:</label>
<input type="text" id="font02" name="font02"><br>
<label for="font03">字体文件名 03:</label>
<input type="text" id="font03" name="font03"><br>
<label for="font04">字体文件名 04:</label>
<input type="text" id="font04" name="font04"><br>
<label for="font05">字体文件名 05:</label>
<input type="text" id="font05" name="font05"><br>
<label for="font06">字体文件名 06:</label>
<input type="text" id="font06" name="font06"><br>
<input type="submit" value="保存">
</form>
</body>
</html>

View File

@@ -4,7 +4,6 @@ f_name="clean.py"
dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
logdir="${dir%/*}/log" logdir="${dir%/*}/log"
service_name="raspi_e-Paper.service" service_name="raspi_e-Paper.service"
hold_time_seconds=5 # 设置维持时间例如300秒5分钟
# 停止raspi_e-Paper服务 # 停止raspi_e-Paper服务
echo "正在停止$service_name服务..." echo "正在停止$service_name服务..."
@@ -19,9 +18,6 @@ if [ -n "$pids" ]; then
kill -9 $pids kill -9 $pids
fi fi
# 使用nohup在后台运行Python脚本并将输出重定向到日志文件 echo "正在清除屏幕内容"
nohup /usr/bin/python3 -u "$dir/$f_name" > "${logdir}/info-clean.log" 2>&1 & # 运行Python脚本并将输出重定向到日志文件
/usr/bin/python3 -u "$dir/$f_name" > "${logdir}/info-clean.log" 2>&1
# 等待维持时间
echo "正在运行脚本,将在 ${hold_time_seconds} 秒后停止服务..."
sleep $hold_time_seconds

View File

@@ -10,126 +10,211 @@ from threading import Timer
import requests import requests
white = 255 #颜色 white = 255 #颜色
black = 0 black = 0
logging.basicConfig(level=logging.DEBUG) logging.basicConfig(level=logging.INFO)
################################引入配置文件开始################################################ ################################引入配置文件开始################################################
picdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'pic') picdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'pic')
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib') libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir): if os.path.exists(libdir):
sys.path.append(libdir)#将引入文件添加到环境变量 sys.path.append(libdir) # 将引入文件添加到环境变量
from waveshare_epd import epd2in13_V4 #引入墨水屏驱动文件 from waveshare_epd import epd2in13_V4 # 引入墨水屏驱动文件
logging.debug("Loading Fonts") logging.debug("Loading Fonts")
font01 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 20) #字体文件 font01 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 20) # 字体文件
font02 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 15) #字体文件 font02 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 15) # 字体文件
font03 = ImageFont.truetype(os.path.join(picdir, 'DSEG7Modern-Bold.ttf'), 38) #字体文件 font03 = ImageFont.truetype(os.path.join(picdir, 'DSEG7Modern-Bold.ttf'), 66) # 字体文件
font04 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 10) #字体文件 font04 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 10) # 字体文件
font05 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 12) #字体文件 font05 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 12) # 字体文件
font06 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 13) #字体文件 font06 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 13) # 字体文件
################################引入配置文件结束################################################ ################################引入配置文件结束################################################
def Local_strong_brush(): #局部强制刷新显示
i = 0
while i < 5: def Local_strong_brush(): # 局部强制刷新显示
epd.displayPartial(epd.getbuffer(info_image.rotate(180)))#局刷开始 i = 0
i = i + 1 while i < 5:
def get_date():#返回当前年月日及星期几 epd.displayPartial(epd.getbuffer(info_image.rotate(180))) # 局刷开始
i += 1
def get_date(): # 返回当前年月日及星期几
date = datetime.datetime.now() date = datetime.datetime.now()
today=LunarDate.today() today = LunarDate.today()
week_day_dict = {0: '星期一',1: '星期二',2: '星期三',3: '星期四',4: '星期五',5: '星期六',6: '星期日',} week_day_dict = {0: '星期一', 1: '星期二', 2: '星期三', 3: '星期四', 4: '星期五', 5: '星期六', 6: '星期日'}
day = date.weekday() day = date.weekday()
return time.strftime('%Y年%m月%d')+' '+week_day_dict[day]+' '+today.strftime(' %M月%D') return time.strftime('%Y年%m月%d') + '' + week_day_dict[day] + '' + today.strftime('%M月%D')
def get_time():#返回当前时间,不到秒,大写 # 定义一个全局标志变量,用于检查是否已经设置了系统时间或尝试过设置
return time.strftime('%H:%M') has_set_system_time = False
def Get_address():#获取当前的IP地址
return (subprocess.check_output(u"hostname -I | cut -d\' \' -f1 | head --bytes -1", shell = True ).decode('gbk')) def set_system_time_from_hwclock(utc=True):
def CPU_temperature():#CPU温度获取 """Set the system time from the hardware clock.
temperatura = os.popen('vcgencmd measure_temp').readline()
temperatura = temperatura.replace('temp=','').strip() Args:
return str(temperatura) utc (bool): Whether the RTC is in UTC. Default is True.
def Memory_footprint():#显示内存占用百分比 """
return(subprocess.check_output(u"free -m | awk -F '[ :]+' 'NR==2{printf \"%d\", ($3)/$2*100}'", shell = True ).decode('gbk')) try:
def CPU_usage(): #显示CPU占用百分比 # 记录调用 hwclock 前的时间
return(str(int(float(os.popen("top -b -n1 | awk '/Cpu\(s\):/ {print $2}'").readline().strip())))) before_time = datetime.datetime.now()
def power_battery():#获取当前电池电量 logging.debug(f"System time before hwclock call: {before_time}")
return(str(int(subprocess.check_output(u"echo \"get battery\" | nc -q 0 127.0.0.1 8423|awk -F':' '{print int($2)}'", shell = True ).decode('gbk')))+u'%')
# 构造 hwclock 命令及其参数
hwclock_args = ['sudo', 'hwclock', '--hctosys']
if not utc:
hwclock_args.append('--localtime')
logging.debug(f"Executing hwclock command: {' '.join(hwclock_args)}")
# 使用 subprocess.run 执行 hwclock --hctosys 并捕获输出
result = subprocess.run(hwclock_args,
check=True, # 如果命令失败,则抛出 CalledProcessError 异常
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
# 等待一小段时间以确保时间更新完成
time.sleep(0.1) # 根据需要调整
# 记录调用 hwclock 后的时间
after_time = datetime.datetime.now()
logging.debug("System time successfully set from hardware clock.")
logging.debug(f"System time after hwclock call: {after_time}")
# 检查时间是否发生了倒退
if after_time < before_time:
logging.info(f"Time went backwards after hwclock call: before={before_time}, after={after_time}")
return True
except subprocess.CalledProcessError as e:
logging.error(f"Failed to set system time from hardware clock: {e.stderr}")
return False
except Exception as e:
logging.error(f"An unexpected error occurred: {str(e)}")
return False
def get_time():
global has_set_system_time
if not has_set_system_time:
# 尝试从硬件时钟设置系统时间,默认假设 RTC 是 UTC
success = set_system_time_from_hwclock(utc=True)
# 无论成功与否,都更新标志变量以避免重复尝试
has_set_system_time = True
# 获取并返回当前时间,格式为 HH:MM 大写
current_time = time.strftime('%H:%M').upper()
logging.debug(f"Returning current time: {current_time}")
return current_time
def Get_address(): # 获取当前的IP地址
return subprocess.check_output(u"hostname -I | cut -d' ' -f1 | head --bytes -1", shell=True).decode('gbk').strip()
def CPU_temperature(): # CPU温度获取
temperatura = os.popen('vcgencmd measure_temp').readline()
temperatura = temperatura.replace('temp=', '').strip()
return str(temperatura)
def Memory_footprint(): # 显示内存占用百分比
return subprocess.check_output(u"free -m | awk -F '[ :]+' 'NR==2{printf \"%d\", ($3)/$2*100}'", shell=True).decode('gbk')
def CPU_usage(): # 显示CPU占用百分比
return str(int(float(os.popen("top -b -n1 | awk '/Cpu\(s\):/ {print $2}'").readline().strip())))
def power_battery(): # 获取当前电池电量
return str(int(subprocess.check_output(u"echo \"get battery\" | nc -q 0 127.0.0.1 8423|awk -F':' '{print int($2)}'", shell=True).decode('gbk'))) + u'%'
# 打印电量信息 # 打印电量信息
print(power_battery()) print(power_battery())
def Bottom_edge(): #在图片中添加底边内容
draw.rectangle((0, 105, 250, 122), 'black', 'black')
'''电池图标画图''' def Bottom_edge(): # 在图片中添加底边内容
draw.line((126,109,154,109),fill=255, width=1) #电池顶边 draw.rectangle((0, 105, 250, 122), 'black', 'black')
draw.line((126,110,126,119),fill=255, width=1) #电池左边 '''电池图标画图'''
draw.line((127,119,154,119),fill=255, width=1) #电池 draw.line((126, 109, 154, 109), fill=255, width=1) # 电池
draw.line((154,110,154,118),fill=255, width=1) draw.line((126, 110, 126, 119), fill=255, width=1) # 电池左边
draw.line((155,112,157,112),fill=255, width=1) draw.line((127, 119, 154, 119), fill=255, width=1) # 电池下边
draw.line((155,116,157,116),fill=255, width=1) draw.line((154, 110, 154, 118), fill=255, width=1)
draw.line((157,113,157,115),fill=255, width=1) draw.line((155, 112, 157, 112), fill=255, width=1)
global power_str draw.line((155, 116, 157, 116), fill=255, width=1)
power_str=power_battery() draw.line((157, 113, 157, 115), fill=255, width=1)
draw.text((128,108),power_str,font = font04,fill =255) #显示当前电量百分比 global power_str
'''电池图标画图''' power_str = power_battery()
draw.ellipse((192, 107, 207, 120), 0, 255)# 时钟图标 draw.text((128, 108), power_str, font=font04, fill=255) # 显示当前电量百分比
draw.line((199,109,199,114),fill=255, width=1) '''电池图标画图'''
draw.line((200,114,204,114),fill=255, width=1) draw.ellipse((192, 107, 207, 120), 0, 255) # 时钟图标
global local_addr #获取当前IP地址 draw.line((199, 109, 199, 114), fill=255, width=1)
local_addr= Get_address() #获取当前IP地址 draw.line((200, 114, 204, 114), fill=255, width=1)
draw.text((10,107),"IP:"+local_addr,font = font05,fill =255)#显示当前IP地址 global local_addr # 获取当前IP地址
def Basic_refresh(): #全刷函数 local_addr = Get_address() # 获取当前IP地址
logging.info("Refresh and prepare the basic content before starting the canvas")#开始画布前刷新准备基础内容 draw.text((10, 107), "IP:" + local_addr, font=font05, fill=255) # 显示当前IP地址
def Basic_refresh(): # 全刷函数
logging.info("Refresh and prepare the basic content before starting the canvas") # 开始画布前刷新准备基础内容
global get_date_var global get_date_var
get_date_var=get_date() #记录开始数据 get_date_var = get_date() # 记录开始数据
draw.text((2,2),get_date_var,font = font02,fill =0)#将日期及星期几显示到屏幕 draw.text((2, 2), get_date_var, font=font02, fill=0) # 将日期及星期几显示到屏幕
global local_time global local_time
local_time=get_time() local_time = get_time()
draw.text((5,40),local_time,font = font03,fill =0)#显示当前时间 draw.text((5, 28), local_time, font=font03, fill=0) # 显示当前时间
Bottom_edge() #添加底边内容 Bottom_edge() # 添加底边内容
epd.display(epd.getbuffer(info_image.rotate(180))) epd.display(epd.getbuffer(info_image.rotate(180)))
def Partial_full_brush(): #局部定时全刷函数
Basic_refresh() #全局刷新
logging.debug("局部定时全局刷新") def Partial_full_brush(): # 局部定时全刷函数
epd.init() Basic_refresh() # 全局刷新
def Partial_refresh():#局刷函数 logging.debug("局部定时全局刷新")
logging.info("Partial content update, this update is recommended to be synchronized with the minute to save the life of the ink screen")#局部内容更新,此更新建议与分钟同步,以节省墨水屏寿命 epd.init()
epd.displayPartBaseImage(epd.getbuffer(info_image.rotate(180)))
epd.init()
while (True): def Partial_refresh(): # 局刷函数
global local_time logging.info(
local_time1=get_time() "Partial content update, this update is recommended to be synchronized with the minute to save the life of the ink screen") # 局部内容更新,此更新建议与分钟同步,以节省墨水屏寿命
if (local_time1==local_time) ==False: epd.displayPartBaseImage(epd.getbuffer(info_image.rotate(180)))
draw.rectangle((5, 40, 133, 82), fill = 255) #时间局刷区域 epd.init()
draw.text((5,40),local_time1,font = font03,fill =0)#刷新当前时间 while True:
local_time=local_time1 global local_time
Local_strong_brush() #局部强刷 local_time1 = get_time()
get_date_var1=get_date() #局刷判断,如果时间与前一次不一致说明内容变化,需要刷新显示 if local_time1 != local_time:
global get_date_var #再次声明这个是全局变量 draw.rectangle((5, 28, 133, 95), fill=255) # 时间局刷区域
if(get_date_var1==get_date_var) ==False: draw.text((5, 28), local_time1, font=font03, fill=0) # 刷新当前时间
draw.rectangle((2, 2, 250, 16), fill = 255) #设置头部刷新区域 local_time = local_time1
draw.text((2,2),get_date_var1,font = font02,fill =0)#将日期及星期几刷新显示到屏幕 Local_strong_brush() # 局部强刷
get_date_var=get_date_var1 #将更新的值保存到初始变量,直到下一次变化时执行该刷新操作 get_date_var1 = get_date() # 局刷判断,如果时间与前一次不一致说明内容变化,需要刷新显示
logging.debug("头部日期部位发生刷新变化.") global get_date_var # 再次声明这个是全局变量
Local_strong_brush() #局部强刷 if get_date_var1 != get_date_var:
global local_addr #当前IP地址 draw.rectangle((2, 2, 250, 16), fill=255) # 设置头部刷新区域
local_addr1 = Get_address() draw.text((2, 2), get_date_var1, font=font02, fill=0) # 将日期及星期几刷新显示到屏幕
if (local_addr1==local_addr) ==False: get_date_var = get_date_var1 # 将更新的值保存到初始变量,直到下一次变化时执行该刷新操作
draw.rectangle((1, 107, 94, 120), fill = 0) #设置头部刷新区域 logging.debug("头部日期部位发生刷新变化.")
draw.text((10,107),"IP:"+local_addr1,font = font05,fill =255)#显示当前IP地址 Local_strong_brush() # 局部强刷
local_addr=local_addr1 global local_addr # 当前IP地址
Local_strong_brush() #局部强刷 local_addr1 = Get_address()
#显示当前电量百分比 if local_addr1 != local_addr:
power_str=power_str1 draw.rectangle((1, 107, 94, 120), fill=0) # 设置头部刷新区域
Local_strong_brush() #局部强刷 draw.text((10, 107), "IP:" + local_addr1, font=font05, fill=255) # 显示当前IP地址
logging.info("电源电量局部刷新") local_addr = local_addr1
Local_strong_brush() # 局部强刷
# 显示当前电量百分比
global power_str
power_str1 = power_battery()
power_str = power_str1
Local_strong_brush() # 局部强刷
try: try:
##################屏幕初始化######################### ##################屏幕初始化#########################
getWeath()#天气获取函数开始运行 epd = epd2in13_V4.EPD() # 初始化
epd = epd2in13_V4.EPD() #初始化 epd.init() # 设定屏幕刷新模式
epd.init()#设定屏幕刷新模式 # epd.Clear(0xFF) # 清除屏幕内容
#epd.Clear(0xFF) #清除屏幕内容 ##################屏幕初始化#########################
##################屏幕初始化######################### logging.info("Width = %s, Height = %s", format(epd.width), format(epd.height)) # 打印屏幕高度及宽度
logging.info("Width = %s, Height = %s", format(epd.width), format(epd.height)) #打印屏幕高度及宽度 logging.info("Initialize and clear the display") # 屏幕开始准备相关展示
logging.info("Initialize and clear the display")#屏幕开始准备相关展示 info_image = Image.new('1', (epd.height, epd.width), 255) # 画布创建准备
info_image = Image.new('1', (epd.height, epd.width), 255) #画布创建准备
draw = ImageDraw.Draw(info_image) draw = ImageDraw.Draw(info_image)
Basic_refresh() #全局刷新 Basic_refresh() # 全局刷新
Partial_refresh() #局部刷新 Partial_refresh() # 局部刷新
epd.init() epd.init()
epd.Clear(0xFF) epd.Clear(0xFF)
epd.sleep() epd.sleep()
@@ -139,7 +224,7 @@ except KeyboardInterrupt:
logging.info("Keyboard interrupt detected, exiting gracefully.") logging.info("Keyboard interrupt detected, exiting gracefully.")
epd.init() epd.init()
epd.Clear(0xFF) # 清除屏幕内容 epd.Clear(0xFF) # 清除屏幕内容
epd.sleep() # 使屏幕进入休眠状态 epd.sleep() # 使屏幕进入休眠状态
epd2in13_V4.epdconfig.module_exit() # 清理资源 epd2in13_V4.epdconfig.module_exit() # 清理资源
exit() exit()
@@ -147,13 +232,13 @@ except Exception as e:
logging.error("An unexpected error occurred: %s", e) logging.error("An unexpected error occurred: %s", e)
epd.init() epd.init()
epd.Clear(0xFF) # 清除屏幕内容 epd.Clear(0xFF) # 清除屏幕内容
epd.sleep() # 使屏幕进入休眠状态 epd.sleep() # 使屏幕进入休眠状态
epd2in13_V4.epdconfig.module_exit() # 清理资源 epd2in13_V4.epdconfig.module_exit() # 清理资源
exit() exit()
# 脚本正常结束后的清理操作 # 脚本正常结束后的清理操作
epd.init() epd.init()
epd.Clear(0xFF) # 清除屏幕内容 epd.Clear(0xFF) # 清除屏幕内容
epd.sleep() # 使屏幕进入休眠状态 epd.sleep() # 使屏幕进入休眠状态
epd2in13_V4.epdconfig.module_exit() # 清理资源 epd2in13_V4.epdconfig.module_exit() # 清理资源
exit() exit()

View File

@@ -121,25 +121,14 @@ is_raspberry_pi() {
fi fi
} }
# 定义链接变量 # 使用中国镜像源
DEBIAN_MIRROR="http://deb.debian.org/debian/" DEBIAN_MIRROR="https://mirrors.tuna.tsinghua.edu.cn/debian"
DEBIAN_SECURITY_MIRROR="http://security.debian.org/"
PISUGAR_WIFI_CONF_URL="https://cdn.pisugar.com/PiSugar-wificonfig/script/install.sh"
PISUGAR_POWER_MANAGER_URL="https://cdn.pisugar.com/release/pisugar-power-manager.sh"
PIPY_MIRROR="https://pypi.org/simple"
# 修改 Raspberry Pi 特定源链接
RASPBERRY_PI_SOURCE_DEBIAN11="https://archive.raspberrypi.org/debian/"
RASPBERRY_PI_SOURCE_DEBIAN12="https://archive.raspberrypi.com/debian/"
# 如果使用中国镜像源,则更新链接变量
if [ "$USE_CN_MIRROR" = true ]; then
DEBIAN_MIRROR="https://mirrors.tuna.tsinghua.edu.cn/debian/"
DEBIAN_SECURITY_MIRROR="https://mirrors.tuna.tsinghua.edu.cn/debian-security" DEBIAN_SECURITY_MIRROR="https://mirrors.tuna.tsinghua.edu.cn/debian-security"
PIPY_MIRROR="https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple" PIPY_MIRROR="https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
# 使用中国镜像源时Raspberry Pi 特定源链接保持不变 # 使用中国镜像源时Raspberry Pi 特定源链接保持不变
RASPBERRY_PI_SOURCE_DEBIAN11="https://mirrors.tuna.tsinghua.edu.cn/raspberrypi/" RASPBERRY_PI_SOURCE_DEBIAN11="https://mirrors.tuna.tsinghua.edu.cn/raspberrypi"
RASPBERRY_PI_SOURCE_DEBIAN12="https://mirrors.tuna.tsinghua.edu.cn/raspberrypi/" RASPBERRY_PI_SOURCE_DEBIAN12="https://mirrors.tuna.tsinghua.edu.cn/raspberrypi"
fi
# 定义仓库链接变量 # 定义仓库链接变量
INK_SCREEN_CLOCK_REPO_URL="https://github.com/kxgx/2.13-Ink-screen-clock" INK_SCREEN_CLOCK_REPO_URL="https://github.com/kxgx/2.13-Ink-screen-clock"
@@ -155,6 +144,7 @@ update_sources_list() {
local raspberry_pi_source_in_use=$(grep -oP 'deb\s+\K.+' /etc/apt/sources.list.d/raspi.list | head -1) local raspberry_pi_source_in_use=$(grep -oP 'deb\s+\K.+' /etc/apt/sources.list.d/raspi.list | head -1)
# 检查并替换 Debian 源 # 检查并替换 Debian 源
if [ "$USE_CN_MIRROR" = true ]; then
if [ "$debian_mirror_in_use" != "$DEBIAN_MIRROR" ]; then if [ "$debian_mirror_in_use" != "$DEBIAN_MIRROR" ]; then
sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
{ {
@@ -196,12 +186,13 @@ update_sources_list() {
else else
echo "Raspberry Pi 源链接已更新,跳过替换" >&2 echo "Raspberry Pi 源链接已更新,跳过替换" >&2
fi fi
fi
} }
# 安装包函数 # 安装包函数
install_packages() { install_packages() {
echo "正在更新源列表" echo "正在更新源列表"
if ! sudo apt-get -q -y update; then if ! sudo apt-get -q update; then
echo "更新源列表失败" >&2 echo "更新源列表失败" >&2
exit 1 exit 1
fi fi
@@ -317,6 +308,7 @@ if [ -f /etc/debian_version ]; then
install_packages install_packages
install_pip_packages install_pip_packages
setup_service setup_service
#install_webui
install_pisugar-wifi-conf install_pisugar-wifi-conf
install_pisugar-power-manager install_pisugar-power-manager
;; ;;
@@ -326,6 +318,7 @@ if [ -f /etc/debian_version ]; then
install_packages install_packages
install_pip_packages install_pip_packages
setup_service setup_service
#install_webui
install_pisugar-wifi-conf install_pisugar-wifi-conf
install_pisugar-power-manager install_pisugar-power-manager
;; ;;

View File

@@ -1,24 +1,20 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
from PIL import Image,ImageDraw,ImageFont #引入图片处理库 from PIL import Image, ImageDraw, ImageFont # 引入图片处理库
import os,sys,re,json,time,datetime #引入系统相关库 import os, sys, json, time, datetime # 引入系统相关库
from borax.calendars.lunardate import LunarDate #农历日期以及天干地支纪年法的 Python 库 from borax.calendars.lunardate import LunarDate # 农历日期以及天干地支纪年法的 Python 库
import logging #日志库 import logging # 日志库
import subprocess import subprocess
import os
from threading import Timer
import requests
import socket
white = 255 #颜色 white = 255 # 颜色
black = 0 black = 0
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s') logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
################################引入配置文件开始################################################ ################################引入配置文件开始################################################
picdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'pic') picdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'pic')
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib') libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir): if os.path.exists(libdir):
sys.path.append(libdir)#将引入文件添加到环境变量 sys.path.append(libdir) # 将引入文件添加到环境变量
from waveshare_epd import epd2in13_V4 #引入墨水屏驱动文件 from waveshare_epd import epd2in13_V4 # 引入墨水屏驱动文件
logging.debug("Loading Fonts") logging.debug("Loading Fonts")
font01 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 20) #字体文件 font01 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 20) #字体文件
font02 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 15) #字体文件 font02 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 15) #字体文件
@@ -27,229 +23,254 @@ font04 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 10) #字体文件
font05 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 12) #字体文件 font05 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 12) #字体文件
font06 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 13) #字体文件 font06 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 13) #字体文件
################################引入配置文件结束################################################ ################################引入配置文件结束################################################
def Local_strong_brush(): #局部强制刷新显示
i = 0
while i < 5: def Local_strong_brush(): # 局部强制刷新显示
epd.displayPartial(epd.getbuffer(info_image.rotate(180)))#局刷开始 for _ in range(5):
i = i + 1 epd.displayPartial(epd.getbuffer(info_image.rotate(180)))
def get_date():#返回当前年月日及星期几
def get_date(): # 返回当前年月日及星期几
date = datetime.datetime.now() date = datetime.datetime.now()
today=LunarDate.today() today = LunarDate.today()
week_day_dict = {0: '星期一',1: '星期二',2: '星期三',3: '星期四',4: '星期五',5: '星期六',6: '星期日',} week_day_dict = {0: '星期一', 1: '星期二', 2: '星期三', 3: '星期四', 4: '星期五', 5: '星期六', 6: '星期日'}
day = date.weekday() day = date.weekday()
return time.strftime('%Y年%m月%d')+' '+week_day_dict[day]+' '+today.strftime(' %M月%D') return f"{date.strftime('%Y年%m月%d')}{week_day_dict[day]}{today.strftime('%M月%D')}"
def get_time():#返回当前时间,不到秒,大写
return time.strftime('%H:%M') # 定义一个全局标志变量,用于检查是否已经设置了系统时间或尝试过设置
def Get_address():#获取当前的IP地址 has_set_system_time = False
return (subprocess.check_output(u"hostname -I | cut -d\' \' -f1 | head --bytes -1", shell = True ).decode('gbk'))
def set_system_time_from_hwclock(utc=True):
"""Set the system time from the hardware clock.
Args:
utc (bool): Whether the RTC is in UTC. Default is True.
"""
try:
# 记录调用 hwclock 前的时间
before_time = datetime.datetime.now()
logging.debug(f"System time before hwclock call: {before_time}")
# 构造 hwclock 命令及其参数
hwclock_args = ['sudo', 'hwclock', '--hctosys']
if not utc:
hwclock_args.append('--localtime')
logging.debug(f"Executing hwclock command: {' '.join(hwclock_args)}")
# 使用 subprocess.run 执行 hwclock --hctosys 并捕获输出
result = subprocess.run(hwclock_args,
check=True, # 如果命令失败,则抛出 CalledProcessError 异常
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
# 等待一小段时间以确保时间更新完成
time.sleep(0.1) # 根据需要调整
# 记录调用 hwclock 后的时间
after_time = datetime.datetime.now()
logging.debug("System time successfully set from hardware clock.")
logging.debug(f"System time after hwclock call: {after_time}")
# 检查时间是否发生了倒退
if after_time < before_time:
logging.warning(f"Time went backwards after hwclock call: before={before_time}, after={after_time}")
return True
except subprocess.CalledProcessError as e:
logging.error(f"Failed to set system time from hardware clock: {e.stderr}")
return False
except Exception as e:
logging.error(f"An unexpected error occurred: {str(e)}")
return False
def get_time():
global has_set_system_time
if not has_set_system_time:
# 尝试从硬件时钟设置系统时间,默认假设 RTC 是 UTC
success = set_system_time_from_hwclock(utc=True)
# 无论成功与否,都更新标志变量以避免重复尝试
has_set_system_time = True
# 获取并返回当前时间,格式为 HH:MM 大写
current_time = time.strftime('%H:%M').upper()
logging.debug(f"Returning current time: {current_time}")
return current_time
def Get_ipv4_address(): # 获取当前的IP地址 def Get_ipv4_address(): # 获取当前的IP地址
try: try:
# 执行命令获取IP地址并处理输出以仅返回IPv4地址 ip_output = subprocess.check_output(
ip_output = subprocess.check_output("hostname -I | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}'", shell=True).decode('utf-8').strip() "hostname -I | grep -oE '[0-9]{1,3}(\.[0-9]{1,3}){3}'", shell=True).decode('utf-8').strip()
# 检查是否为IPv4地址 ip_list = ip_output.split()
if ip_output and not ip_output.startswith("127."): filtered_ips = [ip for ip in ip_list if not ip.startswith("172.")]
return ip_output return filtered_ips[0] if filtered_ips else "地址获取失败"
else: except subprocess.CalledProcessError:
return "IPv4获取失败" return "获取失败"
except subprocess.CalledProcessError as e:
return f"获取失败"
def CPU_temperature():#CPU温度获取
temperatura = os.popen('vcgencmd measure_temp').readline()
temperatura = temperatura.replace('temp=','').strip()
return str(temperatura)
def Memory_footprint():#显示内存占用百分比
return(subprocess.check_output(u"free -m | awk -F '[ :]+' 'NR==2{printf \"%d\", ($3)/$2*100}'", shell = True ).decode('gbk'))
def CPU_usage(): #显示CPU占用百分比
return(str(int(float(os.popen("top -b -n1 | awk '/Cpu\(s\):/ {print $2}'").readline().strip()))))
def power_battery():#获取当前电池电量
return(str(int(subprocess.check_output(u"echo \"get battery\" | nc -q 0 127.0.0.1 8423|awk -F':' '{print int($2)}'", shell = True ).decode('gbk')))+u'%')
# 打印电量信息
print(power_battery())
def Bottom_edge(): #在图片中添加底边内容
draw.rectangle((0, 105, 250, 122), 'black', 'black')
'''电池图标画图'''
draw.line((126,109,154,109),fill=255, width=1) #电池顶边
draw.line((126,110,126,119),fill=255, width=1) #电池左边
draw.line((127,119,154,119),fill=255, width=1) #电池下边
draw.line((154,110,154,118),fill=255, width=1)
draw.line((155,112,157,112),fill=255, width=1)
draw.line((155,116,157,116),fill=255, width=1)
draw.line((157,113,157,115),fill=255, width=1)
global power_str
power_str=power_battery()
draw.text((129,108),power_str,font = font04,fill =255) #显示当前电量百分比
'''电池图标画图'''
draw.ellipse((192, 107, 207, 120), 0, 255)# 时钟图标
draw.line((199,109,199,114),fill=255, width=1)
draw.line((200,114,204,114),fill=255, width=1)
global local_addr #获取当前IP地址
local_addr= Get_ipv4_address() #获取当前IP地址
draw.text((10,107),"IP:"+local_addr,font = font05,fill =255)#显示当前IP地址
def Weather(): #在图片中添加天气内容
Weather_json = open('/root/2.13-Ink-screen-clock/bin/weather.json','r')
Weather_data = Weather_json.read()
Weather_json.close()
Weather_text=json.loads(Weather_data)
global Weather_position
global temperature
global weather
global wind_direction
global weather_update
global weather_date
global humidity
Weather_position = Weather_text['cityname'] #定位位置
temperature=Weather_text['temp']+u'°C' #温度
weather = Weather_text['weather'] #天气情况
wind_direction = Weather_text['WD'] #风向
weather_update = Weather_text['time'] #天气更新时间
weather_date = Weather_text['date'] #日期
humidity = Weather_text['SD'] #湿度
draw.text((150,25),"天气:",font = font06,fill =0)#显示当前天气前缀
draw.text((150,45),"温度:",font = font06,fill =0)#显示当前温度前缀
draw.text((150,65),"湿度:",font = font06,fill =0)#显示当前湿度前缀
draw.text((150,85),"城市:",font = font06,fill =0)#显示当前城市前缀
draw.text((191,25),weather,font = font06,fill =0)
draw.text((191,45),temperature,font = font06,fill =0)
draw.text((191,65),humidity,font = font06,fill =0)
draw.text((191,85),Weather_position,font = font06,fill =0)
draw.text((211,107),weather_update,font = font05,fill =255) #显示天气更新时间
def Basic_refresh(): #全刷函数
logging.info("在启动画布之前,刷新并准备基本内容")#开始画布前刷新准备基础内容 def power_battery(): # 获取当前电池电量
return str(int(subprocess.check_output(
u"echo \"get battery\" | nc -q 0 127.0.0.1 8423|awk -F':' '{print int($2)}'",
shell=True).decode('gbk'))) + u'%'
def Bottom_edge(): # 在图片中添加底边内容
draw.rectangle((0, 105, 250, 122), 'black', 'black')
'''电池图标画图'''
draw.line((126, 109, 154, 109), fill=255, width=1) # 电池顶边
draw.line((126, 110, 126, 119), fill=255, width=1) # 电池左边
draw.line((127, 119, 154, 119), fill=255, width=1) # 电池下边
draw.line((154, 110, 154, 118), fill=255, width=1)
draw.line((155, 112, 157, 112), fill=255, width=1)
draw.line((155, 116, 157, 116), fill=255, width=1)
draw.line((157, 113, 157, 115), fill=255, width=1)
global power_str
power_str = power_battery()
draw.text((129, 108), power_str, font=font04, fill=255) # 显示当前电量百分比
'''电池图标画图'''
draw.ellipse((192, 107, 207, 120), 0, 255) # 时钟图标
draw.line((199, 109, 199, 114), fill=255, width=1)
draw.line((200, 114, 204, 114), fill=255, width=1)
global local_addr # 获取当前IP地址
local_addr = Get_ipv4_address() # 获取当前IP地址
draw.text((10, 107), f"IP:{local_addr}", font=font05, fill=255) # 显示当前IP地址
def Weather(): # 在图片中添加天气内容
with open('/root/2.13-Ink-screen-clock/bin/weather.json', 'r') as file:
weather_data = json.load(file)
global Weather_position, temperature, weather, wind_direction, weather_update, weather_date, humidity
Weather_position = weather_data['cityname'] # 定位位置
temperature = weather_data['temp'] + u'°C' # 温度
weather = weather_data['weather'] # 天气情况
wind_direction = weather_data['WD'] # 风向
weather_update = weather_data['time'] # 天气更新时间
weather_date = weather_data['date'] # 日期
humidity = weather_data['SD'] # 湿度
draw.text((150, 25), "天气:", font=font06, fill=0) # 显示当前天气前缀
draw.text((150, 45), "温度:", font=font06, fill=0) # 显示当前温度前缀
draw.text((150, 65), "湿度:", font=font06, fill=0) # 显示当前湿度前缀
draw.text((150, 85), "城市:", font=font06, fill=0) # 显示当前城市前缀
draw.text((191, 25), weather, font=font06, fill=0)
draw.text((191, 45), temperature, font=font06, fill=0)
draw.text((191, 65), humidity, font=font06, fill=0)
draw.text((191, 85), Weather_position, font=font06, fill=0)
draw.text((211, 107), weather_update, font=font05, fill=255) # 显示天气更新时间
def Basic_refresh(): # 全刷函数
logging.info("在启动画布之前,刷新并准备基本内容") # 开始画布前刷新准备基础内容
global get_date_var global get_date_var
get_date_var=get_date() #记录开始数据 get_date_var = get_date() # 记录开始数据
draw.text((2,2),get_date_var,font = font02,fill =0)#将日期及星期几显示到屏幕 draw.text((2, 2), get_date_var, font=font02, fill=0) # 将日期及星期几显示到屏幕
global local_time global local_time
local_time=get_time() local_time = get_time()
draw.text((5,40),local_time,font = font03,fill =0)#显示当前时间 draw.text((5, 40), local_time, font=font03, fill=0) # 显示当前时间
Bottom_edge() #添加底边内容 Bottom_edge() # 添加底边内容
Weather() #天气内容 Weather() # 天气内容
epd.display(epd.getbuffer(info_image.rotate(180))) epd.display(epd.getbuffer(info_image.rotate(180)))
def Partial_full_brush(): #局部定时全刷函数
Basic_refresh() #全局刷新
logging.debug("局部定时全局刷新") def Partial_full_brush(): # 局部定时全刷函数
epd.init() Basic_refresh() # 全局刷新
def Partial_refresh():#局刷函数 logging.debug("局部定时全局刷新")
logging.info("部分内容更新,此更新建议与分钟同步,以节省墨水屏的使用寿命")#局部内容更新,此更新建议与分钟同步,以节省墨水屏寿命
epd.displayPartBaseImage(epd.getbuffer(info_image.rotate(180)))
epd.init() def Partial_refresh(): # 局刷函数
while (True): logging.info("部分内容更新,此更新建议与分钟同步,以节省墨水屏的使用寿命") # 局部内容更新,此更新建议与分钟同步,以节省墨水屏寿命
global local_time epd.displayPartBaseImage(epd.getbuffer(info_image.rotate(180)))
local_time1=get_time()
if (local_time1==local_time) ==False:
draw.rectangle((5, 40, 133, 82), fill = 255) #时间局刷区域
draw.text((5,40),local_time1,font = font03,fill =0)#刷新当前时间
local_time=local_time1
Local_strong_brush() #局部强刷
get_date_var1=get_date() #局刷判断,如果时间与前一次不一致说明内容变化,需要刷新显示
global get_date_var #再次声明这个是全局变量
if(get_date_var1==get_date_var) ==False:
draw.rectangle((2, 2, 250, 16), fill = 255) #设置头部刷新区域
draw.text((2,2),get_date_var1,font = font02,fill =0)#将日期及星期几刷新显示到屏幕
get_date_var=get_date_var1 #将更新的值保存到初始变量,直到下一次变化时执行该刷新操作
logging.debug("头部日期部位发生刷新变化.")
Local_strong_brush() #局部强刷
global local_addr #当前IP地址
local_addr1 = Get_ipv4_address()
if (local_addr1==local_addr) ==False:
draw.rectangle((1, 107, 123, 120), fill = 0) #设置头部刷新区域
draw.text((10,107),"IP:"+local_addr1,font = font05,fill =255)#显示当前IP地址
local_addr=local_addr1
Local_strong_brush() #局部强刷
'''天气局部更新函数'''
Weather_json = open('/root/2.13-Ink-screen-clock/bin/weather.json','r')
Weather_data = Weather_json.read()
Weather_json.close()
Weather_text=json.loads(Weather_data)
global Weather_position
global temperature
global weather
global wind_direction
global weather_update
global weather_date
global humidity
Weather_position1 = Weather_text['cityname'] #定位位置
temperature1=Weather_text['temp']+u'°C' #温度
weather11 = Weather_text['weather'] #天气情况
wind_direction1 = Weather_text['WD'] #风向
weather_update1 = Weather_text['time'] #天气更新时间
weather_date1 = Weather_text['date'] #日期
humidity1 = Weather_text['SD'] #湿度
if (weather11==weather) ==False:
draw.rectangle((191, 25, 249, 38), fill = 255) #天气局刷区域
draw.text((191,25),weather11,font = font06,fill =0)
weather=weather11
logging.info("天气局部刷新")
Local_strong_brush() #局部强刷
if (temperature1==temperature) ==False:
draw.rectangle((191, 45, 249, 57), fill = 255) #局刷区域
draw.text((191,45),temperature1,font = font06,fill =0)
temperature=temperature1
logging.info("温度局部刷新")
Local_strong_brush() #局部强刷
if (humidity1==humidity) ==False:
draw.rectangle((191, 65, 249, 77), fill = 255) #局刷区域
draw.text((191,65),humidity1,font = font06,fill =0)
humidity = humidity1
logging.info("湿度局部刷新")
Local_strong_brush() #局部强刷
if (Weather_position1==Weather_position) ==False:
draw.rectangle((191, 85, 249, 98), fill = 255) #局刷区域
draw.text((191,85),Weather_position1,font = font06,fill =0)
Weather_position = Weather_position1
logging.info("城市局部刷新")
Local_strong_brush() #局部强刷
if (weather_update1==weather_update) ==False:
draw.rectangle((211, 107, 248, 118), fill = 0) #设置更新时间刷新区域
draw.text((211,107),weather_update1,font = font05,fill =255) #显示天气更新时间
weather_update=weather_update1
logging.info("天气更新时间局部刷新")
Local_strong_brush() #局部强刷
'''天气局部更新函数'''
global power_str
power_str1 =power_battery()
if (power_str1==power_str) ==False:
draw.rectangle((128, 110, 153, 117), fill = 0) #设置更新时间刷新区域
draw.text((129,108),power_battery(),font = font04,fill =255) #显示当前电量百分比
power_str=power_str1
Local_strong_brush() #局部强刷
logging.info("电源电量局部刷新")
try:
##################屏幕初始化#########################
epd = epd2in13_V4.EPD() #初始化
epd.init()#设定屏幕刷新模式
#epd.Clear(0xFF) #清除屏幕内容
##################屏幕初始化#########################
logging.info("Width = %s, Height = %s", format(epd.width), format(epd.height)) #打印屏幕高度及宽度
logging.info("初始化并清空显示屏")#屏幕开始准备相关展示
info_image = Image.new('1', (epd.height, epd.width), 255) #画布创建准备
draw = ImageDraw.Draw(info_image)
Basic_refresh() #全局刷新
Partial_refresh() #局部刷新
epd.init() epd.init()
epd.Clear(0xFF) while True:
epd.sleep() global local_time
local_time1 = get_time()
if local_time1 != local_time:
draw.rectangle((5, 40, 133, 82), fill=255) # 时间局刷区域
draw.text((5, 40), local_time1, font=font03, fill=0) # 刷新当前时间
local_time = local_time1
Local_strong_brush() # 局部强刷
get_date_var1 = get_date() # 局刷判断,如果时间与前一次不一致说明内容变化,需要刷新显示
global get_date_var # 再次声明这个是全局变量
if get_date_var1 != get_date_var:
draw.rectangle((2, 2, 250, 16), fill=255) # 设置头部刷新区域
draw.text((2, 2), get_date_var1, font=font02, fill=0) # 将日期及星期几刷新显示到屏幕
get_date_var = get_date_var1 # 将更新的值保存到初始变量,直到下一次变化时执行该刷新操作
logging.debug("头部日期部位发生刷新变化.")
Local_strong_brush() # 局部强刷
global local_addr # 当前IP地址
local_addr1 = Get_ipv4_address()
if local_addr1 != local_addr:
draw.rectangle((1, 107, 123, 120), fill=0) # 设置头部刷新区域
draw.text((10, 107), f"IP:{local_addr1}", font=font05, fill=255) # 显示当前IP地址
local_addr = local_addr1
Local_strong_brush() # 局部强刷
'''天气局部更新函数'''
with open('/root/2.13-Ink-screen-clock/bin/weather.json', 'r') as file:
weather_data = json.load(file)
global Weather_position, temperature, weather, wind_direction, weather_update, weather_date, humidity
Weather_position1 = weather_data['cityname'] # 定位位置
temperature1 = weather_data['temp'] + u'°C' # 温度
weather11 = weather_data['weather'] # 天气情况
humidity1 = weather_data['SD'] # 湿度
weather_update1 = weather_data['time'] # 天气更新时间
if weather11 != weather:
draw.rectangle((191, 25, 249, 38), fill=255) # 天气局刷区域
draw.text((191, 25), weather11, font=font06, fill=0)
weather = weather11
logging.info("天气局部刷新")
Local_strong_brush() # 局部强刷
if temperature1 != temperature:
draw.rectangle((191, 45, 249, 57), fill=255) # 局刷区域
draw.text((191, 45), temperature1, font=font06, fill=0)
temperature = temperature1
logging.info("温度局部刷新")
Local_strong_brush() # 局部强刷
if humidity1 != humidity:
draw.rectangle((191, 65, 249, 77), fill=255) # 局刷区域
draw.text((191, 65), humidity1, font=font06, fill=0)
humidity = humidity1
logging.info("湿度局部刷新")
Local_strong_brush() # 局部强刷
if Weather_position1 != Weather_position:
draw.rectangle((191, 85, 249, 98), fill=255) # 局刷区域
draw.text((191, 85), Weather_position1, font=font06, fill=0)
Weather_position = Weather_position1
logging.info("城市局部刷新")
Local_strong_brush() # 局部强刷
if weather_update1 != weather_update:
draw.rectangle((211, 107, 248, 118), fill=0) # 设置更新时间刷新区域
draw.text((211, 107), weather_update1, font=font05, fill=255) # 显示天气更新时间
weather_update = weather_update1
logging.info("天气更新时间局部刷新")
Local_strong_brush() # 局部强刷
'''天气局部更新函数'''
global power_str
power_str1 = power_battery()
if power_str1 != power_str:
draw.rectangle((128, 110, 153, 117), fill=0) # 设置更新时间刷新区域
draw.text((129, 108), power_str1, font=font04, fill=255) # 显示当前电量百分比
power_str = power_str1
Local_strong_brush() # 局部强刷
try:
##################屏幕初始化#########################
epd = epd2in13_V4.EPD() # 初始化
epd.init() # 设定屏幕刷新模式
logging.info("Width = %s, Height = %s", format(epd.width), format(epd.height)) # 打印屏幕高度及宽度
logging.info("初始化并清空显示屏") # 屏幕开始准备相关展示
info_image = Image.new('1', (epd.height, epd.width), 255) # 画布创建准备
draw = ImageDraw.Draw(info_image)
Basic_refresh() # 全局刷新
Partial_refresh() # 局部刷新
except OSError as e: except OSError as e:
logging.info(e) logging.info(e)
except KeyboardInterrupt: except KeyboardInterrupt:
logging.info("检测到键盘中断,正在清理并退出") logging.info("检测到键盘中断,正在清理并退出")
finally:
epd.init() epd.init()
epd.Clear(0xFF) # 清除屏幕内容 epd.Clear(0xFF) # 清除屏幕内容
epd.sleep() # 使屏幕进入休眠状态 epd.sleep() # 使屏幕进入休眠状态
epd2in13_V4.epdconfig.module_exit() # 清理资源 epd2in13_V4.epdconfig.module_exit() # 清理资源
exit() exit()
except Exception as e:
logging.error("发生了意外的错误: %s", e)
epd.init()
epd.Clear(0xFF) # 清除屏幕内容
epd.sleep() # 使屏幕进入休眠状态
epd2in13_V4.epdconfig.module_exit() # 清理资源
exit()
# 脚本正常结束后的清理操作
epd.init()
epd.Clear(0xFF) # 清除屏幕内容
epd.sleep() # 使屏幕进入休眠状态
epd2in13_V4.epdconfig.module_exit() # 清理资源
exit()

View File

@@ -4,11 +4,10 @@ After=network.target
[Service] [Service]
Type=forking Type=forking
# 等待网络完全启动
ExecStartPre=/bin/bash -c 'until ping -c1 baidu.com &>/dev/null; do sleep 1; done'
ExecStart=/root/2.13-Ink-screen-clock/bin/start.sh ExecStart=/root/2.13-Ink-screen-clock/bin/start.sh
ExecStop=/usr/bin/screen -S main_screen -X quit ExecStop=/bin/bash -c "pkill -f /root/2.13-Ink-screen-clock/bin/main.py; pkill -f /root/2.13-Ink-screen-clock/bin/weather.py"
Restart=on-failure WorkingDirectory=/root/2.13-Ink-screen-clock/bin
Restart=always
User=root User=root
[Install] [Install]

View File

@@ -1,10 +1,8 @@
#!/bin/bash #!/bin/bash
f_name=main.py f_name=main.py
f1_name=weather.py f1_name=weather.py
f2_name=app.py
dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
logdir="${dir%/*}/log" logdir="${dir%/*}/log"
appdir="${dir%/*}/app"
# 确保日志目录存在 # 确保日志目录存在
mkdir -p "${logdir}" mkdir -p "${logdir}"
pid=`ps -ef |grep $dir/$f_name | grep -v grep |awk '{print $2}'` pid=`ps -ef |grep $dir/$f_name | grep -v grep |awk '{print $2}'`
@@ -14,4 +12,3 @@ do
done done
nohup /usr/bin/python3 -u $dir/$f_name > $logdir/info.log 2>&1 & nohup /usr/bin/python3 -u $dir/$f_name > $logdir/info.log 2>&1 &
nohup /usr/bin/python3 -u $dir/$f1_name > $logdir/info-wenter.log 2>&1 & nohup /usr/bin/python3 -u $dir/$f1_name > $logdir/info-wenter.log 2>&1 &
nohup /usr/bin/python3 -u $appdir/$f2_name > $logdir/info-app.log 2>&1 &

View File

@@ -1,21 +1,16 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding:utf-8 -*- # -*- coding:utf-8 -*-
import os, sys, re, json, time, datetime
import logging
import subprocess
import os import os
from threading import Timer import json
import time
import logging
import requests import requests
from threading import Timer
white = 255 # 颜色 white = 255 # 颜色
black = 0 black = 0
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s') # 设置日志级别 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s') # 设置日志级别
picdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'pic')
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir):
sys.path.append(libdir) # 将引入文件添加到环境变量
def get_area_id(city_name): def get_area_id(city_name):
"""从city.js中检索AREAID无限重试直到成功""" """从city.js中检索AREAID无限重试直到成功"""
url = "https://j.i8tq.com/weather2020/search/city.js" url = "https://j.i8tq.com/weather2020/search/city.js"
@@ -23,25 +18,20 @@ def get_area_id(city_name):
try: try:
response = requests.get(url) response = requests.get(url)
response.raise_for_status() # 检查请求是否成功 response.raise_for_status() # 检查请求是否成功
# 直接打印原始数据 city_data_text = response.text.strip().split('var city_data = ')[-1].rstrip(';')
logging.debug("Raw data from city.js: %s", response.text)
# 预处理返回的数据去除非JSON部分
city_data_text = response.text.strip()
city_data_text = city_data_text.split('var city_data = ')[-1].rstrip(';')
if city_data_text: if city_data_text:
city_data = json.loads(city_data_text) city_data = json.loads(city_data_text)
# 遍历数据结构,查找城市名称
for province, cities in city_data.items(): for province, cities in city_data.items():
for city, districts in cities.items(): for city, districts in cities.items():
for district, info in districts.items(): for district, info in districts.items():
if info['NAMECN'] == city_name: if info['NAMECN'] == city_name:
return info['AREAID'] return info['AREAID']
logging.error("城市名称 '%s' 在城市数据中未找到,将使用默认城市信息", city_name) logging.error("城市名称 '%s' 在城市数据中未找到", city_name)
else: else:
logging.error("从city.js接收到的数据为空") logging.error("从city.js接收到的数据为空")
except (requests.RequestException, json.JSONDecodeError) as e: except (requests.RequestException, json.JSONDecodeError) as e:
logging.error("检索或解析城市数据时发生错误: %s", e) logging.error("检索或解析城市数据时发生错误: %s", e)
time.sleep(5) # 重试前等待5秒 time.sleep(180) # 重试前等待
def get_current_city(): def get_current_city():
"""获取当前城市名称,无限重试直到成功""" """获取当前城市名称,无限重试直到成功"""
@@ -57,13 +47,17 @@ def get_current_city():
logging.error("获取当前城市失败: %s", data['message']) logging.error("获取当前城市失败: %s", data['message'])
except (requests.RequestException, json.JSONDecodeError) as e: except (requests.RequestException, json.JSONDecodeError) as e:
logging.error("检索或解析当前城市时出现错误: %s", e) logging.error("检索或解析当前城市时出现错误: %s", e)
time.sleep(5) # 重试前等待5秒 time.sleep(180) # 重试前等待
# 注意:无限重试可能会在特定情况下导致程序无法终止,请确保在实际使用中考虑适当的退出条件或限制重试次数。
def schedule_getWeath():
"""调度 getWeath 函数每3分钟执行一次"""
getWeath()
Timer(180, schedule_getWeath).start() # 重新设置定时器
def getWeath(city='101060101'): def getWeath(city='101060101'):
headers = { headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
'Referer': 'http://www.weather.com.cn/' 'Referer': 'https://www.weather.com.cn/'
} }
current_city = get_current_city() current_city = get_current_city()
if current_city: if current_city:
@@ -71,14 +65,12 @@ def getWeath(city='101060101'):
if area_id: if area_id:
city = area_id city = area_id
try: try:
response = requests.get('http://d1.weather.com.cn/sk_2d/'+city+'.html',headers=headers) response = requests.get(f'https://d1.weather.com.cn/sk_2d/{city}.html', headers=headers)
response.raise_for_status() # 检查请求是否成功 response.raise_for_status() # 检查请求是否成功
response.encoding = 'utf-8' response.encoding = 'utf-8'
Weath = response.text[11:] weather_data = response.text[11:]
fileHandle = open('/root/2.13-Ink-screen-clock/bin/weather.json', 'w') with open('/root/2.13-Ink-screen-clock/bin/weather.json', 'w') as fileHandle:
fileHandle.write(str(Weath)) fileHandle.write(weather_data)
fileHandle.close()
Timer(180, getWeath).start() # 定时器函数,间隔三分钟下载文件至本地
print("天气文件更新") print("天气文件更新")
except requests.RequestException as e: except requests.RequestException as e:
logging.error("获取天气数据时出现网络错误: %s", e) logging.error("获取天气数据时出现网络错误: %s", e)
@@ -86,9 +78,7 @@ def getWeath(city='101060101'):
logging.error("发生了意外错误: %s", e) logging.error("发生了意外错误: %s", e)
try: try:
getWeath() # 天气获取函数开始运行 schedule_getWeath() # 开始调度天气获取函数
except IOError as e:
logging.info(e)
except KeyboardInterrupt: except KeyboardInterrupt:
logging.info("检测到键盘中断,正在退出") logging.info("检测到键盘中断,正在退出")
except Exception as e: except Exception as e: