Skip to Content

← All functionalities

Water pumping (sanitation)ESP32 PLC 38ARGPIOControl

Dual pump station with alternation and LoRaWAN telemetry

When a pumping station is an hour's drive away and has no network coverage, you need two things: a controller that survives a pump failure on its own, and telemetry that works without WiFi. This example runs a dual-pump station with automatic alternation and failover on an ESP32 PLC 38AR, and reports everything over LoRaWAN in a 4-byte frame — battery-friendly and free of SIM cards.

Alternation and failover

Each filling cycle starts the opposite pump, balancing wear between the two motors. If the running pump trips (thermal relay or missing contactor confirmation), the controller switches to the healthy one and flags the error — the station keeps pumping with a degraded redundancy instead of flooding.

Three FreeRTOS tasks, three responsibilities

Control runs every 100 ms; the LoRaWAN task sends a frame every 60 s; a third task re-joins OTAA every hour as a communications watchdog. Separating them means a slow radio never blocks the pump logic — the dual-core ESP32 handles this naturally.

4 bytes that tell the whole story

Eleven digital inputs, two outputs, two error flags and a 10-bit analog level probe are bit-packed into 4 bytes. Small frames mean lower airtime, better LoRaWAN duty-cycle compliance and longer range on high spreading factors.

A snippet from the implementation

Straight from the example as deployed on the ESP32 PLC 38AR — copy it freely:

void setup() {
  Serial.begin(115200);
  const int ins[] = {I_MIN, I_MAX, I_OVERLVL, I_RESET, I_MAN_P1, I_MAN_P2,
                     I_CONF_P1, I_CONF_P2, I_THERM_P1, I_THERM_P2};
  for (int p : ins) pinMode(p, INPUT);
  pinMode(Q_P1, OUTPUT); pinMode(Q_P2, OUTPUT); pinMode(Q_PILOT, OUTPUT);
  stopAll();

  lora_init(57600);                             // RN2xx3 via SerialSC1
  lora_join_otaa("APP_EUI", "APP_KEY");

  xTaskCreate(vTaskControl, "control", 4096, NULL, 3, NULL);
  xTaskCreate(vTaskLora,    "lora",    4096, NULL, 1, NULL);
  xTaskCreate(vTaskRejoin,  "rejoin",  4096, NULL, 2, NULL);
}

The full example is a complete program — wiring header, setup and main loop — ready to adapt to your application.

Frequently asked questions

What LoRa module does this use?

Any RN2xx3-style modem on the PLC serial port. The lora_init/lora_join_otaa calls map to the module commands — see the LoRaWAN template in our solution catalog.

Why bit-pack instead of sending JSON?

LoRaWAN payloads are precious: 4 bytes versus ~200 bytes of JSON is the difference between SF12-compatible frames and messages that do not fit the duty cycle.

How is the analog level probe wired?

A 4-20 mA level transmitter on input I0_11, read as 0-1023 and sent as 10 bits in the frame.

Related functionalities