Demo of DHT11->mDot->TTN

Dependencies:   DHT22 DS18B20_1wire SHTx TSL2561_I2C libmDot mbed-rtos mbed

Fork of mDot_TTN_DHT11 by Chris Merck

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /** mDot_TTN_Raingarden -- Rain Garden Sensor by The Things Network New York
00002  * 
00003  *  This firmware runs an mDot dev board, with the following sensors:
00004  *   - DHT22 - air temp & humidity
00005  *   - TSL2561 - ambient light
00006  *   - SHT10 - soil temp & humidity
00007  *   - DS18B20 - water temp
00008  * 
00009  * Uses MultiTech mDot developer board http://www.multitech.com/models/94558010LF
00010  * Requires a MultiTech MultiConnect Conduit http://www.multitech.com/models/94557203LF
00011  * http://www.multitech.net/developer/software/lora/conduit-mlinux-convert-to-basic-packet-forwarder/
00012  * http://forum.thethingsnetwork.org/t/setting-up-multitech-conduit-gateway-for-ttn/216/35
00013  *
00014  * To receive and visualize this data:
00015  *
00016  */
00017 
00018 #include "mbed.h"
00019 #include "mDot.h"
00020 #include "MTSLog.h"
00021 #include "MTSText.h"
00022 #include "DHT22.h"
00023 #include "TSL2561_I2C.h"
00024 #include "sht15.hpp"
00025 #include "DS18B20.h"
00026 #include <string>
00027 #include <vector>
00028 
00029 using namespace mts;
00030 
00031 /* Pin definitions */
00032 
00033 // air temp/humid sensor
00034 #define DHT_PIN PA_1
00035 DHT22 dht(DHT_PIN);
00036 
00037 // water temp sensor
00038 #define DS_PIN PA_11
00039 DS18B20 thermom(DS_PIN, DS18B20::RES_12_BIT); 
00040 
00041 // soil temp/humid sensor
00042 #define SHT_DATA_PIN PA_4
00043 #define SHT_SCK_PIN PC_13
00044 SHTx::SHT15 sht(SHT_DATA_PIN, SHT_SCK_PIN);
00045 
00046 // light sensor
00047 #define TSL_DATA_PIN PC_9
00048 #define TSL_SCK_PIN PA_8
00049 TSL2561_I2C tsl(TSL_DATA_PIN, TSL_SCK_PIN);
00050 
00051 // LEDs
00052 #define STATUS PB_1
00053 
00054 #define MIN(a,b) (((a)<(b))?(a):(b))
00055 #define MAX(a,b) (((a)>(b))?(a):(b))
00056 
00057 
00058 /** ABP
00059  * Register your device and update these values:
00060  * https://account.thethingsnetwork.org/
00061  */
00062 
00063 uint8_t AppSKey[16] = /* replace with Application Session Key in MSB format from TTN dashboard */;
00064 uint8_t NwkSKey[16] = /* replace with Network Session Key in MSB format from TTN dashboard */;
00065 uint8_t NetworkAddr[4] = /* replace with 4-byte Device Address from TTN dashboard */;
00066 
00067 // Some defines for the LoRa configuration
00068 #define LORA_SF mDot::SF_7
00069 #define LORA_ACK 0
00070 #define LORA_TXPOWER 20
00071 static uint8_t config_frequency_sub_band = 2;
00072 
00073 // functions for ensuring network endianness (little-endian)
00074 uint16_t hton16(const uint16_t x)
00075 {
00076   uint16_t t = x;
00077   uint8_t * a = (uint8_t*)&t;
00078   a[0] = x>>(8*1);
00079   a[1] = x>>(8*0);
00080   return t;
00081 }
00082 void hton16(uint16_t * x)
00083 {
00084   *x = hton16(*x);
00085 }
00086 
00087 
00088 
00089 // build a transmit buffer (from https://raw.githubusercontent.com/mcci-catena/Catena4410-Sketches/master/catena4410_sensor1/catena4410_sensor1.ino)
00090 class TxBuffer_t
00091         {
00092 public:
00093         uint8_t buf[32];   // this sets the largest buffer size
00094         uint8_t *p;
00095 
00096         TxBuffer_t() : p(buf) {};
00097         void begin()
00098                 {
00099                 p = buf;
00100                 }
00101         void put(uint8_t c)
00102                 {
00103                 if (p < buf + sizeof(buf))
00104                         *p++ = c;
00105                 }
00106         void put1u(int32_t v)
00107                 {
00108                 if (v > 0xFF)
00109                         v = 0xFF;
00110                 else if (v < 0)
00111                         v = 0;
00112                 put((uint8_t) v);
00113                 }
00114         void put2(uint32_t v)
00115                 {
00116                 if (v > 0xFFFF)
00117                         v = 0xFFFF;
00118 
00119                 put((uint8_t) (v >> 8));
00120                 put((uint8_t) v);
00121                 }
00122         void put2(int32_t v)
00123                 {
00124                 if (v < -0x8000)
00125                         v = -0x8000;
00126                 else if (v > 0x7FFF)
00127                         v = 0x7FFF;
00128 
00129                 put2((uint32_t) v);
00130                 }
00131         void put3(uint32_t v)
00132                 {
00133                 if (v > 0xFFFFFF)
00134                         v = 0xFFFFFF;
00135 
00136                 put((uint8_t) (v >> 16));
00137                 put((uint8_t) (v >> 8));
00138                 put((uint8_t) v);
00139                 }
00140         void put2u(int32_t v)
00141                 {
00142                 if (v < 0)
00143                         v = 0;
00144                 else if (v > 0xFFFF)
00145                         v = 0xFFFF;
00146                 put2((uint32_t) v);
00147                 }
00148         void put3(int32_t v)
00149                 {
00150                 if (v < -0x800000)
00151                         v = -0x800000;
00152                 else if (v > 0x7FFFFF)
00153                         v = 0x7FFFFF;
00154                 put3((uint32_t) v);
00155                 }
00156         uint8_t *getp(void)
00157                 {
00158                 return p;
00159                 }
00160         size_t getn(void)
00161                 {
00162                 return p - buf;
00163                 }
00164         uint8_t *getbase(void)
00165                 {
00166                 return buf;
00167                 }
00168         void put2sf(float v)
00169                 {
00170                 int32_t iv;
00171 
00172                 if (v > 32766.5f)
00173                         iv = 0x7fff;
00174                 else if (v < -32767.5f)
00175                         iv = -0x8000;
00176                 else
00177                         iv = (int32_t)(v + 0.5f);
00178 
00179                 put2(iv);
00180                 }
00181         void put2uf(float v)
00182                 {
00183                 uint32_t iv;
00184 
00185                 if (v > 65535.5f)
00186                         iv = 0xffff;
00187                 else if (v < 0.5f)
00188                         iv = 0;
00189                 else
00190                         iv = (uint32_t)(v + 0.5f);
00191 
00192                 put2(iv);
00193                 }
00194         void put1uf(float v)
00195                 {
00196                 uint8_t c;
00197 
00198                 if (v > 254.5)
00199                         c = 0xFF;
00200                 else if (v < 0.5)
00201                         c = 0;
00202                 else
00203                         c = (uint8_t) v;
00204 
00205                 put(c);
00206                 }
00207         void putT(float T)
00208                 {
00209                 put2sf(T * 256.0f + 0.5f);                
00210                 }
00211         void putRH(float RH)
00212                 {
00213                 put1uf((RH / 0.390625f) + 0.5f);
00214                 }
00215         void putV(float V)
00216                 {
00217                 put2sf(V * 4096.0f + 0.5f);
00218                 }
00219         void putP(float P)
00220                 {
00221                 put2uf(P / 4.0f + 0.5f);
00222                 }
00223         void putLux(float Lux)
00224                 {
00225                 put2uf(Lux);
00226                 }
00227         };
00228 
00229 /* the magic byte at the front of the buffer */
00230 enum    {
00231         FormatSensor1 = 0x11,
00232         };
00233 
00234 /* the flags for the second byte of the buffer */
00235 enum    {
00236         FlagVbat = 1 << 0,
00237         FlagVcc = 1 << 1,
00238         FlagTPH = 1 << 2,
00239         FlagLux = 1 << 3,
00240         FlagWater = 1 << 4,
00241         FlagSoilTH = 1 << 5,
00242         };
00243 
00244 
00245 
00246 // Serial via USB for debugging only
00247 Serial pc(USBTX,USBRX);
00248 
00249 int main()
00250 {
00251     TxBuffer_t b;
00252     
00253     int32_t ret;
00254     mDot* dot;
00255     std::vector<uint8_t> send_data;
00256     std::vector<uint8_t> recv_data;
00257     std::vector<uint8_t> nwkSKey;
00258     std::vector<uint8_t> appSKey;
00259     std::vector<uint8_t> nodeAddr;
00260     std::vector<uint8_t> networkAddr;
00261 
00262     float temperature = 0.0;
00263 
00264     DigitalInOut status_led(STATUS);
00265     status_led.output();
00266 
00267     pc.baud(115200);
00268     pc.printf("TTN mDot LoRa Temperature & Humidity Sensor\n\r");
00269 
00270     // get a mDot handle
00271     dot = mDot::getInstance();
00272 
00273 //  dot->setLogLevel(MTSLog::WARNING_LEVEL);
00274     dot->setLogLevel(MTSLog::TRACE_LEVEL);
00275 
00276     logInfo("Checking Config");
00277 
00278     // Test if we've already saved the config
00279     std::string configNetworkName = dot->getNetworkName();
00280 
00281     uint8_t *it = NwkSKey;
00282     for (uint8_t i = 0; i<16; i++)
00283         nwkSKey.push_back((uint8_t) *it++);
00284         
00285     it = AppSKey;
00286     for (uint8_t i = 0; i<16; i++)
00287         appSKey.push_back((uint8_t) *it++);
00288 
00289     it = NetworkAddr;
00290     for (uint8_t i = 0; i<4; i++)
00291         networkAddr.push_back((uint8_t) *it++);
00292 
00293     logInfo("Resetting Config");
00294     // reset to default config so we know what state we're in
00295     dot->resetConfig();
00296 
00297     // Set byte order - AEP less than 1.0.30
00298 //    dot->setJoinByteOrder(mDot::LSB);
00299     dot->setJoinByteOrder(mDot::MSB);       // This is default for > 1.0.30 Conduit
00300 
00301 
00302 
00303     logInfo("Set TxPower");
00304     if((ret = dot->setTxPower( LORA_TXPOWER )) != mDot::MDOT_OK) {
00305         logError("Failed to set Tx Power %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00306     }
00307 
00308     logInfo("Set Public mode");
00309     if((ret = dot->setPublicNetwork(true)) != mDot::MDOT_OK) {
00310         logError("failed to set Public Mode %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00311     }
00312 
00313     logInfo("Set MANUAL Join mode");
00314     if((ret = dot->setJoinMode(mDot::MANUAL)) != mDot::MDOT_OK) {
00315         logError("Failed to set MANUAL Join Mode %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00316     }
00317 
00318     logInfo("Set Ack");
00319     // 1 retries on Ack, 0 to disable
00320     if((ret = dot->setAck( LORA_ACK)) != mDot::MDOT_OK) {
00321         logError("Failed to set Ack %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00322     }
00323 
00324     //Not applicable for 868MHz in EU
00325     if ((ret = dot->setFrequencySubBand(config_frequency_sub_band)) != mDot::MDOT_OK) {
00326         logError("failed to set frequency sub band", ret);
00327     }
00328 
00329     logInfo("Set Network Address");
00330     if ((ret = dot->setNetworkAddress(networkAddr)) != mDot::MDOT_OK) {
00331         logError("Failed to set Network Address %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00332     }
00333 
00334     logInfo("Set Data Session Key");
00335     if ((ret = dot->setDataSessionKey(appSKey)) != mDot::MDOT_OK) {
00336         logError("Failed to set Data Session Key %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00337     }
00338 
00339     logInfo("Set Network Session Key");
00340     if ((ret = dot->setNetworkSessionKey(nwkSKey)) != mDot::MDOT_OK) {
00341         logError("Failed to set Network Session Key %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00342     }
00343 
00344     logInfo("Saving Config");
00345     // Save config
00346     if (! dot->saveConfig()) {
00347         logError("failed to save configuration");
00348     }
00349 
00350     // Display what is set
00351     std::vector<uint8_t> tmp = dot->getNetworkSessionKey();
00352     pc.printf("Network Session Key: ");
00353     pc.printf("%s\r\n", mts::Text::bin2hexString(tmp, " ").c_str());
00354 
00355     tmp = dot->getDataSessionKey();
00356     pc.printf("Data Session Key: ");
00357     pc.printf("%s\r\n", mts::Text::bin2hexString(tmp, " ").c_str());
00358 
00359     pc.printf("Device ID ");
00360     std::vector<uint8_t> deviceId;
00361     deviceId = dot->getDeviceId();
00362     for (std::vector<uint8_t>::iterator it = deviceId.begin() ; it != deviceId.end(); ++it)
00363         pc.printf("%2.2x",*it );
00364     pc.printf("\r\n");
00365 
00366     std::vector<uint8_t> netAddress;
00367 
00368     pc.printf("Network Address ");
00369     netAddress = dot->getNetworkAddress();
00370     for (std::vector<uint8_t>::iterator it = netAddress.begin() ; it != netAddress.end(); ++it)
00371         pc.printf("%2.2x",*it );
00372 
00373     pc.printf("\r\n");
00374 
00375     // Display LoRa parameters
00376     // Display label and values in different colours, show pretty values not numeric values where applicable
00377     pc.printf("Public Network: %s\r\n", (char*)(dot->getPublicNetwork() ? "Yes" : "No") );
00378     pc.printf("Frequency: %s\r\n", (char*)mDot::FrequencyBandStr(dot->getFrequencyBand()).c_str() );
00379     pc.printf("Sub Band: %s\r\n", (char*)mDot::FrequencySubBandStr(dot->getFrequencySubBand()).c_str() );
00380     pc.printf("Join Mode: %s\r\n", (char*)mDot::JoinModeStr(dot->getJoinMode()).c_str() );
00381     pc.printf("Join Retries: %d\r\n", dot->getJoinRetries() );
00382     pc.printf("Join Byte Order: %s\r\n", (char*)(dot->getJoinByteOrder() == 0 ? "LSB" : "MSB") );
00383     pc.printf("Link Check Count: %d\r\n", dot->getLinkCheckCount() );
00384     pc.printf("Link Check Thold: %d\r\n", dot->getLinkCheckThreshold() );
00385     pc.printf("Tx Data Rate: %s\r\n", (char*)mDot::DataRateStr(dot->getTxDataRate()).c_str() );
00386     pc.printf("Tx Power: %d\r\n", dot->getTxPower() );
00387     pc.printf("TxWait: %s, ", (dot->getTxWait() ? "Y" : "N" ));
00388     pc.printf("CRC: %s, ", (dot->getCrc() ? "Y" : "N") );
00389     pc.printf("Ack: %s\r\n", (dot->getAck() ? "Y" : "N")  );
00390 
00391     logInfo("Joining Network");
00392     while ((ret = dot->joinNetwork()) != mDot::MDOT_OK) {
00393         logError("failed to join network [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
00394         wait_ms(dot->getNextTxMs() + 1);
00395     }
00396     logInfo("Joined Network");
00397     wait_ms(500);
00398     
00399     /* Setup Sensors */
00400  
00401     logInfo("Configure Soil Sensor (SHT)");
00402 /*    DigitalInOut sht_data(SHT_DATA_PIN);
00403     DigitalInOut sht_sck(SHT_SCK_PIN);
00404     sht_data.output();
00405     sht_sck.output();
00406     while (1) {
00407         sht_data.write(1);
00408         wait_ms(1);
00409         sht_data.write(0);
00410         wait_ms(1);
00411     }*/
00412  
00413     //logInfo("Configure Air Sensor (DHT)");
00414     // no config needed for DHT
00415     logInfo("Configure Water Sensor (DS)");
00416     wait_ms(500);
00417     DS18B20::ROM_Code_t ROM_Code;
00418     wait_ms(500);
00419     thermom.ReadROM(&ROM_Code);
00420     logInfo("Family code: 0x%X\n\r", ROM_Code.BYTES.familyCode);
00421     wait_ms(500);
00422     logInfo("Serial Number: ");
00423     for (unsigned i = 6; i != 0; --i) {
00424         logInfo("%02X%s", ROM_Code.BYTES.serialNo[i-1], (i != 1)?":":"\r\n");
00425     }
00426     logInfo("CRC: 0x%X\r\n", ROM_Code.BYTES.VTV);
00427 
00428     wait_ms(500);    
00429     logInfo("Configure Light Sensor (TSL)");
00430     tsl.enablePower();
00431 
00432     char dataBuf[50];
00433     uint16_t seq = 0;
00434     char * sf_str;
00435     while( 1 ) {
00436         
00437         /* cycle through spreading factors */
00438         uint8_t sf;
00439         seq = 0; /* force SF7 */
00440         switch (seq % 4) {
00441             case 0:
00442                 sf = mDot::SF_7;
00443                 sf_str = "SF7";
00444                 break;
00445             case 1:
00446                 sf = mDot::SF_8;
00447                 sf_str = "SF8";
00448                 break;
00449             case 2:
00450                 sf = mDot::SF_9;
00451                 sf_str = "SF9";
00452                 break;
00453             case 3:
00454                 sf = mDot::SF_10;
00455                 sf_str = "SF10";
00456                 break;
00457         }        
00458         // Set Spreading Factor, higher is lower data rate, smaller packets but longer range
00459         // Lower is higher data rate, larger packets and shorter range.
00460         logInfo("Set SF: %s",sf_str);
00461         if((ret = dot->setTxDataRate( sf )) != mDot::MDOT_OK) {
00462             logError("Failed to set SF %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00463         }
00464         
00465         /* set default data values */
00466         int temp = 0;
00467         int humid = -1;
00468         
00469         /* build packet */
00470         b.begin();
00471         uint8_t flag = 0;
00472         b.put(FormatSensor1);
00473         uint8_t * const pFlag = b.getp(); // save pointer to flag location
00474         b.put(0x00); // placeholder for flags
00475         
00476         // TODO: read battery voltage 
00477         b.putV(13.8);
00478         flag |= FlagVbat;
00479         
00480         // read from Bme280 sensor:
00481         float air_temp=0, air_humid=0;
00482         bool dht_success = dht.sample();    
00483         wait_ms(100);
00484         logInfo("Air Sensor Status: %s", dht_success?"OK":"ERROR");
00485         wait_ms(100);
00486         air_temp = (float)dht.getTemperature()/10.0;
00487         air_humid = (float)dht.getHumidity()/10.0;
00488         logInfo("Air Temp: %1.01fC  Air Humid: %1.01f%%", air_temp, air_humid);
00489         
00490         
00491         b.putT(air_temp); // air temp
00492         b.putP(1010.0); // air pressure
00493         b.putRH(air_humid); // air humidity
00494         flag |= FlagTPH;
00495         
00496         wait_ms(100);
00497         // read from light sensor
00498         float lux = tsl.getLux();
00499         logInfo("Ambient Light: %.4f", lux);
00500         wait_ms(100);
00501         b.putLux(lux*100); // ambient light
00502         flag |= FlagLux;
00503         
00504         // read water temperature
00505         wait_ms(100);
00506         logInfo("Running temperature conversion...");
00507         float water_temp = thermom.GetTemperature();
00508         logInfo("Water Temperature: %.4fC", water_temp);         
00509         wait_ms(100);
00510         b.putT(water_temp); // water temperature
00511         flag |= FlagWater;
00512         
00513         // read soil sensor
00514         wait_ms(100);
00515         logInfo("sht.ready = %s", sht.ready?"true":"false");
00516         sht.ready = true; // override error... 
00517         sht.reset();
00518         wait_ms(50);
00519         bool sht_success = sht.update();
00520         logInfo("Soil Sensor Status: %s", sht_success?"OK":"ERROR");
00521         float soil_temp = (float)sht.getTemperature();  
00522         float soil_humid = (float)(sht.humidity)/(float)35.0;
00523         logInfo("sht->humid = %d",sht.humidity);
00524         logInfo("Soil Temp: %1.01fC  Soil Humid: %1.01f%%", soil_temp, soil_humid);
00525         b.putT(soil_temp); // soil temperature
00526         b.putRH(soil_humid); // soil humidityupdate
00527         
00528         flag |= FlagSoilTH;
00529         
00530         // write flag byte
00531         *pFlag = flag;
00532         
00533         /* load vector */
00534         send_data.clear();
00535         uint8_t c;
00536         int n = b.getn();
00537         for( int i=0; i< n; i++ ) {
00538             c = b.buf[i];
00539             send_data.push_back( c );
00540         }
00541 
00542         wait_ms(100);
00543         /* send packet */
00544         if ((ret = dot->send(send_data)) != mDot::MDOT_OK) {
00545             logError("failed to send: [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
00546         } else {
00547             logInfo("data len: %d,  send data: %s", n, Text::bin2hexString(send_data).c_str());
00548         }
00549 
00550         /* sleep */
00551         uint32_t sleep_time = MAX((dot->getNextTxMs() / 1000), 10 /* use 6000 for 10min */);
00552         logInfo("going to sleep for %d seconds", sleep_time);
00553         
00554         status_led.write(1);
00555         wait_ms(1*1000);
00556         status_led.write(0);
00557         wait_ms(4*1000);
00558         
00559         seq++;
00560     }
00561 
00562     return 0;
00563 }