Переход с python на lua для всех демонов.
[weathermon.git] / bin / weather-display
1 #!/usr/bin/lua
2
3 require "uci"
4 local cur = uci.cursor()
5 local socket = require "socket"
6 local lfs = require "lfs"
7 local json = require "json"
8
9 require "wm_util"
10
11 function get_levels_list(config_name)
12   local levels, engage, engage_mode, disengage_mode, levels_idx
13   levels = {}
14   levels_idx = {}
15   engage = {}
16   engage_mode = {}
17   disengage_mode = {}
18   cur.foreach(config_name, "alarm", function(s)
19     local idx = #levels+1
20     levels[idx] = s["name"]
21     engage[idx] = s["engage"]
22     engage_mode[idx] = s["engage_mode"]
23     disengage_mode[idx] = s["disengage_mode"]
24     levels_idx[s[".name"]] = idx
25   end)
26   return levels, engage, engage_mode, disengage_mode, levels_idx
27 end
28
29 function get_params(config_name,levels_idx)
30   local a_names, a_formats, a_limits
31   a_names = {}
32   a_formats = {}
33   a_limits = {}
34   cur.foreach(config_name,"params", function(s)
35     if s["name"] then
36       a_names[s["param"]] = s["name"]
37     end
38     if s["format"] or s["scale"] then
39       local format, scale
40       if s["scale"] then
41         scale = s["scale"]
42       else
43         scale = 1  
44       end
45       if s["format"] then
46         format = s["format"]
47       else
48         format = "4s"
49       end
50       a_formats[s["param"]] = {format,scale}
51     end  
52     if s["limits"] then
53       for i,record in pairs(s["limits"]) do
54         rec = split(record,":")
55         idx = levels_idx[rec[1]]
56         low = tonumber(rec[2])
57         high = tonumber(rec[3])
58         if not a_limits[s["param"]] then
59           a_limits[s["param"]] = {}
60         end
61         if not a_limits[s["param"]][idx] then
62           a_limits[s["param"]][idx] = {}
63         end
64         rec = a_limits[s["param"]][idx]
65         a_limits[s["param"]][idx][#rec+1] = {low,high}
66       end  
67     end
68   end)
69   return a_names,a_formats,a_limits;
70 end
71
72 function check_limit(param,value,limits)
73
74   limit = limits[param]
75   if limit then
76   
77     for level,ranges in pairs(limit) do
78       for key,range in pairs(ranges) do
79         if value>=range[1] and value<range[2] then
80           return level
81         end  
82       end
83     end
84
85     return 0
86   
87   else
88   
89     return 0
90   
91   end
92
93 end
94
95 local config_name = arg[1]
96
97 if not config_name then
98   config_name = "weathermon"
99 end
100
101 print("loading config...")
102
103 local a_levels, a_engage, a_engage_mode, a_disengage_mode, levels_idx = get_levels_list(config_name)
104
105 a_leds = {}
106
107 for level,leds in pairs(a_engage) do
108
109   for key,led in pairs(leds) do
110   
111     a_leds[led] = a_disengage_mode[level]
112   
113   end
114
115 end
116
117 local a_names,a_formats,limits = get_params(config_name,levels_idx)
118
119 local w_led = cur.get(config_name, "process", "engage")
120 local w_engage = cur.get(config_name, "process", "engage_mode")
121 local w_disengage = cur.get(config_name, "process", "disengage_mode")
122
123 local senstemplate = string.gsub(cur.get(config_name, "display", "formatstr"),"~",string.char(223))
124 local out_file = cur.get(config_name, "display", "file")
125
126 local watch_file = cur.get(config_name,"process","dump_file")
127
128 if not watch_file then
129   return
130 end  
131
132 local last = 0
133
134 local data = ""
135 local old_data = ""
136 local sensor_data
137 local res
138
139 local mute_file=cur.get(config_name, "process", "mute_file")
140 local mute_time=tonumber(cur.get(config_name, "process", "mute_time"))
141 local alarm_raise = 2
142 local onoff=true
143
144 local timestr_template = cur.get(config_name, "display", "timestr")
145 if not timestr_template then
146   timestr_template = "  %d.%m.%y   %H:%M  "
147 end
148
149 local alarmstr_len = cur.get(config_name, "display", "strlen")
150 if not alarmstr_len then
151   alarmstr_len = 20
152 end
153 alarmstr_len=tonumber(alarmstr_len)
154
155 web_id = uci.get(config_name,"web","devid")
156
157 while true do
158
159   onoff = not onoff
160
161   local timestr = os.date(timestr_template)
162
163   pcall(function ()
164
165     local mod = lfs.attributes(watch_file,"modification")
166     local muted_mod = lfs.attributes(mute_file,"modification")
167     local muted_beep = muted_mod and (muted_mod > (os.time() - mute_time))
168   
169     if mod then
170    
171       if last < mod then
172         last = mod
173         res,sensor_data = pcall(function ()
174           local f = io.open(watch_file,"r")
175           content = f:read("*all")
176           io.close(f)
177           return json.decode(content)
178         end)      
179     
180         write_file(w_led,w_engage)
181    
182       else
183
184         write_file(w_led,w_disengage)
185       
186       end 
187
188       local values = {}
189       local printable = {}
190
191       for sensor,sensor_params in pairs(sensor_data[web_id]) do
192         if sensor ~= "timestamp" then
193           for param,value in pairs(sensor_params) do
194             local name = sensor.."."..param
195             values[name]=value
196             if a_formats[name] then
197               printable[name]=string.format("%"..a_formats[name][1],value*a_formats[name][2])
198             end  
199           end
200         end  
201       end
202
203       level = 1
204       alarms = ""
205
206       if not muted_beep then
207         for key,value in pairs(values) do
208           value_level = check_limit(key,value,limits)
209           if value_level > level then
210             level = value_level
211             alarms = a_names[key]
212           elseif value_level == level then  
213             alarms = alarms.." "..a_names[key]
214           end   
215         end
216       end  
217
218       leds_engage = {} 
219     
220       for key,value in pairs(a_engage[level]) do
221         leds_engage[value] = a_engage_mode[level]
222       end
223  
224       for led,mode in pairs(a_leds) do
225         if leds_engage[led] then
226           write_file(led,leds_engage[led])
227         else  
228           write_file(led,mode)
229         end
230       end
231   
232       alarms = trim(alarms)
233       alarmstr = a_levels[level]..": "..alarms
234     
235       if alarmstr:len()>alarmstr_len then
236         alarmstr=alarmstr:sub(1,alarmstr_len)
237       elseif alarmstr:len()<alarmstr_len then
238         local delta = alarmstr_len - alarmstr:len()
239         local before = math.floor(delta/2)
240         local after = delta - before
241         alarmstr = string.rep(" ",before)..alarmstr..string.rep(" ",after)
242       end
243
244       sensstr = string.gsub(senstemplate,"%{.-%}", function (s) return printable[s:sub(2,s:len()-1)]; end)
245
246       if onoff and (level>=alarm_raise) then
247         data = alarmstr..sensstr
248       else
249         data = timestr..sensstr
250       end
251
252       if old_data ~= data then
253    
254         old_data = data
255         print(data)
256         write_file(out_file,data)
257    
258       end   
259   
260     end
261     
262   end)  
263
264   local t = os.date("*t",os.time()+60) 
265   t["sec"] = 0
266   local sec = os.time(t)-os.time()
267   if sec>0 then
268     if sec>5 then
269       sec=5
270     end
271     socket.sleep(sec)
272   end
273
274 end