MQTT with the ENC28J60 Ethershield

My old ENC28J60 based shield surely has gathered some dust
My old ENC28J60 based shield surely has gathered some dust

While playing with MQTT on various ESP8266’s, I started to wonder if maybe I could do something with an old ENC28j60 shield and module I still had laying around and actually hardly ever used.

For the youngsters: The ENC28J60 Ethernetshield was the first shield to connect the Arduino with the internet. The major drawback of the chip was that it was lacking a stack, that subsequently had to be constructed in software. As a result it was kinda memory hungry. The initial version was without an SD card slot, the later version had an SD card slot. There were two libraries available: The Ethercard and the Ethershield library. The UIPEthernet library came later.
As far as I could figure out, the PubSubClient library that is needed for MQTT doesnt work with the original Ethershield/EtherCard libraries. It does work with the UIPEthernet library though (extended fork here). The UIPEthernet library is a smart piece of coding that made programs written for the W5100 Ethernetshield suitable to be used with the ENC28J60 Shield, simply by changing the included library. Ofcourse there is a price to pay for this, namely more memory consumption. There is also an MQTT client for the ENC28J60/Atmega328 based Nanode. The Ethercard seems to work with the EthercardMQTT library.

Anyway, there still is enough memory to read a DHT11 sensor an analog port and some switches. In my case those were 3 door contacts. The PubSubClient is the original from Knolleary, though normally I am more a fan of the fork by Imroy. For this example I have used the Mosquitto public broker but ofcourse any broker can be used. I have installed the Mosquitto broker on a local raspberry and I found that a call to (“raspberrypi.local”,1883) does not work, using the  local ip number does work though

MQTT-Output ‘Dicht’ means ‘Closed’

The program is rather ‘spartan’, to save space. Print statements have been removed or commented out after initial testing.

#include <UIPEthernet.h>
#include "PubSubClient.h"
#include "DHT.h"

#define CLIENT_ID       "UnoMQTT"
#define INTERVAL        3000 // 3 sec delay between publishing
#define DHTPIN          3
#define DHTTYPE         DHT11
bool statusKD=HIGH;//living room door
bool statusBD=HIGH;//front door
bool statusGD=HIGH;//garage door
int lichtstatus;
uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};

EthernetClient ethClient;
PubSubClient mqttClient;

long previousMillis;

void setup() {
  // setup serial communication
  // setup ethernet communication using DHCP
  if(Ethernet.begin(mac) == 0) {
    //Serial.println(F("Ethernet configuration using DHCP failed"));
  // setup mqtt client
  //mqttClient.setServer("",1883); //for using local broker
  //Serial.println(F("MQTT client configured"));

  // setup DHT sensor
  previousMillis = millis();

void loop() {
  lichtstatus = analogRead(A0);
  // check interval
  if(millis() - previousMillis > INTERVAL) {
    previousMillis = millis();

void sendData() {
  char msgBuffer[20];
  float h=dht.readHumidity();
  float t = dht.readTemperature();
  if(mqttClient.connect(CLIENT_ID)) {
   mqttClient.publish("hal/temp", dtostrf(t, 6, 2, msgBuffer));
   mqttClient.publish("hal/humid", dtostrf(h, 6, 2, msgBuffer));
   mqttClient.publish("hal/door", (statusBD == HIGH) ? "OPEN" : "DICHT");
   mqttClient.publish("hal/garage",(statusGD == HIGH) ? "OPEN" : "DICHT");
   mqttClient.publish("hal/kamer",(statusKD == HIGH) ? "OPEN" : "DICHT");
   mqttClient.publish("hal/licht", dtostrf(lichtstatus, 4, 0, msgBuffer));
 //hal=hallway, DICHT=Closed, kamer=room, licht=light
The old ENC28J60 shield at work
The old ENC28J60 shield at work

Just for completeness sake, this sketch takes about 77% of memory. This same sketch for the WIZ5100 based Ethernet shield, with the  Ethernet.h library takes about 52% of memory. If you decide to adapt the sketch, be careful with altering the character strings. For instance, using the string “OPEN” 3 times is likely less memory consuming than having 3 different strings of the same or even shorter length. Obviously the ‘topic’ strings take a lot of space as well and if you were to shorten them to less meaningful names, you could add more sensors such as for instance a PIR sensor.

Should you copy the program from this  blog page, you may copy ‘stray characters’  that you have to delete. You can also download it here.
An updated version is found here.

Freeing up memory

Should you really be pressed for memory, there is a way to free up about 5K of Flash: Go to your /../sketchfolder/libraries/UIPEthernet-master/utility/uipethernet-conf.h  and open the uipethernet-conf.h file.
in that file you will see the following section:

If you set UIP_CONF_UDP to ‘0’ you will save 5kB flash, by disabling UDP. However, if you use DHCP to connect to your router, you cannot disable UDP as the DHCP connection requires UDP. In that case you still can gain a bit of memory by reducing the UIP_UDP_CONNS.
An example of using a fixed address is this:

#include <UIPEthernet.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 
//the IP address for the shield:
byte ip[] = { 192, 168, 1, 120 };

void setup()
 Ethernet.begin(mac, ip);
void loop() {}

A final warning… after I updated my libraries, including the Adafruit DHT library, I received an error on compiling this sketch. That disappeared when I returned it to version 1.2.1. I thought I was not using the Adafruit library but the Tillaert library, but DHT libraries come a dime a dozen so maybe my compiler linked in another than I thought.
(The main sketch is my adaptation of work I found on internet, but I think the original source is from Luca Dentella)

Connecting to Thingspeak with Ethernetshield, EtherCard, Ethershield or ESP8266

I wanted to collect some weather-data with my Arduino and have that available as nice graphs, on a webpage, so I could also monitor it from afar
One could of course just use an Arduino as a webserver, but if you want to do anything more than send numbers to a webpage, the Arduino will soon run out of memory.
There are services that will do that for you. Pachube, later called Xively is a known one but currently they have a waiting list for their free accounts. Truthfully, I have a Pachube account that became a Xively account, but just never got any results on it.

There’re few alternatives for Xively:

I picked ‘Thingspeak’
As the signup and creating a channel etcetera is quite easy and well explained I will not go into too much detail of that. Basically after you sign up you create a channel to which you add fields where later sensors will send their data.
Under the API tab you will find an API that you later should put in your program.

I describe a simple connection with an ethernet cable and a connection via WiFi

Hurdle 1
Now where to find a program? a working example would be nice right? In the right top corner there is a button ‘Support’ that will go to ‘Tutorials’.
Under ‘Tutorials’ you will find:

“Using an Arduino + Ethernet Shield to Update a ThingSpeak Channel”
Sounds great, so you download that program into your IDE, add the API -key and then compile it.
Darn…. it doesnt compile, you try to fix it (and that is certainly possible) until you come to a point you have no idea what is required.
Apparently the program still expects everybody to use the 022 or 023 IDE.
There is a link to a Github page but that will give u a program to tweet and that is not what you want, at least not for now.
You ill find a better program to start from right here:…

That program takes a reading from the A0 port and sends that to “Field1” in your data stream

Ok so you try that, you hang a variable resistor like an LDR or NTC on port A0, add your API in the program and run it.
That works fine, but I didn’t only want to read a value from an Analog port, I had a DHT11 Moisture&Temperature sensor as well as a BMP180 Pressure & temperature sensor. I figured it shouldn’t be too hard.

Hurdle 2
I added the necessary libraries to the Thingspeak, added the objects and read the sensors into a variable.
The sensors however have floats as outcome and Thingspeak wants you to send strings.
With most variables it is rather easy to turn them into a string with the simple ‘string’ function, but it isnt that easy for floats. With floats you have to use the “dtostrf” command (which I guess stands for ‘double-to-string-function’

Trying to find info on that function on internet quickly led me to endless discussions on ‘how stupid’ it was and people asking questions were often told “why would you need that, Serial.print will do that for you” Yeah, true, but I don’t want to print, I need it because Thingspeak wants it.

To use the dtostrf command you need to set up a buffer space where the string will be stored. It works like this:

char t_buffer[10];
String temp=dtostrf(t,0,5,t_buffer);

That bufferspace is important. I had it working with ‘7’ or even ‘5’, but when I added a second sensor that needs this function, my data-stream would crash and or I got the weirdest results. I also figured that I could use the same bufferspace alternating for each sensor, but that also didn’t really work, so now i have a bufferspace for each sensor.
Now I am no crack in C, so maybe there is a better way to do this, if so i would love to hear it, but this worked for me.

Once I had the string conversions, I could add the data to the data stream.
The Thingspeak example program shows that for one field only, but it becomes clear pretty fast that you have to add the strings.

So for say 4 different fields it becomes like this:


The Program

Below you will find the full code.
Just a few remarks:
The BMP180 is an updated version of the BMP085. The BMP085 libraries are compatible with the BMP180.
AdaFruit has 2 versions of the library. I picked version 1 as i found it easier to work with. Version 2 also requires installation of the ‘Sensor’ library.
In the code I also present an extra float: ‘m’. that gives the Pressure in “mmHg” as I haven’t used it for now there is no string conversion yet and it is not added to the data stream

Arduino --> ThingSpeak Channel via Ethernet
The ThingSpeak Client sketch is designed for the Arduino and Ethernet.
This sketch updates a channel feed with an analog input reading via the
ThingSpeak API (
using HTTP POST. The Arduino uses DHCP and DNS for a simpler network setup.
The sketch also includes a Watchdog / Reset function to make sure the
Arduino stays connected and/or regains connectivity after a network outage.
Use the Serial Monitor on the Arduino IDE to see verbose network feedback
and ThingSpeak connectivity status.
Getting Started with ThingSpeak:
* Sign Up for New User Account -

* Register your Arduino by selecting Devices, Add New Device
* Once the Arduino is registered, click Generate Unique MAC Address
* Enter the new MAC Address in this sketch under "Local Network Settings"
* Create a new Channel by selecting Channels and then Create New Channel
* Enter the Write API Key in this sketch under "ThingSpeak Settings"
Arduino Requirements:
* Arduino with Ethernet Shield or Arduino Ethernet
* Arduino 1.0 IDE
Network Requirements:
* Ethernet port on Router
* DHCP enabled on Router
* Unique MAC Address for Arduino
Created: October 17, 2011 by Hans Scharler (
Additional Credits:
Example sketches from Arduino team, Ethernet by Adrian McEwen
Added dht11/BMP180 showed dtostrf function by diy_bloke 22/11/2014
#include <SPI.h>
#include <Ethernet.h>
#include <dht11.h>
#include <Wire.h>
#include <Adafruit_BMP085.h> // This is the version 1 library
#define DHT11PIN 4  // The Temperature/Humidity sensor
Adafruit_BMP085 bmp;
dht11 DHT11;

// Local Network Settings
byte mac[] = { 0xD4, 0x28, 0xB2, 0xFF, 0xA0, 0xA1 }; // Must be unique on local network
// ThingSpeak Settings
char thingSpeakAddress[] = "";
const int updateThingSpeakInterval = 16 * 1000; // Time interval in milliseconds to update ThingSpeak (number of seconds * 1000 = interval)
// Variable Setup
long lastConnectionTime = 0;
boolean lastConnected = false;
int failedCounter = 0;
// Initialize Arduino Ethernet Client
EthernetClient client;
void setup()
// Start Serial for debugging on the Serial Monitor
// Start Ethernet on Arduino
void loop()
// Read value from Analog Input Pin 0
String analogPin0 = String(analogRead(A0), DEC);
// Print Update Response to Serial Monitor
if (client.available())
char c =;
int chk =;
char t_buffer[10];
char h_buffer[10];
float t=(DHT11.temperature);
String temp=dtostrf(t,0,5,t_buffer);
//Serial.print(" ");
float h=(DHT11.humidity);
String humid=dtostrf(h,0,5,h_buffer);

            float p=(bmp.readPressure()/100.0);//this is for pressure in hectoPascal
            float m=(bmp.readPressure()/133.3);//  this is for pressure in mmHG
            float t2=(bmp.readTemperature());
            char p_buffer[15];
            char t2_buffer[10];
            String pres=dtostrf(p,0,5,p_buffer);
            String temp2=dtostrf(t2,0,5,t2_buffer);
 //         }

// Disconnect from ThingSpeak

if (!client.connected() && lastConnected)
// Update ThingSpeak
if(!client.connected() && (millis() - lastConnectionTime > updateThingSpeakInterval))
// Check if Arduino Ethernet needs to be restarted
if (failedCounter > 3 ) {startEthernet();}
lastConnected = client.connected();
void updateThingSpeak(String tsData)
if (client.connect(thingSpeakAddress, 80))
client.print("POST /update HTTP/1.1\n");
client.print("Connection: close\n");
client.print("X-THINGSPEAKAPIKEY: "+writeAPIKey+"\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
lastConnectionTime = millis();
if (client.connected())
Serial.println("Connecting to ThingSpeak...");
failedCounter = 0;
Serial.println("Connection to ThingSpeak failed ("+String(failedCounter, DEC)+")");
Serial.println("Connection to ThingSpeak Failed ("+String(failedCounter, DEC)+")");
lastConnectionTime = millis();
void startEthernet()
Serial.println("Connecting Arduino to network...");
// Connect to network amd obtain an IP address using DHCP
if (Ethernet.begin(mac) == 0)
Serial.println("DHCP Failed, reset Arduino to try again");
Serial.println("Arduino connected to network using DHCP");

Using an Ethercard/Ethershield

In case you do not have a WS5100 baset ethernetshield but an ENC28J60 based Ethershield or Ethercard, use the program below:

// Simple demo for feeding some random data to Pachube.
// 2011-07-08 <>

// Handle returning code and reset ethernet module if needed
// 2013-10-22

// Modifing so that it works on my setup for
// Arduino pro-mini 5V/16MHz, ETH modul on SPI with CS on pin 10.
// Also added a few changes found on various forums. Do not know what the 
// res variable is for, tweaked it so it works faster for my application
// 2015-11-09

// added dht11/bmp108. tweaked it to work with new IDE
// 2016-06-01  june 1, 2016

#include  <Ethercard.h>//Ethercard.h
#include   <Wire.h>//Wire.h
#include  <Adafruit_BMP085.h>//Adafruit_BMP085.h
#include  <dht11.h>//dht11.h
#define DHT11PIN 2
Adafruit_BMP085 bmp;
dht11 DHT11;
#define APIKEY "QTRR45T7UVW44" // put your key here
#define ethCSpin 10 // put your CS/SS pin here.
// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x75,0x68,0x68,0x68,0x68,0x68 };
const char website[] PROGMEM = "";
byte Ethernet::buffer[700];
uint32_t timer;
Stash stash;
byte session;
//timing variable
int res = 100; // was 0

void setup () {
  Serial.println("\n[ThingSpeak example]");

  //Initialize Ethernet

void loop () { 
int chk =;
int t=(DHT11.temperature);
int h=(DHT11.humidity);

            float p=(bmp.readPressure()/100.0);//this is for pressure in hectoPascal
            float m=(bmp.readPressure()/133.3);//  this is for pressure in mmHG
            float t2=(bmp.readTemperature());
  //if correct answer is not received then re-initialize ethernet module
  if (res > 220){
  res = res + 1;
  //200 res = 10 seconds (50ms each res)
  if (res == 200) {

    // field1=(Field 1 Data)&field2=(Field 2 Data)&field3=(Field 3 Data)&field4=(Field 4 Data)&field5=(Field 5 Data)&field6=(Field 6 Data)&field7=(Field 7 Data)&field8=(Field 8 Data)&lat=(Latitude in Decimal Degrees)&long=(Longitude in Decimal Degrees)&elevation=(Elevation in meters)&status=(140 Character Message)
    byte sd = stash.create();

      // generate the header with payload - note that the stash size is used,
    // and that a "stash descriptor" is passed in as argument using "$H"
    Stash::prepare(PSTR("POST /update HTTP/1.0" "\r\n"
      "Host: $F" "\r\n"
      "Connection: close" "\r\n"
      "X-THINGSPEAKAPIKEY: $F" "\r\n"
      "Content-Type: application/x-www-form-urlencoded" "\r\n"
      "Content-Length: $D" "\r\n"
    website, PSTR(APIKEY), stash.size(), sd);

    // send the packet - this also releases all stash buffers once done
    session = ether.tcpSend(); 

 // added from:
 int freeCount = stash.freeCount();
    if (freeCount <= 3) { Stash::initMap(56); } } const char* reply = ether.tcpReply(session); if (reply != 0) { res = 0; // Serial.println(F(" >>>REPLY recieved...."));
    // Serial.println(reply);

void initialize_ethernet(void){  
  for(;;){ // keep trying until you succeed 
    //Reinitialize ethernet module
    //Serial.println("Reseting Ethernet...");
    //digitalWrite(5, LOW);
    //digitalWrite(5, HIGH);

    if (ether.begin(sizeof Ethernet::buffer, mymac, ethCSpin) == 0){ 
      Serial.println( F("Failed to access Ethernet controller"));
    if (!ether.dhcpSetup()){
      Serial.println(F("DHCP failed"));

    ether.printIp("IP:  ", ether.myip);
    ether.printIp("GW:  ", ether.gwip);  
    ether.printIp("DNS: ", ether.dnsip);  

    if (!ether.dnsLookup(website))
      Serial.println(F("DNS failed"));

    ether.printIp("SRV: ", ether.hisip);

    //reset init value
    res = 180;

Using a ESP8266

Edit: This ofcourse is now a totally obsolete method. One would just use the ESP8266 by itself -without an Arduino- to send data to Thingspeak. I leave it here for ‘historical purposes’

esp The previous presented internet connection was made via a cable. However, there is a cheap WiFi module that is available to attach to the Arduino: The ESP 8266. Bear in mind that it needs 3.3 Volt. Some models however claim to be 5 Volt tolerant. I added 2 circuits that could be used as voltage converter. The ESP8266 really needs its own 3.3 V source as the current coming from the Arduino just doesn’t cut it. Also, if you have any problems with it, Connect a decoupling/buffer capacitor  (50uF) between ground and Vcc close to the board There is plenty of information on how to connect the module, I want to focus on the software to make a Thingspeak connection The SoftSerial library is added for debugging. it is not really necessary once the program is working. The same goes for all the print statements to the Software serial port I use 3 analogue values rather than an example with the BMP108 and DHT11 as that requires libraries, so the implementation of theESP8266 is easier to follow. Once you get that, it is easy to implement other sensors. Just make sure you turn all output into a string Below a program to Connect 3 analogue sensors to Thingspeak via an ESP8166 module:

The program

// <a href="" rel="nofollow">
#include <SoftwareSerial.h>
int sensor_temp = A0;
int value_temp;
int sensor_light = A1;
int value_light;
int sensor_humid = A2;
int value_humid;

#define DEBUG FALSE //comment out to remove debug msgs

//*-- Hardware Serial
#define _baudrate 9600

//*-- Software Serial
#define _rxpin      2
#define _txpin      3
SoftwareSerial debug( _rxpin, _txpin ); // RX, TX

//*-- IoT Information
#define SSID "[YOURSSID]"
#define IP "" // ThingSpeak IP Address:

// GET /update?key=[THINGSPEAK_KEY]&field1=[data 1]&filed2=[data 2]...;
String GET = "GET /update?key=[ThingSpeak_(Write)API_KEY]";

void setup() {
   Serial.begin( _baudrate );
  debug.begin( _baudrate );

    debug.println("RECEIVED: OK\nData ready to sent!");


void loop() {
  value_temp = analogRead(sensor_temp);
  value_light = analogRead(sensor_light);
  value_humid = analogRead(sensor_humid);
  String temp =String(value_temp);// turn integer to string
  String light= String(value_light);// turn integer to string
  String humid=String(value_humid);// turn integer to string
  updateTS(temp,light, humid);
  delay(3000); //
//----- update the  Thingspeak string with 3 values
void updateTS( String T, String L , String H)
  // ESP8266 Client
  String cmd = "AT+CIPSTART=\"TCP\",\"";// Setup TCP connection
  cmd += IP;
  cmd += "\",80";
  if( Serial.find( "Error" ) )
    debug.print( "RECEIVED: Error\nExit1" );

  cmd = GET + "&field1=" + T +"&field2="+ L + "&field3=" + H +"\r\n";
  Serial.print( "AT+CIPSEND=" );
  Serial.println( cmd.length() );
  if(Serial.find( ">" ) )
    sendDebug( "AT+CIPCLOSE" );//close TCP connection
  if( Serial.find("OK") )
    debug.println( "RECEIVED: OK" );
    debug.println( "RECEIVED: Error\nExit2" );

void sendDebug(String cmd)
  debug.print("SEND: ");

boolean connectWiFi()
  Serial.println("AT+CWMODE=1");//WiFi STA mode - if '3' it is both client and AP
  //Connect to Router with AT+CWJAP="SSID","Password";
  // Check if connected with AT+CWJAP?
  String cmd="AT+CWJAP=\""; // Join accespoint
    debug.println("RECEIVED: OK");
    return true;
    debug.println("RECEIVED: Error");
    return false;

  cmd = "AT+CIPMUX=0";// Set Single connection
  sendDebug( cmd );
  if( Serial.find( "Error") )
    debug.print( "RECEIVED: Error" );
    return false;