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

news/2024/7/10 22:09:08 标签: java, 开源, 教程, oa办公, 开发平台

我们已经登录到了O2OA服务器,本章就要连接Websocket,接收服务器的消息。

创建O2IOTWebsocket类

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

#ifndef O2IOTWEBSOCKET_H_
#define O2IOTWEBSOCKET_H_

#include <WebSocketsClient.h>   //引用WebSocketsClient类,第二章中介绍的引用的WebSockets库中
#include "O2IOTClient.h"        //应用上一章创建的Client类,用来获取连接的token

//定义Websocket接受到消息的回调事件方法
typedef std::function<void(WStype_t type, uint8_t * payload, size_t length)> WebSocketClientEvent;

class O2IOTWebsocket {
public:
    bool begin();       //开始连接websocket
    void listening();   //监听websocket消息
    WebSocketsClient o2webSocket;   //websocket类
private:


};
extern O2IOTWebsocket O2_IOTWebsocket;
#endif /* O2IOTWEBSOCKET_H_ */

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

#include "O2IOTWebsocket.h"
#include "ArduinoJson.h"

//接收websocket消息的事件
void webSocketEvent(WStype_t type, uint8_t * payload, size_t length) {
    //根据接收到消息类型的不同,输出相关信息
    switch(type) {
        case WStype_DISCONNECTED:   //接收到连接断开消息
            Serial.printf("[WSc] Disconnected!\n");
            break;
        case WStype_CONNECTED: {    //接收到连接成功消息
            Serial.printf("[WSc] Connected to url: %s\n", payload);
            break;
        case WStype_TEXT:           //接收到文本消息
            Serial.printf("[WSc] get text: %s\n", payload);
            break;
        case WStype_BIN:            //接收到二进制流消息
            Serial.printf("[WSc] get binary length: %u\n", length);
            hexdump(payload, length);
            break;
        case WStype_PING:           //接收到PING消息,用于心跳保持连接
            // 当接收到服务器发送来的PING消息,会自动向服务器发送PONG消息
            Serial.printf("[WSc] get ping\n");
            break;
        case WStype_PONG:           //接收到PONG消息,用于心跳保持连接
            // 客户端向服务器发送PING消息后,服务器会向客户端发送PONG消息
            Serial.printf("[WSc] get pong\n");
            break;
    }
}

bool O2IOTWebsocket::begin() {      //发起Websocket连接
    //首先确保在设备配置中能获取到O2OA服务器的地址和端口,以及token
    //这些信息在连接websocket时都要用到
    if (!O2_IOTClient.o2host.equalsIgnoreCase("") && !O2_IOTClient.o2port.equalsIgnoreCase("") && !O2_IOTClient.xtoken.equalsIgnoreCase("")){
        
        //首先向服务器发起一个getService的接口请求,这个接口我们会稍后创建
        //其作用是获取要连接的websocket的服务地址。
        //O2OA服务器支持集群,所以一般会在客户端第一次访问时向center服务器请求所有的服务地址
        //center服务器会根据集群中服务器的繁忙程度,分配一组服务地址。
        //如果我们使用浏览器访问,这个工作平台已经做了,不需要用户干预。
        //但是我们通过其他终端设备访问服务器就需要向center请求分配地址了,但我们不需要全部的服务地址
        //所以我们创建一个getService接口,只返回我们需要的服务即可。
        String url = "http://"+O2_IOTClient.o2host+":"+O2_IOTClient.o2port+"/x_program_center/jaxrs/invoke/getService/execute";
        
        //发起post请求,并传入消息体
        //消息体中的:'content':'x_message_assemble_communicate',就是我们需要的服务
        //此请求的作用是:请告诉我“x_message_assemble_communicate”这个服务的访问地址是什么。
        String payload = O2_IOTClient._doPost(url, "{'content':'x_message_assemble_communicate', 'source': '"+O2_IOTClient.o2host+"'}");
        
        //此处在串口输出请求响应消息体
        Serial.print("payload:");
        Serial.println(payload);
        
        //如果没有取到地址,就直接退出程序
        if (payload.equalsIgnoreCase("")) return false;

        //通过ArduinoJson库来解析请求返回的json
        //请求返回的json格式是:
        //{
        //  "data": {
        //     "host": "xxx.xxx.xxx.xxx", 
        //     "port": 20020
        //  }
        //}
        //解析后得到 host 和 port,既是连接websocket的地址和端口
        StaticJsonDocument<256> doc;
        DeserializationError error = deserializeJson(doc, payload);
        JsonObject json = doc["data"].as<JsonObject>();
        String host = json["host"].as<String>();
        int port = json["port"].as<int>();

        doc.clear();

        //此处在串口输入取到的host和port
        Serial.print("host: ");
        Serial.println(host);
        Serial.print("port: ");
        Serial.println(port);

        //在websocket连接路径后加上参数x-token,就是登录O2OA系统后得到的token
        String path = "/x_message_assemble_communicate/ws/collaboration?x-token="+O2_IOTClient.xtoken;

        
        WebSocketClientEvent o2webSocketEvent = webSocketEvent;
        //连接websocket
        o2webSocket.begin(host, port, path);
        //将接收消息事件绑定到o2webSocketEvent,就是webSocketEvent方法
        o2webSocket.onEvent(o2webSocketEvent);
        //设置如果断开连接,5秒后重连
        o2webSocket.setReconnectInterval(5000);
        //设置启用心跳机制
        //每隔15秒,会向服务器发起PING消息,如果在3秒内没有接收到PONG消息,视为失败
        //如果连续失败2次,则进行重新连接
        o2webSocket.enableHeartbeat(15000, 3000, 2);

        return true;
    }
    return false;
}
void O2IOTWebsocket::listening(){   //监听websocket消息
    o2webSocket.loop();             //监听websocket消息
}

O2IOTWebsocket O2_IOTWebsocket;

此时O2IOTWebsocket类已经创建,它完成了websocket连接地址端口的获取,并连接到websocket,响应的websocket事件。但是在websocket事件中,只是在串口输出了信息,以便我们确认收到了服务器发来的消息。后续我们将在O2OA系统中创建门户页面,通过脚本向设备发送消息,设备收到消息后进行解析,并让esp8266执行相应的动作,如让GPIO口输出PWM,通过软串口控制红外模块等,以到达通过web页面控制设备的目的。这些将在后续章节一一介绍。

现在我们需要在O2OA平台中创建上述代码中调用的getService接口。

创建getService接口

以服务管理员身份登录O2OA服务器,进入服务管理平台,新建一个接口,命名为“getService”。此接口要实现的功能是,获取消息体中的content字段,向服务器请求所有服务器地址,并返回请求消息体中要求的“content”字段所对应的服务地址和端口。代码如下:

//将请求消息体解析为json
var res = JSON.parse(this.requestText.toString());
//获取请求消息体中的content
var content = res.content;
//获取请求消息体中的source,从O2IOTWebsocket类中的代码可以看到,这个就是中心服务器的地址
var source = res.source;

//发起获取所有服务地址的请求
this.Actions.load("x_program_center").DistributeAction.assemble(source, function(json){
    //获取的content对应的地址信息
    var o = json.data[content];
    //将其包装成新的json,作为响应的消息体
    this.response.setBody({"data": {"host": o.host, "port": o.port}}, "application/json");
}.bind(this));

image.png

配置自定义消息

O2OA平台可以配置自定义消息,配置了自定义消息后就可以通过服务或脚本向用户推送消息,当然也包括websocket消息。

本项目中,需要一个自定义消息的类型配置,用于发送websocket消息给设备。

打开O2OA平台系统设置-平台设置-message(消息发送配置):

image.png

image.png

本项目中,创建了一个名为“custom_iot”的消息配置(自定义的消息必须以“custom_”开头)

在此json配置文件的最后添加一组消息配置:

java">"custom_iot": {
  "consumers": [],
  "consumersV2": {
    "ws": ""
  }
}

因为我们只需要发送websocket消息,所以在consumersV2中只添加ws字段。关于消息配置的详细说明请参考文档库中的相关文档。

在O2IOTClient类中调用

我们需要在O2IOTClient类中调用O2IOTWebsocket类,在O2IOTClient类获取到登录token之后,发起websocket连接,需要在O2IOTClient.h文件中,加入对O2IOTWebsocket类的引用,并增加三个方法:wensocketBegin和webSocketListening,以及一个表示websocket是否连接成功的布尔型变量:connectedWebsocket。修改后的O2IOTClient.h文件如下。修改内容为第9行、30-32行。

#ifndef O2IOTCLIENT_H_
#define O2IOTCLIENT_H_

#include <ESP8266WiFiMulti.h>   //引用ESP8266的WiFi库
#include <ESP8266HTTPClient.h>  //引用ESP8266的HttpClient库
#include <EEPROM.h>             //引用EEPROM库
#include "ArduinoJson.h"        //引用ArduinoJson库

#include "O2IOTWebsocket.h"     //+此处添加对O2IOTWebsocket类的引用

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();             //解析设备配置信息
    
    bool connectedWebsocket;    //+表示websocket是否连接成功
    void websocketBegin();      //+连接websocket
    void webSocketListening();  //+监听websocket事件
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_ */
接着要实现新添加的方法,在O2IOTClient.cpp文件中添加以下方法:

void O2IOTClient::websocketBegin(){
    connectedWebsocket = O2_IOTWebsocket.begin();   //调用O2IOTWebsocket对象的begin方法,发起连接
    if (connectedWebsocket) blink(4);               //如果连接成功,led灯闪速4次。
}
void O2IOTClient::webSocketListening(){
    if (connectedWebsocket) O2_IOTWebsocket.listening();    //监听websocket事件
}
然后在O2IOTClient的begin方法中,调用websocketBegin方法:

bool O2IOTClient::begin() { //开始连接WiFi和登录
    Serial.println("begin");
    EEPROM.begin(512);      //ESP8266使用EEPROM需要首先调用EEPROM.begin(size)方法
    if (connect()){         //将设备连接到WiFi热点
        blink(2);
        if (_getToken()){   //登录到O2OA服务器,并获取toekn
            blink(3);       //如果成功登录,并获取到token,让设备led灯闪烁3次
            websocketBegin();   //+获取token成功后,连接websocket
        }   
    }
    return false;
}

在设备主程序中调用

我们回到o2iot.ino文件,更新一下代码,加入监听Websocket事件。第15行。

#include "Arduino.h"        //引用Arduino核心库
#include "O2IOTServer.h"    //引用O2IOTServer类
#include "O2IOTClient.h"    //引用O2IOTClient类
void setup() {
    Serial.begin(115200);               //初始化串口,波特率为115200
    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请求
    O2_IOTClient.webSocketListening();      //+监听Websocket事件
}

验证和上载程序

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

看看效果

在上一步中,我们已经初始化设置了设备配置信息,由于配置信息是写在EEPROM存储器中,在重新下载程序时,是不会清除EEPROM信息的,所以不需要重新设置了。

设备重新上电后,我们可以看到设备连接到wifi后,led灯闪烁2次,登录到O2OA后闪烁3次,连接websocket成功后闪烁4次。

同时,可以在串口监视器中看到如下的输出结果:

image.png

此时,可以通过O2OA平台服务发送个websocket消息,给登录用户,在设备就会接收到消息,并把消息内容输出到串口。

打开O2OA平台的服务页面:http://xxx.xxx.xxx..xxx:20030/x_program_center,在列出的服务列表中点击:“消息通讯”的服务连接:

image.png

然后在左边导航找到“MessageAction”-“customCreate”:

image.png

此方法用于发送一个自定义消息给指定的人。

在“type类型”中填写“custom_iot”(就是我们创建的自定义消息类型)

在“person人员”中填写“iot@iot@P”(上一章中创建的用户全称)

在“title标题”中填写“测试消息标题”(随意填写,本项目中没有用到)

在“body推送内容”中填写“{"type": "gpio", "gpio": "12", "value": 1}”(body必须是一个json格式的字符串,任意都可以,这个json的作用,在后面章节介绍,这里我们只要确保设备收到了消息即可)。

然后点击“post”按钮:

可以看到请求发送成功。(如果发送不成功,请检查自定义消息类型配置、body的格式是否符合json规范,person是否填写了用户的全称)

image.png

同时,在串口监视器中,可以看到设备接收到了服务器发出的信息,并在监视器中打印出来了:

image.png

说明通过websocket传递消息的路径已经联通了,就可以控制设备了。

下一章,我们就介绍通过websocket消息,点亮金鱼灯,并实现调光。


http://www.niftyadmin.cn/n/953295.html

相关文章

开源OA办公平台搭建:流程开发中常见的正则表达式

在线测试正则地址 https://tool.oschina.net/regex/ 腾讯QQ号 腾讯QQ号从10000开始 [1-9][0-9]{4,} 中国邮政编码 中国邮政编码为6位数字 [1-9]\d{5}(?!\d) 邮箱 xxxgmail.com 只允许英文字母、数字、下划线、英文句号、以及中划线组成 ^[a-zA-Z0-9_-][a-zA-Z0-9_-](\.[a-…

O2OA开源企业应用开发平台——关于企业网盘

许多企业都需要一款可以集中储存、管理公司内的文件的企业网盘&#xff0c;网盘不仅要确保数字资产安全&#xff0c;更需要支持远程访问、多端协作&#xff0c;随时随地将文件分享给同事、客户、合作伙伴&#xff0c;为协同办公添砖加瓦。 O2OA开源企业应用开发平台是基于J2EE…

小众好用的开源协同OA项目,或许你也正在找这个?

虽然这样的标题&#xff0c;大家也司空见惯了&#xff0c;但是今天给大家介绍的&#xff0c;确确实实是一款鲜为人知&#xff0c;但是无比好用的全开源协同OA项目&#xff0c;它的名字叫做&#xff1a;O2OA企业应用开发平台&#xff08;简称O2OA平台&#xff09;。 O2OA平台是什…

java开源办公OA项目:通过极光SDK获取设备号绑定到用户属性

用户需求&#xff1a;用户自行开发app&#xff0c;想通过O2OA集成的极光推送消息把O2OA的消息发送到自己的app中。前提是这个app需要集成极光的SDK。 关于集成极光SDK可以参考极光官方的文档&#xff1a;集成文档 获取手机设备号 集成完成后&#xff0c;使用SDK获取当前设备的…

开源协同OA应用市场新功能:流程管理数据迁移使用手册

本应用的使用范围面向系统维护管理员。用于系统迁移时迁移流程相关的工作实例。 功能简介 通过配置的方式导入老系统的历史数据到自建表中去&#xff0c;然后从自建表再生成相应的工作实例&#xff0c;只支持导入流转完成的work数据。 系统要求 需要服务器安装或者升级到O2…

开源快速开发协同OA:给政府做个好用的OA系统吧

对于政府来说&#xff0c;OA最重要的功能&#xff0c;绝对是公文管理&#xff0c;没有之一。它的存在&#xff0c;能够极大程度提高办公效率&#xff0c;而且响应“绿色办公”号召&#xff0c;节省办公成本。公文管理包含着公文的流转、审批&#xff0c;这个过程会涉及多个组织…

开源企业开发平台教程干货:在O2OA中使用网络会议(二)

O2OA支持将o2server本身作为OAUTH服务器&#xff0c;也支持将o2server作为客户端接入到其他的OAUTH服务器中。 此例中&#xff0c;我们以O2Server本身作为OAUTH服务器&#xff0c;这也是通常的配置方案&#xff0c;O2Server中有完整的组织人员信息&#xff0c;并且投入协同办公…

Java开源企业开发平台教程:老版本custom后端源码编译

一、 功能介绍 在O2Server服务器源码目录下编译老版本custom后端源码&#xff0c;以crm&#xff08;客户管理&#xff09;为例 二、开发环境 1&#xff0c;JDK1.8 2&#xff0c;maven V3.5 3&#xff0c;运行环境 o2server V5.3 三、关于O2Server服务器源码整体编译 crm源码…