黑客空间网络摄像头

几乎每个黑客空间都在其网站上安装了某种实时摄像头,并且每个空间都以自己的方式解决。如果你想参观商店,知道是否有人在附近是个好事。在The Bodgery,我们决定基于Raspberry Pi创建一个每30秒上传一张图片的摄像头。当成员打开空间时,开关会激活Pi的一个“通用输入/输出” (GPIO) 引脚,这会使Pi开始拍照。当关闭时,会显示一个默认图片,声明我们已关闭。

第一项任务是制作一个盒子。Bodgery有一个50W激光切割机,所以我开始使用MakerCase创建设计。在测量Pi并输入尺寸后,MakerCase创建了一个带“指接”的盒子(适合边缘的条状物)。使用Inkscape和一些测量,在前面板上为Pi的摄像头打了一个孔。不幸的是,我没有考虑到Pi的SD卡一边的长度和另一边的WiFi适配器,所以我原来的设计有点短。不过,盒子的后面可以留空,以适应这个项目。

在Web服务器端,创建了一个具有写入特定文件权限的账户。创建了一个ssh密钥并将其添加到该账户的~/.ssh/authroized_keys文件中。

使用Device::WebIO::RaspberryPi,您可以查询GPIO引脚的状态,还可以获取从摄像头读取图片的文件句柄。摄像头是通过“rpicamsrc”实现的,这是GStreamer的一个插件,可以直接访问Raspberry Pi的摄像头模块——这太棒了,因为我之前使用GStreamer的v4lsrc或其他方法获取数据时通常都以挫折告终。

基本模板设置17号引脚为输入,然后设置图像宽度、高度和JPEG质量(介于0和100之间,值越大质量越好,但文件大小也越大)。

my $rpi = Device::WebIO::RaspberryPi->new;
$rpi->set_as_input( 17 );
$rpi->img_set_width( 0, 800 );
$rpi->img_set_height( 0, 600 );
$rpi->img_set_quality( 0, 70 );

下一步是要定期轮询输入引脚(每秒一次即可)。有很多种方法可以做到这一点,我选择了AnyEvent计时器。

my $condvar = AnyEvent->condvar;
my $input_timer; $input_timer = AnyEvent->timer(
    after    => 1,
    interval => 1,
    cb       => sub {
        $INPUT = $rpi->input_pin( 17 );
        $input_timer;
    },
);

这设置了全局变量$INPUT。当$INPUT被设置时,另一个计时器会捕获图片并上传。在一个更复杂的程序中,我可能会直接激活另一个计时器来发送图片。但对于这样一个简单的程序,我对它不太担心。

img_stream()方法将返回一个用于读取图像的文件句柄

my $fh = $rpi->img_stream( 0, 'image/jpeg' );

该方法接受摄像头的一个频道号(如果您只有一个摄像头,您有一个频道)和一个期望的MIME类型。img_allowed_content_types()方法将返回支持MIME类型的列表。在Device::WebIO::RaspberryPi上,目前只支持image/jpeg

一旦您有了文件句柄,就可以使用scp上传它。一个简单但粗糙的方法是创建一个临时文件(使用File::Temp),然后调用scp作为外部程序

use File::Temp 'tempdir';
my ($tmp_fh, $tmp_filename) = tempfile();

# Write to a temporary file
my $buffer = '';
while( read( $fh, $buffer, 4096 ) ) {
    print $tmp_fh $buffer;
}
close $tmp_fh;
close $fh;

# Upload to server using scp
my @scp_command = (
    'scp',
    '-i', PRIVATE_KEY_FILE,
    $tmp_filename,
    SERVER_USERNAME . '@' . SERVER_HOST . ':' . SERVER_UPLOAD_PATH,
);
say "Executing: @scp_command" if DEBUG;
(system( @scp_command ) == 0)
    or warn "Could not exec '@scp_command': $!\n";

# Delete temp file
unlink $tmp_filename;

Net::SCP是另一种实现方式,尽管它只是像上面那样封装外部命令。

作为对读者的练习,在您的Raspberry Pi上创建一个tmpfs(RAM磁盘),并将临时文件写入其中。10MB应该足够了。File::Temp::tempfile()可以通过传递一个DIR参数来写入该位置。这样可以避免写入SD卡,因为SD卡既慢又容易提前磨损。

完整的代码在GitHub上。


本文最初发表在PerlTricks.com上。

标签

蒂姆·默里

蒂姆·默里是一位Perl程序员和硬件专家。他是UAV::Pilot的创建者,这是事实上的标准Perl无人机库。他经常博客关于Perl和硬件黑客攻击。

浏览他们的文章

反馈

这篇文章有什么问题吗?请通过在GitHub上打开一个issue或pull request来帮助我们。