NodeMCU e Alexa

Buongiorno a tutti, è da un po' che mi stò documentando per realizzare un progetto in apparenza semplice ma non riesco a venirne a capo.
Vorrei interfacciare Alexa con nodeMCU, su questo ci sono molti esempi, però ho trovato solo per dare un comando da Alexa ed eseguire un comando (accendere luce...) su nodeMCU senza un ritorno. Io sarei interessato a far si che chiedendo la temperatura (nel mio caso di una caldaia a legna) alexa mi dicesse la temperatura rilevata dal sensore ds18b20 collegato al nodeMCU.
In che modo posso trasmettere questo dato ad Alexa?
Ho provato con sirinc ma mi sono perso e non sono riuscito, qualcuno saprebbe darmi una mano?

Prova a cercare con Google "alexa esp temperature" ... troverai vari risultati che fanno quanto chiedi.

Guglielmo

Grazie gpb01 per la risposta. Avevo già provato a cercare come mi hai consigliato, però non sono riuscito nella parte di trasmissione della temperatura ad Alexa. Nel senso che probabilmente sbaglio qualcosa nel passaggio da nodemcu e Alexa (skill e cluod vari...)
Riproverò ancora con più calma e vi terrò aggiornati...

Come promesso ho fatto progressi e vi aggiorno in merito...
Sono riuscito a far dire ad Alexa la temperatura rilevata dal mio sensore collegato al nodeMCU. E' stato abbastanza laborioso, ma alla fine sono riuscito appoggiandomi a thingspeak per salvare i dati e tramite voiceflow per creare una skill di Alexa in modo da prelevare l'ultimo dato memorizzato.
Adesso però vorrei andare oltre... mai fermarsi!!!
Vorrei potere prelevare i dati salvati in thingspeak tramite un altro nodeMCU e visualizzare la temperatura su un display. Ho provato a cercare in rete ma non ho trovato nulla... ci sono moltissime guide su come mandare i dati al sito ma non trovo come invertire il proceso...
Avete qualche idea?

Si, leggere la documentazione di thingspeak

Guarda gli esempi.

Pubblica anche come hai fatto. A me sembra una cosa da Ufficio Complicazione Affari Semplici ma se Amazon ha deciso di fare così un motivo ci sarà.

grazie per la risposta zoomx, avevo già guardato la documentazione di thingspeak, mi è servita per generare l'url da inserire in voiceflow... appena ho un attimo posto la procedura che ho usato, magari c'è un metodo più semplice ma per ora non ci sono arrivato...
Il mio problema è che non so come utilizzare i dati all'interno dello sketch, non ho queste competenze, sono all'inizio e fatico molto perchè sono cose nuove..

Prova ad inserire l'url in un browser così vedi cosa ti restituisce.
Il CVS è un file di testo con i valori separati da una virgola, se non ricordo male.
Il JSON è pure di testo ma formattato diversamente, potrebbe essere trattato con la relativa libreria.

Tu vuoi prendere un intervallo e fare il grafico? Oppure mostrare solo alcuni valori?

Ho trovato il video e c'è il codice su GitHub. Usa il JSON

Willy76:
Come promesso ho fatto progressi e vi aggiorno in merito...
Sono riuscito a far dire ad Alexa la temperatura rilevata dal mio sensore collegato al nodeMCU. E' stato abbastanza laborioso, ma alla fine sono riuscito appoggiandomi a thingspeak per salvare i dati e tramite voiceflow per creare una skill di Alexa in modo da prelevare l'ultimo dato memorizzato.

Mi pare interessante. Sono ai primi contatti con questo meccanismo Alexa/server. Io ho seguito indicazioni di Brunello qui: LINK
In quel thread non si parla di risposta a voce. Non capisco però se non c'è strada più semplice rispetto a quella che hai fatto tu appoggiandosi ad ulteriori 2 oggetti/siti/server.
Su sito Amazon x sviluppo Alexia (in inglese) si parla di StateReport che può essere settato come interrogabile da Alexia: LINK

Grazie zoomx, io vorrei visualizzare su un display l'ultimo dato memorizzato. Ho visto il video che mi hai gentilmente segnalato. Ho provato a caricare il codice che utilizza nell'esempio cpsì com'è in modo da capire come funziona per poi adattarlo alle mie esigenze.
Il problema è che dopo averlo caricato, aprendo il monitor seriale mi appare questo...
wdt reset
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
vffffffff
~ld
⸮bl r⸮o$ph
Adesso devo capire il motivo... perchè caricando altri codici la scheda funziona normalmente...

nid69ita:
Mi pare interessante. Sono ai primi contatti con questo meccanismo Alexa/server. Io ho seguito indicazioni di Brunello qui: LINK
In quel thread non si parla di risposta a voce. Non capisco però se non c'è strada più semplice rispetto a quella che hai fatto tu appoggiandosi ad ulteriori 2 oggetti/siti/server.
Su sito Amazon x sviluppo Alexia (in inglese) si parla di StateReport che può essere settato come interrogabile da Alexia: LINK

Mi spiace non saprei se ci sono strade meno complicate... io per ora non ne ho trovate. Così sono riuscito a fare quello che volevo, cioè leggere i dati di temperatura, caricarli su thingspeak e interrogando Alexa mi risponde con l'ultimo dato di temperatura memorizzato...

NON è per NodeMCU (e mi pare ovvio), ma Arduino ha fatto una libreria apposta per la connessione con Alexa ...
... ne hanno parlato in QUESTO articolo nel blog.

Al momento la libreria funziona su MKR 1000, MKR WiFi 1010, MKR GSM 1400 e Nano 33 IoT ... magari, con un piccolo costo in più dell'hardware, si risparmia un mucchio di tempo nello sviluppo ... ::slight_smile:

Guglielmo

Vedo che lo sketch risale al 2017, nel frattempo ci sono stati aggiornamenti nel core.

Il problema che ti appare è perché lo sketch perde troppo tempo in qualche punto ed entra in funzione il watchdog.
Mi sa che da qualche parte ci vuole uno yield(), il mio sospetto cade sui due cicli while.
Se ho tempo sperimento anche io.

Grazie zoomx, avevo capito che il problema potesse essere quello (guardando in rete..) però tramite le mie conoscenze di programmazione non saprei dove intervenire in questo codice...
Ti sarei molto grato se mi dessi una mano a capire cosa non và, intanto cerco pure io, perchè la funzione yield() non la conosco... ne ho da studiare...

La funzione yeld() non fa altro che permettere ai task del WiFi di poter girare ed evitare che scatti il watchdog e non influisce sul comportamento dello sketch a meno che in quel momento serva tutta l'attenzione della MCU.

Ma il reset ti appare subito, ancora prima di connettersi al WiFi?

Grazie zoomx, purtroppo non sono ancora riuscito a guardare la funzione yield(), sono incasinato con il lavoro...

Il reset parte subito senza mostrare nulla sul monitor seriale, il codice che ho caricato è questo...

#include <WiFi.h>
#include <ArduinoJson.h>
WiFiServer server(80); 

char   host[] = "api.thingspeak.com"; // ThingSpeak address
String APIkey = "320098";             // Thingspeak Read Key, works only if a PUBLIC viewable channel
const int httpPort = 80;

const char *ssid     = "your_SSID"; 
const char *password = "your_PASSWORD"; 
WiFiClient client;
const unsigned long HTTP_TIMEOUT = 10000;  // max respone time from server

void setup(){
Serial.begin(115200);
WiFi.begin(ssid,password);

}

void loop(){
RetrieveTSChannelData();
delay(60000); //Wait before we request again
}

void RetrieveTSChannelData() {  // Receive data from Thingspeak
static char responseBuffer[3*1024]; // Buffer for received data
client = server.available(); 
if (!client.connect(host, httpPort)) { 
  Serial.println("connection failed"); 
  return; 
} 
String url = "/channels/" + APIkey; // Start building API request string
url += "/fields/1.json?results=5";  // 5 is the results request number, so 5 are returned, 1 woudl return the last result received
client.print(String("GET ") + url + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n");
while (!skipResponseHeaders());                      // Wait until there is some data and skip headers
while (client.available()) {                         // Now receive the data
  String line = client.readStringUntil('\n');
  if ( line.indexOf('{',0) >= 0 ) {                  // Ignore data that is not likely to be JSON formatted, so must contain a '{'
    Serial.println(line);                            // Show the text received
    line.toCharArray(responseBuffer, line.length()); // Convert to char array for the JSON decoder
    decodeJSON(responseBuffer);                      // Decode the JSON text
  }
}
client.stop();
}

bool skipResponseHeaders() { 
char endOfHeaders[] = "\r\n\r\n"; // HTTP headers end with an empty line 
client.setTimeout(HTTP_TIMEOUT); 
bool ok = client.find(endOfHeaders); 
if (!ok) { Serial.println("No response or invalid response!"); } 
return ok; 
} 

bool decodeJSON(char *json) {
StaticJsonBuffer <3*1024> jsonBuffer;
char *jsonstart = strchr(json, '{'); // Skip characters until first '{' found and ignore length, if present
if (jsonstart == NULL) {
  Serial.println("JSON data missing");
  return false;
}
json = jsonstart;
JsonObject& root = jsonBuffer.parseObject(json); // Parse JSON
if (!root.success()) {
  Serial.println(F("jsonBuffer.parseObject() failed"));
  return false;
}
JsonObject& root_data = root["channel"]; // Begins and ends within first set of { }
String id   = root_data["id"];
String name = root_data["name"];
String field1_name = root_data["field1"]; // Extracts field name in this example field1 is called 'Pressure'
String field2_name = root_data["field2"]; // Extracts field name in this example field2 is called 'Temperature'
String field3_name = root_data["field3"]; // Extracts field name in this example field3 is called 'Humidity'
String datetime    = root_data["updated_at"];
Serial.println("\n\n Channel id: "+id+" Name: "+ name);
Serial.println(" Readings last updated at: "+datetime);

for (int result = 0; result < 5; result++){
  JsonObject& channel = root["feeds"][result]; // Now we can read 'feeds' values and so-on
  String entry_id     = channel["entry_id"];
  String field1value  = channel["field1"];
  String field2value  = channel["field2"];
  String field3value  = channel["field3"];
  Serial.print(" Field1 entry number ["+entry_id+"] had a value of: ");Serial.println(field1value);
  Serial.print(" Field2 entry number ["+entry_id+"] had a value of: ");Serial.println(field2value);
  Serial.print(" Field3 entry number ["+entry_id+"] had a value of: ");Serial.println(field3value);
}
}
//Thing speak response to GET request(headers removed) and /result=1:
/*
 * 
  {"channel":{"id":320098,"name":"Test Channel","latitude":"0.0","longitude":"0.0","field1":"Pressure","field2":"Temperature","field3":"Humidity",
   "created_at":"2017-08-21T13:22:12Z","updated_at":"2017-08-26T22:18:16Z","last_entry_id":85},"feeds":[{"created_at":"2017-08-26T22:18:16Z","entry_id":85,"field1":"40"}]}
 */

Dove dovrei mettere la funzione yield()?

>Willy76: ti ricordo che in conformità al regolamento, punto 7, devi editare il tuo post qui sopra (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More -> Modify che si trova in basso a destra del tuo post) e racchiudere il codice all'interno dei tag CODE (... sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).

In pratica, tutto il tuo codice dovrà trovarsi racchiuso tra due tag: [code] _il _tuo_ codice_ [/code] così da non venire interpretato e non dare adito alla formazione di caratteri indesiderati o cattiva formattazione del testo. Grazie.

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non avrai sistemato il codice come richiesto, nessuno ti potrà rispondere, quindi ti consiglio di farlo al più presto. :wink:

Chiedo scusa Guglielmo, ero convinto di avere inserito i tag. Ho corretto... Grazie per la pazienza...

Willy76:
Chiedo scusa Guglielmo, ero convinto di avere inserito i tag. Ho corretto... Grazie per la pazienza...

Nessun problema, ma rileggeteli sempre i post ... che vi accorgete di molte sviste che capitano ... ::slight_smile:

Per dire ... ho un altro thread dove sono due volte che l'utente è convito di aver allegato delle immagini ed invece non ha allegato nulla ... pensi se ne sia accorto? :smiley:

Guglielmo

Ho trovato un'altro modo molto più semplice per leggere i dati da Thingspeak.
Utilizzando la libreria ThingSpeak.h
In questo modo ho ovviato al problema del reset dovuto al watchdog del mio nodeMCU ed in più il codice risulta molto semplificato rispetto a quello postato precedentemente...
Ho provato anche a prelevare i dati da due canali differenti di thingspeak e funziona, adesso non mi resta che aggiungere un display per la visualizzazione.

Sono uno stupido.
All'inizio di thingspeak avevo provato ad inserire dai con uno sketch trovando un sacco di problemi che risolsi usando la libreria. Non ho pensato che la libreria funzionasse anche per prendere dati.
Karma+

zoomx:
Sono uno stupido.
All'inizio di thingspeak avevo provato ad inserire dai con uno sketch trovando un sacco di problemi che risolsi usando la libreria. Non ho pensato che la libreria funzionasse anche per prendere dati.
Karma+

Ma figurati può capitare...

Adesso il mio progetto è quasi completo, ho realizzato anche la visualizzazione su display dei valori di temperatura presi da due canali di thingspeak.
Ho solo un problema dovuto alla visualizzazione, utilizzo un display da 2,4" con collegamento spi e un nodeMCU.
Ho creato dei bordi e delle righe per separare i valori ma ogni tanto all'interno di queste righe mancano dei pixel o alcuni pezzi non vengono visualizzati. Ho collegato il display ai pin HSCLK, HMOSI, HCL ma il problema di visualizzazione permane in maniera casuale ad ogni refresh
Il codice che utilizzo è il seguente...

#include "ThingSpeak.h"
#include <ESP8266WiFi.h>
#include <SPI.h>
#include <TFT_22_ILI9225.h>
#include <../fonts/FreeMonoBold24pt7b.h>
#include <../fonts/FreeMonoBold9pt7b.h>
#include <../fonts/FreeMonoBold12pt7b.h>
#include <../fonts/FreeSans24pt7b.h>
#include <../fonts/FreeSerifBoldItalic12pt7b.h>

#define TFT_RST D4
#define TFT_RS  D2
#define TFT_CS  D8  // SS
#define TFT_SDI D7  // MOSI
#define TFT_CLK D5  // SCK
#define TFT_LED D1   // 0 if wired to +5V directly


TFT_22_ILI9225 tft = TFT_22_ILI9225(TFT_RST, TFT_RS, TFT_CS, TFT_LED);


void setup()
{
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  ThingSpeak.begin(client);
  tft.begin();
  tft.setOrientation (1);
  tft.clear();
  tft.setBackgroundColor(COLOR_BLACK);
  tft.fillRectangle(0, 0, tft.maxX() -1, tft.maxY() -1, COLOR_WHITE);
  
}

void loop()
{
  
  tft.setGFXFont(&FreeSerifBoldItalic12pt7b);
  tft.drawRectangle(0, 0, tft.maxX() - 1, tft.maxY() - 1, COLOR_BLUE);
  tft.drawRectangle(1, 1, tft.maxX() - 2, tft.maxY() - 2, COLOR_BLUE);
  tft.drawLine(0, 50, tft.maxX() - 1, 50, COLOR_BLUE);
  tft.drawLine(0, 51, tft.maxX() - 1, 51, COLOR_BLUE);
  tft.drawGFXText(40, 25, "Temperatura", COLOR_RED);
  
  tft.setGFXFont(&FreeMonoBold9pt7b);
  tft.drawLine(0, 115, tft.maxX() - 1, 115, COLOR_SKYBLUE);
  tft.drawGFXText(5, 90, " Caldaia", COLOR_BLACK);
  tft.drawGFXText(10, 150, "Pannelli", COLOR_BLACK);
  tft.drawCircle(195, 83, 2, COLOR_BLACK);
  tft.drawCircle(195, 142, 2, COLOR_BLACK);
  tft.drawGFXText(200, 95, "C", COLOR_BLACK);
  tft.drawGFXText(200, 155, "C", COLOR_BLACK);
  tft.setGFXFont(&FreeSans24pt7b);

Avete suggerimenti?