Demonstration TTN OTAA node
Dependencies: BME280 DS1820 libmDot mbed-rtos mbed
This is an example application for the MultiTech mDot and connects to The Things Network using Over The Air Activation (OTAA). It sends data from a Dallas Semiconductors DS18B20 OneWire temperature sensor.
Register a device and generate a random AppKey for the currently used application Id: (You need to use your own device IDs, the ones shown here are examples only)
./ttnctl devices register 0080000000000000 INFO Generating random AppKey... INFO Registered device AppKey=000102030405060708090A0B0C0D0E0F DevEUI=0080000000000000
or to specify the same AppKey for a new device or to reregister the same device again:
./ttnctl devices register 0080000000000000 000102030405060708090A0B0C0D0E0F
./ttnctl devices info 0080000000000000 Dynamic device:
AppEUI: 70B3D50000000000 {0x70, 0xB3, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00}
DevEUI: 0080000000000000 {0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
AppKey: 000102030405060708090A0B0C0D0E0F {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}
Copy the AppEUI and AppKey values provided in hex array notation above to the AppEUI and AppKey parameters below.
Diff: main.cpp
- Revision:
- 13:5369ba22389a
- Parent:
- 12:e82913ee9c61
- Child:
- 15:8a0ebf59b8bb
--- a/main.cpp Sat Nov 14 20:58:36 2015 +0000 +++ b/main.cpp Wed May 11 06:18:15 2016 +0000 @@ -1,5 +1,5 @@ -/** mDot_TTN_DS18B20 - Simple mDot temperature sensor using Dallas Semiconductors DS18B20 OneWire temperature sensor. - * It used the MANUAL join mode with parameters for The Things Network. +/** mDot_TTN_Node - Simple mDot temperature sensor using Dallas Semiconductors DS18B20 OneWire temperature sensor. + * It used the AUTO_OTA join mode with parameters for The Things Network. * * * Uses MultiTech mDot developer board http://www.multitech.com/models/94558010LF @@ -7,10 +7,36 @@ * 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 * + * Register a device and generate a random AppKey for the currently used application Id: + * + *./ttnctl devices register 0080000000009FC4 + * INFO Generating random AppKey... + * INFO Registered device AppKey=EC22CBC24733E3397B83C4C9DEA685A8 DevEUI=0080000000009FC4 + * + * or to specify the same AppKey for a new device or to reregister the same device again: + * + * ./ttnctl devices register 0080000000009FC4 EC22CBC24733E3397B83C4C9DEA685A8 + * + * ./ttnctl devices info 0080000000009FC4 + * Dynamic device: + * + * AppEUI: 70B3D57ED00000F6 + * {0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x00, 0x00, 0xF6} + * + * DevEUI: 0080000000009FC4 + * {0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xC4} + * + * AppKey: EC22CBC24733E3397B83C4C9DEA685A8 + * {0xEC, 0x22, 0xCB, 0xC2, 0x47, 0x33, 0xE3, 0x39, 0x7B, 0x83, 0xC4, 0xC9, 0xDE, 0xA6, 0x85, 0xA8} + * + * + * Copy the AppEUI and AppKey values provided in hex array notation above to the AppEUI and AppKey parameters below. + * */ #include "mbed.h" #include "DS1820.h" +//#include "BME280.h" #include "mDot.h" #include "MTSLog.h" #include "MTSText.h" @@ -22,34 +48,50 @@ #define MIN(a,b) (((a)<(b))?(a):(b)) #define MAX(a,b) (((a)>(b))?(a):(b)) -// Values as used by The Things Network -//const uint8_t AppKey[16]={0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C}; -// Application session key -uint8_t AppSKey[16]= {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C}; -// Network session key -uint8_t NwkSKey[16]= {0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C}; - -// Network Address - Get your own address range at http://thethingsnetwork.org/wiki/AddressSpace -uint8_t NetworkAddr[4]= {0x02,0x01,0x00,0x00}; // Our Network address or Node ID - +// AppEUI +uint8_t AppEUI[8]={0x70, 0xB3, 0xD5, 0x7E, 0xD0, 0x00, 0x00, 0xF6}; +// AppKey +uint8_t AppKey[16]={0xEC, 0x22, 0xCB, 0xC2, 0x47, 0x33, 0xE3, 0x39, 0x7B, 0x83, 0xC4, 0xC9, 0xDE, 0xA6, 0x85, 0xA8}; // Some defines for the LoRa configuration -#define LORA_SF mDot::SF_12 +/* + * EU868 Datarates + * --------------- + * DR0 - SF12BW125 + * DR1 - SF11BW125 + * DR2 - SF10BW125 + * DR3 - SF9BW125 + * DR4 - SF8BW125 + * DR5 - SF7BW125 + * DR6 - SF7BW250 + * + * US915 Datarates + * --------------- + * DR0 - SF10BW125 + * DR1 - SF9BW125 + * DR2 - SF8BW125 + * DR3 - SF7BW125 + * DR4 - SF8BW500 + */ +#define LORA_SF mDot::DR5 #define LORA_ACK 0 #define LORA_TXPOWER 14 // Ignoring sub band for EU modules. -//static uint8_t config_frequency_sub_band = 1; +static uint8_t config_frequency_sub_band = 1; // DS18B20 OneWire pin // D13 on Dev Board, pin 18 on mDot, Compatible with Oxford Flood Network PCB temperature sensor. -#define DATA_PIN PA_5 -// A0 on Dev Board, pin 20 on mDot -//#define DATA_PIN PB_1 +//#define DATA_PIN PA_5 +// A1 on Dev Board, pin 19 on mDot +#define DATA_PIN PC_13 // Temperature sensor object DS1820 probe(DATA_PIN); +// BME280 Temperature/Humidity/Pressure sensor +//BME280 sensor(I2C_SDA, I2C_SCL); + // Serial via USB for debugging only Serial pc(USBTX,USBRX); @@ -59,42 +101,36 @@ mDot* dot; std::vector<uint8_t> send_data; std::vector<uint8_t> recv_data; - std::vector<uint8_t> nwkSKey; - std::vector<uint8_t> nodeAddr; - std::vector<uint8_t> networkAddr; + std::vector<uint8_t> nwkId; + std::vector<uint8_t> nwkKey; float temperature = 0.0; + float humidity = 0.0; + float pressure = 0.0; pc.baud(115200); - pc.printf("TTN mDot LoRa Temperature sensor\n\r"); + pc.printf("TTN OTAA mDot LoRa Temperature sensor\n\r"); // get a mDot handle dot = mDot::getInstance(); - dot->setLogLevel(MTSLog::WARNING_LEVEL); -// dot->setLogLevel(MTSLog::TRACE_LEVEL); +// 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; + uint8_t *it = AppEUI; + for (uint8_t i = 0; i<8; i++) + nwkId.push_back((uint8_t) *it++); + + it = AppKey; for (uint8_t i = 0; i<16; i++) - nwkSKey.push_back((uint8_t) *it++); - - it = NetworkAddr; - for (uint8_t i = 0; i<4; i++) - networkAddr.push_back((uint8_t) *it++); + nwkKey.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 - // 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"); @@ -112,9 +148,9 @@ 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 AUTO_OTA Join mode"); + if((ret = dot->setJoinMode(mDot::AUTO_OTA)) != mDot::MDOT_OK) { + logError("Failed to set AUTO_OTA Join Mode %d:%s", ret, mDot::getReturnCodeString(ret).c_str()); } logInfo("Set Ack"); @@ -123,25 +159,18 @@ 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) { -// initStatus = false; -// logError(dot, "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()); + // Library ignores the frequency sub band for 868MHz in EU + if ((ret = dot->setFrequencySubBand(config_frequency_sub_band)) != mDot::MDOT_OK) { + logError("Failed to set frequency sub band %d:%s", ret, mDot::getReturnCodeString(ret).c_str()); } - logInfo("Set Data Session Key"); - if ((ret = dot->setDataSessionKey(nwkSKey)) != mDot::MDOT_OK) { - logError("Failed to set Data Session Key %d:%s", ret, mDot::getReturnCodeString(ret).c_str()); + logInfo("Set Network Id"); + if ((ret = dot->setNetworkId(nwkId)) != mDot::MDOT_OK) { + logError("Failed to set Network Id %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("Set Network Key"); + if ((ret = dot->setNetworkKey(nwkKey)) != mDot::MDOT_OK) { + logError("Failed to set Network Id %d:%s", ret, mDot::getReturnCodeString(ret).c_str()); } logInfo("Saving Config"); @@ -150,33 +179,36 @@ 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 "); + 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; + for (std::vector<uint8_t>::iterator it = deviceId.begin() ; it != deviceId.end(); ++it) { + pc.printf("0x%2.2X",*it ); + pc.printf("%s", it != (deviceId.end() -1 ) ? ", " : " " ); + } + pc.printf("}\r\n"); - 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 ); + std::vector<uint8_t> netId; + pc.printf("Network Id/App EUI {"); + netId = dot->getNetworkId(); + for (std::vector<uint8_t>::iterator it = netId.begin() ; it != netId.end(); ++it) { + pc.printf("0x%2.2X", *it ); + pc.printf("%s", it != (netId.end() -1 ) ? ", " : " " ); + } + pc.printf("}\r\n"); - pc.printf("\r\n"); + std::vector<uint8_t> netKey; + pc.printf("Network Key/App Key {"); + netKey = dot->getNetworkKey(); + for (std::vector<uint8_t>::iterator it = netKey.begin() ; it != netKey.end(); ++it) { + pc.printf("0x%2.2X", *it ); + pc.printf("%s", it != (netKey.end() -1 ) ? ", " : " " ); + } + 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() ); @@ -190,7 +222,7 @@ 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) { @@ -200,34 +232,50 @@ logInfo("Joined Network"); + // Display Network session key and data session key from Join command +/* + 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()); +*/ // Set the Temperature sesnor resolution, 9 bits is enough and makes it faster to provide a reading. probe.setResolution(9); char dataBuf[50]; while( 1 ) { - //Start temperature conversion, wait until ready + // Output data as JSON e.g. {"t":21.3} +// temperature = sensor.getTemperature(); +// humidity = sensor.getHumidity(); +// pressure = sensor.getPressure(); + + //Start temperature conversion, wait until ready probe.convertTemperature(true, DS1820::all_devices); - // Output data as JSON e.g. {"t":21.3} + // Output data as JSON e.g. {"t":21.3} temperature = probe.temperature(); sprintf(dataBuf, "{\"t\":%3.1f}", temperature ); - send_data.clear(); - // probably not the most efficent way to do this - for( int i=0; i< strlen(dataBuf); i++ ) - send_data.push_back( dataBuf[i] ); +// sprintf(dataBuf, "%3.1f,%3.1f,%04.2f", temperature,humidity,pressure ); + pc.printf("%s\n",dataBuf); + send_data.clear(); + // probably not the most efficent way to do this + for( int i=0; i< strlen(dataBuf); i++ ) + send_data.push_back( dataBuf[i] ); - 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()); - } + 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()); + } - // Should sleep here and wakeup after a set 10 minute interval. - uint32_t sleep_time = MAX((dot->getNextTxMs() / 1000), 600); - logInfo("going to sleep for %d seconds", sleep_time); - - // go to sleep and wake up automatically sleep_time seconds later - dot->sleep(sleep_time, mDot::RTC_ALARM); + // Should sleep here and wakeup after a set 5 minute interval. + // in the 868 (EU) frequency band, we need to wait until another channel is available before transmitting again + uint32_t sleep_time = std::max((uint32_t)300000, (uint32_t)dot->getNextTxMs()) / 1000; +//wait_ms(2000); + // go to sleep and wake up automatically sleep_time seconds later + dot->sleep(sleep_time, mDot::RTC_ALARM); } - return 0; }