Protocolo de Comunicación

Nota

Actualización: El paquete GroundGpsPacket ahora incluye un campo energy de tipo EnergyData para enviar datos energéticos junto con los datos de suelo y GPS.

struct GroundGpsPacket {
    GroundSensor ground; // Datos de suelo
    GpsSensor gps;       // Datos GPS
    EnergyData energy;   // Datos energéticos (voltaje y corriente)
};

Esto permite que el nodo envíe en un solo mensaje los datos de suelo, GPS y energía al gateway.

Protocol

Descripción

El Protocol define las estructuras de datos y constantes utilizadas en todo el sistema de monitoreo agrícola. Proporciona una interfaz unificada para el intercambio de datos entre componentes y la transmisión por la red mesh LoRa.

Características Principales

  • Estructuras Unificadas: Definiciones consistentes de datos

  • Constantes del Sistema: Valores de configuración centralizados

  • Tipos de Datos Optimizados: Uso eficiente de memoria

  • Validación de Datos: Verificación de integridad

  • Compatibilidad: Soporte para diferentes versiones del protocolo

Estructuras de Datos

AtmosphericSample

Estructura para almacenar muestras atmosféricas.

struct AtmosphericSample {
    int16_t temp;        // Temperatura (x10 para precisión)
    uint16_t moisture;   // Humedad (x10 para precisión)
    uint8_t hour;        // Hora de la muestra
    uint8_t minute;      // Minuto de la muestra
};

GroundSensor

Estructura para datos de sensores de suelo.

struct GroundSensor {
    int16_t temp;        // Temperatura del suelo
    uint16_t moisture;   // Humedad del suelo
    uint16_t n;          // Nitrógeno (mg/kg)
    uint16_t p;          // Fósforo (mg/kg)
    uint16_t k;          // Potasio (mg/kg)
    uint16_t EC;         // Conductividad eléctrica
    uint16_t PH;         // pH (x10 para precisión)
};

GpsSensor

Estructura para datos GPS.

struct GpsSensor {
    float latitude;       // Latitud
    float longitude;      // Longitud
    float altitude;       // Altitud
    uint8_t hour;         // Hora UTC
    uint8_t minute;       // Minuto UTC
    uint8_t flags;        // Flags de validación
};

EnergyData

Estructura para datos energéticos.

struct EnergyData {
    float volt;           // Voltaje del sistema
    float amp;            // Corriente del sistema
};

Constantes del Sistema

Valores de Error

#define SENSOR_ERROR_TEMP -999
#define SENSOR_ERROR_MOISTURE 999
#define SENSOR_ERROR_TIME_COMPONENT 99
#define SENSOR_ERROR_LATITUDE -999.0
#define SENSOR_ERROR_LONGITUDE -999.0
#define SENSOR_ERROR_ALTITUDE -999.0

Configuración de Sensores

#define NUMERO_MUESTRAS_ATMOSFERICAS 10
#define SAMPLEINTERVAL 2000  // 2 segundos

Flags de Validación GPS

#define GPS_LOCATION_VALID 0x01
#define GPS_ALTITUDE_VALID 0x02
#define GPS_TIME_VALID 0x04

Ejemplo de Uso

#include "protocol.h"

// Crear muestra atmosférica
Protocol::AtmosphericSample sample;
sample.temp = 250;        // 25.0°C
sample.moisture = 650;    // 65.0%
sample.hour = 14;
sample.minute = 30;

// Crear datos de suelo
Protocol::GroundSensor ground;
ground.temp = -201;       // -20.1°C
ground.moisture = 750;    // 75.0%
ground.n = 1000;          // 1000 mg/kg
ground.p = 150;           // 150 mg/kg
ground.k = 133;           // 133 mg/kg
ground.EC = 2556;         // 2556 μS/cm
ground.PH = 68;           // 6.8 pH

// Crear datos GPS
Protocol::GpsSensor gps;
gps.latitude = -34.6037;
gps.longitude = -58.3816;
gps.altitude = 25.0;
gps.hour = 14;
gps.minute = 30;
gps.flags = GPS_LOCATION_VALID | GPS_TIME_VALID;

Validación de Datos

Validación de Temperatura: .. code-block:: cpp

bool isValidTemperature(int16_t temp) {
return temp != SENSOR_ERROR_TEMP &&

temp >= -400 && temp <= 800; // -40°C a 80°C

}

Validación de Humedad: .. code-block:: cpp

bool isValidMoisture(uint16_t moisture) {
return moisture != SENSOR_ERROR_MOISTURE &&

moisture <= 1000; // 0% a 100%

}

Validación de GPS: .. code-block:: cpp

bool isValidGpsLocation(const GpsSensor& gps) {
return (gps.flags & GPS_LOCATION_VALID) &&

gps.latitude != SENSOR_ERROR_LATITUDE && gps.longitude != SENSOR_ERROR_LONGITUDE;

}

Serialización de Datos

Conversión a Bytes: .. code-block:: cpp

void serializeAtmosphericSample(const AtmosphericSample& sample,

uint8_t* buffer) {

buffer[0] = (sample.temp >> 8) & 0xFF; buffer[1] = sample.temp & 0xFF; buffer[2] = (sample.moisture >> 8) & 0xFF; buffer[3] = sample.moisture & 0xFF; buffer[4] = sample.hour; buffer[5] = sample.minute;

}

Conversión desde Bytes: .. code-block:: cpp

void deserializeAtmosphericSample(const uint8_t* buffer,

AtmosphericSample& sample) {

sample.temp = (buffer[0] << 8) | buffer[1]; sample.moisture = (buffer[2] << 8) | buffer[3]; sample.hour = buffer[4]; sample.minute = buffer[5];

}

Optimizaciones de Memoria

Tamaños Optimizados: * Temperatura: int16_t (-32768 a 32767, precisión 0.1°C) * Humedad: uint16_t (0 a 65535, precisión 0.1%) * Coordenadas: float (precisión de 7 decimales) * Flags: uint8_t (8 bits para múltiples flags)

Alineación de Datos: .. code-block:: cpp

#pragma pack(push, 1) // Alineación de 1 byte struct OptimizedPacket {

uint8_t header; uint8_t nodeId; AtmosphericSample atmos; GroundSensor ground; GpsSensor gps; EnergyData energy;

}; #pragma pack(pop)

Compatibilidad de Versiones

Versión del Protocolo: .. code-block:: cpp

#define PROTOCOL_VERSION 1 #define PROTOCOL_SUBVERSION 0

Estructura de Header: .. code-block:: cpp

struct ProtocolHeader {

uint8_t version; uint8_t subversion; uint8_t packetType; uint8_t nodeId; uint32_t timestamp;

};

Casos de Uso

Transmisión de Datos: .. code-block:: cpp

// Preparar paquete de datos Protocol::AtmosphericSample samples[10]; // … llenar datos …

// Serializar para transmisión uint8_t buffer[256]; serializeData(samples, buffer, sizeof(samples));

Validación de Datos Recibidos: .. code-block:: cpp

// Deserializar datos recibidos Protocol::GroundSensor groundData; deserializeGroundData(receivedBuffer, groundData);

// Validar datos if (isValidGroundData(groundData)) {

processGroundData(groundData);

}

Debug de Datos: .. code-block:: cpp

void printAtmosphericSample(const AtmosphericSample& sample) {

Serial.print(«Temp: «); Serial.print(sample.temp / 10.0); Serial.print(»°C, Hum: «); Serial.print(sample.moisture / 10.0); Serial.print(«%, Time: «); Serial.print(sample.hour); Serial.print(«:»); Serial.println(sample.minute);

}

Notas de Implementación

  • Endianness: Los datos se transmiten en little-endian

  • Checksum: Validación de integridad en transmisiones

  • Compresión: Datos comprimidos para ahorrar ancho de banda

  • Versionado: Soporte para múltiples versiones del protocolo

Ver también