一直从事容灾、云计算、ICT方面的规划、设计、实施和运维工作。近几年则比较看好人工智能和物联网技术。今年国网提出建设“三型两网”(泛在电力物联网),终于可以名正言顺的搞事情了。
物联网涉及诸多技术领域,用“泛在”定义的电力物联网,更是个巨坑。为了分享心得、与同好交流,打算在这里把填坑的点点滴滴记录下来。
这次搞事情的对象选择了中移物联网的OneNet平台,主要原因是支持NB-IoT、灵活的接入方式、支持可视化、可以免费申请开发板(这个才是关键吧,哈哈)。最近还上线了应用编排功能(貌似与华为合作?),有点意思了,虽然只是一点点,但毕竟是向“三流合一”的方向靠近(能源流没有,业务流、数据流可以有)。
盘点了一下手头硬件资源:
嗯,足够搭一个最简单的物联网环境了。
智能终端暂时只能用ESP8266,手头有01S和NODEMCU。NODEMCU自带MicroUSB,程序烧写方便。,而且自带多个GPIO脚,可以设成PWM、I2C、1-Wire,有SPI有UART,能连接各种传感器执行器。编程可以用Arduino,也可以用原厂或第三方的SDK。
中国移动的开放物联网平台OneNet,在三大运营商中算是NO.1了,平台功能也许不能与互联网公司们比,但人家是掌握信道。支持的协议不少,包括私有协议EDP、常见的MQTT、NB的LWM2M等等。功能也勉强够用。接口也比较开放,至少MQTT比较方便移植。自己的设备接入后可以定义数据流,并编辑应用,实现数据的可视化以及对设备下发指令。
新上线的OneNet View和应用开发环境则更进一步,支持对数据流进行编排,支持定制应用。可惜暂时没时间细看,不知道能不能编排应用系统,包括机器学习、深度学习等。
说回信道,这次挺想玩玩NB-IoT的,可惜NB模块还没到货,暂时只能用Wifi了。用ESP8266连接任何能上网的AP都行,我用的是自己手机热点和4G Wifi路由器。通信协议选了MQTT,主要是移植性好,使用TCP支持长连接,日后再试试使用UDP低耗电的NB。
具体实现过程先不说,看看做出来的效果吧(请无视巨大的温差,那不是温湿度传感器采集的数据,只是为了在平台看出明显变化取的随机数)。
链接(刚点了公开,要等审核通过才能看到):https://open.iot.10086.cn/iotbox/appsquare/appview?openid=304a6ec5a16c2d77c638b00437fa6cda
截图:
搜集资料期间发现OneNet+MQTT的资料很少,找到的代码要么不全,要么就是有语法和逻辑错误。所以这里直接给出完整代码,Arduino1.8.5编译通过,只要相关库的版本合适,参数配置正确,应该没什么问题。
/*
* Email:[email protected]
* WeChat:song641606
*/
#include
#include
#include
#include
#define wifi_ssid "xxxxxxxxxxx"
#define wifi_password "xxxxxxxxxxx"
#define mqtt_server "183.230.40.39" //OneNet-MQTT IP
#define mqtt_port 6002 //OneNet-MQTT port
#define mqtt_devid "xxxxxxxx"
#define mqtt_pubid "xxxxxxxx"
#define mqtt_password "xxxxxxxxxxxxxxxxxxxxxxxxxx" //OneNet-MQTT APIkey
#define pin_led 13
long lastMsg = 0;
char msg_buf[200];
char dataTemplete[] = "{\"dht01\":%d, \"dht02\":%d}";
char msgJson[75];
char debug_buf[200];
unsigned short json_len = 0;
uint8_t debug_buffer_start_index = 0;
int pl_0 = 0;
int temp_r = 0;
int humi_r = 0;
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
pinMode(BUILTIN_LED, OUTPUT);
pinMode(pin_led, OUTPUT);
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(wifi_ssid);
WiFi.begin(wifi_ssid, wifi_password);
while (WiFi.status() != WL_CONNECTED) {
delay(3000); Serial.print("w?");
}
Serial.println("--WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
if ((char)payload[0] == '0') {
digitalWrite(BUILTIN_LED, HIGH);
} else {
digitalWrite(BUILTIN_LED, LOW);
}
pl_0 = (int)payload[0] - 48;
if (pl_0 >= 0 && pl_0 < 10) {
for (int ii = 0; ii < pl_0; ii++) {
digitalWrite(pin_led, HIGH); delay(1000);
digitalWrite(pin_led, LOW); delay(1000);
}
}
else {
digitalWrite(pin_led, LOW);
}
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect(mqtt_devid, mqtt_pubid, mqtt_password)) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5s");
delay(5000);
}
}
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
long now = millis();
if (now - lastMsg > 10000) {
lastMsg = now;
temp_r = random(-20, 40);
humi_r = random(1, 80);
snprintf(msgJson, 40, dataTemplete, temp_r, humi_r);
memset(msg_buf, 0, 200);
json_len = strlen(msgJson); //packet length count the end char '\0'
msg_buf[0] = char(0x03); //palyLoad packet byte 1, one_net mqtt Publish packet payload byte 1, type3 , json type2
msg_buf[1] = char(json_len >> 8); //high 8 bits of json_len (16bits as short int type)
msg_buf[2] = char(json_len & 0xff); //low 8 bits of json_len (16bits as short int type)
memcpy(msg_buf + 3, msgJson, strlen(msgJson));
Serial.print("Lngth of published message: ");
client.publish("$dp", (uint8_t*)msg_buf, 3 + strlen(msgJson)); //// msg_buf as payload length which may have a "0x00"byte
Serial.println(strlen(msgJson));
/*
for (i = 0 ; i < 200; i++)
{
sprintf(debug_buf, "0x%02x ", msg_buf[i]);
Serial.print(debug_buf);
}
Serial.println();
Serial.println(debug_buffer_start_index);
*/
}
}
ESP8266烧写完成并加电后,每10秒向平台上传温度和湿度两个数据。同时可以接收平台下发的指令,控制板载LED和GPIO外接的LED灯。
代码注释不多,主要是IDE汉字支持的不好,写完注释变乱码了。实在懒得重新写了,有问题就留言吧。还有具体的开发过程和填过哪些坑,后面再一一道来。