d288edf935d599d63f236ca97835c663c85313fb
[weathermon.git] / bin / weathermon-iio
1 #!/usr/bin/lua
2
3 require "uci"
4 cur = uci.cursor()
5
6 lfs = require "lfs"
7 json = require "json"
8 socket = require "socket"
9
10 require "wm_util"
11
12 io.stdout:setvbuf('no')
13
14 function dump(o)
15    if type(o) == 'table' then
16       local s = '{ '
17       for k,v in pairs(o) do
18          if type(k) ~= 'number' then k = '"'..k..'"' end
19          s = s .. '['..k..'] = ' .. dump(v) .. ','
20       end
21       return s .. '} '
22    else
23       return tostring(o)
24    end
25 end
26
27 function get_device_list(config_name)
28
29   local devices
30   devices = {}
31
32   cur.foreach(config_name, "device", function(s)
33     devices[#devices+1] = s[".name"]
34   end)
35
36   return devices
37
38 end
39
40 function get_device(config_name,device_name)
41
42   local device
43   device = {}
44   
45   cur.foreach(config_name, "device", function(s)
46     if s[".name"] == device_name then
47       device = s
48     end
49   end)  
50   
51   return device
52   
53 end
54
55 function find_device(name,subsystem)
56
57   local search_base
58
59   if subsystem == "iio" then
60     search_base = "/sys/bus/iio/devices"
61     for file in lfs.dir(search_base) do
62       if get_file_content(search_base.."/"..file.."/name") == name then
63         return search_base.."/"..file
64       end
65     end
66   elseif subsystem == "hwmon" then
67     search_base = "/sys/class/hwmon"
68     for file in lfs.dir(search_base) do
69       if get_file_content(search_base.."/"..file.."/device/name") == name then
70         return search_base.."/"..file.."/device"
71       end
72     end  
73   end
74   
75   return nil
76
77 end
78
79 function get_parameter(record)
80   return tonumber(get_file_content(record["path"])) * record["scale"] + record["correction"]
81 end
82
83 function string.fromhex(str)
84   return (str:gsub('..', function (cc)
85     return string.char(tonumber(cc, 16))
86   end))
87 end
88
89 function string.tohex(str)
90   return (str:gsub('.', function (c)
91     return string.format('%02X', string.byte(c))
92   end))
93 end
94
95 function get_mhz(record)
96   local p = record["rs232"]  
97   p:read(9,100)
98   p:write(string.fromhex("ff0186000000000079"))
99   local e, s = p:read(9,1000)
100   if (e == 0) and (s:len() == 9) and (s:byte(1) == 255) then
101     local crc = 0
102     for i = 2, 8 do
103       crc = crc + s:byte(i)
104       if (crc>=256) then
105         crc = crc - 256
106       end  
107     end  
108     crc = 255 - crc
109     crc = crc + 1;
110     if crc == s:byte(9) then
111       return s:byte(3)*256+s:byte(4)
112     end  
113   end
114   
115   return nil
116    
117 end
118
119 function init_serial_device(device,subsystem,parameters)
120
121   rs232 = require("luars232")
122
123   pcall(function ()
124
125     local e, port = rs232.open(device["port"])
126   
127     if subsystem == "mhz" then
128     
129       assert(port:set_baud_rate(rs232.RS232_BAUD_9600) == rs232.RS232_ERR_NOERROR)
130       assert(port:set_data_bits(rs232.RS232_DATA_8) == rs232.RS232_ERR_NOERROR)
131       assert(port:set_parity(rs232.RS232_PARITY_NONE) == rs232.RS232_ERR_NOERROR)
132       assert(port:set_stop_bits(rs232.RS232_STOP_1) == rs232.RS232_ERR_NOERROR)
133       assert(port:set_flow_control(rs232.RS232_FLOW_OFF)  == rs232.RS232_ERR_NOERROR)
134     
135       getparameter = {}
136
137       getparameter["rs232"] = port
138       getparameter["function"] = get_mhz 
139       getparameter["name"] = "CO2_PPM"
140       getparameter["sensor"] = "MHZ19"
141       parameters[#parameters+1] = getparameter
142
143     end
144     
145   end)
146
147 end
148
149 function init_i2c_device(device,subsystem,parameters)
150
151   if not i2c_bus then
152     i2c_bus = 0
153   end
154
155   pcall(function ()
156     local f = io.open("/sys/class/i2c-dev/i2c-"..i2c_bus.."/device/new_device","w")
157     io.output(f)
158     io.write(device["name"].." "..device["address"])
159     io.close(f)
160   end)  
161
162   device_path=find_device(device["name"],subsystem)
163
164   if device_path and device["set_param"] then
165     for key,record in pairs(device["set_param"]) do
166       setparam = split(record,":")
167       setpath = device_path.."/"..setparam[1]
168       pcall(function ()
169         local f = io.open(setpath,"w")
170         io.output(f)
171         io.write(setparam[2])
172         io.close(f)
173       end)  
174     end
175   end
176
177   if device_path and device["parameter"] then
178
179     for key,record in pairs(device["parameter"]) do
180
181       getparam = split(record,":")
182       getparameter = {}
183       getparameter["path"] = device_path.."/"..getparam[1]
184       getparameter["name"] = getparam[2]
185       getscale = getparam[3]
186       getcorrection = getparam[4]
187       if not getscale then
188         getscale = 1
189       end  
190       if not getcorrection then
191         getcorrection = 0
192       end
193       getparameter["scale"] = tonumber(getscale)
194       getparameter["sensor"] = device["name"]:upper()
195       getparameter["correction"] = tonumber(getcorrection)
196       getparameter["function"] = get_parameter
197       parameters[#parameters+1] = getparameter
198
199     end
200
201   end
202   
203 end
204
205 function init_device(device,parameters)
206
207   if device["module"] then
208     os.execute("modprobe "..device["module"])
209   end    
210
211   if device["type"] then
212
213     devtype = split(device["type"],":")
214     bus = devtype[1]
215     subsystem = devtype[2]
216     
217     if (bus == "i2c") then
218
219       init_i2c_device(device,subsystem,parameters)
220     
221     elseif (bus == "serial") then
222       
223       init_serial_device(device,subsystem,parameters) 
224     
225     end
226     
227   end
228
229 end
230
231 function init(config_name)
232
233   local parameters= {}
234
235   i2c_bus = uci.get(config_name,"hardware","i2c_bus")
236
237   local devices = get_device_list(config_name)
238   
239   for key,devname in pairs(devices) do
240   
241     device = get_device(config_name,devname)
242     
243     if device then
244       init_device(device,parameters)
245     end  
246   
247   end
248
249   return parameters
250
251 end
252
253 function get_parameters(parameters)
254   local results = {}
255   for key,record in pairs(parameters) do
256
257     if not results[record["sensor"]] then 
258       results[record["sensor"]] = {}
259     end
260     pcall(function ()
261         results[record["sensor"]][record["name"]] = record["function"](record)
262       end)
263   end
264   
265   return results
266 end
267
268 config_name = arg[1]
269 if not config_name then
270   config_name = "weathermon"
271 end  
272
273 web_id = get_devid(config_name)
274
275 parameters = init(config_name)
276
277 local delay = uci.get(config_name,"process","delay")
278
279 local working_dir = uci.get(config_name,"process","working_dir")
280 if working_dir then
281   lfs.mkdir(working_dir)
282 end
283
284 if not delay then
285   delay = 60
286 end
287
288 while true do
289     values = get_parameters(parameters)
290     records = {}
291     records[web_id] = {}
292     for key,record in pairs(values) do
293       records[web_id][key] = record
294       records[web_id]["timestamp"] = os.date("%Y-%m-%dT%H:%M:%S")
295     end
296     for key,value in pairs(values) do
297       value["device"] = key
298       print(json.encode(value))
299     end
300   socket.sleep(delay)
301 end