Monday, 28 July 2014

Connecting Arduino with DIoTY's Cloud MQTT Broker

In my previous post I showed how to get started with DIoTY's Cloud MQTT Broker.  Now that you are all set up, proved to yourself all is working, it's time to do something a little more interesting.  So today we will use an Arduino Uno and a temperature sensor to publish the current temperature to the MQTT Broker.

We use following hardware for our example:
  • Arduino Uno with ethernet shield
  • One-wire temperature sensor (DS18B20)
  • 4.7k resistor
  • breadboard and some wires
Make sure you verify the the pin layout before wiring as incorrect wiring can damage the sensor and the arduino + ethernet shield (and we accept no liability at all).

Wiring is done as in the picture below:


Next we need to load the software to the Arduino.  For this, first import the following two libraries into your Arduino Development Environment: OneWire and PubSubClient.

The latest OneWire library can be downloaded from Paul Stoffregen's site.
The latest PubSubClient library can be downloaded from GitHub.  Full documentation is found on Nick O'Leary's site.

If you haven't imported libraries before take a look at following guide.

Once the libraries are in place it's just a matter of copying and pasting the following code into the sketch, replacing the bits in red with values suitable for yourself.  Note that yourUserID is the email address with which you registered at DIoTY.  You need to use that same full email address at the start of your topic as you will only have authorisation under that subtree.



#include <SPI.h>
#include <PubSubClient.h>
#include <Ethernet.h>
#include <OneWire.h>

#define DEBUG
#ifdef DEBUG
  #define DEBUG_PRINT(x)  Serial.println (x)
#else
  #define DEBUG_PRINT(x)
#endif

byte mac[]= {0x90, 0xA2, 0xDA, 0x0D, 0x88, 0x5E} ; // change by your arduino mac address
char userId[] = "yourUserID"; // use your DIoTY user id (=email address)
char passwd[] = "yourPassword";  // use your DIoTY password
char server[] = "mqtt.dioty.co";
unsigned int port = 1883;
char topic[] = "/yourUserID/temp"; // topic where to publish; must be under your root topic
EthernetClient client; 
PubSubClient arduinoClient(server, port, 0, client) ; //no callback function is specified as we only publish


void setup() {                
  Serial.begin(9600); 
  DEBUG_PRINT(F("Initialisation"));
  beginConnection();
}

void beginConnection(){
  DEBUG_PRINT(F("Entering beginConnection"));
  if (Ethernet.begin(mac) == 0) {
    Serial.println(F("Failed to configure Ethernet using DHCP"));
    exit(-1);
  };
  DEBUG_PRINT(F("Obtained IP Address:"));
  DEBUG_PRINT(Ethernet.localIP());
  if (arduinoClient.connect(NULL,userId,passwd)) {
    DEBUG_PRINT(F("Connected to MQTT Server..."));
  } else {
    Serial.println(F("Failed to connect to the MQTT Server"));
    exit(-1);
  }
}

// reconnect after network hiccup      
void reConnect(){
  DEBUG_PRINT(F("Entering reConnect"));
  
  if (arduinoClient.connected()){
    DEBUG_PRINT(F("arduinoClient is connected"));
  } else {
    DEBUG_PRINT(F("arduinoClient is not connected"));
      if (Ethernet.begin(mac) == 0) {
        Serial.println(F("Failed to configure Ethernet using DHCP"));
      };
      DEBUG_PRINT(Ethernet.localIP());
      if (arduinoClient.connect(NULL,userId,passwd)) {
        DEBUG_PRINT(F("Reconnected to MQTT Server..."));
      } else {
        Serial.println(F("Failed to connect to the MQTT Server"));
      }
  };
}
  

// DS18S20 Temperature chip i/o
OneWire ds(2);  // on pin 10
byte i;
byte present = 0;
byte data[12];
byte addr[8];
int HighByte, LowByte, SignBit, Whole, Fract, TReading, Tc_100;
char buf[10];
char lastPublished[10];

void loop(void) {

  if (arduinoClient.loop()){
    DEBUG_PRINT(F("Arduino Client loop ok"));
    
    if ( !ds.search(addr)) {
        DEBUG_PRINT(F("No more addresses."));
        ds.reset_search();
        return;
    };
    if ( OneWire::crc8( addr, 7) != addr[7]) {
        DEBUG_PRINT(F("CRC is not valid!"));
        return;
    };

    getTemp();
    dtostrf(((float)(Whole*100+Fract)/100),1,2, buf);
    
    if (strcmp (buf,lastPublished) == 0) {
      DEBUG_PRINT(F("temp not changed"));
      DEBUG_PRINT(buf);
    } else {
      arduinoClient.publish(topic, (uint8_t*) buf, strlen(buf), 1); 
      memcpy(lastPublished, buf, 10);
      DEBUG_PRINT(buf);
    };
    
  } else {
    DEBUG_PRINT(F("Arduino Client loop nok"));
    reConnect();
  }
  delay(5000);     
}

void getTemp() {
  int foo, bar;
  
  ds.reset();
  ds.select(addr);
  ds.write(0x44,1);
  
  present = ds.reset();
  ds.select(addr);    
  ds.write(0xBE);

  for ( i = 0; i < 9; i++) {
    data[i] = ds.read();
  }
  
  LowByte = data[0];
  HighByte = data[1];
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  
  if (SignBit) {
    TReading = -TReading;
  }
  Tc_100 = (6 * TReading) + TReading / 4;    // multiply by (100 * 0.0625) or 6.25
  Whole = Tc_100 / 100;          // separate off the whole and fractional portions
  Fract = Tc_100 % 100;
  if (Fract > 49) {
    if (SignBit) {
      --Whole;
    } else {
      ++Whole;
    }
  }

  if (SignBit) {
    bar = -1;
  } else {
    bar = 1;
  }
}

After uploading the sketch to your Arduino, it will measure the temperature every 5 seconds.  When the measured temperature is different to the previous measuring, the new temperature will be published to the topic /temp topic underneath your root topic (/<yourUserID>/temp).  As the publication is retained, all clients subscribing to the topic will immediately receive the latest temperature measured and receive any changes for as long as they stay subscribed...

4 comments:

  1. Can we connect wifi module like esp8266 to mqtt server instead of ethernet with arduino? also what changes has to be done in above code to do that?

    ReplyDelete
  2. In mobile app the subscription topic is updated only once. where could be the issue? I can see this subscription topic and value in MQTTLens . The Publishing of switch is working fine.

    ReplyDelete
  3. Hi Santosh, are you on Android or iOS ? Note that for Android you will need to be on version 4.4 or above for the app to work properly...

    ReplyDelete