欢迎来到IoT的世界。让我们来学习和了解IoT世界里最精彩和有趣的部分。
在这篇教程里,我们会搭建和部署一个经典的、完整的IoT应用网络。
我们搭建一个LoRa网络。
我们使用Mud库来帮助MCU硬件板接入到LoRa网络中。
在LoRa网关端,我们使用LoRa Gateway插件来简化网关的开发。LoRa Gateway会给终端MCU硬件板动态分配地址(LoRa DAC插件),并把它添加为下级节点(Concentrator插件)。
最后,我们依然通过手机App,来遥控MCU硬件板上的LED,亮灯、熄灯、闪灯。
Java >= 11
Granite Lite IoT XMPP Server
点击这里下载Granite Lite IoT XMPP Server
Raspberry Pi 3A+硬件板
Arduino Micro硬件板
LED模块
LoRa模块
一把杜邦线
下图是这个教程中使用到的硬件。
在学习这篇教程之前,我们假设读者已经具备以下的基础知识:
- 了解IoT(物联网)相关基础概念。
- 熟悉Linux技术,会安装树莓派操作系统。
- 知道GPIO是什么,了解相关基础知识。
- 熟悉Java语言,有C语言基础。
- 了解掌握的Arduino IDE的基本使用。
在这篇教程里,我们不会再去花时间讲解以上的基础知识。
建议在学习这篇教程之前,先学习Hello, Actuator教程。
如果你不了解Arduino IDE的使用,可以读官方网站这篇Getting Started with Arduino IDE 2。
UART是Universal Asynchronous Receiver/Transmitter。
中文名通用异步收发器协议。
UART是一种硬件串口通讯协议,常被用于连接嵌入式硬件板和外部模块之间的通讯。
当使用UART在两个设备之间进行通讯时,须将设备1的TX接到设备2的RX,将设备1的RX接到设备2的TX。如下图。
在IoT系统中,集线器(Concentrator)是指可以添加和管理下级IoT设备的中心节点设备。
LoRa DAC是是LoRa Dynamic Address Configuration的缩写。
中文为LoRa动态地址配置协议。
在同一个LoRa网络中,如果想要精确控制每一个LoRa中终端节点,需要给每个终端节点配置不同的LoRa地址。
这和TCP/IP网络很像,在本地局域网内,需要给每个主机节点配置不同的IP地址。
地址配置,有静态配置和动态配置两种方法,在TCP/IP网络中,我们使用DHCP服务来动态分配IP地址,简化网络的配置操作。
在LoRa网络中,目前还缺少动态分配地址的相关协议。
Lithsphere为解决这个问题,提供了LoRa DAC协议。并内置实现了LoRa DAC协议的LoRa DAC Client和LoRa DAC Service的组件。
LoRa协议并不兼容TCP/IP。
所以使用LoRa协议的IoT终端节点,并不能直接连接到互联网中。
为了让LoRa终端节点连接到互联网,我们需要使用LoRa网关设备。
LoRa网关设备,在IoT网络这一端,使用LoRa协议,连接LoRa终端节点。
在互联网端,LoRa网关通过WiFi或者运营商网络(4G、5G,....)、连接到互联网云端服务器。
在Lithospere里,LoRa Gateway插件,使用Concentrator插件管理下级LoRa终端节点,提供互联网连通服务。
LoRa Gateway插件还使用LoRa DAC插件提供的LoRa DAC服务,来分配和管理LoRa终端节点地址。
LoRa网关有两种工作模式,DAC模式和ROUTER模式。
这是因为Lithospere中的LoRa网关插件,被设计成了可执行成多功能任务的设备,它具备以下两个功能:
- ROUTER功能
LoRa网关,在使用ROUTER工作模式时,可以帮助LoRa网络中的终端节点,连接到互联网服务器。在这个工作模式下,LoRa网关实际上起到了一个连接LoRa网络和Internet网络的路由器作用。 - DAC功能
LoRa网关,在使用DAC工作模式时,它其实是一个辅助组网LoRa网络的工具。
使用LoRa协议组网时,一个比较啰嗦的事情,是如何给每个终端节点,分配一个在LoRa网络里唯一、不冲突的LoRa地址。
当然,我们可以给LoRa模块静态配置地址,这个就需要严格做设备和地址的分配管理,以避免LoRa组网地址冲突。
在工厂里组装LoRa协议智能设备时,还必须有一个给LoRa终端设备配置静态地址的流程,将被管理的不冲突、唯一地址,配置到LoRa协议智能设备中。
另外一种方案是在组网时,给终端设备动态分配地址,这类似于在TCP/IP网络里使用DHCP协议。问题在于,LoRa网络协议,目前没有动态地址分配相关的协议。
Lithosphere提供了LoRa DAC协议,来帮助简化LoRa组网过程。当LoRa网关处于DAC工作模式下时,它被用于配置和组网LoRa网络。
Lithosphere目前的版本,这两种工作模式,不能同时并发使用。
我们在本教程案例中,会使用到ChangeWorkingMode指令,来遥控LoRa网关切换工作模式,来跑通整个案例。
TUXP是Things Unified and Extensiable Protocol。
中文为智能物件统一和可扩展协议。
为何会有TUXP?
这是因为,在IoT应用中,我们通常会面对多端和多协议带来的复杂性。
在IoT应用中,终端部署地点和部署环境,较传统互联网和移动互联网来说,更为复杂和多变。
而且在IoT应用架构上,由于引入了IoT专用通讯协议,往往需要部署IoT网关节点来帮助连接到互联网的通讯。
较传统互联网应用来说,IoT应用引入了更多端(移动端、服务器端、IoT网关端、终端节点端)和更多协议(BlueTooth,WiFi,LoRa,ZigBee,JSON, XML,MQTT,....)。
为了解决IoT应用多端和多协议带来的复杂性问题,Lithosphere平台采用了TUXP。
TUXP是一组面向IoT通讯的XMPP扩展协议。
目前,TUXP包括以下一些子协议:
- IBTR Protocol 物件在线注册协议
- Notification Protocol
物件事件通知协议。 - Execution Protocol
远程控制执行协议。 - Report Protocol
传感器数据上报协议。 - LoRa DAC
LoRa动态地址分配协议。 - Friends Protocol
友物件事件监听协议 - ... ...
Lithosphere在IoT应用中,统一使用TUXP协议来简化多端和多协议问题。
基于Lithosphere来做IoT应用开发,其它所有IoT相关协议都被屏蔽掉了,我们只使用TUXP。
No LoRa,No JSON,No XML,No MQTT,No HTTP,... ...
Only TUXP。
让我们来聊聊Lithosphere平台里锐利的宝剑,BXMPP!
一个最简单的回答,当然是:
优化通讯效率
让我们再深入一些分析这个问题。
开发IoT应用,就会涉及到多端、多协议问题。
- IoT专用通讯协议,需要二进制通讯协议。
一些IoT专用通讯协议,因为省电、低能耗的需求,被设计为低速率。
对于JSON,XML来说,这些低速率的通讯协议,速度太慢了!在这些IoT专用网络里,JSON,XML格式数据包太大了!
我们需要二进制协议来改善优化网络通讯。 - 终端设备环境,需要二进制通讯协议。
IoT的世界,千变万化!IoT里的T - Thing,数量多如泥沙!
因为部署环境、功耗、以及成本的考虑,我们常在应用中使用低成本、廉价的MCU解决方案。
MCU硬件板的性能、资源,往往有限。许多MCU的板子,甚至不能运行JSON、XML解析器。
就算使用性能更好的高端MCU板,有限的资源,也不应该消耗在JSON、XML的解析上。
二进制通讯协议,很明显是更好的解决方案。
在本教程中,我们使用Arduino Micro来作为终端设备硬件板,开发教程的例子。它的内存SRAM容量为2.5K。
本教程案例,也在Arduino UNO R3上测试通过,这是一款廉价10元板,我在淘宝上购买它的价格是15元,它的内存SRAM容量为2k。
在IoT开发中,使用XMPP协议,可能会遭到最大的质疑是,基于XML的BXMPP,通讯效率太差了,这个协议不适合用于需要高效通讯的IoT应用。
解决方案是什么?其实有一个公司,已经为我们做出了最佳示范。
这个公司是WhatsApp。它使用叫名为FunXMPP的XMPP二进制变种协议,来支撑全球20亿IM用户的使用。
Lithosphre也提供了XMPP的二进制变种协议,来改善通讯效率问题。这个二进制XMPP变种协议被命名为BXMPP。
我们直接来看使用BXMPP的实际效果。
在LoRa网络中,LoRa终端设备通过LoRa网关注册到服务器。
在这个注册过程中,LoRa终端上报Thing ID(13字节)和Registration Code(12字节);LoRa网关给LoRa终端动态分配地址并设置数据上报通道;最后网关发消息给终端设备确认注册成功。
整个过程LoRa终端设备和LoRa网关总共有4次通讯,全部通讯过程,总计交换94字节数据,完成整个终端设备注册过程。
所以,请放心使用Lithosphere平台开发IoT应用,不用担心通讯效率问题。
我们总是先要开发协议包。
本教程中开发协议包过程,和Hello, Actuator教程开发协议包中类似。
只有些细节区别。
创建hello-lora-protocol工程,pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
... ...
<groupId>com.thefirstlineofcode.lithosphere.tutorials.hellolora</groupId>
<artifactId>hello-lora-protocol</artifactId>
<name>Hello LoRa protocol</name>
<version>0.0.1-RELEASE</version>
... ...
</project>
代码说明
- 除了协议包的groupId和artifactId不一样之外,其它内容和Hello, Actuator教程创建协议工程中的pom.xml完全相同。不再赘述。
和Hello, Actuator教程定义协议对象中完全相同。不再赘述。
在这个教程案例中,我们有2种型号智能物件需要登记到服务器:
- LoRa智能网关
- 可控终端LED小灯
以下代码定义可控终端LED小灯类型描述器。
public class HltModelDescriptor extends SimpleThingModelDescriptor {
public static final String MODEL_NAME = "HLT";
public static final String DESCRIPTION = "Hello LoRa thing";
public HatModelDescriptor() {
super(MODEL_NAME, DESCRIPTION, false, null, null, createSupportedActions());
}
private static Map<Protocol, Class<?>> createSupportedActions() {
Map<Protocol, Class<?>> supportedActions = new HashMap<>();
supportedActions.put(Flash.PROTOCOL, Flash.class);
supportedActions.put(TurnOn.PROTOCOL, TurnOn.class);
supportedActions.put(TurnOff.PROTOCOL, TurnOff.class);
return supportedActions;
}
}
代码说明
- 和[Hello, Actuator教程定义Model Descriptor](./Hello_Actuator_Tutorial.md#定义Model Descriptor)类似,只是设备型号名改为了HLT(Hello LoRa Thing)。不再赘述。
以下代码定义LoRa网关类型描述器。
public class HlgModelDescriptor extends SimpleThingModelDescriptor {
public static final String MODEL_NAME = "HLG";
public static final String DESCRIPTION = "Hello LoRa Gateway";
public HlgModelDescriptor() {
super(MODEL_NAME, DESCRIPTION, true, null, null, createSupportedActions());
}
private static Map<Protocol, Class<?>> createSupportedActions() {
Map<Protocol, Class<?>> supportedActions = new HashMap<>();
supportedActions.put(ChangeWorkingMode.PROTOCOL, ChangeWorkingMode.class);
return supportedActions;
}
}
代码说明
- 设备型号名为HLG(Hello LoRa Gateway)。
- LoRa网关,只支持一个Action,ChangeWorkingMode,用来遥控LoRa网关切换工作模式。
- 不需要在协议包中定义ChangeWorkingMode对象。因为LoRa Gateway网关插件中已经内置了ChangeWorkingMode协议对象,我们可以使用系统自带的这个协议对象。
因为需要在后续开发客户端和服务器端插件包时,引用协议包,所以我们在hello-lora-protocol工程里,执行构建安装指令,把协议包安装到本地maven仓库。
cd hello-lora-protocol
mvn clean install
协议包已经开发完成,你可以参考官方开源仓库代码hello-lora-protocol协议包工程源码
创建hello-lora-server目录,添加pom.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
... ...
<groupId>com.thefirstlineofcode.lithosphere.tutorials.hellolora</groupId>
<artifactId>hello-lora-server</artifactId>
<version>0.0.1-RELEASE</version>
<name>Hello LoRa server plugin</name>
... ...
</project>
代码说明
- 除了服务器插件包的groupId和artifactId不一样之外,其它内容和Hello, Actuator教程服务器端插件工程中的pom.xml完全相同。不再赘述。
@Extension
public class ThingModelsProvider implements IThingModelsProvider {
@Override
public IThingModelDescriptor[] provide() {
return new IThingModelDescriptor[] {
new HlgModelDescriptor(),
new HltModelDescriptor()
};
}
}
代码说明
- 注册HLG和HLT设备到服务器。
public IThingModelDescriptor[] provide() { return new IThingModelDescriptor[] { new HlgModelDescriptor(), new HltModelDescriptor() }; }
@Extension
public class ThingRegistrationCustomizer extends ThingRegistrationCustomizerAdapter {
private static final String HARD_CODED_REGISTRATION_CODE = "abcdefghijkl";
@Override
public boolean isUnregisteredThing(String thingId, String registrationCode) {
if (!super.isUnregisteredThing(thingId, registrationCode))
return false;
return HARD_CODED_REGISTRATION_CODE.equals(registrationCode);
}
@Override
public boolean isAuthorizationRequired() {
return false;
}
@Override
public boolean isConfirmationRequired() {
return false;
}
}
代码说明
- 和Hello, Actuator教程案例里的ThingRegistrationCustomizer相比,只多了一个isConfirmationRequired方法,返回false值。
public boolean isConfirmationRequired() { return false; }
我们在Hello,Actuator教程里,提到了设备注册的概念。
我们在sAuthorizationRequired()方法中返回false,禁止掉了Edge设备(直连Internet服务器的设备)的人工授权步骤。禁止人工授权后,设备仅需要通过Thing ID和Registration Code合法性检查,就会自动注册到服务器
对于非直连Internet服务器的设备,例如在这个案例中的HLT(Hello LoRa Thing)设备,它是通过LoRa网关来连接Internet服务器的。则需要在isConfirmationRequired()方法中返回false,来禁止掉了此类设备的人工授权步骤。
- 同样的,我们检查设备的Registration Code必须为"abcdefghijkl"。
在src/main/resources目录下,创建plugin.properties。
plugin.id=hello-lora-server
plugin.provider=TheFirstLineOfCode
plugin.version=0.0.1-RELEASE
plugin.dependencies=sand-server-things
non-plugin.dependencies=sand-protocols-lora-gateway,hello-lora-protocol
代码说明
- 和Hello, Actuator教程服务器编写插件配置文件类似,仅有细节区别,不再赘述。
构建hello-lora-server插件包
cd hello-lora-server
mvn clean package
将hello-lora-server插件包和它依赖的hello-lora-protocol包,把这两个jar包,copy到服务器的plugins目录下。
cp hello-lora-protocol/target/hello-lora-protocol-0.0.1-RELEASE.jar granite-lite-iot-1.0.5-RELEASE/plugins
cp hello-lora-server/target/hello-lora-server-0.0.1-RELEASE.jar granite-lite-iot-1.0.5-RELEASE/plugins
服务器端插件已经开发完成,你可以参考官方开源仓库代码hello-lora-server服务器端插件包工程源码
和[Hello, Actuator教程检查Granite Lite XMPP Server状态](./Hello_Actuator_Tutorial.md#检查Granite Lite XMPP Server状态)类似,不再赘述。
和Hello, Actuator教程创建测试用户类似,不再赘述。
让我们来做些硬件组装的工作。
我们来看看LoRa网关用到的LoRa模块长啥样。
这个LoRa模块型号AS32-TTL-100,在淘宝上买,零售价还挺贵的,30块钱一个。头上黑黑的、粗粗的东西,是信号天线,5块钱一个。
我们可以看到,它有7个引脚:
引脚名 | 作用 |
---|---|
GND | 地线 |
VCC | 5V电源 |
MD0 | 模块配置引脚0 |
MD1 | 模块配置引脚1 |
AUX | 模块状态指示引脚 |
RXD | UART串口通讯RXD引脚,接硬件板上TX引脚 |
TXD | UART串口通讯TXD引脚,接硬件板上RX引脚 |
再来看树莓派硬件板这一端。
LoRa模块上的MD0、MD1控制引脚,以及AUX状态指示引脚,可以接到树莓派任意的有效GPIO引脚上。在本教程案例里,我们把这3个引脚接到了树莓派板的GPIO_02,GPIO_03,GPIO_04引脚上。
树莓派硬件板接上LoRa模块之后,看上去是这样的。
安装了纯净RaspBerry Pi OS操作系统的树莓派,还需要做一些环境配置。
接上电源,启动树莓派。
使用ssh登录到树莓派上,然后安装默认的JDK。树莓派OS默认安装的JDK版本是Open JDK11。
ssh [email protected]
sudo apt-get update
sudo apt-get install default-jdk
Pi4J通过采用JNI技术访问C库,来提供GPIO,Serial口通讯等功能。
从V2版本开始,Pi4J放弃了使用WiringPi库,改用pigpio库作为控制GPIO的底层C库。
我们需要先安装pigpio库,才能让Pi4J正常工作。
按照以下的步骤安装pigpio库。
编辑/boot/config.txt文件。
sudo vi /boot/config.txt
在文件结尾添加以下的两行内容。
enable_uart=1
dtoverlay=disable-bt
说明:
- Raspberry Pi板上有两种类型的UART,PL011和mini UART。其中PL011是全功能的UART;mini UART是一个缩减了功能的版本。
在本教程中使用的Raspberry Pi 3A+版本硬件板,默认将PL011 UART被配置给了蓝牙使用。
我们想使用PL011 UART来连接LoRa模块,需要调整树莓派的默认配置,我们需要关掉蓝牙,让它把PL011 UART让出来用。所以,需要以下的这行配置,关掉蓝牙。
dtoverlay=disable-bt
我们已经在配置中,关掉蓝牙了。但可以再彻底一些,我们移除掉蓝牙相关的系统服务。
sudo systemctl disable hciuart
sudo systemctl disable bluetooth
编辑/boot/cmdline.txt文件
sudo vi /boot/cmdline.txt
将console==serial0,xxxx的内容删除掉,这里的xxxx是配置的波特率。
在我的树莓派3A+板上,需要被移除的内容为console=serial0,115200。
让我们来开发LoRa网关程序。
创建hello-lora-gateway目录,添加pom.xml文件。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.thefirstlineofcode.sand</groupId>
<artifactId>sand-client</artifactId>
<version>1.0.0-BETA4</version>
</parent>
<groupId>com.thefirstlineofcode.lithosphere.tutorials.hellolora</groupId>
<artifactId>hello-lora-gateway</artifactId>
<version>0.0.1-RELEASE</version>
<name>Hello LoRa Gateway</name>
<dependencies>
<dependency>
<groupId>com.thefirstlineofcode.sand.protocols</groupId>
<artifactId>sand-protocols-bxmpp-extensions</artifactId>
</dependency>
<dependency>
<groupId>com.thefirstlineofcode.chalk</groupId>
<artifactId>chalk-logger</artifactId>
</dependency>
<dependency>
<groupId>com.thefirstlineofcode.sand.client</groupId>
<artifactId>sand-client-edge</artifactId>
</dependency>
<dependency>
<groupId>com.thefirstlineofcode.sand.client</groupId>
<artifactId>sand-client-lora-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.thefirstlineofcode.sand.client.pi</groupId>
<artifactId>sand-client-pi-ashining</artifactId>
</dependency>
<dependency>
<groupId>com.thefirstlineofcode.lithosphere.tutorials.hellolora</groupId>
<artifactId>hello-lora-protocol</artifactId>
<version>0.0.1-RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs/</classpathPrefix>
<mainClass>com.thefirstlineofcode.lithosphere.tutorials.hellolora.gateway.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/assembly/descriptor.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>com.thefirstlineofcode.releases</id>
<name>TheFirstLineOfCode Repository - Releases</name>
<url>http://120.25.166.188:9090/repository/maven-releases/</url>
</repository>
</repositories>
</project>
代码说明
- POM继承com.thefirstlineofcode.sand:sand-client,以便复用父POM里的依赖配置管理。
- hello-lora-gateway是一个独立运行的Java程序。我们使用maven-assembly-plugin和maven-jar-plugin来打包和配置可这个可运行程序。
- 依赖com.thefirstlineofcode.sand.client:sand-client-edge库,我们使用Edge库来帮助网关设备进行设备注册和连接服务器。
<dependency> <groupId>com.thefirstlineofcode.sand.client</groupId> <artifactId>sand-client-edge</artifactId> </dependency>
- 依赖com.thefirstlineofcode.sand.client:sand-client-lora-gateway库,我们需要使用Lora Gateway插件。
<dependency> <groupId>com.thefirstlineofcode.sand.client</groupId> <artifactId>sand-client-lora-gateway</artifactId> </dependency>
- 我们使用型号为AS32-TTL-100的LoRa模块。Sand项目提供了在树莓派硬件板上对这个型号LoRa模块的硬件通讯器封装,具体实现在com.thefirstlineofcode.sand.client.pi:sand-client-pi-ashining库中。这个库间接引用了Pi4J库,所以我们不需要再另行配置Pi4J库依赖。
<dependency> <groupId>com.thefirstlineofcode.sand.client.pi</groupId> <artifactId>sand-client-pi-ashining</artifactId> </dependency>
- 依赖hello-lora-protocol协议包。
<dependency> <groupId>com.thefirstlineofcode.lithosphere.tutorials.hellolora</groupId> <artifactId>hello-lora-protocol</artifactId> <version>0.0.1-RELEASE</version> </dependency>
public class HelloLoraGateway extends AbstractEdgeThing {
public static final String THING_MODEL = HlgModelDescriptor.MODEL_NAME;
public static final String SOFTWARE_VERSION = "0.0.1-RELEASE";
private static final String ATTRIBUTE_NAME_COMMUNICATOR_HAS_CONFIGURED = "communicator_has_configured";
private ICommunicator<LoraAddress, LoraAddress, byte[]> communicator;
private ILoraGateway loraGateway;
public HelloLoraGateway() {
super(THING_MODEL, null, true);
communicator = createLoraCommunicator();
}
@Override
public String getSoftwareVersion() {
return SOFTWARE_VERSION;
}
@Override
protected boolean doProcessAttributes(Map<String, String> attributes) {
return initializeAndConfigureCommunicator(attributes);
}
private boolean initializeAndConfigureCommunicator(Map<String, String> attributes) {
if (!communicator.isInitialized())
communicator.initialize();
if (!"true".equals(attributes.get(ATTRIBUTE_NAME_COMMUNICATOR_HAS_CONFIGURED))) {
communicator.configure();
attributes.put(ATTRIBUTE_NAME_COMMUNICATOR_HAS_CONFIGURED, "true");
return true;
}
return false;
}
@Override
protected void registerIotPlugins() {
chatClient.register(LoraGatewayPlugin.class);
}
@Override
protected void startIotComponents() {
if (loraGateway == null) {
loraGateway = chatClient.createApi(ILoraGateway.class);
loraGateway.setDownlinkCommunicator(communicator);
loraGateway.setUplinkCommunicators(Collections.singletonList(communicator));
configureConcentrator(loraGateway);
}
loraGateway.start();
}
private void configureConcentrator(ILoraGateway gateway) {
IConcentrator concentrator = gateway.getConcentrator();
concentrator.registerLanThingModel(new HltModelDescriptor());
regiserExecutors(concentrator, gateway);
}
private ICommunicator<LoraAddress, LoraAddress, byte[]> createLoraCommunicator() {
As32Ttl100LoraCommunicator communicator = new As32Ttl100LoraCommunicator();
communicator.setMd0Pin(2);
communicator.setMd1Pin(3);
communicator.setAuxPin(4);
return communicator;
}
private void regiserExecutors(IActuator actuator, final ILoraGateway loraGateway) {
actuator.registerExecutor(ChangeWorkingMode.class, ChangeWorkingModeExecutor.class, loraGateway);
}
@Override
protected void stopIotComponents() {
loraGateway.stop();
}
@Override
protected String loadThingId() {
return THING_MODEL + "-" + ThingsUtils.generateRandomId(8);
}
@Override
protected String loadRegistrationCode() {
return "abcdefghijkl";
}
}
代码说明
- 继承AbstractEdgeThing。我们使用sand-client-edge库来简化LoRa网关程序的编写。
- As32Ttl100LoraCommunicator类将树莓派板上型号为AS32-TTL-100的LoRa Module,封装成了标准的ICommunicator接口实现。我们创建这个As32Ttl100LoraCommunicator实例,并根据我们实际的接线,设置树莓派连接到MD0,MD1,AUX的对应GPIO引脚。
private ICommunicator<LoraAddress, LoraAddress, byte[]> createLoraCommunicator() { As32Ttl100LoraCommunicator communicator = new As32Ttl100LoraCommunicator(); communicator.setMd0Pin(2); communicator.setMd1Pin(3); communicator.setAuxPin(4); return communicator; }
- AbstractEdgeThing使用一个名为${THING_MODE_NAME}-attributes.propertis的属性配置文件来保存属性参数。并且,留下了一个doProcessAttributes()方法允许子类使用这个属性文件。我们在HelloLoraGateway中重载了这个方法,借用属性配置文件来保存我们用到的通讯器已配置(communicator_has_configured)参数。
protected boolean doProcessAttributes(Map<String, String> attributes) { return initializeAndConfigureCommunicator(attributes); } private boolean initializeAndConfigureCommunicator(Map<String, String> attributes) { if (!communicator.isInitialized()) communicator.initialize(); if (!"true".equals(attributes.get(ATTRIBUTE_NAME_COMMUNICATOR_HAS_CONFIGURED))) { communicator.configure(); attributes.put(ATTRIBUTE_NAME_COMMUNICATOR_HAS_CONFIGURED, "true"); return true; } return false; }
我们使用Communicator之前,需要对它做initialize和configure。
communicator.initialize()方法,每次程序启动,都需要用它初始化Communicator。
communicator.configure()方法,则只需要调用一次。
这里的的逻辑是,LoRa模块提供了持久化保存配置的功能。所以,调用过一次communicator.configure()后,相关配置信息就被LoRa模块的硬件持久化保存记住了。即使所有硬件掉电重启,重启后,LoRa模块依然可以读取到已经持久化保存的配置信息。所以configure()只需要调用一次,之后不再需要反复调用。
我们在第一次做configure时,这时候属性配置文件中,还不能读到名为communicator_has_configured的属性参数。我们调用configure(),调用结束后,设置communicator_has_configured属性参数值为"true"。
然后,我们返回true,这个返回值表示我们修改了属性配置,需要将最新的属性列表保存到属性配置文件。
下次再进入initializeAndConfigureCommunicator()方法,我们能读取到communicator_has_configured的属性值为"true"。我们直接退出,不再重复调用configure()。
- 在HelloLoraGateway中,我们只需要使用LoRaGateway插件。
protected void registerIotPlugins() { chatClient.register(LoraGatewayPlugin.class); }
- 在startIotComponents方法中,我们创建LoRa Gateway组件,然后对它进行配置。我们需要为LoRa Gateway设置Downlink Communicator和Uplink Communicators。其中,被设置的Uplink Communicators参数是一个ICommunicator的列表。在多频道的网关中,我们会指定多个Uplink Communicators,来提升LoRa网关的上行通讯容量。在本教程的案例中,我们只使用一块LoRa通讯芯片,这是一个单频道LoRa网关。所以我们使用Collections.singletonList(communicator)创建一个单元素的列表,然后设置到LoRa Gateway组件。
loraGateway.setDownlinkCommunicator(communicator); loraGateway.setUplinkCommunicators(Collections.singletonList(communicator));
- 我们为网关配置ChangeWorkingMode执行器,这样它才能被遥控切换Working Mode。
注意一个细节,我们不需要自己来编写ChangeWorkingModeExecutor。LoRa Gateway插件中,已经内置提供了ChangeWorkingModeExecutor,我们直接使用它。
这里需要注意的另一个细节是:Conconcenator组件实现了IActuator接口,我们可以用它来注册Executors。... ... IConcentrator concentrator = gateway.getConcentrator(); ... ... regiserExecutors(concentrator, gateway); ... ... private void regiserExecutors(IActuator actuator, final ILoraGateway loraGateway) { actuator.registerExecutor(ChangeWorkingMode.class, ChangeWorkingModeExecutor.class, loraGateway); }
- 我们需要登记HltModeDescriptor到网关。我们在前面的教程里,提到过需要将Mode Descriptor登记到服务器。Granite服务器完全基于插件架构,当我们通过开发插件来提供新的IoT设备功能,这时需要登记设备相关信息到服务器,服务器才能知道如何处理新IoT设备的相关功能。
我们在网关端使用Chalk库开发网关设备。同样的,Chalk也完全基于插件架构。所以,我们需要将终端设备的Model Descriptor注册到网关中,网关才能知道如何处理设备的相关通讯功能。我们使用IConcentrator的registerLanThingModel()API来做这个事。我们从LoRa Gateway中拿到Concentrator组件,并登记HLT(Hello LoRa Thing)设备到Concentrator。IConcentrator concentrator = gateway.getConcentrator(); concentrator.registerLanThingModel(new HltModelDescriptor());
编写一个简单的Main程序来启动运行LoRa网关。
... ...
public static void main(String[] args) {
new Main().run(args);
}
private void run(String[] args) {
... ...
LogConfigurator.configure(HlgModelDescriptor.MODEL_NAME, getLogLevel(logLevel));
... ...
gateway.start();
... ...
}
代码说明
- 我们使用chalk-logger库来配置logger。因为Hello, LoRa教程的例子相较其它几篇教程,涉及到更多端和更多协议。我们配置logger方便调试和跟踪。
LogConfigurator.configure(HlgModelDescriptor.MODEL_NAME, getLogLevel(logLevel));
LogConfigurator.configure()方法的两个参数是日志文件名,和配置的LogLevel等级。
以上代码将日志文件保存为${USER_HOME}/.com.thefirstlineofcode.chalk/logs/${MODE_NAME}.yyyy-MM-DD.log。
让我们来配置使用BXMPP。
考虑到LoRa网络的低速率,以及Arduio低端硬件板的资源处理能力,我们需要在LoRa网络里,使用二进制的BXMPP协议。
sand项目内置的IoT通讯相关协议,都已经配置好。我们只要引入相关BXMPP协议扩展库就Ok了。
在项目的pom.xml文件中,我们引入com.thefirstlineofcode.sand.protocols:sand-protocols-bxmpp-extensions依赖库。
... ...
<dependency>
<groupId>com.thefirstlineofcode.sand.protocols</groupId>
<artifactId>sand-protocols-bxmpp-extensions</artifactId>
</dependency>
... ...
我们在hello-lora-protocol协议包中,引入了应用专用的Flash、TurnOn、TurnOff协议对象。我们需要为它们配置BXMPP协议扩展。
二进制XMPP的一个关键思路,就是采用替换法,将把XMPP里的长长的字符串常量,都替换成单字节的替换字节。
例如,Flash协议对象,当repeat属性被设置为5时,会被OXM框架翻译成以下的XMPP文档:
<flash xmlns="urn:leps:things:simple-light" repeat=5/>
我们能够看到,flash、xmlns、urn:leps:things:simple-light、repeat这几个字符串都很长,而且它们都是字符串常量。
在通讯时,我们可以把这些字符串,都换成单字节的字节替换符,以优化通讯的效率。
具体怎么做呢?
我们在src/main/resources目录下,创建/META-INF/iot-lan-bxmpp-extensions.txt文件,在这个文件里,我们列出需要引入的BXMPP协议扩展文件。
在本教程案例里,我们只需要在iot-lan-bxmpp-extensions.txt文件里,引入hello-lora-protocol协议包的BXMPP协议扩展配置文件。
iot-lan-bxmpp-extensions.txt文件内容如下:
hello-lora-bxmpp-extension.properties
我们在src/main/resources目录下,创建hello-lora-bxmpp-extension.properties文件,在这文件里,我们配置hello-lora-protocol协议的BXMPP替换规则。
0xf70x01=urn:leps:things:simple-light
0x00=flash
0x01=repeat
0x02=turn-on
0x03=turn-off
代码说明
- XMPP协议使用xmlns来扩展协议,不同的xmlns,表示不同的协议。
在hello-lora-protocol中,flash协议的local name是flash,它的的xmlns被定义为"urn:leps:things:simple-light"。
所以XMPP版本的flash协议,完整的协议名为urn:leps:things:simple-light | flash
根据hello-lora-bxmpp-extension.properties的配置,flash协议在它的BXMPP版本中,协议名被替换成3字节替换符0xf70x010x00。 - 属性名repeat,被替换成了1字节替换符0x01。
- turn-on和turn-off协议,被翻译成BXMPP协议时,规则同flash协议类似,不再赘述。
我们来测试一下网关程序,启动LoRa网关主程序,将网关设备注册到服务器。
将树莓派接通电源启动起来,然后将编译好的LoRa网关程序,用scp拷贝到树莓派上。
cd hello-lora-gateway
mvn clean package
scp target/hello-lora-gateway-0.0.1-RELEASE.tar.gz [email protected]:/home/pi
注:
- 192.168.1.180是树莓派板的网络地址。请改为你配置树莓派板时,指定的静态IP地址。
- pi为树莓派用户。请改为你配置树莓派时,初始化创建的用户名。
启动网关程序,检查它是否能够正确注册到服务器。
ssh [email protected]
tar -xzvf hello-lora-gateway-0.0.1-RELEASE.tar.gz
cd hello-lora-gateway-0.0.1-RELEASE
sudo java -jar hello-lora-gateway-0.0.1-RELEASE.jar --host=192.168.1.80
注:
- 在启动网关程序之前,先启动Granite XMPP Lite IoT Server。
- 这里,我们需要使用sudo来启动网关程序。这是由于Pi4J库的使用限制。官方文档的说法:Need to run as sudo。下图来自Pi4J官方文档。
如果能够看到Thing thing has started,说明网关程序已经成功注册,并连接到服务器。
我们还是用sand-demo App来遥控LoRa网关。
点击这里下载构建好的sand-demo App。
使用sand-demo用户登录到sand-demo App里后,我们可以看到型号为HLG的一个设备,它是前面注册成功的LoRa网关设备。
可以看到它有唯一一个控制菜单项,Change Working Mode。
点击菜单改变LoRa网关工作模式,在LoRa网关程序的控制台里,我们可以看到切换网关Working Mode的日志输出。
让我们来实现最后一块拼图 - 终端设备。
先把硬件组装起来。终端硬件板上要接上LoRa模块和LoRa网关通讯,它还需要接上LED用于执行亮灯、熄灯、闪灯指令
我们使用一块Arduino Micro的硬件板子。
这个硬件板有点贵的,在淘宝上,带USB接口线的版本,零售价47元。
为何我们不使用更便宜的板子?
这个教程里的终端程序,在Arduino Uno R3的板子上测试可以正常运行。Arduino Uno R3板在淘宝上的价格,15元。
问题在于,Arduino Uno R3板,不能在Arduino IDE中使用串口监视器打印调试信息。这是因为这个板子的USB接口线使用了UART串口。那么,因为我们使用的LoRa模块也要使用UART串口,这会产生冲突,除非我们愿意放弃在IDE中打印调试信息,
Arduino Nano板,也和Arduino Uno R3板有同样的问题。似乎Arduino的10元板,都有这个问题,在外接设备使用UART串口时,无法同时使用Arduino IDE的的串口监视器来打印调试信息。
好吧,为了方便打印调试信息,强烈建议使用Arduino Micro来开发本教程中的终端设备案例。
来接线吧,让我们来看看如何将LoRa模块和LED灯接到Arduino Micro板上。
接好之后,看上去是这样的。
让我们开始来写终端程序吧。
我们使用Arduino IDE来编写和安装hello_lora_thing硬件板程序。
如果你的开发机器上,并没有安装Arduino IDE,请从官方网站下载Arduino IDE 2安装。
如果你以往并没有使用Arduino IDE的相关经验,请阅读官方文档Getting Started with Arduino IDE 2,稍微熟悉一下这个开发工具。
在开发终端程序之前,我们先安装要使用到的用到的依赖库。
终端程序依赖以下第三方库:
-
mud
Lithosphere平台Mud通讯库。
点击这里下载Mud通讯库 -
mud_arduino_avr
Arduino AVR硬件板的Mud适配库。
点击这里下载Arduino AVR硬件板的Mud适配库 -
mud_as32_ttl_100
AS32-TTL-100型号LoRa模块的Mud适配库。
点击这里下载AS32-TTL-100型号LoRa模块的Mud适配库 -
arduino_unique_id_generator
Arduino硬件板唯一ID生成器。
点击这里下载Arduino硬件板唯一ID生成器 -
mud_configuration
Arduino硬件板的Mud适配配置文件
https://github.com/TheFirstLineOfCode/mud/releases/download/1.0.0-BETA2/mud_configuration.zip
如果你不知道如何导入一个zip格式Library,那么可以阅读官方文档Import a .zip Library
Mud提供的arduino_unique_id_generator库,依赖ArduinoUniqueID库提供的Arduino硬件板唯一ID读取功能。
ArduinoUniqueID库可以直接从Arduino IDE的Library Manager里安装。
打开Library Manager,输入ArduinoUniqueID关键字查询,找到ArduinoUniqueID库后,安装它。
创建hello-lora-thing目录,然后在这个目录下,创建hello-lora-thing.ino文件,代码如下。
#include <Arduino_BuiltIn.h>
#include <thing.h>
#include <mcu_board_adaptation.h>
#include <radio_module_adaptation.h>
#include <arduino_unique_id_generator.h>
#define MODEL_NAME "HLT"
#define LED_PIN 12
void setup() {
configureMcuBoard(MODEL_NAME);
configureRadioModule();
registerThingIdLoader(loadThingId);
registerRegistrationCodeLoader(loadRegistrationCode);
registerThingProtocolsConfigurer(configureThingProtocolsImpl);
pinMode(LED_PIN, OUTPUT);
toBeAThing();
}
char *loadThingId() {
return generateThingIdUsingUniqueIdLibrary(MODEL_NAME);
}
char *loadRegistrationCode() {
return "abcdefghijkl";
}
void turnLedOn() {
digitalWrite(LED_PIN, HIGH);
}
void turnLedOff() {
digitalWrite(LED_PIN, LOW);
}
void flashLed() {
digitalWrite(LED_PIN, HIGH);
delay(200);
digitalWrite(LED_PIN, LOW);
}
int8_t processFlash(Protocol *protocol) {
int repeat;
if (!getIntAttributeValue(protocol, 0x01, &repeat)) {
repeat = 1;
}
if (repeat <= 0 || repeat > 8)
return -1;
for (int i = 0; i < repeat; i++) {
flashLed();
delay(500);
}
return 0;
}
int8_t processTurnOn(Protocol *protocol) {
turnLedOn();
return 0;
}
int8_t processTurnOff(Protocol *protocol) {
turnLedOff();
return 0;
}
void configureThingProtocolsImpl() {
ProtocolName pnFlash = {0xf7, 0x01, 0x00};
registerActionProtocol(pnFlash, processFlash, false);
ProtocolName pnTurnOn = {0xf7, 0x01, 0x02};
registerActionProtocol(pnTurnOn, processTurnOn, false);
ProtocolName pnTurnOff = {0xf7, 0x01, 0x03};
registerActionProtocol(pnTurnOff, processTurnOff, false);
}
void loop() {
int result = doWorksAThingShouldDo();
if (result != 0) {
#ifdef ENABLE_DEBUG
Serial.print(F("Error occurred when the thing does the works it should do. Error number: "));
Serial.print(result);
Serial.println(F("."));
#endif*
}
}
代码说明
- 引入mud通讯库、Arduino AVR板mud适配库、AS32-TTL-100 LoRa模块适配库、Arduino硬件板唯一ID生成器库。
#include <thing.h> #include <mcu_board_adaptation.h> #include <radio_module_adaptation.h> #include <arduino_unique_id_generator.h>
- 定义常量MODEL_NAME和LED_PIN。LED控制引针在教程中,被连在了GPIO12引针上。如果你接LED的控制的引针不是GPIO12,那请根据自己的接线修改LED_PIN的值。
#define MODEL_NAME "HLT" #define LED_PIN 12
- 使用mud适配库,配置Arduino AVR硬件板和LoRa模块。
configureMcuBoard(MODEL_NAME); configureRadioModule();
- 设备注册时,需要提供Thing ID和Registration Code值。我们注册loadThingId和loadRegistrationCode两个函数指针,使用它们来获取Thing ID和Registration Code值。
registerThingIdLoader(loadThingId); registerRegistrationCodeLoader(loadRegistrationCode); ... ... char *loadThingId() { return generateThingIdUsingUniqueIdLibrary(MODEL_NAME); } char *loadRegistrationCode() { return "abcdefghijkl"; }
注:
- arduino_unique_id_generator库的API函数generateThingIdUsingUniqueIdLibrary()读取Arduino硬件板的唯一ID,组合MODEL_NAME来生成一个Thing ID。
- loadRegistrationCode()直接返回硬编码"abcdefghijkl"字符串。还记得我们在服务器端会检查这个硬编码的Registration Code吗?
- 我们在configureThingProtocolsImpl()里配置Action处理函数,我们需要将configureThingProtocolsImpl()函数注册为协议配置器。
registerThingProtocolsConfigurer(configureThingProtocolsImpl); ... ... void configureThingProtocolsImpl() { ProtocolName pnFlash = {0xf7, 0x01, 0x00}; registerActionProtocol(pnFlash, processFlash, false); ProtocolName pnTurnOn = {0xf7, 0x01, 0x02}; registerActionProtocol(pnTurnOn, processTurnOn, false); ProtocolName pnTurnOff = {0xf7, 0x01, 0x03}; registerActionProtocol(pnTurnOff, processTurnOff, false); }
注:
- 我们在协议配置器里,登记三个Action协议Flash、TurnOn,TurnOff对应的处理函数。
注意这里3字节的BXMPP协议名定义,它来自我们在前面定义的BXMPP协议扩展配置文件hello-lora-bxmpp-extension.properties。
- 还是遵循责任分离原则,我们来看看怎么做硬件控制。使用Arduino的API设置LED_PIN的PIN Mode。然后,我们在turnOn(),turnOff(),flashLED()函数里,通过LED_PIN引针控制LED灯。
... ... pinMode(LED_PIN, OUTPUT); ... ... void turnLedOn() { digitalWrite(LED_PIN, HIGH); } void turnLedOff() { digitalWrite(LED_PIN, LOW); } void flashLed() { digitalWrite(LED_PIN, HIGH); delay(200); digitalWrite(LED_PIN, LOW); }
注: pinMode()、delay()、digitalWrite()都是Arduino的开发API。Arduino开发比较简单,在本教程中不再赘述,请自行学习。
关于Arduino的开发,可以参考Arduino官方文档Arduino程序语言参考。
- 现在来处理IoT通讯逻辑,我们使用mud库来简化IoT的通讯。
... ... toBeAThing(); ... ... int result = doWorksAThingShouldDo(); ... ... int8_t processFlash(Protocol *protocol) { int repeat; if (!getIntAttributeValue(protocol, 0x01, &repeat)) { repeat = 1; } if (repeat <= 0 || repeat > 8) return -1; for (int i = 0; i < repeat; i++) { flashLed(); delay(500); } return 0; }
注:
- 在setup()里,调用toBeAThing(),让设备变身智能物件。在loop()里,调用doWorksAThingShouldDo(),做智能物件该做的事。魔法就在藏在这两个函数中,它们会搞定一切。
- 我们在processFlash()里,处理收到的Flash指令。函数会收到带Protocol数据结构的参数的回调。我们调用getIntAttributeValue()来获取repeat参数。并做响应逻辑处理。
- 我们获取repeat参数值时,使用了参数名的替换字符0x01。它来自我们在前面定义的BXMPP协议扩展配置文件hello-lora-bxmpp-extension.properties。
- 在指令处理函数里,如果有错误,返回0之外的返回值,表示这个错误的错误码。返回0表示指令已被正常执行。
- trunOn()和turnOff()函数的处理更简单,不再赘述。
用Arduino IDE将程序上传到Arduino Micro硬件板。
如果你不知道怎么做,请参考官方文档How to upload a sketch with the Arduino IDE 2。
现在可以来测试终端设备了。
将Granite Lite IoT XMPP Server启动起来。
然后,登录到树莓派硬件板,将LoRa网关程序启动起来。
登录sand-demo App程序。
如果还没有安装sand-demo App,请点击这里下载安装使用sand-demo App。
使用LoRa网关设备的Changing Working Mode菜单,修改网关设备的工作模式为DAC。在DAC工作模式下,终端设备才能通过网关注册到服务器。切换工作模式后,应该能够看到网关控制台有"DAC service has started."信息输出。
在Arduino IDE里,打开Serial Monitor。
接通Arduino Micro硬件板,会看到一些终端硬件板协商地址,申请节点添加的调试信息。
如果能看到"I'm a thing now!"信息出现在串口监视器里,终端设备已经成功注册。
如果一直sand-demo App一直处于打开状态,终端设备注册成功后,会收到添加终端接到网关成功的提示信息。
点击"是的,刷新智能物件列表"按钮,刷新设备列表。现在可以看到网关设备和终端设备,都出现在App的智能物件列表中了。
使用LoRa网关设备的Changing Working Mode菜单,修改网关设备的工作模式为ROUTER。在ROUTER工作模式下,网关才能够转发远程控制指令。
现在,可以使用终端设备的控制菜单,来遥控终端设备亮灯、熄灯、闪灯了。
一个最简单的解决方法,能不能重来一次啊?
可以的!
在setup()里调用toBeAThing()之前,先调用resetThing();
这会重置终端硬件板的状态为初始化状态,它会重新申请设备注册。
登录到树莓派网关硬件板上。删除掉Edge Thing的属性配置文件。
ssh [email protected]
sudo -i
rm -rf .com.thefirstlineofcode.sand.client.edge/HLG-attributes.properties
exit
注:
- 网关程序将状态保存在属性配置文件中,删除这个文件,会重置网关程序状态。
- Edge Thing的属性配置文件,被保存为${USER_HOME}/.com.thefirstlineofcode.sand.client.edge/${EDGE_THING_MODEL_NAME}-attributes.properties。
- 在删除这个文件之前,先执行sudo -i切换到root身份。还记得我们因为要使用Pi4J V2版本,必须要使用sudo指令来执行网关程序吗?
删除掉服务器目录下data子目录,可以重置服务器状态,如下:
cd granite-lite-iot-1.0.5-RELEASE
rm -rf data
注:
删除data目录,会重置服务器所有状态。
所以重置服务器后,记得要重新执行sand-demo create-test-users,重新创建测试用户。
通过这篇教程,我们可以学习到以下的内容:
- 使用UART串口通讯,我们可以在Linux系统中,集成使用较复杂的外部通讯模块,例如本教程中的LoRa模块。
- IoT专用网络协议,不兼容互联网的TCP/IP。所以,我们需要使用IoT网关来帮助IoT终端连接到互联网。
- 相较于传统互联网应用,IoT应用会涉及到更多端和更多协议,这给IoT应用带来了额外的复杂性。
为简化这个问题,Lithosphere使用TUXP协议来屏蔽其它的IoT协议。 - 在通讯协议层,由于我们使用TUXP和OXM技术,我们只需要定义协议对象,然后在开发API中直接使用它。我们定义的协议对象,从移动端App开始,通过服务器、IoT网关,最终直达IoT终端设备,这个过程不需要做任何协议翻译解析相关的任何工作。
- 使用LoRa网关插件,我们用不到100行代码,开发了一个全功能的LoRa网关程序。
- 在IoT终端,我们用95行代码,开发了LED灯终端控制程序。这其中大部分是硬件控制、协议配置、协议处理的相关代码。使用Mud库,给终端设备带来LoRa通讯能力所需要的代码数量,是4行代码。
- 在IoT专用网络里,我们使用BXMPP协议。通过简单的配置,协议包在IoT网络内被翻译成为二进制XMPP兼容协议。
所以,我们不需要担心通讯效率问题。 - 树莓派和Arduino,都不复杂。传统的纯软件开发人员,完全可以通过使用这些硬件平台,进入到IoT应用领域。