# Key Outcomes
±0.5%
Flow Accuracy
<10ms
Alarm Response
32
Nodes per Hub
5yr
Battery Life
TLS 1.3
Security
OTA
Remote Update
# Problem & Solution
The Problem
- Water treatment plant had 4–20 mA flow sensors with no digital readout
- SCADA system required OPC-UA — existing Arduino solutions didn't support it
- Field technicians couldn't commission devices without laptop + USB cable
- Cloud-sent firmware updates required physically visiting each remote station
- E-ink displays needed to show live flow rates without power drain
The Solution
- ESP32-S3 with 16-bit ADS1115 ADC reads 4–20 mA loop at ±0.5% accuracy
- open62541 OPC-UA client stack compiled for ESP-IDF — direct SCADA integration
- Custom BLE GATT profile — iOS/Android app configures Wi-Fi, calibration, thresholds
- ESP-IDF OTA with automatic rollback on consecutive boot failures
- 2.9" Waveshare E-Paper SPI display — updates every 5s, zero standby draw
# Firmware Architecture (Sample)
flow_sensor.c — 4-20mA current loop ADC sampling
/* Reads 4-20mA industrial current loop via ADS1115 (16-bit I²C ADC) Maps 4mA → 0 L/min, 20mA → MAX_FLOW_LPM with linearisation */ #define ADS1115_ADDR 0x48 #define SHUNT_OHMS 100.0f /* 100Ω precision shunt resistor */ #define CURRENT_4MA 4.0f #define CURRENT_20MA 20.0f #define MAX_FLOW_LPM 500.0f static i2c_master_dev_handle_t ads_dev; esp_err_t flow_sensor_init(void) { i2c_master_bus_config_t bus_cfg = { .i2c_port = I2C_NUM_0, .sda_io_num = GPIO_SDA, .scl_io_num = GPIO_SCL, .clk_source = I2C_CLK_SRC_DEFAULT, .glitch_ignore_cnt = 7, .flags.enable_internal_pullup = true, }; return i2c_new_master_bus(&bus_cfg, &i2c_bus); } float flow_read_lpm(void) { /* Trigger single-shot conversion on AIN0 (PGA ±2.048V) */ uint8_t cfg[] = {0x01, 0xC1, 0x83}; /* OS=1, AIN0-GND, FS=2.048V */ i2c_master_transmit(ads_dev, cfg, sizeof(cfg), 100); vTaskDelay(pdMS_TO_TICKS(9)); /* Wait for 860 SPS conversion */ uint8_t reg = 0x00; uint8_t raw[2]; i2c_master_transmit_receive(ads_dev, ®, 1, raw, 2, 100); int16_t adc_val = (raw[0] << 8) | raw[1]; /* Convert raw → voltage → current → flow */ float voltage = adc_val * (2.048f / 32768.0f); float current_mA = (voltage / SHUNT_OHMS) * 1000.0f; float flow_lpm = ((current_mA - CURRENT_4MA) / (CURRENT_20MA - CURRENT_4MA)) * MAX_FLOW_LPM; return (flow_lpm < 0) ? 0 : flow_lpm; }
ble_commissioning.c — Custom GATT profile for field configuration
/* Custom GATT service UUID: 0xAB01 — Wi-Fi + calibration commissioning */ static const esp_gatts_attr_db_t flowsense_gatt_db[] = { [IDX_SVC] = { {ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t*)&primary_service_uuid, ESP_GATT_PERM_READ, sizeof(uint16_t), sizeof(flowsense_svc_uuid), (uint8_t*)&flowsense_svc_uuid} }, /* Characteristic: Wi-Fi SSID (write, UTF-8, max 64 bytes) */ [IDX_CHAR_SSID_VAL] = { {ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t*)&char_wifi_ssid_uuid, ESP_GATT_PERM_WRITE, 64, 0, NULL} }, /* Characteristic: Flow calibration factor (float32, notify + write) */ [IDX_CHAR_CAL_VAL] = { {ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t*)&char_cal_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, sizeof(float), sizeof(cal_factor), (uint8_t*)&cal_factor} }, }; void gatts_event_handler(esp_gatts_cb_event_t event, ...) { if (event == ESP_GATTS_WRITE_EVT && param->write.handle == ssid_handle) { memcpy(wifi_config.sta.ssid, param->write.value, param->write.len); ble_respond_ok(param); wifi_reconnect(); /* apply new SSID immediately */ } }
# Full Tech Stack
Hardware
ESP32-S3-WROOM-1
ADS1115 16-bit ADC
100Ω Precision Shunt
Pulse Flow Meter (NPN)
2.9" E-Paper (Waveshare)
4-Ch MOSFET Relay
Custom 4-layer PCB (KiCad)
DIN Rail Enclosure IP54
Firmware & Software
ESP-IDF v5.2
FreeRTOS
open62541 OPC-UA
BLE GATT Server
MQTT/TLS (ESP-MQTT)
AWS IoT Core
OTA (esp_https_ota)
Node-RED + SCADA
# Project Timeline
Week 1
PCB Design & Sensor Bringup
4-layer KiCad PCB, ADS1115 I²C driver, pulse counter ISR, E-paper SPI driver verification
Week 2
OPC-UA & BLE Stack
Porting open62541 to ESP-IDF build system, custom GATT commissioning service, iOS/Android BLE app (Flutter)
Week 3
MQTT/TLS & OTA Pipeline
AWS IoT mutual-auth TLS certificates, HTTPS OTA with rollback, Node-RED SCADA dashboard integration
Week 4
Site Testing & Compliance Docs
FAT at water treatment plant, EMC pre-compliance checks, IEC 61508 SIL-1 evidence pack, handover training
Need a SCADA Gateway for Your Plant?
I'll design a flow monitoring system tailored to your process — from 4-20mA sensors to your existing SCADA platform.