Browse Source

genesis

master
Sophie Schiller 2 years ago
parent
commit
8e04ef49a6
  1. 45
      colorutils.lua
  2. 84
      init.lua
  3. 209
      led.lua
  4. 34
      list.lua
  5. 6
      lookup.lua
  6. 62
      message_handler.lua
  7. 42
      mqtt.lua
  8. 14
      settings.lua
  9. 30
      trigonometric.lua

45
colorutils.lua

@ -0,0 +1,45 @@
function rgbToHsv(r, g, b, a)
r, g, b, a = r / 255, g / 255, b / 255, a / 255
local max, min = math.max(r, g, b), math.min(r, g, b)
local h, s, v
v = max
local d = max - min
if max == 0 then s = 0 else s = d / max end
if max == min then
h = 0 -- achromatic
else
if max == r then
h = (g - b) / d
if g < b then h = h + 6 end
elseif max == g then h = (b - r) / d + 2
elseif max == b then h = (r - g) / d + 4
end
h = h / 6
end
return h, s, v, a
end
function hsvToRgb(h, s, v, a)
local r, g, b
local i = math.floor(h * 6);
local f = h * 6 - i;
local p = v * (1 - s);
local q = v * (1 - f * s);
local t = v * (1 - (1 - f) * s);
i = i % 6
if i == 0 then r, g, b = v, t, p
elseif i == 1 then r, g, b = q, v, p
elseif i == 2 then r, g, b = p, v, t
elseif i == 3 then r, g, b = p, q, v
elseif i == 4 then r, g, b = t, p, v
elseif i == 5 then r, g, b = v, p, q
end
return r * 255, g * 255, b * 255, a * 255
end

84
init.lua

@ -0,0 +1,84 @@
-- load credentials, 'SSID' and 'PASSWORD' declared and initialize in there
dofile("settings.lua")
function startup()
if abort == true then
print('startup aborted')
return
end
if file.open("init.lua") == nil then
print("init.lua deleted or renamed")
else
print("Running")
file.close("init.lua")
print("enabling LEDs")
dofile("led.lua")
print("setup message handling")
dofile("message_handler.lua")
print("connect to mqtt")
dofile("mqtt.lua")
end
end
-- Define WiFi station event callbacks
wifi_connect_event = function(T)
print("Connection to AP("..T.SSID..") established!")
print("Waiting for IP address...")
if disconnect_ct ~= nil then disconnect_ct = nil end
end
wifi_got_ip_event = function(T)
-- Note: Having an IP address does not mean there is internet access!
-- Internet connectivity can be determined with net.dns.resolve().
print("\n\tSTA - GOT IP".."\n\tStation IP: "..T.IP.."\n\tSubnet mask: "..T.netmask.."\n\tGateway IP: "..T.gateway)
print("Wifi connection is ready! IP address is: "..T.IP)
abort=false
print("Startup will resume momentarily, you have 10 seconds to abort with abort=true")
print("Waiting...")
tmr.create():alarm(10000, tmr.ALARM_SINGLE, startup)
end
wifi_disconnect_event = function(T)
print("disconnect event fired")
if T.reason == wifi.eventmon.reason.ASSOC_LEAVE then
--the station has disassociated from a previously connected AP
return
end
-- total_tries: how many times the station will attempt to connect to the AP. Should consider AP reboot duration.
local total_tries = 75
print("\nWiFi connection to AP("..T.SSID..") has failed!")
--There are many possible disconnect reasons, the following iterates through
--the list and returns the string corresponding to the disconnect reason.
for key,val in pairs(wifi.eventmon.reason) do
if val == T.reason then
print("Disconnect reason: "..val.."("..key..")")
break
end
end
if disconnect_ct == nil then
disconnect_ct = 1
else
disconnect_ct = disconnect_ct + 1
end
if disconnect_ct < total_tries then
print("Retrying connection...(attempt "..(disconnect_ct+1).." of "..total_tries..")")
else
wifi.sta.disconnect()
print("Aborting connection to AP!")
disconnect_ct = nil
end
end
-- Register WiFi Station event callbacks
wifi.eventmon.register(wifi.eventmon.STA_CONNECTED, wifi_connect_event)
wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, wifi_got_ip_event)
wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, wifi_disconnect_event)
print("Connecting to WiFi access point...")
wifi.setmode(wifi.STATION)
wifi.sta.config({ssid=SSID, pwd=PASSWORD})
-- wifi.sta.connect() not necessary because config() uses auto-connect=true by default

209
led.lua

@ -0,0 +1,209 @@
dofile("trigonometric.lua")
dofile("lookup.lua")
dofile("colorutils.lua")
local LED_COUNT = length
ws2812.init()
strip = ws2812.newBuffer(LED_COUNT, 3)
function colorSet(r, g, b)
strip:fill(lup(g),lup(r), lup(b))
ws2812.write(strip)
end
function allOff()
colorSet(0,0,0)
end
function colorSetPartial(r, g, b, percentage)
percentage = percentage % 100
for i=1,math.floor(percentage/100*strip:size())-1 do
strip:set(i,lup(g),lup(r), lup(b))
end
for i=math.floor(percentage/100*strip:size()),strip:size() do
strip:set(i,lup(math.floor(g/3)),lup(math.floor(r/3)), lup(math.floor(b/3)))
end
ws2812.write(strip)
end
function rainbowSetPartial(rotation, percentage)
rotation = rotation % strip:size()
percentage = percentage % 100
local offset = rotation/strip:size()
if math.floor(percentage/100*strip:size()) > 0 then
for i=1,math.floor(percentage/100*strip:size()) do
h_value = (i/strip:size() + offset) % 1
r,g,b = hsvToRgb(h_value, 1, .8, 1)
strip:set(i, lup(g), lup(r), lup(b))
end
end
for i=math.floor(percentage/100*strip:size()),strip:size() do
if i == 0 then
i = 1
end
h_value = (i/strip:size() + offset) % 1
r,g,b = hsvToRgb(h_value, 1, .3, 1)
strip:set(i, lup(g), lup(r), lup(b))
end
ws2812.write(strip)
end
function colorWipe(r, g, b)
allOff()
local i = 1
local t = tmr.create()
t:register(20, tmr.ALARM_AUTO, function()
strip:set(i, lup(g),lup(r), lup(b))
ws2812.write(strip)
i = i+1
if ( i == LED_COUNT) then
t:unregister()
end
end)
t:start()
end
function colorStrobe(r, g, b, strobes)
local j=1
local t = tmr.create()
local lr = lup(r)
local lg = lup(g)
local lb = lup(b)
t:register(70, tmr.ALARM_AUTO, function()
if j%10 == 1 or j%10 == 3 then
strip:fill(lg,lr,lb)
ws2812.write(strip)
else
strip:fill(0,0,0)
ws2812.write(strip)
end
j = j+1
if ( j == 10*strobes) then
t:unregister()
end
end)
t:start()
end
function colorPulse(r, g, b, iterations)
h, s, v = color_utils.grb2hsv(g, r, b)
local steps = 100
local step = 1
local t = tmr.create()
t:register(15, tmr.ALARM_AUTO, function()
local f = 0.5-0.5*fcos(360/steps*step)
g,r,b = color_utils.hsv2grb(h, s, math.floor(f*v))
strip:fill(g,r,b)
ws2812.write(strip)
step = step + 1
if (step > steps*iterations) then
t:unregister()
end
end)
t:start()
end
function colorChase(r, g, b, iterations)
allOff()
local segments = 6
local segment_length = LED_COUNT/segments
local t = tmr.create()
for i=1,LED_COUNT do
if (math.floor(i/segment_length)%3==0) then
strip:set(i,lup(g),lup(r), lup(b))
end
end
local step = 1
local steps = 3
t:register(100, tmr.ALARM_AUTO, function()
ws2812.write(strip)
strip:shift(segment_length, ws2812.SHIFT_CIRCULAR)
step = step+1
if (step > steps*iterations) then
t:unregister()
allOff()
end
end)
t:start()
end
function roundWipe(r, g, b, rounds)
allOff()
local segments = 6
local segment_length = LED_COUNT/segments
local step = math.floor(segment_length/3)
for i=1,segment_length do
strip:set(i, lup(g),lup(r), lup(b))
end
local j=1
local t = tmr.create()
t:register(24, tmr.ALARM_AUTO, function()
ws2812.write(strip)
strip:shift(step, ws2812.SHIFT_CIRCULAR)
j = j+step
if (j > LED_COUNT*rounds) then
t:unregister()
allOff()
end
end)
t:start()
end
function colorRand(rounds)
allOff()
local j = 1
local t = tmr.create()
t:register(24, tmr.ALARM_AUTO, function()
strip:fill(0,0,0)
ws2812.write(strip)
local r=node.random(255)
local g=node.random(255)
local b=node.random(255)
local i=node.random(LED_COUNT)
strip:set(i, g,r,b)
ws2812.write(strip)
j = j+1
if (j > 24*rounds) then
t:unregister()
allOff()
end
end)
t:start()
end
function clamp(val, lower, upper)
return math.max(lower, math.min(upper, val))
end
function activateLight(data)
local s = data["effect"]
local r = clamp(0, data['r'], 255)
local g = clamp(0, data['g'], 255)
local b = clamp(0, data['b'], 255)
local i = clamp(0, data['iterations'], 100)
if s =='color' then
colorSet(r, g, b)
elseif s == 'wipe' then
colorWipe(r, g, b)
elseif s == 'chase' then
colorChase(r, g, b, i)
elseif s == 'strobe' then
colorStrobe(r, g, b, i)
elseif s == 'pulse' then
colorPulse(r, g, b, i)
elseif s == 'round' then
roundWipe(r, g, b, i)
elseif s == 'rand' then
colorRand(i)
elseif s == 'partial' then
colorSetPartial(r, g, b, i)
elseif s == 'rainbow' then
rainbowSetPartial(r, i)
elseif s == 'off' then
allOff()
end
end

34
list.lua

@ -0,0 +1,34 @@
List = {}
function List.new ()
return {first = 0, last = -1}
end
function List.pushleft (list, value)
local first = list.first - 1
list.first = first
list[first] = value
end
function List.pushright (list, value)
local last = list.last + 1
list.last = last
list[last] = value
end
function List.popleft (list)
local first = list.first
if first > list.last then error("list is empty") end
local value = list[first]
list[first] = nil -- to allow garbage collection
list.first = first + 1
return value
end
function List.popright (list)
local last = list.last
if list.first > last then error("list is empty") end
local value = list[last]
list[last] = nil -- to allow garbage collection
list.last = last - 1
return value
end

6
lookup.lua

@ -0,0 +1,6 @@
function lup(i)
local gamma = 2.8
local max_in = 255
local max_out = 255
return math.floor(math.pow(i/max_in, gamma)*max_out + 0.5)
end

62
message_handler.lua

@ -0,0 +1,62 @@
dofile("list.lua")
info = {r=0, g=170, b=255, iterations=3, effect='chase'}
warn = {r=255, g=128, b=0, iterations=5, effect='round'}
err = {r=255, g=0, b=50, iterations=5, effect='strobe'}
misc = {r=0, g=128, b=50,iterations=3, effect='strobe'}
stby = {r=0, g=0, b=0, iterations=1, effect='rainbow'}
rotation = 0
percentage = 0
messages = List.new()
function csplit(str,sep)
local ret={}
local n=1
for w in str:gmatch("([^"..sep.."]*)") do
ret[n] = ret[n] or w -- only set once (so the blank after a string is ignored)
if w=="" then
n = n + 1
end -- step forwards on a blank but not a string
end
return ret
end
function recieveC3VOC(data)
local j = sjson.decode(data)
print(j['msg'])
print(string.match(j['msg'], "Overall Progress"))
if (string.match(j['msg'], "Overall Progress") ) then
local s = csplit(j['msg'], ' ')
print(s[1])
percentage = math.floor(s[#s]:sub(1, -2))
print(percentage)
stby['iterations'] = percentage
end
if not string.match(j['component'], "encoder42") and not string.match(j['component'], "tallycom") and not string.match(j['component'], "fusion") then
if ((j['level'] == 'info') or (j['level'] == 'INFO')) then
List.pushright(messages, info)
elseif ((j['level'] == 'warn') or (j['level'] == 'WARN')) then
List.pushright(messages, warn)
elseif ((j['level'] == 'error') or (j['level'] == 'ERROR')) then
List.pushright(messages, err)
end
end
end
function recieveDirect(data)
List.pushright(messages, data)
end
local t = tmr.create()
t:register(2000, tmr.ALARM_AUTO, function()
rotation = rotation + 1
if pcall(function() data = List.popleft(messages) end) then
activateLight(data)
print("activate event fired")
else
stby['r']=rotation
activateLight(stby)
end
end)
t:start()

42
mqtt.lua

@ -0,0 +1,42 @@
m = mqtt.Client(node.random(1024), 120, mqtt_user, mqtt_password)
m:lwt("/lwt", "offline", 0, 0)
m:on("connect", function(client) print ("connected") end)
m:on("offline", function(client)
print ("offline, reconnecting")
handle_mqtt_error()
end)
m:on("message", function(client, topic, data)
print(topic .. ":" )
if data ~= nil then
print(data)
if topic == "/voc/alert-viri" then
recieveC3VOC(data)
elseif topic == "/signal/led" then
receiveDirect(data)
end
end
end)
function handle_mqtt_error(client, reason)
tmr.create():alarm(10 * 1000, tmr.ALARM_SINGLE, do_mqtt_connect)
end
function do_mqtt_connect()
m:connect(mqtt_server, mqtt_port, 0, function(client)
print("connected")
-- subscribe topic with qos = 0
client:subscribe({["/voc/alert-viri/#"]=0,["/signal/led/#"]=0}, function(client)
roundWipe(0,255,0,1)
end)
end,
function(client, reason)
print("failed reason: " .. reason)
handle_mqtt_error()
end)
end
do_mqtt_connect()

14
settings.lua

@ -0,0 +1,14 @@
-- wifi credentials
SSID = "wifi"
PASSWORD = "changeme"
-- mosquitto info
mqtt_user = "script"
mqtt_password = "changeme"
mqtt_server = "mqtt.example.com"
mqtt_port = 1883
-- led strip length
length = 24
-- length = 144
-- length = 200

30
trigonometric.lua

@ -0,0 +1,30 @@
function fsin(s)
local x=s
if x>180.0 then
x=(x+180)%360-180
elseif x<-180.0 then
x=(x-180)%-360+180
end
if x>90.0 then
x=180.0-x
elseif x<-90.0 then
x=-180-x
end
-- print (x)
x=math.pi*x/180.0
local p=x
local f=1
local r=p
-- print (x)
-- 6 Stellen hinter dem Komma fuer 1/4-Kreis
for j=2,10,2 do
p=-p * x * x
f=f*j*(j+1)
r=r+p/f
end
return(r)
end
function fcos(c)
return fsin(90-c)
end
Loading…
Cancel
Save