define(`TITLE', `First ESP8266 Project: WiFi Power Switch') define(`DATE', `2015-09-14') define(`CONTENT', ` IMG_3826 The ESP8266 boards (ESP-01, cmp. http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family#esp-01 ) were lying on my desk for already some time. I never took the time to install the SDK on my Mac. Now I came around nodemcu ( http://www.nodemcu.com/index_en.html) and it is exactly what I was looking for since a while: Lua on a microcontroller. The idea behind is simple: When you are coding on a PC (or a Mac) and you have a rather small problem, a rather simple task to perform, you (or at least: I) would tend to use a scripting language. On a PC my first choice would be Python, other people prefer Perl or even Lua. On a microcontroller I also was faced those simple tasks (like toggling one bit based on an MQTT message) but never had a scripting language available. But here it is. No need to install an SDK on the PC, just an upload tool like nodemcu-uploader.py or esplorer is required. First the nodemcu firmware needs to be installed on the ESP8266 board. I found a very good intro here. My Lua script for this project running on the microcontroller consists of two files: ''init.lua'' and ''mqtt.lua''. Coding Lua for nodemcu isn't really intuitive, at least not when you come from Arduinos or so. You can't simple write a ''setup'' method and do all the initialization within and a ''loop'' method to be continuously run. Doing it this way would either drive you into the chip's watchdog and would consume any available CPU any and leave nothing for the WiFi and TCP/IP stack. You've to work with timers and callback functions. I found two really good articles here and here. What I also had to learn the hard way is that the nodemcu does not leave much space for the script. With a handful of debug messages containing some meaningful text (as it is no problem on the Arduino or Teensy) I over and over run into out of memory messages or even worse in misbehaving code. I finally came to this code:
-- init.lua
-- Constants
SSID    = "MessWLAN"
APPWD   = "geheim"
CMDFILE = "mqtt.lua" 

-- Some control variables
wifiTrys     = 0    
NUMWIFITRYS  = 200 

function launch()
  print("A")
  print("B: " .. wifi.sta.getip())
  tmr.alarm(0, 5000, 0, function() dofile(CMDFILE) end )
end

function checkWIFI() 
  if ( wifiTrys > NUMWIFITRYS ) then
    print("C")
  else
    ipAddr = wifi.sta.getip()
    if ( ( ipAddr ~= nil ) and  ( ipAddr ~= "0.0.0.0" ) )then
      tmr.alarm( 1 , 500 , 0 , launch )
    else
      tmr.alarm( 0 , 2500 , 0 , checkWIFI)
      print("D: " .. wifiTrys)
      wifiTrys = wifiTrys + 1
    end 
  end 
end

print("E")

ipAddr = wifi.sta.getip()
if ( ( ipAddr == nil ) or  ( ipAddr == "0.0.0.0" ) ) then
  print("F")
  wifi.setmode( wifi.STATION )
  wifi.sta.config( SSID , APPWD)
  print("G")
  tmr.alarm( 0 , 2500 , 0 , checkWIFI )
else
 launch()
end
BROKER = "172.16.2.15" 
BRPORT = 1883
BRUSER = ""
BRPWD  = "" 
CLIENTID = "ESP8266-" ..  node.chipid()

SWITCH_PIN = 3

SWITCH_ID = 1

topics = {"IoT/Watchdog", "IoT/Switch" .. SWITCH_ID} 
TOPIC_WATCHDOG = 1
TOPIC_SWITCH = 2

pub_sem = 0 
current_topic  = 1
topicsub_delay = 50 
id2 = 0

switch_state = false
old_switch_state = true


function alarm()
  node.restart()
end


gpio.mode(SWITCH_PIN, gpio.OUTPUT)
gpio.write(SWITCH_PIN, gpio.LOW)

m = mqtt.Client( CLIENTID, 120, BRUSER, BRPWD)
tmr.alarm(4, 60000, 1, alarm)
m:connect( BROKER , BRPORT, 0, function(conn)
     print("4")
     mqtt_sub()
end)




function mqtt_sub()
     if table.getn(topics) < current_topic then
          run_main_prog()
     else
          m:subscribe(topics[current_topic] , 0, function(conn)
          end)
          current_topic = current_topic + 1 
          tmr.alarm(5, topicsub_delay, 0, mqtt_sub )
     end
end


function publish_status()
   if pub_sem == 0 then 
     pub_sem = 1
     local uptime = tmr.time()
     local switch_state_pres = 0
     if (switch_state) then
        switch_state_pres = 1
     end
     local msg = "{"metadata":{"device":"WiFiSwitch" .. SWITCH_ID .. ""}, "data":{"uptime":" .. uptime .. ", "state":" .. switch_state_pres .. "}}"
     m:publish("IoT/Status/WiFiSwitch" .. SWITCH_ID, msg ,0,0, function(conn) 
        print("8: " .. id2 .. ", " .. switch_state_pres)
        pub_sem = 0 
        id2 = id2 +1 
     end)
   end  
end



function run_main_prog()
     tmr.alarm(3, 1000, 1, publish_status )
     m:on("message", function(conn, topic, data)
        print(topic .. ":" )
        if (data ~= nil ) then
          print ( data )
          if (topic == topics[TOPIC_SWITCH] and data == "switch on") then
            switch_state = true
          elseif (topic == topics[TOPIC_SWITCH] and data == "switch off") then
            switch_state = false
          elseif (topic == topics[TOPIC_SWITCH] and data == "switch toggle") then
            switch_state = not switch_state
          elseif (topic == topics[TOPIC_WATCHDOG] and data == "WauWau!") then
            print("9")
            tmr.alarm(4, 60000, 1, alarm)
          end

          if (switch_state ~= old_switch_state) then
            old_switch_state = switch_state
            if (switch_state) then
              gpio.write(SWITCH_PIN, gpio.LOW)
            else
              gpio.write(SWITCH_PIN, gpio.HIGH)
            end
          end
        end
      end )
end
IMG_3814 scan_006894 Important note: this thing runs on mains power. Don't play with it unless you know exactly what you are doing! ')