Demo of DHT11->mDot->TTN

Dependencies:   DHT22 DS18B20_1wire SHTx TSL2561_I2C libmDot mbed-rtos mbed

Fork of mDot_TTN_DHT11 by Chris Merck

main.cpp

Committer:
merckeng
Date:
2016-08-17
Revision:
15:c61c5f1533e8
Parent:
14:e4574212176a
Child:
16:01a1058d9c8e

File content as of revision 15:c61c5f1533e8:

/** mDot_TTN_DHT11 -- The Things Network Temperature & Humidity Sensor
 *
 * Uses MultiTech mDot developer board http://www.multitech.com/models/94558010LF
 * Requires a MultiTech MultiConnect Conduit http://www.multitech.com/models/94557203LF
 * http://www.multitech.net/developer/software/lora/conduit-mlinux-convert-to-basic-packet-forwarder/
 * http://forum.thethingsnetwork.org/t/setting-up-multitech-conduit-gateway-for-ttn/216/35
 *
 * To receive and visualize this data,
 *  consider using InitialState and the bridge code here:
 * https://github.com/things-nyc/initial-state-example
 */

#include "mbed.h"
#include "DHT11.h"
#include "mDot.h"
#include "MTSLog.h"
#include "MTSText.h"
#include <string>
#include <vector>

using namespace mts;

#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))


/** ABP
 * Register your device and update these values:
 * https://account.thethingsnetwork.org/
 */
uint8_t AppSKey[16]= { 0x50, 0x41, 0xE5, 0x57, 0xB6, 0x24, 0x7D, 0x4E, 0x6F, 0xF9, 0x9D, 0x0E, 0xDE, 0x13, 0xD6, 0xA2, };
uint8_t NwkSKey[16]= { 0x3E, 0x1C, 0xA9, 0x8A, 0x4C, 0x0A, 0xA9, 0x91, 0x3A, 0xFD, 0xAE, 0x70, 0x66, 0x37, 0x51, 0x9D, };
uint8_t NetworkAddr[4]= {0x26,0xFC,0x2A,0x9B};


// Some defines for the LoRa configuration
#define LORA_SF mDot::SF_7
#define LORA_ACK 0
#define LORA_TXPOWER 20
static uint8_t config_frequency_sub_band = 2;

// functions for ensuring network endianness (little-endian)
uint16_t hton16(const uint16_t x)
{
  uint16_t t = x;
  uint8_t * a = (uint8_t*)&t;
  a[0] = x>>(8*1);
  a[1] = x>>(8*0);
  return t;
}
void hton16(uint16_t * x)
{
  *x = hton16(*x);
}


// packet payload format
#pragma pack(push, 1) // exact fit - no padding
struct sigmap_packet_t {
  uint16_t seq;
  uint8_t pwr;    /* tx power in dbm, +128 offset */
  uint16_t temp;  /* temperature, in hundreths of a degree C, +32768 offset  */
  uint16_t humid; /* relative humidity, in hundreths of a percent, +32768 offset */
  void hton() {
    hton16(&seq);
    hton16(&temp);
    hton16(&humid);
  }
};
#pragma pack(pop) // back to whatever the previous packing mode was 

// Temperature sensor object
#define DHT_PIN PB_1
DHT11 dht(DHT_PIN);

// Serial via USB for debugging only
Serial pc(USBTX,USBRX);

int main()
{
    sigmap_packet_t pkt;
    
    int32_t ret;
    mDot* dot;
    std::vector<uint8_t> send_data;
    std::vector<uint8_t> recv_data;
    std::vector<uint8_t> nwkSKey;
    std::vector<uint8_t> appSKey;
    std::vector<uint8_t> nodeAddr;
    std::vector<uint8_t> networkAddr;

    float temperature = 0.0;

    pc.baud(115200);
    pc.printf("TTN mDot LoRa Temperature  & Humidity Sensor\n\r");

    // get a mDot handle
    dot = mDot::getInstance();

//  dot->setLogLevel(MTSLog::WARNING_LEVEL);
    dot->setLogLevel(MTSLog::TRACE_LEVEL);

    logInfo("Checking Config");

    // Test if we've already saved the config
    std::string configNetworkName = dot->getNetworkName();

    uint8_t *it = NwkSKey;
    for (uint8_t i = 0; i<16; i++)
        nwkSKey.push_back((uint8_t) *it++);
        
    it = AppSKey;
    for (uint8_t i = 0; i<16; i++)
        appSKey.push_back((uint8_t) *it++);

    it = NetworkAddr;
    for (uint8_t i = 0; i<4; i++)
        networkAddr.push_back((uint8_t) *it++);

    logInfo("Resetting Config");
    // reset to default config so we know what state we're in
    dot->resetConfig();

    // Set byte order - AEP less than 1.0.30
//    dot->setJoinByteOrder(mDot::LSB);
    dot->setJoinByteOrder(mDot::MSB);       // This is default for > 1.0.30 Conduit



    logInfo("Set TxPower");
    if((ret = dot->setTxPower( LORA_TXPOWER )) != mDot::MDOT_OK) {
        logError("Failed to set Tx Power %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
    }

    logInfo("Set Public mode");
    if((ret = dot->setPublicNetwork(true)) != mDot::MDOT_OK) {
        logError("failed to set Public Mode %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
    }

    logInfo("Set MANUAL Join mode");
    if((ret = dot->setJoinMode(mDot::MANUAL)) != mDot::MDOT_OK) {
        logError("Failed to set MANUAL Join Mode %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
    }

    logInfo("Set Ack");
    // 1 retries on Ack, 0 to disable
    if((ret = dot->setAck( LORA_ACK)) != mDot::MDOT_OK) {
        logError("Failed to set Ack %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
    }

    //Not applicable for 868MHz in EU
    if ((ret = dot->setFrequencySubBand(config_frequency_sub_band)) != mDot::MDOT_OK) {
        logError("failed to set frequency sub band", ret);
    }

    logInfo("Set Network Address");
    if ((ret = dot->setNetworkAddress(networkAddr)) != mDot::MDOT_OK) {
        logError("Failed to set Network Address %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
    }

    logInfo("Set Data Session Key");
    if ((ret = dot->setDataSessionKey(appSKey)) != mDot::MDOT_OK) {
        logError("Failed to set Data Session Key %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
    }

    logInfo("Set Network Session Key");
    if ((ret = dot->setNetworkSessionKey(nwkSKey)) != mDot::MDOT_OK) {
        logError("Failed to set Network Session Key %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
    }

    logInfo("Saving Config");
    // Save config
    if (! dot->saveConfig()) {
        logError("failed to save configuration");
    }

    // Display what is set
    std::vector<uint8_t> tmp = dot->getNetworkSessionKey();
    pc.printf("Network Session Key: ");
    pc.printf("%s\r\n", mts::Text::bin2hexString(tmp, " ").c_str());

    tmp = dot->getDataSessionKey();
    pc.printf("Data Session Key: ");
    pc.printf("%s\r\n", mts::Text::bin2hexString(tmp, " ").c_str());

    pc.printf("Device ID ");
    std::vector<uint8_t> deviceId;
    deviceId = dot->getDeviceId();
    for (std::vector<uint8_t>::iterator it = deviceId.begin() ; it != deviceId.end(); ++it)
        pc.printf("%2.2x",*it );
    pc.printf("\r\n");

    std::vector<uint8_t> netAddress;

    pc.printf("Network Address ");
    netAddress = dot->getNetworkAddress();
    for (std::vector<uint8_t>::iterator it = netAddress.begin() ; it != netAddress.end(); ++it)
        pc.printf("%2.2x",*it );

    pc.printf("\r\n");

    // Display LoRa parameters
    // Display label and values in different colours, show pretty values not numeric values where applicable
    pc.printf("Public Network: %s\r\n", (char*)(dot->getPublicNetwork() ? "Yes" : "No") );
    pc.printf("Frequency: %s\r\n", (char*)mDot::FrequencyBandStr(dot->getFrequencyBand()).c_str() );
    pc.printf("Sub Band: %s\r\n", (char*)mDot::FrequencySubBandStr(dot->getFrequencySubBand()).c_str() );
    pc.printf("Join Mode: %s\r\n", (char*)mDot::JoinModeStr(dot->getJoinMode()).c_str() );
    pc.printf("Join Retries: %d\r\n", dot->getJoinRetries() );
    pc.printf("Join Byte Order: %s\r\n", (char*)(dot->getJoinByteOrder() == 0 ? "LSB" : "MSB") );
    pc.printf("Link Check Count: %d\r\n", dot->getLinkCheckCount() );
    pc.printf("Link Check Thold: %d\r\n", dot->getLinkCheckThreshold() );
    pc.printf("Tx Data Rate: %s\r\n", (char*)mDot::DataRateStr(dot->getTxDataRate()).c_str() );
    pc.printf("Tx Power: %d\r\n", dot->getTxPower() );
    pc.printf("TxWait: %s, ", (dot->getTxWait() ? "Y" : "N" ));
    pc.printf("CRC: %s, ", (dot->getCrc() ? "Y" : "N") );
    pc.printf("Ack: %s\r\n", (dot->getAck() ? "Y" : "N")  );

    logInfo("Joining Network");

    while ((ret = dot->joinNetwork()) != mDot::MDOT_OK) {
        logError("failed to join network [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
        wait_ms(dot->getNextTxMs() + 1);
    }

    logInfo("Joined Network");

    char dataBuf[50];
    uint16_t seq = 0;
    char * sf_str;
    while( 1 ) {
        
        /* cycle through spreading factors */
        uint8_t sf;
        switch (seq % 4) {
            case 0:
                sf = mDot::SF_7;
                sf_str = "SF7";
                break;
            case 1:
                sf = mDot::SF_8;
                sf_str = "SF8";
                break;
            case 2:
                sf = mDot::SF_9;
                sf_str = "SF9";
                break;
            case 3:
                sf = mDot::SF_10;
                sf_str = "SF10";
                break;
        }        
        // Set Spreading Factor, higher is lower data rate, smaller packets but longer range
        // Lower is higher data rate, larger packets and shorter range.
        logInfo("Set SF: %s",sf_str);
        if((ret = dot->setTxDataRate( sf )) != mDot::MDOT_OK) {
            logError("Failed to set SF %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
        }
        
        /* set default data values */
        int temp = 0;
        int humid = -1;
        
        /* read from sensor */
        int r = dht.readData();
        switch (r) {
            case DHT11::OK:
            {
                temp = dht.readTemperature();
                humid = dht.readHumidity();
                pc.printf("[DHT] T %d degC   H %d %%\r\n",temp,humid);
                break;
            }
            default:
            {
                pc.printf("[DHT] ERROR %d\r\n",r);
                break;
            }
        };
        
        /* build packet */
        pkt.seq = seq;
        pkt.pwr = LORA_TXPOWER + 128;
        pkt.temp = temp*100 + 32768;
        pkt.humid = humid*100 + 32768;
        
        /* load vector */
        pkt.hton();        
        send_data.clear();        
        for( int i=0; i< sizeof(pkt); i++ )
            send_data.push_back( ((uint8_t*)&pkt)[i] );

        /* send packet */
        if ((ret = dot->send(send_data)) != mDot::MDOT_OK) {
            logError("failed to send: [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
        } else {
            logInfo("send data: %s", Text::bin2hexString(send_data).c_str());
        }

        /* sleep */
        uint32_t sleep_time = MAX((dot->getNextTxMs() / 1000), 10 /* use 6000 for 10min */);
        logInfo("going to sleep for %d seconds", sleep_time);
        wait_ms(10*1000);
        
        seq++;
    }

    return 0;
}