#!/usr/bin/lua require "uci" local cur = uci.cursor() local socket = require "socket" local lfs = require "lfs" local json = require "json" require "wm_util" function get_levels_list(config_name) local levels, engage, engage_mode, disengage_mode, levels_idx levels = {} levels_idx = {} engage = {} engage_mode = {} disengage_mode = {} cur.foreach(config_name, "alarm", function(s) local idx = #levels+1 levels[idx] = s["name"] engage[idx] = s["engage"] engage_mode[idx] = s["engage_mode"] disengage_mode[idx] = s["disengage_mode"] levels_idx[s[".name"]] = idx end) return levels, engage, engage_mode, disengage_mode, levels_idx end function get_params(config_name,levels_idx) local a_names, a_formats, a_limits a_names = {} a_formats = {} a_limits = {} cur.foreach(config_name,"params", function(s) if s["name"] then a_names[s["param"]] = s["name"] end if s["format"] or s["scale"] then local format, scale if s["scale"] then scale = s["scale"] else scale = 1 end if s["format"] then format = s["format"] else format = "4s" end a_formats[s["param"]] = {format,scale} end if s["limits"] then for i,record in pairs(s["limits"]) do rec = split(record,":") idx = levels_idx[rec[1]] low = tonumber(rec[2]) high = tonumber(rec[3]) if not a_limits[s["param"]] then a_limits[s["param"]] = {} end if not a_limits[s["param"]][idx] then a_limits[s["param"]][idx] = {} end rec = a_limits[s["param"]][idx] a_limits[s["param"]][idx][#rec+1] = {low,high} end end end) return a_names,a_formats,a_limits; end function check_limit(param,value,limits) limit = limits[param] if limit then for level,ranges in pairs(limit) do for key,range in pairs(ranges) do if value>=range[1] and value<range[2] then return level end end end return 0 else return 0 end end local config_name = arg[1] if not config_name then config_name = "weathermon" end web_id = get_devid(config_name) local a_levels, a_engage, a_engage_mode, a_disengage_mode, levels_idx = get_levels_list(config_name) a_leds = {} for level,leds in pairs(a_engage) do for key,led in pairs(leds) do a_leds[led] = a_disengage_mode[level] end end local a_names,a_formats,limits = get_params(config_name,levels_idx) local w_led = cur.get(config_name, "process", "engage") local w_engage = cur.get(config_name, "process", "engage_mode") local w_disengage = cur.get(config_name, "process", "disengage_mode") local senstemplate = string.gsub(cur.get(config_name, "display", "formatstr"),"~",string.char(223)) local out_file = cur.get(config_name, "display", "file") local watch_file = cur.get(config_name,"process","dump_file") if not watch_file then return end local last = 0 local data = "" local old_data = "" local sensor_data local res local mute_file=cur.get(config_name, "process", "mute_file") local mute_time=tonumber(cur.get(config_name, "process", "mute_time")) local alarm_raise = 2 local onoff=true local timestr_template = cur.get(config_name, "display", "timestr") if not timestr_template then timestr_template = " %d.%m.%y %H:%M " end local alarmstr_len = cur.get(config_name, "display", "strlen") if not alarmstr_len then alarmstr_len = 20 end alarmstr_len=tonumber(alarmstr_len) while true do onoff = not onoff local timestr = os.date(timestr_template) pcall(function () local mod = lfs.attributes(watch_file,"modification") local muted_mod = lfs.attributes(mute_file,"modification") local muted_beep = muted_mod and (muted_mod > (os.time() - mute_time)) if mod then if last < mod then last = mod res,sensor_data = pcall(function () local f = io.open(watch_file,"r") content = f:read("*all") io.close(f) return json.decode(content) end) write_file(w_led,w_engage) else write_file(w_led,w_disengage) end local values = {} local printable = {} for sensor,sensor_params in pairs(sensor_data[web_id]) do if sensor ~= "timestamp" then for param,value in pairs(sensor_params) do local name = sensor.."."..param values[name]=value if a_formats[name] then printable[name]=string.format("%"..a_formats[name][1],value*a_formats[name][2]) end end end end level = 1 alarms = "" if not muted_beep then for key,value in pairs(values) do value_level = check_limit(key,value,limits) if value_level > level then level = value_level alarms = a_names[key] elseif value_level == level then alarms = alarms.." "..a_names[key] end end end leds_engage = {} for key,value in pairs(a_engage[level]) do leds_engage[value] = a_engage_mode[level] end for led,mode in pairs(a_leds) do if leds_engage[led] then write_file(led,leds_engage[led]) else write_file(led,mode) end end alarms = trim(alarms) alarmstr = a_levels[level]..": "..alarms if alarmstr:len()>alarmstr_len then alarmstr=alarmstr:sub(1,alarmstr_len) elseif alarmstr:len()<alarmstr_len then local delta = alarmstr_len - alarmstr:len() local before = math.floor(delta/2) local after = delta - before alarmstr = string.rep(" ",before)..alarmstr..string.rep(" ",after) end sensstr = string.gsub(senstemplate,"%{.-%}", function (s) return printable[s:sub(2,s:len()-1)]; end) if onoff and (level>=alarm_raise) then data = alarmstr..sensstr else data = timestr..sensstr end if old_data ~= data then old_data = data print(data) write_file(out_file,data) end end end) local t = os.date("*t",os.time()+60) t["sec"] = 0 local sec = os.time(t)-os.time() if sec>0 then if sec>5 then sec=5 end socket.sleep(sec) end end