Weird behavior with Arduino MEGA, TCP server and sensors

Hi to all,

I have a Arduino MEGA running a program that receives data from two sensors over the net and save them to a SD card.
Each sensor runs a TCP server, so I use the Ethernet shield to connect to them and receive the data.
In particular, these two sensors uses the same public IP, but they have different ports (I'm using a VPN server, so the public IP is the same for both devices, but the ports are different).

The sensors send data by terminating them with \n, so the program check them and when it reaches the "\n", it saves the data on the SD card.

The problem is that the program runs fine sometimes, other times it gets stuck (does it crash somehow?) and I need to manually restart the program to make it work again.
Other times, it connects to both the TCP server, but prints only the data coming from one of them.
For example, sometimes it prints also the data from the wind_sensor, then I reboot it, and it prints only the Svs60 sensor, other times, it prints both correctly.

I really can't understand why this happens!
Can you please help me trying to find the error?

Is it because the sensors have the same IP and so the ethernet library is not able to handle it correctly? I use different variable names to connect to the TCP servers.

// Library includes
#include <SD.h>
#include <FTP.h>
#include <RTC.h>
#include <Ethernet.h>

// Set Ethernet properties of our PLC
uint8_t mac[] = { 0xDE, 0xAD, 0x4E, 0x55, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 100);
IPAddress netmask(255, 255, 255, 0);
IPAddress server(2, 45, 150, 21);

byte server_svs60[] = { 188, 34, xxx, xxx};  // same ip
int tcp_port_svs60 = 18627;
byte server_wind[] = { 188, 34, xxx, xxx};  // same ip
int tcp_port_wind = 18625;
EthernetClient client_svs60;
EthernetClient client_wind;

const byte numChars = 32 * 4;
char receivedChars[numChars + 1];
char tempChars[numChars + 1];  // temporary array for use when parsing

const byte numChars_wind = 32 * 4;
char receivedChars_wind[numChars + 1];
char tempChars_wind[numChars + 1];  // temporary array for use when parsing

byte lineCount = 0;

IPAddress time_server(147, 156, 7, 26);  // es.ntp.pool.org
unsigned int udpPort = 2390;
EthernetUDP udp;
const int NTP_PACKET_SIZE = 48;      // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[NTP_PACKET_SIZE];  //buffer to hold incoming and outgoing packets


// Variable to save the hour and second
int savedHour;
int savedSecond;
char datetime[50];
// Variables to manage the SD card
Sd2Card card;
SdVolume volume;

bool flag_wind = false;
bool flag_svs60 = false;

// Setup function
void setup() {
  // Set the speed of the serial port
  Serial.begin(9600);

  // Init the SD Card
  if (!SD.begin(53)) {
    Serial.println("Card failed, or not present");
    while (true)
      ;
  }

  // Configure the ethernet protocol in our PLC
  Ethernet.begin(mac, ip, netmask);
  Serial.print("IP address: ");
  Serial.println(Ethernet.localIP());


  if (client_svs60.connect(server_svs60, tcp_port_svs60)) {
    Serial.println("Connected to the SVS60 server");
    client_svs60.println();
  } else {
    Serial.println("Connection to the SVS60 TCP Server failed");
  }
  delay(1000);

  if (client_wind.connect(server_wind, tcp_port_wind)) {
    Serial.println("Connected to the Wind server");
    client_wind.println();
  } else {
    Serial.println("Connection to the Wind Server failed");
  }

  udp.begin(udpPort);
  sendRequest();
}


// Loop function
void loop() {

  if (udp.parsePacket()) {

    udp.read(packetBuffer, NTP_PACKET_SIZE);

    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    const unsigned long seventyYears = 2208988800UL;
    unsigned long epoch = secsSince1900 - seventyYears;

    RTC.setTime(epoch);
    RTC.write();
  }

  if (!RTC.read()) {
    Serial.println("Read date error: is time set?");
  } else {
    //filename_sd = String(RTC.getYear() + String("") + RTC.getMonth() + String("") + RTC.getMonthDay() + String(".txt"));

    sprintf(datetime, "%04d-%02d-%02d %02d:%02d:%02d",
            RTC.getYear(), RTC.getMonth(), RTC.getMonthDay(),
            RTC.getHour(), RTC.getMinute(), RTC.getSecond());
  }
  // Serial.println(datetime);

  if (client_svs60.available()) {
    char c = client_svs60.read();
    strncat(tempChars, &c, 1);
    if (c == '\n') {
      strcpy(receivedChars, tempChars);
      strcpy(tempChars, "");
      Serial.println("I got this from SVS60: ");
      Serial.println(receivedChars);
      logToSd_svs60(receivedChars);
      // memset(0, receivedChars, sizeof(receivedChars));
    }
  }

  if (client_wind.available()) {
    char c1 = client_wind.read();
    strncat(tempChars_wind, &c1, 1);

    if (c1 == '\n') {
      if (++lineCount == 4) {
        strcpy(receivedChars_wind, tempChars_wind);
        strcpy(tempChars_wind, "");
        lineCount = 0;
        Serial.println("I got this from the uSonic Wind Sensor: ");
        Serial.println(receivedChars_wind);
        logToSd_wind(receivedChars_wind);
        // memset(0, receivedChars_wind, sizeof(receivedChars_wind));
      }
    }
  }

  delay(100);
}


// Function to save information to SD
void logToSd_svs60(char value[]) {
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (dataFile) {
    Serial.println("Saving SVS60 to SD");
    dataFile.println("Sensore Ondametrico: ");
    dataFile.println(datetime);
    dataFile.println(value);
    dataFile.close();
  } else {
    Serial.println("Error opening datalog.txt");
    while (true)
      ;
  }
}

// Function to save information to SD
void logToSd_wind(char value[]) {
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (dataFile) {
    Serial.println("Saving Wind to SD");
    dataFile.println("Dati sistema: ");
    dataFile.println(datetime);
    dataFile.println(value);
    dataFile.close();
  } else {
    Serial.println("Error opening datalog.txt");
    while (true)
      ;
  }
}

unsigned long sendRequest() {
  memset(packetBuffer, 0, NTP_PACKET_SIZE);

  packetBuffer[0] = 0b11100011;  // LI, Version, Mode
  packetBuffer[1] = 0;           // Stratum, or type of clock
  packetBuffer[2] = 6;           // Polling Interval
  packetBuffer[3] = 0xEC;        // Peer Clock Precision
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;

  //Serial.println("I check the time server");

  if (!udp.beginPacket(time_server, 123)) {
    Serial.println("Begin packet error");
  } else {
    udp.write(packetBuffer, NTP_PACKET_SIZE);
    if (!udp.endPacket()) {
      Serial.println("End packet error");
    }
  }
}

This is what I get when the program works correctly:

I got this from SVS60:
VOLTAGE: 4.95\n
Saving SVS60 to SD
I got this from the uSonic Wind Sensor:
$WIMWV,000.0,R,00.0,M,A*10\n
$WIMTA,022.8,C*23\n
$WIMHU,083.3,,019.8,C*05\n
$WIMMB,,,1006.8,B*0F\n

My brain is stuck on the duplicate IP addresses. I'd change that first before doing anything else.

1 Like

The problem is that since I'm using a vpn service to make the sensors available outside the local network, I can only use one IP address with a total of 10 ports.

Do you think the issue is caused by the use of the same IP?

I definitely don't see it helping. Can you put all the sensors behind a router with port forwarding and VLAN them? then they'd all be the same IP as viewed from outside the router but different info on different ports.

1 Like

I already use the port forward.

This is my configuration:

Sensor 1, local IP: 192.168.1.200, port 1649
Sensor 2, local IP: 192.168.1.201, port 1647

Router with sim card: 192.168.1.1

VPN service: 188.34.xxx.xxx with available ports: 18627->18630

Port forwarding on the router:

Sensor 1 -> 188.34.xxx.xxx @ 18625 to 192.168.1.200:1649
Sensor 2 -> 188.34.xxx.xxx @ 18627 to 192.168.1.201:1647

Note: 188.34.xxx.xxx is the same IP address for both sensors, it only have different ports.

I use the VPN service from ipstatico.org since the Ip address provided by the SIM card is private and cannot receive incoming connections. Using the 188.34.xxx.xxx allows me to connect to the router from the external network.

Okay, so they do have different local IP's. I'll have to reboot my brain and think about it again.

1 Like

Yes, they have different local IP, but in the arduino code I write the same IP because I have to use the public one.

I do not even know if the problem is related to the IP address of the sensors. It was just a doubt.

The problem is that it acts randomly, sometimes it works, sometimes it crashes somehow, sometimes it reads data from only one sensor.

Could it be related to the fact that one sensor continuously sends data while the second sensor sends data every 20 minutes? So the TCP connection from Arduino get closed for inactivity?

However, I have to say that sometimes the problem occurs immediately as soon as I power on Arduino, so it cannot be related to inactivity.

I spent all the night working on it, but I wasn't able to find out the problem.
Sometimes, it works correctly for 15 or 20 minutes and then it get stuck (or crashes, I do not know) or it only receives data from one sensor.

So, I did a test by connecting arduino to theblocal network so I used the local ip addresses for the sensors and it gives the same problem!

So definitely the problem is not related to the use of the same ip address.

This is really strange.

I can also post the public IP address of the sensors so you can test the code on your computer (if you have the ethernet or wifi shield).
I'm really getting crazy to find the error.

I think it is a memory problem because now I stopped the Arduino since it wasn't printing anything (since several hours) and was stuck and I noticed that as soon as I tried to upload a new sketch it uploaded a file with all the readings coming from one of the two sensors while there were nothing related to the other sensor.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.