-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode
More file actions
234 lines (197 loc) · 6.07 KB
/
code
File metadata and controls
234 lines (197 loc) · 6.07 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
#include <Arduino.h>
#include <LiquidCrystal.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <ArduinoBLE.h>
// ==================== PIN DEFINITIONS ====================
#define LCD_RS 17
#define LCD_EN 16
#define LCD_D4 4
#define LCD_D5 5
#define LCD_D6 18
#define LCD_D7 19
#define LED_RED 27
#define LED_GREEN 26
#define LED_BLUE 25
#define TEMP_SENSOR_PIN 2 // DS18B20 from pH sensor
#define TDS_SENSOR_PIN A3 // TDS
#define PH_SENSOR_PIN A6 // pH
#define TURBIDITY_PIN A2 // Turbidity
#define DO_I2C_ADDR 0x61 // Dissolved Oxygen I2C
// ==================== SENSOR CALIBRATIONS ====================
#define TURBIDITY_CLEAR_WATER 1500 // Adjust this based on your sensor in clear water
#define PH_CALIBRATION_OFFSET 0.0 // Adjust during calibration
// ==================== BLE SETUP ====================
BLEService waterService("19B10000-E8F2-537E-4F6C-D104768A1214");
BLEStringCharacteristic sensorChar("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify, 100);
bool btConnected = false;
const char* btDeviceName = "WaterQualityMonitor";
// ==================== LCD INIT ====================
LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
// ==================== RGB LED ====================
namespace RGB_LED {
void setColor(int r, int g, int b) {
analogWrite(LED_RED, 255 - r);
analogWrite(LED_GREEN, 255 - g);
analogWrite(LED_BLUE, 255 - b);
}
void init() {
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
setColor(0, 0, 0);
}
}
// ==================== SENSOR NAMESPACES ====================
// -------------------- TDS SENSOR ---------------------------
namespace TDS_Sensor {
float tdsValue = 0;
float temperature = 25.0;
void updateTemperature(float newTemp) {
if (newTemp != DEVICE_DISCONNECTED_C) {
temperature = newTemp;
}
}
void loop() {
static unsigned long lastSampleTime = 0;
if (millis() - lastSampleTime > 20) {
int rawReading = analogRead(TDS_SENSOR_PIN);
float voltage = rawReading * 3.3 / 4096.0;
float compVoltage = voltage / (1.0 + 0.02 * (temperature - 25.0));
tdsValue = (750.0 * compVoltage);
lastSampleTime = millis();
}
}
}
// -------------------- PH & TEMPERATURE SENSOR --------------------
namespace PH_Sensor {
float pHValue = 7.0;
float temperature = 25.0;
OneWire oneWire(TEMP_SENSOR_PIN);
DallasTemperature tempSensor(&oneWire);
void init() {
tempSensor.begin();
tempSensor.setResolution(12);
tempSensor.setWaitForConversion(false);
}
void loop() {
static unsigned long lastTempRequest = 0;
static bool tempRequested = false;
// Non-blocking temperature reading
if (!tempRequested) {
tempSensor.requestTemperatures();
lastTempRequest = millis();
tempRequested = true;
}
else if (millis() - lastTempRequest > 750) { // DS18B20 conversion time
float rawTemp = tempSensor.getTempCByIndex(0);
if (rawTemp != DEVICE_DISCONNECTED_C) {
temperature = rawTemp;
TDS_Sensor::updateTemperature(temperature);
} else {
Serial.println("Temp sensor error!");
}
tempRequested = false;
}
// pH reading
int buffer[10];
for (int i = 0; i < 10; i++) {
buffer[i] = analogRead(PH_SENSOR_PIN);
delay(5);
}
// Median filter
for (int i = 0; i < 9; i++) {
for (int j = i+1; j < 10; j++) {
if (buffer[i] > buffer[j]) {
int temp = buffer[i];
buffer[i] = buffer[j];
buffer[j] = temp;
}
}
}
float volt = (buffer[4] + buffer[5]) / 2 * 3.3 / 4096.0;
pHValue = (-5.70 * volt) + 21.34 + PH_CALIBRATION_OFFSET;
}
}
// -------------------- TURBIDITY SENSOR --------------------
namespace Turbidity_Sensor {
int turbidityValue = 0;
float ntuValue = 0;
void loop() {
int raw = analogRead(TURBIDITY_PIN);
// Apply calibration
turbidityValue = raw;
ntuValue = map(raw, 0, 3000, 3000, 0); // Invert and scale (adjust 3000 to your sensor's max)
ntuValue = constrain(ntuValue, 0, 3000);
}
}
// -------------------- DISSOLVED OXYGEN SENSOR --------------------
namespace DO_Sensor {
float doValue = 0.0;
void loop() {
Wire.requestFrom(DO_I2C_ADDR, 20);
if (Wire.available()) {
char response[20];
byte len = Wire.readBytesUntil(0, response, 19);
response[len] = '\0';
doValue = atof(response);
}
}
}
// ==================== DISPLAY MANAGER ====================
namespace Display {
void update() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("pH:");
lcd.print(PH_Sensor::pHValue, 1);
lcd.print(" TDS:");
lcd.print(TDS_Sensor::tdsValue, 0);
lcd.setCursor(0, 1);
lcd.print("T:");
lcd.print(PH_Sensor::temperature, 1);
lcd.print("C DO:");
lcd.print(DO_Sensor::doValue, 1);
}
}
// ==================== MAIN PROGRAM ====================
void setup() {
Serial.begin(115200);
while (!Serial);
Serial.println("System Initializing...");
pinMode(LED_BUILTIN, OUTPUT);
if (!BLE.begin()) {
Serial.println("BLE Init Failed!");
while(1);
}
BLE.setLocalName(btDeviceName);
BLE.setAdvertisedService(waterService);
waterService.addCharacteristic(sensorChar);
BLE.addService(waterService);
BLE.advertise();
lcd.begin(16, 2);
lcd.print("Initializing...");
RGB_LED::init();
Wire.begin();
PH_Sensor::init();
Serial.println("System Ready");
}
void loop() {
BLE.poll();
PH_Sensor::loop();
TDS_Sensor::loop();
Turbidity_Sensor::loop();
DO_Sensor::loop();
Display::update();
// Serial output
Serial.print("pH: "); Serial.print(PH_Sensor::pHValue, 2);
Serial.print(" | TDS: "); Serial.print(TDS_Sensor::tdsValue, 0);
Serial.print("ppm | Temp: "); Serial.print(PH_Sensor::temperature, 1);
Serial.print("°C | DO: "); Serial.print(DO_Sensor::doValue, 1);
Serial.print("mg/L | Turb: "); Serial.print(Turbidity_Sensor::turbidityValue);
Serial.print(" (");
Serial.print(Turbidity_Sensor::ntuValue);
Serial.println(" NTU)");
delay(2000);
}