#!/usr/bin/lua require("json") require("socket") function startswith(String,Start) if String then return string.sub(String,1,string.len(Start))==Start else return False end end function url_encode(str) if (str) then str = string.gsub (str, "\n", "\r\n") str = string.gsub (str, "([^%w %-%_%.%~])", function (c) return string.format ("%%%02X", string.byte(c)) end) str = string.gsub (str, " ", "+") end return str end function capture(cmd, raw) local f = assert(io.popen(cmd, 'r')) local s = assert(f:read('*a')) f:close() if raw then return s end s = string.gsub(s, '^%s+', '') s = string.gsub(s, '%s+$', '') s = string.gsub(s, '[\n\r]+', ' ') return s end function mqtt_encode(str) if (str) then str = string.gsub (str, "\n", "") str = string.gsub (str, "/", "-") end return str end function getConfig(configname) local uci=require("uci") local cur=uci.cursor() local config if configname then config=configname else config="weathermon" end web_url = cur.get(config,"web","url") web_user = cur.get(config,"web","user") web_pass = cur.get(config,"web","password") web_devid = cur.get(config,"web","devid") web_iface = cur.get(config,"web","iface") if web_iface then command = '/sbin/ifconfig '..web_iface..' | grep \'\\\' | sed -n \'1p\' | tr -s \' \' | cut -d \' \' -f3 | cut -d \':\' -f2' f=io.popen(command,'r') ip_addr=f:read() end if not web_devid then if web_iface then io.input("/sys/class/net/"..web_iface.."/address") else io.input("/sys/class/net/eth0/address") end mac = io.read("*line") mac = mac:gsub(":","") mac = mac:upper() web_devid = mac end logging = cur.get(config,"logging","enabled") touch_file = cur.get(config,"logging","touch_file") serial_port = cur.get(config,"serial","port") serial_baud = cur.get(config,"serial","baud") input_file = cur.get(config,"input","file") input_exec = cur.get(config,"input","exec") alarm_exec = cur.get(config,"alarm","exec") if serial_port then command = "stty -F "..serial_port.." "..serial_baud capture(command) end mqtt_host = cur.get(config,"mqtt","host") mqtt_port = cur.get(config,"mqtt","port") mqtt_id = cur.get(config,"mqtt","id") mqtt_topic = cur.get(config,"mqtt","topic") mqtt_alarm_topic = cur.get(config,"mqtt","alarm_topic") mqtt_user = cur.get(config,"mqtt","user") mqtt_passwd = cur.get(config,"mqtt","password") if mqtt_host and not mqtt_id then mqtt_id="weather-"..web_devid end if mqtt_host and not mqtt_port then mqtt_port = 1883 end if mqtt_host and not mqtt_topic then mqtt_topic = 'weathermon/{dev}/{type}/{id}/{param}' end if mqtt_host and not mqtt_alarm_topic then mqtt_alarm_topic = 'alarm/{dev}/{type}/{id}' end end function touch() if touch_file then local file = io.open(touch_file, 'w') file:close() end end function sleep(sec) socket.select(nil, nil, sec) end function splitStr(str,char) local res = {} local idx = 1 while str:len()>0 do pos = str:find(char); if pos == nil then res[idx]=str str="" else res[idx]=str:sub(1,pos-1) idx=idx+1 str=str:sub(pos+1) end end return res end function printLog(str) if logging=="on" then capture("logger -t weathermon "..str) print(str) elseif logging=="syslog" then capture("logger -t weathermon "..str) elseif logging=="stdout" then print(str) end end function submitValue(type,id,param,val) url = web_url.."?stype="..url_encode(type).."&sid="..url_encode(id).."¶m="..url_encode(param).."&value="..url_encode(val) command = "curl" if web_iface then command = command.." --interface "..ip_addr end if web_user then command = command.." -u "..web_user..":"..web_pass end command = command.." \""..url.."\" 2>&1" result = capture(command) touch() end function processJson(str) msg=json.decode(str) sensor={} for key,value in pairs(msg) do if value then if key=="model" or key=="device" then sensor_type=value elseif key=="id" then sensor_id=value elseif key=='time' then sensor_time=value else sensor[key]=value end end end if not (sensor_type==nil or sensor_id==nil or sensor_type=='' or sensor_id=='') then if next(sensor)==nil then sensor["command"]="alarm" end for k,v in pairs(sensor) do printLog("Type = "..sensor_type..", ID = "..sensor_id..", Param = "..k..", Value = \""..v.."\"") submitValue(sensor_type,sensor_id,k,v) if mqtt_client then mqtt_path=string.gsub(mqtt_topic,"{(.-)}", function (name) if name=="dev" then return mqtt_encode(web_devid) elseif name=="type" then return mqtt_encode(sensor_type) elseif name=="id" then return mqtt_encode(sensor_id) elseif name=="param" then return k else return '{'..name..'}' end end) mqtt_client:publish(mqtt_path,v) end end else printLog("Cannot parse sensor input: "..msg_body) end end function processLine(str) msg=splitStr(line,':') msg_type=msg[1] or '' msg_body=msg[2] or '' if msg_type=="STATUS" then printLog("Status: "..msg_body) elseif msg_type=="ERROR" then printLog("Error: "..msg_body) elseif msg_type=="SENSOR" then printLog("SENSOR: "..msg_body) sens = splitStr(msg_body,",") sensor = {} idx = 1 sensor_type = nil sensor_id = web_devid for i,rec in ipairs(sens) do recrd=splitStr(rec,'=') key=recrd[1] or '' value=recrd[2] or '' if value then if key=="TYPE" then sensor_type=value elseif key=="ID" then sensor_id=value else sensor[key]=value end end end if not (sensor_type==nil or sensor_id==nil or sensor_type=='' or sensor_id=='') then for k,v in pairs(sensor) do printLog("Type = "..sensor_type..", ID = "..sensor_id..", Param = "..k..", Value = "..v) submitValue(sensor_type,sensor_id,k,v) if mqtt_client then mqtt_path=string.gsub(mqtt_topic,"{(.-)}", function (name) if name=="dev" then return web_devid elseif name=="type" then return sensor_type elseif name=="id" then return sensor_id elseif name=="param" then return k else return '{'..name..'}' end end) mqtt_client:publish(mqtt_path,v) end end else printLog("Cannot parse sensor input: "..msg_body) end elseif msg_type=="ALARM" then printLog("ALARM: "..msg_body) sens = splitStr(msg_body,",") sensor = {} idx = 1 sensor_type = nil sensor_id = web_devid mqtt_param = {} for i,rec in ipairs(sens) do recrd=splitStr(rec,'=') key=recrd[1] or '' value=recrd[2] or '' if value then if key=="TYPE" then alarm_type=value elseif key=="ID" then alarm_id=value end end end if not (alarm_type==nil or alarm_id==nil or alarm_type=='' or alarm_id=='') then if mqtt_client then mqtt_path=string.gsub(mqtt_alarm_topic,"{(.-)}", function (name) if name=="dev" then return web_devid elseif name=="type" then return sensor_type elseif name=="id" then return sensor_id else return '{'..name..'}' end end) mqtt_client:publish(mqtt_path,msg_body) end if alarm_exec then command=alarm_exec.. " \""..string.gsub(alarm_type,"\"","\\\"").. "\" \""..string.gsub(alarm_id,"\"","\\\"").. "\" \""..string.gsub(msg_body,"\"","\\\"").."\"" capture(command) end else printLog("Cannot parse alarm input: "..msg_body) end end end getConfig(arg[1]) if mqtt_host then MQTT = require "mosquitto" mqtt_client = MQTT.new(mqtt_id) if mqtt_user then mqtt_client:login_set(mqtt_user, mqtt_passwd) end mqtt_client:connect(mqtt_host,mqtt_port) end if serial_port then serialin=io.open(serial_port,"r") elseif input_file == "-" then serialin=io.stdin; elseif input_file then serialin=io.open(input_file,"r") elseif input_exec then serialin=io.popen(input_exec,"r") else printLog("No input selected") return end while 1 do line=serialin:read() if line == nil then break end printLog("Received: "..line); if startswith(line,'{') then processJson(line) else processLine(line) end end