0

Add sensor to Azure Starter Pack
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Add sensor to Azure Starter Pack

by Rezivor on Thu Aug 09, 2018 3:38 am

Currently I am working on a decide that sends data from a sensor to the amazon azure cloud. Currently I have gotten the code setup to send data from a temp/humidity sensor and a gas sensor-- both of these decides called for serial data the same so I was able to easily adapt the code from the libraries to use.

The Temperature/Sensor sensor calls to the following library
Code: Select all | TOGGLE FULL SIZE
/* DHT library

MIT license
written by Adafruit Industries
*/
#ifndef DHT_H
#define DHT_H

#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif


// Uncomment to enable printing out nice debug messages.
//#define DHT_DEBUG

// Define where debug output will be printed.
#define DEBUG_PRINTER Serial

// Setup debug printing macros.
#ifdef DHT_DEBUG
  #define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); }
  #define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); }
#else
  #define DEBUG_PRINT(...) {}
  #define DEBUG_PRINTLN(...) {}
#endif

// Define types of sensors.
#define DHT11 11
#define DHT22 22
#define DHT21 21
#define AM2301 21


class DHT {
  public:
   DHT(uint8_t pin, uint8_t type, uint8_t count=6);
   void begin(void);
   float readTemperature(bool S=false, bool force=false);
   float convertCtoF(float);
   float convertFtoC(float);
   float computeHeatIndex(float temperature, float percentHumidity, bool isFahrenheit=true);
   float readHumidity(bool force=false);
   boolean read(bool force=false);

 private:
  uint8_t data[5];
  uint8_t _pin, _type;
  #ifdef __AVR
    // Use direct GPIO access on an 8-bit AVR so keep track of the port and bitmask
    // for the digital pin connected to the DHT.  Other platforms will use digitalRead.
    uint8_t _bit, _port;
  #endif
  uint32_t _lastreadtime, _maxcycles;
  bool _lastresult;

  uint32_t expectPulse(bool level);

};

class InterruptLock {
  public:
   InterruptLock() {
    noInterrupts();
   }
   ~InterruptLock() {
    interrupts();
   }

};

#endif

And the message section of the code that sends the data to the web interface is as follows
Code: Select all | TOGGLE FULL SIZE
#include <Adafruit_Sensor.h>
#include <ArduinoJson.h>
#include <DHT.h>
#include <MQ2.h>
#include <hpma115S0.h>
#include <SoftwareSerial.h>


#if SIMULATED_DATA

hpma115S0.Init();
hpma115S0.StartParticleMeasurement();

void initSensor()
{
    // use SIMULATED_DATA, no sensor need to be inited
}

float readTemperature()
{
    return random(20, 30);
}

float readHumidity()
{
    return random(30, 40);
}

#else

static DHT dht(DHT_PIN, DHT_TYPE);
static MQ2 mq2(MQ_PIN);
SoftwareSerial hpmaSerial(TX, RX);
void initSensor()
{
    dht.begin();
    hpmaSerial.begin();

}
int GetPM2_5()
{
  return hpma115S0.GetPM2_5();
}
float readLPG()
{
    return mq2.readLPG();
}

float readSmoke()
{
    return mq2.readSmoke();
}

float readCO()
{
    return mq2.readCO();
}
float readTemperature()
{
    return dht.readTemperature();
}
float readHumidity()
{
    return dht.readHumidity();
}

#endif

bool readMessage(int messageId, char *payload)
{
    float smoke = readSmoke();
    init _pm2_5 = GetPM2_5();
    float lpg = readLPG();
    float co  = readCO();
    float humidity = readHumidity();
    float temperature = readTemperature();
    StaticJsonBuffer<MESSAGE_MAX_LEN> jsonBuffer;
    JsonObject &root = jsonBuffer.createObject();
    root["deviceId"] = DEVICE_ID;
    root["messageId"] = messageId;   
    bool temperatureAlert = false;

    // NAN is not the valid json, change it to NULL
     if (std::isnan(_pm2_5))
    {
        root["_pm2_5"] = NULL;
    }
    else
    {
        root["_pm2_5"] = _pm2_5;

    }
    if (std::isnan(smoke))
    {
        root["smoke"] = NULL;
    }
    else
    {
        root["smoke"] = smoke;

    }
    if (std::isnan(lpg))
    {
        root["lpg"] = NULL;
    }
    else
    {
        root["lpg"] = lpg;

    }

    if (std::isnan(co))
    {
        root["co"] = NULL;
    }
    else
    {
        root["co"] = co;

    }

    if (std::isnan(temperature))
    {
        root["temperature"] = NULL;
    }
    else
    {
        root["temperature"] = temperature;
    }
    if (std::isnan(humidity))
    {
        root["humidity"] = NULL;
    }
    else
    {
        root["humidity"] = humidity;
    }
    /* My modification */    root["tempAlert"] = temperatureAlert;
    root.printTo(payload, MESSAGE_MAX_LEN);
    return temperatureAlert;
}

void parseTwinMessage(char *message)
{
    StaticJsonBuffer<MESSAGE_MAX_LEN> jsonBuffer;
    JsonObject &root = jsonBuffer.parseObject(message);
    if (!root.success())
    {
        Serial.printf("Parse %s failed.\r\n", message);
        return;
    }

    if (root["desired"]["interval"].success())
    {
        interval = root["desired"]["interval"];
    }
    else if (root.containsKey("interval"))
    {
        interval = root["interval"];
    }
}

As you can see,

the call
Code: Select all | TOGGLE FULL SIZE
float readTemperature()
{
    return dht.readTemperature();
}

pulls the senor data

the code

Code: Select all | TOGGLE FULL SIZE
float humidity = readHumidity();

defines the value pulled

and the code
Code: Select all | TOGGLE FULL SIZE
if (std::isnan(temperature))
    {
        root["temperature"] = NULL;
    }
    else
    {
        root["temperature"] = temperature;
    }

tells the program to send that data to the server via another rest part of the code

This is the basic functionality and it works great.

I've attached a different sensor and i'm having trouble figuring how to extract that code from it in a similar fashion because it doesn't come with any truadional library where i can easily translate it like I was able to with the DHT library

It is for the Honeywell HPMA115S0-XXX Particle Sensor

The code for simply reading the data from the unit and displaying it to a serial port is as follows
Code: Select all | TOGGLE FULL SIZE
    /*
 * Read particle matter using a Honeywell HPMA115S0-XXX and a ESP8266 (WeMos Mini)
 */
#include <SoftwareSerial.h>

#define DEBUG false
#define pin_rx D5
#define pin_tx D6

SoftwareSerial Device(pin_rx, pin_tx);

const int AutoSendOn[4] =     {0x68, 0x01, 0x40, 0x57};
const int AutoSendOff[4] =    {0x68, 0x01, 0x20, 0x77};
const int StartPmMeasure[4] = {0x68, 0x01, 0x01, 0x96};
const int StopPmMeasure[4] =  {0x68, 0x01, 0x02, 0x95};
const int ReadPm[4] =         {0x68, 0x01, 0x04, 0x93};

int isAutoSend = true;
int useReading = true;

int pm25 = 0;   // PM2.5
int pm10 = 0;   // PM10

unsigned long lastReading = 0;

void sendCommand(const int *cmd) {
  int i;
  for(i=0;i<4; i++) {
    Device.write(cmd[i]);
  }
  // let a unicorn pass
  delay(10);
}

int readResponse(int l = 32) {
  int i = 0;
  int buf[l];

  unsigned long start = millis();

  while(Device.available() > 0 && i < l) {

    buf[i] = Device.read();                 // read bytes from device

    if(DEBUG) {
      Serial.print("i: "); Serial.print(i);
      Serial.print(" buf[i]: "); Serial.println(buf[i], HEX);
    }

    // check for HEAD or skip a byte
    if(i == 0 && !(buf[0] == 0x40 || buf[0] == 0x42 || buf[0] == 0xA5 || buf[0] == 0x96)) {
      if(DEBUG) { Serial.println("Skipping Byte"); }
      continue;
    } else {
      i++;
    }

    if(buf[0] == 0x42 && buf[1] == 0x4d) {  // Autosend
      if(DEBUG) { Serial.println("Autosend"); }
      l=32;
    }

    if(buf[0] == 0x40 && buf[2] == 0x4) {   // Reading
      if(DEBUG) { Serial.println("Reading"); }
      l=8;
    }

    if(buf[0] == 0xA5 && buf[1] == 0xA5) {  // Pos. ACK
      if(DEBUG) { Serial.println("ACK"); }
      return true;
    }

    if(buf[0] == 0x96 && buf[1] == 0x96) {  // Neg. ACK
      if(DEBUG) { Serial.println("NACK"); }
      return false;
    }

    if (millis() - start > 1000) {          // trigger Timeout after 1 sec
      Serial.println("Timeout");
      return false;
    }

  }

  // check checksum in Reading
  if(buf[2] == 0x04) {
    // HEAD+LEN+CMD
    int cs = buf[0] + buf[1] + buf[2];
    int c;

    // DATA
    for(c = 3; c < (2 + buf[1]); c++) {
      // Serial.println(buf[c]);
      cs += buf[c];
    }
    // CS = MOD((65536-(HEAD+LEN+CMD+DATA)), 256)
    cs = (65536 - cs) % 256;

    // validate checksum
    if(cs == buf[c]) {
      // calculate PM values
      pm25 = buf[3] * 256 + buf[4];
      pm10 = buf[5] * 256 + buf[6];
      return true;
    } else {
      Serial.println("Checksum mismatch");
    }
  } else if(buf[3] == 0x1c) {  // Autoreading
    int cs = 0;
    int c;
    // DATA
    for(c = 0; c <= buf[3]; c++) {
      // Serial.println(buf[c]);
      cs += buf[c];
    }
    int checksum = buf[30] * 256 + buf[31];
    if(DEBUG) {
      Serial.print("Checksum: "); Serial.print(checksum, HEX);
      Serial.print(" CS: "); Serial.println(cs, HEX);
    }

    if(cs == checksum) {
      // calculate PM values
      pm25 = buf[6] * 256 + buf[7];
      pm10 = buf[8] * 256 + buf[9];
      return true;
    } else {
      Serial.println("Checksum mismatch");
    }
  } else {
    // unkown
  }

  return false;
}

void setup() {
  // init Serial for ESP8266
  Serial.begin(115200); Serial.println();
  // init Serial for Device
  Device.begin(9600); Device.println();
}

void loop() {

  if(millis() - lastReading >= 1000 || lastReading == 0) {
    lastReading = millis();

    // handle AutoSend
    if(isAutoSend) {
      if(useReading) {
        if(readResponse()) {
          Serial.print("PM 2.5: "); Serial.print(pm25);
          Serial.print(" / PM 10: "); Serial.println(pm10);
        }
      } else { // disable
        Serial.println("Stop AutoSend");
        sendCommand(AutoSendOff);
        if(readResponse()) {
          Serial.println("AutoSend disabled.");
          isAutoSend = !isAutoSend;
        }
      }
    } else {
      sendCommand(ReadPm);
      if(readResponse()) {
        Serial.print("PM 2.5: "); Serial.print(pm25);
        Serial.print(" / PM 10: "); Serial.println(pm10);
      }
    }
  }
}

Can anyone please help me with a way to call off the data in a way similar to the DHT sensor so that I can simply pull the value and send it to the IOT cloud like I have the other sensors?

The full Azure Code is attached here https://github.com/rezivor/Multisensor

Rezivor
 
Posts: 2
Joined: Fri Jun 22, 2018 7:58 am

Please be positive and constructive with your questions and comments.