Project

General

Profile

« Previous | Next » 

Revision 45c4b73a

Added by dsorber about 13 years ago

Adding web remote display code. All the basic functionality is complete but I'd like to play around with adding some graphs for S&G.

View differences:

525.743/code/web/README
1. Install apache and mod_wsgi.
2. Add this line to your apache config file
WSGIScriptAlias /bcfs /path/to/web/folder/app.wsgi
3. Restart apache and you should be able to see BCFS web display at "/bcfs".
525.743/code/web/app.wsgi
import sqlite3
from genshi.template import TemplateLoader
from genshi.template.base import Context
DB_PATH = '/home/dsorber/bcfs/beer_temps.db'
# It accepts two arguments:
# environ points to a dictionary containing CGI like environment variables
# which is filled by the server for each received request from the client
# start_response is a callback function supplied by the server
# which will be used to send the HTTP status and headers to the server
def application(environ, start_response):
loader = TemplateLoader('/home/dsorber/bcfs/templates',
auto_reload=True)
# Testing purposes only -- REMOVE BEFORE SHIPPING
response_body = 'The environ dict: %s' % environ['PATH_INFO']
if not environ['PATH_INFO']:
# Load the index template
template = loader.load('index.html')
# Create the response args
response_args = {'title': 'Beer Fermentation Control System'}
# Open up the connection to the database, execute the query,
# grab the results, then close the DB connection.
db_conn = sqlite3.connect(DB_PATH)
db = db_conn.cursor()
db.execute("select strftime('%m/%d/%Y', date(ts, 'unixepoch')), "
" count(ts), avg(temp1), max(temp1), min(temp1),"
" avg(temp2), max(temp2), min(temp2), avg(temp3),"
" max(temp3), min(temp3), avg(temp4), max(temp4),"
" min(temp4)"
"from temp_data "
"group by date(ts, 'unixepoch')")
response_args['results'] = db.fetchall()
db_conn.close()
# Generate the stream and then render it to HTML
stream = template.generate(**response_args)
response_body = stream.render('html', doctype='html')
# Set the appropriate response headers
response_headers = [('Content-Type', 'text/html'),
('Content-Length', str(len(response_body)))]
elif environ['PATH_INFO'].startswith('/day/'):
# Load the day template
template = loader.load('day.html')
day = environ['PATH_INFO'][5:7]
month = environ['PATH_INFO'][7:9]
year = environ['PATH_INFO'][9:13]
date = '%s/%s/%s' % (month, day, year)
# Create the response args
response_args = {'title': 'Sensor Readings for %s' % date}
# Open up the connection to the database, execute the query,
# grab the results, then close the DB connection.
db_conn = sqlite3.connect(DB_PATH)
db = db_conn.cursor()
db.execute("select strftime('%m/%d/%Y %H:%M:%S', ts, 'unixepoch'), "
" temp1, temp2, temp3, temp4, relay_status "
"from temp_data "
"where date(ts, 'unixepoch') is date('2013-04-22')"
"order by ts desc")
response_args['results'] = db.fetchall()
db_conn.close()
# Generate the stream and then render it to HTML
stream = template.generate(**response_args)
response_body = stream.render('html', doctype='html')
# Set the appropriate response headers
response_headers = [('Content-Type', 'text/html'),
('Content-Length', str(len(response_body)))]
else:
# User supplied an invalid URL
response_body = 'Invalid URL "%s"' % environ['PATH_INFO']
response_headers = [('Content-Type', 'text/plain'),
('Content-Length', str(len(response_body)))]
# HTTP response code and message
status = '200 OK'
# Send the status and response headers to the server
start_response(status, response_headers)
# Return the response body. (Notice it is wrapped in a list although it
# could be any iterable.)
return [response_body]
525.743/code/web/templates/day.html
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/">
<head>
<title>Beer Fermenation Control System</title>
<style type="text/css">
body {font-family: sans-serif;
font-size: 16px}
h3 {font-size: 24px;}
table {border: 1px solid #000;
border-spacing: 0px;}
table a:link {color: #000;
text-decoration: none;}
table a:visited {color: #000;
text-decoration: none;}
table a:hover {color: #000;
text-decoration: underline;}
tr.even {background-color: #FFF;}
tr.odd {background-color: #FFC;}
th {border: 1px solid #000;
padding: 10px;
border-spacing: 2px;}
td {border-top: 1px solid #000;
padding: 2px 5px;}
.center {text-align: center;}
.sensor1 {background-color: #FC0;}
.sensor2 {background-color: #C3F;}
.sensor3 {background-color: #0C0;}
.sensor4 {background-color: #F60;}
.avg {background-color: #AAA;}
.max {background-color: #CCC;}
.min {background-color: #EEE;}
.relay_on {font-weight: bold;
color: #0C0;}
</style>
</head>
<body>
<h1>${title}</h1>
<table>
<tr>
<th>Datetime</th>
<th class="sensor1">Sensor 1</th>
<th class="sensor2">Sensor 2</th>
<th class="sensor3">Sensor 3</th>
<th class="sensor4">Sensor 4</th>
<th class="max">Relay Status</th>
</tr>
<tr py:for="ctr, row in enumerate(results)" class="${ctr % 2 and 'odd' or 'even'}">
<td><a href="bcfs/day/${row[0][3:5] + row[0][0:2] + row[0][6:10]}">${row[0]}</a></td>
<td class="center">${row[1]}</td>
<td class="center">${row[2]}</td>
<td class="center">${row[3]}</td>
<td class="center">${row[4]}</td>
<td class="center ${row[5] == 1 and 'relay_on' or ''}">${int(row[5]) and 'on' or 'off'}</td>
</tr>
</table>
<br />
<a href="/bcfs">Back</a>
</body>
</html>
525.743/code/web/templates/index.html
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:py="http://genshi.edgewall.org/">
<head>
<title>Beer Fermenation Control System</title>
<style type="text/css">
body {font-family: sans-serif;
font-size: 16px}
h3 {font-size: 24px;}
table {border: 1px solid #000;
border-spacing: 0px;}
table a:link {color: #000;
text-decoration: none;}
table a:visited {color: #000;
text-decoration: none;}
table a:hover {color: #000;
text-decoration: underline;}
tr.even {background-color: #FFF;}
tr.odd {background-color: #FFC;}
th {border: 1px solid #000;
padding: 10px;
border-spacing: 2px;}
td {border-top: 1px solid #000;
padding: 2px 5px;}
.center {text-align: center;}
.sensor1 {background-color: #FC0;}
.sensor2 {background-color: #C3F;}
.sensor3 {background-color: #0C0;}
.sensor4 {background-color: #F60;}
.avg {background-color: #AAA;}
.max {background-color: #CCC;}
.min {background-color: #EEE;}
</style>
</head>
<body>
<h1>${title}</h1>
<h3>Sensor Reading Summary</h3>
<table>
<tr>
<th colspan="2"> </th>
<th colspan="3" class="sensor1">Sensor 1</th>
<th colspan="3" class="sensor2">Sensor 2</th>
<th colspan="3" class="sensor3">Sensor 3</th>
<th colspan="3" class="sensor4">Sensor 4</th>
</tr>
<tr>
<th>Date</th>
<th>Readings</th>
<th class="avg">Avg</th>
<th class="max">Max</th>
<th class="min">Min</th>
<th class="avg">Avg</th>
<th class="max">Max</th>
<th class="min">Min</th>
<th class="avg">Avg</th>
<th class="max">Max</th>
<th class="min">Min</th>
<th class="avg">Avg</th>
<th class="max">Max</th>
<th class="min">Min</th>
</tr>
<tr py:for="ctr, row in enumerate(results)" class="${ctr % 2 and 'odd' or 'even'}">
<td><a href="bcfs/day/${row[0][3:5] + row[0][0:2] + row[0][6:10]}">${row[0]}</a></td>
<td class="center">${row[1]}</td>
<td class="center">${round(float(row[2]), 3)}</td>
<td class="center">${row[3]}</td>
<td class="center">${row[4]}</td>
<td class="center">${round(float(row[5]), 3)}</td>
<td class="center">${row[6]}</td>
<td class="center">${row[7]}</td>
<td class="center">${round(float(row[8]), 3)}</td>
<td class="center">${row[9]}</td>
<td class="center">${row[10]}</td>
<td class="center">${round(float(row[11]), 3)}</td>
<td class="center">${row[12]}</td>
<td class="center">${row[13]}</td>
</tr>
</table>
</body>
</html>

Also available in: Unified diff