目前仅支持在 linux 上运行。
已支持以下功能:
- 数据上传:从文件读取或者从串口接收 JSON 格式的数据,通过 MQTT 发送给服务器
- 远程控制:可以借助 MQTT 的订阅机制从服务器接收数据,通过串口发送出去
- 网关离线时可以将数据暂时缓存到数据库内,网络连接恢复后再从数据库里面取出来上传
- 支持数据模板功能,即可以根据数据模板重新格式化来自终端的数据、添加自定义属性、预定义属性(例如添加时间戳)等,从而生成新的JSON数据
- 支持日志功能
- 支持 MQTTS(TLS v1.2,v1.3)
在本地启动 MQTT broker,例如使用 mosquitto:
# 默认监听 1883 端口
mosquitto -v或者修改配置文件 gw.toml,指定可用的 MQTT broker:
[server]
address = "127.0.0.1:1883"修改配置文件(默认是 gw.toml),指定文件,并且将数据接口类型设置为 text_file(默认为此配置):
[data_if]
if_name = "./data_if.txt"
if_type = "text_file"运行网关程序:
cargo run -- -c gw.toml在文件中写入数据(需要有换行 '\n'):
echo "{\"id\":1,\"name\":\"SN-001\",\"temperature\": 27.45,\"humidity\": 25.36,\"voltage\": 3.88,\"status\": 0}" > data_if.txt说明:网关程序每隔 1 秒读清一次文件,读清后需要手动写入数据。
顺利的话,可以在 mosquitto 的窗口内看到网关发送过去的消息。
修改配置文件(默认是 gw.toml),指定串口,并且将数据接口类型设置为 serial_port:
[data_if]
if_name = "/dev/ttyS14"
if_type = "serial_port"网关程序:
cargo run -- -c gw.toml使用外部设备按 MIN 协议向串口发送数据( arduino/min 目录内有 Arduino UNO 的示例,烧录 min 中的程序):
{"id":1,"name":"SN-001","temperature": 27.45,"humidity": 25.36,"voltage": 3.88,"status": 0}
如果是 Arduino UNO,只有一个串口,只能用于和网关通信,网关的配置文件中配置接该串口即可。
顺利的话,网关会收到 Arduino 发送的消息,并且会发送给 mosquitto(可以在 mosquitto 的窗口内看到)。
将 SX1276 Lora 模块连接到 SPI 口上,修改配置文件(默认是 gw.toml),指定 spi 设备,并且将数据接口类型设置为 spi_sx1276:
[data_if]
if_name = "/dev/spidev0.0"
if_type = "spi_sx1276"网关程序:
cargo run -- -c gw.toml需要使用另一个射频参数和 SpiIf::setup_lora 中定义的射频参数匹配的 Lora 设备发送数据(4字节头 + 前面提到的 json 字符串)。
网关已支持远程控制功能。该远程控制不是指可以远程控制网关,而是网关会将服务器发过来的控制命令发送给 MCU,MCU 去响应命令,例如点灯等。
arduino 目录下有 Arduino UNO 和 Arduino DUE 的代码示例(min 子目录),可以通过服务器控制 Arduino 点亮或熄灭 LED。
这里还是以使用 mosquitto 作为 broker 为例:
# 默认监听 1883 端口
mosquitto -v按照 (2) 中的指引操作。
在另一个终端内使用 mosquitto_pub 按照 gw.toml 里面配置的 sub_topic(默认为“ctrl/#”) 发送数据:
# 点亮 LED
mosquitto_pub -d -h "localhost" -p 1883 -t "ctrl/1" -m "turn_on"
# 熄灭 LED
mosquitto_pub -d -h "localhost" -p 1883 -t "ctrl/1" -m "turn_off"从发布数据到 LED 点亮或熄灭大概会有 3s 左右延时。
在本地启动 MQTT broker,例如使用 mosquitto:
mosquitto -c mosquitto.conf配置文件内容(按实际情况修改 ca 文件路径):
# mosquitto.conf
log_type error
log_type warning
log_type notice
log_type information
log_type debug
allow_anonymous true
# non-SSL listeners
listener 1883
# server authentication - no client authentication
listener 18885
# 指定 ca 文件路径
cafile ca/ca.crt
certfile ca/server.crt
keyfile ca/server.key
require_certificate false
tls_version tlsv1.2修改 Cargo.toml 文件,开启 ssl 特性:
[features]
default = ["build_bindgen", "ssl"]
build_bindgen = ["paho-mqtt-sys/build_bindgen"]
ssl = []修改配置文件(默认是 gw.toml),使用 ssl 协议,并指定 ca 文件:
[server]
#address = "127.0.0.1:1883"
address = "ssl://127.0.0.1:18885"
[tls]
cafile = "ca/ca.crt"
# pem 文件生成方式:cat client.crt client.key ca.crt > client.pem
key_store = "ca/client.pem"编译运行网关程序:
cargo run -- -c gw.toml[待整理]
数据模板引擎需要在配置文件中配置,减 gw.toml 内 [msg] 部分。
模板支持的功能:
- 可以使用原消息中字符串类型的属性值作为属性名
- 可以使用原消息中的属性值
- 可以新增自定义的属性名/属性值
- 可以使用有特定内容的模板,比如时间戳
对原始数据的要求:
-
格式为 JSON
-
不能有同名的属性
-
打算用做模板属性名的字符串属性值需要符合 JSON 属性名命名规范
模板示例(以 gw.toml 中的为例):
# 原始数据示例
"{\"l\":\"SN-004\",\"t\": 27.45,\"h\": 25.36,\"v\": 3.88,\"e\": 0}"
# 模板
template = "{<{l}>: [{\"ts\": <#TS#>,\"values\": {\"temperature\": <{t}>, \"humidity\": <{h}>,\"voltage\": <{v}>,\"status\": <{e}>}}]}"以上设置的转换效果为:
# 原始数据
{"l":"SN-001","t": 27.45,"h": 25.36,"v": 3.88,"e": 0}
# 输出数据
{"SN-001": [{"ts": 1596965153255,"values": {"temperature": 27.45, "humidity": 25.36,"voltage": 3.88,"status": 0}}]}模板注解:
<{l}>:取原消息属性l对应的属性值。例如,需要使用消息"t": 27.45中t的属性值27.45作为输出数据中的属性值,需要在模板中填写<{t}><#NAME#>:使用模板引擎可以提供的值。例如<#TS#>表示自 EPOCH 以来的秒数;- 符合 JSON 属性名命名规范的字符串类型的属性值可以作为模板中的属性名。需要将模板填成 "<{属性名}>" 的形式. 例如, 需要使用消息
{"l": "SN-001"}中l的属性值SN-001作为输出数据中的属性名, 需要在模板中填写<{l}>。
-
x86_64-unknown-linux-gnu
-
mips-unknown-linux-uclibc
- 需要为该目标平台编译 rust:Cross Compile Rust For OpenWRT
-
arm-unknown-linux-gnueabihf(树莓派)
-
mipsel-unknown-linux-musl
-
riscv64gc-unknown-linux-gnu
目录 tools 内有部分平台的编译脚本。
/mnt/f/wsl/OpenWRT/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/../lib/gcc/mips-openwrt-linux-uclibc/4.8.3/../../../../mips-openwrt-linux-uclibc/bin/ld: cannot find -lanl
按照 src/CMakeLists.txt: fix build on uclibc or musl 修改 .cargo/registry/src/crates.rustcc.com-a21e0f92747beca3/paho-mqtt-sys-0.3.0/paho.mqtt.c/src/CMakeLists.txt
修改后仍然可能因找到了主机的 libanl 报错,如果还报错,按如下方式修改:
#SET(LIBS_SYSTEM c dl pthread anl rt)
SET(LIBS_SYSTEM c dl pthread rt)thread 'main' panicked at 'Unable to find libclang: "couldn't find any valid shared libraries matching: ['libclang.so', 'libclang-.so', 'libclang.so.']
sudo apt-get install clang libclang-devthread 'main' panicked at 'No generated bindings exist for the version/target: bindings/bindings_paho_mqtt_c_1.3.2-mips-unknown-linux-uclibc.rs', paho-mqtt-sys/build.rs:102:13
cargo install bindgen
sudo apt install libc6-dev-i386
cd ~/.cargo/registry/src/crates.rustcc.com-a21e0f92747beca3/paho-mqtt-sys-0.5.0
TARGET=mips-unknown-linux-uclibc bindgen wrapper.h -o bindings/bindings_paho_mqtt_c_1.3.2-mips-unknown-linux-uclibc.rs -- -Ipaho.mqtt.c/src --verbosedebug:clang version: clang version 10.0.0-4ubuntu1 debug:bindgen include path: -I/mnt/f/wsl/project/iot_gw/target/mipsel-unknown-linux-musl/release/build/paho-mqtt-sys-0e7cd946c58a7093/out/include
--- stderr fatal: not a git repository (or any of the parent directories): .git /usr/include/stdio.h:33:10: fatal error: 'stddef.h' file not found /usr/include/stdio.h:33:10: fatal error: 'stddef.h' file not found, err: true thread 'main' panicked at 'Unable to generate bindings: ()', /home/dell/.cargo/registry/src/crates.rustcc.com-a21e0f92747beca3/paho-mqtt-sys-0.3.0/build.rs:139:14 note: run with
RUST_BACKTRACE=1environment variable to display a backtrace
安装 clang
sudo apt-get install clang指定交叉编译工具链,例如:
export CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc
export CXX_mipsel_unknown_linux_musl=mipsel-openwrt-linux-g++找不到 -lz:
将对应平台上的 libz.so 复制到所对应的工具链的库目录下。例如:
/mnt/f/wsl/tool/raspberrypi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/arm-linux-gnueabihf/lib$ ls -l libz*
lrwxrwxrwx 1 dell dell 14 Oct 29 18:16 libz.so -> libz.so.1.2.11
-rwxrwxrwx 1 dell dell 95880 Oct 29 18:15 libz.so.1.2.11
找不到 libz.h:
根据运行环境上的 libz.so 的版本,下载对应的 zlib 源码,然后在编译时指定头文件路径,例如:
CFLAGS="-I/home/dell/wsl/source/libz-1.2.1100+2/libz
- error: unknown target triple 'riscv64gc-unknown-linux-gnu', please use -triple or -arch thread 'main' panicked at 'libclang error; possible causes include:
- Invalid flag syntax
- Unrecognized flags
- Invalid flag arguments
- File I/O errors If you encounter an error missing from this list, please file an issue or a PR!', /home/dell/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/bindgen-0.52.0/src/ir/context.rs:574:15
修改 bindgen-0.52.0 的源码,在打印上述信息前的位置将传给 clang 的标志打印出来:
println!("{:?}", clang_args);
clang::TranslationUnit::parse(
&index,
"",
&clang_args,
&options.input_unsaved_files,
parse_options,
).expect("libclang error; possible causes include:
- Invalid flag syntax
- Unrecognized flags
- Invalid flag arguments
- File I/O errors
If you encounter an error missing from this list, please file an issue or a PR!")
得到如下信息:
debug:Using bindgen for Paho C debug:clang version: clang version 10.0.0-4ubuntu1 debug:bindgen include path: -I/mnt/f/wsl/project/iot_gw/target/riscv64gc-unknown-linux-gnu/release/build/paho-mqtt-sys-b3925b784bd5c394/out/include ["--target=riscv64gc-unknown-linux-gnu", "-I/mnt/f/wsl/project/iot_gw/target/riscv64gc-unknown-linux-gnu/release/build/paho-mqtt-sys-b3925b784bd5c394/out/include", "-isystem", "/usr/local/include", "-isystem", "/usr/lib/llvm-10/lib/clang/10.0.0/include", "-isystem", "/usr/include/x86_64-linux-gnu", "-isystem", "/usr/include", "wrapper.h"]
可以看到,三元组 riscv64gc-unknown-linux-gnu 被传给了 clang,同时,从 paho-mqtt-sys-0.5.0/build.rs 打印的信息可以看到 clang 的版本比较老,可能还不支持 riscv64gc-unknown-linux-gnu 三元组。最新的 16.0.0 版本是支持的()。
试一下 clang-13:
sudo apt-get install clang-13
sudo apt-get install libclang-13-dev
ls -l /usr/bin/clang*
lrwxrwxrwx 1 root root 24 Mar 21 2020 /usr/bin/clang -> ../lib/llvm-10/bin/clang
lrwxrwxrwx 1 root root 26 Mar 21 2020 /usr/bin/clang++ -> ../lib/llvm-10/bin/clang++
lrwxrwxrwx 1 root root 26 Apr 20 2020 /usr/bin/clang++-10 -> ../lib/llvm-10/bin/clang++
lrwxrwxrwx 1 root root 26 Jul 6 20:01 /usr/bin/clang++-13 -> ../lib/llvm-13/bin/clang++
lrwxrwxrwx 1 root root 24 Apr 20 2020 /usr/bin/clang-10 -> ../lib/llvm-10/bin/clang
lrwxrwxrwx 1 root root 24 Jul 6 20:01 /usr/bin/clang-13 -> ../lib/llvm-13/bin/clang
lrwxrwxrwx 1 root root 28 Apr 20 2020 /usr/bin/clang-cpp-10 -> ../lib/llvm-10/bin/clang-cpp
lrwxrwxrwx 1 root root 28 Jul 6 20:01 /usr/bin/clang-cpp-13 -> ../lib/llvm-13/bin/clang-cpp
将 clang 软链接指向 clang-13:
sudo rm /usr/bin/clang
sudo ln -s /lib/llvm-13/bin/clang /usr/bin/clang
仍然有问题:
debug:clang version: Ubuntu clang version 13.0.1-2ubuntu2~20.04.1 debug:bindgen include path: -I/mnt/f/wsl/project/iot_gw/target/riscv64gc-unknown-linux-gnu/release/build/paho-mqtt-sys-b3925b784bd5c394/out/include ["--target=riscv64gc-unknown-linux-gnu", "-I/mnt/f/wsl/project/iot_gw/target/riscv64gc-unknown-linux-gnu/release/build/paho-mqtt-sys-b3925b784bd5c394/out/include", "-isystem", "/usr/lib/llvm-13/lib/clang/13.0.1/include", "-isystem", "/usr/local/include", "-isystem", "/usr/include/x86_64-linux-gnu", "-isystem", "/usr/include", "wrapper.h"]
从 llvm 源码可以看到,支持 riscv64(https://github.com/llvm/llvm-project/blob/release/13.x/llvm/include/llvm/ADT/Triple.h):
riscv32, // RISC-V (32-bit): riscv32
riscv64, // RISC-V (64-bit): riscv64
但是好像没有 riscv64gc-unknown-linux-gnu 的组合。
继续搜索,有人提到,RISC-V 在 clang 和 rustc 上的三元组不同:https://github.com/rust-lang/rust-bindgen/issues/2136,并且该问题已经得到了解决,但是查看代码时,发现相关提交是 rust-bindgen 0.52.0 之后合入的。
修改 paho-mqtt-sys-0.5.0/Cargo.toml,将 bindgen 的版本修改为 0.60,但还是不行,不知道什么原因,从报错信息中看,调用的仍然是 0.52.0 版。
阅读 paho-mqtt-sys-0.5.0/build.rs 源码可知,可以禁用 build_bindgen 属性,不要在编译过程中调用 bindgen 生成绑定。而是使用 bindgen 0.61.0 版手动生成绑定:
# 删除老版本的 bindgen
cargo uninstall bindgen
# 0.61.0 版本,bindgen 的 crate 改名了
cargo install bindgen-cli
cd ~/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/paho-mqtt-sys-0.5.0
# 但是运行的时候仍然是 bindgen
RUST_BACKTRACE=full TARGET=riscv64gc-unknown-linux-gnu bindgen wrapper.h -o bindings/bindings_paho_mqtt_c_1.3.8-riscv64gc-unknown-linux-gnu.rs -- -Ipaho.mqtt.c/src --verbose有如下报错:
End of search list. thread 'main' panicked at 'assertion failed:
(left == right)left:4, right:8: Target platform requires--no-size_t-is-usize. The size ofssize_t(4) does not match the target pointer size (8)', /home/dell/.cargo/registry/src/mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd/bindgen-0.61.0/codegen/mod.rs:851:25
带上 --no-size_t-is-usize 选项:
RUST_BACKTRACE=full TARGET=riscv64gc-unknown-linux-gnu bindgen --no-size_t-is-usize wrapper.h -o bindings/bindings_paho_mqtt_c_1.3.8-riscv64gc-unknown-linux-gnu.rs -- -Ipaho.mqtt.c/src --verbose
可以生成绑定 paho-mqtt-sys-0.5.0/bindings/bindings_paho_mqtt_c_1.3.8-riscv64gc-unknown-linux-gnu.rs:
然后在 iot_gw/Cargo.toml 中,禁用 paho-mqtt-sys/build_bindgen 特性:
[features]
default = []
build_bindgen = ["paho-mqtt-sys/build_bindgen"]
ssl = []进入 tools 目录,运行 build_f133.sh 即可。
thread 'main' panicked at 'Init data interface failed: DataIfUnknownType'
Cargo.toml 中有关数据接口的特性和网关配置文件内的不一致。
Error connecting to the broker: NULL Parameter: NULL Parameter
使用 ssl 连接 broker,但是没有在 Cargo.toml 中启用 ssl 特性。