Refactored we pages

Former-commit-id: a64def61acdcbf63bf4792b9084a48dded9eb41a
This commit is contained in:
Ziver Koc 2015-12-10 21:30:37 +01:00
parent c669cca664
commit 84fd5adb5e
12 changed files with 421 additions and 424 deletions

View file

@ -5,6 +5,7 @@ import se.koc.hal.deamon.DataAggregatorDaemon;
import se.koc.hal.deamon.DataSynchronizationClient;
import se.koc.hal.deamon.DataSynchronizationDaemon;
import se.koc.hal.deamon.HalDaemon;
import se.koc.hal.page.HalHttpPage;
import se.koc.hal.page.PCConfigureHttpPage;
import se.koc.hal.page.PCHeatMapHttpPage;
import se.koc.hal.page.PCOverviewHttpPage;
@ -24,6 +25,7 @@ public class PowerChallenge {
private static HalDaemon[] daemons;
private static HalHttpPage[] pages;
public static void main(String[] args) throws Exception {
// init logging
@ -47,12 +49,18 @@ public class PowerChallenge {
for(HalDaemon daemon : daemons){
daemon.initiate(daemonTimer);
}
pages = new HalHttpPage[]{
new PCOverviewHttpPage(),
new PCHeatMapHttpPage(),
new PCConfigureHttpPage()
};
HttpServer http = new HttpServer(HalContext.getIntegerProperty("http_port"));
http.setDefaultPage(new HttpFilePage(FileUtil.find("web-resource/")));
http.setPage("/", new PCOverviewHttpPage());
http.setPage("/configure", new PCConfigureHttpPage());
http.setPage("/heatmap", new PCHeatMapHttpPage());
http.setPage("/", pages[0]);
for(HalHttpPage page : pages){
http.setPage(page.getURL(), page);
}
http.start();
}
}

View file

@ -0,0 +1,70 @@
package se.koc.hal.page;
import se.koc.hal.HalContext;
import se.koc.hal.struct.Sensor;
import se.koc.hal.struct.User;
import zutil.db.DBConnection;
import zutil.io.file.FileUtil;
import zutil.net.http.HttpHeaderParser;
import zutil.net.http.HttpPage;
import zutil.net.http.HttpPrintStream;
import zutil.parser.Templator;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Map;
/**
* Created by Ziver on 2015-12-10.
*/
public abstract class HalHttpPage implements HttpPage{
private static ArrayList<HalHttpPage> pages = new ArrayList<>();
private final String name;
private final String id;
public HalHttpPage(String name, String id){
this.name = name;
this.id = id;
pages.add(this);
}
public String getName(){
return name;
}
public String getId(){
return id;
}
public String getURL(){
return "/" + this.id;
}
@Override
public void respond(HttpPrintStream out, HttpHeaderParser client_info,
Map<String, Object> session, Map<String, String> cookie,
Map<String, String> request) throws IOException {
try {
DBConnection db = HalContext.getDB();
Templator tmpl = new Templator(FileUtil.find("web-resource/index.tmpl"));
tmpl.set("user", User.getLocalUser(db));
tmpl.set("navigation", pages);
tmpl.set("content", httpRespond(session, cookie, request));
out.print(tmpl.compile());
} catch (Exception e) {
throw new IOException(e);
}
}
public abstract Templator httpRespond(
Map<String, Object> session,
Map<String, String> cookie,
Map<String, String> request)
throws Exception;
}

View file

@ -14,26 +14,30 @@ import zutil.net.http.HttpPage;
import zutil.net.http.HttpPrintStream;
import zutil.parser.Templator;
public class PCConfigureHttpPage implements HttpPage {
public class PCConfigureHttpPage extends HalHttpPage {
public PCConfigureHttpPage() {
super("Configuration", "config");
}
@Override
public Templator httpRespond(
Map<String, Object> session,
Map<String, String> cookie,
Map<String, String> request)
throws Exception{
@Override
public void respond(HttpPrintStream out, HttpHeaderParser client_info,
Map<String, Object> session, Map<String, String> cookie,
Map<String, String> request) throws IOException {
try {
DBConnection db = HalContext.getDB();
Templator tmpl = new Templator(FileUtil.find("web-resource/configure.html"));
Templator tmpl = new Templator(FileUtil.find("web-resource/configure.tmpl"));
tmpl.set("user", User.getLocalUser(db));
tmpl.set("localSensor", Sensor.getLocalSensors(db));
tmpl.set("extUsers", User.getExternalUsers(db));
tmpl.set("extSensor", Sensor.getExternalSensors(db));
out.print(tmpl.compile());
} catch (SQLException e) {
throw new IOException(e);
}
return tmpl;
}
}

View file

@ -9,15 +9,21 @@ import zutil.net.http.HttpPage;
import zutil.net.http.HttpPrintStream;
import zutil.parser.Templator;
public class PCHeatMapHttpPage implements HttpPage {
public class PCHeatMapHttpPage extends HalHttpPage {
public PCHeatMapHttpPage() {
super("Heatmap", "map");
}
@Override
public void respond(HttpPrintStream out, HttpHeaderParser client_info,
Map<String, Object> session, Map<String, String> cookie,
Map<String, String> request) throws IOException {
public Templator httpRespond(
Map<String, Object> session,
Map<String, String> cookie,
Map<String, String> request)
throws Exception{
Templator tmpl = new Templator(FileUtil.find("web-resource/heatmap.html"));
out.print(tmpl.compile());
Templator tmpl = new Templator(FileUtil.find("web-resource/heatmap.tmpl"));
return tmpl;
}
}

View file

@ -18,75 +18,80 @@ import zutil.net.http.HttpPage;
import zutil.net.http.HttpPrintStream;
import zutil.parser.Templator;
public class PCOverviewHttpPage implements HttpPage {
public class PCOverviewHttpPage extends HalHttpPage {
public PCOverviewHttpPage() {
super("Overview", "overview");
}
@Override
public Templator httpRespond(
Map<String, Object> session,
Map<String, String> cookie,
Map<String, String> request)
throws Exception{
DBConnection db = HalContext.getDB();
PreparedStatement stmt = db.getPreparedStatement(
"SELECT user.username as username,"
+ " sensor_data_aggr.timestamp_start as timestamp_start,"
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
+ " sensor_data_aggr.data as data,"
+ " sensor_data_aggr.confidence as confidence,"
+ DataAggregatorDaemon.FIVE_MINUTES_IN_MS + " as period_length"
+ " FROM sensor_data_aggr, user, sensor"
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
+ " AND user.id = sensor.user_id"
+ " AND timestamp_end-timestamp_start == ?"
+ " AND timestamp_start > ?"
+ " ORDER BY timestamp_start ASC");
stmt.setLong(1, DataAggregatorDaemon.FIVE_MINUTES_IN_MS-1);
stmt.setLong(2, (System.currentTimeMillis() - DataAggregatorDaemon.DAY_IN_MS) );
ArrayList<PowerData> minDataList = DBConnection.exec(stmt , new SQLPowerDataBuilder());
stmt = db.getPreparedStatement(
"SELECT user.username as username,"
+ " sensor_data_aggr.timestamp_start as timestamp_start,"
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
+ " sensor_data_aggr.data as data,"
+ " sensor_data_aggr.confidence as confidence,"
+ DataAggregatorDaemon.HOUR_IN_MS + " as period_length"
+ " FROM sensor_data_aggr, user, sensor"
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
+ " AND user.id = sensor.user_id"
+ " AND timestamp_end-timestamp_start == ?"
+ " AND timestamp_start > ?"
+ " ORDER BY timestamp_start ASC");
stmt.setLong(1, DataAggregatorDaemon.HOUR_IN_MS-1);
stmt.setLong(2, (System.currentTimeMillis() - 3*DataAggregatorDaemon.DAY_IN_MS) );
ArrayList<PowerData> hourDataList = DBConnection.exec(stmt, new SQLPowerDataBuilder());
stmt = db.getPreparedStatement(
"SELECT user.username as username,"
+ " sensor_data_aggr.timestamp_start as timestamp_start,"
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
+ " sensor_data_aggr.data as data,"
+ " sensor_data_aggr.confidence as confidence,"
+ DataAggregatorDaemon.DAY_IN_MS + " as period_length"
+ " FROM sensor_data_aggr, user, sensor"
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
+ " AND user.id = sensor.user_id"
+ " AND timestamp_end-timestamp_start == ?"
+ " ORDER BY timestamp_start ASC");
stmt.setLong(1, DataAggregatorDaemon.DAY_IN_MS-1);
ArrayList<PowerData> dayDataList = DBConnection.exec(stmt, new SQLPowerDataBuilder());
Templator tmpl = new Templator(FileUtil.find("web-resource/overview.tmpl"));
tmpl.set("minData", minDataList);
tmpl.set("hourData", hourDataList);
tmpl.set("dayData", dayDataList);
tmpl.set("username", new String[]{"Ziver", "Daniel"});
return tmpl;
@Override
public void respond(HttpPrintStream out, HttpHeaderParser client_info, Map<String, Object> session, Map<String, String> cookie, Map<String, String> request) throws IOException {
try {
DBConnection db = HalContext.getDB();
PreparedStatement stmt = db.getPreparedStatement(
"SELECT user.username as username,"
+ " sensor_data_aggr.timestamp_start as timestamp_start,"
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
+ " sensor_data_aggr.data as data,"
+ " sensor_data_aggr.confidence as confidence,"
+ DataAggregatorDaemon.FIVE_MINUTES_IN_MS + " as period_length"
+ " FROM sensor_data_aggr, user, sensor"
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
+ " AND user.id = sensor.user_id"
+ " AND timestamp_end-timestamp_start == ?"
+ " AND timestamp_start > ?"
+ " ORDER BY timestamp_start ASC");
stmt.setLong(1, DataAggregatorDaemon.FIVE_MINUTES_IN_MS-1);
stmt.setLong(2, (System.currentTimeMillis() - DataAggregatorDaemon.DAY_IN_MS) );
ArrayList<PowerData> minDataList = DBConnection.exec(stmt , new SQLPowerDataBuilder());
stmt = db.getPreparedStatement(
"SELECT user.username as username,"
+ " sensor_data_aggr.timestamp_start as timestamp_start,"
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
+ " sensor_data_aggr.data as data,"
+ " sensor_data_aggr.confidence as confidence,"
+ DataAggregatorDaemon.HOUR_IN_MS + " as period_length"
+ " FROM sensor_data_aggr, user, sensor"
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
+ " AND user.id = sensor.user_id"
+ " AND timestamp_end-timestamp_start == ?"
+ " AND timestamp_start > ?"
+ " ORDER BY timestamp_start ASC");
stmt.setLong(1, DataAggregatorDaemon.HOUR_IN_MS-1);
stmt.setLong(2, (System.currentTimeMillis() - 3*DataAggregatorDaemon.DAY_IN_MS) );
ArrayList<PowerData> hourDataList = DBConnection.exec(stmt, new SQLPowerDataBuilder());
stmt = db.getPreparedStatement(
"SELECT user.username as username,"
+ " sensor_data_aggr.timestamp_start as timestamp_start,"
+ " sensor_data_aggr.timestamp_end as timestamp_end,"
+ " sensor_data_aggr.data as data,"
+ " sensor_data_aggr.confidence as confidence,"
+ DataAggregatorDaemon.DAY_IN_MS + " as period_length"
+ " FROM sensor_data_aggr, user, sensor"
+ " WHERE sensor.id = sensor_data_aggr.sensor_id"
+ " AND user.id = sensor.user_id"
+ " AND timestamp_end-timestamp_start == ?"
+ " ORDER BY timestamp_start ASC");
stmt.setLong(1, DataAggregatorDaemon.DAY_IN_MS-1);
ArrayList<PowerData> dayDataList = DBConnection.exec(stmt, new SQLPowerDataBuilder());
Templator tmpl = new Templator(FileUtil.find("web-resource/index.html"));
tmpl.set("minData", minDataList);
tmpl.set("hourData", hourDataList);
tmpl.set("dayData", dayDataList);
tmpl.set("username", new String[]{"Ziver", "Daniel"});
out.print(tmpl.compile());
} catch (SQLException e) {
throw new IOException(e);
}
}
public static class PowerData{

View file

@ -1,136 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Power;Challenge</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/main.css" rel="stylesheet">
<script src="js/jquery-1.11.3.min.js"></script>
<script src="js/bootstrap.min.js"></script>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">Power;Challenge</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Ziver</a></li>
</ul>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li><a href="/">Overview</a></li>
<li><a href="heatmap">Heat Map</a></li>
<li><a href="#">Statistics</a></li>
<li class="active"><a href="configure">Configuration <span class="sr-only">(current)</span></a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Configuration</h1>
<div class="panel panel-default">
<div class="panel-heading">Profile Information</div>
<div class="panel-body">
<form>
<hidden id="id" value="{{user.getId()}}">
<div class="form-group col-md-4">
<label for="username">Username</label>
<input type="text" class="form-control" id="username" value="{{user.username}}">
</div>
<div class="form-group col-md-8">
<label for="address">Address</label>
<input type="text" class="form-control" id="username" value="{{user.address}}">
</div>
<div class="col-md-12">
<button type="submit" class="btn btn-default">Save</button>
</div>
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">Local Sensors</div>
<div class="panel-body">
This is a local list of sensors connected to this node.
</div>
<table class="table table-hover">
<tr>
<th>Name</th>
<th>Type</th>
<th>Configuration</th>
</tr>
{{#localSensor}}
<tr>
<td>{{.name}}</td>
<td>{{.type}}</td>
<td>{{.config}}</td>
</tr>
{{/localSensor}}
</table>
</div>
<div class="panel panel-default">
<div class="panel-heading">External Users</div>
<div class="panel-body">
Add or remove users that you want to synchronized data with.
</div>
<table class="table table-hover">
<tr>
<th>Username</th>
<th>Address</th>
<th>Hostname</th>
<th>Port</th>
</tr>
{{#extUsers}}
<tr>
<td>{{.username}}</td>
<td>{{.address}}</td>
<td>{{.hostname}}</td>
<td>{{.port}}</td>
</tr>
{{/extUsers}}
</table>
</div>
<div class="panel panel-default">
<div class="panel-heading">External Sensors</div>
<div class="panel-body">
This is a read only list of synchronized sensors from external users.
</div>
<table class="table table-hover">
<tr>
<th>Name</th>
<th>Type</th>
<th>Configuration</th>
</tr>
{{#extSensor}}
<tr>
<td>{{.name}}</td>
<td>{{.type}}</td>
<td>{{.config}}</td>
</tr>
{{/extSensor}}
</table>
</div>
</div>
</div>
</div>
</body>
</html>

86
web-resource/configure.tmpl Executable file
View file

@ -0,0 +1,86 @@
<h1 class="page-header">Configuration</h1>
<div class="panel panel-default">
<div class="panel-heading">Profile Information</div>
<div class="panel-body">
<form>
<hidden id="id" value="{{user.getId()}}">
<div class="form-group col-md-4">
<label for="username">Username</label>
<input type="text" class="form-control" id="username" value="{{user.username}}">
</div>
<div class="form-group col-md-8">
<label for="address">Address</label>
<input type="text" class="form-control" id="address" value="{{user.address}}">
</div>
<div class="col-md-12">
<button type="submit" class="btn btn-default">Save</button>
</div>
</form>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">Local Sensors</div>
<div class="panel-body">
This is a local list of sensors connected to this node.
</div>
<table class="table table-hover">
<tr>
<th>Name</th>
<th>Type</th>
<th>Configuration</th>
</tr>
{{#localSensor}}
<tr>
<td>{{.name}}</td>
<td>{{.type}}</td>
<td>{{.config}}</td>
</tr>
{{/localSensor}}
</table>
</div>
<div class="panel panel-default">
<div class="panel-heading">External Users</div>
<div class="panel-body">
Add or remove users that you want to synchronized data with.
</div>
<table class="table table-hover">
<tr>
<th>Username</th>
<th>Address</th>
<th>Hostname</th>
<th>Port</th>
</tr>
{{#extUsers}}
<tr>
<td>{{.username}}</td>
<td>{{.address}}</td>
<td>{{.hostname}}</td>
<td>{{.port}}</td>
</tr>
{{/extUsers}}
</table>
</div>
<div class="panel panel-default">
<div class="panel-heading">External Sensors</div>
<div class="panel-body">
This is a read only list of synchronized sensors from external users.
</div>
<table class="table table-hover">
<tr>
<th>Name</th>
<th>Type</th>
<th>Configuration</th>
</tr>
{{#extSensor}}
<tr>
<td>{{.name}}</td>
<td>{{.type}}</td>
<td>{{.config}}</td>
</tr>
{{/extSensor}}
</table>
</div>

View file

@ -1,88 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Power;Challenge</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/main.css" rel="stylesheet">
<script src="js/jquery-1.11.3.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="http://maps.googleapis.com/maps/api/js"></script>
<script>
function initialize() {
var mapProp = {
center:new google.maps.LatLng(59.329323,18.068581),
zoom:12,
mapTypeId:google.maps.MapTypeId.ROADMAP
};
var map=new google.maps.Map(document.getElementById("googleMap"),mapProp);
var home = new google.maps.Circle({
center: {lat: 59.365954, lng: 17.975351},
radius:2000,
strokeColor:"#00FF00",
strokeOpacity:0.8,
strokeWeight:2,
fillColor:"#00FF00",
fillOpacity:0.4,
map: map
});
var external = new google.maps.Circle({
center: {lat: 59.275638, lng: 18.024362},
radius:2000,
strokeColor:"#FF0000",
strokeOpacity:0.8,
strokeWeight:2,
fillColor:"#FF0000",
fillOpacity:0.4,
map: map
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">Power;Challenge</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Ziver</a></li>
</ul>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li><a href="/">Overview</a></li>
<li class="active"><a href="heatmap">Heat Map <span class="sr-only">(current)</span></a></li>
<li><a href="#">Statistics</a></li>
<li><a href="configure">Configuration</a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Heat Map</h1>
<div id="googleMap" style="width: 95%;height: 800px;"></div>
</div>
</div>
</div>
</body>
</html>

39
web-resource/heatmap.tmpl Executable file
View file

@ -0,0 +1,39 @@
<h1 class="page-header">Heat Map</h1>
<div id="googleMap" style="width: 95%;height: 800px;"></div>
<script src="http://maps.googleapis.com/maps/api/js"></script>
<script>
function initialize() {
var mapProp = {
center:new google.maps.LatLng(59.329323,18.068581),
zoom:12,
mapTypeId:google.maps.MapTypeId.ROADMAP
};
var map=new google.maps.Map(document.getElementById("googleMap"),mapProp);
var home = new google.maps.Circle({
center: {lat: 59.365954, lng: 17.975351},
radius:2000,
strokeColor:"#00FF00",
strokeOpacity:0.8,
strokeWeight:2,
fillColor:"#00FF00",
fillOpacity:0.4,
map: map
});
var external = new google.maps.Circle({
center: {lat: 59.275638, lng: 18.024362},
radius:2000,
strokeColor:"#FF0000",
strokeOpacity:0.8,
strokeWeight:2,
fillColor:"#FF0000",
fillOpacity:0.4,
map: map
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>

View file

@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Power;Challenge</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/main.css" rel="stylesheet">
<script src="http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="js/jquery-1.11.3.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/morris.min.js"></script>
<script>
$(function(){
chartData("min-power-chart",
[
{ y: (Date.now()-24*60*60*1000) },
{{#minData}}
{ y: {{.timestamp}}, {{.username}}: {{.data}} },
{{/minData}}
{ y: Date.now() }
]
);
chartData("hour-power-chart",
[
{ y: (Date.now()-3*24*60*60*1000) },
{{#hourData}}
{ y: {{.timestamp}}, {{.username}}: {{.data}} },
{{/hourData}}
{ y: (Date.now()-24*60*60*1000) }
]
);
chartData("day-power-chart",
[{{#dayData}}
{ y: {{.timestamp}}, {{.username}}: {{.data}} },
{{/dayData}}
{ y: (Date.now()-3*24*60*60*1000) }
]
);
});
var userArray = [ {{#username}} '{{.}}', {{/username}} ];
function chartData(elementId, data){
Morris.Line({
element: elementId,
data: data,
xkey: 'y',
ykeys: userArray,
labels: userArray,
continuousLine: false,
pointSize: 1,
postUnits: 'kWh',
resize: true
});
}
</script>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">Power;Challenge</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Ziver</a></li>
</ul>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li class="active"><a href="/">Overview <span class="sr-only">(current)</span></a></li>
<li><a href="heatmap">Heat Map</a></li>
<li><a href="#">Statistics</a></li>
<li><a href="configure">Configuration</a></li>
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Overview</h1>
<div class="row placeholders">
<H1>Last 24 hours (kWh/5min)</H1>
<div id="min-power-chart" style="height:450px;"></div>
</div>
<div class="row placeholders">
<H1>Previous two days (kWh/h)</H1>
<div id="hour-power-chart" style="height:450px;"></div>
</div>
<div class="row placeholders">
<H1>Long term (kWh/day)</H1>
<div id="day-power-chart" style="height:450px;"></div>
</div>
</div>
</div>
</div>
</body>
</html>

51
web-resource/index.tmpl Executable file
View file

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Power;Challenge</title>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/main.css" rel="stylesheet">
<script src="js/jquery-1.11.3.min.js"></script>
<script src="js/bootstrap.min.js"></script>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">Power;Challenge</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="#">{{user.username}}</a></li>
</ul>
</div>
</div>
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<!-- <li class="active"><a href="/">Overview</a></li> -->
{{#navigation}}
<li><a href="{{.getURL()}}">{{.getName()}}</a></li>
{{/navigation}}
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
{{content}}
</div>
</div>
</div>
</body>
</html>

63
web-resource/overview.tmpl Executable file
View file

@ -0,0 +1,63 @@
<h1 class="page-header">Overview</h1>
<div class="row placeholders">
<H1>Last 24 hours (kWh/5min)</H1>
<div id="min-power-chart" style="height:450px;"></div>
</div>
<div class="row placeholders">
<H1>Previous two days (kWh/h)</H1>
<div id="hour-power-chart" style="height:450px;"></div>
</div>
<div class="row placeholders">
<H1>Long term (kWh/day)</H1>
<div id="day-power-chart" style="height:450px;"></div>
</div>
<script src="js/raphael-min.js"></script>
<script src="js/morris.min.js"></script>
<script>
$(function(){
chartData("min-power-chart",
[
{ y: (Date.now()-24*60*60*1000) },
{{#minData}}
{ y: {{.timestamp}}, {{.username}}: {{.data}} },
{{/minData}}
{ y: Date.now() }
]
);
chartData("hour-power-chart",
[
{ y: (Date.now()-3*24*60*60*1000) },
{{#hourData}}
{ y: {{.timestamp}}, {{.username}}: {{.data}} },
{{/hourData}}
{ y: (Date.now()-24*60*60*1000) }
]
);
chartData("day-power-chart",
[{{#dayData}}
{ y: {{.timestamp}}, {{.username}}: {{.data}} },
{{/dayData}}
{ y: (Date.now()-3*24*60*60*1000) }
]
);
});
var userArray = [ {{#username}} '{{.}}', {{/username}} ];
function chartData(elementId, data){
Morris.Line({
element: elementId,
data: data,
xkey: 'y',
ykeys: userArray,
labels: userArray,
continuousLine: false,
pointSize: 1,
postUnits: 'kWh',
resize: true
});
}
</script>