Garrett Bartley
Published © CC BY

Photon IoT Gateway

Not all IoT devices are part of the Particle Cloud. Now they can be!

BeginnerProtip4,651
Photon IoT Gateway

Things used in this project

Story

Read more

Code

photon-gateway.ide

C/C++
The "gateway" code for the Photon
#include "application.h"

// Output debugging information to serial
// #define SERIAL_DEBUG

// Output debugging information to Particle.publish(...)
// #define PUBLISH_DEBUG

// Your local time zone
#define TIME_ZONE -5;

// The port to listen for UDP broadcast messages
#define BROADCAST_PORT 9877

// The publish event to use
#define PUBLISH_EVENT "statsd"

// Use the onboard RGB LED to blink when a packet is processed
#define USE_LED

UDP udp;

void setup() {
#ifdef SERIAL_DEBUG
	Serial.begin(9600);
	Time.zone(TIMEZONE);
#endif

	udp.begin(BROADCAST_PORT);
}


void loop() {
	checkUDP();
}


// See if we've received a packet
void checkUDP() {
	if (udp.parsePacket() > 0) {
#ifdef USE_LED
		RGB.control(true);
		RGB.color(127, 0, 0);
#endif

		char packetBuffer[64] = "";
	    udp.read(packetBuffer, 64);

	    parsePacket(String(packetBuffer));

		delay(100);

#ifdef USE_LED
	    RGB.control(false);
#endif
	}
}


// Parse the packet for a checksum
void parsePacket(String packet) {
	uint32_t checksum = 0;
	packet.trim();

#ifdef SERIAL_DEBUG
	Serial.print(timestamp());
	Serial.print("<<< ");
	Serial.println(packet);
#endif

#ifdef PUBLISH_DEBUG
	Particle.publish("debug", packet, 60, PRIVATE);
#endif

	// Calculate checksum up to ";"
	for(uint8_t i=0; i<packet.lastIndexOf(";"); i++) {
		checksum += ord(packet.charAt(i));
	}

	// Get the checksum sent with the packet
	String str_checksum = packet.substring(packet.lastIndexOf(";")+1);

	if(String(checksum, HEX)==str_checksum)
		sendPacket(packet.substring(0, packet.lastIndexOf(";")));
	else {
		String pub = packet+" :: checksum "+str_checksum+" != "+String(checksum, HEX);
#ifdef SERIAL_DEBUG
		Serial.print(timestamp());
		Serial.print("!!! checksum does not match: ");
		Serial.print(str_checksum);
		Serial.print(" != ");
		Serial.println(String(checksum, HEX));
#endif

#ifdef PUBLISH_DEBUG
		Particle.publish("error", pub, 60, PRIVATE);
#endif
	}
}


// Forward the packet on to Particle.publish(...)
void sendPacket(String packet) {
#ifdef SERIAL_DEBUG
	Serial.print(timestamp());
	Serial.print(">>> ");
	Serial.println(packet);
#endif
	Particle.publish(PUBLISH_EVENT, packet);
}


// Convert ASCII character to its integer value
uint8_t ord(char b) {
	uint8_t a;
	a = b-'0';
	return a;
}


#ifdef SERIAL_DEBUG
String timestamp() {
	return "["+Time.format(Time.now(), "%F %T")+"] ";
}
#endif

esp8266.ino

C/C++
The code for the ESP8266 with a DS18B20 temperature sensor
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <OneWire.h>

extern "C" {
  #include "user_interface.h"
}

//#define  DEBUG_SERIAL

// The arbitrary name for this device
#define DEVICE_NAME       "iot"

// Wifi network name
#define WIFI_SSID         "MyNetwork"

// Wifi network password
#define WIFI_PASS         "p455w0rd"

// UDP port to broadcast on
#define BROADCAST_PORT     9877

// UDP IP address to broadcast to
#define BROADCAST_ADDRESS "255.255.255.255"

// External "status" LED
#define LED_PIN            14

// How long to sleep
#define SLEEP_DURATION     55

// How long to wait (in seconds) before going back to sleep
#define POST_DATA_DELAY    1

bool statusLED = false;
uint16_t timeToConnect = 0;

char packetBuffer[UDP_TX_PACKET_MAX_SIZE];

OneWire ds(5);

WiFiUDP udp;

float t = 185;

void setup() {
#ifdef DEBUG_SERIAL
  Serial.begin(115200);
  Serial.println("");
  Serial.println("BEGIN");
#endif
  timeToConnect = millis();
  
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
  
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  
  udp.begin(BROADCAST_PORT);
}

void loop() {
  readSensors();
  sendData();
}


void readSensors() {
  // Loop until we get a reasonable value
  while(t>150) {
    t = getTempF();
    delay(50);
  }
}


void sendData() {
  digitalWrite(LED_PIN, LOW);
  
  // Connect to the wifi network
  if(connect()) {
    // Assemble the UDP packet
    udp.beginPacket(BROADCAST_ADDRESS, BROADCAST_PORT);
    
    String str = String(DEVICE_NAME)+";f:"+String(t, 2)+"|g,conn:"+String(millis()-timeToConnect)+"|g";
    
    str += ";"+checksum(str);
    
    char data[str.length()];
    str.toCharArray(data, str.length()+1);
        
  #ifdef DEBUG_SERIAL
    Serial.print("> ");
    Serial.print(str.length()+1);
    Serial.print(": ");
    Serial.println(data);
  #endif
    
    // Send the packet!
    udp.write(data, str.length());
    udp.endPacket();
    
    // Wait for things to settle down
    delay(POST_DATA_DELAY*1000);
    
    // Disconnect from wifi
    WiFi.disconnect();
    
    digitalWrite(LED_PIN, HIGH);
    
#ifdef DEBUG_SERIAL
    Serial.print("Sleeping for ");
    Serial.println(SLEEP_DURATION);
#endif
    
    // Go to sleep!
    system_deep_sleep_set_option(0);
    system_deep_sleep(SLEEP_DURATION * 1000000);
  }

  digitalWrite(LED_PIN, HIGH);
}


float getTempC() {
  byte data[12];
  byte addr[8];
  
  if(!ds.search(addr)) {
    ds.reset_search();
    return -1000;
  }
  
  if(OneWire::crc8(addr, 7)!=addr[7]) {
#ifdef DEBUG_SERIAL
    Serial.println("CRC is not valid!");
#endif
    return -1000;
  }
  
  if(addr[0] != 0x10 && addr[0] != 0x28) {
#ifdef DEBUG_SERIAL
    Serial.println("Device is not recognized");
#endif
    return -1000;
  }
  
  ds.reset();
  ds.select(addr);
  ds.write(0x44, 1);
  
  byte present = ds.reset();
  ds.select(addr);
  ds.write(0xBE);
  
  for(uint8_t i=0; i<9; i++) {
    data[i] = ds.read();
  }
  
  ds.reset_search();
  
  byte MSB = data[1];
  byte LSB = data[0];
  
  float tempRead = ((MSB<<8) | LSB);
  return tempRead/16;
}


float getTempF() {
  return getTempC() * 9/5 + 32;
}


uint8_t ord(char b) {
  uint8_t a;
  a = b-'0';
  return a;
}


String checksum(String s) {
  uint16_t crc = 0;
  
  for(uint8_t i=0; i<s.length(); i++) {
    crc += ord(s.charAt(i));
  }
  
  return String(crc, HEX);
}


bool connect() {
 #ifdef DEBUG_SERIAL
   Serial.print("Connecting: ");
 #endif
 
  while(WiFi.status() != WL_CONNECTED) {
    if(millis()%100==0) {
#ifdef DEBUG_SERIAL
      Serial.print(".");
#endif
      statusLED = !statusLED;
      digitalWrite(LED_PIN, statusLED);
      delay(1);
    }
  }
  
#ifdef DEBUG_SERIAL
  Serial.println(" done!");
#endif

  return true;
}

Credits

Garrett Bartley

Garrett Bartley

16 projects • 52 followers
Husband, father, maker.

Comments