Proyecto sonda para control de riego Low Power y Económica.

Hola a todos, me gustaría exponer mi proyecto y las dudas que me surgen en su desarrollo.

Llevo unos días leyendo el foro y es un proyecto típico (una sonda para controlar el riego) pero la mía tiene una serie de particularidades. En fin, lo que quiero hacer es una sonda con sensores de humedad, temperatura y caudal de agua, que haga lecturas cada 15 min. por ejemplo, las almacene en una SD y cuando me conecte por BLE envie los datos almacenados en la tarjeta.

En principio es bastante simple, aunque debe cumplir unos requisitos:

1.- Simple y barata: pues la quiero replicar para amigos y familiares.
2.- Gran autonomía: lo ideal sería que con una pequeña batt lipo funcionase 3 o 4 meses.

He visto Xiaomi Mi Plant y me parece un gadget muy chulo, pero no cumple con lo que necesito ya que me gustaría medir la humedad a tres niveles de profundidad y tampoco tiene caudalímetro. Si tuviese esas cosas no me metería en este proyecto, pues soy fan de Xiaomi, me parece una pasada las pulseras cuantificadores que tienen, tengo una y la batería le dura meses, con un simple acelerómetro y un vibrador hace maravillas. Con la pulsera he modificado la app para adaptarla a mis necesidades.

Soy informático de formación, así que en principio no tengo problemas con el código (aunque hace años que toco no C ni C++) pero con la electrónica ando bastante perdido, de ahí la idea de abrir este post, para intentar resolver las dudas que tengo.

Hasta ahora he estado investigando mis opciones y estás son las conclusiones que he sacado:

  • Voy a utilizar placas basadas en Arduino de 3.3V y 8Mhz, pues son las que están orientadas al bajo consumo. Por ejemplo, Adafruit, ESP32 (esta placa me la recomendaron en este foro y tiene muy buena pinta, en su datasheet explican los modos de energía y los patrones que se pueden aplicar para un consumo mínimo) o Pro Mini.

  • Me parece una solución muy elegante la placa de Adafruit o la Esp32, pues al llevar integrado el BLE solo necesito añadirle un datalogger y los sensores, para tenerlo todo.

  • El protocolo de comunicación elegido es el Bluetooth de baja energía BLE, pues es el que mas se adapta a mis requerimientos y cualquier smartphone moderno lo incorpora, por lo tanto cualquiera podría recoger los datos almacenados en el datalogger.

  • Se que añadirle una placa solar y un cargador, haría mi sonda autonoma, pero esa es la solución fácil, en mi intento de abaratar hardware quiero intentar prescindir de estos elementos en mi montaje.

  • Busco conseguir la máxima autonomía combinando una electrónica de bajo consumo, con librerías como LowPower o la específica de Adafruit.

Componentes de mi sonda:

1.- Placa compatible arduino de 3.3v 8Mhz con BLE (por ejemplo ESP32). Si fuese el Arduino Mini le tendría que añadir un modulo HC08 o HC10 BLE.

2.- Datalogger (SD + RTC) para almacenar los datos y el sello de tiempo, por ejemplo Adalogger y para despertar al arduino para que lea los sensores.

3.- Sensores de Humedad, Temperatura y Caudal de agua. Tres sensores de humedad que se situan a diferentes profundidades, un sensor de temperatura y uno de caudal.

4.-Sistema de alimentación basado en una batería Lipo, que no describo pues aquí tengo dudas.

Funcionamiento deseado:

1.- Una vez instalado y funcionando el arduino, leerá los valores de los sensores (varias veces y promediará los resultados leidos) y junto con otra información (temperatura del chip, nivel de batería....y por supuesto fecha y hora) los almacenará en la tarjeta SD.

2.- Se dormirá (a ver que modo sleep me permite y que patrón a aplicar) hasta que pasado el tiempo estipulado, se despierte para volver a repetir la operación de lectura/almacenado de datos.

3.- (Esta era la duda que expuse en mi primer post) Lo ideal sería que cuando reciba una conexión entrante BLE se despierte y envie los datos a través de dicha conexión. Ya he visto que el ESP32 tiene una funcion "stub" creo recordar que me permitiría hacer esto sin ni siquiera despertarse completamente.

4.- Una vez haya recogido los datos crudos, se vuelve a dormir.

Dudas que me surgen:

1.- En primer lugar la alimentación de la sonda. Se que lo mejor es probar cuando esté todo montado y funcionando, pero me gustaría que alguien me diera sugerencias siempre con esa meta de 3 o 4 meses de autonomía en mente. También podría espaciar las lecturas a 30 min o una hora, eso no sería problema. Un problema que me he encontrado con la electrónica de 3.3v es que el caudalimetro trabaja a partir de 4.5v, entonces no sé como alimentarlo. Aqui explica como sacar 5v de la placa Adafruit pero de manera puntual. Se podría poner una batt lipo de 7.4v y una fuente Step Down para alimentar la placa, pero ya estamos añadiendo hardware a la sonda.

2.- Otra cuestión que me preocupa es la lectura del caudalimetro, pues si riego durante una hora sería un gasto enorme de energía monitorizarlo durante tanto tiempo. He pensado que mediante una interrupción (Change) el chip se despierte y almacene el comienzo del riego y el caudal estimado, y se vuelva a despertar cuando el riego termine. Así puedo calcular cuanto se ha regado.

3.- Esto es lo que estoy probando, como despertar al arduino, bien con Interrupción del RTC, una alarma, interrución generada por BLE...sugerencias?

En fin, como veis va todo orientado al bajo consumo y bajo coste. A ver si me podéis brindar vuestra ayuda y aportar ideas.

Muchas gracias de antemano y perdonad el tocho.
Saludos,

Hola alfredomrh , que tal, yo estoy metido en un proyecto con cierta similitud al tuyo, aunque yo no pretendo transmitir datos, no obstante tu solución me parece muy interesante, un poco caro el Adafruit, y muy versatil y asequible el ESP 32, Me surgen algunas dudas en tu planteamiento. Tu idea cual es desconectar el suministro a los sensores cuando no estén en uso?, como pretendes activar el riego, una ¿solenoide? ¿alimentada de otra fuente externa? aquí es donde veo yo el máximo consumo.

Hola elduino, pues a ver si nos podemos aportar algo los dos. Tienes razón el Adafruit tiene buen soporte pero es algo caro y le falta una funcionalidad que me vendría muy bien que es que se pudiese despertar cuando le entra una conexión BLE, ya lo hemos discutido aqui espero poder hacer eso (despuertarlo desde el BLE que tiene integrado el ESP32, que la verdad promete mucho...ya estoy esperando a recibirlo. También creo que con un Mini Pro si lo podría hacer conectado el RX del modulo bluetooth a la interrupcion, pero me gustan más las placas que tienen el modulo bt integrado.

Con respecto a tus dudas, sería interesante desconectar los sensores cuando no se usen, pero no sé como se podría hacer, aunque con la placa en modo sleep, deben consumir muy poco y no creo que haga falta cortarles la corriente.

Mira una prueba que he hecho con el Adafruit es dormirlo con la librería LowPower y me duraba con tres sensores 2 dias una batería lipo de 2000mAh, y después con el mismo código y sensores pero utilizando una librería específica de bajo consumo que tiene Adafruit, el resultado es que la batería duraba más de 5 días.

El ESP32 tiene varios modos sleep y después también he leido que tiene patrones de ahorro de energía que se combinan con esos modos. Ahora mismo no sé como se utilizan, pero creo que el consumo en modo hibernación es casi tan bajo como cortarle el suministro...son microamperios.

Como respuesta a tu última pregunta te digo que no, yo no quiero activar el riego. Solo pretendo detectar que se está regando con un sensor de caudal. Para mi el comportamiento ideal sería que cuando se comience a regar el duino se despierte y registre el caudal y la hora de comienzo. Después cuando se termine de regar haga lo mismo. Espero poder hacerlo mediante una interrupción y así no gastar mucha energía. El único inconveniente "teórico" que veo es que estos sensores de caudal trabajan de 4.5v en adelante y las placas low power a 3.3v.

A ver que te parece...

Alfredomrh, yo en electrónica estoy bastante flojo, y eso siendo optimista, no obstante a falta de respuesta por foreros cualificados en el tema te doy mi opinión.
-Creo, no estoy seguro, que la alimentación de los sensores no se interrumpe al estar en modo sleep, tampoco te interesa dado que no te funcionaria el medidor de caudal.
-Te interesaría interrumpir la alimentación a los sensores de humedad, dado que por un lado es un consumo constante de energía, y por otro supone una oxidación bastante fuerte a la parte metálica enterrada.
-Para interrumpir la alimentación de los sensores de humedad probablemente con un transistor que actives cuando quieras medir te serviría.
-El problema de adaptar las tensiones de los sensores, si nadie cualificado en el tema te dice nada, yo intentaría alimentarlos a 5 voltios con fuente externa y en la entrada del sensor al pin del esp32, colocaría un divisor de tension, para dejarla en el margen de los 3.3 voltios desde los 5 voltios que te llegan.

Te adjunto enlaces por si te son de ayuda.
Tutoial del medidor de caudal
divisor de voltaje

elduino:
Alfredomrh, yo en electrónica estoy bastante flojo, y eso siendo optimista

Jejeje Elduino, pues anda que yo...seguro estoy más pez que tú en electrónica, pero bueno poco a poco.

Lo primero agradecerte tus sugerencias. Tienes razón sería interesante cortar el suministro de los sensores de humedad y temperatura, por las dos razones que esgrimes. Sobre el tema de la corrosión he leido un par de post y no daban la solución que tu planteas, aunque si se puede implementar es sencilla y barata. A ver si algún experto nos lo confirma, de todas formas lo voy a estudiar. He hecho algunas pruebas ya, y la verdad no he detectado corrosión en los sensores, al igual que la batería necesito que aguanten esos 3 o 4 meses, si aguantan "la campaña de riego" me valdría.

Por otro lado la alimentación del caudalímetro la tendré que hacer como dices, por ejemplo con una batería Lipo de 7.4v, una fuente step down para bajar la tensión que alimenta la placa y un divisor de tensión para la tensión de referencia del sensor y que las medidas sean las correctas, que supongo que es la utilidad del divisor de voltaje.

En fin, voy a investigar a ver como podría desconectar los sensores de humedad y temperatura, mientras el arduino duerme...alguna sugerencia más???

He encontrado un post en el que tratan el mismo problema, esta parece ser la conclusión final:

The standard method is to power the sensor through a p-MOSFET or power switch IC, or even
a PNP as high side switch.

También hay imágenes describiendo el circuito. A ver si alguien me podría explicar mejor como se montaría la desconexión de los sensores con el mosfet y si se podría hacer, supongo que si, de todos a la vez. Es decir, con un mosfet cortar la alimentación de los tres sensores de humedad y los de temperatura. Después que el mismo arduino al despertarse volviese a suministrarles corriente para realizar las lecturas.

Gracias.

Hola de nuevo, sigo añadiendo conclusiones y cuando tenga montajes hechos iré añadiendolo (estoy esperando material del chino).

1.- Los sensores que conecte a mi placa, los alimentaré directamente desde la batería, colocando un Mosfet para cortar el suministro de energía justo antes de dormir el arduino. Cuando se despierte, lo primero que hará será volver a proporcionarles tensión para después poder leer los sensores. Con esto debemos conseguir un ahorro importante de energía.

2.- La placa será de 3.3v y la batería de 7.4v (Lipo) por tanto necesitaré una fuente Step Down, para alimentar la placa de forma eficiente.

Si alguien ve algún problema en esto, por favor que me lo comente.

Estudiando el hardware que he comprado de Adafruit, he descubierto un ejemplo que por lo que entiendo permite convertir el pin DFU en un pin de interrupción del chip BLE nRF51822 de nordic.

Esto es lo que dice la documentación

Added AT+DFUIRQ to enable using the DFU Pin for IRQ purposes when there is a supported event on the nRF51822

Este es el Sketch de ejemplo,

#include "Adafruit_BLE.h"
#include "Adafruit_BluefruitLE_SPI.h"
#include "Adafruit_BluefruitLE_UART.h"
#include "Adafruit_BLEGatt.h"

#include "BluefruitConfig.h"

/* This example demonstrates how to use Bluefruit callback API :
   - setConnectCallback(), setDisconnectCallback(), setBleUartRxCallback(),
   setBleGattRxCallback() are used to install callback function for specific
   event.
   - Furthermore, update() must be called inside loop() for callback to
   be executed.

   The sketch will add an custom service with 2 writable characteristics,
   and install callback to execute when there is an update from central device
   - one hold string
   - one hold a 4-byte integer
*/

/*=========================================================================
    APPLICATION SETTINGS

      FACTORYRESET_ENABLE     Perform a factory reset when running this sketch
     
                              Enabling this will put your Bluefruit LE module
                            in a 'known good' state and clear any config
                            data set in previous sketches or projects, so
                              running this at least once is a good idea.
     
                              When deploying your project, however, you will
                            want to disable factory reset by setting this
                            value to 0.  If you are making changes to your
                              Bluefruit LE device via AT commands, and those
                            changes aren't persisting across resets, this
                            is the reason why.  Factory reset will erase
                            the non-volatile memory where config data is
                            stored, setting it back to factory default
                            values.
         
                              Some sketches that require you to bond to a
                            central device (HID mouse, keyboard, etc.)
                            won't work at all with this feature enabled
                            since the factory reset will clear all of the
                            bonding data stored on the chip, meaning the
                            central device won't be able to reconnect.

    MINIMUM_FIRMWARE_VERSION  Minimum firmware version to have some new features
    -----------------------------------------------------------------------*/
#define FACTORYRESET_ENABLE        1
#define MINIMUM_FIRMWARE_VERSION   "0.7.1"
/*=========================================================================*/



// Create the bluefruit object, either software serial...uncomment these lines
/*
  SoftwareSerial bluefruitSS = SoftwareSerial(BLUEFRUIT_SWUART_TXD_PIN, BLUEFRUIT_SWUART_RXD_PIN);

  Adafruit_BluefruitLE_UART ble(bluefruitSS, BLUEFRUIT_UART_MODE_PIN,
                      BLUEFRUIT_UART_CTS_PIN, BLUEFRUIT_UART_RTS_PIN);
*/

/* ...or hardware serial, which does not need the RTS/CTS pins. Uncomment this line */
// Adafruit_BluefruitLE_UART ble(BLUEFRUIT_HWSERIAL_NAME, BLUEFRUIT_UART_MODE_PIN);

/* ...hardware SPI, using SCK/MOSI/MISO hardware SPI pins and then user selected CS/IRQ/RST */
Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);

/* ...software SPI, using SCK/MOSI/MISO user-defined SPI pins and then user selected CS/IRQ/RST */
//Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_SCK, BLUEFRUIT_SPI_MISO,
//                             BLUEFRUIT_SPI_MOSI, BLUEFRUIT_SPI_CS,
//                             BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);

Adafruit_BLEGatt gatt(ble);

int32_t charid_string;
int32_t charid_number;

// Wire DFU pin to interruptable pin
int irq_pin = 1;

// use boolean variable to signal loop() to call ble.update()
// You could call ble.update() is ISR but it will increase ISR lattency
volatile boolean irq_event_available = false;

// A small helper
void error(const __FlashStringHelper*err) {
  Serial.println(err);
  while (1);
}

void connected(void)
{
  Serial.println( F("Connected") );
}

void disconnected(void)
{
  Serial.println( F("Disconnected") );
}

void BleUartRX(char data[], uint16_t len)
{
  Serial.print( F("[BLE UART RX]" ) );
  Serial.write(data, len);
  Serial.println();
}

void BleGattRX(int32_t chars_id, uint8_t data[], uint16_t len)
{
  Serial.print( F("[BLE GATT RX] (" ) );
  Serial.print(chars_id);
  Serial.print(") ");

  if (chars_id == charid_string)
  {
    Serial.write(data, len);
    Serial.println();
  } else if (chars_id == charid_number)
  {
    int32_t val;
    memcpy(&val, data, len);
    Serial.println(val);
  }
}

void DfuIrqHandle(void)
{
  // signal loop() to handle event
  irq_event_available = true;
}

/**************************************************************************/
/*!
    @brief  Sets up the HW an the BLE module (this function is called
            automatically on startup)
*/
/**************************************************************************/
void setup(void)
{
  while (!Serial);  // required for Flora & Micro
  delay(500);

  Serial.begin(115200);
  Serial.println(F("Adafruit Bluefruit Callback with DFU IRQ Example"));
  Serial.println(F("-------------------------------------"));

  pinMode(irq_pin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(irq_pin), DfuIrqHandle, FALLING);

  /* Initialise the module */
  Serial.print(F("Initialising the Bluefruit LE module: "));

  if ( !ble.begin(VERBOSE_MODE) )
  {
    error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?"));
  }
  Serial.println( F("OK!") );

  if ( FACTORYRESET_ENABLE )
  {
    /* Perform a factory reset to make sure everything is in a known state */
    Serial.println(F("Performing a factory reset: "));
    if ( ! ble.factoryReset() ) {
      error(F("Couldn't factory reset"));
    }
  }

  if ( !ble.isVersionAtLeast(MINIMUM_FIRMWARE_VERSION) )
  {
    error( F("Callback with DFU Pin as IRQ requires at least 0.7.1") );
  }

  Serial.println( F("Adding Service 0x1234 with 2 chars 0x2345 & 0x6789") );
  gatt.addService(0x1234);
  charid_string = gatt.addCharacteristic(0x2345, GATT_CHARS_PROPERTIES_WRITE, 1, 6, BLE_DATATYPE_STRING, "string");
  charid_number = gatt.addCharacteristic(0x6789, GATT_CHARS_PROPERTIES_WRITE, 4, 4, BLE_DATATYPE_INTEGER, "number");

  /* Reset the device for the new service setting changes to take effect */
  Serial.print(F("Performing a SW reset (service changes require a reset): "));
  ble.reset();

  /* Disable command echo from Bluefruit */
  ble.echo(false);

  Serial.println("Requesting Bluefruit info:");
  /* Print Bluefruit information */
  ble.info();

  /* Change DFU Pin to IRQ mode */
  Serial.println( F("Change DFU Pin to IRQ Mode") );
  ble.sendCommandCheckOK( F("AT+DFUIRQ=on") );

  /* Set callbacks */
  ble.setConnectCallback(connected);
  ble.setDisconnectCallback(disconnected);
  ble.setBleUartRxCallback(BleUartRX);

  /* Only one BLE GATT function should be set, it is possible to set it
    multiple times for multiple Chars ID  */
  ble.setBleGattRxCallback(charid_string, BleGattRX);
  ble.setBleGattRxCallback(charid_number, BleGattRX);
}



/**************************************************************************/
/*!
    @brief  Constantly poll for new command or response data
*/
/**************************************************************************/
void loop(void)
{
  if (irq_event_available)
  {
    // Registered callbacks for the event will be fired accordingly
    ble.handleDfuIrq();
  }
}

Alguien podría explicarme un poco que hace realmente esto.

Hola a todos otra vez, voy a exponer otra duda que me surge en el desarrollo a ver si alguien puede ayudarme.

He intentado usar interrupciones programadas con varias librerías (TimerOne, TimerThree, FlexiTimer...) y hay algunas que me funcionan bien con mi hardware (32u4) pero ninguna funciona para tiempos de programación algos, por ejemplo de 30 minutos. Todos los timers que he probado funcionan para ordenes de milisegundos.

Al igual que me pasa con las librerías de bajo consumo, solo puedes dormir el chip durante 8 segundos máximo.

Se que el reloj interno del duino se resetea cada cierto tiempo por su capacidad, pero ahora tengo montado un RTC y pienso si se podrían vincular estas funciones al RTC para así alargar los tiempos todo lo que queramos???

Saludos,