欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

开源OA办公平台搭建教程:O2OA+Arduino实现物联网应用(四)

程序员文章站 2022-03-03 16:53:24
...

        之前我们通过O2IOTServer类已经实现了设备的初始化配置,现在我们需要使用配置信息,连接到可以用的WiFi,并连接登录到O2OA服务器。

创建O2IOTClient类

在o2iot目录下创建文件:O2IOTClient.h,代码如下:

#ifndef O2IOTCLIENT_H_
#define O2IOTCLIENT_H_
#include <ESP8266WiFiMulti.h>   //引用ESP8266的WiFi库
#include <ESP8266HTTPClient.h>  //引用ESP8266的HttpClient库
#include <EEPROM.h>             //引用EEPROM库
#include "ArduinoJson.h"        //引用ArduinoJson库
class O2IOTClient {
public:
    //配置信息变量
    String xtoken="";
    String o2host="";
    String o2port="";
    String o2user="";
    String o2pass="";
    bool begin();       //初始化client,连接WiFi,并登录O2OA
    bool connect();     //连接WiFi
    String _doGet(String url);                  //发起http-get请求
    String _doPost(String url, String data);    //发起http-post请求
    String _doPut(String url, String data);     //发起http-put请求
    void getConfig();               //获取设备配置信息
    void parseConfig();             //解析设备配置信息
private:
    ESP8266WiFiMulti WiFiMulti;     //esp8266WiFi对象
    void blink(char n);             //芯片led灯闪烁
    bool _getToken();               //登录到O2OA,并获取token
    char _ssidConfig[128];          //配置信息存储128字节
    char *ssid_name;                //热点名称
    char *ssid_pass;                //热点密码
};
extern O2IOTClient O2_IOTClient;
#endif /* O2IOTCLIENT_H_ */

然后我们需要创建.cpp来实现头文件中定义的方法,所以在o2iot目录下创建文件:O2IOTClient.cpp,代码如下:

#include "O2IOTClient.h"
void O2IOTClient::blink(char n){    //此方法用于让芯片的led灯闪烁n次
    for (char i = 0; i < n; i++) {
        digitalWrite(LED_BUILTIN, LOW);
        delay(100);
        digitalWrite(LED_BUILTIN, HIGH);
        delay(100);
    }
}
bool O2IOTClient::begin() { //开始连接WiFi和登录
    EEPROM.begin(512);      //ESP8266使用EEPROM需要首先调用EEPROM.begin(size)方法
    if (connect()){         //将设备连接到WiFi热点
        blink(2);       //如果成功连接到WiFi让设备led灯闪烁2次
        if (_getToken()){   //登录到O2OA服务器,并获取toekn
            blink(3);       //如果成功登录,并获取到token,让设备led灯闪烁3次
        }   
    }
    return false;
}
void O2IOTClient::getConfig() {     //从EEPROM中获取设备配置信息
    for (int i = 0; i < 128; i++) {
        _ssidConfig[i] = EEPROM.read(i);
    }
}
void O2IOTClient::parseConfig() {   //解析设备配置信息,存储到变量
    if (strchr(_ssidConfig, '|')!=NULL){
        if (_ssidConfig[0] != NULL) {
            ssid_name = strtok(_ssidConfig, "|");
            ssid_pass = strtok(NULL, "|");
            o2user = strtok(NULL, "|");
            o2pass = strtok(NULL, "|");
            o2host = strtok(NULL, "|");
            o2port = strtok(NULL, "|");
        }
    }
}
bool O2IOTClient::connect() {       //连接WiFi热点
    getConfig();
    parseConfig();
    if (ssid_name[0] != NULL && ssid_pass[0] != NULL) {
        WiFiMulti.addAP(ssid_name, ssid_pass);      //连接WiFi热点
        int n = 0;
        while (WiFiMulti.run() != WL_CONNECTED && n<20) {   //如果没有链接到,重试20次
            delay(500);                                     //每500毫秒重连一次
            n++;
        }
        if (WiFiMulti.run() == WL_CONNECTED) {              //已连接到WiFi,返回true
            return true;
        }
        return false;
    }
    return false;
}
bool O2IOTClient::_getToken(){          //发起Post请求进行登录O2OA
    if (!o2host.equalsIgnoreCase("") && !o2port.equalsIgnoreCase("")){
        //获取登录token的url,此处是O2OA服务平台的一个接口,等会我们会创建这个接口服务
        String url = "http://"+o2host+":"+o2port+"/x_program_center/jaxrs/invoke/getToken/execute";
        //发起post请求,传输用户名和密码
        String payload = _doPost(url, "{'user':'"+o2user+"', 'pass': '"+o2pass+"'}");
        if (payload.equalsIgnoreCase("")) return false;
        //解析请求的返回结果,先创建json的document对象
        StaticJsonDocument<256> doc;
        DeserializationError error = deserializeJson(doc, payload);
        //获取到data.token,保存到xToken变量
        JsonObject json = doc["data"].as<JsonObject>();
        xtoken = json["token"].as<String>();
        doc.clear();
        return true;
    }
    return false;
}
String O2IOTClient::_doGet(String url){  //此方法发起get请求
    HTTPClient http;        //创建http对象
    http.begin(url);        //开始http请求
    //设置http头
    http.addHeader("Content-Type", "application/json; charset=utf-8");
    http.addHeader("Origin", "http://"+o2host);
    String payload="";
    //发起get请求
    int httpCode = http.GET();
    if (httpCode > 0) {
        if (httpCode == HTTP_CODE_OK) {
            payload = http.getString();
            payload.trim();
        }
    }
    http.end();
    return payload;
}
String O2IOTClient::_doPost(String url, String data) {   //此方法发起post请求
    HTTPClient http;
    http.begin(url); //HTTP
    http.addHeader("Content-Type", "application/json; charset=utf-8");
        http.addHeader("Origin", "http://"+o2host);
    String payload="";
    int httpCode = http.POST(data);
    if (httpCode > 0) {
        if (httpCode == HTTP_CODE_OK) {
            payload = http.getString();
            payload.trim();
        }
    }
    http.end();
    return payload;
}
String O2IOTClient::_doPut(String url, String data) {    //此方法发起post请求
    HTTPClient http;
    http.begin(url); //HTTP
    http.addHeader("Content-Type", "application/json; charset=utf-8");
    http.addHeader("Origin", "http://"+o2host);
    String payload="";
    int httpCode = http.sendRequest("put", data);
    if (httpCode > 0) {
        if (httpCode == HTTP_CODE_OK) {
            payload = http.getString();
            payload.trim();
        }
    }
    http.end();
    return payload;
}
O2IOTClient O2_IOTClient;

现在我们完成了O2IOTClient类,实现了连接WiFi和登录O2OA,并获取token,但还缺少O2OA的登录接口。

创建O2OA登录接口

接下来,我们要在O2OA服务器创建一个接口服务,以便设备登录并获取token。就是上述代码中调用的getToken服务。以服务管理员身份登录O2OA服务器,进入服务管理平台,新建一个接口,命名为“getToken”,并输入以下代码:

//将请求消息体解析为json
var res = JSON.parse(this.requestText.toString());
//创建登录请求需要的消息体
var o = {"credential":res.user,"codeAnswer":res.pass};
//通过x_organization_assemble_authentication中的AuthenticationAction.codeLogin方法登录系统
this.Actions.load("x_organization_assemble_authentication").AuthenticationAction.codeLogin(o, function(json){
    //获取登录的token
    var token = json.data.token;
    //将token作为响应返回给客户端
    this.response.setBody({"data": {"token": token}}, "application/json");
}.bind(this));

开源OA办公平台搭建教程:O2OA+Arduino实现物联网应用(四)
            
    
    博客分类: O2OA二次开发手册企业信息化系统架构企业信息化系统 二次开发开源软件OA软件办公开发企业架构

在O2OA中创建用户

我们需要在O2OA服务器创建一个用户,用于设备登录,创建用户过程,请自行查阅文档。在此我创建了一个叫做iot的用户。

开源OA办公平台搭建教程:O2OA+Arduino实现物联网应用(四)
            
    
    博客分类: O2OA二次开发手册企业信息化系统架构企业信息化系统 二次开发开源软件OA软件办公开发企业架构

在设备主程序中调用

我们回到o2iot.ino文件,更新一下代码,调用O2IOTClient类。

#include "Arduino.h"        //引用Arduino核心库
#include "O2IOTServer.h"    //引用O2IOTServer类
#include "O2IOTClient.h"    //引用O2IOTClient类
void setup() {
    pinMode(LED_BUILTIN, OUTPUT);       //将LED_BUILTIN引脚配置为输出
    digitalWrite(LED_BUILTIN, HIGH);    
    O2_IOTServer.begin();   //启动AP接入点,并启动Web服务
    O2_IOTClient.begin();   //连接WiFi,并登录到O2OA
}
void loop() {
    O2_IOTServer.listening();   //监听http请求
}

验证和上载程序

这个步骤和上一章中所讲的一样。

看看效果

此时,我们开发板上已经开始运行我们的程序了,按上一章所讲,设置好要连接的WiFi,O2OA中心服务器器地址,端口,以及登录用户名和密码。将设备重新上电,我们应该就可以看到效果了。当连接到WiFi时,led灯闪烁2次,当登录到O2OA服务器后,led灯闪烁3次。

调试程序

arduino调试

当然,能够一次正确运行程序的,毕竟不多,所以我们可以在代码中添加一些串口输出语句进行调试。

现在主程序中初始化串口,在setup中加入代码:

Serial.begin(115200);

整个代码如下:

#include "Arduino.h"        //引用Arduino核心库
#include "O2IOTServer.h"    //引用O2IOTServer类
#include "O2IOTClient.h"    //引用O2IOTServer类
void setup() {
    Serial.begin(115200);   //初始化串口,波特率为115200
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);
    O2_IOTServer.begin();   //启动AP接入点,并启动Web服务
    O2_IOTClient.begin();   //连接WiFi,并登录到O2OA
}
void loop() {
    O2_IOTServer.listening();   //监听http请求
}

然后可以在任何位置,使用Serial.print()或者Serial.println()在串口输出信息,以便调试。如在_getToken方法中:

bool O2IOTClient::_getToken(){          //发起Post请求进行登录O2OA
    if (!o2host.equalsIgnoreCase("") && !o2port.equalsIgnoreCase("")){
        //此处就可以输出调试信息
        Serial.print("url:" );
        Serial.println("http://"+o2host+":"+o2port+"/x_program_center/jaxrs/invoke/getToken/execute");
        //获取登录token的url,此处是O2OA服务平台的一个接口,等会我们会创建这个接口服务
        String url = "http://"+o2host+":"+o2port+"/x_program_center/jaxrs/invoke/getToken/execute";
        //发起post请求,传输用户名和密码
        String payload = _doPost(url, "{'user':'"+o2user+"', 'pass': '"+o2pass+"'}");
        if (payload.equalsIgnoreCase("")) return false;
        //解析请求的返回结果,先创建json的document对象
        StaticJsonDocument<256> doc;
        DeserializationError error = deserializeJson(doc, payload);
        //获取到data.token,保存到xToken变量
        JsonObject json = doc["data"].as<JsonObject>();
        xtoken = json["token"].as<String>();
        Serial.print("xtoken:" );
        Serial.println(xtoken);
        doc.clear();
        return true;
    }
    return false;
}

然后就可以使用任何串口工具,连接到设备串口,设置相同的波特率(本列中为115200),就可以看到输出信息。

VS Code也已经集成了串口工具,我们只要点击右下角的图标,就可以打开串口工具.

开源OA办公平台搭建教程:O2OA+Arduino实现物联网应用(四)
            
    
    博客分类: O2OA二次开发手册企业信息化系统架构企业信息化系统 二次开发开源软件OA软件办公开发企业架构

打开串口工具后,在右下角可调整波特率.

开源OA办公平台搭建教程:O2OA+Arduino实现物联网应用(四)
            
    
    博客分类: O2OA二次开发手册企业信息化系统架构企业信息化系统 二次开发开源软件OA软件办公开发企业架构

可以看到这里输出的请求url,同时我把token信息也输出了。

 

O2OA接口调试

对于接口的调试,我们也可以是使用print()方法输出调试信息,然后在平台的日志中查看。如在接口中输出请求消息体内容,代码如下:

//输出请求消息体
print(this.requestText.toString());
//将请求消息体解析为json
var res = JSON.parse(this.requestText.toString());
//创建登录请求需要的消息体
var o = {"credential":res.user,"codeAnswer":res.pass};
//通过x_organization_assemble_authentication中的AuthenticationAction.codeLogin方法登录系统
this.Actions.load("x_organization_assemble_authentication").AuthenticationAction.codeLogin(o, function(json){
    //获取登录的token
    var token = json.data.token;
    //将token作为响应返回给客户端
    this.response.setBody({"data": {"token": token}}, "application/json");
}.bind(this));

然后打开日志,等待请求,就可以看到输出信息了。

开源OA办公平台搭建教程:O2OA+Arduino实现物联网应用(四)
            
    
    博客分类: O2OA二次开发手册企业信息化系统架构企业信息化系统 二次开发开源软件OA软件办公开发企业架构

开源OA办公平台搭建教程:O2OA+Arduino实现物联网应用(四)
            
    
    博客分类: O2OA二次开发手册企业信息化系统架构企业信息化系统 二次开发开源软件OA软件办公开发企业架构

 

 

本章就到这里,下一章,我们要连接WebSocket了。