minix/share/beaglebone/weather/weatherstation.lua
Thomas Cort 60a61dffae weatherstation: BeagleBone Weather Cape demo app.
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
2013-08-26 21:51:32 +02:00

175 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())