20221219-HomeAssistant智能家居系统搭建指南

Home assistant 是一个成熟完整的基于python 的智能家居系统,设备支持度高,支持自动化 automation 群组化,ui 客制化等等高度定制化设置,背后又有庞大的社群基础,且不断更新,最重要的是我们可以通过homeassistant-homebridge 插件打通两个平台,同样实现设备的siri 控制,整套体系的框架如下

本系列将围绕安装,配置、开发等内容,详细介绍HASS 平台的方方面面,同时针对HASS 与hb 兼容与选择,自动化配置方法等等问题给出自己的观点和探索

HASS 支持大部分平台,简而言之,只要你的主机能跑python 基本就能安装hass 配合魔镜项目,以及便捷性的考虑,
本系列教程也将基于树莓派展开

初始安装

在树莓派安装HASS 有2种方法供选择

以其他操作系统,(这里以树莓派 官方系统 raspbian 为例) 为根系统,再通过指令安装

直接安装集成了HASS 的hassbian 操作系统

以上2种方法从性能上来说并无二异,均能实现hass全部功能,hassbian 实际上亦基于raspbian 唯一需要纳入考虑的是图形化操作界面的需求。由于树莓派基金官方尚未公开单独安装图形化操作界面的方法,在当下,如果有该需求,只能通过官方图形化操作系统 raspbian with desktop 实现

方法1
安装前,请参考 梓姵君文章 对树莓派进行初始基础设置,重点关注地区、WiFi、源替换的内容,这里不再展开,特别注意,2016年11月 后的官方系统默认关闭ssh 功能,请务必打开

使用任何方法连接到树莓派终端、输入以下安装代码

1
$ curl -O https://raw.GitHubusercontent.com/home-assistant/fabric-home-assistant/master/hass_rpi_installer.sh && sudo chown pi:pi hass_rpi_installer.sh && bash hass_rpi_installer.sh

注意,不要以sudo 运行,然后泡杯茶,做点别的事情,等待程序跑完,安装时间根据网络情况不等,大约需要1-2 个小时,国内网络环境大家自行改善

如果你是使用此方法安装hass 的话,未来更新指令如下

1
2
3
4
sudo su -s /bin/bash homeassistant
source /srv/homeassistant/homeassistant_venv/bin/activate
pip3 install --upgrade homeassistant
exit

方法2

参考 copriwolf 的

教程

使用 Etcher 安装官方最新

固件

镜像。

感谢少数派友 DJ 千辛万苦的搬运至度娘盘(password: 2e98)

要注意的是,hassbian 初次启动时需要联网进行原始设置,由于无法在初次启动前设置无限网络,因此务必将树莓派与电脑或者路由器有线连接起来,以保证树莓派在有网环境下顺利设置

官方教程告知初次启动需要等待5分钟左右,基于国内的网络环境,我这里测试多次,都需要等待近10分钟,所以大家不要焦躁,可以看部番剧或者往下研究一下此篇文章以便接下来顺利进展。

如果等待时间过久却没有出现初始界面,可尝试使用以下命令强制初始安装

1
2
sudo systemctl enable install_homeassistant.service
sudo systemctl start install_homeassistant.service

如果使用此方法,未来更新指令如下

1
2
3
4
5
6
$ sudo systemctl stop home-assistant@homeassistant.service
$ sudo su -s /bin/bash homeassistant
$ source /srv/homeassistant/bin/activate
$ pip3 install --upgrade homeassistant
$ exit
$ sudo systemctl start home-assistant@homeassistant.service

无论使用哪种方法,等待过后,在浏览器输入 http://树莓派的ip 地址:8123 查找树莓派ip 地址可以直接前往路由器界面

如果出现类似下图,则表示初始安装完成,如若没有出现界面,或者无法连接,有很大可能是尚未安装完毕,不要着急再等等,注意地址冒号为英文字符,请勿输入中文冒号

Hassbian 安装注意,初次启动请等待安装出现以下界面,再进行后续操作,否则你的一切工作都是前功尽弃,并且除此启动时,勿SSH ,勿输入任何代码,保持通电,联网,静置状态,非常重要

macOS

macos 自带python,如果你不小心误删,请先重新安装,macos 下安装hass 也相当简单

pip3 install homeassistant

附加功能

SMB 必须

SMB 可以帮助我们开启树莓派的网盘模式,方便未来文件传输,这里我们除安装外把该功能加入了系统自启项目

通用安装指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
sudo apt-get install samba 
sudo smbpasswd -a homeassistant -n
sudo nano /etc/samba/smb.conf
[global]
netbios name = raspberrypi
server string = The Pi File Center
workgroup = WORKGROUP
hosts allow =
remote announce =
remote browse sync =
[HOME ASSISTANT]
path = /home/homeassistant/.homeassistant
comment = No comment
browsable = yes
read only = no
valid users =
writable = yes
guest ok = yes
public = yes
create mask = 0777
directory mask = 0777
force user = homeassistant
force create mode = 0777
force directory mode = 0777
hosts allow =

Ctrl+X,Y,回车

1
sudo systemctl restart smbd.service

hassbian 提供了一个附加功能工具包hassbian-config 这使我们的安装更加简单,使用工具包安装原则上已经自动配置好一切,建议大家还是修改一下权限和密码

安装指令

1
2
sudo hassbian-config install samba
sudo smbpasswd -a pi

重启服务

1
sudo systemctl restart home-assistant@homeassistant.service

2.2 MQTT
MQTT 是基于二进制消息的发布,订阅编程模式的消息协议,广泛用于物联网部署中,部分智能家居设备需要MQTT 连接

通用安装指令

1
2
sudo apt-get install mosquitto mosquitto-clients python-mosquitto
sudo systemctl start mosquitto

hassbian 工具包安装

1
2
sudo hassbian-config install mosquitto
sudo systemctl start mosquitto
  1. Homebridge 安装
    HASS 本身可以通过网页控制,这也赋予了其全平台的控制能力,当然,想必不少人还是冲着语言控制功能考虑智能家居的,对于ios 用户来说,想要更自由地使用homekit HB依然是绕不开的环节

HB 的安装我就更不多说了,欢迎大家参考另外几篇文章,这里我根据之前指导派友的经验简单概括一下。

HB 提供一行安装指令:sudo npm install -g –unsafe-perm homebridge 但是安装成功率比较低,推荐大家使用下面的手动安装指令。

sudo apt-get install git make
sudo apt-get install g++
curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -
sudo apt-get install -y nodejs
sudo apt-get install libavahi-compat-libdnssd-dev
sudo npm install -g –unsafe-perm homebridge hap-nodejs node-gyp
cd /usr/local/lib/node_modules/homebridge/
(注意这里如果显示不存在文件夹,替换成 cd /usr/lib/node_modules/homebridge/)
sudo npm install –unsafe-perm bignum
cd /usr/local/lib/node_modules/hap-nodejs/node_modules/mdns
(注意这里如果显示不存在文件夹,替换成 cd /usr/lib/node_modules/hap-nodejs/node_modules/mdns)
sudo node-gyp BUILDTYPE=Release rebuild

运行到这里,HB就已经安装完成了,这里建议大家直接输入homebridge 运行一次,以生成示例配置文件,然后ctrl+C退出

接着,安装homeassistant-homebridge 插件,实现平台联动

sudo npm install -g homebridge-homeassistant

  1. 添加自启任务

忙活了那么久,即将大功告成了,最后临门一脚,我们把HASS和HB 添加至树莓派开机任务中,这样每次启动后就会自动运行上述2个进程

注意:配置 HB 前程序会运行错误,提示缺少配置文件,可先不理会。

cd /
sudo useradd –system homebridge
sudo mkdir /var/homebridge
sudo cp ~/.homebridge/config.json /var/homebridge/
sudo cp -r ~/.homebridge/persist /var/homebridge
sudo chmod -R 0777 /var/homebridge
cd /etc/default
sudo nano homebridge 复制粘贴

Defaults / Configuration options for homebridge

The following settings tells homebridge where to find the config.json file and where to persist the data (i.e. pairing and others)

HOMEBRIDGE_OPTS=-U /var/homebridge

If you uncomment the following line, homebridge will log more

You can display this via systemd’s journalctl: journalctl -f -u homebridge

DEBUG=*

Ctrl+X,Y,回车

cd /etc/systemd/system
sudo nano homebridge.service
复制粘贴

[Unit]
Description=Node.js HomeKit Server
After=syslog.target network-online.target
[Service]
Type=simple
User=homebridge
EnvironmentFile=/etc/default/homebridge
ExecStart=/usr/lib/node_modules/homebridge/bin/homebridge $HOMEBRIDGE_OPTS
Restart=on-failure
RestartSec=10
KillMode=process
[Install]
WantedBy=multi-user.target
Ctrl+X,Y,回车

cd /
sudo systemctl daemon-reload
sudo systemctl enable homebridge
sudo systemctl start homebridge
sudo systemctl status homebridge
sudo systemctl enable mosquitto

最后重启,sudo reboot

20221219-microPython是什么

microPython是什么

先了解一下,什么是python

python 是一种简单易用的,能够运行在多个平台下的计算机编程语言

microPython 是跑在mcu 微控制器上的python,通过内置的解释器执行py 文件或者py 命令,就可以让微控制器运行您想要的功能了,microPython 和python 编程语言一样,在任何板子上都可以使用通用的api 控制硬件底层,比如点亮LED 灯,读取传感器信息,LCD 显示字符串,控制电机、连接网络、连接蓝牙等等

如果说Arduino让创客摆脱了各种编程环境配置,那么micropython直接让创客摆脱了底层。命令行和解释执行,都是C语言所不具备的优势,运行micropython的soc,就类似一台完整的电脑,我们用python文件和命令行,轻松控制这台电脑中的一切。

micropython 是人们连接各种任务的黏合剂,即便您不懂编程,不懂硬件,也可以通过它来控制mcu 要给microPython

microPython诞生啦!

Damien George是一名计算机工程师,他每天都要使用Python语言工作,同时也在做一些机器人项目。有一天,他突然冒出了一个想法:能否用Python语言来控制单片机,进行实现对机器人的操控呢?

要知道,Python是一款比较容易上手的脚本语言,而且有强大的社区支持,一些非计算机专业领域的人都选它作为入门语言。遗憾的是,它不能实现一些非常底层的操控,所以在硬件领域并不起眼。

Damien为了突破这种限制,他花费了六个月的时间来打造Micro Python。它基于ANSI C,语法跟Pyton 3基本一致,拥有自家的解析器、编译器、虚拟机和类库等。目前它支持基于32-bit的ARM处理器,比如说pyboard(STM32F405),支持NRF51822(micro:bit)、支持FireBeetle-ESP32、支持WiPy、支持ESP8266核心主控、支持CC3200等等。

pyload 是microPython 官方出的一款支持microPython 的微控制器,采用stm32f405rg MCU主芯片,邮票孔设计,体积小巧
在性能方面,pyboard除了将stm32f405rg本身的外设延用出来,还拓展了微型SD卡插槽、三周加速度计(mma7660)。在小巧的pyboard上,设有29个GPIO,4个LED灯,板载3.3V LDO电源管理芯片,可以提供高达250mA的电流,3.6~16V的宽电压输入。

micro:bit

micro:bit是由英国广播公司BBC推出的可编程微型计算机,可以帮助用户学习基础编程知识。它最大的亮点在于支持图形化编程,支持microPython编程。micro:bit主控采用nrf51822芯片作为主控,IC包括256KB片上闪存,16KB RAM,32位ARM®Cortex™ M0 CPU,支持Bluetooth低功耗,在低功耗模式下,最低功耗可以达到0.6uA。

FireBeetle-ESP32

FireBeetle-ESP32全称是FireBeetle Board-ESP32微控制器,是由DFRobot基于Espressif ESP32主芯片开发的物联网、低功耗为控制器。FireBeetle-ESP32板载ESP-WROOM-32双核芯片,支持WiFi和蓝牙双模通信,外围兼容低功耗硬件设计,深度睡眠模式下功耗仅为10uA。FireBeetle-ESP32控制器还提供了3.7V锂电池接口,并可以通过USB口给锂电池充电。其次,在软件方面,已经支持WiFi和蓝牙功能的使用,支持I2S音频的解码,结合uPyCraft IDE,可以轻松完成物联网开发设计。值得说明的是,本书的microPython教程是基于FireBeetle-ESP32控制器硬件。

WiPy

WiPy是支持microPython编程、支持WiFi和蓝牙的开发板,定位于物联网应用的设计。WiPy控制器的核心采用Espressif ESP32芯片,其最大的特点在于体积小巧,支持蓝牙和WiFi,这点和DFRobot的FireBeetle萤火虫系列主板相似。

20221219-固件firmware固件与驱动的区别

https://www.jianshu.com/p/0222686c0fb4

固件 firmware 就是写入EROM 可擦写只读存储器,或者EEPROM 电可擦写可编程只读存储器中的程序

固件是指设备内部保存的设备驱动程序,通过固件,操作系统才能按照标准的设备驱动实现特定机器的运行运作,比如 光驱、刻录机 等都有内部固件

固件是担任着一个系统最基础最底层工作的软件,而在硬件设备中,固件就是硬件设备的灵魂,因为一些硬件设备除了固件以外没有其他软件组成,因此固件也就决定了这硬件设备的功能以及性能

手机、数码相机、mp3、mp4、路由器、电子书、交换机、猫、PSP、PS3、NDS、XBOX、U盘、主板、打印机的BIOS(BIOS就是一种固件)、显卡的BIOS。

固件既然是软件,就有大小之分,大的可有几百兆,小的也许只有几K 甚至不足1k

而对于非独立的电子产品,比如硬盘、鼠标 bios 光驱、是、盘等设备,固件就是指其最底层的,让设备得以运行的程序代码

固件与驱动的区别

驱动和固件都是代码,前者为软件服务,后者为硬件服务

随着计算机体系结构的发展,硬件的种类开始变多,操作系统的种类也变多了,这个时候,因为各种技术的、商业的原因,硬件厂商希望自己的硬件能被更多的软件厂商使用,所以就需要在硬件之上做一些封装,让自己的硬件操纵起来更容易,这个时候就要有 firmware 这种东西了,它简化了软件与硬件的交互

但是为什么不把firmware 做的很完美,做的不需要驱动支持呢?因为有不同的操作系统

不同的操作系统,对于操作硬件的方式完全不同,在windows 里应用态是无法直接写io 端口的,而在嵌入式系统里,一般都不限制直接操作io 端口,所以,硬件厂商一方面为了自己的硬件能被软件更简单的使用,就需要写firmware ,而另一方面为了兼容各种操作系统,又不能把firmware 写的太死,必须预留足够的余地让软件自由发挥,软件的自由发挥就是驱动

不同操作系统的驱动是不能兼容的,原因就是驱动是为操作系统服务的,有的操作系统是单线程的,有些操作系统不允许动态申请内存,所以不同的操作系统要操作硬件,就要根据自身的特性编写对应的操作代码,这就是驱动存在的意义–适应系统需要

假如世界上只有一种操作系统,并且版本永远不会改变,那么firmware 和驱动就可以融合在一起,但这只能是一个不现实的梦想,要知道民用操作系统和工业控制操作系统差别是十分巨大的

从计算机领域来说,驱动和固件从来没有过明确的定义,就好像今天我们说内存,大部分人用来表示SDRAM 但也有人把android 里的固化的flash storage 称为内存,你不能说这样说就错了,因为这确实是一种内部存储

但在linux kernel 中,driver 和firmware 是有明确含义的,其中 driver 是控制被操作系统管理的外部设备 device 的代码段,很多时候 driver 会被实现为LKM 但这不是必要条件,driver 通过 register_driver 注册到总线上,当某个device 被注册到同样的总线的时候,driver 和device 会通过一定的策略进行binding ,最终在probe 函数中由driver 实际控制对应的设备,并把对该设备的控制接口注册到linux 的其他子系统上

而 firmware,是表示运行在非 控制处理器 (指不直接运行操作系统的处理器,例如外设中的处理器,或者被用于bare metal 的主处理器的其中一些核) 中的程序,这些程序很多时候使用和操作所运行的处理器完全不同的指令集,这些程序以二进制形式存在于linux内核的源代码树中,根据配置,可以直接集成到最终的映像中,或者被拷贝到指定的位置,当driver 对device 进行初始化的时候,通过load_firmware 等接口,可以把指定的firmware 加载到内存中,由驱动传输到指定的设备上

所以,总的来说,其实 driver 和firmware 没有什么直接的关系

20221218-MQTT入门介绍

MQTT 消息对流遥测传输协议,是一种基于发布/订阅 模式的轻量级 通讯协议,该协议构建于TCP/IP 协议上,由IBM在1999年发布,MQTT 最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务,作为一种低开销、低带宽的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用

MQTT 是一个基于客户端-服务器的消息发布/订阅传输协议,MQTT 协议是轻量、简单、开放和易于实现的,这些特点使它适用范围非常广泛,在很多情况下,如机器与机器 M2M 通信和物联网 IoT ,其在,通过卫星链路通信传感器、偶尔拨号的医疗设备、智能家居 、及一些小型化设备中已广泛使用

二、设计规范

由于物联网的环境是非常特别的,所以MQTT 遵循以下设计原则

精简 不添加可有可无的功能

发布/订阅 模式 方便消息在传感器之间传递

允许用户动态创建主题,零运维成本

把传输量降到最低以提高传输效率

把低带宽、高延迟、不稳定的网络等因素考虑在内

支持连续的会话控制

理解客户端计算能力可能很低

提供服务质量管理

假设数据不可知,不强求传输数据的类型与格式,保持灵活性

三、主要特性

MQTT 协议工作在低带宽、不可靠的网络的远程传感器和控制设备通讯而设计的,它具有以下主要的几项特性

使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合

这一点很类似于XMPP ,但是MQTT 的信息冗余远小于XMPP ,因为XMPP 使用XML 格式文本来传递数据

对负载内容屏蔽的消息传输

使用TCP/IP 提供网络连接

主流的MQTT 是基于TCP 连接进行数据推送的,但是同样有基于UDP 的版本,叫做MQTT-SN。这两种版本由于基于不同的连接方式,优缺点自然也就各有不同了

有三种消息发布服务质量

“至多一次”,消息发布完全依赖底层TCP/IP网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。这一种方式主要普通APP的推送,倘若你的智能设备在消息推送时未联网,推送过去没收到,再次联网也就收不到了。

至少一次,确保消息到达,但消息重复可能会发生

只有一次,确保消息到达一次,在一些要求比较严格的计费系统中,可以使用此级别,在计费系统中,消息重复或丢失会导致不正确的结果,这种最高质量的消息发布服务还可以用于即时通讯类的app 的推送,确保用户收到且只会收到一次

小型传输,开销很小,固定长度的头部是2字节 协议交换最小化,以降低网络流量

这就是为什么在介绍里说它非常适合 在物联网领域,传感器与服务器的通信,信息的收集,要知道嵌入式设备的运算能力和带宽都相对薄弱,使用这种协议来传递消息再适合不过了

使用last will 和testament 特性通知有关各方客户端异常中断的机制

last will 即遗言机制,用于通知同一主题下的其他设备发送遗言的设备已经断开了连接

testament 遗嘱机制,功能类似于last will

四、MQTT 协议原理
MQTT 协议实现方式

实现MQTT 协议需要客户端和服务端通讯完成,在通讯过程中,MQTT 协议中有三种身份,发布者,代理(服务器),订阅者。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者
MQTT 传输的消息分为 主题topic 和负载 payload 两部分

topic 可以理解为消息的类型,订阅者 subscribe 后,就会收到该主题的消息内容 payload
payload 可以理解为消息的内容,是指订阅者具体要使用的内容

网络传输与应用消息

MQTT 会构建底层网络传输,它将建立客户端到服务器的连接,提供两者之间的一个有序的、无损的、基于字节流的双向传输。当应用数据通过MQTT 网络发送时,MQTT 会把与之相关的服务质量 QoS 和主题名topic 相关联

MQTT 客户端

一个使用MQTT 协议的应用程序或者设备,它总是建立到服务器的网络连接,客户端可以

发布其他客户端可能会订阅的信息

订阅其他客户端发布的消息

退订或删除应用程序的消息

断开与服务器连接

MQTT 服务器
MQTT 服务器以称为消息代理,可以是一个应用程序或一台设备,它是位于消息发布者和订阅者之间,它可以

接受来自客户的网络连接

接受客户发布的应用信息

处理来自客户端的订阅和退订请求

向订阅的客户转发应用程序消息

MQTT 协议中的订阅、主题、会话

订阅
订阅包含主题筛选器和最大服务质量,订阅会与一个会话关联,一个会话可以包含多个订阅,每一个会话中的每个订阅都有一个不同的主题筛选器

会话
每个客户端与服务器建立连接后就是一个会话,客户端和服务器之间有状态交互,会话存在于一个网络之间,也可能在客户端和服务器之间跨越多个连续的网络连接

主题名

连接到一个应用程序消息的标签,该标签与服务器的订阅相匹配,服务器会将消息发送给订阅所匹配标签的每个客户端

主题筛选器

一个对主题名通配符筛选器,在订阅表达式中使用,表示订阅所匹配到的多个主题

负载

消息订阅者所具体接收的内容

MQTT 协议中的方法

MQTT 协议中定义了一些方法,也被称为动作,来于表示对确定资源所进行操作,这个资源可以代表预先存在的数据或动态生成数据,这取决于服务器的实现,通常来说,资源指服务器上的文件或输出,主要方法有

connect 等待与服务器建立连接

Disconnect 等待MQTT 客户端完成所做的工作,并与服务器断开TCP/IP 会话

subscribe 等待完成订阅

unsubscribe 等待服务器取消客户端的一个或多个topics 订阅

publish MQTT 客户端发送消息请求,发送完成后返回应用程序线程

五、MQTT 协议数据包结构

在MQTT 协议中,一个MQTT 数据包由 固定头 可变头,消息体 三部分构成,MQTT 数据包结构如下

固定头(fixed header) 存在于所有MQTT 数据包中,表示数据包类型及数据包的分组类标识

可变头(variable header) 存在于部分MQTT数据包中,数据包类型决定了可变头是否存在及其具体内容

消息体 (payload) 存在于部分MQTT数据包中,表示客户端收到的具体内容

MQTT 固定头

固定头存在于所有MQTT 数据包中,其结构如下

MQTT 数据包类型

位置 byte 1 中bits 7-4
相于一个4位的无符号值,类型,取值及描述如下

标识位

位置:Byte 1中bits 3-0。

在不使用标识位的消息类型中,标识位被作为保留位。如果收到无效的标志时,接收端必须关闭网络连接:

(1)DUP:发布消息的副本。用来在保证消息的可靠传输,如果设置为1,则在下面的变长中增加MessageId,并且需要回复确认,以保证消息传输完成,但不能用于检测消息重复发送。

(2)QoS:发布消息的服务质量,即:保证消息传递的次数

RETAIN 发布保留标识,表示服务器要保留这次推送的信息,如果有新的订阅者出现,就报这消息推送给它,如果没有那么推送至当前订阅者后释放

剩余长度

地址Byte 2

固定头的第二字节用来保存变长头部和消息体的总大小的,但不是直接保存的,这一字节是可以扩展,其保存机制,前7位用于保存长度,后一部用做标识,当最后一位为1时,表示长度不足,需要使用二个字节继续保存。例如:计算出后面的大小为0

MQTT 可变头

MQTT 数据包中包含一个可变头,它驻位于固定的头和负载之间,可变头的内容因数据包类型而不同,较常的应用是作为包的标识。
很多类型数据包中都包括一个2字节的数据包标识字段,这些类型的包有:PUBLISH (QoS > 0)、PUBACK、PUBREC、PUBREL、PUBCOMP、SUBSCRIBE、SUBACK、UNSUBSCRIBE、UNSUBACK。

Payload 消息体

Payload 消息体位MQTT 数据包的第三部分,包含connect subscribe suback unsubscribe 四种类型的消息

connect 消息体内容主要是 客户端的clientID 订阅的topic message 以及用户名和密码

subscribe 消息体内容是一系列的要订阅的主题以及QoS

suback 消息体内容是服务器对于subscribe 所申请的主题及QoS 进行确认和回复

unsubscribe 消息体内容是要订阅的主题

20221217-电子电路元器件列表

1 科创大赛启发

(1)围棋棋子筛选

TCS3200颜色传感器

(2)语音识别模块

WEGASUN-M6

(3)图形化语言编程

机械控制部分采用Micro-BIT单片机模块

(4)无线六路开关量模块

L24YK

(5)RDWORKS平面设计软件

(6)Arduino开发板

(7)温度传感器

DT11、DS18B20

(8)红外对管传感器

(9)实时时钟模块

DS1320

(10)加速度传感器

(11)Android 手机APP编写

Android Studio 3.5平台、Android SDK、Eclipse、Jave

(12)物联网无线网络遥控

ESP8266

(13)气体传感器

Q2

(14)陀螺仪

(15)光敏传感器

(16)单片机

STC51、STM32、MSP430F149

(17)放大器放大电流

LM324

(18)图像处理

Open CV软件

(19)霍尔开关

(20)图像处理

(21)无线遥控装置

433MHZ

(22)人体红外线感应传感器

PIR

(23)Android小程序

(24)Robot C编程

2 开发过程中用到的元器件

(1)USB转串口芯片CH340G

20221217-低功耗蓝牙BLE学习笔记

http://doc.iotxx.com/BLE%E6%8A%80%E6%9C%AF%E6%8F%AD%E7%A7%98

蓝牙4.0 版本分两种模式,单模蓝牙 和双模蓝牙

常见的蓝牙音箱,是典型的双模蓝牙,它需要传输大量的音频数据,而小米手环,蓝牙温度计则属于单模蓝牙,行业里一般不讲单模蓝牙,而是统一称为低功耗蓝牙

蓝牙5.0 已经发布和应用,4倍通信速度,2倍的通信距离以及Mesh 组网特性,将使蓝牙成为物联网领域的重要的技术之一

  1. 蓝牙简介

蓝牙是一种近距离无线通信技术,运行在2.4GHz免费频段,目前已大量应用于各种移动终端,物联网,健康医疗,智能家居等行业。蓝牙4.0以后的版本分为两种模式,单模蓝牙和双模蓝牙。

单模蓝牙 即低功耗蓝牙模式,是蓝牙4.0 中的重点技术,低功耗,块连接,长距离

双模蓝牙,支持低功耗蓝牙的同时还兼容经典蓝牙,经典蓝牙的特点是大数据高速率,例如音频、视频等数据传输。

经典蓝牙支持音频(HFP/HSP, A2DP)和数据(SPP, HID等)两大类协议,在音箱,耳机,汽车电子及传统数传行业,由于苹果对经典蓝牙数据传输接口有限制(需要过MFI认证),加上功耗偏大,因此在目前移动互联应用中慢慢地被边缘化。因此低功耗蓝牙顺势而出,由于可支持苹果4S以上及安卓4.3系统以上的数据传输,且功耗极低,目前正在被越来越多的移动互联设备所采用,但低功耗蓝牙不支持音频协议,并且受数据传输速度限制,其应用也被限制在小数据传输行业。

蓝牙双模则是综合了两者的优缺点,既可以支持音频传输,同样可支持数据传输,并且兼容性也是两者之和,在对功耗要求不苛刻的情况下,是比较理想的选择

2 BLE特点

低功耗蓝牙瞄准多个市场,特别是移动智能终端,智能家居,互联设备等领域,主要特点包括

低功耗
快连接
远距离

为低功耗蓝牙定义了一些标准Profile ,Profile 理解为数据规范,只要遵守该规范,任意厂家的蓝牙设备,均可以相互连接与通信,例如无线蓝牙键盘鼠标,无论是安卓或是iOS还是Windows,均是即插即用,这便是“标准”的力量。低功耗蓝牙支持的标准Profile有:

HID 用于无线鼠标,键盘或其他遥控设备

BatteryServices 电池状态服务,用于告知电池电量状态

HRP 心率计,Profile 用于心率 采集,等等

另外,低功耗蓝牙还可以自定义Profile ,伴随着智能手机的发展和普及,低功耗蓝牙的这个特性得到了发扬光大,同时也拓宽了低功耗蓝牙的应用领域。例如,可以自定义一个开关量的Profile,数据01表示开灯,数据00表示关灯,然后手机发送数据01和00就可以控制灯的亮和灭。类似的应用案例有很多,下面总结应用特点

支持自定义Profile ,可以收发任意格式的数据,如01 和 00
支持自定义设备,支持任意设备的连接和通信,例如 只能蓝牙插座等等

提示:低功耗蓝牙的Profile均基于GATT(通用属性规范,后面会详解)之上,如HID over GATT。也就是说,经典蓝牙中的HID规范与低功耗蓝牙中的HID规范用的是两个不同的通道。

BLE 工作流程
为后面的低功耗蓝牙协议的学习准备基础

角色

BLE 设备角色主要分为两种角色,主机和从机,,当主机和从机建立连接之后才能相互收发数据

主机,主机可以发起对从机的扫描连接,例如手机,通常作为BLE 的主机设备

从机,从机只能广播并等待主机的连接,例如智能手环,是作为BLE 的从机设备

另外还有观察者和广播者,这两种角色不常使用,但也十分有用,例如iBeacon 就可以使用广播者 角色来做,只需要广播特定内容即可

观察者,观察者角色监听空中的广播事件,和主机的区别是不能发起连接,只能持续扫描从机

广播者 广播者可以持续广播信息,和从机的唯一区别是不能被主机连接,只能广播数据

蓝牙协议栈没呀限制设备的角色范围,同一个BLE 设备,可以作为主机,也可以作为从机,我们称之为主从一体,主从一体的好处是,每个BLE 设备都是对等的,可以发起连接,也可以被别人连接,更加实用

广播

广播是指从机没经过一个时间间隔发送一次广播数据包,这个时间间隔称为广播间隔,这个广播动作叫做广播事件,只有当从机处于广播状态时,主机从能发现该从机

在每个广播事件中,广播包会分别在37 38 和 39 三个信道上依次广播,如下所示

广播时间间隔的范围是从20ms到10.24s,广播间隔影响建立连接的时间。广播间隔越大,连接的时间越长。

另外BLE 链路层会在两个广播事件之间添加0-10 ms 的随机演示,保证多个设备广播时,不会一直碰撞广播,也就是说,设置100ms 的广播间隔,实际上两次广播事件的时间间隔可能是100-110 ms 之间的任意时间

广播数据包最多能携带31个字节的数据,一般包含可读的设备名称,设备是否可连接等信息

当主机收到从机广播的数据包后,它可以再发送获取更多数据包的请求,这个时候从机将广播 扫描回应 数据包,扫描回应数据包和广播包一样,可以携带31个字节的数据

提示:蓝牙4.x,广播有效载荷最多是31个字节。而在蓝牙5.0中,通过添加额外的广播信道和新的广播PDU,将有效载荷增加到了255个字节

  1. 扫描

扫描是主机监听从机广播数据包和发送扫描请求的过程,主机通过扫描,可以获取到从机的广播包以及扫描回应数据包,主机可以对已扫描到的从机设备发起连接请求,从而连接从机设备并通信

扫描动作由两个比较重要的时间参数,扫描窗口 和扫描间隔,如果扫描窗口等于扫描间隔,那么主机将一直处于扫描状态中,持续监听从机广播包

被动扫描,主机监听广播信道的数据,当接收到广播包时,协议栈将向上层 也就是应用层,用户可编程 传递广播包

主动扫描,主动扫描除了完成被动扫描的动作外,还会向从机发送一个扫描请求,从机收到该请求时,会再次发送一个称作 扫描回应 的广播包

主动扫描比被动扫描,可以多收到扫描回应数据包

连接

在BLE 连接中,使用调频方案,两个设备在特定时间、特定频道上彼此发送和接收数据,这些设备稍后在新的通道(协议栈的链路层处理通道切换)上通过这个约定的时间相遇,这次用于收发数据的相遇称为连接事件,如果没有有发送或接收的应用数据,则交换链路层数据来维护连接,两个连接事件之间的时间跨度称为连接间隔,是以1.25ms 为单位,范围从最小值 7.5 ms 到最大值 4.0s

连接参数

Connection Interval 连接间隔,两次连接事件之间的时间间隔称为连接间隔,1.25ms 为单位,范围从最小值 7.5 ms 到最大值 4.0s

slave latency 从机延迟,如果从机没有要发送的数据,则可以跳过连接事件,继续保持睡眠节省电量

supervision Time-out 监控超时,是两次成功连接事件之间的最长时间,如果在此时间内没有成功的连接事件,设备将终止连接并返回到未连接状态,该参数值以10ms 为单位,监控超时值可以从最小值10 到3200 超时必须大于有效的连接间隔

连接参数更新请求

连接参数由主机发起连接的时候提供,如果从机对连接参数有自己的要求,例如要求更低的功耗,或者更高的通信速率等,从机可以向主机发送连接参数更新请求

从机可以在连接后的任何时候发起连接参数更新请求,但最好不要在主从建立连接后like发起,建议延迟5s 左右再发送请求

连接参数更新请求可以修改:Connection Interval连接间隔,Slave Latency从机延迟,Supervision Time-out监控超时。

有效连接间隔

effective connection interval 有效连接间隔等于两个连接事件之间的时间跨度,假设从机跳过最大数量的连接事件,且允许从机延迟,

从机延迟表示可以跳过的最大事件数。该数字的范围可以从最小值0(意味着不能跳过连接事件)到最大值499。最大值不能使有效连接间隔(见下列公式)大于16秒。间隔可以使用以下公式计算:

Effective Connection Interval = (Connection Interval) × (1 + [Slave Latency])

Consider the following example:

Connection Interval: 80 (100 ms)
Slave Latency: 4
Effective Connection Interval: (100 ms) × (1 + 4) = 500 ms

当没有数据从从机发送到主机时,从机每500ms 一个连接事件交互一次

ios 对连接参数的要求
不同的平台对有连接间隔有着不同的要求,例如ios 系统对ble 的连接间隔有着如下的要求

Interval Max * (Slave Latency + 1) <=2s
Interval Min >=20ms
Interval Min + 20 ms <= Interval Max
Slave Latency <= 4
SupervisionTimeout <= 6 s
Interval Max * ( Slave Latency + 1) * 3 < SupervisionTimeout

连接参数的优化考量

在许多应用中,从机跳过最大连接事件数,选择正确的连接参数组在低功耗蓝牙设备的功率优化中起重要作用,以下列表给出了连接参数设置中权衡的总体概述

减少连接间隔如下

增加两个设备的功耗
增加双向吞吐量
减少任一方向发送数据的时间

增加连接间隔如下
降低两个设备的功耗
降低双向吞吐量
增加任一方向发送数据的时间

减少从机延迟 或将其设置为零 如下
增加外围设备的功耗
减少外围设备接收从中央设备发送的数据的时间

增加从机延迟如下
在周边没有数据发送期间,可以降低外设的功耗到主机设备
增加外设设备接收从机设备发送的数据的时间

通信

通俗的说,我们将从机具有的数据或者属性特征,称之为profile 可以翻译为配置文件

从机中添加profile 配置文件,作为GATT 的server 端,主机作为GATT 的client 端

profile 包含一个或者多个service 每个service 又包含一个或者多个characteristic 主机可以发现和获取从机的service 和characteristic 然后与之通信,characteristic 是主从通信的最小单元

主机可主动向从机write 写入或read 读取数据

从机可主动向主机notify 通知数据

注意,这里引用了服务 service 和特征值 characteristic 的概念,每个服务和特征值都有自己的唯一标识uuid 标准UUID 为128位,蓝牙协议栈中一般采用16位,也就是两个字节的UUID 格式

一个从机设备包括一个或者多个服务,一个服务中又可以包括一条或者多条特征值,每个特征值都有自己的属性 property 属性的取值有 可读 read 可写 write 以及通知 notify

可读可写的字面意思容易理解,表示该特征值可以被主机读取和写入数据

而通知则表示从机可以主动向主机发送通知数据,这便是主从机之间两个典型的通信方式

下图是一个典型的从机设备,该从机包含有一个profile 两个service 和五个characteristic 我们先来介绍这些特征值的作用,然后介绍如何通过特征值通信

服务0x180A

180A 是蓝牙协议里标准的服务uuid,用来描述设备信息device information,可以通过该服务,来提供从机设备的相关说明,例如硬件版本,软件版本,序列号等信息,这样,主机就可以获取从机的设备信息,上图中我们添加了三个提供具体设备信息的特征值,他们分别是

特征值0x2A24,描述产品型号 Model Number String,例如某智能锁的产品型号为:“DSL-C07”。
特征值0x2A25,描述产品序列号 Serial Number String,例如某智能锁的产品序列号为:“lkjl0016190502500269”
特征值0x2A26,描述产品固件版本号 Firmaware Revision String,例如某智能锁的固件号为:“2.7.2.0”

上述特征值仅有read 属性,因此主机只能读,不能执行写操作

服务0xfff0

FFF0 是我们自定义的服务uuid,它包含两个特征值,用来发送和接收数据

特征值0xfff1 自定义的数据发送通道,具有read 和write 属性,主机可以通过该特征值,向从机发送数据,至于发送的数据的最大长度,可以在profile 中配置
特征值0xfff2 ,自定义的数据接收通道,具有notify 属性,从机可以通过该特征值,主动向主机发送数据

假设主机写特征值的协议栈函数原型为 int GATT_WriteCharValue(uuid_t UUID, uint8 *pValue, uint8 len)

假设从机发送通知的协议栈函数原型为 int GATT_Notification(uuid_t UUID, uint8 *pValue, uint8 len)

那么主机向从机发送Hello,可以这样调用协议栈的函数:GATT_WriteCharValue(0xFFF1,”Hello”,5)

那么从机向主机发送1234,可以这样调用协议栈的函数:GATT_Notification(0xFFF2,”1234”,4)

断开

主机或从机都可以发起断开连接请求,对方会收到该请求,然后断开连接恢复连接前的状态

过程演示

现在我们总结一下BLE 的工作流程,使用两个虚拟的ble 硬件来模拟主从机的交互过程

假设有两个ble 设备,使用的是BLE261 低功耗蓝牙模块,假设已经下载了用于交互演示的功能固件,一个是主机,名称为blecentral ,另一个是从机,名称为bleperipheral,如下图所示

步骤1 上电初始化

主机,从机上电后 不分先后顺序,首先进行协议栈初始化和相关功能调用,如下图所示

主机设备,主机初始化时,需要设置设备类型,设置用于扫描的相关参数,初始化 gatt 等协议相关的参数
从机设备,从机初始化时,需要设置设备名称,广播相关参数,从机profile,等,从机一般会立即开启广播,也可以等待一个事件来触发广播,例如按键触发

步骤二 主机扫描从机

按键按下,触发主机扫描从机,此时,主机显示屏打印scanning 正在扫描,此刻的从机仍然处于广播状态

步骤三 发现从机设备

当主机扫描到从机时,可以返回已扫描到的从机相关信息,例如可以提取到下图中的从机设备名称,从机mac 地址,从机的RSSI 信号值等数据,因此,有些应用在从机的广播包或者扫描回应包中添加自定义字段,这样就可以被主机通过扫描的方式拿到数据

步骤四 发送连接请求
当主机扫描到从机后,通过mac 地址向从机发送连接请求,低功耗蓝牙的连接速度非常快,10ms 左右即可成功连接上,如果从机的广播比较大,则会影响连接的速度

从机在未收到连接请求之前仍然处于自由的广播状态

步骤五 成功连接从机

当从机收到连接请求后,双方成功建立连接,此时双方的状态均变为已连接状态

然后主机可以调用协议栈提供的接口函数来获取从机的服务

步骤6 获取从机服务

获取从机服务通常是在连接成功后就立即执行的,因为只有获取从机的服务后,从能与其通信,下图是主机想从机发送获取服务的请求

此刻,从机处于已连接状态,响应服务获取请求是在底层自动完成的,上层无需理会

步骤7 成功获取服务

如下图所示,主机成功获取到从机的服务,例如获取到UUID 为0xfff0的services 该service 有两个特征值,分别是具有读写属性的0xfff1 ,以及具有通知属性的0xfff2

读写属性是指主机可以读写该特征值的内容,而通知属性是指从机可以通过该特征值向主机发送数据

步骤8 主机向从机发送数据

主机通过特征值0xfff1 主动向从机发送自定义数据hello ,当数据成功发送后,主机状态变为:数据已发送,从机将收到主机发来的数据,从机状态变为收到数据

步骤9 从机向主机发送数据

从机可以通过norify 的方式主动向主机发送数据,例如下图,从机通过特征值0xfff2 发送了一条 notify 通知,数据内筒为1234

步骤10 发送断开请求

主机和从机任何一方均可以发起断开连接的请求,对方收到后,状态将变为已断开

步骤11 成功断开连接

从机收到主机发来的断开请求,此刻状态变为已断开

4 BLE 协议栈

BLE 协议栈一般是指芯片厂家,以及Bluetooth SIG 发布的Bluetooth core specification 核心协议的实现的代码固件,并提供函数接口,有芯片内部程序调用,可实现上节BLE 工作流程等相关功能

常见的协议栈有 德州仪器 TI 的ble-stack 和nordic 的softdevice

功能框图

在本节中,我们列举两家典型的蓝牙芯片厂家,TI 和noridc 来深入了解低功耗蓝牙协议栈

下图是TI的CC26系列芯片协议栈结构图,

下图是Nordic的nRF52系列芯片的协议栈结构图。

协议栈结构

从上节的两张协议栈功能框图中可以看出,无论是哪个芯片厂商实现的ble 协议栈,其结构都非常的相似,均三个部分

底层 controller
中层 host
顶层 application

然后每一层又分成若干个子模块,我们现在由下而上,逐层介绍

我们将位于顶层的应用层application 也归到协议栈中描述,其实,应用层application 不属于协议栈,它是用来调用协议栈提供的接口,然后实现蓝牙的功能

控制器 controller

physical layer 简称 PHY,物理层,PHY层用来指定BLE 所用的无线频段,调制解调方式和方法等,phy 层做得好不好,直接决定整个ble 芯片的功耗,灵敏度以及selectivity 等频射指标

link layer 简称 LL,链路层,ll层是整个ble 协议栈的核心,也是ble 协议栈的难点和重点,像nordic 的ble 协议栈能同时支持20个link 连接,就是ll 层的功劳,ll 层要做的事情非常多,比如具体选择哪个射频通道进行通信,怎么识别空中数据包,具体在哪个时间点把数据包发送出去,怎么保证数据的完整性,ACK 如何接收,如何进行重传,以及如何对链路进行管理和控制等等,LL层只负责把数据发出去或者收回来,对数据进行怎样的解析则交给上面的GAP 或者ATT

host controller interface 简称 HCI,协议栈应用开发中,我们会经常看到HCI 的身影,它对上host 提供controller 的功能接口,所以称作 host controller interface

主控Host

Logical link control adaptation protocol 简称 L2CAP L2CAP 对LL 进行了一次简单封装,LL 只关心传输的数据本身,L2CAP 就要区分加密通道还是普通通道,同时还要对连接间隔进行管理

Attribute Protocol 简称ATT ATT 层用来定义用户命令及命令操作的数据,比如读取某个数据或者写某个数据,BLE 协议栈中,开发者接触最多的就是ATT。BLE 引入了attribute 共年,用来描述一条一条的数据,attribute 除了定义数据,同时定义该数据可以使用的att 命令,因此这一层被称为ATT 层

Security Manager 简称SM SMP 用来管理BLE 连接的加密和安全的,如何保证连接的安全性,同时不影响用户的体验,这些都是SMP要考虑的工作

Generic Access Profile 简称GAP GAP 是对LL 层payload 有效数据包 如何进行解析的两种方式中的一种,而且是最简单的那一种,GAP 简单的对LL payload 进行一些规范和定义,因此gap 能实现的功能极其有限,GAP 目前主要用来进行广播,扫描和发起连接等

Generic Attribute Profile 简称GATT
GATT 用来规范attribute 中的数据内容,并运用group 分组的概念对attribute 进行分类管理,没有GATT BLE 协议栈也能跑,但互联互通就会出现问题,也正是因为有了GATT 和各种各样的应用Profile,BLE 摆脱了zigbee等无线协议的兼容性困境,成了出货量最大的2.4G 无线通信产品

应用application

应用层是用户开发实际蓝牙应用的地方,包含必要的协议栈参数设置,以及各种功能函数的调用,我们分别从蓝牙从机和蓝牙主机两种设备来分析

蓝牙从机

相关硬件和基础服务初始化

设置广播参数,广播数据,广播间隔,扫描回应等参数或者数据

设置profile 添加从机服务,特征是,还有设置回调函数用于接收主机数据等
设置绑定管理参数 可选

启动广播,开始运行

等待相关事件,及事件处理,例如收到主机发来的数据,被链接等

蓝牙主机

相关硬件和基础服务初始化

设置扫描参数

设置连接参数

设置绑定管理参数 可选

启动协议栈,开始运行

等待相关事件,及事件处理,例如扫描事件,从机的notify 事件等

  1. GAP 和GATT

蓝牙协议分为两类结构,控制器 和主机,每个类别都有子类别,这些子类别执行特定的角色,我们将要研究的两个子类别是,通用访问配置文件 GAP 和通用属性配置文件 GATT

GAP是Generic Access Profile的缩写,中文含义是:通用访问配置文件。
GATT是Generic Attribute Profile的缩写,中文含义是:通用属性配置文件。

5.1 GAP 和gatt 区别

区分GAP 和gatt 很重要

GAP 定义了BLE 网络堆栈的一般拓扑

GATT 详细描述了一旦设备建立连接后如何传输属性数据

GATT 特别关注如何根据其描述的规则格式化打包和发送数据,在BLE 网络堆栈中,属性协议,ATT 与GATT 紧密对齐,GATT 直接位于ATT 的顶部,GATT
实际上使用ATT 来描述如何从两个连接的设备交换数据

通用访问配置文件 GAP

BLE 设备可以使用两种机制与外界通信,广播或连接,这些机制受通用访问配置文件 GAP 准则的约束,GAP 定义了启用BLE 的设备如何使其自身可用,以及两个设备如何直接相互通信

建立联系

设备可以通过采用 GAP 中指定的以下角色来加入BLE 网络

A、广播(Broadcasting):这些角色不必显式地相互连接即可传输数据。

广播者(Broadcaster):广播公共数据包的设备,例如可以广播按下按钮的时间。
观察者(Observer):侦听广播者发送的广告包中数据的设备。广播者和观察者之间没有任何连接。/2、/2
B、连接(Connecting):这些角色必须显式连接和握手才能传输数据。这些角色比广播角色更常用。

从机设备(Peripheral): 通过广播,告知其他设备自己的存在,以便主机设备可以建立连接。连接后,从机设备不再向其他主机设备广播数据,而是保持与主机设备的连接。
从机设备功耗低,因为它们只需要定期发送信标即可。主机设备负责开始与从机设备的通信。
手环是BLE外设的一个示例。
主机设备(Central):一种通过侦听广播包来启动与从机设备的连接的设备。主机设备可以连接到许多其他从机设备。
当主机设备要连接时,它将请求连接数据包发送到从机设备。如果从机设备接受来自主机设备的请求,则建立连接。
当您的手机连接到手环时,就是BLE Central设备的一个示例。

连接后

主机设备可以更新连接参数,主机设备通常在设备与其自身之间建立连接参数,只有主机设备能修改连接参数,但是,采集设备可以要求主机设备更改连接参数,及从机发送更新参数请求

从机设备或主机设备可以终止连接,连接可能由于多种原因而终止,例如设备的电池可能耗尽或网络干扰可能导致连接失败,设备还可以主动与对等设备断开连接

通用属性配置文件 GATT

GATT 分为两种类型,注意与从机或主机无关

客户端,客户端可以发送请求给GATT 服务端,客户端可以读写 服务端的属性,通过属性可以通信数据

服务端,服务端是用来存储属性的,每当客户端发送请求时,服务端会响应这些请求

客户端与服务端的关系

一个示例如下,手环采集了心跳信息,希望计算机读取该信息,手环充当服务端并提供信息,手机充当客户端,读取该信息

GAP 和GATT 模型角色基本上彼此独立从机设备或主机设备都可以充当服务端或客户端,这取决于数据的流动方式

在一般的主从机通信时,主机可以通过读写从机的属性,实现接收和发送数据给从机,从机可以通过发送通知的方式实现与主机的通信,因此,一般从机是作为GATT 的服务端,主机作为GATT 的客户端

协议栈分层协作
下面以如何发送一个无线数据包的例子来简单阐述协议栈中各分层的作用和必要性,实际上,协议栈的实现可能更加负责,它需要考虑方方面面的因素

发送数据包

假设有设备A 和设备B 设备A 要把自己的电量状态83 % 0x53 发给设备B,该怎么做呢?作为一个开发者,他希望越简单越好,对他而言,它希望调用一个简单的api 就能完成这件事,比如 send 0x53 实际上我们的BLE 协议栈就是这样设计的,开发者只需调用 send 0x53 就可以把数据发送出去了,其余的事情BLE 协议栈帮你搞定,很多人会想,BLE 协议栈是不是直接在物理层就把0x53 发出去,就如下图所示

这种方式初看起来挺美的,但由于很多细节没有考虑到,实际是不可行的,首先,它没有考虑用哪一个射频信道来进行传输,在不更改API 的情况下,我们只能对协议栈进行分层,为此引入 LL 层,开发者还是调用 send 0x53 send 0x53 再调用 send_LL 0x53 2402M 注 2402M 为信道频率,这里还有一个问题,设备B 怎么知道这个数据包是发给自己的还是其他人的,为此BLE 引入 access address 概念,用来指明接受者身份,其中,0x8e89bed6 这个access address 比较特殊,它表示要发给周边所有设备,即广播,如果你要一对一的进行通信,BLE 协议将其称为连接,即设备A 的数据包只能设备B 接收,同样设备B 的数据包只能设备A 接收,那么就必须生成一个独特的随机access address 标识设备A 和设备B 两者之间的连接

广播方式

我们先来看一下简单的广播情况,这种情况下,我们把设备A 叫advertiser 设备B叫 scanner 或者observer 扫描者,广播状态下设备A 的LL 层api 将变成 send_LL 0x53 2402M 0x8e89bed6 由于设备B 可以同时接收到很多设备的广播,因此数据包还必须包含设备A 的device address 0xE1022AAB753B 以确认该广播包来自设备A 为此send LL 参数需要变成
send_LL(0x53,2402M, 0x8E89BED6, 0xE1022AAB753B)
LL 层还要检查数据的完整性,即数据在传输过程中有没有发生窜改,为此引入CRC24 对数据包进行检验,假设为0xb2c7be 同时为了调制解调电路工作更高效,每一个数据包的最前面会加上1个字节的preamble preamble 一般为0x55 或者0xAA 这样,整个空中包变成

空中包用小端模式表示

上面这个数据包还有如下问题

没有对数据包进行分类组织,设备B 无法找到自己想要的数据0x53 为此,我们需要在access address 之后加入两个字段,LL header 和长度字节,LL header 用来表示数据包的LL 类型,长度字节用来指明payload 的长度

设备B 什么时候开启射频窗口以接收空中数据包,如上图case1所示,当设备A 的数据包在空中传输的时候,设备B 包接收窗口关闭,此时通信将失败,同样对case2 来说,当设备A 没有空中发送数据包时,设备B 把接收窗口打开,此时通信也将失败,只有case3的情况,通信才能成功,即设备A的数据包在空中传输时,设备B 正好打开射频接收窗口,此时通信才能成功,换句话说,LL 层还必须定义通信时序

当设备B 拿到数据0x53 后,该如何解析这个数据呢? 它到底表示湿度还是电量,还是别的意思,这个就是GAP 层要做的工作,GAP 层引入了LTV length type value 结构来定义数据,比如020105
02 长度 01 类型,强制字段,表示广播flag ,广播包必须包含该字段,05 值,由于广播包最大只能为31 个字节,它能定义的数据类型极其有限,像这里说的电量,gap 就没有定义,因此要通过广播方式把电量数据发出去,只能使用供应商自定义数据类型 0xff 及04ff590053 其中04 表示长度,ff 表示数据类型,自定义数据,0x0059 是供应商 id 自定义数据中的强制字段,0x53 就是我们的数据,设备双方约定0x53 就是表示电量,而不是其他意思

AAD6BE898E600E3B75AB2A02E102010504FF5900538EC7B2

AA 前导帧
D6BE898E – 访问地址(access address)
60 – LL帧头字段(LL header)
0E – 有效数据包长度(payload length)
3B75AB2A02E1 – 广播者设备地址(advertiser address)
02010504FF590053 – 广播数据
8EC7B2 – CRC24值

有了PHY LL 和gap,就可以发送广播包了,但广播包携带的信息极其有限,而且还有如下几大限制

无法进行一对一双向通信,广播是一对多通信,而且是单方向的通信

由于不支持组包和拆包,因此无法传输大数据

通信不可靠及效率低下,广播信道不能太多,否则将导致扫描端效率低下,为止 ble 只使用37 2402MHZ 38 2426 39 2480 三个信道进行广播和扫描,因此广播不支持调频,由于广播是一对多的,所以广播也无法支持ack,这些都使广播通信变得不可靠

扫描端口功耗高,由于扫描端不知道设备端何时广播,也不知道设备端选用哪个频道进行广播,扫描端只能拉长扫描窗口时间,并同时对37 38 39 三个通道进行扫描,这样功耗就会比较高

而连接则可以很好解决上述问题,下面我们就来看看连接是如何将0x53 发送出去的

6.3 连接方式

到底什么叫连接,像有线uart ,很容易理解,就是用线 rx tx 等,把设备A 和设备B 相连,即为连接,用线把两个设备相连,实际是让两个设备有共同的通信媒介,并让两者时钟同步起来,蓝牙连接有何尝不是这个道理
所谓设备A 和设备B 建立蓝牙连接,就是指设备A 和设备B 两者一对一 同步成功,其具体包含以下几方面

设备A 和设备B 对接下来要用的物理信道达成一致

设备A 和设备B 双方建立一个共同的时间锚点,也就是说,把双方的时间原点变成同一个点

设备A 和设备B 两者时钟同步成功,即双方都知道对方什么时候发送数据包什么时候接收数据包

连接成功后,设备A 和设备B 通信流程如下所示

如上图所示,一旦设备A 和设备B 连接成功(此种情况下,我们把设备A称为Master 或者central ,把设备B 称为slave 或者peripheral),设备A 将周期性以CI connection interval 为间隔向设备B 发送数据包,而设备B 也周期性地以ci 为间隔打开射频接收窗口以接收设备A 的数据包,同时按照蓝牙spec 要求,设备B 收到设备A 数据包150us 后,设备B 切换到发送状态,把自己的数据发给设备A,设备A则切换到接收状态,接收设备B 发过来的数据,由此可见,连接状态下,设备A 和设备B 的射频发送和接收窗口都是周期性地有计划地开和关,而且开的时间非常短,从而大大降低系统功耗并大大提高系统效率

现在我们看看连接状态下是如何把数据0x53 发送出去的,从中大家可以体会到蓝牙协议分层的妙处

对开发者来说,很简单,他只需要调用 send 0x53

GATT层定义数据的类型和分组,方便起见,我们用0x0013表示电量这种数据类型,这样GATT层把数据打包成130053(小端模式!)
ATT层用来选择具体的通信命令,比如读/写/notify/indicate等,这里选择notify命令0x1B,这样数据包变成了:1B130053
L2CAP用来指定connection interval(连接间隔),比如每10ms同步一次(CI不体现在数据包中),同时指定逻辑通道编号0004(表示ATT命令),最后把ATT数据长度0x0004加在包头,这样数据就变为:040004001B130053
LL层要做的工作很多,首先LL层需要指定用哪个物理信道进行传输(物理信道不体现在数据包中),然后再给此连接分配一个Access address(0x50655DAB)以标识此连接只为设备A和设备B直连服务,然后加上LL header和payload length字段,LL header标识此packet为数据packet,而不是control packet等,payload length为整个L2CAP字段的长度,最后加上CRC24字段,以保证整个packet的数据完整性,所以数据包最后变成:
AAAB5D65501E08040004001B130053D550F6
AA – 前导帧(preamble)
0x50655DAB – 访问地址(access address)
1E – LL帧头字段(LL header)
08 – 有效数据包长度(payload length)
04000400 – ATT数据长度,以及L2CAP通道编号
1B – notify command
0x0013 – 电量数据handle
0x53 – 真正要发送的电量数据
0xF650D5 – CRC24值

虽然 开发者只调用了send 0x53 ,但由于低功耗蓝牙协议栈层层打包,最后空中实际传输的数据将变成下图所示的模样,这就既满足了低功耗蓝牙通信的需求,又让客户api 变得简单,可微一箭双雕

蓝牙广播

蓝牙状态切换

蓝牙服务和特性

SPP 协议, MID 协议

HID 协议 等等

MicroPython BLE

NodeMCU-32

蓝牙广播 advertising

常见的广播类型

0x01 设备标识

0x02 16bit uuid

0x07 128 bit uuid

0x19 设备外观

0x08 缩略设备名称

0x09 完整设备名称

0x0A 发射功率

0xff 厂商自定义数据

app nrf connected

蓝牙广播类型

可连接非定向

可连接定向

不可连接非定向

可扫描非定向

扫描响应数据和广播数据格式是一样的

扫描响应数据是非必需的

总结

低功耗蓝牙通信基于特性

常用通信方式 read write notify
手机订阅才能收到 notify

https://www.bilibili.com/read/cv18236129

BF54D165-942B-D6A0-5425-E593CD317472

20221216-HC-06蓝牙模块

主机:用于向从机下发指令,能够搜索并主动建立连接的一方

从机:用于接收主机下发的命令,不能主动建立连接,只能等别人连接自己。(HC-06只能工作在从机模式下。)
主从一体:能够在主机和从机模式间切换,即可做主机也可作从机。如:HC-05既可以设置为主机也可以设置为从机。

引脚说明

HC-05 和HC-06的硬件相同,都采用CSR 公司的BC417143 芯片,支持蓝牙2.1+EDR 规范,只是芯片内部的控制程序不同

通常可采用万用表「电阻」档,测量底板RxD引脚和蓝牙模块本身(就是焊接上去那块板)的第2脚,如果电阻值为接近于0,则代表沒有限流电阻。如下图:

使用AT 指令前,最好由一块USB 转TTL 的模块,将蓝牙模块与usb 转ttl 模块连接完成,

AT指令
终端返回信息
功能描述
AT
oK
确认连接状态
AT+VERSION
OK linvor V1.8
查看软件版本号
AT+NAMEOOo
oK setname
设置蓝牙名称
AT+PINOO0o
oK setPIN
设定密码
AT+BAUD1
OK 1200
将波特率设置为:1200
AT+BAUD2
OK 2400
将波特率设置为:2400
AT+BAUD3
OK 4800
将波特率设置为:4800
AT+BAUD4
oK 9600
将波特率设置为:9600
AT+BAUD5
OK 19200
将波特率设置为:19200
AT+BAUD6
OK 38400
将波特率设置为:38400
AT+BAUD7
OK 57600
将波特率设置为:57600
AT+BAUD8
OK 115200
将波特率设置为::115200 dn.net/O17136(

20221216-AT指令介绍

AT 指令最初是用来指导modem 工作的,

虽然在PC 端,手机上已经没有了AT 的使用,但其却在嵌入式行业里各类联网模块中发挥着重要的作用,而且不仅仅只应用在蜂窝模块,还应用到了wifi ble 等模块中

相关标准

随着技术的发展,目前 AT 指令发展过程中形成两个重要标准

V.250:该标准于 1995 年建立,1998 年重命名为 V.250
ETSI GSM 07.07(3GPP TS 27.007):用于控制 GSM modem 的 AT 指令集
GSM 07.07 是基于 V.250 标准的。是目前最新的 AT 标准。

当下AT 指令的应用

目前 的AT 指令着重应用在蜂窝模块 wifi 模块,ble 模块,目的是为了简化嵌入式设备联网的复杂度

AT 标准定义了At 命令的格式本身,比如命令以 AT 为前缀,以 或者 结尾,这被现有的AT 模块所延用

但是,由于每个厂家的模块不一样,实现的功能不一样,导致每个 AT 模块厂家有自己的一套私有的 AT 命令集,每一个 AT 模块厂家实现的 AT 指令集解析器也不一样(解析器实现的 AT 标准功能也参差不齐)。像上图所示的 AT 命令使用方式不被大多数模块厂家所实现。

AT模块的应用框图

既然是指令集,那么必然会有指令集的解析处理,通常,我们把AT 模块端的解析处理程序称为AT Server,而将控制AT 模块的处理器端的解析处理程序称为AT client 由AT client 发起命令请求,AT Server 通过URC 来主动给AT client 发送数据

一些约定

AT 命令的常用格式

1
AT+CMD=<xxx>[,<xxx>,<xxx>]

AT命令以AT 开始,以 \r 或者 \r\n 结尾,参数之间使用 , 隔开,字符串参数使用双引号 “” 包裹,整形参数不适用双引号。

:回车符
:换行符

尖括号中的名称 xxx 在 AT 里是一个语法元素,要求必须指定。尖括号本身不会出现在命令行里。
[xxx]
中括号中的名称 xxx 在 AT 里是一个语法元素,表示可选择指定。中括号本身不出现在命令行里。

四类AT 命令

Test 命令:AT+=?
测试指令类似于命令行里的 help 指令,用于提供该命令的使用信息,以及命令参数的取值范围。
Read 命令:AT+?
用于查询该指令对应功能的当前值。
Set 命令:AT+=<…>
设置用户指定的参数到对应的功能里。
Execute 命令:AT+
执行相关操作。

响应结果字符串

AT 标准定义了标准的响应结果字符串:

\r\nOK\r\n
如果 AT 指令被 AT Server 识别,并正确执行,则返回该结果。
“ 标准中的 V1 模式下响应结果代码的方式。V0 模式下返回 0\r。

\r\nERROR\r\n
“ 标准中的 V1 模式下响应结果代码的方式。V0 模式下返回 4\r。

数据模式与指令模式

在收到 +++,并且接下来 1s 内未收到其他数据的话,将从数据模式切换到指令模式。

数据模式,可以透传数据,client 发什么,server 就原封不动发出去。指令模式时,AT Server 需要解析 AT 指令,并作出响应。

  • Copyrights © 2015-2024 TeX_baitu
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~