TCP Server and Client Example Socket Programs "D7-ON" please

Could someone please write bare bones example socket programs for both the TCP Server and the TCP Client that just communicate with a string sending “D7-ON” and “D7-OFF”, and without all the debug information. We need the micro-controller version of “Hello World”. The example snippets in the Spark documentation does not show the whole story.

There is so much confusion about this. VoodooSpark seems to have it all working but we need simple examples to get things working for our own projects.

TCP Client needs an example Nodejs socket.io server that can send “D7-ON” and “D7-OFF” and the TCP Server needs someone to show how to communicate with it, perhaps through telnet or some kind of modern browser websocket. I have a hard time believing that TCP Client and TCP Server only work on a local network! I am fine making a youtube video of how to do these things, but I can’t make the video if I can’t get it working.

I have got telnet working using the following code (Thanks Brian Ogilvie @bko for solving that on another post). Note: I am using telnet putty.exe and have the telnet session set to passive, and the Telnet window set to never close, port 23 and use a web link to access the core IP using this link (replace core-id and access-token as needed)

<a href="https://api.spark.io/v1/devices/{core-ID}/Address?access_token={acces-token}">Address</a>

Code to load to the spark is as follows:

TCPServer server = TCPServer(23);
TCPClient client;

char addr[16];

char incoming;

void setup()
{
    
   pinMode(D7, OUTPUT);
   digitalWrite(D7, HIGH); 
   delay(1000);
   digitalWrite(D7, LOW); 
   delay(1000); 
   delay(1000);
   delay(1000);  // give a few seconds to reflash the core if it gets unresponsive on startup
   digitalWrite(D7, HIGH); 
   delay(1000);
   digitalWrite(D7, LOW); 
    
    
  server.begin();
  IPAddress localIP = WiFi.localIP();
  sprintf(addr, "%u.%u.%u.%u", localIP[0], localIP[1], localIP[2], localIP[3]);
  Spark.variable("Address", addr, STRING);
}

void loop()
{
  client = server.available();

  if (client.connected()) {
    client.println("Connected to Spark!");
    client.println(WiFi.localIP());
    client.println(WiFi.subnetMask());
    client.println(WiFi.gatewayIP());
    client.println(WiFi.SSID());
    client.println(">");

    while (client.connected()) {
      while (client.available()) {
          
        incoming = client.read();
        client.write(incoming);  // great to show on telnet what has been printed
        if (incoming == 'A'){   digitalWrite(D7, HIGH); }
        if (incoming == 'B'){   digitalWrite(D7, LOW); }
      }
    }
  }
}

My next step is how to send telnet style commands from a web page. I will try both AJAX and websockets, but would appreciate some working code if anyone has done it before.

So I got almost real time communication of information to the core using the following server.ino and client web page

TCPServer server = TCPServer(80);
TCPClient client;

char   addr[16];
char   myInput[30];
char   myIncoming;
int    myLoop1;
String myInStr;


void setup()
{
    
   pinMode(D7, OUTPUT);
   digitalWrite(D7, HIGH); 
   delay(1000);
   digitalWrite(D7, LOW); 
   delay(1000); 
   digitalWrite(D7, HIGH); 
   delay(1000);
   digitalWrite(D7, LOW); 
   delay(1000); 
   delay(1000);
   delay(1000);  // give a few seconds to reflash the core if it gets unresponsive on startup
   digitalWrite(D7, HIGH); 
   delay(300);
   digitalWrite(D7, LOW); 
    
    
  server.begin();
  IPAddress localIP = WiFi.localIP();
  sprintf(addr, "%u.%u.%u.%u", localIP[0], localIP[1], localIP[2], localIP[3]);
  Spark.variable("Address", addr, STRING);
  Spark.variable("myIn",  myInput, STRING);  
  Spark.variable("myLoop1", &myLoop1, INT);
}


void loop() {
    // listen for incoming clients
    client = server.available();
    if (client) {

      
        myLoop1 = 0;
        myInput[0] = '\0';

        boolean currentLineIsBlank = true;
        while (client.connected()) {
            

            if (client.available()) {



          
                myIncoming = client.read();       // read from the http request

               if (myLoop1 < 29 ){                 // http request should be much longer than 29 characters!
                   myInput[myLoop1] = myIncoming; // put the character into an array
                   
                } else {                           // read enough information from the http request
               
                    myInput[myLoop1] = '\0';      // helps make a char array compatible with a string.
      
                    myInStr = myInput;
                    myInStr.toUpperCase();
                          
                   if (myInStr.indexOf("D7-ON") >= 0){   digitalWrite(D7, HIGH); }  
                   if (myInStr.indexOf("D7-OFF") >= 0){  digitalWrite(D7, LOW); }  
                   

                   
                   }
              
                 myLoop1++;
                
                       
                       
                      
                if (myIncoming == '\n' && currentLineIsBlank) {

                   
                    //client.println("<H1>Hello World.</h1>");   // use for debugging to check if http request can get returned
                    
        
                    delay(1);
                    break;
                }
                if (myIncoming == '\n') {          // you're starting a new line
                    currentLineIsBlank = true;
                }
                else if (myIncoming != '\r') {     // you've gotten a character on the current line
                    currentLineIsBlank = false;
                }
                

            }
        }
        // give the web browser time to receive the data
        delay(1);
    }
    client.flush();
    client.stop();
}










/*

MAKE THIS HTML PAGE TO COMMUNICATE WITH YOUR CORE



<a  target="myI" href="https://api.spark.io/v1/devices/{CORE-ID}/Address?access_token={ACCESS-TOKEN}" >Address</a><br>


<a  target="myI" href="http://192.145.1.65?D7-ON" >D7-ON</a>...
<a  target="myI" href="http://192.145.1.65?D7-OFF" >D7-OFF</a><br><br><br>

<iframe name="myI" width=500 height=400></iframe>















The serial printout looks like

192.145.1.65
GET /?D7-ON HTTP/1.1
Host: 192.145.1.65
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,* / *;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2231.0 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8




*/

The github site is at https://github.com/hpssjellis/spark-core-socket-client-or-server which contains a better web page that uses localstorage to store your core ID and Access Token as well as the Spark Core IP Address.

Could someone please take a look at the code. It works really quick at turning on D7, but there is a time lag before it will take a second command. I am not sending any reply to the website so, If we could close the connection faster I think this would be a fast way to communicate with the core. Note that I am not using AJAX or Websockets at all.

Thanks to @harrisonhjones and @bko for important parts to this code.

4 Likes

Hey Guys: @peekay123 @ScruffR @kennethlimcp @mdma we worked well with the last issue at https://community.spark.io/t/create-time-out-for-spark-connect/10351 can we put a bit of time into this issue?

Basically, I am trying to make near real time communication between the Core and a webpage (or Phonegap Mobile App), so I can drive a rover or fly a drone, without spamming the Spark Cloud. My last bit of code works fine except there is a bit of time lag AFTER the call. (D7 lights almost immediately, the fastest I ever got from the cloud was about a 300 ms delay). I think I can get rid of the present returning delay using AJAX.

The github site is at https://github.com/hpssjellis/spark-core-socket-client-or-server It inlcudes the .ino an unsafe web page and a safer webpage using local storage to save your Spark credentials. Any of you guys have any suggestions?

You can consider turning off connection to the :cloud: if you need near real-time communication so that process the :cloud: messages does not slow things down.

Also, it might be better to sit on this for a little more until the new firmware is released as loop() executes way faster with the improvements.

1 Like

@rocksetta, I agree with @kennethlimcp regarding the Cloud connection. If you disable the Cloud in your code don’t forget that Spark.variables() will no longer work.

I looked at your code and I think it can be cleaned up some. One thing I noticed right away is the use of client.flush() which we know does not actually flush the CC3000 receive buffer. This can be done using:

while(client.available()) char c=client.read();

I believe there is a more efficient way to parse your incoming data, similar to the way you would do it Spark.function. Your entire receiver could be a function call that gets a pointer to your receive String object. Upon return you parse your receive String using string methods. Take a look at the Tinker code to see how the command String is parsed.

One method I use to avoid dynamic string memory allocation is to pre-allocate space using the reserve() method:

    String myInStr;
    
    setup() {
      myInStr.reserve(100);  //reserves 100 chars of String space

...
    }
2 Likes

Wow, great ideas @kennethlimcp and @peekay123, I am including them on the Github site, will test later. Can someone expand on how to turn off the cloud connection. It almost sounds like my old method may work fast without using this Core Server idea. My old webpage to Core control code is at

You’ve already turned the cloud connection off in your other thread :wink:
SYSTEM_MODE(SEMI_AUTOMATIC) or SYSTEM_MODE(MANUAL) or Spark.disconnect()

For some more speed you could tweak @peekay123 's flush proc this way

while(client.read() >= 0);
// I've not tested with `client` but with `Serial` - so don't flame if it doesn't ;-)
// But looking at the code, this way you'll save a job lot of instructions that
// make up 'client.available()'  

It’s a very tiny speedup, but combined with some other tweaks (e.g. implicit myLoop1++, …) it might become noticeable :wink:

1 Like

Great suggestions @peekay123 and @ScruffR, both compile and work. I found the problem with my Ajax calls. My previous code stopped at the first line break and blank line, which was fine for GET calls

Hello Computer
GET /?D7-ON HTTP/1.1
Host: 195.163.1.80
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Use64) ecko0 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

...end...

but Ajax based POST calls look like

Hello Computer
POST / HTTP/1.1
Host: 195.163.1.80
Connection: keep-alive
Content-Length: 16
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2231.0 Safari/537.36
Origin: null
Content-type: application/x-www-form-urlencoded
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8

myNamePost=D7-ON

So the important stuff comes after the Linebreak and blank line, which my code was ignoring. Not got it fully working but I think it can be done. Thanks for the help. Hopefully things still work after version 4.0 comes out with the faster main loop.

1 Like

Good idea @kennethlimcp, I did not realize that Spark.disconnect() left the Wifi working. Have not tested it but this code should get things going:

SYSTEM_MODE(SEMI_AUTOMATIC);


char   addr[16];


void setup() {

   pinMode(D7, OUTPUT);  
   digitalWrite(D7, HIGH); 
   Spark.connect();            // Really important to connect
   
   IPAddress localIP = WiFi.localIP();
   sprintf(addr, "%u.%u.%u.%u", localIP[0], localIP[1], localIP[2], localIP[3]);
   Spark.variable("Address", addr, STRING);
  
   delay(30000);              // give 30 seconds to either reflash the Core
                              // or to get Core IP from the cloud
                              // Get your IP using this code in a web page (security leave it on your computer)
                              
// <a  target="myI" href="https://api.spark.io/v1/devices/{CORE-ID}/Address?access_token={ACCESS-TOKEN}" >Address</a><br>

                              // or just put this in your browser
// https://api.spark.io/v1/devices/{CORE-ID}/Address?access_token={ACCESS-TOKEN}"                              

   digitalWrite(D7, LOW); 
   Spark.disconnect();        // Disconnect from the cloud but keep Wifi
    
}


void loop() {
    
   // your HTTP server code 
    
}
1 Like

Got the near-real time working but with some ugly hack to the AJAX request. (I did a page reset inside the AJAX). Just clued in to why the AJAX fails and that is; I have to print out a correctly formed HTTP response header. Strangely having a really hard time finding out how that header should look. Any one have any ideas? It should have HTTP and content length and then send the reply. Then AJAX will close.

P.S. I had to eventually give up on serial.println(""); as it caused a ton of Core crashing, eventually thought it should work, got rid of the serial, and D7 lite up immediately.

Found other information here

the link here seems interesting
http://blog.ubidots.com/measure-temperature-and-humidity-with-your-spark-core

and

UPDATE: May 9th.
The response header to a POST request should look something like

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: 8

done-now

Very frustrating. I am either getting a good AJAX response but no D7 connection, or I am getting D7 turning on, but AJAX does not finish. Leaning towards my AJAX timer page reset as a bad solution.

I don't think server.println("anything"); works for AJAX, server.write('C'); does seem to work.

So the github site at GitHub - hpssjellis/spark-core-socket-client-or-server: Attempt to test using the spark core or photon as a client or server for fast communication to light D7 LED does work, everything is a bit of a mess. I found code sort of like XMLHttpRequest().abort() which solved the page refresh issue. Still a slight time lag after the call, so really, things are not much better than the non-ajax situation I set up for GET calls.

I will try to clean up the code.

Got it working! I think I could drive my Rover (or maybe a drone) with this code.

Thanks @peekay123 @ScruffR @kennethlimcp @mdma and @bko. You might want to have a look at this @zachary. The real tragedy is my school wants to purchase Lego Mindstorms EV3 for student Robotics competitions and probably will not give me any money for a class set of Photons.

What I have working is a simple way to send multiple commands to the Core without Spamming the Cloud. My delay for each command is about 50-70 ms, much better than 300-1200 ms using the cloud. The github site is at:

I will put my safer local storage method of saving the Core Credentials there and will try to get Ajax working with it, but I had to use some hacks to get the POST command working, this latest code uses GET and seems to work fine without Ajax.

This can even be activated from the browser URL. Remember that this is for students projects so I have basically thrown Core security out the window.

// By Jeremy Ellis twitter @rocksetta or http://www.rocksetta.com
TCPServer server = TCPServer(80);
TCPClient client;

char   addr[16];
char   myInput[30];
char   myIncoming;
int    myLoop1;
String myInStr;

void setup()
{
   myInStr.reserve(30);  //reserves 30 chars of String space 
   pinMode(D7, OUTPUT);

   IPAddress localIP = WiFi.localIP();
   sprintf(addr, "%u.%u.%u.%u", localIP[0], localIP[1], localIP[2], localIP[3]);
   Spark.variable("Address", addr, STRING);
   
   // call this from a web page using
   //<a  target="myI" href="https://api.spark.io/v1/devices/{CORE-ID}/Address?access_token={ACCESS-TOKEN}" >Address</a><br>
   // or from you browser using
   //https://api.spark.io/v1/devices/{CORE-ID}/Address?access_token={ACCESS-TOKEN}
   

   pinMode(D7, OUTPUT);
   digitalWrite(D7, HIGH); 
   delay(15000);                 // a little bit of time to re-flash core, check cloud etc.
   digitalWrite(D7, LOW); 
    
   server.begin();

}

void loop() {
   if (client.connected()) {     
        myLoop1 = 0;
        myInput[0] = '\0';

        while (client.available()) {
            myIncoming = client.read();         // read from the http request
            if (myLoop1 < 29 ){                 // http request should be much longer than 29 characters!
                myInput[myLoop1] = myIncoming;  // put the character into an array
                } else {                        // have read enough information from the http request
               
                    myInput[myLoop1] = '\0';    // helps make a char array compatible with a string.
                    myInStr = myInput;
                    myInStr.toUpperCase();
                          
                    if (myInStr.indexOf("D7-ON")  >= 0){ digitalWrite(D7, HIGH); }  
                    if (myInStr.indexOf("D7-OFF") >= 0){ digitalWrite(D7, LOW);  }  
                    if (myInStr.indexOf("DARK")   >= 0){ RGB.brightness(1);      }  
                    if (myInStr.indexOf("BRIGHT") >= 0){ RGB.brightness(250);    }  
                   
                    while(client.read() >= 0);    // ignore the rest of the http request
                    client.stop();                // shut down the client for next connection
                   }
                 myLoop1++;
        }  
    } else {     
        client = server.available();        // if no client is yet connected, check for a new connection
      }
}   




/*

--Cut this into a web page only for your computer. Use the localStorage webpage for anything on the actual web.
What is really cool is that you can call this line directly from your browser to check something on your Spark Core or Photon

http://192.168.1.2?D7-ON





So your web page simply needs, to find your IP using <br>

<a  target="myI" href="https://api.spark.io/v1/devices/{CORE-ID}/Address?access_token={ACCESS-TOKEN}" >Address</a><br>



And change the IP in the following javascript<br>

<a id="myOn" target="myI" href="http://192.168.1.2?D7-ON" >D7-ON</a>...
<a id="myOff" target="myI" href="http://192.168.1.2?D7-OFF" >D7-OFF</a>...<br>

<iframe id="myIframe" name="myI" width=200 height=100></iframe>





For a bit fancier<br>
<input id="myOn2" type=button value="D7-ON-2" onclick="{
   document.getElementById('myIframe').src = 'http://192.168.1.2?D7-ON'
   setTimeout(function(){ document.getElementById('myIframe').src = 'generic.html' }, 17); 

}"><br>

<input id="myOff2" type=button value="D7-Off-2" onclick="{
    document.getElementById('myIframe').src = 'http://192.168.1.2?D7-OFF'
    setTimeout(function(){ document.getElementById('myIframe').src = 'generic.html' }, 17); 
}"><br><br>

Note: you need to make a simple web page called generic.html for the above to work.

*/
2 Likes

@rocksetta, how many is a class set of Photons?

I am going to ask my Principal for 15 Photon Starter sets (30 students, 2 students per photon starter set), but if money is tight even 15 Photons is better than nothing, actually 15 Cores would be awesome. We can grab LED’s and motors from donated toys.

Great! You should check out the voodoospark firmware on github as well! At least it contains good tips/tricks, and it makes setting up the local connection a little less manual.

Sorry, not near a computer right now, but search github for voodoospark. It’s created by @voodootikigod.

1 Like

Continuing the discussion from TCP Server and Client Example Socket Programs "D7-ON" please:

@zachary That was how this thread got started. I emailed Rick Waldron of voodoospark and he replied that "Spark.io and VoodooSpark need to be on the same WiFi network to communicate with each other". Which explains why I could not get it working. Come to think of it, I bet VoodooSpark works great over the internet but I could not properly send the 3 digit Byte code. Anyone got any suggestions? For my students to make Mobile Apps connected to Spark Devices I need to communicate from a Web page (We use Adobe Phonegap to make iOS and Android Apps from regular web pages).

My code works, is sort of fast, but very easy for a kid to understand:

In the .ino file

if (myInStr.indexOf("D7-ON")  >= 0){ digitalWrite(D7, HIGH); }  

In the Web Page (using a fake IP)

<a id="myOn" target="myI" href="http://192.168.1.2?D7-ON" >D7-ON</a>...

It could be optimized, possibly using streaming data by someone who understands such things, but that is for another day.

P.S. @kennethlimcp Spark.disconnect(); actually kills the WiFi connection both if I am on automatic mode or semi-automatic. Link here. Possibly another DOC that needs to be changed. I tested it using the code from my server.

if (myInStr.indexOf("CLOUD-OFF")  >= 0){ Spark.disconnect(); }

@rocksetta that's odd. When I do Spark.disconnect() my WiFi connections keeps running (in SEMI_AUTOMATIC atleast)
How do you experience the WiFi dropout? Does the connection come back by itself?

Good question, I may need to leave it on longer in semi-automatic. All I see is flashing green and I can’t send any more information to my IP address. What colors from the RGB LED do you get when you Spark.disconnect();

When I do, my Core goes into breathing green.

But I’m running some UDP things in my project. I’ll try a minimal sketch to confirm the behaviour some time soon :wink:

You are correct @ScruffR, when I move Spark.disconnect(); outside of my main TCP server loop it switches to breathing cyan immediately and my server still works. I still have some tweaking to do since the time needed to get the IP from the server is a bit unpredictable. Sometimes happens within the first few seconds, other times I get an IP of 0.0.0.0 for a few minutes. At least things are working. Thanks.

1 Like