Internet de les coses amb ESP32 i ESP8266

Exemples Referència Plaques   Recursos CITCEA
Projectes Programació Perifèrics   Inici

Canviem el color d'un NeoPixel amb MQTT

En aquest exemple controlarem el color d'un NeoPixel des d'una aplicació mòbil fent servir MQTT. En aquest cas, a més del programa del microcontrolador, ens caldrà configurar l'aplicació per poder fer la interacció. El programa del microcontrolador seria el que surt a continuació i que més endavant comentarem. Aquest programa és semblant al de l'exemple del LED però amb alguns canvis.

// Està parcialment basat en programes de Demetrio Pina i Fábio Souza
#include <SPI.h>    // Carreguem la biblioteca SPI
#include <WiFiNINA.h>    // Carreguem la biblioteca WiFiNINA
#include <PubSubClient.h>   // Biblioteca per a MQTT
#include <Adafruit_NeoPixel.h>
const char idXarxa[] = "xarxa-wifi";    // Nom del punt d'accés 
const char contrasenya[] = "contrasenya-wifi";    // Contrasenya de connexió 
const char servidor[] = "broker.mqtt-dashboard.com";    // Contrasenya de connexió 
WiFiClient clientwifi;   // Client Wi-Fi
PubSubClient client(clientwifi);    // Client MQTT
Adafruit_NeoPixel cadena = Adafruit_NeoPixel(1, 1, NEO_GRB + NEO_KHZ800);
byte R, G, B;  // Els tres colors per al NeoPixel
void connecta_xarxa() {
  delay(1000);
  Serial.print("Connectant a la xarxa ");
  Serial.println(idXarxa);
  WiFi.begin(idXarxa, contrasenya);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.print("Connectat!");
  Serial.print("Adreça IP: ");
  Serial.println(WiFi.localIP());
}
// Aquesta funció s'executarà automàticament quan es detecti un canvi
void callback(char* topic, byte* payload, unsigned int length) {
  int valor = 0;
  char estat[25];  // Aquí hi posarem l'estat (RGB) del NeoPixel
                   // Suposem que no arribarem a 25 caràcters
  String etiq((char*)topic);  // Convertim l'etiqueta (topic) a String
  String enviar = "";  // Text que enviarem amb l'estat del NeoPixel
  String rebut = "";  // Aquí hi posarem el valor rebut (payload) convertit a String
  Serial.print("Topic:  ");
  Serial.println(topic);
  for (int i = 0; i < length; i++){
    rebut = rebut + (char)payload[i];  // Passem payload a String
  }
  valor = rebut.toInt();  // I ho convertim en un enter
  Serial.print("Payload:  ");
  Serial.println(valor);
  if (valor < 0){
    valor = 0;
  }
  if (valor > 255){
    valor = 255;
  }
  if (etiq == "oba_neopixel_R"){
    R = valor;  // Si l'etiqueta correspon a vermell, ho guardem a R
  }
  if (etiq == "oba_neopixel_G"){
    G = valor;  // Si l'etiqueta correspon a verd, ho guardem a G
  }
  if (etiq == "oba_neopixel_B"){
    B = valor;  // Si l'etiqueta correspon a blau, ho guardem a B
  }
  cadena.setPixelColor(0, R, G, B);  // Posa el color
  cadena.show(); // Actualitza
  enviar = enviar + "R = " + R + "\n" + "G = " + G + "\n" + "B = " + B;
  enviar.toCharArray(estat, 25);  // Cal convertir enviar a char
  client.publish("oba_estat_neopixel", estat);  // Ho enviem al servidor
}
void connecta_mqtt() {
  while (!client.connected()) {
    Serial.println("Connectant al servidor MQTT");
    if (client.connect("oba_mqtt")) {
      Serial.println("Connectat!");
      client.subscribe("oba_neopixel_R");
      client.subscribe("oba_neopixel_G");
      client.subscribe("oba_neopixel_B");
    } else {
      Serial.println("Ha fallat la connexió!");
      Serial.print("Resposta = ");
      Serial.println(client.state());
      delay(5000);
    }
  }
}
void setup() {    // Inicialització
  Serial.begin(9600);
  cadena.begin();  // Inicialitza els NeoPixels				
  cadena.show();
  connecta_xarxa();
  client.setServer(servidor, 1883);
  client.setCallback(callback);
}
void loop() {    // Programa que es repeteix indefinidament
  if (!client.connected()) {
    connecta_mqtt();
  }
  client.loop();  // Consulta el servidor MQTT
}

Respecte a l'exemple del LED, observem que ara es subscriuen tres etiquetes, una per a cada color, amb les que rebrem el valor (entre 0 i 255) per a vermell, blau o verd. La resta de canvis importants estan a la funció callback.

Atès que rebrem informacions corresponents, indistintament, a qualsevol de les tres etiquetes, caldrà mirar quina etiqueta hem rebut a cada moment. Ara el valor rebut no serà només un caràcter i, per tant, haurem de mirar quants caracters hem rebut (paràmetre length de la funció) i convertir els caràcters primer en un char, després en un String i finalment en un valor enter. Serà convenient comprovar que el valor rebut està entre 0 i 255, el rang que admet cada component de color del NeoPixel. El valor rebut el guardarem en el color corresponent (els altres no canviaran) i actualitzarem el color del NeoPixel. També prepararem un text per enviar a l'aplicació. El prepararem com a String, ja que és més fàcil, però després l'haurem de passar a char.

Un cop tenim fet el programa per al microcontrolador, cal preparar l'aplicació per tal que es puguin comunicar. En aquesta pàgina podem trobar informació més general sobre l'ús de l'aplicació. Per a aquest exemple en concret, cal crear un espai per al projecte picant al botó ⊕ i deixant la majoria de paràmetres per defecte. Només haurem d'editar els següents:

Paràmetre Exemple Comentaris
Name Control NeoPixel Qualsevol nom que ens permeti diferenciar el projecte dels altres
Address broker.mqtt-dashboard.com Adreça del servidor MQTT que fem servir
Port 1883 Port emprat pel servidor, el normal és 1883

Després d'acabar la configuració, picarem sobre la icona Disquet

Dins del projecte posarem quatre elements. Tres entrades de text (text) per ajustar els colors i un text (text) per mostrar-ne els valors en cada moment. Els paràmetres que hem de configurar a cada text són:

Text Paràmetre Exemple Comentaris
Valors Name NeoPixel Qualsevol nom que ens permeti diferenciar aquest element d'altres similars
Topic (sub) oba_estat_neopixel L'etiqueta que hem posat al programa
Main text size Small Mida de la lletra del text que es mostrarà
Main text color Color de la lletra del text que es mostrarà
Vermell Name R
Topic (sub) oba_neopixel_R L'etiqueta que hem posat al programa
Main text size Medium Mida de la lletra del text que es mostrarà
Main text color Color de la lletra del text que es mostrarà
Verd Name G
Topic (sub) oba_neopixel_G L'etiqueta que hem posat al programa
Main text size Medium Mida de la lletra del text que es mostrarà
Main text color Color de la lletra del text que es mostrarà
Blau Name B
Topic (sub) oba_neopixel_B L'etiqueta que hem posat al programa
Main text size Medium Mida de la lletra del text que es mostrarà
Main text color Color de la lletra del text que es mostrarà

Després d'acabar la configuració, picarem sobre la icona Disquet

L'aspecte dels botons de l'aplicació serà el que es mostra a la imatge següent. En picar en un dels requadres, podrem entrar-hi un nou valor.

Botons de l'aplicació

Versió amb selectors de rang

Farem una nova versió en la que, en lloc d'entrar els tres valors en format text, seleccionarem les components de color amb selectors de rang. Atès que ara el selector només ens permetrà l'entrada de valors dins el rang establert, el programa és una mica més senzill ja que no cal comprovar que els valors rebuts siguin correctes. Per mostrar el color que s'envia al NeoPixel farem servir un element color, això farà necessari enviar les dades en el format hexadecimal de sis xifres que es fa servir en html. Per exemple, per enviar el color groc seria #ffff00.

// Està parcialment basat en programes de Demetrio Pina i Fábio Souza
#include <SPI.h>    // Carreguem la biblioteca SPI
#include <WiFiNINA.h>    // Carreguem la biblioteca WiFiNINA
#include <PubSubClient.h>   // Biblioteca per a MQTT
#include <Adafruit_NeoPixel.h>
const char idXarxa[] = "xarxa-wifi";    // Nom del punt d'accés 
const char contrasenya[] = "contrasenya-wifi";    // Contrasenya de connexió 
const char servidor[] = "broker.mqtt-dashboard.com";    // Contrasenya de connexió 
WiFiClient clientwifi;   // Client Wi-Fi
PubSubClient client(clientwifi);    // Client MQTT
Adafruit_NeoPixel cadena = Adafruit_NeoPixel(1, 1, NEO_GRB + NEO_KHZ800);
byte R, G, B;  // Els tres colors per al NeoPixel
void connecta_xarxa() {
  delay(1000);
  Serial.print("Connectant a la xarxa ");
  Serial.println(idXarxa);
  WiFi.begin(idXarxa, contrasenya);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.print("Connectat!");
  Serial.print("Adreça IP: ");
  Serial.println(WiFi.localIP());
}
// Aquesta funció s'executarà automàticament quan es detecti un canvi
void callback(char* topic, byte* payload, unsigned int length) {
  int valor = 0;
  char estat[25];  // Aquí hi posarem l'estat (RGB) del NeoPixel
                   // Suposem que no arribarem a 25 caràcters
  String etiq((char*)topic);  // Convertim l'etiqueta (topic) a String
  String enviar = "#";  // Text que enviarem amb l'estat del NeoPixel
  String rebut = "";  // Aquí hi posarem el valor rebut (payload) convertit a String
  Serial.print("Topic:  ");
  Serial.println(topic);
  for (int i = 0; i < length; i++){
    rebut = rebut + (char)payload[i];  // Passem payload a String
  }
  valor = rebut.toInt();  // I ho convertim en un enter
  Serial.print("Payload:  ");
  Serial.println(valor);
  if (etiq == "oba_neopixel_R"){
    R = valor;  // Si l'etiqueta correspon a vermell, ho guardem a R
  }
  if (etiq == "oba_neopixel_G"){
    G = valor;  // Si l'etiqueta correspon a verd, ho guardem a G
  }
  if (etiq == "oba_neopixel_B"){
    B = valor;  // Si l'etiqueta correspon a blau, ho guardem a B
  }
  cadena.setPixelColor(0, R, G, B);  // Posa el color
  cadena.show(); // Actualitza
  if (R < 16){  // Si és menor de 16
    enviar = enviar + "0";  // Afegim el 0
  }
  enviar = enviar + String(R, HEX);
  if (G < 16){  // Si és menor de 16
    enviar = enviar + "0";  // Afegim el 0
  }
  enviar = enviar + String(G, HEX);
  if (B < 16){  // Si és menor de 16
    enviar = enviar + "0";  // Afegim el 0
  }
  enviar = enviar + String(B, HEX);
  enviar.toCharArray(estat, 25);  // Cal convertir enviar a char
  client.publish("oba_estat_neopixel", estat);  // Ho enviem al servidor
}
void connecta_mqtt() {
  while (!client.connected()) {
    Serial.println("Connectant al servidor MQTT");
    if (client.connect("oba_mqtt")) {
      Serial.println("Connectat!");
      client.subscribe("oba_neopixel_R");
      client.subscribe("oba_neopixel_G");
      client.subscribe("oba_neopixel_B");
    } else {
      Serial.println("Ha fallat la connexió!");
      Serial.print("Resposta = ");
      Serial.println(client.state());
      delay(5000);
    }
  }
}
void setup() {    // Inicialització
  Serial.begin(9600);
  cadena.begin();  // Inicialitza els NeoPixels				
  cadena.show();
  connecta_xarxa();
  client.setServer(servidor, 1883);
  client.setCallback(callback);
}
void loop() {    // Programa que es repeteix indefinidament
  if (!client.connected()) {
    connecta_mqtt();
  }
  client.loop();  // Consulta el servidor MQTT
}

Un cop tenim fet el programa per al microcontrolador, cal preparar l'aplicació per tal que es puguin comunicar. En aquesta pàgina podem trobar informació més general sobre l'ús de l'aplicació. Per a aquest exemple en concret, cal crear un espai per al projecte picant al botó ⊕ i deixant la majoria de paràmetres per defecte. Només haurem d'editar els següents:

Paràmetre Exemple Comentaris
Name Control NeoPixel Qualsevol nom que ens permeti diferenciar el projecte dels altres
Address broker.mqtt-dashboard.com Adreça del servidor MQTT que fem servir
Port 1883 Port emprat pel servidor, el normal és 1883

Després d'acabar la configuració, picarem sobre la icona Disquet

Dins del projecte posarem quatre elements. Tres selectors de rang (range/progress) per ajustar els colors i un color (color) per mostrar el color enviat en cada moment. En el cas dels selectors de rang, els paràmetres que hem de configurar són:

Selector Paràmetre Exemple Comentaris
Vermell Name R
Topic (sub) oba_neopixel_R L'etiqueta que hem posat al programa
Min 0.0 Valor mínim del rang
Max 255.0 Valor mínim del rang
Progress color Color del selector
Verd Name G
Topic (sub) oba_neopixel_G L'etiqueta que hem posat al programa
Min 0.0 Valor mínim del rang
Max 255.0 Valor mínim del rang
Progress color Color del selector
Blau Name B
Topic (sub) oba_neopixel_B L'etiqueta que hem posat al programa
Min 0.0 Valor mínim del rang
Max 255.0 Valor mínim del rang
Progress color Color del selector

Després d'acabar la configuració, picarem sobre la icona Disquet

Els paràmetres que hem de configurar al color són:

Paràmetre Exemple Comentaris
Name NeoPixel Qualsevol nom que ens permeti diferenciar aquest element d'altres similars
Topic (sub) oba_estat_neopixel L'etiqueta que hem posat al programa
Payload format HEX string Format en el que es rebran les dades
Icon Bombeta Icona sobre la que es mostrarà el color

Després d'acabar la configuració, picarem sobre la icona Disquet

L'aspecte dels botons de l'aplicació serà el que es mostra a la imatge següent. En picar en un dels selectors, podrem ajustar-ne el valor desplaçant el disc que fa de punter.

Botons de l'aplicació

Versió amb un selector de color

Farem una tercera versió en la que, en lloc d'entrar els tres valors individualment, seleccionarem un color amb un selector de color. El selector enviarà el color en format hexadecimal i, per tant, caldrà convertir-lo a tres components decimals. Per mostrar el color que s'envia al NeoPixel farem servir un element text. Ara només caldrà subscriure una etiqueta.

// Està parcialment basat en programes de Demetrio Pina i Fábio Souza
#include <SPI.h>    // Carreguem la biblioteca SPI
#include <WiFiNINA.h>    // Carreguem la biblioteca WiFiNINA
#include <PubSubClient.h>   // Biblioteca per a MQTT
#include <Adafruit_NeoPixel.h>
const char idXarxa[] = "xarxa-wifi";    // Nom del punt d'accés 
const char contrasenya[] = "contrasenya-wifi";    // Contrasenya de connexió 
const char servidor[] = "broker.mqtt-dashboard.com";    // Contrasenya de connexió 
WiFiClient clientwifi;   // Client Wi-Fi
PubSubClient client(clientwifi);    // Client MQTT
Adafruit_NeoPixel cadena = Adafruit_NeoPixel(1, 1, NEO_GRB + NEO_KHZ800);
byte R, G, B;  // Els tres colors per al NeoPixel
byte HEXtoDEC(byte car){
  byte res;
  if((car >= 48) && (car <= 57)){  // Si està entre 0 i 9
    res = car -48;  // Restem el codi ASCII de 0
  }
  if((car >= 65) && (car <= 70)){  // Si està entre 10 i 15
    res = car -65 +10;  // Restem el codi ASCII de la lletra A i sumem 10
  }
  if((car >= 97) && (car <= 102)){  // Per si les lletres estan en minúscules
    res = car -97 +10;  // Restem el codi ASCII de la lletra a i sumem 10
  }
  return res;
}
void connecta_xarxa() {
  delay(1000);
  Serial.print("Connectant a la xarxa ");
  Serial.println(idXarxa);
  WiFi.begin(idXarxa, contrasenya);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.print("Connectat!");
  Serial.print("Adreça IP: ");
  Serial.println(WiFi.localIP());
}
// Aquesta funció s'executarà automàticament quan es detecti un canvi
void callback(char* topic, byte* payload, unsigned int length) {
  char estat[25];  // Aquí hi posarem l'estat (RGB) del NeoPixel
                   // Suposem que no arribarem a 25 caràcters
  String etiq((char*)topic);  // Convertim l'etiqueta (topic) a String
  String enviar = "";  // Text que enviarem amb l'estat del NeoPixel
  Serial.print("Topic:  ");
  Serial.println(topic);
  if (length >= 7){
    R = HEXtoDEC(payload[1]) * 16 + HEXtoDEC(payload[2]);
    G = HEXtoDEC(payload[3]) * 16 + HEXtoDEC(payload[4]);
    B = HEXtoDEC(payload[5]) * 16 + HEXtoDEC(payload[6]);
    Serial.print("R:  ");
    Serial.println(R);
    Serial.print("G:  ");
    Serial.println(G);
    Serial.print("B:  ");
    Serial.println(B);
    cadena.setPixelColor(0, R, G, B);  // Posa el color
    cadena.show(); // Actualitza
  }
  enviar = enviar + "R = " + R + "\n" + "G = " + G + "\n" + "B = " + B;
  enviar.toCharArray(estat, 25);  // Cal convertir enviar a char
  client.publish("oba_estat_neopixel", estat);  // Ho enviem al servidor
}
void connecta_mqtt() {
  while (!client.connected()) {
    Serial.println("Connectant al servidor MQTT");
    if (client.connect("oba_mqtt")) {
      Serial.println("Connectat!");
      client.subscribe("oba_neopixel_RGB");
    } else {
      Serial.println("Ha fallat la connexió!");
      Serial.print("Resposta = ");
      Serial.println(client.state());
      delay(5000);
    }
  }
}
void setup() {    // Inicialització
  Serial.begin(9600);
  cadena.begin();  // Inicialitza els NeoPixels				
  cadena.show();
  connecta_xarxa();
  client.setServer(servidor, 1883);
  client.setCallback(callback);
}
void loop() {    // Programa que es repeteix indefinidament
  if (!client.connected()) {
    connecta_mqtt();
  }
  client.loop();  // Consulta el servidor MQTT
}

Un cop tenim fet el programa per al microcontrolador, cal preparar l'aplicació per tal que es puguin comunicar. En aquesta pàgina podem trobar informació més general sobre l'ús de l'aplicació. Per a aquest exemple en concret, cal crear un espai per al projecte picant al botó ⊕ i deixant la majoria de paràmetres per defecte. Només haurem d'editar els següents:

Paràmetre Exemple Comentaris
Name Control NeoPixel Qualsevol nom que ens permeti diferenciar el projecte dels altres
Address broker.mqtt-dashboard.com Adreça del servidor MQTT que fem servir
Port 1883 Port emprat pel servidor, el normal és 1883

Després d'acabar la configuració, picarem sobre la icona Disquet

Dins del projecte posarem dos elements. Un selector de color (color) i un per mostrar el text (text) per mostrar les components del color enviat en cada moment. En el cas del selector de color, els paràmetres que hem de configurar són:

Paràmetre Exemple Comentaris
Name Selector Qualsevol nom que ens permeti diferenciar aquest element d'altres similars
Topic (sub) oba_neopixel_RGB L'etiqueta que hem posat al programa
Payload format HEX string Format en el que es rebran les dades
Icon Bombeta Icona sobre la que es mostrarà el color

Després d'acabar la configuració, picarem sobre la icona Disquet

Els paràmetres que hem de configurar al text són:

Paràmetre Exemple Comentaris
Name NeoPixel Qualsevol nom que ens permeti diferenciar aquest element d'altres similars
Topic (sub) oba_estat_neopixel L'etiqueta que hem posat al programa
Main text size Small Mida de la lletra del text que es mostrarà
Main text color Color de la lletra del text que es mostrarà

Després d'acabar la configuració, picarem sobre la icona Disquet

L'aspecte dels botons de l'aplicació serà el que es mostra a la imatge següent. En picar en el selector de color, podrem triar el que desitgem.

Botons de l'aplicació

 

 

 

 

 

 

 

 

 

 

Llicència de Creative Commons
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.