Advertisement
Guest User

Niston Cloud's IoT Signaleer - Firmware 1.0

a guest
Apr 13th, 2016
255
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.22 KB | None | 0 0
  1. -- WiFi IoT Signaleer 1.0 for ESP8266/nodeMCU - See http://imgur.com/sNi8Ou6
  2. -- (c) 2016 Chris Burri @ NISTON Engineering Works
  3. -- http://niston.wordpress.com
  4.  
  5. -- HTTP Polling Version:
  6. -- Periodically retrieves a status URL and updates connected lamps & beeper accordingly.
  7. -- Status page must serve string in the format: "ID=SIGNLR;R=0;Y=0;G=1;S=0" where
  8. -- R=Red Lamp, Y=Yellow Lamp, G=Green Lamp, S=Beeper and
  9. -- 0=Off, 1=On, 2=Blink, 3=Blink_Reversed (see Signal definitions below for explanation of "reversed")
  10. -- ID=SIGNLR is the Protocol's Magic String. It must preclude everything else and match with what's in the magicID variable.
  11.  
  12.  
  13. -- Signaleer configuration
  14. httpURL = "https://my.server.com/signaleer.aspx";   -- status page URL
  15. wlanSSID = "wlanSSID";      -- WiFi network name
  16. wlanPwd = "wlanPassword";   -- WiFi network password
  17. pollInterval = 90;          -- HTTP polling run interval (polling for status update) in seconds
  18. pollMaxRetries = 5;         -- maximum http.get() retries during poll run before aborting
  19. pollRetryDelay = 5;         -- delay in seconds between failure and rescheduled poll
  20. beepMaxDuration = 15;       -- maximum audible alert duration in seconds
  21.  
  22. -- Code Below --
  23.  
  24. -- Update protocol related
  25. magicID = "ID=SIGNLR";      -- magic string
  26.  
  27. -- Timer definitions (7 IDs available form 0...6).
  28. timerBlink = 0;             -- Main/Blinker procedure timer
  29. timerPoll = 1;              -- HTTP poll procedure timer
  30. timerRescheduler = 2;       -- HTTP failed poll reschedule timer
  31. timerResetBeeper = 3;       -- Beep limiter timer
  32.  
  33. -- GPIO pin definitions
  34. pinBeeper = 1;              -- beeper GPIO pin
  35. pinLampRed = 2;             -- red lamp GPIO pin
  36. pinLampYellow = 6;          -- yellow lamp GPIO pin
  37. pinLampGreen = 7;           -- green lamp GPIO pin
  38.  
  39. -- Signal definitions
  40. SIG_OFF = "0";              -- signal off
  41. SIG_ON = "1";               -- signal on
  42. SIG_BLINK = "2";            -- signal alternating (2Hz)
  43. SIG_BLINK_REV = "3";        -- signal alternating (2Hz reversed: on when blink is off, off when blink is on)
  44.  
  45. -- signal image variables
  46. signalRed = SIG_OFF;        -- red signal lamp
  47. signalYellow = SIG_OFF;     -- yellow signal lamp
  48. signalGreen = SIG_OFF;      -- green signal lamp
  49. signalBeeper = SIG_OFF;     -- piezo beeper
  50.  
  51. -- State variables
  52. intervalBlink = 500;        -- milliseconds between run/blinker state change intervals - do NOT configure this
  53. stringLastStatus = nil;     -- last obtained status string; nil when no update
  54. blinkState = 0;             -- blinker status; alternates between 0 and 1 at 2Hz (intervalBlink=500ms)
  55. pollFails = 0;              -- count of subsequently failed HTTP polls. reset to zero after pollMaxRetries
  56. flagBeeptimeExceeded = 0;   -- Beep duration limiter: set to 1 if beeper is to be silenced
  57. signalBeeperPrevious = 0;   -- previous beeper state, used to detect state transitions
  58.  
  59. -- Initialize GPIO ports
  60. function InitGPIO()
  61.     gpio.mode(pinBeeper,gpio.OUTPUT);
  62.     gpio.mode(pinLampRed,gpio.OUTPUT);
  63.     gpio.mode(pinLampYellow, gpio.OUTPUT);
  64.     gpio.mode(pinLampGreen, gpio.OUTPUT);
  65.     gpio.write(pinBeeper, 0);
  66.     gpio.write(pinLampRed, 0);
  67.     gpio.write(pinLampYellow, 0);
  68.     gpio.write(pinLampGreen, 0);
  69. end
  70.  
  71. -- WiFi STA_GOTIP callback
  72. function WifiConnected(previousState)
  73.   ip, nm, gw = wifi.sta.getip();
  74.   print("WiFi connected (DHCP). IPAddr=" .. ip .. " Netmask=" .. nm .. " Gateway=" .. gw);
  75.   ExecutePoll(); -- poll immediately when connected
  76. end
  77.  
  78. -- Wifi STA_WRONGPWD callback
  79. function WifiWrongPwd()
  80.   print("WiFi connection failed: Invalid Password.");
  81. end
  82.  
  83. -- Wifi STA_CONNECTING callback
  84. function WifiConnecting()
  85.   ssid, password, bssid_set, bssid = wifi.sta.getconfig();
  86.   print("WiFi connecting to " .. ssid .. " (" .. bssid .. ")...");
  87. end
  88.  
  89. -- Wifi STA_FAIL callback
  90. function WifiConnectionFail()
  91.  print("WiFi connection failed: Connection Failure.");
  92. end
  93.  
  94. -- WiFi Setup
  95. function SetupWiFi()
  96.   wifi.sta.eventMonStop();
  97.   wifi.sta.autoconnect(0);
  98.   wifi.setmode(wifi.STATION);
  99.   wifi.setphymode(wifi.PHYMODE_N);
  100.   wifi.sta.sethostname("Signaleer");
  101.   wifi.sta.config(wlanSSID, wlanPwd, 0);
  102.   wifi.sleeptype(wifi.NONE_SLEEP);
  103.   wifi.sta.eventMonReg(wifi.STA_GOTIP, function(previous_State) WifiConnected(previous_State) end);
  104.   wifi.sta.eventMonReg(wifi.STA_WRONGPWD, function() WifiWrongPwd() end);
  105.   wifi.sta.eventMonReg(wifi.STA_CONNECTING, function() WifiConnecting() end);
  106.   wifi.sta.eventMonReg(wifi.STA_FAIL, function() WifiConnectionFail() end);
  107.   wifi.sta.eventMonStart(200);
  108.   wifi.sta.connect();
  109.   wifi.sta.autoconnect(1);
  110. end
  111.  
  112. -- test all actors (lamp & beeper test)
  113. function TestActors()
  114.  ClearActors();
  115.  Beep(500);
  116.  tmr.delay(1000000);
  117.  tmr.wdclr();
  118.  gpio.write(pinLampRed, 1);
  119.  Beep(75);
  120.  tmr.delay(1000000);
  121.  tmr.wdclr();
  122.  gpio.write(pinLampYellow, 1);
  123.  Beep(75);
  124.  tmr.delay(1000000);
  125.  tmr.wdclr();
  126.  gpio.write(pinLampGreen, 1);
  127.  Beep(75);
  128.  tmr.delay(1000000);
  129.  tmr.wdclr();
  130.  ClearActors();
  131.  tmr.delay(1000000);
  132.  tmr.wdclr();
  133. end
  134.  
  135. -- stop all actors
  136. function ClearActors()
  137.   gpio.write(pinBeeper, 0);
  138.   gpio.write(pinLampRed, 0);
  139.   gpio.write(pinLampYellow, 0);
  140.   gpio.write(pinLampGreen, 0);
  141. end
  142.  
  143. -- hard beep for duration milliseconds
  144. function Beep(duration)
  145.   duration = duration or 500;
  146.   gpio.write(pinBeeper, 1);
  147.   tmr.delay(duration * 1000);
  148.   gpio.write(pinBeeper, 0);
  149. end
  150.  
  151. -- signal image "WAITING FOR IP": red/yellow alternating blink
  152. function SignalWaitIP()
  153.     signalRed = SIG_BLINK;
  154.     signalYellow = SIG_BLINK_REV;
  155.     signalGreen = SIG_OFF;
  156.     signalBeeper = SIG_OFF;
  157.     UpdateSignaleer();
  158. end
  159.  
  160. -- signal image "WAITING FOR UPDATE": red/yellow+green alternating blink
  161. function SignalWaitUpdate()
  162.     signalRed = SIG_BLINK;
  163.     signalYellow = SIG_BLINK_REV;
  164.     signalGreen = SIG_BLINK_REV;
  165.     signalBeeper = SIG_OFF;
  166.     UpdateSignaleer();
  167. end
  168.  
  169. -- signal image "GENERAL ERROR": red/beeper alternating blink
  170. function SignalErrorStatus()
  171.     signalRed = SIG_BLINK;
  172.     signalYellow = SIG_OFF;
  173.     signalGreen = SIG_OFF;
  174.     signalBeeper = SIG_BLINK_REV;
  175.     UpdateSignaleer();
  176. end
  177.  
  178. -- fetch status URL from HTTP server
  179. function ExecutePoll()
  180.   print("Polling " .. httpURL .. " for update...");
  181.   http.get(httpURL, nil, function(code, data)
  182.     if (code == 200) then
  183.       -- reset poll fail count
  184.       pollFails = 0;
  185.       -- parse the received data
  186.       if ParseStatusString(data) == 0 then
  187.         print("OK: " .. stringLastStatus);
  188.       else
  189.         print("FAIL: Protocol error (Magic not found).");
  190.       end
  191.     else
  192.       pollFails = pollFails + 1;
  193.       if pollFails < pollMaxRetries then
  194.         -- schedule retry
  195.         print("FAIL (Code " .. code .. "): Scheduling retry #" .. pollFails .. "...");
  196.         tmr.alarm(timerRescheduler, (pollRetryDelay * 1000), tmr.ALARM_SINGLE, function()
  197.             -- execute rescheduled Poll
  198.             ExecutePoll();
  199.         end)
  200.       else
  201.         -- give up
  202.         print("FAIL (Code " .. code .. "): Update failed.");
  203.         stringLastStatus = 'ERROR';
  204.         pollFails = 0;
  205.       end
  206.     end
  207.   end)
  208. end
  209.  
  210. -- parse status string from HTTP server
  211. function ParseStatusString(statusString)
  212.     -- statusString must start with protocol magic string
  213.     if string.find(statusString, magicID) == 1 then
  214.         -- parse status String (thanks to RyanE@Freenode)
  215.         for kv in (statusString .. ";"):gfind("(.-);") do local _,_,k,v = kv:find("(.+)=(.+)")
  216.             if (k == "R") then signalRed = v end
  217.             if (k == "Y") then signalYellow = v end
  218.             if (k == "G") then signalGreen = v end
  219.             if (k == "S") then signalBeeper = v end
  220.         end        
  221.         stringLastStatus = statusString;
  222.         return 0;
  223.     else
  224.         -- magic ID not present : Communications error, probably wrong protocol/URL
  225.         stringLastStatus = "ERROR";
  226.         return -1;
  227.     end
  228. end
  229.  
  230. -- update signaleer with current signal image & implement beep duration limiter
  231. function UpdateSignaleer()
  232.     -- upate lamps
  233.     UpdatePin(pinLampRed, signalRed);
  234.     UpdatePin(pinLampYellow, signalYellow);
  235.     UpdatePin(pinLampGreen, signalGreen);
  236.     -- detect state transition: beeper disabled->enabled - arm beep limiter
  237.     if signalBeeperPrevious == SIG_OFF and signalBeeper ~= SIG_OFF then
  238.         -- spin up one-shot timer
  239.         tmr.alarm(timerResetBeeper, (beepMaxDuration * 1000), tmr.ALARM_SINGLE, function()
  240.             -- trigger beep limiter: set flag after beepMaxDuration
  241.             flagBeeptimeExceeded = 1;
  242.             --print("Beeper maximum alert duration exceeded; limiter triggered.");
  243.         end)
  244.     end
  245.     -- detect state transition: beeper enabled->disabled - reset beep limiter
  246.     if signalBeeperPrevious ~= SIG_OFF and signalBeeper == SIG_OFF then
  247.         -- reset & disarm beep limiter
  248.         flagBeeptimeExceeded = 0;
  249.         tmr.stop(timerResetBeeper);
  250.         tmr.unregister(timerResetBeeper);
  251.     end
  252.     signalBeeperPrevious = signalBeeper;
  253.     -- check if beep time exceeded
  254.     if flagBeeptimeExceeded == 0 then
  255.         -- no, update beeper according to status string
  256.         UpdatePin(pinBeeper, signalBeeper);
  257.     else
  258.         -- yes, always silence beeper
  259.         UpdatePin(pinBeeper, SIG_OFF);
  260.     end
  261. end
  262.  
  263. -- update GPIO pin with signal value
  264. function UpdatePin(pinNumber, Value)
  265.     if Value == SIG_OFF then
  266.       gpio.write(pinNumber, 0);
  267.     elseif Value == SIG_ON then
  268.       gpio.write(pinNumber, 1);
  269.     elseif Value == SIG_BLINK then
  270.       gpio.write(pinNumber, blinkState);
  271.     elseif Value == SIG_BLINK_REV then
  272.       gpio.write(pinNumber, 1 - blinkState);
  273.     end
  274. end
  275.  
  276. -- string splitter function [sourced from stackoverflow]
  277. function SplitString(pString, pPattern)
  278.    local Table = {}  -- NOTE: use {n = 0} in Lua-5.0
  279.    local fpat = "(.-)" .. pPattern
  280.    local last_end = 1
  281.    local s, e, cap = pString:find(fpat, 1)
  282.    while s do
  283.       if s ~= 1 or cap ~= "" then
  284.      table.insert(Table,cap)
  285.       end
  286.       last_end = e+1
  287.       s, e, cap = pString:find(fpat, last_end)
  288.    end
  289.    if last_end <= #pString then
  290.       cap = pString:sub(last_end)
  291.       table.insert(Table, cap)
  292.    end
  293.    return Table
  294. end
  295.  
  296. -- main program
  297. print("");
  298. print("");
  299. print("WiFi IoT Signaleer - (c) 2016 Chris Burri @ NISTON Engineering Works");
  300. print("See http://niston.wordpress.com");
  301. print("");
  302. -- initialize GPIO
  303. InitGPIO();
  304. -- Power On Self Test
  305. print ("Lamps & Beeper Test...");
  306. TestActors();
  307. -- Setup and connect WiFi
  308. SetupWiFi();
  309.  
  310. -- setup main "loop" timer
  311. tmr.alarm(timerBlink, intervalBlink, 1, function()
  312.   -- toggle blinker state
  313.   blinkState = 1 - blinkState;
  314.   -- update light signal & beeper status
  315.   if wifi.sta.getip() == nil then
  316.     -- waiting for IP: blink red/yellow alternating
  317.     SignalWaitIP();
  318.   elseif stringLastStatus == nil then
  319.     -- first status update: blink red/yellow&green alternating
  320.     SignalWaitUpdate();
  321.   elseif stringLastStatus == 'ERROR' then
  322.     -- ERROR: blink red
  323.     SignalErrorStatus();
  324.   else
  325.     -- OK; Update signaleer according to signal image variables
  326.     UpdateSignaleer();    
  327.   end
  328. end)
  329.  
  330. -- setup HTTP polling timer
  331. tmr.alarm(timerPoll, pollInterval * 1000, 1, function()
  332.   if wifi.sta.getip() ~= nil then
  333.     ExecutePoll();
  334.   end
  335. end)
  336.  
  337. -- ## END OF CODE ##
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement