Retrofitting for Brownfield Systems with TinyAutomator

It's time to solve a real-life issue you have in your production line! 🏭

Retrofitting for Brownfield Systems with TinyAutomator

Motivation

First of all, check out our Introduction to TinyAutomator tutorial to have the stack installed on your compatible hardware. It's time to solve a real-life issue you have in your production line!

In the industrial environment, a production line has a life expectancy between 10 and 30 years, varying from one domain to another with the conditions in the facility, the frequency and quality of maintenance procedures and use time.

As time passes and technologies become obsolete, equipping old machinery with new functional extensions like electrical consumption monitoring, temperature and cycle speed measurement and wireless connectivity ensures the rentability of the machine and the competitiveness of the production line in the long run.

If you have more production lines in your factory chances are they were bought in batches and while the new ones have all the data collected in neat dashboards, the old ones simply do not have the sensors to gather all that data. Identifying these blind spots will be the first task in retrofitting the system to bring it up to speed with current technology.

Our use case 🏭

The facility in which we deployed this device is equipped with numerous plastic extruders and while most are less than 5 years old, some of them have been pushing out plastic for longer than 20 years and monitoring their running parameters is critical in making them fit in with the newer equipment.

Our machinery is a KME 75-36 B/R single-screw extruder from 2007 by KraussMaffei.

KME 75-36 B/R single-screw extruder from 2007 by KraussMaffei

We want to track a few more temperatures in certain areas of the extruder based on the feedback from the employees and trigger an automatic response based on it via a relay.

Because of the sheer length of the machine, we opted for making the hardware components connect wirelessly and send data through MQTT.

Things used in this project

Hardware components

NORVI-IIOT-AE02-V×1

Industrial Shields Raspberry PLC CPU - Configurable×1

Power supply (12-24V and > 1.5A)×1NTC Temperature Sensor×3

Software apps and online services

Waylay TinyAutomator

Hand tools and fabrication machines

Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires

Wire Stripper / Crimper, 10AWG - 20AWG Strip
Wire Stripper / Crimper, 10AWG - 20AWG Strip

Hardware requirements 🧰

  • Industrial Shields RPI based PLC - running a TinyAutomator instance
  • NTC Temperature sensors

Data gathering 📊

For our use case, we had to monitor the temperature at different points on the production line.

We accomplished this with NTC based sensors that were read by a NORVI-IIOT-AE02-V that sends the data over MQTT to the TinyAutomator concentrator that based on the readings takes the decisions and acts accordingly.

Communication block diagram

You can find the code attached for the sensors being read and sent to the concentrator (the ReadNTC10k_SendMqtt.ino file from the Github repository).

#include 
#include 
#include 
#include 
#include 

Adafruit_ADS1115 ads1;

float Voltage = 0.0;

//////////temp sensor ////////
int decimalPrecision = 2;               // decimal places for all values shown in LED Display & Serial Monitor


/* 1- Temperature Measurement */

//int ThermistorPin = A5;                 // The analog input pin for measuring temperature
float voltageDividerR1 = 5100;         // Resistor value in R1 for voltage devider method
float BValue = 3977;                    // The B Value of the thermistor for the temperature measuring range
float R1 = 10000;                        // Thermistor resistor rating at based temperature (25 degree celcius)
float t1 = 298.15;                      /* Base temperature t1 in Kelvin (default should be at 25 degree)*/
float R2 ;                              /* Resistance of Thermistor (in ohm) at Measuring Temperature*/
float t2, Temperature ;                             /* Measurement temperature t2 in Kelvin */

float a ;                               /* Use for calculation in Temperature*/
float b ;                               /* Use for calculation in Temperature*/
float c ;                               /* Use for calculation in Temperature*/
float d ;                               /* Use for calculation in Temperature*/
float e = 2.718281828 ;                 /* the value of e use for calculation in Temperature*/

float tempSampleRead  = 0;               /* to read the value of a sample including currentOffset1 value*/
float tempLastSample  = 0;               /* to count time for each sample. Technically 1 milli second 1 sample is taken */
float tempSampleSum   = 0;               /* accumulation of sample readings */
float tempSampleCount = 0;               /* to count number of sample. */
float tempMean ;                         /* to calculate the average value from all samples, in analog values*/

//////////

const char* ssid = "WifiSSid";
const char* password =  "WifiPwd";
const char* mqttServer = "IpAddressMqttTinyAutomator";
const int mqttPort = 1883;
#define MQTT_PUB_TEMP "test-topic"
//const char* mqttUser = "yourInstanceUsername";
//const char* mqttPassword = "yourInstancePassword";

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  ads1.setGain(GAIN_ONE);
  ads1.begin(0x48, &Wire);

  Wire.begin(16, 17);
  Serial.begin(115200);
  Serial.println();

  WiFi.begin(ssid, password);
  Serial.println("Connecting to WIFI…");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());
  Serial.println("After 10 seconds the first reading will be displayed");
  client.setServer(mqttServer, mqttPort);
  //
  while (!client.connected()) {
    Serial.println("Connecting to MQTT...");

    if (client.connect("ESP32Client"/*, mqttUser, mqttPassword */)) {

      Serial.println("connected");

    } else {

      Serial.print("failed with state ");
      Serial.print(client.state());
      delay(2000);

    }
  }

}

void loop() {
for(int i=0;i<99;i++){
  int16_t adc1, ts;
  float volts0, tm;
   if (millis() >= tempLastSample + 1)  {
    tm = ads1.readADC_SingleEnded(0);
    ts = map(tm, 0, 16000, 0, 1023);
    //Serial.print(tm);
    // Serial.println(ts);
    tempSampleRead = ts;                                                                         /* read analog value from sensor */
    tempSampleSum = tempSampleSum + tempSampleRead;                                             /* add all analog value for averaging later*/
    tempSampleCount = tempSampleCount + 1;                                                      /* keep counting the sample quantity*/
    tempLastSample = millis();                                                                  /* reset the time in order to repeat the loop again*/
   }

  if (tempSampleCount == 100)                                                                        /* after 1000 sample readings taken*/
  {
    tempMean = tempSampleSum / tempSampleCount;                                                 /* find the average analog value from those data*/
    R2 = (voltageDividerR1 * tempMean) / (1023 - tempMean);                                     /* convert the average analog value to resistance value*/
    a = 1 / t1;                                                                                 /* use for calculation */
    b = log10(R1 / R2);                                                                         /* use for calculation */
    c = b / log10(e);                                                                           /* use for calculation */
    d = c / BValue ;                                                                            /* use for calculation */
    t2 = 1 / (a - d);                                                                           /* the measured temperature value based on calculation (in Kelvin) */
    Serial.print(t2 - 298.15, decimalPrecision);                                                /* display in Serial monitor the temperature in Celcius*/
    Serial.println(" °C");
    Temperature = t2 - 298.15;
  
    tempSampleSum = 0;                                                                          /* reset all the total analog value back to 0 for the next count */
    tempSampleCount = 0;                                                                        /* reset the total number of samples taken back to 0 for the next count*/
  }
  delay(10);
}
  char buffer1[256];
  StaticJsonDocument<300> doc;
  //JsonObject& doc = doc.createObject();

  doc["device"] = "ESP32";
  doc["sensorType"] = "Temperature";
  doc["value"] = Temperature;

  char JSONmessageBuffer[100];
  serializeJson(doc, Serial);
  serializeJson(doc, buffer1);
  Serial.println("Sending message to MQTT topic..");
  Serial.println(JSONmessageBuffer);

  if (client.publish(MQTT_PUB_TEMP, buffer1) == true) {
    Serial.println("Success sending message");
  } else {
    Serial.println("Error sending message");
  }

  client.loop();
  Serial.println("-------------");


  delay(10000);

}

Low-code programming 💻

Open your TinyAutomator instance in your browser and go to the Resources tab. You will see the resource already created if you succeeded in sending the data over MQTT in the previous step.

Now go to Templates, click the arrow next to the Add template button, then click Upload template and add the following template that we have created that you can adjust according to your needs (the ActuatorExample.json file from the Github repository):

{
  "sensors": [
    {
      "label": "condition_1",
      "name": "condition",
      "version": "1.1.6",
      "properties": {
        "condition": "${nodes.stream_1.rawData.stream.value}>23"
      },
      "position": [
        397,
        329
      ],
      "dataTrigger": false,
      "tickTrigger": true,
      "timeout": "PT50S"
    },
    {
      "label": "debugDialog_1",
      "name": "debugDialog",
      "version": "1.0.2",
      "position": [
        646,
        309
      ],
      "dataTrigger": false,
      "tickTrigger": true,
      "timeout": "PT50S"
    },
    {
      "label": "debugDialog_2",
      "name": "debugDialog",
      "version": "1.0.2",
      "properties": {
        "message": "actutor on"
      },
      "resource": "test-topic",
      "position": [
        838,
        408
      ],
      "dataTrigger": false,
      "tickTrigger": true,
      "timeout": "PT50S"
    },
    {
      "label": "sendMQTTmessage_1",
      "name": "sendMQTTmessage",
      "version": "1.0.4",
      "properties": {
        "server": "192.168.0.161",
        "port": 1883,
        "message": "1",
        "topic": "inTopic",
        "protocol": "mqtt"
      },
      "resource": "test-topic",
      "sequence": 0,
      "position": [
        630,
        404
      ],
      "dataTrigger": false,
      "tickTrigger": true,
      "timeout": "PT50S"
    },
    {
      "label": "stream_1",
      "name": "stream",
      "version": "1.0.1",
      "resource": "test-topic",
      "position": [
        154,
        332
      ],
      "dataTrigger": true,
      "tickTrigger": false,
      "timeout": "PT50S"
    }
  ],
  "triggers": [
    {
      "sourceLabel": "sendMQTTmessage_1",
      "destinationLabel": "debugDialog_2",
      "statesTrigger": [
        "Success"
      ]
    },
    {
      "sourceLabel": "stream_1",
      "destinationLabel": "condition_1"
    },
    {
      "sourceLabel": "condition_1",
      "destinationLabel": "sendMQTTmessage_1",
      "statesTrigger": [
        "True"
      ]
    },
    {
      "sourceLabel": "condition_1",
      "destinationLabel": "debugDialog_1",
      "statesTrigger": [
        "True"
      ]
    }
  ],
  "name": "ActuatorExample",
  "user": "test@waylay.io",
  "createTime": 1641396098756,
  "lastUpdateTime": 1641467955080,
  "discoveryTemplate": false,
  "taskDefaults": {
    "type": "reactive",
    "tags": {}
  }
}

As you can see, when the TinyAutomator receives a temperature value over 24 over MQTT it triggers an automatic response from the relay module that starts the actuator to signal the threshold detection.

Trigger handling 🚀

Here is the code for the relay module based on the same NORVI-IIOT-AE02-V module used for data gathering in the first step SubscribeMqtt_DeserializeJson_TriggerRelay.ino file from the Github repository).

#include 
#include 

// Update these with values suitable for your network.

const char* ssid = "WifiSSID";
const char* password = "WifiPWd";
const char* mqtt_server = "IpAddressMqttTinyAutomator";

WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE  (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;
#define LED_pin  12
void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  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();

  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(LED_pin, HIGH);
    delay(2000);
    digitalWrite(LED_pin, LOW);

  }

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP32Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");

      // ... and resubscribe
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  pinMode(LED_pin, OUTPUT);     
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);


}

void loop() {

  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

While you could do this logic directly on the PLC updating it in the future or logging it could be cumbersome, especially when dealing with multiple devices or long distances between measure points.

What’s next? 🚀

"happy machinery sounds"

While this is a simple example of how you can retrofit an existing machine or production line with needed functionality, of course, if needed, even direct integration with the PLC of the machinery can be done.

We have other tutorials from which you can learn to use TinyAutomator for industrial use-cases:

  • Predictive Maintenance with TinyAutomator
  • Quality Assurance with TinyAutomator

If you need help in deploying this solution or building something similar please contact Waylay.io for the low-code IoT Solution or Zalmotek.com for IoT-enabled hardware prototypes.

Github Repository

Zalmotek / Retrofitting_for_brownfield_systems_with_tiny_automator