黑客空间网络摄像头

几乎每个黑客空间都在其网站上安装了某种实时摄像头,并且每个空间都以自己的方式解决。如果你想参观商店,知道是否有人在附近是个好事。在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上。
标签
反馈
这篇文章有什么问题吗?请通过在GitHub上打开一个issue或pull request来帮助我们。