65.9K
CodeProject 正在变化。 阅读更多。
Home

树莓派:灯光、摄像、行动,以及异地存储

starIconstarIconstarIconstarIconstarIcon

5.00/5 (11投票s)

2015年8月13日

CPOL

16分钟阅读

viewsIcon

38691

构建一个带房间照明、可捕捉视频异地存储、安全远程管理的运动触发摄像头……所有这些都通过简单的 bash 脚本实现。非常适合异地监控和野生动物摄像。

同时学习

本教程包含几个可以单独使用的组件,其中一些是任何 Linux 系统上的重要技能。如果您直接跳转到这些部分,请确保先安装适用的 附加软件包。可从以下列表快速跳转到这些部分:

Finished Project Image yet another

预计完成时间
  • 初学者:几天
  • 经验丰富者:几小时
目标能力
  • 检测到运动时收集视频片段
  • 基于 PIR,可在黑暗中进行运动检测
  • 录制视频时打开房间灯
  • 将视频传输到安全、异地的位置进行存储
  • 不累积磁盘空间使用量
  • 易于 SDD 访问
  • 长时间稳定运行,无需重启
  • 断电后自动恢复
  • 紧凑、轻便、低功耗
  • 简单的编程,低开销
  • 完全由用户控制,安全远程管理
  • 定期报告外部 IP 地址
  • 开源、完全透明的硬件和软件,无可能导致设备变砖的黑盒固件更新
  • 如果您感到厌倦,可以无限次地重新分配任务
  • 有趣
  • 便宜

我的第一个装置是在五个月前完成的。该装置从 700 英里外忠实地为我服务了两个多月,期间没有重启……除了断电一次,但它恢复了。每天两次,它通过发送视频给我并附带其外部 IP 地址,来友善地提醒我它正在工作。

背景

必备组件

材质

以下是项目中使用的零件:

您可以购买更便宜的 PI 和 SDD,也许能节省 30 美元,但 PI 2 – 拥有 1GB 内存 – 使项目更加稳健……而且 NOOBS 设置的简单性无与伦比。设置完成后,系统可以完全通过 SSH 管理,因此键盘、鼠标和 HDMI 连接器可以用于其他地方。我更喜欢为此应用硬连接的网络接口,因为它在远程无人值守的系统上(可能长达数月)要可靠得多。

此监控摄像头最好作为“即用即弃”设备运行:当收集到视频或图片时,它会被以某种方式处理并被后续的视频覆盖。(当然,您可以更改此行为。)如果没有即用即弃,SDD 可能会在用户干预之间的时间内填满(或被损坏)。为了处理视频,设备被编程为在事件发生时将信息传输到异地。在此项目中,我将使用 FTP 将视频传输到另一台计算机。如果您没有某个地方的 FTP 帐户,您可以在另一台计算机上设置一个。或者,修改代码以将视频发送到云服务,或使用 scp、电子邮件、网络共享等。

我将此教程标记为中级,仅仅是因为您必须首先熟悉您的树莓派、Raspian 操作系统和非常基础的电子知识。安装和使用 Raspian 操作系统,配置/使用相机,使用终端等。在打第一个哈欠后不久,您就可以继续前进。

关于表示法的一个注释:在下面的某些命令中,我使用了表示法<something>,例如 pi@<Pi's IP>。当您看到此内容时,表示用您对应的内容替换整个<something>(包括 < 和 >),例如 pi@192.168.0.17。

最小 Raspian 操作系统

在 PI 关闭的情况下,连接相机、SDD、鼠标/键盘和 HDMI 显示器,然后将其插入。您可能已经有一个已加载软件包和配置/自定义的有效安装,但我建议您从新的 SDD 开始,并重新安装。在设置过程中:

  • 更改密码
  • 启用引导至桌面
  • 国际化>语言、键盘、时区
  • 启用相机
  • 高级>启用 SSH
  • 高级>设置主机名

稍后,在机器重启后,您可以使用 sudo raspi-config 进行其他配置更改。现在您拥有一个“刚刚好”的系统,从相同的地方开始并采取相同的步骤,我们应该会到达相同的地方。我也将在我的 PI 上遵循这里的过程。编辑系统文件时,我们将首先使用以下命令创建一个备份文件:sudo cp <thePath/theOriginalFile> <thePath/theBackupFile>。如果需要恢复,则运行:sudo mv <thePath/theBackupFile> <thePath/theOriginalFile>。最后,除非此处打印,否则不要使用 sudo。

启动到 Rasbian 后,使用静态 IP 配置您的网络。

附加软件包

更新操作系统并安装一些必需的软件包

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install wget lynx ffmpeg mplayer x11vnc omxplayer
将内存用作磁盘空间

为了减轻 SDD 卡的负担,也许还能延长其使用寿命,并提高视频录制的效率,我们希望使用内存作为临时视频存储。为此创建一个空间:

mkdir ~/volatile

告诉操作系统将该空间分配给内存

sudo cp /etc/fstab /etc/fstab.backUp
gksu leafpad /etc/fstab

仔细、精确地在末尾添加以下新行:

tmpfs /home/pi/volatile tmpfs defaults,noatime,nosuid,nodev,noexec,mode=1777,size=20M 0 0

保存、退出并重启。现在,您的主文件夹中应该有一个名为volatile的目录,它指向内存,并且可以容纳最多 20MB 的文件数据。要进行测试,请运行:

touch ~/volatile/helloMemory

转到文件管理器,查看名为helloMemory的新文件是否在 volatile 目录中。然后,重启并验证它是否已消失。如果消失了,那么一切正常。我们将所有视频都写入此 volatile 文件夹,并在其被处理后尽快删除。

SSH,以及可选的 VNC 隧道

能够从其他地方 SSH 登录到 PI 对于远程管理至关重要。我更喜欢通过 SSH 隧道连接 VNC,这样我就可以像坐在那里使用鼠标、键盘和显示器一样操作 PI 桌面。

SSH 的默认配置在文件/etc/ssh/sshd_config中提供。我们现在将使用它,但请确保您的 PI 尚未将端口 22 暴露给互联网(例如,通过转发端口 22 到您的 PI IP 地址的路由器,或通过将 PI 视为非军事区提供商/设备)。在面对互联网之前,我们需要更好地锁定它。

另一台 LAN 计算机上,您将要连接的计算机(称为客户端),安装一个 SSH 客户端和一个 VNC 查看器。我在客户端上使用 Linux,并使用 open-ssh 进行 SSH 连接,使用 remmina 进行 VNC 查看器。对于许多 Linux 发行版,open-ssh 默认已安装,因此唯一的命令是:

sudo apt-get install remmina 

还有其他方法,包括允许从 Windows 计算机进行连接的方法,但 x11vnc 搭配 remmina 快速、轻量且功能丰富。如果您在客户端计算机上使用商业操作系统,您将需要做一些研究(putty是一个优秀的跨平台 SSH 客户端)。当您没有本地 Linux 机器可以在客户端上安装 VirtualBox 并创建一个带有桥接适配器的 Debian Linux VBox 虚拟机时,一个更好的选择是。

现在(假设是 Linux 客户端),从客户端测试与 PI 的连接:

ssh -L 5092:localhost:5900 pi@<Pi's IP> 

这会在 PI 上创建一个 SSH 终端会话,将 PI 上的端口 5900 隧道到您的客户端的端口 5902。在该终端会话中,启动 x11vnc:

x11vnc -ncache -display :0 # must be run on each new session

这会在 PI 上打开端口 5900 作为 VNC 端口。要从客户端获取桌面,请在客户端计算机上打开 remmina,并使用以下配置文件进行连接:协议 VNC,服务器 127.0.0.1:5092,颜色深度真彩色,质量中等。如果一切顺利,您现在将在客户端机器上的一个窗口中看到 PI 桌面……并具有复制/粘贴和相机查看功能。

始终以优雅的方式重启/关闭 PI。从 SSH 终端会话:

sudo reboot -h && exit

sudo shutdown -h now && exit

 

在通过打开路由器上的端口将 PI 暴露给互联网之前,请创建一个 SSH 密钥对,配置 SSH 使用PubkeyAuthentication,并将PasswordAuthentication设置为 no。以下是基本步骤:

在 PI 上,创建一个名为.ssh的隐藏文件夹:

mkdir ~/.ssh

在客户端计算机上(而不是 PI 上),创建一个 SSH 密钥:

ssh-keygen -t rsa -b 4096 -C "$(whoami)@$(hostname)-$(date -I)" #open-ssh required

当被问及位置时,输入:/home/<user>/.ssh/piClient_rsa。我设置了一个密码,以防有人物理访问我的机器(这不是登录密码)。该命令会创建一个密钥对和一个单独的文件,其中包含客户端~/.ssh文件夹中的公钥部分。

然后,从客户端将公钥传输到 pi。

ssh-copy-id -i ~/.ssh/piClient_rsa.pub pi@<PI's IP> # PI's password when asked

在 PI 上,打开隐藏文件夹~/.ssh。那里应该有一个authorized_keys文件,其中包含客户端的公钥。接下来,编辑/etc/ssh/sshd_config文件:

sudo cp /etc/sshd_config /etc/sshd_config.backUp
gksu leafpad /etc/ssh/sshd_config

以下是我sshd_config中唯一未注释的行:

Port 22
Protocol 2
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_dsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
UsePrivilegeSeparation yes
KeyRegenerationInterval 1h
ServerKeyBits 2048
LoginGraceTime 1m
PermitRootLogin no
StrictModes yes
PubkeyAuthentication yes
AuthorizedKeysFile %h/.ssh/authorized_keys
IgnoreRhosts yes
RhostsRSAAuthentication no
HostbasedAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
PasswordAuthentication no
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server

有了这个,PasswordAuthentication就不再被使用。

最后,在 PI 上,更改一些权限,否则将无法工作:

  chmod 700 ~/.ssh
  chmod 600 ~/.ssh/*

尽管有争议的好处,您可能还希望将端口从默认端口(22)更改为大于 1024 的非标准端口。这样隐藏 SSH 端口可以阻止不熟练的攻击者用无谓的密码尝试轰炸您的路由器。(您不会受到简单的密码攻击的威胁,因为您很聪明并且使用了公钥认证。)如果您在一个潜在危险的本地网络上,请保留端口 22。最好的方法是在 PI 上保留端口 22,并让路由器将 WAN 请求转发到一个不寻常的端口,例如 1141,到 PI 上的端口 22。

重启或重新启动 PI 上的 SSH:

sudo service ssh restart

注意:如果您在创建密钥时设置了密码,您的会话将要求您输入密码。这是读取密钥所需的密码,而不是系统密码。(可以将其视为第二层安全。)现在,回到客户端。使用 SSH 密钥登录 PI:

ssh -i ~/.ssh/piClient_rsa pi@<PI's IP>

使用 SSH 密钥隧道 VNC:

ssh -i ~/.ssh/piClient_rsa -L 5092:localhost:5900 pi@<IpForPi> 

(如果您更改了默认端口,请包含开关-p <yourPort#>)。

要了解更多关于 SSH 和 SSH 密钥的信息,请访问以下两个链接。它们是 Arch Wiki 页面,但除了安装和守护进程内容外,它们也适用于 Raspian。Raspian 默认启用守护进程,并且 SSH 已安装。

[可选]强制 HDMI 分辨率

当 HDMI 连接在启动时拔掉时,Raspian 操作系统默认使用低分辨率。正常使用时,我的 HDMI 连接是断开的,并且在使用 VNC 时,我更喜欢更高的分辨率。

sudo cp /boot/config.txt /boot/config.txt.backUp
gksu leafpad /boot/config.txt

在显示NOOBS Auto-generated Settings的行之后,将其改为:

# NOOBS Auto-generated Settings:
hdmi_force_hotplug=1
config_hdmi_boost=4
start_x=1
gpu_mem=128
#Modified below to enable higher resolution when hdmi is unplugged
disable_overscan=1
hdmi_group=2
hdmi_mode=51

保存、退出、重启。

测试相机

注意:raspivid 和 omxplayer 都不会通过 VNC 显示视频。要观看视频,您需要将其转换为 mp4 并使用 mplayer 显示。

从 PI 桌面打开一个终端并运行:

raspivid -t 15000 -o ~/volatile/video.h264 -fps 4 -w 600 -h 400 -rot 180 -p '10,10,600,400'

这将从相机收集 15 秒的视频,帧率为 4 帧/秒,并将其保存在~/volatile/video.h264中。-w-h标志设置图像尺寸。-rot标志旋转图像,-p string设置预览窗口。添加-n标志可在录制期间抑制预览以节省资源。

如果 PI 连接到 HDMI 显示器,您可以使用:omxplayer /volatile/video.h264 --fps 4观看视频,但 omxplayer 不会在 VNC 客户端中渲染。而是运行:

ffmpeg -r 4 -i volatile/video.h264 -vcodec copy video.mp4
mplayer video.mp4 -fps 4
rm volatile/video.h264

第一个命令从volatile/video.h264文件创建了一个 4fps 的 mp4 视频,并将其存储在您的主目录中,名为video.mp4。mplayer 命令播放了视频。处理完成后,原始视频volatile/video.h264文件被删除。

尝试使用其他 raspivid 帧率等。我根据实际应用需求设置了持续时间和帧率。我只需要 15 秒的视频,4 fps 创建的视频小于 1MB,因此上传速度很快。如果您正在录制活跃、鬼鬼祟祟的野生动物,请提高帧率。(我主要录制一种行动缓慢的哺乳动物。)

配置引脚

首先,加入gpio组:

sudo gpasswd -a pi gpio

注销,然后重新登录以完成成员资格。

我们将使用两个引脚,GPIO 23 和 GPIO 24。GPIO 23 将作为输入(传感器引脚),用于感应运动检测器何时被激活。GPIO 24 将作为输出(信号引脚),用于触发房间灯。我们希望在启动时配置这些引脚。我们将使用简单的 bash 脚本完成所有操作。首先,我们将为所有这些创建一个文件夹:

mkdir ~/bashScripts

然后,创建一个脚本来配置引脚:

leafpad ~/bashScripts/configPins

将以下内容输入文件,保存并退出:

#!/bin/bash
cd /sys/class/gpio/
echo "23" > export
echo "in" > gpio23/direction
echo "24" > export
echo "out" > gpio24/direction
chown root:gpio gpio24/value
chmod 660 gpio24/value

使其可执行:

chmod +x ~/bashScripts/configPins

现在,我们需要让 PI 在启动时运行configPins脚本:

sudo cp /etc/rc.local /etc/rc.local.backUp
gksu leafpad /etc/rc.local

使最后两行读为:

sh /home/pi/bashScripts/configPins
exit 0

保存、退出、重启。每次启动时,GPIO 23 始终是输入,24 始终是输出,除非您稍后删除在rc.local中添加的行。

电子学

在接线最终项目之前,最好先做一个测试电路,并验证引脚是否按预期工作。首先,让我们看一下电路板上引脚的物理位置。以下图片来源为 http://elinux.org/RPi_Low-level_peripherals#P2_header

pin out

注意图片中电路板的朝向。偶数引脚位于右侧,从上到下递增(2、4、6 等)。

  • 引脚 4 为 +5V
  • 引脚 6 为接地 (GND)
  • 引脚 16 为 GPIO 23
  • 引脚 18 为 GPIO 24

左上角的引脚是引脚 1 (+3V)。

永远不要让 5V 引脚(例如引脚 4)的导线连接到除 GND 之外的任何其他引脚,即使如此,也只能在它们之间放置一个高值的电阻。就我们而言,我们不会让任何引脚直接连接到任何其他引脚。我们所有的引脚,无论是在测试电路中还是在最终电路中,都将始终连接到设备。在测试电路中,设备是电阻或电阻-LED 组合。这是测试电路的原理图:

schematic

avconv

我在引脚 4 和引脚 6 之间使用了一个 2.2K 电阻来驱动(红色)电源指示 LED。用于(蓝色)引脚 18 LED 的电阻是 570 欧姆。我还将一个 47 欧姆的电阻放在了开关电路中(实际上不是必需的,只是为了保持编辑一致性)。

引脚 2 的(红色)LED 充当电源指示灯(应亮起)。

蓝色 LED 显示引脚 18 (GPIO 24)的状态。要打开它,请运行:

echo "1" > /sys/class/gpio/gpio24/value

用以下命令关闭它:

echo "0" > /sys/class/gpio/gpio24/value

在测试电路中,引脚 16 (GPIO 23)感应开关是否闭合。要进行测试,请运行:

while [ true ]; do cat /sys/class/gpio/gpio23/value; done

终端将连续输出 0,直到您闭合开关,此时它将输出 1。

项目电路图如下:

project circuit

请注意,在测试电路中连接到引脚 1 (+3V)的橙色电线在最终电路中已被移除,因为 3 伏信号现在由 PIR 的黄色引线提供。您希望 PIR 跳线处于 H 位置(触发然后释放,而不是触发并保持 http://learn.adafruit.com/downloads/pdf/pir-passive-infrared-proximity-motion-sensor.pdf)。我将时间设置旋钮完全逆时针(非常短)——刚好足以触发新的运动事件。根据您的需要调整灵敏度。我所有的调整都在 PI 关闭的情况下进行。

Run

while [ true ]; do cat /sys/class/gpio/gpio23/value; done

如果几分钟内没有任何移动,您将看到一串 0,直到您在 PIR 上挥手,这时它将输出 1。

关于 Powerswitchtail II 的说明:接地线连接到负极。在我的 switchtail 上,我还用跳线将负极连接到了接地端。将 switchtail 插在台灯上,运行:

echo "1" > /sys/class/gpio/gpio24/value # on
echo "0" > /sys/class/gpio/gpio24/value # off

最后,代码

仅限 PIR 触发的灯光和相机

创建一个新的 bash 脚本,名为litesCamera

leafpad ~/bashscripts/litesCamera

使其内容如下:

#!/bin/bash
echo control c to quit
while [ true ]; do    
   sleep 0.5
   state=$(cat /sys/class/gpio/gpio23/value)
   if [[ $state -eq 1 ]]; then
     if [ -e ~/volatile/video.h264 ]; then
        rm ~/volatile/video.h264
     fi
     echo "1" > /sys/class/gpio/gpio24/value
     raspivid -t 15000 -o ~/volatile/video.h264 -fps 4 -w 600 -h 600 -rot 180 -n
     echo "0" > /sys/class/gpio/gpio24/value
     echo control c to quit
   fi
done

这表示:如果 PIR 检测到运动,则删除上一个视频(如果存在),打开灯,录制一个 15 秒的视频,关闭灯,然后等待 PIR 的下一个信号。(尝试找出为什么文件被显式删除而不是简单覆盖。)

使脚本可执行:

chmod +x ~/bashscripts/litesCamera

运行它:

~/bashscripts/litesCamera

当 PIR 激活时,一个视频将在内存中的~/volatile/video.h264中录制。您可以像在“测试相机”部分那样处理此视频。注意,如果 PIR 再次触发,录制的视频将在您工作时被覆盖。

即时 FTP 视频到异地

假设您在另一台计算机上有一个 FTP 帐户,位于ftp://example.com,并且上面有一个名为myVideos的文件夹。还假设您的用户名是userName,密码是passWd

创建一个名为litesCameraFtp的脚本:

leafpad ~/bashScripts/litesCameraFtp

使其内容如下:

#!/bin/bash
path=~/volatile/
suffix=MyVideo.h264
################## Enter your ftp url and user:pwd here ################
secretUrl='ftp://example.com/myVideos/'
user=userName:passWd

while [ true ]; do
   sleep 0.5
   state=$(cat /sys/class/gpio/gpio23/value)
   if [[ $state -eq 1 ]]; then
     now=$(date +"%b_%d_%T")    
     url=$secretUrl$(echo ${now//:/_})$suffix
     if [ -e ~/volatile/video.h264 ]; then
        rm ~/volatile/video.h264
     fi
     echo "1" > /sys/class/gpio/gpio24/value
     raspivid -t 15000 -o ~/volatile/video.h264 -fps 4 -w 600 -h 600 -rot 180  -n
     echo "0" > /sys/class/gpio/gpio24/value
     curl -T ~/volatile/video.h264 $url --user $user
   fi
done

别忘了在上面的脚本中填入您真实的secretUrl和用户名。在不安全的 LAN 环境或物理环境中,硬编码 ftp user:pwd存在风险,需要进一步锁定。(有哪些方法?简单的 ftp 真的安全吗?)

使其可执行:

chmod +x ~/bashScripts/litesCameraFtp

运行它:

~/bashscripts/litesCameraFtp

然后触发一个视频,观察终端以查看 ftp 完成情况,并验证它是否在您的 ftp 站点上。

最后,结果存在固有的不确定性。我们将定期发送一个视频来向我们保证设备仍在运行。此视频将在文件名中包含 PI 的外部 IP。这样,我们将拥有当前的 IP 地址,用于远程管理任务。

~/bashscripts文件夹中创建一个名为litesCameraAction的 bash 脚本。

leafpad ~/bashScripts/litesCameraAction

使其内容如下:

#!/bin/bash
path=~/volatile/
suffix=MyVideo.h264
################## Enter your ftp url and user:pwd here ################
secretUrl='ftp://example.com/myVideos'
user=userName:passWd

iteration=0
while [ true ]; do
   let iteration="iteration+1"
   sleep 0.5
   now=$(date +"%b_%d_%T")    
   state=$(cat /sys/class/gpio/gpio23/value)
   if [[ $state -eq 1 ]]; then   now=$(date +"%b_%d_%T")
        url=$secretUrl$(echo ${now//:/_})$suffix  
        if [ -e ~/volatile/video.h264 ]; then
           rm ~/volatile/video.h264
        fi
        echo "1" > /sys/class/gpio/gpio24/value
        raspivid -t 15000 -o ~/volatile/video.h264 -fps 4 -w 600 -h 600 -rot 180 -n
        echo "0" > /sys/class/gpio/gpio24/value
        curl -T ~/volatile/video.h264 $url --user $user
   fi
   if [[ $iteration -gt 20000 ]]; then
        ip=$(lynx --dump checkip.dyndns.org | grep -Eo '[0-9\.]+')    
        ipSuffix=$(echo ip)$ip$(echo _)$suffix        
        iteration=0
        if [ -e ~/volatile/video.h264 ]; then
            rm ~/volatile/video.h264
        fi
        echo "1" > /sys/class/gpio/gpio24/value
        raspivid -t 15000  -o ~/volatile/video.h264 -fps 4 -w 600 -h 600 -rot 180 -n
        echo "0" > /sys/class/gpio/gpio24/value
        curl -T ~/volatile/video.h264 $secretUrl$(echo ${now//:/_})$ipSuffix --user $user
    fi
done

使其可执行:

chmod +x ~/bashScripts/litesCameraAction

在脚本中,IP 每 20000 个周期检查一次,我 PI 上每天只检查几次。确保您的检查频率不会滥用 dyndns.org。用以下命令进行测试:

~/bashScripts/litesCameraAction

litesCameraAction脚本在登录时运行:

为脚本添加自动启动(此方法假定您将引导至桌面):

leafpad ~/.config/lxsession/LXDE-pi/autostart

使其内容如下:

@lxterminal --command="bashScripts/litesCameraAction"

保存、退出,然后注销/重新登录以进行完整的系统测试。

重要

请勿将此设备用于医疗应用或其他任何要求高可靠性的应用。请勿在可能存在易燃气体/蒸汽或其他危险环境的区域使用这些设备。

我仅保证我已构建此项目,尽我所能记录了过程,并经过长时间的测试。

 

唯一的高电压是在 PI 的封装电源和 Powerswitch II 设备外壳内部。如果您在连接组件时出错,可能会损坏 PI 和/或 PIR。我的 PI 摸起来非常温热(这是个好迹象)。如果您的芯片发热严重,请考虑散热片。USB 设备、HDMI 适配器和其他外围设备会产生热量。如果您将 PI 放入机箱/盒子中,请确保它具有足够的空气流通。如果设备可能暴露机密信息,请采取进一步措施增强网络和物理安全。

尽管提供了组件分销商的链接,但我并不代表他们或担保他们的产品。我确实从他们那里购买了零件,并且对他们的产品和服务感到满意。对于其他网络链接,其信息的安全性和内容由他们自行负责。

一些预告

PI 能够感知外部世界并对其做出反应。它可以与周围环境互动。发挥你的创意!

  • 与基于像素差异的运动检测相比,使用 PIR 检测运动的六个理由是什么?
  • 如何通过从不重复相同的行来缩短litesCameraAction脚本?
  • 如何让设备仅录制夜行动物?
  • 如何让它在事件发生时给我们发短信?
  • 还有其他方法可以减少 SDD 访问吗?
  • 为什么作者使用 Hello Kitty 盒子?

历史

  • 更新:2015 年 8 月 13 日
© . All rights reserved.