EtherMega

EtherMega by Freetronics is Arduino Mega 2560 compatible board with onboard Ethernet and Power-over-Ethernet support.

After a lot of research I decided that EtherMega are going to be my primary boards for home automatation, because of their PoE support, compatibiity with Arduino and all its other features ie. I couldn’t find anything better on the market than this.

MQTT Node

I decided to use MQTT as a protocol to communicate between devices at home.

I found MQTT client library for Arduino which, as it turns out, works just fine on EtherMega.

My current thinking is to create bunch of nodes for our home that will have different roles and perform different tasks.

Goal of my first office node project is to measure temperature in my office using DS18B20 (OneWire) sensor

To simplify the project I used DS18B20 Arduino module” that I bought online.

Node v1 will be an experimental proof-of-concept MQTT client running on EtherMega.

Node v1

I started playing around with EtherMega, using provided examples for ethernet and OneWire, getting a basic webserver done first, then playing with DS18B20 temperature sensor.

After trying out MQTT I added MQTT client into my code and spent couple of more hours of hacking to get the project working the way I want.

I connected DS18B20 Arduino module to 5V, GND and its output to digital pin 7.

I used parts of provided OneWire example code to retrieve temperature in degrees celsius and get MQTT client to publish it to /home/office/temperature/ topic.

Testing

Output of /home/status/ topic after the node starts:

$ mosquitto_sub -t /home/status/
office up

Output of /home/office/temperature/ topic when the node runs:

$ mosquitto_sub -t /home/office/temperature/
21.81
21.81
21.81
21.88
21.88
...

The following is my code for Node v1 (node.ino):

/*

 Node (office)
 -------------

 Node (v1) located in the office does the following:

 1) TEMPERATURE - read temperature from DS18B20 module

 /home/office/temperature/

 */


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


// Networking
// MQTT server
byte server[] = {192,168,2,101};
// MQTT client - this node IP address
byte ip[] = {192,168,2,201};
// MAC address
byte mac[] = {0xFE,0xED,0xDE,0xAD,0xBE,0xEF};


// Temperature (DS18B20) connected to pin 7
OneWire ds(7);


// MQTT message buffer
char message_buff[30];

// MQTT callback
void callback(char* topic, byte* payload, unsigned int length);

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

// MQTT callback function
void callback(char* topic, byte* payload, unsigned int length) {
  // Convert payload to string
  int i = 0;
  for(i=0; i<length; i++) {
    message_buff[i] = payload[i];
  }
  message_buff[i] = '\0';
  String msg = String(message_buff);
}


// Setup
void setup() {
  // Start the node at the IP address
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  // Start MQTT client,
  // let the home know the office is up
  if (client.connect("office")) {
    client.publish("/home/status/","office up");
  }
}


// Loop
void loop() {
  // Start MQTT client
  client.loop();
  // Read current temperature and
  // publish it to /home/office/temperature/
  float celsius;
  char temp[10];
  celsius = readTemperature();
  dtostrf(celsius,2,2,temp);
  if (celsius && celsius != -300.00) {
    client.publish("/home/office/temperature/", temp);
  }
}


// Temperature reading from DS18B20 module
// Code is from OneWire library example
float readTemperature() {
  byte i;
  byte present = 0;
  byte type_s;
  byte data[12];
  byte addr[8];
  float celsius;
  // Can I haz an address?
  if ( !ds.search(addr)) {
    ds.reset_search();
    delay(250);
    return -300.00;
  }
  // Is CRC valid?
  if (OneWire::crc8(addr, 7) != addr[7]) {
      return -200.00;
  }
  ds.reset();
  ds.select(addr);
  // Start conversion, with parasite power on at the end
  ds.write(0x44, 1);
  delay(1000);
  // We might do a ds.depower() here, but the reset will take care of it.
  present = ds.reset();
  ds.select(addr);
  // Read Scratchpad
  ds.write(0xBE);
  // Read 9 bytes
  for ( i = 0; i < 9; i++) {
    data[i] = ds.read();
  }
  // Convert the data to actual temperature
  // because the result is a 16 bit signed integer, it should
  // be stored to an "int16_t" type, which is always 16 bits
  // even when compiled on a 32 bit processor.
  int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; // 9 bit resolution default
    if (data[7] == 0x10) {
      // "count remain" gives full 12 bit resolution
      raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    // at lower res, the low bits are undefined, so let's zero them
    if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
    else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
    else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
    //// default is 12 bit resolution, 750 ms conversion time
  }
  celsius = (float)raw / 16.0;
  return celsius;
}