Rudra Lad
Published © GPL3+

NodeMCU ESP8266 GPIO control web server

A basic web server hosted on ESP8266 to Toggle and control brightness of LED, implemented using NodeMCU Lua firmware

BeginnerFull instructions provided3 hours1,984
NodeMCU ESP8266 GPIO control web server

Things used in this project

Hardware components

Adafruit Feather HUZZAH with ESP8266 WiFi
Adafruit Feather HUZZAH with ESP8266 WiFi
×1

Software apps and online services

NodeMCU firmware
NodeMCU firmware
The NodeMCU Lua firmware.
Esplorer IDE
IDE written in Java, for programmig hardware flashed with NodeMCU firmware.
NodeMCU cloud build service
Online service to build NodeMCU service as per the modules of your choice
NodeMCU PyFlasher
GUI application to flash NodeMCU firmware to ESP8266 hardware, available for Windows (and Mac).
Python 3
We will use python script to convert html script to Lua String code
NodeMCU Documentation
Up-to-Date detailed Online Documentation for everything about NodeMCU

Story

Read more

Schematics

pinout

Code

LED_control_x2_get_form_STA_1.lua

Lua
The Lua file to be uploaded to NodeMCU
RedLED = 3                  -- declare LED pins
BlueLED = 4

Toggle_switch = false
gpio.mode(RedLED, gpio.OUTPUT)
gpio.write(RedLED, gpio.HIGH)   -- Turn off the LED at start up.

PWM_clock = 500
PWM_duty = 512
pwm.setup(BlueLED, PWM_clock, PWM_duty)
pwm.start(BlueLED)
pwm.setduty(BlueLED, PWM_duty)     -- set to 50% duty cycle at start up.

server = net.createServer(net.TCP)-- create TCP server



function SendHTML(sck, switch_val, duty_val) -- Send LED brightness HTML page
    htmlstring = "<!DOCTYPE html>\r\n"
    htmlstring = htmlstring.."<html lang=\"en\">\r\n"
    htmlstring = htmlstring.."<head>\r\n"
    htmlstring = htmlstring.."<title>NodeMCU Web Server</title>\r\n"
    htmlstring = htmlstring.."<style>\r\n"
    htmlstring = htmlstring.."table {\r\n"
    htmlstring = htmlstring.."width: 500px;\r\n"
    htmlstring = htmlstring.."margin-left: auto;\r\n"
    htmlstring = htmlstring.."margin-right: auto;\r\n"
    htmlstring = htmlstring.."}\r\n"
    htmlstring = htmlstring.."table, th, td {\r\n"
    htmlstring = htmlstring.."border: 1px solid black;\r\n"
    htmlstring = htmlstring.."border-collapse: collapse;\r\n"
    htmlstring = htmlstring.."text-align: center;\r\n"
    htmlstring = htmlstring.."}\r\n"
    htmlstring = htmlstring.."tr {\r\n"
    htmlstring = htmlstring.."height: 50px;\r\n"
    htmlstring = htmlstring.."}\r\n"
    htmlstring = htmlstring.."</style>\r\n"
    htmlstring = htmlstring.."</head>\r\n"
    htmlstring = htmlstring.."<body style=\"font-family: 'Segoe UI'\">\r\n"
    htmlstring = htmlstring.."<div>\r\n"
    htmlstring = htmlstring.."<table>\r\n"
    htmlstring = htmlstring.."<tr>\r\n"
    htmlstring = htmlstring.."<th colspan=\"2\"> <h1>NodeMCU GPIO Control </h1> </th>\r\n"
    htmlstring = htmlstring.."</tr>\r\n"
    htmlstring = htmlstring.."<tr>\r\n"
    htmlstring = htmlstring.."<td colspan=\"2\"> <h3> Use the controls below <br> to control the LEDs </h3> </td>\r\n"
    htmlstring = htmlstring.."</tr>\r\n"
    htmlstring = htmlstring.."<form method=\"get\">\r\n"
    htmlstring = htmlstring.."<tr>\r\n"
    htmlstring = htmlstring.."<td style=\"width: 300px\"> <label for=\"gpio3\"> <b> <i> Red LED - #3 </i> </b> </label> </td>\r\n"
    htmlstring = htmlstring.."<td style=\"width: 200px\"> \r\n"

    if (switch_val) then
        htmlstring = htmlstring.."<input type=\"radio\" id=\"ON\" name=\"gpio3\" value=\"ON\" checked> <label for=\"ON\">ON</label> <br>\r\n"
        htmlstring = htmlstring.."<input type=\"radio\" id=\"OFF\" name=\"gpio3\" value=\"OFF\"> <label for=\"ON\">OFF</label> <br>\r\n"
    else
        htmlstring = htmlstring.."<input type=\"radio\" id=\"ON\" name=\"gpio3\" value=\"ON\"> <label for=\"ON\">ON</label> <br>\r\n"
        htmlstring = htmlstring.."<input type=\"radio\" id=\"OFF\" name=\"gpio3\" value=\"OFF\" checked> <label for=\"ON\">OFF</label> <br>\r\n"
    end

    --htmlstring = htmlstring.."<input type=\"radio\" id=\"ON\" name=\"gpio3\" value=\"ON\" checked> <label for=\"ON\">ON</label> <br>\r\n"
    --htmlstring = htmlstring.."<input type=\"radio\" id=\"OFF\" name=\"gpio3\" value=\"OFF\"> <label for=\"ON\">OFF</label> <br>\r\n" 
    
    htmlstring = htmlstring.."</td>\r\n"
    htmlstring = htmlstring.."</tr>\r\n"
    htmlstring = htmlstring.."<tr>\r\n"
    htmlstring = htmlstring.."<td style=\"width: 300px\"> <label for=\"gpio4\"> <b> <i> Blue LED - #4 </i> </b> </label> </td>\r\n"
    htmlstring = htmlstring.."<td style=\"width: 200px\"> <input type=\"range\" min=\"0\" max=\"1023\" value=\""..tostring(duty_val).."\" class=\"slider\" id=\"gpio4\" name=\"gpio4\"> </td>\r\n"
    htmlstring = htmlstring.."</tr>\r\n"
    htmlstring = htmlstring.."<tr>\r\n"
    htmlstring = htmlstring.."<td colspan=\"2\"> <input type=\"submit\" value=\"Change Now\"> </td>\r\n"
    htmlstring = htmlstring.."</tr>\r\n"
    htmlstring = htmlstring.."</form>\r\n"
    htmlstring = htmlstring.."</table>\r\n"
    htmlstring = htmlstring.."</div>\r\n"
    htmlstring = htmlstring.."</body>\r\n"
    htmlstring = htmlstring.."</html>\r\n"

    sck:send(htmlstring)
end




function receiver(sck, data)-- process callback on recive data from client
    first_line_end = string.find(data, "\r")
    GET_response = string.sub(data, 1, first_line_end)
    print(GET_response)

    if string.find(GET_response, "gpio3") and string.find(GET_response, "gpio4") then
        words = {}
        keyz= {}
        valuez = {}

        for w in (GET_response):gmatch("%w+=+%w+") do 
            table.insert(words, w) 
        end

        for i = 1, #words do
            local equalsign = string.find( words[i], "=" )
            --print(equalsign)
            local tempkey = string.sub(words[i], 1, equalsign - 1 )
            local tempvalue = string.sub(words[i], equalsign + 1, string.len(words[i]) )
            --print(tostring(tempkey).."=>"..tostring(tempvalue))
            keyz[#keyz + 1] = tempkey
            valuez[#valuez + 1] = tempvalue
        end

        for i = 1, #words do
            print(tostring(keyz[i]).." => "..tostring(valuez[i]) ) 
        end

        local k1 = tostring(keyz[1])
        local v1 = tostring(valuez[1])

        local k2 = tostring(keyz[2])
        local v2 = tonumber(valuez[2])

        if v1 ~= nil then
            if v1 == "ON" then
                gpio.write(RedLED, gpio.LOW)
                Toggle_switch = true
                print("Turned ON")
            elseif v1 == "OFF" then
                gpio.write(RedLED, gpio.HIGH)
                Toggle_switch = false
                print("Turned OFF")
            else
                print("Wrong value for GPIO3")
            end
        end

        if v2 ~= nil then   -- not equal to operator.
            if v2 >= 0 and v2 <= 1023 then
                PWM_duty = 1023 - v2
            end
        end

        pwm.setduty(BlueLED, PWM_duty)
        PWM_duty = pwm.getduty(BlueLED)
        
        
        SendHTML(sck, Toggle_switch,(1023 - PWM_duty))

        words = {}
        keyz= {}
        valuez = {}
    elseif  string.find(data, "GET / ") then
        SendHTML(sck, Toggle_switch,(1023 - PWM_duty))
    else
        SendHTML(sck, Toggle_switch,(1023 - PWM_duty))
    end

    -- never use below line,
    -- until and unless you want to reset the http connection
    --sck:on("sent", function(conn) conn:close() end)
end





function client_connected (conn)
    conn:on("receive", receiver)
    print(conn:getpeer())
end



if server then
    server:listen(80, client_connected)-- listen to the port 80
end

read_html_to_write_lua.py

Python
A python script to convert HTML script to a single Lua string
# Python program to 
# demonstrate readline() 
  
#L = ["Geeks\n", "for\n", "Geeks\n"] 
  
# Writing to a file 
##file1 = open('myfile.txt', 'w') 
##file1.writelines((L)) 
##file1.close() 
  
# Using readline() 
##file1 = open('myfile.txt', 'r') 
##count = 0
##  
##while True: 
##    count += 1
##  
##    # Get next line from file 
##    line = file1.readline() 
##  
##    # if line is empty 
##    # end of file is reached 
##    if not line: 
##        break
##    print("Line{}: {}".format(count, line.strip())) 
##  
##file1.close()

file1 = open('pwm_ui_2.html', 'r')
file2 = open('pwm_ui_2.lua', 'w')
count = 0

while True:
    count += 1

    line = file1.readline()
    #print(type(line))

    if not line:
        break

    # remove all the leaading and trailing spaces
    line0 = line.strip(" ")

    # Slice the string from first character to second last character.
    # We don't need last character as it is a new-line character '\n'
    line1 = line0[0:(len(line0) - 1):1]

    # add backslash before each double quote - ( " ) character inside the string
    # because double quote is itself used as the string enclosing character in lua.
    line2 = line1.replace('\"', '\\\"')

    # add the standard leading string used for concatenation in lua code to send HTML as a string.
    # also add CR-LF characters inside the string and LF then at the end of the actual string
    line3 = 'htmlstring = htmlstring..' + '\"' + line2 + '\\r\\n' + '\"' + '\n' 

    # Just print the line3 on console for info
    print( str(len(line1)) + " - " + line3)

    # write the line to file only if it is not an empty string.
    # required because since " we believe in clean code :) ",
    # there would be many blank lines in our html code.
    # all of these empty lines must have become empty strings,
    # because we stripped all the spaces in line0.
    # And we don't need such empty strings added to standard lua string in our code.
    # As they don't add any value and just increase the size of lua scripts.
    if (len(line1) != 0) :
        file2.write(line3)
    
file1.close()
file2.close()

pwm_ui_2.html

HTML
Sample HTML page for GPIO control
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>NodeMCU Web Server</title>

        <style>
            table {
                width: 500px;
                margin-left: auto;
                margin-right: auto;
            }

            table, th, td {
                border: 1px solid black;
                border-collapse: collapse;
                text-align: center;
            }

            tr {
                height: 50px;
            }


        </style>

    </head>

    <body style="font-family: 'Segoe UI'">
        <div>
            <table>
                <tr>
                    <th colspan="2"> <h1>NodeMCU GPIO Control </h1> </th>
                </tr>
                <tr>
                    <td colspan="2"> <h3> Use the controls below <br> to control the LEDs </h3> </td>
                </tr>
                <form method="get">
                    <tr>
                        <td style="width: 300px"> <label for="gpio3"> <b> <i> Red LED - #3 </i> </b> </label> </td>
                        <td style="width: 200px"> 
                            <input type="radio" id="ON" name="gpio3" value="ON" checked> <label for="ON">ON</label> <br>
                            <input type="radio" id="OFF" name="gpio3" value="OFF"> <label for="ON">OFF</label> <br>
                        </td>
                    </tr>
                    <tr>
                        <td style="width: 300px"> <label for="gpio4"> <b> <i> Blue LED - #4 </i> </b> </label> </td>
                        <td style="width: 200px"> <input type="range" min="0" max="1023" value="512" class="slider" id="gpio4" name="gpio4"> </td>
                    </tr>
                    <tr>
                        <td colspan="2"> <input type="submit" value="Change Now"> </td>
                    </tr>
                </form>
            </table>
        </div>
    </body>
</html>

Credits

Rudra Lad

Rudra Lad

7 projects • 14 followers

Comments