OPC-UA Web service - ESP32

martinius96
Posts: 9
Joined: Thu Dec 13, 2018 1:39 am

OPC-UA Web service - ESP32

Postby martinius96 » Thu Dec 26, 2019 8:44 pm

OPC UA architecture has been operating since 2008. Today I would like to write something about my implementation in Arduino core of a simple sensor network based on OPC UA architecture. The implementation includes standard client --> server communication, using various types of clients to send and receive information from a central web server. Communication for the easiest possible implementation works on a standard HTTP port 80. I originally extended the implementation for the ESP8266, Arduino with Ethernet module Wiznet W5100, W5500.

OPC UA webserver based on ESP32 platform can run in two main modes:
  • It runs STATION mode on existing LAN network
  • ESP32 becomes an access point - AP, boardcast its own encrypted WiFi network under the WPA / WPA2 - PSK protocol, or as an open WiFi network without encryption. ESP32 also takes care of assigning DHCP addresses to clients. The advantage is a separate WiFi network for OPC UA architecture.
The OPC UA webserver receives data from the client - value from ADC converter, or random datas. Webserver can also distribute these datas - to other clients, that are subscribers of that "topic". Subscribers can request this information by specific HTTP request. The system can be easily scalable, with one request it is possible to receive several data that are suitable formatted with a separator.

All data in the system is accessible in real time. The data is not stored, running on the webserver in its RAM memory. Webserver is also used for human interaction, as it is possible to connect to it from the browser, while it is possible to browse the data or control outputs via HTML page and its elements. The HTML page can also incorporate a simple SCADA visualization with the possibility of control through this visualization.

For implementation I used simple examples for HTTP webserver for ESP32 platform directly from examples. I have expanded the examples for the expected HTTP "requests" (their form) to specific GET subpages with parameters.

By implementing such a web server, I was able to build a simple communication network that is cross-platform. This means that if the OPC UA webserver is ESP32, we can use ESP8266 development boards, Arduino with Ethernet module, or other ESP32 development boards as clients.

Block diagram representing the OPC UA architecture used. (Common to all ESP platforms).
Image
Supported HTTP server queries:
  • URL | Function
  • / (Root) | Overview of recent data + automatic refresh of data on the page - accessable from Windows, smartphone device in same network. OUTPUT BELOW, value 943 for instance as last value:
  • Image
  • /data/?sensor_data=NUMBER | Server receiving datas via GET method using parameter sensor_data with value of NUMBER (Publish_Client), in that case 943 for instance
  • /get_data/ | Request data from a server (Subscriber_Client ) from the server -> value NUMBER, in that case 943 will send server to response HTTP payload
Client types:
  • Type | Function
  • Publish_Client | sends data from ADC converter to server, prints received server response - acknowledges received data sent
  • Publish_Client_UDP | sends data from ADC converter to server, skip server response (process it, do not write received response, do not work with it)
  • Subscriber_Client | performs an HTTP request to the server - the server responds with a received value from the (Publish) client, for example, the value can be a temperature. It is possible to work with the value, use it further (ventilation, boiler switching, relay)
In the advanced implementation of OPC UA architecture it is possible to use own Root CA certificate together with HTTPS encrypted transmission. You can also use client certificate authentication against the server.

The OPC UA implementation can also be used to send multiple data from clients to the server via one simple HTTP request, they must be separated by: &. The architecture can be expanded to include PLC or other systems used in automation, or Arduino, or ESP to implement the existing OPC UA network.

More about the project can be found at: https://arduino.php5.sk/opc-ua-esp8266.php?lang=en
Donate me for more examples and more free software: https://paypal.me/chlebovec
I will not publish the source code for OPC UA webserver. Since it took me a lot of effort to implement the webserver, I would like to offer the webserver program for a small payment, for example through PayPal. If interested, you can contact me via mail, which is available in the source code. Implementations for OPC UA clients are available free of charge. Codes were tested under Arduino Core 1.0.1. ESP32 can also be connected to eduroam powered network or similar under WPA/WPA2 Enterprise.

Video from implementation for ESP8266. ESP32 codes are almost the same: https://www.youtube.com/watch?v=pxey3PC_u8s
ESP32 OPC-UA Clients
Updated source codes: 22. March 2020
OPC-UA ESP32 Publish_Client:

Code: Select all

//ESP32 (devkit) - Publish_Client
//Author: Martin Chlebovec (martinius96)
//Web: https://arduino.php5.sk
//Donate: https://paypal.me/chlebovec

#include <WiFi.h>
const char * ssid = "WIFI_NAME";
const char * password = "WIFI_PASSWORD";
const char * host = "192.168.1.3"; //IP address of OPC-UA webserver --> second NodeMCU
const int httpPort = 80; //http port
unsigned long previousMillis = 0;
const long interval = 5000;
WiFiClient client;
void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi uspesne pripojene");
  Serial.println("IP adresa: ");
  Serial.println(WiFi.localIP());
  Serial.println("Ready");
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.begin(ssid, password);
  }
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  if (millis() - previousMillis >= interval) {
    previousMillis = millis();
    client.stop();
    String mac = WiFi.macAddress();
    String data = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n";
    data += "<ServiceRequest>\n";
    data += "<ID_BOARD>" + mac + "</ID_BOARD>\n";
    data += "<BME280_VALUE_PRESSURE>1013.48</BME280_VALUE_PRESSURE>\n";
    data += "<BME280_VALUE_TEMPERATURE>-20.34</BME280_VALUE_TEMPERATURE>\n";
    data += "<BME280_VALUE_HUMIDITY>48.55</BME280_VALUE_HUMIDITY>\n";
    data += "</ServiceRequest>\n";
    String url = "/body";
    if (client.connect(host, httpPort)) {
      client.println("POST " + url + " HTTP/1.0");
      client.println("Host: " + (String)host);
      client.println("User-Agent: ESP32");
      client.println("Connection: close");
      client.println("Content-Type: application/x-www-form-urlencoded;");
      client.print("Content-Length: ");
      client.println(data.length());
      client.println();
      client.println(data);
      while (client.connected()) {
        String line = client.readStringUntil('\n');
        if (line == "\r") {
          break;
        }
      }
      String line = client.readStringUntil('\n');
    } else {
      Serial.println("Problem connecting to webserver");
    }
  }
}
OPC-UA ESP32 Subscriber_Client:

Code: Select all

  
//ESP8266 (NodeMCU) - OPC-UA Client - XML (SOAP) data payload
//Autor: martinius96
//Web: https://arduino.php5.sk

#include <WiFi.h>
const char * ssid = "WIFI_NAME";
const char * password = "WIFI_PASSWORD";
const char * host = "192.168.1.3"; //IP address of OPC-UA webserver --> second NodeMCU
const int httpPort = 80; //http port
unsigned long previousMillis = 0;
const long interval = 5000;
String mac;
String bme_pressure;
String bme_temperature;
String bme_humidity;
WiFiClient client;

String midString(String str, String start, String finish) {
  int locStart = str.indexOf(start);
  if (locStart == -1) return "";
  locStart += start.length();
  int locFinish = str.indexOf(finish, locStart);
  if (locFinish == -1) return "";
  return str.substring(locStart, locFinish);
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi uspesne pripojene");
  Serial.println("IP adresa: ");
  Serial.println(WiFi.localIP());
  Serial.println("Ready");
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.begin(ssid, password);
  }
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  if (millis() - previousMillis >= interval) {
    previousMillis = millis();
    client.stop();
    String url = "/subscribe";
    if (client.connect(host, httpPort)) {
      client.println("POST " + url + " HTTP/1.0");
      client.println("Host: " + (String)host);
      client.println("User-Agent: ESP8266");
      client.println("Connection: close");
      client.println();
      while (client.connected()) {
        String line = client.readStringUntil('\n');
        if (line == "\r") {
          break;
        }
      }
      String line = client.readString();
      // Serial.println(line);
      mac = midString(line, "<ID_BOARD>", "</ID_BOARD>");
      bme_pressure = midString(line, "<BME280_VALUE_PRESSURE>", "</BME280_VALUE_PRESSURE>");
      bme_temperature = midString(line, "<BME280_VALUE_TEMPERATURE>", "</BME280_VALUE_TEMPERATURE>");
      bme_humidity = midString(line, "<BME280_VALUE_HUMIDITY>", "</BME280_VALUE_HUMIDITY>");
      Serial.println(mac);
      Serial.println(bme_pressure);
      Serial.println(bme_temperature);
      Serial.println(bme_humidity);
    } else {
      Serial.println("Problem connecting to webserver");
    }
  }
}

Who is online

Users browsing this forum: No registered users and 30 guests