Skip to content

Yet another simple and minimalistic webserver for ESP8266

License

Notifications You must be signed in to change notification settings

QB4-dev/esp_nano_httpd

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

esp_nano_httpd

Yet another simple and minimalistic webserver for ESP8266

Why do You need it?

In almost all your ESP8266 projects you need to setup WiFi connection parameters(SSID, password) to connect with your home router. Hardcoding this parameters is definitely not a good idea. If you change router settings, or even take your device somewhere else you will need to recompile your code - sounds bad isn't it?

esp_nano_httpd will help you ( ͡° ͜ʖ ͡°)

esp_nano_httpd features:

  • small and easy to use - all you need to do is to copy esp_nano_httpd directory into your project source, configure urls, and start it!
  • designed to host minimalistic html interfaces - use it to host simple html pages to setup WiFi connection with your home router, create web browser user interface to control your device, or to handle and send data by CGI-like functions.

Thats all - its only simple and robust webserver. If you need more features like image hosting, web sockets and so on use fantastic libesphttpd by Sprite_tm.

OK I like it, it's enough for me. How to use it?

  1. Copy esp_nano_httpd directory into your project source tree.

  2. Add esp_nano_httpd module to be compiled in Makefile (I recommend to use this Makefile template for NONOS SDK projects)

# which modules (subdirectories) of the project to include in compiling
MODULES	= driver user esp_nano_httpd
  1. Include esp_nano_httpd.h header file in your user_main.c file or wherever you need it.
#include "../esp_nano_httpd/esp_nano_httpd.h
  1. Now it's time to prepare our HTML content...
    If you ever tried manually include HTML code inside C file you know the pain when you mixing two programming languages - all damn backslashes before quotation marks, no web browser preview, etc. (╯°□°)╯︵ ┻━┻
    Not this time... I'll show you the trick ( ͡~ ͜ʖ ͡°)
    ...
    Copy html directory from esp_nano_httpd_basic_example. Add there your own html files. You will find small and handy shell script gen_includes.sh It will create C header files in include directory from your html files by using Linux xxd tool. Just use it!

  2. Okay. We have our html content easy to include into C code, and esp_nano_httpd . Lets connect them together.
    Create url config table inside your user_main.c file:

#include "../esp_nano_httpd/esp_nano_httpd.h" //to use esp_nano_httpd

//include your html pages here
#include "../html/include/index.h" 
#include "../html/include/about.h"

//and create URL config table
const http_callback_t url_conf[] = {
    {"/", send_html, index_html, sizeof(index_html)},
    {"/about", send_html, about_html, sizeof(about_html)},
    {0,0,0,0} //last item always 0
};

const http_callback_t url_conf[] explained:

server path callback function_ callback arg callback arg lenght
"/" send_html index_html sizeof(index_html)
"/about" send_html about_html sizeof(about_html)
  • server path - http request server path. When internet browser comunicates with ESP8266 device sends HTTP requests to ESP_IP/path .
    "/" is device root path. When you simply type ESP_IP for example http://192.168.4.1 into your web browser address bar it will request device root path and ESP device will respond by sending to the browser index.html page.
    If you want to access some other pages by path add it after ESP_IP address. To see about.html page type ESP_IP/about for eg. http://192.168.4.1/about
  • callback function_ - this function is called when ESP8266 device will recieve HTTP request with matching server path
    In this example We are using send_html function from esp_nano_httpd API to make things easy. You can use your own callback functions, to do device function, or send json data etc. (see below).
  • callback arg - calllback function argument passed to callback function_ in this example its html page code in array index_html.
  • callback arg lenght - calllback function argument length. callback arg is not always null terminated string, it might be binary data, and sender needs to know its's length.
  1. Now it's time to tell esp_nano_httpd how to handle requests:
esp_nano_httpd_register_content(url_conf);

and start it when needed:

 esp_nano_httpd_init_AP(STATIONAP_MODE, "ESP-LED",NULL); //when used as AP*
//or
esp_nano_httpd_init();  //when used as router client

NOTE: Two last bytes of your ESP8266 device MAC address will be added at the end of AP name to create unique AP names for multiple ESP8266 devices.
For example:
#define NANO_HTTPD_AP_NAME "ESP-LED"

  • device 1 AP name: ESP-LED-13DF
  • device 2 AP name: ESP-LED-C0A1
    ...
  • device x AP name: ESP-LED-XXXX

Using esp_nano_httpd:

The moment and mode when you need to init esp_nano_httpd is dependent on your application. Typical workflow is:

  • esp_nano_httpd_init_AP is called with STATIONAP_MODE when you need to setup your device options at first time run, or reconfigure the device(for example by setting ESP8266 device into config mode when button is pressed for 5s).

and/or

  • esp_nano_httpd_init is called when you need to always have access to your device special functions via web browser (for example setting GPIO, playing sounds etc)

esp_nano_httpd API:

void esp_nano_httpd_register_content(const http_callback_t *content_info) - used to pass to the esp_nano_httpd bullit in URL table with callback functions.

void esp_nano_httpd_init(uint8_t wifi_mode) - used to initialize esp_nano_httpd web server.

  • When wifi_mode = STATIONAP_MODE - ESP8266 will create an open Access Point with SSID defined by NANO_HTTPD_AP_NAME in user_config.h
  • When wifi_mode = STATION_MODE - ESP8266 will only create server and listen HTTP requests on port 80.

Some useful functions to write CGI - like request callbacks:

void send_http_response(struct espconn *conn, const char *code, const char *cont_type, const char *content, uint32_t cont_len) - used to send various HTTP response types.

  • struct espconn *conn - pointer to current connection structure
  • const char *code - response HTTP status code
  • const char *cont_type - response content type
  • const char *cont - pointer to response content
  • uint32_t cont_len - response content length

void send_html(struct espconn *conn, void *arg, uint32_t len) - send HTML page(basic callback function - more details below)

void resp_http_ok(struct espconn *conn) - send HTTP OK status(status code: 200)

void resp_http_404(struct espconn *conn) - send HTTP Not Found status status(status code: 404)

void resp_http_error(struct espconn *conn) - send HTTP Internal Error status(status code: 500)

Writing callback functions

Until now We know how to use esp_nano_httpd to send our html files only. Here is how to write other functions that will handle another requests, and allow us to make some real actions on ESP8266 device like changing options, setting GPIOs, controling peripherials, reading sensors on web browser user demand.

callback function prototype explained:

All callback functions should be designed like:

void ICACHE_FLASH_ATTR http_callback_fun(struct espconn *conn, void *arg, uint32_t len)
{
	http_request_t *req = conn->reverse; //get parsed request
}

Input arguments:

  • struct espconn *conn - current TCP connection. It is used to point where to send requested data.
  • http_request_t *req - received and parsed HTTP request. Defined in esp_nano_httpd.h

Use it to check what type of request has been received, read request path, query string, and content

typedef struct {
    enum req_type {
        TYPE_UNKNOWN = 0,
        TYPE_GET     = 1,
        TYPE_POST    = 2
    } type; 
    const char* path;
    const char* query;

    const char* content_type;
    uint32_t content_len;
    void *content;
    //things below are used for long requests that doesn't fit into read buffer
    enum {							
        REQ_GOT_HEADER		= 0,    //is returned when got request header
        REQ_CONTENT_PART	= 1     //is returned when got part of request content
    } read_state;	
    uint32_t cont_part_len;         //length of content part
    uint32_t cont_bytes_left;       //content bytes left to receive
} http_request_t;
  • void *arg - callback function argument. It might be any data used in callback function. It might be pointer to LED driver, because this callback function is used to setup RGB led color, HTML page as in html_send() function.

  • uint32_t len - callback function argument length in bytes

Basic http request callback function

This example callback is used to change wifi station settings:

#include "../html/include/wifi_connect_html.h" //here is our wifi connection status page

void ICACHE_FLASH_ATTR wifi_config_cb(struct espconn *conn, void *arg, uint32_t len)
{
    struct station_config station_conf = {0};
    char *param;
    
    http_request_t *req = conn->reverse; //get parsed request
    if(req == NULL)
    	return;
    //We only handle POST requests
    if(req->type != TYPE_POST || req->content == NULL)
       return resp_http_error(conn);
       
    /* in request content We expect serialized input form query like: ssid=MY_SSID&passwd=MY_PASSWD
    Use strtok to divide query into tokens*/
    param=strtok(req->content,"&");
    do {
        if( os_memcmp(param,"ssid=",5) == 0 )         //ssid value found
            ets_strncpy(station_conf.ssid, strchr(param,'=')+1,32);
        else if( os_memcmp(param,"passwd=",7) == 0 )  //password value found
            ets_strncpy(station_conf.password, strchr(param,'=')+1,64);
    } while( (param=strtok(NULL,"&")) != NULL);

    station_conf.bssid_set = 0;               //do not look for specific router MAC address
    wifi_station_set_auto_connect(0);	      //disable autoconnect
    wifi_station_set_config(&station_conf);   //save new WiFi settings
    wifi_station_connect();		      //connect to network

    send_html(conn, wifi_connect_html, sizeof(wifi_connect_html)); //show HTML page
}

Next we need to add the <form> in our index.html file to get WiFi SSID and password:

<p><strong>WiFi configuration:<strong></p>
<form method="post" action="/wifi_conf">
SSID<br>
<input type="text" name="ssid" pattern="[A-Za-z0-9]{1,32}" required="required" title="Access Point name"><br>
password<br>
<input type="text" name="passwd" pattern="^\S{0,64}$" title="password 0-64 characters"><br>
<input type="submit" value="WiFi connect">
</form>

When function is ready all you need to do is to connect it to path in url_config in user_main.c

const http_callback_t url_cfg[] = {
	{"/", send_html, index_html, sizeof(index_html)},
	{"/demo", led_demo_cb, NULL, 0},
	{"/wifi_conf", wifi_config_cb, NULL, 0 },
	{0,0,0}
};

Releases

No releases published

Packages

No packages published

Languages