Hi kids. So, I have this thing where I like to know exactly how cold it is in the garage before I head out there. Since I've been wanting to play around with the arduino stuff, this seemed like a good project.
This code pushes the sensor readings over MQTT, which I can then pick up and incorporate into the various places I want it. The code is running on an arduino Uno with a wiznet ethernet shield. I'm running the ethernet through a bridged wifi client until I get some network in the garage.
Here's the sketch:
/*
Environment Monitor
Build for Garage - 1 DHT11 Sensor
2014-01-23
*/
#include <stdarg.h>
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include "DHTSensor.h"
#include <ICMPPing.h>
// Fixed Definitions
#define VERSION "1.2-Garage"
#define DEVID "F3"
#define SENSORNAME "Outdoors"
#define CMDQ "net-command"
#define DHTTYPE DHT11
#define DHTPIN 2
// Network config
byte mac[]= {0xAA, 0x00, 0x00, 0xE1, 0x00, 0x73};
byte ip[]= {192, 168, 100, 73};
byte gateway[]= {192, 168, 100, 254};
byte subnet[]= {255, 255, 255, 0};
byte mqtt_broker[]= {192, 168, 100, 150};
// Function declarations
String splitString(String s, char parser,int index);
void callback(char* topic, byte* payload, unsigned int length);
// Instances
EthernetClient ethClient;
PubSubClient client(mqtt_broker, 1883, callback, ethClient);
DHT dht(DHTPIN, DHTTYPE);
// sockets
SOCKET pingSocket = 3;
// State Variables
char* commandText = "";
char* deviceId = DEVID;
char* cmdTopic = CMDQ;
char* sensorName = SENSORNAME;
char* sensorTemp = "";
char* sensorRh = "";
int sampleDelay = 30000;
long lastSampleTime = 0;
char pingBuffer[256];
int pingDelay = 10000;
long lastPingTime = 0;
int netUp = 1;
// printf work-around
char* p(char *fmt, ... ){
char tmp[128]; // resulting string limited to 128 chars
va_list args;
va_start (args, fmt );
vsnprintf(tmp, 128, fmt, args);
va_end (args);
return tmp;
}
void softwareReset() // Restarts program from beginning but does not reset the peripherals and registers
{
asm volatile (" jmp 0");
}
void clientConnect() {
if (client.connect(deviceId)) {
commandText = p("Status:%s:Connected",deviceId);
client.publish(cmdTopic,commandText);
Serial.println(commandText);
commandText = p("Status:%s:%i.%i.%i.%i",deviceId,ip[0],ip[1],ip[2],ip[3]);
client.publish(cmdTopic,commandText);
Serial.println(commandText);
client.subscribe(cmdTopic);
commandText = p("Status:%s:Subscribed to %s",deviceId,cmdTopic);
Serial.println(commandText);
} else {
Serial.println("Connection failed to MQTT");
netUp = 0; // Set network down - loop will retry connect
}
}
// Program setup
void setup() {
delay(200);
Ethernet.begin(mac,ip,gateway,subnet);
delay(200);
dht.begin();
Serial.begin(9600);
Serial.println();
Serial.println("Environment Monitor");
Serial.println(VERSION);
Serial.println();
clientConnect();
Serial.println();
}
char* deblank(char* input)
{
char *output=input;
int k,j;
for (k = 0, j = 0; i<strlen(input); k++,j++)
{
if (input[k]!=' ')
output[j]=input[k];
else
j--;
}
output[j]=0;
return output;
}
// splitString function
String splitString(String s, char parser,int index){
String rs='\0';
int parserIndex = index;
int parserCnt=0;
int rFromIndex=0, rToIndex=-1;
while(index>=parserCnt){
rFromIndex = rToIndex+1;
rToIndex = s.indexOf(parser,rFromIndex);
if(index == parserCnt){
if(rToIndex == 0 || rToIndex == -1){
return '\0';
}
return s.substring(rFromIndex,rToIndex);
}
else{
parserCnt++;
}
}
return rs;
}
void sendHumidity1() {
float hum = dht.readHumidity();
char hum_c[5] = "";
dtostrf(hum,5, 1, hum_c);
sensorRh = hum_c;
commandText = p("Status:%s:RH=%s",deviceId,deblank(hum_c));
client.publish(cmdTopic,commandText);
Serial.println(commandText);
}
void sendTemperature1() {
float tempf = dht.readTemperature(1);
char tempf_c[5] = "";
dtostrf(tempf,5, 1, tempf_c);
sensorTemp = tempf_c;
commandText = p("Status:%s:Temp=%s",deviceId,deblank(tempf_c));
client.publish(cmdTopic,commandText);
Serial.println(commandText);
}
// Callback function
void callback(char* topic, byte* payload, unsigned int length) {
//convert byte to char
payload[length] = '\0';
String strPayload = String((char*)payload);
String strPayloadOrig = strPayload;
strPayload += ":"; // splitString has issues...
String receiveId = splitString(strPayload,':',0);
String receiveCmd = splitString(strPayload,':',1);
String receiveChn = splitString(strPayload,':',2);
if (strPayloadOrig != commandText) {
if (receiveId == deviceId) {
if (receiveCmd == "REQ") {
commandText = p("Status:%s:OK",deviceId);
client.publish(cmdTopic,commandText);
Serial.println(commandText);
}
if (receiveCmd == "RST") {
commandText = p("Status:%s:Reset in 5 seconds",deviceId);
client.publish(cmdTopic,commandText);
Serial.println(commandText);
delay(5000);
softwareReset();
}
if (receiveCmd == "VER") {
commandText = p("Status:%s:%s",deviceId,VERSION);
client.publish(cmdTopic,commandText);
Serial.println(commandText);
}
}
}
}
void loop() {
client.loop();
if ((millis() - lastPingTime) > pingDelay) {
if ( netUp == 0 ) {
delay(5000);
clientConnect(); // Wait 5 seconds, and re-init client
}
ICMPPing ping(pingSocket);
if (ping(4, mqtt_broker, pingBuffer)) {
netUp = 1;
} else {
Serial.println("NetFail");
netUp = 0;
}
lastPingTime = millis();
}
if ((millis() - lastSampleTime) > sampleDelay) {
if ( netUp == 1 ) {
commandText = p("Status:%s:Name=%s",deviceId,sensorName);
client.publish(cmdTopic,commandText);
Serial.println(commandText);
sendTemperature1();
sendHumidity1();
lastSampleTime = millis();
}
}
}
To use it, you'll need a few libraries. The DHT sensor library is from Adafruit. You can read about it
here. The MQTT piece uses the PubSubClient library, found
here. To handle network glitches, it's using ping to check connectivity, and will reconnect if it can't find the server. The ping library is
here. All-in-all, it may not be the most sophisticated sketch, but this one is getting the job done. Good luck!