Serving a Webpage

TL;DR - jump to the final code.

In this chapter we'll cover the basics of serve a Webpage.

For this example, we don't need any wiring.

Setup

New ThingsSDK Project

The first step is start a new Things project. Plug your device into your desired USB port. Then in your terminal run:

$ thingssdk new HTTP_API

You should see this in your console:

thingssdk new Webpage
? Select a port: (Use arrow keys)
? Select a port: # This will show your port
? Select the baud rate: (Use arrow keys)
? Select the baud rate: 115200
To install the project dependencies:
    cd Webpage && npm install
To upload to your device:
    cd Webpage && npm run deploy
Project successfully created

Follow the prompts to get our dependencies installed:

$ cd Webpage && npm install

When everything is installed, $ npm run dev sends the code to your device and runs it. I like to perform a quick sanity check with the default hello world code just to make sure everything is correctly connected.

$ npm run dev

The Code

Connect to WIFI

There is an entire chapter of this guide dedicated to how to connect to a WIFI network.

Here's some boilerplate code:

// main.js

const wifi = require('Wifi')


// wifi.connect(ssid, options object, callback)
wifi.connect(WIFI_NAME, { password: WIFI_PASSWORD }, error => {
  if (error){
      console.error(error)
  }else{
      console.log(`Connected to: ${ wifi.getIP().ip }`)
      //you are connected to WIFI!
  }
})

Create the web server

Ok, now we are connected to Internet, let's begin to write the real code! To create a new server, we need to use the http library.

let handleRequest=((req,res)=>{
    console.log("Somebody is connected!");
})
require("http").createServer(handleRequest).listen(80);
console.log(`I'm ready on ${ wifi.getIP().ip }:80`);

This will permit the Espruino to listen to port 80 on his assigned IP address (we are using wifi.getIP() to know the IP address).

Build a response

Right now we don't serve a response, so the client will try to load the website forever. The handleRequest function has 2 object params similar to any node.js server, Request and Response. Request contains the URL, the method used, and the paramethers sent to it, while the Response permits to serve data to the client. For example, if we want to return a simple HTML page, we should do something like this:

const handleRequest=(req, res) => {
  res.writeHead(200, {'Content-Type': 'text/html'});
  res.end(`<html>
          <head>Test Page</head>
          <body>
              <h1>Hello World!</h1>
          </body>    
      </html>`);
}

This will return "Hello World!".

Handle different methods

Let's create a simple form that will send the name of the user to another page. We need to differentiate between the GET request (where we will display the form) and the POST request (where we will get the user name and show it on a different page.

const handleRequest=(req, res) => {
  res.writeHead(200, {'Content-Type': 'text/html'});
  if(req.method=="GET"){
      res.end(`<html>
           <head>Test Page</head>
           <body>
             <h1>Write your name here:</h1>
              <form method="POST" action="/">
                <input type="text" name="name_user">
               <input type="submit" value="Send">
             </form>
           </body>    
      </html>`);     
  }else{
      let params=parseRequestData(req.read());
        let name=obj.name_user;
         res.end(`<html>
          <head>Test Page</head>
          <body>
            <h1>Hello, ${name}</h1>
          </body>    
      </html>`);     
  }
}

//function to return an object with all request paramethers 
const parseRequestData =(str)=>{
  return str.split("&").reduce(function(prev, curr, i, arr) {
    var p = curr.split("=");
    prev[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
    return prev;
  }, {});
}

Keep the HTML/CSS/JS slim!

Remember: you have a limited amount of memory on Espruino. Everytime you add new fancy CSS attributes or lots of JS functions, you are using memory and this can drive to a Out Of Memory! error. Be sure to put some print(process.memory()); inside your code to monitor the amount of free memory still available.

Final Code

const wifi = require('Wifi')
const WIFI_NAME= "...";
const WIFI_PASSWORD= "...";

function main(){
  // wifi.connect(ssid, options object, callback)
  wifi.connect(WIFI_NAME, { password: WIFI_PASSWORD }, error => {
    if (error){
     console.error(error)
    }else{
        console.log(`Connected to: ${ wifi.getIP().ip }`)
        require("http").createServer(handleRequest).listen(80);
    }
  })
}

const handleRequest= (req, res) =>{
  res.writeHead(200, {'Content-Type': 'text/html'});
  if(req.method=="GET"){
      res.end(`<html>
           <head>Test Page</head>
           <body>
             <h1>Write your name here:</h1>
              <form method="POST" action="/">
                <input type="text" name="name_user">
               <input type="submit" value="Send">
             </form>
           </body>    
      </html>`);     
  }else{
      let params=parseRequestData(req.read());
        let name=obj.name_user;
         res.end(`<html>
          <head>Test Page</head>
          <body>
            <h1>Hello, ${name}</h1>
          </body>    
      </html>`);     
  }
}

//function to return an object with all request paramethers 
const parseRequestData = (str) =>{
  return str.split("&").reduce(function(prev, curr, i, arr) {
    var p = curr.split("=");
    prev[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
    return prev;
  }, {});
}

results matching ""

    No results matching ""