In TTN Console , Gateway Only Receives Initial Uplink – No Further Uplinks Sent

I’ve started setting up (2) my RAK833 gateway (USB supported) (1) using this repository: RAKWireless/RAK2247-RAK833-LoRaGateway-RPi-USB . I also have 10 LilyGo LoRa32 v2.1 boards, which I’m connecting to The Things Network (TTN). To do this, I followed the example in the LilyGo-LoRa-Series repository, specifically the RadioLib_OTAA example, to register each end device on TTN. After registering my gateway (it connects successfully), I registered each end devices**(4)** according to the TTN documentation: TTN LilyGo LoRa32 guide.

I’ve filled in the device EUI, appKey, and nwkKey in the example code for each node. Initially, they can send an uplink and receive a downlink successfully, as shown in my serial monitor below.(3)

However, I’ve run into some issues:

  1. I read that the RAK833 module can overheat and requires a heatsink or fan to maintain stable performance (source). I currently have no heatsinks on my RAK833 module, which may be causing problems.
  2. I intermittently get the error Join failed - RADIOLIB_ERR_NO_JOIN_ACCEPT (-1116), which according to the RadioLib documentation means “check your keys or this may be a range issue.” I’ve tested the setup at a short range (3-4 meters), but the error still occasionally appears.
  3. When the error does not occur, the devices successfully join the network server, which I can confirm from my serial monitor. However, with the 5-minute uplink interval I set, the gateway only shows live data for the initial uplink but no further uplinks appear after that.(5)

Here are my setup and configuration images:
Gateway Setup (1) and Configuration (2)

(1)
lora_pktStart (2)

Serial Monitor
serial monitor (3)
End devices
lora32 (4)
Gateway live data

(5)

As I’m new to this community, any help or insights would be greatly appreciated. Thank you ,

This is a common error, LoRa = Long Range, you will be shouting so loudly in the ears of the gateway that it just won’t understand what’s being said - same goes for humans.

Per forum search as this is a regular query, can you put 10 to 20 meters & a brick wall between the device & gateway and retest.

A USB based gateway is sub-optimal but for a few devices should work OK and if it’s all out in the open air I’d not see the need for a fan.

If it’s text, please post as text (images 2 &3). No point posting images of nothing to see (image 5). But overall, useful detail, thank you!

1 Like

Thank you so much for your advice! I decided to reconfigure my gateway yesterday using rak_common_for_gateway, and now my end device successfully sends uplinks and receives downlinks every five minutes. My goal is to transmit PZEM004 sensor measurements to TTN. After I successfully received uplinks and downlinks from TTN today, I set up my sensor payloads according to the PZEM sensor data as follows:

function decodeUplink(input) {
  
  var voltage = ((input.bytes[0] << 8) | input.bytes[1]) / 100.0; 
  var current = ((input.bytes[2] << 8) | input.bytes[3]) / 100.0; 
  var power = ((input.bytes[4] << 8) | input.bytes[5]) / 10.0;    
  var energy = ((input.bytes[6] << 8) | input.bytes[7]) / 10.0;   
  
  return {
    data: {
      voltage: voltage,
      current: current,
      power: power,
      energy: energy
    }
  };
}

Now , my problem is I could not establish UART communication in PZEM sensor, which can be seen in PZEM-004T 100A datasheet . In the code below, I previously managed to establish UART communication with the PZEM sensor and successfully sent data over LoRa.

//PZEM
#include <PZEM004Tv30.h>
//LoRa
#include <SPI.h>
#include <LoRa.h>
//Libraries for OLED Display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define RX_PIN 34
#define TX_PIN 25

#define SCK 5 
#define MISO 19
#define MOSI 27
#define SS 18
#define RST 23
#define DIO0 26

#define BAND 866E6 //Available bandwidth for EU

//OLED pins
#define OLED_SDA 21
#define OLED_SCL 22 
#define OLED_RST -1
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RST);
HardwareSerial SerialPort(1); //Note that SerialPort(0) is the USB port, which might conflict with Serial Monitor.
PZEM004Tv30 pzem(SerialPort, RX_PIN, TX_PIN);

void setup() {
  //initialize Serial Monitor
  Serial.begin(115200);
  SerialPort.begin(9600, SERIAL_8N1, RX_PIN, TX_PIN); 

  //Reset OLED display via software
  pinMode(OLED_RST, OUTPUT);
  digitalWrite(OLED_RST, LOW);
  delay(20);
  digitalWrite(OLED_RST, HIGH);

  //Initialize OLED
  Wire.begin(OLED_SDA, OLED_SCL);
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c, false, false)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Stop, loop forever
  }

  display.clearDisplay();
  display.setTextColor(WHITE);
  display.setTextSize(1);
  display.setCursor(0,0);
  display.print("LORA PZEM SENDER");
  display.display();
  
  Serial.println("LoRa PZEM Test");

  //SPI LoRa pins
  SPI.begin(SCK, MISO, MOSI, SS);

  //Setup LoRa transceiver module
  LoRa.setPins(SS, RST, DIO0);
  
  if (!LoRa.begin(BAND)) {
    Serial.println("Starting LoRa failed!");
    while (1);
  }
  Serial.println("LoRa Initializing OK!");
  display.setCursor(0,10);
  display.print("LoRa Initializing OK!");
  display.display();
  delay(2000);
}

void loop() {
  float voltage = pzem.voltage();
  float current = pzem.current();
  float power = pzem.power();
   
  Serial.println("Sending Packet");
  
  //Send LoRa packet to receiver
  LoRa.beginPacket();
  LoRa.printf("V: %.2f V\nI: %.2f A\nP: %.2f W\n", voltage, current, power);
  LoRa.endPacket();

  // Update OLED display  
  display.clearDisplay();
  display.setCursor(0,0);
  display.println("LORA SENDER");
  display.setCursor(0,10);
  display.setTextSize(1);
  display.print("PZEM SENSOR");
  display.setCursor(0,20);
  display.print("V: ");
  display.print(voltage);
  display.setCursor(0,30);
  display.print("I: ");
  display.print(current);
  display.setCursor(0,40);
  display.print("P: ");
  display.print(power);
  display.display();
  
  // Monitor measurements from serial
  Serial.println(voltage);
  Serial.println(current);
  Serial.println(power);

  delay(2000);
}

In this code, I’m aware that data is sent via LoRa, not LoRaWAN. However, I previously managed to get UART communication to work, but in my RadioLib_OTAA code, it fails which I could not figure out.
The RadioLib_OTAA code with PZEM integration ,

#include <PZEM004Tv30.h>
#include <RadioLib.h>
#include "LoRaBoards.h"

#define RX_PIN 34 //it is an input only pin but using it won't be a problem because it is using for only receiving.
#define TX_PIN 25

#if  defined(USING_SX1276)
SX1276 radio = new Module(RADIO_CS_PIN, RADIO_DIO0_PIN, RADIO_RST_PIN, RADIO_DIO1_PIN);
#elif defined(USING_SX1262)
SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#elif defined(USING_SX1278)
SX1278 radio = new Module(RADIO_CS_PIN, RADIO_DIO0_PIN, RADIO_RST_PIN, RADIO_DIO1_PIN);
#elif   defined(USING_LR1121)
LR1121 radio = new Module(RADIO_CS_PIN, RADIO_DIO9_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN);
#endif

// joinEUI - previous versions of LoRaWAN called this AppEUI
// for development purposes you can use all zeros - see wiki for details
#define RADIOLIB_LORAWAN_JOIN_EUI  0x0000000000000000


// the Device EUI & two keys can be generated on the TTN console
#ifndef RADIOLIB_LORAWAN_DEV_EUI   // Replace with your Device EUI
#define RADIOLIB_LORAWAN_DEV_EUI   0x---------------
#endif
#ifndef RADIOLIB_LORAWAN_APP_KEY   // Replace with your App Key 
#define RADIOLIB_LORAWAN_APP_KEY   0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
#endif
#ifndef RADIOLIB_LORAWAN_NWK_KEY   // Put your Nwk Key here
#define RADIOLIB_LORAWAN_NWK_KEY   0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--, 0x--
#endif

// how often to send an uplink - consider legal & FUP constraints - see notes
const uint32_t uplinkIntervalSeconds = 5UL * 60UL;    // minutes x seconds


// for the curious, the #ifndef blocks allow for automated testing &/or you can
// put your EUI & keys in to your platformio.ini - see wiki for more tips

// regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500
const LoRaWANBand_t Region = EU868;
const uint8_t subBand = 0;  // For US915, change this to 2, otherwise leave on 0

// ============================================================================


// copy over the EUI's & keys in to the something that will not compile if incorrectly formatted
uint64_t joinEUI =   RADIOLIB_LORAWAN_JOIN_EUI;
uint64_t devEUI  =   RADIOLIB_LORAWAN_DEV_EUI;
uint8_t appKey[] = { RADIOLIB_LORAWAN_APP_KEY };
uint8_t nwkKey[] = { RADIOLIB_LORAWAN_NWK_KEY };

// create the LoRaWAN node
LoRaWANNode node(&radio, &Region, subBand);
HardwareSerial SerialPort(1); //note that SerialPort(0) is same port with Serial monitor so it will be cause code uploading errors. 
PZEM004Tv30 pzem(SerialPort, RX_PIN, TX_PIN);


// result code to text - these are error codes that can be raised when using LoRaWAN
// however, RadioLib has many more - see https://jgromes.github.io/RadioLib/group__status__codes.html for a complete list
String stateDecode(const int16_t result)
{
    switch (result) {
    case RADIOLIB_ERR_NONE:
        return "ERR_NONE";
    case RADIOLIB_ERR_CHIP_NOT_FOUND:
        return "ERR_CHIP_NOT_FOUND";
    case RADIOLIB_ERR_PACKET_TOO_LONG:
        return "ERR_PACKET_TOO_LONG";
    case RADIOLIB_ERR_RX_TIMEOUT:
        return "ERR_RX_TIMEOUT";
    case RADIOLIB_ERR_CRC_MISMATCH:
        return "ERR_CRC_MISMATCH";
    case RADIOLIB_ERR_INVALID_BANDWIDTH:
        return "ERR_INVALID_BANDWIDTH";
    case RADIOLIB_ERR_INVALID_SPREADING_FACTOR:
        return "ERR_INVALID_SPREADING_FACTOR";
    case RADIOLIB_ERR_INVALID_CODING_RATE:
        return "ERR_INVALID_CODING_RATE";
    case RADIOLIB_ERR_INVALID_FREQUENCY:
        return "ERR_INVALID_FREQUENCY";
    case RADIOLIB_ERR_INVALID_OUTPUT_POWER:
        return "ERR_INVALID_OUTPUT_POWER";
    case RADIOLIB_ERR_NETWORK_NOT_JOINED:
        return "RADIOLIB_ERR_NETWORK_NOT_JOINED";
    case RADIOLIB_ERR_DOWNLINK_MALFORMED:
        return "RADIOLIB_ERR_DOWNLINK_MALFORMED";
    case RADIOLIB_ERR_INVALID_REVISION:
        return "RADIOLIB_ERR_INVALID_REVISION";
    case RADIOLIB_ERR_INVALID_PORT:
        return "RADIOLIB_ERR_INVALID_PORT";
    case RADIOLIB_ERR_NO_RX_WINDOW:
        return "RADIOLIB_ERR_NO_RX_WINDOW";
    case RADIOLIB_ERR_INVALID_CID:
        return "RADIOLIB_ERR_INVALID_CID";
    case RADIOLIB_ERR_UPLINK_UNAVAILABLE:
        return "RADIOLIB_ERR_UPLINK_UNAVAILABLE";
    case RADIOLIB_ERR_COMMAND_QUEUE_FULL:
        return "RADIOLIB_ERR_COMMAND_QUEUE_FULL";
    case RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND:
        return "RADIOLIB_ERR_COMMAND_QUEUE_ITEM_NOT_FOUND";
    case RADIOLIB_ERR_JOIN_NONCE_INVALID:
        return "RADIOLIB_ERR_JOIN_NONCE_INVALID";
    case RADIOLIB_ERR_N_FCNT_DOWN_INVALID:
        return "RADIOLIB_ERR_N_FCNT_DOWN_INVALID";
    case RADIOLIB_ERR_A_FCNT_DOWN_INVALID:
        return "RADIOLIB_ERR_A_FCNT_DOWN_INVALID";
    case RADIOLIB_ERR_DWELL_TIME_EXCEEDED:
        return "RADIOLIB_ERR_DWELL_TIME_EXCEEDED";
    case RADIOLIB_ERR_CHECKSUM_MISMATCH:
        return "RADIOLIB_ERR_CHECKSUM_MISMATCH";
    case RADIOLIB_ERR_NO_JOIN_ACCEPT:
        return "RADIOLIB_ERR_NO_JOIN_ACCEPT";
    case RADIOLIB_LORAWAN_SESSION_RESTORED:
        return "RADIOLIB_LORAWAN_SESSION_RESTORED";
    case RADIOLIB_LORAWAN_NEW_SESSION:
        return "RADIOLIB_LORAWAN_NEW_SESSION";
    case RADIOLIB_ERR_NONCES_DISCARDED:
        return "RADIOLIB_ERR_NONCES_DISCARDED";
    case RADIOLIB_ERR_SESSION_DISCARDED:
        return "RADIOLIB_ERR_SESSION_DISCARDED";
    }
    return "See https://jgromes.github.io/RadioLib/group__status__codes.html";
}

// helper function to display any issues
void debug(bool failed, const __FlashStringHelper *message, int state, bool halt)
{
    if (failed) {
        Serial.print(message);
        Serial.print(" - ");
        Serial.print(stateDecode(state));
        Serial.print(" (");
        Serial.print(state);
        Serial.println(")");
        while (halt) {
            delay(1);
        }
    }
}

// helper function to display a byte array
void arrayDump(uint8_t *buffer, uint16_t len)
{
    for (uint16_t c = 0; c < len; c++) {
        char b = buffer[c];
        if (b < 0x10) {
            Serial.print('0');
        }
        Serial.print(b, HEX);
    }
    Serial.println();
}


void setup()
{
    Serial.begin(115200);
    while (!Serial);

    setupBoards();

#ifdef  RADIO_TCXO_ENABLE
    pinMode(RADIO_TCXO_ENABLE, OUTPUT);
    digitalWrite(RADIO_TCXO_ENABLE, HIGH);
#endif

    delay(5000);  // Give time to switch to the serial monitor

    Serial.println(F("\nSetup ... "));

    Serial.println(F("Initialise the radio"));

    int16_t state = 0;  // return value for calls to RadioLib
    Serial.println(F("Initialise the radio"));
    state = radio.begin();
    debug(state != RADIOLIB_ERR_NONE, F("Initialise radio failed"), state, true);

#ifdef USING_DIO2_AS_RF_SWITCH
#ifdef USING_SX1262
    // Some SX126x modules use DIO2 as RF switch. To enable
    // this feature, the following method can be used.
    // NOTE: As long as DIO2 is configured to control RF switch,
    //       it can't be used as interrupt pin!
    if (radio.setDio2AsRfSwitch() != RADIOLIB_ERR_NONE) {
        Serial.println(F("Failed to set DIO2 as RF switch!"));
        while (true);
    }
#endif //USING_SX1262
#endif //USING_DIO2_AS_RF_SWITCH

#ifdef RADIO_SWITCH_PIN
    // T-MOTION
    const uint32_t pins[] = {
        RADIO_SWITCH_PIN, RADIO_SWITCH_PIN, RADIOLIB_NC,
    };
    static const Module::RfSwitchMode_t table[] = {
        {Module::MODE_IDLE,  {0,  0} },
        {Module::MODE_RX,    {1, 0} },
        {Module::MODE_TX,    {0, 1} },
        END_OF_MODE_TABLE,
    };
    radio.setRfSwitchTable(pins, table);
#endif

#if  defined(USING_LR1121)
    // LR1121
    // set RF switch configuration for Wio WM1110
    // Wio WM1110 uses DIO5 and DIO6 for RF switching
    static const uint32_t rfswitch_dio_pins[] = {
        RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6,
        RADIOLIB_NC, RADIOLIB_NC, RADIOLIB_NC
    };

    static const Module::RfSwitchMode_t rfswitch_table[] = {
        // mode                  DIO5  DIO6
        { LR11x0::MODE_STBY,   { LOW,  LOW  } },
        { LR11x0::MODE_RX,     { HIGH, LOW  } },
        { LR11x0::MODE_TX,     { LOW,  HIGH } },
        { LR11x0::MODE_TX_HP,  { LOW,  HIGH } },
        { LR11x0::MODE_TX_HF,  { LOW,  LOW  } },
        { LR11x0::MODE_GNSS,   { LOW,  LOW  } },
        { LR11x0::MODE_WIFI,   { LOW,  LOW  } },
        END_OF_MODE_TABLE,
    };
    radio.setRfSwitchTable(rfswitch_dio_pins, rfswitch_table);

    // LR1121 TCXO Voltage 2.85~3.15V
    radio.setTCXO(3.0);
#endif

    // Override the default join rate
    uint8_t joinDR = 4;

    // Setup the OTAA session information
    node.beginOTAA(joinEUI, devEUI, nwkKey, appKey);

    Serial.println(F("Join ('login') the LoRaWAN Network"));
    state = node.activateOTAA(joinDR);
    debug(state != RADIOLIB_LORAWAN_NEW_SESSION, F("Join failed"), state, true);

    // Print the DevAddr
    Serial.print("[LoRaWAN] DevAddr: ");
    Serial.println((unsigned long)node.getDevAddr(), HEX);

    // Enable the ADR algorithm (on by default which is preferable)
    node.setADR(true);

    // Set a datarate to start off with
    node.setDatarate(5);

    // Manages uplink intervals to the TTN Fair Use Policy
    node.setDutyCycle(true, 1250);

    // Enable the dwell time limits - 400ms is the limit for the US
    node.setDwellTime(true, 400);

    Serial.println(F("Ready!\n"));

    if (u8g2) {
        u8g2->clearBuffer();
        u8g2->setFont(u8g2_font_NokiaLargeBold_tf );
        uint16_t str_w =  u8g2->getStrWidth(BOARD_VARIANT_NAME);
        u8g2->drawStr((u8g2->getWidth() - str_w) / 2, 16, BOARD_VARIANT_NAME);
        u8g2->drawHLine(5, 21, u8g2->getWidth() - 5);

        u8g2->setCursor(0, 38);
        u8g2->print("Join LoRaWAN Ready!");
        u8g2->sendBuffer();
    }
}


void loop()
{
    int16_t state = RADIOLIB_ERR_NONE;

    // set battery fill level - the LoRaWAN network server
    // may periodically request this information
    // 0 = external power source
    // 1 = lowest (empty battery)
    // 254 = highest (full battery)
    // 255 = unable to measure
    uint8_t battLevel = 146;
    node.setDeviceStatus(battLevel);

     // This is the place to gather the sensor inputs
    float voltage = pzem.voltage();
    float current = pzem.current();
    float power = pzem.power();
    float energy = pzem.energy();

     // Build payload byte array
    uint8_t uplinkPayload[8];
    uplinkPayload[0] = (uint16_t)(voltage * 100) >> 8;      // V (high byte)
    uplinkPayload[1] = (uint16_t)(voltage * 100) & 0xFF;    // V(low byte)
    uplinkPayload[2] = (uint16_t)(current * 100) >> 8;      // I (high byte)
    uplinkPayload[3] = (uint16_t)(current * 100) & 0xFF;    // I (low byte)
    uplinkPayload[4] = (uint16_t)(power * 10) >> 8;         // P (high byte)
    uplinkPayload[5] = (uint16_t)(power * 10) & 0xFF;       // P (low byte)
    uplinkPayload[6] = (uint16_t)(energy * 10) >> 8;        // E (high byte)
    uplinkPayload[7] = (uint16_t)(energy * 10) & 0xFF;      // E (low byte)


    uint8_t downlinkPayload[10];  // Make sure this fits your plans!
    size_t  downlinkSize;         // To hold the actual payload size received

    // you can also retrieve additional information about an uplink or
    // downlink by passing a reference to LoRaWANEvent_t structure
    LoRaWANEvent_t uplinkDetails;
    LoRaWANEvent_t downlinkDetails;

    uint8_t fPort = 10;

    // Retrieve the last uplink frame counter
    uint32_t fCntUp = node.getFCntUp();

    // Send a confirmed uplink on the second uplink
    // and also request the LinkCheck and DeviceTime MAC commands
    Serial.println(F("Sending uplink"));
    if (fCntUp == 1) {
        Serial.println(F("and requesting LinkCheck and DeviceTime"));
        node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_LINK_CHECK);
        node.sendMacCommandReq(RADIOLIB_LORAWAN_MAC_DEVICE_TIME);
        state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), fPort, downlinkPayload, &downlinkSize, true, &uplinkDetails, &downlinkDetails);
    } else {
        state = node.sendReceive(uplinkPayload, sizeof(uplinkPayload), fPort, downlinkPayload, &downlinkSize, false, &uplinkDetails, &downlinkDetails);
    }
    debug(state < RADIOLIB_ERR_NONE, F("Error in sendReceive"), state, false);

    // Check if a downlink was received
    // (state 0 = no downlink, state 1/2 = downlink in window Rx1/Rx2)
    if (state > 0) {
        Serial.println(F("Received a downlink"));
        // Did we get a downlink with data for us
        if (downlinkSize > 0) {
            Serial.println(F("Downlink data: "));
            arrayDump(downlinkPayload, downlinkSize);
        } else {
            Serial.println(F("<MAC commands only>"));
        }

        // print RSSI (Received Signal Strength Indicator)
        Serial.print(F("[LoRaWAN] RSSI:\t\t"));
        Serial.print(radio.getRSSI());
        Serial.println(F(" dBm"));

        // print SNR (Signal-to-Noise Ratio)
        Serial.print(F("[LoRaWAN] SNR:\t\t"));
        Serial.print(radio.getSNR());
        Serial.println(F(" dB"));

        // print extra information about the event
        Serial.println(F("[LoRaWAN] Event information:"));
        Serial.print(F("[LoRaWAN] Confirmed:\t"));
        Serial.println(downlinkDetails.confirmed);
        Serial.print(F("[LoRaWAN] Confirming:\t"));
        Serial.println(downlinkDetails.confirming);
        Serial.print(F("[LoRaWAN] Datarate:\t"));
        Serial.println(downlinkDetails.datarate);
        Serial.print(F("[LoRaWAN] Frequency:\t"));
        Serial.print(downlinkDetails.freq, 3);
        Serial.println(F(" MHz"));
        Serial.print(F("[LoRaWAN] Frame count:\t"));
        Serial.println(downlinkDetails.fCnt);
        Serial.print(F("[LoRaWAN] Port:\t\t"));
        Serial.println(downlinkDetails.fPort);
        Serial.print(F("[LoRaWAN] Time-on-air: \t"));
        Serial.print(node.getLastToA());
        Serial.println(F(" ms"));
        Serial.print(F("[LoRaWAN] Rx window: \t"));
        Serial.println(state);

        uint8_t margin = 0;
        uint8_t gwCnt = 0;
        if (node.getMacLinkCheckAns(&margin, &gwCnt) == RADIOLIB_ERR_NONE) {
            Serial.print(F("[LoRaWAN] LinkCheck margin:\t"));
            Serial.println(margin);
            Serial.print(F("[LoRaWAN] LinkCheck count:\t"));
            Serial.println(gwCnt);
        }

        uint32_t networkTime = 0;
        uint8_t fracSecond = 0;
        if (node.getMacDeviceTimeAns(&networkTime, &fracSecond, true) == RADIOLIB_ERR_NONE) {
            Serial.print(F("[LoRaWAN] DeviceTime Unix:\t"));
            Serial.println(networkTime);
            Serial.print(F("[LoRaWAN] DeviceTime second:\t1/"));
            Serial.println(fracSecond);
        }

    } else {
        Serial.println(F("[LoRaWAN] No downlink received"));
    }

    // wait before sending another packet
    uint32_t minimumDelay = uplinkIntervalSeconds * 1000UL;
    uint32_t interval = node.timeUntilUplink();     // calculate minimum duty cycle delay (per FUP & law!)
    uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows

    Serial.print(F("[LoRaWAN] Next uplink in "));
    Serial.print(delayMs / 1000);
    Serial.println(F(" seconds\n"));

    delay(delayMs);
}

When I commented out all sections in the loop() except for PZEM readings, such as float voltage = pzem.voltage(); and Serial.println(voltage);, UART communication with the sensor seems to work fine.

The issue appears to stem from something in the setup() section. I know it’s unreasonable to expect anyone to find the exact line causing the issue, but your suggestions have been very valuable to me. Thank you very much for the help and insights you’ve provided so far.

Do you take the fair use policy into account? Just 10 downlinks a day per device. And for scalability you should limit downlinks to one or two a week.

1 Like

Before the gateway was disconnected yesterday (it shows as 16 hours ago on TTN), I see it received 22 uplinks and 15 downlinks. According to the FUP, it’s 10 per node, as you mentioned. I hadn’t paid attention to this :slight_smile: Thank you for the information. But it seems I violated downlink limit , but it did not cause a problem. Maybe I got some downlinks from my another end devices which did not exceed 10 for per device.

Maybe not for you, but as you are on TTN, a shared community network that includes the infrastructure, you never know what impact downlinks may have on other users.

If you need that many downlinks, then LoRaWAN may not be the right technology for your use case.

As to your second problem, always better to open a new topic so the topic is clearer, perhaps you forgot to provide the PZEM with a serial port to use?

1 Like

I forgot to add

SerialPort.begin()

while I rewrited the code in the forum , but the actual code which I tried to run , I added it as ;

SerialPort(9600 , SERIAL_8N1 , RX_PIN , TX_PIN);
but it did not work , thank you so much for your helps ,

You can’t be sure what issues it might have caused other LoRaWAN users. And ‘borrowing’ downlinks from other devices is not happening.

You should limit downlinks to the absolute minimum your application requires. Why you wonder, because gateways are asymmetrical, they can receive 8 uplinks in parallel but only transmit one downlink at a time. And to make things worse, during transmission a gateway can not receive a single uplink. LoRaWAN is designed to be a mostly (with moderate frequency) uplink and very seldomly downlink protocol for small packets of sensor data. If your use case requires large amounts of data or frequent downlinks you need to look at another protocol.

1 Like