Hackster is hosting Hackster Holidays, Finale: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Tuesday!Stream Hackster Holidays, Finale on Tuesday!
Emile Ackbarali
Published © GPL3+

SCADA Using Cellular IoT with MKR GSM 1400

Applying IoT technologies to revive an old SCADA telemetry system.

IntermediateFull instructions provided3 hours5,999
SCADA Using Cellular IoT with MKR GSM 1400

Things used in this project

Hardware components

Arduino MKR GSM 1400
Arduino MKR GSM 1400
×1
MAX485 TTL to RS485 Converter
×1
MT-102 GSM RTU from Inventia
×1

Software apps and online services

Arduino IDE
Arduino IDE
Visual Studio 2017
Microsoft Visual Studio 2017

Story

Read more

Code

ModbusReader01

Arduino
Reads a single Input Register value and displays it on the serial monitor.
// ---------------------------------------------------------------------------
// Include the base required libraries
// ---------------------------------------------------------------------------
#include <Arduino.h>
#include <SensorModbusMaster.h>

// ---------------------------------------------------------------------------
// Set up the MT-102 Modbus slave information
// ---------------------------------------------------------------------------

// Define the sensor's modbus address
byte modbusAddress = 0x01;    // The sensor's modbus address, or SlaveID
long modbusBaudRate = 9600;   // The baud rate the sensor uses

// Define pin number variables
const int DEREPin = 7;       // The pin controlling Recieve Enable and Driver Enable

// Serial1 is the serial port used on the MKR 1400
HardwareSerial* modbusSerial = &Serial1;

// Construct the modbus instance
modbusMaster modbus;

// ---------------------------------------------------------------------------
// Main setup function
// ---------------------------------------------------------------------------
void setup()
{
    pinMode(DEREPin, OUTPUT);
    
    // Turn on the "main" serial port for debugging via USB Serial Monitor
    Serial.begin(9600);

    // Turn on your modbus serial port
    Serial1.begin(modbusBaudRate, SERIAL_8N1);

    // Turn on debugging, if desired
    // modbus.setDebugStream(&Serial);

    // Start the modbus instance
    modbus.begin(modbusAddress, modbusSerial, DEREPin);

}

// ---------------------------------------------------------------------------
// Main setup function
// ---------------------------------------------------------------------------
void loop()
{
    // Get data values from read-only input registers (0x04)
    uint16_t analog01 = 0;

    analog01 = modbus.int16FromRegister(0x04, 0x04, bigEndian);

    // Print results
    Serial.print("Analog_Input_01: ");
    Serial.println(analog01);

    delay(3000);
}

ModbusMQTT01

Arduino
// ---------------------------------------------------------------------------
// Include the base required libraries
// ---------------------------------------------------------------------------
#include <ArduinoMqttClient.h>
#include <MKRGSM.h>
#include <Arduino.h>
#include <SensorModbusMaster.h>
#include "arduino_secrets.h" 

// ---------------------------------------------------------------------------
// Set up the MT-102 Modbus slave information
// ---------------------------------------------------------------------------

// Define the RTU's modbus address
byte modbusAddress = 0x01;    // The RTU's modbus address, or SlaveID
long modbusBaudRate = 9600;   // The baud rate the sensor uses

// Define pin number variables
const int DEREPin = 7;       // The pin controlling Recieve Enable and Driver Enable

// Serial1 is the serial port used on the MKR 1400
HardwareSerial* modbusSerial = &Serial1;

// Construct the modbus instance
modbusMaster modbus;

// ---------------------------------------------------------------------------
// Set up the information for 2G/3G data connection
// ---------------------------------------------------------------------------

// Please enter your sensitive data in the Secret tab or arduino_secrets.h
// PIN Number
const char PINNUMBER[]     = SECRET_PINNUMBER;
// APN data
const char GPRS_APN[]      = SECRET_GPRS_APN;
const char GPRS_LOGIN[]    = SECRET_GPRS_LOGIN;
const char GPRS_PASSWORD[] = SECRET_GPRS_PASSWORD;

// To connect with SSL/TLS:
// 1) Change GSMClient to GSMSSLClient.
// 2) Change port value from 1883 to 8883.
// 3) Change broker value to a server with a known SSL/TLS root certificate 
//    flashed in the WiFi module.

GPRS gprs;
GSM gsmAccess;
GSMClient gsmClient;
MqttClient mqttClient(gsmClient);

const char broker[] = "mqtt.eclipse.org";
int        port     = 1883;
const char topic[]  = "eackbarali/to";
const char publishTopic[]  = "eackbarali/analog";

// ---------------------------------------------------------------------------
// Main setup function
// ---------------------------------------------------------------------------

void setup() {
  
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // attempt to connect to GSM and GPRS:
  Serial.print("Attempting to connect to GSM and GPRS");
   // connection state
  bool connected = false;

  // After starting the modem with GSM.begin()
  // attach the shield to the GPRS network with the APN, login and password
  while (!connected) {
    if ((gsmAccess.begin(PINNUMBER) == GSM_READY) &&
        (gprs.attachGPRS(GPRS_APN, GPRS_LOGIN, GPRS_PASSWORD) == GPRS_READY)) {
      connected = true;
    } else {
      Serial.println("Not connected");
      delay(1000);
    }
  }

  Serial.println("You're connected to the network");
  Serial.println();

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(broker);

  if (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());

    while (1);
  }

  Serial.println("You're connected to the MQTT broker!");
  Serial.println();

  pinMode(DEREPin, OUTPUT);

  // Turn on your modbus serial port
  Serial1.begin(modbusBaudRate, SERIAL_8N1);

  // Start the modbus instance
  modbus.begin(modbusAddress, modbusSerial, DEREPin);

}

void loop() {

  uint16_t analog01 = 0;
  
  // call poll() regularly to allow the library to receive MQTT messages and
  // send MQTT keep alives which avoids being disconnected by the broker
  mqttClient.poll();

  // read the first Analog pin
  //int sensorVal = analogRead(0);
  analog01 = modbus.int16FromRegister(0x04, 0x04, bigEndian);
  
  // Publish our sensor value
  mqttClient.beginMessage(publishTopic);
  mqttClient.print(analog01);
  mqttClient.endMessage();

  // Print results
  Serial.print("Analog_Input_01: ");
  Serial.println(analog01);

  // Set the rate at which we send our values
  delay(5000);
  
}

MQTT to Modbus TCP .NET Forms Application Code

VB.NET
Reads a single topic from a cloud MQTT broker and exposes the value via a Modbus TCP Server
Public Class Form1

    Dim client As MqttClient
    Dim Msg As String
    Dim modbusServer = New EasyModbus.ModbusServer

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If (TextBox1.Text.Length <> 0) Then


            Try
                client = New MqttClient(TextBox1.Text)

                Dim clientId As String = Guid.NewGuid().ToString()

                AddHandler client.MqttMsgPublishReceived, AddressOf Client_MqttMsgPublishReceived
                AddHandler client.ConnectionClosed, AddressOf Client_Disconnect

                client.Connect(clientId)

                If client.IsConnected Then
                    ComboBox1.SelectedIndex = 0
                    'ComboBox2.SelectedIndex = 0

                    ToolStripStatusLabel1.Text = "Connected to " + "'" + TextBox1.Text + "'"
                Else
                    ToolStripStatusLabel1.Text = "Disconnected"
                End If

            Catch ex As Exception

                ToolStripStatusLabel1.Text = "Error"
                MsgBox(ex.Message(), MsgBoxStyle.Critical)
            End Try
        Else
            ToolStripStatusLabel1.Text = "Please enter a valid Broker address "

        End If
    End Sub

    Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
        If (client IsNot Nothing AndAlso client.IsConnected()) Then
            client.Disconnect()
        Else
            ToolStripStatusLabel1.Text = "Error"
        End If
    End Sub

    Private Sub Client_Disconnect(sender As Object, e As EventArgs)
        ToolStripStatusLabel1.Text = "Connection Lost"
    End Sub

    Private Sub Client_MqttMsgPublishReceived(ByVal sender As Object, ByVal e As MqttMsgPublishEventArgs)

        Msg = Encoding.Default.GetString(e.Message)
        SetText(Msg.ToString)

    End Sub

    Delegate Sub SetTextCallback(newString As String)
    Private Sub SetText(ByVal newString As String)
        ' Calling from another thread? -> Use delegate
        If Me.TextBox2.InvokeRequired Then
            Dim d As New SetTextCallback(AddressOf SetText)
            ' Execute delegate in the UI thread, pass args as an array
            Me.Invoke(d, New Object() {newString})
        Else ' Same thread, assign string to the textbox
            'Me.RichTextBox2.Text = newString
            Me.TextBox2.Text = newString
            modbusServer.InputRegisters(1) = CInt(newString)
        End If
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        If (client IsNot Nothing AndAlso client.IsConnected()) Then
            If (TextBox3.Text.Length <> 0) Then

                Try
                    Dim Topic() As String = {TextBox3.Text}
                    Dim Qos() As Byte = {ComboBox1.SelectedIndex}
                    client.Subscribe(Topic, Qos)
                    ToolStripStatusLabel1.Text = "Subscribe to " + "{" + TextBox3.Text + "}"

                Catch ex As Exception
                    ToolStripStatusLabel1.Text = "Error"
                    MsgBox(ex.Message, MsgBoxStyle.Critical)

                End Try


            Else
                ToolStripStatusLabel1.Text = "Please enter a valid topic "
            End If


        Else
            ToolStripStatusLabel1.Text = "Disconnected !! subscription procedure is not valid"
        End If


    End Sub

    Public Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load

        modbusServer.Listen()

    End Sub

End Class

Credits

Emile Ackbarali
1 project • 10 followers
I am a systems integrator in the field of industrial automation.

Comments