0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

NodeMCU で web LED signal

Last updated at Posted at 2017-01-08

infinite loop さんが Crystal Signal Pi と言う製品を発売されました。Raspberry Pi を使った RGB color LED 信号灯です。これって NodeMCU で間に合うよね、と貧乏性なワタシです。当初は MicroPython で考えてみたものの、socket の非同期動作ができない(?)と言うことで不慣れな Lua で書いています。結局 socket の非同期処理とは関係なく、コマンドのパラメータをグローバルに置いてタイマで LED の点滅制御をしています。排他、それ何?みたいな雑なコードですみません。無駄に 100ms 毎にタイマ割込みを入れているのは PWM による LED の明るさ制御も自前でやってみようとした名残りです。

http://example.com//ctrl/?red=0&green=64&blue=255&period=500&rpt=300 のようににして使います。このパラメータ形式は当初の Crystal Sigal Pi の仕様にならったつもりなのですが、現行の仕様とは異なります。YouTubeにバラックで動作中の様子を置きました。

websignal.lua

params = {red=0, green=0, blue=0, period=500, rpt=0}
ptimer = 0
power = false

pwm.setup(1, 500, 0) -- LED RED
pwm.setup(2, 500, 0) -- LED GREEN
pwm.setup(3, 500, 0) -- LED BLUE
pwm.start(1)
pwm.start(2)
pwm.start(3)

function split(str, pattern, n)
   if not string.find(str, pattern) then
	  return { str }
   end
   local result = {}
   local fpat = "(.-)" .. pattern
   local insertCnt = 1
   local lastEnd = 1
   local s, e, cap = string.find(str, fpat, 1)
   while s do
	  if insertCnt > n and n > 0 then
		 break
	  end
	  if s ~= 1 or cap ~= "" then
		 table.insert(result, cap)
	  end
	  insertCnt = insertCnt + 1
	  lastEnd = e + 1
	  s, e, cap = string.find(str, fpat, lastEnd)
   end
   if lastEnd <= #str then
	  cap = string.sub(str, lastEnd)
	  table.insert(result, cap)
   end
   return result
end

function pp()
   local k, v
   local s = ""
   for k,v in pairs(params) do s = s.."<br>\n"..k..":"..v end
   return s
end

function getparams(s)
   local t = split(s, "\n", 2) -- get first line
   t = split(t[1], " ", 4) -- get 'GET' argument
   -- t[1]: s = "/ctrl/?red=0&green=64&blue=255&period=500&rpt=300"
   t = split(t[2], "/", 2)
   if not (#t > 1 and t[1] == 'ctrl' and string.sub(t[2], 1, 1) == '?') then
	  return false
   end
   tt = split(string.sub(t[2], 2), "&", 10)
   local k, v
   for k, v in pairs(tt) do
	  local a = split(v, "=", 2)
	  local k = a[1]
	  local v = a[2]
	  if params[k] ~= nil then
		 v = tonumber(v)
		 if v < 0 then v = 0 end
		 if k ~= 'period' and k ~= 'rpt' and v > 1023 then v = 1023 end
		 params[k] = v
	  end
   end
   print(pp())
   tmfunc()

   return true
end

function led(r, g, b)
   print("R:"..r..",G:"..g..",B:"..b)
   pwm.setduty(1, r)
   pwm.setduty(2, g)
   pwm.setduty(3, b)
end

function tmfunc()
   local npower = power
   if params['rpt'] > 0 then
	  if params['period'] == 0 then
		 npower = true
	  else
		 if ptimer > 0 then
			ptimer = ptimer - 1
		 else
			npower = not power
			if not npower then params['rpt'] = params['rpt'] - 1 end
			ptimer = params['period'] / 200
		 end
	  end
   else
	  npower = off
   end

   -- LED on or off by params['power']
   if power ~= npower then
	  power = npower
	  if power then led(params['red'], params['green'], params['blue']) else led(0, 0, 0) end
   end
end

--

wifi.setmode(wifi.STATION)
wifi.sta.config("SSID", "PASSWORD")
wifi.sta.autoconnect(1)

tmr.register(0, 100, tmr.ALARM_AUTO, function() tmfunc() end)
tmr.start(0)

srv=net.createServer(net.TCP)
srv:listen(80,
		   function(conn) 
			  conn:on("receive",
					  function(conn,payload) 
						 print(payload)
						 local r = getparams(payload)
						 if r then
							conn:send("<h1>ESP8266 - Signal NodeMCU working!</h1><p>"..pp().."</p>")
						 else
							conn:send("<h1>ESP8266 - Server is working!</h1><p>"..pp().."</p>")
						 end
						 conn:close()
			  end)
end)
0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?