JalSense Hardware Deep Dive

Every Component · Every Signal · Every Byte

19 Components 7 Signal Interfaces 12-Step Edge AI 10-Layer Micro Data Flow Full BOM · INR Costs
JalOS Technologies  ·  April 2026  ·  CONFIDENTIAL
01
OVERVIEW

System Overview — 6 Subsystems

JalSense integrates six field-hardened subsystems in one ruggedised node. Each is independent and replaceable, but operates as a unified intelligent water management device.

WQ

Water Quality Sensors

What the water looks like
Atlas EZO-pH
pH 0–14, ±0.02, I2C 0x63, 900ms read
Atlas EZO-EC
TDS/EC/Salinity, I2C 0x64, auto temp-comp
Atlas EZO-DO
Dissolved O₂ mg/L & %, I2C 0x61
DFRobot SEN0189
Turbidity 0–500 NTU, 0–5V analog
DS18B20
Water temp ±0.5°C, 1-Wire
FP

Flow & Pressure

How much water is moving
Ultrasonic Clamp-on Flow Meter
DN15–DN100, RS485 Modbus RTU, ±1–2%
4–20mA Pressure Transducer
0–10 bar, 304 SS, IP67, 100Ω shunt
A02YYUW Level Sensor
30–450cm, UART 9600, IP68, auto-output
ADS1115 16-bit ADC
4-20mA→voltage, I2C 0x48, 65535 steps
CPU

Compute Subsystem

Brain of the node
ESP32-S3
Dual LX7 240MHz, 512KB SRAM, 8MB PSRAM
TFLite Micro (on-chip)
INT8 models: anomaly 45KB, classify 30KB
DS3231 RTC
±2ppm TCXO, I2C 0x68, CR2032 backup
MicroSD (SPI)
7-day offline FAT32 buffer, 512B blocks
TX

Transmission

How data leaves the node
RYLR998 LoRa (SX1276)
868MHz, SF7–SF12, −148dBm, UART AT
SIM7080G NB-IoT
Band 28/3/8, native MQTT, PSM 3.8µA
u-blox NEO-M8N GPS
4-constellation, ±2.5m, UART 9600
PWR

Power Subsystem

Energy independence
10W Monocrystalline Solar
6V Voc, UV-stabilised frame
CN3791 MPPT Charger
4.5–28V in, 2A max, trickle+CC+CV
Li-Ion 10,000mAh 3.7V
72hr backup, 500+ cycles, protected PCB
INA226 Power Monitor
V/I/W to cloud, I2C 0x40, 2.5µV/LSB
ACT

Actuator Subsystem

Controls, not just monitors
DN25 Motorized Ball Valve
0–10V proportional, ±1% pos feedback
4-ch Opto-isolated Relay
Pump/solenoid/alarm, 10A@250VAC
PWM + RC + Op-Amp DAC
PWM → 0–3.3V → ×3 → 0–10V valve input
02
COMPONENTS

Complete Component Catalog

19 components — each with role, interface, specifications, and INR unit cost at prototype scale.

01

ESP32-S3

Espressif · Main MCU
₹250–350
Brain. Core 0 = sensor polling + edge AI. Core 1 = comms + storage. Deep sleep between cycles keeps avg current under 3 mA. ESP-NN hardware gives 7.2× TFLite speedup.
UART×3I2C×2SPI×445 GPIO20ch ADC
CoresDual Xtensa LX7 @ 240 MHz
RAM512 KB SRAM + 8 MB PSRAM
AI accelESP-NN, 7.2× speedup, int8 ops
Active~78 mW (23.9 mA @ 3.3V)
Deep sleep~27 µW (7–150 µA)
TFLite arena512 KB PSRAM tensor arena
Inference5–60 ms per model
02

RYLR998 LoRa (SX1276)

Reyax · Primary uplink
₹450–650
Primary wireless uplink. 1 gateway covers 50+ nodes over 5 km. Sleep current <1 µA. SF7–SF12 adaptive spreading for range vs. speed tradeoff.
UART 9600AT Commands868 MHz ISM
Sensitivity−148 dBm @ SF12
TX power+20 dBm max
Airtime SF7~328 ms for 100B payload
Airtime SF12~2,636 ms for 100B payload
TX current~120 mA peak
Sleep current<1 µA
Max payload251 bytes (raw LoRa)
03

SIM7080G NB-IoT

SIMCom · Cellular fallback
₹1,200–1,600
Auto-activates after 3 failed LoRa attempts. Band 28 (700 MHz) gives 50+ km rural coverage. PSM sleep: 3.8 µA. Native MQTT AT commands — no translation layer.
UARTNative MQTTBand 28/3/8
India bandsB28 (Jio/Airtel), B3, B8
PSM sleep3.8 µA (T3412=1hr, T3324=5min)
TX current~230 mA active
MQTT cmdAT+SMQTCONN, AT+SMQTPUB
Rural range50+ km at Band 28
04

Atlas EZO-pH

Atlas Scientific · pH
₹3,500–4,500
CPHEEO limit: 6.5–8.5. Below 6.5 = contamination. EZO circuit converts analog probe to I2C digital — eliminates ADC noise. Quarterly calibration.
I2C 0x63UART alt
Range0.001–14.000 pH
Accuracy±0.02 pH
Active22 mA @ 3.3V
Sleep2.6 mA
Read seqWrite 'R' → 900ms → read 20B ASCII
CalibrationCal,7 → Cal,4 → Cal,10 (3-point)
05

Atlas EZO-EC

Atlas Scientific · TDS/Conductivity
₹3,800–4,800
Outputs EC, TDS, salinity, specific gravity simultaneously. Critical for Rajasthan/Gujarat bore wells where TDS often exceeds 2000 ppm. Auto temp compensation.
I2C 0x64Auto temp-comp
EC range0.07–500,000 µS/cm
Accuracy±2%
OutputsEC, TDS (PPM), Salinity, SG
Budget altDFRobot SEN0244 (~₹600)
06

Atlas EZO-DO

Atlas Scientific · Dissolved O₂
₹4,200–5,200
DO <4 mg/L = hypoxia. Detects septic contamination and algae blooms. WHO limit: >6 mg/L. Auto compensation for temperature, salinity, and pressure.
I2C 0x61Press+temp comp
Range0–saturation (~14 mg/L)
Response~8 seconds
WHO limit>6 mg/L drinking water
07

DFRobot SEN0189 Turbidity

DFRobot · Suspended solids
₹550–800
WHO limit: 1 NTU for drinking water. Monsoon runoff spikes above 100 NTU. IR LED transmittance → 0–5V analog → voltage divider → ADS1115 → NTU lookup table.
Analog 0–5Vvia ADS1115
Range0.5–500 NTU
Pure water4.1±0.3V output
Current~10 mA
08

Ultrasonic Clamp-on Flow Meter

Industrial Grade · DN15–DN100
₹8,000–12,000
No pipe cutting. No moving parts = zero maintenance. Transit-time ultrasonic. Modbus RTU via MAX485 → ESP32 UART2. ±1–2% accuracy for NRW calculation.
RS485 Modbus RTUMAX485 adapter
Pipe sizeDN15–DN100
Accuracy±1–2%
Reg 0x0000Flow rate (m³/h × 0.001)
Reg 0x0002Cumulative total (m³)
Supply24 VDC, IP68
09

4–20mA Pressure Transducer

Industrial Grade · 0–10 bar
₹2,000–3,000
Pressure drop = burst pipe or illegal tapping. Loop current immune to 100m+ cable noise. 100Ω shunt → 0.4–2.0V → ADS1115 A0 at 16-bit resolution.
4–20mA loop100Ω shuntADS1115 A0
Range0–10 bar gauge
Signal4mA=0bar, 20mA=10bar
Accuracy±0.5% FS
Wetted304 stainless steel, 1/4" BSP
Resolution0.15 mbar via 16-bit ADS1115
10

A02YYUW Level Sensor

Waterproof Ultrasonic · Tank level
₹800–1,200
Continuous 4-byte UART output — no trigger pin needed. Mounts on tank lid looking down. Calculates fill %, volume in litres. Feeds demand forecasting model.
UART 96004-byte autoIP68
Range30–450 cm
Accuracy±3 cm
Packet0xFF, distH, distL, checksum
Power5V, ~10 mA
11

ADS1115 16-bit ADC

Texas Instruments · Signal conversion
₹300–500
16-bit resolution = 65,535 steps. Detects 0.125 mbar pressure changes — enough to find slow leaks. Converts 4–20mA and turbidity voltage to digital for ESP32.
I2C 0x48–0x4B4 channels
Resolution16-bit (65,535 steps)
PGA range±256mV to ±6144mV
A0Pressure 4–20mA shunt
A1Turbidity 0–3.3V
A2Valve feedback 4–20mA
12

DS3231 RTC

Maxim · Accurate timekeeping
₹200–300
±2ppm TCXO = ±1.7 sec/month drift. Timestamps all readings even during power outages. Without RTC, readings during outages become legally inadmissible for CPHEEO reports.
I2C 0x68CR2032 backupTCXO
Accuracy±2 ppm (±1.7 sec/month)
Backup life5+ years on CR2032
Alarms2× programmable + interrupt
13

INA226 Power Monitor

Texas Instruments · Battery telemetry
₹300–500
V/I/W transmitted to cloud with every report. Operators see battery health remotely. INA226 with 10mΩ shunt gives 10 mA current resolution — detects parasitic drain.
I2C 0x40–0x4F16 addr
Bus voltage0–36V, 1.25 mV resolution
With 10mΩ10 mA current resolution
CalibrationCAL = 0.00512 / (I_max × R_shunt)
14

CN3791 MPPT Solar Charger

CONSONANCE · Solar power
₹400–600
Standalone IC — no firmware needed. Trickle → CC → CV phases protect battery longevity. Set charge current via single resistor: R = 0.5 / I_max_amps.
Analog feedbackPWM buck
Input range4.5–28V DC
Max charge2A
Efficiency~85–90%
Battery reg4.2V ±1%
15

Li-Ion Battery 10,000 mAh

18650 Cells · Energy storage
₹1,000–1,500
72-hour offline at full duty cycle. 500+ charge cycles = 5+ year life. Protected PCB prevents over/under-voltage. Recharges from 10W solar in ~5–6 hours.
3.7V nominalProtected PCB
Capacity10,000 mAh @ 3.7V
Cycles500+ to 80% retention
Offline72 hours @ 46 mA avg
16

u-blox NEO-M8N GPS

u-blox · Location + tamper
₹1,000–1,500
Records install GPS. If device moves (theft/tamper), coordinate changes → alert. Polled 30s once/week. Also syncs RTC time on boot. Multi-constellation reduces urban multipath.
UART 9600NMEA/UBX
ConstellationsGPS+GLONASS+BeiDou+Galileo
Accuracy±2.5m cold, ±0.8m warm
Cold TTFF~25 seconds
Active~60 mA acquisition
Usage30s ON once/week then sleep
17

DN25 Motorized Ball Valve

Industrial Grade · Flow control
₹5,500–8,000
Proportional control (not just on/off). Position feedback via 4–20mA confirms valve moved. Emergency shutoff on contamination. Manual override lever for maintenance.
0–10V signal4–20mA feedback24VDC
Control0V=closed, 10V=fully open
Rotation≤7 seconds
Accuracy±1% via potentiometer
Pressure10–15 bar rated
18

4-ch Opto-isolated Relay

Industrial Grade · Pump + solenoid
₹300–500
Optocoupler isolates ESP32 GPIO from 24V pump inductive spikes. Active-LOW: GPIO pulled LOW = relay ON. CH1: pump, CH2: solenoid, CH3: alarm siren, CH4: spare.
GPIO active-LOWOptocoupler
Channels4 independent
Rating10A @ 250VAC / 30A @ 28VDC
Control<5 mA per channel from 3.3V GPIO
19

MicroSD Card Module

SPI Interface · Offline buffer
₹200–400
Stores all readings during connectivity gaps. On reconnect, uploads backlog in order — cloud backfills TimescaleDB. 32GB = 15+ years of 5-min interval readings.
SPI 20MbpsFAT32512B blocks
Log formatCSV: ts,pH,EC,DO,turb,flow,press,lvl
Buffer7-day window before overwrite
Write power~100 mA, ~1 µA sleep
03
SIGNAL CHAIN

Signal Chain — Physical Measurement to Digital Value

Every sensor uses a different electrical interface. This is the complete path from physical phenomenon in the water to a digital number inside the ESP32.

I2C Digital BuspH · EC · DO · RTC · INA226 · ADS1115
2 shared wires (SDA + SCL) with 4.7 kΩ pull-ups to 3.3V

ESP32 is master. All sensors share the same bus — unique addresses prevent conflicts. Atlas sensors need 900ms after "R" command before reading back ASCII. I2C mutex semaphore in FreeRTOS prevents concurrent bus access from multiple tasks.

Wire.beginTransmission(0x63); Wire.write('R'); Wire.endTransmission();
delay(900); Wire.requestFrom(0x63, 20); // returns "7.245\r"
4–20mA Current LoopPressure · Valve feedback
Current → 100Ω shunt resistor → 0.4–2.0V → ADS1115 A0

4–20mA loops are immune to noise on cable runs 100m+. A 100Ω shunt converts current to voltage. ADS1115 at 16-bit resolution detects 0.15 mbar pressure changes — enough to find slow leaks. Protection: 1N4148 diodes clamp the shunt from reverse current damage.

V_shunt = I × 100Ω  |  4mA→0.4V (0 bar)   20mA→2.0V (10 bar)
Pressure_bar = (V_shunt − 0.4) × 10 / 1.6
Analog VoltageTurbidity sensor 0–5V
0–5V sensor output → 10kΩ/20kΩ voltage divider → ADS1115 A1

Turbidity sensor max output is 5V but ADS1115 accepts 3.3V. A voltage divider scales it: V_out = 5V × 20k / (10k + 20k) = 3.33V max. Non-linear NTU lookup table stored in ESP32 flash maps voltage to NTU values calibrated during deployment.

V_out = V_in × 20k/(10k+20k) = 3.33V max at ADS1115 A1
NTU = firmware_lookup_table(V_out) // calibrated non-linear curve
RS485 Modbus RTUUltrasonic flow meter
MAX485 chip → differential RS485 → ESP32 UART2

RS485 differential signalling (A/B pair) is immune to noise over 1200m. MAX485 transceiver chip converts to single-ended UART. ESP32 sends Modbus RTU request frame, waits ~50ms, receives 9-byte response with flow rate and cumulative total. DE/RE pins on MAX485 toggled for half-duplex TX/RX switching.

TX: 01 04 00 00 00 02 71 CB  // slave=1, func=04, reg=0x0000, count=2, CRC
RX: 01 04 04 00 0A 00 00 FA 33  // flow=10×0.001=0.01m³/h, total=0m³
UART Auto-OutputA02YYUW level sensor
4-byte continuous UART packets at 9600 baud — no trigger pin required

Sensor continuously sends distance measurements. ESP32 reads on UART1. Header byte 0xFF identifies packet start. Distance in mm from two data bytes. Checksum validation in firmware. Far simpler than JSN-SR04T trigger/echo which needs precise timing from two GPIO pins.

Packet: [0xFF][dist_high][dist_low][checksum]
dist_mm = (dist_high × 256) + dist_low  |  level = tank_height − dist_mm
UART AT CommandsLoRa · NB-IoT · GPS
3 hardware UARTs — one per radio module, managed by dedicated FreeRTOS tasks on Core 1

LoRa (UART0), NB-IoT (UART1), GPS (UART2) each have their own hardware UART peripheral. A binary semaphore per UART prevents task collisions. Responses are ASCII (AT) or binary (GPS NMEA). GPIO interrupt on DIO0 pin signals LoRa TX complete to release semaphore.

LoRa TX: AT+SEND=0,20,hex_payload\r\n → +OK\r\n
NB-IoT: AT+SMQTPUB="topic",45,"payload"\r\n → +SMQTPUB:0\r\n
GPIO Digital + PWM DACRelay · Valve control
GPIO LOW = relay ON  ·  PWM → RC filter → op-amp ×3 → 0–10V valve

Relay module is active-LOW: GPIO output LOW activates relay coil via optocoupler. Valve proportional control: ESP32 PWM (8-bit, 10 kHz) → RC low-pass filter (R=10kΩ, C=10µF, fc=1.6Hz) averages to 0–3.3V DC → LM324 op-amp unity+gain buffer ×3 amplifies to 0–10V. Valve feedback 4–20mA read back on ADS1115 A2 confirms position.

Valve 50%: 50% PWM duty → 1.65V after RC → ×3 → 4.95V → valve 49.5% open
Feedback: 4–20mA → 100Ω → 0.4–2.0V → ADS1115 A2 → position%
04
EDGE AI

Edge AI Pipeline — On-Device Intelligence

TFLite Micro with ESP-NN hardware acceleration. INT8 quantised models, 512KB PSRAM tensor arena, <50ms total inference. Works completely offline — no cloud needed for real-time decisions.

Why edge AI matters: Contamination events don't wait for connectivity. If the node detects contaminated water while offline, it still must close the valve and trigger the alarm within seconds. Cloud AI handles historical analysis; edge AI handles the immediate autonomous response.
Step 1 — Core 0

FreeRTOS sensor_task

Priority 5, 4KB stack. Polls all sensors every 30 seconds. Acquires I2C mutex semaphore → reads Atlas pH/EC/DO → reads ADS1115 (pressure, turbidity) → reads flow meter via Modbus → reads DS3231 timestamp. Writes to ring buffer in PSRAM.

xTaskCreate priority 5 · Core 0
Step 2 — Core 0

Kalman Filter

Per-channel 1D Kalman filter removes sensor noise spikes. State estimate updated each reading. pH spike from dirty probe → covariance increase → spike discarded. Runs in <1ms per channel.

1D Kalman, O(1) per channel
Step 3 — Core 0

5-Point Moving Average

Ring buffer of last 5 filtered readings per channel. Smooths transient artefacts after Kalman. Output: one representative value per sensor per 30s polling cycle.

Ring buffer, O(1)
Step 4 — Core 1

Feature Vector Assembly

12 normalised values assembled into input tensor: [pH/14, EC/500000, DO/20, turbidity/1000, temp/100, flow/100, pressure/10, Δpressure/10, level/100, Δlevel/100, power/50, tod/24]. Shape: float32[1,12].

Input tensor float32[1,12]
Step 5 — Core 1

Anomaly Detector

Dense neural network: Input[12] → Dense(64, ReLU) → Dense(32, ReLU) → Dense(1, Sigmoid). INT8 quantised, 45KB, 15ms inference. Output: anomaly_score [0.0–1.0]. Threshold: >0.75 = anomaly flag.

MLP INT8 · 45KB · 15ms
Step 6 — Core 1

Quality Classifier

3-layer MLP: Input[12] → Dense(32, ReLU) → Dense(16, ReLU) → Dense(3, Softmax). INT8, 30KB, 20ms. Output: confidence scores for [POTABLE, BORDERLINE, CONTAMINATED]. Threshold: CONTAMINATED >0.8.

MLP INT8 · 30KB · 20ms
Step 7 — Core 1

Leak Detector

Decision tree on 60-second pressure waveform (120 samples). Rapid drop (>3 bar in 10s) = burst pipe. Low-amplitude oscillation (±0.2 bar at 0.5Hz) = slow leak. INT8, 15KB, 8ms.

Decision Tree INT8 · 15KB · 8ms
Step 8 — Core 1

Decision Engine

Priority queue: Emergency > Safety > AI > Schedule > Manual. CONTAMINATED + anomaly >0.9 → close valve (0V) + relay CH3 alarm + QoS2 alert packet. Valve position confirmed via feedback within 10 seconds.

Rule + Model Fusion
Step 9 — Core 0

CRON Scheduler

EEPROM-stored CRON schedule survives power cycles. Sources: manual (dashboard), cloud-pushed (MQTT downlink), sensor-triggered (e.g., open valve when level <20%). Operates fully offline. Audit log per actuation.

CRON in EEPROM · Offline-first
Step 10 — Core 1

MessagePack Assembly

15 fields packed into ~45 bytes: [uint32 timestamp, float32×8 sensors, uint8×3 classes, int16×2 RSSI/SNR, uint8 flags]. Total inference overhead: ~50ms per 30s cycle = 0.28% CPU time on Core 1.

MessagePack ~45B · 0.28% CPU
Step 11 — Cloud

LSTM Demand Forecast

72-hour demand prediction per deployment. Retrained monthly with latest TimescaleDB data. Output: hourly valve scheduling pushed back to edge as CRON update via MQTT downlink.

LSTM · TimescaleDB features
Step 12 — Cloud

NRW + Predictive Maintenance

NRW balance weekly per zone. Sensor drift scoring via rolling regression — predicts calibration failure 7–14 days ahead. Battery discharge curve analysis. Outputs maintenance work orders to field app.

Gradient Boost + Water Balance
05
DATA FLOW

Micro-Level End-to-End Data Flow

10 layers from physical measurement to push notification. Every protocol, every data format, every timing value, every component — micro-level detail. Scroll each layer independently.

L1
PHYSICAL SENSING
in pipe / tank / pump
pH Probe
I2C 0x63 · UART alt
Output: "7.245\r" ASCII
Read: Write 'R' → 900ms
Accuracy: ±0.02 pH
22 mA active · 2.6 mA sleep
+
EC/TDS Probe
I2C 0x64 · auto temp-comp
Output: "1250.5,500.3,0.6,1.0002\r"
Fields: EC,TDS,Salinity,SG
Range: 0.07–500k µS/cm
22 mA active · 2.6 mA sleep
+
DO Probe
I2C 0x61 · press+temp comp
Output: "8.4,95.2\r"
Fields: mg/L, % saturation
Response: ~8 seconds
22 mA active · 2.6 mA sleep
+
Turbidity Sensor
0–5V analog → 10k/20k divider
Output: 0–3.33V (scaled)
Pure water: 4.1V → 3.33V max
NTU: lookup table in FW
10 mA always-on
+
Flow Meter
RS485 Modbus RTU 9600
Reg 0x0000: flow rate
Reg 0x0002: cumulative m³
MAX485 → ESP32 UART2
24V supply · poll every 30s
+
Pressure Xducer
4–20mA → 100Ω shunt
0.4V=0bar, 2.0V=10bar
ADS1115 A0 · 16-bit
Resolution: 0.15 mbar
20 mA always-on (loop)
+
Level Sensor
UART 9600 auto-output
4B packet: FF,dH,dL,CK
dist_mm = dH×256+dL
Level = height − dist
10 mA · continuous output
+
INA226 Power
I2C 0x40 · 10mΩ shunt
Reg 0x01: shunt voltage
Reg 0x02: bus voltage
Reg 0x04: current
330 µA · 1.1ms conversion
I2C · RS485 · UART · 4-20mA
raw sensor structs · 30-second polling interval
FreeRTOS sensor_task priority 5 · Core 0
L2
SIGNAL CONDITIONING
ADC conversion + filtering
ADS1115 ADC
I2C 0x48 · PGA ±4.096V
A0: pressure 0.4–2.0V
A1: turbidity 0–3.33V
A2: valve feedback 0.4–2.0V
16-bit · 860 SPS max
<150 µA · 1.1ms/conv
Kalman Filter
1D per sensor channel
x̂ₙ = x̂ₙ₋₁ + K(zₙ − x̂ₙ₋₁)
Noise cov Q=0.001, R=0.1
Removes spike artefacts
Runs <1ms per channel
CPU only · no extra HW
Moving Average
5-point ring buffer
avg = Σ(last 5) / 5
Per sensor channel
Removes residual noise
O(1) memory per channel
~0.1ms per channel
Unit Conversion
firmware lookup tables
pH: ASCII→float parse
EC: ASCII→float parse
Pressure: V→bar formula
Turbidity: V→NTU table
Level: dist_mm→fill%
<1ms total
DS3231 Timestamp
I2C 0x68 · ±2ppm TCXO
Unix epoch uint32
±1.7 sec/month drift
CR2032 backup when off
Syncs to GPS on boot
<500 µA · 3µA on backup
sensor_reading_t struct
PSRAM ring buffer
{ uint32 ts;
float ph, ec, do, turb;
float flow, press, lvl;
float V, I, W;
uint8 flags; }
~48 bytes per record
xQueue push → Core 1
xQueue IPC
sensor_reading_t struct · 48 bytes · QueueLength=16
FreeRTOS xQueueSend from Core 0 → Core 1
L3
EDGE AI INFERENCE
ESP32-S3 Core 1 · TFLite Micro
Feature Normalise
Core 1 · ml_task priority 5
12 features: [pH/14,
EC/500000, DO/20,
turbidity/1000, temp/100,
flow/100, press/10,
Δpress/10, level/100,
Δlevel/100, power/50,
time_of_day/24]
Input tensor: float32[1,12]
~0.2ms
Anomaly Detector
TFLite Micro INT8
MLP: 12→64→32→16→1
Activation: ReLU+Sigmoid
Model size: 45KB
PSRAM arena: 512KB
Threshold: score>0.75
Output: float32 [0,1]
~15ms ESP-NN accel
Quality Classifier
TFLite Micro INT8
MLP: 12→32→16→3
Activation: ReLU+Softmax
Model size: 30KB
Classes: POTABLE(0)
BORDERLINE(1)
CONTAMINATED(2)
Threshold: class2>0.80
~20ms ESP-NN accel
Leak Detector
Decision Tree INT8
Input: 60s press waveform
(120 float32 samples)
Burst: drop>3bar in 10s
Slow leak: ±0.2bar@0.5Hz
Model size: 15KB
Output: bool+enum
~8ms
Decision Engine
Rule + model fusion
Priority queue:
1. Emergency shutoff
2. Safety interlock
3. AI-commanded
4. Scheduled CRON
5. Manual override
CONTAMINATED+score>0.9
→ close valve (0V cmd)
→ relay CH3 alarm
→ QoS2 MQTT alert
~2ms rule evaluation
AI output + sensor data
annotated_reading_t · anomaly_score, quality_class, leak_flag, valve_cmd
xQueueSend to storage_task · Core 1
L4
LOCAL STORAGE + TX QUEUE
Core 1 · DS3231 + MicroSD + xQueue
MessagePack Encoder
Core 1 · mpack library
15 fields → ~45 bytes wire:
0xce [4B] timestamp
0xca [4B] × 8 floats
0xcc [1B] × 3 uint8
0xd1 [2B] × 2 int16
Total: ~45 bytes vs
JSON ~215 bytes (79% save)
~0.5ms encoding
MicroSD Logger
SPI 20MHz · FAT32
Path: /YYYYMMDD/log.csv
Append 512B aligned write
7-day circular buffer
~100mA write burst
Daily rotation at midnight
Checksum per record
~0.5s per write burst
TX Ring Buffer
PSRAM · 32-item queue
pending_ack[32] array
QoS 1: 5-min telemetry
QoS 2: emergency alert
QoS 0: 60s heartbeat
Priority: alert > telemetry
Retry: 3× on no ACK
in-RAM, no latency
Actuator Control
GPIO + PWM + I2C
Valve: PWM→RC→op-amp
Relay CH1: pump GPIO
Relay CH2: solenoid GPIO
Relay CH3: alarm GPIO
Valve feedback: ADS1115 A2
Safety: watchdog 5s
7s valve rotation
TX Queue dispatch
MessagePack payload ~45B → RF transmission every 5 minutes
lora_task priority 4 · Core 0 · or NB-IoT fallback after 3 failures
L5
RADIO TRANSMISSION
SX1276 LoRa · SIM7080G NB-IoT fallback
LoRa Packet Build
SX1276 SPI · SF7 default
MHDR: 0x40 (unconf UL)
FHDR: DevAddr(4B)+FCtrl(1B)
FCnt(2B)+FOpts(0B)
FPort: 10 (telemetry)
11 (alert) 12 (cmd)
FRMPayload: 45B MsgPack
encrypted w/ AppSKey
MIC: AES-CMAC NwkSKey(4B)
Total frame: ~59 bytes
~0.5ms frame assembly
LoRa RF Transmit
868 MHz · BW125kHz
SF7 (default): ~328ms TX
SF12 (max range): ~2636ms
TX power: +20 dBm max
TX current: ~120mA peak
DIO0 interrupt: TX done
ADR: RSSI<−120→↑SF
Airtime duty cycle: <1%
UART: AT+SEND=0,59,hex
OR
NB-IoT Fallback
SIM7080G · Band 28/3/8
Activates: 3 LoRa failures
PSM: T3412=1hr,T3324=5min
Sleep: 3.8µA (PSM off)
TX: ~230mA active
AT+SMQTPUB direct
MQTT over TCP 8883 TLS
Session: persistent clean=0
~2-5s to acquire + TX
Backlog Upload
On reconnect · SD card
Read CSV from SD in order
Re-encode to MsgPack
Batch upload to MQTT
QoS 1 per record
Cloud fills TimescaleDB gaps
Up to 7 days buffered
~50KB/day at 5min intervals
~1KB/sec upload rate
LoRa RF 868 MHz
Encrypted LoRaWAN frame · NwkSKey+AppSKey AES-128 · MIC 4B
2–15km range · SF7–SF12 adaptive · <1% duty cycle ISM band
L6
LORA GATEWAY
RAK7268 · 1 per 5km · 50 nodes
RAK7268 Gateway
SX1301 8-ch concentrator
8 simultaneous channels
BW: 125/250/500 kHz
All SFs simultaneously
Listens all devices in range
RX window: continuous
LTE/Ethernet backhaul
Solar-capable mounting
50 nodes · 5km radius
UDP Packet Forwarder
UDP port 1700 → ChirpStack
Semtech pkt fwd protocol
PUSH_DATA type 0x02:
{ rxpk: [{ time, tmms,
chan, rfch, freq, stat,
modu, datr:"SF7BW125",
codr:"4/5", rssi:-95,
lsnr:5.2, size:59,
data:"QEd..." (base64)}]}
JSON over UDP
<10ms forwarding latency
Gateway Bridge
ChirpStack GW bridge
Translates UDP→MQTT
Topic: gateway/{eui}/event/up
Re-encodes to Protobuf
Forwards to NS MQTT
Handles PULL_DATA
for downlink scheduling
TLS MQTT to NS
UDP Semtech Protocol → MQTT Protobuf
{ rxpk: [{datr:"SF7BW125", rssi:-95, lsnr:5.2, data: base64_payload}] }
LTE/Ethernet backhaul · <50ms end-to-end gateway → NS
L7
CHIRPSTACK NS
OTAA · MIC verify · Dedup · AppSKey decrypt
Frame Deduplication
Redis · 200ms window
Multiple GW send same frame
Dedup key: DevAddr+FCnt
Window: 200ms
Select: best RSSI/SNR
Forward: 1 copy only
Redis bloom filter store
200ms dedup window
OTAA Session
NwkSKey + AppSKey
JoinRequest: DevEUI+DevNonce
JoinAccept: DevAddr+keys
NwkSKey=AES-CMAC(AppKey,
0x01|JoinNonce|NetID|DevNonce)
AppSKey=AES-CMAC(AppKey,
0x02|JoinNonce|NetID|DevNonce)
Keys stored: NVS AES-256
1× at activation
MIC Verification
AES-CMAC NwkSKey
B0=0x49|DevAddr|FCnt
Expected_MIC=
AES-CMAC(NwkSKey,
B0|FHDR|FPort|FRMPayload)
If mismatch→drop silently
FCnt replay check
(prevents replay attacks)
~0.5ms crypto
FRMPayload Decrypt
AES-128-CTR AppSKey
FRMPayload(45B) → plaintext
Key: AppSKey (128-bit)
Nonce: DevAddr+FCnt+dir
Hardware AES on ESP-S3
Decrypted payload passed
to Application Server
via gRPC integration
~0.5ms crypto
Application Server
ChirpStack AS · gRPC
Receives plaintext payload
Adds context: device metadata
zone_id, deploy_location
Publishes to EMQX MQTT
Topic: jalsense/{id}/telemetry
QoS 1 · retain=false
<5ms total NS processing
MQTT v5 · TLS 1.3 · X.509 mutual auth
topic: jalsense/{device_id}/telemetry · QoS 1 · payload: MsgPack 45B
Persistent session · LWT: jalsense/{id}/status {"status":"offline"}
L8
EMQX + KAFKA
Message broker → event streaming
EMQX Broker
MQTT v5 · 10k+ connections
Topics:
jalsense/+/telemetry (QoS1)
jalsense/+/alert (QoS2)
jalsense/+/command (QoS1)
jalsense/+/heartbeat (QoS0)
LWT: jalsense/+/status
Session: persistent clean=0
TLS 1.3 · X.509 per-device
Storage: RocksDB ~1KB/session
10k+ concurrent conns
EMQX Rule Engine
SQL-like rules → Kafka
Rule: SELECT * FROM
"jalsense/+/telemetry"
→ Kafka raw-telemetry
Rule: SELECT * FROM
"jalsense/+/alert"
→ Kafka alerts
No transformation at EMQX
Pass-through to Kafka
<1ms rule eval
Kafka Topics
Partition key: device_id hash
raw-telemetry: 5 partitions
retention: 30 days
Snappy compress: ~4:1
alerts: 3 partitions
retention: 24 hours
valve-commands: 5 parts
Replication factor: 3
Idempotent producer: on
~100k msg/sec capacity
Consumer Groups
3 independent groups
telemetry-writer:
reads raw-telemetry
writes TimescaleDB
commit every 5k msgs
alert-engine:
reads raw-telemetry+alerts
evaluates thresholds
ml-pipeline:
reads raw-telemetry
batch 100 msgs or 30s
Independent lag
Kafka consumer → TimescaleDB + ML + Alert Engine
Kafka offset commit every 5,000 records · exactly-once semantics on alerts
Partition key: device_id hash → ordered processing per device
L9
CLOUD STORAGE + ML
TimescaleDB · ML Pipeline · Alert Engine
TimescaleDB
PostgreSQL hypertable
Table: telemetry
Chunk interval: 1 day
Schema: (time,device_id,
ph,ec,do,turbidity,
flow_rate,pressure,
level,power_w,
anomaly_score,quality_class,
valve_pct,rssi,snr)
Index: (device_id,time DESC)
Compress after: 1 day (90%)
Raw 90d→hourly 2yr→daily ∞
Continuous Aggregates
TimescaleDB auto-refresh
telemetry_1h: refresh hourly
AVG(ph,ec,do,turb,flow)
MAX(anomaly_score)
COUNT(readings)
telemetry_1d: refresh daily
SUM(flow×15/60) daily_liters
MAX(anomaly) daily_max
Query <50ms for 7-day range
Query <20ms for 2-year hourly
Auto background refresh
ML Pipeline
Python workers · scheduled
02:00 daily: LSTM demand
72-hr forecast per device
Input: 7-day hourly history
Output: demand_forecasts tbl
03:00 Sunday: NRW analysis
flow_in−consumed−loss=NRW%
04:00 daily: pred maintenance
sensor drift regression
battery discharge curve
Cron: 02:00/03:00/04:00
Alert Engine
Kafka consumer · real-time
Evaluate per-reading:
a) Operator thresholds
b) Edge AI score in packet
c) Rate-of-change rules
pH drop >0.5 in 1min
Dedup: Redis bloom filter
30-min TTL per alert type
Route: GPS zone → engineer
Escalation: 15m→supervisor
30m→ops manager
60m CRITICAL→nodal SMS
<100ms per reading eval
FCM HTTP v1 · WebSocket · Webhook
POST https://fcm.googleapis.com/v1/projects/{id}/messages:send · topic: zone_{zone_id}
OAuth2 service account · Bearer token · 4KB max payload
L10
DELIVERY TO OPERATORS
FCM · WebSocket · WhatsApp · Auto-reports
FCM Push (Android)
Firebase Cloud Messaging v1
Topic: "zone_{zone_id}"
All engineers subscribed
Notification payload:
title: "CRITICAL: Contam."
body: "Zone 3 · pH 5.2"
Data payload:
device_id, severity,
anomaly_score, action
Deep link → device detail
Retry: 24hr exponential
<2 seconds delivery
+
WebSocket Dashboard
React + Socket.IO
Event: "telemetry_update"
Event: "alert_created"
Event: "node_status_change"
GIS map: node turns RED
Alert triage queue update
Valve control panel sync
Live chart data stream
Connected: govt operators
Real-time <100ms
+
WhatsApp Webhook
WhatsApp Business API
Supervisor channel message:
"[CRITICAL] Zone 3 · T+0s
pH 5.2 · Turbidity 180NTU
Valve auto-closed.
Engineer Rahul notified.
Tap to view dashboard."
Template message (pre-approved)
Webhook POST from alert engine
<5 seconds delivery
+
Auto Reports
Cron job · PDF generation
Daily 00:00: quality report
PDF+CSV per deployment
CPHEEO format
Weekly: NRW summary
production−billed−loss
Monthly: SLA performance
uptime%, alert response time
On-demand: tender data pack
historical export for govt
Cron: 00:00 daily
T+0 to notification: Physical contamination detected → edge AI closes valve (T+2s) → LoRa packet transmitted (T+5s) → EMQX received (T+8s) → alert created (T+12s) → FCM push delivered (T+25–45s). Entire pipeline end-to-end: under 45 seconds.
Offline resilience: Up to 7 days of data stored on MicroSD with DS3231 timestamps. On reconnect, backlog uploads in chronological order. TimescaleDB auto-backfills. Redis deduplication prevents duplicate alerts from replayed records.
06
INSTALLATION

Installation Flow — Site Visit to Live Monitoring

8 steps from first site visit to node going GREEN on the government GIS map.

1

Site Survey

  • Measure pipe diameter — select correct flow meter transducer spacing
  • Check pipe material (cast iron needs ultrasonic coupling gel)
  • Survey sun exposure — south-facing, no shadow 8AM–4PM
  • Test NB-IoT signal: AT+CSQ, value >10 = acceptable
  • Measure tank dimensions for level sensor offset calculation
  • Photograph + record GPS in field app before any work
2

Mechanical Installation

  • Mount enclosure on DIN rail or IP67 wall bracket
  • Clamp flow transducers (upstream + downstream per DN spacing table)
  • Thread pressure transducer into 1/4" BSP tapping (3 turns Teflon)
  • Mount A02YYUW on tank lid, face down, clear of inlet splash
  • Insert Atlas probes through bulkhead fittings into sample port
  • Mount turbidity in bypass loop — protects from direct flow debris
  • Route cables through IP67 glands into enclosure
  • Mount valve inline between isolation valves for maintenance access
3

Electrical Wiring

  • Solar panel → CN3791 input (red=+6V, black=GND)
  • Battery → CN3791 output + INA226 shunt in series on BAT+
  • Atlas sensors → shared I2C (SDA, SCL, 3.3V, GND)
  • ADS1115 → same I2C bus (ADDR pin sets address)
  • Pressure 4–20mA → 100Ω shunt → ADS1115 A0
  • Turbidity 0–5V → 10k/20k divider → ADS1115 A1
  • MAX485 transceiver ↔ flow meter RS485 ↔ ESP32 UART2
  • PWM → RC filter → op-amp ×3 → valve 0–10V input
4

Firmware Provisioning

  • Power on → boots in provisioning mode (WiFi AP: JalSense-XXXX)
  • Field engineer connects phone to JalSense AP
  • JalOS App: scan QR code on enclosure → auto-fills DevEUI
  • Enter: site name, pipe DN, LoRa gateway ID, NB-IoT APN
  • App pushes config to device over WiFi → stored in NVS encrypted
  • DS3231 RTC synced to GPS time on first fix
5

Sensor Calibration

  • pH: pH7 buffer→Cal,7→rinse→pH4→Cal,4→rinse→pH10→Cal,10
  • EC: Cal,dry → immerse in 84 µS/cm standard → Cal,84
  • DO: 30s in air → Cal (100% air saturation)
  • Turbidity: pour reference solution → enter NTU value in app
  • Pressure: record zero-flow offset for baseline calibration
  • Level: enter actual tank depth (cm) → app auto-calculates offset
  • All calibration values stored NVS + synced to cloud cal DB
6

OTAA Join + Go-Live

  • LoRa OTAA JoinRequest → ChirpStack assigns DevAddr + session keys
  • Field app confirms gateway receipt of test packet <10 seconds
  • GPS fix → tamper baseline position stored in cloud
  • Dashboard shows node GREEN on GIS map
  • Operator configures supply schedule (e.g., valve OPEN 6AM–8AM)
  • Alert thresholds set: pH <6.5, turbidity >4 NTU
7

Cloud Configuration

  • Assign node to zone (GPS-based field engineer routing)
  • Configure MQTT LWT: jalsense/{id}/status offline message
  • Enable continuous aggregate refresh for this device in TimescaleDB
  • First automated daily report generated at midnight
  • LSTM demand model initialised with default parameters (no history yet)
  • Node added to NRW zone calculation for this municipal cluster
8

Maintenance Schedule

  • Monthly: pH probe clean + single-point recal check
  • Quarterly: full 3-point pH, EC recal, DO membrane check
  • 6-monthly: turbidity reference verification
  • Annual: flow transducer coupling gel, pressure zero-point
  • As-needed: predictive maintenance alert → field app work order
  • Solar panel clean after monsoon (silt reduces output 20–30%)
07
CLOUD

Cloud Pipeline — MQTT to Analytics

From EMQX message receipt to TimescaleDB storage to ML inference to alert routing. Every stage designed for 10→10,000 node scale.

EMQX MQTT
Broker
Persistent sessions · LWT · QoS 1/2 store-and-forward

Receives MessagePack from JalSense via LoRa gateway or NB-IoT. Topics: jalsense/{device_id}/telemetry (QoS 1, 5-min interval), jalsense/{device_id}/alert (QoS 2, immediate). LWT: if TCP drops without DISCONNECT, broker publishes jalsense/{id}/status {"status":"offline"} after 30s. X.509 per-device certificates for mutual TLS 1.3 auth. Persistent sessions (CleanStart=false) queue messages during connectivity gaps.

Apache Kafka
Event Stream
5 partitions by device_id hash · 30-day retention · 3× replication

EMQX rule engine forwards all messages to Kafka topics: raw-telemetry (5 partitions, partition key = device_id hash → ordered processing per device), alerts (3 partitions), valve-commands. Snappy compression: ~4:1 ratio. Idempotent producer prevents duplicate writes. Replay window: 30 days allows reprocessing historical data with updated ML models.

TimescaleDB
Hypertable
Chunk interval: 1 day · Compression: 90% after 1 day · Index: (device_id, time DESC)

Hypertable telemetry partitioned by time (1-day chunks) and device_id (hash, 2 spaces). Raw data retained 90 days → continuous aggregates: hourly averages for 2 years, daily averages forever. Partial index on anomaly_score > 0.5 keeps anomaly queries fast. Typical query latency: <50ms for 7-day raw range, <20ms for 2-year hourly aggregate.

ML Pipeline
Scheduled
LSTM daily · NRW weekly · Predictive maintenance daily

Python ML workers consume from Kafka. LSTM demand forecasting (02:00 AM daily per deployment): reads 7-day hourly history from TimescaleDB, outputs 72-hour demand forecast stored back to demand_forecasts table. NRW analysis (03:00 Sunday): flow_produced − flow_billed − losses = NRW% per zone. Predictive maintenance (04:00 daily): rolling regression on calibration residuals detects sensor drift 7–14 days ahead.

Alert Engine
Real-time
Redis deduplication · GPS zone routing · 30min/supervisor escalation ladder

Kafka consumer evaluates every incoming reading in real-time: (a) operator-configured thresholds per device, (b) edge AI anomaly_score forwarded in packet, (c) rate-of-change rules (pH drop >0.5 in 1 minute). Redis bloom filter deduplicates: same alert type suppressed 30 minutes. GPS zone lookup assigns field engineer. FCM HTTP v1 → push notification in <2 seconds. Escalation: 15min unack → supervisor; 30min → ops manager; 60min CRITICAL → government nodal officer SMS.

08
ALERTS

Alert Flow — Contamination to Phone in 45 Seconds

Step-by-step timeline from edge AI detection to push notification on a field engineer's Android phone.

T + 0s — TRIGGER

Edge AI detects contamination

TFLite quality classifier: CONTAMINATED confidence 94% >0.80 threshold. Decision engine: close valve (GPIO PWM→0V), relay CH3 alarm ON, QoS2 flag set in TX queue.

T + 2s — LOCAL ACTION

Valve closes in 7 seconds, alarm sounds

Motorised valve receives 0V → closes. Relay CH3 activates siren. DS3231 timestamps event. SD card logs: all 15 sensor values, anomaly score, quality confidence, valve command.

T + 5s — LORA TX

QoS 2 alert packet transmitted

LoRaWAN FPort=11 (alert). Confirmed uplink (MHDR=0x80). MIC appended with NwkSKey AES-CMAC. If no ACK in 5s: NB-IoT activates as fallback. AT+SMQTPUB with QoS 2.

T + 8s — CLOUD RECEIPT

ChirpStack MIC-verifies, EMQX receives

ChirpStack deduplicates (200ms window, best RSSI gateway selected). Decrypts FRMPayload with AppSKey. EMQX ACKs QoS 2 (4-step handshake). Kafka routes to alert-engine consumer.

T + 12s — ALERT RECORD

PostgreSQL alert record created

Schema: (id, device_id, timestamp, type=CONTAMINATION, severity=CRITICAL, sensor_values JSON, ai_scores JSON, zone_id, assigned_engineer_id, status=OPEN, created_at).

T + 18s — ROUTING

GPS zone lookup → FCM topic publish

Zone lookup: GPS coordinates → zone_id → assigned field engineer. FCM HTTP v1 POST to topic zone_{zone_id}. Webhook fires to WhatsApp Business API for supervisor channel.

T + 25s — DELIVERY

Push notification on engineer's phone

"CRITICAL: Contamination at Tank B7, Zone 3. pH 5.2, Turbidity 180 NTU. Valve auto-closed. Tap to view." Deep link → device detail screen with full sensor timeline.

T + 45s — DASHBOARD

Government GIS map node turns RED

WebSocket event alert_created pushes to all connected dashboard clients. Node icon RED. Alert in triage queue. Supervisor sees full sensor history, AI confidence, and valve status.

09
POWER

Power Budget

Every milliamp accounted for. Total average ~46 mA = 9-day battery life + 10× solar margin.

ComponentStatemADuty %Avg mANotes
ESP32-S3Active (sensing + AI)2410%2.40Core 0: sensors; Core 1: comms
ESP32-S3Deep sleep0.0190%0.009ULP coprocessor only
Atlas EZO-pHActive read223%0.66Sleep 2.6 mA between reads
Atlas EZO-ECActive read223%0.66Same sleep pattern
Atlas EZO-DOActive read223%0.668s response, awake 10s/read
DFRobot TurbidityAlways on10100%10.00Power-gate via transistor to save
Ultrasonic Flow MeterActive poll805%4.0024V via boost converter
Pressure TransducerAlways on20100%20.004–20mA loop — biggest draw
ADS1115Convert bursts0.155%0.008Negligible
DS3231 RTCAlways on0.5100%0.50CR2032 backup on outage
INA226Always on0.33100%0.33Continuous battery monitoring
LoRa (TX burst)Transmitting1200.5%0.605-min interval, ~2s per TX
LoRa (idle)Sleep199.5%1.00Not in continuous RX
SIM7080G NB-IoTPSM T3412=1hr0.00499%0.004Fallback only, 3.8µA PSM
NEO-M8N GPSWeekly 30s fix500.05%0.02530s ON once/week
MicroSDWrite burst1001%1.00~0.5s write per 5-min cycle
Relay (1 active)Pump control805%4.00Not always active
TOTAL AVERAGE~46 mA10,000 mAh / 46mA = 217hrs (9 days)
Solar margin: 10W panel in India = ~40–50 Wh/day (4–5 peak sun hours). At 3.7V = ~10,800 mAh/day generated. Daily consumption = 46mA × 24h = 1,104 mAh. Solar recharges ~10× faster than consumption — large buffer for 5+ cloudy days in a row.
Biggest optimisation: Replace always-on 4–20mA pressure transducer (20 mA constant) with digital sensor (MS5803, I2C, ~0.5 mA active + gate power). Saves ~18 mA avg — cuts total by 39%, extending battery from 9 to 15 days.
10
BOM & COST

BOM & Cost Analysis

34 line items, full Bill of Materials with INR unit costs at prototype (1–10 units) and production (100+ units) scale. Sources: Robu.in, Mouser India, IndiaMART, JLCPCB.

#ComponentSupplier / SourceQtyProto (₹)Prod 100+ (₹)Line Total
COMPUTE SUBSYSTEM
1ESP32-S3 Development ModuleEspressif / Robu.in1300200300
2DS3231 RTC Module (with CR2032)Maxim / Robu.in1250150250
3MicroSD Card Module (SPI)Generic / Robu.in1300180300
4MicroSD Card 32 GB SamsungAmazon India1450350450
Compute Subtotal1,300
WATER QUALITY SENSORS
5Atlas Scientific EZO-pH Circuit + ProbeAtlas Scientific (direct)14,0003,4004,000
6Atlas Scientific EZO-EC Circuit + ProbeAtlas Scientific (direct)14,3003,6004,300
7Atlas Scientific EZO-DO Circuit + ProbeAtlas Scientific (direct)14,7004,0004,700
8DFRobot SEN0189 Turbidity SensorDFRobot / Robu.in1650400650
9DS18B20 Waterproof Temperature ProbeMaxim / Robu.in110060100
Water Quality Subtotal13,750
FLOW & PRESSURE SUBSYSTEM
10Ultrasonic Clamp-on Flow Meter (DN25)Industrial / IndiaMART110,0007,50010,000
114–20mA Pressure Transducer 0–10 barIndustrial / Moglix12,5001,8002,500
12A02YYUW Ultrasonic Level SensorDFRobot / Robu.in11,0006501,000
13ADS1115 16-bit ADC ModuleAdafruit / Robu.in1400250400
14MAX485 RS485 Transceiver ModuleGeneric / Robu.in1805080
Flow & Pressure Subtotal13,980
TRANSMISSION SUBSYSTEM
15RYLR998 LoRa Module (SX1276)Reyax / Robu.in1550380550
16SIM7080G NB-IoT/GNSS ModuleSIMCom / Waveshare11,4001,1001,400
17u-blox NEO-M8N GPS Moduleu-blox / Robu.in11,2009001,200
18NB-IoT SIM Card (Airtel IoT)Airtel Business1200150200
19LoRa Antenna 868 MHz 3 dBiGeneric / Robu.in1150100150
Transmission Subtotal3,500
POWER SUBSYSTEM
2010W Monocrystalline Solar PanelLoom Solar / Amazon1700500700
21CN3791 MPPT Charger ModuleGeneric / Robu.in1500300500
22Li-Ion Battery Pack 10,000 mAh 3.7VGeneric 18650 pack11,2009001,200
23INA226 Power Monitor ModuleTI / Robu.in1400250400
24USB-C Port + Cable Gland SetGeneric1300180300
Power Subtotal3,100
ACTUATOR SUBSYSTEM
25DN25 Motorized Ball Valve (0–10V, 24V)Industrial / IndiaMART16,5004,5006,500
264-Channel Opto-isolated Relay ModuleGeneric / Robu.in1400250400
27LM324 Op-Amp + RC filter passivesLCSC / Robu.in110060100
Actuator Subtotal7,000
ENCLOSURE & MECHANICAL
28IP67 ABS Enclosure 200×150×80mmFibox / IndiaMART12,0001,4002,000
29DIN Rail + Wall Mount BracketGeneric1300200300
30IP67 Cable Glands (set of 6)Hawke / IndiaMART1400250400
31Terminal Blocks + DIN Rail (set)Phoenix Contact1500350500
Enclosure Subtotal3,200
PCB & MISCELLANEOUS
32Custom PCB 2-layer 100×80mmJLCPCB / PCBWay1800350800
33Passive components (R, C, connectors)LCSC India1400200400
34Wire, connectors, heat shrink setGeneric1300180300
PCB & Misc Subtotal1,500
TOTAL BOM COST PER UNIT₹ 47,330
Biggest cost driver: Atlas sensors (pH+EC+DO = ₹13,000) = 27% of total BOM. Budget alternative: DFRobot analog sensors (~₹1,500 total). Saves ₹11,500/unit but reduces accuracy from ±0.02 to ±0.1 pH and needs more frequent calibration.
Prototype Scale (1–10 units)
BOM₹ 47,330
Assembly (manual)₹ 3,000
Testing + calibration₹ 2,000
PCB (5-pc run)₹ 1,200
Total Unit Cost₹ 53,530
Production Scale (100+ units)
BOM₹ 33,100
PCBA + test jig₹ 1,500
Testing + calibration₹ 800
PCB panel₹ 350
Total Unit Cost₹ 35,750
Government Pricing Model
Hardware (to utility)₹ 80k–1.2L
SaaS/month/node₹ 3,000–5,000
Annual maintenance₹ 8,000–12,000
HW gross margin~55–65%
SaaS gross margin>80%
Budget Version (₹28K target)
Swap Atlas → DFRobotSave ₹ 11,500
Swap 4–20mA → digitalSave ₹ 2,000
Remove GPSSave ₹ 1,200
Remove DO sensorSave ₹ 4,700
Budget BOM~₹ 27,930