Monitor de Salud Fluvial: Sistema de Calidad de Agua con Arduino
Componentes y Suministros
| Componente | Cantidad |
|---|---|
| Arduino MKR1000 (MKR FOX 1200) | 1 |
| Sensor de Nivel de Agua | 1 |
| Sensor de pH | 1 |
| LED (genérico, preferible blanco) | 1 |
| Resistencia 220 ohm | 2 |
| Fotorresistencia (LDR) | 1 |
| Cables jumper | 1 set |
Herramientas Necesarias
- Soldador
- Sierra de calar/metales
Aplicaciones y Servicios Online
- Arduino Web Editor
- Sigfox (red IoT de largo alcance)
- Wia (plataforma IoT para visualización y alertas)
Sobre el Proyecto
Resumen
Un río o lago puede ser fuente de diversión y relax. Pero si se contamina, todo se pierde. Muchos dependen del agua de río para su ganado y no pueden permitirse darles agua sucia.
Imagina vivir junto a un río: no querrás despertar con tu casa inundada. O que tu vecino vierta gasolina en el río, enfermando a tus animales.
MyRiver resuelve esto: opera en zonas aisladas gracias a Sigfox, accesible para todos. Mide pH, nivel de contaminación (método innovador) y nivel de agua. Monitoriza en directo en móvil/PC vía Wia. Detecta problemas y avisa inmediatamente.
Funcionamiento
Basado en Arduino MKR FOX, diseñado para uso remoto. Se coloca en río/lago y se monitoriza desde cualquier sitio. Gracias al modo bajo consumo del SAM D, funciona largo tiempo con 2 pilas AA.
Toma lecturas cada 30 min y duerme (mínimo 20 min sueño). El MKR FOX lee:
- pH del río (sensor pH)
- Nivel de agua (sensor nivel)
- Contaminación por sustancias insolubles: LED ilumina fotorresistencia; si la lectura es baja, hay sustancia sólida (aceite, gasolina, mercurio, etc.) bloqueando la luz
Datos se envían a Sigfox → Wia → procesamiento → visualización y notificaciones al usuario.
El buffer (12 bytes máx. por Sigfox) codifica los 3 valores (cada sensor max 1024 = 10 bits). Cada sensor usa 4 bytes (1/3 del buffer). Arduino fusiona valores añadiendo ceros a la izquierda hasta 4 dígitos cada uno.
Ejemplo: fotorresistencia 620 → 0620; nivel agua 24 → 0024. Se fusionan en buffer de 12 bytes y se envía a Sigfox.
Estructura del Código
Read Sensors: Lee pH, nivel agua, fotorresistencia → variablesFormat Buffer: Fusiona 3 valores en buffer 12 bytesParse Data: Envía buffer a Sigfox
Fragmentos Clave del Código
Lectura de Sensores
struct GetValue {
int riverLevel() { // Nivel río
const int val = analogRead(A2);
if(proDebug) { Serial.print(" River Level "); Serial.println(val); }
return val;
}
int riverPh() { // pH río
const int val = (analogRead(A1) / 5 * 3.3);
if(proDebug) { Serial.print(" River Ph "); Serial.println(val); }
return val;
}
int riverPol() { // Contaminación
const int val = analogRead(A3);
if(proDebug) { Serial.print(" River Pollution "); Serial.println(val); }
return val;
}
};
Formateo Buffer
String data(int level, int ph, int pol) {
int values[3] = {level, ph, pol};
String newValues;
for(int i = 0; i < 3; i++) {
if(values[i] < 10) { newValues += "000"; }
else if(values[i] < 100) { newValues += "00"; }
else if(values[i] < 1000) { newValues += "0"; }
newValues += values[i];
}
return newValues;
}
Envío a Sigfox
void parseData(String data) {
SigFox.beginPacket();
SigFox.print(data);
int ret = SigFox.endPacket();
}
El Dispositivo en Acción
Beneficios
- Monitoriza nivel, pH y contaminación desde cualquier lugar y momento
- Alertas inmediatas por contaminación (soluble/insoluble) o inundación
- Fácil uso y montaje
- Funciona en cualquier país con cobertura Sigfox
Construcción del Proyecto
Paso 1: Materiales
- Arduino MKR FOX 1200
- Sensor pH
- Sensor nivel agua
- Fotorresistencia
- LED blanco
- 2 resistencias 220Ω
- Cables jumper
Paso 2: Conexión del Circuito
Los componentes no van en protoboard; si hay dudas, descargar archivo Fritzing y mover cables virtualmente.
Preparar MKR FOX
Conectar caja de baterías y antena (baterías tras conectar sensores). Ver imágenes de secuencia.
Paso 3: Entender el Código
Tres partes principales explicadas arriba: Read Sensors, Format Buffer, Parse Data.
Paso 4: Configurar Integración Wia-Sigfox
Wia es plataforma IoT profesional: visualiza datos con widgets (web/móvil), crea flujos de procesamiento (block code), notifica eventos.
Requisitos: cuenta Sigfox, cuenta Wia, app Wia (iOS/Android) para notificaciones.
Configurar webhook en Sigfox hacia Wia:
- Type:
Data Uplink - Channel:
URL - Custom Payload Configuration: vacío
- URL Pattern:
https://api.wia.io/v1/events - HTTP Method:
POST - Header:
Authorisation: Bearer <token> - Content-Type:
application/json - Body: código del enlace proporcionado
Paso 5: Configurar Flujo (Flow) en Wia
El flujo convierte HEX → String, parsea 3 valores, convierte a enteros, traduce contaminación y nivel a "HIGH/OK" y pH a valor real, notifica si fuera de rango.
Guía paso a paso con capturas (ver imágenes en contenido original). Funciones Wia clave:
processPayload (HEX a String)
if(input.body) {
output.body.name = "value";
output.body.data = toByteArrayStr(input.body.data.sigfoxData);
}
function toByteArrayStr(sigfoxData) {
let result = Buffer(sigfoxData, 'hex');
return result.toString('utf8');
}
riverPollution (fotorresistencia → POLLUTED/OK)
let minVal = 200; let maxVal = 0;
if(input.body.data.sigfoxData) {
let data = input.body.data.sigfoxData;
let processedData = toByteArrayStr(data);
let newData = cutString(processedData);
output.body.name = "waterPollution";
output.body.data = processData(newData);
}
function cutString(data) {
let newVal = data[8]+data[9]+data[10]+data[11];
return parseInt(newVal);
}
function processData(data) {
return (data < minVal) ? "POLLUTED" : "OK";
}
riverPh (valor raw → pH real)
let minVal = 300; let maxVal = 600;
if(input.body.data.sigfoxData) {
let data = input.body.data.sigfoxData;
let processedData = toByteArrayStr(data);
let newData = cutString(processedData); // bytes 4-7
let finalVal = (newData / 73.1428571);
output.body.name = "waterPh";
output.body.data = finalVal.toFixed(2);
}
riverLevel (nivel → HIGH/OK)
let minVal = 0; let maxVal = 200;
if(input.body.data.sigfoxData) {
let data = input.body.data.sigfoxData;
let processedData = toByteArrayStr(data);
let newData = cutString(processedData); // bytes 0-3
output.body.name = "waterLevel";
output.body.data = processData(newData);
}
function processData(data) {
return (data > maxVal) ? "HIGH" : "OK";
}
Alertas Email (plantillas)
- Contaminación: "Dispositivo ${trigger.source.device.id} detectó problema. Agua contaminada por sustancias insolubles. Datos: ${input.body.data}"
- pH inadecuado: "Dispositivo ${trigger.source.device.id} detectó problema. pH no apropiado, agua contaminada. Datos: ${input.body.data}"
- Nivel alto (inundación): "Dispositivo ${trigger.source.device.id} detectó problema. Nivel de agua muy alto, posible inundación. Datos: ${input.body.data}"
Configuración de Variables
Límites pH y nivel predefinidos; límite fotorresistencia debe calibrarse:
void setup() {
pinMode(1, OUTPUT);
Serial.begin(9600);
while(!Serial) {};
digitalWrite(1, HIGH);
}
void loop() {
const int val = analogRead(A3);
Serial.println(val);
delay(5000);
}
Sumergir sonda en agua limpia, anotar valor estable → ese es tu minVal para riverPollution.
Variable proDebug (default false): si true, imprime en Serial Monitor (requiere USB/PC), ideal para depuración.
Librerías
- Sigfox (c) 2016 Arduino LLC - GNU LGPL
- ArduinoLowPower (c) 2016 Arduino LLC - GNU LGPL
Paso Final: Caja y Despliegue
Subir sketch, conectar caja baterías, verificar circuito. Caja ecológica: botella de agua reciclada.
Secuencia construcción caja (ver imágenes).
Despliegue en río: Ir en pleamar (imprescindible para no confundir marea con inundación). Cinta en boca botella para estanqueidad. Fijar a orilla con cinta o tornillos. Sonda: agua en parte inferior sensor nivel, cubriendo totalmente fotorresistencia.
Probado en río contaminado local: todas las alarmas funcionaron correctamente.
Contexto
Mirar por la ventana y ver un río verde y viscoso en vez de limpio... o que inunde tu casa de noche. MyRiver nace para resolver todo en un dispositivo: avisa si el río se contamina (vecino vertiendo aceite) o va a inundar. En granjas: avisa antes de dar agua a animales y da tiempo a meterlos a salvo.
Solo pH no basta: sustancias insolubles (mercurio, metales) no alteran pH. Método único: fotorresistencia mide luz LED atravesando agua; cualquier impureza reduce luz detectada.
Proceso de manufactura
- Monitor de temperatura casero con Raspberry Pi, MCP9808, InfluxDB y Grafana
- Sensor de Emociones y EEG: Hardware de Bajo Coste para Detección de Emociones en Tiempo Real
- Dispositivo de Medición de Presión y Flujo de Aire de Precisión con Sensor Analógico
- Proyecto Sensor DHT11 Temperatura y Humedad con Indicadores LED y Altavoz Piezo
- UnifiedWater v1 – Kit completo de sensor de calidad de agua con Arduino
- Reloj 3D RGB Arduclock – Bluetooth, LED NeoPixel y RTC
- Sensor de obstáculos IR casero con Arduino – Tutorial fácil con LED IR y fotodiodo
- Juego interactivo con joystick analógico y LEDs en Arduino
- Find Me: Localizador Inteligente de Objetos con Arduino y Bluetooth
- Pequeño Rover con Arduino: Construye tu Robot Autónomo Evita Obstáculos
- Entendiendo el sensor de oxígeno (O2): función, ubicación y señales de fallo