Attivare relè tramite arduino nano ENC28J60 e Telegram bot

Salve a tutti, ho cercato un po' ovunque su internet, ma non sono riuscito a capire se è possibile interfacciare il modulo ENC28J60 con Arduino nano, per poi comandarlo tramite un bot di Telegram.
Ho già pilotato un semplice led utilizzando la board Nodemcu ed un bot di Telegram, ma ora avrei bisogno di un'interfaccia ethernet anzichè wireless.
Leggendo su internet non sono stato in grado di capire se posso fare la stessa cosa utilizzando le board Arduino nano + ENC28J60.
Vorrei utilizzare queste due board per alcuni motivi:

  • già le possiedo
  • non ho trovato alternative
  • mi piacerebbe utilizzare Telegram per il controllo del relè in quanto non dovrò comandarlo solamente io

Vi ringrazio in anticipo.

Arduino Nano + ENC28J60 non c'è problema , che invece il ATmega328P abbia sufficienti risorse per fare quello che vuoi fare tu ... ho qualche dubbio ... :roll_eyes:

Io l'ho fatto ma utilizzando schede della serie MKR che montano un SAM D21 :wink:

Guglielmo

Si che si può, ma di certo non con il nano perché il server telegram non accetta connessioni non SSL ed il nano non ha risorse per crittografare.

Se vuoi dare un'occhiata a questa libreria, ho implementato un esempio con ethernet testato su esp32, stm32 e samd21 al momento.

Vi ringrazio @gpb01 @cotestatnt per le vostre risposte.
Per quanto riguarda la soluzione proposta da @gpb01, posso chiederti il nome specifico delle schede che hai utilizzato?
@cotestatnt, ho sbagliato scrivendo che le avevo entrambe le schede, quella ethernet l'ho ordinata oggi e quindi non appena la riceverò testerò il codice che hai linkato.
Utilizzando una scheda W5100, come quella della figura mi sembra di aver capito che è possibile farlo e vorrei chiedervi conferma.
Lascio il link del tutorial e un'immagine della scheda in questione per maggior chiarezza.

W5100

Intanto lascia stare lo shield eternet ed Arduino UNO/MEGA/Leonardo ... come confermato anche da cotestatnt NON hanno le risorse necessarie.

Per quanto riguarda me, ho usato delle semplicissime MKR 1000 WiFi ... ma ormai ce ne sono talmente tante che offrono il WiFi che ... c'è solo l'imbarazzo della scelta.

Se non si vuole usare il WiFi, si prende una MKR ZERO e ci aggiunge lo shield Ethernet MKR ...

Guglielmo

Perfetto, ti ringrazio.

Alla fine ho utlizzato un ESP32 + W5500.
Lascio un mini tutorial in caso dovesse servire a qualcuno.
Vi ringrazio di nuovo per tutto @gpb01 @cotestatnt

@maximealive grazie a te per il feedback e la condivisione dello sketch.

Se hai bisogno di ulteriori informazioni sulla libreria chiedi pure qui sul forum oppure apri una issue su GitHub se preferisci.

Avrei in realtà una domanda @cotestatnt riguardo al funzionamento della inline keyboard.
Chiedo qui visto che è inerente alla libreria AsyncTelegram2, ma in caso cambierò sezione.
Se invio due volte lo stesso comando tramite l'inline keyboard, esce il pop-up o l'alert entrambe le volte, ma ho notato che il rele alla seconda volta non funzionava.
La scheda riceveva l'impulso solamente dopo abbastanza tempo o dopo aver rinviato il comando di mostrare l'inline keyboard.
Quali informazioni posso fornirti? Oppure è un problema comune?
Se necessario ti fornirò il codice che ho utilizzato, anche se, ricordando bene, anche con quello postato nella cartella "example -> keyboard" il risultato era lo stesso.

@maximealive grazie per la segnalazione. In effetti ho provato lo sketch di esempio keyboards.ino ed il bug è presente.

Abilitando il log di debug della libreria, ho notato che la connessione con il server cade e viene reinizializzata dopo il timeout previsto, per quello che dopo un po' torna a funzionare.

Appena riesco vado più a fondo nella questione :+1:

Perfetto

@maximealive , ho approfondito (in realtà è stato molto più semplice di quel che credevo :open_mouth:)
Non si tratta di un vero e proprio bug, ma di un'impostazione di default sbagliata per quanto riguarda il caching dei messaggi di risposta alle callback query che avevo impostato con un tempo decisamente eccessivo di 30 secondi (credo mi sia scappato uno 0 di troppo).

Se vuoi sistemare, senza aspettare la prossima release della libreria modifica alla riga 391 il file AsyncTelegram2.cpp

Il discorso della connessione che cade era un abbaglio dovuto ad altro.

Perfetto, grazie @cotestatnt per averlo postato direttamente qui! :grinning:
Non appena avrò la possibilità farò la modifica :+1:

Salve, di nuovo, sto avendo un problema.
Ho connesso tutto secondo lo schema e la tabella che posterò di seguito insieme al codice che ho utilizzato.
Quello che accade è che dopo un po' di tempo il bot non risponde più (ha funzionato per circa due giorni).
Non capisco da cosa possa dipendere ed ho pensato ad alcune possibili cause, ma cerco conferme o altre cause:

  • alimentazione/connessioni errata/e (come voltaggio, o gnd in comune)
  • interferenze con scheda ethernet
  • problemi di librerie

schema_1

#include <SPI.h>
#include <Ethernet.h>
#include <SSLClient.h>
#include <WiFi.h>

#include <AsyncTelegram2.h>
#include <tg_certificate.h>

const char* token =  "xxx:xxxxxxxxxxx";

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192, 168, 1, 177);
IPAddress myDns(192, 168, 1, 1);

EthernetClient base_client;
SSLClient client(base_client, TAs, (size_t)TAs_NUM, A0, 1, SSLClient::SSL_ERROR );

AsyncTelegram2 myBot(client);
ReplyKeyboard myReplyKbd;

#define RELAY_CANCELLO       17
#define RELAY_PEDONALE       16
#define RELAY_BOX_LETTERE    33
#define RELAY_TRASFORMATORE  25

#define CHAT_ID_1   xxx
#define CHAT_ID_2   xxx
#define CHAT_ID_3   xxx
#define CHAT_ID_4   xxx
#define CHAT_ID_5   xxx
#define CHAT_ID_6   xxx

uint32_t chat_id;

void setup() {
  pinMode(RELAY_CANCELLO, OUTPUT);
  pinMode(RELAY_PEDONALE, OUTPUT);
  pinMode(RELAY_BOX_LETTERE, OUTPUT);
  pinMode(RELAY_TRASFORMATORE, OUTPUT);

  digitalWrite(RELAY_CANCELLO, LOW);
  digitalWrite(RELAY_PEDONALE, LOW);
  digitalWrite(RELAY_BOX_LETTERE, LOW);
  digitalWrite(RELAY_TRASFORMATORE, LOW);

  // spegnimento modulo wifi
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  
  SPI.begin();
  // You can use Ethernet.init(pin) to configure the CS pin
  Ethernet.init(5);  // Most Arduino shields

  // Open serial communications and wait for port to open:
  Serial.begin(115200);

  // start the Ethernet connection:
  //Serial.println("Initialize Ethernet with DHCP:");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // Check for Ethernet hardware present
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    }
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
    }
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip, myDns);
  } else {
    Serial.print("  DHCP assigned IP ");
    Serial.println(Ethernet.localIP());
  }
  delay(1000);

  // Set the Telegram bot properies
  myBot.setUpdateTime(1000);
  myBot.setTelegramToken(token);

  // Check if all things are ok
  Serial.print("\nTest Telegram connection... ");
  myBot.begin() ? Serial.println("OK") : Serial.println("NOK");

  myReplyKbd.addButton("/cancello");
  myReplyKbd.addButton("/pedonale");
  myReplyKbd.addButton("/box_lettere");
}


void loop() {
  TBMessage msg;

  if (myBot.getNewMessage(msg)) {
    String msgText = msg.text;

    chat_id = msg.sender.id;

    if (chat_id == CHAT_ID_3 || chat_id == CHAT_ID_1 || chat_id == CHAT_ID_2 || chat_id == CHAT_ID_4 || chat_id == CHAT_ID_5 ||chat_id ==CHAT_ID_6) {
      if (msgText.equals("/cancello")) {
        // apertura - chiusura cancello
        digitalWrite(RELAY_CANCELLO, HIGH);
        myBot.sendMessage(msg, "Cancello aperto/chiuso");
        delay(500);
        digitalWrite(RELAY_CANCELLO, LOW);
      }
      else if (msgText.equals("/pulsanti")) {
        // mostra pulsanti anzichè tastiera
        myBot.sendMessage(msg, "Pulsanti attivati", myReplyKbd);
      }
      else if (msgText.equals("/pedonale")) {
        // apertura cancello pedonale
        digitalWrite(RELAY_PEDONALE, HIGH);
        myBot.sendMessage(msg, "Cancello pedonale aperto");
        delay(500);
        digitalWrite(RELAY_PEDONALE, LOW);
      }
      else if (msgText.equals("/box_lettere")) {
        // apertura scatola

        // accensione trasformatore 24V DC- 12V DC
        digitalWrite(RELAY_TRASFORMATORE, HIGH);
        delay(1000);
        myBot.sendMessage(msg, "Box lettere aperto");
        // impulso per elettroserratura a 12V
        digitalWrite(RELAY_BOX_LETTERE, HIGH);
        delay(500);
        digitalWrite(RELAY_BOX_LETTERE, LOW);
        delay(500);
        // spegnimento trasformatore
        digitalWrite(RELAY_TRASFORMATORE, LOW);
      }
      else {
        String reply;
        reply = "Welcome " ;
        reply += msg.sender.username;
        reply += ".\nProva /cancello, /pedonale, o /box_lettere";
        reply += ".\nOppure /pulsanti per attivare i pulsanti";
        myBot.sendMessage(msg, reply);
      }
    }
    else {
      myBot.sendMessage(msg, "Accesso non autorizzato");
    }
  }
}```

Ciao @maximealive
Bisognerebbe riuscire a distinguere se è il bot a bloccarsi oppure la scheda ethernet o magari ancora l'ESP32. Visto che ci sono di mezzo dei relé non si possono escludere eventuali disturbi, ad esmepio la relay shield è optoisolata?

Da una rapida ricerca online, sembrerebbe un problema di questo tipo ogni tanto si presenta con le ENC28J60, specialmente con servizi di questo tipo che richiedono un polling continuo (come ad esempio anche Blynk).
Con il WiFi della scheda io non ho mai riscontrato malfunzionamenti e non ho nemmeno issues aperte simili nel repository.
Ad ogni modo, se riesco metto su una scheda di prova questa sera anche io (ma con ethernet shield w5500 perché ho solo quella disponibile)

Inoltre vedo che fai un uso piuttosto diffuso di delay() cosa che sicuramente non aiuta perché l'ESP32 potrebbe resettarsi per watchdog e magari rimanere piantato li in attesa di reset.

Quindi un paio di consigli che potresti provare (non credo che risolveranno il problema, ma di sicuro aiutano a rendere più "performante" lo sketch).

  1. Sostituisci l'if con tutti quegli OR in parallelo che è proprio brutto da vedere, con una funzioncina semplice semplice che cerca l'id all'interno di un array che contiene quelli "abilitati"

  2. Soprattutto elimina i delay(). Nel tuo caso vedo che li usi sempre per realizzare una specie di "ritardo alla diseccitazione" dei relé. Si è discusso qualche giorno fa proprio di un problema simile in questo post.
    Nel tuo caso potrebbe tornarti utile lo stesso approccio, ma sviluppato come una classe/libreria in modo da rendere più lineare e leggibile il codice (il run() va messo nel loop() principale)

Edit:

Il chat ID di Telegram è un numero che può essere anche piuttosto lungo e negativo (in caso di gruppi). Il tipo dati più corretto da utilizzare è int64_t

#define CHAT_ID_1   xxx
#define CHAT_ID_2   xxx
#define CHAT_ID_3   xxx
#define CHAT_ID_4   xxx
#define CHAT_ID_5   xxx
#define CHAT_ID_6   xxx

int64_t chat_ids[] = {CHAT_ID_1, CHAT_ID_2, CHAT_ID_3, CHAT_ID_4, CHAT_ID_5, CHAT_ID_6} ;

bool isAuthorized(int64_t theId) {
  for(int i=0; i<sizeof(chat_ids)/sizeof(int64_t ); i++){
    if(chat_ids[i] == theId)
      return true;
  }
  return false;
}
 .....
 
if (isAuthorized(msg.sender.id)) {
      String msgText = msg.text;
      ...............

Ciao @cotestatnt, non appena avrò tempo allora mi concentrerò sui possibili disturbi e nel sistemare il codice, accantonando quindi un possibile problema legato alle librerie.

ad esmepio la relay shield è optoisolata?

Aggiorno quest'informazione con certezza non appena riesco, non essendo molto pratico, non riesco a darti una risposta sicura ora.

Ad ogni modo, se riesco metto su una scheda di prova questa sera anche io (ma con ethernet shield w5500 perché ho solo quella disponibile)

A titolo informativo, sto utilizzando la W5500 anche io perchè la ENC28J60 ancora non mi è arrivata.

Nel frattempo ti ringrazio come sempre.

... considera che, se con le schede relè si comandano carichi "induttivi" (come nel tuo caso), i problemi, se non si separano le alimentazioni, sono quasi certi :roll_eyes:

Ne abbiamo parlato decine e decine di volte su questo forum ... il corretto collegamento di quelle schede relè (purché siano quelle con optoisolatore) è questo:

... con DUE alimentazioni separate che NON hanno in comune nulla, neanche il GND.

Guglielmo

Ciao @gpb01, grazie molte per la risposta. Come detto prima, non appena avrò tempo, seguirò le vostre indicazioni, riportando successivamente un feedback qui.

Per quanto riguarda il collegamento dei relè, ho provato a fare diverse ricerche e tentativi, ma avendo avuto anche diversi tipi di problemi(alimentatore rotto all'improvviso, problemi di connessione internet, etc) probabilmente mi è sfuggito questo collegamento.

Ti ringrazio di nuovo :+1:

... oh, naturalemnte, con quel collegamento, avrai un funzionamento inverso dei relè ... pin di controllo HIGH => relè diseccitato, pin di controllo LOW => relè eccitato.

Poi, questo è il minimo ... come sempre devi controllare il passaggio dei cavi, tenere distanti i cavi dei carichi dai cavi della MCU, ecc. ecc.

Guglielmo

P.S.: Vero che sei su ESP e che di memoria ne hai parecchia, ma l'uso della classe String, come fai tu, può portare a problemi, come descritto nel primo post di QUESTO thread. Fossi in te convertirei tutto il codice usando le stringhe classiche del 'C' (char array).

@maximealive ho messo su anche io un ESP32 di prova.
Ho fatto solo alcune piccole modifiche al tuo sketch originario e mi sono reso conto che nel tuo sketch, tu non hai configurato l'ESP32 per recuperare l'ora corretta dai server NTP.

Non ne sono certo, ma la data di sistema credo venga usata dalla libreria ClientSSL che si occupa dell'encrypt SSL per la verifica del certificato.
Purtroppo le librerie incluse nel core non funzionano con l'ethernet (e mi pare una grande stupidaggine :frowning: ).

Comunque, vediamo se anche il mio si blocca ed eventualmente aggiungo la gestione della data.

Questo lo sketch (ho aggiunto solo un comando per vedere lo stato dell'heap ed implementato la funzione per la verifica dell'id)

#include <SPI.h>
#include <Ethernet.h>
#include <SSLClient.h>
#include <WiFi.h>

#include <AsyncTelegram2.h>
#include <tg_certificate.h>

const char* token = "xxxxxx";

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192, 168, 2, 177);
IPAddress myDns(192, 168, 2, 1);

EthernetClient base_client;
SSLClient client(base_client, TAs, (size_t)TAs_NUM, A0, 1, SSLClient::SSL_ERROR );

AsyncTelegram2 myBot(client);
ReplyKeyboard myReplyKbd;

#define RELAY_CANCELLO       17
#define RELAY_PEDONALE       16
#define RELAY_BOX_LETTERE    33
#define RELAY_TRASFORMATORE  25

#define CHAT_ID_1   123456789
#define CHAT_ID_2   -726659123

int64_t chat_ids[] = {CHAT_ID_1, CHAT_ID_2} ;

bool isAuthorized(int64_t theId) {
  for (int i = 0; i < sizeof(chat_ids) / sizeof(int64_t ); i++) {
    if (chat_ids[i] == theId)
      return true;
  }
  return false;
}


void setup() {
  pinMode(RELAY_CANCELLO, OUTPUT);
  pinMode(RELAY_PEDONALE, OUTPUT);
  pinMode(RELAY_BOX_LETTERE, OUTPUT);
  pinMode(RELAY_TRASFORMATORE, OUTPUT);

  digitalWrite(RELAY_CANCELLO, LOW);
  digitalWrite(RELAY_PEDONALE, LOW);
  digitalWrite(RELAY_BOX_LETTERE, LOW);
  digitalWrite(RELAY_TRASFORMATORE, LOW);

  // spegnimento modulo wifi
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);

  SPI.begin();
  // You can use Ethernet.init(pin) to configure the CS pin
  Ethernet.init(5);  // Most Arduino shields

  // Open serial communications and wait for port to open:
  Serial.begin(115200);

  // start the Ethernet connection:
  //Serial.println("Initialize Ethernet with DHCP:");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // Check for Ethernet hardware present
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    }
    if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
    }
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip, myDns);
  } else {
    Serial.print("  DHCP assigned IP ");
    Serial.println(Ethernet.localIP());
  }
  delay(1000);
  // Set the Telegram bot properies
  myBot.setUpdateTime(1000);
  myBot.setTelegramToken(token);

  // Check if all things are ok
  Serial.print("\nTest Telegram connection... ");
  myBot.begin() ? Serial.println("OK") : Serial.println("NOK");

  myReplyKbd.addButton("/cancello");
  myReplyKbd.addButton("/pedonale");
  myReplyKbd.addButton("/box_lettere");
}


void loop() {

  TBMessage msg;
  if (myBot.getNewMessage(msg)) {

    if (isAuthorized(msg.sender.id)) {
      String msgText = msg.text;

      if (msgText.equals("/cancello")) {
        // apertura - chiusura cancello
        digitalWrite(RELAY_CANCELLO, HIGH);
        myBot.sendMessage(msg, "Cancello aperto/chiuso");
        delay(500);
        digitalWrite(RELAY_CANCELLO, LOW);
      }
      else if (msgText.equals("/pulsanti")) {
        // mostra pulsanti anzichè tastiera
        myBot.sendMessage(msg, "Pulsanti attivati", myReplyKbd);
      }
      else if (msgText.equals("/pedonale")) {
        // apertura cancello pedonale
        digitalWrite(RELAY_PEDONALE, HIGH);
        myBot.sendMessage(msg, "Cancello pedonale aperto");
        delay(500);
        digitalWrite(RELAY_PEDONALE, LOW);
      }
      else if (msgText.equals("/box_lettere")) {
        // apertura scatola

        // accensione trasformatore 24V DC- 12V DC
        digitalWrite(RELAY_TRASFORMATORE, HIGH);
        delay(1000);
        myBot.sendMessage(msg, "Box lettere aperto");
        // impulso per elettroserratura a 12V
        digitalWrite(RELAY_BOX_LETTERE, HIGH);
        delay(500);
        digitalWrite(RELAY_BOX_LETTERE, LOW);
        delay(500);
        // spegnimento trasformatore
        digitalWrite(RELAY_TRASFORMATORE, LOW);
      }
      else if (msgText.equals("/heap")) {
        snprintf(buf, sizeof(buf), "Total free: %6d - Max block: %6d\n", heap_caps_get_free_size(0), heap_caps_get_largest_free_block(0));
        myBot.sendMessage(msg, buf); 
      }
      else {
        String reply;
        reply = "Welcome " ;
        reply += msg.sender.username;
        reply += ".\nProva /cancello, /pedonale, o /box_lettere";
        reply += ".\nOppure /pulsanti per attivare i pulsanti";
        myBot.sendMessage(msg, reply);
      }
    }
    else {
      myBot.sendMessage(msg, "Accesso non autorizzato");
    }
  }
}