Telegrambot

Huella, bellagente, saluti, baci abbracci e buona domenica.
Qualche tempo fa avevo letto di uno che usava telegram per comandare il suo arduino, figo, e lo volevo fare anch’io, mi son fatto dare due link e ci ho provato.
Devo dire che si tratta di una libreria fatta bene, che prevede tanti bei casi, ma se devo dire di esserne stato soddisfatto direi una bugia, e grossa.
Macchinosa, e usa troppo gli oggetti stringa, appena ho cominciato a divertirmi la mia povera nodemcu si incatastava, povera piccola. quindi mi sono messo di buzzo buono, e ho stroncato l’intera libreria, sostituita con due/tre funzioni in santo C, senza Stringhe di liquerizia o altri santi da chiamare.
vi metto qui il programma che funzia, funzia abbastanza bene.

// la quarta zucca e' bianca

//una semplice interfaccia ai bot di Telegram


// librerie
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
WiFiClientSecure client;


// Dati connessione wifi
char ssid[] = "XXX";         // SSID
char password[] = "YYY";     // PSK

// token del bot
#define TOKEN "11111:AAAAAAAAA"

// variabili di appoggio
char testo[101];      // il messaggio in ricezione, lungo al massimo 100 caratteri
int lentesto;
unsigned long int ultimo;   // il numero dell'ultimo messaggio ricevuto
unsigned long int appoggio; // il numero del messaggio in ricezione
unsigned long int mittente; // il numero del mittente ultimo messaggio

int passo = 10000;               //tempo tra una richiesta e la successiva
unsigned long int ultimotempo;   //ultima ricezione tentata


void setup() {

  Serial.begin(9600);

  // su il wifi
  Serial.print(F("Connessione al wifi: "));
  Serial.println(ssid);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.print(F("Connesso. IP: "));

  IPAddress ip = WiFi.localIP();
  Serial.println(ip);

}



void loop() {
  // ogni passo millisecondi
  if (millis() - ultimotempo >  passo)  {
    ricevidalbot(); // lancio la ricezione
    // controllo che sia arrivato un nuovo messaggio

    if (appoggio > ultimo) {
      // aggiorno l'ultimo messaggio ricevuto
      ultimo = appoggio;
      // stampo la stringa ricevuta
      Serial.print(F("Updateid: "));
      Serial.println (appoggio);
      Serial.print(F("mittente: "));
      Serial.println(mittente);
      Serial.print(F("testo: "));
      Serial.println(testo);
      // ringrazio per avermi scritto
      trasmettialbot(mittente, "grazie per avermi scritto");

    }
    else {
      Serial.print(F("nulla di nuovo, ultimo update ricevuto: "));
      Serial.println(ultimo);
    }
  }
}




void ricevidalbot(void)  {

  // connessione con telegram
  ultimotempo = millis(); // aggiorno il timer
  IPAddress server(149, 154, 167, 198);
  if (client.connect(server, 443)) {
    Serial.println(F(".... connesso al server"));
    unsigned long ora;
    client.print(F("GET /bot"));
    client.print (TOKEN);
    client.print (F("/getUpdates?offset="));
    client.print (ultimo + 1);
    client.println (F("&limit=1"));
    // resetto la variabile di appoggio che mi serve per conteggiare il valore di ultimo update ricevuto
    appoggio = 0;
    // resetto la variabile di ultimo mittente
    mittente = 0;
    // svuoto il campo testo
    testo[0] = '\0'; // basta il primo carattere, le stringhe sono terminate dallo \0
    // il contatore di lunghezza del testo
    lentesto = 0;

    ora = millis();
    while (millis() - ora < 1000) {
      if (client.available()) {

        // passo alla funzione di trattamento il carattere ricevuto
        if (!tratta(client.read())) {
          break;
          // la tratta restituisce zero quando è il momento di troncare
        };
      }
    }
  }
}


void trasmettialbot(unsigned long int mittente, char messaggio[]) {
  //trasmette al bot il messaggio
  // connessione con telegram
  IPAddress server(149, 154, 167, 198);
  if (client.connect(server, 443)) {
    Serial.println(F(".... connesso al server"));

    client.print(F("GET /bot"));
    client.print (TOKEN);
    client.print (F("/sendMessage?chat_id="));
    client.print (mittente);
    client.print (F("&text="));
    client.print (messaggio);
    client.println();
  }
}


int tratta(char c) {

  // tratta carattere per caratttere il testo messaggio ricevuto da telegram
  // riconosce le coppie di parentesi graffe
  // riconosce alcuni campi
  // restituisce zero per fermare

  static int livello = 0; // il livello di rientro delle parentesi graffe
  static int trovato = 0; // quale nome di oggetto è stato trovato

# define numoggetti  4
  static char * oggetti[numoggetti] = {"none", "\"update_id\":", "chat\":\"id\":", "\"text\":\""};
  // questo somiglia a un array di stringhe
  // realmente e' un array di puntatori a stringa
  // il primo elemento è messo a ciccare, per evitare trovato=0, che si confonde con trovato nulla
  static int corrente[numoggetti];
  // un array di posizioni correnti nell'array di stringhe

  // Serial.println(c);
  if (c == '{') {
    livello++;
    return livello;
  }
  if (c == '}') {
    livello--;
    // trovato=0;
    return livello;
  }

  // ok, siamo nel corpo del messaggio
  //devo riconoscere se stiamo leggendo il nome di un oggetto conosciuto
  if (trovato) {
    // abbiamo trovato un nome di oggetto (: compreso)
    // adesso fino alla virgola o alla virgoletta
    // se si tratta di una virgola
    if (c == ',') {
      trovato = 0;
      // fine del valore
      return 1;

    }
    // o di una virgoletta
    if (c == '\"') {
      trovato = 0;
      // fine del valore
      return 1;
    }
  }
  // ok non è una virgola ne una virgoletta

  // campi numerici
  if (trovato == 1)
  { // updateid, che vale come ultimo messaggio

    appoggio = appoggio * 10 + c - '0';
    // traduco in intero

  }
  if (trovato == 2)
  { // mittente

    mittente = mittente * 10 + c - '0';
    // traduco in intero

  }
  // campi alfabetici, che per ora è solo text, corpo del messaggio
  if (trovato == 3)
    // siamo nel testo
    if (lentesto <= 100) {
      testo[lentesto] = c;
      lentesto++;
      testo[lentesto] = '\0'; // termina qui

    }
    else {
      trovato = 0;
      // tronco la lettura, per non sbordare, siamo oltre i 100 byte
    }

  else {
    // non abbiamo ancora trovato il nome di un oggetto
    // vado avanti a cercarlo

    for (int i = 0; i < numoggetti; i++) {
      //per ogni oggetto

      if (c != oggetti[i][corrente[i]]) {
        // non corrisponde
        corrente[i] = 0;
      }
      else {
        // corrisponde
        corrente[i]++;
        //avanza un passo
        if (oggetti[i][corrente[i]] == '\0') {
          // oggetto finito
          // caso trovato
          corrente[i] = 0; //torno indietro
          trovato = i;
        }
      }
    }
  }
  return 1; // OK in lettura
}

C'è poco da commentare, credo, il programma è ben commentato di suo. i limiti:
riceve un solo messaggio per volta, il più vecchio nella catasta di ricezione di telegram, ma tanto lo da subito per ricevuto e quindi la prossima volta ne riceve un'altro
accetta solo massimo 100 caratteri, dovrei dire i primi 100, non si lamenta se ne arrivano di più, li scarta.
rispetto alle librerie più conosciute usa unsigned long per gli utenti e per i messaggi, come dice papà telegram. interessante che la lavorazione del testo viene fatta mano a mano che arriva, carattere per carattere, questo evita di dover usare Stringhe di liquerizia e non richiede nemmeno grandi buffer di testo
provate e fatemi sapere