#!/usr/bin/lua socket = require "socket" json = require "json" require "uci" cur = uci.cursor() require "wm_util" config_name = arg[1] if not config_name then config_name = "weathermon" end weather_file = uci.get(config_name,"process","dump_file") weather_db = uci.get(config_name,"process","logdb") graph_duration = uci.get(config_name,"display","graph_duration") if graph_duration and not(weather_db == "") then pcall(function () local dbdriver = require "luasql.sqlite3" env = assert(dbdriver.sqlite3()) log_con = assert(env:connect(weather_db)) end) end function round(num, numDecimalPlaces) local mult = 10^(numDecimalPlaces or 0) return math.floor(num * mult + 0.5) / mult end function trim(s) return (s:gsub("^%s*(.-)%s*$", "%1")) end function lpad(s, l, c) local res = string.rep(c or ' ', l - #s) .. s return res, res ~= s end function process_file() txt = get_file_content(weather_file) data = json.decode(txt) for k,v in pairs(data) do return v end end function get_display_config() width = tonumber(uci.get(config_name,"display","width")) height = tonumber(uci.get(config_name,"display","height")) charwidth = tonumber(uci.get(config_name,"display","charwidth")) charheight = tonumber(uci.get(config_name,"display","charheight")) title = uci.get(config_name,"display","title") pages = {} pagetitles = {} pagedurations = {} pagecolumns = {} pagecolwidth = {} local page, def, line, col, pos cur.foreach(config_name,"display", function(s) page = {} local columns = s["columns"] if not columns or columns == "" then columns = 1 else columns = tonumber(columns) end local pagetitle = s["title"] if not pagetitle then pagetitle = title end local pageduration = s["duration"] if not (pagetitle=="") then line = 2 else line = 1 end col = 1 pos = 0 for k,v in pairs(s["parameter"]) do def = {} if not(v == "") then v = split(v,":") def["sensor"] = v[1] def["param"] = v[2] def["label"] = v[3] def["unit"] = v[4] def["scale"] = tonumber(v[5]) def["round"] = tonumber(v[6]) def["pos"] = tonumber(v[7]) def["line"] = line def["col"] = col page[#page+1] = def end col = col + 1 if col > columns then col = 1 line = line + 1 end end pages[#pages+1] = page pagetitles[#pages] = pagetitle pagedurations[#pages] = pageduration pagecolumns[#pages] = columns pagecolwidth[#pages] = math.floor(width/columns) end) end function connect_server() local ip = uci.get(config_name,"display","server") local port = uci.get(config_name,"display","port") conn = socket.connect(ip,port) return conn end function write_command(conn,command) conn:send(command.."\n") local str=conn:receive() return str end function setup_pages(conn) write_command(conn,"hello") write_command(conn,"client_set -name weathermon") for i,page in pairs(pages) do local pageid = "page"..trim(tostring(i)) write_command(conn,"screen_add "..pageid) local pagetitle = pagetitles[i] write_command(conn,"screen_set "..pageid.." -cursor off") if not(pagetitle == "") then write_command(conn,"screen_set "..pageid.." -name "..pagetitle) write_command(conn,"widget_add "..pageid.." "..pageid..".title title") write_command(conn,"widget_set "..pageid.." "..pageid..".title \"".. pagetitle.."\"") end local pageduration = pagedurations[i] if pageduration and not(pageduration == "") then write_command(conn,"screen_set "..pageid.." -duration "..pageduration) end for j,def in pairs(page) do defid = def["sensor"].."."..def["param"] write_command(conn,"widget_add "..pageid.." "..defid.." string") end end if log_con then for i,page in pairs(pages) do for j,def in pairs(page) do pageid = def["sensor"].."."..def["param"] pagetitle = trim(def["label"])..", "..def["unit"] write_command(conn,"screen_add "..pageid) write_command(conn,"screen_set "..pageid.." -cursor off -name "..pagetitle.." -duration "..graph_duration) write_command(conn,"widget_add "..pageid.." "..pageid..".title title") if height>2 then write_command(conn,"widget_add "..pageid.." "..pageid..".max string") write_command(conn,"widget_add "..pageid.." "..pageid..".min string") for k = 3,height-1 do write_command(conn,"widget_add "..pageid.." "..pageid..".place"..trim(tostring(k)).." string") end end write_command(conn,"widget_set "..pageid.." "..pageid..".title \"".. pagetitle.."\"") end end end end function process_vals(vals) for i,page in pairs(pages) do col_width = pagecolwidth[i] local pageid = "page"..trim(tostring(i)) for j,def in pairs(page) do val = vals[def["sensor"]][def["param"]] if val then val = round(val * def["scale"], def["round"]) end defid = def["sensor"].."."..def["param"] val = lpad(tostring(val),def["pos"]).." "..def["unit"] if not(def["label"] == "") then val = def["label"]..": "..val end write_command(conn,"widget_set "..pageid.." "..defid.." "..trim(tostring((def["col"]-1)*col_width+1)).." "..def["line"].." \""..val.."\"") end end end function process_graphs() for i,page in pairs(pages) do for j,def in pairs(page) do local sensor = def["sensor"] local param = def["param"] local pageid = sensor.."."..param local sqlcur = assert (log_con:execute(string.format("select hour,avg(value) val from (select strftime('%%Y-%%m-%%d %%H',time_stamp)||':00' hour,value from log where sensor='%s' and param='%s') group by hour order by hour desc limit 24",sensor,param))) local row = sqlcur:fetch ({}, "a") local vals = {} local maxval = -99999999 local minval = 99999999 local len for k=width,1,-1 do if row then val = row["val"] * def["scale"] row = sqlcur:fetch ({}, "a") else val = nil end vals[k] = val if val and (val > maxval) then maxval = val; end if val and (val < minval) then minval = val; end end sqlcur:close() minval = math.floor(minval) maxval = math.ceil(maxval) if height>2 then local minvalstr = trim(tostring(minval)) local maxvalstr = trim(tostring(maxval)) len = math.max(string.len(minvalstr),string.len(maxvalstr)) write_command(conn,"widget_set "..pageid.." "..pageid..".max "..trim(tostring(width-string.len(maxvalstr)+1)).." 2 "..maxvalstr) write_command(conn,"widget_set "..pageid.." "..pageid..".min "..trim(tostring(width-string.len(minvalstr)+1)).." "..height.." "..minvalstr) for k = 3,height-1 do write_command(conn,"widget_set "..pageid.." "..pageid..".place"..trim(tostring(k)).." "..trim(tostring(width-len+1)).." "..k.." \" "..string.rep("-",len-1).."\"") end else len = 0 end local m = width for k=1,width do write_command(conn,"widget_del "..pageid.." "..pageid..".bar"..trim(tostring(k))) end for k = width-len,1,-1 do val = vals[m] if val then h = math.floor(0.5+(val-minval)/(maxval-minval)*(height-1)*charheight) else h = 0 end write_command(conn,"widget_add "..pageid.." "..pageid..".bar"..trim(tostring(k)).." vbar") write_command(conn,"widget_set "..pageid.." "..pageid..".bar"..trim(tostring(k)).." "..k.." "..height.." "..h) m = m - 1 end end end end get_display_config() conn = connect_server() setup_pages(conn) while true do -- pcall( function () vals = process_file() process_vals(vals) if weather_db then process_graphs() end os.execute("inotifywait -e MODIFY \""..weather_file.."\"") -- end) socket.sleep(3) end