Tiny WebServer code

Continuing the discussion from Will there be a Spark Core II:

2 Likes

A few people now have been talking about serving tiny webpages from the core, so here is a very basic http server based on a community member’s app (with permission):

TCPClient webClient;
TCPServer webServer = TCPServer(80);
char myIpAddress[24];

void setup() {
    Spark.variable("ipAddress", myIpAddress, STRING);
    IPAddress myIp = Network.localIP();
    sprintf(myIpAddress, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);
    
    webServer.begin();
}

void loop() {
    if (webClient.connected() && webClient.available()) {
        serveWebpage();
    }
    else {
        webClient = webServer.available();
    }
}

void serveWebpage() {
    //TODO: read in the request to see what page they want:
    //TODO: retrieve larger content from flash?
   
    webClient.println("<html>I'm serving a webpage!</html>\n\n");
    webClient.flush();
    webClient.stop();
    delay(100);
}
5 Likes

Hi Dave,

Thanks for posting this and not to be lazy but, do I simply paste this in the core and access it from my local network using the IP assigned to the Core by my router ?

Or, do have to insert the Core IP in this code for it to work ?

Your help greatly appreciated.

Bobby

1 Like

Hi @spydrop,

Yes! You can just paste this into a new project file on the build IDE. If you grab your core’s IP address via the variable, or from your router, you should be able to point a web browser at it.

Thanks,
David

Dave -

Thanks and I feel so silly. When I was trying IP’s in my browser earlier, I looked at the DHCP Router Table and saw 192.168.1.101 my router IP so I never tried iit. Spark Core is on .101

AND IT WORKS !!! A Tiny Webserver running on my Spark Core :smile:

OMG- Am I going to have fun this weekend.

Will post some screen shots here.

Thanks Again

Bobby

1 Like

I will work on better Gif animation this weekend.

So my question is. Since Spark Core can run a very simple light weight webserver (Arduino can’t do) and the Spark Core obtains an IP; And once that IP is obtained it can be change to a static assigned IP.

Once there is a static IP from the router and using DNS forward service and multiple iFrames on the Spark Core webserver then hook up several IP Cameras and have them parse in to the Spark Core Webserver page and we are now protected by a Spark Core Home Security System.

Just having a little fun and I am not trying to really take over the world; its much worse :smile:

Cool, I’m guessing you put your Spark Core into one of these:
http://makezine.com/projects/internet-kill-switch/

Yes, the kill switch is part of what the Spark will now empower. My Magic Stop device can be controlled by an Adafruit 4 button remote; a Spark Core (Now Smartphone, Tablet, Wifi) and an Arduino all at the same time. No other device provides multi-control option like this but, they could.

On the phone line I am doing something very nostalgic. The very device that allowed people to log in to Internet 1.0 --> an internal computer modem is being used as a telephone interface. All it takes is my device and 4 wires attached to most modems. The modem is not plugged in to a computer :smile: Jumpers are on the Magic Stop so a person can use PNP Positive Supply; NPN Negative pull down for the modem relay; with jumpers to run modem at either source voltage 6-12v or 5v regulated supply that will power the Spark too.

The very top light blue card on my Magic Stop below is a 20 second voice Record/Play module from Electronics123.com. It is used to play a message to unwanted callers or put them on hold; with music.

A person can use this device to restrict child’s access to Phone (Landline or VOIP) and/or Internet Access. Now with the Spark the device can be controlled from anywhere in the world. They can also use it to take their whole house off the Grid (Cable signals are next) for the time they need to have “100% Privacy with absolute convenience”. Something that had been taken away from us over the last 10 years.

Here is what I call Magic Stop. And the technology for use in a home or business is US Patent Pending. I am hoping to have a China Company produce it world wide and I will maintain distribution in the US.

http://MagicStop.net

1 Like

Ok feeling like a n00b right now… can’t make this work. It’s definitely just the millis() code part that fails. I’m currently running this while connected to my iPhone wifi hotspot so it’s hard to debug -_-

char buffer[256];

void serveWebpage() {
    //TODO: read in the request to see what page they want:
    //TODO: retrieve larger content from flash?
    webClient.print("<html><h1>BDub's Server Uptime: ");
    
    //webClient.print(millis()/1000); // This doesn't work
    
    sprintf(buffer,"%d",millis()/1000); // This doesn't work either
    webClient.print(buffer);
    
    webClient.println(" seconds</h1></html>\n\n");
    webClient.flush();
    webClient.stop();
    delay(100);
}

Cool @spydrop, that’s a lot more complicated than I thought… but you are doing a lot more than I thought as well. Good luck with the patent. Those take forever! I fortunately have two utility patents :wink: But I don’t see them as a way to make money… well not directly. They are more like, “Look at my cool IP”.

I’m hoping I can finish the Patent Pending prior to the year is up.

I do have a question about modding your webApp code that I am modding.

I have 4 buttons working that turn on D3, D4, D5 & D6 or All of them with one button.

I am using 4 functions to control the pins and when I click one button I have to click the next button twice before it will activate the next function.

If I click the same button on / off it works fine.

Do I need to reset or clear the function after a button is pressed ? will I need to do it in IDE or Java function ?

Ok figured it out… it just needed some delays… which sounds like our old Serial1 issues. Kind of interesting to run the core as a TCP Server while it’s also connected to my iPhone’s Wifi Hotspot.

#include "application.h"

#include "LiquidCrystal.h"

TCPClient webClient;
TCPServer webServer = TCPServer(80);
char myIpAddress[24];

void serveWebpage();

// Make sure to update these to match how you've wired your pins.
// pinout on LCD [RS, EN, D4, D5, D6, D7];
// pin nums LCD  [ 4,  6, 11, 12, 13, 14];
// Shield Shield [RS, EN, D4, D5, D6, D7];
// Spark Core    [D3, D5, D2, D4, D7, D8];
LiquidCrystal lcd(D0, D1, D2, D3, D4, D5);
bool done = false;
void setup() {
  IPAddress myIp = Network.localIP();
  sprintf(myIpAddress, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]);

  // set up the LCD's number of columns and rows: 
  lcd.begin(16,2);
  // Print the Core's IP Address to the LCD.
  lcd.print(myIpAddress);

  webServer.begin();
}

void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 1);
  // print the number of seconds since reset:
  lcd.print(millis()/1000);

  if (webClient.connected() && webClient.available()) {
    serveWebpage();
  }
  else {
    webClient = webServer.available();
  }
}

void serveWebpage() {
  webClient.print("<html><body>BDub's Server Uptime: ");
  delay(10);
  webClient.print(millis()/1000);
  delay(10);
  webClient.println(" seconds</body></html>\n\n");
  delay(10);
  webClient.flush();
  webClient.stop();
  delay(100);
}

OK, step into my code ramblings… so I was thinking those delays are a pain in the … so there has to be a better way. I’m pretty sure the reason the delays are helping things is because it ensures the data is being transmitted before the flush() / stop() occurs.

So a better way, not necessarily most intuitive way, is to use the status() method to detect when the socket is inactive:

#define ACTIVE 1

void serveWebpage() {
  webClient.print("<html><body>BDub's Server Uptime: ");
  webClient.print(millis()/1000);
  webClient.println(" seconds</body></html>\n\n");
  while(webClient.status() == ACTIVE); // wait until socket is not active
  webClient.flush();
  webClient.stop();
}

This works, but I’m still not happy with the way it looks. I know I should add a time out on the while() loop, but just so we understand the simplest working code I left it out for the moment. If you can think of a better way to do this, please comment.

I noticed the same issue with an HTTP client. Without delays, Apache would give me a 400 error. With delays, I got a 200. Another issue I ran into was that the Apache server wanted me to send each full line with a single .println(), and each of those lines had to be a char array and not a String. I had to spend a few minutes watching ngrep packets from a web browser (200 OK), telnet session (200 OK), and the :spark: (400 Bad Request). It was an old Apache 1.x dev server at work, so it could just be crotchety.

Hi, @Dave thanks for the sample server, @BDub I have tried your webClient.status() change and it won’t work for me - It never exits the while loop. Using delay works for testing but checks to ensure everything is sent would be a preferred approach. I am compiling using the cloud so was wondering if some of the recent commits are required for this work. Any ideas ?

Hmm, yes that probably going to matter. I’m using this master.


which is many commits ahead of compile-server2 but at least ten commits behind the newest commit.

BTW I’m working on a port of a very nice webserver. Got it to compile last night. Need to do a bunch of testing.

Have anyone figured out a smart way to have the spark host html-files in a way that you don’t need to write it into the code, line by line in print commands? Its becoming abit of a hassle when the html code is increasing. With an arduino and a sd card reader the task is much easier. With the spark core (without adding a sd card reader) I guess that some of the on-board storage can be used for this, but unsure how to access this efficiently. Another idea I had was to host the html code as a public drop-box file (or in any other way available online) and then do a request from the core, and phrase the response to the cores client. Have anyone done anything similar or have any ideas to share?

I am basically trying to do something along the lines of this: http://startingelectronics.com/tutorials/arduino/ethernet-shield-web-server-tutorial/SD-card-gauge/

tomas, choosatron ported an SDFat library a while back which BDub and I have been using without problems. I suspect BDub is working on a port of a webserver that makes use of an SD (just a guess) so stay tuned!