The BeagleBone Weather cape enhances the BeagleBone's capabilities by providing environment sensors (temperature, humidity, pressure, and ambient light level). The weatherstation demo is a port of the bonescript weatherstation to Minix. It provides a nice visual display of the sensor data in a web browser. The code is installed to /usr/share/beaglebone/weather on 'earm' and an embedded web server is started at boot time on port 80 when the cape is attached. Further details are provided in the README.txt file. Change-Id: I1596a2b66b213762ace26c0c750c8154c76b5c6e
174 lines
4.3 KiB
Lua
174 lines
4.3 KiB
Lua
#!/usr/bin/lua
|
|
--
|
|
-- weatherstation.lua - a simple web server intended to be run from tcpd to
|
|
-- expose sensors from the BeagleBone Weather cape and serve the web app.
|
|
--
|
|
|
|
-- List of files shared by this service.
|
|
distfiles={}
|
|
distfiles["/index.html"] = true
|
|
distfiles["/style.css"] = true
|
|
distfiles["/jquery.js"] = true
|
|
distfiles["/processing.js"] = true
|
|
distfiles["/spin.js"] = true
|
|
distfiles["/weatherstation.js"] = true
|
|
|
|
-- Base path for distfiles
|
|
prefix="/usr/share/beaglebone/weather"
|
|
|
|
-- Check that the filename is part of this demo.
|
|
function filename_is_valid(filename)
|
|
return distfiles[filename] ~= nil
|
|
end
|
|
|
|
-- Check if the string 's' starts with 'starting'
|
|
function starts_with(s, starting)
|
|
return string.sub(s, 1, string.len(starting)) == starting
|
|
end
|
|
|
|
-- Check if the string 's' ends with 'ending'
|
|
function ends_with(s, ending)
|
|
return string.sub(s, -string.len(ending)) == ending
|
|
end
|
|
|
|
-- Return the content type of the file based only on the file extension.
|
|
function get_content_type(filename)
|
|
|
|
if ends_with(filename, ".js") then
|
|
return "application/javascript"
|
|
elseif ends_with(filename, ".css") then
|
|
return "text/css"
|
|
elseif ends_with(filename, ".html") then
|
|
return "text/html"
|
|
elseif ends_with(filename, ".json") then
|
|
return "application/json"
|
|
else
|
|
return "text/plain"
|
|
end
|
|
end
|
|
|
|
-- Reads from STDIN until an empty or nil line is received.
|
|
-- Returns the first line of the request.
|
|
function read_request()
|
|
|
|
local i = 0
|
|
local lines = {}
|
|
|
|
repeat
|
|
local line = io.read("*line")
|
|
if line == nil or line == "\r" then
|
|
break
|
|
end
|
|
lines[i] = line
|
|
i = i + 1
|
|
until false
|
|
|
|
return lines[0]
|
|
end
|
|
|
|
-- Return the entire contents of a file
|
|
function read_file(filename)
|
|
local f = io.open(filename, "rb")
|
|
|
|
if f == nil then
|
|
return nil
|
|
end
|
|
local content = f:read("*all")
|
|
f:close()
|
|
|
|
return content
|
|
end
|
|
|
|
-- Extract the value of the LABEL:VALUE pairs read from the device files.
|
|
function extract_value(label, data, pat)
|
|
|
|
local x, y, z = string.find(data, label .. "%s+: (" .. pat .. ")")
|
|
if x == nil or y == nil or z == nil then
|
|
return "0"
|
|
end
|
|
return z
|
|
end
|
|
|
|
-- Read the sensor values and generate json output
|
|
function generate_json()
|
|
local json = ""
|
|
|
|
local tsl2550 = read_file("/dev/tsl2550b3s39")
|
|
if tsl2550 == nil then
|
|
return nil
|
|
end
|
|
local illuminance = extract_value("ILLUMINANCE", tsl2550, "%d+")
|
|
|
|
local sht21 = read_file("/dev/sht21b3s40")
|
|
if sht21 == nil then
|
|
return nil
|
|
end
|
|
local temperature = extract_value("TEMPERATURE", sht21, "%d+.%d+")
|
|
local humidity = extract_value("HUMIDITY", sht21, "%d+.%d+")
|
|
|
|
local bmp085 = read_file("/dev/bmp085b3s77")
|
|
if bmp085 == nil then
|
|
return nil
|
|
end
|
|
local pressure = extract_value("PRESSURE", bmp085, "%d+")
|
|
|
|
json = json .. "{\n"
|
|
json = json .. "\"temperature\": " .. temperature .. ",\n"
|
|
json = json .. "\"humidity\": " .. humidity .. ",\n"
|
|
json = json .. "\"illuminance\": " .. illuminance .. ",\n"
|
|
json = json .. "\"pressure\": " .. pressure .. "\n"
|
|
json = json .. "}\n"
|
|
|
|
return json
|
|
end
|
|
|
|
function handle_request(req)
|
|
|
|
if req == nil then
|
|
response("404 Not Found", "text/plain", "Unknown Request")
|
|
return
|
|
end
|
|
|
|
-- Parse filename out of HTTP request
|
|
local filename = (string.match(req, " %S+ "):gsub("^%s+", ""):gsub("%s+$", ""))
|
|
if filename == "" or filename == "/" then
|
|
filename = "/index.html"
|
|
end
|
|
|
|
-- Check if the filename is known (i.e. it's a file in the web app)
|
|
if filename_is_valid(filename) then
|
|
local contents = read_file(prefix .. filename)
|
|
|
|
if contents ~= nil then
|
|
response("200 OK", get_content_type(filename), contents)
|
|
else
|
|
response("404 Not Found", "text/plain", "Failed to load known file")
|
|
end
|
|
-- Else maybe the user is requesting the dynamic json data
|
|
elseif starts_with(filename, "/weather.json") then
|
|
local json = generate_json()
|
|
if json == nil then
|
|
response("500 Internal Server Error", "text/plain", "Could not get sensor values")
|
|
else
|
|
response("200 OK", get_content_type("/weather.json"), json)
|
|
end
|
|
-- Else, the user is requesting something not part of the app
|
|
else
|
|
response("403 Forbidden", "text/plain", "File not allowed.")
|
|
end
|
|
|
|
return
|
|
end
|
|
|
|
-- Send the response to the HTTP request.
|
|
function response(err_code, content_type, content)
|
|
io.write("HTTP/1.1 " .. err_code .. "\r\n")
|
|
io.write("Content-Type: " .. content_type .. "\r\n")
|
|
io.write("\r\n")
|
|
io.write(content)
|
|
io.write("\r\n")
|
|
end
|
|
|
|
-- Read the request and then handle it.
|
|
handle_request(read_request())
|
|
|