Projeto IoT faça você mesmo: Construa um vaso de plantas inteligente de baixo custo

Há algumas semanas, decidi comprar uma suculenta para a minha mesa de escritório, simplesmente pelos benefícios que elas podem trazer para o ambiente. Caso você não saiba, cultivar suculentas ou cactos pode trazer diversos benefícios: elas ajudam a purificar o ar, melhoram a umidade dos ambientes e adicionam oxigênio fresco ao espaço

Depois de alguns dias com a Lana (sim, eu a batizei de Lana 💕) na minha mesa, comecei a sentir que faltava algo. Como uma entusiasta da criação e IoT na Ubidots , decidi criar um " vaso inteligente " para a Lana usando nossas ferramentas. Depois de alguns dias de trabalho árduo e muitos problemas com a impressão, finalmente cheguei a este resultado incrível e estava ansiosa para compartilhar meu processo com vocês 🙆‍♀️💚:

Este projeto foi inspirado em um anterior criado por Paul a Maker 👨‍💻 (Impressão 3D, Eletrônica, Software) que venho acompanhando há meses, e posso dizer que aprendi muitas dicas e truques com ele. Se você está buscando inspiração para seus projetos de eletrônica, siga -o , acredite em mim.

Pessoalmente, gosto muito de buscar inspiração em projetos de outras pessoas. De qualquer forma, sempre dou um jeito de adicionar meu próprio estilo, dar os devidos créditos e, claro, compartilhar o resultado final para que outras pessoas como eu também se inspirem. 🤓 🤓

Esta postagem contém um passo a passo do meu projeto, bem como todos os recursos necessários para replicar o " Plantador Inteligente ".

Requisitos

Passo a passo

  1. Impressão 3D
  2. Fiação
  3. Revestimento
  4. Programação do NodeMCU ESP8266
  5. Dashboard - Controle e monitoramento
  6. Resumo

1. Impressão 3D

Minhas habilidades em modelagem 3D são um tanto limitadas (estou trabalhando nisso para criar mais projetos usando a impressora 3D), mas existe uma comunidade aberta chamada Thingiverse que facilita bastante a nossa vida. É uma comunidade de design próspera para descobrir, criar e compartilhar objetos imprimíveis em 3D. Depois de analisar vários modelos de vasos de plantas, decidi imprimir o seguinte:

Clique aqui para baixar o projeto - item:2857938

Gostei muito deste design porque já era um vaso de plantas IoT Coisas) e a luminária era um acessório bonito e moderno. Basicamente, este modelo era perfeito para o que eu tinha em mente desde o início:

  • Lâmpada para controle remoto.
  • Espaço para colocar componentes eletrônicos e adicionar alguns sensores.

No entanto, eu sabia que o espaço para os componentes eletrônicos não era suficiente para todas as funcionalidades que eu queria incluir. Para resolver isso, imprimi a peça inferior duas vezes:

  • Peça branca : Para posicionar o NodeMCU ESP8266, os sensores e os fios.
  • Peça transparente : Para colocar o anel NeoPixel.

Tendo como resultado a obra-prima abaixo:

NOTA: O anel NeoPixel não é obrigatório para este projeto; ele foi apenas um acessório para deixá-lo mais bonito. Você também pode usar apenas uma peça.

2. Fiação

De acordo com o firmware fornecido neste guia, consulte o diagrama e a tabela abaixo para estabelecer uma conexão adequada entre os componentes utilizados.

3. Revestimento

Com as conexões de fios já feitas corretamente, coloque todos os componentes dentro do vaso conforme mostrado abaixo:

Como podem ver, coloquei o NodeMCU numa placa de prototipagem com 10 pinos de ângulo reto. A ideia era estabelecer a ligação com os sensores e poupar espaço para a eletrónica. Para ser sincero, poderia ter organizado melhor os cabos. No entanto, a ideia era criar uma placa de circuito impresso personalizada para o vaso, e, eventualmente, tudo ficaria embutido. Também fiz furos na peça branca para passar os cabos do anel NeoPixel. Para finalizar, colei o anel NeoPixel com a face para baixo na parte inferior e, em seguida, colei a peça transparente sobre a branca para suavizar a luz. No final, obtive este resultado fantástico:

4. Programação do NodeMCU ESP8266

1. Para poder trabalhar com a ESP8266 na IDE do Arduino, você precisará instalar a plataforma ESP8266 usando o Gerenciador de Placas do Arduino . Se você não estiver familiarizado com a adição de uma placa com a IDE do Arduino, consulte este artigo para obter mais orientações .

2. Com a plataforma ESP8266 instalada, selecione o dispositivo ESP8266 com o qual você está trabalhando. Neste caso, estamos trabalhando com um “ NodeMCU 1.0 ”. Para selecionar sua placa na IDE do Arduino, selecione Ferramentas > Placa > “Módulo ESP8266 Genérico” .

3. Baixe e instale a Ubidots MQTTESP8266 . Para obter uma explicação detalhada de como instalar bibliotecas usando a IDE do Arduino, consulte este guia .

4. Cole o código abaixo no Arduino IDE. Em seguida, atribua seu TOKEN Ubidots exclusivo , SSID (nome da rede Wi-Fi ) e senha da rede disponível.

NOTA: Lembre-se de atribuir os pinos corretos aos componentes utilizados caso use uma conexão diferente da fornecida acima.

Repositório GitHub

/* Vaso Inteligente RGB integrado com Ubidots para Monitoramento e Controle. Este código funciona para: 1) Ler dois sensores: DHT11 e Umidade do Solo. 2) Publicar as leituras dos sensores no Ubidots. 3) Inscrever-se em múltiplas variáveis ​​para controle remoto. Bibliotecas necessárias: - Ubidots ESP8266 MQTT - (https://github.com/ubidots/ubidots-mqtt-esp) -ubidotsNeoPixel - (https://github.com/adafruit/Adafruit_NeoPixel) - DHT - (https://github.com/adafruit/DHT-sensor-library) Criado por: Maria Hernández - Defensora de Desenvolvimento IoT @ Ubidots Revisão: José GarcíaubidotsGerente de Desenvolvimento e Suporte @ Ubidots /**************************************** * Incluir Bibliotecas ****************************************/ #include<Adafruit_NeoPixel.h> #incluir<stdio.h> #incluir<map> #include "DHT.h" #include "UbidotsESPMQTT.h" /**************************************** * Definição de Pinos ****************************************/ #define LIGHTPIN D1 // Pino digital para lâmpada LED. #define DHTPIN D5 // Pino digital para sensor DHT. #define NEOPIXELSPIN D6 // Pino digital para anel NeoPixel. #define MOISTUREPIN A0 // Pino analógico para sensor de umidade. /**************************************** * Definição de Constantes ****************************************/ #define TOKEN "BBFF-xxxxxxxxxx" // Atribua seu TOKEN Ubidots . #define WIFINAME "xxxxxxxxxx" // Atribua seu SSID. #define WIFIPASS "xxxxxxxxxx" // Atribua sua senha de Wi-Fi. #define DEVICE "planter" // Rótulo do dispositivo Ubidots . #define VAR_PUB_1 "temperatura" // Rótulo das variáveis Ubidots para publicação de dados. #define VAR_PUB_2 "umidade" #define VAR_PUB_3 "umidade do solo" #define VAR_PUB_4 "índice de calor" #define VAR_SUB_1 "luz-1" // Rótulo das variáveis Ubidots para inscrição em dados; \ // Essas variáveis ​​precisam ser criadas no Ubidots. #define VAR_SUB_2 "light-2" #define NUMPIXELS 12 // Anel NeoPixel de 12 bits // Descomente o tipo que você estiver usando #define DHTTYPE DHT11 // DHT 11 //#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 //#define DHTTYPE DHT21 // DHT 21 (AM2301) typedef enum { red, green, blue, yellow, white, black } NeoPixelColor; // R, G, B uint8_t myColors[][6] = {{250, 0, 0}, // Vermelho. {0, 255, 0}, // Verde. {0, 0, 255}, // Azul. {255, 255, 0}, // Amarelo. {255, 255, 255}, // Branco. {0, 0, 0}}; // Preto. const uint8_t numberOfVariables = 2; // Número de variáveis ​​para assinatura. char *variableLabels[numberOfVariables] = {VAR_SUB_1, VAR_SUB_2}; // Rótulo das variáveis ​​para assinatura. float value; // Armazena o valor recebido. int lastValue; bool bottomLight; // Flag para controlar as condições da luz inferior. unsigned long initTime; // Armazena o tempo de inicialização. const long SECONDS_TO_RECONNECT = 180000; // Período para reconectar a conexão MQTT. // Functor de comparação para mapear funções. struct cmp_str { bool operator()(char const *a, char const *b) const { return strcmp(a, b) < 0; } }; // Declaração da função de mapeamento. typedef std::function<void()> TipoFunção; typedef std::map<const char *, FunctionType, cmp_str> mapTopicSubscription; /**************************************** * Define Instâncias ****************************************/ Ubidots client(TOKEN); Adafruit_NeoPixel pixels(NUMPIXELS, NEOPIXELSPIN, NEO_GRB + NEO_KHZ800); DHT dht(DHTPIN, DHTTYPE); mapTopicSubscription ubiSubTopic; /**************************************** * Funções Principais ****************************************/ void setup() { initTime = millis(); // Salva o tempo de inicialização Serial.begin(115200); pinMode(LIGHTPIN, OUTPUT); // Declara o modo do pino // Define as funções mapeadas para lidar com o evento de assinatura. ubiSubTopic[VAR_SUB_1] = &subscriptionHandler1; ubiSubTopic[VAR_SUB_2] = &subscriptionHandler2;ubidotsSetBroker("ubidots"); // Define o broker corretamente para a // conta comercial. client.setDebug(true); // Passe um valor booleano verdadeiro ou falso para ativar as mensagens de depuração. client.wifiConnection(WIFINAME, WIFIPASS); // Estabelece a conexão Wi-Fi. client.begin(callback); dht.begin(); // Inicializa o sensor DHT. pixels.begin(); // Inicializa o anel NeoPixel. pixels.clear(); // Desativa todas as cores dos pixels. // Estabelece a assinatura com as variáveis ​​definidas.ubidotsSubscribe(DEVICE, VAR_SUB_1);ubidotsSubscribe(DEVICE, VAR_SUB_2); } void loop() { // Reestabelece a assinatura com as variáveis ​​definidas quando a conexão é perdida ou a cada 3 minutos. if (!client.connected() || abs(millis() - initTime) > SECONDS_TO_RECONNECT) { initTime = millis(); client.reconnect();ubidotsSubscribe(DEVICE, VAR_SUB_1);ubidotsSubscribe(DEVICE, VAR_SUB_2); } client.reconnect(); // Lendo os valores de temperatura, umidade e umidade do solo. float humidity = dht.readHumidity(); float temperature = dht.readTemperature(); int soilMoisture = analogRead(MOISTUREPIN); // Calculando o índice de calor em Celsius (isFahreheit = false). float heatIndexC = dht.computeHeatIndex(temperature, humidity, false); // Verificando se alguma leitura falhou e encerrando antecipadamente (para tentar novamente). if (isnan(humidity) || isnan(temperature)) { Serial.println(F("Falha ao ler do sensor DHT!")); } // Controla as cores do NeoPixel com base nos valores de temperatura. if (bottomLight) { if (inRange(temperature, 0, 16)) colorWipe(blue, 50); if (inRange(temperature, 16, 21)) colorWipe(green, 50); if (inRange(temperature, 21, 26)) colorWipe(yellow, 50); if (inRange(temperature, 26, 40)) colorWipe(red, 50); } // Adiciona variáveis ​​para serem publicadas no Ubidots. client.add(VAR_PUB_1, temperature); client.add(VAR_PUB_2, humidity); client.add(VAR_PUB_3, soilMoisture); client.add(VAR_PUB_4, heatIndexC); // Publica todas as variáveis ​​adicionadas no dispositivo definido.ubidots(DEVICE); client.loop(); delay(1000); } /**************************************** * Funções de Assinatura ****************************************/ // Função a ser executada quando var_sub_1 mudar seu status. void subscriptionHandler1() { if (value == 1) { Serial.println("Lâmpada do vaso ligada."); digitalWrite(LIGHTPIN, HIGH); } else { Serial.println("Lâmpada do vaso desligada."); digitalWrite(LIGHTPIN, LOW); } }; // Função a ser executada quando var_sub_2 mudar seu status. void subscriptionHandler2() { if (value != lastValue) { if (value == 1) { Serial.println("Luz inferior do vaso ligada."); for (int i = 0; i < 3; i++) { colorWipe(red, 50); colorWipe(green, 50); colorWipe(blue, 50); }; colorWipe(white, 200); bottomLight = true; } else { Serial.println("Luz inferior do vaso desligada."); colorWipe(white, 50); colorWipe(black, 200); bottomLight = false; } } lastValue = value; }; /**************************************** * Funções Auxiliares ****************************************/ // Retorna um int com o comprimento de um char int strLen(char *s) { int l = 0; while (*s != '\0') { s++; l++; } return (l); } // Callback para lidar com a assinatura void callback(char *topic, byte *payload, unsigned int length) { char *variableLabel = (char *)malloc(sizeof(char) * 30); getVariableLabelTopic(topic, variableLabel); // Salva o rótulo da variável. value = btof(payload, length); // Salva o valor da variável assinada. executeCases(variableLabel); // Executa o manipulador de função para a // variável assinada. free(variableLabel); // Libera a memória. } // Analisa o tópico recebido para extrair o rótulo da variável. void getVariableLabelTopic(char *topic, char *variableLabel) { sprintf(variableLabel, ""); for (int i = 0; i < numberOfVariables; i++) { char *resultLv = strstr(topic, variableLabels[i]); if (resultLv != NULL) { uint8_t len ​​= strlen(resultLv); char result[100]; uint8_t i = 0; for (i = 0; i < len - 3; i++) { result[i] = resultLv[i]; } result[i] = '\0'; snprintf(variableLabel, strLen(result) + 1, "%s", result); break; } } } // Converte um array de caracteres para um valor float. float btof(byte *payload, unsigned int length) { char *demo_ = (char *)malloc(sizeof(char) * 10); for (int i = 0; i < length; i++) { demo_[i] = payload[i]; } return atof(demo_); } // Executa a respectiva "Função de Assinatura" com base no valor recebido. void executeCases(char *variableLabel) { if (ubiSubTopic.find(variableLabel) != ubiSubTopic.end()) { mapTopicSubscription::iterator i = ubiSubTopic.find(variableLabel); (i->second)(); } } // Preenche os pixels do anel NeoPixel um após o outro com cor. void colorWipe(NeoPixelColor color, int wait) { int r, g, b; r = myColors[color][0]; g = myColors[color][1]; b = myColors[color][2]; for (int i = 0; i < pixels.numPixels(); i++) { pixels.setPixelColor(i, r, g, b); pixels.show(); delay(wait); } } // Verifica se o valor recebido está no intervalo esperado bool inRange(float x, int low, int high) { return ((x - low) > 0 && (high - x) >= 0); }

5. Verifique seu código na IDE do Arduino. Para isso, no canto superior esquerdo da IDE do Arduino, você verá o ícone de " Marca de seleção "; selecione-o para verificar seu código.

6. Carregue o código no seu “NodeMCU 1.0” . Para fazer isso, escolha o ícone de “ seta para a direita” ao lado do ícone de “ marca de seleção ”.

7. Para verificar a conectividade do dispositivo e os dados enviados, abra o monitor serial selecionando o ícone de " lupa " no canto superior direito da IDE do Arduino para visualizar os logs , bem como as respostas do Ubidots .

8. Após alguns segundos de inicialização, o código fornecido criará automaticamente um novo dispositivo em sua Ubidots . Acesse a seção de dispositivos da sua conta Ubidots ; você deverá ver os novos dispositivos criados automaticamente.

Acesse o dispositivo “ Planter ” e veja as variáveis ​​configuradas para transmitir os dados:

9. Em seguida, crie duas novas variáveis ​​brutas para estabelecer a assinatura e controlar as luzes remotamente. Para fazer isso, clique em "Adicionar variável > Variável bruta " e atribua o rótulo da variável definido no código. Para o código de exemplo fornecido, os rótulos das variáveis ​​a serem criadas são "light-1" e "light-2" .

Com as variáveis ​​criadas com sucesso, você deverá obter o seguinte resultado:

5. Dashboard - Controle e monitoramento

Com tudo já integrado, é hora de apresentar os dados dos dispositivos em um Dashboard . Além disso, o dashboard também servirá para controlar o status de ambas as lâmpadas.

1. Para criar seu primeiro dashboard , acesse o Dashboard Na guia (Dados → Dashboards ) , selecione o ícone de mais (+) no canto superior direito e, em seguida, selecione o tipo de widget desejado. Você poderá criar dashboards como o abaixo:

Mais sobre Dashboards Ubidots : Identidade visual do aplicativo: Estilos personalizados para seus dashboards e widgets

Ubidots é muito intuitivo para qualquer usuário administrar seus dados, permitindo que todos o personalizem ao máximo; caso queira saber mais, recomendo consultar os seguintes guias:

2. Ubidots já oferece suporte a eventos integrados, permitindo que você envie eventos, alertas e notificações com base nos dados de seus sensores e atuadores.

Confira os tipos de eventos suportados e aprenda como configurar cada um deles:

  1. Notificações por e-mail
  2. notificações por SMS
  3. Eventos Webhook - saiba mais
  4. notificações do Telegram
  5. Notificações do Slack - saiba mais
  6. Notificações de chamadas de voz - saiba mais
  7. Notificação de retorno ao normal - saiba mais
  8. Notificações de geocercas - saiba mais

6. Resumo

Depois de algumas horas de criação e programação (e muitos cafés), dei vida a este Vaso Inteligente:

Como mencionei no início, fiz isso não só porque queria uma nova decoração para a mesa, mas também porque sentia que faltava algo para a Lana. Queria inventar minha própria maneira de me comunicar com ela através IoT e de dados. Caso você queira outras formas de se comunicar com suas plantas, pode ouvi-las usando o MIDI Sprout . Legal, né? 🤩

Esta é apenas a versão 0 do Smart Planter e há algumas coisas que quero melhorar, como o design, a organização dos componentes eletrônicos com uma placa de circuito impresso personalizada e a integração com outros serviços, como o Google Assistente, a Alexa e o Twitter.

Espero que tenham gostado tanto quanto eu. Caso tenham algum comentário ou dúvida sobre o projeto, fiquem à vontade para entrar em contato! Estou totalmente aberta a feedbacks construtivos para aprimorar esse tipo de projeto e compartilhá-lo com vocês. 😁💚

Mais projetos úteis IoT :