Ir al contenido

← Bit packing de payload LoRaWAN en un PLC ESP32 (4 bytes)

Bombeo de agua (saneamiento)ESP32 PLC 14 / 38ARLoRaWANComunicación

Bit packing de payload LoRaWAN en un PLC ESP32 (4 bytes) — ejemplo completo

Comprime 11 entradas digitales, flags de error y una sonda de 10 bits en un payload LoRaWAN de 4 bytes en un PLC ESP32. Ejemplo real de bit packing en Arduino.

Programa completo y ejecutable para el ESP32 PLC 14 / 38AR (lorawan-telemetry-bitpacking.ino): incluye cabecera de conexionado, requisitos y notas de integración.

Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales

Vista de solo lectura.

/*
 * COMPLETE EXAMPLE — LoRaWAN OTAA telemetry with bit packing (4 bytes)
 *
 * Hardware: ESP32 PLC 38AR (Industrial Shields) + LoRa RN2xx3 module (EU868)
 * Based on: water pumping project (sanitation), bombament-2b-38ar.ino
 *
 * Wiring:
 *   I0_0..I0_9  Eleven digital signals of the station (float switches, selectors,
 *   I0_10       contactor feedback, thermal relays...) — see pins[] table
 *   I0_11       4-20 mA level sensor (analog, 0-1023)
 *   Q0_0        Pump 1 contactor         Q0_1  Pump 2 contactor
 *
 * Logic:
 *   The whole station state fits in a 4-byte frame:
 *     byte 0      : digital inputs 0..7                  (1 bit each)
 *     byte 1      : inputs 8..10 + padding               (bits 7..5)
 *     byte 2      : confirmation/fault flags (bits 7,6) + sensor bits 10..8
 *     byte 3      : level sensor, low 8 bits
 *   Transmitted over LoRaWAN (OTAA, EU868) every 60 s. 4 bytes versus ~200 of
 *   a JSON: less airtime, duty-cycle compliance even at SF12.
 *
 * Integration: the frame is the same one decoded by the dual control example
 * (ejemplos/bombeo-agua/dual-pump-control-lorawan-38ar.ino); the network
 * server decoder only has to undo the bit shifts.
 */

// --- I/O map (ESP32 PLC 38AR pins, industrialshields-arduino library)
#define I_LEVEL_SENSOR  I0_11
#define Q_P1            Q0_0
#define Q_P2            Q0_1

// Eleven digital inputs in the same order as the frame in the original project
const int pins[] = {I0_0, I0_1, I0_2, I0_3, I0_4, I0_5,
                    I0_6, I0_7, I0_8, I0_9, I0_10};
const uint8_t NUM_INPUTS = sizeof(pins) / sizeof(pins[0]);   // = 11

// --- State to transmit
bool     inputs_d[11];              // copy of the digital inputs
bool     confirmation_p1 = false;   // flag: contactor confirmation failure
bool     fault_p1        = false;   // flag: thermal relay tripped
uint16_t sensor_level    = 0;       // 10-bit analog (0-1023)

const uint32_t SEND_PERIOD_MS = 60000;   // 60 s between frames
uint32_t t_last_send = 0;

// ------------------------------------------------- Packing: state -> 4 bytes
void pack_and_send() {
  byte message[4] = {0, 0, 0, 0};

  // Digital inputs: 1 bit per signal, MSB first (i/8 picks the byte,
  // 7 - i%8 places the bit). 11 inputs fill byte 0 and 3 bits of byte 1.
  for (uint8_t i = 0; i < NUM_INPUTS; i++)
    message[i / 8] |= inputs_d[i] << (7 - i % 8);

  // Error flags in the high bits of byte 2
  message[2] |= confirmation_p1 << 7;
  message[2] |= fault_p1        << 6;

  // 10-bit analog sensor split between byte 2 (bits 10..8) and byte 3
  message[2] |= (sensor_level & 0x0700) >> 8;
  message[3] |=  sensor_level & 0xFF;

  lora_send_bytes(message, 4);      // unconfirmed uplink, default port

  Serial.printf("[lora] frame: %02X %02X %02X %02X (sensor=%u)\n",
                message[0], message[1], message[2], message[3], sensor_level);
}

// ------------------------------------------------- Signal acquisition
void read_station() {
  for (uint8_t i = 0; i < NUM_INPUTS; i++)
    inputs_d[i] = digitalRead(pins[i]);

  sensor_level = analogRead(I_LEVEL_SENSOR);   // 4-20 mA -> 0-1023

  // Flag example: thermal relay on I0_8, feedback expected on I0_6 with Q0_0 active
  fault_p1        = inputs_d[8];
  confirmation_p1 = digitalRead(Q_P1) && !inputs_d[6];
}

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

  for (uint8_t i = 0; i < NUM_INPUTS; i++) pinMode(pins[i], INPUT);
  pinMode(I_LEVEL_SENSOR, INPUT);
  pinMode(Q_P1, OUTPUT);
  pinMode(Q_P2, OUTPUT);

  // OTAA join: the network server derives the session keys on every join.
  // Credentials: placeholders — use the ones from your LoRaWAN application.
  lora_init(57600);                          // RN2xx3 via SerialSC1, EU868 band
  while (!lora_join_otaa("APP_EUI", "APP_KEY")) {
    Serial.println("[lora] join failed, retrying in 30 s");
    delay(30000);
  }
  Serial.println("[lora] OTAA join successful");
}

void loop() {
  read_station();

  // The pump control logic would go here — see the state machine and the
  // dual control with alternation in the catalog. This example focuses
  // on telemetry.

  if (millis() - t_last_send >= SEND_PERIOD_MS) {
    t_last_send = millis();
    pack_and_send();
  }

  delay(100);
}
Descarga el pack completo del proyecto — gratisEste ejemplo + los relacionados + lista de materiales