Tuesday, November 24, 2015

Temperature and humidity sender

For my ESP8266 chronothermostat I need a sensor to transmit temperature every two minutes ( humidity is a bonus) and to be battery operated.

Between the transmissions the ESP is in deep sleep. As a sensor I've used the DTH22 for one sensor and BMP180 for the other one.

For rapid development I've installed the Arduino IDE (1.6.5) and update it for ESP8266.

As additional libraries I've used: PubSubClient for MQTT and ArduinoJSON for JSON formatting.

Code is sending two JSON strings one for device capabilities, and one with the data.


#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <PubSubClient.h>
#include <DHT.h>


#define DHTTYPE DHT22
#define DHTPIN  5
#define wifi_ssid "................"
#define wifi_password ".................."
#define mqtt_server "................"
#define mqtt_user "............."
#define mqtt_password "..........."
#define mqtt_port "1880"
#define dth_topic "/62/dth"
#define device_status_topic "/62/device/status"
#define DEBUG false
#define Serial if(DEBUG)Serial

WiFiClient espClient;
PubSubClient client(espClient);
DHT dht(DHTPIN, DHTTYPE, 11); // 11 works fine for ESP8266


float humidity, temp_f;  // Values read from sensor
// Time to sleep (in seconds):
const int sleepTimeS = 120; //120 seconds


/********************************************************************
* FunctionName: gettemperature                                          
* Description : Read temperature and humidity from sensor
*               Values are stored in humidity and temp_f   
* Parameters  : None                             
* Returns     : None                                                     
*********************************************************************/

void gettemperature() 
{
  int runs=0;
  do {
       delay(2000);
       temp_f = dht.readTemperature(false);     
       humidity = dht.readHumidity();          

       if(runs > 0)
           Serial.println("##Failed to read from DHT sensor! ###");
       Serial.println(String(temp_f ).c_str());
       Serial.println(String(humidity ).c_str());
       runs++;
    }
    while(isnan(temp_f) && isnan(humidity));
}

/********************************************************************
* FunctionName: setup_wifi                                          
* Description : Setup wifi network   
* Parameters  : None                             
* Returns     : None                                                     
*********************************************************************/

void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(wifi_ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(wifi_ssid, wifi_password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

/********************************************************************
* FunctionName: reconnect                                          
* Description : Reconnect to the wifi network in case the connection
*               is lost  
* Parameters  : None                             
* Returns     : None                                                     
*********************************************************************/
void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) 
  {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    // If you do not want to use a username and password, change next line to
    // if (client.connect("ESP8266Client")) {
    if (client.connect("ESP8266ClientT", mqtt_user, mqtt_password)) {
      Serial.println("connected");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

/********************************************************************
* FunctionName: setup                                          
* Description : SETUP function  
* Parameters  : None                             
* Returns     : None                                                     
*********************************************************************/

void setup() 
{
  Serial.begin(115200);
  char dev_name[50];  
/*
  Serial.println( "Booting" );
  Serial.println();
  Serial.printf( "Sketch size: %u\n", ESP.getSketchSize() );
  Serial.printf( "Free size: %u\n", ESP.getFreeSketchSpace() );
  Serial.printf( "Heap: %u\n", ESP.getFreeHeap() );
  Serial.printf( "Boot Vers: %u\n", ESP.getBootVersion() );
  Serial.printf( "CPU: %uMHz\n", ESP.getCpuFreqMHz() );
  Serial.printf( "SDK: %s\n", ESP.getSdkVersion() );
  Serial.printf( "Chip ID: %u\n", ESP.getChipId() );
  Serial.printf( "Flash ID: %u\n", ESP.getFlashChipId() );
  Serial.printf( "Flash Size: %u\n", ESP.getFlashChipRealSize() );
  Serial.printf( "Vcc: %u\n", ESP.getVcc() );
  Serial.println();
*/
  char json_buffer[512];
  char json_buffer_status[512];
  char my_ip_s[16];

  //this one is static allocation
  StaticJsonBuffer<512> jsonBuffer;
  JsonObject& root = jsonBuffer.createObject(); 

  //This one is dynamic one (just for fun). Avoid this in embeded system
  //Can be changed to Static one like: StaticJsonBuffer<512> jsonDeviceStatus;
  DynamicJsonBuffer jsonDeviceStatus;
  JsonObject& jsondeviceStatus = jsonDeviceStatus.createObject();
  
  sprintf(dev_name, "ESP_%d", ESP.getChipId());

  setup_wifi();
  client.setServer(mqtt_server, 1880);
  client.connect(dev_name, mqtt_user, mqtt_password);
  
  if (!client.connected()) 
  {
    reconnect();
  }
  client.loop();

  IPAddress my_ip_addr = WiFi.localIP();
  sprintf(my_ip_s, "%d.%d.%d.%d",   my_ip_addr[0],my_ip_addr[1],my_ip_addr[2],my_ip_addr[3]);
  jsondeviceStatus ["device_name"] = dev_name;
  jsondeviceStatus["type"] = "dth"; 
  jsondeviceStatus["ipaddress"] = String(my_ip_s).c_str();
  jsondeviceStatus["bgn"] = 3;
  jsondeviceStatus["sdk"] = ESP.getSdkVersion();
  jsondeviceStatus["version"] = "1";
  jsondeviceStatus["uptime"] = 0;
  
  jsondeviceStatus.printTo(json_buffer_status, sizeof(json_buffer_status));  
  client.publish(device_status_topic, json_buffer_status , false);
  Serial.println(json_buffer_status);



  gettemperature();
  String hum;
  hum = String(humidity ).c_str();  
  root["device_name"] = dev_name;
  root["type"] = "dth";  
  root["temperature"] = String(temp_f).c_str();
  root["humidity"]    = hum; 
  root.printTo(json_buffer, sizeof(json_buffer));  
  client.publish(dth_topic, json_buffer , false);

  Serial.println("Go to sleep!!!!");
  // deepSleep time is defined in microseconds. Multiply
  // seconds by 1e6 
  ESP.deepSleep(sleepTimeS * 1000000); //
}


/********************************************************************
* FunctionName: loop                                          
* Description : LOOP function  
* Parameters  : None                             
* Returns     : None                                                     
*********************************************************************/
void loop() {}





8 comments:

  1. Hi, which dht library you are using? I've tried the adafruit with this one and the latest version automatically calculates the timings of the data stream and the temp values are too high and the humidity varies wildly. I think it calculating the data stream timings incorrectly in my case, I notice you can set the timing constant to 11, is this an older version or another library? Thanks. Richard

    ReplyDelete
  2. Hi Richard,

    I have used the Adafruit library. Is the same as in https://learn.adafruit.com/esp8266-temperature-slash-humidity-webserver/code

    Try to tune the timing (11) value.

    ReplyDelete
  3. Hi Thanks, I was using the latest version not 1.0. I'll try it tonight.

    ReplyDelete
  4. Great article and code, thanks for sharing.

    Would you mind elaborating more around your mqtt configuration? The charts look like ThingSpeak, which I am using successfully. But your code seems to be using mqtt messages. I am not aware of an mqtt interface into ThingSpeak - am I simply not seeing it?

    Would love to get away from the REST interface and onto messaging... Any insights on your cloud mqtt service and how you are using it would be appreciated!

    Thanks,

    Jay

    ReplyDelete
  5. Hi Jay,

    I am using mosquitto as an MQTT broker. It is installed on a raspberry pi and bridged to another cloud instance. In this way when I am away my mobile app is connecting to the cloud mqtt instance and when I am at home is using the raspberry pi's instance.

    ReplyDelete
  6. Thanks Catalin.

    I've seen Mosquito, but not tried it. I have looked at PubNub as a cloud service provider for MQTT. They offer a free plan for 100 devices and 1 million messages a month. I just hesitate to refactor too many parts of my project at the same time. Current approach is to move away from a centralized Arduino Due into a more distributed ESP8266 model for collecting data closer to the sensor. (Ultimately MQTT makes very good sense in this model too.)

    Was Mosquito simple install on the Pi, or was there an SD card image with the broker already included? I am okay with Linux, but not super deep, so it could turn into a project of it's own...

    Regarding a GUI - Have you considered standing up a website to present and interact with your data? I am currently working to replace ThingSpeak with a Rails app that exposes API end points for the ESP to upload data, while also providing a GUI to display and interact with the data. A rather straight forward use case for Rails - but early work in progress for me. In the end I can envision the ability to manage devices, calibrations, and analytics in this app layer.

    Curious what you are doing regarding the GUI? Is it all mobile?

    Thanks!

    Jay

    ReplyDelete
  7. Hi Jay,

    Mosquitto is easy to install on a raspberry pi. I am using cloudmqtt.com as roaming broker. The GUI web server will be the last piece to develop, when I'll have all sensors/nodes in place. For now you can see the mobile app that I've developed for controling thinkgs around the house here: http://myesp8266.blogspot.ro/2015/10/update-android-application-to-control.html

    ReplyDelete
  8. Hy, I want to make a wifi cronotermostat. I'm new in RPI. (I have a rpi2). Can you send me a mail with how to start this project

    ReplyDelete