Thursday, May 7, 2015

MPDMv3 - WIFI Mains Power Dimmer / Switch - Web Interface


WARNING!! You will play with LIVE MAINS!! Deadly zone!! 

      If you don't have any experience and are not qualified for working with MAINS power I will not encourage you to play arround!. The author take no responsibility for any injury or death resulting, directly or indirectly, from your inability to appreciate the hazards of household mains voltages.
   The circuit diagrams are as accurately as possible, but are offered with no guarantees whatsoever. 
    There is no guarantee that this design meets any Rules which may be in force in your country so please check before your local rules/regulations.


     For any new requests please feel free to use as usual: tech at
     If you want to order MAINS POwer Dimmer/Switch bare PCBs only, you can also do it directly at Dirty PCBs, our preferred PCB House:


     As I promised in the last article about the new MAINS Dimmer / Switch Module, Today we will continue with designing the Web interface access.

      What we will need:  

MAINS Power Dimmer / Switch Module - MPDMv3 - Connections

CBDB Evolution DevBoard

     Because I don't like to have flying MAINS wires on my workdesk I have created a temporary separate MPDMv3 Module Box, containing all the MAINS part of the story :).

Isolated MAINS unit - keep your fingers away from the Deadly zone !

      Remember, Safety First! And also more relaxing knowing that is no Russian Roulette wire game on progress on my table. Shit happens all the time, but at least let's try to reduce the chances to hit badly the fan too often :)

Live Testing on progress

   In the Box above is enough space for all the parts going inside, including ESP8266 module, power supply, Dimmer Module, Choke, etc, but at this stage I find it easier to connect them together like that.

MPDMv3 Web Server Software

For programming CBDBv2 Board and uploading the driver and the software we will continue to use the LuaUploader as before. 

1. Define used GPIO pin

      outpin=7                                                       -- Select Triac Command pin - GPIO13
      gpio.write(outpin,gpio.LOW)                       -- Triac OFF
      inpin=6                                                         -- Zero crossing detector input - GPIO12 
      gpio.mode(inpin,gpio.INT,gpio.PULLUP)   -- attach interrupt to ZCD

  2. Zero Cross Detector function and Triac command

      For a more detailed explanation how Zero cross detection circuit works please take a look at the previous MPDMv3 article.

      function zero_cross()
           dt = 76*dim
           --print("Zero cross detected!")
           stat = "ON"
           tmr.delay(dt)                                 -- Firing delay time calculated above
           gpio.write(outpin,gpio.HIGH)     -- Triac ON - Zero cross detected
           tmr.delay(100)                              -- Triac ON - Propagation time 
          gpio.write(outpin,gpio.LOW)        -- Triac OFF - let's be sure it's OFF before next cycle :)
          return stat

3. WEB Server

   conn:on("receive", function(conn,payload)
      --debugging output only
      -- print(payload)
      if (string.find(payload, "GET / HTTP/1.1") ~= nil) then
         --print("GET received")
         --If POST value exist, set power switch status
         if swstat[2]~=nil then
            --print("Command received: " .. payload)
   conn:on("sent", function(conn)
      conn = nil -- clear and allow the garbage collector to free the memory
      --print("Connection closed")


4. Send page function based on received requests

function sendPage(conn)
   conn:send('HTTP/1.1 200 OK\n\n')
   conn:send("<META HTTP-EQUIV=\"REFRESH\" CONTENT=\"5\">")
   conn:send('<!DOCTYPE HTML>')
   conn:send('<head><meta content="text/html; charset=utf-8">')
   conn:send('<LINK href="  

   conn:send('rel="stylesheet" type="text/css">')
   conn:send('<title>ESP8266 - Power Switch Controller</title></head>')
   conn:send('<body><center><h1>ESP8266 MAINS Power Dimmer Controller</h1></center>')
   conn:send('<br /><br />')
   conn:send('<form action="/" name="dimmer" oninput="outputUpdate(cmd.value)" 

   conn:send('<font color=red><b>ON </b></font><input style="width:550px; height:50px" 

                     type="range" name="cmd" id="cmd" value="')
   conn:send('" min=1 max=128 step=1 />')
   conn:send('<font color=red><b>OFF</b></font></form>')
   conn:send('<br><center>Dimmer Value: <b>')        
      conn:send(' pts</b></center>')
   conn:send('<script type="text/javascript">')
   conn:send('function outputUpdate(dim) {document.querySelector("#cmd").value = dim;')


 CSS file created for this example is just for fancy decorations. If you don't like it you can very easy change the style attributes or add local ones.

5. Check received Dimmer value and update status

     function PwrSW(swstat,payload)
           status = tonumber(newstat)
           print("Dimmer Value:" ..  status)

4. Main code

       status = 60                   -- around 50% - choose your desired start value.
       newstat = 60
        outpin=7                     -- Select Triac Command pin - GPIO13  
        gpio.write(outpin,gpio.LOW)  -- Triac OFF
        inpin=6                      -- Zero crossing detector input - GPIO12 
        gpio.mode(inpin,gpio.INT,gpio.PULLUP)  -- attach interrupt to ZCD

       gpio.trig(inpin,"up",zero_cross)                 -- ZCD interrupt attached - trigger on falling edge
       print(wifi.sta.getip())                                  -- print our new MPDMv3 WebServer IP

      For testing, just save the code on ESP as 'dimserver.lua', restart ESP and run:   
            dofile("dimserver.lua")      -- Start the Dimmer Listening WebServer
               =wifi.sta.getip()              -- find the IP Address where your Web Server will be


     Open your favorite Web browser and type your new MPDMv3 Web Server IP address. If all ok, should look something like below :

MPDMv3 Web Interface

If you want the MPDMv3 software to start automatically when your CBDB module starts or reboots, then you neet to create and add some lines in your 'init.lua' file:
          dofile("dimserver.lua")  -- Start automatically the Dimmer Listening WebServer

Save the code on ESP as 'init.lua', restart ESP. It should reboot and restart automatically the program.

A short video presentation, testing the Web Interface:


Joe said...

you use GPIO5=pin1 and GPIO4=pin2 address that I see in code here but on picture you gave me a wallhanger it says GPIO4=pin1 and GPIO5=pin2 address
So which is it ?

Unknown said...

It's working ok on my new ESP07 modules with GPIO5=pin1 and GPIO4=pin2.
GPIO4/5 are silkscreen reversed on some ESP boards. See also and arround for some more details about.

Unknown said...

I wonder if your codes work at all. continuosly.

tmr.delay takes processor in own thread and exclusively (known bug of firmware)
if srv:listen will try to proccess in the same time, the whole firmware crashed.

because tmr.delay execute 50 times per seconds it is no accidental to crash when control from web page.

Another known "bug" issue of Nodemcu: tmr.wdclr overwrites memory when it executes too frequently. We can use it only every seconds, not mili- or microseconds.

I started to learn LUA and ESP8266 from your blog.
Thank you.
But in consequency it is not working and stable.

Unknown said...

Hi Janusz,

First of all I want to thank you for reading my Blog. I am very happy to see that people are sharing here their own experiences about ESP8266 world.

Regarding NodeMCU, at least from my point of view, the main purpose of the LUA Interpreter on ESP8266 is pure Educational, as been a nice tool to help people to learn coding in a easy way. Also a nice tool for early stage development .

For more serious things I recommend you to use a different environment based on the Eclipse + ESP8266 SDK, or, why not, Arduino IDE.

I have run some tests with MPDMv3 and ESP8266 NodeMCU and was working OK as you can see from the demo above.

Did you tried also the latest NodeMCU release? looks more stable.

Unknown said...

Thanks fo reply.
I generated own firmware from Nodemcu online builder. So it is the latest version I hope.

Your idea of coding is working. Generally.

tmr.wdclr() will crash the firmware after few seconds in this way. It was discussed in another forum.
But for this issue is simple solution:

if (i==1000) then tmr.wdclr() i=0 end

And the more difficult is that we cannot send wifi commends together with tmr.delay.
Because tmr.delay lock system's time and wifi server cannot response.

Please try to open your IP several times every second (or even every a few seconds) and it will crash frimaware later or sooner accidentally.

OK. I did not copied your codes, but I written my own base your idea.
I believe there is not mistake, because I write and test 2 parts separetly.
Only light dimming - works ok. Only web server - works ok.
Uploaded connected - crash.
The only common part is one value: dimset, which is used in zer_cross to calculate the delay, and which server receive function changes simple.

I will try with your codes copied today.

Unknown said...
This comment has been removed by the author.
Unknown said...

Did anyone ever get this to work reliably? I've tried using ESP8266 Arduino code and have exactly the same problem . . .

Unknown said...

I did not. It's a horror. We cannot use two or more timers in ESP. So, if you want to set web server/page which is listening (1st timer), you cannot use any more timer. For this moment I see only one solution: ESP as web serwer only, connected to arduino as pwm trigger (dimming control)

Unknown said...

Hi, I can't get the dimmer values from the range form to update the "status" variable. The range part seems to be working (sending values from the browser to the esp and back), but the dimmer value does not change on the hardware. Any suggestions?

Post a Comment