Close
0%
0%

Wi-Fi christmas lights

Connecting some old fairy lights to an ESP8266 for absolutely no reason whatsoever

Similar projects worth following
It's Christmas (sort of) and I wanted to upgrade some old fairy lights. A simple, cheap and quick hack with some interesting Lua learning points.

This is a super simple project but provides a good introduction to the ESP8266 and Lua. A "Hello World" of Wi-Fi projects.

Build instructions

  1. Flash the nodeMCU firmware to your ESP8266. In order for this project to work, you will need the PWM, HTTP and WiFi modules enabled. The firmware in the documents section has everything you need.
  2. Butcher your lack-luster battery powered christmas lights as explained in "the circuit" below. I stuck all my components on a bit of proto board.
  3. Upload the lua script and HTML page to your ESP8266. I use ESPlorer to handle this side of things. Set your baud rate to 115200 when using the firmware.
  4. Plug in the module and connect to the Wi-Fi access point.
  5. Navigate to 192.168.4.1 (the default IP address served up by nodeMCU in AP mode).
  6. Make christmas lights flash!

As an optional extra, I installed my lights inside an Altoids tin (of course) and attached a second string of lights. If you go down this route, make sure you protect any wires from shorting on the case.

The circuit

Super simple! Hook up pin 1 of the nodemcu to a mosfet transistor and put this between the fairy lights and the ground pin. That's all there is to it! If you have no emotional attachments to the lights, just chop the wires off where they enter the battery pack and solder them to the correct ESP pins.

Still confused? Here's a hand drawn gloomy circuit schematic.

The code

This is the more interesting part of the project and a more detailed explanation is in the project logs below. However, here are a few things I learnt:

  1. NodeMCU has a low buffer limit which restricts the amount of HTML you can dump in a single file;
  2. It is possible to monitor the results of an HTML form input pretty easily (although this was frustrating to start with as I couldn't work out where in the payload they were found).

The webpage

A reasonably straightforward HTML form with four sliders for the different settings:

firmware.bin

nodeMCU firmware

octet-stream - 500.00 kB - 12/17/2016 at 11:11

Download

Christmas Lights.lua

Main LUA script

lua - 4.48 kB - 12/17/2016 at 11:11

Download

mainPage.html

HTML source for webpage

HyperText Markup Language (HTML) - 1.37 kB - 12/17/2016 at 11:11

Download

  • 1 × Nodemcu Can just use normal ESP8266 module instead
  • 1 × 2N7000 through hole transistor Why not go SMT? Mad props!
  • 1 × A string of uninspiring battery powered fairy lights I ordered hundreds for my wedding a few years ago
  • 1 × Perf board and hookup wire Dig inside the parts bin

  • The Code!

    Alex Hunt12/17/2016 at 11:07 0 comments

    Here's the code I am currently running. The broad structure is:

    1. Create an open access point for users to connect to;
    2. Declare the variables needed to control the LED flashing speed etc.
    3. Create a table with the locations of various additional files needed. See this excellent tutorial here for how to serve up big files. I have copied most of this code but with a few small tweaks.
    4. Start the PWM on pin 1.
    5. Loop through all of the submitted data from the HTML form (stored in _GET in this example).
    6. Use the data to set the PWM value and alarm cycles.

    The only slightly strange bit of the codes is the lines that follow this pattern:

    partial_data = string.gsub(partial_data,"xxBVxx",ledPWM)

    In the HTML files, each of the values for the form inputs is as follows:

    <input class="slider-width" type="range" name="Brightness" min="0" max="1023" value="xxBVxx" onChange="form.submit()">
    The nodemcu code goes through the HTML source and replaces xxBVxx with the correct PWM value. This ensures that the webpage served up has the sliders in the correct position.
    --Close any servers already running
    if srv then srv:close() srv=nil end
    
    wifi.setmode(wifi.SOFTAP)
    cfg={}
    cfg.ssid="AlexsXmasLights"
    wifi.ap.config(cfg)
    
    --Variables for flashing lights
    led1 = 1
    ledPWM=500
    flashSpeedOn=500
    flashSpeedOff=500
    glowOn="On"
    glowSpeed=5
    gpio.mode(led1, gpio.OUTPUT)
    value = true
    glow=true
    scan=true
    
    --Tables for file locations
    local httpRequest={}
    httpRequest["/"]="mainPage.html";
    httpRequest["/index.html"]="mainPage.html";
    local getContentType={};
    getContentType["/"]="text/html";
    getContentType["/index.htm"]="text/html";
    
    local filePos=0;
    
    
    --Start the PWM stuff at full
    pwm.setup(led1,1000,ledPWM);
    pwm.start(led1);
    
    tmr.alarm(0, 500, 1, function ()
        if(glowSpeed>0)then
            if(glow==true)then
                ledPWM=ledPWM+1
            else
                ledPWM=ledPWM-1
            end
            if(ledPWM==1000)then
                glow=false
            end
            if(ledPWM==1)then
                glow=true
            end
            pwm.setduty(led1,ledPWM);
            tmr.interval(0, glowSpeed)
        else
            value = not value
            if(value==true) then
                pwm.setduty(led1,ledPWM);
                tmr.interval(0, flashSpeedOn)
            else
                pwm.setduty(led1,0);
                tmr.interval(0, flashSpeedOff)
            end
        end
    end)
    
    srv=net.createServer(net.TCP)
    srv:listen(80,function(conn)
        conn:on("receive", function(client,request)
            local buf = "";
            scan=false
            local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
            if(method == nil)then
                _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
            end
            local _GET = {}
            if (vars ~= nil)then
                for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
                    _GET[k] = v
                end
            end
          
            --Loop through info submitted
            for key,value in pairs(_GET) do 
                if(key=="FlashSpeedOn") then
                    flashSpeedOn = tonumber(value);
                    if(flashSpeedOn>0) then
                        tmr.start(0)
                    else
                        tmr.stop(0)
                        pwm.setduty(led1,ledPWM);
                    end
                end
                if(key=="glowSpeed") then
                    glowSpeed = tonumber(value)
                end
                if(key=="FlashSpeedOff") then
                    flashSpeedOff = tonumber(value);
                    if(flashSpeedOff==0) then
                        tmr.stop(0)
                        pwm.setduty(led1,led1023);
                    end
                end
                if(key=="Brightness") then
                    ledPWM = tonumber(value);
                end
                if(key=="glowOn") then
                    scan=true
                    glow=true
                end
             end
            if getContentType[path] then
                requestFile=httpRequest[path];
                print("[Sending file "..requestFile.."]");            
                filePos=0;
                conn:send("HTTP/1.1 200 OK\r\nContent-Type: "..getContentType[path].."\r\n\r\n");            
            else
                print("[File "..path.." not found]");
                conn:send("HTTP/1.1 404 Not Found\r\n\r\n")
                conn:close();
                collectgarbage();
            end
        end)
        conn:on("sent",function(conn)
            local next1 = 0;
            if requestFile then
                if file.open(requestFile,r) then
                    file.seek("set",filePos);
                    local partial_data=file.read(512);
                    if(partial_data~=nil) then
                        if (string.len(partial_data)==512) then
                            next1 = 1
                        end
                        partial_data = string.gsub(partial_data,"xxBVxx",ledPWM)
                        partial_data = string.gsub(partial_data,"xxFONVxx",flashSpeedOn)
                        partial_data = string.gsub(partial_data,"xxFOFFVxx",flashSpeedOff)
                        partial_data = string.gsub(partial_data,"xxGSxx",glowSpeed)
                        file.close();
                        if partial_data then
                            filePos=filePos+(512-string...
    Read more »

View project log

Enjoy this project?

Share

Discussions

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates