Yunclient write() only works once

Hello, first time poster.

My objective is to have my YUN connect to a TCP service on my home automation system (Crestron), periodically request some parameters from it (relating to the thermostat), and store them locally on the YUN. Eventually I will use Tembo to write them to a Google spreadsheet, this is just the first step for me in the process of putting the whole thing together.

So far, it works great... once. The sketch connects to the Crestron succesfully, write() the "poll" string to the Crestron, receive the data from the Crestron, and parse the data on the YUN side.

The trouble is, it only works once. Subsequent iterations of the write() function return 0. (The first iteration returns 6). I can see on my Crestron debugger that the socket is still open, but no data are received on the socket.

Does it have something to do with the fact the YunClient is invoked every iteration through the loop? This also doesn't make sense, because it is invoked, then the "poll" command is sent, and it is after the 2nd call of the YunClient when the return data are parsed.

Thank you for any help.

#include <Console.h>
#include <YunClient.h>
IPAddress cp3(192,168,76,21);

String command, heatCall, coolCall;
float setpoint, currtemp;
unsigned long time;
unsigned long pollLast;
const unsigned long pollDelay = 4000;

void setup()
{
  pinMode(13, OUTPUT);
  digitalWrite(13, LOW);
  Bridge.begin();
  Console.begin();
  digitalWrite(13, HIGH);
  
  while (!Console); // wait for a serial connection
  Console.println("Hello Kevin");

}

void loop() 
{
  YunClient crestron;
  crestron.connect(cp3,7654);
  time = millis();
  
  while (crestron.available()) 
  {
    char c = crestron.read();
    if ( c == '\n')
    {
      Console.print("Command is ");
      Console.println(command);
      parseCommand(command);
      command = "";
    }
    else
    {
      command += c;
    }
  }

  if ( time - pollLast > pollDelay )
  {
    int bytesSent = crestron.println("poll");  //THIS ONLY WORKS THE FIRST TIME
    pollLast = time;
    Console.println(bytesSent);
  }
  
  delay(1000); // I really shouldn't need this, right?
}

By putting everything related to the YunClient connection in loop(), you are making and breaking the connection on every iteration. I'm surprised it even works the first time, since it appears you are saying the response to the first poll isn't received until the second iteration?

I think you will have much more luck if you make the YunClient global, do the connect in setup(), then do only the reads and writes in loop(). That should be a good proof of concept requiring minimal changes.

If that works, you will probably want to make it more robust (but don't add that complication until the basic comm is working.) the issue is that if the connection is lost (network gets unplugged, Crestron closes the socket for some reason, or the Crestron reboots) the only way to get communications back would be to reset the Yun.

To make it more reliable, have a flag that says wether the connection is open or closed. Set that to closed in setup(). At the top of the loop, if the flag says closed, open the connection and set the flag to open. In the body of loop, check for and track errors. At the bottom of the loop, if there were errors, close the connection and set the flag to closed.

This way, the connection is opened in one place at the top of the loop, but only if necessary. And if there is a problem, the connection will be automatically closed and reopened.

The alternative is to make the connection at the top of loop(), send the command and WAIT until you get a response or a timeout, then close the connection. This way the connection is opened/closed every time, which may be a lot of unnecessary overhead.

Thank you for your response. I think I fixed it based on your suggestion.

Originally I tried to move both the Yunclient declaration and the connect call into the setup() and then tried the declarations section, neither worked. It seems to work when I put the YunClient declaration above the setup(), and the connect() within setup().

I will try your suggestion of flagging or testing the connect feedback in loop(), so if it gets disconnected it will get connected again, but not repeatedly if already connected.

Thank you for the help.

djkevinz:
It seems to work when I put the YunClient declaration above the setup(), and the connect() within setup().

Good news, Yes, that's exactly the right pattern.

Putting the declaration at the top of the file makes it globally accessible to everything below it in that file, including setup() and loop(). By not having it within a function it has a permanent lifespan, so it is never deallocated or destroyed. Then setup() can make the initial connection once, and loop() can maintain the connection and process the communications.

You could put the connect() call in loop(), but then you would have to add some protection mechanism to prevent it from constantly calling connect() and only call it when necessary (the second part of the discussion.)