C++ code library
Tested, reusable examples to speed up industrial ESP32 firmware development.
Non-blocking automatic Wi-Fi reconnection
Manages the ESP32 Wi-Fi connection asynchronously, restoring the signal without interrupting the main loop.
| 1 | #include <WiFi.h> |
| 2 | |
| 3 | const char* SSID = "REDE_INDUSTRIAL"; |
| 4 | const char* PASSWORD = "SENHA_INDUSTRIAL"; |
| 5 | unsigned long lastWifiCheck = 0; |
| 6 | |
| 7 | void handleWiFi() { |
| 8 | if (WiFi.status() != WL_CONNECTED) { |
| 9 | if (millis() - lastWifiCheck > 10000) { |
| 10 | lastWifiCheck = millis(); |
| 11 | Serial.println("[Wi-Fi] Tentando reconectar..."); |
| 12 | WiFi.disconnect(); |
| 13 | WiFi.reconnect(); |
| 14 | } |
| 15 | } |
| 16 | } |
| 17 | |
| 18 | void setup() { |
| 19 | Serial.begin(115200); |
| 20 | WiFi.mode(WIFI_STA); |
| 21 | WiFi.begin(SSID, PASSWORD); |
| 22 | } |
| 23 | |
| 24 | void loop() { |
| 25 | handleWiFi(); |
| 26 | // Seu código de automação continua rodando sem travar |
| 27 | } |
Publishing JSON MQTT telemetry with PubSubClient
Builds a structured JSON payload with ArduinoJson and sends it periodically to an MQTT broker.
| 1 | #include <WiFi.h> |
| 2 | #include <PubSubClient.h> |
| 3 | #include <ArduinoJson.h> |
| 4 | |
| 5 | WiFiClient espClient; |
| 6 | PubSubClient client(espClient); |
| 7 | |
| 8 | void publishTelemetry(float temp, float pressao, int pecas) { |
| 9 | JsonDocument doc; |
| 10 | doc["dev_id"] = "ESP32_GW01"; |
| 11 | doc["temperatura"] = temp; |
| 12 | doc["pressao_bar"] = pressao; |
| 13 | doc["pecas_totais"] = pecas; |
| 14 | doc["uptime_ms"] = millis(); |
| 15 | |
| 16 | char buffer[256]; |
| 17 | size_t length = serializeJson(doc, buffer, sizeof(buffer)); |
| 18 | if (client.connected() && length > 0 && length < sizeof(buffer)) { |
| 19 | client.publish( |
| 20 | "industria/setor1/prensa01/telemetria", |
| 21 | reinterpret_cast<const uint8_t*>(buffer), |
| 22 | length |
| 23 | ); |
| 24 | } |
| 25 | } |
Reading Modbus RTU master registers over RS-485
Configures Serial2 and performs non-blocking reads of Holding registers (0x03) with the ModbusRTU library.
| 1 | #include <ModbusRTU.h> |
| 2 | |
| 3 | #define RX2_PIN 16 |
| 4 | #define TX2_PIN 17 |
| 5 | #define DE_RE_PIN 4 |
| 6 | |
| 7 | ModbusRTU mb; |
| 8 | uint16_t res[4]; |
| 9 | |
| 10 | bool cbRead(Modbus::ResultCode event, uint16_t transactionId, void* data) { |
| 11 | if (event == Modbus::EX_SUCCESS) { |
| 12 | Serial.printf("Tensoes lidas: L1=%d, L2=%d, L3=%d\n", res[0], res[1], res[2]); |
| 13 | } |
| 14 | return true; |
| 15 | } |
| 16 | |
| 17 | void setupModbus() { |
| 18 | Serial2.begin(9600, SERIAL_8N1, RX2_PIN, TX2_PIN); |
| 19 | mb.begin(&Serial2, DE_RE_PIN); |
| 20 | mb.master(); |
| 21 | } |
| 22 | |
| 23 | void readSlave() { |
| 24 | if (!mb.slave()) { |
| 25 | mb.readHreg(1, 0x0001, res, 3, cbRead); |
| 26 | } |
| 27 | mb.task(); |
| 28 | } |
RS-485 direction control (transmit/receive)
Switches the RS-485 transceiver DE/RE pin between transmit and receive modes.
| 1 | #define DE_RE_PIN 4 |
| 2 | |
| 3 | void setupRS485Direction() { |
| 4 | pinMode(DE_RE_PIN, OUTPUT); |
| 5 | digitalWrite(DE_RE_PIN, LOW); // Inicia em recepção |
| 6 | } |
| 7 | |
| 8 | void setRS485Transmit() { |
| 9 | digitalWrite(DE_RE_PIN, HIGH); |
| 10 | delayMicroseconds(10); |
| 11 | } |
| 12 | |
| 13 | void setRS485Receive() { |
| 14 | Serial2.flush(); // Garante envio dos bytes acumulados |
| 15 | digitalWrite(DE_RE_PIN, LOW); |
| 16 | } |
ESPAsyncWebServer with WebSockets for real-time state
A high-speed embedded web server that sends instantaneous data to the client browser.
| 1 | #include <WiFi.h> |
| 2 | #include <ESPAsyncWebServer.h> |
| 3 | |
| 4 | AsyncWebServer server(80); |
| 5 | AsyncWebSocket ws("/ws"); |
| 6 | |
| 7 | void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { |
| 8 | if (type == WS_EVT_CONNECT) { |
| 9 | client->text("{\"status\":\"CONECTADO_ESP32\"}"); |
| 10 | } |
| 11 | } |
| 12 | |
| 13 | void setupServer() { |
| 14 | ws.onEvent(onEvent); |
| 15 | server.addHandler(&ws); |
| 16 | server.begin(); |
| 17 | } |
ArduinoOTA setup for wireless flashing
Initializes the OTA firmware update service with a security password.
| 1 | #include <WiFi.h> |
| 2 | #include <ArduinoOTA.h> |
| 3 | |
| 4 | void setupOTA() { |
| 5 | ArduinoOTA.setHostname("esp32-node-01"); |
| 6 | ArduinoOTA.setPassword("TROQUE_POR_UMA_SENHA_FORTE"); |
| 7 | ArduinoOTA.onStart([]() { Serial.println("Iniciando OTA..."); }); |
| 8 | ArduinoOTA.begin(); |
| 9 | } |
| 10 | |
| 11 | void handleOTA() { |
| 12 | ArduinoOTA.handle(); // Chame continuamente dentro de loop() |
| 13 | } |
Digital input interrupt with software debounce
Accurately counts industrial sensor pulses with interrupts and rejects noise-induced false triggers.
| 1 | #define SENSOR_PIN 18 |
| 2 | volatile unsigned long pulseCount = 0; |
| 3 | volatile uint32_t lastPulseUs = 0; |
| 4 | |
| 5 | void IRAM_ATTR sensorISR() { |
| 6 | uint32_t now = micros(); |
| 7 | if (now - lastPulseUs >= 50000) { // 50 ms; ajuste à frequência máxima do sensor |
| 8 | pulseCount++; |
| 9 | lastPulseUs = now; |
| 10 | } |
| 11 | } |
| 12 | |
| 13 | void setupInterrupt() { |
| 14 | pinMode(SENSOR_PIN, INPUT_PULLUP); |
| 15 | attachInterrupt(digitalPinToInterrupt(SENSOR_PIN), sensorISR, FALLING); |
| 16 | } |
Reading a 4–20 mA sensor with ADS1115 I2C
High-precision differential analog reading (16-bit) for pressure and temperature transmitters.
| 1 | #include <Wire.h> |
| 2 | #include <Adafruit_ADS1X15.h> |
| 3 | |
| 4 | Adafruit_ADS1115 ads; |
| 5 | |
| 6 | bool setupADC() { |
| 7 | ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V |
| 8 | return ads.begin(); |
| 9 | } |
| 10 | |
| 11 | float readCurrentmA() { |
| 12 | int16_t adc0 = ads.readADC_SingleEnded(0); |
| 13 | float volts = ads.computeVolts(adc0); |
| 14 | // Resistor de 165 Ohms: 0,66 V a 3,30 V correspondem a 4 mA a 20 mA |
| 15 | float current_mA = (volts / 165.0) * 1000.0; |
| 16 | return current_mA; |
| 17 | } |
ESP-IDF / Arduino Task Watchdog Timer (esp_task_wdt)
Configures the Task WDT to restart the ESP32 if a task remains stuck for more than five seconds.
| 1 | #include <esp_task_wdt.h> |
| 2 | #include <esp_idf_version.h> |
| 3 | |
| 4 | #define WDT_TIMEOUT 5 // 5 segundos |
| 5 | |
| 6 | void setupWDT() { |
| 7 | #if ESP_IDF_VERSION_MAJOR >= 5 |
| 8 | esp_task_wdt_config_t config = { |
| 9 | .timeout_ms = WDT_TIMEOUT * 1000, |
| 10 | .idle_core_mask = (1 << portNUM_PROCESSORS) - 1, |
| 11 | .trigger_panic = true |
| 12 | }; |
| 13 | esp_err_t result = esp_task_wdt_init(&config); |
| 14 | if (result == ESP_ERR_INVALID_STATE) { |
| 15 | ESP_ERROR_CHECK(esp_task_wdt_reconfigure(&config)); |
| 16 | } else { |
| 17 | ESP_ERROR_CHECK(result); |
| 18 | } |
| 19 | #else |
| 20 | esp_err_t result = esp_task_wdt_init(WDT_TIMEOUT, true); |
| 21 | if (result != ESP_ERR_INVALID_STATE) { |
| 22 | ESP_ERROR_CHECK(result); |
| 23 | } |
| 24 | #endif |
| 25 | ESP_ERROR_CHECK(esp_task_wdt_add(NULL)); // Adiciona a tarefa atual |
| 26 | } |
| 27 | |
| 28 | void loop() { |
| 29 | esp_task_wdt_reset(); // Alimenta o cão de guarda |
| 30 | delay(1000); |
| 31 | } |
Reading and writing JSON files with LittleFS
Stores and retrieves industrial settings in ESP32 flash memory without relying on EEPROM.
| 1 | #include <LittleFS.h> |
| 2 | #include <ArduinoJson.h> |
| 3 | |
| 4 | bool setupStorage() { |
| 5 | return LittleFS.begin(false); // Não formata automaticamente em caso de falha |
| 6 | } |
| 7 | |
| 8 | bool saveConfig(const char* mqttServer, int port) { |
| 9 | File file = LittleFS.open("/config.json", FILE_WRITE); |
| 10 | if (!file) return false; |
| 11 | |
| 12 | JsonDocument doc; |
| 13 | doc["server"] = mqttServer; |
| 14 | doc["port"] = port; |
| 15 | |
| 16 | serializeJson(doc, file); |
| 17 | file.close(); |
| 18 | return true; |
| 19 | } |
| 20 | |
| 21 | bool loadConfig(String& mqttServer, int& port) { |
| 22 | File file = LittleFS.open("/config.json", FILE_READ); |
| 23 | if (!file) return false; |
| 24 | |
| 25 | JsonDocument doc; |
| 26 | DeserializationError error = deserializeJson(doc, file); |
| 27 | file.close(); |
| 28 | if (error || !doc["server"].is<const char*>() || !doc["port"].is<int>()) { |
| 29 | return false; |
| 30 | } |
| 31 | |
| 32 | mqttServer = doc["server"].as<const char*>(); |
| 33 | port = doc["port"].as<int>(); |
| 34 | return true; |
| 35 | } |
Secure MQTTS connection with an SSL/TLS certificate
Configures WiFiClientSecure with a complete CA certificate for encrypted MQTT communication.
| 1 | #include <WiFiClientSecure.h> |
| 2 | #include <PubSubClient.h> |
| 3 | |
| 4 | // Substitua o trecho abaixo pelo certificado CA PEM completo do seu broker. |
| 5 | const char* CA_CERT = |
| 6 | "-----BEGIN CERTIFICATE-----\n" |
| 7 | "MIIDSjCCAjqgAwIBAgIQRK+og6vx7zgO77/29GHHzTANBgkqhkiG9w0BAQsFADBh\n" |
| 8 | "...\n" |
| 9 | "-----END CERTIFICATE-----\n"; |
| 10 | |
| 11 | WiFiClientSecure secureClient; |
| 12 | PubSubClient mqttClient(secureClient); |
| 13 | |
| 14 | void setupSecureMQTT() { |
| 15 | secureClient.setCACert(CA_CERT); |
| 16 | mqttClient.setServer("broker.seudominio.com.br", 8883); |
| 17 | } |
Parsing and validating input JSON over MQTT/Web
Receives and deserializes JSON commands while validating required fields.
| 1 | #include <ArduinoJson.h> |
| 2 | |
| 3 | void parseCommandPayload(const uint8_t* payload, size_t length) { |
| 4 | JsonDocument doc; |
| 5 | DeserializationError error = deserializeJson(doc, payload, length); |
| 6 | |
| 7 | if (error) { |
| 8 | Serial.print("Falha ao ler JSON: "); |
| 9 | Serial.println(error.f_str()); |
| 10 | return; |
| 11 | } |
| 12 | |
| 13 | if (!doc["comando"].is<const char*>() || !doc["valor"].is<int>()) { |
| 14 | Serial.println("JSON sem os campos obrigatórios ou com tipos inválidos"); |
| 15 | return; |
| 16 | } |
| 17 | |
| 18 | const char* cmd = doc["comando"].as<const char*>(); |
| 19 | int valor = doc["valor"].as<int>(); |
| 20 | Serial.printf("Executando comando: %s com valor %d\n", cmd, valor); |
| 21 | } |
