Repository navigation
Expand file tree
/
Copy pathProjectReport.html
More file actions
1445 lines (1319 loc) · 77.2 KB
/
Copy pathProjectReport.html
File metadata and controls
1445 lines (1319 loc) · 77.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VetNode: IoT-Based Cattle Health Monitoring System — Project Report</title>
<style>
:root {
--primary: #1a3c5e;
--accent: #2e7d32;
--border: #cfd8dc;
--bg-light: #f5f7fa;
--text: #263238;
--text-muted: #546e7a;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Georgia', 'Times New Roman', serif;
line-height: 1.8;
color: var(--text);
max-width: 900px;
margin: 0 auto;
padding: 40px 30px;
background: #fff;
}
/* ── Cover Page ── */
.cover-page {
text-align: center;
page-break-after: always;
padding: 60px 0 40px;
border-bottom: 3px double var(--primary);
margin-bottom: 50px;
}
.cover-page .institution {
font-size: 1.1em;
text-transform: uppercase;
letter-spacing: 2px;
color: var(--text-muted);
margin-bottom: 60px;
}
.cover-page h1 {
font-size: 2.2em;
color: var(--primary);
margin-bottom: 10px;
line-height: 1.3;
}
.cover-page .subtitle {
font-size: 1.15em;
color: var(--text-muted);
font-style: italic;
margin-bottom: 50px;
}
.cover-page .meta {
font-size: 1em;
line-height: 2;
color: var(--text);
}
.cover-page .meta strong {
color: var(--primary);
}
/* ── Table of Contents ── */
.toc {
page-break-after: always;
margin-bottom: 50px;
padding-bottom: 40px;
border-bottom: 1px solid var(--border);
}
.toc h2 {
font-size: 1.6em;
color: var(--primary);
margin-bottom: 20px;
border-bottom: 2px solid var(--primary);
padding-bottom: 8px;
}
.toc ol {
list-style: none;
counter-reset: toc-counter;
}
.toc > ol > li {
counter-increment: toc-counter;
margin-bottom: 6px;
}
.toc > ol > li::before {
content: counter(toc-counter) ". ";
font-weight: bold;
color: var(--primary);
}
.toc > ol > li > a {
text-decoration: none;
color: var(--text);
font-size: 1.05em;
}
.toc > ol > li > a:hover {
color: var(--accent);
text-decoration: underline;
}
.toc ol ol {
margin-left: 28px;
margin-top: 4px;
list-style: none;
counter-reset: toc-sub;
}
.toc ol ol li {
counter-increment: toc-sub;
margin-bottom: 3px;
}
.toc ol ol li::before {
content: counter(toc-counter) "." counter(toc-sub) " ";
color: var(--text-muted);
font-size: 0.95em;
}
.toc ol ol li a {
text-decoration: none;
color: var(--text-muted);
font-size: 0.95em;
}
.toc ol ol li a:hover {
color: var(--accent);
}
/* ── Sections ── */
.section {
margin-bottom: 45px;
}
h2.section-title {
font-size: 1.5em;
color: var(--primary);
border-bottom: 2px solid var(--primary);
padding-bottom: 6px;
margin-bottom: 20px;
}
h3 {
font-size: 1.2em;
color: var(--primary);
margin: 25px 0 12px;
}
h4 {
font-size: 1.05em;
color: var(--text);
margin: 18px 0 8px;
font-style: italic;
}
p {
margin-bottom: 14px;
text-align: justify;
}
ul, ol {
margin: 10px 0 16px 28px;
}
li {
margin-bottom: 6px;
}
/* ── Tables ── */
table {
width: 100%;
border-collapse: collapse;
margin: 16px 0 24px;
font-size: 0.92em;
}
thead {
background: var(--primary);
color: #fff;
}
th {
padding: 10px 14px;
text-align: left;
font-weight: 600;
letter-spacing: 0.3px;
}
td {
padding: 9px 14px;
border-bottom: 1px solid var(--border);
}
tbody tr:nth-child(even) {
background: var(--bg-light);
}
tbody tr:hover {
background: #e8edf2;
}
/* ── Code Blocks ── */
code {
font-family: 'Courier New', monospace;
background: var(--bg-light);
padding: 2px 6px;
border-radius: 3px;
font-size: 0.9em;
}
pre {
background: #1e293b;
color: #e2e8f0;
padding: 18px 22px;
border-radius: 6px;
overflow-x: auto;
margin: 14px 0 20px;
font-size: 0.88em;
line-height: 1.6;
}
pre code {
background: none;
padding: 0;
color: inherit;
}
/* ── Figures & Diagrams ── */
.diagram-box {
background: var(--bg-light);
border: 1px solid var(--border);
border-radius: 8px;
padding: 24px;
margin: 20px 0;
text-align: center;
}
.diagram-box pre {
background: #fff;
color: var(--text);
text-align: left;
display: inline-block;
padding: 20px 30px;
border: 1px solid var(--border);
font-size: 0.82em;
line-height: 1.5;
}
.diagram-box .caption {
margin-top: 12px;
font-style: italic;
color: var(--text-muted);
font-size: 0.92em;
}
/* ── Highlights / Notes ── */
.note {
background: #e8f5e9;
border-left: 4px solid var(--accent);
padding: 14px 18px;
margin: 16px 0;
border-radius: 0 6px 6px 0;
font-size: 0.95em;
}
.note strong {
color: var(--accent);
}
/* ── Print Styles ── */
@media print {
body {
padding: 20px;
font-size: 11pt;
}
.cover-page {
page-break-after: always;
}
.toc {
page-break-after: always;
}
.section {
page-break-inside: avoid;
}
h2.section-title {
page-break-after: avoid;
}
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
}
/* ── Mermaid Diagrams ── */
.mermaid-container {
background: var(--bg-light);
border: 1px solid var(--border);
border-radius: 8px;
padding: 24px 16px;
margin: 20px 0 28px;
overflow-x: auto;
}
.mermaid-container .mermaid {
display: flex;
justify-content: center;
}
.mermaid-container .mermaid svg {
max-width: 100%;
height: auto;
}
.fig-caption {
text-align: center;
font-style: italic;
color: var(--text-muted);
font-size: 0.92em;
margin-top: 10px;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<script>
mermaid.initialize({
startOnLoad: true,
theme: 'base',
themeVariables: {
primaryColor: '#e3f2fd',
primaryTextColor: '#1a3c5e',
primaryBorderColor: '#1565c0',
lineColor: '#546e7a',
secondaryColor: '#fce4ec',
tertiaryColor: '#f5f7fa',
fontFamily: 'Georgia, Times New Roman, serif',
fontSize: '13px'
},
flowchart: { curve: 'basis', padding: 15 },
stateDiagram: { padding: 15 },
gantt: { fontSize: 12 }
});
</script>
</head>
<body>
<!-- ════════════════════════════════════════════════════════════════════
COVER PAGE
════════════════════════════════════════════════════════════════════ -->
<div class="cover-page">
<div class="institution">
Department of Electronics & Telecommunication Engineering<br>
Final Year Engineering Project Report
</div>
<h1>VetNode: IoT-Based Cattle Health<br>Monitoring System</h1>
<div class="subtitle">
An ESP32-based Wireless Sensor Network using LoRa and GSM<br>
for Real-Time Livestock Vital Sign Monitoring and Alert Generation
</div>
<div class="meta">
<strong>Academic Year:</strong> 2025–2026<br>
<strong>Submission Date:</strong> March 2026<br>
<strong>Platform:</strong> ESP32-WROOM-32 / Arduino Framework<br>
<strong>Version:</strong> v1.3 (Production Release)
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════════
TABLE OF CONTENTS
════════════════════════════════════════════════════════════════════ -->
<div class="toc">
<h2>Table of Contents</h2>
<ol>
<li><a href="#introduction">Introduction</a>
<ol>
<li><a href="#overview">Project Overview</a></li>
<li><a href="#problem">Problem Statement</a></li>
<li><a href="#objectives">Objectives</a></li>
</ol>
</li>
<li><a href="#system-overview">System Overview</a>
<ol>
<li><a href="#solution">High-Level Description of the Solution</a></li>
<li><a href="#features">Key Features and Functionality</a></li>
</ol>
</li>
<li><a href="#architecture">Architecture Design</a>
<ol>
<li><a href="#arch-explain">System Architecture</a></li>
<li><a href="#data-flow">System Architecture Diagram</a></li>
<li><a href="#block-diagram">Data Flow Diagram</a></li>
</ol>
</li>
<li><a href="#hardware">Hardware Components</a>
<ol>
<li><a href="#hw-list">Component List</a></li>
<li><a href="#hw-desc">Component Descriptions</a></li>
<li><a href="#pin-map">Pin Mapping</a></li>
</ol>
</li>
<li><a href="#software">Software & Code Flow</a>
<ol>
<li><a href="#sw-tech">Technologies and Libraries</a></li>
<li><a href="#sw-node">Node Firmware Logic</a></li>
<li><a href="#sw-gateway">Gateway Firmware Logic</a></li>
<li><a href="#sw-protocol">Communication Protocol</a></li>
</ol>
</li>
<li><a href="#implementation">Implementation Details</a>
<ol>
<li><a href="#impl-steps">Step-by-Step Working</a></li>
<li><a href="#impl-integration">Hardware–Software Integration</a></li>
<li><a href="#impl-config">Configuration and Persistence</a></li>
</ol>
</li>
<li><a href="#results">Results & Observations</a>
<ol>
<li><a href="#res-output">System Output</a></li>
<li><a href="#res-perf">Performance Metrics</a></li>
<li><a href="#res-threshold">Alert Threshold Behavior</a></li>
</ol>
</li>
<li><a href="#conclusion">Conclusion</a>
<ol>
<li><a href="#summary">Project Summary</a></li>
<li><a href="#learnings">Key Learnings</a></li>
</ol>
</li>
<li><a href="#future">Future Scope</a></li>
<li><a href="#references">References</a></li>
</ol>
</div>
<!-- ════════════════════════════════════════════════════════════════════
1. INTRODUCTION
════════════════════════════════════════════════════════════════════ -->
<div class="section" id="introduction">
<h2 class="section-title">1. Introduction</h2>
<h3 id="overview">1.1 Project Overview</h3>
<p>
<strong>VetNode</strong> is an Internet of Things (IoT) based cattle health monitoring system designed to provide real-time, continuous surveillance of livestock vital signs. The system employs wearable sensor nodes attached to individual cattle to measure body temperature and heart rate, transmitting the collected data wirelessly to a centralized gateway unit using Long Range (LoRa) radio communication at 433 MHz.
</p>
<p>
The central gateway aggregates incoming telemetry, evaluates the readings against configurable health thresholds, and dispatches descriptive SMS alerts to the farmer's mobile phone via a GSM modem when anomalous conditions are detected. A built-in OLED dashboard provides on-site real-time visualization, while a menu-driven interface allows field configuration without requiring firmware re-flashing.
</p>
<p>
The project targets small to medium-scale dairy and cattle farms where veterinary resources are limited and early detection of health anomalies—such as fever, hypothermia, tachycardia, or bradycardia—can significantly reduce livestock mortality and improve farm productivity.
</p>
<h3 id="problem">1.2 Problem Statement</h3>
<p>
Livestock health monitoring in rural and semi-urban farming operations remains predominantly manual, relying on periodic visual inspections and intermittent veterinary visits. This approach presents several critical limitations:
</p>
<ul>
<li><strong>Delayed Detection:</strong> Symptoms of common bovine diseases such as mastitis, bovine respiratory disease (BRD), and tick-borne fever often manifest through subtle changes in body temperature and heart rate hours before visible clinical signs appear. Manual observation frequently misses these early indicators.</li>
<li><strong>Scalability Constraints:</strong> As herd sizes grow, the labor and time required for individual animal assessment become unsustainable, leading to monitoring gaps and increased risk of undetected illness spreading within the herd.</li>
<li><strong>Limited Connectivity:</strong> Rural farming areas often lack reliable internet infrastructure, rendering cloud-dependent IoT solutions impractical. A communication method that operates independently of Wi-Fi or cellular data networks is essential.</li>
<li><strong>Cost Barriers:</strong> Commercial livestock monitoring systems are prohibitively expensive for smallholder farmers, creating an accessibility gap in precision livestock farming technologies.</li>
<li><strong>Absence of Automated Alerting:</strong> Without continuous monitoring and automated notification mechanisms, abnormal health events during nighttime hours or when farm personnel are off-site go undetected until they escalate into emergencies.</li>
</ul>
<h3 id="objectives">1.3 Objectives</h3>
<p>The primary objectives of the VetNode project are as follows:</p>
<ol>
<li>Design and implement a wearable, low-power sensor node capable of continuously measuring bovine body temperature and heart rate with clinically acceptable accuracy.</li>
<li>Establish a reliable long-range wireless communication link between sensor nodes and a central gateway using LoRa modulation at 433 MHz, achieving effective coverage of 100–200 meters in typical farm environments.</li>
<li>Develop a centralized gateway unit that aggregates multi-node telemetry, evaluates health thresholds, and dispatches descriptive SMS alerts via a GSM modem to the farmer's mobile phone.</li>
<li>Implement a non-blocking, state-machine-driven firmware architecture that ensures responsive user interaction and uninterrupted data acquisition.</li>
<li>Provide an on-device user interface with a real-time OLED dashboard and menu-driven configuration system, enabling threshold adjustment and system diagnostics without programming tools.</li>
<li>Support multi-node operation with Time Division Multiple Access (TDMA) scheduling to prevent transmission collisions across simultaneously monitored cattle.</li>
<li>Achieve a cost-effective, open-source solution accessible to smallholder farmers using commercially available, off-the-shelf components.</li>
</ol>
</div>
<!-- ════════════════════════════════════════════════════════════════════
2. SYSTEM OVERVIEW
════════════════════════════════════════════════════════════════════ -->
<div class="section" id="system-overview">
<h2 class="section-title">2. System Overview</h2>
<h3 id="solution">2.1 High-Level Description of the Solution</h3>
<p>
The VetNode system follows a star-topology wireless sensor network architecture comprising two primary subsystems:
</p>
<ol>
<li><strong>Sensor Nodes (Wearable Units):</strong> Each node is an ESP32-based embedded device equipped with a MAX30102 pulse oximetry sensor for heart rate detection, a DS18B20 digital temperature sensor for body temperature measurement, and a DS3231 real-time clock for timestamping. The node continuously acquires sensor data and transmits structured telemetry packets via an SX1278 LoRa transceiver at 2-second intervals.</li>
<li><strong>Central Gateway (Base Station):</strong> The gateway is an ESP32-based receiver that monitors the LoRa channel for incoming node transmissions. It parses telemetry packets, updates per-node health records, evaluates readings against configurable thresholds, and triggers SMS alerts through a SIM800L GSM modem when anomalies are detected. A 128×64 SH1106 OLED display provides real-time dashboard visualization, and a two-button interface enables menu navigation and configuration.</li>
</ol>
<p>
The system operates entirely on the unlicensed 433 MHz ISM band for node-to-gateway communication and the 2G GSM network for alert delivery, making it independent of local internet infrastructure.
</p>
<h3 id="features">2.2 Key Features and Functionality</h3>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>Non-Blocking Architecture</td>
<td>All GSM, LoRa, and sensor operations are driven by finite state machines, preventing any single operation from blocking the main loop and ensuring responsive UI and continuous data acquisition.</td>
</tr>
<tr>
<td>Robust LoRa Communication</td>
<td>Synchronized LoRa parameters (433 MHz, BW 125 kHz, SF7, CR 4/5) with automatic link recovery and per-packet RSSI monitoring.</td>
</tr>
<tr>
<td>TDMA Anti-Collision</td>
<td>Time-slotted transmission scheduling (500 ms per node) prevents packet collisions in multi-node deployments without requiring a coordination protocol.</td>
</tr>
<tr>
<td>Descriptive SMS Alerts</td>
<td>Alert messages include the cow ID, violation type (temperature high/low, heart rate high/low), and live vital sign values, enabling immediate remote diagnosis.</td>
</tr>
<tr>
<td>Persistent Configuration</td>
<td>All configurable parameters (thresholds, phone number, alert intervals) are stored in ESP32 Non-Volatile Storage (NVS) and persist across power cycles.</td>
</tr>
<tr>
<td>Real-Time OLED Dashboard</td>
<td>Live display of cow ID, temperature, heart rate, LoRa signal bars, GSM signal strength, and "Last Seen" ticker with automatic refresh.</td>
</tr>
<tr>
<td>Power Management</td>
<td>Configurable OLED auto-off timeout and gateway sleep timer to conserve battery in field deployments.</td>
</tr>
<tr>
<td>Graceful Degradation</td>
<td>System continues operation with partial sensor failures, reporting error flags in telemetry packets rather than halting.</td>
</tr>
<tr>
<td>Heart Rate Outlier Rejection</td>
<td>4-beat rolling average with ±30% deviation filtering suppresses spurious readings from sensor noise or motion artifacts.</td>
</tr>
<tr>
<td>Remote Node Control</td>
<td>Gateway can send commands to nodes (LED control, ping) for field diagnostics and hardware verification.</td>
</tr>
</tbody>
</table>
</div>
<!-- ════════════════════════════════════════════════════════════════════
3. ARCHITECTURE DESIGN
════════════════════════════════════════════════════════════════════ -->
<div class="section" id="architecture">
<h2 class="section-title">3. Architecture Design</h2>
<h3 id="arch-explain">3.1 System Architecture</h3>
<p>
The VetNode system adopts a <strong>two-tier, star-topology wireless sensor network</strong> architecture. At the edge layer, multiple wearable sensor nodes operate as independent data acquisition units, each responsible for a single animal. At the aggregation layer, a centralized gateway serves as the network coordinator, data processor, and communication bridge to the GSM cellular network.
</p>
<p>
Within each tier, the firmware follows a <strong>cooperative multitasking</strong> model built on non-blocking finite state machines. This architectural decision ensures that no single operation (sensor read, radio transmission, serial communication, or user interface update) monopolizes the processor, thereby maintaining system responsiveness and preventing watchdog timer resets.
</p>
<p>
The communication layer employs a <strong>unidirectional primary / bidirectional secondary</strong> pattern: nodes primarily transmit heartbeat and data packets to the gateway, while the gateway may optionally send command packets (LED control, pings) to specific nodes. This asymmetric design minimizes node power consumption while preserving remote diagnostic capabilities.
</p>
<h3 id="data-flow">3.2 System Architecture Diagram</h3>
<div class="mermaid-container">
<div class="mermaid">
graph LR
subgraph NODE[" SENSOR NODE (Per Cow) "]
direction TB
DS18["DS18B20<br/>Temperature"]
MAX["MAX30102<br/>Heart Rate"]
RTC["DS3231<br/>RTC"]
ESP_N["ESP32<br/>Node MCU"]
LORA_N["SX1278<br/>LoRa TX"]
LED_G["Green LED<br/>Status"]
LED_R["Red LED<br/>Pulse/Error"]
DS18 -->|OneWire| ESP_N
MAX -->|I2C| ESP_N
RTC -->|I2C| ESP_N
ESP_N -->|SPI| LORA_N
ESP_N --> LED_G
ESP_N --> LED_R
end
subgraph GW[" CENTRAL GATEWAY "]
direction TB
LORA_G["SX1278<br/>LoRa RX"]
ESP_G["ESP32<br/>Gateway MCU"]
OLED["SH1106<br/>OLED Display"]
GSM["SIM800L<br/>GSM Modem"]
BTN["Buttons<br/>Menu + Select"]
BUZ["Buzzer<br/>Audio Alert"]
LORA_G -->|SPI| ESP_G
ESP_G -->|I2C| OLED
ESP_G -->|UART| GSM
BTN --> ESP_G
ESP_G --> BUZ
end
LORA_N ==>|"LoRa 433MHz<br/>HB/DATA Packets"| LORA_G
LORA_G -.->|"CMD/PING<br/>Packets"| LORA_N
GSM ==>|"SMS Alert<br/>2G Network"| PHONE["Farmer's<br/>Mobile Phone"]
</div>
<div class="fig-caption">Figure 1: System architecture diagram showing Node and Gateway subsystems with communication links</div>
</div>
<h3 id="block-diagram">3.3 Data Flow Diagram</h3>
<div class="mermaid-container">
<div class="mermaid">
flowchart TD
A["Sensors<br/>DS18B20 + MAX30102 + DS3231"] -->|"Raw Readings"| B["ESP32 Node<br/>Data Processing"]
B -->|"Packet Assembly<br/>HB,seq,id,temp,hr,err"| C["SX1278 LoRa TX<br/>433 MHz"]
C -->|"Wireless Transmission<br/>TDMA Scheduled"| D["SX1278 LoRa RX<br/>Gateway"]
D -->|"Raw Packet String"| E["ESP32 Gateway<br/>Packet Parser"]
E -->|"Parsed Data"| F["NodeData Structure<br/>Update per Cow ID"]
F --> G{"Threshold<br/>Evaluation"}
G -->|"Normal"| H["OLED Dashboard<br/>Real-Time Display"]
G -->|"Breach Detected"| I["queueAlert<br/>Build SMS String"]
I --> J["Buzzer<br/>3x 100ms Beeps"]
I --> K["SIM800L GSM<br/>State Machine"]
K --> L["SMS Delivered<br/>to Farmer"]
I --> H
E -->|"Sequence Tracking"| M["Packet Loss<br/>Detection"]
M --> H
style A fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
style C fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
style D fill:#fce4ec,stroke:#c62828,stroke-width:2px
style G fill:#fff3e0,stroke:#e65100,stroke-width:2px
style I fill:#ffebee,stroke:#c62828,stroke-width:2px
style L fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
style H fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
</div>
<div class="fig-caption">Figure 2: End-to-end data flow from sensor acquisition to alert delivery and dashboard display</div>
</div>
<h3>3.4 TDMA Transmission Scheduling</h3>
<div class="mermaid-container">
<div class="mermaid">
gantt
title TDMA Slot Allocation per 2-Second Cycle
dateFormat X
axisFormat %Lms
section Node 1 COW_ID=1
TX Slot 0ms offset :active, n1, 0, 100
Guard Interval :done, g1, 100, 500
section Node 2 COW_ID=2
TX Slot 500ms offset :active, n2, 500, 600
Guard Interval :done, g2, 600, 1000
section Node 3 COW_ID=3
TX Slot 1000ms offset :active, n3, 1000, 1100
Guard Interval :done, g3, 1100, 1500
section Node 4 COW_ID=4
TX Slot 1500ms offset :active, n4, 1500, 1600
Guard Interval :done, g4, 1600, 2000
</div>
<div class="fig-caption">Figure 3: TDMA time-slot allocation preventing multi-node packet collisions within a 2-second transmission cycle</div>
</div>
</div>
<!-- ════════════════════════════════════════════════════════════════════
4. HARDWARE COMPONENTS
════════════════════════════════════════════════════════════════════ -->
<div class="section" id="hardware">
<h2 class="section-title">4. Hardware Components</h2>
<h3 id="hw-list">4.1 Component List</h3>
<table>
<thead>
<tr>
<th>Component</th>
<th>Quantity</th>
<th>Used In</th>
<th>Interface</th>
</tr>
</thead>
<tbody>
<tr><td>ESP32-WROOM-32 Development Board</td><td>2+ (1 per node + 1 gateway)</td><td>Node & Gateway</td><td>—</td></tr>
<tr><td>SX1278 LoRa Transceiver Module (433 MHz)</td><td>2+</td><td>Node & Gateway</td><td>SPI</td></tr>
<tr><td>MAX30102 Pulse Oximetry & Heart Rate Sensor</td><td>1 per node</td><td>Node</td><td>I2C (0x57)</td></tr>
<tr><td>DS18B20 Digital Temperature Sensor</td><td>1 per node</td><td>Node</td><td>OneWire</td></tr>
<tr><td>DS3231 Real-Time Clock Module</td><td>1 per node</td><td>Node</td><td>I2C (0x68)</td></tr>
<tr><td>SIM800L GSM/GPRS Module</td><td>1</td><td>Gateway</td><td>UART</td></tr>
<tr><td>SH1106 128×64 OLED Display</td><td>1</td><td>Gateway</td><td>I2C (0x3C)</td></tr>
<tr><td>Push Buttons (Tactile)</td><td>2</td><td>Gateway</td><td>GPIO (Pullup)</td></tr>
<tr><td>Active Buzzer</td><td>1</td><td>Gateway</td><td>GPIO</td></tr>
<tr><td>LEDs (Green & Red)</td><td>2 per node</td><td>Node</td><td>GPIO</td></tr>
<tr><td>4.7 kΩ Resistor (DS18B20 Pull-up)</td><td>1 per node</td><td>Node</td><td>—</td></tr>
<tr><td>2A 5V Power Supply (SIM800L)</td><td>1</td><td>Gateway</td><td>—</td></tr>
</tbody>
</table>
<h3 id="hw-desc">4.2 Component Descriptions and Roles</h3>
<h4>ESP32-WROOM-32 (Microcontroller)</h4>
<p>
The ESP32-WROOM-32 serves as the central processing unit for both the sensor node and gateway. Featuring a 32-bit Xtensa LX6 dual-core processor clocked at 240 MHz, 520 KB of SRAM, and 4 MB of flash memory, it provides ample computational resources for concurrent sensor management, radio communication, and user interface rendering. Its native support for SPI, I2C, and UART peripherals makes it an ideal platform for interfacing with the diverse set of sensors and communication modules required by this project.
</p>
<h4>SX1278 LoRa Transceiver (Communication)</h4>
<p>
The Semtech SX1278 is a sub-GHz LoRa spread-spectrum transceiver operating in the 433 MHz ISM band. It provides long-range wireless communication with high sensitivity (−148 dBm) and configurable link parameters. In this project, it is configured with a bandwidth of 125 kHz, spreading factor 7, coding rate 4/5, and transmit power of 10 dBm, achieving an effective range of 100–200 meters in line-of-sight farm conditions. The module interfaces with the ESP32 via the SPI bus using the RadioLib library.
</p>
<h4>MAX30102 Pulse Oximetry Sensor (Heart Rate)</h4>
<p>
The MAX30102 is an integrated pulse oximetry and heart rate sensor module with dual-wavelength (red and infrared) LEDs and a photodetector. In this application, the infrared channel is used for heart rate detection through photoplethysmography (PPG). The sensor is configured for a sample rate of 400 Hz with an 18-bit ADC resolution (411 μs pulse width), providing high-fidelity pulse waveform data. A custom beat detection algorithm processes the raw IR values to extract beats per minute (BPM) with a rolling 4-beat average.
</p>
<h4>DS18B20 Digital Temperature Sensor</h4>
<p>
The DS18B20 is a digital thermometer that communicates over a single-wire (OneWire) interface, providing temperature measurements with a factory-calibrated accuracy of ±0.5°C over the range of −10°C to +85°C. Its digital output eliminates the need for analog-to-digital conversion and associated calibration errors, making it well-suited for body temperature monitoring in the 37–42°C range relevant to bovine health.
</p>
<h4>DS3231 Real-Time Clock (Timekeeping)</h4>
<p>
The DS3231 is a high-precision I2C real-time clock with an integrated temperature-compensated crystal oscillator (TCXO), providing timekeeping accuracy of ±2 ppm (±1 minute per year). It serves as the timestamp source for sensor readings on the node side, enabling accurate temporal correlation of health data.
</p>
<h4>SIM800L GSM Module (Cellular Communication)</h4>
<p>
The SIM800L is a quad-band (850/900/1800/1900 MHz) GSM/GPRS module used exclusively on the gateway for dispatching SMS alerts. It interfaces with the ESP32 via UART (Serial2) at 9600 baud and is managed by a non-blocking state machine that handles AT command sequences for SMS transmission. The module requires a dedicated 5V power supply capable of delivering 2A peak current during radio bursts.
</p>
<h4>SH1106 128×64 OLED Display (User Interface)</h4>
<p>
The SH1106 OLED display provides a monochrome, high-contrast visual interface on the gateway. It renders the real-time dashboard showing cow identification, vital signs, LoRa signal quality, GSM status, and alert notifications. The display is driven via I2C using the Adafruit SH110X and GFX libraries, with support for automatic power-off after a configurable inactivity timeout.
</p>
<h3 id="pin-map">4.3 Pin Mapping</h3>
<h4>Node Pin Configuration</h4>
<table>
<thead>
<tr><th>Function</th><th>GPIO Pin</th><th>Direction</th><th>Protocol</th></tr>
</thead>
<tbody>
<tr><td>LoRa SCK</td><td>18</td><td>Output</td><td>SPI Clock</td></tr>
<tr><td>LoRa MISO</td><td>19</td><td>Input</td><td>SPI Data In</td></tr>
<tr><td>LoRa MOSI</td><td>23</td><td>Output</td><td>SPI Data Out</td></tr>
<tr><td>LoRa CS (SS)</td><td>5</td><td>Output</td><td>SPI Chip Select</td></tr>
<tr><td>LoRa RST</td><td>14</td><td>Output</td><td>Module Reset</td></tr>
<tr><td>LoRa DIO0</td><td>2</td><td>Input</td><td>TX/RX Interrupt</td></tr>
<tr><td>I2C SDA (MAX30102, DS3231)</td><td>21</td><td>Bidirectional</td><td>I2C Data</td></tr>
<tr><td>I2C SCL (MAX30102, DS3231)</td><td>22</td><td>Bidirectional</td><td>I2C Clock</td></tr>
<tr><td>DS18B20 Data</td><td>15</td><td>Bidirectional</td><td>OneWire</td></tr>
<tr><td>LED Green (Status)</td><td>32</td><td>Output</td><td>Digital</td></tr>
<tr><td>LED Red (Error/Pulse)</td><td>33</td><td>Output</td><td>Digital</td></tr>
</tbody>
</table>
<h4>Gateway Pin Configuration</h4>
<table>
<thead>
<tr><th>Function</th><th>GPIO Pin</th><th>Direction</th><th>Protocol</th></tr>
</thead>
<tbody>
<tr><td>LoRa SCK</td><td>18</td><td>Output</td><td>SPI Clock</td></tr>
<tr><td>LoRa MISO</td><td>19</td><td>Input</td><td>SPI Data In</td></tr>
<tr><td>LoRa MOSI</td><td>23</td><td>Output</td><td>SPI Data Out</td></tr>
<tr><td>LoRa CS (SS)</td><td>5</td><td>Output</td><td>SPI Chip Select</td></tr>
<tr><td>LoRa RST</td><td>14</td><td>Output</td><td>Module Reset</td></tr>
<tr><td>LoRa DIO0</td><td>2</td><td>Input</td><td>TX/RX Interrupt</td></tr>
<tr><td>OLED SDA</td><td>21</td><td>Bidirectional</td><td>I2C Data</td></tr>
<tr><td>OLED SCL</td><td>22</td><td>Bidirectional</td><td>I2C Clock</td></tr>
<tr><td>GSM TX</td><td>17</td><td>Output</td><td>UART2 TX</td></tr>
<tr><td>GSM RX</td><td>16</td><td>Input</td><td>UART2 RX</td></tr>
<tr><td>Menu Button</td><td>25</td><td>Input (Pullup)</td><td>Digital</td></tr>
<tr><td>Select Button</td><td>26</td><td>Input (Pullup)</td><td>Digital</td></tr>
<tr><td>Buzzer</td><td>27</td><td>Output</td><td>Digital</td></tr>
</tbody>
</table>
</div>
<!-- ════════════════════════════════════════════════════════════════════
5. SOFTWARE & CODE FLOW
════════════════════════════════════════════════════════════════════ -->
<div class="section" id="software">
<h2 class="section-title">5. Software & Code Flow</h2>
<h3 id="sw-tech">5.1 Technologies and Libraries</h3>
<table>
<thead>
<tr><th>Library</th><th>Version</th><th>Purpose</th></tr>
</thead>
<tbody>
<tr><td>Arduino Framework (ESP32 Core)</td><td>Latest</td><td>Base development framework for ESP32 microcontroller</td></tr>
<tr><td>RadioLib</td><td>v7.6.0+</td><td>LoRa/SX1278 packet radio communication</td></tr>
<tr><td>Adafruit SH110X</td><td>Latest</td><td>SH1106 OLED display driver</td></tr>
<tr><td>Adafruit GFX</td><td>Latest</td><td>Graphics primitives library for OLED rendering</td></tr>
<tr><td>DallasTemperature</td><td>Latest</td><td>DS18B20 high-level temperature sensor interface</td></tr>
<tr><td>OneWire</td><td>Latest</td><td>OneWire protocol implementation for DS18B20</td></tr>
<tr><td>RTClib</td><td>Latest</td><td>DS3231 real-time clock driver</td></tr>
<tr><td>MAX30105 (SparkFun)</td><td>Latest</td><td>MAX30102 heart rate and SpO2 sensor driver</td></tr>
<tr><td>Preferences (Built-in)</td><td>ESP32 Core</td><td>Non-volatile storage (NVS) for persistent configuration</td></tr>
</tbody>
</table>
<h3 id="sw-node">5.2 Node Firmware Logic</h3>
<p>
The sensor node firmware (<code>Node.ino</code>, approximately 461 lines) implements a cooperative multitasking loop that manages sensor acquisition, LoRa transmission, command reception, and LED diagnostics. The key functional components are:
</p>
<h4>Sensor Initialization and Recovery</h4>
<p>
The <code>attemptSensorInit()</code> function initializes the MAX30102 pulse sensor with precisely tuned parameters: LED brightness of 0x1F, sample averaging of 4, dual-wavelength mode (Red + IR), sample rate of 400 Hz, and pulse width of 411 μs for 18-bit ADC resolution. If any I2C sensor (MAX30102 or DS3231) fails to initialize or becomes disconnected during operation, the system automatically retries initialization every 10 seconds while continuing to transmit available data with error flags.
</p>
<h4>Heart Rate Detection Algorithm</h4>
<p>
The <code>processHeartRate()</code> function implements a non-blocking, real-time beat detection algorithm:
</p>
<ol>
<li><strong>Finger Detection:</strong> The infrared (IR) reflectance value is compared against a threshold of 50,000 counts. Values below this threshold indicate no contact with the sensor surface.</li>
<li><strong>Beat Detection:</strong> A derivative-based peak detection identifies cardiac beats from the IR waveform.</li>
<li><strong>Interval Validation:</strong> Only beat intervals between 300 ms (200 BPM cap) and 2000 ms (30 BPM floor) are accepted.</li>
<li><strong>Warm-up Phase:</strong> The first 4 detected beats establish a baseline average before reporting.</li>
<li><strong>Outlier Rejection:</strong> Any beat interval deviating more than ±30% from the rolling average is discarded.</li>
<li><strong>Rolling Average:</strong> A 4-beat FIFO circular buffer computes a smoothed BPM value.</li>
<li><strong>Staleness Detection:</strong> If no beats are detected for 30 seconds, the heart rate reading is cleared to zero.</li>
</ol>
<div class="mermaid-container">
<div class="mermaid">
flowchart TD
A(["processHeartRate"]) --> B["Read MAX30102 IR Sample"]
B --> C{"IR Value<br/>> 50000?"}
C -->|No| D["No Finger Detected<br/>Clear HR"]
C -->|Yes| E{"Beat Peak<br/>Detected?"}
D --> Z(["Return"])
E -->|No| F{"No Beat<br/>> 30 sec?"}
F -->|Yes| G["Staleness Timeout<br/>Clear HR to 0"]
F -->|No| Z
G --> Z
E -->|Yes| H["Calculate Beat Interval"]
H --> I{"Interval<br/>>= 300ms?"}
I -->|No| J["Reject: Too Fast"]
I -->|Yes| K{"Interval<br/><= 2000ms?"}
K -->|No| L["Reject: Too Slow"]
K -->|Yes| M{"Warmup<br/>Done? 4+"}
J --> Z
L --> Z
M -->|No| N["Store in Warmup Buffer"]
N --> O{"Counter<br/>>= 4?"}
O -->|Yes| P["Set Warmup Complete"]
O -->|No| Z
P --> Z
M -->|Yes| Q["Compute avg +/- 30%"]
Q --> R{"Within<br/>Range?"}
R -->|No| S["Reject Outlier"]
R -->|Yes| T["Add to 4-Beat FIFO"]
S --> Z
T --> U["Recalculate BPM"]
U --> V["Update hrBeatAvg"]
V --> W["Flash Red LED 10ms"]
W --> Z
style A fill:#1a3c5e,color:#fff
style D fill:#757575,color:#fff
style G fill:#757575,color:#fff
style J fill:#c62828,color:#fff
style L fill:#c62828,color:#fff
style S fill:#e65100,color:#fff
style V fill:#2e7d32,color:#fff
</div>
<div class="fig-caption">Figure 4: Heart rate detection algorithm flowchart with outlier rejection and rolling average computation</div>
</div>
<h4>Temperature Acquisition</h4>
<p>
The <code>readTemperature()</code> function queries the DS18B20 sensor via the OneWire protocol, performing a single-point sampling. LED outputs are disabled during the read cycle to prevent electrical noise from affecting the measurement. A <code>yield()</code> call is inserted to prevent watchdog timer resets during the conversion delay.
</p>
<h4>Transmission Schedule</h4>
<p>
The node transmits two types of packets on a fixed schedule with TDMA offsets to prevent multi-node collisions:
</p>
<ul>
<li><strong>Heartbeat (HB) Packets:</strong> Transmitted every 2000 ms, containing the full telemetry payload with error flags.</li>
<li><strong>Data (DATA) Packets:</strong> Transmitted every 5000 ms after the warm-up period, containing validated sensor readings only.</li>
</ul>
<p>
Each node's transmission is offset by <code>(COW_ID − 1) × 500 ms</code> from the base interval, providing non-overlapping time slots for up to 4 nodes per cycle.
</p>
<h4>Node Main Loop Flowchart</h4>
<div class="mermaid-container">
<div class="mermaid">
flowchart TD
A(["Node Power On"]) --> B["Initialize I2C, SPI, OneWire"]
B --> C{"Sensors OK?"}
C -->|Yes| D["Configure MAX30102<br/>400Hz, 18-bit ADC"]
C -->|No| E["Set Error Flags<br/>Retry in 10s"]
E --> D
D --> F["Initialize SX1278<br/>433 MHz LoRa"]
F --> G{"LoRa OK?"}
G -->|Yes| H["Enter Main Loop"]
G -->|No| I["Red LED Blink 2x100ms"]
I --> F
H --> J[/"Main Loop Start"/]
J --> K["processHeartRate<br/>Sample MAX30102 IR"]
K --> L{"Beat<br/>Detected?"}
L -->|Yes| M["Validate Interval<br/>300-2000ms"]
L -->|No| N{"HB Timer<br/>2000ms?"}
M --> O{"Within 30%<br/>of Average?"}
O -->|Yes| P["Update 4-Beat<br/>Rolling Buffer"]
O -->|No| Q["Discard Outlier"]
P --> N
Q --> N
N -->|Yes| R["readTemperature<br/>Query DS18B20"]
N -->|No| S{"CMD Packet<br/>on DIO0?"}
R --> T["Assemble HB Packet"]
T --> U["LoRa Transmit<br/>with TDMA Offset"]
U --> V["Green LED Flash"]
V --> S
S -->|Yes| W{"CMD Type?"}
S -->|No| X["LED Status Update"]
W -->|LED_ON| Z1["Red LED On"]
W -->|LED_OFF| Z2["Red LED Off"]
W -->|PING| Z4["Transmit ACK"]
Z1 --> X
Z2 --> X
Z4 --> X
X --> J
style A fill:#1a3c5e,color:#fff
style H fill:#2e7d32,color:#fff
style I fill:#c62828,color:#fff
style E fill:#e65100,color:#fff
style U fill:#1565c0,color:#fff
</div>
<div class="fig-caption">Figure 5: Sensor node main loop flowchart showing data acquisition, transmission, and command handling</div>
</div>
<h3 id="sw-gateway">5.3 Gateway Firmware Logic</h3>
<p>
The gateway firmware (<code>Gateway.ino</code>, approximately 1410 lines) is a substantially more complex application managing radio reception, data processing, alert generation, GSM communication, OLED rendering, and user input. Its operation is governed by multiple cooperating state machines:
</p>
<h4>GSM State Machine</h4>
<p>
The <code>handleGsmState()</code> function implements a fully non-blocking state machine for SIM800L management:
</p>
<p>
Each state issues an AT command and transitions to a wait state that monitors the UART buffer for expected responses, with timeout handling for each step. This ensures that the gateway remains responsive during the 5–15 second SMS transmission process.
</p>
<div class="mermaid-container">
<div class="mermaid">
stateDiagram-v2
[*] --> GSM_BOOT : Power On
GSM_BOOT : Send AT command
GSM_BOOT --> GSM_SET_TEXT : OK received
GSM_SET_TEXT : Send AT+CMGF=1
GSM_SET_TEXT --> GSM_IDLE : OK received
GSM_IDLE : Ready - Monitor pending flag
GSM_IDLE --> GSM_TX_START : SMS pending true
GSM_TX_START : Send AT+CMGS with phone
GSM_TX_START --> GSM_TX_BODY : Prompt received
GSM_TX_BODY : Send SMS content + Ctrl Z
GSM_TX_BODY --> GSM_WAIT_OK : Body sent
GSM_WAIT_OK : Await CMGS confirmation
GSM_WAIT_OK --> GSM_IDLE : Delivery confirmed
GSM_WAIT_OK --> GSM_BOOT : Timeout or Error
GSM_BOOT --> GSM_BOOT : No response retry
GSM_SET_TEXT --> GSM_BOOT : Error restart
</div>
<div class="fig-caption">Figure 6: GSM SMS transmission state machine diagram</div>
</div>
<h4>UI State Machine</h4>
<p>
The user interface operates across seven display states:
</p>
<ul>
<li><strong>S_DASH:</strong> Main dashboard showing real-time vital signs, signal quality, and alert status.</li>
<li><strong>S_MENU:</strong> Navigation menu with five categories (Monitor, Test, Config, Debug, Info).</li>
<li><strong>S_EDIT:</strong> Parameter editing mode with increment/decrement controls.</li>
<li><strong>S_TEST:</strong> Hardware test functions (LoRa ping, LED control, GSM call/SMS).</li>
<li><strong>S_DEBUG:</strong> Diagnostic view showing raw LoRa data, system memory, and CSQ values.</li>
<li><strong>S_INFO:</strong> System information display (firmware version, uptime, packet statistics).</li>
<li><strong>S_MONITOR:</strong> Extended real-time monitoring mode.</li>
</ul>
<div class="mermaid-container">
<div class="mermaid">