Committing source

This commit is contained in:
Clayton Walker
2016-04-13 21:40:40 -04:00
parent 7ab0bccd11
commit 000b695324
21 changed files with 7710 additions and 0 deletions

14
blinky.py Executable file
View File

@ -0,0 +1,14 @@
import RPi.GPIO as GPIO
import time
pin = 7
GPIO.setmode(GPIO.BOARD)
GPIO.setup(pin, GPIO.OUT)
for i in range (0,20):
GPIO.output(pin, GPIO.HIGH)
time.sleep(1)
GPIO.output(pin, GPIO.LOW)
time.sleep(1)
GPIO.cleanup()

14
button.py Executable file
View File

@ -0,0 +1,14 @@
import RPi.GPIO as GPIO ## Import GPIO Library
inPin = 8 ## Switch connected to pin 8
GPIO.setmode(GPIO.BOARD) ## Use BOARD pin numbering
GPIO.setup(inPin, GPIO.IN) ## Set pin 8 to INPUT
while True: ## Do this forever
value = GPIO.input(inPin) ## Read input from switch
if value: ## If switch is released
print "Not Pressed"
else: ## Else switch is pressed
print "Pressed"
GPIO.cleanup()

32
html/index.nginx-debian.html Executable file
View File

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx on Debian!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx on Debian!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working on Debian. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a></p>
<p>
Please use the <tt>reportbug</tt> tool to report bugs in the
nginx package with Debian. However, check <a
href="http://bugs.debian.org/cgi-bin/pkgreport.cgi?ordering=normal;archive=0;src=nginx;repeatmerged=0">existing
bug reports</a> before reporting a new bug.
</p>
<p><em>Thank you for using debian and nginx.</em></p>
</body>
</html>

65
lab_app/env_log.py Executable file
View File

@ -0,0 +1,65 @@
#!/usr/bin/env python
'''
FILE NAME
env_log.py
1. WHAT IT DOES
Takes a reading from a DHT sensor and records the values in an SQLite3 database using a Raspberry Pi.
2. REQUIRES
* Any Raspberry Pi
* A DHT sensor
* A 10kOhm resistor
* Jumper wires
3. ORIGINAL WORK
Raspberry Full stack 2015, Peter Dalmaris
4. HARDWARE
D17: Data pin for sensor
5. SOFTWARE
Command line terminal
Simple text editor
Libraries:
import sqlite3
import sys
import Adafruit_DHT
6. WARNING!
None
7. CREATED
8. TYPICAL OUTPUT
No text output. Two new records are inserted in the database when the script is executed
// 9. COMMENTS
--
// 10. END
'''
import sqlite3
import sys
import Adafruit_DHT
def log_values(sensor_id, temp, hum):
conn=sqlite3.connect('/var/www/lab_app/lab_app.db') #It is important to provide an
#absolute path to the database
#file, otherwise Cron won't be
#able to find it!
curs=conn.cursor()
curs.execute("""INSERT INTO temperatures values(datetime(CURRENT_TIMESTAMP, 'localtime'),
(?), (?))""", (sensor_id,temp))
curs.execute("""INSERT INTO humidities values(datetime(CURRENT_TIMESTAMP, 'localtime'),
(?), (?))""", (sensor_id,hum))
conn.commit()
conn.close()
humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.AM2302, 17)
temperature = temperature * 9/5.0 + 32
# If you don't have a sensor but still wish to run this program, comment out all the
# sensor related lines, and uncomment the following lines (these will produce random
# numbers for the temperature and humidity variables):
# import random
# humidity = random.randint(1,100)
# temperature = random.randint(10,30)
if humidity is not None and temperature is not None:
log_values("1", temperature, humidity)
else:
log_values("1", -999, -999)

11
lab_app/hello.py Executable file
View File

@ -0,0 +1,11 @@
from flask import Flask
from flask import render_template
app = Flask(__name__)
app.debug = True
@app.route("/")
def hello():
return render_template('hello.html', message="Hello World!")
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080)

BIN
lab_app/lab_app.db Executable file

Binary file not shown.

219
lab_app/lab_app.py Executable file
View File

@ -0,0 +1,219 @@
'''
FILE NAME
lab_app.py
Version 9
1. WHAT IT DOES
This version adds support for Plotly.
2. REQUIRES
* Any Raspberry Pi
3. ORIGINAL WORK
Raspberry Full Stack 2015, Peter Dalmaris
4. HARDWARE
* Any Raspberry Pi
* DHT11 or 22
* 10KOhm resistor
* Breadboard
* Wires
5. SOFTWARE
Command line terminal
Simple text editor
Libraries:
from flask import Flask, request, render_template, sqlite3
6. WARNING!
None
7. CREATED
8. TYPICAL OUTPUT
A simple web page served by this flask application in the user's browser.
The page contains the current temperature and humidity.
A second page that displays historical environment data from the SQLite3 database.
The historical records can be selected by specifying a date range in the request URL.
The user can now click on one of the date/time buttons to quickly select one of the available record ranges.
The user can use Jquery widgets to select a date/time range.
The user can explore historical data to Plotly for visualisation and processing.
// 9. COMMENTS
--
// 10. END
'''
from flask import Flask, request, render_template
import time
import datetime
import arrow
app = Flask(__name__)
app.debug = True # Make this False if you are no longer debugging
@app.route("/")
def hello():
return "Hello World!"
@app.route("/lab_temp")
def lab_temp():
import sys
import Adafruit_DHT
humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.AM2302, 17)
temperature = temperature * 9/5.0 + 32
if humidity is not None and temperature is not None:
return render_template("lab_temp.html",temp=temperature,hum=humidity)
else:
return render_template("no_sensor.html")
@app.route("/lab_env_db", methods=['GET']) #Add date limits in the URL #Arguments: from=2015-03-04&to=2015-03-05
def lab_env_db():
temperatures, humidities, timezone, from_date_str, to_date_str = get_records()
# Create new record tables so that datetimes are adjusted back to the user browser's time zone.
time_adjusted_temperatures = []
time_adjusted_humidities = []
for record in temperatures:
local_timedate = arrow.get(record[0], "YYYY-MM-DD HH:mm").to(timezone)
time_adjusted_temperatures.append([local_timedate.format('YYYY-MM-DD HH:mm'), round(record[2],2)])
for record in humidities:
local_timedate = arrow.get(record[0], "YYYY-MM-DD HH:mm").to(timezone)
time_adjusted_humidities.append([local_timedate.format('YYYY-MM-DD HH:mm'), round(record[2],2)])
print "rendering lab_env_db.html with: %s, %s, %s" % (timezone, from_date_str, to_date_str)
return render_template("lab_env_db.html", timezone = timezone,
temp = time_adjusted_temperatures,
hum = time_adjusted_humidities,
from_date = from_date_str,
to_date = to_date_str,
temp_items = len(temperatures),
query_string = request.query_string, #This query string is used
#by the Plotly link
hum_items = len(humidities))
def get_records():
import sqlite3
from_date_str = request.args.get('from',time.strftime("%Y-%m-%d 00:00")) #Get the from date value from the URL
to_date_str = request.args.get('to',time.strftime("%Y-%m-%d %H:%M")) #Get the to date value from the URL
timezone = request.args.get('timezone','Etc/UTC');
range_h_form = request.args.get('range_h',''); #This will return a string, if field range_h exists in the request
range_h_int = "nan" #initialise this variable with not a number
print "REQUEST:"
print request.args
try:
range_h_int = int(range_h_form)
except:
print "range_h_form not a number"
print "Received from browser: %s, %s, %s, %s" % (from_date_str, to_date_str, timezone, range_h_int)
if not validate_date(from_date_str): # Validate date before sending it to the DB
from_date_str = time.strftime("%Y-%m-%d 00:00")
if not validate_date(to_date_str):
to_date_str = time.strftime("%Y-%m-%d %H:%M") # Validate date before sending it to the DB
print '2. From: %s, to: %s, timezone: %s' % (from_date_str,to_date_str,timezone)
# Create datetime object so that we can convert to UTC from the browser's local time
from_date_obj = datetime.datetime.strptime(from_date_str,'%Y-%m-%d %H:%M')
to_date_obj = datetime.datetime.strptime(to_date_str,'%Y-%m-%d %H:%M')
# If range_h is defined, we don't need the from and to times
if isinstance(range_h_int,int):
arrow_time_from = arrow.utcnow().replace(hours=-range_h_int)
arrow_time_to = arrow.utcnow()
from_date_utc = arrow_time_from.strftime("%Y-%m-%d %H:%M")
to_date_utc = arrow_time_to.strftime("%Y-%m-%d %H:%M")
from_date_str = arrow_time_from.to(timezone).strftime("%Y-%m-%d %H:%M")
to_date_str = arrow_time_to.to(timezone).strftime("%Y-%m-%d %H:%M")
else:
#Convert datetimes to UTC so we can retrieve the appropriate records from the database
from_date_utc = arrow.get(from_date_obj, timezone).to('Etc/UTC').strftime("%Y-%m-%d %H:%M")
to_date_utc = arrow.get(to_date_obj, timezone).to('Etc/UTC').strftime("%Y-%m-%d %H:%M")
conn = sqlite3.connect('/var/www/lab_app/lab_app.db')
curs = conn.cursor()
curs.execute("SELECT * FROM temperatures WHERE rDateTime BETWEEN ? AND ?", (from_date_utc.format('YYYY-MM-DD HH:mm'), to_date_utc.format('YYYY-MM-DD HH:mm')))
temperatures = curs.fetchall()
curs.execute("SELECT * FROM humidities WHERE rDateTime BETWEEN ? AND ?", (from_date_utc.format('YYYY-MM-DD HH:mm'), to_date_utc.format('YYYY-MM-DD HH:mm')))
humidities = curs.fetchall()
conn.close()
return [temperatures, humidities, timezone, from_date_str, to_date_str]
@app.route("/to_plotly", methods=['GET']) #This method will send the data to ploty.
def to_plotly():
import plotly.plotly as py
from plotly.graph_objs import *
temperatures, humidities, timezone, from_date_str, to_date_str = get_records()
# Create new record tables so that datetimes are adjusted back to the user browser's time zone.
time_series_adjusted_tempreratures = []
time_series_adjusted_humidities = []
time_series_temprerature_values = []
time_series_humidity_values = []
for record in temperatures:
local_timedate = arrow.get(record[0], "YYYY-MM-DD HH:mm").to(timezone)
time_series_adjusted_tempreratures.append(local_timedate.format('YYYY-MM-DD HH:mm'))
time_series_temprerature_values.append(round(record[2],2))
for record in humidities:
local_timedate = arrow.get(record[0], "YYYY-MM-DD HH:mm").to(timezone)
time_series_adjusted_humidities.append(local_timedate.format('YYYY-MM-DD HH:mm')) #Best to pass datetime in text
#so that Plotly respects it
time_series_humidity_values.append(round(record[2],2))
temp = Scatter(
x=time_series_adjusted_tempreratures,
y=time_series_temprerature_values,
name='Temperature'
)
hum = Scatter(
x=time_series_adjusted_humidities,
y=time_series_humidity_values,
name='Humidity',
yaxis='y2'
)
data = Data([temp, hum])
layout = Layout(
title="Temperature and Humidity in Clayton's Apartment",
xaxis=XAxis(
type='date',
autorange=True
),
yaxis=YAxis(
title='Fahrenheit',
type='linear',
autorange=True
),
yaxis2=YAxis(
title='Percent',
type='linear',
autorange=True,
overlaying='y',
side='right'
)
)
fig = Figure(data=data, layout=layout)
plot_url = py.plot(fig, filename='lab_temp_hum')
return plot_url
def validate_date(d):
try:
datetime.datetime.strptime(d, '%Y-%m-%d %H:%M')
return True
except ValueError:
return False
if __name__ == "__main__":
app.run(host='0.0.0.0', port=8080)

18
lab_app/lab_app_nginx.conf Executable file
View File

@ -0,0 +1,18 @@
#Full path: /var/www/lab_app/lab_app_nginx.conf
server {
listen 80;
server_name localhost;
charset utf-8;
client_max_body_size 75M;
location /static {
root /var/www/lab_app/;
}
location / { try_files $uri @labapp; }
location @labapp {
include uwsgi_params;
uwsgi_pass unix:/var/www/lab_app/lab_app_uwsgi.sock;
}
}

24
lab_app/lab_app_uwsgi.ini Executable file
View File

@ -0,0 +1,24 @@
#Full path: /var/www/lab_app/lab_app_uwsgi.ini
[uwsgi]
#application's base folder
base = /var/www/lab_app
#python module to import
app = lab_app
module = %(app)
home = %(base)/venv
pythonpath = %(base)
#socket file's location
socket = /var/www/lab_app/%n.sock
#permissions for the socket file
chmod-socket = 666
#the variable that holds a flask application inside the module imported at line #6
callable = app
#location of log files
logto = /var/log/uwsgi/%n.log

View File

@ -0,0 +1,9 @@
<html>
<head>
<title>Static page</title>
</head>
<body>
<h1>This is an example of a static page</h1>
<p>Neat, isnt it?</p>
</body>
</html>

View File

@ -0,0 +1,23 @@
<html>
<head>
<meta charset="utf-8">
<title>Static page</title>
<!-- Mobile Specific Metas
-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- FONT
-->
<link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">
<!-- CSS
-->
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/skeleton.css">
<!-- Favicon
-->
<link rel="icon" type="image/png" href="images/favicon.png">
</head>
<body>
<h1>This is an example of a static page</h1>
<p>Neat, isnt it?</p>
</body>
</html>

View File

@ -0,0 +1,568 @@
.xdsoft_datetimepicker {
box-shadow: 0 5px 15px -5px rgba(0, 0, 0, 0.506);
background: #fff;
border-bottom: 1px solid #bbb;
border-left: 1px solid #ccc;
border-right: 1px solid #ccc;
border-top: 1px solid #ccc;
color: #333;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
padding: 8px;
padding-left: 0;
padding-top: 2px;
position: absolute;
z-index: 9999;
-moz-box-sizing: border-box;
box-sizing: border-box;
display: none;
}
.xdsoft_datetimepicker.xdsoft_rtl {
padding: 8px 0 8px 8px;
}
.xdsoft_datetimepicker iframe {
position: absolute;
left: 0;
top: 0;
width: 75px;
height: 210px;
background: transparent;
border: none;
}
/*For IE8 or lower*/
.xdsoft_datetimepicker button {
border: none !important;
}
.xdsoft_noselect {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
.xdsoft_noselect::selection { background: transparent }
.xdsoft_noselect::-moz-selection { background: transparent }
.xdsoft_datetimepicker.xdsoft_inline {
display: inline-block;
position: static;
box-shadow: none;
}
.xdsoft_datetimepicker * {
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
margin: 0;
}
.xdsoft_datetimepicker .xdsoft_datepicker, .xdsoft_datetimepicker .xdsoft_timepicker {
display: none;
}
.xdsoft_datetimepicker .xdsoft_datepicker.active, .xdsoft_datetimepicker .xdsoft_timepicker.active {
display: block;
}
.xdsoft_datetimepicker .xdsoft_datepicker {
width: 224px;
float: left;
margin-left: 8px;
}
.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_datepicker {
float: right;
margin-right: 8px;
margin-left: 0;
}
.xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_datepicker {
width: 256px;
}
.xdsoft_datetimepicker .xdsoft_timepicker {
width: 58px;
float: left;
text-align: center;
margin-left: 8px;
margin-top: 0;
}
.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker {
float: right;
margin-right: 8px;
margin-left: 0;
}
.xdsoft_datetimepicker .xdsoft_datepicker.active+.xdsoft_timepicker {
margin-top: 8px;
margin-bottom: 3px
}
.xdsoft_datetimepicker .xdsoft_mounthpicker {
position: relative;
text-align: center;
}
.xdsoft_datetimepicker .xdsoft_label i,
.xdsoft_datetimepicker .xdsoft_prev,
.xdsoft_datetimepicker .xdsoft_next,
.xdsoft_datetimepicker .xdsoft_today_button {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAeCAYAAADaW7vzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Q0NBRjI1NjM0M0UwMTFFNDk4NkFGMzJFQkQzQjEwRUIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6Q0NBRjI1NjQ0M0UwMTFFNDk4NkFGMzJFQkQzQjEwRUIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDQ0FGMjU2MTQzRTAxMUU0OTg2QUYzMkVCRDNCMTBFQiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDQ0FGMjU2MjQzRTAxMUU0OTg2QUYzMkVCRDNCMTBFQiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PoNEP54AAAIOSURBVHja7Jq9TsMwEMcxrZD4WpBYeKUCe+kTMCACHZh4BFfHO/AAIHZGFhYkBBsSEqxsLCAgXKhbXYOTxh9pfJVP+qutnZ5s/5Lz2Y5I03QhWji2GIcgAokWgfCxNvcOCCGKqiSqhUp0laHOne05vdEyGMfkdxJDVjgwDlEQgYQBgx+ULJaWSXXS6r/ER5FBVR8VfGftTKcITNs+a1XpcFoExREIDF14AVIFxgQUS+h520cdud6wNkC0UBw6BCO/HoCYwBhD8QCkQ/x1mwDyD4plh4D6DDV0TAGyo4HcawLIBBSLDkHeH0Mg2yVP3l4TQMZQDDsEOl/MgHQqhMNuE0D+oBh0CIr8MAKyazBH9WyBuKxDWgbXfjNf32TZ1KWm/Ap1oSk/R53UtQ5xTh3LUlMmT8gt6g51Q9p+SobxgJQ/qmsfZhWywGFSl0yBjCLJCMgXail3b7+rumdVJ2YRss4cN+r6qAHDkPWjPjdJCF4n9RmAD/V9A/Wp4NQassDjwlB6XBiCxcJQWmZZb8THFilfy/lfrTvLghq2TqTHrRMTKNJ0sIhdo15RT+RpyWwFdY96UZ/LdQKBGjcXpcc1AlSFEfLmouD+1knuxBDUVrvOBmoOC/rEcN7OQxKVeJTCiAdUzUJhA2Oez9QTkp72OTVcxDcXY8iKNkxGAJXmJCOQwOa6dhyXsOa6XwEGAKdeb5ET3rQdAAAAAElFTkSuQmCC);
}
.xdsoft_datetimepicker .xdsoft_label i {
opacity: 0.5;
background-position: -92px -19px;
display: inline-block;
width: 9px;
height: 20px;
vertical-align: middle;
}
.xdsoft_datetimepicker .xdsoft_prev {
float: left;
background-position: -20px 0;
}
.xdsoft_datetimepicker .xdsoft_today_button {
float: left;
background-position: -70px 0;
margin-left: 5px;
}
.xdsoft_datetimepicker .xdsoft_next {
float: right;
background-position: 0 0;
}
.xdsoft_datetimepicker .xdsoft_next,
.xdsoft_datetimepicker .xdsoft_prev ,
.xdsoft_datetimepicker .xdsoft_today_button {
background-color: transparent;
background-repeat: no-repeat;
border: 0 none;
cursor: pointer;
display: block;
height: 30px;
opacity: 0.5;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
outline: medium none;
overflow: hidden;
padding: 0;
position: relative;
text-indent: 100%;
white-space: nowrap;
width: 20px;
min-width: 0;
}
.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_prev,
.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_next {
float: none;
background-position: -40px -15px;
height: 15px;
width: 30px;
display: block;
margin-left: 14px;
margin-top: 7px;
}
.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker .xdsoft_prev,
.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_timepicker .xdsoft_next {
float: none;
margin-left: 0;
margin-right: 14px;
}
.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_prev {
background-position: -40px 0;
margin-bottom: 7px;
margin-top: 0;
}
.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box {
height: 151px;
overflow: hidden;
border-bottom: 1px solid #ddd;
}
.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div {
background: #f5f5f5;
border-top: 1px solid #ddd;
color: #666;
font-size: 12px;
text-align: center;
border-collapse: collapse;
cursor: pointer;
border-bottom-width: 0;
height: 25px;
line-height: 25px;
}
.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div > div:first-child {
border-top-width: 0;
}
.xdsoft_datetimepicker .xdsoft_today_button:hover,
.xdsoft_datetimepicker .xdsoft_next:hover,
.xdsoft_datetimepicker .xdsoft_prev:hover {
opacity: 1;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
}
.xdsoft_datetimepicker .xdsoft_label {
display: inline;
position: relative;
z-index: 9999;
margin: 0;
padding: 5px 3px;
font-size: 14px;
line-height: 20px;
font-weight: bold;
background-color: #fff;
float: left;
width: 182px;
text-align: center;
cursor: pointer;
}
.xdsoft_datetimepicker .xdsoft_label:hover>span {
text-decoration: underline;
}
.xdsoft_datetimepicker .xdsoft_label:hover i {
opacity: 1.0;
}
.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select {
border: 1px solid #ccc;
position: absolute;
right: 0;
top: 30px;
z-index: 101;
display: none;
background: #fff;
max-height: 160px;
overflow-y: hidden;
}
.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select.xdsoft_monthselect{ right: -7px }
.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select.xdsoft_yearselect{ right: 2px }
.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option:hover {
color: #fff;
background: #ff8000;
}
.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option {
padding: 2px 10px 2px 5px;
text-decoration: none !important;
}
.xdsoft_datetimepicker .xdsoft_label > .xdsoft_select > div > .xdsoft_option.xdsoft_current {
background: #33aaff;
box-shadow: #178fe5 0 1px 3px 0 inset;
color: #fff;
font-weight: 700;
}
.xdsoft_datetimepicker .xdsoft_month {
width: 100px;
text-align: right;
}
.xdsoft_datetimepicker .xdsoft_calendar {
clear: both;
}
.xdsoft_datetimepicker .xdsoft_year{
width: 48px;
margin-left: 5px;
}
.xdsoft_datetimepicker .xdsoft_calendar table {
border-collapse: collapse;
width: 100%;
}
.xdsoft_datetimepicker .xdsoft_calendar td > div {
padding-right: 5px;
}
.xdsoft_datetimepicker .xdsoft_calendar th {
height: 25px;
}
.xdsoft_datetimepicker .xdsoft_calendar td,.xdsoft_datetimepicker .xdsoft_calendar th {
width: 14.2857142%;
background: #f5f5f5;
border: 1px solid #ddd;
color: #666;
font-size: 12px;
text-align: right;
vertical-align: middle;
padding: 0;
border-collapse: collapse;
cursor: pointer;
height: 25px;
}
.xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_calendar td,.xdsoft_datetimepicker.xdsoft_showweeks .xdsoft_calendar th {
width: 12.5%;
}
.xdsoft_datetimepicker .xdsoft_calendar th {
background: #f1f1f1;
}
.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_today {
color: #33aaff;
}
.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_highlighted_default {
background: #ffe9d2;
box-shadow: #ffb871 0 1px 4px 0 inset;
color: #000;
}
.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_highlighted_mint {
background: #c1ffc9;
box-shadow: #00dd1c 0 1px 4px 0 inset;
color: #000;
}
.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_default,
.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current,
.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_current {
background: #33aaff;
box-shadow: #178fe5 0 1px 3px 0 inset;
color: #fff;
font-weight: 700;
}
.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month,
.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled,
.xdsoft_datetimepicker .xdsoft_time_box >div >div.xdsoft_disabled {
opacity: 0.5;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
cursor: default;
}
.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_other_month.xdsoft_disabled {
opacity: 0.2;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
}
.xdsoft_datetimepicker .xdsoft_calendar td:hover,
.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div:hover {
color: #fff !important;
background: #ff8000 !important;
box-shadow: none !important;
}
.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_current.xdsoft_disabled:hover,
.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box>div>div.xdsoft_current.xdsoft_disabled:hover {
background: #33aaff !important;
box-shadow: #178fe5 0 1px 3px 0 inset !important;
color: #fff !important;
}
.xdsoft_datetimepicker .xdsoft_calendar td.xdsoft_disabled:hover,
.xdsoft_datetimepicker .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_disabled:hover {
color: inherit !important;
background: inherit !important;
box-shadow: inherit !important;
}
.xdsoft_datetimepicker .xdsoft_calendar th {
font-weight: 700;
text-align: center;
color: #999;
cursor: default;
}
.xdsoft_datetimepicker .xdsoft_copyright {
color: #ccc !important;
font-size: 10px;
clear: both;
float: none;
margin-left: 8px;
}
.xdsoft_datetimepicker .xdsoft_copyright a { color: #eee !important }
.xdsoft_datetimepicker .xdsoft_copyright a:hover { color: #aaa !important }
.xdsoft_time_box {
position: relative;
border: 1px solid #ccc;
}
.xdsoft_scrollbar >.xdsoft_scroller {
background: #ccc !important;
height: 20px;
border-radius: 3px;
}
.xdsoft_scrollbar {
position: absolute;
width: 7px;
right: 0;
top: 0;
bottom: 0;
cursor: pointer;
}
.xdsoft_datetimepicker.xdsoft_rtl .xdsoft_scrollbar {
left: 0;
right: auto;
}
.xdsoft_scroller_box {
position: relative;
}
.xdsoft_datetimepicker.xdsoft_dark {
box-shadow: 0 5px 15px -5px rgba(255, 255, 255, 0.506);
background: #000;
border-bottom: 1px solid #444;
border-left: 1px solid #333;
border-right: 1px solid #333;
border-top: 1px solid #333;
color: #ccc;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box {
border-bottom: 1px solid #222;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box >div >div {
background: #0a0a0a;
border-top: 1px solid #222;
color: #999;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label {
background-color: #000;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label > .xdsoft_select {
border: 1px solid #333;
background: #000;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label > .xdsoft_select > div > .xdsoft_option:hover {
color: #000;
background: #007fff;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label > .xdsoft_select > div > .xdsoft_option.xdsoft_current {
background: #cc5500;
box-shadow: #b03e00 0 1px 3px 0 inset;
color: #000;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_label i,
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_prev,
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_next,
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_today_button {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAeCAYAAADaW7vzAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QUExQUUzOTA0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QUExQUUzOTE0M0UyMTFFNDlBM0FFQTJENTExRDVBODYiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpBQTFBRTM4RTQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpBQTFBRTM4RjQzRTIxMUU0OUEzQUVBMkQ1MTFENUE4NiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pp0VxGEAAAIASURBVHja7JrNSgMxEMebtgh+3MSLr1T1Xn2CHoSKB08+QmR8Bx9A8e7RixdB9CKCoNdexIugxFlJa7rNZneTbLIpM/CnNLsdMvNjM8l0mRCiQ9Ye61IKCAgZAUnH+mU3MMZaHYChBnJUDzWOFZdVfc5+ZFLbrWDeXPwbxIqrLLfaeS0hEBVGIRQCEiZoHQwtlGSByCCdYBl8g8egTTAWoKQMRBRBcZxYlhzhKegqMOageErsCHVkk3hXIFooDgHB1KkHIHVgzKB4ADJQ/A1jAFmAYhkQqA5TOBtocrKrgXwQA8gcFIuAIO8sQSA7hidvPwaQGZSaAYHOUWJABhWWw2EMIH9QagQERU4SArJXo0ZZL18uvaxejXt/Em8xjVBXmvFr1KVm/AJ10tRe2XnraNqaJvKE3KHuUbfK1E+VHB0q40/y3sdQSxY4FHWeKJCunP8UyDdqJZenT3ntVV5jIYCAh20vT7ioP8tpf6E2lfEMwERe+whV1MHjwZB7PBiCxcGQWwKZKD62lfGNnP/1poFAA60T7rF1UgcKd2id3KDeUS+oLWV8DfWAepOfq00CgQabi9zjcgJVYVD7PVzQUAUGAQkbNJTBICDhgwYTjDYD6XeW08ZKh+A4pYkzenOxXUbvZcWz7E8ykRMnIHGX1XPl+1m2vPYpL+2qdb8CDAARlKFEz/ZVkAAAAABJRU5ErkJggg==);
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td,
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th {
background: #0a0a0a;
border: 1px solid #222;
color: #999;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th {
background: #0e0e0e;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_today {
color: #cc5500;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_highlighted_default {
background: #ffe9d2;
box-shadow: #ffb871 0 1px 4px 0 inset;
color:#000;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_highlighted_mint {
background: #c1ffc9;
box-shadow: #00dd1c 0 1px 4px 0 inset;
color:#000;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_default,
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td.xdsoft_current,
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box >div >div.xdsoft_current {
background: #cc5500;
box-shadow: #b03e00 0 1px 3px 0 inset;
color: #000;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar td:hover,
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_timepicker .xdsoft_time_box >div >div:hover {
color: #000 !important;
background: #007fff !important;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_calendar th {
color: #666;
}
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright { color: #333 !important }
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright a { color: #111 !important }
.xdsoft_datetimepicker.xdsoft_dark .xdsoft_copyright a:hover { color: #555 !important }
.xdsoft_dark .xdsoft_time_box {
border: 1px solid #333;
}
.xdsoft_dark .xdsoft_scrollbar >.xdsoft_scroller {
background: #333 !important;
}
.xdsoft_datetimepicker .xdsoft_save_selected {
display: block;
border: 1px solid #dddddd !important;
margin-top: 5px;
width: 100%;
color: #454551;
font-size: 13px;
}
.xdsoft_datetimepicker .blue-gradient-button {
font-family: "museo-sans", "Book Antiqua", sans-serif;
font-size: 12px;
font-weight: 300;
color: #82878c;
height: 28px;
position: relative;
padding: 4px 17px 4px 33px;
border: 1px solid #d7d8da;
background: -moz-linear-gradient(top, #fff 0%, #f4f8fa 73%);
/* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(73%, #f4f8fa));
/* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #fff 0%, #f4f8fa 73%);
/* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #fff 0%, #f4f8fa 73%);
/* Opera 11.10+ */
background: -ms-linear-gradient(top, #fff 0%, #f4f8fa 73%);
/* IE10+ */
background: linear-gradient(to bottom, #fff 0%, #f4f8fa 73%);
/* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#fff', endColorstr='#f4f8fa',GradientType=0 );
/* IE6-9 */
}
.xdsoft_datetimepicker .blue-gradient-button:hover, .xdsoft_datetimepicker .blue-gradient-button:focus, .xdsoft_datetimepicker .blue-gradient-button:hover span, .xdsoft_datetimepicker .blue-gradient-button:focus span {
color: #454551;
background: -moz-linear-gradient(top, #f4f8fa 0%, #FFF 73%);
/* FF3.6+ */
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f4f8fa), color-stop(73%, #FFF));
/* Chrome,Safari4+ */
background: -webkit-linear-gradient(top, #f4f8fa 0%, #FFF 73%);
/* Chrome10+,Safari5.1+ */
background: -o-linear-gradient(top, #f4f8fa 0%, #FFF 73%);
/* Opera 11.10+ */
background: -ms-linear-gradient(top, #f4f8fa 0%, #FFF 73%);
/* IE10+ */
background: linear-gradient(to bottom, #f4f8fa 0%, #FFF 73%);
/* W3C */
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f8fa', endColorstr='#FFF',GradientType=0 );
/* IE6-9 */
}

427
lab_app/static/css/normalize.css vendored Executable file
View File

@ -0,0 +1,427 @@
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS text size adjust after orientation change, without disabling
* user zoom.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 8/9.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio,
canvas,
progress,
video {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
}
/**
* Prevent modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* Improve readability when focused and also mouse hovered in all browsers.
*/
a:active,
a:hover {
outline: 0;
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b,
strong {
font-weight: bold;
}
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Address styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
/* Embedded content
========================================================================== */
/**
* Remove border when inside `a` element in IE 8/9/10.
*/
img {
border: 0;
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
*/
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
*/
button,
input,
optgroup,
select,
textarea {
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* It's recommended that you don't attempt to style these elements.
* Firefox's implementation doesn't respect box-sizing, padding, or width.
*
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
* (include `-moz` to future-proof).
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
-moz-box-sizing: content-box;
-webkit-box-sizing: content-box; /* 2 */
box-sizing: content-box;
}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}

418
lab_app/static/css/skeleton.css vendored Executable file
View File

@ -0,0 +1,418 @@
/*
* Skeleton V2.0.4
* Copyright 2014, Dave Gamache
* www.getskeleton.com
* Free to use under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
* 12/29/2014
*/
/* Table of contents
- Grid
- Base Styles
- Typography
- Links
- Buttons
- Forms
- Lists
- Code
- Tables
- Spacing
- Utilities
- Clearing
- Media Queries
*/
/* Grid
*/
.container {
position: relative;
width: 100%;
max-width: 960px;
margin: 0 auto;
padding: 0 20px;
box-sizing: border-box; }
.column,
.columns {
width: 100%;
float: left;
box-sizing: border-box; }
/* For devices larger than 400px */
@media (min-width: 400px) {
.container {
width: 85%;
padding: 0; }
}
/* For devices larger than 550px */
@media (min-width: 550px) {
.container {
width: 80%; }
.column,
.columns {
margin-left: 4%; }
.column:first-child,
.columns:first-child {
margin-left: 0; }
.one.column,
.one.columns { width: 4.66666666667%; }
.two.columns { width: 13.3333333333%; }
.three.columns { width: 22%; }
.four.columns { width: 30.6666666667%; }
.five.columns { width: 39.3333333333%; }
.six.columns { width: 48%; }
.seven.columns { width: 56.6666666667%; }
.eight.columns { width: 65.3333333333%; }
.nine.columns { width: 74.0%; }
.ten.columns { width: 82.6666666667%; }
.eleven.columns { width: 91.3333333333%; }
.twelve.columns { width: 100%; margin-left: 0; }
.one-third.column { width: 30.6666666667%; }
.two-thirds.column { width: 65.3333333333%; }
.one-half.column { width: 48%; }
/* Offsets */
.offset-by-one.column,
.offset-by-one.columns { margin-left: 8.66666666667%; }
.offset-by-two.column,
.offset-by-two.columns { margin-left: 17.3333333333%; }
.offset-by-three.column,
.offset-by-three.columns { margin-left: 26%; }
.offset-by-four.column,
.offset-by-four.columns { margin-left: 34.6666666667%; }
.offset-by-five.column,
.offset-by-five.columns { margin-left: 43.3333333333%; }
.offset-by-six.column,
.offset-by-six.columns { margin-left: 52%; }
.offset-by-seven.column,
.offset-by-seven.columns { margin-left: 60.6666666667%; }
.offset-by-eight.column,
.offset-by-eight.columns { margin-left: 69.3333333333%; }
.offset-by-nine.column,
.offset-by-nine.columns { margin-left: 78.0%; }
.offset-by-ten.column,
.offset-by-ten.columns { margin-left: 86.6666666667%; }
.offset-by-eleven.column,
.offset-by-eleven.columns { margin-left: 95.3333333333%; }
.offset-by-one-third.column,
.offset-by-one-third.columns { margin-left: 34.6666666667%; }
.offset-by-two-thirds.column,
.offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
.offset-by-one-half.column,
.offset-by-one-half.columns { margin-left: 52%; }
}
/* Base Styles
*/
/* NOTE
html is set to 62.5% so that all the REM measurements throughout Skeleton
are based on 10px sizing. So basically 1.5rem = 15px :) */
html {
font-size: 62.5%; }
body {
font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
line-height: 1.6;
font-weight: 400;
font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #222; }
/* Typography
*/
h1, h2, h3, h4, h5, h6 {
margin-top: 0;
margin-bottom: 2rem;
font-weight: 300; }
h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
/* Larger than phablet */
@media (min-width: 550px) {
h1 { font-size: 5.0rem; }
h2 { font-size: 4.2rem; }
h3 { font-size: 3.6rem; }
h4 { font-size: 3.0rem; }
h5 { font-size: 2.4rem; }
h6 { font-size: 1.5rem; }
}
p {
margin-top: 0; }
/* Links
*/
a {
color: #1EAEDB; }
a:hover {
color: #0FA0CE; }
/* Buttons
*/
.button,
button,
input[type="submit"],
input[type="reset"],
input[type="button"] {
display: inline-block;
height: 38px;
padding: 0 30px;
color: #555;
text-align: center;
font-size: 11px;
font-weight: 600;
line-height: 38px;
letter-spacing: .1rem;
text-transform: uppercase;
text-decoration: none;
white-space: nowrap;
background-color: transparent;
border-radius: 4px;
border: 1px solid #bbb;
cursor: pointer;
box-sizing: border-box; }
.button:hover,
button:hover,
input[type="submit"]:hover,
input[type="reset"]:hover,
input[type="button"]:hover,
.button:focus,
button:focus,
input[type="submit"]:focus,
input[type="reset"]:focus,
input[type="button"]:focus {
color: #333;
border-color: #888;
outline: 0; }
.button.button-primary,
button.button-primary,
input[type="submit"].button-primary,
input[type="reset"].button-primary,
input[type="button"].button-primary {
color: #FFF;
background-color: #33C3F0;
border-color: #33C3F0; }
.button.button-primary:hover,
button.button-primary:hover,
input[type="submit"].button-primary:hover,
input[type="reset"].button-primary:hover,
input[type="button"].button-primary:hover,
.button.button-primary:focus,
button.button-primary:focus,
input[type="submit"].button-primary:focus,
input[type="reset"].button-primary:focus,
input[type="button"].button-primary:focus {
color: #FFF;
background-color: #1EAEDB;
border-color: #1EAEDB; }
/* Forms
*/
input[type="email"],
input[type="number"],
input[type="search"],
input[type="text"],
input[type="tel"],
input[type="url"],
input[type="password"],
textarea,
select {
height: 38px;
padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
background-color: #fff;
border: 1px solid #D1D1D1;
border-radius: 4px;
box-shadow: none;
box-sizing: border-box; }
/* Removes awkward default styles on some inputs for iOS */
input[type="email"],
input[type="number"],
input[type="search"],
input[type="text"],
input[type="tel"],
input[type="url"],
input[type="password"],
textarea {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none; }
textarea {
min-height: 65px;
padding-top: 6px;
padding-bottom: 6px; }
input[type="email"]:focus,
input[type="number"]:focus,
input[type="search"]:focus,
input[type="text"]:focus,
input[type="tel"]:focus,
input[type="url"]:focus,
input[type="password"]:focus,
textarea:focus,
select:focus {
border: 1px solid #33C3F0;
outline: 0; }
label,
legend {
display: block;
margin-bottom: .5rem;
font-weight: 600; }
fieldset {
padding: 0;
border-width: 0; }
input[type="checkbox"],
input[type="radio"] {
display: inline; }
label > .label-body {
display: inline-block;
margin-left: .5rem;
font-weight: normal; }
/* Lists
*/
ul {
list-style: circle inside; }
ol {
list-style: decimal inside; }
ol, ul {
padding-left: 0;
margin-top: 0; }
ul ul,
ul ol,
ol ol,
ol ul {
margin: 1.5rem 0 1.5rem 3rem;
font-size: 90%; }
li {
margin-bottom: 1rem; }
/* Code
*/
code {
padding: .2rem .5rem;
margin: 0 .2rem;
font-size: 90%;
white-space: nowrap;
background: #F1F1F1;
border: 1px solid #E1E1E1;
border-radius: 4px; }
pre > code {
display: block;
padding: 1rem 1.5rem;
white-space: pre; }
/* Tables
*/
th,
td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid #E1E1E1; }
th:first-child,
td:first-child {
padding-left: 0; }
th:last-child,
td:last-child {
padding-right: 0; }
/* Spacing
*/
button,
.button {
margin-bottom: 1rem; }
input,
textarea,
select,
fieldset {
margin-bottom: 1.5rem; }
pre,
blockquote,
dl,
figure,
table,
p,
ul,
ol,
form {
margin-bottom: 2.5rem; }
/* Utilities
*/
.u-full-width {
width: 100%;
box-sizing: border-box; }
.u-max-full-width {
max-width: 100%;
box-sizing: border-box; }
.u-pull-right {
float: right; }
.u-pull-left {
float: left; }
/* Misc
*/
hr {
margin-top: 3rem;
margin-bottom: 3.5rem;
border-width: 0;
border-top: 1px solid #E1E1E1; }
/* Clearing
*/
/* Self Clearing Goodness */
.container:after,
.row:after,
.u-cf {
content: "";
display: table;
clear: both; }
/* Media Queries
*/
/*
Note: The best way to structure the use of media queries is to create the queries
near the relevant code. For example, if you wanted to change the styles for buttons
on small devices, paste the mobile query code up in the buttons section and style it
there.
*/
/* Larger than mobile */
@media (min-width: 400px) {}
/* Larger than phablet (also point when grid becomes active) */
@media (min-width: 550px) {}
/* Larger than tablet */
@media (min-width: 750px) {}
/* Larger than desktop */
@media (min-width: 1000px) {}
/* Larger than Desktop HD */
@media (min-width: 1200px) {}

BIN
lab_app/static/images/favicon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

22
lab_app/templates/hello.html Executable file
View File

@ -0,0 +1,22 @@
<html>
<head>
<meta charset="utf-8">
<title>Static page</title>
<!-- Mobile Specific Metas
-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- FONT
-->
<link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">
<!-- CSS
-->
<link rel="stylesheet" href="/static/css/normalize.css">
<link rel="stylesheet" href="/static/css/skeleton.css">
<!-- Favicon
-->
<link rel="icon" type="/static/image/png" href="images/favicon.png">
</head>
<body>
<h1>{{ message }}</h1>
</body>
</html>

246
lab_app/templates/lab_env_db.html Executable file
View File

@ -0,0 +1,246 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Basic Page Needs
-->
<meta charset="utf-8">
<title>Temp Conditions by RPi</title>
<meta name="description" content="Temp conditions - RPi">
<meta name="author" content="Clayton Walker">
<!-- Mobile Specific Metas
-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- FONT
-->
<link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">
<!-- CSS
-->
<link rel="stylesheet" href="/static/css/normalize.css">
<link rel="stylesheet" href="/static/css/skeleton.css">
<!-- Favicon
-->
<link rel="icon" type="image/png" href="/static/images/favicon.png">
</head>
<body>
<div class="container">
<div class="row">
<form id="datetime_range" action="/lab_env_db" method="GET">
<!-- <div class="row"> -->
<div class="three columns">
<label for="from">From date</label>
<input class="u-full-width" id="datetimepicker1" type="text" value="{{from_date}}" name="from">
</div>
<!-- </div> -->
<!-- <div class="row"> -->
<div class="three columns">
<label for="to">To date</label>
<input class="u-full-width" id="datetimepicker2" type="text" value="{{to_date}}" name="to">
</div>
<!-- </div> -->
<!-- <div class="row"> -->
<div class="two columns">
<input type="hidden" class="timezone" name="timezone" />
<input class="button-primary" type="submit" value="Submit" style="position:relative; top: 28px" id="submit_button" />
</div>
<!-- </div> -->
</form>
</div>
<div class="row">
<div class="eleven columns">
<div class="one column">
<div class="one column">
<a href="" id="plotly" style="position:relative;top:15px">Plotly</a>
</div>
<a href="/lab_temp" style="position:relative;top:15px">Current</a>
</div>
<form id="range_select" action = "/lab_env_db" method="GET">
<input type="hidden" class="timezone" name="timezone" />
<div class="one column">
<input type="radio" name="range_h" value="3" id="radio_3" /><label for="radio_3">3hrs</label>
</div>
<div class="one column">
<input type="radio" name="range_h" value="6" id="radio_6" /><label for="radio_6">6hrs</label>
</div>
<div class="one column">
<input type="radio" name="range_h" value="12" id="radio_12" /><label for="radio_12">12hrs</label>
</div>
<div class="one column">
<input type="radio" name="range_h" value="24" id="radio_24" /><label for="radio_24">24hrs</label>
</div>
</form>
</div>
</div>
<div class="row">
<a href="" id="plotly_url" target="_blank"></a><span id="plotly_wait"></span>
</div>
<div class="row">
<div class="one-third column" style="margin-top: 5%">
<strong>Showing all records</strong>
<h2>Temperatures</h2>
<table class="u-full-width">
<thead style="display:block;">
<tr>
<th>Date</th>
<th>                              &deg;F</th>
</tr>
</thead>
<tbody style="height:450px; overflow:scroll; display:block;">
{% for row in temp %}
<tr>
<td>{{row[0]}}</td>
<td>{{'%0.2f'|format(row[1])}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<h2>Humidities</h2>
<table class="u-full-width">
<thead style="display:block;">
<tr>
<th>Date</th>
<th>                              %</th>
</tr>
</thead>
<tbody style="height:450px; overflow:scroll; display:block;">
{% for row in hum %}
<tr>
<td>{{row[0]}}</td>
<td>{{'%0.2f'|format(row[1])}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div class="two-thirds column" style="margin-top: 5%">
<div class="row">
<div class="row">
<div class="three columns">
<div id="chart_temps"></div>
<div id="chart_humid"></div>
</div>
</div>
</div>
</div>
</div>
</body>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="//code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
<link rel="stylesheet" type="text/css" href="/static/css/jquery.datetimepicker.css"/ >
<script src="/static/javascript/jquery.datetimepicker.full.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.4/jstz.min.js" ></script>
<script>
jQuery( "#datetime_range" ).submit(function( event ) {
timezone = jstz.determine();
jQuery(".timezone").val(timezone.name());
});
jQuery('#datetimepicker1').datetimepicker(
{
format:'Y-m-d H:i',
defaultDate:'{{from_date}}'
});
jQuery('#datetimepicker2').datetimepicker({
format:'Y-m-d H:i',
defaultDate:'{{to_date}}'
});
jQuery("#range_select input[type=radio]").click(function(){
timezone = jstz.determine();
jQuery(".timezone").val(timezone.name());
jQuery("#range_select").submit();
});
jQuery("#plotly").click(function(){
jQuery("#plotly_wait").text("Sending data...");
jQuery("#plotly_url").text("");
{% autoescape false %}
jQuery.get("/to_plotly?{{query_string}}")
{% endautoescape %}
.done(function( data ) {
jQuery("#plotly_url").attr("href",data);
jQuery("#plotly_url").text("Click to see your plot");
jQuery("#plotly_wait").text("");
});
return false; //This is so that the click on the link does not cause the page to refresh
});
</script>
<script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1','packages':['corechart']}]}"></script>
<script>
google.load('visualization', '1', {packages: ['corechart']});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('datetime', 'Time');
data.addColumn('number', 'Temperature');
data.addRows([
{% for row in temp %}
[new Date({{row[0][0:4]}},{{row[0][5:7]}}-1,{{row[0][8:10]}},{{row[0][11:13]}},{{row[0][14:16]}}),{{'%0.2f'|format(row[1])}}],
{% endfor %}
]);
var options = {
width: 600,
height: 563,
hAxis: {
title: "Date",
gridlines: { count: {{temp_items}}, color: '#CCC' },
format: 'dd-MMM-yyyy HH:mm' },
vAxis: {
title: 'Degrees'
},
title: 'Temperature',
curveType: 'function' //Makes line curved
};
var chart = new google.visualization.LineChart(document.getElementById('chart_temps'));
chart.draw(data, options);
}
</script>
<script>
google.load('visualization', '1', {packages: ['corechart']});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('datetime', 'Time');
data.addColumn('number', 'Humidity');
data.addRows([
{% for row in hum %}
[new Date({{row[0][0:4]}},{{row[0][5:7]}}-1,{{row[0][8:10]}},{{row[0][11:13]}},{{row[0][14:16]}}),{{'%0.2f'|format(row[1])}}],
{% endfor %}
]);
var options = {
width: 600,
height: 563,
hAxis: {
title: "Date",
gridlines: { count: {{hum_items}}, color: '#CCC' },
format: 'dd-MMM-yyyy HH:mm' },
vAxis: {
title: 'Percent'
},
title: 'Humidity',
curveType: 'function' //Makes line curved
};
var chart = new google.visualization.LineChart(document.getElementById('chart_humid'));
chart.draw(data, options);
}
</script>
</html>

55
lab_app/templates/lab_temp.html Executable file
View File

@ -0,0 +1,55 @@
<html>
<meta charset="utf-8">
<title>Temp Conditions by RPi</title>
<meta http-equiv="refresh" content="10">
<meta name="description" content="Temp conditions - RPi">
<meta name="author" content="Clayton Walker">
<!-- Mobile Specific Metas
-->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- FONT
-->
<link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">
<!-- CSS
-->
<link rel="stylesheet" href="/static/css/normalize.css">
<link rel="stylesheet" href="/static/css/skeleton.css">
<!-- Favicon
-->
<link rel="icon" type="image/png" href="/static/images/favicon.png">
</head>
<body>
<div class="container">
<div class="row">
<div class="two-third column" style="margin-top: 5%">
<h2>Real time conditions</h2>
<h1>Temperature: {{"{0:0.1f}".format(temp) }}°F</h1>
<h1>Humidity: {{"{0:0.1f}".format(hum)}}%</h1>
<p>This page refreshes every 10 seconds</p>
</div>
</div>
<div class="row">
<div class="eleven columns">
<form id="range_select" action = "/lab_env_db" method="GET">
<input type="hidden" class="timezone" name="timezone" />
<div class="one column">
<a href="/lab_env_db" style="position:relative;top:15px">Historic</a>
</div>
</form>
</div>
</div>
</body>
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstimezonedetect/1.0.4/jstz.min.js" ></script>
<script>
jQuery( document ).ready(function() {
timezone = jstz.determine();
jQuery("#timezone").text(timezone.name());
});
jQuery("#range_select input[type=radio]").click(function(){
timezone = jstz.determine();
jQuery(".timezone").val(timezone.name());
jQuery("#range_select").submit();
});
</script>
</html>

View File

@ -0,0 +1,8 @@
<html>
<head>
</head>
<div class='test_container'>
<h1>Sorry, can't access the sensor!</h1>
</div>
</html>