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.

Committer:
SomeRandomBloke
Date:
Sun Aug 23 21:28:18 2015 +0000
Revision:
0:5a0b43f3b143
Child:
1:45cec6aea002
First commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
SomeRandomBloke 0:5a0b43f3b143 1 /** mDot_display - Uses 160x128 SPI LCD display to show results of message
SomeRandomBloke 0:5a0b43f3b143 2 * sending and receiving.
SomeRandomBloke 0:5a0b43f3b143 3 * Uses MultiTech mDot developer board http://www.multitech.com/models/94558010LF
SomeRandomBloke 0:5a0b43f3b143 4 * Requires a MultiTech MultiConnect Conduit http://www.multitech.com/models/94557203LF
SomeRandomBloke 0:5a0b43f3b143 5 *
SomeRandomBloke 0:5a0b43f3b143 6 * Example JSON received on Conduit:
SomeRandomBloke 0:5a0b43f3b143 7 { "chan": 5, "codr": "4/5", "datr": "SF9BW125", "freq": "869.5",
SomeRandomBloke 0:5a0b43f3b143 8 "lsnr": "8.8", "modu": "LORA", "rfch": 1, "rssi": -41, "seqn": 13,
SomeRandomBloke 0:5a0b43f3b143 9 "size": 12, "timestamp": "2015-07-22T21:19:11Z", "tmst": 517590990,
SomeRandomBloke 0:5a0b43f3b143 10 "payload": "{\"temperature\":21.3}", "eui": "00:80:00:00:00:00:9a:63", "_msg
SomeRandomBloke 0:5a0b43f3b143 11 id": "73bcd8dd.8c4328" }
SomeRandomBloke 0:5a0b43f3b143 12 *
SomeRandomBloke 0:5a0b43f3b143 13 */
SomeRandomBloke 0:5a0b43f3b143 14
SomeRandomBloke 0:5a0b43f3b143 15 #include "mbed.h"
SomeRandomBloke 0:5a0b43f3b143 16 #include "DS1820.h"
SomeRandomBloke 0:5a0b43f3b143 17 #include "mDot.h"
SomeRandomBloke 0:5a0b43f3b143 18 #include "MTSLog.h"
SomeRandomBloke 0:5a0b43f3b143 19 #include "MTSText.h"
SomeRandomBloke 0:5a0b43f3b143 20 #include <string>
SomeRandomBloke 0:5a0b43f3b143 21 #include <vector>
SomeRandomBloke 0:5a0b43f3b143 22
SomeRandomBloke 0:5a0b43f3b143 23 using namespace mts;
SomeRandomBloke 0:5a0b43f3b143 24
SomeRandomBloke 0:5a0b43f3b143 25 // these options must match the settings on your Conduit in
SomeRandomBloke 0:5a0b43f3b143 26 // /var/config/lora/lora-network-server.conf
SomeRandomBloke 0:5a0b43f3b143 27 static std::string config_network_name = "ThingInnovations";
SomeRandomBloke 0:5a0b43f3b143 28 static std::string config_network_pass = "donkey123";
SomeRandomBloke 0:5a0b43f3b143 29 static uint8_t config_frequency_sub_band = 1;
SomeRandomBloke 0:5a0b43f3b143 30
SomeRandomBloke 0:5a0b43f3b143 31 // mDot/dev board activity LED
SomeRandomBloke 0:5a0b43f3b143 32 #define ACTIVITY_LED PA_0
SomeRandomBloke 0:5a0b43f3b143 33 #define DATA_PIN PC_13
SomeRandomBloke 0:5a0b43f3b143 34
SomeRandomBloke 0:5a0b43f3b143 35 // must use the hardware SPI pins
SomeRandomBloke 0:5a0b43f3b143 36 //SPI device(SPI_MOSI, SPI_MISO, SPI_SCK);
SomeRandomBloke 0:5a0b43f3b143 37
SomeRandomBloke 0:5a0b43f3b143 38 // SPI device defines
SomeRandomBloke 0:5a0b43f3b143 39 #define MDOT_MOSI PA_7
SomeRandomBloke 0:5a0b43f3b143 40 #define MDOT_MISO PA_6
SomeRandomBloke 0:5a0b43f3b143 41 #define MDOT_SCK PA_5
SomeRandomBloke 0:5a0b43f3b143 42 #define MDOT_TFT_CS PA_4
SomeRandomBloke 0:5a0b43f3b143 43
SomeRandomBloke 0:5a0b43f3b143 44 DS1820 probe(DATA_PIN);
SomeRandomBloke 0:5a0b43f3b143 45
SomeRandomBloke 0:5a0b43f3b143 46 //void log_error(mDot* dot, const char* msg, int32_t retval);
SomeRandomBloke 0:5a0b43f3b143 47
SomeRandomBloke 0:5a0b43f3b143 48 Serial pc(USBTX,USBRX);
SomeRandomBloke 0:5a0b43f3b143 49
SomeRandomBloke 0:5a0b43f3b143 50
SomeRandomBloke 0:5a0b43f3b143 51 int main()
SomeRandomBloke 0:5a0b43f3b143 52 {
SomeRandomBloke 0:5a0b43f3b143 53 int32_t ret;
SomeRandomBloke 0:5a0b43f3b143 54 mDot* dot;
SomeRandomBloke 0:5a0b43f3b143 55 std::vector<uint8_t> send_data;
SomeRandomBloke 0:5a0b43f3b143 56 std::vector<uint8_t> recv_data;
SomeRandomBloke 0:5a0b43f3b143 57
SomeRandomBloke 0:5a0b43f3b143 58 int32_t next_tx;
SomeRandomBloke 0:5a0b43f3b143 59 int32_t wait_time = 2;
SomeRandomBloke 0:5a0b43f3b143 60 // uint8_t iterations = 99;
SomeRandomBloke 0:5a0b43f3b143 61 uint16_t txCount = 0;
SomeRandomBloke 0:5a0b43f3b143 62 uint16_t txFailCount = 0;
SomeRandomBloke 0:5a0b43f3b143 63 uint16_t rxCount = 0;
SomeRandomBloke 0:5a0b43f3b143 64 uint16_t rxOkCount = 0;
SomeRandomBloke 0:5a0b43f3b143 65 uint16_t noRxCount = 0;
SomeRandomBloke 0:5a0b43f3b143 66 uint16_t rxFailCount = 0;
SomeRandomBloke 0:5a0b43f3b143 67 bool initStatus = true; // All intialised OK until told otherwise
SomeRandomBloke 0:5a0b43f3b143 68 float temperature = 0.0;
SomeRandomBloke 0:5a0b43f3b143 69
SomeRandomBloke 0:5a0b43f3b143 70 pc.baud(115200);
SomeRandomBloke 0:5a0b43f3b143 71 pc.printf("mDot LoRa Temperature sensor\n\r");
SomeRandomBloke 0:5a0b43f3b143 72 /* wait_ms(5000);
SomeRandomBloke 0:5a0b43f3b143 73 for(int i=0; i<10; i++ )
SomeRandomBloke 0:5a0b43f3b143 74 pc.printf(".");
SomeRandomBloke 0:5a0b43f3b143 75 pc.printf("\n\r");
SomeRandomBloke 0:5a0b43f3b143 76 */
SomeRandomBloke 0:5a0b43f3b143 77 /* while( 1 ) {
SomeRandomBloke 0:5a0b43f3b143 78 // This takes upto 750mS, way too long. Change to 9 bit resolution if not already used.
SomeRandomBloke 0:5a0b43f3b143 79
SomeRandomBloke 0:5a0b43f3b143 80 probe.convertTemperature(true, DS1820::all_devices); //Start temperature conversion, wait until ready
SomeRandomBloke 0:5a0b43f3b143 81 // printf("It is %3.1fC\r\n", probe.temperature());
SomeRandomBloke 0:5a0b43f3b143 82 // Output data as JSON e.g. {"temperature":"21.3"}
SomeRandomBloke 0:5a0b43f3b143 83 temperature = probe.temperature();
SomeRandomBloke 0:5a0b43f3b143 84 pc.printf("Temperature %3.1f\r\n", temperature );
SomeRandomBloke 0:5a0b43f3b143 85 wait_ms(2000);
SomeRandomBloke 0:5a0b43f3b143 86 }
SomeRandomBloke 0:5a0b43f3b143 87 */
SomeRandomBloke 0:5a0b43f3b143 88 //#ifdef bollocks
SomeRandomBloke 0:5a0b43f3b143 89 // get a mDot handle
SomeRandomBloke 0:5a0b43f3b143 90 dot = mDot::getInstance();
SomeRandomBloke 0:5a0b43f3b143 91
SomeRandomBloke 0:5a0b43f3b143 92 dot->setLogLevel(MTSLog::TRACE_LEVEL);
SomeRandomBloke 0:5a0b43f3b143 93
SomeRandomBloke 0:5a0b43f3b143 94 // reset to default config so we know what state we're in
SomeRandomBloke 0:5a0b43f3b143 95 dot->resetConfig();
SomeRandomBloke 0:5a0b43f3b143 96
SomeRandomBloke 0:5a0b43f3b143 97 // Set byte order - AEP less than 1.0.30, currently using 1.0.25Beta
SomeRandomBloke 0:5a0b43f3b143 98 dot->setJoinByteOrder(mDot::MSB);
SomeRandomBloke 0:5a0b43f3b143 99
SomeRandomBloke 0:5a0b43f3b143 100 // If on developer board then you can enable activity LED
SomeRandomBloke 0:5a0b43f3b143 101 // Currently no spare pins that LEDs are connected too.
SomeRandomBloke 0:5a0b43f3b143 102 // dot->setActivityLedPin( ACTIVITY_LED );
SomeRandomBloke 0:5a0b43f3b143 103 // dot->setActivityLedEnable(false);
SomeRandomBloke 0:5a0b43f3b143 104
SomeRandomBloke 0:5a0b43f3b143 105 dot->setJoinRetries( 5 );
SomeRandomBloke 0:5a0b43f3b143 106 dot->setTxDataRate( mDot::SF_9 );
SomeRandomBloke 0:5a0b43f3b143 107 dot->setTxPower( 14 );
SomeRandomBloke 0:5a0b43f3b143 108 // dot->setAck( 0 ); // 1 retries on Ack, 0 to disable
SomeRandomBloke 0:5a0b43f3b143 109
SomeRandomBloke 0:5a0b43f3b143 110 if ((ret = dot->setFrequencySubBand(config_frequency_sub_band)) != mDot::MDOT_OK) {
SomeRandomBloke 0:5a0b43f3b143 111 initStatus = false;
SomeRandomBloke 0:5a0b43f3b143 112 // logError(dot, "failed to set frequency sub band", ret);
SomeRandomBloke 0:5a0b43f3b143 113 }
SomeRandomBloke 0:5a0b43f3b143 114
SomeRandomBloke 0:5a0b43f3b143 115 if ((ret = dot->setNetworkName(config_network_name)) != mDot::MDOT_OK) {
SomeRandomBloke 0:5a0b43f3b143 116 initStatus = false;
SomeRandomBloke 0:5a0b43f3b143 117 // logError(dot, "failed to set network name", ret);
SomeRandomBloke 0:5a0b43f3b143 118 }
SomeRandomBloke 0:5a0b43f3b143 119
SomeRandomBloke 0:5a0b43f3b143 120 if ((ret = dot->setNetworkPassphrase(config_network_pass)) != mDot::MDOT_OK) {
SomeRandomBloke 0:5a0b43f3b143 121 initStatus = false;
SomeRandomBloke 0:5a0b43f3b143 122 // logError(dot, "failed to set network password", ret);
SomeRandomBloke 0:5a0b43f3b143 123 }
SomeRandomBloke 0:5a0b43f3b143 124
SomeRandomBloke 0:5a0b43f3b143 125 // wait_ms(2000);
SomeRandomBloke 0:5a0b43f3b143 126
SomeRandomBloke 0:5a0b43f3b143 127 // Display protocol/connection info
SomeRandomBloke 0:5a0b43f3b143 128
SomeRandomBloke 0:5a0b43f3b143 129 while ((ret = dot->joinNetwork()) != mDot::MDOT_OK) {
SomeRandomBloke 0:5a0b43f3b143 130 logError("failed to join network [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
SomeRandomBloke 0:5a0b43f3b143 131 //wait(2);
SomeRandomBloke 0:5a0b43f3b143 132 wait_ms(dot->getNextTxMs() + 1);
SomeRandomBloke 0:5a0b43f3b143 133 }
SomeRandomBloke 0:5a0b43f3b143 134
SomeRandomBloke 0:5a0b43f3b143 135 probe.setResolution(9);
SomeRandomBloke 0:5a0b43f3b143 136
SomeRandomBloke 0:5a0b43f3b143 137 char dataBuf[50];
SomeRandomBloke 0:5a0b43f3b143 138 // for (uint8_t i = 0; i < iterations; i++) {
SomeRandomBloke 0:5a0b43f3b143 139 while( 1 ) {
SomeRandomBloke 0:5a0b43f3b143 140 // This takes upto 750mS, way too long. Change to 9 bit resolution if not already used.
SomeRandomBloke 0:5a0b43f3b143 141
SomeRandomBloke 0:5a0b43f3b143 142 probe.convertTemperature(true, DS1820::all_devices); //Start temperature conversion, wait until ready
SomeRandomBloke 0:5a0b43f3b143 143 // printf("It is %3.1fC\r\n", probe.temperature());
SomeRandomBloke 0:5a0b43f3b143 144 // Output data as JSON e.g. {"temperature":"21.3"}
SomeRandomBloke 0:5a0b43f3b143 145 temperature = probe.temperature();
SomeRandomBloke 0:5a0b43f3b143 146 sprintf(dataBuf, "{\"temperature\":%3.1f}", temperature );
SomeRandomBloke 0:5a0b43f3b143 147 send_data.clear();
SomeRandomBloke 0:5a0b43f3b143 148 // probably not the most efficent way to do this
SomeRandomBloke 0:5a0b43f3b143 149 for( int i=0; i< strlen(dataBuf); i++ )
SomeRandomBloke 0:5a0b43f3b143 150 send_data.push_back( dataBuf[i] );
SomeRandomBloke 0:5a0b43f3b143 151
SomeRandomBloke 0:5a0b43f3b143 152 if ((ret = dot->send(send_data)) != mDot::MDOT_OK) {
SomeRandomBloke 0:5a0b43f3b143 153 logError("failed to send: [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
SomeRandomBloke 0:5a0b43f3b143 154 txFailCount++;
SomeRandomBloke 0:5a0b43f3b143 155 } else {
SomeRandomBloke 0:5a0b43f3b143 156 txCount++;
SomeRandomBloke 0:5a0b43f3b143 157 logInfo("send data: %s", Text::bin2hexString(send_data).c_str());
SomeRandomBloke 0:5a0b43f3b143 158 /*
SomeRandomBloke 0:5a0b43f3b143 159 if ((ret = dot->recv(recv_data)) != mDot::MDOT_OK) {
SomeRandomBloke 0:5a0b43f3b143 160 logError("failed to recv: [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
SomeRandomBloke 0:5a0b43f3b143 161 noRxCount++;
SomeRandomBloke 0:5a0b43f3b143 162 } else {
SomeRandomBloke 0:5a0b43f3b143 163 // Received something
SomeRandomBloke 0:5a0b43f3b143 164 logInfo("recv data: %s", Text::bin2hexString(recv_data).c_str());
SomeRandomBloke 0:5a0b43f3b143 165 rxCount++;
SomeRandomBloke 0:5a0b43f3b143 166 if (recv_data == send_data) {
SomeRandomBloke 0:5a0b43f3b143 167 rxOkCount++;
SomeRandomBloke 0:5a0b43f3b143 168 logInfo("recv data matches");
SomeRandomBloke 0:5a0b43f3b143 169 } else {
SomeRandomBloke 0:5a0b43f3b143 170 rxFailCount++;
SomeRandomBloke 0:5a0b43f3b143 171 logInfo("recv data failed to match");
SomeRandomBloke 0:5a0b43f3b143 172 }
SomeRandomBloke 0:5a0b43f3b143 173 }
SomeRandomBloke 0:5a0b43f3b143 174 recv_data.clear();
SomeRandomBloke 0:5a0b43f3b143 175 */
SomeRandomBloke 0:5a0b43f3b143 176 }
SomeRandomBloke 0:5a0b43f3b143 177
SomeRandomBloke 0:5a0b43f3b143 178 // TODO: Should really sleep here and wakeup after a set interval.
SomeRandomBloke 0:5a0b43f3b143 179
SomeRandomBloke 0:5a0b43f3b143 180 next_tx = dot->getNextTxMs() + 1;
SomeRandomBloke 0:5a0b43f3b143 181 logInfo("waiting %ld ms to transmit again", next_tx);
SomeRandomBloke 0:5a0b43f3b143 182 wait_ms(next_tx);
SomeRandomBloke 0:5a0b43f3b143 183 logInfo("waiting another %d seconds", wait_time);
SomeRandomBloke 0:5a0b43f3b143 184 wait(wait_time);
SomeRandomBloke 0:5a0b43f3b143 185 }
SomeRandomBloke 0:5a0b43f3b143 186 //#endif
SomeRandomBloke 0:5a0b43f3b143 187 return 0;
SomeRandomBloke 0:5a0b43f3b143 188 }
SomeRandomBloke 0:5a0b43f3b143 189 /*
SomeRandomBloke 0:5a0b43f3b143 190 void log_error(mDot* dot, const char* msg, int32_t retval)
SomeRandomBloke 0:5a0b43f3b143 191 {
SomeRandomBloke 0:5a0b43f3b143 192 printf("%s - %ld:%s, %s\r\n", msg, retval, mDot::getReturnCodeString(retval).c_str(), dot->getLastError().c_str());
SomeRandomBloke 0:5a0b43f3b143 193 }
SomeRandomBloke 0:5a0b43f3b143 194 */