树莓派相框:主要幻灯片播放选项 + 温度监控脚本 树莓派相框:主要幻灯片播放选项 + 温度监控脚本

树莓派相框:主要幻灯片播放选项 + 温度监控脚本

数码相框

我在之前的帖子中提到过,我用树莓派为客厅制作了一个数码相框。它每小时循环播放240张照片,每张照片之间间隔15秒。以前,我用的是树莓派3上的帧缓冲图像查看器fbi。现在我想升级到更新的树莓派操作系统(它是基于Debian的定制系统,以前叫Raspbian),所以决定换成树莓派5。

FBI 仍然可以在 Raspberry Pi OS(又名 Bookworm)上运行,但是用于在夜间开关 HDMI 的 tvservice 命令却无法正常工作,所以我不得不重新设计这个功能, 正如之前讨论过的。这导致我需要迁移到基于 X Window 的设置,因此我想列出一些在 Raspberry Pi 或 Linux 上进行全屏幻灯片播放的主要选项。

周边基础设施

在这个环境中,我创建了一个每小时自动生成的图片“播放列表”,其中包含一些代码,可以将图片放置在 1920×1080 的背景上,并显示拍摄日期,同时穿插各种应季和励志海报。这里我就不赘述了,只想说 ImageMagick 的功能非常强大。

关键在于……

  • 我每小时都会生成一个新的包含 240 张图片的播放列表。有些是现有的全屏 JPG 图片,例如著名古迹、励志名言等等,另一些则是放置在背景上的照片。
  • 对于后者,我使用 ImageMagick 创建了一个以 UUID 命名的 JPG 文件。
  • 每到整点,我都会关闭当前幻灯片,然后用当小时的播放列表重新启动它。

软件选项

ImageMagick animate:这大概是这样的

我没有选择这个,因为我的播放列表(一个文件列表)指向多个目录中的文件(按日期、主题等排序)。而且由于其中很多文件都是我动态创建的,所以它们的名称类似于animate -pause 15 *.jpg

 /pictures/img_gen/photo_ffe5a9b2-7087-4b29-9d26-77dfe948fce4.jpg

那可是 65 个字符,240 * 65 = 15,600,超过了 Linux 命令行最大长度限制(我记得是 4K)。其实,无论我显式地使用“animate…”并指定每个文件名,还是使用“*.jpg”指定目录中的所有文件,都没关系,因为 shell 会自动展开通配符。

侏儒之眼 (eog):这东西……呃,算了。我安装了,但是

  • 手册页非常简短。
  • eog –help 讨论了 man 手册页中未列出的标志。
  • 该项目的主页没有任何文档。

我觉得这对我来说太高级了。

mplayer:我其实没试过这个,不过我在做研究的时候看到有人提到过。mplayer 当然是个视频播放器,但你也可以把它设置成幻灯片应用:

 feh: mplayer mf://*.jpg -mf fps=10

现在我们来谈谈真正的竞争对手。feh 是一款“轻量级、可配置且功能全面图像查看器”,面向命令行用户。你可以像这样把它当作幻灯片来使用:

 feh --verbose --geometry 1920x1080 --borderless --hide-pointer \
--slideshow-delay 15 -f file_list.txt

这是我的首选,但不知何故,feh 经常在我的树莓派上卡死。屏幕会黑屏,直到我重启树莓派才会恢复正常。我尝试将问题范围缩小到特定照片,但问题是随机发生的,而且我所有的照片/生成的图像都能正常循环显示,直到切换到下一个应用程序。此外,我对 `--verbose` 参数的实际输出效果感到失望。我通过 cron 定时任务调用脚本来运行 feh,并将标准输出和标准错误重定向到一个输出文件,但输出始终为空。

公平地说,我使用的是 R Pi OS 软件包管理器中的 feh 3.9.1-2 版本。feh 网站上有更新的版本 (3.10),所以这些问题可能已经解决了。

然而,我后来发现……

获胜者:令人印象深刻

根据手册页的描述, Impressive是一款“带有炫酷视觉效果的演示工具”。

Impressive 是一款简洁的演示程序,可以播放 PDF 文档、图像文件或视频文件的幻灯片。它使用 OpenGL 进行渲染,因此可以实现一些炫酷的视觉效果。

托管在 SourceForge 上……想想都觉得可怕……但这几乎是它唯一的缺点了。

以下是一个命令行示例:

令人印象深刻 --verbose --cache memory --wrap --auto 15 \
--fullscreen --geometry 1920x1080 @/some/path/to/filelist.txt

`--auto` 参数决定了每张“幻灯片”(在本例中是图片)自动播放的时间间隔(以秒为单位)。我可能不需要 `--wrap` 参数,它表示“播放完最后一张幻灯片后重新开始”。请注意文件列表中的“@”符号。

我觉得我只用了 Impressive 大约 1% 的功能……等等……它的功能列表真是令人印象深刻。你可以用它内置的脚本语言 Python 实现非常复杂的演示控制。我可能只是用这个应用做了最简单的事情而已。

Impressive 的一个优点是,它不会简单地切换到每一期,而是使用随机的转场效果:擦除、淡入淡出等等。非常养眼!当然,我可以自己选择使用哪些转场效果,但我通常不做任何指定,直接说“全部使用”。

Impressive 在启动时会从 Pillow 库发出一些关于已弃用 API 的警告。如果您查看应用的新闻,会发现这些问题已在 Impressive 的后续版本 (0.13.2) 中修复,但我使用的是通过包管理器安装的 0.13.1 版本。这些只是警告,不会影响应用的正常运行。

令人印象深刻的缓存

最初使用 Impressive 时,它​​经常卡死,而且 CPU 使用率会飙升到 100%。有好几次我走进客厅,发现画面切换到一半就卡住了,这让我很沮丧。

我正要放弃它的时候,注意到了-cache 内存选项。

如果没有缓存,Impressive 必须在显示每个页面之前进行预渲染。请记住,它是一款演示软件,假设您有一个 PDF 文件。Impressive 需要解析下一页,并按照预期的方式进行渲染等等。

默认情况下,Impressive 会将缓存存储在磁盘上,这对于普通笔记本电脑来说没问题,但在使用 Micro SD 卡的树莓派上,它会频繁地读写磁盘。手册页中指出,`--cache memory` 选项是“最快的缓存方式”。  方法,  但是  需要  非常大的内存容量(在 1024×768 分辨率下,每页约 3 MiB )。

这或许有点天真,但我的思路是这样的:

  • 1024×768 = 786,432 像素
  • 1920×1080 = 2,073,600 像素
  • 所以 1920×1080 的尺寸比 1024×768 大约大 2.6 倍。就当是 3 倍吧。
  • 因此,粗略估计,每个 1920×100 分辨率的图像将比 1024×768 分辨率的图像占用 3 倍的 RAM,或者说大约 9MiB。

每小时“演示”240张图片,那就是(240*9MiB = )2.16GB。我的树莓派5有4GB内存,所以这不是问题。

Impressive 实际上会告诉你它使用了多少内存。调用并渲染后,它会输出:

后台渲染完成,使用了 1423.8 MiB 内存。

每张图片略低于 6MB。

凭借出色的跑步表现,我还有很大的提升空间:

 # 免费 -m
               全部的        用过的        自由的      共享  增益/缓存  可用的
内存:            4042        2166        879        101        1170        1876
交换:            99          0          99

热冲击

与之前的树莓派不同,树莓派 5 对温度更加敏感。运行大量任务不会导致主板过热损坏,但主板会降低性能,直到温度下降。这种热应力对主板不利,性能自然也会降低。

我选择使用铝制散热片外壳而不是风扇,因为我怀疑风扇 24 小时运转最终需要更换,而且我也不打算让树莓派高强度运行。

但我当时想……实际上,我每小时都会让 Impressive 运行缓存和渲染,加上我的 ImageMagick 在后台运行,再加上正常的操作系统运行,驱动 wifi 和显示……在所有这些程序都在运行的时候,我是否会给主板造成压力?

我创建了一个定时任务,每分钟将温度信息写入文件:

 /usr/bin/echo "$(/usr/bin/date) $(/usr/bin/vcgencmd measure_temp)" \
>> /pictures/log/temperature.$(date '+%Y-%m-%d').log 2>&1

这会在日志文件中生成类似这样的行:

 2026 年太平洋标准时间 1 月 15 日星期一 12:10:01 温度=42.2'C

然后我编写了一个简单的脚本来分析数据。

 #!/usr/bin/perl -w

my $file = shift || die "没有文件!\n";
峰值 = ();
$peak{'temp'} = 0;

打开(IN,$file);
while (<IN>) {
大口咀嚼;
$info = $temp = $_;
$temp =~ s/^.*=//;
$temp =~ s/\'.*$//;
如果($temp > $peak{'temp'}){
$info =~ s/ temp=.*$//;
$peak{'date'} = $info;
$peak{'temp'} = $temp;
}
}
关闭(IN);
$fahr = sprintf("%.1f",( $peak{'temp'} * 1.8 ) + 32);
# 打印 115 而不是 115.0
if ( int($fahr) == $fahr ) { $fahr = int($fahr); }
print("峰值温度:$peak{'temp'}摄氏度(${fahr}华氏度),日期:$peak{'date'}\n");

今天,我的 R Pi 显示:

最高气温:47.2摄氏度(117华氏度),时间:2026年1月15日星期一太平洋标准时间12:02:01