Demo of DHT11->mDot->TTN

Dependencies:   DHT11 libmDot mbed-rtos mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /** mDot_TTN_DHT11 -- The Things Network Temperature & Humidity Sensor
00002  * 
00003  *  This is a rough demo of mDot+DHT11 on The Things Network.
00004  *  This code is not indended as a reference design.
00005  *  In particular, it lacks:
00006  *   (1) power management
00007  *   (2) reasonable transmission period 
00008  *   (3) adaptive data rate
00009  * 
00010  * Uses MultiTech mDot developer board http://www.multitech.com/models/94558010LF
00011  * Requires a MultiTech MultiConnect Conduit http://www.multitech.com/models/94557203LF
00012  * http://www.multitech.net/developer/software/lora/conduit-mlinux-convert-to-basic-packet-forwarder/
00013  * http://forum.thethingsnetwork.org/t/setting-up-multitech-conduit-gateway-for-ttn/216/35
00014  *
00015  * To receive and visualize this data,
00016  *  consider using InitialState and the bridge code here:
00017  * https://github.com/things-nyc/initial-state-example
00018  */
00019 
00020 #include "mbed.h"
00021 #include "DHT11.h"
00022 #include "mDot.h"
00023 #include "MTSLog.h"
00024 #include "MTSText.h"
00025 #include <string>
00026 #include <vector>
00027 
00028 using namespace mts;
00029 
00030 #define MIN(a,b) (((a)<(b))?(a):(b))
00031 #define MAX(a,b) (((a)>(b))?(a):(b))
00032 
00033 
00034 /** ABP
00035  * Register your device and update these values:
00036  * https://account.thethingsnetwork.org/
00037  */
00038 uint8_t AppSKey[16]= { 0x11, 0x6F, 0xA9, 0x2A, 0x46, 0xDE, 0xE6, 0x1D, 0x11, 0xE3, 0x71, 0x37, 0x24, 0xBC, 0x44, 0x1A };
00039 uint8_t NwkSKey[16]= { 0xF1, 0xA4, 0x78, 0x09, 0x75, 0xE2, 0x3C, 0x2B, 0x76, 0x8F, 0x9F, 0x8D, 0xE0, 0x5E, 0xAA, 0x64 };
00040 uint8_t NetworkAddr[4]= { 0x68, 0x8E, 0x64, 0xE5 };
00041 
00042 
00043 // Some defines for the LoRa configuration
00044 #define LORA_SF mDot::SF_7
00045 #define LORA_ACK 0
00046 #define LORA_TXPOWER 20
00047 static uint8_t config_frequency_sub_band = 2;
00048 
00049 // functions for ensuring network endianness (little-endian)
00050 uint16_t hton16(const uint16_t x)
00051 {
00052   uint16_t t = x;
00053   uint8_t * a = (uint8_t*)&t;
00054   a[0] = x>>(8*1);
00055   a[1] = x>>(8*0);
00056   return t;
00057 }
00058 void hton16(uint16_t * x)
00059 {
00060   *x = hton16(*x);
00061 }
00062 
00063 
00064 
00065 // build a transmit buffer (from https://raw.githubusercontent.com/mcci-catena/Catena4410-Sketches/master/catena4410_sensor1/catena4410_sensor1.ino)
00066 class TxBuffer_t
00067         {
00068 public:
00069         uint8_t buf[32];   // this sets the largest buffer size
00070         uint8_t *p;
00071 
00072         TxBuffer_t() : p(buf) {};
00073         void begin()
00074                 {
00075                 p = buf;
00076                 }
00077         void put(uint8_t c)
00078                 {
00079                 if (p < buf + sizeof(buf))
00080                         *p++ = c;
00081                 }
00082         void put1u(int32_t v)
00083                 {
00084                 if (v > 0xFF)
00085                         v = 0xFF;
00086                 else if (v < 0)
00087                         v = 0;
00088                 put((uint8_t) v);
00089                 }
00090         void put2(uint32_t v)
00091                 {
00092                 if (v > 0xFFFF)
00093                         v = 0xFFFF;
00094 
00095                 put((uint8_t) (v >> 8));
00096                 put((uint8_t) v);
00097                 }
00098         void put2(int32_t v)
00099                 {
00100                 if (v < -0x8000)
00101                         v = -0x8000;
00102                 else if (v > 0x7FFF)
00103                         v = 0x7FFF;
00104 
00105                 put2((uint32_t) v);
00106                 }
00107         void put3(uint32_t v)
00108                 {
00109                 if (v > 0xFFFFFF)
00110                         v = 0xFFFFFF;
00111 
00112                 put((uint8_t) (v >> 16));
00113                 put((uint8_t) (v >> 8));
00114                 put((uint8_t) v);
00115                 }
00116         void put2u(int32_t v)
00117                 {
00118                 if (v < 0)
00119                         v = 0;
00120                 else if (v > 0xFFFF)
00121                         v = 0xFFFF;
00122                 put2((uint32_t) v);
00123                 }
00124         void put3(int32_t v)
00125                 {
00126                 if (v < -0x800000)
00127                         v = -0x800000;
00128                 else if (v > 0x7FFFFF)
00129                         v = 0x7FFFFF;
00130                 put3((uint32_t) v);
00131                 }
00132         uint8_t *getp(void)
00133                 {
00134                 return p;
00135                 }
00136         size_t getn(void)
00137                 {
00138                 return p - buf;
00139                 }
00140         uint8_t *getbase(void)
00141                 {
00142                 return buf;
00143                 }
00144         void put2sf(float v)
00145                 {
00146                 int32_t iv;
00147 
00148                 if (v > 32766.5f)
00149                         iv = 0x7fff;
00150                 else if (v < -32767.5f)
00151                         iv = -0x8000;
00152                 else
00153                         iv = (int32_t)(v + 0.5f);
00154 
00155                 put2(iv);
00156                 }
00157         void put2uf(float v)
00158                 {
00159                 uint32_t iv;
00160 
00161                 if (v > 65535.5f)
00162                         iv = 0xffff;
00163                 else if (v < 0.5f)
00164                         iv = 0;
00165                 else
00166                         iv = (uint32_t)(v + 0.5f);
00167 
00168                 put2(iv);
00169                 }
00170         void put1uf(float v)
00171                 {
00172                 uint8_t c;
00173 
00174                 if (v > 254.5)
00175                         c = 0xFF;
00176                 else if (v < 0.5)
00177                         c = 0;
00178                 else
00179                         c = (uint8_t) v;
00180 
00181                 put(c);
00182                 }
00183         void putT(float T)
00184                 {
00185                 put2sf(T * 256.0f + 0.5f);                
00186                 }
00187         void putRH(float RH)
00188                 {
00189                 put1uf((RH / 0.390625f) + 0.5f);
00190                 }
00191         void putV(float V)
00192                 {
00193                 put2sf(V * 4096.0f + 0.5f);
00194                 }
00195         void putP(float P)
00196                 {
00197                 put2uf(P / 4.0f + 0.5f);
00198                 }
00199         void putLux(float Lux)
00200                 {
00201                 put2uf(Lux);
00202                 }
00203         };
00204 
00205 /* the magic byte at the front of the buffer */
00206 enum    {
00207         FormatSensor1 = 0x11,
00208         };
00209 
00210 /* the flags for the second byte of the buffer */
00211 enum    {
00212         FlagVbat = 1 << 0,
00213         FlagVcc = 1 << 1,
00214         FlagTPH = 1 << 2,
00215         FlagLux = 1 << 3,
00216         FlagWater = 1 << 4,
00217         FlagSoilTH = 1 << 5,
00218         };
00219 
00220 
00221 // Temperature sensor object
00222 #define DHT_PIN PB_1
00223 DHT11 dht(DHT_PIN);
00224 
00225 // Serial via USB for debugging only
00226 Serial pc(USBTX,USBRX);
00227 
00228 int main()
00229 {
00230     TxBuffer_t b;
00231     
00232     int32_t ret;
00233     mDot* dot;
00234     std::vector<uint8_t> send_data;
00235     std::vector<uint8_t> recv_data;
00236     std::vector<uint8_t> nwkSKey;
00237     std::vector<uint8_t> appSKey;
00238     std::vector<uint8_t> nodeAddr;
00239     std::vector<uint8_t> networkAddr;
00240 
00241     float temperature = 0.0;
00242 
00243     pc.baud(115200);
00244     pc.printf("TTN mDot LoRa Temperature  & Humidity Sensor\n\r");
00245 
00246     // get a mDot handle
00247     dot = mDot::getInstance();
00248 
00249 //  dot->setLogLevel(MTSLog::WARNING_LEVEL);
00250     dot->setLogLevel(MTSLog::TRACE_LEVEL);
00251 
00252     logInfo("Checking Config");
00253 
00254     // Test if we've already saved the config
00255     std::string configNetworkName = dot->getNetworkName();
00256 
00257     uint8_t *it = NwkSKey;
00258     for (uint8_t i = 0; i<16; i++)
00259         nwkSKey.push_back((uint8_t) *it++);
00260         
00261     it = AppSKey;
00262     for (uint8_t i = 0; i<16; i++)
00263         appSKey.push_back((uint8_t) *it++);
00264 
00265     it = NetworkAddr;
00266     for (uint8_t i = 0; i<4; i++)
00267         networkAddr.push_back((uint8_t) *it++);
00268 
00269     logInfo("Resetting Config");
00270     // reset to default config so we know what state we're in
00271     dot->resetConfig();
00272 
00273     // Set byte order - AEP less than 1.0.30
00274 //    dot->setJoinByteOrder(mDot::LSB);
00275     dot->setJoinByteOrder(mDot::MSB);       // This is default for > 1.0.30 Conduit
00276 
00277 
00278 
00279     logInfo("Set TxPower");
00280     if((ret = dot->setTxPower( LORA_TXPOWER )) != mDot::MDOT_OK) {
00281         logError("Failed to set Tx Power %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00282     }
00283 
00284     logInfo("Set Public mode");
00285     if((ret = dot->setPublicNetwork(true)) != mDot::MDOT_OK) {
00286         logError("failed to set Public Mode %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00287     }
00288 
00289     logInfo("Set MANUAL Join mode");
00290     if((ret = dot->setJoinMode(mDot::MANUAL)) != mDot::MDOT_OK) {
00291         logError("Failed to set MANUAL Join Mode %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00292     }
00293 
00294     logInfo("Set Ack");
00295     // 1 retries on Ack, 0 to disable
00296     if((ret = dot->setAck( LORA_ACK)) != mDot::MDOT_OK) {
00297         logError("Failed to set Ack %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00298     }
00299 
00300     //Not applicable for 868MHz in EU
00301     if ((ret = dot->setFrequencySubBand(config_frequency_sub_band)) != mDot::MDOT_OK) {
00302         logError("failed to set frequency sub band", ret);
00303     }
00304 
00305     logInfo("Set Network Address");
00306     if ((ret = dot->setNetworkAddress(networkAddr)) != mDot::MDOT_OK) {
00307         logError("Failed to set Network Address %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00308     }
00309 
00310     logInfo("Set Data Session Key");
00311     if ((ret = dot->setDataSessionKey(appSKey)) != mDot::MDOT_OK) {
00312         logError("Failed to set Data Session Key %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00313     }
00314 
00315     logInfo("Set Network Session Key");
00316     if ((ret = dot->setNetworkSessionKey(nwkSKey)) != mDot::MDOT_OK) {
00317         logError("Failed to set Network Session Key %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00318     }
00319 
00320     logInfo("Saving Config");
00321     // Save config
00322     if (! dot->saveConfig()) {
00323         logError("failed to save configuration");
00324     }
00325 
00326     // Display what is set
00327     std::vector<uint8_t> tmp = dot->getNetworkSessionKey();
00328     pc.printf("Network Session Key: ");
00329     pc.printf("%s\r\n", mts::Text::bin2hexString(tmp, " ").c_str());
00330 
00331     tmp = dot->getDataSessionKey();
00332     pc.printf("Data Session Key: ");
00333     pc.printf("%s\r\n", mts::Text::bin2hexString(tmp, " ").c_str());
00334 
00335     pc.printf("Device ID ");
00336     std::vector<uint8_t> deviceId;
00337     deviceId = dot->getDeviceId();
00338     for (std::vector<uint8_t>::iterator it = deviceId.begin() ; it != deviceId.end(); ++it)
00339         pc.printf("%2.2x",*it );
00340     pc.printf("\r\n");
00341 
00342     std::vector<uint8_t> netAddress;
00343 
00344     pc.printf("Network Address ");
00345     netAddress = dot->getNetworkAddress();
00346     for (std::vector<uint8_t>::iterator it = netAddress.begin() ; it != netAddress.end(); ++it)
00347         pc.printf("%2.2x",*it );
00348 
00349     pc.printf("\r\n");
00350 
00351     // Display LoRa parameters
00352     // Display label and values in different colours, show pretty values not numeric values where applicable
00353     pc.printf("Public Network: %s\r\n", (char*)(dot->getPublicNetwork() ? "Yes" : "No") );
00354     pc.printf("Frequency: %s\r\n", (char*)mDot::FrequencyBandStr(dot->getFrequencyBand()).c_str() );
00355     pc.printf("Sub Band: %s\r\n", (char*)mDot::FrequencySubBandStr(dot->getFrequencySubBand()).c_str() );
00356     pc.printf("Join Mode: %s\r\n", (char*)mDot::JoinModeStr(dot->getJoinMode()).c_str() );
00357     pc.printf("Join Retries: %d\r\n", dot->getJoinRetries() );
00358     pc.printf("Join Byte Order: %s\r\n", (char*)(dot->getJoinByteOrder() == 0 ? "LSB" : "MSB") );
00359     pc.printf("Link Check Count: %d\r\n", dot->getLinkCheckCount() );
00360     pc.printf("Link Check Thold: %d\r\n", dot->getLinkCheckThreshold() );
00361     pc.printf("Tx Data Rate: %s\r\n", (char*)mDot::DataRateStr(dot->getTxDataRate()).c_str() );
00362     pc.printf("Tx Power: %d\r\n", dot->getTxPower() );
00363     pc.printf("TxWait: %s, ", (dot->getTxWait() ? "Y" : "N" ));
00364     pc.printf("CRC: %s, ", (dot->getCrc() ? "Y" : "N") );
00365     pc.printf("Ack: %s\r\n", (dot->getAck() ? "Y" : "N")  );
00366 
00367     logInfo("Joining Network");
00368 
00369     while ((ret = dot->joinNetwork()) != mDot::MDOT_OK) {
00370         logError("failed to join network [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
00371         wait_ms(dot->getNextTxMs() + 1);
00372     }
00373 
00374     logInfo("Joined Network");
00375 
00376     char dataBuf[50];
00377     uint16_t seq = 0;
00378     char * sf_str;
00379     while( 1 ) {
00380         
00381         /* cycle through spreading factors */
00382         uint8_t sf;
00383         switch (seq % 4) {
00384             case 0:
00385                 sf = mDot::SF_7;
00386                 sf_str = "SF7";
00387                 break;
00388             case 1:
00389                 sf = mDot::SF_8;
00390                 sf_str = "SF8";
00391                 break;
00392             case 2:
00393                 sf = mDot::SF_9;
00394                 sf_str = "SF9";
00395                 break;
00396             case 3:
00397                 sf = mDot::SF_10;
00398                 sf_str = "SF10";
00399                 break;
00400         }        
00401         // Set Spreading Factor, higher is lower data rate, smaller packets but longer range
00402         // Lower is higher data rate, larger packets and shorter range.
00403         logInfo("Set SF: %s",sf_str);
00404         if((ret = dot->setTxDataRate( sf )) != mDot::MDOT_OK) {
00405             logError("Failed to set SF %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
00406         }
00407         
00408         /* set default data values */
00409         int temp = 0;
00410         int humid = -1;
00411         
00412         /* read from sensor */
00413         int r = dht.readData();
00414         switch (r) {
00415             case DHT11::OK:
00416             {
00417                 temp = dht.readTemperature();
00418                 humid = dht.readHumidity();
00419                 pc.printf("[DHT] T %d degC   H %d %%\r\n",temp,humid);
00420                 break;
00421             }
00422             default:
00423             {
00424                 pc.printf("[DHT] ERROR %d\r\n",r);
00425                 break;
00426             }
00427         };
00428         
00429         /* build packet */
00430         b.begin();
00431         uint8_t flag = 0;
00432         b.put(FormatSensor1);
00433         uint8_t * const pFlag = b.getp(); // save pointer to flag location
00434         b.put(0x00); // placeholder for flags
00435         
00436         // TODO: read battery voltage 
00437         b.putV(13.8);
00438         flag |= FlagVbat;
00439         
00440         // TODO: read from Bme280 sensor:
00441         b.putT(27.0); // air temp
00442         b.putP(1010.0); // air pressure
00443         b.putRH(66.0); // air humidity
00444         flag |= FlagTPH;
00445         
00446         // TODO: read from light sensor
00447         b.putLux(1234); // ambient light
00448         flag |= FlagLux;
00449         
00450         // TODO: read water temperature
00451         b.putT(22.0); // water temperature
00452         flag |= FlagWater;
00453         
00454         // TODO: read soil sensor
00455         b.putT(25.2); // soil temperature
00456         b.putRH(82.0); // soil humidity
00457         flag |= FlagSoilTH;
00458         
00459         // write flag byte
00460         *pFlag = flag;
00461         
00462         /* load vector */
00463         send_data.clear();
00464         uint8_t c;
00465         int n = b.getn();
00466         for( int i=0; i< n; i++ ) {
00467             c = b.buf[i];
00468             send_data.push_back( c );
00469         }
00470 
00471         /* send packet */
00472         if ((ret = dot->send(send_data)) != mDot::MDOT_OK) {
00473             logError("failed to send: [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
00474         } else {
00475             logInfo("data len: %d,  send data: %s", n, Text::bin2hexString(send_data).c_str());
00476         }
00477 
00478         /* sleep */
00479         uint32_t sleep_time = MAX((dot->getNextTxMs() / 1000), 10 /* use 6000 for 10min */);
00480         logInfo("going to sleep for %d seconds", sleep_time);
00481         wait_ms(10*1000);
00482         
00483         seq++;
00484     }
00485 
00486     return 0;
00487 }