Skip to content

Instantly share code, notes, and snippets.

@knolleary
Created April 3, 2011 22:29
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save knolleary/900885 to your computer and use it in GitHub Desktop.
Save knolleary/900885 to your computer and use it in GitHub Desktop.
CurrentCost MQTT Bridge
/*
CurrentCost MQTT Bridge
Example sketch for the CurrentCost Bridge device that causes
readings to be published over MQTT.
Requires:
- Arduino 0022
- PubSubClient v1.6+
http://knolleary.net/arduino-client-for-mqtt/
- Ethernet DHCP/DNS
http://www.mcqn.com/files/Ethernet-DHCP-DNS.zip
This must be compiled with the board set to:
Arduino Pro or Pro Mini (3.3V, 8MHz) w/ ATmega328
Nicholas O'Leary, 04-2011
http://knolleary.net/?p=1024
This code is in the public domain
*/
#include <SPI.h>
#include <Ethernet.h>
#include <Dhcp.h>
#include <dns.h>
#include <PubSubClient.h>
#include <EEPROM.h>
// Use either SERVER_HOST_NAME or SERVER_IP_ADDRESS - not both
#define _SERVER_HOST_NAME "example.com"
#define SERVER_IP_ADDRESS { 172, 16, 0, 2 }
// The port to connect to
#define SERVER_PORT 1883
// The template Cliend ID. The blanks are filled with the first
// eight bytes of the uuid.
#define CLIENTID "cc "
// The template topic. The second topic-level is filled with the
// uuid of the bridge. The third/fourth levels are populated depending
// what is being published
#define TOPIC "cc/ / / "
// The char position at which the third topic level starts
#define TOPIC_ROOT_LENGTH 36
// Should the temperature be published
#define PUBLISH_TEMPERATURE
// Should birth/will messages be used
#define PUBLISH_CONNECTION_STATE
// Ethernet reset line attached to pin 7
#define ETHERNET_RESET 7
// Where in EEPROM to start the uuid
#define UUID_START_BYTE 4
char hexChars[] = "0123456789ABCDEF";
#define HEX_MSB(v) hexChars[(v & 0xf0) >> 4]
#define HEX_LSB(v) hexChars[v & 0x0f]
// Struct to store a reading in
typedef struct {
char sensor;
char channel;
char value[10];
} Reading;
// A single message my contain up to three channels
Reading readings[3];
byte readingCount = 0;
char powertopic[] = TOPIC;
char clientId[] = CLIENTID;
byte mac[6];
byte ip[4];
#ifdef SERVER_IP_ADDRESS
byte server[] = SERVER_IP_ADDRESS;
#else
byte server[4];
#endif
byte uuidBytes[16];
char uuid[33];
#define STATE_INITIAL 0
#define STATE_IN_MSG 1
byte state = STATE_INITIAL;
char temperature[5];
int lastPublishedTemperature;
PubSubClient mqttClient(server, SERVER_PORT,cb);
// Subscription callback; unused
void cb(char* topic, byte* payload,int length) {
}
// Returns the next byte from the meter
// Blocks until there is something to return
char get_byte() {
int a = -1;
while((a = Serial.read()) == -1) {};
return a;
}
// Handle a reading; causes it to be published
// to the approprite topic
void handleReading(char sensor, char channel, char* reading) {
if (sensor != '\0' && channel != '\0') {
char readingLength = 5;
if (channel == '0') {
readingLength = 10;
}
boolean validReading = true;
for (int i=0;i<readingLength;i++) {
validReading = (validReading && isDigit(reading[i]));
}
if (validReading) {
powertopic[TOPIC_ROOT_LENGTH] = sensor;
powertopic[TOPIC_ROOT_LENGTH+1] = '/';
powertopic[TOPIC_ROOT_LENGTH+2] = channel;
publish(powertopic,reading,readingLength,0);
}
}
}
void publish(char* topic, char* value, int len, int retained) {
mqttClient.publish(topic,(uint8_t*)value,len,retained);
}
void setup() {
// Read EEPROM to get the uuid
byte i;
uuid[32] = '\0';
byte b0 = EEPROM.read(0+UUID_START_BYTE);
if (b0 == 0xFF) {
// Generate a UUID
randomSeed(analogRead(5));
for (i=0;i<16;i++) {
EEPROM.write(i+UUID_START_BYTE,(byte)random(256));
}
}
for (i=0;i<16;i++) {
byte v = EEPROM.read(i+UUID_START_BYTE);
uuid[2*i] = HEX_MSB(v);
uuid[(2*i)+1] = HEX_LSB(v);
if (i > 9) {
mac[i-10] = v;
}
uuidBytes[i] = v;
}
// The LSB(it) of the MSB(yte) must be even to be a valid MAC Address
if ((mac[0]&1) == 1) {
mac[0] ^= 1;
}
// Fill in the Topic & Client ID templates
for (i=0;i<32;i++) {
powertopic[3+i] = uuid[i];
if (i<8) {
clientId[2+i] = uuid[i];
}
}
delay(500);
Serial.begin(57600);
}
int resetConnection() {
// Reset Ethernet shield in a controlled manner
pinMode(ETHERNET_RESET,OUTPUT);
digitalWrite(ETHERNET_RESET,LOW);
delay(250);
digitalWrite(ETHERNET_RESET,HIGH);
pinMode(ETHERNET_RESET,INPUT);
delay(500);
for (int i=0;i<16;i++) {
byte v = EEPROM.read(i+UUID_START_BYTE);
if (i > 9) {
mac[i-10] = v;
}
}
// The LSB(it) of the MSB(yte) must be even to be a valid MAC Address
if ((mac[0]&1) == 1) {
mac[0] ^= 1;
}
// Get an IP address - will timeout after 1 minute
int attempts = 0;
while (Dhcp.beginWithDHCP(mac) != 1) {
attempts++;
if (attempts == 2) {
return 0;
}
delay(15000);
}
delay(1000);
#ifdef SERVER_HOST_NAME
// Look-up server address if set
DNSClient dns;
Dhcp.getDnsServerIp(server);
dns.begin(server);
attempts = 0;
while (dns.gethostbyname(SERVER_HOST_NAME, server) != 1) {
attempts++;
if (attempts == 2) {
return 0;
}
delay(15000);
}
#endif
return 1;
}
void loop()
{
// Check we're still connected
if (!mqttClient.connected()) {
while (resetConnection() != 1) {
delay(5000);
}
#ifdef PUBLISH_CONNECTION_STATE
// Setup the WILL message on connect
powertopic[TOPIC_ROOT_LENGTH] = 's';
powertopic[TOPIC_ROOT_LENGTH+1] = 0;
if (mqttClient.connect(clientId,powertopic,0,1,"0")) {
mqttClient.publish(powertopic,(uint8_t*)"1",1,1);
}
#else
mqttClient.connect(clientId);
#endif
}
readingCount = 0;
state = STATE_INITIAL;
while (state == STATE_INITIAL) {
// Scan for </time
while (get_byte() != '<') {}
if (get_byte() == '/' && get_byte() == 't' &&
get_byte() == 'i' && get_byte() == 'm' &&
get_byte() == 'e') {
state = STATE_IN_MSG;
}
mqttClient.loop();
}
get_byte(); // '>'
get_byte(); // '<'
if (get_byte() == 'h') {
// skip history messages
state = STATE_INITIAL;
}
else {
for (int i=0;i<4;i++) { // 'mpr>'
get_byte();
}
for (int i=0;i<4;i++) {
temperature[i]=get_byte();
}
temperature[4] = '\0';
char sensor = 0;
while (state == STATE_IN_MSG) {
while (get_byte() != '<') {}
char c = get_byte();
if (c == 's' && get_byte() == 'e' && get_byte() == 'n' &&
get_byte() == 's' && get_byte() == 'o' && get_byte() == 'r') {
get_byte();
sensor = get_byte();
}
else if (c == 'c' && get_byte() == 'h') {
memset(&(readings[readingCount]),0,sizeof(Reading));
readings[readingCount].sensor = sensor;
readings[readingCount].channel = get_byte();
for (int i=0;i<8;i++) { // '><watts>'
get_byte();
}
for (int i=0;i<5;i++) {
readings[readingCount].value[i] = get_byte();
}
readingCount++;
}
else if (c == 'i' && get_byte() == 'm' && get_byte() == 'p') {
get_byte(); // '>'
memset(&(readings[readingCount]),0,sizeof(Reading));
readings[readingCount].sensor = sensor;
readings[readingCount].channel = '0';
for (int i=0;i<10;i++) {
readings[readingCount].value[i] = get_byte();
}
readingCount++;
}
else if (c == '/' && get_byte() == 'm') {
for (int i=0;i<readingCount;i++) {
handleReading(readings[i].sensor,readings[i].channel,readings[i].value);
}
readingCount = 0;
#ifdef PUBLISH_TEMPERATURE
if (isDigit(temperature[0]) &&
isDigit(temperature[1]) &&
temperature[2]=='.' &&
isDigit(temperature[3])) {
int temperatureValue = atoi(temperature)*10+atoi(&(temperature[3]));
if (abs(temperatureValue-lastPublishedTemperature) > 4) {
powertopic[TOPIC_ROOT_LENGTH] = 't';
powertopic[TOPIC_ROOT_LENGTH+1] = 0;
publish(powertopic,temperature,4,1);
lastPublishedTemperature = temperatureValue;
}
}
#endif
state = STATE_INITIAL;
}
}
}
}
@sheppy99
Copy link

Is there a later version of this that works with the latest series of IDE? I've managed I think to get it working using IDE V0.23 for compiling into hex with PubSubClient V1.6 and Ethernet-DHCP-DNS. Followed by AVRDUDE to upload it, however before I try and hack OPENCMS to do something with the information I'd like to check this is the way to go with the Current Cost Bridge.

@kechap
Copy link

kechap commented Nov 10, 2015

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


// The hostname of server
#define SERVER_HOST_NAME "test.mosquitto.org"
// The port to connect to
#define SERVER_PORT 1883

// The template Cliend ID. The blanks are filled with the first
// eight bytes of the uuid.
#define CLIENTID "cc                "

// The template topic. The second topic-level is filled with the
// uuid of the bridge. The third/fourth levels are populated depending
// what is being published
#define TOPIC "cc/                                / / "
// The char position at which the third topic level starts
#define TOPIC_ROOT_LENGTH 36

// Ethernet reset line attached to pin 7
#define ETHERNET_RESET 7

// Where in EEPROM to start the uuid
#define UUID_START_BYTE 4

char hexChars[] = "0123456789ABCDEF";
#define HEX_MSB(v) hexChars[(v & 0xf0) >> 4]
#define HEX_LSB(v) hexChars[v & 0x0f]

long lastReconnectAttempt = 0;

char temperature[5];
int lastPublishedTemperature;

typedef struct {
  char sensor;
  char channel;
  char value[10];
} Reading;

// A single message my contain up to three channels
Reading readings[3];
byte readingCount = 0;

char powertopic[] = TOPIC;
char clientId[] = CLIENTID;

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
char uuid[] = "YOURIDHERE";

char server[] = SERVER_HOST_NAME;

// setup states
#define ST_FROZEN 0
#define ST_READIN 2

#define STATE_INITIAL 0
#define STATE_IN_MSG 1
byte state = STATE_INITIAL;

// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192, 168, 1, 177);

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;
PubSubClient mqttClient(client);

// Returns the next byte from the meter
// Blocks until there is something to return
char get_byte() {
  int a = -1;
  while ((a = Serial.read()) == -1) {};
  return a;
}

// Handle a reading; causes it to be published
// to the approprite topic
void handleReading(char sensor, char channel, char* reading) {
  if (sensor != '\0' && channel != '\0') {
    char readingLength = 5;
    if (channel == '0') {
      readingLength = 10;
    }
    boolean validReading = true;
    for (int i=0;i<readingLength;i++) {
      validReading = (validReading && isDigit(reading[i]));
    }
    if (validReading) {
      powertopic[TOPIC_ROOT_LENGTH] = sensor;
      powertopic[TOPIC_ROOT_LENGTH+1] = '/';
      powertopic[TOPIC_ROOT_LENGTH+2] = channel;
      publish(powertopic,reading,readingLength,0);
    }
  }
}

void publish(char* topic, char* value, int len, int retained) {
  mqttClient.publish(topic,(uint8_t*)value,len,retained);
}

boolean reconnect() {
  // Setup the WILL message on connect
  powertopic[TOPIC_ROOT_LENGTH] = 's';
  powertopic[TOPIC_ROOT_LENGTH+1] = 0;
  if (mqttClient.connect("cc",powertopic,0,1,"0")) {
    // Once connected, publish an announcement...
    mqttClient.publish(powertopic,(uint8_t*)"1",1,1);
  }
  return mqttClient.connected();
}


void setup() {
  // ethernet hack
  pinMode(7, OUTPUT);
  digitalWrite(7, HIGH);

  // Fill in the Topic & Client ID templates
  for (int i=0;i<32;i++) {
    powertopic[3+i] = uuid[i];
    if (i<8) {
      clientId[2+i] = uuid[i];
    }
  }

  delay(500);

  // Open serial communications and wait for port to open:
  Serial.begin(57600);
  mqttClient.setServer(server, 1883);

  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    // no point in carrying on, so do nothing forevermore:
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip);
  }
  // give the Ethernet shield a second to initialize:
  delay(1500);

  lastReconnectAttempt = 0;
}

void loop()
{
  if (!mqttClient.connected()) {
    long now = millis();
    if (now - lastReconnectAttempt > 5000) {
      lastReconnectAttempt = now;
      // Attempt to reconnect
      if (reconnect()) {
        lastReconnectAttempt = 0;
      }
    }
  } else {
    // Client connected
    mqttClient.loop();
  }

  readingCount = 0;
  state = STATE_INITIAL;
  while (state == STATE_INITIAL) {
    // Scan for </time
    while (get_byte() != '<') {}
    if (get_byte() == '/' && get_byte() == 't' && 
        get_byte() == 'i' && get_byte() == 'm' && 
        get_byte() == 'e') {
      state = STATE_IN_MSG;
    }
    mqttClient.loop();
  }
  get_byte(); // '>'
  get_byte(); // '<'
  if (get_byte() == 'h') {
    // skip history messages
    state = STATE_INITIAL;
  } 
  else {
    for (int i=0;i<4;i++) { // 'mpr>'
      get_byte();
    }
    for (int i=0;i<4;i++) {
      temperature[i]=get_byte();
    }
    temperature[4] = '\0';
    char sensor = 0;
    while (state == STATE_IN_MSG) {
      while (get_byte() != '<') {}
      char c = get_byte();
      if (c == 's' && get_byte() == 'e' && get_byte() == 'n' && 
          get_byte() == 's' && get_byte() == 'o' && get_byte() == 'r') {
        get_byte();
        sensor = get_byte();
      }
      else if (c == 'c' && get_byte() == 'h') {
        memset(&(readings[readingCount]),0,sizeof(Reading));
        readings[readingCount].sensor = sensor;
        readings[readingCount].channel = get_byte();
        for (int i=0;i<8;i++) { // '><watts>'
          get_byte();
        }
        for (int i=0;i<5;i++) {
          readings[readingCount].value[i] = get_byte();
        }
        readingCount++;
      }
      else if (c == 'i' && get_byte() == 'm' && get_byte() == 'p') {
        get_byte(); // '>'
        memset(&(readings[readingCount]),0,sizeof(Reading));
        readings[readingCount].sensor = sensor;
        readings[readingCount].channel = '0';
        for (int i=0;i<10;i++) {
          readings[readingCount].value[i] = get_byte();
        }
        readingCount++;
      }
      else if (c == '/' && get_byte() == 'm') {
        for (int i=0;i<readingCount;i++) {
          handleReading(readings[i].sensor,readings[i].channel,readings[i].value);
        }
        readingCount = 0;
        if (isDigit(temperature[0]) &&
            isDigit(temperature[1]) &&
            temperature[2]=='.' &&
            isDigit(temperature[3])) {
          int temperatureValue = atoi(temperature)*10+atoi(&(temperature[3]));
          if (abs(temperatureValue-lastPublishedTemperature) > 1) {
            powertopic[TOPIC_ROOT_LENGTH] = 't';
            powertopic[TOPIC_ROOT_LENGTH+1] = 0;
            publish(powertopic,temperature,4,1);
            lastPublishedTemperature = temperatureValue;
          }
        }
        state = STATE_INITIAL;
      }
    }
  }
  Ethernet.maintain();
}

@ramirezfrullato
Copy link

Both versions dosn't work for me :(
1st version (Knolleray, 04-2011) produces in compilation "exit status 1 'cb' was not declared in this scope".
2nd version (ketchap 11-2015) it's compilable. I burn it in Current Cost bridge. You can see Bridge in LAN. Write only a "0" in test.mosquitto.org and disconnect.
There are newer versions ?

@sheppy99
Copy link

sheppy99 commented Jan 18, 2018

To revise an old topic, I just reprogrammed a Current Cost Bridge using Arduino 0023 and a modified copy of the original sketch. Now it publishes to topic emon/cc/x where x it the sensor number or "t" for temperature. I chose this topic because it works with Open Energy Monitor which is only subscribed to a single base topic. I have only one bridge so I've traded the unique ID for a more useful topic. I left the original code commented out so it should be obvious to anyone how to revert it to Nicks original. Arduino 0023 spits an error at startup saying The library "pubsubclient-2.6" cannot be used, but despite this it DOES compile, and the file you want ends in .cpp.hex and appears in a folder of the Windows Temp Directory. I programmed the Bridge using a USBASP programmer, and the jumper next to the button on the board needs shorting before pressing the button to enter programming mode. Further notes are at the start of the sketch. I'm not a programmer so there are likely more elegant ways of getting this working. I can also provide versions of the libraries used if anyone can tell me how to get to them in Arduino 0023 as it doesn't have a library manager.
Good luck to anyone following on


/*
      CurrentCost MQTT Bridge

 Notes:
 1) Use Arduino23
 2) Ignore PubSub error at start
 3) Don't mess with original topic settings, it breaks DHCP
 4) Required topic is added alongside original and as at 18/1/2018 it publishes the 3 CC devices plus temperature to emon/cc/SENSORNUMBER, or emon/cc/t for temperature
 5) DNS is not used due to my finicky Fritz Box 7490 giving out wrong name resolution
 6) Ignore occasional Java errors at compilation time and just compile again

 Requires:
  - Arduino 0022
  - PubSubClient v1.6+
      http://knolleary.net/arduino-client-for-mqtt/
  - Ethernet DHCP/DNS
      http://www.mcqn.com/files/Ethernet-DHCP-DNS.zip

 This must be compiled with the board set to:
   Arduino Pro or Pro Mini (3.3V, 8MHz) w/ ATmega328

 Nicholas O'Leary,  04-2011
 http://knolleary.net/?p=1024

 This code is in the public domain
*/

#include <SPI.h>
#include <Ethernet.h>
#include <Dhcp.h>
#include <dns.h>
#include <PubSubClient.h>
#include <EEPROM.h>

// Use either SERVER_HOST_NAME or SERVER_IP_ADDRESS - not both
#define _SERVER_HOST_NAME "example.com"
#define SERVER_IP_ADDRESS { 192, 168, 1, 69 }
// The port to connect to
#define SERVER_PORT 1883

// The template Cliend ID. The blanks are filled with the first
// eight bytes of the uuid.
#define CLIENTID "cc                "

// The template topic. The second topic-level is filled with the
// uuid of the bridge. The third/fourth levels are populated depending
// what is being published
#define TOPIC "cc/                                / / "
#define KDFT "emon/cc/ "
// The char position at which the third topic level starts
#define TOPIC_ROOT_LENGTH 36
#define KDFT_ROOT_LENGTH 8

// Should the temperature be published
#define PUBLISH_TEMPERATURE
// Should birth/will messages be used
//#define PUBLISH_CONNECTION_STATE

// Ethernet reset line attached to pin 7
#define ETHERNET_RESET 7 

// Where in EEPROM to start the uuid
#define UUID_START_BYTE 4

char hexChars[] = "0123456789ABCDEF";
#define HEX_MSB(v) hexChars[(v & 0xf0) >> 4]
#define HEX_LSB(v) hexChars[v & 0x0f]

// Struct to store a reading in
typedef struct {
  char sensor;
  char channel;
  char value[10];
} Reading;

// A single message my contain up to three channels
Reading readings[3];
byte readingCount = 0;

char powertopic[] = TOPIC;
char kevinstopic[] = KDFT;
char clientId[] = CLIENTID;

byte mac[6];
byte ip[4];
#ifdef SERVER_IP_ADDRESS
byte server[] = SERVER_IP_ADDRESS;
#else
byte server[4];
#endif

byte uuidBytes[16];
char uuid[33];

#define STATE_INITIAL 0
#define STATE_IN_MSG 1
byte state = STATE_INITIAL;

char temperature[5];
int lastPublishedTemperature;

PubSubClient mqttClient(server, SERVER_PORT,cb);

// Subscription callback; unused
void cb(char* topic, byte* payload,int length) {
}

// Returns the next byte from the meter
// Blocks until there is something to return
char get_byte() {
  int a = -1; 
  while((a = Serial.read()) == -1) {};
  return a;
}

// Handle a reading; causes it to be published
// to the approprite topic
void handleReading(char sensor, char channel, char* reading) {
  if (sensor != '\0' && channel != '\0') {
    char readingLength = 5;
    if (channel == '0') {
      readingLength = 10;
    }
    boolean validReading = true;
    for (int i=0;i<readingLength;i++) {
      validReading = (validReading && isDigit(reading[i]));
    }
    if (validReading) {
      
        kevinstopic[KDFT_ROOT_LENGTH] = sensor;
//      powertopic[TOPIC_ROOT_LENGTH] = sensor;
//      powertopic[TOPIC_ROOT_LENGTH+1] = '/';
//      powertopic[TOPIC_ROOT_LENGTH+2] = channel;
        publish(kevinstopic,reading,readingLength,0);
//      publish(powertopic,reading,readingLength,0);
    }
  }
}

void publish(char* topic, char* value, int len, int retained) {
  mqttClient.publish(topic,(uint8_t*)value,len,retained);
}

void setup() { 
  // Read EEPROM to get the uuid
  byte i;
  uuid[32] = '\0';
  byte b0 = EEPROM.read(0+UUID_START_BYTE);
  if (b0 == 0xFF) {
    // Generate a UUID
    randomSeed(analogRead(5));
    for (i=0;i<16;i++) {
      EEPROM.write(i+UUID_START_BYTE,(byte)random(256));
    }
  }
  for (i=0;i<16;i++) {
    byte v = EEPROM.read(i+UUID_START_BYTE);
    uuid[2*i] = HEX_MSB(v);
    uuid[(2*i)+1] = HEX_LSB(v);
    if (i > 9) {
      mac[i-10] = v;
    }
    uuidBytes[i] = v;
  }
  // The LSB(it) of the MSB(yte) must be even to be a valid MAC Address
  if ((mac[0]&1) == 1) {
    mac[0] ^= 1;
  }

  // Fill in the Topic & Client ID templates
  for (i=0;i<32;i++) {
    powertopic[3+i] = uuid[i];
    if (i<8) {
      clientId[2+i] = uuid[i];
    }
  }

  delay(500);
  Serial.begin(57600);
}

int resetConnection() {
  // Reset Ethernet shield in a controlled manner
  pinMode(ETHERNET_RESET,OUTPUT);
  digitalWrite(ETHERNET_RESET,LOW);
  delay(250);
  digitalWrite(ETHERNET_RESET,HIGH);
  pinMode(ETHERNET_RESET,INPUT);
  delay(500);

  for (int i=0;i<16;i++) {
    byte v = EEPROM.read(i+UUID_START_BYTE);
    if (i > 9) {
      mac[i-10] = v;
    }
  }
  // The LSB(it) of the MSB(yte) must be even to be a valid MAC Address
  if ((mac[0]&1) == 1) {
    mac[0] ^= 1;
  }

  
  // Get an IP address - will timeout after 1 minute
  int attempts = 0;
  while (Dhcp.beginWithDHCP(mac) != 1) {
    attempts++;
    if (attempts == 2) {
      return 0;
    }
    delay(15000);
  }    
  delay(1000);  

#ifdef SERVER_HOST_NAME
  // Look-up server address if set
  DNSClient dns;
  Dhcp.getDnsServerIp(server);
  dns.begin(server);
  attempts = 0;
  while (dns.gethostbyname(SERVER_HOST_NAME, server) != 1) {
    attempts++;
    if (attempts == 2) {
      return 0;
    }
    delay(15000);
  }
#endif
  return 1;
}

void loop()
{
  // Check we're still connected
  if (!mqttClient.connected()) {
    while (resetConnection() != 1) {
      delay(5000);
    }
#ifdef PUBLISH_CONNECTION_STATE
    // Setup the WILL message on connect
    powertopic[TOPIC_ROOT_LENGTH] = 's';
    powertopic[TOPIC_ROOT_LENGTH+1] = 0;

    if (mqttClient.connect(clientId,powertopic,0,1,"0")) {
      mqttClient.publish(powertopic,(uint8_t*)"1",1,1);
    }
#else
    mqttClient.connect(clientId);
#endif
  }  
  readingCount = 0;
  
  state = STATE_INITIAL;
  while (state == STATE_INITIAL) {
    // Scan for </time
    while (get_byte() != '<') {}
    if (get_byte() == '/' && get_byte() == 't' && 
        get_byte() == 'i' && get_byte() == 'm' && 
        get_byte() == 'e') {
      state = STATE_IN_MSG;
    }
    mqttClient.loop();
  }
  get_byte(); // '>'
  get_byte(); // '<'
  if (get_byte() == 'h') {
    // skip history messages
    state = STATE_INITIAL;
  } 
  else {
    for (int i=0;i<4;i++) { // 'mpr>'
      get_byte();
    }
    for (int i=0;i<4;i++) {
      temperature[i]=get_byte();
    }
    temperature[4] = '\0';
    char sensor = 0;
    while (state == STATE_IN_MSG) {
      while (get_byte() != '<') {}
      char c = get_byte();
      if (c == 's' && get_byte() == 'e' && get_byte() == 'n' && 
          get_byte() == 's' && get_byte() == 'o' && get_byte() == 'r') {
        get_byte();
        sensor = get_byte();
      }
      else if (c == 'c' && get_byte() == 'h') {
        memset(&(readings[readingCount]),0,sizeof(Reading));
        readings[readingCount].sensor = sensor;
        readings[readingCount].channel = get_byte();
        for (int i=0;i<8;i++) { // '><watts>'
          get_byte();
        }
        for (int i=0;i<5;i++) {
          readings[readingCount].value[i] = get_byte();
        }
        readingCount++;
      }
      else if (c == 'i' && get_byte() == 'm' && get_byte() == 'p') {
        get_byte(); // '>'
        memset(&(readings[readingCount]),0,sizeof(Reading));
        readings[readingCount].sensor = sensor;
        readings[readingCount].channel = '0';
        for (int i=0;i<10;i++) {
          readings[readingCount].value[i] = get_byte();
        }
        readingCount++;
      }
      else if (c == '/' && get_byte() == 'm') {
        for (int i=0;i<readingCount;i++) {
          handleReading(readings[i].sensor,readings[i].channel,readings[i].value);
        }
        readingCount = 0;
#ifdef PUBLISH_TEMPERATURE
        if (isDigit(temperature[0]) &&
            isDigit(temperature[1]) &&
            temperature[2]=='.' &&
            isDigit(temperature[3])) {
          int temperatureValue = atoi(temperature)*10+atoi(&(temperature[3]));
          if (abs(temperatureValue-lastPublishedTemperature) > 4) {
            kevinstopic[KDFT_ROOT_LENGTH] = 't';
            //powertopic[TOPIC_ROOT_LENGTH] = 't';
            //powertopic[TOPIC_ROOT_LENGTH+1] = 0;
            publish(kevinstopic,temperature,4,1);
            lastPublishedTemperature = temperatureValue;
          }
        }
#endif
        state = STATE_INITIAL;
      }
    }
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment