Demo of DHT11->mDot->TTN
Dependencies: DHT11 libmDot mbed-rtos mbed
main.cpp
- Committer:
- merckeng
- Date:
- 2016-08-17
- Revision:
- 16:01a1058d9c8e
- Parent:
- 15:c61c5f1533e8
- Child:
- 17:3dc30f4a8da2
File content as of revision 16:01a1058d9c8e:
/** mDot_TTN_DHT11 -- The Things Network Temperature & Humidity Sensor * * This is a rough demo of mDot+DHT11 on The Things Network. * This code is not indended as a reference design. * In particular, it lacks: * (1) power management * (2) reasonable transmission period * (3) adaptive data rate * * 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; }