3 -- weatherstation.lua - a simple web server intended to be run from tcpd to
4 -- expose sensors from the BeagleBone Weather cape and serve the web app.
7 -- List of files shared by this service.
9 distfiles
["/index.html"] = true
10 distfiles
["/style.css"] = true
11 distfiles
["/jquery.js"] = true
12 distfiles
["/processing.js"] = true
13 distfiles
["/spin.js"] = true
14 distfiles
["/weatherstation.js"] = true
16 -- Base path for distfiles
17 prefix
="/usr/share/beaglebone/weather"
19 -- Check that the filename is part of this demo.
20 function filename_is_valid(filename
)
21 return distfiles
[filename
] ~= nil
24 -- Check if the string 's' starts with 'starting'
25 function starts_with(s
, starting
)
26 return string.sub(s
, 1, string.len(starting
)) == starting
29 -- Check if the string 's' ends with 'ending'
30 function ends_with(s
, ending
)
31 return string.sub(s
, -string.len(ending
)) == ending
34 -- Return the content type of the file based only on the file extension.
35 function get_content_type(filename
)
37 if ends_with(filename
, ".js") then
38 return "application/javascript"
39 elseif ends_with(filename
, ".css") then
41 elseif ends_with(filename
, ".html") then
43 elseif ends_with(filename
, ".json") then
44 return "application/json"
50 -- Reads from STDIN until an empty or nil line is received.
51 -- Returns the first line of the request.
52 function read_request()
58 local line
= io
.read("*line")
59 if line
== nil or line
== "\r" then
69 -- Return the entire contents of a file
70 function read_file(filename
)
71 local f
= io
.open(filename
, "rb")
76 local content
= f
:read("*all")
82 -- Extract the value of the LABEL:VALUE pairs read from the device files.
83 function extract_value(data
, pat
)
85 local x
= string.match(data
, pat
)
93 -- Read the sensor values and generate json output
94 function generate_json()
97 local tsl2550
= read_file("/dev/tsl2550b3s39")
98 if tsl2550
== nil then
101 local illuminance
= extract_value(tsl2550
, "ILLUMINANCE: (%d+)")
103 local sht21
= read_file("/dev/sht21b3s40")
107 local temperature
= extract_value(sht21
, "TEMPERATURE: (%d+.%d+)")
108 local humidity
= extract_value(sht21
, "HUMIDITY: (%d+.%d+)")
110 local bmp085
= read_file("/dev/bmp085b3s77")
111 if bmp085
== nil then
114 local pressure
= extract_value(bmp085
, "PRESSURE: (%d+)")
117 json
= json
.. "\"temperature\": " .. temperature
.. ",\n"
118 json
= json
.. "\"humidity\": " .. humidity
.. ",\n"
119 json
= json
.. "\"illuminance\": " .. illuminance
.. ",\n"
120 json
= json
.. "\"pressure\": " .. pressure
.. "\n"
126 function handle_request(req
)
129 response("404 Not Found", "text/plain", "Unknown Request")
133 -- Parse filename out of HTTP request
134 local filename
= (string.match(req
, " %S+ "):gsub("^%s+", ""):gsub("%s+$", ""))
135 if filename
== "" or filename
== "/" then
136 filename
= "/index.html"
139 -- Check if the filename is known (i.e. it's a file in the web app)
140 if filename_is_valid(filename
) then
141 local contents
= read_file(prefix
.. filename
)
143 if contents
~= nil then
144 response("200 OK", get_content_type(filename
), contents
)
146 response("404 Not Found", "text/plain", "Failed to load known file")
148 -- Else maybe the user is requesting the dynamic json data
149 elseif starts_with(filename
, "/weather.json") then
150 local json
= generate_json()
152 response("500 Internal Server Error", "text/plain", "Could not get sensor values")
154 response("200 OK", get_content_type("/weather.json"), json
)
156 -- Else, the user is requesting something not part of the app
158 response("403 Forbidden", "text/plain", "File not allowed.")
164 -- Send the response to the HTTP request.
165 function response(err_code
, content_type
, content
)
166 io
.write("HTTP/1.1 " .. err_code
.. "\r\n")
167 io
.write("Content-Type: " .. content_type
.. "\r\n")
173 -- Read the request and then handle it.
174 handle_request(read_request())