App work
32
.editorconfig
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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"></i>
|
||||
|
||||
|
||||
bulb : lightbulb_outline
|
||||
<i class="material-icons"></i>
|
||||
|
||||
calendar: event_note
|
||||
<i class="material-icons"></i>
|
||||
|
||||
projector: cast
|
||||
<i class="material-icons"></i>
|
||||
|
||||
*/
|
15
app/css/material-icons.css
Normal 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;
|
||||
}
|
3008
app/css/mui.css
2
app/css/mui.min.css
vendored
BIN
app/fav/android-chrome-144x144.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/fav/android-chrome-192x192.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
app/fav/android-chrome-36x36.png
Normal file
After Width: | Height: | Size: 611 B |
BIN
app/fav/android-chrome-48x48.png
Normal file
After Width: | Height: | Size: 767 B |
BIN
app/fav/android-chrome-72x72.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
app/fav/android-chrome-96x96.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/fav/apple-touch-icon-114x114.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/fav/apple-touch-icon-120x120.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/fav/apple-touch-icon-144x144.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/fav/apple-touch-icon-152x152.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/fav/apple-touch-icon-180x180.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
app/fav/apple-touch-icon-57x57.png
Normal file
After Width: | Height: | Size: 875 B |
BIN
app/fav/apple-touch-icon-60x60.png
Normal file
After Width: | Height: | Size: 924 B |
BIN
app/fav/apple-touch-icon-72x72.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
app/fav/apple-touch-icon-76x76.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/fav/apple-touch-icon-precomposed.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
app/fav/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
12
app/fav/browserconfig.xml
Normal 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
After Width: | Height: | Size: 401 B |
BIN
app/fav/favicon-32x32.png
Normal file
After Width: | Height: | Size: 564 B |
BIN
app/fav/favicon-96x96.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/fav/favicon.ico
Normal file
After Width: | Height: | Size: 7.2 KiB |
43
app/fav/manifest.json
Normal 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
After Width: | Height: | Size: 1.9 KiB |
BIN
app/fav/mstile-150x150.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/fav/mstile-310x150.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/fav/mstile-310x310.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
app/fav/mstile-70x70.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
46
app/fav/safari-pinned-tab.svg
Normal 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
After Width: | Height: | Size: 894 B |
BIN
app/gfx/icons/Cellular Network.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
app/gfx/icons/Chance of Storm.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Clock.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Cloud Lighting.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Cloud.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
app/gfx/icons/Coffee Maker.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/gfx/icons/Downpour.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/gfx/icons/Electric Teapot.png
Normal file
After Width: | Height: | Size: 1015 B |
BIN
app/gfx/icons/Fan.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/gfx/icons/Fog Day.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/gfx/icons/Fog Night.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
app/gfx/icons/Full Moon.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/Hail.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
app/gfx/icons/Heavy Rain.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Icy.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/gfx/icons/Idea.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Intense Rain.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Light Automation.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/gfx/icons/Light Off.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/Light Rain 2.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Light Rain.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Light Snow.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
app/gfx/icons/Lightning Bolt.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
app/gfx/icons/Moderate Rain.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/No Rain.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Partly Cloudy Day.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/Partly Cloudy Night.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Partly Cloudy Rain.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Rain.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Sleet.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
app/gfx/icons/Snow Storm.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/Snow.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
app/gfx/icons/Storm.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/gfx/icons/Sun.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/gfx/icons/TV On.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
app/gfx/icons/Temperature Outside.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
app/gfx/icons/Thermometer Automation.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/Torrential Rain.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
app/gfx/icons/Wet.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
app/gfx/icons/Winter.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
app/gfx/icons/air-conditioner.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/gfx/icons/av-receiver.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/gfx/icons/bright-moon.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
app/gfx/icons/globe-bulb.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
app/gfx/icons/video-projector.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
389
app/index.html
@ -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"></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"></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"></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"></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"></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"></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">---</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>
|
||||
<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>
|
||||
</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
@ -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) + '°c ');
|
||||
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
9842
app/lib/jquery.js
vendored
Normal file
55
app/lib/microevent.js
Normal 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
730
app/lib/skycons.js
Normal 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
3
fonts.list
Normal file
@ -0,0 +1,3 @@
|
||||
Ubuntu:300,400,500,700
|
||||
Ubuntu+Condensed
|
||||
Material+Icons
|
124
gulpfile.js
@ -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');
|
||||
});
|
||||
|
322
lib/office/calendarInterface.js
Normal 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;
|
66
lib/office/getTimeAndDate.js
Normal 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); */
|
252
lib/office/officeController.js
Normal 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
@ -0,0 +1,3 @@
|
||||
/**
|
||||
* Created by Martin on 26/02/2016.
|
||||
*/
|
32
package.json
@ -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
@ -0,0 +1,7 @@
|
||||
/**
|
||||
*
|
||||
* User: Martin Donnelly
|
||||
* Date: 2016-04-18
|
||||
* Time: 10:28
|
||||
*
|
||||
*/
|