Skocz do zawartości

Arduino Nano i Ethernet Shield + MQTT - problem z siecią


xillo

Pomocna odpowiedź

Cześć!

Mam mały problem z obsługą sieci z Ethernet Shield  w Arduino Nano.

Dodam że przy UNO i PICO (inne shieldy) nie mam problemów, wszystko działa.

 

Otóż:

Na początku nie działało nic - doczytałem w końcu, że NANO Ethernet Shield V1.0 firmy DK ma błędnie dołączony pin D12 z masą i należy to połączenie usunąć - tak też zrobiłem i coś już zaczęło działać - czyli używając biblioteki UIPEthernet (standardowa Ethernet.h nie wykrywa shielda na nano) jestem w stanie przypisać sobie adres IP (stały i z dhcp) - ale za każdym razem muszę dodać coś w loop:

#include <UIPEthernet.h> // Used for Ethernet

byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x78, 0xEE  };                                       
IPAddress ip(192, 168, 99, 159);                        
EthernetServer server(80);

void setup() {
  Serial.begin(9600);

  Ethernet.begin(mac, ip);
  Serial.print("IP Address: ");
  Serial.println(Ethernet.localIP());
}

void loop() {
  EthernetClient client = server.available();
}

Jeśli nie dodam linijki "EthernetClient client = server.available();" albo "Ethernet.maintain(); " w loop - dostanę adres IP ale nie mogę go nawet pingować.

Chciałbym dodać serwer MQTT - ale przecież chyba nie mogę zrobić tego połączenia w loop?

Mam to w takim wydaniu:

#include <SPI.h>
#include <UIPEthernet.h>
#include <ArduinoMqttClient.h>
byte mac[] = {
  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02
};
EthernetClient client;
MqttClient mqttClient(client);

const char broker[] = "192.168.99.108";
int        port     = 1883;
const char topicListy[]  = "arduino2/Listy";
const char topicZmierzch[]  = "arduino2/Zmierzch";

void setup() {

  Serial.begin(9600);
  while (!Serial) {
    ; 
  }

  Serial.println("Initialize Ethernet with DHCP:");
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    if (Ethernet.hardwareStatus() == EthernetNoHardware) {
      Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    } else if (Ethernet.linkStatus() == LinkOFF) {
      Serial.println("Ethernet cable is not connected.");
    }
    // no point in carrying on, so do nothing forevermore:
    while (true) {
      delay(1);
    }
  }
  // print your local IP address:
  Serial.print("My IP address: ");
  Serial.println(Ethernet.localIP());

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(broker);

  mqttClient.setUsernamePassword("homeassistant", "xxxx");

  if (!mqttClient.connect(broker, port)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());

    while (1);
  }
 
  Serial.println("You're connected to the MQTT broker!");
  Serial.println();
 
}

void loop() {
  Ethernet.maintain(); 
}

Co nie działa, bo w chwili kiedy chcę wystartować z MQTT, nie działa mi jeszcze sieć 😐

Próbowałem linijki "EthernetClient client = server.available();" / "Ethernet.maintain(); użyć w setup zamiast loop, ale to nic nie daje.

 

Podpowiecie proszę co robię źle...?

 

Edytowano przez xillo
  • Lubię! 1
Link do komentarza
Share on other sites

Przepraszam, jeśli strzelam kulą w płot (nie bawię się Arduino), ale tak naiwnie:
 

2 godziny temu, xillo napisał:

Jeśli nie dodam linijki "EthernetClient client = server.available();" albo "Ethernet.maintain(); " w loop - dostanę adres IP ale nie mogę go nawet pingować.

Zatem co stoi na przeszkodzie, żeby umieścić wywołanie odpowiedniej z wymienionych wyżej funkcji w setup()? W razie potrzeby w setup() możesz również napisać odpowiednią pętlę, jeśli trzeba na przykład ponawiać wywołanie jakiejś funkcji aż zwróci odpowiedni status (konfiguracji sieci) itp. Nie jesteś ograniczony do wyboru między wstawieniem określonej "linijki" do setup() vs loop()...

PS Czy do tej biblioteki (pytam tak z ciekawości, przy okazji też się czegoś nauczę) jest jakaś dokumentacja oprócz kodu źródłowego? Bo kiedy wchodzę na https://www.arduino.cc/reference/en/libraries/uipethernet/, to znajduję tylko link do eleganckiego repo gitHuba.

Edytowano przez ReniferRudolf
  • Lubię! 2
Link do komentarza
Share on other sites

(edytowany)

Cześć, niestety jeśli te wywołania umieszczę w Setup, nie osiągam zamierzonego efektu (jest adres z DHCP, ale zero komunikacji).

Co więcej próbowałem również tworzyć całe połączenie w loop, ale jeśli dodam dodatkowo jakiekolwiek delay - koniec, brak komunikacji.

Z przykładów znalezionych w sieci spróbowałem przełączyć się z ArduinoMqttClient na PubSubClient i to zadziałało - mqttClient.loop() wrzucone w loop również umożliwia uruchomienie działania sieci. Problem w tym, że nie wiem dlaczego 😐 Trochę testów i szukania ciągle przede mną.... W sumie wychodzi wg starego powiedzenia "Teoria jest wtedy, kiedy wiemy wszystko, a nic nie działa. Praktyka jest wtedy, kiedy wszystko działa, a nikt nie wie dlaczego." 

Tak teraz wygląda pełna wersja programu:

#include <UIPEthernet.h>
#include <PubSubClient.h>
#define CLIENT_ID       "ArduinoBrama"
uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};
volatile boolean relay1On = false;

int light = 0;
const char topicListy[20]  = "arduino2/Listy";
const char topicZmierzch[20]  = "arduino2/Zmierzch";
char temperature[10];
int histereza = 10;
int lightOn = 600;
char msg[20] = "";
EthernetClient ethClient;
PubSubClient mqttClient;

long previousMillis;
 
void setup() {
 pinMode(2, INPUT_PULLUP);
 pinMode(13, OUTPUT);

 pinMode(3, OUTPUT);

 digitalWrite(3, HIGH);
  
  Serial.begin(9600);
while (!Serial) {
   ; // wait for serial port to connect. Needed for native USB port only
 }
  if(Ethernet.begin(mac) == 0) {
    Serial.println(F("Ethernet configuration using DHCP failed"));
    for(;;);
  }
  Serial.println(Ethernet.localIP());
  // setup mqtt client
  mqttClient.setClient(ethClient);
  
  mqttClient.setServer("192.168.99.108",1883); //for using local broker

  previousMillis = millis();
  attachInterrupt(digitalPinToInterrupt(2), turnOnOff, CHANGE); // Przerwanie reagujące na zbocze rosnące
}

void loop() {
  
  if(millis() - previousMillis > 3000) {
    light = analogRead(2);
    if (light <= lightOn + histereza && light) {
    digitalWrite(3, HIGH);
    sendData(topicZmierzch, "Jasno :)           ");

  }
  else {
    digitalWrite(3, LOW);
    sendData(topicZmierzch, "Ciemno :)           ");

  }
  Serial.println(light, DEC);
    previousMillis = millis();
  }
  
  mqttClient.loop();
}

void sendData(char topic[20], char msg[20]) {
  char msgBuffer[20];
  if(mqttClient.connect(CLIENT_ID, "homeassistant", "xxx")) {
   mqttClient.publish(topic, msg);
 }
}

void turnOnOff() {

  if (relay1On)
  {
    relay1On = false;

    sendData(topicListy, "Skrzynka zamknięta  ");
  }
 // else
 // {
 //   relay1On = true;
 //   sendData(topicListy, "Skrzynka otwarta    ");
 // }
  
}

Ale jak to przystało - łączę teorię z praktyką - działa, chociaż nie wiem dlaczego, a jednocześnie też do końca nie działa 🙂

Else w komentarzu - kiedy to dodam, program się kompiluje, ale zamiast wydrukować IP drukuje jedynie dwa pierwsze znaki "19", wcześniej drukował "?".

A kiedy wyrzucę UIPEthernet, to przerwanie daje taki efekt jaki chciałem

#define CLIENT_ID       "ArduinoBrama"
uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05};
volatile boolean relay1On = false;

int light = 0;
const char topicListy[20]  = "arduino2/Listy";
const char topicZmierzch[20]  = "arduino2/Zmierzch";
char temperature[10];
int histereza = 10;
int lightOn = 600;
char msg[20] = "";

long previousMillis;
 
void setup() {
 pinMode(2, INPUT_PULLUP);
 pinMode(13, OUTPUT);
 pinMode(3, OUTPUT);
 digitalWrite(3, HIGH);
  
  Serial.begin(9600);
while (!Serial) {
   ; 
 }
  previousMillis = millis();
  attachInterrupt(digitalPinToInterrupt(2), turnOnOff, CHANGE);
}

void loop() {
  
  if(millis() - previousMillis > 3000) {
    light = analogRead(2);
    if (light <= lightOn + histereza && light) {
    digitalWrite(3, HIGH);
    sendData(topicZmierzch, "Jasno :)           ");
  }
  else {
    digitalWrite(3, LOW);
    sendData(topicZmierzch, "Ciemno :)           ");
  }
  Serial.println(light, DEC);
    previousMillis = millis();
  }
}

void sendData(char topic[20], char msg[20]) {
 Serial.println(msg);
}

void turnOnOff() {

  if (relay1On)
  {
    relay1On = false;
    sendData(topicListy, "Skrzynka zamknięta  ");
  }
  else
  {
    relay1On = true;
    sendData(topicListy, "Skrzynka otwarta    ");
  }
}

Kombinuję dalej... Jakieś podpowiedzi? 🙂

Odnośnie dokumentacji - doszukałem się tylko tej z githuba i przykładów rozsianych po sieci.

Edytowano przez xillo
Link do komentarza
Share on other sites

3 godziny temu, xillo napisał:

Else w komentarzu - kiedy to dodam, program się kompiluje, ale zamiast wydrukować IP drukuje jedynie dwa pierwsze znaki "19", wcześniej drukował "?".

Wywoływanie biblioteki sieciowej w kontekście procedury obsługi przerwania to nie jest dobry pomysł. Stąd takie dziwne efekty jak wyżej. Procedura obsługi może co najwyżej ustawić jakąś flagę itp. którą przetestujesz i obkodujesz poza obsługą przerwania.

  • Lubię! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Jeśli shield z tym samym chipem Ethernet działa Ci z UNO, a nie działa z NANO to wina jest tego shielda. Możesz ten od NANO podłączyć do UNO, to jest tylko parę kabelków, SPI + zasilanie (6), reszta to skopiowanie pinów na górę, by były dostępne z shielda. Poza tym lepiej użyć czegoś z chipami W5100 czy 5500, właściwie to takie właśnie mam shieldy do UNO.

A jak połączenie po kablu nie jest kluczowym wymogiem, to jeszcze lepiej i taniej  użyć ESP8266.

  • Lubię! 2
Link do komentarza
Share on other sites

(edytowany)
Dnia 6.08.2023 o 22:56, ReniferRudolf napisał:

Wywoływanie biblioteki sieciowej w kontekście procedury obsługi przerwania to nie jest dobry pomysł. Stąd takie dziwne efekty jak wyżej. Procedura obsługi może co najwyżej ustawić jakąś flagę itp. którą przetestujesz i obkodujesz poza obsługą przerwania.

Dokładnie takiej informacji mi brakowało 🙂

Dodałem osobną flagę - przerwanie tylko informuje że wartość się zmieniła i wszystko działa jak należy. Dziękuję za pomoc!

 

 

  

Dnia 7.08.2023 o 13:00, kaczakat napisał:

Jeśli shield z tym samym chipem Ethernet działa Ci z UNO, a nie działa z NANO to wina jest tego shielda. Możesz ten od NANO podłączyć do UNO, to jest tylko parę kabelków, SPI + zasilanie (6), reszta to skopiowanie pinów na górę, by były dostępne z shielda. Poza tym lepiej użyć czegoś z chipami W5100 czy 5500, właściwie to takie właśnie mam shieldy do UNO.

A jak połączenie po kablu nie jest kluczowym wymogiem, to jeszcze lepiej i taniej  użyć ESP8266.

Akurat na innych używam 5500 i W5100 - a ten który mam w shieldzie Nano to ENC28J60 - i nie dało się go obsłużyć w taki samo sposób. ESP8266 nie mogę użyć w tym miejscu - potrzebuję kabel, ale ogólnie to bardzo je sobie cenię tam gdzie to możliwe 🙂

 

Dziękuję za pomoc jeszcze raz!

Edytowano przez xillo
  • Lubię! 1
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.