篇七:树莓派zero w蓝牙网关
因为大家强烈需求,我优先先写树莓派蓝牙网关把。
我选的是树莓派zero w,主要是第一个小巧非常小。并且能提供蓝牙、wifi。
也可以选择焊接好阵脚,毕竟这个也支持gpio的数据通信,接个433+红外就是全面网关。
系统安装
先去下载树莓派官方的镜像,因为zero的cpu比毕竟比较若不想在上面跑什么高负载的东西,所以我直接选择,没有桌面环境的只有命令行的版本。 Raspbian Buster Lite
,下载地址 ,下载好2.2个G。
然后写入到mini sd卡的镜像。
- 可以用工具,我是mac os所以我使用
balenaEtcher
以下mac命令,和linux完全不同,linux使用fdisk
diskutil list
dd if=2019-07-10-raspbian-buster-lite.img of=/dev/disk3 bs=10m
配置wifi
因为安装的没有图形界面,同样的配置wifi连接比较麻烦,所以官方提供了一种方案直接写wifi配置。
新建一个配置文件 wpa_supplicant.conf
,内容如下,可以配置多个network。
注意树莓在zero w仅支持2.4Gwifi网络。
country=CN
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
ssid="WiFi-A"
psk="12345678"
key_mgmt=WPA-PSK
priority=1
}
network={
ssid="WiFi-B"
psk="12345678"
key_mgmt=WPA-PSK
priority=2
scan_ssid=1
}
#ssid:网络的ssid
#psk:密码
#priority:连接优先级,数字越大优先级越高(不可以是负数)
#scan_ssid:连接隐藏WiFi时需要指定该值为1
如果你的 WiFi 没有密码
network={
ssid="你的无线网络名称(ssid)"
key_mgmt=NONE
}
如果你的 WiFi 使用WEP加密
network={
ssid="你的无线网络名称(ssid)"
key_mgmt=NONE
wep_key0="你的wifi密码"
}
如果你的 WiFi 使用WPA/WPA2加密
network={
ssid="你的无线网络名称(ssid)"
key_mgmt=WPA-PSK
psk="你的wifi密码"
}
然后把这个文件wpa_supplicant.conf
复制到写好的sd卡内,写入成功以后拔出重新插入就会出现一个boot的u盘,复制到里面。
配置SSH
因为没有屏幕,没有键盘,所以需要一个能连接进去的方法,而且树莓派的系统又默认没有开启ssh,所以新建一个文件。
同样在 boot 分区新建一个文件,空白的即可,文件命名为 ssh。注意要小写且不要有任何扩展名。
树莓派在启动之后会在检测到这个文件之后自动启用 ssh 服务。随后即可通过登录路由器找到树莓派的 IP 地址,通过 ssh 连接到树莓派了。
windows特别注意,因为windows默认保存的文件都是有后缀的,这个完全需要把后缀删除。
然后把SD卡插回去,并通电。
配置树莓派
连接树莓派
首先通过路由器查看树莓派的ip,因为只要连接了网络总要分配ip地址,在路由器上会出现一个新的设备。
能ping通说明已经联网好了。
现在ssh过去。 ssh mailto:[email protected]
,密码是:raspberry,地址换成你自己的,用户名和密码是固定的。
初始化基础配置
sudo raspi-config
修改系统配置,密码就是ssh的密码。
要改的有几项,
- 第一个把密码改了。
- 第四个修改地区,
- 第一天修改语言,我会修改成
zh_CN.UTF8
,确定以后要等好一会。
- 然后修改时区,改成亚洲上海。
- 然后键盘类型,改成chinese。
设置root登陆
- 设置root密码:
sudo passwd root
- 解锁root密码登陆:
sudo passwd --unlock root
- 设置ssh登陆:
sudo nano /etc/ssh/sshd_config
Ctrl + W 快捷键 搜索 PermitRootLogin without-password
在下一行增加PermitRootLogin yes,注意不能#号注释。
Ctrl + O 快捷键 保存
Ctrl + O 快捷键 退出 Nano 编辑器
- 然后重启树莓派:
sudo reboot
- 使用root登陆:
ssh root@pi_host
注意:为什么要改成root,网关是需要通过系统调度的,有一些比如蓝牙搜索是root权限,所以通过root账号才能进行python配置,当然也可以在系统内 sudo su
方式切换成root。
修改更新源
因为我都是root用户所以都不加sudo了。
默认的源在国外那速度简直了。
nano /etc/apt/sources.list
可以全删掉,也可以在前面加上#号注释然后增加源。
deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ buster main contrib non-free rpi
Ctrl + O
Ctrl + O
保存并退出。
sudo nano /etc/apt/sources.list.d/raspi.list
这个全注释掉或者删除就好了。
更新库,并安装需要的组件
有同学一直装不上bluepy,完整按照我操作我保你成功。
apt update
# 更新本地缓存源
apt update
# 安装python3 pip
apt install python3-pip -y
# 安装git
apt install git -y
# 安装bluepy依赖
apt install python-pip libglib2.0-dev -y
# 安装mqtt客户端,方便查看mqtt消息
apt install mosquitto-clients -y
# 安装vim,我习惯用这个
apt install vim -y
# 安装bluepy
pip3 install bluepy
pip3 install btlewrap
修改pip的源否则这货安装也巨慢:
esc是按键不是敲的。。。
mkdir ~/.pip
vim pip.conf
esc
:set paste
i
换成阿里的。
[global]
timeout = 10 # 超时
index-url = http://mirrors.aliyun.com/pypi/simple/ # 第一源
index-index-url = http://pypi.douban.com/simple/ # 第二
[install]
trusted-host =
mirrors.aliyun.com
pypi.douban.com
然后esc输入:wq保存并退出。
测试蓝牙
协议个bluepy蓝牙扫描测试以下。
编写一个文件vim、nano都行,我习惯vim
vim scan_bt.py
esc
:set paste
i
然后粘贴代码,crtl+v:
from btlewrap import BluepyBackend
def scan(backend, timeout=10):
"""Scan for miflora devices.
Note: this must be run as root!
"""
result = []
for (mac, name) in backend.scan_for_devices(timeout):
print("%s --> %s" % (name, mac))
return result
if __name__ == '__main__':
print("START_SCAN")
scan(BluepyBackend)
print("SCAN_FINISH")
然后esc输入:wq保存并退出。
然后执行扫描: python3 scan_bt.py
这就ok了,蓝牙这几个地址其实我用过的是有规律的。
- 68:3e:34 开头的这个都是魅族遥控器的。
- c4:7c:8d 开头的都是花花草草的。
- 58:2D:34 开头的都是小米那个蓝牙温度计的。
备份树莓派
中间插一个步骤,备份树莓派,可以是备份安装好的,也可以随时备份,因为我的sd卡是32g的如果用普通的dd命令制作的img镜像会高达32G。
网上找了好几天终于找到一个脚本不需要其他的,只要通过脚本并插入u盘,就可以制作一个最小img镜像,后面可以快速恢复。
脚本是:
#!/bin/sh
echo ===================== part 1, install tools ===============================
sudo apt-get -y install rsync dosfstools parted kpartx exfat-fuse pv
echo ===================== part 2, choose USB ===============================
#mount USB device
usbmount=/mnt
mkdir -p $usbmount
if [ -z $1 ]; then
echo "no argument, assume the mount device is /dev/sda1 ? Y/N"
read key
if [ "$key" = "y" -o "$key" = "Y" ]; then
sudo mount -o uid=1000 /dev/sda1 $usbmount
else
echo "$0 [backup dest device name], e.g. $0 /dev/sda1"
exit 0
fi
else
sudo mount -o uid=1000 $1 $usbmount
fi
if [ -z "`grep $usbmount /etc/mtab`" ]; then
echo "mount fail, exit now"
exit 0
fi
img=$usbmount/rpi-back-`date +%Y%m%d-%H%M`.img
echo "备份文件位置:$img"
echo ===================== part 3, create a new blank img ===============================
# New img file
#sudo rm $img
bootsz=`df -P | grep /boot | awk '{print $2}'`
rootsz=`df -P | grep /dev/root | awk '{print $3}'`
totalsz=`echo $bootsz $rootsz | awk '{print int(($1+$2)*1.3)}'`
echo "start create img,total size=${totalsz}K"
#sudo dd if=/dev/zero of=$img bs=1K count=$totalsz
pv -tpreb /dev/zero |sudo dd of=$img bs=1K count=$totalsz
# format virtual disk
bootstart=`sudo fdisk -l /dev/mmcblk0 | grep mmcblk0p1 | awk '{print $2}'`
bootend=`sudo fdisk -l /dev/mmcblk0 | grep mmcblk0p1 | awk '{print $3}'`
rootstart=`sudo fdisk -l /dev/mmcblk0 | grep mmcblk0p2 | awk '{print $2}'`
echo "format virtual disk: boot: $bootstart >>> $bootend, root: $rootstart >>> end"
#rootend=`sudo fdisk -l /dev/mmcblk0 | grep mmcblk0p2 | awk '{print $3}'`
sudo parted $img --script -- mklabel msdos
sudo parted $img --script -- mkpart primary fat32 ${bootstart}s ${bootend}s
sudo parted $img --script -- mkpart primary ext4 ${rootstart}s -1
loopdevice=`sudo losetup -f --show $img`
device=/dev/mapper/`sudo kpartx -va $loopdevice | sed -E 's/.*(loop[0-9])p.*/\1/g' | head -1`
sleep 5
sudo mkfs.vfat ${device}p1 -n boot
sudo mkfs.ext4 ${device}p2
echo "format finish"
echo ===================== part 4, fill the data to img =========================
# mount partitions
mountb=$usbmount/backup_boot/
mountr=$usbmount/backup_root/
mkdir -p $mountb $mountr
# backup /boot
sudo mount -t vfat ${device}p1 $mountb
sudo cp -rfp /boot/* $mountb
sync
echo "...Boot partition done"
# backup /root
sudo mount -t ext4 ${device}p2 $mountr
if [ -f /etc/dphys-swapfile ]; then
SWAPFILE=`cat /etc/dphys-swapfile | grep ^CONF_SWAPFILE | cut -f 2 -d=`
if [ "$SWAPFILE" = "" ]; then
SWAPFILE=/var/swap
fi
EXCLUDE_SWAPFILE="--exclude $SWAPFILE"
fi
sudo rsync --force -rltWDEgop --delete --stats --progress \
$EXCLUDE_SWAPFILE \
--exclude '.gvfs' \
--exclude '/dev' \
--exclude '/media' \
--exclude '/mnt' \
--exclude '/proc' \
--exclude '/run' \
--exclude '/sys' \
--exclude '/tmp' \
--exclude 'lost\+found' \
--exclude '$usbmount' \
// $mountr
# special dirs
for i in dev media mnt proc run sys boot; do
if [ ! -d $mountr/$i ]; then
sudo mkdir $mountr/$i
fi
done
if [ ! -d $mountr/tmp ]; then
sudo mkdir $mountr/tmp
sudo chmod a+w $mountr/tmp
fi
#移除网络配置
#sudo rm -f $mountr/etc/udev/rules.d/70-persistent-net.rules
sync
ls -lia $mountr/home/pi/
echo "...Root partition done"
# if using the dump/restore
# tmp=$usbmount/root.ext4
# sudo chattr +d $img $mountb $mountr $tmp
# sudo mount -t ext4 ${device}p2 $mountr
# cd $mountr
# sudo dump -0uaf - / | sudo restore -rf -
# cd
# replace PARTUUID
opartuuidb=`blkid -o export /dev/mmcblk0p1 | grep PARTUUID`
opartuuidr=`blkid -o export /dev/mmcblk0p2 | grep PARTUUID`
npartuuidb=`blkid -o export ${device}p1 | grep PARTUUID`
npartuuidr=`blkid -o export ${device}p2 | grep PARTUUID`
sudo sed -i "s/$opartuuidr/$npartuuidr/g" $mountb/cmdline.txt
sudo sed -i "s/$opartuuidb/$npartuuidb/g" $mountr/etc/fstab
sudo sed -i "s/$opartuuidr/$npartuuidr/g" $mountr/etc/fstab
sudo umount $mountb
sudo umount $mountr
# umount loop device
sudo kpartx -d $loopdevice
sudo losetup -d $loopdevice
sudo umount $usbmount
rm -rf $mountb $mountr
echo "==== All done. You can un-plug the backup device"
保存成 backup.sh
,然后赋予执行权限 chmod +x backup.sh
然后插上u盘,推荐找个空的u盘格式化成exfat格式,毕竟命令行很多人搞不懂磁盘工具。
执行 ./backup.sh
这段只有一个参数输入,是否确定挂在/dev/sda1,这个就是u盘,挂在并创建镜像然后复制文件。
===================== part 1, install tools ===============================
正在读取软件包列表... 完成
正在分析软件包的依赖关系树
正在读取状态信息... 完成
dosfstools 已经是最新版 (4.1-2)。
exfat-fuse 已经是最新版 (1.3.0-1)。
kpartx 已经是最新版 (0.7.9-3)。
parted 已经是最新版 (3.2-25)。
pv 已经是最新版 (1.6.6-1)。
rsync 已经是最新版 (3.1.3-6)。
升级了 0 个软件包,新安装了 0 个软件包,要卸载 0 个软件包,有 3 个软件包未被升级。
===================== part 2, choose USB ===============================
no argument, assume the mount device is /dev/sda1 ? Y/N
y
FUSE exfat 1.3.0
WARN: volume was not unmounted cleanly.
备份文件位置:/mnt/rpi-back-20190822-2150.img
===================== part 3, create a new blank img ===============================
start create img,total size=2199256K
19.6MiB 0:00:11 [1.94MiB/s] [ <=>
然后就等着复制就好了,如果是没有图形界面的树莓派系统,没有装什么大的应用,一般2.2个G左右。
出现这个就是制作完成了。
注意:如果需要配置新的网络只要还是配置上面那个网络文件放到boot下启动的时候会覆盖以前的wifi设置。
注意:复制完成以后因为是通过缩小硬盘的方式缩小的,所以需要在启动以后通过 raspi-config --> 7高级设置 --> A1 扩展文件系统来扩展
安装配置蓝牙网关
cd /opt/
git clone https://github.com/meishild/bt-mqtt-gateway.git
cd bt-mqtt-gateway
cp config.yaml.example config.yaml
config.yaml这个就是蓝牙网关的配置文件了。
我这个配置提供了三个我常用的花花草草、魅族、小米温度计、和蓝牙信号强度扫描的配置。
mqtt:
host: 10.0.0.8
port: 1883
#username: user
#password: password
#ca_cert: /etc/ssl/certs/ca-certificates.crt # Uncomment to enable MQTT TLS, update path to appropriate location.
#ca_verify: False # Verify TLS certificate chain and host, disable for testing with self-signed certificates, default to True
topic_prefix: # All messages will have that prefix added, remove if you dont need this.
client_id: bt-mqtt-gateway
availability_topic: lwt_topic
manager:
sensor_config:
topic: homeassistant
retain: true
topic_subscription:
update_all:
topic: homeassistant/status
payload: online
command_timeout: 35 # Timeout for worker operations. Can be removed if the default of 35 seconds is sufficient.
workers:
# 蓝牙强度
btrssi:
args:
topic_prefix: rssi
devices:
name: 蓝牙的地址,不知道通过上面的那个测试获取
name: 蓝牙的地址
# 更新频次间隔,单位秒
update_interval: 60
# 花花草草
miflora:
args:
devices:
name: 蓝牙的地址
topic_prefix: miflora
update_interval: 300
# 小米蓝牙温度计
mithermometer:
args:
devices:
name: 蓝牙的地址
topic_prefix: mithermometer
update_interval: 300
# 魅族红外
mzbtir:
args:
devices:
name: 蓝牙的地址
topic_prefix: mzbtir
update_interval: 300
安装基础依赖:
pip3 install -r requirements.txt
# 花花草草依赖
pip3 install miflora
# 小米依赖
pip3 install mithermometer
修改好了,可以通过直接启动测试以下 python3 gateway.py
这时候如果配置没有问题,就开始打印日志了.
21:59:56 Starting
22时00分02秒 Adding 4 btrssi devices
22时00分04秒 Adding 2 miflora devices
22时00分07秒 Adding 1 mithermometer devices
22时00分07秒 Adding 1 mzbtir devices
22时00分12秒 Updating btrssi device 'xiezhualan' (C4:7C:8D:6B:0A:8C)
22时00分12秒 Updating btrssi device 'lvluo' (C4:7C:8D:6B:0B:E3)
22时00分12秒 Updating btrssi device 'mztest1' (68:3E:34:CCF:68)
22时00分12秒 Updating btrssi device 'mith_mr' (58:2D:34:34:A4:A7)
22时00分12秒 Updating 2 miflora devices
也可以直接通过mqtt消息查看发送了什么,需要新打开个控制台窗口执行: mosquitto_sub -h 10.0.0.8 -t "#" -v
homeassistant/sensor/68-3E-34-CC-DF-68/btrssi_mztest1_rssi/config {"unique_id": "bt-mqtt-gateway/68-3E-34-CC-DF-68/btrssi_mztest1_rssi", "name": "btrssi_mztest1_rssi", "state_topic": "rssi/mztest1/rssi", "device": {"identifiers": ["68:3E:34:CCF:68", "bt-mqtt-gateway/68-3E-34-CC-DF-68/btrssi_mztest1"], "manufacturer": "bluetooth", "model": "rssi", "name": "btrssi_mztest1"}, "unit_of_measurement": "dBm"}
light_mr_closet/tele/LWT 在线
tele/sonoff/LWT 在线
tele/home_power/LWT 离线
localtest/lwt_topic online
mzbtir/test1/temperature 59.4
mzbtir/test1/humidity 28.94
mzbtir/test1/battery 20
rssi/xiezhualan/stat ON
rssi/xiezhualan/rssi_level 4
rssi/xiezhualan/rssi -81
rssi/lvluo/stat OFF
rssi/lvluo/rssi_level -1
rssi/mztest1/stat ON
rssi/mztest1/rssi_level 2
rssi/mztest1/rssi -92
rssi/mith_mr/stat ON
rssi/mith_mr/rssi_level 4
rssi/mith_mr/rssi -73
好了,整体配置完成了,但是这个是我们手动启动的下面切换成系统服务。
注意:这个bt-mqtt-gateway.service里面配置了目录和启动命令,大家根据自己情况修改,很多人不是放到了opt下面,那启动命令也一起改。
cp bt-mqtt-gateway.service /etc/systemd/system/
# 开机自启动
systemctl enable bt-mqtt-gateway.service
# 启动服务,没有报错就是启动成功了
systemctl start bt-mqtt-gateway.service
# 查看服务状态
systemctl status bt-mqtt-gateway.service
● bt-mqtt-gateway.service - Bluetooth MQTT gateway
Loaded: loaded (/etc/systemd/system/bt-mqtt-gateway.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2019-08-22 22:02:52 CST; 32s ago
Docs: https://github.com/zewelor/bt-mqtt-gateway
Main PID: 21941 (python3)
Memory: 20.7M
CGroup: /system.slice/bt-mqtt-gateway.service
├─21941 python3 /opt/bt-mqtt-gateway/gateway.py
└─21949 /usr/local/lib/python3.7/dist-packages/bluepy/bluepy-helper 0
8月 22 22:03:11 raspberrypi gateway.py[21941]: 22:03:11 Starting
8月 22 22:03:15 raspberrypi gateway.py[21941]: 22:03:15 Adding 4 btrssi devices
8月 22 22:03:16 raspberrypi gateway.py[21941]: 22:03:16 Adding 2 miflora devices
8月 22 22:03:17 raspberrypi gateway.py[21941]: 22:03:17 Adding 1 mithermometer devices
8月 22 22:03:18 raspberrypi gateway.py[21941]: 22:03:18 Adding 1 mzbtir devices
8月 22 22:03:23 raspberrypi gateway.py[21941]: 22:03:23 Updating btrssi device 'xiezhualan' (C4:7C:8D:6B:0A:8C)
8月 22 22:03:23 raspberrypi gateway.py[21941]: 22:03:23 Updating btrssi device 'lvluo' (C4:7C:8D:6B:0B:E3)
8月 22 22:03:23 raspberrypi gateway.py[21941]: 22:03:23 Updating btrssi device 'mztest1' (68:3E:34:CCF:68)
8月 22 22:03:23 raspberrypi gateway.py[21941]: 22:03:23 Updating btrssi device 'mith_mr' (58:2D:34:34:A4:A7)
8月 22 22:03:23 raspberrypi gateway.py[21941]: 22:03:23 Updating 2 miflora devices
查看整个服务日志: tail -100f /var/log/syslog
因为这个是整个系统的日志,如果只看网关:tail -100f /var/log/syslog | grep gateway
hass
网关也配置好了,如果hass开着mqtt自动发现应该就能在未使用设备列表或者状态列表看到了。