178 lines
6.8 KiB
HTML

define(`TITLE', `First ESP8266 Project: WiFi Power Switch')
define(`DATE', `2015-09-14')
define(`CONTENT', `
<a href="http://a385e-5.de/wp-content/uploads/IMG_3826-e1442696191894.jpg" rel="attachment wp-att-693"><img src="http://a385e-5.de/wp-content/uploads/IMG_3826-e1442696191894-768x1024.jpg" alt="IMG_3826" width="474" height="632" class="alignnone size-large wp-image-693" /></a>
The ESP8266 boards (ESP-01, cmp. <a href="http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family#esp-01"> http://www.esp8266.com/wiki/doku.php?id=esp8266-module-family#esp-01 </a>
) 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 (<a href="http://www.nodemcu.com/index_en.html"> http://www.nodemcu.com/index_en.html</a>) and it is exactly what I was looking for since a while: <a href="http://www.lua.org/">Lua</a> 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.
<!--more-->
No need to install an SDK on the PC, just an upload tool like <a href="https://github.com/kmpm/nodemcu-uploader">nodemcu-uploader.py</a> or <a href="http://esp8266.ru/esplorer/">esplorer</a> is required. First the nodemcu firmware needs to be installed on the ESP8266 board. I found a very good intro <a href="http://www.whatimade.today/loading-the-nodemcu-firmware-on-the-esp8266-windows-guide/">here</a>.
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 <a href="https://primalcortex.wordpress.com/2014/12/30/esp8266-nodemcu-and-lua-language-and-some-arduino-issues/">here</a> and <a href="https://primalcortex.wordpress.com/2015/02/06/nodemcu-and-mqtt-how-to-start/">here</a>.
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:
<pre>
-- 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 &gt; 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
</pre>
<pre>
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) &lt; 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 = &quot;{&quot;metadata&quot;:{&quot;device&quot;:&quot;WiFiSwitch&quot; .. SWITCH_ID .. &quot;&quot;}, &quot;data&quot;:{&quot;uptime&quot;:&quot; .. uptime .. &quot;, &quot;state&quot;:&quot; .. switch_state_pres .. &quot;}}&quot;
m:publish(&quot;IoT/Status/WiFiSwitch&quot; .. SWITCH_ID, msg ,0,0, function(conn)
print(&quot;8: &quot; .. id2 .. &quot;, &quot; .. 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(&quot;message&quot;, function(conn, topic, data)
print(topic .. &quot;:&quot; )
if (data ~= nil ) then
print ( data )
if (topic == topics[TOPIC_SWITCH] and data == &quot;switch on&quot;) then
switch_state = true
elseif (topic == topics[TOPIC_SWITCH] and data == &quot;switch off&quot;) then
switch_state = false
elseif (topic == topics[TOPIC_SWITCH] and data == &quot;switch toggle&quot;) then
switch_state = not switch_state
elseif (topic == topics[TOPIC_WATCHDOG] and data == &quot;WauWau!&quot;) then
print(&quot;9&quot;)
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
</pre>
<img src="http://a385e-5.de/wp-content/uploads/IMG_3814-1024x768.jpg" alt="IMG_3814" width="474" height="356" class="alignnone size-large wp-image-688" />
<a href="http://a385e5.files.wordpress.com/2015/09/scan_006894_1.pdf"><img src="http://a385e5.files.wordpress.com/2015/09/scan_006894.png" alt="scan_006894" width="924" height="603" class="alignnone size-full wp-image-675" /></a>
Important note: this thing runs on mains power. Don't play with it unless you know exactly what you are doing!
')