Revision 98f4e4a6
Added by dsorber almost 12 years ago
| software/bookmark_library/bmklib/web/base_controller.py | ||
|---|---|---|
|
|
||
|
from genshi.template import TemplateLoader
|
||
|
|
||
|
BASE_PATH = '/home/dsorber/Documents/phalanx-repo/software/bookmark_library/web'
|
||
|
DB_PATH = os.path.join(BASE_PATH, 'beer_temps.db')
|
||
|
TEMPLATE_PATH = os.path.join(BASE_PATH, 'templates')
|
||
|
BASE_PATH = '/home/dsorber/Documents/phalanx-repo/software/bookmark_library/'
|
||
|
DB_PATH = os.path.join(BASE_PATH, 'bookmarks.db')
|
||
|
TEMPLATE_PATH = os.path.join(BASE_PATH, 'bmklib', 'web', 'templates')
|
||
|
|
||
|
class BaseHTMLController(object):
|
||
|
|
||
| ... | ... | |
|
""" This function generates the actual response which is made up of two
|
||
|
parts, the response headers and the response body.
|
||
|
"""
|
||
|
self.build_content()
|
||
|
|
||
|
# Generate the stream and then render it to HTML
|
||
|
stream = self.template.generate(**response_args)
|
||
|
stream = self.template.generate(**self.content)
|
||
|
body = stream.render('html', doctype='html', encoding='utf-8')
|
||
|
|
||
|
# Set the appropriate response headers
|
||
| ... | ... | |
|
self.environ = environ
|
||
|
|
||
|
# This string will be the response body
|
||
|
self.body
|
||
|
self.body = ''
|
||
|
|
||
|
def build_content(self):
|
||
|
""" This method is used to build the content that is used to generate
|
||
| ... | ... | |
|
""" This function generates the actual response which is made up of two
|
||
|
parts, the response headers and the response body.
|
||
|
"""
|
||
|
self.build_content()
|
||
|
|
||
|
headers = [('Content-Type', 'text/plain'),
|
||
|
('Content-Length', str(len(self.body)))]
|
||
|
|
||
|
return headers, self.body
|
||
|
|
||
|
|
||
|
class TestController(BaseTextController):
|
||
|
|
||
|
def build_content(self):
|
||
|
self.body = 'hello there handsome'
|
||
| software/bookmark_library/bmklib/web/bmklib.wsgi | ||
|---|---|---|
|
import cgi
|
||
|
import datetime
|
||
|
import os
|
||
|
import sqlite3
|
||
|
from genshi.template import TemplateLoader
|
||
|
from genshi.template.base import Context
|
||
|
|
||
|
BASE_PATH = '/home/dsorber/bfcs'
|
||
|
DB_PATH = os.path.join(BASE_PATH, 'beer_temps.db')
|
||
|
TEMPLATE_PATH = os.path.join(BASE_PATH, 'templates')
|
||
|
from bmklib.web.controllers.main import MainPageController
|
||
|
|
||
|
# It accepts two arguments:
|
||
|
# environ points to a dictionary containing CGI like environment variables
|
||
| ... | ... | |
|
# 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(TEMPLATE_PATH, auto_reload=True)
|
||
|
|
||
|
if not environ['PATH_INFO'] or 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', encoding='utf-8')
|
||
|
# Set the appropriate response headers
|
||
|
response_headers = [('Content-Type', 'text/html; charset=utf-8'),
|
||
|
('Content-Length', str(len(response_body)))]
|
||
|
elif environ['PATH_INFO'].startswith('/day/') and environ['PATH_INFO'].endswith('/all'):
|
||
|
# Load the all template
|
||
|
template = loader.load('all.html')
|
||
|
# Parse the date out of the URL (TODO: validate all this)
|
||
|
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
|
||
|
# (limit to today and the past 5 minutes),
|
||
|
# grab the results, then close the DB connection.
|
||
|
db_conn = sqlite3.connect(DB_PATH)
|
||
|
db = db_conn.cursor()
|
||
|
db.execute("select strftime('%%H:%%M:%%S', ts, 'unixepoch'), "
|
||
|
" temp1, temp2, temp3, temp4, relay_status "
|
||
|
"from temp_data "
|
||
|
"where date(ts, 'unixepoch') is date('%s-%s-%s')"
|
||
|
"order by ts desc" % (year, month, day))
|
||
|
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', encoding='utf-8')
|
||
|
# Set the appropriate response headers
|
||
|
response_headers = [('Content-Type', 'text/html; charset=utf-8'),
|
||
|
('Content-Length', str(len(response_body)))]
|
||
|
elif environ['PATH_INFO'].startswith('/day/'):
|
||
|
# Load the day template
|
||
|
template = loader.load('day.html')
|
||
|
|
||
|
# Parse the date out of the URL (TODO: validate all this)
|
||
|
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,
|
||
|
'url_date': environ['PATH_INFO'][5:13]}
|
||
|
# Open up the connection to the database, execute the query
|
||
|
# (limit to today and the past 5 minutes),
|
||
|
# grab the results, then close the DB connection.
|
||
|
db_conn = sqlite3.connect(DB_PATH)
|
||
|
db = db_conn.cursor()
|
||
|
db.execute("select strftime('%%H:%%M:%%S', ts, 'unixepoch'), "
|
||
|
" temp1, temp2, temp3, temp4, relay_status "
|
||
|
"from temp_data "
|
||
|
"where date(ts, 'unixepoch') is date('%s-%s-%s')"
|
||
|
"order by ts desc limit 300" % (year, month, day))
|
||
|
response_args['results'] = db.fetchall()
|
||
|
# Chart query
|
||
|
#
|
||
|
db.execute("select strftime('%%H:%%M:%%S', ts, 'unixepoch'), ts, temp1, "
|
||
|
" temp2, temp3, temp4 from ( "
|
||
|
"select ts, temp1, temp2, temp3, temp4 "
|
||
|
"from temp_data "
|
||
|
"where date(ts, 'unixepoch') is date('%s-%s-%s')"
|
||
|
"order by ts desc limit 60) order by ts"
|
||
|
% (year, month, day))
|
||
|
chart_results = db.fetchall()
|
||
|
# Process chart query results
|
||
|
sensor1_data = []
|
||
|
sensor2_data = []
|
||
|
sensor3_data = []
|
||
|
sensor4_data = []
|
||
|
for row in chart_results:
|
||
|
sensor1_data.append([int(row[1]) * 1000, row[2]])
|
||
|
sensor2_data.append([int(row[1]) * 1000, row[3]])
|
||
|
sensor3_data.append([int(row[1]) * 1000, row[4]])
|
||
|
sensor4_data.append([int(row[1]) * 1000, row[5]])
|
||
|
response_args['sensor1_data'] = str(sensor1_data)
|
||
|
response_args['sensor2_data'] = str(sensor2_data)
|
||
|
response_args['sensor3_data'] = str(sensor3_data)
|
||
|
response_args['sensor4_data'] = str(sensor4_data)
|
||
|
# This is a bit of hack to get around a javascript issue in
|
||
|
# the template
|
||
|
# response_args['chart_results'] = chart_results[:-1]
|
||
|
# response_args['chart_last_row'] = chart_results[-1]
|
||
|
db_conn.close()
|
||
|
# Generate the stream and then render it to HTML
|
||
|
stream = template.generate(**response_args)
|
||
|
response_body = stream.render('html', doctype='html', encoding='utf-8')
|
||
|
# Set the appropriate response headers
|
||
|
response_headers = [('Content-Type', 'text/html; charset=utf-8'),
|
||
|
('Content-Length', str(len(response_body)))]
|
||
|
elif environ['PATH_INFO'] == ('/chart_update'):
|
||
|
# Update the self updating chart
|
||
|
response_body = ''
|
||
|
if environ['QUERY_STRING']:
|
||
|
# Parse the query string to get the last timestamp from the client
|
||
|
get_args = cgi.parse_qs(environ['QUERY_STRING'])
|
||
|
last_ts = int(get_args['last_ts'][0])
|
||
|
date_from_ts = datetime.datetime.fromtimestamp(last_ts)
|
||
|
# Reconstruct portions of the date from the ts
|
||
|
year = date_from_ts.year
|
||
|
month = '%02d' % date_from_ts.month
|
||
|
day = '%02d' % date_from_ts.day
|
||
|
|
||
|
# Grab any entries from the supplied date that are greater than
|
||
|
# the last timestamp sent from the client javascript
|
||
|
db_conn = sqlite3.connect(DB_PATH)
|
||
|
db = db_conn.cursor()
|
||
|
db.execute("select strftime('%%H:%%M:%%S', ts, 'unixepoch'), ts, "
|
||
|
" temp1, temp2, temp3, temp4, relay_status "
|
||
|
"from temp_data "
|
||
|
"where date(ts, 'unixepoch') is date('%s-%s-%s') and "
|
||
|
" ts > %s "
|
||
|
"order by ts asc limit 60" % (year, month, day, last_ts))
|
||
|
db_rows = db.fetchall()
|
||
|
db_conn.close()
|
||
|
# Iterate over the rows fetched by the query and pretty them up
|
||
|
# in preparation of being sent back to the client javascript for
|
||
|
# display
|
||
|
result_rows = []
|
||
|
for row in db_rows:
|
||
|
result_rows.append('%s %s %s %s %s %s %s' %
|
||
|
(row[0], (int(row[1]) * 1000),
|
||
|
row[2], row[3], row[4], row[5],
|
||
|
int(row[6]) and 'on' or 'off'))
|
||
|
response_body = ','.join(result_rows)
|
||
|
response_body = response_body.encode('utf-8')
|
||
|
response_headers = [('Content-Type', 'text/plain; charset=utf-8'),
|
||
|
('Content-Length', str(len(response_body)))]
|
||
|
|
||
|
controller = MainPageController('main.html', environ)
|
||
|
response_headers, response_body = controller.generate_response()
|
||
|
|
||
|
else:
|
||
|
# User supplied an invalid URL
|
||
|
response_body = 'Invalid URL "%s"' % environ['PATH_INFO']
|
||
| software/bookmark_library/bmklib/web/controllers/main.py | ||
|---|---|---|
|
import sqlite3
|
||
|
|
||
|
from bmklib.web.base_controller import BaseHTMLController, DB_PATH
|
||
|
|
||
|
class MainPageController(BaseHTMLController):
|
||
|
|
||
|
def build_content(self):
|
||
|
conn = sqlite3.connect(DB_PATH)
|
||
|
|
||
|
db = conn.cursor()
|
||
|
db.execute("SELECT COUNT(*) FROM bookmarks")
|
||
|
row = db.fetchone()
|
||
|
|
||
|
self.content['total_num_bmks'] = row[0]
|
||
| software/bookmark_library/bmklib/web/templates/main.html | ||
|---|---|---|
|
<html xmlns="http://www.w3.org/1999/xhtml"
|
||
|
xmlns:py="http://genshi.edgewall.org/">
|
||
|
<head>
|
||
|
<title>Bookmark Library</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;
|
||
|
margin-left: auto;
|
||
|
margin-right: auto;
|
||
|
}
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
</style>
|
||
|
</head>
|
||
|
|
||
|
<body>
|
||
|
<h1>Bookmark Library</h1>
|
||
|
|
||
|
There are currently ${total_num_bmks} bookmarks in the library.
|
||
|
|
||
|
</body>
|
||
|
</html>
|
||
Continued working on the web GUI, taking baby steps.