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:
Thu Oct 15 20:34:52 2015 +0000
Revision:
4:f649ab1b61d1
Parent:
3:367aa95f9771
Child:
5:48eb9245a914
sleep updates

Who changed what in which revision?

UserRevisionLine numberNew contents of line
SomeRandomBloke 2:9db840d12557 1 /** mDot_DS18B20 - Simple mDot temperature sensor using Dallas Semiconductors DS18B20 OneWire temperature sensor.
SomeRandomBloke 4:f649ab1b61d1 2 * It used the OTA_AUTO join mode using saved parameters. If the config is to be reset then pin A2 on the
SomeRandomBloke 3:367aa95f9771 3 * dev board must be held low during a reset or power up.
SomeRandomBloke 2:9db840d12557 4 *
SomeRandomBloke 0:5a0b43f3b143 5 * Uses MultiTech mDot developer board http://www.multitech.com/models/94558010LF
SomeRandomBloke 0:5a0b43f3b143 6 * Requires a MultiTech MultiConnect Conduit http://www.multitech.com/models/94557203LF
SomeRandomBloke 0:5a0b43f3b143 7 *
SomeRandomBloke 0:5a0b43f3b143 8 * Example JSON received on Conduit:
SomeRandomBloke 0:5a0b43f3b143 9 { "chan": 5, "codr": "4/5", "datr": "SF9BW125", "freq": "869.5",
SomeRandomBloke 0:5a0b43f3b143 10 "lsnr": "8.8", "modu": "LORA", "rfch": 1, "rssi": -41, "seqn": 13,
SomeRandomBloke 0:5a0b43f3b143 11 "size": 12, "timestamp": "2015-07-22T21:19:11Z", "tmst": 517590990,
SomeRandomBloke 2:9db840d12557 12 "payload": "{\"tmp\":21.3}", "eui": "00:80:00:00:00:00:9a:63", "_msg
SomeRandomBloke 0:5a0b43f3b143 13 id": "73bcd8dd.8c4328" }
SomeRandomBloke 0:5a0b43f3b143 14 *
SomeRandomBloke 0:5a0b43f3b143 15 */
SomeRandomBloke 0:5a0b43f3b143 16
SomeRandomBloke 0:5a0b43f3b143 17 #include "mbed.h"
SomeRandomBloke 0:5a0b43f3b143 18 #include "DS1820.h"
SomeRandomBloke 0:5a0b43f3b143 19 #include "mDot.h"
SomeRandomBloke 0:5a0b43f3b143 20 #include "MTSLog.h"
SomeRandomBloke 0:5a0b43f3b143 21 #include "MTSText.h"
SomeRandomBloke 0:5a0b43f3b143 22 #include <string>
SomeRandomBloke 0:5a0b43f3b143 23 #include <vector>
SomeRandomBloke 0:5a0b43f3b143 24
SomeRandomBloke 0:5a0b43f3b143 25 using namespace mts;
SomeRandomBloke 0:5a0b43f3b143 26
SomeRandomBloke 4:f649ab1b61d1 27 #define MIN(a,b) (((a)<(b))?(a):(b))
SomeRandomBloke 4:f649ab1b61d1 28 #define MAX(a,b) (((a)>(b))?(a):(b))
SomeRandomBloke 4:f649ab1b61d1 29
SomeRandomBloke 0:5a0b43f3b143 30 // these options must match the settings on your Conduit in
SomeRandomBloke 0:5a0b43f3b143 31 // /var/config/lora/lora-network-server.conf
SomeRandomBloke 4:f649ab1b61d1 32 static std::string config_network_name = "ThingInnovations";
SomeRandomBloke 4:f649ab1b61d1 33 static std::string config_network_pass = "donkey123";
SomeRandomBloke 3:367aa95f9771 34 // Ignoring sub band for EU modules.
SomeRandomBloke 1:45cec6aea002 35 //static uint8_t config_frequency_sub_band = 1;
SomeRandomBloke 0:5a0b43f3b143 36
SomeRandomBloke 0:5a0b43f3b143 37 // mDot/dev board activity LED
SomeRandomBloke 1:45cec6aea002 38 //#define ACTIVITY_LED PA_0
SomeRandomBloke 2:9db840d12557 39
SomeRandomBloke 2:9db840d12557 40 // DS18B20 OneWire pin
SomeRandomBloke 3:367aa95f9771 41 // D13 on Dev Board, pin 18 on mDot
SomeRandomBloke 1:45cec6aea002 42 #define DATA_PIN PA_5
SomeRandomBloke 3:367aa95f9771 43 // A0 on Dev Board, pin 20 on mDot
SomeRandomBloke 1:45cec6aea002 44 //#define DATA_PIN PB_1
SomeRandomBloke 0:5a0b43f3b143 45
SomeRandomBloke 3:367aa95f9771 46 // A2 - input to reset LoRaWAN config. Pin 15 om mDot.
SomeRandomBloke 3:367aa95f9771 47 #define CONFIG_RESET PC_1
SomeRandomBloke 3:367aa95f9771 48
SomeRandomBloke 3:367aa95f9771 49 // Config Reset intput
SomeRandomBloke 3:367aa95f9771 50 DigitalIn configReset(CONFIG_RESET);
SomeRandomBloke 3:367aa95f9771 51
SomeRandomBloke 3:367aa95f9771 52 // Temperature sensor object
SomeRandomBloke 0:5a0b43f3b143 53 DS1820 probe(DATA_PIN);
SomeRandomBloke 0:5a0b43f3b143 54
SomeRandomBloke 3:367aa95f9771 55 // Serial via USB for debugging only
SomeRandomBloke 0:5a0b43f3b143 56 Serial pc(USBTX,USBRX);
SomeRandomBloke 0:5a0b43f3b143 57
SomeRandomBloke 0:5a0b43f3b143 58
SomeRandomBloke 0:5a0b43f3b143 59 int main()
SomeRandomBloke 0:5a0b43f3b143 60 {
SomeRandomBloke 0:5a0b43f3b143 61 int32_t ret;
SomeRandomBloke 0:5a0b43f3b143 62 mDot* dot;
SomeRandomBloke 0:5a0b43f3b143 63 std::vector<uint8_t> send_data;
SomeRandomBloke 0:5a0b43f3b143 64 std::vector<uint8_t> recv_data;
SomeRandomBloke 0:5a0b43f3b143 65
SomeRandomBloke 0:5a0b43f3b143 66 float temperature = 0.0;
SomeRandomBloke 1:45cec6aea002 67
SomeRandomBloke 3:367aa95f9771 68 // Enable internal pullup on input pin
SomeRandomBloke 3:367aa95f9771 69 configReset.mode(PullUp);
SomeRandomBloke 3:367aa95f9771 70
SomeRandomBloke 0:5a0b43f3b143 71 pc.baud(115200);
SomeRandomBloke 0:5a0b43f3b143 72 pc.printf("mDot LoRa Temperature sensor\n\r");
SomeRandomBloke 1:45cec6aea002 73
SomeRandomBloke 0:5a0b43f3b143 74 // get a mDot handle
SomeRandomBloke 0:5a0b43f3b143 75 dot = mDot::getInstance();
SomeRandomBloke 0:5a0b43f3b143 76
SomeRandomBloke 4:f649ab1b61d1 77 // dot->setLogLevel(MTSLog::WARNING_LEVEL);
SomeRandomBloke 4:f649ab1b61d1 78 dot->setLogLevel(MTSLog::TRACE_LEVEL);
SomeRandomBloke 0:5a0b43f3b143 79
SomeRandomBloke 1:45cec6aea002 80 logInfo("Checking Config");
SomeRandomBloke 1:45cec6aea002 81
SomeRandomBloke 1:45cec6aea002 82 // Test if we've already saved the config
SomeRandomBloke 1:45cec6aea002 83 std::string configNetworkName = dot->getNetworkName();
SomeRandomBloke 1:45cec6aea002 84
SomeRandomBloke 3:367aa95f9771 85 // Reset config if network name is different or pin is low then reset config.
SomeRandomBloke 3:367aa95f9771 86 if( config_network_name.compare(configNetworkName) != 0 || !configReset ) {
SomeRandomBloke 1:45cec6aea002 87 // Not saved config, reset
SomeRandomBloke 1:45cec6aea002 88 logInfo("Setting Config");
SomeRandomBloke 0:5a0b43f3b143 89
SomeRandomBloke 1:45cec6aea002 90 // reset to default config so we know what state we're in
SomeRandomBloke 1:45cec6aea002 91 dot->resetConfig();
SomeRandomBloke 1:45cec6aea002 92
SomeRandomBloke 1:45cec6aea002 93 // Set byte order - AEP less than 1.0.30
SomeRandomBloke 1:45cec6aea002 94 // dot->setJoinByteOrder(mDot::MSB);
SomeRandomBloke 1:45cec6aea002 95 dot->setJoinByteOrder(mDot::LSB);
SomeRandomBloke 0:5a0b43f3b143 96
SomeRandomBloke 1:45cec6aea002 97 logInfo("setting Join mode");
SomeRandomBloke 1:45cec6aea002 98 if ((ret = dot->setJoinMode(mDot::AUTO_OTA)) != mDot::MDOT_OK) {
SomeRandomBloke 1:45cec6aea002 99 logError("failed to set Join Mode %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
SomeRandomBloke 1:45cec6aea002 100 }
SomeRandomBloke 1:45cec6aea002 101
SomeRandomBloke 1:45cec6aea002 102 // If on developer board then you can enable activity LED
SomeRandomBloke 1:45cec6aea002 103 // Currently no spare pins that LEDs are connected too.
SomeRandomBloke 0:5a0b43f3b143 104 // dot->setActivityLedPin( ACTIVITY_LED );
SomeRandomBloke 0:5a0b43f3b143 105 // dot->setActivityLedEnable(false);
SomeRandomBloke 0:5a0b43f3b143 106
SomeRandomBloke 2:9db840d12557 107 // Have a decent nubmer of retries in connecting to LoRaWAN
SomeRandomBloke 2:9db840d12557 108 dot->setJoinRetries( 3 );
SomeRandomBloke 2:9db840d12557 109
SomeRandomBloke 2:9db840d12557 110 // Set Spreading Factor, higher is lower data rate, smaller packets but longer range
SomeRandomBloke 2:9db840d12557 111 // Lower is higher data rate, larger packets and shorter range.
SomeRandomBloke 2:9db840d12557 112 // dot->setTxDataRate( mDot::SF_9 );
SomeRandomBloke 3:367aa95f9771 113 dot->setTxDataRate( mDot::SF_12 );
SomeRandomBloke 1:45cec6aea002 114 dot->setTxPower( 14 );
SomeRandomBloke 1:45cec6aea002 115 dot->setAck( 0 ); // 1 retries on Ack, 0 to disable
SomeRandomBloke 3:367aa95f9771 116
SomeRandomBloke 1:45cec6aea002 117 // Not applicable for 868MHz in EU
SomeRandomBloke 1:45cec6aea002 118 // if ((ret = dot->setFrequencySubBand(config_frequency_sub_band)) != mDot::MDOT_OK) {
SomeRandomBloke 1:45cec6aea002 119 // initStatus = false;
SomeRandomBloke 0:5a0b43f3b143 120 // logError(dot, "failed to set frequency sub band", ret);
SomeRandomBloke 1:45cec6aea002 121 // }
SomeRandomBloke 1:45cec6aea002 122
SomeRandomBloke 1:45cec6aea002 123 if ((ret = dot->setNetworkName(config_network_name)) != mDot::MDOT_OK) {
SomeRandomBloke 1:45cec6aea002 124 logError("failed to set network name %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
SomeRandomBloke 1:45cec6aea002 125 }
SomeRandomBloke 0:5a0b43f3b143 126
SomeRandomBloke 1:45cec6aea002 127 if ((ret = dot->setNetworkPassphrase(config_network_pass)) != mDot::MDOT_OK) {
SomeRandomBloke 1:45cec6aea002 128 logError("failed to set network password %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
SomeRandomBloke 1:45cec6aea002 129 }
SomeRandomBloke 1:45cec6aea002 130
SomeRandomBloke 2:9db840d12557 131 if ((ret = dot->setJoinMode( mDot::AUTO_OTA )) != mDot::MDOT_OK) {
SomeRandomBloke 2:9db840d12557 132 logError("failed to set join mode %d:%s", ret, mDot::getReturnCodeString(ret).c_str());
SomeRandomBloke 2:9db840d12557 133 }
SomeRandomBloke 2:9db840d12557 134
SomeRandomBloke 1:45cec6aea002 135 logInfo("Saving Config");
SomeRandomBloke 1:45cec6aea002 136
SomeRandomBloke 1:45cec6aea002 137 // Save config
SomeRandomBloke 1:45cec6aea002 138 if (! dot->saveConfig()) {
SomeRandomBloke 1:45cec6aea002 139 logError("failed to save configuration");
SomeRandomBloke 1:45cec6aea002 140 }
SomeRandomBloke 1:45cec6aea002 141 } else {
SomeRandomBloke 1:45cec6aea002 142 logInfo("Using existing Config");
SomeRandomBloke 0:5a0b43f3b143 143 }
SomeRandomBloke 0:5a0b43f3b143 144
SomeRandomBloke 4:f649ab1b61d1 145 logInfo("Joining Network");
SomeRandomBloke 4:f649ab1b61d1 146
SomeRandomBloke 0:5a0b43f3b143 147 while ((ret = dot->joinNetwork()) != mDot::MDOT_OK) {
SomeRandomBloke 0:5a0b43f3b143 148 logError("failed to join network [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
SomeRandomBloke 0:5a0b43f3b143 149 wait_ms(dot->getNextTxMs() + 1);
SomeRandomBloke 0:5a0b43f3b143 150 }
SomeRandomBloke 1:45cec6aea002 151
SomeRandomBloke 4:f649ab1b61d1 152 logInfo("Joined Network");
SomeRandomBloke 4:f649ab1b61d1 153
SomeRandomBloke 0:5a0b43f3b143 154 probe.setResolution(9);
SomeRandomBloke 0:5a0b43f3b143 155
SomeRandomBloke 0:5a0b43f3b143 156 char dataBuf[50];
SomeRandomBloke 0:5a0b43f3b143 157 while( 1 ) {
SomeRandomBloke 0:5a0b43f3b143 158 // This takes upto 750mS, way too long. Change to 9 bit resolution if not already used.
SomeRandomBloke 1:45cec6aea002 159
SomeRandomBloke 0:5a0b43f3b143 160 probe.convertTemperature(true, DS1820::all_devices); //Start temperature conversion, wait until ready
SomeRandomBloke 0:5a0b43f3b143 161 // printf("It is %3.1fC\r\n", probe.temperature());
SomeRandomBloke 3:367aa95f9771 162 // Output data as JSON e.g. {"tmp":21.3}
SomeRandomBloke 0:5a0b43f3b143 163 temperature = probe.temperature();
SomeRandomBloke 1:45cec6aea002 164 sprintf(dataBuf, "{\"tmp\":%3.1f}", temperature );
SomeRandomBloke 0:5a0b43f3b143 165 send_data.clear();
SomeRandomBloke 0:5a0b43f3b143 166 // probably not the most efficent way to do this
SomeRandomBloke 0:5a0b43f3b143 167 for( int i=0; i< strlen(dataBuf); i++ )
SomeRandomBloke 0:5a0b43f3b143 168 send_data.push_back( dataBuf[i] );
SomeRandomBloke 0:5a0b43f3b143 169
SomeRandomBloke 0:5a0b43f3b143 170 if ((ret = dot->send(send_data)) != mDot::MDOT_OK) {
SomeRandomBloke 0:5a0b43f3b143 171 logError("failed to send: [%d][%s]", ret, mDot::getReturnCodeString(ret).c_str());
SomeRandomBloke 0:5a0b43f3b143 172 } else {
SomeRandomBloke 0:5a0b43f3b143 173 logInfo("send data: %s", Text::bin2hexString(send_data).c_str());
SomeRandomBloke 0:5a0b43f3b143 174 }
SomeRandomBloke 0:5a0b43f3b143 175
SomeRandomBloke 1:45cec6aea002 176 // Should sleep here and wakeup after a set interval.
SomeRandomBloke 4:f649ab1b61d1 177 uint32_t sleep_time = MAX((dot->getNextTxMs() / 1000), 60);
SomeRandomBloke 2:9db840d12557 178 logInfo("going to sleep for %d seconds", sleep_time);
SomeRandomBloke 0:5a0b43f3b143 179
SomeRandomBloke 1:45cec6aea002 180 // go to sleep and wake up automatically sleep_time seconds later
SomeRandomBloke 2:9db840d12557 181 dot->sleep(sleep_time, mDot::RTC_ALARM);
SomeRandomBloke 2:9db840d12557 182
SomeRandomBloke 0:5a0b43f3b143 183 }
SomeRandomBloke 2:9db840d12557 184
SomeRandomBloke 0:5a0b43f3b143 185 return 0;
SomeRandomBloke 0:5a0b43f3b143 186 }