2021-05-09 18:45:59 +00:00
# include "lorawan.h"
# if defined(AMPEL_LORAWAN) && defined(ESP32)
namespace config {
// Values should be defined in config.h
uint16_t lorawan_sending_interval = LORAWAN_SENDING_INTERVAL ; // [s]
static const u1_t PROGMEM APPEUI [ 8 ] = LORAWAN_APPLICATION_EUI ;
static const u1_t PROGMEM DEVEUI [ 8 ] = LORAWAN_DEVICE_EUI ;
static const u1_t PROGMEM APPKEY [ 16 ] = LORAWAN_APPLICATION_KEY ;
}
// Payloads will be automatically sent via MQTT by TheThingsNetwork, and can be seen with:
// mosquitto_sub -h eu.thethings.network -t '+/devices/+/up' -u 'APPLICATION-NAME' -P 'ttn-account-v2.4xxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxx' -v
// or encrypted:
// mosquitto_sub -h eu.thethings.network -t '+/devices/+/up' -u 'APPLICATION-NAME' -P 'ttn-account-v2.4xxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxx' -v --cafile mqtt-ca.pem -p 8883
// ->
// co2ampel-test/devices/esp3a7c94/up {"app_id":"co2ampel-test","dev_id":"esp3a7c94","hardware_serial":"00xxxxxxxx","port":1,"counter":5,"payload_raw":"TJd7","payload_fields":{"co2":760,"rh":61.5,"temp":20.2},"metadata":{"time":"2020-12-23T23:00:51.44020438Z","frequency":867.5,"modulation":"LORA","data_rate":"SF7BW125","airtime":51456000,"coding_rate":"4/5","gateways":[{"gtw_id":"eui-xxxxxxxxxxxxxxxxxx","timestamp":1765406908,"time":"2020-12-23T23:00:51.402519Z","channel":5,"rssi":-64,"snr":7.5,"rf_chain":0,"latitude":22.7,"longitude":114.24,"altitude":450}]}}
// More info : https://www.thethingsnetwork.org/docs/applications/mqtt/quick-start.html
void os_getArtEui ( u1_t * buf ) {
memcpy_P ( buf , config : : APPEUI , 8 ) ;
}
void os_getDevEui ( u1_t * buf ) {
memcpy_P ( buf , config : : DEVEUI , 8 ) ;
}
void os_getDevKey ( u1_t * buf ) {
memcpy_P ( buf , config : : APPKEY , 16 ) ;
}
namespace lorawan {
bool waiting_for_confirmation = false ;
bool connected = false ;
2021-11-15 12:45:36 +00:00
char last_transmission [ 23 ] = " " ;
2021-05-09 18:45:59 +00:00
void initialize ( ) {
Serial . println ( F ( " Starting LoRaWAN. Frequency plan : " LMIC_FREQUENCY_PLAN " MHz. " ) ) ;
// More info about pin mapping : https://github.com/mcci-catena/arduino-lmic#pin-mapping
// Has been tested successfully with ESP32 TTGO LoRa32 V1, and might work with other ESP32+LoRa boards.
const lmic_pinmap * pPinMap = Arduino_LMIC : : GetPinmap_ThisBoard ( ) ;
// LMIC init.
os_init_ex ( pPinMap ) ;
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset ( ) ;
// Join, but don't send anything yet.
LMIC_startJoining ( ) ;
2021-11-15 12:45:36 +00:00
sensor_console : : defineIntCommand ( " lora " , setLoRaInterval , F ( " 300 (Sets LoRaWAN sending interval, in s) " ) ) ;
2021-05-09 18:45:59 +00:00
}
// Checks if OTAA is connected, or if payload should be sent.
// NOTE: while a transaction is in process (i.e. until the TXcomplete event has been received, no blocking code (e.g. delay loops etc.) are allowed, otherwise the LMIC/OS code might miss the event.
2021-11-15 12:45:36 +00:00
// If this rule is not followed, a typical symptom is that the first send is ok and all following ones end with the 'TX not complete' failure.
2021-05-09 18:45:59 +00:00
void process ( ) {
os_runloop_once ( ) ;
}
void printHex2 ( unsigned v ) {
v & = 0xff ;
if ( v < 16 )
Serial . print ( ' 0 ' ) ;
Serial . print ( v , HEX ) ;
}
void onEvent ( ev_t ev ) {
2021-11-15 12:45:36 +00:00
char current_time [ 23 ] ;
ntp : : getLocalTime ( current_time ) ;
2021-05-09 18:45:59 +00:00
Serial . print ( " LoRa - " ) ;
2021-11-15 12:45:36 +00:00
Serial . print ( current_time ) ;
2021-05-09 18:45:59 +00:00
Serial . print ( " - " ) ;
switch ( ev ) {
case EV_JOINING :
Serial . println ( F ( " EV_JOINING " ) ) ;
break ;
case EV_JOINED :
waiting_for_confirmation = false ;
connected = true ;
led_effects : : onBoardLEDOff ( ) ;
Serial . println ( F ( " EV_JOINED " ) ) ;
{
u4_t netid = 0 ;
devaddr_t devaddr = 0 ;
u1_t nwkKey [ 16 ] ;
u1_t artKey [ 16 ] ;
LMIC_getSessionKeys ( & netid , & devaddr , nwkKey , artKey ) ;
Serial . print ( F ( " netid: " ) ) ;
Serial . println ( netid , DEC ) ;
Serial . print ( F ( " devaddr: " ) ) ;
Serial . println ( devaddr , HEX ) ;
Serial . print ( F ( " AppSKey: " ) ) ;
for ( size_t i = 0 ; i < sizeof ( artKey ) ; + + i ) {
if ( i ! = 0 )
Serial . print ( " - " ) ;
printHex2 ( artKey [ i ] ) ;
}
Serial . println ( ) ;
2021-11-15 12:45:36 +00:00
Serial . print ( F ( " NwkSKey: " ) ) ;
2021-05-09 18:45:59 +00:00
for ( size_t i = 0 ; i < sizeof ( nwkKey ) ; + + i ) {
if ( i ! = 0 )
Serial . print ( " - " ) ;
printHex2 ( nwkKey [ i ] ) ;
}
Serial . println ( ) ;
}
Serial . println ( F ( " Other services may resume, and will not be frozen anymore. " ) ) ;
// Disable link check validation (automatically enabled during join)
LMIC_setLinkCheckMode ( 0 ) ;
break ;
case EV_JOIN_FAILED :
Serial . println ( F ( " EV_JOIN_FAILED " ) ) ;
break ;
case EV_REJOIN_FAILED :
Serial . println ( F ( " EV_REJOIN_FAILED " ) ) ;
break ;
case EV_TXCOMPLETE :
2021-11-15 12:45:36 +00:00
ntp : : getLocalTime ( last_transmission ) ;
2021-05-09 18:45:59 +00:00
Serial . println ( F ( " EV_TXCOMPLETE " ) ) ;
break ;
case EV_TXSTART :
waiting_for_confirmation = ! connected ;
Serial . println ( F ( " EV_TXSTART " ) ) ;
break ;
case EV_TXCANCELED :
waiting_for_confirmation = false ;
led_effects : : onBoardLEDOff ( ) ;
Serial . println ( F ( " EV_TXCANCELED " ) ) ;
break ;
case EV_JOIN_TXCOMPLETE :
waiting_for_confirmation = false ;
led_effects : : onBoardLEDOff ( ) ;
Serial . println ( F ( " EV_JOIN_TXCOMPLETE: no JoinAccept. " ) ) ;
Serial . println ( F ( " Other services may resume. " ) ) ;
break ;
default :
Serial . print ( F ( " LoRa event: " ) ) ;
Serial . println ( ( unsigned ) ev ) ;
break ;
}
if ( waiting_for_confirmation ) {
led_effects : : onBoardLEDOn ( ) ;
Serial . println ( F ( " LoRa - waiting for OTAA confirmation. Freezing every other service! " ) ) ;
}
}
void preparePayload ( int16_t co2 , float temperature , float humidity ) {
// Check if there is not a current TX/RX job running
if ( LMIC . opmode & OP_TXRXPEND ) {
Serial . println ( F ( " OP_TXRXPEND, not sending " ) ) ;
} else {
uint8_t buff [ 3 ] ;
// Mapping CO2 from 0ppm to 5100ppm to [0, 255], with 20ppm increments.
buff [ 0 ] = ( util : : min ( util : : max ( co2 , 0 ) , 5100 ) + 10 ) / 20 ;
// Mapping temperatures from [-10°C, 41°C] to [0, 255], with 0.2°C increment
buff [ 1 ] = static_cast < uint8_t > ( ( util : : min ( util : : max ( temperature , - 10 ) , 41 ) + 10.1f ) * 5 ) ;
// Mapping humidity from [0%, 100%] to [0, 200], with 0.5°C increment (0.4°C would also be possible)
buff [ 2 ] = static_cast < uint8_t > ( util : : min ( util : : max ( humidity , 0 ) + 0.25f , 100 ) * 2 ) ;
Serial . print ( F ( " LoRa - Payload : ' " ) ) ;
printHex2 ( buff [ 0 ] ) ;
Serial . print ( " " ) ;
printHex2 ( buff [ 1 ] ) ;
Serial . print ( " " ) ;
printHex2 ( buff [ 2 ] ) ;
Serial . print ( F ( " ', " ) ) ;
Serial . print ( buff [ 0 ] * 20 ) ;
Serial . print ( F ( " ppm, " ) ) ;
Serial . print ( buff [ 1 ] * 0.2 - 10 ) ;
Serial . print ( F ( " °C, " ) ) ;
Serial . print ( buff [ 2 ] * 0.5 ) ;
Serial . println ( F ( " %. " ) ) ;
// Prepare upstream data transmission at the next possible time.
LMIC_setTxData2 ( 1 , buff , sizeof ( buff ) , 0 ) ;
//NOTE: To decode in TheThingsNetwork:
//function Decoder(bytes, port) {
// return {
// co2: bytes[0] * 20,
// temp: bytes[1] / 5.0 - 10,
// rh: bytes[2] / 2.0
// };
//}
}
}
void preparePayloadIfTimeHasCome ( const int16_t & co2 , const float & temperature , const float & humidity ) {
static unsigned long last_sent_at = 0 ;
unsigned long now = seconds ( ) ;
if ( connected & & ( now - last_sent_at > config : : lorawan_sending_interval ) ) {
last_sent_at = now ;
preparePayload ( co2 , temperature , humidity ) ;
}
}
2021-11-15 12:45:36 +00:00
/*****************************************************************
* Callbacks for sensor commands *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void setLoRaInterval ( int32_t sending_interval ) {
config : : lorawan_sending_interval = sending_interval ;
Serial . print ( F ( " Setting LoRa sending interval to : " ) ) ;
Serial . print ( config : : lorawan_sending_interval ) ;
Serial . println ( " s. " ) ;
led_effects : : showKITTWheel ( color : : green , 1 ) ;
}
2021-05-09 18:45:59 +00:00
}
void onEvent ( ev_t ev ) {
lorawan : : onEvent ( ev ) ;
}
# endif