Hello. Please bare with me, as I'm new to the forum and Arduino in general, so I hope this is in the right place and please excuse any mistakes I may make along the way. LONG STORY ! :o
TL/DR: I need help with a VERY simple client-server setup to read the state of a switch from one board and control a second board via Ethernet. The problem is the connection drops sometimes and doesn't resume on its own - THIS is my real problem, as I managed to mull through most of this mess on my own and when it works....it works, despite being "wrong" on so many levels - not a programmer here, but I love this stuff and want to learn more by talking to actual people rather than by reading "dry" documentation. The fact that I at least tried to it myself should warrant that I get some help and prove I'm not just trying to get others to do it for me. There's some specifics involved too, hence why I'd like "human" interaction please.
LONG VERSION:
I'm working on a project involving two Nucleo144 boards (F767ZI). I'm using the required libraries, as shown at the top of my code. What I need this setup to do is read the state of a float switch (so a toggle switch) connected to one board and then control some output pins on the second board over Ethernet. The reason I don't do it directly with one board is because the float switch is sitting in a tank which is filled by a pump that is too far away from the tank. The board at the pump end should do just that: switch this three phase pump on/off depending on the state of the float switch. Sounds simple, right ? In addition, one very important thing, I also need to work out if the two boards get cut off so the pump doesn't keep filling the tank and cause it to overflow !
On my own, I managed to "concoct" something very rude and rudimentary (and probably very "wrong") by putting together various pieces of code in my own little way, but it doesn't work right and I REALLY need to get this thing going and also learn what I'm doing wrong. The code is a mess from a professional's point of view, but that's just the point: I never claimed I was a pro, hence why I'd like to learn to do it right. I also added my own ideas and twists here and there which are not "industry standard", so that's another thing I need to point out: don't go too professional on me It all seems to work on paper, but the problem is it's not reliable over time. The thing needs to run constantly and often it locks up. Without further ado, let's look at the "server side" code (attached). Please feel free to ask questions, as the whole code doesn't fit.
I chose to make the board near the tank the "server" and the one near the pump the "client".....I think this may not be the best idea, but bare with me.
Over at the "server", I have this: I start by including the two libraries required for the Nucleo boards:
I then commented out the mac line because I learned from here that the ethernet IC that's on these Nucleo boards can use its own mac, so it's not needed. Indeed it works - no problems here.
Now here's where I took the first "liberty": instead of attempting to use DHCP every time, regardless of whether it succeeds or not (like in all the example codes I've seen), I created my own bool ("doDHCP") to act as a "checkbox" that sets whether I want to use DHCP or not. I then left the following lines intact to set what IPs should be used if doDHCP is set to false. I also initialize the ethernet server which I call "theServer"....(does this name matter ??) This part works and I DO get an address like I envisioned.
Some pins come next: these correspond to a Nucleo144 board obviously. The colors represent the color of the wires I ran to my float switch, for my own convenience. This is a SPDT switch, so when the float is up, one contact closes and pulls to GND acting as a "stop" and when the float drops, the other contact closes and represents a "run". The doDHCP thing also comes next and I set it to true - this part works too.
Next, I ran into the problem of not being able to tell when the network cable is unplugged. This is apparently a shortcoming of the library used for the Nucleo boards and there was nothing I could do about it, so I just commented that part out. The idea would've been to "halt" here if a cable is not plugged (no link), because there's no point, but I couldn't get it to work, despite trying to seek help from the library creator...it's a little over my head
Next comes that doDHCP mess and then the server is also "started". This all works.
This is how I'm reading the state of the switch: thinking it'd be "safer" for the board, I'm using a set of optocouplers between the contacts and the Nucleo, despite the switch itself not being powered by any dangerous voltages - doesn't matter. The idea works: I'm first checking to see if the switch has been in that position before ( if (tankStatus != 1) ). At startup, tankStatus is not declared, so we enter the if statement (because it's NOT equal to 1): I set millis as the time the switch closed. I then read the state of both the "run" AND "stop" pins to ensure they're not stuck on at the same time (corrosion, etc). The state has to be maintained like that for the time at "debounceTime" in order to set tankStatus to 1, otherwise the while loop breaks and the code moves on to the next part, which is literally the same thing, but "mirrored" and with 0 instead of 1 for tankStatus....whew...please bare with me if you're still reading
There's also that "ERR" state I mentioned where both contacts either get stuck ON at the same time or OFF at the same time and that sets tankStatus to 2.
Everything so far works and it's just fine and dandy: my crude "debounce" mechanism ensures the state doesn't toggle immediately if there's like a "wave" in the water tank and the float bounces up and down several times. True, it does "block" the code for 10 seconds every time the state changes, but hey: that's why I'm discussing it.
Now comes the fun part which drove me insane: The first line seems to be standard on every "server": it creates a client called "theClient" from whatever client is connected to my server here. This confused me to no end at first because I couldn't understand it: if this is a "server", why am I suddenly creating a client ? I think I managed to understand why: the "server" class has no "read" function like the client class does, so to actually "READ" anything from a client that's connected, I have to create a client on the server.....if that makes any sense. Again, I find the info rather insufficient sometimes....
After that, I initialize a blank string called commandString.
While the clients sends out data, I halt in that loop and keep on receiving characters and adding them to commandString until it spits out the end of line character \n, at which point the loop breaks and I read my message: I set my client at the pump side to spell "POLL" when it wants to get the state of the switch, so when POLL "forms", I call the function "doReply()" which is in the next part.
I'm not sure if I should be calling "theClient.stop()" after returning from the function...not enough info on this, but I tried it with and without it and it doesn't seem to make a difference. I read somewhere that it's required to call it to "flush the buffer"....which makes sense, though I don't know IF this happens as it should or if it should be there.
EthernetClient theClient = theServer.available(); //Get available client
String commandString;
while (theClient.available())
{ char c = theClient.read();
if (c != '\n') {
commandString += c; // Read char until linefeed, then add received char to commandString variable
}
else {
Serial.println("POLLED");
if (commandString == "POLL") {
doReply();
theClient.stop();
}
}
}
Lastly, there's the doReply() function which I created....functions by themselves also took me a while to comprehend and couldn't figure out what goes on, but then I learned that when called upon, the code jumps to the function, RUNS the function, then the code goes back to where the function was originally called, so in my case: my idea is that I'm calling the doReply() function where I reply to my pump client who is still waiting for the state of the switch (0, 1 or 2), then I snap back to the "main" code and do "client.Stop()"......then repeat the loop.
void doReply() {
if (tankStatus == 1)
{
theServer.print("ON\n");
}
else if (tankStatus == 0)
{
theServer.print("OFF\n");
}
else if (tankStatus == 2)
{
theServer.print("ERR\n");
}
}
The client code is a lot more messy due to the numerous pins and stuff I want it to do....pilot lamps and whatnot, so I shall do a second post for that. Thank you for your patience thus far.
TankSideServer.ino (5.92 KB)