The Libelium LoRaWAN module has been integrated into the main sensor lines Waspmote and Plug & Sense!, however it has also been ported to Arduino and Raspberry Pi, so now you can create your own Low Power Wide Area Network (LPWAN) networks.
LoRaWAN is a new, private and spread-spectrum modulation technique which allows sending data at extremely low data-rates to extremely long ranges. The low data-rate (down to few bytes per second) and LoRaWAN modulation lead to very low receiver sensitivity (down to -136 dBm), which combined to an output power of +14 dBm means extremely large link budgets: up to 150 dB, what means more than 22km (13.6 miles) in LOS links and up to 2km (1.2miles) in NLOS links in urban environment (going through buildings).
Libelium's LoRaWAN 868 module works in both 868 and 433MHz ISM bands (and the LoRaWAN 900 module works in 900MHz ISM band), which makes it suitable for virtually any country. Those frequency bands are lower than the popular 2.4 GHz band, so path loss attenuation is better in LoRaWAN. In addition, 868 and 900MHz are bands with much fewer interference than the highly populated 2.4 GHz band. Besides, these low frequencies provide great penetration in possible materials (brick walls, trees, concrete), so these bands get less loss in the presence of obstacles than higher band.
With the LoRaWAN modules we can send the data directly to any Base Station (BS) that is LoRaWAN compatible. Some companies already offering solutions are: Kerlink, Link-Labs, Multitech, Cisco, Augtek, Manthink, Gupsy, Gemteck, ExpEmb, Embedded Planet, Calao, RFI, etc. In order to visualize the information we will need also a Cloud platform where the data has to be sent. Normally when you acquire a BS you can install your preferred SW packet in order to make it work against the Cloud platform. We tested the LoRaWAN radios with three Cloud platforms: Actility, Orbiwise and Loriot, you can find more information about the configuration in this tutorial.
As well as the LoRaWAN to Base Station mode, the modules may be used in two different more configurations.
In the P2P Mode nodes may connect directly among them and send messages directly at no cost (as they are not using the LoRaWAN Network but just direct radio communication). This is useful as we can create secondary networks at any time as we don't need to change the firmware but just use specific AT Commands in the current library. This mode works without the need of a Base Station or a Cloud account so in case you don't want to purchase any license (or renew the license after the initial period) you will be able to keep on using the modules this way. For more info go to the section P2P Mode.
In the Hybrid Mode we use a combination of the LoRaWAN and P2P modes allowing to send just certain messages using the LoRaWAN Network. In this case we use one node as GW of the network (P2P + LoRaWAN mode) and the rest of the nodes in P2P mode. This mode may work using just one LoRaWAN License. For more info go to the section Hybrid Mode.
Libelium currently offers two options of this type of radio technology: LoRa and LoRaWAN
Libelium offers two types of sensor platforms: OEM lines (Waspmote , Arduino, Raspberry Pi) and Plug & Sense!.
http://www.libelium.com/products/waspmote/
CE Mark: In accordance with the 1999/5/EC (R&TTE) and the EU Directive 2011/65/EU (RoHS2), Libelium Comunicaciones Distribuidas S.L. declares that the "Plug & Sense! LoRaWAN 868" device conforms to the following regulations:
Libelium has certified the model "Plug & Sense! LoRa 900 / 915" for US (FCC) and Canada (IC). Specifically under the Part 15 Spread Spectrum Transmitter (FCC Rule Part 15 C) and the Industry Canada Regulation (IC) - (RSS-210) respectively.
LoRaWAN is a Low Power Wide Area Network (LPWAN) specification intended for wireless battery operated devices in regional, national or global network. LoRaWAN target key requirements of Internet of things such as secure bi-directional communication, mobility and localization services. This standard will provide seamless interoperability among smart Things without the need of complex local installations and gives back the freedom to the user, developer, businesses enabling the role out of Internet of Things.
LoRaWAN network architecture is typically laid out in a star-of-stars topology in which gateways is a transparent bridge relaying messages between end-devices and a central network server in the back-end. Gateways are connected to the network server via standard IP connections while end-devices use single-hop wireless communication to one or many gateways.
Communication between end-devices and gateways is spread out on different frequency channels and data rates. The selection of the data rate is a trade-off between communication range and message duration. Due to the spread spectrum technology, communications with different data rates do not interfere with each other and create a set of "virtual" channels increasing the capacity of the gateway. To maximize both battery life of the end-devices and overall network capacity, the LoRaWAN network server is managing the data rate and RF output for each end-device individually by means of an adaptive data rate (ADR) scheme.
National wide networks targeting internet of things such as critical infrastructure, confidential personal data or critical functions for the society has a special need for secure communication. This has been solved by several layer of encryption:
The LoRaWAN module is managed via UART and it can be connected to SOCKET0 or SOCKET1.
The main features of the modules are listed below:
The main features of the modules are listed below:
Libelium commercializes different items depending on the band the user wants to use. In the case of 868 and 433, the module is the same, but the antenna is different for each band. The module for 868 and 433 MHz includes 2 RP-SMA connectors for the antenna. One is for the 868 band and the other for the 433 band. A sticker on the bottom of the modules specifies clearly where to screw the antenna.
The LoRaWAN 868 module is powered at 3.3 V. The next table shows the module's average current consumption in different states of the module.
ON | |
Transmitting data | |
Receiving data |
The LoRaWAN 900 module is powered at 3.3 V. The next table shows the module's average current consumption in different states of the module.
ON | |
Transmitting data | |
Receiving data |
The elapsed periods defined in this chapter take into account the following steps depending on the case:
These periods of time depend on the data rate set which is defined by the spreading factor and signal bandwidth configured.
Send unconfirmed at 5470 bps | |
Send unconfirmed at 250 bps | |
Send confirmed at 5470 bps | |
Send confirmed at 250 bps |
Get the Multiprotocol Radio Shield
Get the Raspberry Pi to Arduino shields connection bridge
Get the LoRaWAN module for Raspberry Pi
Waspmote is an open source wireless sensor platform specially focused on the implementation of low consumption modes to allow the sensor nodes ("motes") to be completely autonomous and battery powered, offering a variable lifetime between 1 and 5 years depending on the duty cycle and the radio used. The platform counts with more than 100 sensors already integrated and ready to use.
Know more at:
Are Waspmote and Arduino platforms compatible?
Waspmote uses the same IDE (compiler and core libraries) than Arduino. For this reason the same code is compatible in both platforms just adjusting small things like the pinout and the I/O scheme. We love the fast learning curve of Arduino and for this reason we tried to make a platform compatible with it. The idea is an Arduino user may work with Waspmote in a transparent and easy way (as the source code will be the same the learning curve does not exists).
Then, are Waspmote and Arduino competence?
Definitely no. Arduino is a really nice platform to learn how to use electronics and intended to make cheap "home projects" while Waspmote is a device specially designed to create wireless sensor networks which need long lifetime and are meant to be deployed in a real scenario like a city.
I just want to "play" with Waspmote, isn't it cheaper using Arduino?
The answer is, what do you want to do exactly? Waspmote is a very compact board including all needed for creating wireless sensor networks: wireless communications, RTC clock to allow scheduling interruptions, uSD to store data from sensors, 3-axis accelerometer (very useful for detecting falling nodes and as a sensor by itself) and of course, a battery and solar socket with charger regulator for making the node completely autonomous. You can find below a chart comparing Arduino and Waspmote features according to Cooking Hacks prices, so you can see how much does it cost adding those features separately to Arduino. We just want you to get the most appropriate device for your project!
Is Waspmote open source?
Yes. All the source code libraries are released under the LGPL license so developers may choose if the programs they do are released as open source or not.
The Expansion Board allows the user to connect two communication modules at the same time in the Waspmote sensor platform. This means a lot of different combinations are possible using any of the wireless radios available for Waspmote: 802.15.4, ZigBee, DigiMesh, 868 MHz, 900 MHz, LoRaWAN, LoRa, Sigfox, Bluetooth Pro, Bluetooth Low Energy, RFID/NFC, WiFi, GPRS Pro, GPRS+GPS and 3G/GPRS. Besides, the following Industrial Protocols modules are available: RS-485/Modbus, RS-232 Serial/Modbus and CAN Bus.
Some of the possible combinations are:
In the next photo you can see the sockets available along with the UART assigned. On one hand, SOCKET0 allows the user to plug any kind of radio module through the UART0. On the other hand, SOCKET1 permits to connect a radio module through the UART1.
The API provides a function called ON() in order to switch the module on. This function supports a parameter which permits to select the SOCKET. It is possible to choose between SOCKET0 and SOCKET1.
Selecting SOCKET0: LoRaWAN.ON(SOCKET0);
Selecting SOCKET1: LoRaWAN.ON(SOCKET1);
The rest of functions are used the same way as they are used with older API versions. In order to understand them we recommend to read this guide.
- Gases Board: Incompatible with SOCKET4 and NO2/O3 sensor.
- Agriculture Board: Incompatible with Sensirion and the atmospheric pressure sensor.
- Smart Metering Board: Incompatible with SOCKET11 and SOCKET13.
- Smart Cities Board: Incompatible with microphone and the CLK of the interruption shift register.
- Events Board: Incompatible with interruption shift register.
The LoRaWAN module counts with a C++ library that lets you manage the LoRaWAN module in a simple way. This library offers a simple-to-use open source system.
Waspmote, Arduino and Raspberry Pi communicate with the LoRaWAN module via UART. So different commands are sent from the microcontroller unit to the module so as to perform different tasks.
The LoRaWAN module includes a high level library functions for an easy manage. Before start using this functions you should download the library. The next zip includes all the files needed in different folders. Copy these folders in the arduino IDE folder “libraries”. Don't forget include these libraries in your codes.
Download the LoRaWAN Libraries for Arduino.
Libraries are often distributed as a ZIP file or folder. The name of the folder is the name of the library. Inside the folder will be the .cpp files, .h files and a examples folder.
To install the library, first quit the Arduino application. Then uncompress the ZIP file containing the library. For installing libraries, uncompress zip file. Drag these folders into your libraries folder. Under Windows, it will likely be called "My Documents\Arduino\libraries". For Mac users, it will likely be called "Documents/Arduino/libraries". On Linux, it will be the "libraries" folder in your sketchbook.
The library won't work if you put the .cpp and .h files directly into the libraries folder or if they're tested in an extra folder. Restart the Arduino application. Make sure the new library appears in the Sketch->Import Library menu item of the software.
The LoRaWAN library for Raspberry Pi requires the ArduPi library and the rest of the libraries should be in the same path.
Download the LoRaWAN Libraries for Raspberry Pi.
http://www.cooking-hacks.com/media/cooking/images/documentation/tutorial_kit_lorawan/arduPi_api_LoRaWAN_v1_3.zip && unzip -u arduPi_api_LoRaWAN_v1_3.zip && cd cooking/examples/LoRaWAN && chmod +x cook.sh && cd ../../..
Creating a program that uses the library is as simple as putting your code in this template where it says "your Arduino code here"
/* * LoRaWAN module * * Copyright (C) Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Version: 1.0 * Design: David Gascón * Implementation: Yuri Carmona & Ruben Martin */ /********************************************************* * IF YOUR ARDUINO CODE HAS OTHER FUNCTIONS APART FROM * * setup() AND loop() YOU MUST DECLARE THEM HERE * * *******************************************************/ /************************** * YOUR ARDUINO CODE HERE * * ************************/ void setup() { } void loop(void) { } int main (){ setup(); while(1){ loop(); } return (0); } //////////////////////////////////////////////
Follow the next steps to compile a sketch:
ArduPi For Raspberry Pi:
wget http://www.cooking-hacks.com/media/cooking/images/documentation/raspberry_arduino_shield/raspberrypi.zip && unzip raspberrypi.zip && cd cooking/arduPi && chmod +x install_arduPi && ./install_arduPi && rm install_arduPi && cd ../..
ArduPi For Raspberry Pi 2:
wget http://www.cooking-hacks.com/media/cooking/images/documentation/raspberry_arduino_shield/raspberrypi2.zip && unzip raspberrypi2.zip && cd cooking/arduPi && chmod +x install_arduPi && ./install_arduPi && rm install_arduPi && cd ../..
LoRaWAN Library:
wget http://www.cooking-hacks.com/media/cooking/images/documentation/tutorial_kit_lorawan/arduPi_api_LoRaWAN_v1_3.zip && unzip -u arduPi_api_LoRaWAN_v1_3.zip && cd cooking/examples/LoRaWAN && chmod +x cook.sh && cd ../../..
cd cooking/examples/LoRaWAN/
./cook.sh my_example.cpp
./my_example.cpp_exe
The script "cook.sh" compiles everything in their folders and the link in the examples foldes with the "_exe" executable.
The files related to the LoRaWAN libraries are:
It is mandatory to include the LoRaWAN library when using this module. So the following line must be added at the beginning of the code:
To start using the LoRaWAN library, an object must be created. This object, called LoRaWAN, is already created by default inside LoRaWAN library. It will be used through this guide to show how Waspmote works.
When using the class constructor, all variables are initialized to a default value.
The API constants used in functions are:
LORAWAN_ANSWER_OK | Successful response to a function |
LORAWAN_ANSWER_ERROR | Erratic response to a function |
LORAWAN_NO_ANSWER | No response to a command |
LORAWAN_INIT_ERROR | Required keys to join to a network were not initialized |
LORAWAN_LENGTH_ERROR | Data to be sent length limit exceeded |
LORAWAN_SENDING_ERROR | Server did not response |
LORAWAN_NOT_JOINED | Module has not joined a network |
LORAWAN_INPUT_ERROR | Invalid input parameter |
LORAWAN_VERSION_ERROR | The module does not support this function |
RN2483_MODULE | LoRaWAN module plugged is LoRaWAN 868 |
RN2903_MODULE | LoRaWAN module plugged is LoRaWAN 900 |
The variables used inside functions and Waspmote codes are:
_buffer | The buffer of memory used for storing the responses from the module |
_length | The useful length of the buffer |
_def_delay | The time to wait after sending every command until listen for a response |
_baudrate | The baudrate to be used when the module is switched on |
_uart | The MCU uart selected (regarding the socket used: SOCKET0 or SOCKET1) |
_adr | The adaptive data rate state (on or off) |
_eui | The buffer used for storing the preprogrammed globally unique identifier from the module's hardware |
_devEUI | The buffer used for storing the globally unique identifier for the module (software programmable) |
_appEUI | The buffer used for storing the application identifier for the module |
_nwkSKey | The buffer used for storing the network session key for the module |
_appSKey | The buffer used for storing the application session key for the module |
_appKey | The buffer used for storing the application key for the module |
_devAddr | The buffer used for storing network device address for module |
_band | The buffer used for storing the frequency band |
_margin | The demodulation margin received in the last Link Check Answer frame |
_gwNumber | The number of gateways successfully received the last Link Check Answer frame |
_freq | The buffer used for storing the operating frequency for every channel |
_radioFreq | The transceiver operating frequency |
_radioFreqDev | The transceiver frequency deviation |
_preambleLength | The preamble length for transceiver |
_dCycle | The buffer used for storing the operating duty cycle for every channel |
_drrMin | The minimum operating data rate range for every channel |
_drrMax | The maximum operating data rate range for every channel |
_dCyclePS | The duty cycle prescaler (which can only be configured by the server) |
_crcStatus | The CRC status to determine if it is to be included during operation |
_powerIndex | The output power to be used on LoRaWAN transmissions |
_dataRate | The data rate to be used on LoRaWAN transmissions |
_retries | The number of retransmissions for an uplink |
_upCounter | The value of the uplink frame counter |
_downCounter | The value of the downlink frame counter |
_radioPower | The output power level used by the transceiver |
_radioSF | The spreading factor to be used by the transceiver |
_radioRxBW | The receiving bandwidth used by the transceiver |
_radioCR | The coding rate used by the transceiver |
_radioWDT | The time to be used by the transceiver watchdog timer |
_radioBW | The value used for the transceiver bandwidth |
_radioSNR | The SNR value for the last received packet by the transceiver |
_status | The status of every LoRaWAN channel |
_data | The buffer of memory used for storing data received from the back-end |
_port | The port where data was received |
_dataReceived | The flag used to inform if any data was received |
_version | The version of the module plugged into Waspmote |
Through this guide there are lots of examples of using functions. In these examples, API functions are called to execute the commands, storing in their related variables the parameter value in each case. The functions are called using the predefined object LoRaWAN.
All public functions return one of these possible values:
The ON() function allows to switch on the LoRaWAN module, it opens the MCU UART for communicating with the module and it automatically enters into command mode.
In addition, when the module has been powered and communication is opened, this function checks whether a module is plugged to the socket and which type of module has been plugged. This check is done within every function that reboots the module such as “ON”, “reset” or “factoryReset”.
After this step the module will be able to receive commands to configure it or send packets. It is necessary to indicate the socket that it is being used: SOCKET0 or SOCKET1.
Example of use:
{ LoRaWAN.ON(SOCKET0); }
Related variable:
The OFF() function allows the user to switch off the LoRaWAN module and close the UART. This function must be called in order to keep battery level when the module is not going to be managed. It is necessary to indicate the socket that it is being used: SOCKET0 or SOCKET1.
Example of use:
{ LoRaWAN.OFF(SOCKET0); }
The reset() function allows the user to reset and restart the LoRaWAN module. The stored internal configurations will be loaded automatically upon reboot.
Example of use
{ LoRaWAN.reset(); }
Related variable:
The factoryReset() function allows the user to reset the module's configuration data and user EEPROM to factory default values and restart the module.
Example of use:
{ LoRaWAN.factoryReset(); }
Related variable:
Example of LoRaWAN 868 configuration:
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the module * and all general settings related to back-end registration * process. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 1.2 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include <Wire.h> // Cooking API libraries #include <arduinoUART.h> #include <arduinoUtils.h> // LoRaWAN library #include <arduinoLoRaWAN.h> // Pin definition for LoRaWAN module error LED: const int error_led = 13; ////////////////////////////////////////////// uint8_t socket = SOCKET1; ////////////////////////////////////////////// // Device parameters for Back-End registration //////////////////////////////////////////////////////////// char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; char APP_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // variable uint8_t error; void setup() { //LoRaWAN example - Module configuration pinMode(error_led, OUTPUT); digitalWrite(error_led, LOW); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Reset to factory default values ////////////////////////////////////////////// error = LoRaWAN.factoryReset(); // Check status if( error == 0 ) { //2. Reset to factory default values OK digitalWrite(error_led, LOW); } else { //2. Reset to factory error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 3. Set/Get Device EUI ////////////////////////////////////////////// // Set Device EUI error = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( error == 0 ) { //3.1. Set Device EUI OK digitalWrite(error_led, LOW); } else { //3.1. Set Device EUI error digitalWrite(error_led, HIGH); } // Get Device EUI error = LoRaWAN.getDeviceEUI(); // Check status if( error == 0 ) { //3.2. Get Device EUI OK. //Device EUI in LoRaWAN._devEUI digitalWrite(error_led, LOW); } else { //3.2. Get Device EUI error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 4. Set/Get Device Address ////////////////////////////////////////////// // Set Device Address error = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( error == 0 ) { //4.1. Set Device address OK digitalWrite(error_led, LOW); } else { //4.1. Set Device address error digitalWrite(error_led, HIGH); } // Get Device Address error = LoRaWAN.getDeviceAddr(); // Check status if( error == 0 ) { //4.2. Get Device address OK. //Device address in LoRaWAN._devAddr digitalWrite(error_led, LOW); } else { //4.2. Get Device address error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 5. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { //5. Set Network Session Key OK digitalWrite(error_led, LOW); } else { //5. Set Network Session Key error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 6. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { //6. Set Application Session Key OK digitalWrite(error_led, LOW); } else { //6. Set Application Session Key error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 7. Set retransmissions for uplink confirmed packet ////////////////////////////////////////////// // set retries error = LoRaWAN.setRetries(7); // Check status if( error == 0 ) { //7.1. Set Retransmissions for uplink confirmed packet OK digitalWrite(error_led, LOW); } else { //7.1. Set Retransmissions for uplink confirmed packet error digitalWrite(error_led, HIGH); } // Get retries error = LoRaWAN.getRetries(); // Check status if( error == 0 ) { //7.2. Get Retransmissions for uplink confirmed packet OK. //TX retries in LoRaWAN._retries digitalWrite(error_led, LOW); } else { //7.2. Get Retransmissions for uplink confirmed packet error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 8. Set application key ////////////////////////////////////////////// error = LoRaWAN.setAppKey(APP_KEY); // Check status if( error == 0 ) { //8. Application key set OK digitalWrite(error_led, LOW); } else { //8. Application key set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 9. Channel configuration. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// // Set channel 3 -> 867.1 MHz // Set channel 4 -> 867.3 MHz // Set channel 5 -> 867.5 MHz // Set channel 6 -> 867.7 MHz // Set channel 7 -> 867.9 MHz uint32_t freq = 867100000; for (int ch = 3; ch <= 7; ch++) { error |= LoRaWAN.setChannelFreq(ch, freq); freq += 200000; } // Check status if( error == 0 ) { //9. Frequency set OK. //Frequency in LoRaWAN._freq[3] digitalWrite(error_led, LOW); } else { //9. Enable Frequency error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 10. Set Duty Cycle for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (int ch = 0; ch <= 2; ch++) { error |= LoRaWAN.setChannelDutyCycle(ch, 33333); } for (int ch = 3; ch <= 7; ch++) { error |= LoRaWAN.setChannelDutyCycle(ch, 40000); } // Check status if( error == 0 ) { //10. Duty cycle channel set OK. digitalWrite(error_led, LOW); } else { //10. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 11. Set Data Range for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (int ch = 0; ch <= 7; ch++) error |= LoRaWAN.setChannelDRRange(ch, 0, 5); // Check status if( error == 0 ) { //11. Data rate range channel set OK. //Data Rate min in LoRaWAN._drrMin[3] //Data Rate max in LoRaWAN._drrMax[3] digitalWrite(error_led, LOW); } else { //11. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 12. Set Data rate range for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (int ch = 0; ch <= 7; ch++) error |= LoRaWAN.setChannelStatus(ch, "on"); // Check status if( error == 0 ) { //12. Channel status set OK digitalWrite(error_led, LOW); } else { //12. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 13. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { //13. Save configuration OK digitalWrite(error_led, LOW); } else { //13. Save configuration error digitalWrite(error_led, HIGH); } //------------------------------------ //Now the LoRaWAN module is ready for //joining networks and send messages. //Please check the next examples... //------------------------------------ } void loop() { // do nothing }
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the module * and all general settings related to back-end registration * process. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 0.4 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include "arduPiLoRaWAN.h" ////////////////////////////////////////////// uint8_t sock = SOCKET0; ////////////////////////////////////////////// // Device parameters for Back-End registration //////////////////////////////////////////////////////////// char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; char APP_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // variable uint8_t error; void setup() { printf("LoRaWAN example - Module configuration\n"); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(sock); // Check status if( error == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n", error); } ////////////////////////////////////////////// // 2. Reset to factory default values ////////////////////////////////////////////// error = LoRaWAN.factoryReset(); // Check status if( error == 0 ) { printf("2. Reset to factory default values OK\n"); } else { printf("2. Reset to factory error = %d\n", error); } ////////////////////////////////////////////// // 3. Set/Get Device EUI ////////////////////////////////////////////// // Set Device EUI error = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( error == 0 ) { printf("3.1. Set Device EUI OK\n"); } else { printf("3.1. Set Device EUI error = %d\n", error); } // Get Device EUI error = LoRaWAN.getDeviceEUI(); // Check status if( error == 0 ) { printf("3.2. Get Device EUI OK. "); printf("Device EUI: %s\n",LoRaWAN._devEUI); } else { printf("3.2. Get Device EUI error = %d\n", error); } ////////////////////////////////////////////// // 4. Set/Get Device Address ////////////////////////////////////////////// // Set Device Address error = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( error == 0 ) { printf("4.1. Set Device address OK\n"); } else { printf("4.1. Set Device address error = %d\n", error); } // Get Device Address error = LoRaWAN.getDeviceAddr(); // Check status if( error == 0 ) { printf("4.2. Get Device address OK. "); printf("Device address: %s\n", LoRaWAN._devAddr); } else { printf("4.2. Get Device address error = %d\n", error); } ////////////////////////////////////////////// // 5. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { printf("5. Set Network Session Key OK\n"); } else { printf("5. Set Network Session Key error = %d\n", error); } ////////////////////////////////////////////// // 6. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { printf("6. Set Application Session Key OK\n"); } else { printf("6. Set Application Session Key error = %d\n", error); } ////////////////////////////////////////////// // 7. Set retransmissions for uplink confirmed packet ////////////////////////////////////////////// // set retries error = LoRaWAN.setRetries(7); // Check status if( error == 0 ) { printf("7.1. Set Retransmissions for uplink confirmed packet OK\n"); } else { printf("7.1. Set Retransmissions for uplink confirmed packet error = %d\n", error); } // Get retries error = LoRaWAN.getRetries(); // Check status if( error == 0 ) { printf("7.2. Get Retransmissions for uplink confirmed packet OK. \n"); printf("TX retries: %d\n", LoRaWAN._retries); } else { printf("7.2. Get Retransmissions for uplink confirmed packet error = %d\n", error); } ////////////////////////////////////////////// // 8. Set application key ////////////////////////////////////////////// error = LoRaWAN.setAppKey(APP_KEY); // Check status if( error == 0 ) { printf("8. Application key set OK\n"); } else { printf("8. Application key set error = %d\n", error); } ////////////////////////////////////////////// // 9. Channel configuration. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// // Set channel 3 -> 867.1 MHz // Set channel 4 -> 867.3 MHz // Set channel 5 -> 867.5 MHz // Set channel 6 -> 867.7 MHz // Set channel 7 -> 867.9 MHz uint32_t freq = 867100000; for (int ch = 3; ch <= 7; ch++) { error = LoRaWAN.setChannelFreq(ch, freq); freq += 200000; // Check status if( error == 0 ) { printf("9. Application key set OK\n"); } else { printf("9. Application key set error = %d\n", error); } } ////////////////////////////////////////////// // 10. Set Duty Cycle for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (uint8_t ch = 0; ch <= 2; ch++) { error = LoRaWAN.setChannelDutyCycle(ch, 33333); // Check status if( error == 0 ) { printf("10. Duty cycle channel set OK"); } else { printf("10. Duty cycle channel set error = %d\n", error); } } for (uint8_t ch = 3; ch <= 7; ch++) { error = LoRaWAN.setChannelDutyCycle(ch, 40000); // Check status if( error == 0 ) { printf("10. Duty cycle channel set OK"); } else { printf("10. Duty cycle channel set error = %d\n", error); } } ////////////////////////////////////////////// // 11. Set Data Range for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (int ch = 0; ch <= 7; ch++) { error = LoRaWAN.setChannelDRRange(ch, 0, 5); // Check status if( error == 0 ) { printf("11. Data rate range channel set OK"); } else { printf("11. Data rate range channel set error = %d\n", error); } } ////////////////////////////////////////////// // 12. Set Data rate range for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (int ch = 0; ch <= 7; ch++) { error = LoRaWAN.setChannelStatus(ch, (char*)"on"); // Check status if( error == 0 ) { printf("12. Channel status set OK"); } else { printf("12. Channel status set error = %d\n", error); } } ////////////////////////////////////////////// // 13. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { printf("13. Save configuration OK\n"); } else { printf("13. Save configuration error = %d\n", error); } printf("------------------------------------\n"); printf("Now the LoRaWAN module is ready for\n"); printf("joining networks and send messages.\n"); printf("Please check the next examples...\n"); printf("------------------------------------\n"); } void loop() { // do nothing } ////////////////////////////////////////////// // Main loop setup() and loop() declarations ////////////////////////////////////////////// int main (){ setup(); while(1){ loop(); } return (0); } //////////////////////////////////////////////
www.libelium.com/development/waspmote/examples/lorawan-01-configure
Example of LoRaWAN 900 configuration:
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the module * and all general settings related to back-end registration * process. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 1.2 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include <Wire.h> // Cooking API libraries #include <arduinoUART.h> #include <arduinoUtils.h> // LoRaWAN library #include <arduinoLoRaWAN.h> // Pin definition for LoRaWAN module error LED: const int error_led = 13; ////////////////////////////////////////////// uint8_t socket = SOCKET1; ////////////////////////////////////////////// // Device parameters for Back-End registration //////////////////////////////////////////////////////////// char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; char APP_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // variable uint8_t error; void setup() { //LoRaWAN example - Module configuration pinMode(error_led, OUTPUT); digitalWrite(error_led, LOW); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Reset to factory default values ////////////////////////////////////////////// error = LoRaWAN.factoryReset(); // Check status if( error == 0 ) { //2. Reset to factory default values OK digitalWrite(error_led, LOW); } else { //2. Reset to factory error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 3. Set/Get Device EUI ////////////////////////////////////////////// // Set Device EUI error = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( error == 0 ) { //3.1. Set Device EUI OK digitalWrite(error_led, LOW); } else { //3.1. Set Device EUI error digitalWrite(error_led, HIGH); } // Get Device EUI error = LoRaWAN.getDeviceEUI(); // Check status if( error == 0 ) { //3.2. Get Device EUI OK. //Device EUI in LoRaWAN._devEUI digitalWrite(error_led, LOW); } else { //3.2. Get Device EUI error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 4. Set/Get Device Address ////////////////////////////////////////////// // Set Device Address error = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( error == 0 ) { //4.1. Set Device address OK digitalWrite(error_led, LOW); } else { //4.1. Set Device address error digitalWrite(error_led, HIGH); } // Get Device Address error = LoRaWAN.getDeviceAddr(); // Check status if( error == 0 ) { //4.2. Get Device address OK. //Device address in LoRaWAN._devAddr digitalWrite(error_led, LOW); } else { //4.2. Get Device address error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 5. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { //5. Set Network Session Key OK digitalWrite(error_led, LOW); } else { //5. Set Network Session Key error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 6. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { //6. Set Application Session Key OK digitalWrite(error_led, LOW); } else { //6. Set Application Session Key error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 7. Set retransmissions for uplink confirmed packet ////////////////////////////////////////////// // set retries error = LoRaWAN.setRetries(7); // Check status if( error == 0 ) { //7.1. Set Retransmissions for uplink confirmed packet OK digitalWrite(error_led, LOW); } else { //7.1. Set Retransmissions for uplink confirmed packet error digitalWrite(error_led, HIGH); } // Get retries error = LoRaWAN.getRetries(); // Check status if( error == 0 ) { //7.2. Get Retransmissions for uplink confirmed packet OK. //TX retries in LoRaWAN._retries digitalWrite(error_led, LOW); } else { //7.2. Get Retransmissions for uplink confirmed packet error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 8. Set application key ////////////////////////////////////////////// error = LoRaWAN.setAppKey(APP_KEY); // Check status if( error == 0 ) { //8. Application key set OK digitalWrite(error_led, LOW); } else { //8. Application key set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 9. For 900MHz US bands with gateways limited // to 8 channels, disable the unavailable channels ////////////////////////////////////////////// for (int ch = 8; ch <= 64; ch++) error |= LoRaWAN.setChannelStatus(ch, "off"); // Check status if( error == 0 ) { //9. setup channel correctly digitalWrite(error_led, LOW); } else { //9. error in setup channel digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 10. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { //10. Save configuration OK digitalWrite(error_led, LOW); } else { //10. Save configuration error digitalWrite(error_led, HIGH); } //------------------------------------ //Now the LoRaWAN module is ready for //joining networks and send messages. //Please check the next examples... //------------------------------------ } void loop() { // do nothing }
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the module * and all general settings related to back-end registration * process. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 0.4 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include "arduPiLoRaWAN.h" ////////////////////////////////////////////// uint8_t sock = SOCKET0; ////////////////////////////////////////////// // Device parameters for Back-End registration //////////////////////////////////////////////////////////// char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; char APP_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // variable uint8_t error; void setup() { printf("LoRaWAN example - Module configuration\n"); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(sock); // Check status if( error == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n", error); } ////////////////////////////////////////////// // 2. Reset to factory default values ////////////////////////////////////////////// error = LoRaWAN.factoryReset(); // Check status if( error == 0 ) { printf("2. Reset to factory default values OK\n"); } else { printf("2. Reset to factory error = %d\n", error); } ////////////////////////////////////////////// // 3. Set/Get Device EUI ////////////////////////////////////////////// // Set Device EUI error = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( error == 0 ) { printf("3.1. Set Device EUI OK\n"); } else { printf("3.1. Set Device EUI error = %d\n", error); } // Get Device EUI error = LoRaWAN.getDeviceEUI(); // Check status if( error == 0 ) { printf("3.2. Get Device EUI OK. "); printf("Device EUI: %s\n",LoRaWAN._devEUI); } else { printf("3.2. Get Device EUI error = %d\n", error); } ////////////////////////////////////////////// // 4. Set/Get Device Address ////////////////////////////////////////////// // Set Device Address error = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( error == 0 ) { printf("4.1. Set Device address OK\n"); } else { printf("4.1. Set Device address error = %d\n", error); } // Get Device Address error = LoRaWAN.getDeviceAddr(); // Check status if( error == 0 ) { printf("4.2. Get Device address OK. "); printf("Device address: %s\n", LoRaWAN._devAddr); } else { printf("4.2. Get Device address error = %d\n", error); } ////////////////////////////////////////////// // 5. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { printf("5. Set Network Session Key OK\n"); } else { printf("5. Set Network Session Key error = %d\n", error); } ////////////////////////////////////////////// // 6. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { printf("6. Set Application Session Key OK\n"); } else { printf("6. Set Application Session Key error = %d\n", error); } ////////////////////////////////////////////// // 7. Set retransmissions for uplink confirmed packet ////////////////////////////////////////////// // set retries error = LoRaWAN.setRetries(7); // Check status if( error == 0 ) { printf("7.1. Set Retransmissions for uplink confirmed packet OK\n"); } else { printf("7.1. Set Retransmissions for uplink confirmed packet error = %d\n", error); } // Get retries error = LoRaWAN.getRetries(); // Check status if( error == 0 ) { printf("7.2. Get Retransmissions for uplink confirmed packet OK. \n"); printf("TX retries: %d\n", LoRaWAN._retries); } else { printf("7.2. Get Retransmissions for uplink confirmed packet error = %d\n", error); } ////////////////////////////////////////////// // 8. Set application key ////////////////////////////////////////////// error = LoRaWAN.setAppKey(APP_KEY); // Check status if( error == 0 ) { printf("8. Application key set OK\n"); } else { printf("8. Application key set error = %d\n", error); } ////////////////////////////////////////////// // 9. For 900MHz US bands with gateways limited // to 8 channels, disable the unavailable channels ////////////////////////////////////////////// for (int ch = 8; ch <= 64; ch++) { error = LoRaWAN.setChannelStatus(ch, (char*)"off"); // Check status if( error == 0 ) { printf("9. Channel %d status set OK\n", ch); } else { printf("9. Channel %d status set error = %d\n", ch, error); } } ////////////////////////////////////////////// // 10. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { printf("10. Save configuration OK\n"); } else { printf("10. Save configuration error = %d\n", error); } printf("------------------------------------\n"); printf("Now the LoRaWAN module is ready for\n"); printf("joining networks and send messages.\n"); printf("Please check the next examples...\n"); printf("------------------------------------\n"); } void loop() { // do nothing } ////////////////////////////////////////////// // Main loop setup() and loop() declarations ////////////////////////////////////////////// int main (){ setup(); while(1){ loop(); } return (0); } //////////////////////////////////////////////
www.libelium.com/development/waspmote/examples/lorawan-01-configure
The getEUI() function allows the user to query the preprogrammed EUI node address from the module. The preprogrammed EUI node address is a read-only value and cannot be changed or erased. It is a global unique 64-bit identifier.
Example of use:
{ LoRaWAN.getEUI(); }
Related variable:
The resetMacConfig() function allows the user to reset the software LoRaWAN stack and initialize it with the parameters for the selected band: 433 MHz, 868 MHz or 900MHz.
The getBand() function allows the user to query the current frequency band of operation. This function is not available for the LoRaWAN 900 module since it can only work in the 902-928 MHz ISM band. The attribute _band permits to access to the settings of the module. The default value is 868. This value can be saved into the module's memory with the saveConfig() function due to keep the band configuration after a reboot. Value can be either 433 or 868.
Example of use:
{ LoRaWAN.resetMacConfig(433); LoRaWAN.getBand(); }
Related variable:
LoRaWAN._band → Stores the current frequency band of operation
The sendUnconfirmed() function allows the user to transmit data on a specified port number. This function will not expect any acknowledgement back from the server. It is necessary to indicate the port to use. The range is from 1 to 223. The second input of the sending function is the payload of the packet to send. The payload must be specified in hexadecimal format as a string. The length of the payload capable of being transmitted is dependent upon the set data rate. Please refer to the LoRaWAN Specification for the payload length values.
Example of use:
{ uint8_t port = 1; char data[] = “010203040506070809”; LoRaWAN.sendUnconfirmed( port, data); }
Example of sending a packet without ACK:
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the module * and send packets to a LoRaWAN gateway without ACK after join a network * using ABP * * Copyright (C) 2016 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 1.2 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include <Wire.h> // Cooking API libraries #include <arduinoUART.h> #include <arduinoUtils.h> // LoRaWAN library #include <arduinoLoRaWAN.h> // Pin definition for LoRaWAN module error LED: const int error_led = 13; ////////////////////////////////////////////// uint8_t socket = SOCKET1; ////////////////////////////////////////////// // Device parameters for Back-End registration //////////////////////////////////////////////////////////// char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // Define port to use in Back-End: from 1 to 223 uint8_t PORT = 3; // Define data payload to send (maximum is up to data rate) char data[] = "0102030405060708090A0B0C0D0E0F"; // variable uint8_t error; void setup() { //LoRaWAN example - Send Unconfirmed packets (no ACK) pinMode(error_led, OUTPUT); digitalWrite(error_led, LOW); //------------------------------------ //Module configuration //------------------------------------ ////////////////////////////////////////////// // 1. Switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Set Device EUI ////////////////////////////////////////////// error = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( error == 0 ) { //2. Device EUI set OK digitalWrite(error_led, LOW); } else { //2. Device EUI set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 3. Set Device Address ////////////////////////////////////////////// error = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( error == 0 ) { //3. Device address set OK digitalWrite(error_led, LOW); } else { //3. Device address set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 4. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { //"4. Network Session Key set OK")); digitalWrite(error_led, LOW); } else { //4. Network Session Key set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 5. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { //5. Application Session Key set OK digitalWrite(error_led, LOW); } else { //5. Application Session Key set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 6. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { //6. Save configuration OK digitalWrite(error_led, LOW); } else { //6. Save configuration error digitalWrite(error_led, HIGH); } //------------------------------------ //Module configured //------------------------------------ LoRaWAN.getDeviceEUI(); //Device EUI in LoRaWAN._devEUI LoRaWAN.getDeviceAddr(); //Device Address in LoRaWAN._devAddr } void loop() { ////////////////////////////////////////////// // 1. Switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Join network ////////////////////////////////////////////// error = LoRaWAN.joinABP(); // Check status if( error == 0 ) { //2. Join network OK digitalWrite(error_led, LOW); ////////////////////////////////////////////// // 3. Send unconfirmed packet ////////////////////////////////////////////// error = LoRaWAN.sendUnconfirmed( PORT, data); // Error messages: /* * '6' : Module hasn't joined a network * '5' : Sending error * '4' : Error with data length * '2' : Module didn't response * '1' : Module communication error */ // Check status if( error == 0 ) { //3. Send Unconfirmed packet OK if (LoRaWAN._dataReceived == true) { //There's data on //port number: LoRaWAN._port //and Data in: LoRaWAN._data digitalWrite(error_led, LOW); } } else { //3. Send Unconfirmed packet error digitalWrite(error_led, HIGH); } } else { //2. Join network error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 4. Switch off ////////////////////////////////////////////// error = LoRaWAN.OFF(socket); // Check status if( error == 0 ) { //4. Switch OFF OK digitalWrite(error_led, LOW); } else { //4. Switch OFF error digitalWrite(error_led, HIGH); } delay(10000); }
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the module * and send packets to a LoRaWAN gateway without ACK * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 0.3 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include "arduPiLoRaWAN.h" // socket to use ////////////////////////////////////////////// uint8_t sock = SOCKET0; ////////////////////////////////////////////// // Device parameters for Back-End registration //////////////////////////////////////////////////////////// char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // Define port to use in Back-End: from 1 to 223 uint8_t PORT = 3; // Define data payload to send (maximum is up to data rate) char data[] = "0102030405060708090A0B0C0D0E0F"; // variable uint8_t error; void setup() { printf("LoRaWAN example - Send Unconfirmed packets (no ACK)\n"); printf("------------------------------------\n"); printf("Module configuration\n"); printf("------------------------------------\n\n"); ////////////////////////////////////////////// // 1. Switch on ////////////////////////////////////////////// error = LoRaWAN.ON(sock); // Check status if( error == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n", error); } ////////////////////////////////////////////// // 2. Set Device EUI ////////////////////////////////////////////// error = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( error == 0 ) { printf("2. Device EUI set OK\n"); } else { printf("2. Device EUI set error = %d\n", error); } ////////////////////////////////////////////// // 3. Set Device Address ////////////////////////////////////////////// error = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( error == 0 ) { printf("3. Device address set OK\n"); } else { printf("3. Device address set error = %d\n", error); } ////////////////////////////////////////////// // 4. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { printf("4. Network Session Key set OK\n"); } else { printf("4. Network Session Key set error = %d\n",error); } ////////////////////////////////////////////// // 5. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { printf("5. Application Session Key set OK\n"); } else { printf("5. Application Session Key set error = %d\n", error); } ////////////////////////////////////////////// // 6. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { printf("6. Save configuration OK\n"); } else { printf("6. Save configuration error = %d\n", error); } printf("\n------------------------------------\n"); printf("Module configured\n"); printf("------------------------------------\n\n"); LoRaWAN.getDeviceEUI(); printf("Device EUI: %s\n", LoRaWAN._devEUI); LoRaWAN.getDeviceAddr(); printf("Device Address: %s\n\n", LoRaWAN._devAddr); } void loop() { ////////////////////////////////////////////// // 1. Switch on ////////////////////////////////////////////// error = LoRaWAN.ON(sock); // Check status if( error == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n", error); } ////////////////////////////////////////////// // 2. Join network ////////////////////////////////////////////// error = LoRaWAN.joinABP(); // Check status if( error == 0 ) { printf("2. Join network OK\n"); } else { printf("2. Join network error = %d\n",error); } ////////////////////////////////////////////// // 3. Send unconfirmed packet ////////////////////////////////////////////// error = LoRaWAN.sendUnconfirmed( PORT, data); // Check status if( error == 0 ) { printf("3. Send Unconfirmed packet OK\n"); } else { printf("3. Send Unconfirmed packet error = %d\n",error); } ////////////////////////////////////////////// // 4. Switch off ////////////////////////////////////////////// error = LoRaWAN.OFF(sock); // Check status if( error == 0 ) { printf("4. Switch OFF OK\n"); } else { printf("4. Switch OFF error = %d\n",error); } printf("\n"); delay(5000); } ////////////////////////////////////////////// // Main loop setup() and loop() declarations ////////////////////////////////////////////// int main (){ setup(); while(1){ loop(); } return (0); }
www.libelium.com/development/waspmote/examples/lorawan-02-send-unconfirmed www.libelium.com/development/waspmote/examples/lorawan-08-join-otaa-send-unconfirmed
The sendConfirmed() function allows the user to transmit data on a specified port number. This function will expect an acknowledgement from the server. If no ACK is received, the message will be retransmitted automatically up to a maximum of times specified by the setRetries() function. It is necessary to indicate the port to use. The range is from 1 to 223. The second input of the sending function is the payload of the packet to send. The payload must be specified in hexadecimal format as a string. The length of the payload capable of being transmitted is dependent upon the set data rate. Please refer to the LoRaWAN Specification for the payload length values.
Example of use:
{ uint8_t port = 1; char data[] = “010203040506070809”; LoRaWAN.sendConfirmed( port, data); }
Example of sending a packet with ACK:
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the module * and all general settings related to back-end registration * process. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 1.2 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include <Wire.h> // Cooking API libraries #include <arduinoUART.h> #include <arduinoUtils.h> // LoRaWAN library #include <arduinoLoRaWAN.h> // Pin definition for LoRaWAN module error LED: const int error_led = 13; ////////////////////////////////////////////// uint8_t socket = SOCKET1; ////////////////////////////////////////////// // Device parameters for Back-End registration //////////////////////////////////////////////////////////// char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // Define port to use in Back-End: from 1 to 223 uint8_t PORT = 3; // Define data payload to send (maximum is up to data rate) char data[] = "0102030405060708090A0B0C0D0E0F"; // variable uint8_t error; void setup() { //LoRaWAN example - Send Confirmed packets (with ACK) pinMode(error_led, OUTPUT); digitalWrite(error_led, LOW); //------------------------------------ //Module configuration //------------------------------------ ////////////////////////////////////////////// // 1. Switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Set Device EUI ////////////////////////////////////////////// error = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( error == 0 ) { //2. Device EUI set OK digitalWrite(error_led, LOW); } else { //2. Device EUI set error digitalWrite(error_led, LOW); } ////////////////////////////////////////////// // 3. Set Device Address ////////////////////////////////////////////// error = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( error == 0 ) { //3. Device address set OK digitalWrite(error_led, LOW); } else { //3. Device address set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 4. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { //4. Network Session Key set OK digitalWrite(error_led, LOW); } else { //4. Network Session Key set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 5. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { //5. Application Session Key set OK digitalWrite(error_led, LOW); } else { //5. Application Session Key set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 6. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { //6. Save configuration OK digitalWrite(error_led, LOW); } else { //6. Save configuration error digitalWrite(error_led, HIGH); } //------------------------------------ //Module configured //------------------------------------ LoRaWAN.getDeviceEUI(); //Device EUI in LoRaWAN._devEUI LoRaWAN.getDeviceAddr(); //Device Addres in LoRaWAN._devAddr } void loop() { ////////////////////////////////////////////// // 1. Switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Join network ////////////////////////////////////////////// error = LoRaWAN.joinABP(); // Check status if( error == 0 ) { //2. Join network OK digitalWrite(error_led, LOW); ////////////////////////////////////////////// // 3. Send unconfirmed packet ////////////////////////////////////////////// error = LoRaWAN.sendConfirmed( PORT, data); // Error messages: /* * '6' : Module hasn't joined a network * '5' : Sending error * '4' : Error with data length * '2' : Module didn't response * '1' : Module communication error */ // Check status if( error == 0 ) { //3. Send Unconfirmed packet OK if (LoRaWAN._dataReceived == true) { //There's data on //port number: LoRaWAN._port //and Data in: LoRaWAN._data digitalWrite(error_led, LOW); } } else { //3. Send Confirmed packet error digitalWrite(error_led, HIGH); } } else { //2. Join network error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 4. Switch off ////////////////////////////////////////////// error = LoRaWAN.OFF(socket); // Check status if( error == 0 ) { //4. Switch OFF OK digitalWrite(error_led, LOW); } else { //4. Switch OFF error digitalWrite(error_led, HIGH); } delay(10000); }
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the module and * send packets to a LoRaWAN gateway with acknowledgement. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 0.3 * Design: David Gascon * Implementation: Luismi Marti, Rubén Martín */ #include "arduPiLoRaWAN.h" // socket to use ////////////////////////////////////////////// uint8_t sock = SOCKET0; ////////////////////////////////////////////// // Device parameters for Back-End registration //////////////////////////////////////////////////////////// char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // Define port to use in Back-End: from 1 to 223 uint8_t PORT = 3; // Define data payload to send (maximum is up to data rate) char data[] = "0102030405060708090A0B0C0D0E0F"; // variable uint8_t error; void setup() { printf("LoRaWAN example - Send Confirmed packets (with ACK)\n"); printf("------------------------------------\n"); printf("Module configuration\n"); printf("------------------------------------\n\n"); ////////////////////////////////////////////// // 1. Switch on ////////////////////////////////////////////// error = LoRaWAN.ON(sock); // Check status if( error == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n", error); } ////////////////////////////////////////////// // 2. Set Device EUI ////////////////////////////////////////////// error = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( error == 0 ) { printf("2. Device EUI set OK\n"); } else { printf("2. Device EUI set error = %d\n", error); } ////////////////////////////////////////////// // 3. Set Device Address ////////////////////////////////////////////// error = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( error == 0 ) { printf("3. Device address set OK\n"); } else { printf("3. Device address set error = %d\n",error); } ////////////////////////////////////////////// // 4. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { printf("4. Network Session Key set OK\n"); } else { printf("4. Network Session Key set error = %d\n", error); } ////////////////////////////////////////////// // 5. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { printf("5. Application Session Key set OK\n"); } else { printf("5. Application Session Key set error = %d\n", error); } ////////////////////////////////////////////// // 6. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { printf("6. Save configuration OK\n"); } else { printf("6. Save configuration error = %d\n", error); } printf("\n------------------------------------\n"); printf("Module configured\n"); printf("------------------------------------\n\n"); LoRaWAN.getDeviceEUI(); printf("Device EUI: %s ",LoRaWAN._devEUI); LoRaWAN.getDeviceAddr(); printf("Device Address: %s\n\n",LoRaWAN._devAddr); } void loop() { ////////////////////////////////////////////// // 1. Switch on ////////////////////////////////////////////// error = LoRaWAN.ON(sock); // Check status if( error == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n", error); } ////////////////////////////////////////////// // 2. Join network ////////////////////////////////////////////// error = LoRaWAN.joinABP(); // Check status if( error == 0 ) { printf("2. Join network OK\n"); } else { printf("2. Join network error = %d\n", error); } ////////////////////////////////////////////// // 3. Send unconfirmed packet ////////////////////////////////////////////// error = LoRaWAN.sendConfirmed( PORT, data); // Check status if( error == 0 ) { printf("3. Send Confirmed packet OK\n"); } else { printf("3. Send Confirmed packet error = %d\n", error); } ////////////////////////////////////////////// // 4. Switch off ////////////////////////////////////////////// error = LoRaWAN.OFF(sock); // Check status if( error == 0 ) { printf("4. Switch OFF OK\n"); } else { printf("4. Switch OFF error = %d\n",error); } printf("\n"); delay(10000); } ////////////////////////////////////////////// // Main loop setup() and loop() declarations ////////////////////////////////////////////// int main (){ setup(); while(1){ loop(); } return (0); }
www.libelium.com/development/waspmote/examples/lorawan-03-send-confirmed www.libelium.com/development/waspmote/examples/lorawan-09-join-otaa-send-confirmed
Note that not every back-end is able to send data to end devices. The back-ends which are able to perform data downlink use the ACK process to send a special ACK frame containing data. So once the user programs a downlink process, this downlink data will be received by the target module the next time it performs a transmission. Note that not every back-end is able to send data to end devices. The back-ends which are able to perform data downlink use the ACK process to send a special ACK frame containing data. So once the user programs a downlink process, this downlink data will be received by the target module the next time it performs a transmission.
There is no specific function to receive data from back-ends in this library. The sendUnconfirmed() and the sendConfirmed() functions check if any special ACK is received and store data if any has been received. In case data has been received, _dataReceived flag will be set to true.
Related variable:
LoRaWAN._port → Stores the port used by the back-ends to send data
LoRaWAN._data → Stores the received data
LoRaWAN._dataReceived → Data received flag
Before sending packets to a gateway, the node must join a network first. The joinABP() function allows the user to attempt joining the network using the Activation By Personalization mode (ABP). The joinOTAA() function allows the user to attempt joining the network using the Over the Air Activation mode (OTAA). Before joining the network, the specific parameters for activation should be configured depending on the joining procedure.
Before joining the network, the specific parameters for activation should be configured: device EUI, device address, network session key and application session key.
Example of use:
{ LoRaWAN.joinABP(); }
Before joining the network, the specific parameters for activation should be configured: device EUI, application EUI and application key.
{ LoRaWAN.joinOTAA(); }
The saveConfig() function allows the user to save LoRaWAN Class A protocol configuration parameters to the module's non-volatile memory. This function must be issued after the configuration parameters have been appropriately set.
The LoRaWAN Class A protocol configuration savable parameters are:
There are some exceptions for the LoRaWAN 900 module, it does not save:
Example of use:
{ LoRaWAN.saveConfig(); }
The macResume() function allows the user to enable LoRaWAN mode. After switching on the module it is not mandatory to call this function because the default mode upon reboot is LoRaWAN mode. However, if P2P mode was previously set and the user needs to switch back to LoRaWAN mode, then this function must be called.
Example of use:
{ LoRaWAN.macResume(); }
The setDeviceEUI() function allows the user to set the 64-bit hexadecimal number representing the device EUI. There are two function prototypes which are explained below:
The getDeviceEUI() function allows the user to query the device EUI which was previously set by the user. The attribute _devEUI permits to access to the settings of the module. The default value is 0000000000000000.
Depending on the network to join, it is needed to configure a random device EUI or a fixed device EUI provided by the back-end. This matter relies on the registering process for new devices in each back-end.
For further information please go to “LoRaWAN back-ends” chapter.
Example for preprogrammed EUI:
{ LoRaWAN.setDeviceEUI(); LoRaWAN.getDeviceEUI(); }
Example for user-provided device EUI:
{ LoRaWAN.setDeviceEUI(“0102030405060708”); LoRaWAN.getDeviceEUI(); }
Related variable:
LoRaWAN._devEUI → Stores the previously set device EUI
The setDeviceAddr() function allows the user to set the 32-bit hexadecimal number representing the device address. This address must be unique to the current network. There are two function prototypes which are explained below:
The getDeviceAddr() function allows the user to query the device address which was previously set by the user. The attribute _devAddr permits to access to the settings of the module. The range goes from 00000000 to FFFFFFFF. The default value is 00000000.
Depending on the network to join, it is possible configure a random device address or a fixed device address. This matter depends on the back-end and the registering process for new devices. For further information please go to “LoRaWAN back-ends” chapter.
Example for using the preprogrammed EUI:
{ LoRaWAN.setDeviceAddr(); LoRaWAN.getDeviceAddr(); }
Example for user-provided device address:
{ LoRaWAN.setDeviceAddr(“01020304”); LoRaWAN.getDeviceAddr(); }
The setAppSessionKey() function allows the user to set the 128-bit hexadecimal number representing the application session key.
All payloads are encrypted using an AES algorithm with a 128-bit secret key, the Application Session Key. Each end-device has its own unique Application Session Key only known by the end-device and the application server.
The attribute _appSKey stores the application session key previously set by the user. The range goes from 00000000000000000000000000000000 to FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.
{ LoRaWAN.setAppSessionKey(“00102030405060708090A0B0C0D0E0F”); }
Related variable:
LoRaWAN._appSKey → Stores the previously set application session key
The setNwkSessionKey() function allows the user to set the 128-bit hexadecimal number representing the network session key. The network session key is used by both the network server and the end-device to calculate and verify the message integrity code. It is further used to encrypt and decrypt the payload field of a MAC-only data messages.
All frames contain a 32-bit cryptographic Message Integrity Check (MIC) signature computed using the AES algorithm with a 128-bit secret key, the Network Session Key. Each end-device has its own Network Session Key only known by the end-device and the network server.
The attribute _nwkSKey stores the network session key previously set by the user. The range goes from 00000000000000000000000000000000 to FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.
Example os use:
{ LoRaWAN.setNwkSessionKey(“00102030405060708090A0B0C0D0E0F”); }
Related variable:
LoRaWAN._nwkSKey → Stores the previously set network session key
The setAppKey() function allows the user to set the 128-bit hexadecimal number representing the application key. Whenever an end-device joins a network via OTAA, the Application Key is used to derive the session keys, Network Session Key and Application Session Key, which are specific for that end-device to encrypt and verify network communication and application data.
The attribute _appKey stores the application session key previously set by the user. The range goes from 00000000000000000000000000000000 to FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.
Example of use:
{ LoRaWAN.setAppKey(“00102030405060708090A0B0C0D0E0F”); }
Related variable:
LoRaWAN._appKey → Stores the previously set application session key
The setPower() function allows the user to set the output power to be used on the next transmissions.
The getPower() function allows the user to query the device power index which was previously set by the user. The attribute _powerIndex permits to access to the settings of the module. The range goes from 0 to 5 for the 433 MHz frequency band and from 1 to 5 for the 868 MHz frequency band. LoRaWAN 900 power index values can be: 5, 7, 8, 9 or 10.
Example of use:
{ LoRaWAN.setPower(1); LoRaWAN.getPower(); }
Related variable:
LoRaWAN._powerIndex → Stores the previously set power
Example of setting power level:
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the power level * LoRaWAN interface: * 900/868 MHz 433 MHz * 0: N/A 10 dBm * 1: 14 dBm 7 dBm * 2: 11 dBm 4 dBm * 3: 8 dBm 1 dBm * 4: 5 dBm -2 dBm * 5: 2 dBm -5 dBm * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 1.2 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include <Wire.h> // Cooking API libraries #include <arduinoUART.h> #include <arduinoUtils.h> // LoRaWAN library #include <arduinoLoRaWAN.h> // Pin definition for LoRaWAN module error LED: const int error_led = 13; ////////////////////////////////////////////// uint8_t socket = SOCKET1; ////////////////////////////////////////////// // variable uint8_t error; void setup() { //LoRaWAN example - Power configuration pinMode(error_led, OUTPUT); digitalWrite(error_led, LOW); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Set Power level ////////////////////////////////////////////// error = LoRaWAN.setPower(1); // Check status if( error == 0 ) { //2. Power level set OK digitalWrite(error_led, LOW); } else { //2. Power level set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 3. Get Device EUI ////////////////////////////////////////////// error = LoRaWAN.getPower(); // Check status if( error == 0 ) { //3. Power level get OK //Power index in LoRaWAN._powerIndex digitalWrite(error_led, LOW); } else { //3. Power level set error digitalWrite(error_led, HIGH); } //------------------------------------ //Keep in mind the power setting cannot //be saved in the module's memory. Every //time the module is powered on, the user //must set the parameter again //------------------------------------ } void loop() { }
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the power level * LoRaWAN interface: * 868 MHz 433 MHz * 0: N/A 10 dBm * 1: 14 dBm 7 dBm * 2: 11 dBm 4 dBm * 3: 8 dBm 1 dBm * 4: 5 dBm -2 dBm * 5: 2 dBm -5 dBm * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 0.3 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include "arduPiLoRaWAN.h" // socket to use ////////////////////////////////////////////// uint8_t sock = SOCKET0; ////////////////////////////////////////////// // variable uint8_t error; void setup() { printf("LoRaWAN example - Power configuration\n"); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(sock); // Check status if( error == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n", error); } ////////////////////////////////////////////// // 2. Set Power level ////////////////////////////////////////////// error = LoRaWAN.setPower(1); // Check status if( error == 0 ) { printf("2. Power level set OK\n"); } else { printf("2. Power level set error = %d\n", error); } ////////////////////////////////////////////// // 3. Get Device EUI ////////////////////////////////////////////// error = LoRaWAN.getPower(); // Check status if( error == 0 ) { printf("3. Power level get OK.\n"); printf("Power index: %d\n",LoRaWAN._powerIndex); } else { printf("3. Power level set error = %d\n", error); } ////////////////////////////////////////////// // 4. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { printf("4. Save configuration OK\n"); } else { printf("4. Save configuration error = %d\n", error); } } void loop() { //Do nothing } ////////////////////////////////////////////// // Main loop setup() and loop() declarations ////////////////////////////////////////////// int main (){ setup(); while(1){ loop(); } return (0); }
www.libelium.com/development/waspmote/examples/lorawan-04-power-level
The setADR() function allows the user to enable or disable the adaptive data rate (ADR). The server is informed about the status of the module's ADR in every uplink frame it receives from ADR field in uplink data packet. If ADR is enabled, the server will optimize the data rate and the transmission power based on the information collected from the network: the RSSI / SNR of the last received packets.
The getADR() function allows the user to query the device adaptive data rate status. The attribute _adr permits to access to the settings of the module. This attribute is set to 'true' if ADR is enabled or 'false' if ADR is disabled.
Example of use:
{ LoRaWAN.setADR(“on”); LoRaWAN.setADR(“off”); LoRaWAN.getADR(); }
Related Variable:
LoRaWAN._adr → Stores the previously set ADR status
Example of setting adaptive data rate:
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to enable / disable the * adaptive data rate. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 1.2 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include <Wire.h> // Cooking API libraries #include <arduinoUART.h> #include <arduinoUtils.h> // LoRaWAN library #include <arduinoLoRaWAN.h> // Pin definition for LoRaWAN module error LED: const int error_led = 13; ////////////////////////////////////////////// uint8_t socket = SOCKET1; ////////////////////////////////////////////// // variable uint8_t error; void setup() { //LoRaWAN example - Data Rate configuration pinMode(error_led, OUTPUT); digitalWrite(error_led, LOW); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Enable Adaptive Data Rate (ADR) ////////////////////////////////////////////// error = LoRaWAN.setADR("on"); // Check status if( error == 0 ) { //2. Adaptive Data Rate enabled OK. //ADR in LoRaWAN._adr digitalWrite(error_led, LOW); } else { //2. Enable data rate error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 3. Disable Adaptive Data Rate (ADR) ////////////////////////////////////////////// error = LoRaWAN.setADR("off"); // Check status if( error == 0 ) { //3. Adaptive Data Rate disabled OK. //ADR in LoRaWAN._adr digitalWrite(error_led, LOW); } else { //3. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 4. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { //4. Save configuration OK digitalWrite(error_led, LOW); } else { //4. Save configuration error digitalWrite(error_led, HIGH); } } void loop() { }
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to enable / disable the * adaptive data rate. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 0.3 * Design: David Gascon * Implementation: Luismi Marti, Rubén Martín */ #include "arduPiLoRaWAN.h" // socket to use ////////////////////////////////////////////// uint8_t sock = SOCKET0; ////////////////////////////////////////////// // variable uint8_t error; void setup() { printf("LoRaWAN example - Data Rate configuration\n"); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(sock); // Check status if( error == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n", error); } ////////////////////////////////////////////// // 2. Enable Adaptive Data Rate (ADR) ////////////////////////////////////////////// error = LoRaWAN.setADR((char*)"on"); // Check status if( error == 0 ) { printf("2. Adaptive Data Rate enabled OK. "); printf("ADR: %d\n", LoRaWAN._adr); } else { printf("2. Enable data rate error = %d\n", error); } ////////////////////////////////////////////// // 3. Disable Adaptive Data Rate (ADR) ////////////////////////////////////////////// error = LoRaWAN.setADR((char*)"off"); // Check status if( error == 0 ) { printf("3. Adaptive Data Rate disabled OK. "); printf("ADR: %d\n", LoRaWAN._adr); } else { printf("3. Data rate set error = %d\n", error); } ////////////////////////////////////////////// // 4. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { printf("4. Save configuration OK\n"); } else { printf("4. Save configuration error = %d\n", error); } } void loop() { } ////////////////////////////////////////////// // Main loop setup() and loop() declarations ////////////////////////////////////////////// int main (){ setup(); while(1){ loop(); } return (0); }
www.libelium.com/development/waspmote/examples/lorawan-06-adaptive-data-rate
The setDataRate() function allows the user to set the data rate to be used for the next transmission. The following encoding is used for Data Rate (DR):
LoRa: SF12 / 125 kHz/td> | ||
LoRa: SF11 / 125 kHz | ||
LoRa: SF10 / 125 kHz/td> | ||
LoRa: SF9 / 125 kHz | ||
LoRa: SF8 / 125 kHz | ||
LoRa: SF7 / 125 kHz |
LoRa: SF10 / 125 kHz/td> | ||
LoRa: SF19 / 125 kHz | ||
LoRa: SF18 / 125 kHz/td> | ||
LoRa: SF7 / 125 kHz | ||
LoRa: SF8 / 500 kHz |
The getDataRate() function allows the user to query the device data rate. The attribute _dataRate permits to access to the settings of the module.
Example of use:
{ LoRaWAN.setDatarate(0); LoRaWAN.getDataRate(); }
Related Variable:
LoRaWAN._dataRate → Stores the previously set data rate
Example of setting data rate:
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the data rate. * The possibilities are: * 0: SF = 12, BW = 125 kHz, BitRate = 250 bps * 1: SF = 11, BW = 125 kHz, BitRate = 440 bps * 2: SF = 10, BW = 125 kHz, BitRate = 980 bps * 3: SF = 9, BW = 125 kHz, BitRate = 1760 bps * 4: SF = 8, BW = 125 kHz, BitRate = 3125 bps * 5: SF = 7, BW = 125 kHz, BitRate = 5470 bps * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 1.2 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include <Wire.h> // Cooking API libraries #include <arduinoUART.h> #include <arduinoUtils.h> // LoRaWAN library #include <arduinoLoRaWAN.h> // Pin definition for LoRaWAN module error LED: const int error_led = 13; ////////////////////////////////////////////// uint8_t socket = SOCKET1; ////////////////////////////////////////////// // variable uint8_t error; void setup() { //LoRaWAN example - Data Rate configuration //Data Rate options: //------------------------------------------------------ // 0: SF = 12, BW = 125 kHz, BitRate = 250 bps // 1: SF = 11, BW = 125 kHz, BitRate = 440 bps // 2: SF = 10, BW = 125 kHz, BitRate = 980 bps // 3: SF = 9, BW = 125 kHz, BitRate = 1760 bps // 4: SF = 8, BW = 125 kHz, BitRate = 3125 bps // 5: SF = 7, BW = 125 kHz, BitRate = 5470 bps //------------------------------------------------------ pinMode(error_led, OUTPUT); digitalWrite(error_led, LOW); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Set Data Rate ////////////////////////////////////////////// error = LoRaWAN.setDataRate(5); // Check status if( error == 0 ) { //2. Data rate set OK digitalWrite(error_led, LOW); } else { //2. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 3. Get Data Rate ////////////////////////////////////////////// error = LoRaWAN.getDataRate(); // Check status if( error == 0 ) { //3. Data rate get OK. //Data rate index in LoRaWAN._dataRate digitalWrite(error_led, LOW); } else { //3. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 4. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { //4. Save configuration OK digitalWrite(error_led, LOW); } else { //4. Save configuration error digitalWrite(error_led, HIGH); } } void loop() { }
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the data rate. * The possibilities are: * 0: SF = 12, BW = 125 kHz, BitRate = 250 bps * 1: SF = 11, BW = 125 kHz, BitRate = 440 bps * 2: SF = 10, BW = 125 kHz, BitRate = 980 bps * 3: SF = 9, BW = 125 kHz, BitRate = 1760 bps * 4: SF = 8, BW = 125 kHz, BitRate = 3125 bps * 5: SF = 7, BW = 125 kHz, BitRate = 5470 bps * 6: SF = 7, BW = 250 kHz, BitRate = 11000 bps * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 0.3 * Design: David Gascon * Implementation: Luis M. Martinez, Ruben Martin */ #include "arduPiLoRaWAN.h" // socket to use ////////////////////////////////////////////// uint8_t sock = SOCKET0; ////////////////////////////////////////////// // variable uint8_t error; void setup() { printf("LoRaWAN example - Data Rate configuration\n"); printf("\nData Rate options:\n"); printf("------------------------------------------------------\n"); printf(" 0: SF = 12, BW = 125 kHz, BitRate = 250 bps\n"); printf(" 1: SF = 11, BW = 125 kHz, BitRate = 440 bps\n"); printf(" 2: SF = 10, BW = 125 kHz, BitRate = 980 bps\n"); printf(" 3: SF = 9, BW = 125 kHz, BitRate = 1760 bps\n"); printf(" 4: SF = 8, BW = 125 kHz, BitRate = 3125 bps\n"); printf(" 5: SF = 7, BW = 125 kHz, BitRate = 5470 bps\n"); printf(" 6: SF = 7, BW = 250 kHz, BitRate = 11000 bps\n"); printf("------------------------------------------------------\n\n"); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(sock); // Check status if( error == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n", error); } ////////////////////////////////////////////// // 2. Set Power level ////////////////////////////////////////////// error = LoRaWAN.setDataRate(0); // Check status if( error == 0 ) { printf("2. Data rate set OK\n"); } else { printf("2. Data rate set error = %d\n",error); } ////////////////////////////////////////////// // 3. Get Device EUI ////////////////////////////////////////////// error = LoRaWAN.getDataRate(); // Check status if( error == 0 ) { printf("3. Data rate get OK.\n"); printf("Data rate index: %d\n",LoRaWAN._dataRate); } else { printf("3. Data rate set error = %d\n", error); } ////////////////////////////////////////////// // 4. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { printf("4. Save configuration OK\n"); } else { printf("4. Save configuration error = %d\n", error); } } void loop() { } ////////////////////////////////////////////// // Main loop setup() and loop() declarations ////////////////////////////////////////////// int main (){ setup(); while(1){ loop(); } return (0); }
www.libelium.com/development/waspmote/examples/lorawan-05-data-rate
The setRetries() function allows the user to set the number of retransmissions to be used for an uplink confirmed packet, if no downlink acknowledgment is received from the server.
The getRetries() function allows the user to query the number of retransmissions which was previously set by the user. The attribute _retries permits to access to the settings of the module. The attribute range is from 0 to 255.
Example of use:
{ LoRaWAN.setRetries (3); LoRaWAN.getRetries (); }
Related Variable:
LoRaWAN._retries → Stores the previously set number of retransmissions
The setUpCounter() function allows the user to set the uplink frame counter that will be used for the next uplink transmission.
The getUpCounter() function allows the user to query the uplink frame counter that will be used for the next uplink transmission. The attribute _upCounter permits to access the settings of the module. The attribute range is from 0 to 4294967295.
If the back-end's sequence number check is set to strict, this uplink counter must be synchronized with the back-end uplink counter. The _upCounter is saved into the module's memory after every transmission.
Example of use:
{ LoRaWAN.setUpCounter(10); LoRaWAN.getUpCounter(); }
Related Variable:
LoRaWAN._upCounter → Stores the previously set uplink frame sequence number
The setDownCounter() function allows the user to set the downlink frame counter that will be used for the next downlink reception.
The getDownCounter() function allows the user to query the downlink frame counter that will be used for the next downlink reception. The attribute _downCounter permits to access the settings of the module. The attribute range is from 0 to 4294967295.
If the back-end check sequence number function is set to strict, this downlink counter must be synchronized with the back-end downlink counter. The _downCounter is saved into the module's memory after every reception.
Example of use:
{ LoRaWAN.setDownCounter(10); LoRaWAN.getDownCounter(); }
Related Variable:
LoRaWAN._downCounter → Stores the previously set downlink frame sequence number
The LoRaWAN 868 module has 16 channels available to be configured. The channel parameters are:
Channel 0 | Frequency (Hz) | ||
Duty cycle | |||
Data rate range | |||
Status | |||
Channel 1 | Frequency (Hz) | ||
Duty cycle | |||
Data rate range | |||
Status | |||
Channel 2 | Frequency (Hz) | ||
Duty cycle | |||
Data rate range | |||
Status | |||
Channel 3-15 | Frequency (Hz) | ||
Duty cycle | |||
Data rate range | |||
Status |
The LoRaWAN 900 module has 72 channels with a preset fixed frequency for every channel. Data rate range and channel status are the only settable parameters.
Channel 0-63 | Frequency (Hz) | |
Data rate range (min - max)/td> | ||
Status | ||
Channel 64-71 | Frequency (Hz) | |
Data rate range (min - max) | ||
Status |
Below you can see how the parameters can be configured.
The first three channels have a fixed frequency value. The rest of them can be configured in the following ranges: from 863250000 to 869750000 Hz for the 868 MHz band, and from 433050000 to 434790000 Hz for the 433 MHz band. Though frequency is not a settable parameter in LoRaWAN 900 module frequency can be queried with ranges from 902300000 to 914900000 Hz.
The setChannelFreq() function allows the user to set the operational frequency on the given channel number (from 0 to 15). The default channels (0-2) cannot be modified in terms of frequency. This function is not available for LoRaWAN 900 module because channels have a fixed frequency.
The getChannelFreq() function allows the user to query the channel frequency which was previously set by the user. This function can query channels from 0 to 15 when using LoRaWAN 868 module and channels from 0 to 71 when using LoRaWAN 900 module. The attribute _freq permits to access to the settings of the module.
Example of use:
{ LoRaWAN.setChannelFreq(3,868000000); LoRaWAN.getChannelFreq(3); }
Related Variable:
LoRaWAN._freq[n] → Stores the previously set frequency for channel 'n'
Example of channel settings configuration:
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the channels settings. * There are 16 channels. The first three of them are always preconfigured * and cannot be changed: 868.1 MHz, 868.3 MHz and 868.5 MHz. Besides other * parameters can be changed in all channels: Duty Cycle, Data rate range * and channel status. This is not supported in 900.0 MHz (RN2903) modules. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 1.2 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include <Wire.h> // Cooking API libraries #include <arduinoUART.h> #include <arduinoUtils.h> // LoRaWAN library #include <arduinoLoRaWAN.h> // Pin definition for LoRaWAN module error LED: const int error_led = 13; ////////////////////////////////////////////// uint8_t socket = SOCKET1; ////////////////////////////////////////////// // variable uint8_t error; void setup() { //LoRaWAN example - Channels configuration pinMode(error_led, OUTPUT); digitalWrite(error_led, LOW); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Set frequency for specific channel ////////////////////////////////////////////// error = LoRaWAN.setChannelFreq(3, 865000000); // Check status if( error == 0 ) { //2. Frequency set OK. //Frequency in LoRaWAN._freq[3] digitalWrite(error_led, LOW); } else { //2. Enable data rate error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 3. Set Duty Cycle for specific channel ////////////////////////////////////////////// error = LoRaWAN.setChannelDutyCycle(3, 999); // Check status if( error == 0 ) { //3. Adaptive Data Rate disabled OK. //Duty Cycle in LoRaWAN._dCycle[3] digitalWrite(error_led, LOW); } else { //3. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 4. Set Data rate range for specific channel ////////////////////////////////////////////// error = LoRaWAN.setChannelDRRange(3, 0, 2); // Check status if( error == 0 ) { //4. Data Rate range set OK. //Data Rate min in LoRaWAN._drrMin[3] //Data Rate max in LoRaWAN._drrMax[3] digitalWrite(error_led, LOW); } else { //4. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 5. Set Data rate range for specific channel ////////////////////////////////////////////// error = LoRaWAN.setChannelStatus(3, "on"); // Check status if( error == 0 ) { //5. Channel status set OK in LoRaWAN._status[3] digitalWrite(error_led, LOW); } else { //5. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 6. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { //4. Save configuration OK digitalWrite(error_led, LOW); } else { //4. Save configuration error digitalWrite(error_led, HIGH); } /////////////////////////////////////////////////////////// // show configuration for all channels available /////////////////////////////////////////////////////////// for( int i=0; i<16; i++) { LoRaWAN.getChannelFreq(i); LoRaWAN.getChannelDutyCycle(i); LoRaWAN.getChannelDRRange(i); LoRaWAN.getChannelStatus(i); //Channel: i // Freq: LoRaWAN._freq[i] // Duty cycle: LoRaWAN._dCycle[i] // DR min: LoRaWAN._drrMin[i] // DR max: LoRaWAN._drrMax[i] // Status: LoRaWAN._status[i] } } void loop() { }
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the channels settings. * There are 16 channels. The first three of them are always preconfigured * and cannot be changed: 868.1 MHz, 868.3 MHz and 868.5 MHz. Besides other * parameters can be changed in all channels: Duty Cycle, Data rate range * and channel status * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 0.3 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include "arduPiLoRaWAN.h" // socket to use ////////////////////////////////////////////// uint8_t sock = SOCKET0; ////////////////////////////////////////////// // variable uint8_t error; void setup() { printf("LoRaWAN example - Channels configuration\n"); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(sock); // Check status if( error == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n",error); } ////////////////////////////////////////////// // 2. Set frequency for specific channel ////////////////////////////////////////////// error = LoRaWAN.setChannelFreq(3, 865000000); // Check status if( error == 0 ) { printf("2. Frequency set OK. "); printf("Frequency: %u\n",LoRaWAN._freq[3]); } else { printf("2. Enable data rate error = %d\n", error); } ////////////////////////////////////////////// // 3. Set Duty Cycle for specific channel ////////////////////////////////////////////// error = LoRaWAN.setChannelDutyCycle(3, 999); // Check status if( error == 0 ) { printf("3. Adaptive Data Rate disabled OK. "); printf("Duty Cycle: %d\n", LoRaWAN._dCycle[3]); } else { printf("3. Data rate set error = %d\n", error); } ////////////////////////////////////////////// // 4. Set Data rate range for specific channel ////////////////////////////////////////////// error = LoRaWAN.setChannelDRRange(3, 0, 2); // Check status if( error == 0 ) { printf("4. Data Rate range set OK. "); printf("Data Rate min: %d",LoRaWAN._drrMin[3]); printf(". Data Rate max: %d\n", LoRaWAN._drrMax[3]); } else { printf("4. Data rate set error = %d\n", error); } ////////////////////////////////////////////// // 5. Set Data rate range for specific channel ////////////////////////////////////////////// error = LoRaWAN.setChannelStatus(3, (char*)"on"); // Check status if( error == 0 ) { printf("5. Channel status set OK: %d\n", LoRaWAN._status[3]); } else { printf("5. Data rate set error = %d\n", error); } ////////////////////////////////////////////// // 6. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { printf("4. Save configuration OK\n"); } else { printf("4. Save configuration error = %d\n", error); } /////////////////////////////////////////////////////////// // show configuration for all channels available /////////////////////////////////////////////////////////// printf("\n----------------------------\n"); for( int i=0; i<16; i++) { LoRaWAN.getChannelFreq(i); LoRaWAN.getChannelDutyCycle(i); LoRaWAN.getChannelDRRange(i); LoRaWAN.getChannelStatus(i); printf("Channel: %d\n", i); printf(" Freq: %d\n",LoRaWAN._freq[i]); printf(" Duty cycle: %d\n",LoRaWAN._dCycle[i]); printf(" DR min: %d\n",LoRaWAN._drrMin[i]); printf(" DR max: %d\n",LoRaWAN._drrMax[i]); printf(" Status: %d\n",LoRaWAN._status[i]); printf("----------------------------\n"); } } void loop() { } ////////////////////////////////////////////// // Main loop setup() and loop() declarations ////////////////////////////////////////////// int main (){ setup(); while(1){ loop(); } return (0); }
www.libelium.com/development/waspmote/examples/lorawan-07-channels-configuration
The setChannelDutyCycle() function allows the user to set the operational duty cycle on the given channel number (from 0 to 15). The duty cycle value that needs to be used as input argument can be obtained from the wanted duty cycle X (in percentage) using the following formula: duty cycle = (100/X) – 1. The default settings consider only the three default channels (0-2), and their default duty cycle is 0.33%. If a new channel is created either by the server or by the user, all the channels (including the default ones) must be updated by the user in terms of duty cycle to comply with the applicable regulations in the country. This function is not available for LoRaWAN 900 module.
The getChannelDutyCycle() function allows the user to query the channel duty cycle which was previously set by the user. The attribute _dCycle permits to access to the settings of the module. The attribute range goes from 0 to 65535. The _dCycle value that needs to be configured can be obtained from the actual duty cycle X (in percentage) using the following formula: X = 100/(_dCycle + 1). This function is not available for LoRaWAN 900 module.
Example of use:
{ LoRaWAN.setChannelDutyCycle(3,9); LoRaWAN.getChannelDutyCycle(3); }
Related Variable:
LoRaWAN._dCycle[n] → Stores the previously set duty cycle for channel 'n'
The setChannelDRRange() function allows the user to set the operational data rate range, from minimum to maximum values, for the given channel number. The range for both maximum and minimum values goes from 0 to 7.
The LoRaWAN 868 module supports data rate ranges from 0 to 7 on channels 0 to 15.
The LoRaWAN 900 module supports data rate ranges from 0 to 4 on channels 0 to 63. Channels from 64 to 71 have a fixed data rate range.
The getChannelDRRange() function allows the user to query the data rate range which was previously set by the user. The attributes to store the maximum and minimum data rates are _drrMax and _drrMin respectively. For both values the range goes from 0 to 7.
Example of use:
{ LoRaWAN.setChannelDRRange(3,0,6); LoRaWAN.getChannelDRRange(3); }
Related Variable:
LoRaWAN._drrMax[n] → Stores the previously set maximum data rate for channel 'n'
LoRaWAN._drrMin[n] → Stores the previously set minimum data rate for channel 'n'
The setChannelStatus() function allows the user to set the operation of the given channel, either ”on” or ”off”.
LoRaWAN 868 allows to configure the channel status on channels from 0 to 15.
LoRaWAN 900 allows to configure the channel status on channels from 0 to 71.
The getChannelStatus() function allows the user to query the operation channel status. The attribute _status permits to access to the settings of the module.
Example of use:
{ LoRaWAN.setChannelStatus(3,”on”); LoRaWAN.setChannelStatus(3,”off”); LoRaWAN.getChannelStatus(3); }
Related Variable:
LoRaWAN._status[n] → Stores the previously set status for channel 'n'
The getDutyCyclePrescaler() function allows the user to query the duty cycle prescaler. The value of the prescaler can be configured only by the server through use of the Duty Cycle Request frame. Upon reception of this command from the server, the duty cycle prescaler is changed for all enabled channels. The attribute _dCyclePS permits to access to the settings of the module.
Example of use:
{ LoRaWAN.getDutyCyclePrescaler(); }
Related Variable:
LoRaWAN._dCyclePS → Stores the duty cycle prescaler established by the server
The getMargin() function allows the user to query the demodulation margin as received in the last Link Check Answer frame. The attribute _margin permits to access to the settings of the module.
Example of use:
{ LoRaWAN.getMargin(); }
Related Variable:
LoRaWAN._margin → Stores the margin received in the last Link Check Answer frame
The getGatewayNumber() function allows the user to query the number of gateways that successfully received the last Link Check Request frame command, as received in the last Link Check Answer. The attribute _gwNumber permits to access to the settings of the module.
Example of use:
{ LoRaWAN.getGatewayNumber(); }
Related Variable:
LoRaWAN._gwNumber → Stores the number of gateways that received the last Link Check Request frame
The macPause() function allows the user to disable LoRaWAN mode and enable P2P mode. After power reboot, the module's default mode is LoRaWAN. So, it is mandatory to call this function in order to work with the P2P mode. After calling this function, all P2P functions explained in this section will be able to be run
Example of use:
{ LoRaWAN.macPause(); }
The sendRadio() function allows the user to transmit data using the radio transceiver. This function will not expect any acknowledgement back from the receiver. The maximum length of the frame is 255 bytes (510 ASCII digits).
Example of use:
{ char data[] = “010203040506070809”; LoRaWAN.macPause(); LoRaWAN.sendRadio(data); }
The receiveRadio() function allows the user to receive data using the radio transceiver. This function needs a timeout parameter to keep the module listening for any data. The range for this timeout input parameter is from 0 ms to 4294967295 ms. If any data frame is received, it is stored in _buffer. The length of the buffer is specified in _length. The user must keep in mind that this buffer structure is used for all functions in the API. So, the packet contents should be stored in a program buffer for being used after reception.
Example of use:
{ uint32_t time = 10000; LoRaWAN.macPause(); LoRaWAN.receiveRadio(time); }
Related Variable:
LoRaWAN._buffer→ Stores data received through radio transceiver
LoRaWAN._length→ Stores length of the data stored in _buffer
The setRadioPower() function allows the user to set the operating output power in P2P mode.
The getRadioPower() function allows the user to query the operating output power level in P2P mode which was previously set by the user. The attribute _radioPower permits to access to the settings of the module. The range of this attribute goes from -3 to 5 for the LoRaWAN 868 module.
The range of this attribute goes from 2 to 20 for the LoRaWAN 900 module.
The output power level in dBm can be consulted in the radio transceiver module datasheet, RN2483 to see about LoRaWAN 868 and RN2903 to see about LoRaWAN 900.
Example of use:
{ LoRaWAN.setRadioPower(3); LoRaWAN.getRadioPower(); }
Related Variable:
LoRaWAN._radioPower→ Stores the previously set output power level
The setRadioSF() function allows the user to set the operating spreading factor (SF) in P2P mode.
The getRadioSF() function allows the user to query the operating Spreading Factor (SF) in P2P mode which was previously set by the user. The attribute _radioSF permits to access to the settings of the module. The spreading factor can take the following values: “sf7”, “sf8”, “sf9”, “sf10”, “sf11” and “sf12”.
Example of use:
{ LoRaWAN.setRadioSF(3); LoRaWAN.getRadioSF(); }
Related Variable:
LoRaWAN._radioSF → Stores the previously set Spreading Factor
The setRadioFreqDeviation() function allows the user to set the frequency deviation during operation in P2P mode.
The getRadioFreqDeviation() function allows the user to query the operating frequency deviation which was previously set by the user. The attribute _radioFreqDev permits to access to the settings of the module. The frequency deviation range goes from 0 to 200000.
Example of use:
{ LoRaWAN.setRadioFreqDeviation(5000); LoRaWAN.getRadioFreqDeviation(); }
Related Variable:
LoRaWAN._radioFreqDev → Stores the previously set frequency deviation
The setRadioPreamble() function allows the user to set the preamble length for transmit/receive in P2P mode.
The getRadioPreamble() function allows the user to query the preamble length which was previously set by the user. The attribute _preambleLength permits to access to the settings of the module. The preamble length range goes from 0 to 65535.
Example of use:
{ LoRaWAN.setRadioPreamble(8); LoRaWAN.getRadioPreamble(); }
Related Variable:
LoRaWAN._preambleLength → Stores the previously set preamble length
The setRadioCRC() function allows the user to set the Cyclic Redundancy Check (CRC) header status for transmit/receive in P2P mode.
The getRadioCRC() function allows the user to query the CRC status which was previously set by the user. The attribute _crcStatus permits to access to the settings of the module. This attribute is set to "on" if CRC is enabled or "off" if CRC is disabled.
Example of use:
{ LoRaWAN.setRadioCRC(“on”); LoRaWAN.setRadioCRC(“off”); LoRaWAN.getRadioCRC(); }
Related Variable:
LoRaWAN._crcStatus → Stores the previously set CRC status
The setRadioCR() function allows the user to set the Coding Rate (CR) for communications in P2P mode.
The getRadioCR() function allows the user to query the CR which was previously set by the user. The attribute _radioCR permits to access to the settings of the module. The CR can take the following values: “4/5”, “4/6”, “4/7” and “4/8”.
Example of use:
{ LoRaWAN.setRadioCR(“4/5”); LoRaWAN.getRadioCR(); }
Related Variable:
LoRaWAN._radioCR → Stores the previously set coding rate
The setRadioBandwidth() function allows the user to set the operating radio bandwidth (BW) for LoRa operation.
The getRadioBandwidth() function allows the user to query radio bandwidth which was previously set by the user. The attribute _radioBW permits to access to the settings of the module. The radio bandwidth can take the following values: 125 kHz, 250 kHz and 500 kHz.
Example of use:
{ LoRaWAN.setRadioBandwidth(250); LoRaWAN.getRadioBandwidth(); }
Related Variable:
LoRaWAN._radioBW → Stores the previously set radio bandwidth
The setRadioFrequency() function allows the user to set the communication frequency of the radio transceiver.
The getRadioFrequency() function allows the user to query radio frequency which was previously set by the user. The attribute _radioFreq permits to access to the settings of the module. The radio bandwidth can take values from 433250000 to 434550000 or from 863250000 to 869750000.
When using the LoRaWAN 868 module, the operation frequency can take values from 433250000 to 434550000 or from 863250000 to 869750000, for the 433 and 868 MHz bands.
When using the LoRaWAN 900 module, the operation frequency can take values from 902000000 to 928000000.
Example of use:
{ LoRaWAN.setRadioFrequency(868100000); LoRaWAN.getRadioFrequency(); }
Related Variable:
LoRaWAN._radioFreq→ Stores the previously set communication frequency
The getRadioSNR() function allows the user to query the Signal to Noise Ratio (SNR) for the last received packet. The attribute _radioSNR permits to access to the settings of the module. The SNR can take values from -127 to 128.
Example of use:
{ LoRaWAN.getRadioSNR(); }
Related Variable:
LoRaWAN._radioSNR→ Stores the previously set communication frequency
It is possible to set up hybrid networks using both Radio and LoRaWAN protocols. Therefore, several nodes can use a P2P star topology to reach a central node which will access to the LoRaWAN network to route the information. The basis of this operation is that the central node listens to P2P packets and sends them to the LoRaWAN infrastructure. See the following diagram to understand this hybrid network:
The user must keep in mind that there is a mismatch between the maximum payload in P2P networks (255 bytes) and LoRaWAN networks (292 bytes). Therefore, the central node will be able to resend all received frames from the other P2P nodes. The following example shows how to operate as a central node sending data of the incoming P2P packets to the LoRaWAN network:
/* * ------ P2P Code Example -------- * * Explanation: This example shows how to configure the module * for P2P mode and LoRaWAN mode too. In this code, the Waspmote * waits for new incoming P2P packets. Then routes the information * received to the LoRaWAN gateway. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 1.2 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include <Wire.h> // Cooking API libraries #include <arduinoUART.h> #include <arduinoUtils.h> // LoRaWAN library #include <arduinoLoRaWAN.h> // Pin definition for LoRaWAN module error LED: const int error_led = 13; ////////////////////////////////////////////// uint8_t socket = SOCKET1; ////////////////////////////////////////////// // define radio settings (P2P interface) ////////////////////////////////////////////// uint8_t power = 15; uint32_t frequency = 868100000; char spreading_factor[] = "sf12"; char coding_rate[] = "4/5"; uint16_t bandwidth = 125; char crc_mode[] = "on"; ////////////////////////////////////////////// // Define LoRaWAN settings (LoRaWAN interface) //////////////////////////////////////////////////////////// uint8_t PORT = 3; char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // define char packet[256]; // variable uint8_t error; void setup() { //P2P to LoRaWAN gateway pinMode(error_led, OUTPUT); digitalWrite(error_led, LOW); // module setup error = lorawanModuleSetup(); // Check status if (error == 0) { //LoRaWAN interface configured OK digitalWrite(error_led, LOW); } else { //LoRaWAN interface configured ERROR digitalWrite(error_led, HIGH); } // module setup error = radioModuleSetup(); // Check status if (error == 0) { //Radio interface configured OK digitalWrite(error_led, LOW); } else { //Radio interface configured ERROR digitalWrite(error_led, HIGH); } } void loop() { //------------------------------------------------------- //Listening to packets: //------------------------------------------------------- // Set receive mode error = LoRaWAN.receiveRadio(10000); // Check status if (error == 0) { //--> Packet received //data in LoRaWAN._buffer //length in LoRaWAN._length // copy packet contents into a global buffer strncpy( packet, (char*) LoRaWAN._buffer, sizeof(packet)); //------------------------------------------------------- //Route data to LoRaWAN gateway: //------------------------------------------------------- // switch to LoRaWAN mode LoRaWAN.macResume(); // join error = LoRaWAN.joinABP(); // Check status if( error == 0 ) { //Join network OK digitalWrite(error_led, LOW); } else { //Join network error digitalWrite(error_led, HIGH); } // send received packet to LoRaWAN gateway error = LoRaWAN.sendConfirmed(PORT, packet); // Check status if( error == 0 ) { //Send Confirmed packet OK digitalWrite(error_led, LOW); } else { //Send Confirmed packet error digitalWrite(error_led, HIGH); } // module setup error = lorawanModuleSetup(); // Check status if (error == 0) { //LoRaWAN interface configured OK digitalWrite(error_led, LOW); } else { //LoRaWAN interface configured ERROR digitalWrite(error_led, HIGH); } // module setup error = radioModuleSetup(); // Check status if (error == 0) { //Radio interface configured OK digitalWrite(error_led, LOW); } else { //Radio interface configured ERROR digitalWrite(error_led, HIGH); } } else { // error code // 1: error // 2: no incoming packet //Error waiting for packets. error digitalWrite(error_led, LOW); } } /*********************************************************************************** * * radioModuleSetup() * * This function includes all functions related to the module setup and configuration * The user must keep in mind that each time the module powers on, all settings are set * to default values. So it is better to develop a specific function including all steps * for setup and call it everytime the module powers on. * * ***********************************************************************************/ uint8_t radioModuleSetup() { uint8_t status = 0; uint8_t e = 0; ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// e = LoRaWAN.ON(socket); // Check status if (e == 0) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); status = 1; } //------------------------------------------------------- ////////////////////////////////////////////// // 2. Enable P2P mode ////////////////////////////////////////////// e = LoRaWAN.macPause(); // Check status if (e == 0) { //2. P2P mode enabled OK digitalWrite(error_led, LOW); } else { //2. Enable P2P mode error digitalWrite(error_led, HIGH); status = 1; } //------------------------------------------------------- ////////////////////////////////////////////// // 3. Set/Get Radio Power ////////////////////////////////////////////// // Set power e = LoRaWAN.setRadioPower(power); // Check status if (e == 0) { //3.1. Set Radio Power OK digitalWrite(error_led, LOW); } else { //3.1. Set Radio Power error digitalWrite(error_led, HIGH); status = 1; } // Get power e = LoRaWAN.getRadioPower(); // Check status if (e == 0) { //3.2. Get Radio Power OK. //"Power in LoRaWAN._radioPower digitalWrite(error_led, LOW); } else { //3.2. Get Radio Power error digitalWrite(error_led, HIGH); status = 1; } //------------------------------------------------------- ////////////////////////////////////////////// // 4. Set/Get Radio Frequency ////////////////////////////////////////////// // Set frequency e = LoRaWAN.setRadioFreq(frequency); // Check status if (e == 0) { //4.1. Set Radio Frequency OK digitalWrite(error_led, LOW); } else { //4.1. Set Radio Frequency error digitalWrite(error_led, LOW); status = 1; } // Get frequency e = LoRaWAN.getRadioFreq(); // Check status if (e == 0) { //4.2. Get Radio Frequency OK //Frequency in LoRaWAN._radioFreq digitalWrite(error_led, LOW); } else { //4.2. Get Radio Frequency error digitalWrite(error_led, HIGH); status = 1; } //------------------------------------------------------- ////////////////////////////////////////////// // 5. Set/Get Radio Spreading Factor (SF) ////////////////////////////////////////////// // Set SF e = LoRaWAN.setRadioSF(spreading_factor); // Check status if (e == 0) { //5.1. Set Radio SF OK digitalWrite(error_led, LOW); } else { //5.1. Set Radio SF error digitalWrite(error_led, HIGH); status = 1; } // Get SF e = LoRaWAN.getRadioSF(); // Check status if (e == 0) { //5.2. Get Radio SF OK //Spreading Factor in LoRaWAN._radioSF digitalWrite(error_led, LOW); } else { //5.2. Get Radio SF error digitalWrite(error_led, HIGH); status = 1; } //------------------------------------------------------- ////////////////////////////////////////////// // 6. Set/Get Radio Coding Rate (CR) ////////////////////////////////////////////// // Set CR e = LoRaWAN.setRadioCR(coding_rate); // Check status if (e == 0) { //6.1. Set Radio CR OK digitalWrite(error_led, LOW); } else { //6.1. Set Radio CR error digitalWrite(error_led, HIGH); status = 1; } // Get CR e = LoRaWAN.getRadioCR(); // Check status if (e == 0) { //6.2. Get Radio CR OK. //Coding Rate in LoRaWAN._radioCR digitalWrite(error_led, LOW); } else { //6.2. Get Radio CR error digitalWrite(error_led, HIGH); status = 1; } //------------------------------------------------------- ////////////////////////////////////////////// // 7. Set/Get Radio Bandwidth (BW) ////////////////////////////////////////////// // Set BW e = LoRaWAN.setRadioBW(bandwidth); // Check status if (e == 0) { //7.1. Set Radio BW OK digitalWrite(error_led, LOW); } else { //7.1. Set Radio BW error digitalWrite(error_led, HIGH); } // Get BW e = LoRaWAN.getRadioBW(); // Check status if (e == 0) { //7.2. Get Radio BW OK. //Bandwidth in LoRaWAN._radioBW digitalWrite(error_led, LOW); } else { //7.2. Get Radio BW error digitalWrite(error_led, HIGH); status = 1; } //------------------------------------------------------- ////////////////////////////////////////////// // 8. Set/Get Radio CRC mode ////////////////////////////////////////////// // Set CRC e = LoRaWAN.setRadioCRC(crc_mode); // Check status if (e == 0) { //8.1. Set Radio CRC mode OK digitalWrite(error_led, LOW); } else { //8.1. Set Radio CRC mode error digitalWrite(error_led, HIGH); status = 1; } // Get CRC e = LoRaWAN.getRadioCRC(); // Check status if (e == 0) { //8.2. Get Radio CRC mode OK. //CRC status in LoRaWAN._crcStatus digitalWrite(error_led, LOW); } else { //8.2. Get Radio CRC mode error digitalWrite(error_led, HIGH); status = 1; } //------------------------------------------------------- return status; } /*********************************************************************************** * * lorawanModuleSetup() * * This function includes all functions related to the module setup for LoRaWAN * performance. * * ***********************************************************************************/ uint8_t lorawanModuleSetup() { uint8_t status = 0; uint8_t e = 0; //------------------------------------------------------- //LoRaWAN mode configuration: //------------------------------------------------------- ////////////////////////////////////////////// // 1. Switch on ////////////////////////////////////////////// e = LoRaWAN.ON(socket); // Check status if( e == 0 ) { //1. Switch ON OK" digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); status = 1; } LoRaWAN.factoryReset(); ////////////////////////////////////////////// // 2. Set Device EUI ////////////////////////////////////////////// e = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( e == 0 ) { //2.1. Device EUI set OK")); digitalWrite(error_led, LOW); } else { //2.1. Device EUI set error digitalWrite(error_led, HIGH); status = 1; } e = LoRaWAN.getDeviceEUI(); // Check status if( e == 0 ) { //2.2. Device EUI get OK. //Device EUI in LoRaWAN._devEUI digitalWrite(error_led, LOW); } else { //2.2. Device EUI get error digitalWrite(error_led, HIGH); status = 1; } ////////////////////////////////////////////// // 3. Set Device Address ////////////////////////////////////////////// e = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( e == 0 ) { //3.1. Device address set OK digitalWrite(error_led, LOW); } else { //3.1. Device address set error digitalWrite(error_led, HIGH); status = 1; } e = LoRaWAN.getDeviceAddr(); // Check status if( e == 0 ) { //3.2. Device address get OK. //Device address is LoRaWAN._devAddr digitalWrite(error_led, LOW); } else { //3.2. Device address get error digitalWrite(error_led, HIGH); status = 1; } ////////////////////////////////////////////// // 4. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { //4. Network Session Key set OK digitalWrite(error_led, LOW); } else { //4. Network Session Key set error digitalWrite(error_led, HIGH); status = 1; } ////////////////////////////////////////////// // 5. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { //5. Application Session Key set OK" digitalWrite(error_led, LOW); } else { //5. Application Session Key set error digitalWrite(error_led, HIGH); status = 1; } ////////////////////////////////////////////// // 6. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { //6. Save configuration OK digitalWrite(error_led, LOW); } else { //6. Save configuration error digitalWrite(error_led, HIGH); status = 1; } //------------------------------------------------------- return status; }
/* * ------ P2P Code Example -------- * * Explanation: This example shows how to configure the module * for P2P mode and LoRaWAN mode too. In this code, the Waspmote * waits for new incoming P2P packets. Then routes the information * received to the LoRaWAN gateway. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 0.3 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include "arduPiLoRaWAN.h" // socket to use ////////////////////////////////////////////// uint8_t sock = SOCKET0; ////////////////////////////////////////////// // define radio settings (P2P interface) ////////////////////////////////////////////// uint8_t power = 15; uint32_t frequency = 868100000; char spreading_factor[] = "sf12"; char coding_rate[] = "4/5"; uint16_t bandwidth = 125; char crc_mode[] = "on"; ////////////////////////////////////////////// // Define LoRaWAN settings (LoRaWAN interface) //////////////////////////////////////////////////////////// uint8_t PORT = 3; char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // define functions uint8_t radioModuleSetup(void); uint8_t lorawanModuleSetup(void); // define char packet[512]; // variable uint8_t error; void setup() { printf("P2P to LoRaWAN gateway\n\n"); // module setup error = lorawanModuleSetup(); // Check status if (error == 0) { printf("LoRaWAN interface configured OK\n"); } else { printf("LoRaWAN interface configured ERROR\n"); } // module setup error = radioModuleSetup(); // Check status if (error == 0) { printf("Radio interface configured OK\n"); } else { printf("Radio interface configured ERROR\n"); } printf("\n"); } void loop() { printf("\n-------------------------------------------------------\n"); printf("Listening to packets:\n"); printf("-------------------------------------------------------\n"); // Set receive mode error = LoRaWAN.receiveRadio(10000); // Check status if (error == 0) { printf("--> Packet received\n"); printf("data: %s\n",(char*) LoRaWAN._buffer); printf("length: %u\n", LoRaWAN._length); // copy packet contents into a global buffer strncpy( packet, (char*) LoRaWAN._buffer, sizeof(packet)); printf("\n-------------------------------------------------------\n"); printf("Route data to LoRaWAN gateway:\n"); printf("-------------------------------------------------------\n"); // switch to LoRaWAN mode LoRaWAN.macResume(); // join error = LoRaWAN.joinABP(); // Check status if( error == 0 ) { printf("Join network OK\n"); } else { printf("Join network error = %d\n", error); } // send received packet to LoRaWAN gateway error = LoRaWAN.sendConfirmed( PORT, packet); // Check status if( error == 0 ) { printf("Send Confirmed packet OK\n"); } else { printf("Send Confirmed packet error = %d\n", error); } // module interface error = lorawanModuleSetup(); // Check status if (error == 0) { printf("LoRaWAN interface configured OK\n"); } else { printf("LoRaWAN interface configured ERROR\n"); } // module setup error = radioModuleSetup(); // Check status if (error == 0) { printf("Radio interface configured OK\n"); } else { printf("Radio interface configured ERROR\n"); } printf("\n"); } else { // error code // 1: error // 2: no incoming packet printf("Error waiting for packets. error = %d\n", error); } } /*********************************************************************************** * * radioModuleSetup() * * This function includes all functions related to the module setup and configuration * The user must keep in mind that each time the module powers on, all settings are set * to default values. So it is better to develop a specific function including all steps * for setup and call it everytime the module powers on. * * ***********************************************************************************/ uint8_t radioModuleSetup() { uint8_t status = 0; uint8_t e = 0; printf("\n-------------------------------------------------------\n"); printf("P2P mode configuration:\n"); printf("-------------------------------------------------------\n"); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// e = LoRaWAN.ON(sock); // Check status if (e == 0) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n",e); status = 1; } printf("-------------------------------------------------------\n"); ////////////////////////////////////////////// // 2. Enable P2P mode ////////////////////////////////////////////// e = LoRaWAN.macPause(); // Check status if (e == 0) { printf("2. P2P mode enabled OK\n"); } else { printf("2. Enable P2P mode error = %d\n", e); status = 1; } printf("-------------------------------------------------------\n"); ////////////////////////////////////////////// // 3. Set/Get Radio Power ////////////////////////////////////////////// // Set power e = LoRaWAN.setRadioPower(power); // Check status if (e == 0) { printf("3.1. Set Radio Power OK\n"); } else { printf("3.1. Set Radio Power error = %d\n", e); status = 1; } // Get power e = LoRaWAN.getRadioPower(); // Check status if (e == 0) { printf("3.2. Get Radio Power OK. "); printf("Power: %d\n",LoRaWAN._radioPower); } else { printf("3.2. Get Radio Power error = %d\n", e); status = 1; } printf("-------------------------------------------------------\n"); ////////////////////////////////////////////// // 4. Set/Get Radio Frequency ////////////////////////////////////////////// // Set frequency e = LoRaWAN.setRadioFreq(frequency); // Check status if (e == 0) { printf("4.1. Set Radio Frequency OK\n"); } else { printf("4.1. Set Radio Frequency error = %d\n", error); status = 1; } // Get frequency e = LoRaWAN.getRadioFreq(); // Check status if (e == 0) { printf("4.2. Get Radio Frequency OK. "); printf("Frequency: %d\n", LoRaWAN._radioFreq); } else { printf("4.2. Get Radio Frequency error = %d\n", e); status = 1; } printf("-------------------------------------------------------\n"); ////////////////////////////////////////////// // 5. Set/Get Radio Spreading Factor (SF) ////////////////////////////////////////////// // Set SF e = LoRaWAN.setRadioSF(spreading_factor); // Check status if (e == 0) { printf("5.1. Set Radio SF OK\n"); } else { printf("5.1. Set Radio SF error = %e\n", e); status = 1; } // Get SF e = LoRaWAN.getRadioSF(); // Check status if (e == 0) { printf("5.2. Get Radio SF OK. "); printf("Spreading Factor: %s\n", LoRaWAN._radioSF); } else { printf("5.2. Get Radio SF error = %d\n", e); status = 1; } printf("-------------------------------------------------------\n"); ////////////////////////////////////////////// // 6. Set/Get Radio Coding Rate (CR) ////////////////////////////////////////////// // Set CR e = LoRaWAN.setRadioCR(coding_rate); // Check status if (e == 0) { printf("6.1. Set Radio CR OK\n"); } else { printf("6.1. Set Radio CR error = %d\n", e); status = 1; } // Get CR e = LoRaWAN.getRadioCR(); // Check status if (e == 0) { printf("6.2. Get Radio CR OK. "); printf("Coding Rate: %s\n",LoRaWAN._radioCR); } else { printf("6.2. Get Radio CR error = %d\n", e); status = 1; } printf("-------------------------------------------------------\n"); ////////////////////////////////////////////// // 7. Set/Get Radio Bandwidth (BW) ////////////////////////////////////////////// // Set BW e = LoRaWAN.setRadioBW(bandwidth); // Check status if (e == 0) { printf("7.1. Set Radio BW OK\n"); } else { printf("7.1. Set Radio BW error = %d\n", e); } // Get BW e = LoRaWAN.getRadioBW(); // Check status if (e == 0) { printf("7.2. Get Radio BW OK. "); printf("Bandwidth: %u\n", LoRaWAN._radioBW); } else { printf("7.2. Get Radio BW error = %d\n", e); status = 1; } printf("-------------------------------------------------------\n"); ////////////////////////////////////////////// // 8. Set/Get Radio CRC mode ////////////////////////////////////////////// // Set CRC e = LoRaWAN.setRadioCRC(crc_mode); // Check status if (e == 0) { printf("8.1. Set Radio CRC mode OK\n"); } else { printf("8.1. Set Radio CRC mode error = %d\n", e); status = 1; } // Get CRC e = LoRaWAN.getRadioCRC(); // Check status if (e == 0) { printf("8.2. Get Radio CRC mode OK. "); printf("CRC status: %u\n",LoRaWAN._crcStatus); } else { printf("8.2. Get Radio CRC mode error = %e\n", e); status = 1; } printf("-------------------------------------------------------\n"); return status; } /*********************************************************************************** * * lorawanModuleSetup() * * This function includes all functions related to the module setup for LoRaWAN * performance. * * ***********************************************************************************/ uint8_t lorawanModuleSetup() { uint8_t status = 0; uint8_t e = 0; printf("\n-------------------------------------------------------\n"); printf("LoRaWAN mode configuration:\n"); printf("-------------------------------------------------------\n"); ////////////////////////////////////////////// // 1. Switch on ////////////////////////////////////////////// e = LoRaWAN.ON(sock); // Check status if( e == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n", e); status = 1; } LoRaWAN.factoryReset(); ////////////////////////////////////////////// // 2. Set Device EUI ////////////////////////////////////////////// e = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( e == 0 ) { printf("2.1. Device EUI set OK\n"); } else { printf("2.1. Device EUI set error = %d\n", e); status = 1; } e = LoRaWAN.getDeviceEUI(); // Check status if( e == 0 ) { printf("2.2. Device EUI get OK. "); printf("Device EUI: %s\n", LoRaWAN._devEUI); } else { printf("2.2. Device EUI get error = %d\n", e); status = 1; } ////////////////////////////////////////////// // 3. Set Device Address ////////////////////////////////////////////// e = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( e == 0 ) { printf("3.1. Device address set OK\n"); } else { printf("3.1. Device address set error = %d\n", e); status = 1; } e = LoRaWAN.getDeviceAddr(); // Check status if( e == 0 ) { printf("3.2. Device address get OK. "); printf("Device address: %s\n", LoRaWAN._devAddr); } else { printf("3.2. Device address get error = %d\n", e); status = 1; } ////////////////////////////////////////////// // 4. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { printf("4. Network Session Key set OK\n"); } else { printf("4. Network Session Key set error = %d\n", error); status = 1; } ////////////////////////////////////////////// // 5. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { printf("5. Application Session Key set OK\n"); } else { printf("5. Application Session Key set error = %d\n", error); status = 1; } ////////////////////////////////////////////// // 6. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { printf("6. Save configuration OK\n"); } else { printf("6. Save configuration error = %d\n", error); status = 1; } printf("-------------------------------------------------------\n"); return status; } ////////////////////////////////////////////// // Main loop setup() and loop() declarations ////////////////////////////////////////////// int main (){ setup(); while(1){ loop(); } return (0); }
www.libelium.com/development/waspmote/examples/lorawan-p2p-04-hybrid-p2p-to-lorawan
LoRaWAN network architecture is typically laid out in a star-of-stars topology in which a gateway is a transparent bridge relaying messages between end-devices and a central network server in the back-end.
Before using a LoRaWAN module with the back-ends explained below or any other back-end, it is strongly recommended to know the configuration that the LoRaWAN gateway is using so we can configure it in the same way.
We will need to pay attention to some of these parameters:
Depending on the LoRaWAN module version we work with, it will be necessary to configure different parameters.
Make sure that the gateway's firmware is always up to date. If there is no certain about it, contact the gateway provider or the back-end provider.
As we can see in the section “Channel parameters”, the LoRaWAN 868 module supports up to 16 channels to transmit information. According to the LoRa Alliance: LoRaWAN Specification document, it has 3 channels configured by default with fixed frequencies.
Depending on the gateway manufacturer, the number of supported channels may vary. To get the best performance it is recommended to configure the module to use as many channels as the gateway may support.
There is a set of functions to configure these channels parameters, and to turn on channels so the module can use them. Before turning on channels we must configure them, otherwise the module will not allow the user to activate them.
So set frequencies for every channel according to the gateway's configuration. Set the data rate (max range depends on that) as desired. Keep in mind that the duty cycle must be set and modified for the existence of other channels so it complies with the applicable regulations in the country as shown in the “Channel Duty Cycle” section.
Once the configuration has been correctly done, channels can be activated.
Window reception parameters may also vary from a gateway to another. They should be configured according to the parameters given by the back-end provider.
As we can see in the section “Channel parameters”, LoRaWAN 900 module supports up to 64 channels to transmit uplink messages. By default, the whole set of channels is activated when the module starts working.
Depending on the gateway manufacturer, the number of supported channels may vary. To get the best performance it is recommended to configure the module to use as many channels as gateway may support.
It is strongly recommended to deactivate channels that are not supported by the gateway so the module does not try to send information on these channels.
Before setting on any channel, it is necessary to configure the data rate (max range depends on that) as desired.
Window reception parameters may also vary from a gateway to another. They should be configured according to the parameters given by the back-end provider.
The ThingPark Wireless Device Manager is the back-end User Interface (UI) which allows you to manage all of your LoRaWAN devices.
This Guide will provide the guidelines on the entire GUI, the device provisioning, device configuration and management, alarm and routing profile management and connectivity plan association.
The Device Manager can be fully integrated into a third party customer UI, through all the ThingPark Wireless OSS REST API.
The device provisioning is the process that allows users to create devices and register them on the network through Activation By Personalization (ABP).
Information required to create a new device:
These parameters match with the ones which must be configured in the ThingPark Actility Portal (back-end).
Actility Portal lets the user configure all parameters needed to connect into a network. NwkSKey and AppSKey are 128-bit keys specific for the end-device, used to calculate and verify an application-level MIC (message integrity code) and also used by both network server and end-device to encrypt and decrypt the payload field of application-specific data messages.
Both NwkSKey and AppSKey will be configured by the user in the Actility Portal and set into the end-device. These keys are not shown in the ThingPark Wireless Device Manager once they have been configured so it is strongly recommended to set them into the end-device before configuring the end-device creation in the Actility Portal.
About DevEUI and DevAddr, there are two ways to configure it into the module with Waspmote.
OrbiWise introduces its comprehensive UbiQ core network solution for Low-Power Wide-Area (LPWA) networks taking full advantage of LoRaTM bidirectional communication technology.
LPWA networks are of special interest to wireless operators, utilities and industrial companies that want to serve many applications in the Internet-of-Things domain with a single low-cost infrastructure.
OrbiWise's UbiQ solution enables the deployment of such infrastructure from city-scale to nation-wide coverage with seamless expansion and support for millions of connected objects. Furthermore, UbiQ's O&M tool suite allows operations and maintenance of the entire network from a single web-based graphical user interface.
The Add New Device process allows users to create devices and register them on the network through Activation By Personalization (ABP).
Information required to create a new device:
Optional information:
Always have in mind to select the Personalized Registration Type. Despite AppSKey is an optional parameter to create the device in the server, it is mandatory to be configured in the module. In any case, it is always better to set an AppSKey both in server and module (same for both) so data can be decrypted by server.
To perform data downlinks, a button called “Send Data” can be found in Data section. Clicking on it will open a pop-up that the user can fill with data for the payload and select the message type. Data will be received by the module after the next data uplink. It does not matter if the next uplink process is confirmed or unconfirmed, the downlink will be performed.
Once the new device was created in the OrbiWise portal only DevEUI will be shown, so user should set the device address, network session key and application session key in both portal and module at the same time.
LORIOT.io is a provider of a LoRaWAN Network Server and Application Server software, which is commercially offered through a set of business models.
They provide:
As a gateway owner, users can use LORIOT.io software on gateways to connect them to their cloud. From then on, all data received by the gateways will be relayed to the user through the LORIOT.io APIs or 3rd party services.
The network server components fulfills to role of protocol processor. It is a TLS connection end-point for the gateways and the customer applications. It is responsible for processing the incoming end node data according to the LoRaWAN protocol.
The specific roles of LORIOT.io Network Server are:
Some parameters must be set into the module so it can join to a network through Activation By Personalization (ABP).
When a new device is generated in the LORIOT.io portal these parameters are provided. The user will have to configure the module according to these parameters.
Once the device is created you can access to its configuration and data clicking over the Device EUI field with the mouse. Data messages can be seen there.
Data sent to the back-end can be found inside every device page. Data could also be found in the WebSocket API section.
To perform data downlinks click on the “Send data” button and the “Send to device” section will be displayed. In this section, Device EUI, port number and data payload to send must be filled. Finally, the “Send to device” button will enqueue the data to be downloaded. Data will be received by the module after the next data uplink. It does not matter if the next uplink process is confirmed or unconfirmed, the downlink will be performed.
LORIOT.io portal provides by default the whole configuration required by the module to connect to a network. The mandatory field to field are the ones which where mentioned in the previous section. They can be copied as is to the code so module is configured the same way it was created in the portal.
Inside the device description in the LORIOT.io portal they warn to copy EUI and Address in little endian format, but it won't be necessary for the Waspmote code, it can be copied big endian format.
Libelium currently offers two options of this type of radio technology: LoRa and LoRaWAN
LoRaWAN is a protocol with a good long-range performance. It is achieved thanks to the excellent receiver sensitivity of the LoRa modulation, which is possible due to very low data rates (few bps). The main drawback of LoRaWAN is the low data rate of the transmission modes with high Spreading Factor. The better range, the worse bitrate. This may be a problem in crowded networks, because the shared channel could be too busy because it can take several seconds to send each frame. The base station and the back-end server will try to find an efficient balance in the network thanks to the LoRaWAN algorithms. So:
Libelium offers two types of sensor platforms: OEM lines (Waspmote , Arduino, Raspberry Pi) and Plug & Sense!.
http://www.libelium.com/products/waspmote/
CE Mark: In accordance with the 1999/5/EC (R&TTE) and the EU Directive 2011/65/EU (RoHS2), Libelium Comunicaciones Distribuidas S.L. declares that the "Plug & Sense! LoRaWAN 868" device conforms to the following regulations:
If desired, the Declaration of Conformity document can be requested using the Contact section at:
http://www.libelium.com/contact
Libelium has certified the model "Plug & Sense! LoRaWAN 900 / 915" for US. Specifically under the Part 15 Spread Spectrum Transmitter (FCC Rule Part 15 C).
If you want to know more contact the Libelium Sales Department.
Libelium has certified the model "Plug & Sense! LoRaWAN 900 / 915" for Canada. Specifically under the Industry Canada Regulation (IC) - (RSS-210).
If you want to know more contact the Libelium Sales Department.
Example of LoRaWAN 868:
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the module * and all general settings related to back-end registration * process. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 1.2 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include <Wire.h> // Cooking API libraries #include <arduinoUART.h> #include <arduinoUtils.h> // LoRaWAN library #include <arduinoLoRaWAN.h> // Pin definition for LoRaWAN module error LED: const int error_led = 13; ////////////////////////////////////////////// uint8_t socket = SOCKET1; ////////////////////////////////////////////// // Device parameters for Back-End registration //////////////////////////////////////////////////////////// char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; char APP_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // variable uint8_t error; void setup() { //LoRaWAN example - Module configuration pinMode(error_led, OUTPUT); digitalWrite(error_led, LOW); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Reset to factory default values ////////////////////////////////////////////// error = LoRaWAN.factoryReset(); // Check status if( error == 0 ) { //2. Reset to factory default values OK digitalWrite(error_led, LOW); } else { //2. Reset to factory error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 3. Set/Get Device EUI ////////////////////////////////////////////// // Set Device EUI error = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( error == 0 ) { //3.1. Set Device EUI OK digitalWrite(error_led, LOW); } else { //3.1. Set Device EUI error digitalWrite(error_led, HIGH); } // Get Device EUI error = LoRaWAN.getDeviceEUI(); // Check status if( error == 0 ) { //3.2. Get Device EUI OK. //Device EUI in LoRaWAN._devEUI digitalWrite(error_led, LOW); } else { //3.2. Get Device EUI error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 4. Set/Get Device Address ////////////////////////////////////////////// // Set Device Address error = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( error == 0 ) { //4.1. Set Device address OK digitalWrite(error_led, LOW); } else { //4.1. Set Device address error digitalWrite(error_led, HIGH); } // Get Device Address error = LoRaWAN.getDeviceAddr(); // Check status if( error == 0 ) { //4.2. Get Device address OK. //Device address in LoRaWAN._devAddr digitalWrite(error_led, LOW); } else { //4.2. Get Device address error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 5. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { //5. Set Network Session Key OK digitalWrite(error_led, LOW); } else { //5. Set Network Session Key error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 6. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { //6. Set Application Session Key OK digitalWrite(error_led, LOW); } else { //6. Set Application Session Key error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 7. Set retransmissions for uplink confirmed packet ////////////////////////////////////////////// // set retries error = LoRaWAN.setRetries(7); // Check status if( error == 0 ) { //7.1. Set Retransmissions for uplink confirmed packet OK digitalWrite(error_led, LOW); } else { //7.1. Set Retransmissions for uplink confirmed packet error digitalWrite(error_led, HIGH); } // Get retries error = LoRaWAN.getRetries(); // Check status if( error == 0 ) { //7.2. Get Retransmissions for uplink confirmed packet OK. //TX retries in LoRaWAN._retries digitalWrite(error_led, LOW); } else { //7.2. Get Retransmissions for uplink confirmed packet error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 8. Set application key ////////////////////////////////////////////// error = LoRaWAN.setAppKey(APP_KEY); // Check status if( error == 0 ) { //8. Application key set OK digitalWrite(error_led, LOW); } else { //8. Application key set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 9. Channel configuration. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// // Set channel 3 -> 867.1 MHz // Set channel 4 -> 867.3 MHz // Set channel 5 -> 867.5 MHz // Set channel 6 -> 867.7 MHz // Set channel 7 -> 867.9 MHz uint32_t freq = 867100000; for (int ch = 3; ch <= 7; ch++) { error |= LoRaWAN.setChannelFreq(ch, freq); freq += 200000; } // Check status if( error == 0 ) { //9. Frequency set OK. //Frequency in LoRaWAN._freq[3] digitalWrite(error_led, LOW); } else { //9. Enable Frequency error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 10. Set Duty Cycle for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (int ch = 0; ch <= 2; ch++) { error |= LoRaWAN.setChannelDutyCycle(ch, 33333); } for (int ch = 3; ch <= 7; ch++) { error |= LoRaWAN.setChannelDutyCycle(ch, 40000); } // Check status if( error == 0 ) { //10. Duty cycle channel set OK. digitalWrite(error_led, LOW); } else { //10. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 11. Set Data Range for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (int ch = 0; ch <= 7; ch++) error |= LoRaWAN.setChannelDRRange(ch, 0, 5); // Check status if( error == 0 ) { //11. Data rate range channel set OK. //Data Rate min in LoRaWAN._drrMin[3] //Data Rate max in LoRaWAN._drrMax[3] digitalWrite(error_led, LOW); } else { //11. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 12. Set Data rate range for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (int ch = 0; ch <= 7; ch++) error |= LoRaWAN.setChannelStatus(ch, "on"); // Check status if( error == 0 ) { //12. Channel status set OK digitalWrite(error_led, LOW); } else { //12. Data rate set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 13. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { //13. Save configuration OK digitalWrite(error_led, LOW); } else { //13. Save configuration error digitalWrite(error_led, HIGH); } //------------------------------------ //Now the LoRaWAN module is ready for //joining networks and send messages. //Please check the next examples... //------------------------------------ } void loop() { // do nothing }
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the module * and all general settings related to back-end registration * process. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 0.4 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include "arduPiLoRaWAN.h" ////////////////////////////////////////////// uint8_t sock = SOCKET0; ////////////////////////////////////////////// // Device parameters for Back-End registration //////////////////////////////////////////////////////////// char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; char APP_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // variable uint8_t error; void setup() { printf("LoRaWAN example - Module configuration\n"); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(sock); // Check status if( error == 0 ) { printf("1. Switch ON OK\n"); } else { printf("1. Switch ON error = %d\n", error); } ////////////////////////////////////////////// // 2. Reset to factory default values ////////////////////////////////////////////// error = LoRaWAN.factoryReset(); // Check status if( error == 0 ) { printf("2. Reset to factory default values OK\n"); } else { printf("2. Reset to factory error = %d\n", error); } ////////////////////////////////////////////// // 3. Set/Get Device EUI ////////////////////////////////////////////// // Set Device EUI error = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( error == 0 ) { printf("3.1. Set Device EUI OK\n"); } else { printf("3.1. Set Device EUI error = %d\n", error); } // Get Device EUI error = LoRaWAN.getDeviceEUI(); // Check status if( error == 0 ) { printf("3.2. Get Device EUI OK. "); printf("Device EUI: %s\n",LoRaWAN._devEUI); } else { printf("3.2. Get Device EUI error = %d\n", error); } ////////////////////////////////////////////// // 4. Set/Get Device Address ////////////////////////////////////////////// // Set Device Address error = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( error == 0 ) { printf("4.1. Set Device address OK\n"); } else { printf("4.1. Set Device address error = %d\n", error); } // Get Device Address error = LoRaWAN.getDeviceAddr(); // Check status if( error == 0 ) { printf("4.2. Get Device address OK. "); printf("Device address: %s\n", LoRaWAN._devAddr); } else { printf("4.2. Get Device address error = %d\n", error); } ////////////////////////////////////////////// // 5. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { printf("5. Set Network Session Key OK\n"); } else { printf("5. Set Network Session Key error = %d\n", error); } ////////////////////////////////////////////// // 6. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { printf("6. Set Application Session Key OK\n"); } else { printf("6. Set Application Session Key error = %d\n", error); } ////////////////////////////////////////////// // 7. Set retransmissions for uplink confirmed packet ////////////////////////////////////////////// // set retries error = LoRaWAN.setRetries(7); // Check status if( error == 0 ) { printf("7.1. Set Retransmissions for uplink confirmed packet OK\n"); } else { printf("7.1. Set Retransmissions for uplink confirmed packet error = %d\n", error); } // Get retries error = LoRaWAN.getRetries(); // Check status if( error == 0 ) { printf("7.2. Get Retransmissions for uplink confirmed packet OK. \n"); printf("TX retries: %d\n", LoRaWAN._retries); } else { printf("7.2. Get Retransmissions for uplink confirmed packet error = %d\n", error); } ////////////////////////////////////////////// // 8. Set application key ////////////////////////////////////////////// error = LoRaWAN.setAppKey(APP_KEY); // Check status if( error == 0 ) { printf("8. Application key set OK\n"); } else { printf("8. Application key set error = %d\n", error); } ////////////////////////////////////////////// // 9. Channel configuration. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// // Set channel 3 -> 867.1 MHz // Set channel 4 -> 867.3 MHz // Set channel 5 -> 867.5 MHz // Set channel 6 -> 867.7 MHz // Set channel 7 -> 867.9 MHz uint32_t freq = 867100000; for (int ch = 3; ch <= 7; ch++) { error = LoRaWAN.setChannelFreq(ch, freq); freq += 200000; // Check status if( error == 0 ) { printf("9. Application key set OK\n"); } else { printf("9. Application key set error = %d\n", error); } } ////////////////////////////////////////////// // 10. Set Duty Cycle for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (uint8_t ch = 0; ch <= 2; ch++) { error = LoRaWAN.setChannelDutyCycle(ch, 33333); // Check status if( error == 0 ) { printf("10. Duty cycle channel set OK"); } else { printf("10. Duty cycle channel set error = %d\n", error); } } for (uint8_t ch = 3; ch <= 7; ch++) { error = LoRaWAN.setChannelDutyCycle(ch, 40000); // Check status if( error == 0 ) { printf("10. Duty cycle channel set OK"); } else { printf("10. Duty cycle channel set error = %d\n", error); } } ////////////////////////////////////////////// // 11. Set Data Range for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (int ch = 0; ch <= 7; ch++) { error = LoRaWAN.setChannelDRRange(ch, 0, 5); // Check status if( error == 0 ) { printf("11. Data rate range channel set OK"); } else { printf("11. Data rate range channel set error = %d\n", error); } } ////////////////////////////////////////////// // 12. Set Data rate range for specific channel. (Recomemnded) // Consult your Network Operator and Backend Provider ////////////////////////////////////////////// for (int ch = 0; ch <= 7; ch++) { error = LoRaWAN.setChannelStatus(ch, (char*)"on"); // Check status if( error == 0 ) { printf("12. Channel status set OK"); } else { printf("12. Channel status set error = %d\n", error); } } ////////////////////////////////////////////// // 13. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { printf("13. Save configuration OK\n"); } else { printf("13. Save configuration error = %d\n", error); } printf("------------------------------------\n"); printf("Now the LoRaWAN module is ready for\n"); printf("joining networks and send messages.\n"); printf("Please check the next examples...\n"); printf("------------------------------------\n"); } void loop() { // do nothing } ////////////////////////////////////////////// // Main loop setup() and loop() declarations ////////////////////////////////////////////// int main (){ setup(); while(1){ loop(); } return (0); } //////////////////////////////////////////////
www.libelium.com/development/waspmote/examples/lorawan-01-configure
Example of LoRaWAN 900:
/* * ------ LoRaWAN Code Example -------- * * Explanation: This example shows how to configure the module * and all general settings related to back-end registration * process. * * Copyright (C) 2015 Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Version: 1.2 * Design: David Gascon * Implementation: Luismi Marti, Ruben Martin */ #include <Wire.h> // Cooking API libraries #include <arduinoUART.h> #include <arduinoUtils.h> // LoRaWAN library #include <arduinoLoRaWAN.h> // Pin definition for LoRaWAN module error LED: const int error_led = 13; ////////////////////////////////////////////// uint8_t socket = SOCKET1; ////////////////////////////////////////////// // Device parameters for Back-End registration //////////////////////////////////////////////////////////// char DEVICE_EUI[] = "0102030405060708"; char DEVICE_ADDR[] = "05060708"; char NWK_SESSION_KEY[] = "01020304050607080910111213141516"; char APP_SESSION_KEY[] = "000102030405060708090A0B0C0D0E0F"; char APP_KEY[] = "000102030405060708090A0B0C0D0E0F"; //////////////////////////////////////////////////////////// // variable uint8_t error; void setup() { //LoRaWAN example - Module configuration pinMode(error_led, OUTPUT); digitalWrite(error_led, LOW); ////////////////////////////////////////////// // 1. switch on ////////////////////////////////////////////// error = LoRaWAN.ON(socket); // Check status if( error == 0 ) { //1. Switch ON OK digitalWrite(error_led, LOW); } else { //1. Switch ON error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 2. Reset to factory default values ////////////////////////////////////////////// error = LoRaWAN.factoryReset(); // Check status if( error == 0 ) { //2. Reset to factory default values OK digitalWrite(error_led, LOW); } else { //2. Reset to factory error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 3. Set/Get Device EUI ////////////////////////////////////////////// // Set Device EUI error = LoRaWAN.setDeviceEUI(DEVICE_EUI); // Check status if( error == 0 ) { //3.1. Set Device EUI OK digitalWrite(error_led, LOW); } else { //3.1. Set Device EUI error digitalWrite(error_led, HIGH); } // Get Device EUI error = LoRaWAN.getDeviceEUI(); // Check status if( error == 0 ) { //3.2. Get Device EUI OK. //Device EUI in LoRaWAN._devEUI digitalWrite(error_led, LOW); } else { //3.2. Get Device EUI error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 4. Set/Get Device Address ////////////////////////////////////////////// // Set Device Address error = LoRaWAN.setDeviceAddr(DEVICE_ADDR); // Check status if( error == 0 ) { //4.1. Set Device address OK digitalWrite(error_led, LOW); } else { //4.1. Set Device address error digitalWrite(error_led, HIGH); } // Get Device Address error = LoRaWAN.getDeviceAddr(); // Check status if( error == 0 ) { //4.2. Get Device address OK. //Device address in LoRaWAN._devAddr digitalWrite(error_led, LOW); } else { //4.2. Get Device address error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 5. Set Network Session Key ////////////////////////////////////////////// error = LoRaWAN.setNwkSessionKey(NWK_SESSION_KEY); // Check status if( error == 0 ) { //5. Set Network Session Key OK digitalWrite(error_led, LOW); } else { //5. Set Network Session Key error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 6. Set Application Session Key ////////////////////////////////////////////// error = LoRaWAN.setAppSessionKey(APP_SESSION_KEY); // Check status if( error == 0 ) { //6. Set Application Session Key OK digitalWrite(error_led, LOW); } else { //6. Set Application Session Key error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 7. Set retransmissions for uplink confirmed packet ////////////////////////////////////////////// // set retries error = LoRaWAN.setRetries(7); // Check status if( error == 0 ) { //7.1. Set Retransmissions for uplink confirmed packet OK digitalWrite(error_led, LOW); } else { //7.1. Set Retransmissions for uplink confirmed packet error digitalWrite(error_led, HIGH); } // Get retries error = LoRaWAN.getRetries(); // Check status if( error == 0 ) { //7.2. Get Retransmissions for uplink confirmed packet OK. //TX retries in LoRaWAN._retries digitalWrite(error_led, LOW); } else { //7.2. Get Retransmissions for uplink confirmed packet error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 8. Set application key ////////////////////////////////////////////// error = LoRaWAN.setAppKey(APP_KEY); // Check status if( error == 0 ) { //8. Application key set OK digitalWrite(error_led, LOW); } else { //8. Application key set error digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 9. For 900MHz US bands with gateways limited // to 8 channels, disable the unavailable channels ////////////////////////////////////////////// for (int ch = 8; ch <= 64; ch++) error |= LoRaWAN.setChannelStatus(ch, "off"); // Check status if( error == 0 ) { //9. setup channel correctly digitalWrite(error_led, LOW); } else { //9. error in setup channel digitalWrite(error_led, HIGH); } ////////////////////////////////////////////// // 10. Save configuration ////////////////////////////////////////////// error = LoRaWAN.saveConfig(); // Check status if( error == 0 ) { //10. Save configuration OK digitalWrite(error_led, LOW); } else { //10. Save configuration error digitalWrite(error_led, HIGH); } //------------------------------------ //Now the LoRaWAN module is ready for //joining networks and send messages. //Please check the next examples... //------------------------------------ } void loop() { // do nothing }
/* * LoRaWAN module * * Copyright (C) Libelium Comunicaciones Distribuidas S.L. * http://www.libelium.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Version: 1.0 * Design: David Gascón * Implementation: Yuri Carmona & Ruben Martin */
www.libelium.com/development/waspmote/examples/lorawan-01-configure
If you are interested in Internet of Things (IoT) or M2M projects check our open source sensor platform Waspmote which counts with more than 100 sensors available to use 'off the shelf', a complete API with hundreds of ready to use codes and a low consumption mode of just 0.7µA to ensure years of battery life.
Know more at:
Get the Starter Kits at: