My board is a TTGO LoRa32 V2
I am building a simple weather station, and need to send some data to TTN, in order to do a integration later.
The problem is, the node makes the connection one or two times, then it doesn’t comeback.
The code is as follows:
/* LoRa */
#include <lmic.h>
#include <hal/hal.h>
#include <SPI.h>
#ifdef COMPILE_REGRESSION_TEST
# define FILLMEIN 0
#else
# warning "You must replace the values marked FILLMEIN with real values from the TTN control panel!"
# define FILLMEIN (#dont edit this, edit the lines that use FILLMEIN)
#endif
uint8_t counter = 0;
static const PROGMEM u1_t NWKSKEY[16] = xxxxxxxxxxxxxxxxxxxx;
static const u1_t PROGMEM APPSKEY[16] = xxxxxxxxxxxxxxxxxxxxxxx;
static const u4_t DEVADDR = xxxxxxxxxxxxxxxxx;
void os_getArtEui (u1_t* buf) { }
void os_getDevEui (u1_t* buf) { }
void os_getDevKey (u1_t* buf) { }
uint8_t mydata[32];
char payload[32];
static osjob_t sendjob;
static osjob_t keepalivejob;
const unsigned TX_INTERVAL = 60;
#define KeepAlive_TX_INTERVAL 600
const lmic_pinmap lmic_pins = {
.nss = 18,
.rxtx = LMIC_UNUSED_PIN,
.rst = LMIC_UNUSED_PIN,
.dio = {/*dio0*/ 26, /*dio1*/ 33, /*dio2*/ LMIC_UNUSED_PIN}
};
void onEvent (ev_t ev) {
Serial.print(os_getTime());
Serial.print(": ");
switch (ev) {
case EV_SCAN_TIMEOUT:
Serial.println(F("EV_SCAN_TIMEOUT"));
break;
case EV_BEACON_FOUND:
Serial.println(F("EV_BEACON_FOUND"));
break;
case EV_BEACON_MISSED:
Serial.println(F("EV_BEACON_MISSED"));
break;
case EV_BEACON_TRACKED:
Serial.println(F("EV_BEACON_TRACKED"));
break;
case EV_JOINING:
Serial.println(F("EV_JOINING"));
break;
case EV_JOINED:
Serial.println(F("EV_JOINED"));
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:
Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
if (LMIC.txrxFlags & TXRX_ACK)
Serial.println(F("Received ack"));
if (LMIC.dataLen) {
Serial.println(F("Received "));
Serial.println(LMIC.dataLen);
Serial.println(F(" bytes of payload"));
}
(counter == 4) ? counter = 1 : counter++;
// Schedule next transmission
os_setTimedCallback(&sendjob, os_getTime() + sec2osticks(TX_INTERVAL), do_send);
break;
case EV_LOST_TSYNC:
Serial.println(F("EV_LOST_TSYNC"));
break;
case EV_RESET:
Serial.println(F("EV_RESET"));
break;
case EV_RXCOMPLETE:
// data received in ping slot
Serial.println(F("EV_RXCOMPLETE"));
break;
case EV_LINK_DEAD:
Serial.println(F("EV_LINK_DEAD"));
break;
case EV_LINK_ALIVE:
Serial.println(F("EV_LINK_ALIVE"));
break;
case EV_TXSTART:
Serial.println(F("EV_TXSTART"));
break;
case EV_TXCANCELED:
Serial.println(F("EV_TXCANCELED"));
break;
case EV_RXSTART:
/* do not print anything -- it wrecks timing */
break;
case EV_JOIN_TXCOMPLETE:
Serial.println(F("EV_JOIN_TXCOMPLETE: no JoinAccept"));
break;
default:
Serial.print(F("Unknown event: "));
Serial.println((unsigned) ev);
break;
}
}
void do_keepalive(osjob_t* k)
{
// Re-Schedule a timed job to run this task again at the given timestamp (absolute system time)
os_setTimedCallback(k, os_getTime() + sec2osticks(KeepAlive_TX_INTERVAL), do_keepalive);
}
/**************************************************************************/
/* DHT */
#include "DHT.h"
#define DHTPIN 4
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
int humidity;
float temperature;
void update_dht_readings()
{
humidity = int(dht.readHumidity());
temperature = dht.readTemperature();
}
void serial_print_dht()
{
Serial.println(String(humidity) + " %H | " + String(temperature) + " *C");
}
/**************************************************************************/
/* Photoressitor */
#define LDR_PIN 15
#define MAX_ADC_READING 4095
#define ADC_REF_VOLTAGE 3.3
#define REF_RESISTANCE 4860
#define LUX_CALC_SCALAR 12518931
#define LUX_CALC_EXPONENT -1.405
int ldrRawData;
float resistorVoltage, ldrVoltage;
float ldrResistance;
int ldrLux;
void update_ldr_readings()
{
ldrRawData = analogRead(LDR_PIN);
resistorVoltage = (float)ldrRawData / MAX_ADC_READING * ADC_REF_VOLTAGE;
ldrVoltage = ADC_REF_VOLTAGE - resistorVoltage;
ldrResistance = ldrVoltage / resistorVoltage * REF_RESISTANCE;
ldrLux = int(LUX_CALC_SCALAR * pow(ldrResistance, LUX_CALC_EXPONENT));
}
void serial_print_ldr()
{
Serial.println(String(ldrLux) + " lux");
}
/**************************************************************************/
/* Rainmeter */
#define RAIN_PIN 13
#define SCALAR_MM 0.3
float rain_mm;
void update_rain_mm_readings()
{
if (digitalRead(RAIN_PIN))
{
rain_mm += SCALAR_MM;
}
delay(120);
}
void reset_rain_mm_readings()
{
rain_mm = 0;
}
void serial_print_rain_mm()
{
Serial.println(String(rain_mm) + " mm");
}
/**************************************************************************/
#define ms_per_hour 3600000
#define ms_per_min 60000
#define ms_per_sec 1000
const long interval = ms_per_sec * 5;
unsigned long previousMillis;
unsigned long currentMillis;
void update_time_counter()
{
currentMillis = millis();
}
void(* reset_arduino) (void) = 0;
void setup()
{
while (!Serial); // wait for Serial to be initialized
Serial.begin(115200);
delay(100); // per sample code on RF_95 test
Serial.println(F("Starting"));
pinMode(LDR_PIN, INPUT);
pinMode(RAIN_PIN, INPUT);
dht.begin();
#ifdef VCC_ENABLE
// For Pinoccio Scout boards
pinMode(VCC_ENABLE, OUTPUT);
digitalWrite(VCC_ENABLE, HIGH);
delay(1000);
#endif
os_init();
LMIC_reset();
LMIC_setClockError(MAX_CLOCK_ERROR * 1 / 100);
#ifdef PROGMEM
// On AVR, these values are stored in flash and only copied to RAM
// once. Copy them to a temporary buffer here, LMIC_setSession will
// copy them into a buffer of its own again.
uint8_t appskey[sizeof(APPSKEY)];
uint8_t nwkskey[sizeof(NWKSKEY)];
memcpy_P(appskey, APPSKEY, sizeof(APPSKEY));
memcpy_P(nwkskey, NWKSKEY, sizeof(NWKSKEY));
LMIC_setSession (0x13, DEVADDR, nwkskey, appskey);
#else
// If not running an AVR with PROGMEM, just use the arrays directly
LMIC_setSession (0x13, DEVADDR, NWKSKEY, APPSKEY);
#endif
LMIC_setLinkCheckMode(0);
LMIC.dn2Dr = DR_SF9;
LMIC_setDrTxpow(DR_SF7, 14);
do_send(&sendjob);
do_keepalive(&keepalivejob);
}
void do_send(osjob_t* j) {
(currentMillis >= ms_per_hour) ? reset_arduino() : update_time_counter();
update_dht_readings();
update_ldr_readings();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
(isnan(temperature) || isnan(humidity)) ? void(Serial.println("Failed to read from DHT")) : serial_print_dht();
(isnan(ldrLux)) ? void(Serial.println("Failed to read from LDR")) : serial_print_ldr();
(isnan(rain_mm)) ? void(Serial.println("Failed to read from Rain Meter")) : serial_print_rain_mm();
}
switch (counter)
{
case 1:
sprintf(payload, "temp|%f", temperature);
break;
case 2:
sprintf(payload, "humid|%d", humidity);
break;
case 3:
sprintf(payload, "lux|%d", ldrLux);
break;
case 4:
sprintf(payload, "rain|%f", rain_mm);
break;
default:
break;
}
for (int i = 0; i <= sizeof(payload); i++) {
mydata[i] = payload[i];
}
Serial.println(F(mydata));
// Check if there is not a current TX/RX job running
if (LMIC.opmode & OP_TXRXPEND) {
Serial.println(F("OP_TXRXPEND, not sending"));
} else {
// Prepare upstream data transmission at the next possible time.
LMIC_setTxData2(1, mydata, sizeof(mydata) - 1, 0);
Serial.println(F("Packet queued"));
}
// Next TX is scheduled after TX_COMPLETE event.
}
void loop()
{
update_rain_mm_readings();
os_runloop_once();
}
Serial:
ets Jun 8 2016 00:22:57
rst:0x1 (POWERON_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 188777542, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:8896
load:0x40080400,len:5816
entry 0x400806ac
Starting
12269: EV_TXSTART
Packet queued
162473: EV_TXCOMPLETE (includes waiting for RX windows)
55 %H | 25.50 *C
443 lux
0.00 mm
temp|25.500000
3921597: EV_TXSTART
Packet queued
4071783: EV_TXCOMPLETE (includes waiting for RX windows)
55 %H | 25.50 *C
435 lux
0.00 mm
temp|25.500000
7830883: EV_TXSTART
Packet queued
7981095: EV_TXCOMPLETE (includes waiting for RX windows)
55 %H | 25.50 *C
443 lux
0.00 mm
temp|25.500000
11740191: EV_TXSTART
Packet queued
11890408: EV_TXCOMPLETE (includes waiting for RX windows)
Here is the payload: