This commit is contained in:
Martin Donnelly 2016-04-20 14:48:48 +01:00
parent d93ebb4466
commit 6e1993c220
100 changed files with 21789 additions and 2041 deletions

32
.editorconfig Normal file
View File

@ -0,0 +1,32 @@
; http://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[*.txt]
insert_final_newline = false
trim_trailing_whitespace = false
[*.py]
indent_size = 4
[*.m]
indent_size = 4
[Makefile]
indent_style = tab
indent_size = 8
[*.{js,json}]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false

155
.gitignore vendored
View File

@ -1,3 +1,124 @@
# Created by .ignore support plugin (hsz.mobi)
### Archives template
# It's better to unpack these files and commit the raw source because
# git has its own built in compression methods.
*.7z
*.jar
*.rar
*.zip
*.gz
*.bzip
*.bz2
*.xz
*.lzma
*.cab
#packing-only formats
*.iso
*.tar
#package management formats
*.dmg
*.xpi
*.gem
*.egg
*.deb
*.rpm
*.msi
*.msm
*.msp
### Windows template
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
### OSX template
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
*.iml
## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:
# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries
# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml
# Gradle:
# .idea/gradle.xml
# .idea/libraries
# Mongo Explorer plugin:
# .idea/mongoSettings.xml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
### Node template
# Logs
logs
*.log
@ -24,12 +145,36 @@ coverage
build/Release
# Dependency directory
# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
node_modules
bower_components
# Optional npm cache directory
.npm
### VisualStudioCode template
.settings
# Optional REPL history
.node_repl_history
### Xcode template
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
.idea
## Build generated
build/
DerivedData
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
## Other
*.xccheckout
*.moved-aside
*.xcuserstate
dist

46
.jscsrc Normal file
View File

@ -0,0 +1,46 @@
{
"disallowKeywords": ["with"],
"disallowKeywordsOnNewLine": ["else"],
"disallowMixedSpacesAndTabs": true,
"disallowMultipleVarDecl": "exceptUndefined",
"disallowNewlineBeforeBlockStatements": true,
"disallowQuotedKeysInObjects": true,
"disallowSpaceAfterObjectKeys": true,
"disallowSpaceAfterPrefixUnaryOperators": true,
"disallowSpacesInFunction": {
"beforeOpeningRoundBrace": true
},
"disallowSpacesInsideParentheses": true,
"disallowTrailingWhitespace": true,
"maximumLineLength": 160,
"requireCamelCaseOrUpperCaseIdentifiers": false,
"requireCapitalizedComments": true,
"requireCapitalizedConstructors": true,
"requireCurlyBraces": true,
"requireSpaceAfterKeywords": [
"if",
"else",
"for",
"while",
"do",
"switch",
"case",
"return",
"try",
"catch",
"typeof"
],
"requireSpaceAfterLineComment": true,
"requireSpaceAfterBinaryOperators": true,
"requireSpaceBeforeBinaryOperators": true,
"requireSpaceBeforeBlockStatements": true,
"requireSpaceBeforeObjectValues": true,
"requireSpacesInFunction": {
"beforeOpeningCurlyBrace": true
},
"requireTrailingComma": false,
"requireEarlyReturn": false,
"validateIndentation": 2,
"validateLineBreaks": "LF",
"validateQuoteMarks": "'"
}

33
.jshintrc Normal file
View File

@ -0,0 +1,33 @@
{
"predef": [
"Promise",
"$"
],
"node":true,
"browser": true,
"boss": true,
"curly": true,
"debug": false,
"devel": true,
"eqeqeq": true,
"evil": true,
"forin": false,
"immed": false,
"laxbreak": false,
"newcap": true,
"noarg": true,
"noempty": false,
"nonew": false,
"nomen": false,
"onevar": false,
"plusplus": false,
"regexp": false,
"undef": true,
"sub": true,
"strict": false,
"white": false,
"eqnull": true,
"esnext": true,
"unused": true,
"supernew":true
}

180
app.js
View File

@ -2,19 +2,33 @@
* Created by Martin on 08/02/2016.
*/
"use strict";
var express = require('express'), path = require('path'), http = require('http'), ejs = require('ejs'), morgan = require('morgan'), cookieparser = require('cookie-parser'), session = require('express-session');
var methodoverride = require('method-override'), bodyparser = require('body-parser'), errorhandler = require('errorhandler');
var express = require('express');
var path = require('path');
var http = require('http');
var ejs = require('ejs');
var morgan = require('morgan');
var cookieparser = require('cookie-parser');
var session = require('express-session');
var methodoverride = require('method-override');
var bodyparser = require('body-parser');
var errorhandler = require('errorhandler');
var mqttConnect = require('./lib/mqtt/mqttConnect');
var log4js = require('log4js');
var logger = log4js.getLogger();
var WebSocketServer = require('websocket').server;
var EventEmitter = require('events');
var lighting_v1 = require('./routes/lighting_v1'), heating_v1 = require('./routes/heating_v1'), projector_v1 = require('./routes/projector_v1');
var EventEmitter = require('events');
var busEmitter = new EventEmitter();
var calendar = require('./lib/office/officeController.js');
var cal = new calendar.officeController(busEmitter);
var lighting_v1 = require('./routes/lighting_v1');
var heating_v1 = require('./routes/heating_v1');
var projector_v1 = require('./routes/projector_v1');
mqttConnect.setEmitter(busEmitter);
mqttConnect.doConnection();
@ -26,8 +40,7 @@ app.set('view engine', 'ejs');
app.use(morgan('combined'));
app.use(cookieparser('your secret here'));
app.use(session({
secret: '1234567890QWERTY', resave: false,
saveUninitialized: false
secret: '1234567890QWERTY', resave: false, saveUninitialized: false
}));
/* 'default', 'short', 'tiny', 'dev' */
app.use(methodoverride());
@ -37,95 +50,124 @@ app.use(bodyparser.urlencoded({extended: false}));
// parse application/json
app.use(bodyparser.json());
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
// app.use(app.router);
app.use(express.static(path.join(__dirname, 'app')));
app.use(express.static(path.join(__dirname, 'dist')));
app.use(errorhandler({dumpExceptions: true, showStack: true}));
lighting_v1.use(mqttConnect);
heating_v1.use(mqttConnect);
projector_v1.use(mqttConnect);
busEmitter.on('clientConnected', (socketSet) => {
console.log(socketSet.getClientStatus());
heating_v1.setsocket(socketSet).subscribe();
lighting_v1.setsocket(socketSet).subscribe();
projector_v1.setsocket(socketSet).subscribe();
// Calendar handler
cal.startController(busEmitter);
app.get("/stop", function (request, response) {
cal.stopController();
});
app.get("/start", function (request, response) {
cal.startController();
});
app.get("/api/calendar", function (req, res) {
var calJson = cal.returnCalendar();
console.log(calJson);
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(calJson));
});
app.post('/api/calendar/extend', function(req, res) {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({}));
});
// Events and sockets
busEmitter.on('clientConnected', (socketSet) => {
console.log(socketSet.getClientStatus());
heating_v1.setsocket(socketSet).subscribe();
lighting_v1.setsocket(socketSet).subscribe();
projector_v1.setsocket(socketSet).subscribe();
});
busEmitter.on('clientStatusUpdated', (v) => {
console.log(v);
console.log(v);
});
logger.info('Configuring WebSocket Listener...');
var server = http.createServer(function (request, response) {
console.log((new Date()) + ' Received request for ' + request.url);
response.writeHead(404);
response.end();
var server = http.createServer(function(request, response) {
console.log((new Date()) + ' Received request for ' + request.url);
response.writeHead(404);
response.end();
});
server.listen(8080, function () {
console.log((new Date()) + ' Server is listening on port 8080');
server.listen(8080, function() {
console.log((new Date()) + ' Server is listening on port 8080');
});
var wsServer = new WebSocketServer({
httpServer: server,
// You should not use autoAcceptConnections for production
// applications, as it defeats all standard cross-origin protection
// facilities built into the protocol and the browser. You should
// *always* verify the connection's origin and decide whether or not
// to accept it.
autoAcceptConnections: false
httpServer: server, // You should not use autoAcceptConnections for production
// applications, as it defeats all standard cross-origin protection
// facilities built into the protocol and the browser. You should
// *always* verify the connection's origin and decide whether or not
// to accept it.
autoAcceptConnections: false
});
function originIsAllowed(origin) {
// put logic here to detect whether the specified origin is allowed.
return true;
// put logic here to detect whether the specified origin is allowed.
return true;
}
wsServer.on('request', function (request) {
wsServer.on('request', function(request) {
if (!originIsAllowed(request.origin)) {
// Make sure we only accept requests from an allowed origin
request.reject();
console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
return;
if (!originIsAllowed(request.origin)) {
// Make sure we only accept requests from an allowed origin
request.reject();
console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
return;
}
var connection = request.accept('stream', request.origin);
console.log((new Date()) + ' Connection accepted.');
var sendSocketHandler = (obj) => {
// logger.info('sendSocket: ' , JSON.stringify(obj));
connection.sendUTF(JSON.stringify(obj));
};
busEmitter.on('sendSocket', sendSocketHandler);
connection.on('message', function(message) {
if (message.type === 'utf8') {
console.log('Received Message: ' + message.utf8Data);
connection.sendUTF(message.utf8Data);
}
else if (message.type === 'binary') {
console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
connection.sendBytes(message.binaryData);
}
});
var connection = request.accept('stream', request.origin);
console.log((new Date()) + ' Connection accepted.');
var sendSocketHandler = (obj) => {
// logger.info('sendSocket: ' + JSON.stringify(obj));
connection.sendUTF(JSON.stringify(obj));
};
busEmitter.on('sendSocket', sendSocketHandler);
connection.on('message', function (message) {
if (message.type === 'utf8') {
console.log('Received Message: ' + message.utf8Data);
connection.sendUTF(message.utf8Data);
}
else if (message.type === 'binary') {
console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
connection.sendBytes(message.binaryData);
}
});
connection.on('close', function (reasonCode, description) {
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
busEmitter.removeListener('sendSocket', sendSocketHandler);
});
connection.on('close', function(reasonCode, description) {
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
busEmitter.removeListener('sendSocket', sendSocketHandler);
});
});
mqttConnect.connectWS(function () {
console.log('Ready to plug in sockets...');
mqttConnect.connectWS(function() {
console.log('Ready to plug in sockets...');
});
/*app.get('/', function( req, res) {
@ -141,6 +183,6 @@ app.post('/api/v1/heating/on', heating_v1.turnon);
app.post('/api/v1/projector/off', projector_v1.turnoff);
app.post('/api/v1/projector/on', projector_v1.turnon);
app.listen(3000, function () {
console.log('Express listening on 3000');
app.listen(3000, function() {
console.log('Express listening on 3000');
});

257
app/css/app.css Normal file
View File

@ -0,0 +1,257 @@
body {
font-family: Ubuntu, "Helvetica Neue", Helvetica, arial, sans-serif;
background-color: #004c6d;
}
#weatherIcon {
margin-left:15px;
height:70px;
width:70px;
}
#lightR, #projR { color: red !important; }
#lightG, #projG { color: green !important; }
#lightB, #projB { color: blue !important; }
#lightW, #projW { background-color: #aabbcc; }
.lightBG, .heatingBG, .projectorBG {
float: right;
}
/*.lightBG {
background-color: rgba(255, 255, 0, 0.3);
}
.heatingBG {
background-color: rgba(255, 0, 255, 0.3);
}
.projectorBG {
background-color: rgba(0, 255, 255, 0.3);
}*/
.mui-panel {
background-color: #015579;
}
.h105 {
height: 100px;
}
.mdHeading {
overflow: hidden;
}
.mui--text-title {
color: #ffffff;
}
.item_content {
height: 100px;
/* border: 1px solid grey;*/
min-height: 100px;
overflow: hidden;
}
.item_content a.title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #ffffff;
}
.item_content div.body, .item_content div.site, .item_content div.tags {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #313131;
}
.time, .date, .temp {
font-family: 'Ubuntu Condensed', sans-serif;
font-size: 80px;
color: #bad649;
}
.time span.hour:after {
content: ":";
}
.date {
font-size: 35px;
line-height: 1;
}
.temp::after {
content: "°c";
}
.item_content div.tags {
color: blue;
}
.noConnection {
color: rgb(244, 150, 26);
}
#caltext {
color: #fff;
}
/* Smartphones (portrait and landscape) ----------- */
@media only screen and (min-device-width: 320px) and (max-device-width: 480px) {
/* Styles */
.time, .date, .temp {
font-family: 'Ubuntu Condensed', sans-serif;
font-size: 33px;
/*color: #ff0000;*/
}
.time {
font-size: 50px;
line-height: 1;
}
.time span.hour:after {
content: "\a";
white-space: pre;
}
.temp {
font-size: 70px;
}
.temp::after {
content: "°";
}
.wd-we {
font-size: 75%;
}
.mo {
font-size: 85%;
}
.mo.mo-1, .mo.mo-10 {
font-size: 70%;
}
.mo.mo-2 {
font-size: 65%;
}
.mo.mo-8 {
font-size: 80%;
}
.mo.mo-9 {
font-size: 55%;
}
.mo.mo-11, .mo.mo-12 {
font-size: 60%;
}
}
/* Smartphones (landscape) ----------- */
@media only screen and (min-width: 321px) {
/* Styles */
}
/* Smartphones (portrait) ----------- */
@media only screen and (max-width: 320px) {
/* Styles */
}
.spinner {
margin: 25px auto 0;
width: 70px;
text-align: center;
}
.spinner > div {
width: 18px;
height: 18px;
background-color: rgb(244, 150, 26);
border-radius: 100%;
display: inline-block;
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
}
.spinner .bounce1 {
-webkit-animation-delay: -0.32s;
animation-delay: -0.32s;
}
.spinner .bounce2 {
-webkit-animation-delay: -0.16s;
animation-delay: -0.16s;
}
@-webkit-keyframes sk-bouncedelay {
0%, 80%, 100% { -webkit-transform: scale(0) }
40% { -webkit-transform: scale(1.0) }
}
@keyframes sk-bouncedelay {
0%, 80%, 100% {
-webkit-transform: scale(0);
transform: scale(0);
}
40% {
-webkit-transform: scale(1.0);
transform: scale(1.0);
}
}
.material-icons {
color: #e5f7fd;
}
.material-icons.md-18 { font-size: 18px; }
.material-icons.md-24 { font-size: 24px; }
.material-icons.md-36 { font-size: 36px; }
.material-icons.md-48 { font-size: 48px; }
.material-icons.md-100 { font-size: 100px; }
/* Rules for using icons as black on a light background. */
.material-icons.md-dark { color: rgba(0, 0, 0, 0.54); }
.material-icons.md-dark.md-inactive { color: rgba(0, 0, 0, 0.26); }
/* Rules for using icons as white on a dark background. */
.material-icons.md-light { color: rgba(255, 255, 255, 1); }
.material-icons.md-light.md-inactive { color: rgba(255, 255, 255, 0.3); }
.material-icons.md-bulb {
content: ""
}
/*
fan : toys
<i class="material-icons">&#xE332;</i>
bulb : lightbulb_outline
<i class="material-icons">&#xE90F;</i>
calendar: event_note
<i class="material-icons">&#xE616;</i>
projector: cast
<i class="material-icons">&#xE307;</i>
*/

View File

@ -0,0 +1,15 @@
.material-icons {
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
}

File diff suppressed because it is too large Load Diff

2
app/css/mui.min.css vendored

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 924 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

12
app/fav/browserconfig.xml Normal file
View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square70x70logo src="/fav/mstile-70x70.png"/>
<square150x150logo src="/fav/mstile-150x150.png"/>
<square310x310logo src="/fav/mstile-310x310.png"/>
<wide310x150logo src="/fav/mstile-310x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>

BIN
app/fav/favicon-16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 B

BIN
app/fav/favicon-32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

BIN
app/fav/favicon-96x96.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
app/fav/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

43
app/fav/manifest.json Normal file
View File

@ -0,0 +1,43 @@
{
"name": "Censis Smart Office ",
"icons": [
{
"src": "\/fav\/android-chrome-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": 0.75
},
{
"src": "\/fav\/android-chrome-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": 1
},
{
"src": "\/fav\/android-chrome-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": 1.5
},
{
"src": "\/fav\/android-chrome-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": 2
},
{
"src": "\/fav\/android-chrome-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": 3
},
{
"src": "\/fav\/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": 4
}
],
"display": "standalone",
"orientation": "portrait"
}

BIN
app/fav/mstile-144x144.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
app/fav/mstile-150x150.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
app/fav/mstile-310x150.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
app/fav/mstile-310x310.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

BIN
app/fav/mstile-70x70.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,46 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="991.000000pt" height="991.000000pt" viewBox="0 0 991.000000 991.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata>
<g transform="translate(0.000000,991.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M7465 9503 c-480 -60 -867 -422 -967 -903 -28 -132 -21 -345 16 -517
40 -184 56 -315 56 -460 0 -146 -15 -244 -54 -347 -36 -96 -38 -98 -89 -80
-71 25 -267 73 -372 90 -219 35 -551 33 -774 -5 -973 -169 -1752 -917 -1945
-1871 -14 -67 -27 -124 -30 -127 -9 -9 -162 19 -235 43 -168 56 -304 137 -577
345 -209 157 -328 222 -489 266 -93 25 -114 27 -290 27 -207 0 -253 -8 -420
-73 -270 -104 -514 -347 -624 -623 -113 -281 -105 -620 20 -887 113 -241 291
-426 524 -541 311 -154 673 -157 985 -9 107 51 172 95 328 226 311 258 558
392 752 405 l44 3 17 -70 c115 -492 361 -914 725 -1247 354 -324 795 -530
1294 -604 80 -12 177 -17 320 -17 222 0 346 14 545 58 254 57 407 0 493 -183
25 -52 27 -68 27 -177 -1 -119 -1 -121 -49 -245 -66 -173 -86 -263 -93 -410
-21 -494 279 -940 743 -1106 352 -126 754 -67 1054 156 84 62 205 187 259 269
62 91 126 231 157 341 38 140 45 372 14 520 -96 469 -473 820 -950 886 -179
25 -223 35 -297 69 -85 39 -159 105 -199 177 -27 49 -29 61 -29 158 0 95 3
110 27 156 15 28 70 102 123 165 239 281 410 611 500 963 57 223 70 332 70
596 0 264 -13 373 -70 595 -115 448 -379 885 -712 1179 -57 50 -103 95 -103
100 0 19 92 136 150 189 119 110 264 194 490 282 80 31 176 69 215 86 333 142
568 418 656 770 29 120 36 325 15 448 -84 482 -453 849 -931 926 -82 14 -245
18 -320 8z m-879 -2369 c179 -72 362 -175 526 -296 l67 -49 -23 -52 c-78 -176
-73 -421 13 -642 17 -45 63 -137 103 -205 210 -367 298 -727 268 -1103 -53
-664 -433 -1233 -1019 -1527 -295 -148 -564 -207 -891 -197 -233 7 -398 39
-600 114 -449 168 -823 510 -1029 943 -42 89 -123 311 -116 318 2 2 44 -11 95
-28 199 -66 403 -188 797 -477 211 -155 338 -226 497 -278 766 -251 1582 242
1721 1041 20 113 19 336 0 450 -95 545 -532 983 -1079 1081 -125 22 -354 22
-470 -1 -279 -54 -482 -162 -716 -377 -330 -304 -539 -447 -753 -514 -117 -37
-118 -37 -101 33 82 320 239 603 467 839 161 167 310 274 522 379 232 113 430
166 690 184 357 24 460 45 614 125 111 57 194 125 255 209 26 36 54 66 60 66
7 0 52 -16 102 -36z m-701 -1448 c90 -24 232 -98 307 -160 122 -101 217 -251
259 -411 28 -105 30 -279 4 -380 -91 -359 -405 -608 -770 -608 -123 0 -231 25
-350 83 -165 80 -284 199 -364 363 -54 109 -72 180 -78 308 -11 224 60 417
215 581 109 116 254 198 407 232 87 19 283 15 370 -8z m-2044 -463 c-10 -56
-15 -144 -14 -313 0 -211 3 -246 25 -348 l24 -114 -30 6 c-106 20 -209 26
-353 20 l-162 -6 -6 24 c-31 139 -44 479 -25 664 6 65 13 120 13 120 1 1 114
5 252 9 137 3 252 8 254 11 2 2 12 4 21 4 15 0 15 -6 1 -77z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
app/gfx/icons/Calendar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
app/gfx/icons/Clock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
app/gfx/icons/Cloud.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
app/gfx/icons/Downpour.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1015 B

BIN
app/gfx/icons/Fan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
app/gfx/icons/Fog Day.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
app/gfx/icons/Fog Night.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
app/gfx/icons/Full Moon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
app/gfx/icons/Hail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
app/gfx/icons/Icy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
app/gfx/icons/Idea.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
app/gfx/icons/Light Off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
app/gfx/icons/No Rain.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
app/gfx/icons/Rain.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
app/gfx/icons/Sleet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
app/gfx/icons/Snow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
app/gfx/icons/Storm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
app/gfx/icons/Sun.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
app/gfx/icons/TV On.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
app/gfx/icons/Wet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
app/gfx/icons/Winter.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,221 +1,210 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Console</title>
<link rel="stylesheet" type="text/css" href="css/mui.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/zepto/1.1.4/zepto.min.js"></script>
<style>
#lightR, #projR {color:red !important;}
#lightG, #projG {color:green !important;}
#lightB, #projB {color:blue !important;}
#lightW, #projW {background-color: #aabbcc;}
</style>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Console</title>
<!-- build:fonts -->
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Ubuntu:300,400,500,700" type="text/css">
<link href='https://fonts.googleapis.com/css?family=Ubuntu+Condensed' rel='stylesheet' type='text/css'>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- endbuild -->
<!-- build:css -->
<link href="css/mui.min.css" rel="stylesheet" type="text/css"/>
<link href="css/app.css" rel="stylesheet" type="text/css"/>
<!-- endbuild -->
<link rel="apple-touch-icon" sizes="57x57" href="/fav/apple-touch-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/fav/apple-touch-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/fav/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/fav/apple-touch-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/fav/apple-touch-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/fav/apple-touch-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/fav/apple-touch-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/fav/apple-touch-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/fav/apple-touch-icon-180x180.png">
<link rel="icon" type="image/png" href="/fav/favicon-32x32.png" sizes="32x32">
<link rel="icon" type="image/png" href="/fav/android-chrome-192x192.png" sizes="192x192">
<link rel="icon" type="image/png" href="/fav/favicon-96x96.png" sizes="96x96">
<link rel="icon" type="image/png" href="/fav/favicon-16x16.png" sizes="16x16">
<link rel="manifest" href="/fav/manifest.json">
<link rel="mask-icon" href="/fav/safari-pinned-tab.svg" color="#5bbad5">
<link rel="shortcut icon" href="/fav/favicon.ico">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="msapplication-TileImage" content="/fav/mstile-144x144.png">
<meta name="msapplication-config" content="/fav/browserconfig.xml">
<meta name="theme-color" content="#00aeef">
</head>
<body>
<div id="iosTaskbar" style="height:25px;display:none;"></div>
<div class="mui-container">
<div class="mui-panel" data-bind="with: viewLights">
<div class="mui-row">
<button id="frontLightOn">Front Light On</button>
<button id="frontLightOff">Front Light Off</button>
</div>
<div class="mui-row">
<button id="middleLightOn">Middle Light On</button>
<button id="middleLightOff">Middle Light Off</button>
</div>
<div class="mui-row">
<button id="backLightOn">Back Light On</button>
<button id="backLightOff">Back Light Off</button>
</div>
<div class="mui-panel" id="noSocket" style="display: none;">
<div class="mui-row">
<div class="mui--text-body2 mui--text-center noConnection">Lost connection to server. Waiting for connection</div>
<div id='longWait' class="spinner" style="display: none;">
<div class="bounce1"></div>
<div class="bounce2"></div>
<div class="bounce3"></div>
</div>
</div>
</div>
<div class="mui-panel" data-bind="with: viewHeat">
<div class="mui-row">
<button id="heatingOn">Heating On</button>
<button id="heatingOff">Heating Off</button>
</div>
<div class="mui-panel" id="clock">
<div class="mui-row">
<div class="mui-col-xs-4 ">
<div id="time" class="mui--text-center time">12:34</div>
</div>
<div class="mui-col-xs-4 item_content">
<div id="date" class="mui--text-center date">14 April<br>2016</div>
</div>
<div class="mui-col-xs-4 item_content">
<div id="weather" class="mui--text-center date"><div id="weatherIcon"><canvas id="icon1" width="210" height="210" style="max-width: 70px; max-height:70px"></canvas></div><div class="mui--text-center" id="weatherText"></div></div>
</div>
</div>
</div>
<div class="mui-panel" data-bind="with: viewProjector">
<div class="mui-row">
<button id="projectorOn">Projector On</button>
<button id="projectorOff">Projector Off</button>
<div class="mui-panel" id="calendar" style="display: none;">
<div class="mui-row">
<div class="mui-col-xs-4 mui--text-center"><span class="material-icons md-100">&#xE616;</span></div>
<div class="mui-col-xs-8 item_content">
<div class="mui-row ">
<div class="mui--text-title "><a class='title'
href="#">Meeting room</a>
</div>
</div>
<div class="mui-row">
<span id="caltext"></span>
</div>
</div>
</div>
</div>
<div class="mui-panel" id="front-light">
<div class="mui-row">
<div class="mui-col-xs-4 mui--text-center"><span class="material-icons md-100">&#xE90F;</span></div>
<div class="mui-col-xs-4 item_content">
<div class="mui-row mui--text-center">
<div class="mui--text-title mui--text-center"><a class='title'
href="#">Front light</a>
</div>
</div>
<div class="mui-row mui--text-center">
<button id="frontLightOn"
class="mui-btn mui-btn--primary">On
</button>
<button id="frontLightOff" class="mui-btn mui-btn--danger"
style="display: none;">Off
</button>
</div>
</div>
</div>
<div class="mui-panel">
</div>
<div class="mui-panel" id="middle-light">
<div class="mui-row">
<div class="mui-col-xs-4 mui--text-center"><i class="material-icons md-100">&#xE90F;</i></div>
<div class="mui-col-xs-4 item_content">
<div class="mui-row">
<div class="mui-col-md-3"><span id="lightR">---</span></div>
<div class="mui-col-md-3"><span id="lightG">---</span></div>
<div class="mui-col-md-3"><span id="lightB">---</span></div>
<div class="mui-col-md-3"><span id="lightW">---</span></div>
<div class="mui--text-title mui--text-center"><a class='title'
href="#">Middle light</a>
</div>
</div>
<div class="mui-row">
<div class="mui-col-md-3"><span id="projR">---</span></div>
<div class="mui-col-md-3"><span id="projG">---</span></div>
<div class="mui-col-md-3"><span id="projB">---</span></div>
<div class="mui-col-md-3"><span id="projW">---</span></div>
<div class="mui-row mui--text-center">
<button id="middleLightOn"
class="mui-btn mui-btn--primary">On
</button>
<button id="middleLightOff" class="mui-btn mui-btn--danger"
style="display: none;">Off
</button>
</div>
</div>
</div>
</div>
<div class="mui-panel" id="back-light">
<div class="mui-row">
<div class="mui-col-xs-4 mui--text-center"><i class="material-icons md-100">&#xE90F;</i></div>
<div class="mui-col-xs-4 item_content">
<div class="mui-row">
<div class="mui--text-title mui--text-center"><a class='title' href="#">Back light</a>
</div>
</div>
<div class="mui-row mui--text-center">
<button id="backLightOn"
class="mui-btn mui-btn--primary">On
</button>
<button id="backLightOff" class="mui-btn mui-btn--danger"
style="display: none;">Off
</button>
</div>
</div>
</div>
</div>
<div class="mui-panel" id="heating-panel">
<div class="mui-row">
<div class="mui-col-xs-4 mui--text-center"><i class="material-icons md-100">&#xE332;</i>
</div>
<div class="mui-col-xs-4 item_content">
<div class="mui-row">
<div class="mui--text-title mui--text-center"><a class='title' href="#">Fan</a>
</div>
</div>
<div class="mui-row mui--text-center">
<button id="heatingOn" class="mui-btn mui-btn--primary">On
</button>
<button id="heatingOff" class="mui-btn mui-btn--danger"
style="display: none;">Off
</button>
</div>
</div>
<div class="mui-col-xs-4 mui--text-center">
<div id="curTemp" class="temp"></div>
</div>
</div>
</div>
<div class="mui-panel" id="projector-panel">
<div class="mui-row">
<div class="mui-col-xs-4 mui--text-center"><i class="material-icons md-100">&#xE307;</i></div>
<div class="mui-col-xs-4 item_content">
<div class="mui-row">
<div class="mui--text-title mui--text-center"><a class='title' href="#">Projector</a>
</div>
</div>
<div class="mui-row mui--text-center">
<button id="projectorOn" class="mui-btn mui-btn--primary">On
</button>
<button id="projectorOff" class="mui-btn mui-btn--danger"
style="display: none;">Off
</button>
</div>
</div>
</div>
</div>
<!--<div class="mui-panel">
<div class="mui-row">
<div class="mui-col-md-3"><span id="lightR">-&#45;&#45;</span></div>
<div class="mui-col-md-3"><span id="lightG">-&#45;&#45;</span></div>
<div class="mui-col-md-3"><span id="lightB">-&#45;&#45;</span></div>
<div class="mui-col-md-3"><span id="lightW">-&#45;&#45;</span></div>
</div>
<div class="mui-row">
<div class="mui-col-md-3"><span id="projR">-&#45;&#45;</span></div>
<div class="mui-col-md-3"><span id="projG">-&#45;&#45;</span></div>
<div class="mui-col-md-3"><span id="projB">-&#45;&#45;</span></div>
<div class="mui-col-md-3"><span id="projW">-&#45;&#45;</span></div>
</div>
</div>-->
</div>
<!-- build:vendor -->
<script src="lib/mui.js"></script>
<script src="lib/jquery.js" integrity="sha256-laXWtGydpwqJ8JA+X9x2miwmaiKhn8tVmOVEigRNtP4=" crossorigin="anonymous"></script>
<script src="lib/chroma.js"></script>
<script src="lib/sugar-date.js"></script>
<script src="lib/skycons.js"></script>
<script src="lib/microevent.js"></script>
<!-- endbuild -->
<script>
function turnOnLights(id) {
console.log('turn on the lights');
$.post('api/v1/lighting/on', {light: id}, function (repsonse) {
console.log(repsonse);
});
}
function turnOffLights(id) {
console.log('turn off the lights');
$.post('api/v1/lighting/off', {light: id}, function (repsonse) {
console.log(repsonse);
});
}
function turnOnHeating() {
console.log('turn on the heating');
$.post('api/v1/heating/on', {}, function (repsonse) {
console.log(repsonse);
});
}
function turnOffHeating() {
console.log('turn off the heating');
$.post('api/v1/heating/off', {}, function (repsonse) {
console.log(repsonse);
});
}
function turnOnProjector() {
console.log('turn on the heating');
$.post('api/v1/projector/on', {}, function (repsonse) {
console.log(repsonse);
});
}
function turnOffProjector() {
console.log('turn off the heating');
$.post('api/v1/projector/off', {}, function (repsonse) {
console.log(repsonse);
});
}
$('#projectorOn').on('click', function () {
turnOnProjector();
});
$('#projectorOff').on('click', function () {
turnOffProjector();
});
$('#heatingOn').on('click', function () {
turnOnHeating();
});
$('#heatingOff').on('click', function () {
turnOffHeating();
});
$('#frontLightOn').on('click', function () {
turnOnLights(1);
});
$('#middleLightOn').on('click', function () {
turnOnLights(2);
});
$('#backLightOn').on('click', function () {
turnOnLights(3);
});
$('#frontLightOff').on('click', function () {
turnOffLights('a');
});
$('#middleLightOff').on('click', function () {
turnOffLights('b');
});
$('#backLightOff').on('click', function () {
turnOffLights('c');
});
(function () {
console.log('Starting socket?');
var url = "ws://localhost:8080";
var wsCtor = window['MozWebSocket'] ? MozWebSocket : WebSocket;
this.socket = new wsCtor(url, 'stream');
this.updateLighting = function(obj) {
//console.log(obj);
$('#lightR').text(obj.Red);
$('#lightG').text(obj.Green);
$('#lightB').text(obj.Blue);
var w = '#'+('0'+parseInt(obj.Red).toString(16)).substr(-2,2)+ ('0'+parseInt(obj.Green).toString(16)).substr(-2,2) + ('0'+parseInt(obj.Blue).toString(16)).substr(-2,2);
$('#lightW').text(w);
$('#lightW').css('background-color', w);
};
this.updateProj = function(obj) {
//console.log(obj);
$('#projR').text(obj.Red);
$('#projG').text(obj.Green);
$('#projB').text(obj.Blue);
var w = '#'+('0'+parseInt(obj.Red).toString(16)).substr(-2,2)+ ('0'+parseInt(obj.Green).toString(16)).substr(-2,2) + ('0'+parseInt(obj.Blue).toString(16)).substr(-2,2);
$('#projW').text(w);
$('#projW').css('background-color', w);
};
this.handleData = function(d) {
switch(d.id) {
case 'LightingDataReceived':
this.updateLighting(d.sensorData.d);
break;
case 'ProjectorDataReceived':
this.updateProj(d.sensorData.d);
break;
case 'HeatingDataReceived':
break;
default:
}
};
this.handleWebsocketMessage = function (message) {
try {
var command = JSON.parse(message.data);
}
catch (e) { /* do nothing */
}
if (command) {
//this.dispatchCommand(command);
this.handleData(command);
}
};
this.handleWebsocketClose = function () {
alert("WebSocket Connection Closed.");
};
this.socket.onmessage = this.handleWebsocketMessage.bind(this);
this.socket.onclose = this.handleWebsocketClose.bind(this);
})();
</script>
</body>
</html>
<!-- build:js -->
<script src="js/app.js"></script></body>
<!-- endbuild -->
</html>

567
app/js/app.js Normal file
View File

@ -0,0 +1,567 @@
var bus = {};
MicroEvent.mixin(bus);
var path = '';
var skycons = new Skycons({"color": "#e5f7fd"});
var lights = {
off: ['frontLightOff', 'middleLightOff', 'backLightOff'],
on: ['frontLightOn', 'middleLightOn', 'backLightOn']
};
//Var tempColours = chroma.scale(['blue','yellow','red']).colors(36);
//console.log(tempColours);
var tempColours = [
{
t: 0,
r: 80,
g: 181,
b: 221
},
{
t: 1,
r: 80,
g: 181,
b: 221
},
{
t: 2,
r: 80,
g: 181,
b: 221
},
{
t: 3,
r: 80,
g: 181,
b: 221
},
{
t: 4,
r: 80,
g: 181,
b: 221
},
{
t: 5,
r: 80,
g: 181,
b: 221
},
{
t: 6,
r: 78,
g: 178,
b: 206
},
{
t: 7,
r: 76,
g: 176,
b: 190
},
{
t: 8,
r: 73,
g: 173,
b: 175
},
{
t: 9,
r: 72,
g: 171,
b: 159
},
{
t: 10,
r: 70,
g: 168,
b: 142
},
{
t: 11,
r: 68,
g: 166,
b: 125
},
{
t: 12,
r: 66,
g: 164,
b: 108
},
{
t: 13,
r: 102,
g: 173,
b: 94
},
{
t: 14,
r: 135,
g: 190,
b: 64
},
{
t: 15,
r: 179,
g: 204,
b: 26
},
{
t: 16,
r: 214,
g: 213,
b: 28
},
{
t: 17,
r: 249,
g: 202,
b: 3
},
{
t: 18,
r: 246,
g: 181,
b: 3
},
{
t: 19,
r: 244,
g: 150,
b: 26
},
{
t: 20,
r: 236,
g: 110,
b: 5
},
{
t: 21,
r: 234,
g: 90,
b: 36
},
{
t: 22,
r: 228,
g: 87,
b: 43
},
{
t: 23,
r: 225,
g: 74,
b: 41
},
{
t: 24,
r: 224,
g: 65,
b: 39
},
{
t: 25,
r: 217,
g: 55,
b: 43
},
{
t: 26,
r: 214,
g: 49,
b: 41
},
{
t: 27,
r: 209,
g: 43,
b: 43
},
{
t: 28,
r: 205,
g: 40,
b: 47
},
{
t: 29,
r: 200,
g: 36,
b: 50
},
{
t: 30,
r: 195,
g: 35,
b: 52
},
{
t: 31,
r: 190,
g: 33,
b: 56
},
{
t: 32,
r: 185,
g: 32,
b: 59
}
];
var prevDate, prevTime;
function updateCalendar(d) {
'use strict';
var $calendar = $('#calendar');
if (d.current !== null && d.current.hasOwnProperty('dtstart')) {
var calString = `<div class="mui--text-subhead">${d.current.summary}</div>`;
$('#caltext').html(calString);
$calendar.slideDown();
} else {
$calendar.slideUp();
}
}
function updateDateTime() {
var now = Date.create(new Date());
var $date = $('#date');
var $time = $('#time');
var curTime = now.format('<span class="hour">{24hr}</span>{mm}');
var curDate = now.format('{yyyy}-{MM}-{dd}');
if (prevTime !== curTime) {
$time.html(curTime);
// UpdateCalendar();
prevTime = curTime;
}
if (prevDate !== curDate) {
$date.html(now.format('<span class="wd-{do}">{Weekday}</span><br><span class="mo mo-{M}">{Month} {dd}</span><br>{yyyy}'));
prevDate = curDate;
}
}
function turnOnLights(id) {
var _id = parseInt(id) - 1;
var $lightsOff = ['#', lights.off[_id]].join('');
var $lightsOn = ['#', lights.on[_id]].join('');
$.post(path + 'api/v1/lighting/on', {light: id}, function(res) {
$($lightsOff).show();
$($lightsOn).hide();
});
}
function turnOffLights(id) {
var _id = ['a', 'b', 'c'].indexOf(id);
var $lightsOff = ['#', lights.off[_id]].join('');
var $lightsOn = ['#', lights.on[_id]].join('');
$.post(path + 'api/v1/lighting/off', {light: id}, function(res) {
$($lightsOff).hide();
$($lightsOn).show();
});
}
function turnOnHeating() {
var $heatingOn = $('#heatingOn');
var $heatingOff = $('#heatingOff');
$.post(path + 'api/v1/heating/on', {}, function(repsonse) {
$($heatingOff).show();
$($heatingOn).hide();
});
}
function turnOffHeating() {
var $heatingOn = $('#heatingOn');
var $heatingOff = $('#heatingOff');
$.post(path + 'api/v1/heating/off', {}, function(repsonse) {
$($heatingOn).show();
$($heatingOff).hide();
});
}
function turnOnProjector() {
var $projectorOn = $('#projectorOn');
var $projectorOff = $('#projectorOff');
$.post(path + 'api/v1/projector/on', {}, function(repsonse) {
$($projectorOff).show();
$($projectorOn).hide();
});
}
function turnOffProjector() {
var $projectorOn = $('#projectorOn');
var $projectorOff = $('#projectorOff');
$.post(path + 'api/v1/projector/off', {}, function(repsonse) {
$($projectorOff).hide();
$($projectorOn).show();
});
}
$('#projectorOn').on('click', function() {
turnOnProjector();
});
$('#projectorOff').on('click', function() {
turnOffProjector();
});
$('#heatingOn').on('click', function() {
turnOnHeating();
});
$('#heatingOff').on('click', function() {
turnOffHeating();
});
$('#frontLightOn').on('click', function() {
turnOnLights(1);
});
$('#middleLightOn').on('click', function() {
turnOnLights(2);
});
$('#backLightOn').on('click', function() {
turnOnLights(3);
});
$('#frontLightOff').on('click', function() {
turnOffLights('a');
});
$('#middleLightOff').on('click', function() {
turnOffLights('b');
});
$('#backLightOff').on('click', function() {
turnOffLights('c');
});
function rgb(cv) {
return ['rgb(', cv.r, ',', cv.g, ',', cv.b, ')'].join('');
}
function clock() {
'use strict';
updateDateTime();
var now = new Date;
var mod = 60000 - (now.getTime() % 60000);
setTimeout(function() {clock();},mod + 10);
}
var SOWEBSOCKET = function() {
this.socket = null;
this.retry = 0;
this.timer = 0;
this.previousTemp = 0;
this.startWebSocket = function() {
'use strict';
console.log('Starting socket?');
var url = 'ws://localhost:8080';
var wsCtor = window['MozWebSocket'] ? MozWebSocket : WebSocket;
this.socket = new wsCtor(url, 'stream');
this.socket.onopen = this.handleWebsocketOnOpen.bind(this);
this.socket.onmessage = this.handleWebsocketMessage.bind(this);
this.socket.onclose = this.handleWebsocketClose.bind(this);
this.socket.onerror = function(e) {
console.log('whoops');
console.error(e);
};
};
this.updateHeating = function(obj) {
var $curTemp = $('#curTemp');
if (this.previousTemp !== obj.temp) {
$curTemp.text(obj.temp);
// Console.log(tempColours[parseInt(obj.temp)]);
$curTemp.css('color', rgb(tempColours[parseInt(obj.temp)]));
this.previousTemp = obj.temp;
}
};
this.updateLighting = function(obj) {
//Console.log(obj);
$('#lightR').text(obj.Red);
$('#lightG').text(obj.Green);
$('#lightB').text(obj.Blue);
var r = parseInt(obj.Red);
var g = parseInt(obj.Green);
var b = parseInt(obj.Blue);
var shiftR = (r & 0xff00) >> 8;
var newR = Math.floor(((r / 65535.0) * 100) * 255);
var newG = Math.floor(((g / 65535.0) * 100) * 255);
var newB = Math.floor(((b / 65535.0) * 100) * 255);
var w = '#' + ('0' + parseInt(newR).toString(16)).substr(-2,
2) + ('0' + parseInt(newG).toString(16)).substr(-2,
2) + ('0' + parseInt(newB).toString(16)).substr(-2, 2);
$('#lightW').text(w);
$('#lightW').css('background-color', w);
};
this.updateProj = function(obj) {
//Console.log(obj);
var r = parseInt(obj.Red);
var g = parseInt(obj.Green);
var b = parseInt(obj.Blue);
var newR = Math.floor(((r / 65535.0) * 100) * 255);
var newG = Math.floor(((g / 65535.0) * 100) * 255);
var newB = Math.floor(((b / 65535.0) * 100) * 255);
$('#projR').text(newR);
$('#projG').text(newG);
$('#projB').text(newB);
var y = Math.floor((0.2126 * newR + 0.7152 * newG + 0.0722 * newB));
var w = '#' + ('0' + parseInt(y).toString(16)).substr(-2,
2) + ('0' + parseInt(y).toString(16)).substr(-2, 2) + ('0' + parseInt(
y).toString(16)).substr(-2, 2);
$('#projW').text(w);
$('#projW').css('background-color', w);
};
this.handleData = function(d) {
switch (d.id) {
case 'LightingDataReceived':
// This.updateLighting(d.sensorData.d);
break;
case 'ProjectorDataReceived':
// This.updateProj(d.sensorData.d);
break;
case 'HeatingDataReceived':
this.updateHeating(d.sensorData.d);
break;
case 'calendar':
updateCalendar(d);
break;
default:
console.log(d);
break;
}
};
this.handleWebsocketOnOpen = function() {
'use strict';
this.retry = 0;
$('#longWait').hide();
$('#noSocket').slideUp();
};
this.handleWebsocketMessage = function(message) {
var command;
try {
command = JSON.parse(message.data);
this.updateDateTime();
}
catch (e) { /* Do nothing */
}
if (command) {
//This.dispatchCommand(command);
this.handleData.call(this,command);
}
};
this.handleWebsocketClose = function() {
console.error('WebSocket Connection Closed.');
$('#noSocket').slideDown();
var self = this;
this.retry++;
if (this.retry > 12) {
this.retry = 1;
}
if (this.retry === 3) {
$('#longWait').fadeIn();
}
console.log('Waiting ', 5000 * this.retry);
this.timer = setTimeout(function() {self.startWebSocket();},5000 * this.retry);
};
this.startWebSocket();
};
var get_weather = function() {
navigator.geolocation.getCurrentPosition(show_weather,function(e){alert(e.code + ' / ' + e.message);});
};
bus.bind('displayWeather', function(data) {
console.log(data);
$('#weatherText').html(parseInt(data.currently.temperature) + '&deg;c&nbsp;');
skycons.add("icon1", data.currently.icon);
});
var show_weather = function(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
// Let's show a map or do something interesting!
$.ajax({
type: 'GET',
url: 'https://api.forecast.io/forecast/0657dc0d81c037cbc89ca88e383b6bbf/' + latitude.toString() + ',' + longitude.toString() + '?units=uk2',
data: '',
dataType: 'jsonp',
timeout: 10000,
context: $('body'),
contentType: ('application/json'),
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'PUT, GET, POST, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type'
},
success: function(data) {
bus.trigger('displayWeather', data);
},
error: function(xhr, type) {
console.error('ajax error');
console.error(xhr);
console.error(type);
}
});
};
(function() {
var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0;
if (iOS) {
$('#iosTaskbar').show();
path = 'http://localhost:3000/';
}
clock();
get_weather();
var soWebSocket = new SOWEBSOCKET();
})();

2465
app/lib/chroma.js Normal file

File diff suppressed because it is too large Load Diff

9842
app/lib/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

55
app/lib/microevent.js Normal file
View File

@ -0,0 +1,55 @@
/**
* MicroEvent - to make any js object an event emitter (server or browser)
*
* - pure javascript - server compatible, browser compatible
* - dont rely on the browser doms
* - super simple - you get it immediatly, no mistery, no magic involved
*
* - create a MicroEventDebug with goodies to debug
* - make it safer to use
*/
var MicroEvent = function(){};
MicroEvent.prototype = {
bind : function(event, fct){
this._events = this._events || {};
this._events[event] = this._events[event] || [];
this._events[event].push(fct);
},
unbind : function(event, fct){
this._events = this._events || {};
if( event in this._events === false ) return;
this._events[event].splice(this._events[event].indexOf(fct), 1);
},
trigger : function(event /* , args... */){
this._events = this._events || {};
if( event in this._events === false ) return;
for(var i = 0; i < this._events[event].length; i++){
this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1));
}
}
};
/**
* mixin will delegate all MicroEvent.js function in the destination object
*
* - require('MicroEvent').mixin(Foobar) will make Foobar able to use MicroEvent
*
* @param {Object} the object which will support MicroEvent
*/
MicroEvent.mixin = function(destObject){
var props = ['bind', 'unbind', 'trigger'];
for(var i = 0; i < props.length; i ++){
if( typeof destObject === 'function' ){
destObject.prototype[props[i]] = MicroEvent.prototype[props[i]];
}else{
destObject[props[i]] = MicroEvent.prototype[props[i]];
}
}
return destObject;
};
// export in common js
if( typeof module !== "undefined" && ('exports' in module)){
module.exports = MicroEvent;
}

1809
app/lib/mui.js Normal file

File diff suppressed because it is too large Load Diff

730
app/lib/skycons.js Normal file
View File

@ -0,0 +1,730 @@
(function(global) {
"use strict";
/* Set up a RequestAnimationFrame shim so we can animate efficiently FOR
* GREAT JUSTICE. */
var requestInterval, cancelInterval;
(function() {
var raf = global.requestAnimationFrame ||
global.webkitRequestAnimationFrame ||
global.mozRequestAnimationFrame ||
global.oRequestAnimationFrame ||
global.msRequestAnimationFrame ,
caf = global.cancelAnimationFrame ||
global.webkitCancelAnimationFrame ||
global.mozCancelAnimationFrame ||
global.oCancelAnimationFrame ||
global.msCancelAnimationFrame ;
if(raf && caf) {
requestInterval = function(fn, delay) {
var handle = {value: null};
function loop() {
handle.value = raf(loop);
fn();
}
loop();
return handle;
};
cancelInterval = function(handle) {
caf(handle.value);
};
}
else {
requestInterval = setInterval;
cancelInterval = clearInterval;
}
}());
/* Catmull-rom spline stuffs. */
/*
function upsample(n, spline) {
var polyline = [],
len = spline.length,
bx = spline[0],
by = spline[1],
cx = spline[2],
cy = spline[3],
dx = spline[4],
dy = spline[5],
i, j, ax, ay, px, qx, rx, sx, py, qy, ry, sy, t;
for(i = 6; i !== spline.length; i += 2) {
ax = bx;
bx = cx;
cx = dx;
dx = spline[i ];
px = -0.5 * ax + 1.5 * bx - 1.5 * cx + 0.5 * dx;
qx = ax - 2.5 * bx + 2.0 * cx - 0.5 * dx;
rx = -0.5 * ax + 0.5 * cx ;
sx = bx ;
ay = by;
by = cy;
cy = dy;
dy = spline[i + 1];
py = -0.5 * ay + 1.5 * by - 1.5 * cy + 0.5 * dy;
qy = ay - 2.5 * by + 2.0 * cy - 0.5 * dy;
ry = -0.5 * ay + 0.5 * cy ;
sy = by ;
for(j = 0; j !== n; ++j) {
t = j / n;
polyline.push(
((px * t + qx) * t + rx) * t + sx,
((py * t + qy) * t + ry) * t + sy
);
}
}
polyline.push(
px + qx + rx + sx,
py + qy + ry + sy
);
return polyline;
}
function downsample(n, polyline) {
var len = 0,
i, dx, dy;
for(i = 2; i !== polyline.length; i += 2) {
dx = polyline[i ] - polyline[i - 2];
dy = polyline[i + 1] - polyline[i - 1];
len += Math.sqrt(dx * dx + dy * dy);
}
len /= n;
var small = [],
target = len,
min = 0,
max, t;
small.push(polyline[0], polyline[1]);
for(i = 2; i !== polyline.length; i += 2) {
dx = polyline[i ] - polyline[i - 2];
dy = polyline[i + 1] - polyline[i - 1];
max = min + Math.sqrt(dx * dx + dy * dy);
if(max > target) {
t = (target - min) / (max - min);
small.push(
polyline[i - 2] + dx * t,
polyline[i - 1] + dy * t
);
target += len;
}
min = max;
}
small.push(polyline[polyline.length - 2], polyline[polyline.length - 1]);
return small;
}
*/
/* Define skycon things. */
/* FIXME: I'm *really really* sorry that this code is so gross. Really, I am.
* I'll try to clean it up eventually! Promise! */
var KEYFRAME = 500,
STROKE = 0.08,
TAU = 2.0 * Math.PI,
TWO_OVER_SQRT_2 = 2.0 / Math.sqrt(2);
function circle(ctx, x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, TAU, false);
ctx.fill();
}
function line(ctx, ax, ay, bx, by) {
ctx.beginPath();
ctx.moveTo(ax, ay);
ctx.lineTo(bx, by);
ctx.stroke();
}
function puff(ctx, t, cx, cy, rx, ry, rmin, rmax) {
var c = Math.cos(t * TAU),
s = Math.sin(t * TAU);
rmax -= rmin;
circle(
ctx,
cx - s * rx,
cy + c * ry + rmax * 0.5,
rmin + (1 - c * 0.5) * rmax
);
}
function puffs(ctx, t, cx, cy, rx, ry, rmin, rmax) {
var i;
for(i = 5; i--; )
puff(ctx, t + i / 5, cx, cy, rx, ry, rmin, rmax);
}
function cloud(ctx, t, cx, cy, cw, s, color) {
t /= 30000;
var a = cw * 0.21,
b = cw * 0.12,
c = cw * 0.24,
d = cw * 0.28;
ctx.fillStyle = color;
puffs(ctx, t, cx, cy, a, b, c, d);
ctx.globalCompositeOperation = 'destination-out';
puffs(ctx, t, cx, cy, a, b, c - s, d - s);
ctx.globalCompositeOperation = 'source-over';
}
function sun(ctx, t, cx, cy, cw, s, color) {
t /= 120000;
var a = cw * 0.25 - s * 0.5,
b = cw * 0.32 + s * 0.5,
c = cw * 0.50 - s * 0.5,
i, p, cos, sin;
ctx.strokeStyle = color;
ctx.lineWidth = s;
ctx.lineCap = "round";
ctx.lineJoin = "round";
ctx.beginPath();
ctx.arc(cx, cy, a, 0, TAU, false);
ctx.stroke();
for(i = 8; i--; ) {
p = (t + i / 8) * TAU;
cos = Math.cos(p);
sin = Math.sin(p);
line(ctx, cx + cos * b, cy + sin * b, cx + cos * c, cy + sin * c);
}
}
function moon(ctx, t, cx, cy, cw, s, color) {
t /= 15000;
var a = cw * 0.29 - s * 0.5,
b = cw * 0.05,
c = Math.cos(t * TAU),
p = c * TAU / -16;
ctx.strokeStyle = color;
ctx.lineWidth = s;
ctx.lineCap = "round";
ctx.lineJoin = "round";
cx += c * b;
ctx.beginPath();
ctx.arc(cx, cy, a, p + TAU / 8, p + TAU * 7 / 8, false);
ctx.arc(cx + Math.cos(p) * a * TWO_OVER_SQRT_2, cy + Math.sin(p) * a * TWO_OVER_SQRT_2, a, p + TAU * 5 / 8, p + TAU * 3 / 8, true);
ctx.closePath();
ctx.stroke();
}
function rain(ctx, t, cx, cy, cw, s, color) {
t /= 1350;
var a = cw * 0.16,
b = TAU * 11 / 12,
c = TAU * 7 / 12,
i, p, x, y;
ctx.fillStyle = color;
for(i = 4; i--; ) {
p = (t + i / 4) % 1;
x = cx + ((i - 1.5) / 1.5) * (i === 1 || i === 2 ? -1 : 1) * a;
y = cy + p * p * cw;
ctx.beginPath();
ctx.moveTo(x, y - s * 1.5);
ctx.arc(x, y, s * 0.75, b, c, false);
ctx.fill();
}
}
function sleet(ctx, t, cx, cy, cw, s, color) {
t /= 750;
var a = cw * 0.1875,
b = TAU * 11 / 12,
c = TAU * 7 / 12,
i, p, x, y;
ctx.strokeStyle = color;
ctx.lineWidth = s * 0.5;
ctx.lineCap = "round";
ctx.lineJoin = "round";
for(i = 4; i--; ) {
p = (t + i / 4) % 1;
x = Math.floor(cx + ((i - 1.5) / 1.5) * (i === 1 || i === 2 ? -1 : 1) * a) + 0.5;
y = cy + p * cw;
line(ctx, x, y - s * 1.5, x, y + s * 1.5);
}
}
function snow(ctx, t, cx, cy, cw, s, color) {
t /= 3000;
var a = cw * 0.16,
b = s * 0.75,
u = t * TAU * 0.7,
ux = Math.cos(u) * b,
uy = Math.sin(u) * b,
v = u + TAU / 3,
vx = Math.cos(v) * b,
vy = Math.sin(v) * b,
w = u + TAU * 2 / 3,
wx = Math.cos(w) * b,
wy = Math.sin(w) * b,
i, p, x, y;
ctx.strokeStyle = color;
ctx.lineWidth = s * 0.5;
ctx.lineCap = "round";
ctx.lineJoin = "round";
for(i = 4; i--; ) {
p = (t + i / 4) % 1;
x = cx + Math.sin((p + i / 4) * TAU) * a;
y = cy + p * cw;
line(ctx, x - ux, y - uy, x + ux, y + uy);
line(ctx, x - vx, y - vy, x + vx, y + vy);
line(ctx, x - wx, y - wy, x + wx, y + wy);
}
}
function fogbank(ctx, t, cx, cy, cw, s, color) {
t /= 30000;
var a = cw * 0.21,
b = cw * 0.06,
c = cw * 0.21,
d = cw * 0.28;
ctx.fillStyle = color;
puffs(ctx, t, cx, cy, a, b, c, d);
ctx.globalCompositeOperation = 'destination-out';
puffs(ctx, t, cx, cy, a, b, c - s, d - s);
ctx.globalCompositeOperation = 'source-over';
}
/*
var WIND_PATHS = [
downsample(63, upsample(8, [
-1.00, -0.28,
-0.75, -0.18,
-0.50, 0.12,
-0.20, 0.12,
-0.04, -0.04,
-0.07, -0.18,
-0.19, -0.18,
-0.23, -0.05,
-0.12, 0.11,
0.02, 0.16,
0.20, 0.15,
0.50, 0.07,
0.75, 0.18,
1.00, 0.28
])),
downsample(31, upsample(16, [
-1.00, -0.10,
-0.75, 0.00,
-0.50, 0.10,
-0.25, 0.14,
0.00, 0.10,
0.25, 0.00,
0.50, -0.10,
0.75, -0.14,
1.00, -0.10
]))
];
*/
var WIND_PATHS = [
[
-0.7500, -0.1800, -0.7219, -0.1527, -0.6971, -0.1225,
-0.6739, -0.0910, -0.6516, -0.0588, -0.6298, -0.0262,
-0.6083, 0.0065, -0.5868, 0.0396, -0.5643, 0.0731,
-0.5372, 0.1041, -0.5033, 0.1259, -0.4662, 0.1406,
-0.4275, 0.1493, -0.3881, 0.1530, -0.3487, 0.1526,
-0.3095, 0.1488, -0.2708, 0.1421, -0.2319, 0.1342,
-0.1943, 0.1217, -0.1600, 0.1025, -0.1290, 0.0785,
-0.1012, 0.0509, -0.0764, 0.0206, -0.0547, -0.0120,
-0.0378, -0.0472, -0.0324, -0.0857, -0.0389, -0.1241,
-0.0546, -0.1599, -0.0814, -0.1876, -0.1193, -0.1964,
-0.1582, -0.1935, -0.1931, -0.1769, -0.2157, -0.1453,
-0.2290, -0.1085, -0.2327, -0.0697, -0.2240, -0.0317,
-0.2064, 0.0033, -0.1853, 0.0362, -0.1613, 0.0672,
-0.1350, 0.0961, -0.1051, 0.1213, -0.0706, 0.1397,
-0.0332, 0.1512, 0.0053, 0.1580, 0.0442, 0.1624,
0.0833, 0.1636, 0.1224, 0.1615, 0.1613, 0.1565,
0.1999, 0.1500, 0.2378, 0.1402, 0.2749, 0.1279,
0.3118, 0.1147, 0.3487, 0.1015, 0.3858, 0.0892,
0.4236, 0.0787, 0.4621, 0.0715, 0.5012, 0.0702,
0.5398, 0.0766, 0.5768, 0.0890, 0.6123, 0.1055,
0.6466, 0.1244, 0.6805, 0.1440, 0.7147, 0.1630,
0.7500, 0.1800
],
[
-0.7500, 0.0000, -0.7033, 0.0195, -0.6569, 0.0399,
-0.6104, 0.0600, -0.5634, 0.0789, -0.5155, 0.0954,
-0.4667, 0.1089, -0.4174, 0.1206, -0.3676, 0.1299,
-0.3174, 0.1365, -0.2669, 0.1398, -0.2162, 0.1391,
-0.1658, 0.1347, -0.1157, 0.1271, -0.0661, 0.1169,
-0.0170, 0.1046, 0.0316, 0.0903, 0.0791, 0.0728,
0.1259, 0.0534, 0.1723, 0.0331, 0.2188, 0.0129,
0.2656, -0.0064, 0.3122, -0.0263, 0.3586, -0.0466,
0.4052, -0.0665, 0.4525, -0.0847, 0.5007, -0.1002,
0.5497, -0.1130, 0.5991, -0.1240, 0.6491, -0.1325,
0.6994, -0.1380, 0.7500, -0.1400
]
],
WIND_OFFSETS = [
{start: 0.36, end: 0.11},
{start: 0.56, end: 0.16}
];
function leaf(ctx, t, x, y, cw, s, color) {
var a = cw / 8,
b = a / 3,
c = 2 * b,
d = (t % 1) * TAU,
e = Math.cos(d),
f = Math.sin(d);
ctx.fillStyle = color;
ctx.strokeStyle = color;
ctx.lineWidth = s;
ctx.lineCap = "round";
ctx.lineJoin = "round";
ctx.beginPath();
ctx.arc(x , y , a, d , d + Math.PI, false);
ctx.arc(x - b * e, y - b * f, c, d + Math.PI, d , false);
ctx.arc(x + c * e, y + c * f, b, d + Math.PI, d , true );
ctx.globalCompositeOperation = 'destination-out';
ctx.fill();
ctx.globalCompositeOperation = 'source-over';
ctx.stroke();
}
function swoosh(ctx, t, cx, cy, cw, s, index, total, color) {
t /= 2500;
var path = WIND_PATHS[index],
a = (t + index - WIND_OFFSETS[index].start) % total,
c = (t + index - WIND_OFFSETS[index].end ) % total,
e = (t + index ) % total,
b, d, f, i;
ctx.strokeStyle = color;
ctx.lineWidth = s;
ctx.lineCap = "round";
ctx.lineJoin = "round";
if(a < 1) {
ctx.beginPath();
a *= path.length / 2 - 1;
b = Math.floor(a);
a -= b;
b *= 2;
b += 2;
ctx.moveTo(
cx + (path[b - 2] * (1 - a) + path[b ] * a) * cw,
cy + (path[b - 1] * (1 - a) + path[b + 1] * a) * cw
);
if(c < 1) {
c *= path.length / 2 - 1;
d = Math.floor(c);
c -= d;
d *= 2;
d += 2;
for(i = b; i !== d; i += 2)
ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw);
ctx.lineTo(
cx + (path[d - 2] * (1 - c) + path[d ] * c) * cw,
cy + (path[d - 1] * (1 - c) + path[d + 1] * c) * cw
);
}
else
for(i = b; i !== path.length; i += 2)
ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw);
ctx.stroke();
}
else if(c < 1) {
ctx.beginPath();
c *= path.length / 2 - 1;
d = Math.floor(c);
c -= d;
d *= 2;
d += 2;
ctx.moveTo(cx + path[0] * cw, cy + path[1] * cw);
for(i = 2; i !== d; i += 2)
ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw);
ctx.lineTo(
cx + (path[d - 2] * (1 - c) + path[d ] * c) * cw,
cy + (path[d - 1] * (1 - c) + path[d + 1] * c) * cw
);
ctx.stroke();
}
if(e < 1) {
e *= path.length / 2 - 1;
f = Math.floor(e);
e -= f;
f *= 2;
f += 2;
leaf(
ctx,
t,
cx + (path[f - 2] * (1 - e) + path[f ] * e) * cw,
cy + (path[f - 1] * (1 - e) + path[f + 1] * e) * cw,
cw,
s,
color
);
}
}
var Skycons = function(opts) {
this.list = [];
this.interval = null;
this.color = opts && opts.color ? opts.color : "black";
this.resizeClear = !!(opts && opts.resizeClear);
};
Skycons.CLEAR_DAY = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
sun(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color);
};
Skycons.CLEAR_NIGHT = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
moon(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color);
};
Skycons.PARTLY_CLOUDY_DAY = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
sun(ctx, t, w * 0.625, h * 0.375, s * 0.75, s * STROKE, color);
cloud(ctx, t, w * 0.375, h * 0.625, s * 0.75, s * STROKE, color);
};
Skycons.PARTLY_CLOUDY_NIGHT = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
moon(ctx, t, w * 0.667, h * 0.375, s * 0.75, s * STROKE, color);
cloud(ctx, t, w * 0.375, h * 0.625, s * 0.75, s * STROKE, color);
};
Skycons.CLOUDY = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
cloud(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color);
};
Skycons.RAIN = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
rain(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
};
Skycons.SLEET = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
sleet(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
};
Skycons.SNOW = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
snow(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color);
};
Skycons.WIND = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h);
swoosh(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, 0, 2, color);
swoosh(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, 1, 2, color);
};
Skycons.FOG = function(ctx, t, color) {
var w = ctx.canvas.width,
h = ctx.canvas.height,
s = Math.min(w, h),
k = s * STROKE;
fogbank(ctx, t, w * 0.5, h * 0.32, s * 0.75, k, color);
t /= 5000;
var a = Math.cos((t ) * TAU) * s * 0.02,
b = Math.cos((t + 0.25) * TAU) * s * 0.02,
c = Math.cos((t + 0.50) * TAU) * s * 0.02,
d = Math.cos((t + 0.75) * TAU) * s * 0.02,
n = h * 0.936,
e = Math.floor(n - k * 0.5) + 0.5,
f = Math.floor(n - k * 2.5) + 0.5;
ctx.strokeStyle = color;
ctx.lineWidth = k;
ctx.lineCap = "round";
ctx.lineJoin = "round";
line(ctx, a + w * 0.2 + k * 0.5, e, b + w * 0.8 - k * 0.5, e);
line(ctx, c + w * 0.2 + k * 0.5, f, d + w * 0.8 - k * 0.5, f);
};
Skycons.prototype = {
_determineDrawingFunction: function(draw) {
if(typeof draw === "string")
draw = Skycons[draw.toUpperCase().replace(/-/g, "_")] || null;
return draw;
},
add: function(el, draw) {
var obj;
if(typeof el === "string")
el = document.getElementById(el);
// Does nothing if canvas name doesn't exists
if(el === null)
return;
draw = this._determineDrawingFunction(draw);
// Does nothing if the draw function isn't actually a function
if(typeof draw !== "function")
return;
obj = {
element: el,
context: el.getContext("2d"),
drawing: draw
};
this.list.push(obj);
this.draw(obj, KEYFRAME);
},
set: function(el, draw) {
var i;
if(typeof el === "string")
el = document.getElementById(el);
for(i = this.list.length; i--; )
if(this.list[i].element === el) {
this.list[i].drawing = this._determineDrawingFunction(draw);
this.draw(this.list[i], KEYFRAME);
return;
}
this.add(el, draw);
},
remove: function(el) {
var i;
if(typeof el === "string")
el = document.getElementById(el);
for(i = this.list.length; i--; )
if(this.list[i].element === el) {
this.list.splice(i, 1);
return;
}
},
draw: function(obj, time) {
var canvas = obj.context.canvas;
if(this.resizeClear)
canvas.width = canvas.width;
else
obj.context.clearRect(0, 0, canvas.width, canvas.height);
obj.drawing(obj.context, time, this.color);
},
play: function() {
var self = this;
this.pause();
this.interval = requestInterval(function() {
var now = Date.now(),
i;
for(i = self.list.length; i--; )
self.draw(self.list[i], now);
}, 1000 / 60);
},
pause: function() {
var i;
if(this.interval) {
cancelInterval(this.interval);
this.interval = null;
}
}
};
global.Skycons = Skycons;
}(this));

3335
app/lib/sugar-date.js Normal file

File diff suppressed because it is too large Load Diff

3
fonts.list Normal file
View File

@ -0,0 +1,3 @@
Ubuntu:300,400,500,700
Ubuntu+Condensed
Material+Icons

View File

@ -1,16 +1,114 @@
/**
* Created by Martin on 09/02/2016.
'use strict';
var gulp = require('gulp'),
autoprefixer = require('gulp-autoprefixer'),
cssnano = require('gulp-cssnano'),
jshint = require('gulp-jshint'),
uglify = require('gulp-uglify'),
jsmin = require('gulp-jsmin'),
rename = require('gulp-rename'),
concat = require('gulp-concat'),
notify = require('gulp-notify'),
cache = require('gulp-cache'),
livereload = require('gulp-livereload'),
htmlmin = require('gulp-htmlmin'),
inject = require('gulp-inject'),
del = require('del'),
htmlreplace = require('gulp-html-replace'),
googleWebFonts = require('gulp-google-webfonts');
var debug = require('gulp-debug');
var filePath = {
build_dir: './dist'
};
gulp.task('scripts', function() {
return gulp.src('app/js/**/*.js')
.pipe(jshint('.jshintrc'))
.pipe(jshint.reporter('default'))
.pipe(concat('app.js'))
.pipe(jsmin())
.pipe(gulp.dest('dist/js'));
});
/*
<script src="lib/mui.js"></script>
<script src="lib/jquery.js" integrity="sha256-laXWtGydpwqJ8JA+X9x2miwmaiKhn8tVmOVEigRNtP4=" crossorigin="anonymous"></script>
<script src="lib/chroma.js"></script>
<script src="lib/sugar-date.js"></script>
*/
var gulp = require('gulp')
, jshint = require("gulp-jshint");
gulp.task('vendor', function() {
return gulp.src(['bower_components/jquery/dist/jquery.min.js',
'bower_components/mui/packages/cdn/js/mui.min.js',
'bower_components/chroma-js/chroma.min.js',
'bower_components/sugarjs-date/sugar-date.min.js',
'app/lib/skycons.js',
'app/lib/microevent.js'])
.pipe(concat('vendor.js'))
.pipe(uglify({mangle: false}))
.pipe(gulp.dest('dist/js'));
});
// task
gulp.task('jsLint', function () {
gulp.src('./lib/*.js') // path to your files
.pipe(jshint())
.pipe(jshint.reporter());
gulp.src('./test/*.js') // path to your files
.pipe(jshint())
.pipe(jshint.reporter()); // Dump results
});
gulp.task('styles', function() {
return gulp.src(['bower_components/mui/packages/cdn/css/mui.min.css','app/css/material-icons.css','app/css/app.css'])
.pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
.pipe(cssnano())
.pipe(concat('app.css'))
.pipe(gulp.dest('dist/css'));
});
gulp.task('partials', function() {
// Gulp.src(['app/partials/**/*']).pipe(gulp.dest('dist/partials'));
// gulp.src(['app/libs/ejs_production.js']).pipe(gulp.dest('dist/libs'));
// gulp.src(['app/libs/microevent.js']).pipe(gulp.dest('dist/libs'));
gulp.src(['app/fav/**/*']).pipe(gulp.dest('dist/fav'));
// Gulp.src(['app/gfx/**/*']).pipe(gulp.dest('dist/gfx'));
});
gulp.task('migrate', function() {
return gulp.src(['dist/**/*'])
.pipe(debug({title: 'migrate:'}))
.pipe(gulp.dest('/Users/martin/newdev/SODashApp/www'));
});
gulp.task('index', function() {
var sources = gulp.src(['js/apps.js', 'css/app.css'], {read: false});
return gulp.src(['app/index.html'])
.pipe(htmlreplace({
css: 'css/app.css',
js: 'js/app.js',
vendor: 'js/vendor.js',
fonts: 'fonts/fonts.css'
}))
.pipe(htmlmin({removeComments: true, collapseWhitespace: true, keepClosingSlash: true}))
.pipe(gulp.dest('dist/'));
});
var options = { };
gulp.task('fonts', function() {
return gulp.src('./fonts.list')
.pipe(googleWebFonts(options))
.pipe(gulp.dest('dist/fonts'))
;
});
gulp.task('clean', function() {
return del(['dist']);
});
gulp.task('default', ['clean'], function() {
gulp.start('styles', 'scripts', 'vendor', 'fonts', 'partials', 'index');
});
gulp.task('Cordova', ['clean'], function() {
gulp.start('styles', 'scripts', 'vendor', 'fonts', 'index');
});

View File

@ -0,0 +1,322 @@
var request = require('request');
var cheerio = require('cheerio');
var t = require('./getTimeAndDate');
var log4js = require('log4js');
var logger = log4js.getLogger();
var STRING = require('string');
var util = require('util');
var Elapsed = require('elapsed');
var clone = require('clone');
require('sugar-date');
var meetingStates = {
STARTING: 0,
INPROGRESS: 1,
NONE: 2,
FINISHED: 3
};
var calendarInterface = function() {
this.jsonBlock = [];
this.cachedStatus = {};
this.setJson = function(j) {
'use strict';
this.jsonBlock = j;
};
this.getJson = function() {
'use strict';
return this.jsonBlock;
};
//Console.log('Calendar synchronisation service Started.');
};
function processICAL(ical) {
'use strict';
logger.info('+ processICAL');
var workingBlock = [];
var segments = {
meetingStartID: 'DTSTART;TZID=Europe/London:',
meetingEndID: 'DTEND;TZID=Europe/London:',
meetingDescID: 'DESCRIPTION:',
summaryID: 'SUMMARY:',
begin: 'BEGIN:VEVENT',
end: 'END:VEVENT',
beginAlarm: 'BEGIN:VALARM',
uid: 'UID:'
};
function processBlock(block) {
var workBlock = {
summary: '',
dtstart: null,
dtend: null,
description: '',
timeStart: null,
timeEnd: null,
duration: 0,
combined: '',
uid: ''
};
var alarmFlag = false, ws, blockStep;
for (var step = 0; step < block.length; step++) {
// Logger.info(block[step]);
blockStep = block[step];
if (blockStep.indexOf(segments.summaryID) >= 0) {
workBlock.summary = STRING(block[step].split(segments.summaryID)[1]).collapseWhitespace().s;
}
if (blockStep.indexOf(segments.meetingStartID) >= 0) {
ws = STRING(block[step].split(segments.meetingStartID)[1]).collapseWhitespace().s;
workBlock.dtstart = Date.create(ws);
}
if (blockStep.indexOf(segments.meetingEndID) >= 0) {
ws = STRING(block[step].split(segments.meetingEndID)[1]).collapseWhitespace().s;
workBlock.dtend = Date.create(ws);
}
if (blockStep.indexOf(segments.meetingStartAlt) >= 0) {
ws = STRING(block[step].split(segments.meetingStartAlt)[1]).collapseWhitespace().s;
workBlock.dtstart = Date.create(ws);
}
if (blockStep.indexOf(segments.meetingEndAlt) >= 0) {
ws = STRING(block[step].split(segments.meetingEndAlt)[1]).collapseWhitespace().s;
workBlock.dtend = Date.create(ws);
}
if (blockStep.indexOf(segments.meetingDescID) >= 0) {
if (!alarmFlag) {
workBlock.description = STRING(block[step].split(segments.meetingDescID)[1]).collapseWhitespace().s;
}
}
if (blockStep.indexOf(segments.uid) >= 0) {
if (!alarmFlag) {
workBlock.uid = STRING(block[step].split(segments.uid)[1]).collapseWhitespace().s;
}
}
if (blockStep.indexOf(segments.beginAlarm) >= 0) {
alarmFlag = true;
}
}
if (workBlock.dtstart !== null) {
workBlock.timeStart = workBlock.dtstart.format('{12hr}:{mm}:{ss} {tt}');
workBlock.cronStart = workBlock.dtstart.format('{m} {H} * * *');
// WorkBlock.combined = '<em>' + workBlock.timeStart + '</em> - ';
workBlock.combined = workBlock.timeStart + ' - ';
}
workBlock.combined = workBlock.combined + workBlock.summary;
if (workBlock.dtend !== null) {
workBlock.timeEnd = workBlock.dtend.format('{12hr}:{mm}:{ss} {tt}');
workBlock.cronStop = workBlock.dtend.format('{m} {H} * * *');
}
if (workBlock.dtstart !== null && workBlock.dtend !== null) {
var elapsedTime = new Elapsed(workBlock.dtstart, workBlock.dtend);
workBlock.duration = elapsedTime.optimal;
workBlock.combined = workBlock.combined + ', ' + elapsedTime.optimal;
}
return workBlock;
}
var lines = ical.split('\r\n'), l = lines.length, counter = 0;
while (counter < l) {
if (lines[counter].indexOf(segments.begin) < 0) {
counter++;
} else {
var subcounter = 0, subBlock = [];
while (subcounter < 75) {
if (lines[counter + subcounter].indexOf(segments.end) < 0) {
subBlock.push(lines[counter + subcounter]);
subcounter++;
} else {
break;
}
}
counter = counter + subcounter;
workingBlock.push(processBlock(subBlock));
}
}
logger.info(workingBlock.length);
logger.info('- processICAL');
return workingBlock;
}
calendarInterface.prototype.getTodaysMeetings = function() {
'use strict';
logger.info('+ getTodaysMeetings');
var today = {
previous: [], upcoming: [], current: {}
};
var now = new Date();
var jBlock = this.getJson();
logger.debug(jBlock.length);
for (var t = 0; t < jBlock.length; t++) {
if (jBlock[t].dtstart.isToday()) {
if (now.isBetween(jBlock[t].dtstart, jBlock[t].dtend)) {
today.current = jBlock[t];
}
if (jBlock[t].dtstart.isAfter(now)) {
today.upcoming.push(jBlock[t]);
} else {
if (Object.keys(today.current).length > 0) {
if (today.current.uid !== jBlock[t].uid) {
today.previous.push(jBlock[t]);
}
} else {
today.previous.push(jBlock[t]);
}
}
}
}
// Logger.debug(today);
logger.info('- getTodaysMeetings');
return today;
};
calendarInterface.prototype.getCachedStatus = function() {
'use strict';
return this.cachedStatus;
};
calendarInterface.prototype.getRoomStatusV2 = function(cb) {
'use strict';
var self = this;
// Var calJson = [];
request('http://crmplace.com/censis/ical_server.php?type=ics&key=largemeetingroom&email=largemeetingroom@censis.org.uk', function(err, res, body) {
if (err) {
logger.error('Get remote Calendar Request failed');
// Callback.call(null, new Error('Request failed'));
return;
}
//Self.jsonBlock = processICAL(body);
self.setJson(processICAL(body));
// Self.getTodaysMeetings();
var processedList = self.getTodaysMeetings();
self.cachedStatus = clone(processedList);
//Self.cachedStatus = processedList;
if (typeof cb === 'function') {
cb(processedList);
}
});
};
calendarInterface.prototype.getRoomStatus = function() {
var timeAndDate = new t.getTimeAndDate;
request('http://crmplace.com/censis/ical_server.php?type=ics&key=largemeetingroom&email=largemeetingroom@censis.org.uk', function(err, res, body) {
if (err) {
callback.call(null, new Error('Request failed'));
return;
}
var $ = cheerio.load(body);
var text = $('#element').text();
meetingInfo = $.html();
//Find today's date and time and convert to meeting info format
//getTimeNow.getTimeAndDate();
//console.log(TimeAndDate.time);
//console.log(TimeAndDate.date);
timeNow = timeAndDate.time;
dateToday = timeAndDate.date;
//Define meeting start and end identifying string
var meetingStartID = 'DTSTART;TZID=Europe/London:';
var meetingEndID = 'DTEND;TZID=Europe/London:';
var meetingDescID = 'DESCRIPTION:';
//Look for meetings taking place today
var meetingStart = new Array;
var meetingEnd = new Array;
var meetingDesc = new Array;
// Break up the file into lines.
var lines = meetingInfo.split('\n');
//Console.log(lines);
var meetingNum = 0;
for (i = 0; i < lines.length; i++) {
var n = lines[i].indexOf(meetingStartID);
if (n == -1) {
} else {
var meetingStartStr = lines[i];
var meetingDate = meetingStartStr.substring(meetingStartID.length, meetingStartID.length + 8);
if (meetingDate == dateToday.toString()) {
meetingStart[meetingNum] = lines[i];
meetingEnd[meetingNum] = lines[i + 1];
meetingDesc[meetingNum] = lines[i + 3];
meetingNum += 1;
}
}
}
if (meetingNum == 0) {
console.log('There are no meetings scheduled for today.')
} else {
console.log('Number of meetings today: ' + meetingNum);
//If timeNow is meetingStart, projectorStatus = ON
//if timeNow is within meeting, projectorStatus = ON
//if timeNow is meetingEnd, projectorStatus = OFF
var projectorStatus = 0;
//Is there a meeting on now
for (m = 0; m < meetingStart.length; m++) {
if (parseInt(timeNow) == parseInt(meetingStart[m].substring(36, 40))) {
var currentMeeting = m;
} else if ((parseInt(timeNow) <= parseInt(meetingEnd[m].substring(34, 38))) && (parseInt(timeNow) > parseInt(meetingStart[m].substring(36, 40)))) {
var currentMeeting = m;
} else {
var currentMeeting = 'None';
}
}
//If there is a meeting on now, define projector status
if (currentMeeting == 'None') {
console.log('Time now: ' + timeNow);
console.log('No meeting just now.');
} else {
console.log('Current meeting is: ' + meetingDesc[currentMeeting].substring(12, meetingDesc[currentMeeting].length));
if (parseInt(timeNow) == parseInt(meetingStart[currentMeeting].substring(36, 40))) {
return meetingStates.STARTING;
} else if ((parseInt(timeNow) <= parseInt(meetingEnd[currentMeeting].substring(34, 38))) && (parseInt(timeNow) > parseInt(meetingStart[currentMeeting].substring(36, 40)))) {
return meetingStates.INPROGRESS;
} else if (parseInt(timeNow) > parseInt(meetingEnd[currentMeeting].substring(34, 38))) {
return meetingStates.NONE;
}
console.log('Time now: ' + timeNow);
console.log('Meeting start time: ' + meetingStart[currentMeeting].substring(36, 40));
console.log('Meeting end time: ' + meetingEnd[currentMeeting].substring(34, 38));
console.log('Projector Status: ' + projectorStatus);
console.log('');
//Return projectorStatus;
//module.exports.pStatus = projectorStatus;
}
}
});
};
module.exports.calendarInterface = calendarInterface;

View File

@ -0,0 +1,66 @@
function getTimeAndDate() {
//Define today's date in meetingInfo format
// Get the timestamp in the UTC timezone
var now = new Date();
var utc_timestamp = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(),
now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(),
now.getUTCSeconds(), now.getUTCMilliseconds());
//Define today's date in string format [year month date]
//convert year to string
var year = now.getUTCFullYear();
var yearStr = year.toString();
//convert month to string
var month = now.getUTCMonth();
if (month < 9) {
month += 1;
monthStr = ["0" + month.toString()];
} else {
month += 1;
monthStr = month.toString();
};
//convert date to string
var date = now.getUTCDate();
if (date < 10) {
dateStr = ["0" + date.toString()];
} else {
dateStr = date.toString();
};
//Get UTC hours, minutes
var hours = now.getUTCHours() + 1;
if (hours == 0) {
var hoursStr = ["00"];
} else if (hours < 10){
var hoursStr = ["0" + hours.toString()]
} else {
var hoursStr = hours.toString();
}
var mins = now.getUTCMinutes();
if (mins == 0) {
var minsStr = ["00"];
} else if (mins < 10){
var minsStr = ["0" + mins.toString()]
} else {
var minsStr = mins.toString();
}
//dateToday, timeNow
var dateToday = [yearStr + monthStr + dateStr];
var timeNow = [hoursStr + minsStr];
this.date = dateToday;
this.time = timeNow;
};
module.exports.getTimeAndDate = getTimeAndDate; //public function
/*
var timeNow = new getTimeAndDate();
console.log(timeNow.time);
console.log(timeNow.date); */

View File

@ -0,0 +1,252 @@
'use strict';
var calendar = require('./calendarInterface');
var mqttClient = require('../mqtt/mqttClient');
var cron = require('node-cron');
var log4js = require('log4js');
var logger = log4js.getLogger();
var events = require('events');
var eventBus ;
var util = require('util');
var officeController = function(neweventbus) {
logger.debug((typeof neweventbus));
if ((typeof neweventbus !== 'undefined') && (neweventbus !== null)) {
logger.warn('Using passed eventBus');
eventBus = neweventbus;
} else {
logger.warn('Using internal eventBus');
eventBus = new events();
}
console.log('~~~ officeController');
this.cloneObject = function(from, to) {
if (Object.keys(from).length !== 0) {
for (var key in from) {
if (from.hasOwnProperty(key)) {
if (key !== 'cronJOBS') {
to[key] = from[key];
}
}
}
}
};
var self = this;
this.schedule = {};
this.todaysList = {};
this.calendarControl = new calendar.calendarInterface();
this.calendarControl.getRoomStatusV2((todaysList) => {
this.todaysList = todaysList;
/*This.todaysList = {};
this.cloneObject(todaysList, this.todaysList);
logger.debug(this.todaysList);*/
this.setupNextMeeting(todaysList);
});
this.mqtt = new mqttClient.mqttClient();
//This.timer;
// this.meetings = {cronjobs:{start:null.stop:null}};
this.task = cron.schedule('* * * * *', function() {
var n = new Date();
logger.debug('tick: ' + n);
logger.info('looped Schedule count: ' + Object.keys(this.schedule).length);
var curMeeting = {};
this.cloneObject(this.todaysList.current, curMeeting);
curMeeting.cronJobs = {};
eventBus.emit('sendSocket', {id:'calendar',current:curMeeting});
}.bind(this));
this.task = cron.schedule('*/5 * * * *', function() {
this.calendarControl.getRoomStatusV2((todaysList) => {
this.todaysList = todaysList;
this.setupNextMeeting(todaysList);
var data = todaysList;
data.id = 'calendarData';
eventBus.emit('sendSocket', data);
});
}.bind(this));
eventBus.on('setupNextMeeting', this.setupNextMeeting.bind(this, this.todaysList));
eventBus.on('cleanUp', (id) => {
logger.debug('+ => cleanUp');
this.cleanUpMeeting(id);
});
};
officeController.prototype.cleanUpMeeting = function(id) {
logger.debug('deleting scheduled item: ' + id);
logger.info('Pre delete Schedule count: ' + Object.keys(this.schedule).length);
delete this.schedule[id];
logger.info('post delete Schedule count: ' + Object.keys(this.schedule).length);
};
officeController.prototype.createMeeting = function(obj,delayStart) {
// Logger.debug(util.inspect(this));
var newMeeting = obj, _delayStart = delayStart || false, cronStartStr;
var now = new Date.create();
var self = this;
// Logger.debug(newMeeting);
newMeeting.cronJOBS = {start: null, stop: null};
if (_delayStart) {
cronStartStr = now.addSeconds(15).format('{s} {m} {H} * * *');
} else {
cronStartStr = newMeeting.cronStart;
}
newMeeting.cronJOBS.start = cron.schedule(cronStartStr, function() {
var n = new Date();
logger.debug('MEETING STARTED!!!!' , n);
var key = Object.keys(self.schedule)[0];
var curMeeting = {};
self.cloneObject(self.schedule[key], curMeeting);
curMeeting.cronJOBS = null;
eventBus.emit('sendSocket', {id:'calendar',current:curMeeting});
}, true);
newMeeting.cronJOBS.stop = cron.schedule(newMeeting.cronStop, function() {
var n = new Date();
logger.debug('MEETING ENDED' + n);
newMeeting.cronJOBS.start = null;
newMeeting.cronJOBS.stop = null;
logger.debug(newMeeting.cronJOBS);
eventBus.emit('cleanUp',newMeeting.uid);
}.bind(this), true);
this.schedule[newMeeting.uid] = newMeeting;
};
officeController.prototype.setupNextMeeting = function(calData) {
logger.debug('Setup next meeting...');
var self = this;
var now = new Date.create();
if (Object.keys(calData.current).length > 0) {
if (this.schedule.hasOwnProperty(calData.current.uid)) {
logger.debug('Current Meeting exists in schedule');
} else {
logger.debug('Current Meeting does NOT exist in schedule');
this.createMeeting(calData.current, true);
}
}
if (calData.upcoming.length > 0) {
for (var uCount = 0; uCount < calData.upcoming.length; uCount++) {
var uEntry = calData.upcoming[uCount];
if (this.schedule.hasOwnProperty(uEntry.uid)) {
logger.debug('Upcoming Meeting exists in schedule');
// Lets check to see if it's changed in anyway..
var origEntry, origStart, origEnd, newStart, newEnd;
origEntry = this.schedule[uEntry.uid];
origStart = Date.create(origEntry.dtstart);
origEnd = Date.create(origEntry.dtend);
newStart = Date.create(uEntry.dtstart);
newEnd = Date.create(uEntry.dtend);
if ((origStart.getTime() != newStart.getTime()) || (origEnd.getTime() != newEnd.getTime())) {
logger.error('WE HAVE A CHANGED ENTRY!!');
origEntry.cronJOBS.start.destroy();
origEntry.cronJOBS.stop.destroy();
origEntry = uEntry;
this.createMeeting(origEntry);
}
} else {
logger.debug('Upcoming meeting does NOT exist in schedule');
var newMeeting = uEntry;
this.createMeeting(newMeeting);
}
}
}
// Logger.info(this.schedule);
};
officeController.prototype.startController = function(eventBus) {
console.log('Starting.');
getRoomStatus();
this.timer = setInterval(function() { getRoomStatus() }, 300000);
};
officeController.prototype.stopController = function() {
console.log('Stopping.');
clearInterval(this.timer);
};
officeController.prototype.returnCalendar = function() {
var exportList;
exportList = this.calendarControl.getCachedStatus();
logger.debug(exportList);
return exportList;
};
//OfficeController.prototype.getRoomStatus = function () {
// this.calendarControl.getRoomStatus();
// console.log('Checking Calendar.');
//};
var meetingStates = {
STARTING: 0,
INPROGRESS: 1,
NONE: 2,
FINISHED: 3
};
function getRoomStatus() {
return;
// Var calendarControl = new calendar.calendarInterface();
// var status = calendarControl.getRoomStatusV2();
var status = officeController.calendarControl.getRoomStatusV2();
if (status == meetingStates.STARTING) {
console.log('Meeting about to start - turning on.');
this.mqtt.projectorOn();
this.mqtt.lightsOn();
}
if (status == meetingStates.INPROGRESS) {
console.log('Meeting in progress - do nothing.');
}
if (status == meetingStates.NONE) {
console.log('No meeting - do nothing.');
}
if (status == meetingStates.FINISHED) {
console.log('No meeting - do nothing.');
this.mqtt.projectorOff();
this.mqtt.lightsOff();
}
}
module.exports.officeController = officeController;

3
lib/office/scheduler.js Normal file
View File

@ -0,0 +1,3 @@
/**
* Created by Martin on 26/02/2016.
*/

View File

@ -25,12 +25,36 @@
},
"devDependencies": {
"after": "^0.8.1",
"basic-authentication": "^1.6.2",
"chai": "^3.5.0",
"cheerio": "^0.20.0",
"clone": "^1.0.2",
"del": "^2.2.0",
"elapsed": "0.0.7",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.0",
"gulp-cache": "^0.4.2",
"gulp-concat": "^2.6.0",
"gulp-cssnano": "^2.1.1",
"gulp-html-replace": "^1.5.5",
"gulp-htmlmin": "^1.3.0",
"gulp-inject": "^4.0.0",
"gulp-jshint": "^2.0.0",
"gulp-jsmin": "^0.1.5",
"gulp-livereload": "^3.8.1",
"gulp-notify": "^2.2.0",
"gulp-rename": "^1.2.2",
"gulp-uglify": "^1.5.3",
"jshint": "^2.9.1",
"log4js": "^0.6.31",
"jsonfile": "^2.3.0",
"log4js": "^0.6.35",
"mocha": "^2.4.5",
"mqtt-ws": "^0.2.0",
"node-cron": "^1.1.1",
"require-dir": "^0.3.0",
"should": "^8.2.2",
"string": "^3.3.1",
"sugar-date": "^1.5.1",
"superagent": "^1.7.2",
"supertest": "^1.1.0"
},
@ -38,5 +62,9 @@
"test": "mocha --recursive --reporter spec --bail --check-leaks --timeout 3000"
},
"author": "Martin Donnelly",
"license": "ISC"
"license": "ISC",
"repository": {
"type": "git",
"url": "git+http://gitlab.silvrtree.co.uk/martind2000/SODashServer.git"
}
}

7
routes/api.v1.js Normal file
View File

@ -0,0 +1,7 @@
/**
*
* User: Martin Donnelly
* Date: 2016-04-18
* Time: 10:28
*
*/