Google 推出树莓派 AIY 计算机视觉开发工具

Google 为树莓派(Raspberry Pi)爱好者提供了一套新工具,让他们以更有趣的方式使用 Google 的 AI 工具。AIY Vision Kit 套装包括新的计算机视觉软件和新的电路板,用户可以将其配合自己的树莓派电脑和相机使用,当然还包括一个可爱的硬纸盒,以及一些辅助配件。AIY Vision Kit 要价 44.99 美元,将于 12 月 31 日通过 Micro Center 发售。

AIY Vision Kit 的软件包括 3 种神经网络模型,一个可以识别上千种物体,一个可以识别面部表情,还有一个“人、猫和狗识别器”。用户可以使用 Google 的 TensorFlow 机器学习软件训练自己的模型。

Google 表示这是一个廉价且简单的计算机视觉系统,由于本地处理单元的存在,所以它不需要联网就能完成计算。这是 Google AIY 推出的第 2 个项目,在推出 AIY 计算机视觉开发套包之前,Google 还曾为树莓派推出过一款 Voice HAT 计算机语音开发套包,让用户通过 Google Assistant 命令树莓派控制设备。

购买链接

本文来自:树莓派实验室

用树莓派DIY自动“气象站”

自动气象站可以实时探测气温、湿度、气压、风速、风向、降雨量、紫外线辐射等气象信息,通过不同的传感器采集地面气象数据,数据采集完成后通过网络统一传输到气象服务器上,再经气象采集软件处理各项数据,最后通过专业气象软件传出。

网上搜索到之前大部分的设计都是基于DSP的方案,但是IoT时代,我们需要速成的设计,网上现成的传感器和树莓派教程能帮助我们迅速的设计出一个小型气象站。

正好我在网上看到 DIY hacking 上 Arvind Sanjeev 做了个类似项目。这个完整的天气系统,只用树莓派的基础硬件,摄像头,和一些我们使用的杂七杂八的模拟和数字传感器。

风速计和雨量计也都是自己做的。

产品特点:

  • 在RRD和CSV上记录信息,方便被导出/导入到其它格式
  • 使用天气地下API来得到历史高点和低点,月相和日出/日落等信息
  • 使用树莓派相机拍摄一分钟一次的图片(可以用它来制作延时录像)
  • 有显示当前天气状况和历史天气状况的数据网页(最后一小时,一天,七天,月,年)
  • 网站主题随不同时间而改变(四个选项:日出,日落,白天和夜间)。

所有的进行记录和显示信息的软件在GitHub上开源

这个项目是很好的学习经验,能帮助真正深入理解树莓派的能力,尤其是GPIO。

所需的材料

1、电子元件

  • 9个簧片开关(8个用于风向,1个用于雨计,1个可选用为风速来代替霍尔传感器
  • 1个霍尔传感器 (用于风速,称为风速计)
  • 温度传感器
  • 湿度传感器(许多湿度传感器集成了温度传感器),我用的DHT11
  • 压力传感器(许多也集成了温度传感器),我用的BMP180
  • 光敏电阻
  • GPS芯片或USB GPS
  • 4个强磁体(2个用于风速计,1个用于方向,1个用于雨量计)
  • 各类电阻器
  • MCP3008用来把模拟转换为数字输入

2、硬件

  • 树莓派,我使用的B +
  • 无线适配器
  • 树莓派摄像头
  • 5V电源适配器

3、材料

  • 2个推力轴承 (或滑板或滑旱冰的轴承也行)
  • 2个防水罩——我用的是超市的电器罩,找一个大小合适,有足够的空间且能保护设备的就可以。
  • 一些PVC管和盖子(各种尺寸)
  • PVC安装支架
  • 一些薄有机玻璃片(不用太花哨)
  • 塑料支架
  • 塑料螺钉
  • 2个塑料圣诞树装饰品——用于风速计。
  • 小木钉
  • 小胶合板

4、工具

  • 达美电磨
  • 胶枪
  • 烙铁
  • 万用表
  • 钻孔机

机箱

一个能装进树莓派、摄像头、GPS和光传感器的盒子。需要选防水的,因为它装进了所有关键元件,测量环境风吹雨打。

机箱包含:

  • 树莓派(螺母上)——需要Wi-Fi芯片。
  • 摄像头(螺母上)
  • GPS芯片通过USB连接(我用的FTDI电缆 )。GPS能提供纬度和经度,更重要的是,我可以从GPS获取精确的时间!
  • 2个以太网/CAT5个插口,连接到主外壳与其它传感器。两个容器之间这样链接很方便。我用了大致12跟线缆,两个CAT5提供16个可能的连接,所以有空间做扩展。

测温度、湿度、压力的机箱

这是我放置温度、湿度和压力传感器的板子,以及用于雨量计,风向和风速传感器挂钩。

这一切都非常简单。。

制作雨量器

我大多沿用这个教程进行实际测量仪。

我是用有机玻璃来做的。总的来说,有机玻璃效果不错,结合胶枪,橡胶密封材料,以及整体切割和钻孔就更棒了。

关键点:

  • 该传感器是一个简单的簧片开关和磁体,树莓派上充当按钮。我简单地计算随着时间的推移桶里的水位,后来转换为“雨/英寸。”
  • 让它大到足以容纳足够的水来翻转,但不用太大因为需要很多个。我的第一个制作失败了因为不够大,所以它会被填满,并开始在它倾斜之前开始排水。

风向

这很简单。

关键点:

  • 这是一种模拟传感器。
  • 拧在风向标的后面,您需要校准它,“这个方向就是指向北方。”
  • 我做了一个木试验台,有所以我可以在全量程内轻松切换电阻器。
  • 我使用的推力轴承工作得很好。

软件

该软件也是开源的,可以在同一个GitHub库拿到。

软件是用Python写的,记录来自传感器的数据。 我第三方的库,获得来自传感器和GPS信息。

看起来很不错吧?

 

本文来自:树莓派实验室

 

 

树莓派:Raspbian Stretch 桌面版本更新

树莓派基金会今天发布了第一个 Debain Stretch 树莓派桌面版本,兼容通用 PC 和 Mac 硬件。并且还更新了一下用于树莓派的 Raspbian Stretch 系统。

关于 PC 和 Mac 版本

今年初,树莓派基金会发布了桌面操作系统 PIXEL OS。而后他们看到这个桌面版本逐渐流行,并决定持续发布这一版本。事实证明这项工作异常艰巨,特别是今年从 Jessie 版本的 Debian 版本到 Stretch 版本。

但是我们已经完成了将 Raspbian Stretch 中的所有相关代码移植到 Debian 的工作,所以从今天开始为您的 PC 或 Mac 提供第一个 Debian Stretch 版本的 Raspberry Pi Desktop。

Raspbian Stretch 系统的部分新特性

1.文件管理器
在旧系统中,文件管理器一直是 LXDE 的一部分。它的功能非常丰富,几乎没有什么是不能实现的。但是再使用了数年之后,官方决定将略显复杂的它用精简版替代。

移除了很多大部分用户不喜欢的菜单选项、重整了工具栏的图标风格。支持显示更为简洁的用户界面。

2.笔记本电脑的电量显示
既然都说适配普通 PC 了,当然要考虑笔记本电脑。这个版本在工具栏加入了电量显示,如图。

如果你使用 Pi-Top,请确认配置选项中 I2C 功能是开启的。

3.一些新应用
新系统中加入了一些适用于 PC 版本的新应用。比如 PiServer 允许你搭建一个类似于 Raspbian 的操作系统并将它共享给网络上的其他树莓派客户端。

最后给出传送门,获取新系统
Raspbian 树莓派版本:
https://www.raspberrypi.org/downloads/raspbian/
Raspbian 桌面版本:
https://www.raspberrypi.org/downloads/raspberry-pi-desktop/

本文来自:树莓派实验室

Python+树莓派制作IoT(物联网)门控设备

前些天写了篇文章是利用树莓派制作一个开关门监控设备的雏形《Python+树莓派 是谁在开门?》,但是这个设备运行的前提是需要树莓派正常供电并已经连接了网络,但是如果需要在没有电、没有宽带网络的户外实现随时掌控开关门的状态该怎么办?今天就和大家分享一个正在制作的物联网开关门监控设备。

因为考虑需要在户外使用这套物联网门控设备,所以利用树莓派完成这个设备有两个问题需要解决,
第一是需要解决树莓派和相关模块的供电问题。
第二就是需要户外没有宽带网络情况下的信号传输问题。
只要解决这两个问题那么剩下来的问题就是编程方面的了,针对以上两个问题,这里我们采用比较大众化的方式解决,设备的供电问题我们使用太阳能配合蓄电池进行实现7X24小时供电,信号的传输问题我们使用一块叫做SIM868的通讯模块来实现。下面来介绍一下设备制作的材料准备、制作过程以及程序的编写和调试。

1.准备材料及工具
1.树莓派(Raspberry Pi 3B) 数量:1块

2.SIM868通讯模块(这里使用的是适配树莓派的微雪电子的SIM868通讯模块) 数量:1块

3.电磁感应磁条(常开常闭型) 数量:1组

4.SIM868模块外接天线 数量:1根(根据现场安设实际情况确定)

5.树莓派T型扩展板 数量:1块

6.实验面包板 数量:1块

7.杜邦线(公对公,公对母) 数量:若干

8.太阳能板 数量:1块

9.带保护板的锂电池 数量:2组(根据电池使用的性能情况可适当增加)

10.电压电流转换板 数量:1块

11.连接电线 数量:(根据现场安设实际情况确定)

12.两芯屏蔽线 数量:10米(0.3粗即可根据现场安设实际情况确定)

13.防爆箱 (防尘、防雾) 数量:1个(规格根据实际情况确定)

14.Micro USB充电线 数量:2根

15.SIM卡(移动和联通均可,模块暂不支持电信CDMA) 数量:1张

16.电烙铁及焊锡

2.设备供电及模块链接说明
(1)供电原理:设备的供电依靠太阳能板配合锂电池进行供电,需要一块可以将太阳能板和锂电池的输出电压和电流转换成树莓派和SIM868通讯模块工作电压和电流的转换板,设备供电链接图如图。
实现效果,白天可以通过太阳能负责给树莓派及通讯模块供电并同时给锂电池充电。晚上将由充电完毕的锂电池负责给设备供电。

(2)设备链接:树莓派的GPIO PIN# 2针脚(5V)和 PIN# 23针脚 链接电磁感应模块的引线。负责接收电磁感应模块的开关状态,树莓派的GPIO PIN# 4(5V),PIN# 6(Ground) ,PIN# 8(TX),PIN# 10(RX)分别链接SIM868通讯模块的5V,ground,串口TX和RX,负责实现模块的树莓派与SIM868通讯模块的串口通讯和供电链接,并将信号树莓派的接收到的电磁感应磁条开关信号,通过SIM868通讯模块出输出去(这里采用的是http传输协议,具体实现方法见程序编码部分)

3.程序代码:
(1)python程序源码:

import  RPi.GPIO as GPIO
import time
import serial  
def gpio_init():
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(23,GPIO.OUT)
def send_data(param):
    W_http_6='AT+HTTPPARA="URL","http://**************/iot.php?status='+param+'"\r\n'
    ser.write(W_http_6)
    time.sleep(2)
    W_http_7='AT+HTTPACTION=0\r\n'
    ser.write(W_http_7)
    time.sleep(3)
if __name__ == '__main__':
    ser = serial.Serial("/dev/ttyS0",115200)
    W_http_1='AT+HTTPTERM\r\n'
    ser.write(W_http_1)
    time.sleep(3)
    W_http_2='AT+SAPBR=3,1,"CONTYPE","GPRS"\r\n'
    ser.write(W_http_2)
    time.sleep(3)
    W_http_3='AT+SAPBR=3,1,"APN","CMNET"\r\n'
    ser.write(W_http_3)
    time.sleep(3)
    W_http_4='AT+SAPBR=1,1\r\n'
    ser.write(W_http_4)
    time.sleep(3)
    W_http_5='AT+HTTPINIT\r\n'
    ser.write(W_http_5)
    time.sleep(3)
    gpio_init()
    status=1
    while True:
        if GPIO.input(23) == True:
            if status==1:
                send_data(2)
                status=2
                print "门的状态:关闭"
            else:
                pass
        else:
            if status==2:
                send_data(1)
                status=1
                print "门的状态:打开"
            else:
                pass
        time.sleep(3)
    GPIO.cleanup()

(2)php程序源码:

require_once("../../func/dbaccess.php");
if (doConnect($cn) == false) {         
    return false;
}
$strSQL = "insert into iot_tbl (position,status,create_time) values ("'.第一号门.'",'".
            $_GET['status']."',now())"; 
doInsertUpdate($strSQL);                
doClose($cn);

4.代码解析:
这里使用的Python版本号为2.7.9

import  RPi.GPIO as GPIO
import time
import serial

引用了python的3个类库GPIO,time以及串口调试库serial,为实现程序的调试可编写,在使用serial串口调试库前,要实现树莓派的串口配置和Linux系统下的串口调试工具minicom的安装。具体方法可参考之前的文章《树莓派串口配置及minicom的安装》

ser = serial.Serial("/dev/ttyS0",115200)
W_http_1='AT+HTTPTERM\r\n'
ser.write(W_http_1)
time.sleep(3)
W_http_2='AT+SAPBR=3,1,"CONTYPE","GPRS"\r\n'
ser.write(W_http_2)
time.sleep(3)
W_http_3='AT+SAPBR=3,1,"APN","CMNET"\r\n'
ser.write(W_http_3)
time.sleep(3)
W_http_4='AT+SAPBR=1,1\r\n'
ser.write(W_http_4)
time.sleep(3)
W_http_5='AT+HTTPINIT\r\n'
ser.write(W_http_5)
time.sleep(3)

以上代码实在通过调用serial库,设置树莓派串口通信的波特率为115200,并使用 ser.write()函数向串口写入可操作SIM868模块进行通讯的AT指令,这里的AT指令是对SIM868进行HTTP通讯前的配置,具体AT指令的含义在这里不再赘述,可自行百度查找。这是使用time.sleep()函数控制程序执行的等待时间,确保串口写入数据成功。

def gpio_init():
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(23,GPIO.OUT)

gpio_init()函数是实现对接收电磁感应模块的GPIO PIN#23针脚的初始化配置。

status=1
    while True:
        if GPIO.input(23) == True:
            if status==1:
                send_data(2)
                status=2
                print "门的状态:关闭"
            else:
                pass
        else:
            if status==2:
                send_data(1)
                status=1
                print "门的状态:打开"
            else:
                pass
        time.sleep(3)

这里使用status变量初始化门的状态为1表示门已打开,并使用while True循环分割三秒钟(time.sleep(3))检测GPIO PIN#23 号针脚的电流状态,从而判断门的开关状态,并调用send_data()函数进行数据的发送。

def send_data(param):
    W_http_6='AT+HTTPPARA="URL","http://**************/iot.php?status='+param+'"\r\n'
    ser.write(W_http_6)
    time.sleep(2)
    W_http_7='AT+HTTPACTION=0\r\n'
    ser.write(W_http_7)
    time.sleep(3)

这里将门的状态status变量的值当做参数传送给你个send_data()函数,在添加到HTTP请求的URL中,在服务器端写了个PHP程序iot.php(程序源码j解析如下)用以接收SIM868通讯模块发送过来的HTTP请求,并使用GET的方式获得到HTTP请求URL中传入的status值,并插入到MySQL数据库中。

require_once("../../func/dbaccess.php");//封装链接操作MySQL数据库的函数
if (doConnect($cn) == false) {           //链接数据库
    return false;
}
$strSQL = "insert into iot_tbl (position,status,create_time) values ("'.第一号门.'",'".
            $_GET['status']."',now())";  //将数据插入MySQL数据库的SQL语句
doInsertUpdate($strSQL);                 //执行SQL
doClose($cn);                            //关闭数据库链接

4.程序拓展:
以上程序完成的是对开关门信号的检测、发送和接收数据,属于整个设备接收和处理数据的核心部分,对接收到的数据,还要做进一步的展示,这里我采用了HTML+JQuery+AJAX的方式,并配合在HTML中播放音频文件和刷新开关门状态图表,来动态展示开关门的效果。实现原理是使用AJAX操作PHP程序循环实时读取MySQL数据库,查看当前门的开关状态,并循环局部刷新HTML页面播放音频和刷新html页面图标,对门的开关效果进行动态展示。每个人的需求不同,展示部分的代码就不做说明,也参照上诉方案自行编写。

本文来自:树莓派实验室

 

 

 

借助树莓派模拟Wimonitor并实现WiFi窃听和嗅探

Wimonitor是一款非常优秀的黑客工具,它不仅可以帮渗透测试人员省去配置虚拟机和无线网卡等一系列麻烦事,而且它的Web接口配置起来也非常的方便。实际上,它就是一款TP-Link-MR3020路由器,只不过它使用的是自定义固件,并能够将监控到的网络数据包转发给主机电脑(Mac或Windows等主机),而我们此时就可以使用WireShark来对数据包进行分析了。

但是,我们可不可以使用树莓派来实现一样的功能呢?答案当然是肯定的,因此在这篇文章中,我们将教会大家如何使用树莓派3B来搭建一个稳定的WiFi监控平台,并通过几个简单的步骤来将其模拟成一个Wimonitor。

硬件要求

1.      运行Windows的笔记本电脑(测试设备使用的是Windows 8.1)

2.      树莓派3B、Micro SD卡、电源适配器(USB 3.0足够驱动树莓派+无线网卡了)

3.      网线(连接树莓派和笔记本电脑)

4.      支持监听模式的无线网卡(例如TL-WN722N v1)

安装配置

首先,将RASPBIAN STRETCH LITE刻到Micro SD卡中,这是一个轻量级操作系统,并且支持例如TL-WN722N之类的无线网卡,具体的步骤请参考【操作指南】。

刻录完成之后,我们可以通过在SD卡中创建一个名叫ssh的空文件(无需文件扩展名)来启用树莓派的SSH功能。

为了确保笔记本电脑能够跟Pi正常通信,最简单的方法就是用笔记本给Pi共享WiFi,这样就可以保证Pi的IP地址在192.168.137.x范围内。进入网络连接设置(ncap.cpl),右键点击Wi-Fi适配器,然后选择属性。在“Sharing”标签页中,选择需要插入Pi的以太网适配器,点击OK。

接下来,将Pi与笔记本主机连接,然后把SD卡插到Pi的卡槽中,将无线网卡插入到USB端口连接网线(笔记本主机-Pi),然后启动设备。

当Pi启动之后,它将会使用共享链接的IP地址,你可以在笔记本主机上使用nmap(对192.168.137.1/24子网进行主机搜搜)来查看Pi的IP地址。

打开PuTTY,然后使用ssh登录到Pi,我们所使用的Raspbian操作系统默认的用户名和密码分别为pi和raspberry。

给Pi设置一个静态地址,打开/etc/dhcpcd.conf并将下列代码添加到文件末尾:

interfaceeth0
staticip_address=192.168.137.100/24
staticrouters=192.168.137.1
staticdomain_name_servers=192.168.137.1

我个人比较喜欢使用基于密钥的SSH登录验证。打开PuTTYgen,然后生成一个密钥对。

在Pi的home目录中创建一个.ssh文件夹,然后在这个文件夹中创建一个名叫authorized_keys的文件,将PuTTYgen生成的公钥复制到这个文件中,最后自己保存好PuTTYgen生成的私钥,并重启Pi的SSH服务。结束之后,别忘了修改Pi的默认密码。

Raspbian操作系统没有自带与网络监控有关的数据包,因此你可以使用下列命令来安装这些包:

sudo apt update 
sudo apt install aircrack-ng tcpdump -y

接下来,我们需要在Pi上测试无线网卡的监听功能是否正常。

既然我们已经验证了Pi能够正常进行网络监控了,我们就可以使用SSH登录到Pi,然后在Pi上运行rcpdump,并将信息转发给运行在笔记本主机中的Wireshark。

plink.exe是PuTTY.exe的Windows命令行接口,为了方便起见,我把plink.exe和PuTTYgen生成的SSH私钥放在了同一个文件夹中。如果这些文件不在同一文件夹中,你就需要相应地修改下列代码中的路径了:

plink.exe-ssh -i pi-monitor-ssh-key.ppk pi@192.168.137.234 "sudo tcpdump -niwlan1mon -s 0 -w -" | "C:\Program Files\Wireshark\Wireshark.exe"-k -i -

如果你只想监听信道1,你可以使用下列命令:

sudo iwconfig wlan1mon channel 1

下面的命令可以开启Pi无线网卡的监听模式:

plink.exe-ssh -i pi-monitor-ssh-key.ppk pi@192.168.137.100 "sudo airmon-ng startwlan1"

接下来,我们可以在笔记本主机中开启Wireshark并开始监听无线网络数据:

plink.exe-ssh -i pi-monitor-ssh-key.ppk pi@192.168.137.100 "sudo tcpdump -niwlan1mon -s 0 -w -" | "C:\Program Files\Wireshark\Wireshark.exe"-k -i -

OK,一切搞定!大家快去自己动手尝试一下吧!

转载自FreeBuf.COM

 

 

 

使用MQTT连接树莓派IoT设备

有时候,你可能会发现自己处于一种你想让设备通过互联网相互通信的情况。例如,当我到另一个城市旅行的时候,我意识到我忘了关掉我房间的灯光。在这种情况下,我希望有一个Android应用程序或一个网站,我可以监视我家的灯光状态,并能打开或关闭它们。

所以,假设你想在一个可以在世界任何地方操作的房间里连接一个电灯开关。一个快速而稳定的选项是使用MQTT。

什么是MQTT?

MQTT(消息队列遥测传输)是一种轻量级消息传递协议,非常适用于物联网连接设备的通信。

MQTT有三个组件:代理,发布者和订阅者。经纪人是处理设备之间进行通信的中介实体。发布者是发送消息的设备。订阅者收听发布者发送的消息。

在MQTT中还有一件更重要的事情,那就是一个话题。不同设备之间的通信需要一个主题。例如,设备A想要向设备B发送消息。为此,两者之间应该有一些共同之处,那就是主题。把它想象成一个电话号码。

CloudMQTT

CloudMQTT是为特定数量的设备提供免费MQTT通信的代理服务。

设置MQTT

  • 在“名称”字段中输入CMQTT

  • 点击创建
  • 记下您的数据,如下图所示

 

 

  • 在同一页面上,在管理用户中添加一个用户:
    • 名字:pi
    • 密码:pi

 

  • 点击“保存”
  • 再次在最后的同一页上:
    • 用户:pi
    • 主题:pi

 

  • 并点击“保存”
  • 现在,在顶部的栏中,点击“WebSocket UI”

 

 

  • 你会看到一个页面,所有的传感器数据将被显示
  • 将以下代码上传到Arduino

下面的代码是用虚拟字符串代替传感器的示例代码。您可以用来自传感器的值替换字符串。

String sensorsData=""; 
String randSensorsData=""; 
void setup() {
   // put your setup code here, to run once: 
Serial.begin(9600); 
pinMode(A0,INPUT);//temperature sensor 
pinMode(A1,INPUT);//windspeed sensor 
pinMode(A2,INPUT);//wind direction sensor 
pinMode(A3,INPUT);//rain fall sensor 
pinMode(A4,INPUT);///barometric pressure sensor
} 

void loop() {
   // put your main code here, to run repeatedly:      
sensorsData=String("-")+String("S1=")+String(analogRead(A0))+String(",")+String("S2=")+String(analogRead(A1))+ \
String(",")+String("S3=")+String(analogRead(A2))+String(",")+String("S4=")+  \
String(analogRead(A3))+String(",")+String("S5=")+String(analogRead(A4))+String("+");     
randSensorsData=String("-")+String("S1=")+String(random(100))+String(",")+String("S2=")+ \
String(random(200))+String(",")+String("S3=")+String(random(125))+String(",")+String("S4=")+\
String(random(500))+String(",")+String("S5=")+String(random(50))+String("+");     
   Serial.println(sensorsData);     
   Serial.println(randSensorsData);   
   delay(200); 
}

此代码使用Arduino的模拟引脚来获取传感器的值,并传递到Raspberry Pi进行处理和MQTT通信。上面的代码使用随机函数来生成随机值来模拟模拟引脚。

  • 传感器应连接到A0,A1,A2,A3,A4引脚,
  • Serial.println(randSensorsData);
  • 这一行发送随机数据来检查服务器。
  • 您也可以检查在WebSocket UI中显示的随机数据。
  • 打开python 2.7并在其中编写下面的代码:
import paho.mqtt.client as mqtt
import time
data=”Hello from Raspberry Pi!”
while True:
    print(data)
    try:
        client=mqtt.Client()
        client.username_pw_set("yoyojacky","MyRPiPr0J")#替换成你的用户名和密码
        client.connect("m13.cloudmqtt.com",13017,60)
        client.publish("pi",data) #这里的 pi 是你的话题,客户端就订阅这个话题
        time.sleep(1)
    except KeyboardInterrupt:
        print("end")
        client.disconnect()
  • 现在使用python 2.7运行代码
  • 您将在每秒钟后看到传感器数据显示在CloudMQTT的WebScoket UI中。

  • 在这里,您将看到从Raspberry Pi发送的数据。

令人惊讶的是,CloudMQTT提供了一个完整的dashboard用于测试目的。您可以使用此dashboard订阅或发布主题.

在接下来就可以去配置你的 arduino 和树莓派来管理家里的设备或者查询家里的设备信息了!

 

如何使用树莓派自制网络监视器

本文所介绍的工具适合家庭环境下的“黑盒测试”,它可以帮助你记录网络中发生的所有事情。你可以用它来检测网络威胁,或将数据提供给相关专家来进行网络取证分析。

购物清单

1.      树莓派3 (外壳+电源+电路板)

2.      闪迪Class 10 microSD卡 64GB(80Mb/s)

3.      Debian OS-Linux RaspbianLite

4.      网件千兆交换机或其他支持端口镜像的设备,我使用的是D-Link1100-08P

5.      Critical Stack API(Threat Intel/ IOCs)

6.      Mailgun账号或类似支持警报/通知的邮件服务

概览图

关键技术介绍

什么是端口镜像?

将一个端口的流量数据复制到另一个端口(被动式),会增加交换机的运行负荷。

什么是Bro

一款IDS协议分析工具,你可以把它当作Wireshark的协议分析器,但是它没有GUI界面,而且速度更快。

什么是Netsniff?

进行数据包捕获的守护进程,它使用了AF-packet来提升数据包的捕捉速度。

什么是LOKI

基于YARA的文件扫描守护进程。有些类似基于签名检测的反病毒产品,但是你可以自行制定检测规则。

什么是Critical Stack

一个威胁情报平台,你可以在树莓派上通过API来与该平台链接。

什么是Team Cymru MHR

一个恶意软件哈希库,你可以使用该数据库中的信息来对检测到的恶意程序哈希进行匹配。

开始动手

1.      把系统刷到树莓派中

2.      给树莓派分配一个IP

3.      运行bash脚本

4.      搞定

 

一、把Raspbian刷到microSD卡中

我使用的是MacBook,所以不同平台的方法可能会有所不同,其他平台用户可以参考【这篇教程】来获取更多内容。

插入microSD卡:

diskutil <span class="hljs-built_in">list</span>

找到磁盘号:

diskutil unmountDisk /dev/disk<disk#from diskutil>

将Raspbian镜像刷入到microSD卡’disk’中:

sudo dd bs=<span class="hljs-number">1</span>m <span class="hljs-keyword">if</span>=image.imgof=<span class="hljs-regexp">/dev/rdisk</span><disk<span class="hljs-comment"># from diskutil></span>

完成之后,卸载microSD卡:

diskutil unmountDisk <span class="hljs-meta-keyword">/dev/</span>disk<span class="hljs-params"><disk#from diskutil></span>

二、配置网络

使用默认配置登录。用户名:pi,密码:raspberry。

设置wlan0(wifi)的IP,用于受信管理访问:

sudo nano<span class="hljs-meta-keyword">/etc/</span>wpa_supplicant/wpa_supplicant.conf
network={

ssid="The_ESSID_from_earlier"

psk="Your_wifi_password"

}
sudo ifdown wlan0

sudo ifup wlan0

ifconfig wlan0

当你获取到了一个DHCP IP之后,你可以使用SSH访问这个节点了。接下来,将eth0留下当作镜像接口,它不需要设置IP地址。

sudo apt-get update && sudo apt-get-y install vim

sudo vim /etc/network/interfaces

添加下列代码:

iface eth0 inet static

static ip_address=0.0.0.0

重启eth0接口:

<span class="hljs-attribute">sudo</span> ifconfig eth0 down && sudoifconfig eth0 up

三、部署

下载并运行bash脚本,脚本已在Raspbian上成功测试。

-安装程序的核心组件

-配置网络选项(禁用NIC offloading)

-给每一个程序创建服务

-使用Mailgun/SSMTP创建邮件警报

-配置cron任务

pi@foxhound:~# sudo su -

root@foxhound:~# apt-get install -y git

root@foxhound:~# cd ~

root@foxhound:~# git clonehttps://github.com/sneakymonk3y/foxhound-nsm.git

root@foxhound:~# chmod +xfoxhound-nsm/foxhound.sh

root@foxhound:~# ./foxhound-nsm/foxhound.sh

现在,环境部署已经完全完成啦!

接下来呢?当脚本完成运行之后,所有的服务都会被立刻激活,然后你就可以看到所有流入的数据啦!

性能

通过pcap数据来向镜像端口eth0发送一些垃圾信息,我使用的是一些提前准备好的数据:

pi@foxhound:~ $ sudo tcpreplay -t -K -q--loop=10 --intf1=eth0 /opt/foxhound-1476541443.pcap<br><br>Actual: 1048570 packets (1050923190 bytes)sent in 87.62 seconds. Rated:11994102.0 bps, 91.51 Mbps, 11967.25 pps

下面是发送前和发送后的broctl netstats数据:

root@foxhound:/etc/network# broctl netstats
bro: 1476547903.768150 recvd=1951368 dropped=5408 link=1956776
root@foxhound:/etc/network# broctl netstats
bro: 1476548144.248161 recvd=3012168 dropped=14608 link=3026776

对于家庭或实验室环境来说,它的性能相对还算很好了(1000000个数据包只会丢弃10000个)。我的带宽速度为40Mbps,对于IDS系统来说已经足够了。如果你还需要提升性能,建议考虑换掉树莓派。

如果你想进行更多的NIC perf测试,你可以在服务器上运行下列命令:

mark@ubuntu:~$ sudo apt install iperf3

mark@ubuntu:~$ iperf3 -s

-----------------------------------------------------------

Serverlistening on 5201

然后在树莓派上运行:

root@foxhound:~# apt install iperf3

root@foxhound:~# iperf3 -c 10.0.0.7 -i 1 -t20

Connecting to host 10.0.0.7, port 5201

[ 4]local 10.0.0.180 port 38562 connected to 10.0.0.7 port 5201

[ ID] Interval Transfer Bandwidth Retr Cwnd

[ 4] 0.00-1.00 sec 8.86 MBytes 74.3 Mbits/sec 0 89.1 KBytes

...

...

...

[ 4] 19.00-20.00 sec 9.26 MBytes 77.7 Mbits/sec 0 1.23 MBytes

- - - - - - - - - - - - - - - - - - - - - -- - -

[ ID] Interval Transfer Bandwidth Retr

[ 4] 0.00-20.00 sec 185 MBytes 77.5 Mbits/sec 139 sender

[ 4] 0.00-20.00 sec 184 MBytes 77.1 Mbits/sec receiver

iperf Done.

我假设这里的瓶颈是microSD卡,它的速度大约是80MB/s。

Bro基础

-所有Bro日志的默认存储路径为/nsm/bro/logs/

-默认的脚本路径为/usr/local/bro/share/bro/site/bro-scripts/

日志目录结构大致如下所示:

pi@foxhound:/nsm/bro/logs/current $ ls-lash

total 6.9M

4.0K drwxr-xr-x 3 root root 4.0K Oct 15 16:11 .

4.0K drwxr-xr-x 5 root staff 4.0K Oct 1516:50 ..

4.0K -rw-r--r-- 1 root root 349 Oct 15 16:51 app_stats.log

4.0K -rw-r--r-- 1 root root 121 Oct 15 15:51 .cmdline

16K-rw-r--r-- 1 root root 14K Oct 15 16:30communication.log

2.9M -rw-r--r-- 1 root root 2.9M Oct 15 16:52 conn.log

16K-rw-r--r-- 1 root root 14K Oct 15 16:52dhcp.log

384K -rw-r--r-- 1 root root 379K Oct 15 16:52 dns.log

4.0K -rw-r--r-- 1 root root 345 Oct 15 15:51 .env_vars

1.2M -rw-r--r-- 1 root root 1.2M Oct 15 16:52 files.log

1.6M -rw-r--r-- 1 root root 1.6M Oct 15 16:52 http.log

4.0K -rw-r--r-- 1 root root 291 Oct 15 16:44 known_hosts.log

4.0K -rw-r--r-- 1 root root 327 Oct 15 16:34 known_services.log

12K-rw-r--r-- 1 root root 11K Oct 15 16:50notice.log

4.0K -rw-r--r-- 1 root root 5 Oct 15 15:51 .pid

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.communication

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.conn

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:01 .rotated.conn-summary

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.dhcp

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.dns

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.files

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.http

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.known_hosts

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.known_services

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.loaded_scripts

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.notice

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.packet_filter

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.software

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.ssl

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.weird

4.0K -rw-r--r-- 1 root root 18 Oct 15 16:00 .rotated.x509

4.0K -rw-r--r-- 1 root root 3.0K Oct 15 16:51 software.log

320K -rw-r--r-- 1 root root 314K Oct 15 16:52 ssl.log

4.0K -rw-r--r-- 1 root root 58 Oct 15 15:51 .startup

4.0K drwx------ 3 root root 4.0K Oct 15 15:51 .state

4.0K -rwx------ 1 root root 18 Oct 15 15:51 .status

4.0K -rw-r--r-- 1 root root 46Oct 15 15:51 stderr.log

4.0K -rw-r--r-- 1 root root 188 Oct 15 15:51 stdout.log

24K-rw-r--r-- 1 root root 17K Oct 15 16:52weird.log

416K -rw-r--r-- 1 root root 412K Oct 15 16:52 x509.log

你可以使用head命令来查找文本域名称:

pi@foxhound:$ head dns.log<br><br>#separator \x09<br><br>#set_separator ,<br><br>#empty_field (empty)<br><br>#unset_field -<br><br>#path dns<br><br>#open 2016-10-15-16-00-01<br><br>#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p proto trans_id query qclass qclass_name qtype qtype_name rcode rcode_name AA TC RD RA Z answers TTLs rejected<br><br>#types time string addr port addr port enum count string count string count string count string bool bool bool bool count vector[string] vector[interval] bool

使用bro-cut来解析日志:

pi@foxhound:$ cat dns.log | bro-cut -D tsid.orig_h <span class="hljs-keyword">id</span>.orig_p <span class="hljs-keyword">id</span>.resp_h <span class="hljs-keyword">id</span>.resp_p proto query answers TTLs

基础报告:

pi@foxhound:$ bro-cut query < dns.<span class="hljs-keyword">log</span> |<span class="hljs-keyword">sort</span> | uniq -c | <span class="hljs-keyword">sort</span> -rn | head -n <span class="hljs-number">10</span>

如果你还需要更多的示例,你可以查看Bro提供的官方练习【传送门】。

你可以使用tail命令输出DNS日志并在客户端生成一些DNS流量:

<span class="hljs-attribute">tail</span> -f dns.log | awk  <span class="hljs-string">'{print <span class="hljs-variable">$3</span>, <span class="hljs-variable">$7</span>, <span class="hljs-variable">$9</span>}'</span>

请注意,只有conn.log才可以启用MaxMind GEOIP查询。

pi@foxhound:$ bro-cut resp_cc < conn.log| sort | uniq -c | sort -rn | head -n 10<br><br>755 US<br><br>524 RO<br><br>123 GB<br><br>49 NL<br><br>28 EU<br><br>25 IE<br><br>10 DE<br><br>7 ES<br><br>6 CA

我还没有制作仪表盘(Dashboard),如果你不想自己做的话,你可以直接使用VPS ELK实例在云端存储所有的日志,或者你也可以使用ELK/Splunk/Graylog将日志存储在本地。

基础维护

开启/停止netsniff-ng:

pi@foxhound:~ $ sudo service netsniff-ngstop<br><br>pi@foxhound:~ $ sudo service netsniff-ngstart<br><br>pi@foxhound:~ $ sudo service netsniff-ngstatus

开启/停止bro(网络统计):

pi@foxhound:~ $ sudo -i broctl stop<br><br>pi@foxhound:~ $ sudo -i broctl start<br><br>pi@foxhound:~ $ sudo -i broctl netstats<br><br>pi@foxhound:~ $ sudo -i broctl status

手动运行Loki:

root@foxhound:~ $ python /nsm/Loki/loki.py--noprocscan --dontwait --onlyrelevant -p /nsm/bro/extracted -l /nsm/Loki/log

检测CriticalStack的入侵威胁指标(IoCs),可通过cron脚本实现定期检查:

root@foxhound:~ $ sudo -u critical-stackcritical-stack-intel list

 

参考资料

1.      部署网络安全监控:http://www.appliednsm.com/

2.      网络安全监控实践:https://www.nostarch.com/nsm

3.      Laika BOSS-对象扫描系统:https://github.com/lmco/laikaboss

4.      PassiveDNS:https://github.com/gamelinux/passivedns

5.      D3js(图形化工具):https://d3js.org/

6.      Graylog:https://www.graylog.org/

FB小编Alpha_h4ck编译,转载来自FreeBuf.COM

[找回失落的记忆]树莓派+Pygame模块编写俄罗斯方块

昨天晚上,在家整理东西的时候, 突然翻找出来很早以前小时候的 Gameboy(可能不是这个名字了), 装电池的那种,很古老,只有一款游戏就是俄罗斯方块, 突然回忆就拉回了小学时代和同学一起比拼俄罗斯方块分数的日子,每天都无忧无虑的,不用考虑房贷,车保险….然后突然有一个想法,为什么不用树莓派做一个游戏机呢? 网上教程一堆一堆的, 都是用 retropie, lakka之类的系统实现一个模拟器的平台, 我觉得不够极客, 如果自己用 python 写一个游戏不是更好? 又能巩固 python 的代码能力,又可以让树莓派一机多用, 不仅只是个游戏机, 还可以是下载器,gitlab, 或者是一个 OSMC, 家庭媒体中心呢?

翻找了一下我的 Maker 材料箱, 找到一个吃灰已久的树莓派3B, 通过官方下载全新的镜像,然后烧录系统, 更新系统,配置 ssh, 配置主机名,配置字符集,配置 IP 地址等等一系列操作后. 利用 python 命令执行一下看看版本信息:

$ python -V
Python 2.7.10

就用默认版本吧, 然后去检查一下 pygame 的状态,默认情况下, pygame 已经集成在系统里面了, 如果没有要去官方站点上下载一下并安装, 连接如下: http://pygame.org/wiki/tutorials,官方的这个链接上已经说明:http://pygame.org/wiki/GettingStarted#Raspberry PI

Raspberry PI

This comes with pygame already installed on the default raspberian installation.

那么接下来的事儿就简单多了. 下面是我准备的材料:

  1. 树莓派3 B 型  x1
  2. 16GB class 10 的 TF 卡一张, 最好有SD 卡套方便进行系统烧录
  3. 5v2.5A 电源一套,为了方便,我这里采用的是52Pi 官方的 USB-HUB, 专为树莓派设计, 购买点我
  4. 5寸电阻触摸屏( GPIO 引脚控制), 购买点我 
  5. 外壳你可以自己 DIY 或者利用以下链接下载 STL 文件然后转码成 Gcode 交给3D 打印机打印.3D打印外壳链接

好了,我要开始操作了,首先你要做的事儿是把设备接驳起来,像这样:

然后启动后配置好网络后执行我写好的脚本就可以进行分辨率调节:

git clone https://github.com/yoyojacky/52Pi.git

cd ~/52Pi/

chmod +x restool.sh

sudo ./restool.sh

然后重启, 屏幕的分辨率和电容触摸的驱动就加载好了.

后面需要执行屏幕校准:

cd ~/52Pi/

chmod +x calibrator.sh

sudo ./calibrator.sh

基本配置告一段落了,然后检查 pygame 的版本:

pip list

或者通过 python 的 IDE 直接进行查询,在终端键入python 然后回车继续输入如下 python 代码:

 import  pygame

pygame.ver

看到如下图示:

说明pygame 的模块已经安装过,系统中包含这个模块了,就可以开始下面的操作了.

然后创建一个目录:

mkdir -pv  /home/pi/mygame/music

sudo vim.tiny  /home/pi/mygame/russianblock.py

我一次性创建了一个目录结构, mygame 目录下面创建一个 python 文件, 名字为: russianblock.py

然后可以两首 MP3的歌曲进去, 也可以直接下载我提供的素材:

Have A Drink On Me,Rolling in the Deep

然后继续添加如下python 代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import random, time, pygame, sys
from pygame.locals import *

FPS = 25
WINDOWWIDTH = 640
WINDOWHEIGHT = 480
BOXSIZE = 20
BOARDWIDTH = 10
BOARDHEIGHT = 20
BLANK = '.'

MOVESIDEWAYSFREQ = 0.15
MOVEDOWNFREQ = 0.1

XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2)
TOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5
#        R  G  B
WHITE    = (255, 255, 255)
GRAY    = (185, 185, 185)
BLACK    = ( 0,  0,  0)
RED     = (155,  0,  0)
LIGHTRED  = (175, 20, 20)
GREEN    = ( 0, 155,  0)
LIGHTGREEN = ( 20, 175, 20)
BLUE    = ( 0,  0, 155)
LIGHTBLUE  = ( 20, 20, 175)
YELLOW   = (155, 155,  0)
LIGHTYELLOW = (175, 175, 20)

BORDERCOLOR = BLUE
BGCOLOR = BLACK
TEXTCOLOR = WHITE
TEXTSHADOWCOLOR = GRAY
COLORS   = (   BLUE,   GREEN,   RED,   YELLOW)
LIGHTCOLORS = (LIGHTBLUE, LIGHTGREEN, LIGHTRED, LIGHTYELLOW)
assert len(COLORS) == len(LIGHTCOLORS) # each color must have light color

TEMPLATEWIDTH = 5
TEMPLATEHEIGHT = 5

S_SHAPE_TEMPLATE = [['.....',
           '.....',
           '..OO.',
           '.OO..',
           '.....'],
          ['.....',
           '..O..',
           '..OO.',
           '...O.',
           '.....']]

Z_SHAPE_TEMPLATE = [['.....',
           '.....',
           '.OO..',
           '..OO.',
           '.....'],
          ['.....',
           '..O..',
           '.OO..',
           '.O...',
           '.....']]

I_SHAPE_TEMPLATE = [['..O..',
           '..O..',
           '..O..',
           '..O..',
           '.....'],
          ['.....',
           '.....',
           'OOOO.',
           '.....',
           '.....']]

O_SHAPE_TEMPLATE = [['.....',
           '.....',
           '.OO..',
           '.OO..',
           '.....']]

J_SHAPE_TEMPLATE = [['.....',
           '.O...',
           '.OOO.',
           '.....',
           '.....'],
          ['.....',
           '..OO.',
           '..O..',
           '..O..',
           '.....'],
          ['.....',
           '.....',
           '.OOO.',
           '...O.',
           '.....'],
          ['.....',
           '..O..',
           '..O..',
           '.OO..',
           '.....']]

L_SHAPE_TEMPLATE = [['.....',
           '...O.',
           '.OOO.',
           '.....',
           '.....'],
          ['.....',
           '..O..',
           '..O..',
           '..OO.',
           '.....'],
          ['.....',
           '.....',
           '.OOO.',
           '.O...',
           '.....'],
          ['.....',
           '.OO..',
           '..O..',
           '..O..',
           '.....']]

T_SHAPE_TEMPLATE = [['.....',
           '..O..',
           '.OOO.',
           '.....',
           '.....'],
          ['.....',
           '..O..',
           '..OO.',
           '..O..',
           '.....'],
          ['.....',
           '.....',
           '.OOO.',
           '..O..',
           '.....'],
          ['.....',
           '..O..',
           '.OO..',
           '..O..',
           '.....']]

PIECES = {'S': S_SHAPE_TEMPLATE,
     'Z': Z_SHAPE_TEMPLATE,
     'J': J_SHAPE_TEMPLATE,
     'L': L_SHAPE_TEMPLATE,
     'I': I_SHAPE_TEMPLATE,
     'O': O_SHAPE_TEMPLATE,
     'T': T_SHAPE_TEMPLATE}


def main():
  global FPSCLOCK, DISPLAYSURF, BASICFONT, BIGFONT
  pygame.init()
  FPSCLOCK = pygame.time.Clock()
  DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
  BASICFONT = pygame.font.Font('freesansbold.ttf', 18)
  BIGFONT = pygame.font.Font('freesansbold.ttf', 100)
  pygame.display.set_caption('Tetromino')

  showTextScreen('YoYoJacky')
  while True: # game loop
    if random.randint(0, 1) == 0:
      pygame.mixer.music.load('music/Have A Drink On Me.mp3')
    else:
      pygame.mixer.music.load('music/Rolling In The Deep.mp3')
    pygame.mixer.music.play(-1, 0.0)
    runGame()
    pygame.mixer.music.stop()
    showTextScreen('Game Over')


def runGame():
  # setup variables for the start of the game
  board = getBlankBoard()
  lastMoveDownTime = time.time()
  lastMoveSidewaysTime = time.time()
  lastFallTime = time.time()
  movingDown = False # note: there is no movingUp variable
  movingLeft = False
  movingRight = False
  score = 0
  level, fallFreq = calculateLevelAndFallFreq(score)

  fallingPiece = getNewPiece()
  nextPiece = getNewPiece()

  while True: # game loop
    if fallingPiece == None:
      # No falling piece in play, so start a new piece at the top
      fallingPiece = nextPiece
      nextPiece = getNewPiece()
      lastFallTime = time.time() # reset lastFallTime

      if not isValidPosition(board, fallingPiece):
        return # can't fit a new piece on the board, so game over

    checkForQuit()
    for event in pygame.event.get(): # event handling loop
      if event.type == KEYUP:
        if (event.key == K_p):
          # Pausing the game
          DISPLAYSURF.fill(BGCOLOR)
          pygame.mixer.music.stop()
          showTextScreen('Paused') # pause until a key press
          pygame.mixer.music.play(-1, 0.0)
          lastFallTime = time.time()
          lastMoveDownTime = time.time()
          lastMoveSidewaysTime = time.time()
        elif (event.key == K_LEFT or event.key == K_a):
          movingLeft = False
        elif (event.key == K_RIGHT or event.key == K_d):
          movingRight = False
        elif (event.key == K_DOWN or event.key == K_s):
          movingDown = False

      elif event.type == KEYDOWN:
        # moving the piece sideways
        if (event.key == K_LEFT or event.key == K_a) and isValidPosition(board, fallingPiece, adjX=-1):
          fallingPiece['x'] -= 1
          movingLeft = True
          movingRight = False
          lastMoveSidewaysTime = time.time()

        elif (event.key == K_RIGHT or event.key == K_d) and isValidPosition(board, fallingPiece, adjX=1):
          fallingPiece['x'] += 1
          movingRight = True
          movingLeft = False
          lastMoveSidewaysTime = time.time()

        # rotating the piece (if there is room to rotate)
        elif (event.key == K_UP or event.key == K_w):
          fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])
          if not isValidPosition(board, fallingPiece):
            fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
        elif (event.key == K_q): # rotate the other direction
          fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
          if not isValidPosition(board, fallingPiece):
            fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])

        # making the piece fall faster with the down key
        elif (event.key == K_DOWN or event.key == K_s):
          movingDown = True
          if isValidPosition(board, fallingPiece, adjY=1):
            fallingPiece['y'] += 1
          lastMoveDownTime = time.time()

        # move the current piece all the way down
        elif event.key == K_SPACE:
          movingDown = False
          movingLeft = False
          movingRight = False
          for i in range(1, BOARDHEIGHT):
            if not isValidPosition(board, fallingPiece, adjY=i):
              break
          fallingPiece['y'] += i - 1

    # handle moving the piece because of user input
    if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ:
      if movingLeft and isValidPosition(board, fallingPiece, adjX=-1):
        fallingPiece['x'] -= 1
      elif movingRight and isValidPosition(board, fallingPiece, adjX=1):
        fallingPiece['x'] += 1
      lastMoveSidewaysTime = time.time()

    if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1):
      fallingPiece['y'] += 1
      lastMoveDownTime = time.time()

    # let the piece fall if it is time to fall
    if time.time() - lastFallTime > fallFreq:
      # see if the piece has landed
      if not isValidPosition(board, fallingPiece, adjY=1):
        # falling piece has landed, set it on the board
        addToBoard(board, fallingPiece)
        score += removeCompleteLines(board)
        level, fallFreq = calculateLevelAndFallFreq(score)
        fallingPiece = None
      else:
        # piece did not land, just move the piece down
        fallingPiece['y'] += 1
        lastFallTime = time.time()

    # drawing everything on the screen
    DISPLAYSURF.fill(BGCOLOR)
    drawBoard(board)
    drawStatus(score, level)
    drawNextPiece(nextPiece)
    if fallingPiece != None:
      drawPiece(fallingPiece)

    pygame.display.update()
    FPSCLOCK.tick(FPS)


def makeTextObjs(text, font, color):
  surf = font.render(text, True, color)
  return surf, surf.get_rect()


def terminate():
  pygame.quit()
  sys.exit()


def checkForKeyPress():
  # Go through event queue looking for a KEYUP event.
  # Grab KEYDOWN events to remove them from the event queue.
  checkForQuit()

  for event in pygame.event.get([KEYDOWN, KEYUP]):
    if event.type == KEYDOWN:
      continue
    return event.key
  return None


def showTextScreen(text):
  # This function displays large text in the
  # center of the screen until a key is pressed.
  # Draw the text drop shadow
  titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTSHADOWCOLOR)
  titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2))
  DISPLAYSURF.blit(titleSurf, titleRect)

  # Draw the text
  titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR)
  titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3)
  DISPLAYSURF.blit(titleSurf, titleRect)

  # Draw the additional "Press a key to play." text.
  pressKeySurf, pressKeyRect = makeTextObjs('Press a key to play.', BASICFONT, TEXTCOLOR)
  pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100)
  DISPLAYSURF.blit(pressKeySurf, pressKeyRect)

  while checkForKeyPress() == None:
    pygame.display.update()
    FPSCLOCK.tick()


def checkForQuit():
  for event in pygame.event.get(QUIT): # get all the QUIT events
    terminate() # terminate if any QUIT events are present
  for event in pygame.event.get(KEYUP): # get all the KEYUP events
    if event.key == K_ESCAPE:
      terminate() # terminate if the KEYUP event was for the Esc key
    pygame.event.post(event) # put the other KEYUP event objects back


def calculateLevelAndFallFreq(score):
  # Based on the score, return the level the player is on and
  # how many seconds pass until a falling piece falls one space.
  level = int(score / 10) + 1
  fallFreq = 0.27 - (level * 0.02)
  return level, fallFreq

def getNewPiece():
  # return a random new piece in a random rotation and color
  shape = random.choice(list(PIECES.keys()))
  newPiece = {'shape': shape,
        'rotation': random.randint(0, len(PIECES[shape]) - 1),
        'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2),
        'y': -2, # start it above the board (i.e. less than 0)
        'color': random.randint(0, len(COLORS)-1)}
  return newPiece


def addToBoard(board, piece):
  # fill in the board based on piece's location, shape, and rotation
  for x in range(TEMPLATEWIDTH):
    for y in range(TEMPLATEHEIGHT):
      if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK:
        board[x + piece['x']][y + piece['y']] = piece['color']


def getBlankBoard():
  # create and return a new blank board data structure
  board = []
  for i in range(BOARDWIDTH):
    board.append([BLANK] * BOARDHEIGHT)
  return board


def isOnBoard(x, y):
  return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT


def isValidPosition(board, piece, adjX=0, adjY=0):
  # Return True if the piece is within the board and not colliding
  for x in range(TEMPLATEWIDTH):
    for y in range(TEMPLATEHEIGHT):
      isAboveBoard = y + piece['y'] + adjY < 0
      if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK:
        continue
      if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY):
        return False
      if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK:
        return False
  return True

def isCompleteLine(board, y):
  # Return True if the line filled with boxes with no gaps.
  for x in range(BOARDWIDTH):
    if board[x][y] == BLANK:
      return False
  return True


def removeCompleteLines(board):
  # Remove any completed lines on the board, move everything above them down, and return the number of complete lines.
  numLinesRemoved = 0
  y = BOARDHEIGHT - 1 # start y at the bottom of the board
  while y >= 0:
    if isCompleteLine(board, y):
      # Remove the line and pull boxes down by one line.
      for pullDownY in range(y, 0, -1):
        for x in range(BOARDWIDTH):
          board[x][pullDownY] = board[x][pullDownY-1]
      # Set very top line to blank.
      for x in range(BOARDWIDTH):
        board[x][0] = BLANK
      numLinesRemoved += 1
      # Note on the next iteration of the loop, y is the same.
      # This is so that if the line that was pulled down is also
      # complete, it will be removed.
    else:
      y -= 1 # move on to check next row up
  return numLinesRemoved


def convertToPixelCoords(boxx, boxy):
  # Convert the given xy coordinates of the board to xy
  # coordinates of the location on the screen.
  return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE))


def drawBox(boxx, boxy, color, pixelx=None, pixely=None):
  # draw a single box (each tetromino piece has four boxes)
  # at xy coordinates on the board. Or, if pixelx & pixely
  # are specified, draw to the pixel coordinates stored in
  # pixelx & pixely (this is used for the "Next" piece).
  if color == BLANK:
    return
  if pixelx == None and pixely == None:
    pixelx, pixely = convertToPixelCoords(boxx, boxy)
  pygame.draw.rect(DISPLAYSURF, COLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1))
  pygame.draw.rect(DISPLAYSURF, LIGHTCOLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 4, BOXSIZE - 4))


def drawBoard(board):
  # draw the border around the board
  pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5)

  # fill the background of the board
  pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT))
  # draw the individual boxes on the board
  for x in range(BOARDWIDTH):
    for y in range(BOARDHEIGHT):
      drawBox(x, y, board[x][y])


def drawStatus(score, level):
  # draw the score text
  scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR)
  scoreRect = scoreSurf.get_rect()
  scoreRect.topleft = (WINDOWWIDTH - 150, 20)
  DISPLAYSURF.blit(scoreSurf, scoreRect)

  # draw the level text
  levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR)
  levelRect = levelSurf.get_rect()
  levelRect.topleft = (WINDOWWIDTH - 150, 50)
  DISPLAYSURF.blit(levelSurf, levelRect)


def drawPiece(piece, pixelx=None, pixely=None):
  shapeToDraw = PIECES[piece['shape']][piece['rotation']]
  if pixelx == None and pixely == None:
    # if pixelx & pixely hasn't been specified, use the location stored in the piece data structure
    pixelx, pixely = convertToPixelCoords(piece['x'], piece['y'])

  # draw each of the boxes that make up the piece
  for x in range(TEMPLATEWIDTH):
    for y in range(TEMPLATEHEIGHT):
      if shapeToDraw[y][x] != BLANK:
        drawBox(None, None, piece['color'], pixelx + (x * BOXSIZE), pixely + (y * BOXSIZE))


def drawNextPiece(piece):
  # draw the "next" text
  nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR)
  nextRect = nextSurf.get_rect()
  nextRect.topleft = (WINDOWWIDTH - 120, 80)
  DISPLAYSURF.blit(nextSurf, nextRect)
  # draw the "next" piece
  drawPiece(piece, pixelx=WINDOWWIDTH-120, pixely=100)


if __name__ == '__main__':
  main()

写好以后,先用命令执行测试一下:

sudo python russianblock.py

执行结果看到如下内容就说明成功了:

随便按一个键就可以开始玩儿了,使用键盘的上下左右控制移动, 用空格控制反转,记得把你的耳机插入树莓派3.5mm 的音频复合接口, 然后开始享受游戏的乐趣吧!

如果失败,音乐就停啦!

好了! 这个简单的教程就写到这里, 后期教大家利用 pygame 和树莓派制作更多的好玩儿的小游戏!

用树莓派做 RTMP 流直播服务器,可推送至斗鱼直播

在《用树莓派DIY共享鱼缸,支持微信远程喂鱼》一文中,使用了树莓派来做直播服务器。通过安装在树莓派上的摄像头采集实时视频数据流,推送至 RTMP 监听服务器。同时,其他的客户端访问这个 RTMP 服务器就可以观看视频了。下面我们来详细介绍这个模块如何搭建,文末还将给出将直播视频推送至斗鱼直播平台的方法。

需要用的东西和软件说明:

树莓派主板(本文使用树莓派 Zero W 套件,该套件附带一款完美安装摄像头的外壳)
兼容摄像头(本文使用官方摄像头模块,其他 USB 兼容摄像头亦可)
软件方面:
avconv 和 GStreamer 用于采集摄像头捕获的视频流并推送到 RTMP 服务
NGINX 和 RTMP 模块,用于接收视频流,同时提供视频发布功能
Strobe Media Playback,一款基于 Flash 的网页视频播放器

一、配置摄像头

无论是树莓派官方摄像头模块还是其他兼容的USB摄像头,连接好摄像头之后,运行命令去启用摄像头:

sudo raspi-config

编辑系统模块文件。

sudo nano/etc/modules

在这个文件的最后添加一行

bcm2835-v4l2

保存。建议配置好之后重启一下树莓派。然后测试摄像头是否正常工作。

vcgencmd get_camera

输出如图所示表示被识别到。进一步测试拍照。

raspistill -t 2000 -o 1.jpg

执行上面的指令之后,会你用摄像头拍照,并将照片保存在当前目录下,名为 1.jpg。

如果一切正常,恭喜!可以开始下面的步骤了!

二、网络配置

如果你的树莓派使用有线网络的话可以忽略这一步。笔者用的树莓派是 Zero W 版本,没有有线网口,所以必须手动配置无线网络。

sudo nano/etc/network/interfaces

将配置修改为:

auto lo

iface lo inet loopback

allow-hotplug wlan0

auto wlan0

iface wlan0 inet dhcp

        wpa-ssid "WIFISSID"

        wpa-psk "WIFIPASSWORD"

WIFISSID 和 WIFIPASSWORD 分别替换为你的 WIFI 的 SSID 和密码。

网络配置方法可以参考树莓派实验室的其他文章,例如这篇《树莓派 Raspberry Pi 设置无线上网》。

三、安装 NGINX 和 RTMP

我们用 nginx 加上 nginx-rtmp-module 模块作为 RTMP 服务端。这里先安装 nginx 然后再移除它,目的是利用这个过程吧 nginx 相关的依赖安装好并设定好系统环境。这个通过 apt 安装的 nginx 并不能直接使用,因为他并不包含我们需要的 RTMP 模块,所以将它移除。而后我们手工下载 nginx 和 nginx-rtmp-module 模块源码来手工编译安装,以获得我们最终需要的服务端。

sudo apt-get update

#安装 nginx

sudo apt-get -y<span> </span>install nginx

#移除 nginx

sudo apt-get -y remove nginx

sudo apt-get clean

#清空 nginx 的配置文件

sudo rm -rf<span> </span>/etc/nginx/*

#安装编译用的模块

sudo apt-get<span> </span>install -y curl build-essential libpcre3 libpcre3-dev libpcre++-dev zlib1g-dev libcurl4-openssl-dev libssl-dev

#创建存放网页的目录给 nginx 使用

sudo mkdir -p<span> </span>/var/www

#创建编译用的目录

mkdir -p ~/nginx_src

cd ~/nginx_src

#下载 nginx 源码包

wget http://nginx.org/download/nginx-1.11.8.tar.gz

#下载 nginx-rtmp-module 源码包

wget https://github.com/arut/nginx-rtmp-module/archive/master.zip

tar -zxvf nginx-1.11.8.tar.gz

unzip master.zip

cd nginx-1.11.8

#设定编译参数

./configure --prefix=/var/www --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --with-http_ssl_module --without-http_proxy_module --add-module=/home/pi/nginx_src/nginx-rtmp-module-master

#开始编译安装

make

sudo make install

比较漫长的等待之后,编译安装结束。这时可以测试 nginx 是否安装好。

nginx -v

正常的話,會顯示 nginx 的版本。

配置 nginx。

/etc/nginx/nginx.conf

在末尾添加如下配置:

rtmp {

    server {
        listen 1935;
        chunk_size 4096;
        application live {
            live on;
            record off;
        }<br>}

重启 nginx 服务。

sudo service nginx start

没有错误提示就表示成功了。
到这里 nginx 和 RTMP 模块都准备好了。

四、安装 avconv 和 GStreamer

安装的组件比较多,如果操作的时候因为软件源的问题总是出现错误难以完成,建议更换软件源试试。笔者用的是清华大学软件源安装的。

sudo nano/etc/apt/sources.list
deb https://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ stretch main contrib non-free rpi

deb-src https://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ stretch main contrib non-free rpi

开始安装

sudo apt-get update

sudo apt-get<span> </span>install libav-tools

#安装 GStreamer

sudo apt-get<span> </span>install gstreamer1.0-tools

#安装 GStreamer 扩展组件

sudo apt-get <span> </span>install libgstreamer1.0-0 libgstreamer1.0-0-dbg libgstreamer1.0-dev liborc-0.4-0 liborc-0.4-0-dbg liborc-0.4-dev liborc-0.4-doc gir1.2-gst-plugins-base-1.0 gir1.2-gstreamer-1.0 gstreamer1.0-alsa gstreamer1.0-doc gstreamer1.0-omx gstreamer1.0-plugins-bad gstreamer1.0-plugins-bad-dbg gstreamer1.0-plugins-bad-doc gstreamer1.0-plugins-base gstreamer1.0-plugins-base-apps gstreamer1.0-plugins-base-dbg gstreamer1.0-plugins-base-doc gstreamer1.0-plugins-good gstreamer1.0-plugins-good-dbg gstreamer1.0-plugins-good-doc gstreamer1.0-plugins-ugly gstreamer1.0-plugins-ugly-dbg gstreamer1.0-plugins-ugly-doc gstreamer1.0-pulseaudio gstreamer1.0-tools gstreamer1.0-x libgstreamer-plugins-bad1.0-0 libgstreamer-plugins-bad1.0-dev libgstreamer-plugins-base1.0-0 libgstreamer-plugins-base1.0-dev

这里安装了 avconv 和 GStreamer 两套视频采集组件。 avconv 的使用方式是:

avconv -f video4linux2 -r 24 -i<span> </span>/dev/video0 -f flv rtmp://localhost:1935/live

avconv 采用软编码实现,因此 CPU 消耗比较高,推荐用 GStreamer,GStreamer 的采集使用如下命令:

gst-launch-1.0 -v v4l2src device=/dev/video0 !<span> </span>'video/x-raw, width=1024, height=768, framerate=30/1' ! queue ! videoconvert ! omxh264enc ! h264parse ! flvmux ! rtmpsink location='rtmp://树莓派的IP地址/live live=1'

如果希望在后台运行这两个命令可以在命令后面添加&,例如:

gst-launch-1.0 -v v4l2src device=/dev/video0 !<span> </span>'video/x-raw, width=1024, height=768, framerate=30/1' ! queue ! videoconvert ! omxh264enc ! h264parse ! flvmux ! rtmpsink location='rtmp://树莓派的IP地址/live live=1' &

device=/dev/video0 这个参数可以省去,除非在有多个摄像头的时候,希望指定视频采集自某个指定的摄像头才需要这个参数。
采集的视频怎么播放呢?请看下面介绍。

五、实时视频的呈现

有多种方式呈现直播视频画面:
1、使用 RTMP 播放器播放视频流
例如 VLC 等播放器(桌面版和手机版均有)支持 RTMP 视频流播放,填入 rtmp://树莓派的IP地址/live即可播放。不过这个软件有数十秒的缓冲延迟,需要设定缓冲时间来缩短延迟。

2、使用 Strobe Media Playback 创建播放页面,通过网页播放视频流
这个是在树莓派上创建一个带有播放功能的网页,播放器选用 Strobe Media Playback,当然你也可以选择其他支持 RTMP 的播放器控件。播放的时候用浏览器打开 http://树莓派的IP地址/index.html 进入播放界面。下面介绍这个播放页面的创建方法。

mkdir -p ~/strobe_src
cd ~/strobe_src
wget http://downloads.sourceforge.net/project/smp.adobe/Strobe%20Media%20Playback%201.6%20Release%20%28source%20and%20binaries%29/StrobeMediaPlayback_1.6.328-full.zip
unzip StrobeMediaPlayback_1.6.328-full.zip
sudo cp -rfor\ Flash\ Player\ 10.1/var/www/html/strobe
sudo nano/var/www/html/index.html

填入如下内容,记得把下面的“树莓派的IP地址”替换成你的树莓派实际的IP地址。IP地址可以通过 ifconfig 命令查看。

<!DOCTYPE html><br><br><html><br><br><head><br><br><title>Live Streaming</title><br><br><!-- strobe --><br><br><script type="text/javascript" src="strobe/lib/swfobject.js"></script><br><br><script type="text/javascript"><br><br>  var parameters = { <br><br>     src: "rtmp://{pi_address}/rtmp/live"<span class="s1">,</span> <br><br>     autoPlay: false<span class="s1">,</span> <br><br>     controlBarAutoHide: false<span class="s1">,</span> <br><br>     playButtonOverlay: true<span class="s1">,</span> <br><br>     showVideoInfoOverlayOnStartUp: true<span class="s1">,</span> <br><br>     optimizeBuffering : false<span class="s1">,</span> <br><br>     initialBufferTime : 0.1<span class="s1">,</span> <br><br>     expandedBufferTime : 0.1<span class="s1">,</span> <br><br>     minContinuousPlayback : 0.1<span class="s1">,</span> <br><br>     poster: "images/poster.png" <br><br>  }<span class="s1">;</span> <br><br>  swfobject.embedSWF<span class="s1">(</span><br><br>    "strobe/StrobeMediaPlayback.swf"<br><br>    <span class="s1">,</span> "StrobeMediaPlayback"<br><br>    <span class="s1">,</span> 1024<br><br>    <span class="s1">,</span> 768<br><br>    <span class="s1">,</span> "10.1.0"<br><br>    <span class="s1">,</span> "strobe/expressInstall.swf"<br><br>    <span class="s1">,</span> parameters<br><br>    <span class="s1">,</span> {<br><br>      allowFullScreen: "true"<br><br>    }<br><br>    <span class="s1">,</span> {<br><br>      name: "StrobeMediaPlayback"<br><br>    }<br><br>  <span class="s1">);</span><br><br></script><br><br></head><br><br><body><br><br><div id="StrobeMediaPlayback"></div><br><br></body><br><br></html>

播放的时候用浏览器打开 http://树莓派的IP地址/index.html 进入播放界面。

3、推送至斗鱼直播平台观看
你可能注意到了 GStreamer 这个命令中有 location 这个参数。这个参数是设定采集到的视频流推向哪里,通过设定这个参数可以将视频流推向任何支持 RTMP 协议的服务器。

gst-launch-1.0 -v v4l2src device=/dev/video0 !'video/x-raw, width=1024, height=768, framerate=30/1' ! queue ! videoconvert ! omxh264enc ! h264parse ! flvmux ! rtmpsink location='rtmp://树莓派的IP地址/live live=1'

斗鱼平台同样采用了 RTMP 协议传输直播视频,以斗鱼平台为例来说明一下推流到斗鱼的方法。

首先获取斗鱼的 RTMP 推流地址。开启了直播室之后可以获得推流码。注意,斗鱼的推流码是有时限的,取到推流码需要尽快使用以免过期。

把这两个参数组合起来(中间加上/)。修改之后的命令例如:

gst-launch-1.0 -v v4l2src device=/dev/video0 !'video/x-raw, width=1024, height=768, framerate=30/1' ! queue ! videoconvert ! omxh264enc ! h264parse ! flvmux ! rtmpsink location='rtmp://send1.douyu.com/live/1372rSOMdcBJ8UHD?wsSecret=96d2k4ecdf267d17b8e8c38b6a4a6efd&wsTime=59f92e2e&wsSeek=off live=1'

然后就可以开播了。

打个小广告,欢迎大家关注我的斗鱼直播间~
https://www.douyu.com/1372
这里不定期直播宠物鱼。
应用以上技术实现的远程喂鱼项目:
http://maker.quwj.com/program/nature-aquarium

总体上三种播放方式都有一定延迟,其中网页 Strobe Media Playback 播放延迟最小,大概在1秒左右。VLC 延迟比较固定默认约20秒,个别平台的版本是可以设置延迟数值的笔者没有亲力尝试。然后是斗鱼平台,斗鱼随着播放时间变长延迟也越来越长,需要刷新直播间页面才会同步。

搭建过程有问题请在树莓派实验室原文下面留言,转载请保证文章内容完整、注明出处并附带原文链接~

本文来自:http://shumeipai.nxez.com/2017/11/01/build-rtmp-stream-live-server-with-raspberry-pi.html

树莓派3B 爬虫蓝牙播放器

  

一直没有尝试使用一下树莓派3B 的蓝牙功能,今天特别想试试,于是就烧录了最新的raspbian镜像,然后接上5寸GPIO触摸屏和键盘鼠标,开始了调试,网上看了看其他人的教程,发现都很老了,有的还不能用。所以就诞生了这篇我自己能用的文章,算是做个记录吧。

首先你需要做的准备工作:

  1. 树莓派3B  如果你是2B ,那么你还需要一个USB 的蓝牙接收器(马云家可买)
  2. 树莓派电源5v/2A
  3. 8GB TF 卡一张,读卡器1个
  4. 树莓派外壳(可选) 为了好看和防尘, 还可以选择散热片和风扇,更加专业.
  5. 小米蓝牙小音箱.
  6. 无线网络环境.
  7. 去官方网站下载最新的 Raspbian 系统并且通过 win32_diskimager 烧录到你的 TF卡

好了,万事俱备, 只欠500万,接下来直接进入主题,插上电源,等待RPI开机后,系统中通过点选 wifi 图标先连入网络,然后打开一个终端,执行下面的命令进行更新和安装蓝牙软件:

sudo apt-get  update

sudo apt-get  -y  install  –no-install-recommends bluetooth

sudo service bluetooth status

检查是否有蓝牙服务,如果没有就再重启一下设备。或者用下面的命令尝试扫描一下:

hcitool scan

我之前还尝试了使用blueman,那个在图形上设置更加方便。

sudo apt-get  -y  install  bluetooth  bluez  blueman

但是我更倾向于这样设置:

蓝牙配对

如果看不清楚就看这里:

sudo  bluetoothctl

然后进入bluetooth的交互界面输入

agent  on

default-agent

然后开始扫描

scan on

当找到你的蓝牙设备后,执行配对就好了。

pair  B8:78:2E:12:0F:29   #这里要根据你实际情况选择.

这里输入你的蓝牙的MAC地址,就是类似B8:78:2E:12:0F:29这种

如果要用蓝牙音箱,记得使用blueman,那个有图形界面可以在图形上选择audio的输出方式,可以找到你的蓝牙设备,然后选择成为输出设备,然后就可以用我写好的python爬虫来进行音乐的搜索和播放了。

git  clone   https://github.com/yoyojacy/52Pi.git

cd  52Pi/

python   music.py

第一次执行的时候可能时间比较长,因为在更新系统和安装mplayer,不用担心,通过后就可以看到提示了,输入歌名或者歌手的名字就可以听到歌曲了。如果还想调整一下音量大小可以用:

alsamixer

然后按上下键调整就好了,最后记得ESC退出。

最后,转发的童鞋请注明出处! 谢谢~