Esp8226 to esp8226 communication via same wifi

I have two esp8266 which are both connected to the same wifi network. I have one set with a small server with a button to turn on/off a device. This works perfectly. I can access the server from another device on my wireless network with the local ip or the host name given.

I have another esp8226 which is connected to the wifi fine. However, I can't get it to send the url I need to switch on/off the device (ex. 192.168.1.188/switch_on) This address works fine in a browser on the network.

This is what I have tried:

void lampsOn() {  
const char* host2= "192.168.1.188/switch_on";

HTTPClient http;            
WiFiClientSecure client;
client.setInsecure(); 
client.connect(host2, 80);
  
http.begin(client, host2);

    Serial.println("[Sending a request]");
    client.print(String("GET /") + " HTTP/1.1\r\n" +
                 "Host: " + host2 + "\r\n" +
                 "Connection: close\r\n" +
                 "\r\n"
                );

String payload;
Serial.print("Fetching From: ");
Serial.println(host2);
if (http.GET() == HTTP_CODE_OK)    
    payload = http.getString();     
    Serial.println(payload);  
    Serial.print("switching false");
}

I'm sure it is something simple, but I can't figure it out.

Thanks

What does this show?

It returns nothing on serial. Just a blank line.

Thanks

Not even the "switching false"?

I think you should add more code lines to help with debugging. For example what result code does http.GET() return, if it is not HTTP_CODE_OK ?

Does client.connect() return a status code? Or http.begin() ?

This is what I get on serial:

15.526 -> switching false[Sending a request]
14:19:18.515 -> Fetching From: http://testswitch/switch_on
14:19:18.515 -> 
14:19:18.515 -> switching false[Sending a request]
14:19:21.522 -> Fetching From: http://testswitch/switch_on
14:19:21.522 -> 
14:19:21.522 -> switching false[Sending a request]
14:19:24.514 -> Fetching From: http://testswitch/switch_on
14:19:24.514 -> 
14:19:24.514 -> switching false[Sending a request]
14:19:27.538 -> Fetching From: http://testswitch/switch_on
14:19:27.538 -> 
14:19:27.538 -> switching false

Ok, I guess that means http.GET() is returning HTTP_CODE_OK.

Can you get the server esp to send some kind of message back in the payload? Something like "received xyz". Check this is received when you send GET request from browser and other ESP

on the server side in the loop, I have server.handleClient() . Is this where I should be adding a message to respond to the client?

Thanks

Probably, yes. You should share the complete code, for the server and the client ESPs. You can probably use Client.println("received request to blah blah") to send back some useful data to help diagnose the problem.

There is a lot going on I know.... but here they are:

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            //http://firstswitch use this to access server on local network if don't use ip address
#include <ESP8266WebServer.h>  // creates web server
#include <NTPClient.h>   // gets time from online
#include <WiFiUdp.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h> // allows multiple AP the possibility to connect if the one does not
#include <ArduinoOTA.h>  // allows OTA uploads and host name drop down menu in port 
#include <EEPROM.h>  // memory storage for when power is removed or other things
#include <SDK_Version_Common.h>   // needed to send email out
#include <ESP8266mDNS.h>   // allows you to access server with web addres .local
#include <Espalexa.h>

volatile boolean deviceState = false; //boolean to determine if the output feeding relay is on (true) or off (false)
volatile boolean wifiNotConnected = false;

//int serialSwitch;  //only needed for testing output from serial 
const int debounceDelay = 100;  // length of debounce time for switch

const byte switch1 = D1;
const byte output = D8;

const char* host = "3 way test";  // set this to what you want to show up in the port tab when doing OTA uploads

void firstLightChanged(uint8_t brightness); // callback function to the espAlexa library

const long utcOffsetInSeconds = -18000;//this sets the time zone
byte Hour;
byte Minute;
byte Second;
byte hourToOpen = 12;
byte minuteToOpen = 8;
byte hourToClose = 18; 
byte minuteToClose = 8;
volatile boolean doorMovingUp = false;
volatile boolean doorMovingDown = false;
volatile boolean emergencyFlag;
volatile boolean problemEmailSent = false;

struct dataStruct

{
byte hourClosed;
byte minuteClosed;
byte hourOpened;
byte minuteOpened;
volatile boolean switchOn;
};

dataStruct theStruct; 

long currentMillis;
long emergencyOffMillis = 10000;
int delayMillis = 10000;

Espalexa espalexa;  // must have this as an instance maybe
EspalexaDevice* alexaState;  //name used to be able to change alexas state when an outside source switches

ESP8266WiFiMulti wifiMulti;  // for multiple wifi ssid's

ESP8266WebServer server(80); 

WiFiUDP ntpUDP;  // Define NTP Client to get time

NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);

void setup() {
  Serial.begin(115200);
  delay(100);

  wifiMulti.addAP("");   // add Wi-Fi networks you want to connect to
  wifiMulti.addAP("");
  wifiMulti.addAP("");

  Serial.println("Connecting ...");
  int i = 0;
  while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
    delay(250);
    Serial.print('.');
    if (millis() >= 30000){ // if not connected within about 30 seconds break out of while loop
      wifiNotConnected = true;
      break;
    }
  }
  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());               // Tell us what network we're connected to
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());            // Send the IP address of the ESP8266 to the computer

  ArduinoOTA.setHostname(host);  // this is the line needed to set the name of the device under the "port" column when selecting for OTA uploads host is a variable set it at top

  ArduinoOTA.begin();   //This is for OTA uploading sketch

   if (!MDNS.begin("3 way test")) {
    Serial.println("Error setting up MDNS responder!");
    while (1) {
      delay(1000);
      if (millis() >= 40000){ // if not connected within about 40 seconds break out of while loop
      break;
    }
    }
  }
  Serial.println("mDNS responder started");

  server.on("/", handle_OnConnect);
  server.onNotFound(handle_NotFound);
  server.on("/switch_on", handle_switch_on);
  server.on("/switch_Off", handle_switch_Off);

  server.begin();
  Serial.println("HTTP server started");

  server.onNotFound([](){
  if (!espalexa.handleAlexaApiCall(server.uri(),server.arg(0)))
  {
    server.send(404, "text/plain", "Not found");
  }
});

  Serial.println("HTTP server started");

    // Add service to MDNS-SD
  MDNS.addService("http", "tcp", 80);
  
  pinMode(switch1, INPUT);
  pinMode(output, OUTPUT);

   // attachInterrupt(digitalPinToInterrupt(switch1), isrSwitch, CHANGE);


   //espalexa.addDevice("switch1", firstLightChanged); // name for alexa  this will add a device, but you can't change state of alexa 
// espalexa.addDevice(Device_1_Name, firstLightChanged);
alexaState = new EspalexaDevice("3 way test", firstLightChanged);// this "coop door" is name for alexa if you don't use global variable string like above Device_1_Name
espalexa.addDevice(alexaState);

  espalexa.begin(&server);  // need this if doing alexa and a server

digitalWrite(output, LOW); //Device is off on startup
 deviceState = false; // set the state correct on startup

  EEPROM.begin(512);
    //defaultData();  
   checkDoorState();
}

void loop() {  
  currentMillis = millis();
  ArduinoOTA.handle(); // This is for OTA uploading sketch
  server.handleClient();
  espalexa.loop(); // needed to constantly check for alex updates
  MDNS.update();

    timeClient.update();
  Second = (timeClient.getSeconds());
  Minute = (timeClient.getMinutes());
  Hour = (timeClient.getHours());
  if (Hour > 12) {
    Hour = Hour - 12;
  }
  
     static unsigned long lastCheckWifi = 0;
   if (millis() - lastCheckWifi >= 300000)  //
  {
    lastCheckWifi = millis();
    checkWifi();
  }
  
    static unsigned long lastCheck = 0;
   if (millis() - lastCheck >= debounceDelay)  //50 ms debounce
  {
    lastCheck = millis();
    checkSwitch();
  }
}

void checkWifi(){
    if(wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
    Serial.print("checkWifi () called");
    reconnectWifi();
    }
}

void reconnectWifi(){
  Serial.print("ReconnectWifi () called");
  if (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
    wifiMulti.run();
    Serial.println("should be delayed to run wifi");
    delay(250);
    //wifiNotConnected = true;
  }
  else{
   // wifiNotConnected = false;
    Serial.print("wifi reconnected!");
  }
}

void checkSwitch(){
  byte switchState;
  static byte lastSwitchState;
  switchState = digitalRead(switch1);
   //check if this switch has changed state
  if (switchState != lastSwitchState)
  {
    //update to the changed switch state and perform actions on change
    lastSwitchState = switchState;
     if (deviceState == false){        //  if deviceState (light,fan,etc.) is false (off) turn relay on
              relayOn();
        }
        else{
          relayOff();                     //  if deviceState (light,fan,etc.) is true (on) turn relay off
        }
  }
}
void firstLightChanged(uint8_t brightness) {  // This is the callback function to the espalexa library.  If brigtness changes 255 or 0 relayON/relayOFF
    if (brightness == 255) {
      //Serial.print("switch ON");
      Serial.println(brightness);
      relayOn();
    }
    else 
       {
     // Serial.println("switch OFF");
      Serial.println(brightness);
      relayOff();
    } 
}

void relayOn(){
  
    digitalWrite(output, HIGH); // turn device on
    deviceState = true; //change state of device boolean
    Serial.println("turning on");
    alexaState -> setValue(255); // this sets the status of Alexa "on" if the manual switch is toggled so that alexa will report the correct state on APP
}

void relayOff() {  
  digitalWrite(output, LOW);// turn device off
  deviceState = false;// change state of device boolean
  Serial.println("turning off");
  alexaState -> setValue(0); // this sets the status of Alexa "off" if the manual switch is toggled so that alexa will report the correct state on APP
}

void handle_OnConnect() {
  server.send(200, "text/html", SendHTML(Hour, Minute, Second, theStruct.hourOpened, theStruct.hourClosed, theStruct.minuteOpened, theStruct.minuteClosed, theStruct.switchOn));
}

void handle_switch_on() {
  switchOn();
  server.send(200, "text/html", SendHTML(Hour, Minute, Second, theStruct.hourOpened, theStruct.hourClosed, theStruct.minuteOpened, theStruct.minuteClosed, theStruct.switchOn));
}

void handle_switch_Off() {
  switchOff();
  server.send(200, "text/html", SendHTML(Hour, Minute, Second, theStruct.hourOpened, theStruct.hourClosed, theStruct.minuteOpened, theStruct.minuteClosed, theStruct.switchOn));
}

void handle_NotFound() {
  server.send(404, "text/plain", "Not found");
}

void switchOn() {
  //digitalWrite(RelayUp, HIGH);
 // doorMovingUp = true;
 relayOn();
  emergencyOffMillis = millis() + delayMillis;
  theStruct.switchOn = true;
}

void switchOff() {
 // digitalWrite (RelayDown, HIGH);
 // doorMovingDown = true;
 relayOff();
  emergencyOffMillis = millis() + delayMillis;
  theStruct.switchOn = false;
}

String SendHTML(byte Hour, byte Minute, byte Second, byte hourOpened, byte hourClosed, byte minuteOpened, byte minuteClosed, volatile boolean switchOn) {
  String ptr = "<!DOCTYPE html> <html>\n";
  ptr += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
  ptr += "<title>Switch Trial</title>\n";
  ptr += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
  ptr += "body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
  ptr += ".button {display: block;width: 80px;background-color: #3498db;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
  ptr += ".button-on {background-color: #3498db;}\n";
  ptr += ".button-on:active {background-color: #2980b9;}\n";
  ptr += ".button-off {background-color: #34495e;}\n";
  ptr += ".button-off:active {background-color: #2c3e50;}\n";
  ptr += "p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
  ptr += "</style>\n";

  ptr += "<script>\n";
  ptr += "setInterval(loadDoc,1000);\n";
  ptr += "function loadDoc() {\n";
  ptr += "var xhttp = new XMLHttpRequest();\n";
  ptr += "xhttp.onreadystatechange = function() {\n";
  ptr += "if (this.readyState == 4 && this.status == 200) {\n";
  ptr += "document.body.innerHTML =this.responseText}\n";
  ptr += "};\n";
  ptr += "xhttp.open(\"GET\", \"/\", true);\n";
  ptr += "xhttp.send();\n";
  ptr += "}\n";
  ptr += "</script>\n";

  ptr += "</head>\n";
  ptr += "<body>\n";
  ptr += "<div id=\"nick\">\n";
  ptr += "<h1>Switch</h1>\n";
  ptr += "<p>The time is: ";
  ptr += Hour;
  ptr += ":";
  if (Minute < 10){
    ptr += "0";
    }   
  ptr += Minute;
  ptr += "::";
  ptr += Second;

  if (switchOn == true)
  {
    ptr += "<p>Switch is on</p><a class=\"button button-off\" href=\"/switch_Off\">switch Off</a>\n";
    
  }
  if (switchOn == false)
  {
    ptr += "<p>Switch Off</p><a class=\"button button-on\" href=\"/switch_on\">switch on</a>\n";
  }
  
  ptr += "</div>\n";
  ptr += "</body>\n";
  ptr += "</html>\n";
  return ptr;
}

void checkDoorState()
{
   EEPROM.get(20, theStruct);
}

/*void defaultData()
{
theStruct.hourClosed = 11;
theStruct.minuteClosed =59;
theStruct.hourOpened = 11;
theStruct.minuteOpened = 59;
theStruct.switchOn = true;

EEPROM.put(20, theStruct);
EEPROM.commit ();
}*/

Client:

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            //http://firstswitch use this to access server on local network if don't use ip address
#include <ESP8266WebServer.h>  // creates web server
#include <NTPClient.h>   // gets time from online
#include <WiFiUdp.h>
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h> // allows multiple AP the possibility to connect if the one does not
#include <ArduinoOTA.h>  // allows OTA uploads and host name drop down menu in port 
#include <EEPROM.h>  // memory storage for when power is removed or other things
#include <SDK_Version_Common.h>   // needed to send email out
#include <ESP8266mDNS.h>   // allows you to access server with web addres .local
#include <Espalexa.h>
#include "ESP8266HTTPClient.h"

volatile boolean deviceState = false; //boolean to determine if the output feeding relay is on (true) or off (false)
volatile boolean wifiNotConnected = false;
volatile boolean toggle = false;

//int serialSwitch;  //only needed for testing output from serial 
const int debounceDelay = 100;  // length of debounce time for switch

const byte switch1 = D4;
const byte output = D8;

const char* host = "Grady's Closet";  // set this to what you want to show up in the port tab when doing OTA uploads
void firstLightChanged(uint8_t brightness); // callback function to the espAlexa library

ESP8266WiFiMulti wifiMulti;  // for multiple wifi ssid's

ESP8266WebServer server(80); 

void setup() {
  Serial.begin(115200);
  delay(100);

  wifiMulti.addAP("");   // add Wi-Fi networks you want to connect to
  wifiMulti.addAP("");
  wifiMulti.addAP("");

  Serial.println("Connecting ...");
  int i = 0;
  while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
    delay(250);
    Serial.print('.');
    if (millis() >= 30000){ // if not connected within about 30 seconds break out of while loop
      wifiNotConnected = true;
      break;
    }
  }

  Serial.println('\n');
  Serial.print("Connected to ");
  Serial.println(WiFi.SSID());               // Tell us what network we're connected to
  Serial.print("IP address:\t");
  Serial.println(WiFi.localIP());            // Send the IP address of the ESP8266 to the computer

  ArduinoOTA.setHostname(host);  // this is the line needed to set the name of the device under the "port" column when selecting for OTA uploads host is a variable set it at top

  ArduinoOTA.begin();   //This is for OTA uploading sketch

   if (!MDNS.begin("Grady's Closet")) {
    Serial.println("Error setting up MDNS responder!");
    while (1) {
      delay(1000);
      if (millis() >= 40000){ // if not connected within about 40 seconds break out of while loop
      break;
    }
    }
  }
  Serial.println("mDNS responder started");
/*
  server.on("/", handle_OnConnect);  // these handle the different addresses that can be accessed by button clicks or typed in manual to go to a URL
  server.onNotFound(handle_NotFound);
  server.on("/open_Door", handle_open_Door);
  server.on("/close_Door", handle_close_Door);
*/
 // server.begin();
  Serial.println("HTTP server started");

    // Add service to MDNS-SD
  MDNS.addService("http", "tcp", 80);
  
  pinMode(switch1, INPUT_PULLUP);
  pinMode(output, OUTPUT);


digitalWrite(output, LOW); //Device is off on startup
 deviceState = false; // set the state correct on startup
}

void loop() {  
  ArduinoOTA.handle(); // This is for OTA uploading sketch
  //server.handleClient();
  MDNS.update();
  
     static unsigned long lastCheckWifi = 0;
   if (millis() - lastCheckWifi >= 300000)  //
  {
    lastCheckWifi = millis();
    checkWifi();
  }
  
    static unsigned long lastCheck = 0;
   if (millis() - lastCheck >= 30000)  //50 ms debounce
  {
    lastCheck = millis();
    //checkSwitch();
    lampsOn();
  }
}

void checkWifi(){
    if(wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
    Serial.print("checkWifi () called");
    reconnectWifi();
    }
}

void reconnectWifi(){
  Serial.print("ReconnectWifi () called");
  if (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above
    wifiMulti.run();
    Serial.println("should be delayed to run wifi");
    delay(250);
    //wifiNotConnected = true;
  }
  else{
   // wifiNotConnected = false;
    Serial.print("wifi reconnected!");
  }
}

void checkSwitch(){
  byte switchState;
  static byte lastSwitchState;
  switchState = digitalRead(switch1);
   //check if this switch has changed state
  if (switchState != lastSwitchState)
  {
    //update to the changed switch state and perform actions on change
    lastSwitchState = switchState;
      lampsOn();                     //  if deviceState (light,fan,etc.) is true (on) turn relay off        
  }
}

void lampsOn() {  
const char* host2= "192.168.1.188/switch_on";

HTTPClient http;            
WiFiClientSecure client;
client.setInsecure(); 
client.connect(host2, 80);
  
http.begin(client, host2);

    Serial.println("[Sending a request]");
    client.print(String("GET /") + " HTTP/1.1\r\n" +
                 "Host: " + host + "\r\n" +
                 "Connection: close\r\n" +
                 "\r\n"
                );

String payload;
Serial.print("Fetching From: ");
Serial.println(host2);
if (http.GET() == HTTP_CODE_OK)    
    payload = http.getString();     
    Serial.println(payload);  
    Serial.print("switching false");
}

Thanks

client.connect expects an IP address as the first argument, NOT a URL. The client.connect call is surely failing, but you don't even check the return value.

1 Like

So it should simply be "192.168.1.188"?

I assume to get the /switch_on, That would go in the GET request?

Thanks

I'm still at a loss... I can't seem to figure it out. All I want it to do is have the client esp8226 do the same thing I am doing with a web browser (send "192.168.1.188/switch_on") I don't necessarily need to get any information back. Should I be using the GET request?

Edit I think I just figured it out. I think it has something to do with the http vs https. Now, is it possible to set a Boolean true or false if the request was succesfully completed or not?

Thanks!

Yes, GET is a suitable approach.

Did you try any of the suggestions given? What was the result? Please post updated code with your reply.

The server would send some response back for the client to know if it had been successful:

server.send(200, ...

Code 200 indicates success. Other codes like 404 indicate there was a failure of some kind.

The client can check this code and act appropriately:

int result = http.GET(...);
if (result == HTTP_CODE_OK) ...
else ...

(Note that as per @RayLivingston 's suggestion, http.GET() needs a parameter).

Awesome! I think I've got that working as well! THANKS! One more question (maybe just one)

Is there a way for the server to send the client data when something happens on the servers end without the client sending a request? Or, is the proper way to do this for the client to make a request to see if anything has changed on the servers end periodically (every second)?

Example the client needs to know each time a boolean changes on the servers end. Can the server send that out when the boolean changes, or does the client need to constantly do GET request to see?

Thanks!

That would be very inefficient.

A better way would be for the two esp to be both clients and servers. There is no problem with doing both. That way, the esp connected to the button can send a request to the other esp when the button is pressed.

Ok, I didn't know you could do both simultaneously. So, If the one that I have set as the server now becomes the client and sends a GET request to the new server(previously client only), how do I set the boolean true/false in the new server? It will obviously need to be set when it receives the GET request, but how do I know? Now I am doing it with the HTTP_CODE_OK, but I know when to check for it because I know when the request is being sent and waiting for reply, but If I don't know when the request is going to be sent how do I check for it and set a boolean?

I hope that question makes sense.

Thanks!

The same way that the esp which is currently the server knows.

Let's avoid confusion and stop calling them "client" and "server" because now they will be both. Maybe call them "primary" (the esp controlling the device) and "secondary".

When the primary esp switches the device on or off, it will send a "switch_on" or "switch_off" GET request to the secondary esp. the secondary esp will update its Boolean and respond with status 200 to let the primary esp know that it received the message.

@PaulRB Ok, I think I have the concept and it is working..sorta. When the secondary sends a GET request to turn the device on to the primary, it then waits on a response to confirm that it was received and then the secondary should receive a GET request from the primary that the device has indeed been turned on. The problem I am seeing is each time this happens I get a couple of failed requests in my serial prints before I get the serial print that it actually went through (“on command received”).

When the primary turns the device on and sends the same GET request to the secondary, it goes through immediately and there is no failed requests. I will past a copy of some prints that show both the immediate response and the failed response followed by a successful print.

17:25:33.022 -> [HTTP] begin...
17:25:33.022 -> [HTTP] GET...
17:25:38.331 -> [HTTP] GET... failed, error: read Timeout
17:25:45.362 -> I recieved ON command
17:25:47.375 -> I recieved ON command
17:25:47.375 -> I recieved OFF command
17:25:54.096 -> I recieved ON command
17:25:59.350 -> I recieved OFF command
17:27:33.002 -> [HTTP] begin...
17:27:33.002 -> [HTTP] GET...
17:27:38.067 -> [HTTP] GET... failed, error: read Timeout
17:27:45.092 -> I recieved ON command
17:27:47.122 -> I recieved ON command
17:28:03.009 -> [HTTP] begin...
17:28:03.009 -> [HTTP] GET...
17:28:08.021 -> [HTTP] GET... failed, error: read Timeout
17:28:15.051 -> I recieved OFF command
17:28:19.068 -> I recieved OFF comman

The prints that are back to back are coming from the primary turning the device on/off and then sending the GET request. The errors occur when the secondary sends the GET request and the primary is sending a response back after the device is changed.

Thanks!

No, that's not necessary, and may be what's causing the timeout error.

The secondary already has confirmation because it received HTTP_CODE_OK back from the primary in response to its GET request. The primary does not need to send a GET request to the secondary after that.

The primary only needs to send GET request to the secondary when the device was turned on/off by the primary.