Tuesday, October 4, 2016

ChiliPeppr Cayenn Protocol for Lua on NodeMCU ESP8266

This code let's you announce your devices presence to ChiliPeppr's Serial Port JSON Server. When you announce, a message is sent back to you with what the server is. The goal here is to let the ChiliPeppr browser app popup an icon showing the existence of your device.

-- UDP Hello Announce v3
--local M = {}
M = {}

M.port = 8988
M.myip = nil
M.sock = nil

--M.announce = 

M.isInitted = false

function M.init(jsonTagTable)
  
  print("Initting...")

  -- figure out if i have an IP
  M.myip = wifi.sta.getip()
  if M.myip == nil then
    print("You need to connect to wifi. Unable to init.")
  else 
    print("My IP: " .. M.myip)
    M.isInitted = true

    -- create socket for outbound UDP sending
    M.sock = net.createConnection(net.UDP, 0)

    -- create server to listen to incoming udp
    M.initUdpServer()
    
    -- create server to listen to incoming tcp
    M.initTcpServer()
    
    -- send our announce
    M.sendBroadcast(jsonTagTable)
  
  end 
  
end

function M.createAnnounce(jsonTagTable)
  
  -- see if there is a jsontagtable passed in as extra meta
  local jsontag = ""
  if jsonTagTable ~= nil then
    ok, jsontag = pcall(cjson.encode, jsonTagTable)
    if ok then
      --print("Adding jsontagtable" .. jsontag)
    else
      print("failed to encode jsontag!")
    end
  end

  local a = {}
  a.Announce = "i-am-a-client"
  a.Widget = "com-chilipeppr-widget-ina219"
  a.MyDeviceId = "chip:" .. node.chipid() .. "-flash:" .. node.flashid() .. "-mac:" .. wifi.sta.getmac()
  a.JsonTag = jsontag
  
  local ok, json = pcall(cjson.encode, a)
  if ok then
    --print("Encoded json for announce: " .. json)
  else
    print("failed to encode json!")
  end
  return json
end

-- send announce to broadcast addr so spjs 
-- knows of our existence
function M.sendBroadcast(jsonTagTable)
  if M.isInitted == false then
    print("You must init first.")
    return 
  end
  
  local bip = wifi.sta.getbroadcast()
  --print("Broadcast addr:" .. bip)
  
  print("Sending announce to ip: " .. bip)
  M.sock:connect(M.port, bip)
  M.sock:send(M.createAnnounce(jsonTagTable))
  M.sock:close()
  
end

function M.setupWifi()
  -- setwifi
  wifi.setmode(wifi.STATION)
  -- longest range is b
  wifi.setphymode(wifi.PHYMODE_B)
  --Connect to access point automatically when in range
  wifi.sta.config("NETGEAR-main", "blah")
  wifi.sta.connect()
  
  --register callback
  wifi.sta.eventMonReg(wifi.STA_IDLE, function() print("STATION_IDLE") end)
  --wifi.sta.eventMonReg(wifi.STA_CONNECTING, function() print("STATION_CONNECTING") end)
  wifi.sta.eventMonReg(wifi.STA_WRONGPWD, function() print("STATION_WRONG_PASSWORD") end)
  wifi.sta.eventMonReg(wifi.STA_APNOTFOUND, function() print("STATION_NO_AP_FOUND") end)
  wifi.sta.eventMonReg(wifi.STA_FAIL, function() print("STATION_CONNECT_FAIL") end)
  wifi.sta.eventMonReg(wifi.STA_GOTIP, M.gotip)
  
  --register callback: use previous state
  wifi.sta.eventMonReg(wifi.STA_CONNECTING, function(previous_State)
      if(previous_State==wifi.STA_GOTIP) then 
          print("Station lost connection with access point\n\tAttempting to reconnect...")
      else
          print("STATION_CONNECTING")
      end
  end)
  
  --start WiFi event monitor with default interval
  wifi.sta.eventMonStart(1000)
  
end

function M.gotip()
  print("STATION_GOT_IP")
  M.myip = wifi.sta.getip()
  print("My IP: " .. M.myip)
end


function M.sendinit()
  -- we need to send a UDP announce packet to every IP
  -- on the subnet to let any possible SPJS know we are
  -- available

  -- iterate thru entire subnet
  M.ipctr = 1
  tmr.alarm(6, 200, tmr.ALARM_SINGLE, M.sendNextHello)

end

function M.sendNextHello()
  
  local i, j = string.find(M.myip, "%.%d+$")
  local prefix = string.sub(M.myip, 0, i)
  local ip = prefix .. M.ipctr
  print("Sending announce to ip: " .. ip)
  M.sock:connect(M.port, ip)
  M.sock:send(M.announce)
  M.sock:close()
  M.ipctr = M.ipctr + 1

  if M.ipctr < 25 then
    tmr.alarm(6, 50, tmr.ALARM_SINGLE, M.sendNextHello)
  end

end

function M.initUdpServer()
  M.udpServer = net.createServer(net.UDP)
  --M.udpServer:on("connection", M.onUdpConnection)
  M.udpServer:on("receive", M.onUdpRecv) 
  M.udpServer:listen(8988)
  print("UDP Server started on port 8988")
end

function M.onUdpConnection(sck)
  print("UDP connection.")
  --ip, port = sck:getpeer()
  --print("UDP connection. from: " .. ip)
end

function M.onUdpRecv(sck, data)
  print("UDP Recvd. data: " .. data)
end

function M.initTcpServer()
  M.tcpServer = net.createServer(net.TCP)
  M.tcpServer:listen(8988, M.onTcpListen)
  
  print("TCP Server started on port 8988")
end

function M.onTcpListen(conn)
  conn:on("receive", M.onTcpRecv)
end

function M.onTcpConnection(sck)
  print("TCP connection.")
  --ip, port = sck:getpeer()
  --print("UDP connection. from: " .. ip)
end

function M.onTcpRecv(sck, data)
  local peer = sck:getpeer()
  print("TCP Recvd. data: " .. data .. ", Peer:" .. peer)
end

function M.subscribe(cmd, callback)
  -- we need to inject this cmd to a table so
  -- we can see if any incoming data matches this cmd
  -- and if so we call the callback with the payload
  if M.subscriptionCmds == nil then
    M.subscriptionCmds = {}
  end
  
  if M.subscriptionCmds[cmd] ~= nil then
    print("Warning. Subscription already existed. Overwriting. cmd:" .. cmd)
  end
  
  M.subscriptionCmds[cmd] = callback
  
  -- debug. comment out for production
  M.printKeys(M.subscriptionCmds)

end

-- We will be passed something like /getVals {timeStart:0, timeEnd:100}
-- Or something like /getVals
-- Or something like /setReports {"samples":10, "intervalms", 100}
function M.parseAndPublish(cmd)
  -- get the signal name which is the first part with the / (slash)
  local i, j = string.find(cmd, " ")
  local signal = string.sub(cmd, 0, i - 1)
  local payload = string.sub(cmd, j + 1)
  print("signal got:\"" .. signal .. "\"")
  print("payload:\"" .. payload .. "\"")
  
  -- see if this cmd is subscribed to
  if M.subscriptionCmds[signal] ~= nil then
    M.subscriptionCmds[signal](payload)
  else
    print("Nobody is subscribed to signal:" .. signal)
  end
  
end

function M.printKeys(table)
  --local keyset={}
  local n=0
  
  print("Subscriptions:")
  for k,v in pairs(table) do
    n=n+1
    --keyset[n]=k
    if k ~= nil then
      print("  Signal:" .. k .. ", Callback:good")
    else
      print("  Signal:" .. k .. ", Callback:empty")
    end
    
  end
  --print(cjson.encode(keyset))
end

--return M

--M.setupWifi()
--M.init()
--M.initServer()
--M.sendBroadcast()

cayenn = M

1 comment:

  1. 10 Teton White Wheels, Stainless Steel Wheels | Tithole Engineering
    9 Teton White Wheels. This chrome-plated travel case features the microtouch titanium latest in-line features to help you find the perfect combination for your tube supplier next mens titanium watches trip. Rating: 3.7 · ‎1,586 reviews · titanium stud earrings ‎$52.00 · burnt titanium ‎In stock

    ReplyDelete