commit 45c4b73aec2821a42bd248e8a99d998fed4a625c
Author: dsorber <david.sorber@gmail.com>
Date:   Sun Apr 28 16:12:12 2013 -0400

    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.

diff --git a/525.743/code/web/README b/525.743/code/web/README
new file mode 100644
index 0000000..5857634
--- /dev/null
+++ b/525.743/code/web/README
@@ -0,0 +1,6 @@
+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".
\ No newline at end of file
diff --git a/525.743/code/web/app.wsgi b/525.743/code/web/app.wsgi
new file mode 100644
index 0000000..596a3a8
--- /dev/null
+++ b/525.743/code/web/app.wsgi
@@ -0,0 +1,97 @@
+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]
\ No newline at end of file
diff --git a/525.743/code/web/templates/day.html b/525.743/code/web/templates/day.html
new file mode 100644
index 0000000..ebe4371
--- /dev/null
+++ b/525.743/code/web/templates/day.html
@@ -0,0 +1,59 @@
+<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>
diff --git a/525.743/code/web/templates/index.html b/525.743/code/web/templates/index.html
new file mode 100644
index 0000000..971d587
--- /dev/null
+++ b/525.743/code/web/templates/index.html
@@ -0,0 +1,83 @@
+<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>
