Added mqtt and the first recipe
This commit is contained in:
parent
071384201b
commit
cdd55ccc18
55
.eslintrc
Normal file
55
.eslintrc
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 6,
|
||||||
|
"sourceType": "module",
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"jsx": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"node": true,
|
||||||
|
"es6": true
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"arrow-spacing": "error",
|
||||||
|
"block-scoped-var": "error",
|
||||||
|
"block-spacing": "error",
|
||||||
|
"brace-style": ["error", "stroustrup", {}],
|
||||||
|
"camelcase": "error",
|
||||||
|
"comma-dangle": ["error", "never"],
|
||||||
|
"comma-spacing": ["error", { "before": false, "after": true }],
|
||||||
|
"comma-style": [1, "last"],
|
||||||
|
"consistent-this": [1, "_this"],
|
||||||
|
"curly": [1, "multi"],
|
||||||
|
"eol-last": 1,
|
||||||
|
"eqeqeq": 1,
|
||||||
|
"func-names": 1,
|
||||||
|
"indent": ["error", 2, { "SwitchCase": 1 }],
|
||||||
|
"lines-around-comment": ["error", { "beforeBlockComment": true, "allowArrayStart": true }],
|
||||||
|
"max-len": [1, 240, 2], // 2 spaces per tab, max 80 chars per line
|
||||||
|
"new-cap": 1,
|
||||||
|
"newline-before-return": "error",
|
||||||
|
"no-array-constructor": 1,
|
||||||
|
"no-inner-declarations": [1, "both"],
|
||||||
|
"no-mixed-spaces-and-tabs": 1,
|
||||||
|
"no-multi-spaces": 2,
|
||||||
|
"no-new-object": 1,
|
||||||
|
"no-shadow-restricted-names": 1,
|
||||||
|
"object-curly-spacing": ["error", "always"],
|
||||||
|
"padded-blocks": ["error", { "blocks": "never", "switches": "always" }],
|
||||||
|
"prefer-const": "error",
|
||||||
|
"prefer-template": "error",
|
||||||
|
"one-var": 0,
|
||||||
|
"quote-props": ["error", "always"],
|
||||||
|
"quotes": [1, "single"],
|
||||||
|
"radix": 1,
|
||||||
|
"semi": [1, "always"],
|
||||||
|
"space-before-blocks": [1, "always"],
|
||||||
|
"space-infix-ops": 1,
|
||||||
|
"vars-on-top": 1,
|
||||||
|
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1 }],
|
||||||
|
"spaced-comment": ["error", "always", { "markers": ["/"] }]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -178,3 +178,5 @@ xcuserdata
|
|||||||
*.xcuserstate
|
*.xcuserstate
|
||||||
|
|
||||||
dist
|
dist
|
||||||
|
/jspm_packages/npm/
|
||||||
|
/jspm_packages/github/
|
||||||
|
276
app/css/app.css
Normal file
276
app/css/app.css
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
body {
|
||||||
|
font-family: Ubuntu, "Helvetica Neue", Helvetica, arial, sans-serif;
|
||||||
|
background-color: #004c6d;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#weatherIcon {
|
||||||
|
margin-left:25%;
|
||||||
|
margin-right:25%;
|
||||||
|
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>
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
.md-display {
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity 0.3s, visibility 0.3s;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.lostConnection {
|
||||||
|
opacity: 0.5;
|
||||||
|
transition: opacity 0.3s, visibility 0.3s;
|
||||||
|
}
|
15
app/css/material-icons.css
Normal file
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;
|
||||||
|
}
|
1912
app/css/mui.css
Normal file
1912
app/css/mui.css
Normal file
File diff suppressed because it is too large
Load Diff
1912
app/css/mui.custom.css
Normal file
1912
app/css/mui.custom.css
Normal file
File diff suppressed because it is too large
Load Diff
1
app/css/mui.min.css
vendored
Normal file
1
app/css/mui.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
321
app/index.html
Normal file
321
app/index.html
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<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.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 class="mui--no-user-select">
|
||||||
|
<div id="iosTaskbar" style="height:25px;display:none;"></div>
|
||||||
|
<div class="mui-container">
|
||||||
|
<div class="mui-panel" style="display: ;">
|
||||||
|
<div class="mui-row mui--text-center">
|
||||||
|
<img src="gfx/censis_logo_white.png">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</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" id="noDevice" style="display: none;">
|
||||||
|
<div class="mui-row">
|
||||||
|
<div
|
||||||
|
class="mui--text-body2 mui--text-center noConnection">We are having problems connecting to one or more of the devices. Please restart them and wait for them to reconnect.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</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" id="extender" style="display: none;">
|
||||||
|
<div class="mui-row">
|
||||||
|
<div class="mui-col-xs-12 mui--text-center">
|
||||||
|
<div class="mui--text-title ">
|
||||||
|
Extend meeting
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mui-row">
|
||||||
|
<div class="mui-col-xs-12 mui--text-center">
|
||||||
|
<button id="extend05" class="mui-btn mui-btn--fab">5</button>
|
||||||
|
<button id="extend10" class="mui-btn mui-btn--fab">10</button>
|
||||||
|
<button id="extend15" class="mui-btn mui-btn--fab">15</button>
|
||||||
|
<button id="extend30" class="mui-btn mui-btn--fab">30</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<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">
|
||||||
|
<div id="caltext"></div>
|
||||||
|
<div id="extendInfo" class="mui--text-subhead mui--text-accent"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="front-light" class="md-display">
|
||||||
|
<div class="mui-panel">
|
||||||
|
<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 lightOn">On
|
||||||
|
</button>
|
||||||
|
<button id="frontLightOff" class="mui-btn mui-btn--danger lightOff"
|
||||||
|
style="display: none;">Off
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mui-col-xs-4 mui--text-center" id="auxFront"
|
||||||
|
style="display:none;">
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent lightUp"
|
||||||
|
id="frontUp">BRIGHTER
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent lightDown"
|
||||||
|
id="frontDown">DARKER
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</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--text-title mui--text-center"><a class='title'
|
||||||
|
href="#">Middle light</a>
|
||||||
|
</div>
|
||||||
|
</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 lightOn">On
|
||||||
|
</button>
|
||||||
|
<button id="backLightOff" class="mui-btn mui-btn--danger lightOff"
|
||||||
|
style="display: none;">Off
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mui-col-xs-4 mui--text-center" id="auxBack"
|
||||||
|
style="display: none;">
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent lightUp"
|
||||||
|
id="backUp">BRIGHTER
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent lightDown"
|
||||||
|
id="backDown">DARKER
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mui-panel" id="heating-panel" style="display: none ;">
|
||||||
|
<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" style="display:;">
|
||||||
|
<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 class="mui-col-xs-4 mui--text-center" id="auxProjector"
|
||||||
|
style="display:none;">
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent"
|
||||||
|
id="projectorHDMI">HDMI
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent"
|
||||||
|
id="projectorVGA">VGA
|
||||||
|
</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>
|
||||||
|
<!--<script src="cordova.js"></script>-->
|
||||||
|
<!-- build:vendor -->
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/systemjs/0.20.19/system.js"></script>
|
||||||
|
<script src="lib/mui.js"></script>
|
||||||
|
<script src="lib/jquery.js"></script>
|
||||||
|
<!--<script src="lib/chroma.js"></script>-->
|
||||||
|
|
||||||
|
<script src="lib/underscore.js"></script>
|
||||||
|
<script src="lib/backbone.js"></script>
|
||||||
|
<script src="lib/sugar-date.js"></script>
|
||||||
|
<!--<script src="lib/sugar.js"></script>-->
|
||||||
|
<!--<script src="lib/skycons.js"></script>-->
|
||||||
|
<!--<script src="lib/microevent.js"></script>-->
|
||||||
|
<!-- endbuild -->
|
||||||
|
<!-- build:js -->
|
||||||
|
<!--
|
||||||
|
<script src="js/sowebsocket.js"></script>
|
||||||
|
<script src="js/colours.js"></script>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script src="js/modules/clock.js"></script>
|
||||||
|
<!--
|
||||||
|
<script src="js/parts/meetings.js"></script>
|
||||||
|
<script src="js/parts/lights.js"></script>
|
||||||
|
<script src="js/parts/projector.js"></script>
|
||||||
|
-->
|
||||||
|
<script src="js/app.js"></script>
|
||||||
|
</body>
|
||||||
|
<!-- endbuild -->
|
||||||
|
</html>
|
2
app/js/app.js
Normal file
2
app/js/app.js
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
|
||||||
|
this.clock = new Clock({ 'model': new ClockModel() });
|
122
app/js/modules/clock.js
Normal file
122
app/js/modules/clock.js
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* User: Martin Donnelly
|
||||||
|
* Date: 2016-07-27
|
||||||
|
* Time: 09:23
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
const WeatherModel = Backbone.Model.extend({
|
||||||
|
'initialize': function() {
|
||||||
|
this.set('url', `https://api.forecast.io/forecast/0657dc0d81c037cbc89ca88e383b6bbf/${ this.get('lat').toString() },${ this.get('long').toString() }?units=uk2&exclude=minutely,hourly,daily,alerts,flags`);
|
||||||
|
|
||||||
|
console.log(this.get('url'));
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
'update': function() {
|
||||||
|
this.getWeather();
|
||||||
|
const now = new Date;
|
||||||
|
const mod = 1800000 - (now.getTime() % 1800000);
|
||||||
|
const weatherTrigger = function () {
|
||||||
|
this.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
setTimeout(weatherTrigger.bind(this), mod + 10);
|
||||||
|
},
|
||||||
|
'getWeather': function() {
|
||||||
|
const self = this;
|
||||||
|
$.ajax({
|
||||||
|
'type': 'GET',
|
||||||
|
'url': self.get('url'),
|
||||||
|
'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) {
|
||||||
|
const stored = {
|
||||||
|
'temperature': data.currently.temperature,
|
||||||
|
'icon': data.currently.icon
|
||||||
|
};
|
||||||
|
self.set('data', stored);
|
||||||
|
},
|
||||||
|
'error': function(xhr, type) {
|
||||||
|
console.error('ajax error');
|
||||||
|
console.error(xhr);
|
||||||
|
console.error(type);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ClockModel = Backbone.Model.extend({
|
||||||
|
'initialize': function() {
|
||||||
|
const now = new Sugar.Date();
|
||||||
|
this.set('now', now);
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
'update': function() {
|
||||||
|
const now = new Sugar.Date();
|
||||||
|
const mod = 60000 - (now.getTime().raw % 60000);
|
||||||
|
this.set('now', now);
|
||||||
|
|
||||||
|
const clockFn = function () {
|
||||||
|
this.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
setTimeout(clockFn.bind(this), mod + 10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Clock = Backbone.View.extend({
|
||||||
|
'tagName': 'div',
|
||||||
|
'initialize': function() {
|
||||||
|
_.bindAll(this, 'render');
|
||||||
|
this.model.bind('change', this.render);
|
||||||
|
this.$date = $('#date');
|
||||||
|
this.$time = $('#time');
|
||||||
|
this.render();
|
||||||
|
},
|
||||||
|
'render': function() {
|
||||||
|
const now = this.model.get('now');
|
||||||
|
console.log('now', now);
|
||||||
|
const curTime = now.format('<span class="hour">{24hr}</span>{mm}').raw;
|
||||||
|
const curDate = now.format('{yyyy}-{MM}-{dd}').raw;
|
||||||
|
console.log('curTime', curTime);
|
||||||
|
console.log('curDate', curDate);
|
||||||
|
if (this.prevTime !== curTime) {
|
||||||
|
this.$time.html(curTime);
|
||||||
|
this.prevTime = curTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.prevDate !== curDate) {
|
||||||
|
this.$date.html(now.format(
|
||||||
|
'<span class="wd-{do}">{Weekday}</span><br><span class="mo mo-{M}">{Month} {dd}</span><br>{yyyy}'));
|
||||||
|
this.prevDate = curDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Weather = Backbone.View.extend({
|
||||||
|
'tagName': 'div',
|
||||||
|
'initialize': function() {
|
||||||
|
_.bindAll(this, 'render');
|
||||||
|
this.model.bind('change', this.render);
|
||||||
|
this.$weatherText = $('#weatherText');
|
||||||
|
},
|
||||||
|
'render': function() {
|
||||||
|
console.log('Weather:Render');
|
||||||
|
const data = this.model.get('data');
|
||||||
|
this.$weatherText.html(`${parseInt(data.temperature) }°c `);
|
||||||
|
skycons.remove('icon1');
|
||||||
|
skycons.add('icon1', data.icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
1920
app/lib/backbone.js
Normal file
1920
app/lib/backbone.js
Normal file
File diff suppressed because it is too large
Load Diff
10253
app/lib/jquery.js
vendored
Normal file
10253
app/lib/jquery.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2118
app/lib/mui.js
Normal file
2118
app/lib/mui.js
Normal file
File diff suppressed because it is too large
Load Diff
730
app/lib/skycons.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));
|
6615
app/lib/sugar-date.js
Normal file
6615
app/lib/sugar-date.js
Normal file
File diff suppressed because it is too large
Load Diff
13407
app/lib/sugar.js
Normal file
13407
app/lib/sugar.js
Normal file
File diff suppressed because it is too large
Load Diff
5
app/lib/system.min.js
vendored
Normal file
5
app/lib/system.min.js
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
// system.js - http://github.com/mrdoob/system.js
|
||||||
|
'use strict';var System={browser:function(){var a=navigator.userAgent;return/Arora/i.test(a)?"Arora":/Opera|OPR/.test(a)?"Opera":/Maxthon/i.test(a)?"Maxthon":/Vivaldi/i.test(a)?"Vivaldi":/YaBrowser/i.test(a)?"Yandex":/Chrome/i.test(a)?"Chrome":/Epiphany/i.test(a)?"Epiphany":/Firefox/i.test(a)?"Firefox":/Mobile(\/.*)? Safari/i.test(a)?"Mobile Safari":/MSIE/i.test(a)?"Internet Explorer":/Midori/i.test(a)?"Midori":/Safari/i.test(a)?"Safari":!1}(),os:function(){var a=navigator.userAgent;return/Android/i.test(a)?
|
||||||
|
"Android":/CrOS/i.test(a)?"Chrome OS":/iP[ao]d|iPhone/i.test(a)?"iOS":/Linux/i.test(a)?"Linux":/Mac OS/i.test(a)?"Mac OS":/windows/i.test(a)?"Windows":!1}(),support:{canvas:!!window.CanvasRenderingContext2D,localStorage:function(){try{return!!window.localStorage.getItem}catch(a){return!1}}(),file:!!window.File&&!!window.FileReader&&!!window.FileList&&!!window.Blob,fileSystem:!!window.requestFileSystem||!!window.webkitRequestFileSystem,getUserMedia:!!window.navigator.getUserMedia||!!window.navigator.webkitGetUserMedia||
|
||||||
|
!!window.navigator.mozGetUserMedia||!!window.navigator.msGetUserMedia,requestAnimationFrame:!!window.mozRequestAnimationFrame||!!window.webkitRequestAnimationFrame||!!window.oRequestAnimationFrame||!!window.msRequestAnimationFrame,sessionStorage:function(){try{return!!window.sessionStorage.getItem}catch(a){return!1}}(),svg:function(){try{return!!document.createElementNS&&!!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect}catch(a){return!1}}(),webgl:function(){try{return!!window.WebGLRenderingContext&&
|
||||||
|
!!document.createElement("canvas").getContext("experimental-webgl")}catch(a){return!1}}(),worker:!!window.Worker}};
|
1548
app/lib/underscore.js
Normal file
1548
app/lib/underscore.js
Normal file
File diff suppressed because it is too large
Load Diff
17
app/test.html
Normal file
17
app/test.html
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Title</title>
|
||||||
|
<script src="jspm_packages/system.js"></script>
|
||||||
|
<script src="config.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
SystemJS.import('js/app.js');
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
70
lib/aida.js
Normal file
70
lib/aida.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
const em = require('events').EventEmitter;
|
||||||
|
const util = require('util');
|
||||||
|
const logger = require('log4js').getLogger('Aida');
|
||||||
|
const _ = require('lodash');
|
||||||
|
const Lights = require('./light-controller');
|
||||||
|
const Wemo = require('./wemo-controller');
|
||||||
|
const HS100 = require('./hs100-controller');
|
||||||
|
const Hive = require('./hive-controller');
|
||||||
|
const MqttController = require('./mqtt-controller');
|
||||||
|
const { BedroomRecipe } = require('./recipes');
|
||||||
|
|
||||||
|
logger.level = 'debug';
|
||||||
|
|
||||||
|
const devices = {
|
||||||
|
'sensors': {},
|
||||||
|
'lights': {},
|
||||||
|
'wemo': {},
|
||||||
|
'heating': {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Aida = function() {
|
||||||
|
logger.debug('Aida!!');
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
this.on('newListener', function(listener) {
|
||||||
|
logger.debug(`Event Listener: ${ listener}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
};
|
||||||
|
|
||||||
|
util.inherits(Aida, em);
|
||||||
|
|
||||||
|
Aida.prototype.init = function() {
|
||||||
|
this.lights = new Lights();
|
||||||
|
this.wemo = new Wemo();
|
||||||
|
this.hs100 = new HS100();
|
||||||
|
// this.hive = new Hive();
|
||||||
|
this.mqtt = new MqttController();
|
||||||
|
|
||||||
|
this.lights.on('found', (d) => {
|
||||||
|
if (devices.lights[d.id] === undefined) {
|
||||||
|
logger.debug('Adding to light list');
|
||||||
|
devices.lights[d.id] = d;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.wemo.on('found', (d) => {
|
||||||
|
logger.debug('Found Wemo switch:', d.macAddress);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.hs100.on('found', (d) => {
|
||||||
|
logger.debug('Found hs100 switch:', d.deviceId);
|
||||||
|
});
|
||||||
|
|
||||||
|
/* this.hive.on('update', (d) => {
|
||||||
|
logger.debug('Heating updated');
|
||||||
|
devices.heating = d;
|
||||||
|
});*/
|
||||||
|
|
||||||
|
this.mqtt.on('found', () => {
|
||||||
|
logger.debug('MQTT found device');
|
||||||
|
});
|
||||||
|
|
||||||
|
// this.hive.update();
|
||||||
|
|
||||||
|
this.BedroomRecipe = new BedroomRecipe({ 'mqtt':this.mqtt, 'wemo':this.wemo });
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Aida;
|
61
lib/hive-controller.js
Normal file
61
lib/hive-controller.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
const Hive = require('bg-hive-api');
|
||||||
|
const ClimateControl = require('bg-hive-api/climateControl');
|
||||||
|
const em = require('events').EventEmitter;
|
||||||
|
const util = require('util');
|
||||||
|
const logger = require('log4js').getLogger('Hive');
|
||||||
|
logger.level = 'debug';
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
'login': 'martind2000@gmail.com',
|
||||||
|
'password': '1V3D4m526i'
|
||||||
|
};
|
||||||
|
const hive = new Hive(config.login, config.password);
|
||||||
|
|
||||||
|
const HiveController = function() {
|
||||||
|
const _this = this;
|
||||||
|
|
||||||
|
hive.on('login', function(context) {
|
||||||
|
logger.debug('Connected');
|
||||||
|
// hive.Logout();
|
||||||
|
|
||||||
|
const climate = new ClimateControl(context);
|
||||||
|
|
||||||
|
// Handle the on complete event.
|
||||||
|
climate.on('complete', function(response) {
|
||||||
|
// write the response state object to the console.
|
||||||
|
// console.log(response);
|
||||||
|
_this.emit('update', response);
|
||||||
|
// log out
|
||||||
|
hive.Logout();
|
||||||
|
});
|
||||||
|
|
||||||
|
climate.GetState();
|
||||||
|
});
|
||||||
|
|
||||||
|
// On logout call this event handler
|
||||||
|
hive.on('logout', () => {
|
||||||
|
logger.info('Connection Closed');
|
||||||
|
});
|
||||||
|
|
||||||
|
// On invalid username or password
|
||||||
|
hive.on('not_authorised', () => {
|
||||||
|
logger.error('Connection Refused');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Log in
|
||||||
|
|
||||||
|
this.on('newListener', listener => {
|
||||||
|
logger.info(`Event Listener: ${ listener}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
HiveController.prototype.update = function() {
|
||||||
|
hive.Login();
|
||||||
|
};
|
||||||
|
|
||||||
|
util.inherits(HiveController, em);
|
||||||
|
|
||||||
|
module.exports = HiveController;
|
39
lib/hs100-controller.js
Normal file
39
lib/hs100-controller.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
const Hs100Api = require('hs100-api');
|
||||||
|
const client = new Hs100Api.Client();
|
||||||
|
|
||||||
|
const em = require('events').EventEmitter;
|
||||||
|
const util = require('util');
|
||||||
|
const logger = require('log4js').getLogger('hs100');
|
||||||
|
logger.level = 'debug';
|
||||||
|
|
||||||
|
const Hs100Controller = function() {
|
||||||
|
const _this = this;
|
||||||
|
|
||||||
|
client.startDiscovery().on('device-new', (device) => {
|
||||||
|
device.getSysInfo().then((deviceInfo) => {
|
||||||
|
logger.debug(deviceInfo);
|
||||||
|
_this.emit('found', deviceInfo);
|
||||||
|
});
|
||||||
|
device.setPowerState(true);
|
||||||
|
device.startPolling(10000);
|
||||||
|
|
||||||
|
device.on('power-on', (d) => {
|
||||||
|
logger.debug('Power on', d);
|
||||||
|
});
|
||||||
|
|
||||||
|
device.on('power-off', (d) => {
|
||||||
|
logger.debug('Power off', d);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
this.on('newListener', listener => {
|
||||||
|
logger.info(`Event Listener: ${ listener}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
util.inherits(Hs100Controller, em);
|
||||||
|
|
||||||
|
module.exports = Hs100Controller;
|
77
lib/light-controller.js
Normal file
77
lib/light-controller.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
const LifxClient = require('node-lifx').Client;
|
||||||
|
const client = new LifxClient();
|
||||||
|
const em = require('events').EventEmitter;
|
||||||
|
const util = require('util');
|
||||||
|
const logger = require('log4js').getLogger('Lights');
|
||||||
|
logger.level = 'debug';
|
||||||
|
|
||||||
|
const LightController = function() {
|
||||||
|
const _this = this;
|
||||||
|
client.on('light-new', light => {
|
||||||
|
_this.emit('found', light);
|
||||||
|
logger.debug('New light found.');
|
||||||
|
logger.debug(`ID: ${ light.id}`);
|
||||||
|
logger.debug(`IP: ${ light.address }:${ light.port}`);
|
||||||
|
|
||||||
|
light.getState((err, info) => {
|
||||||
|
if (err)
|
||||||
|
logger.debug(err);
|
||||||
|
|
||||||
|
logger.debug(`Label: ${ info.label}`);
|
||||||
|
logger.debug('Power:', (info.power === 1) ? 'on' : 'off');
|
||||||
|
logger.debug('Color:', info.color);
|
||||||
|
logger.debug('info', info);
|
||||||
|
});
|
||||||
|
|
||||||
|
light.getHardwareVersion((err, info) => {
|
||||||
|
if (err)
|
||||||
|
logger.debug(err);
|
||||||
|
|
||||||
|
logger.debug(`Device Info: ${ info.vendorName } - ${ info.productName}`);
|
||||||
|
logger.debug('Features: ', info.productFeatures, '\n');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on('listening', () => {
|
||||||
|
const address = client.address();
|
||||||
|
logger.debug(
|
||||||
|
`Started LIFX listening on ${
|
||||||
|
address.address }:${ address.port }\n`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on('light-offline', light => {
|
||||||
|
logger.debug(`Light: ${light.id} has gone offline`);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on('light-online', light => {
|
||||||
|
logger.debug(`Light: ${light.id} has come online`);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on('message', msg => {
|
||||||
|
// logger.debug('>> msg', msg);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.init({
|
||||||
|
'lightOfflineTolerance': 3, // A light is offline if not seen for the given amount of discoveries
|
||||||
|
'messageHandlerTimeout': 45000, // in ms, if not answer in time an error is provided to get methods
|
||||||
|
'startDiscovery': true, // start discovery after initialization
|
||||||
|
'resendPacketDelay': 150, // delay between packages if light did not receive a packet (for setting methods with callback)
|
||||||
|
'resendMaxTimes': 3, // resend packages x times if light did not receive a packet (for setting methods with callback)
|
||||||
|
'debug': false, // logs all messages in console if turned on
|
||||||
|
'address': '0.0.0.0', // the IPv4 address to bind the udp connection to
|
||||||
|
'broadcast': '255.255.255.255', // set's the IPv4 broadcast address which is addressed to discover bulbs
|
||||||
|
'lights': [] // Can be used provide a list of known light IPv4 ip addresses if broadcast packets in network are not allowed
|
||||||
|
// For example: ['192.168.0.112', '192.168.0.114'], this will then be addressed directly
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('newListener', listener => {
|
||||||
|
logger.info(`Event Listener: ${ listener}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
util.inherits(LightController, em);
|
||||||
|
|
||||||
|
module.exports = LightController;
|
47
lib/mqtt-controller.js
Normal file
47
lib/mqtt-controller.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
const mqtt = require('mqtt');
|
||||||
|
|
||||||
|
const em = require('events').EventEmitter;
|
||||||
|
const util = require('util');
|
||||||
|
const logger = require('log4js').getLogger('MQTT');
|
||||||
|
logger.level = 'trace';
|
||||||
|
|
||||||
|
const MqttController = function() {
|
||||||
|
const _this = this;
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
'keepalive': 3600,
|
||||||
|
'clientId': 'aida',
|
||||||
|
'clean' : false
|
||||||
|
};
|
||||||
|
|
||||||
|
this.on('newListener', listener => {
|
||||||
|
logger.info(`Event Listener: ${ listener}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.debug('Trying to connect');
|
||||||
|
this.client = mqtt.connect('mqtt://192.168.1.150', options);
|
||||||
|
|
||||||
|
this.client.on('error', function(m) {
|
||||||
|
logger.error(m);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
this.client.on('connect', function () {
|
||||||
|
logger.debug('MQTT Connected');
|
||||||
|
this.client.subscribe('bedroomTemp');
|
||||||
|
this.emit('found');
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
this.client.on('message', function (topic, message) {
|
||||||
|
// message is Buffer
|
||||||
|
const msg = message.toString();
|
||||||
|
const json = JSON.parse(msg);
|
||||||
|
// client.end()
|
||||||
|
this.emit(topic, json.temp);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
util.inherits(MqttController, em);
|
||||||
|
|
||||||
|
module.exports = MqttController;
|
98
lib/recipes.js
Normal file
98
lib/recipes.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
const em = require('events').EventEmitter;
|
||||||
|
const util = require('util');
|
||||||
|
const logger = require('log4js').getLogger('BedroomRecipe');
|
||||||
|
logger.level = 'debug';
|
||||||
|
|
||||||
|
const BedroomRecipe = function(devices) {
|
||||||
|
const _this = this;
|
||||||
|
this.mqtt = devices.mqtt;
|
||||||
|
this.wemo = devices.wemo;
|
||||||
|
|
||||||
|
this.globalMode = 'FanOff';
|
||||||
|
|
||||||
|
this.bedroom = {
|
||||||
|
'temp': 0,
|
||||||
|
'last': 0,
|
||||||
|
'data': []
|
||||||
|
};
|
||||||
|
this.ranges = {
|
||||||
|
'day': { 'low': 20.2, 'high': 22.0, 'max': 22.7 },
|
||||||
|
'night': { 'low': 20.2, 'high': 22.0, 'max': 22.7 }
|
||||||
|
};
|
||||||
|
|
||||||
|
logger.debug('Setting up bedroom recipe');
|
||||||
|
|
||||||
|
this.fanTimer = function() {
|
||||||
|
let n;
|
||||||
|
|
||||||
|
const onTime = 900000;
|
||||||
|
const now = new Date;
|
||||||
|
const mod = onTime - (now.getTime() % onTime);
|
||||||
|
const day = now.getDay();
|
||||||
|
const daytimeLimits = { 'low': 27900000, 'high': 63000000 };
|
||||||
|
const nowMS = (now.getHours() * 3600000) + (now.getMinutes() * 60000);
|
||||||
|
const curRange = (nowMS < 25200000) ? this.ranges.night : this.ranges.day;
|
||||||
|
|
||||||
|
if (this.globalMode === 'FanOff') {
|
||||||
|
logger.info(`Fans off, temp should be <= ${curRange.low}`);
|
||||||
|
mode = (parseFloat(this.bedroom.temp) <= curRange.low) ? 'FanOn' : 'FanOff';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logger.info(`Fans on, temp should not be less than ${curRange.high}`);
|
||||||
|
mode = (parseFloat(this.bedroom.temp) <= curRange.high) ? 'FanOn' : 'FanOff';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((this.globalMode !== 'FanOff' || mode !== 'FanOff') && ((day >= 1 && day <= 5) && (nowMS >= daytimeLimits.low && nowMS <= daytimeLimits.high))) {
|
||||||
|
logger.info('Week day');
|
||||||
|
mode = 'FanOff';
|
||||||
|
}
|
||||||
|
|
||||||
|
n = now.getTime() - this.lastMsg;
|
||||||
|
logger.info('Last msg', n);
|
||||||
|
|
||||||
|
if (n >= 600000) {
|
||||||
|
logger.error('No message received for over 10 minutes');
|
||||||
|
mode = 'FanOff';
|
||||||
|
logger.warn('Setting quit for 15 seconds.');
|
||||||
|
setTimeout(() => {
|
||||||
|
throw new error('Ejecting for restart');
|
||||||
|
}, 15000);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info('LR temp:', this.bedroom.temp);
|
||||||
|
// const data = { 'id': 'temperature', 'data': { 'mode': this.globalMode, 'temp': this.bedroom.temp } };
|
||||||
|
|
||||||
|
logger.debug('Mode', mode);
|
||||||
|
if (this.bedroom.temp !== 0) {
|
||||||
|
logger.debug('trying to turn fann off');
|
||||||
|
_this.wemo.emit('wemo', mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(this.fanTimer.bind(this), mod + 500);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateTemp = (temp) => {
|
||||||
|
const now = new Date;
|
||||||
|
const nowMS = (now.getHours() * 3600000) + (now.getMinutes() * 60000);
|
||||||
|
const curRange = (nowMS < 25200000) ? this.ranges.night : this.ranges.day;
|
||||||
|
|
||||||
|
this.bedroom.temp = parseFloat(temp);
|
||||||
|
logger.info(this.bedroom.temp, this.bedroom.temp >= curRange.max);
|
||||||
|
|
||||||
|
if (this.bedroom.temp >= curRange.max) {
|
||||||
|
logger.warn('Max temp reached, turn off');
|
||||||
|
_this.wemo.emit('wemo', 'fanOff');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.mqtt.on('bedroomTemp', (d) => {
|
||||||
|
updateTemp(d);
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(this.fanTimer.bind(this), 10000);
|
||||||
|
};
|
||||||
|
|
||||||
|
util.inherits(BedroomRecipe, em);
|
||||||
|
|
||||||
|
module.exports = { BedroomRecipe };
|
||||||
|
|
60
lib/wemo-controller.js
Normal file
60
lib/wemo-controller.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
const Wemo = require('wemo-client');
|
||||||
|
const wemo = new Wemo();
|
||||||
|
|
||||||
|
const em = require('events').EventEmitter;
|
||||||
|
const util = require('util');
|
||||||
|
const logger = require('log4js').getLogger('Wemo');
|
||||||
|
logger.level = 'debug';
|
||||||
|
|
||||||
|
const WemoController = function() {
|
||||||
|
const _this = this;
|
||||||
|
|
||||||
|
wemo.discover(function(err, deviceInfo) {
|
||||||
|
logger.debug('Wemo Device Found: %j', deviceInfo);
|
||||||
|
_this.emit('found', deviceInfo);
|
||||||
|
|
||||||
|
// Get the client for the found device
|
||||||
|
_this.client = wemo.client(deviceInfo);
|
||||||
|
|
||||||
|
// You definitely want to listen to error events (e.g. device went offline),
|
||||||
|
// Node will throw them as an exception if they are left unhandled
|
||||||
|
_this.client.on('error', function(err) {
|
||||||
|
logger.error('Error: %s', err.code);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle BinaryState events
|
||||||
|
_this.client.on('binaryState', function(value) {
|
||||||
|
logger.info('Binary State changed to: %s', value);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Turn the switch on
|
||||||
|
_this.client.setBinaryState(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('newListener', listener => {
|
||||||
|
logger.info(`Event Listener: ${ listener}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('wemo-off', function() {
|
||||||
|
_this.client.setBinaryState(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('wemo-on', function() {
|
||||||
|
_this.client.setBinaryState(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('wemo', function(d) {
|
||||||
|
logger.debug('onWemo msg', d);
|
||||||
|
if (d === 'FanOn')
|
||||||
|
this.emit('wemo-on');
|
||||||
|
|
||||||
|
if (d === 'FanOff')
|
||||||
|
this.emit('wemo-off');
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
util.inherits(WemoController, em);
|
||||||
|
|
||||||
|
module.exports = WemoController;
|
50
lib/wshandlerv2.js
Normal file
50
lib/wshandlerv2.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* User: Martin Donnelly
|
||||||
|
* Date: 2016-09-07
|
||||||
|
* Time: 15:33
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const url = require('url');
|
||||||
|
const logger = require('log4js').getLogger();
|
||||||
|
|
||||||
|
module.exports = function(events, wsServer) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
logger.debug('>> new WS', wsServer);
|
||||||
|
wsServer.on('connection', function connection(ws) {
|
||||||
|
// console.log('>> WS:', ws);
|
||||||
|
// const location = url.parse(ws.upgradeReq.url, true);
|
||||||
|
|
||||||
|
logger.info('Creating event for this connection');
|
||||||
|
|
||||||
|
logger.info(`${new Date() } Connection accepted.`);
|
||||||
|
|
||||||
|
const sendSocketHandler = (obj) => {
|
||||||
|
logger.debug('sendSocketHandler', obj);
|
||||||
|
try {
|
||||||
|
ws.send(JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
logger.error(err);
|
||||||
|
logger.warn('Offending object: ', obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
events.on('sendSocket', sendSocketHandler);
|
||||||
|
|
||||||
|
ws.on('message', function(message) {
|
||||||
|
console.log('received:', message);
|
||||||
|
|
||||||
|
if (message === 'update')
|
||||||
|
events.emit('update');
|
||||||
|
});
|
||||||
|
|
||||||
|
ws.on('close', function(reasonCode, description) {
|
||||||
|
logger.info(`${new Date() } Peer ${ connection.remoteAddress } disconnected.`);
|
||||||
|
events.removeListener('sendSocket', sendSocketHandler);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return module;
|
||||||
|
};
|
3581
package-lock.json
generated
Normal file
3581
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
34
package.json
34
package.json
@ -2,7 +2,7 @@
|
|||||||
"name": "aida-server",
|
"name": "aida-server",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "Artificial Intelligent Digital Assistant (A.I.D.A.)",
|
"description": "Artificial Intelligent Digital Assistant (A.I.D.A.)",
|
||||||
"main": "index.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
@ -13,12 +13,38 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"express": "^4.15.3"
|
"babel-eslint": "^8.0.0",
|
||||||
|
"eslint": "^4.7.1",
|
||||||
|
"express": "^4.15.4",
|
||||||
|
"ws": "^3.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bg-hive-api": "^1.0.5",
|
"bg-hive-api": "^1.0.5",
|
||||||
"hs100-api": "^0.4.0",
|
"body-parser": "^1.18.1",
|
||||||
|
"cookieparser": "^0.1.0",
|
||||||
|
"errorhandler": "^1.5.0",
|
||||||
|
"express-session": "^1.15.5",
|
||||||
|
"hs100-api": "^0.14.0",
|
||||||
|
"lodash": "^4.17.4",
|
||||||
|
"log4js": "^2.3.3",
|
||||||
|
"method-override": "^2.3.9",
|
||||||
|
"morgan": "^1.8.2",
|
||||||
|
"mqtt": "^2.14.0",
|
||||||
"node-lifx": "^0.8.0",
|
"node-lifx": "^0.8.0",
|
||||||
"wemo-client": "^0.13.0"
|
"trend": "^0.3.0",
|
||||||
|
"wemo-client": "^0.14.0"
|
||||||
|
},
|
||||||
|
"jspm": {
|
||||||
|
"directories": {
|
||||||
|
"baseURL": "app"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"backbone": "npm:backbone@^1.3.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel": "npm:babel-core@^5.8.24",
|
||||||
|
"babel-runtime": "npm:babel-runtime@^5.8.24",
|
||||||
|
"core-js": "npm:core-js@^1.1.4"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
82
server.js
82
server.js
@ -1,8 +1,84 @@
|
|||||||
/**
|
/**
|
||||||
* Created by mdonnel on 07/06/2017.
|
* Created by mdonnel on 07/06/2017.
|
||||||
*/
|
*/
|
||||||
|
const express = require('express');
|
||||||
|
const path = require('path');
|
||||||
|
const http = require('http');
|
||||||
|
|
||||||
var express = require('express');
|
const morgan = require('morgan');
|
||||||
var path = require('path');
|
const cookieParser = require('cookieparser');
|
||||||
var http = require('http');
|
const session = require('express-session');
|
||||||
|
|
||||||
|
const methodoverride = require('method-override');
|
||||||
|
const bodyparser = require('body-parser');
|
||||||
|
const errorhandler = require('errorhandler');
|
||||||
|
|
||||||
|
const logger = require('log4js').getLogger();
|
||||||
|
|
||||||
|
const SocketHandler = require('./lib/wshandlerv2');
|
||||||
|
const Aida = require('./lib/aida');
|
||||||
|
const EventEmitter = require('events').EventEmitter;
|
||||||
|
const WebSocket = require('ws');
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
GLOBAL.lastcheck = 0;
|
||||||
|
|
||||||
|
const port = process.env.PORT || 9010;
|
||||||
|
|
||||||
|
const isProduction = (process.env.NODE_ENV === 'production');
|
||||||
|
|
||||||
|
const staticDir = isProduction ? 'dist' : 'app';
|
||||||
|
|
||||||
|
logger.warn('isProduction:', isProduction);
|
||||||
|
|
||||||
|
// app.configure(function () {
|
||||||
|
app.set('port', port);
|
||||||
|
app.set('view engine', 'ejs');
|
||||||
|
app.use(morgan('dev'));
|
||||||
|
// app.use(cookieParser('your secret here'));
|
||||||
|
/* app.use(session({
|
||||||
|
secret: 'd2jRT6ZpYFsXsF3kGS21ZszKbPAaEa', resave: false,
|
||||||
|
saveUninitialized: false
|
||||||
|
}));*/
|
||||||
|
/* 'default', 'short', 'tiny', 'dev' */
|
||||||
|
app.use(methodoverride());
|
||||||
|
|
||||||
|
app.use(bodyparser.urlencoded({ 'extended': false }));
|
||||||
|
|
||||||
|
// parse application/json
|
||||||
|
app.use(bodyparser.json());
|
||||||
|
|
||||||
|
app.all('/*', (req, res, next) => {
|
||||||
|
// CORS headers
|
||||||
|
res.header('Access-Control-Allow-Origin', '*'); // restrict it to the required domain
|
||||||
|
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
|
||||||
|
// Set custom headers for CORS
|
||||||
|
res.header('Access-Control-Allow-Headers', 'Content-type,Accept,X-Access-Token,X-Key');
|
||||||
|
if (req.method === 'OPTIONS')
|
||||||
|
res.status(200).end();
|
||||||
|
else
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
// app.use(app.router);
|
||||||
|
app.use(express.static(path.join(__dirname, staticDir)));
|
||||||
|
|
||||||
|
app.use(errorhandler({ 'dumpExceptions': true, 'showStack': true }));
|
||||||
|
|
||||||
|
/*app.get('/', function(req, res) {
|
||||||
|
// res.render('pages/slackV2-min');
|
||||||
|
res.render('pages/index');
|
||||||
|
});*/
|
||||||
|
|
||||||
|
const aidaServer = new Aida();
|
||||||
|
|
||||||
|
const server = http.createServer(app);
|
||||||
|
|
||||||
|
const wss = new WebSocket.Server({ server });
|
||||||
|
|
||||||
|
const webSocket = new SocketHandler(EventEmitter, wss);
|
||||||
|
|
||||||
|
// server.on('request', app);
|
||||||
|
server.listen(port, () => {
|
||||||
|
logger.info(`New server listening on ${ server.address().port}`);
|
||||||
|
});
|
||||||
|
318
views/pages/index.ejs
Normal file
318
views/pages/index.ejs
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<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.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 class="mui--no-user-select">
|
||||||
|
<div id="iosTaskbar" style="height:25px;display:none;"></div>
|
||||||
|
<div class="mui-container">
|
||||||
|
<div class="mui-panel" style="display: ;">
|
||||||
|
<div class="mui-row mui--text-center">
|
||||||
|
<img src="gfx/censis_logo_white.png">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</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" id="noDevice" style="display: none;">
|
||||||
|
<div class="mui-row">
|
||||||
|
<div
|
||||||
|
class="mui--text-body2 mui--text-center noConnection">We are having problems connecting to one or more of the devices. Please restart them and wait for them to reconnect.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</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" id="extender" style="display: none;">
|
||||||
|
<div class="mui-row">
|
||||||
|
<div class="mui-col-xs-12 mui--text-center">
|
||||||
|
<div class="mui--text-title ">
|
||||||
|
Extend meeting
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mui-row">
|
||||||
|
<div class="mui-col-xs-12 mui--text-center">
|
||||||
|
<button id="extend05" class="mui-btn mui-btn--fab">5</button>
|
||||||
|
<button id="extend10" class="mui-btn mui-btn--fab">10</button>
|
||||||
|
<button id="extend15" class="mui-btn mui-btn--fab">15</button>
|
||||||
|
<button id="extend30" class="mui-btn mui-btn--fab">30</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<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">
|
||||||
|
<div id="caltext"></div>
|
||||||
|
<div id="extendInfo" class="mui--text-subhead mui--text-accent"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="front-light" class="md-display">
|
||||||
|
<div class="mui-panel">
|
||||||
|
<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 lightOn">On
|
||||||
|
</button>
|
||||||
|
<button id="frontLightOff" class="mui-btn mui-btn--danger lightOff"
|
||||||
|
style="display: none;">Off
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mui-col-xs-4 mui--text-center" id="auxFront"
|
||||||
|
style="display:none;">
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent lightUp"
|
||||||
|
id="frontUp">BRIGHTER
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent lightDown"
|
||||||
|
id="frontDown">DARKER
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</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--text-title mui--text-center"><a class='title'
|
||||||
|
href="#">Middle light</a>
|
||||||
|
</div>
|
||||||
|
</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 lightOn">On
|
||||||
|
</button>
|
||||||
|
<button id="backLightOff" class="mui-btn mui-btn--danger lightOff"
|
||||||
|
style="display: none;">Off
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mui-col-xs-4 mui--text-center" id="auxBack"
|
||||||
|
style="display: none;">
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent lightUp"
|
||||||
|
id="backUp">BRIGHTER
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent lightDown"
|
||||||
|
id="backDown">DARKER
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="mui-panel" id="heating-panel" style="display: none ;">
|
||||||
|
<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" style="display:;">
|
||||||
|
<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 class="mui-col-xs-4 mui--text-center" id="auxProjector"
|
||||||
|
style="display:none;">
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent"
|
||||||
|
id="projectorHDMI">HDMI
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="mui-btn mui-btn--small mui-btn--accent"
|
||||||
|
id="projectorVGA">VGA
|
||||||
|
</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>
|
||||||
|
<script src="cordova.js"></script>
|
||||||
|
<!-- 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/underscore.js"></script>
|
||||||
|
<script src="lib/backbone.js"></script>
|
||||||
|
<!--<script src="lib/sugar-date.js"></script>-->
|
||||||
|
<script src="lib/sugar.js"></script>
|
||||||
|
<script src="lib/skycons.js"></script>
|
||||||
|
<script src="lib/microevent.js"></script>
|
||||||
|
<!-- endbuild -->
|
||||||
|
<!-- build:js -->
|
||||||
|
<script src="js/sowebsocket.js"></script>
|
||||||
|
<script src="js/colours.js"></script>
|
||||||
|
|
||||||
|
<script src="js/modules/clock.js"></script>
|
||||||
|
<script src="js/parts/meetings.js"></script>
|
||||||
|
<script src="js/parts/lights.js"></script>
|
||||||
|
<script src="js/parts/projector.js"></script>
|
||||||
|
<script src="js/app.js"></script>
|
||||||
|
</body>
|
||||||
|
<!-- endbuild -->
|
||||||
|
</html>
|
Loading…
Reference in New Issue
Block a user