Question about "was not declared in this scope" despite having just used it.

I thought “was not declared in this scope” meant it was in another unindented section. Put another way, I thought everything inside void loop() was the same scope. Here’s some of the code that’s foul:

void loop() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {                         // In this block, the ESP is handling the
    IPAddress pySenderIP = Udp.remoteIP();  // commands sent over WiFi from the PC

Then further down I have:

  if (Serial.available() > 0)  {                  // Listen to Serial for ProMini's commands
    len = Serial.readBytes(serialBuffer, 64);
    serialBuffer[len] = 0;                        // (terminate the array)

    if (serialBuffer[0] == 95)  {                 // (asc(95) is just the symbol I chose to signal, "special case, do this instead")
      Udp.beginPacket(pySenderIP, pySendrPort);

At this point, I get:

‘pySenderIP’ was not declared in this scope

despite having previously used it the same way earlier in the main loop.
What I’m trying to do is use an ESP8266 to pass data between a ProMini and a laptop PC. Communication is: PC<–>ESP using WiFi (UDP), and ESP<–>ProMini using UART (Serial. commands).
The ProMini can tell the ESP to request NTP time, as can the PC. When the ESP gets the NTP response, it always passes the timestamp to both the PC and the ProMini. So the trouble I’m running into is that the ESP has to use UDP to send packets to the NTP server as well as to the laptop. So I have two uses for Udp.beginPacket. The first I pasted from the NTPClient example:

void sendNTPpacket(IPAddress& address) {
  ... (stuff)
  (stuff)...
  udp.beginPacket(address, 123);

and the other is a more general form from other examples which use:

Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());

The problem with this is that it sends the packet to the sender of the most recently received packet. This would return the incoming NTP packet back to the server. So I want to store the IP address when the laptop talks to the ESP. I found an example which seems to do this using:

IPAddress remoteIp = Udp.remoteIP();

which I replaced remoteIp with what I find much clearer, pySenderIP (I use Python on my laptop for UDP packets), which how I came up with this line in my code:

Udp.beginPacket(pySenderIP, pySendrPort);

But this is where I get “‘pySenderIP’ was not declared in this scope”, even though it’s only 19 lines earlier in void loop()

Here are the above pieces in use:

The first time the laptop PC talks to the ESP, the ESP stores the laptop’s IP address in the variable pySenderIP. (first code snippet)

When the ESP gets a time request from the ProMini (ascii(95) in the second code snippet) the ESP initializes a UDP packet to the NTP server (third code snippet)

When the timestamp returns, the ESP wants to initialize a UDP packet to send the PC (sixth code snippet), as well as over Serial to the ProMini.

Whew! So here’s my entire void loop(), the actual request to the NTP server is a paste of the NTPClient example which is what the timeRequested() function does. The chrono array is just the 48 byte NTP packet trimmed down to 4 bytes for just the time.

void loop() {
  int packetSize = Udp.parsePacket();
  if (packetSize) {
    IPAddress pySenderIP = Udp.remoteIP();
    uint16_t pySendrPort = Udp.remotePort();
    int n = Udp.read(incomingUdp, UDP_TX_PACKET_MAX_SIZE);
    incomingUdp[n] = 0;

    if (incomingUdp[0] == 95)  {
      timeRequested();
      Udp.beginPacket(pySenderIP, pySendrPort);
      Udp.write(chrono);
      Udp.endPacket();
      Serial.println(chrono);
    }
    else  {
      Serial.println(incomingUdp);
    }
  }

  if (Serial.available() > 0)  {
    len = Serial.readBytes(serialBuffer, 64);
    serialBuffer[len] = 0;

    if (serialBuffer[0] == 95)  {
      timeRequested();
      Udp.beginPacket(pySenderIP, pySendrPort);
      Udp.write(chrono);
      Udp.endPacket();
      Serial.println(chrono);
    }
    else  {
      Udp.beginPacket(pySenderIP, pySendrPort);
      Udp.write(serialBuffer);
      Udp.endPacket();
    }  
  }
}

EDIT: I just realized there is a weakness in that I’m counting on not getting any NTP packets outside of the code which gets it (the example NTPClient which is called by my function timeRequested()). The example seems to not expect a response if one second goes by after making a request.
(for reference, from the example:)

  sendNTPpacket(timeServerIP); // send an NTP packet to a time server
  // wait to see if a reply is available
  delay(1000);

  int cb = udp.parsePacket();
  if (!cb) {
    Serial.println("no packet yet");
  } else {
    Serial.print("packet received, length=");
    Serial.println(cb);
    // We've received a packet, read the data from it
    udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer

It’s declared inside an ‘if’ statement. Don’t do that. It shows why it’s not a good idea to scatter your declarations all over your code. Do it at the beginning of major blocks if it’s used in several places in the block.

How can I make that declaration at the top, because I have to wait until the PC sends a packet to the ESP? I got the idea from the example Ethernet(esp8266) > WiFiUdpSendReceiveString

IPAddress remoteIp = Udp.remoteIP();

which is inside the main loop. How else can I make a "run-time" delcaration which stores the sender's IP address into a variable for later use?

I should have thought a bit before I posted. Might the answer be that I declare it at the top but don't assign a value. Then when the packet comes in I assign the value? I'll give that a try.

It’s just like any plain type variable, you can and often do declare first and assign later. A compound declaration and assignment like that is perfectly okay, but it must be in the same block as every reference to it.

My general rule, which may have exceptions from time to time, all global variables declared before any code, local variables declared at the top of any functions, anything else is a “throwaway” variable like an index to a ‘for’ loop. For obvious reasons, when you see a compound declaration and assignment it should be at the top of the function block anyways, because it must precede the capture of a value for subsequent processing. A common example is ‘unsigned long nowMillis=millis();’. So there, it must be expressed before ‘nowMillis’ can be used, but also for reasons of clarity, it is better to also express it right at the start of the module (the loop function in this case).

Thanks for the help. It seems like a long stupid question now that I see the answer. I knew that a variable “was not declared in this scope” if it was used in, say, void loop() but declared in a function like void func() or whatever. So I just started thinking that each scope meant a different block like:

void loop()  {
  code...
  ...
  ...code
}

or

void labelNameChosen()  {
  code...
  ...
  ...code
}

(I don’t know the name for these first level indentation { } blocks)

Yet I should have known better because I also knew that typing the variable inside a for loop like

for (int i = 0; i < 9; i++)  {

meant it only lived inside the loop.

I had this conflict between these 2 things I “knew” but never realized it until this verbose faceplant! :slight_smile: Oh well… I was, however, able to get my code working, so that’s a good thing.

Anyway, thanks again for taking the time to clue me in.

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