DS18b20 to MODBUS TCP, 20x4 LCD and MQTT

Hi,

a project i have been working on a while ago...

I have a WAGO PFC200 with codesys for my home automation but wanted to use the DS18b20 sensors to monitor the temperature. You can't directly connect them to the PLC but you can buy a not so cheap converter to convert to MODBUS. I wondered if I could do it myself for cheaper. After hours of searching and copy-pasting and modifying it is working. Disclaimer. Almost non of this code is mine. I can not code and most of the code could as well be Chinese to me. I have used project from others to build this Frankenstein code and adjust where needed to finally get it working.

To real coders the code will probably look like crap but it works.

You need an Arduino mega because the code is too big to work on a UNO.
You also need a W5100 ethernet board and the 20x4 LCD screen

So the program reads the sensors and transmits the temperatures to modbus and displays them on the LCD. You can also send messages over MQTT (don't forget to insert username and password in the code). I use this now only to sent a message once in a while to let a receiver know it is still working :slight_smile:

Code in next post

#include <OneWire.h>
#include <DallasTemperature.h>
#include <SPI.h> 
#include <Ethernet.h> // Use Ethernet2.h if you are using a M-Duino PLUS version
#include "Mudbus.h"
#include "Wire.h" // For I2C
#include "LCD.h" // For LCD
#include "LiquidCrystal_I2C.h" // Added library*
#include "PubSubClient.h" //PubSubClient.h
#include <avr/wdt.h> //Watchdog timer

unsigned long switchMillis = 0;
unsigned long interval = 5000; //5 seconds for each lcd screen
byte count = 0;

boolean firstScreenFlag = false;
boolean secondScreenFlag = false;

 float TempC1 ;
 float TempC2 ;  
 float TempC3 ;
 float TempC4 ;
 float TempC5 ;
 float TempC6 ;
  
IPAddress server(192, 168, 1, 58);

// Function prototypes
void callback(char* topic, byte* payload, unsigned int length) {
  // handle message arrived
}

// MQTT
EthernetClient ethClient;
PubSubClient client(server, 1883, callback, ethClient);

Mudbus Mb;

//Red cable to +5V and Black/Grey cable to GND
//Yellow/Blue Cable is plugged into D3/Pin 3 on Arduino Proto Screw
#define One_Wire_Pin 3

//Thermometer resolution is programmable from 9 to 12 bits
#define Thermometer_Resolution 12

//Setup a one wire communication
OneWire One_Wire(One_Wire_Pin);

//Pass our oneWire reference to Dallas Temperature. 
DallasTemperature Temperature_Sensor(&One_Wire);

//Setup Temperature Sensor Address
DeviceAddress Temperature_Sensor1_Address = {0x28, 0xFF, 0xAF, 0x98, 0x42, 0x18, 0x01, 0x53};
DeviceAddress Temperature_Sensor2_Address = {0x28, 0xFF, 0x8F, 0x83, 0x42, 0x18, 0x01, 0x07};
DeviceAddress Temperature_Sensor3_Address = {0x28, 0xFF, 0x31, 0x4B, 0x40, 0x18, 0x03, 0x3C};
DeviceAddress Temperature_Sensor4_Address = {0x28, 0xFF, 0x11, 0x96, 0x66, 0x18, 0x01, 0xA1};
DeviceAddress Temperature_Sensor5_Address = {0x28, 0xFF, 0xA3, 0x96, 0x66, 0x18, 0x01, 0x6D};
DeviceAddress Temperature_Sensor6_Address = {0x28, 0xFF, 0xB3, 0xED, 0x66, 0x18, 0x01, 0x2D};

LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);    // Set the LCD I2C address

// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis1 = 0;        
unsigned long previousMillis2 = 0;        
unsigned long previousMillis3 = 0;        
unsigned long previousMillis4 = 0;  

// constants won't change:
const long interval1 = 1500; 
const long interval2 = 6000;
const long interval3 = 10000;
const long interval4 = 10000;

long lastReconnectAttempt = 0;

boolean reconnect() {
  if (client.connect("myClientID","username","password")) { //username and password for MQTT server
    // Once connected, publish an announcement...
    client.publish("outTopic","hello world");
    // ... and resubscribe
    client.subscribe("inTopic");
  }
  return client.connected();
}

void setup(void)
{
wdt_enable(WDTO_8S); //set watchdog timer to 8S

// start serial port
  Serial.begin(9600);

lcd.begin(20,4);   // initialize the lcd for 20 chars 4 lines, turn on backlight

//Modbus Slave Setup  
  uint8_t mac[]     = { 0x90, 0xA2, 0xDA, 0x00, 0x51, 0x06 };
  uint8_t ip[]      = { 192, 168, 1, 29 };
  uint8_t gateway[] = { 192, 168, 1, 1 };
  uint8_t subnet[]  = { 255, 255, 255, 0 };
  Ethernet.begin(mac, ip, gateway, subnet);
  //With the last update of Industrial Shields boards it's not necessary to use function pinMode()

delay(2000);

  lastReconnectAttempt = 0;

if (client.connect("myClientID","username","password")) 
  {
    Serial.println("Connection has been established, well done");
 
    // Establish the subscribe event
 client.setCallback(callback);
  } 
  else 
  {
    Serial.println("Looks like the server connection failed...");
  }
  
//Temperature Sensor Setup
  Temperature_Sensor.begin();
 Temperature_Sensor.setResolution(Temperature_Sensor1_Address, Thermometer_Resolution);
 Temperature_Sensor.setResolution(Temperature_Sensor2_Address, Thermometer_Resolution);
 Temperature_Sensor.setResolution(Temperature_Sensor3_Address, Thermometer_Resolution);
 Temperature_Sensor.setResolution(Temperature_Sensor4_Address, Thermometer_Resolution);
 Temperature_Sensor.setResolution(Temperature_Sensor5_Address, Thermometer_Resolution);
 Temperature_Sensor.setResolution(Temperature_Sensor6_Address, Thermometer_Resolution);
 
// ------- Quick 3 blinks of backlight  -------------
 for(int i = 0; i< 3; i++)
 {
   lcd.backlight();
   delay(250);
   lcd.noBacklight();
   delay(250);
 }
 lcd.backlight(); // finish with backlight on  
}

void loop() {
    readtemp();
    modbus(); 
    MQTT();
    scherm();
}

void readtemp()
{ 
  unsigned long currentMillis4 = millis();

  if (currentMillis4 - previousMillis4 >= interval4) {
    previousMillis4 = currentMillis4;
    
Serial.print("lees temperaturen van sensoren");
  
 Temperature_Sensor.requestTemperatures(); 
 //Resolution=9 delay time 94ms per sensor
 //Resolution=10 delay time 188ms per sensor
 //Resolution=11 delay time 375ms per sensor
 //Resolution=12 delay time 750ms per sensor
 //Error -127.00
 TempC1 = Temperature_Sensor.getTempC(Temperature_Sensor1_Address)*100;
 TempC2 = Temperature_Sensor.getTempC(Temperature_Sensor2_Address)*100;  
 TempC3 = Temperature_Sensor.getTempC(Temperature_Sensor3_Address)*100;
 TempC4 = Temperature_Sensor.getTempC(Temperature_Sensor4_Address)*100;
 TempC5 = Temperature_Sensor.getTempC(Temperature_Sensor5_Address)*100;
 TempC6 = Temperature_Sensor.getTempC(Temperature_Sensor6_Address)*100;
  }}

void modbus()
{ 
  unsigned long currentMillis1 = millis();

  if (currentMillis1 - previousMillis1 >= interval1) {
    previousMillis1 = currentMillis1;
    
Serial.print("loop Modbus");

Mb.Run();

  //Digital outputs
  Mb.R[0] = (word)random(1000);
  Mb.R[1] = (word)TempC1;
  Mb.R[2] = (word)TempC2; 
  Mb.R[3] = (word)TempC3; 
  Mb.R[4] = (word)TempC4; 
  Mb.R[5] = (word)TempC5; 
  Mb.R[6] = (word)TempC6; 
}}

void scherm() {
  if (millis() - switchMillis > interval)
  {
    count++;

    if (count == 1)
      firstScreenFlag = true;

    if (count == 2)
    {
      secondScreenFlag = true;
      count = 0;
    }

    switchMillis += interval; //millis();
  }

  if (firstScreenFlag)
  {
    doLcdMsg();
    firstScreenFlag = false;
  }

  if (secondScreenFlag)
  {
    doLcdMsg2();
    secondScreenFlag = false;
  }
}

void doLcdMsg() {
  lcd.home();
  lcd.backlight();  //Backlight ON if under program control  

// Print our characters on the LCD
// NOTE: Line number and character number start at 0 not 1

  lcd.setCursor(0,0); //Start at character 0 on line 0
  lcd.print("BADKA: ");
  lcd.print(TempC5/100);
  lcd.print(" C     ");
  
  lcd.setCursor(0,1); //Start at character 0 on line 1
  lcd.print("BUR+1: ");
  lcd.print(TempC6/100);
  lcd.print(" C     ");
}

void doLcdMsg2() {
  lcd.home();
  lcd.backlight();  //Backlight ON if under program control  

// Print our characters on the LCD
// NOTE: Line number and character number start at 0 not 1

  lcd.setCursor(0,0); //Start at character 0 on line 0
  lcd.print("INKOM: ");
  lcd.print(TempC1/100);
  lcd.print(" C     ");
  
  lcd.setCursor(0,1); //Start at character 0 on line 1
  lcd.print("LIVIN: ");
  lcd.print(TempC2/100);
  lcd.print(" C     ");

  lcd.setCursor(0,2); //Start at character 0 on line 2
  lcd.print("EETKA: ");
  lcd.print(TempC3/100);
  lcd.print(" C     ");
  
  lcd.setCursor(0,3); //Start at character 0 on line 3
  lcd.print("BUR+0: ");
  lcd.print(TempC4/100);
  lcd.print(" C     ");
}

void MQTT()
{

wdt_reset();

  if (!client.connected()) {
    long now = millis();
    if (now - lastReconnectAttempt > 5000) {
      lastReconnectAttempt = now;
      // Attempt to reconnect
      if (reconnect()) {
        lastReconnectAttempt = 0;
      }
    }
  } else {
      unsigned long currentMillis3 = millis();

  if (currentMillis3 - previousMillis3 >= interval3) {
    previousMillis3 = currentMillis3;

  
   client.loop();

  // Ensure that we are subscribed to the topic
  client.subscribe("ArduinoDomitica");
 
  // Attempt to publish a value to the topic
  if(client.publish("ArduinoDomitica", "Arduino still alive"))
  {
    Serial.println("Publish message success");
  }
  else
  {
    Serial.println("Could not send message :(");
  }
    }}}