Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Componentes y materiales

ComponenteCantidad
Seeed Base Shield V21
Seeed Grove - Relé1
Seeed Grove - Sensor de Temperatura1
Arduino UNO1
Helium Starter Kit (LEGACY)1

Aplicaciones y servicios online

Sobre el proyecto

Actualizado para China-US Young Maker Competition 2019

Introducción

La jardinería puede ser un hobby divertido para algunos, pero para muchos es una molestia. En este artículo escribo una guía simple para construir una planta inteligente IoT que envíe datos de sensores a Azure IoT Hub y los almacene en Azure SQL vía Azure Functions, controlando el riego automática y remotamente.

Helium IoT Hub se conecta a Azure IoT Hub sin problemas. Explicaremos todo el proceso. Al ser serverless, el único código necesario es Azure Function y código Arduino.

Paso 1: Reunir componentes

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Paso 2: Configurar Arduino con Helium y sensores

Usaremos Arduino como nuestra app, enviando datos de Helium Atom a Helium Hub. Primero registra tu Atom en Helium Network Dashboard.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Luego registra Element como punto de acceso (versión cellular solo encender).

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Tras activar Element debería verse en Access Point.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Conecta todos los sensores y Helium Atom. Debería verse así (un poco desordenado pero se puede limpiar luego).

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Ejecuta el siguiente código para verificar que el programa funciona.

#include "Arduino.h"
#include "Board.h"
#include "Helium.h"
#include "HeliumUtil.h"
#include <TH02_dev.h>
#include "Arduino.h"
#include "Wire.h"
#include <SeeedGrayOLED.h>
#include <avr/pgmspace.h>
#define CHANNEL_NAME "Azure IoT App"
Helium helium(&atom_serial);
Channel channel(&helium);
int relay = 5;

void setDisplayToOriginalState() {
  SeeedGrayOled.init(SSD1327);
}

void setup() {
  Serial.begin(9600);
  pinMode(relay, OUTPUT);
  delay(150);
  TH02.begin();
  delay(100);
  Serial.println("TH02_dev is available.\n");
  DBG_PRINTLN(F("Starting"));
  helium.begin(HELIUM_BAUD_RATE);
  helium_connect(&helium);
  channel_create(&channel, CHANNEL_NAME);
  Wire.begin();
}

void loop() {
  int moisture = 0;
  for (int i = 0; i < 32; i++) moisture += analogRead(A0);
  int uvlight = 0;
  for (int i = 0; i < 32; i++) uvlight += analogRead(A1);
  float temper = TH02.ReadTemperature();
  float humidity = TH02.ReadHumidity();
  String dataString = "Moisture=" + String(moisture) + "&UVLight=" + String(uvlight) + "&Temperature=" + String(temper) + "&Humidity=" + String(humidity);
  char data[dataString.length()];
  dataString.toCharArray(data, dataString.length());
  channel_send(&channel, CHANNEL_NAME, data, strlen(data));
  Serial.println(data);
  setDisplayToOriginalState();
  SeeedGrayOled.clearDisplay();
  SeeedGrayOled.setNormalDisplay();
  SeeedGrayOled.setVerticalMode();
  SeeedGrayOled.setTextXY(0, 0);
  String moisturestring = "Moisture: " + String(moisture);
  char moibuffer[moisturestring.length()];
  moisturestring.toCharArray(moibuffer, moisturestring.length());
  SeeedGrayOled.putString(moibuffer);
  SeeedGrayOled.setTextXY(2, 0);
  String uvstring = "UVLight: " + String(uvlight);
  char uvbuffer[uvstring.length()];
  uvstring.toCharArray(uvbuffer, uvstring.length());
  SeeedGrayOled.putString(uvbuffer);
  SeeedGrayOled.setTextXY(4, 0);
  String temperaturestring = String(temper) + " C";
  char tempbuffer[temperaturestring.length()];
  temperaturestring.toCharArray(tempbuffer, temperaturestring.length());
  SeeedGrayOled.putString(tempbuffer);
  SeeedGrayOled.setTextXY(6, 0);
  String humidstring = "Humid: " + String(humidity);
  char humidbuffer[temperaturestring.length()];
  humidstring.toCharArray(humidbuffer, humidstring.length());
  SeeedGrayOled.putString(humidbuffer);
  if (moisture < 100) {
    digitalWrite(relay, HIGH);
    delay(5000);
    digitalWrite(relay, LOW);
  }
  delay(60000);
}

La bomba requiere 12V, Arduino solo da 5V máx. Para que funcione, suelda dos cables en la fuente de alimentación (rojo=12V, negro=GND). El relé controla cuándo se bombea agua.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Paso 3: Configurar Helium Hub y Azure IoT Hub

Crea IoT Hub en Azure (nivel estándar o gratis). Ve a Shared Access Policies > RegistryReadWrite > Connection String Primary Key. Crea primer dispositivo para probar.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

En Helium Dashboard crea Helium Connection, pega connection string, lo demás se autollenará.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Los topics MQTT se generan automáticamente en Helium Hub, accesibles por canal.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Para probar envío a Azure:

git clone https://github.com/helium/helium-cli.git
cd helium-cli
make
./helium -p /dev/
./helium -p /dev/serial0 channel create "Azure IoT App"
./helium -p /dev/serial0 channel send 1 "Hello Azure"

Verifica en Helium Dashboard y Azure IoT Hub Overview.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Dispositivo autenticado vía X509, Helium lo gestiona todo.

Paso 4: Crear Azure SQL Database

Crea base de datos SQL (nivel Basic para prototipo). Usa Query Editor para crear tabla:

CREATE TABLE SmartPlant (
  id bigint IDENTITY (1,1) NOT NULL,
  Temperature int NOT NULL,
  Humidity int NOT NULL,
  Moisture int NOT NULL,
  UVLight int NOT NULL,
  DateCreated datetime default CURRENT_TIMESTAMP
)
Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Obtén connection string en Connection Strings.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Paso 5: Crear Azure Function App

Crea Function App en Compute (plan de consumo).

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

En Function > Platform features > Application settings, añade connection string SQL.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Crea Function con trigger Event Hub (IoT Hub). Usa C#. Cambia código para insertar directamente en Azure SQL:

using System.Configuration;
using System.Data.SqlClient;
using System.Threading.Tasks;
public static async Task Run(string myIoTHubMessage, TraceWriter log) {
  var map = myIoTHubMessage.Split('&').Select(x => x.Split('=')).ToDictionary(x => x[0], x => x[1]);
  String Temperature = map["Temperature"];
  String Humidity = map["Humidity"];
  String Moisture = map["Moisture"];
  String UVLight = map["UVLight"];
  var str = ConfigurationManager.ConnectionStrings["sqldb_connection"].ConnectionString;
  using (SqlConnection conn = new SqlConnection(str)) {
    conn.Open();
    var text = "INSERT INTO dbo.SmartPlant (Temperature, Humidity, Moisture, UVLight) VALUES (" + Temperature + ", " + Humidity + ", " + Moisture + ", " + UVLight + ");";
    using (SqlCommand cmd = new SqlCommand(text, conn)) {
      var rows = await cmd.ExecuteNonQueryAsync();
      log.Info($"{rows} rows were updated");
    }
  }
  log.Info($"C# IoT Hub trigger function processed a message: {myIoTHubMessage}");
}

Cuando funcione verás logs de filas insertadas.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Crea HTTP Trigger para recuperar datos (API). Ruta /data, Authorization anonymous, GET only.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Código para devolver último registro:

#r "System.Configuration"
#r "System.Data"
#r "Newtonsoft.Json"
using System;
using System.Net;
using System.Configuration;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.Text;
using Newtonsoft.Json;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) {
  log.Info("C# HTTP trigger function processed a request.");
  var str = ConfigurationManager.ConnectionStrings["sqldb_connection"].ConnectionString;
  using (SqlConnection conn = new SqlConnection(str)) {
    conn.Open();
    var text = "SELECT Top 100 Temperature, Moisture, UVLight, Humidity from dbo.SmartPlant Order by DateCreated DESC";
    SmartPlant ret = new SmartPlant();
    using (SqlCommand cmd = new SqlCommand(text, conn)) {
      SqlDataReader reader = await cmd.ExecuteReaderAsync();
      try {
        while (reader.Read()) {
          ret.Temperature = (int)reader[0];
          ret.Moisture = (int)reader[1];
          ret.UVLight = (int)reader[2];
          ret.Humidity = (int)reader[3];
        }
      } finally { reader.Close(); }
      var json = JsonConvert.SerializeObject(ret, Formatting.Indented);
      return new HttpResponseMessage(HttpStatusCode.OK) {
        Content = new StringContent(json, Encoding.UTF8, "application/json")
      };
    }
  }
}
public class SmartPlant {
  public float Temperature { get; set; }
  public float Moisture { get; set; }
  public float UVLight { get; set; }
  public float Humidity { get; set; }
}

Resultado del último registro.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Paso 6: UI para salida

App Android simple para monitorizar 4 sensores y activar bomba peristáltica. Datos cada 60 segundos.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Caja Arduino cerrada para mejor vista junto a la planta.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Simulación de bombeo.

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Extra: Integración Alexa

Código

Azure Function GET Request

#r "System.Configuration"
#r "System.Data"
#r "Newtonsoft.Json"
using System;
using System.Net;
using System.Configuration;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.Text;
using Newtonsoft.Json;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) {
  log.Info("C# HTTP trigger function processed a request.");
  var str = ConfigurationManager.ConnectionStrings["sqldb_connection"].ConnectionString;
  using (SqlConnection conn = new SqlConnection(str)) {
    conn.Open();
    var text = "SELECT Top 100 Temperature, Moisture, UVLight from dbo.IoTData Order by DateCreated DESC";
    EventData ret = new EventData();
    using (SqlCommand cmd = new SqlCommand(text, conn)) {
      SqlDataReader reader = await cmd.ExecuteReaderAsync();
      try {
        while (reader.Read()) {
          ret.Temperature = (int)reader[0];
          ret.Moisture = (int)reader[1];
          ret.UVLight = (int)reader[1];
        }
      } finally { reader.Close(); }
      var json = JsonConvert.SerializeObject(ret, Formatting.Indented);
      return new HttpResponseMessage(HttpStatusCode.OK) {
        Content = new StringContent(json, Encoding.UTF8, "application/json")
      };
    }
  }
}
public class SmartPlant {
  public float Temperature { get; set; }
  public float Moisture { get; set; }
  public float UVLight { get; set; }
}

Azure Function data insert from IoT Hub

using System.Configuration;
using System.Data.SqlClient;
using System.Threading.Tasks;
public static async Task Run(string myIoTHubMessage, TraceWriter log) {
  var map = myIoTHubMessage.Split('&').Select(x => x.Split('=')).ToDictionary(x => x[0], x => x[1]);
  String Type = map["Type"];
  String Confidence = map["Confidence"];
  log.Info(Type);
  log.Info(Confidence);
  var str = ConfigurationManager.ConnectionStrings["sqldb_connection"].ConnectionString;
  using (SqlConnection conn = new SqlConnection(str)) {
    conn.Open();
    var text = "INSERT INTO dbo.IoTData (Type, Confidence) VALUES ('" + Type + "', " + Confidence + ");";
    using (SqlCommand cmd = new SqlCommand(text, conn)) {
      var rows = await cmd.ExecuteNonQueryAsync();
      log.Info($"{rows} rows were updated");
    }
  }
  log.Info($"C# IoT Hub trigger function processed a message: {myIoTHubMessage}");
}

Azure function shortcut

#r "System.Configuration"
#r "System.Data"
using System;
using System.Configuration;
using System.Data.SqlClient;
using System.Threading.Tasks;
using System.Net;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log) {
  string Temperature = req.GetQueryNameValuePairs()
    .FirstOrDefault(q => string.Compare(q.Key, "Temperature", true) == 0).Value;
  string Moisture = req.GetQueryNameValuePairs()
    .FirstOrDefault(q => string.Compare(q.Key, "Moisture", true) == 0).Value;
  string UVLight = req.GetQueryNameValuePairs()
    .FirstOrDefault(q => string.Compare(q.Key, "UVLight", true) == 0).Value;
  if (Temperature == null || Moisture == null || UVLight == null) {
    return req.CreateResponse(HttpStatusCode.BadRequest, "Please pass a name on the query string or in the request body");
  }
  var str = ConfigurationManager.ConnectionStrings["sqldb_connection"].ConnectionString;
  using (SqlConnection conn = new SqlConnection(str)) {
    conn.Open();
    var text = "INSERT INTO dbo.SmartPlant (Temperature, Moisture, UVLight) VALUES (" + Temperature + ", " + Moisture + ", " + UVLight + ");";
    using (SqlCommand cmd = new SqlCommand(text, conn)) {
      var rows = await cmd.ExecuteNonQueryAsync();
      log.Info($"{rows} rows were updated");
    }
  }
  return req.CreateResponse(HttpStatusCode.OK, "Success");
}

Código Arduino

#include "Arduino.h"
#include "Board.h"
#include "Helium.h"
#include "HeliumUtil.h"
#include <TH02_dev.h>
#include "Arduino.h"
#include "Wire.h"
#include <SeeedGrayOLED.h>
#include <avr/pgmspace.h>
#define CHANNEL_NAME "Azure IoT App"
Helium helium(&atom_serial);
Channel channel(&helium);
int relay = 5;

void setDisplayToOriginalState() {
  SeeedGrayOled.init(SSD1327);
}

void setup() {
  Serial.begin(9600);
  pinMode(relay, OUTPUT);
  delay(150);
  TH02.begin();
  delay(100);
  Serial.println("TH02_dev is available.\n");
  DBG_PRINTLN(F("Starting"));
  helium.begin(HELIUM_BAUD_RATE);
  helium_connect(&helium);
  channel_create(&channel, CHANNEL_NAME);
  Wire.begin();
}

void loop() {
  int moisture = 0;
  for (int i = 0; i < 32; i++) moisture += analogRead(A0);
  int uvlight = 0;
  for (int i = 0; i < 32; i++) uvlight += analogRead(A1);
  float temper = TH02.ReadTemperature();
  float humidity = TH02.ReadHumidity();
  String dataString = "Moisture=" + String(moisture) + "&UVLight=" + String(uvlight) + "&Temperature=" + String(temper) + "&Humidity=" + String(humidity);
  char data[dataString.length()];
  dataString.toCharArray(data, dataString.length());
  channel_send(&channel, CHANNEL_NAME, data, strlen(data));
  Serial.println(data);
  setDisplayToOriginalState();
  SeeedGrayOled.clearDisplay();
  SeeedGrayOled.setNormalDisplay();
  SeeedGrayOled.setVerticalMode();
  SeeedGrayOled.setTextXY(0, 0);
  String moisturestring = "Moisture: " + String(moisture);
  char moibuffer[moisturestring.length()];
  moisturestring.toCharArray(moibuffer, moisturestring.length());
  SeeedGrayOled.putString(moibuffer);
  SeeedGrayOled.setTextXY(2, 0);
  String uvstring = "UVLight: " + String(uvlight);
  char uvbuffer[uvstring.length()];
  uvstring.toCharArray(uvbuffer, uvstring.length());
  SeeedGrayOled.putString(uvbuffer);
  SeeedGrayOled.setTextXY(4, 0);
  String temperaturestring = String(temper) + " C";
  char tempbuffer[temperaturestring.length()];
  temperaturestring.toCharArray(tempbuffer, temperaturestring.length());
  SeeedGrayOled.putString(tempbuffer);
  SeeedGrayOled.setTextXY(6, 0);
  String humidstring = "Humid: " + String(humidity);
  char humidbuffer[temperaturestring.length()];
  humidstring.toCharArray(humidbuffer, humidstring.length());
  SeeedGrayOled.putString(humidbuffer);
  if (moisture < 100) {
    digitalWrite(relay, HIGH);
    delay(5000);
    digitalWrite(relay, LOW);
  }
  delay(60000);
}

Repositorio del proyecto

https://github.com/Nyceane/smart-plant-iot

Esquemático

Arquitectura Helium conecta dispositivo IoT directamente a Azure IoT Hub

Planta Inteligente IoT: Construye un Invernadero Conectado con Arduino y Azure

Proceso de manufactura

  1. Papelera Inteligente: Solución IoT Celular para Gestión Automatizada de Residuos
  2. Barman Inteligente: Construye tu Propia Estación de Cócteles con Raspberry Pi
  3. Revolucionando la agricultura: Cómo IoT impulsa la eficiencia y la sostenibilidad
  4. Datos inteligentes: Navegando la próxima frontera de IoT y Big Data
  5. GE Appliances Inaugura Planta de Refrigeración Inteligente e Industria 4.0 en Decatur, Alabama
  6. Hospitales Inteligentes del Mañana: El Papel Crítico del Software Inteligente
  7. Cómo las smart cities aprovechan IoT, microservicios y dashboards para gestión eficiente de activos
  8. Maximice el ROI de sus inversiones en IoT: Una guía práctica
  9. Construyendo un Almacén Inteligente Optimizado con un Ecosistema IoT Robusto
  10. Asegura tus Dispositivos Inteligentes: Mejores Prácticas para la Seguridad de IoT
  11. Explorando Innovaciones IoT de Vanguardia y Aplicaciones Reales