在设计espnow协议的时候,考虑到我需要在esp32,Linux设备,web上使用相同的数据结构,那就需要考虑一下,是否使用一个通用的跨平台序列化数据结构。这时候我想起了protobuf,这个就是我需要的。
我之前在esp32上使用过protobuf(nanopb),用起来也是比较简单的。
这里我先初步大致写了一下espnow自定义协议需要使用的一些数据结构。
syntax = "proto3";
import "options/gorm.proto";
import "protos/SMN_type.proto";
package smn;
option go_package = "./smn";
message NetInfo {
option (gorm.opts) = { ormable: true };
uint32 device_id = 1 [(gorm.field).tag = {type: "uuid" primary_key: true}];
uint32 group_id = 2;
uint32 level = 3;
uint32 status = 4;
SMNDevice device_type = 10;
bytes node_mac = 11;
uint32 rssi = 15;
uint32 response_time = 16;
uint32 packet_loss_rate = 20;
Bandwidth bandwidth_type = 24;
uint32 heartbeat_interval = 25;
uint32 latest_heartbeat_time = 26;
}
message SystemInfo {
uint32 device_id = 1;
uint32 cpu_temperature = 2;
uint32 cpu0_load = 3;
uint32 cpu1_load = 4;
uint32 ram_load = 5;
uint32 free_ram = 6;
uint32 uptime = 10;
}
message EspnowDevice {
uint32 device_id = 1;
string device_name = 2;
string alias_name = 4;
string manufacturer = 10;
string model = 11;
string hardware_version = 15;
string firmware_version = 20;
}
message DeviceModel {
DeviceModelType type = 1;
uint32 num = 2;
}
message DeviceModelList {
DeviceModel data = 1;
}
以及基本的类型和枚举定义
syntax = "proto3";
package smn;
option go_package = "./smn";
enum SMNCommand {
ADV_BROADCAST = 0;
SCAN_DEVICES = 1;
DEVICE_AUTHORIZATION = 2;
PAIR_NET = 10;
KEY_UPDATE = 12;
ROUTE_DISCOVERY = 20;
ROUTE_REPLY = 21;
DATA_FORWARD = 22;
ATT_READ = 30;
ATT_WRITE = 31;
ATT_NOTIFY = 32;
ATT_INDICATE = 33;
HEARTBEAT = 50;
TOPOLOGY_UPDATE = 51;
PRIORITY_DATA = 52;
TIME_SYNC = 53;
OBSERVER_REGISTER = 70;
OBSERVER_REPORT = 71;
DATA_SUBSCRIBE = 72;
DIAGNOSTICS_TRIGGER = 73;
}
enum SMNDevice {
SMN_EMPTY = 0;
ROUTER = 1;
LEAF = 2;
LP_LEAF = 4;
FRIEND = 8;
PROXY = 16;
OBSERVER = 32;
GATEWAY = 64;
COORDINATOR = 128;
}
enum Bandwidth {
DEDICATED = 0;
HEAVY = 1;
MODERATE = 2;
LIGHTWEIGHT = 8;
MINIMAL = 10;
}
enum DeviceModelType {
TYPE_EMPTY = 0;
LIGHT = 1;
COLOR_LIGHT = 2;
SWITCH = 3;
TEMPERATURE_SENSOR = 30;
HUMIDITY_SENSOR = 31;
SMOKE_SENSOR = 32;
MOTION_SENSOR = 33;
WATER_LEAK_SENSOR = 34;
WATER_LEVEL_SENSOR = 35;
OLED_SCREEN = 50;
COLOR_LCD = 51;
CLOCK = 60;
FAN_SIMPLE = 70;
FAN_PWM = 71;
PCB_HOT_PLATE = 90;
LED = 100;
COLORLED = 101;
GPIO_CONTROLLER = 102;
}
message Heatbeat {
uint32 device_id = 1;
uint32 group_id = 2;
uint32 level = 3;
SMNDevice device_type = 10;
bytes node_mac = 11;
}
message TimeInfo {
uint32 device_id = 1;
uint32 time = 2;
uint32 msec = 3;
uint32 sntp_time = 4;
}
安装protoc编译器,使用protobuf的话,需要安装这个编译器,用来生成对应语言的序列化代码。
我们在github上的链接上,下载对应平台的压缩包。
https://github.com/protocolbuffers/protobuf/releases

下载解压缩后,需要添加对应的环境变量
PROTOC_PATH=$MYBIN/tools/bin/protocexport
PATH=$PROTOC_PATH/bin:$PATH
然后,需要安装protobuf的go插件(生成常规的序列化数据结构)
go get -u github.com/golang/protobuf/protoc-gen-go
以及gorm的插件(生成gorm对应的数据库)
go get github.com/infobloxopen/protoc-gen-gorm
然后,我们需要编写一个脚本,来完成对应文件的生成工作。
protoc \
-I. \
-I$PROTOC_PATH/include/ \
-I$(go env GOPATH)/pkg/mod/github.com/infobloxopen/protoc-gen-gorm@v1.1.4/proto/ \
-I$(go env GOPATH)/pkg/mod/github.com/infobloxopen/protoc-gen-gorm@v1.1.4/third_party/proto/ \
--go_out=. \
--gorm_out=. \
protos/SMN_proto.proto protos/SMN_type.proto
对应参数需要反复测试和尝试,找到对应的文件才能使用,网络上的资料也是比较少的,所以,写成脚本测试会更简单一些(也方便记录,万一以后忘记了就麻烦了)。
生成的文件如截图
gorm的存储数据结构

常规的数据结构和序列化、解序列方法

然后使用这些,就可以简单写一些保存espnow设备数据的服务程序了。