Networking-for-Arduino / EthernetENC

Ethernet library for ENC28J60. This is a modern version of the UIPEthernet library. EthernetENC library is compatible with all Arduino architectures with Arduino SPI library with transactions support. Only include EthernetENC.h instead of Ethernet.h
135 stars 30 forks source link

Nano with ENC28J60 stop transmitting packets #16

Closed Peerke1 closed 3 years ago

Peerke1 commented 3 years ago

I have a Nano running withknolleary/pubsubclient (using a ENC28J60) connecting to HomeAssistent's add-on MQTT broker. I use Wireshark to monitor the network interface of the Nano. The code I am using in the Arduino as a test test-setup

#include <Arduino.h>
#include <SPI.h>
#include <Wire.h>
#include <EthernetENC.h>
#include <PubSubClient.h>

#define INT_PIN 2

byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 100, 7);
IPAddress myDns(192, 168, 100, 4);
IPAddress gateway(192, 168, 100, 254);
IPAddress subnet(255, 255, 255, 0);
IPAddress mqttserver(192, 168, 100, 6);

EthernetClient ethClient;
PubSubClient mqttClient(mqttserver, 1883, ethClient);

uint8_t MqttRegisterCounter;
uint8_t MqttPublishFlag;

volatile int8_t SleepDelayCounter = 0;      // counter used for sleep
int8_t SleepDelay = 10;                    // maximum amount the wdt needs to hit (SleepDelay * 8sec => 450 * 8 = 3600 sec = 1 hour) + 1 extra to stop the loop
// test vars to see what works
const char* TOPIC = "room/plug";  // Topic to subcribe to
const char* MESSAGE = "toggle";   // Message to publish to our topic
// HA corresponding bin-sensor
const char* MQTT_TEST_TOPIC = "mcp/Arduinotestmessage";
boolean rc;

// special DTW wakup function, mustbe named ISR!!
ISR(WDT_vect)
{

    if(SleepDelay != SleepDelayCounter)
    {
      SleepDelayCounter=SleepDelayCounter+1;
      if (SleepDelayCounter == 4)
         MqttPublishFlag = true;
    }
    else
    {
      SleepDelayCounter = 0;
      MqttPublishFlag = true;

    }

    MqttRegisterCounter=MqttRegisterCounter+1;

}

void setup() {

  pinMode(INT_PIN, INPUT); 
  pinMode(LED_BUILTIN, OUTPUT); 

  /*** Setup the WDT ***/

  /* Clear the reset flag. */
  MCUSR &= ~(1<<WDRF);

  /* In order to change WDE or the prescaler, we need to
   * set WDCE (This will allow updates for 4 clock cycles).
   */
  WDTCSR |= (1<<WDCE) | (1<<WDE);

  /* set new watchdog timeout prescaler value */
  WDTCSR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */

  /* Enable the WD interrupt (note no reset). */
  WDTCSR |= _BV(WDIE);

  Serial.begin(115200);
  //Serial.begin(9600);

  // continue with MQTT setup
  //mqttClient.setServer(mqttserver);

  // You can use Ethernet.init(pin) to configure the CS pin
  Ethernet.init(10);  // Most Arduino shields
  Serial.println("Initialize Ethernet");
  Ethernet.begin(mac, ip, myDns, gateway, subnet);
  // Allow the hardware to sort itself out
  delay(1500);
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {  
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
  }
  else
  {
    Serial.print("Arduino is at ");
    Serial.println(Ethernet.localIP());
    Serial.println(Ethernet.hardwareStatus());
    Serial.println(Ethernet.linkStatus());
  }

}

void reconnect() {
  // only every 30 seconds to avoid fludding the broker and be stuck in connect loop
  if (MqttRegisterCounter == 0)
  {

    if (Ethernet.linkStatus() == 1)
    {

      if (!mqttClient.connected()) {

        Serial.print("Attempting MQTT connection...");
        // Attempt to connect
        if (mqttClient.connect("MCP")) {
          mqttClient.setKeepAlive(60);
          Serial.println("connected");
          // Once connected, publish an announcement...
          //mqttClient.publish("outTopic","hello world");
          Serial.println("publishing on");
          rc = mqttClient.publish("mcp/Arduinotestmessage", "on",true);
          Serial.println(rc);
          // ... and resubscribe
          //mqttClient.subscribe("inTopic");
        } else {
          Serial.print("failed, rc=");
          Serial.println(mqttClient.state());
        }

      }

    } else {
      // no ethernet link
      Serial.println("Ethernet Cable disconnected");

    }

    MqttRegisterCounter=MqttRegisterCounter+1;
  }
  else if (MqttRegisterCounter > 3) {
    MqttRegisterCounter = 0;

  } else {
    MqttRegisterCounter=MqttRegisterCounter+1;
  }

}

void loop() {

  if (!mqttClient.connected()) {
    reconnect();
  }

  // publish on every x seconds    
  if (SleepDelayCounter == 0) {
    if (MqttPublishFlag) {

      //boolean rc = mqttClient.publish("mcpArduinotestmessage", "on");
      rc = mqttClient.publish("mcp/Arduinotestmessage", "on",true);

      Serial.print("ON Message 1: ");
      Serial.println(rc);
      SleepDelayCounter= 1;
      MqttPublishFlag = false;

    }

  // publish off every x seconds
  } else if (SleepDelayCounter == 5) {
    if (MqttPublishFlag) {

      //boolean rc = mqttClient.publish("mcpArduinotestmessage", "off");
      rc = mqttClient.publish(MQTT_TEST_TOPIC, String("off").c_str(), true);
      Serial.print("OFF Message: ");
      Serial.println(rc);
      SleepDelayCounter= 6;
      MqttPublishFlag = false;

    }
  }

}

The connect is sent, and the first publish message too, after that its quite in Wireshark. The response (rc) from mqttClient.publish in the serial.print is 1, where it looks like the publish made it to the broker. In Wireshark the packet is not there.

How can I see what actually happens when the publish is being executed?

JAndrassy commented 3 years ago

I think you have to enable the watchdog interrupt after every execution

Peerke1 commented 3 years ago

I have a lot of "OFF Message: 1" and "ON Message: 1" in the console. I have wireshark open at the same time and nothings enters there at the time of a new "XX Message: 1" (my swicth can do port-mirroring for ingress and egress traffic). I asumed the watchdog int would be working an firing the int every 8 sec as of the OFf and On messages or am i missing something here?

Peerke1 commented 3 years ago

after some time i recieve a RST message from the broker, i would asume because of the lack of publish messages within the timeout. When i reset the Arduino it connects again and then same behaviour.

Peerke1 commented 3 years ago

I removed the watchdog and added 2 - 20bit counters (uint32_t). When counter1 == 1 sent a message and when counter2 == 1sent a mesage. every =/- 5 sec there is a message sent. Same behaviour, only the first after init is sent out the ethernet interface.

can i see with some debug what is causing the packet not to be put on the wire? (i have a bit of coding experience, this goes beyond my knowledge)

// simple var counter
  if (MqttRegisterCounter <= 1048576) {

    if (MqttRegisterCounter == 1048576) {
      Serial.println("MqttRegisterCounter at max");
    }
    MqttRegisterCounter = MqttRegisterCounter+1;

  } else if (MqttRegisterCounter == 1048577) {

    if (MqttRegisterCounter2 < 1048576) {

      MqttRegisterCounter2 = MqttRegisterCounter2+1;

    } else {
      // reset all
      MqttRegisterCounter = 0;
      MqttRegisterCounter2 = 0;
      Serial.println("Reset Counters");

    }

  } else{
    Serial.println("Something unexpected happend");

  }
JAndrassy commented 3 years ago

try to add Ethernet.maintain(); as first in the loop()

Peerke1 commented 3 years ago

working now!

Can Ethernet.maintain() stay there or do i need a specific part? i read that tis functions is mainly used for DHCP?

JAndrassy commented 3 years ago

EthernetENC must handle all network traffic targeted to its MAC address and some broadcast packets too. EthernetENC uses every function of the library to do this. If your sketch doesn't call the functions of the library all the time (like with server.available() or client.available()), then put Ethernet.maintain(); as first in loop(). https://github.com/jandrassy/EthernetENC/wiki/Limitations