Big ESP32 + SX127x topic part 2

On the picture below (been taken from this URL), we may see that there are some 0.96 OLED modules that needs no VCC and GND wires crossing.
This item seems to be one of them (with oval mounting holes).


Hello, I can not figure it out. Perhaps someone can make an instruction how to create a device on the EsP32 (heltek board, sx1276) from scratch. I tried, but I do not even compile the code above.

“I cannot figure it out”, figure out what?
You have a Heltec LoRa Wifi 32 board?
What do you mean with “instruction how to create a device”?
Which “above code” did not compile (and in which IDE)?

Have you read the topic start and have you tried running the ttn-abp and ttn-otaa examples first?

I have this board.
I want to make a final device with a configurable SF.
This code is not compiled

    #include <lmic.h>
    #include <hal/hal.h>
    #include <SPI.h>
    #include <U8x8lib.h>

    #define BUILTIN_LED 25

    // the OLED used
    U8X8_SSD1306_128X64_NONAME_SW_I2C u8x8(/* clock=*/ 15, /* data=*/ 4, /* reset=*/ 16);

    // LoRaWAN NwkSKey, network session key
    // This is the default Semtech key, which is used by the early prototype TTN
    // network.
    $$static const PROGMEM u1_t NWKSKEY[16] = { 0xAA, 0xCE, 0x88, 0x69, 0x05, 0xC6, 0xCE, 0xEF, 0x33, 0xF4, 0x76, 0xDC, 0xDC, 0x77, 0x67, 0x9F };

    // LoRaWAN AppSKey, application session key
    // This is the default Semtech key, which is used by the early prototype TTN
    // network.
    $$static const u1_t PROGMEM APPSKEY[16] = { 0x86, 0xF9, 0xB8, 0xC6, 0x69, 0x70, 0x63, 0x37, 0xCA, 0x12, 0xE0, 0x8D, 0xFF, 0xEC, 0x6A, 0xAA };

    // LoRaWAN end-device address (DevAddr)
    $$static const u4_t DEVADDR = 0x310313D8 ; // <-- Change this address for every node!

    // These callbacks are only used in over-the-air activation, so they are
    // left empty here (we cannot leave them out completely unless
    // DISABLE_JOIN is set in config.h, otherwise the linker will complain).
    void os_getArtEui (u1_t* buf) { }
    void os_getDevEui (u1_t* buf) { }
    void os_getDevKey (u1_t* buf) { }

    static uint8_t mydata[] = "Hi!";
    static osjob_t sendjob;

    // Schedule TX every this many seconds (might become longer due to duty
    // cycle limitations).
    const unsigned TX_INTERVAL = 10;

    // Pin mapping
    const lmic_pinmap lmic_pins = {
        .nss = 18,
        .rxtx = LMIC_UNUSED_PIN,
        .rst = 14,
        .dio = {26, 33, 32},

    void onEvent (ev_t ev) {
        u8x8.setCursor(0, 5);
        u8x8.printf("TIME %lu", os_getTime());
        Serial.print(": ");
        switch(ev) {
            case EV_SCAN_TIMEOUT:
                u8x8.drawString(0, 7, "EV_SCAN_TIMEOUT");
            case EV_BEACON_FOUND:
      u8x8.drawString(0, 7, "EV_BEACON_FOUND");
            case EV_BEACON_MISSED:
      u8x8.drawString(0, 7, "EV_BEACON_MISSED");
            case EV_BEACON_TRACKED:
      u8x8.drawString(0, 7, "EV_BEACON_TRACKED");
            case EV_JOINING:
      u8x8.drawString(0, 7, "EV_JOINING");
            case EV_JOINED:
      u8x8.drawString(0, 7, "EV_JOINED ");
            case EV_RFU1:
      u8x8.drawString(0, 7, "EV_RFUI");
            case EV_JOIN_FAILED:
      u8x8.drawString(0, 7, "EV_JOIN_FAILED");
            case EV_REJOIN_FAILED:
      u8x8.drawString(0, 7, "EV_REJOIN_FAILED");
            case EV_TXCOMPLETE:
                Serial.println(F("EV_TXCOMPLETE (includes waiting for RX windows)"));
                u8x8.drawString(0, 7, "EV_TXCOMPLETE");
                digitalWrite(BUILTIN_LED, LOW);
                if (LMIC.txrxFlags & TXRX_ACK)
                  Serial.println(F("Received ack"));
                u8x8.drawString(0, 7, "Received ACK");
                if (LMIC.dataLen) {
                  Serial.println(F("Received "));
        u8x8.drawString(0, 6, "RX ");
        u8x8.setCursor(4, 6);
        u8x8.printf("%i bytes", LMIC.dataLen);
                  Serial.println(F(" bytes of payload"));
        u8x8.setCursor(0, 7);
        u8x8.printf("RSSI %d SNR %.1d", LMIC.rssi, LMIC.snr);
                // Schedule next transmission
                os_setTimedCallback(&sendjob, os_getTime()+sec2osticks(TX_INTERVAL), do_send);
            case EV_LOST_TSYNC:
      u8x8.drawString(0, 7, "EV_LOST_TSYNC");
            case EV_RESET:
      u8x8.drawString(0, 7, "EV_RESET");
            case EV_RXCOMPLETE:
                // data received in ping slot
      u8x8.drawString(0, 7, "EV_RXCOMPLETE");
            case EV_LINK_DEAD:
      u8x8.drawString(0, 7, "EV_LINK_DEAD");
            case EV_LINK_ALIVE:
      u8x8.drawString(0, 7, "EV_LINK_ALIVE");
                Serial.println(F("Unknown event"));
      u8x8.setCursor(0, 7);
      u8x8.printf("UNKNOWN EVENT %d", ev);

    void do_send(osjob_t* j){
        // Check if there is not a current TX/RX job running
        if (LMIC.opmode & OP_TXRXPEND) {
            Serial.println(F("OP_TXRXPEND, not sending"));
    u8x8.drawString(0, 7, "OP_TXRXPEND, not sent");
        } else {
            // Prepare upstream data transmission at the next possible time.
            LMIC_setTxData2(1, mydata, sizeof(mydata)-1, 0);
            Serial.println(F("Packet queued"));
    u8x8.drawString(0, 7, "PACKET QUEUED");
    digitalWrite(BUILTIN_LED, HIGH);
        // Next TX is scheduled after TX_COMPLETE event.

    void setup() {
      u8x8.drawString(0, 1, "HelTec TX LMiC");

    #ifdef VCC_ENABLE
        // For Pinoccio Scout boards
        pinMode(VCC_ENABLE, OUTPUT);
        digitalWrite(VCC_ENABLE, HIGH);
    SPI.begin(5, 19, 27);
    // LMIC init
        // Reset the MAC state. Session and pending data transfers will be discarded.
       // Set static session parameters. Instead of dynamically establishing a session
        // by joining the network, precomputed session parameters are be provided.
        #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 (0x1, DEVADDR, nwkskey, appskey);
        // If not running an AVR with PROGMEM, just use the arrays directly
        LMIC_setSession (0x1, DEVADDR, NWKSKEY, APPSKEY);
       #if defined(CFG_eu868)
        // Set up the channels used by the Things Network, which corresponds
        // to the defaults of most gateways. Without this, only three base
        // channels from the LoRaWAN specification are used, which certainly
        // works, so it is good for debugging, but can overload those
        // frequencies, so be sure to configure the full frequency range of
        // your network here (unless your network autoconfigures them).
        // Setting up channels should happen after LMIC_setSession, as that
        // configures the minimal channel set.
        // NA-US channels 0-71 are configured automatically
        LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI);      // g-band
        LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7),  BAND_CENTI);      // g-band
        LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK,  DR_FSK),  BAND_MILLI);      // g2-band
        // TTN defines an additional channel at 869.525Mhz using SF9 for class B
        // devices' ping slots. LMIC does not have an easy way to define set this
        // frequency and support for class B is spotty and untested, so this
        // frequency is not configured here.
        #elif defined(CFG_us915)
        // NA-US channels 0-71 are configured automatically
        // but only one group of 8 should (a subband) should be active
        // TTN recommends the second sub band, 1 in a zero based count.
    // Disable link check validation
    // TTN uses SF9 for its RX2 window.
        LMIC.dn2Dr = DR_SF9;
    // Set data rate and transmit power for uplink (note: txpow seems to be ignored by the library)
    // Start job
        pinMode(BUILTIN_LED, OUTPUT);
        digitalWrite(BUILTIN_LED, LOW);


    void loop() {

Okay . I roughly realized my mistakes. Sorry for bothering

  1. Learn how to format your posts. Do not simply cut-and-paste code.
  2. If something does not compile, tell us what the issue is. Error messages? Show them.

Does anyone use Micropython to connect this board to the TTN? I cannot find a library that has those functions.

Hey! I have a Heltec Wifi Lora ESP32 board. When I tried running the ttn-abp code, it is able to send the payload once, and it won’t continue to send after that. In the serial monitor output, it never runs the EV_TXCOMPLETE.

In my config.h file, I have set it to #define CFG_us915 and #define CFG_sx1276_radio. I have set the appropriate network session key and application session key. Is there a wiring issue that I might’ve skipped over? Would it be on the TTN side of not configuring something?

const lmic_pinmap lmic_pins = {
    .nss = 18, 
    .rxtx = LMIC_UNUSED_PIN,
    .rst = 14,
    .dio = {/*dio0*/ 26, /*dio1*/ 33, /*dio2*/ 32}

:drum: :drum: :drum: :drum: :drum: :drum: :drum:


My optional 0.96 OLED front panel is a remix of this Thing .


I found another OLED with 1.3" and has the “strange” pin layout too :wink:
The overall size is high: 33.5mm width: 35.4mm
could you please give me the size of the board? I couldn’t find it. Thanks

My T-Beam’s PCB size is (LxH) : 100x33 mm

1 Like

It would be nice if you put the files online on Thingiverse and GitHub, too.

Sure I will, but not today.

Where is the best place to buy the Heltec Wifi LoRa 32?

you find it on some amazon sites, probably fastet way to get one. If you not, you can order it on Aliexpress.

1 Like

Cased my TTGO T-Beam, thanks to the creator of the case! Printed by 3d hubs print service.


1 Like

Can you say how much 3d hubs charged for the print ?

I paid 17,92€ including shipping (tracked). My order was routed to a print service in norther Germany (Joerg in Schortens).
4 days until delivery.

I see blue light coming from battery status LEDs, so you have one of the very first revisions of the T-Beam, right?
Does the window in the lid match your antenna connector ? I saw this picture before for the board similar to yours:


In the revision (t22_v6 21080705) of the T-Beam’s PCB that I’ve used while doing this enclosure design, antenna connector is in 1 mm off the centerline.

Yes, my TTGO T-Beam is probably an early type. Got it from Liliygo as sample for fitting paxcounter to it. Case matches exactly in all dimensions.