homebridge-smartsystem 7.1.21 → 7.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/accessories/accessory.js +2 -2
- package/accessories/dimmer.js +2 -1
- package/accessories/temperature.js +2 -1
- package/duotecno/types.js +5 -1
- package/package.json +2 -2
- package/server/platform.js +1 -1
- package/server/proxy.js +199 -68
- package/server/smartapp.js +72 -5
- package/server/views/assets/custom.css +63 -0
- package/server/views/assets/material-icons.woff2 +0 -0
- package/server/views/device-details.ejs +1 -1
- package/server/views/device-list.ejs +5 -5
- package/server/views/footer.ejs +1 -1
- package/server/views/head.ejs +5 -4
- package/server/views/homekit.ejs +2 -2
- package/server/views/link-details.ejs +1 -1
- package/server/views/link-list.ejs +5 -5
- package/server/views/login.ejs +3 -3
- package/server/views/master-detail.ejs +3 -3
- package/server/views/master-list.ejs +6 -6
- package/server/views/nav.ejs +22 -22
- package/server/views/node-details.ejs +4 -4
- package/server/views/power-binding.ejs +1 -1
- package/server/views/power-rule.ejs +1 -1
- package/server/views/power.ejs +7 -7
- package/server/views/proxy.ejs +55 -24
- package/server/views/scripts.ejs +4 -43
- package/server/views/service-list.ejs +1 -1
- package/server/views/settings.ejs +5 -1
- package/server/views/switch-details.ejs +1 -1
- package/server/views/switch-list.ejs +4 -4
- package/server/views/switch-script.ejs +1 -1
- package/server/views/units.ejs +3 -4
- package/server/webapp.js +98 -7
- package/server/views/style.ejs +0 -65
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/* Page layout with sticky footer */
|
|
2
|
+
html, body { height: 100%; margin: 0; display: flex; flex-direction: column }
|
|
3
|
+
body { min-height: 100vh }
|
|
4
|
+
|
|
5
|
+
/* Main content area - grows to fill space */
|
|
6
|
+
body > *:not(nav):not(.page-footer) { flex: 1 0 auto }
|
|
7
|
+
|
|
8
|
+
form { padding-left: 7px; padding-right: 9px; padding-bottom: 20px }
|
|
9
|
+
form:last-of-type { padding-bottom: 80px }
|
|
10
|
+
|
|
11
|
+
nav, nav .nav-wrapper { height: 64px !important; line-height: 64px !important; flex-shrink: 0 }
|
|
12
|
+
nav .brand-logo { left: 10px !important; -webkit-transform: none !important; transform: none !important }
|
|
13
|
+
|
|
14
|
+
h1 { font-size: 30px }
|
|
15
|
+
h1.btn { margin-top: 18px }
|
|
16
|
+
h1 .btn { margin-left: 10px }
|
|
17
|
+
a span { margin-bottom: 7px; display: inline-block }
|
|
18
|
+
|
|
19
|
+
/* Sticky footer */
|
|
20
|
+
.page-footer { position: fixed; bottom: 0; left: 0; right: 0; width: 100%; flex-shrink: 0; z-index: 100; }
|
|
21
|
+
.page-footer p { text-align: right; padding-bottom: 4px; margin-right: 6px }
|
|
22
|
+
.page-footer a { float: left; margin-left: 10px; color: white; }
|
|
23
|
+
.page-footer { padding-top: 5px; padding-right: 6px }
|
|
24
|
+
.range-field { margin-bottom: -1em }
|
|
25
|
+
b { color: #ee6e73 }
|
|
26
|
+
.btn-small i { font-size: 1.1rem }
|
|
27
|
+
small { font-size: 70% }
|
|
28
|
+
.btn-floating.btn-small { width: 32px; height: 31px }
|
|
29
|
+
.rules p { display: inline-block; margin-bottom: 0px }
|
|
30
|
+
div.select-wrapper { max-width: 212px }
|
|
31
|
+
div.select-wrapper input.select-dropdown { font-size: 16px !important; height: 3rem !important; }
|
|
32
|
+
span.used { color: darkgrey }
|
|
33
|
+
.message { margin-left: 10px; font-size: 15px }
|
|
34
|
+
|
|
35
|
+
/* Hamburger menu icon - positioned on right side */
|
|
36
|
+
nav .sidenav-trigger {
|
|
37
|
+
position: absolute; right: 10px; top: 0;
|
|
38
|
+
height: 64px; line-height: 64px; padding: 0 15px; margin: 0;
|
|
39
|
+
}
|
|
40
|
+
nav .sidenav-trigger i { line-height: 64px; font-size: 2rem }
|
|
41
|
+
|
|
42
|
+
/* Hide hamburger on desktop, show desktop menu */
|
|
43
|
+
@media only screen and (min-width: 993px) {
|
|
44
|
+
nav .sidenav-trigger { display: none !important; }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/* Show hamburger on mobile, hide desktop menu */
|
|
48
|
+
@media only screen and (max-width: 992px) {
|
|
49
|
+
nav .sidenav-trigger { display: block !important; }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Desktop navigation active state */
|
|
53
|
+
nav ul li.active { background-color: rgba(0, 0, 0, 0.1) }
|
|
54
|
+
|
|
55
|
+
/* Sidenav styling */
|
|
56
|
+
.sidenav { width: 280px; }
|
|
57
|
+
.sidenav .user-view { padding: 1px 32px 16px 16px }
|
|
58
|
+
.sidenav .user-view .name { font-size: 18px; font-weight: 500; margin-top: 16px; display: block; }
|
|
59
|
+
.sidenav li > a { height: auto; line-height: 1px; padding: 14px 32px; }
|
|
60
|
+
.sidenav .divider { margin: 8px 0; }
|
|
61
|
+
.sidenav li.active { background-color: rgba(0,0,0,0.05); }
|
|
62
|
+
|
|
63
|
+
.brand-logo-svg { height: 46px; width: auto; display: block }
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
<%- include('/views/nav', this); -%>
|
|
9
9
|
|
|
10
|
-
<form method="POST" action="
|
|
10
|
+
<form method="POST" action="<%= basePath %>/devices">
|
|
11
11
|
<h1>
|
|
12
12
|
Devices
|
|
13
13
|
<button class="right btn waves-effect waves-light" type="submit" name="action" value="add">Add device</button>
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
<tbody>
|
|
24
24
|
<% for (let inx in devices) { let device = devices[inx]; %>
|
|
25
25
|
<tr>
|
|
26
|
-
<td><a href="
|
|
27
|
-
<td><a href="
|
|
28
|
-
<td><a href="
|
|
29
|
-
<td><a href="
|
|
26
|
+
<td><a href="<%= basePath %>/devices/edit/<%= inx %>"><%= device.name %></a></td>
|
|
27
|
+
<td><a href="<%= basePath %>/devices/edit/<%= inx %>"><%= device.id %></a></td>
|
|
28
|
+
<td><a href="<%= basePath %>/devices/edit/<%= inx %>"><%= device.unit?.name || "--" %></a></td>
|
|
29
|
+
<td><a href="<%= basePath %>/devices/edit/<%= inx %>"><%= hex(device.logicalNodeAddress) %>/<%= hex(device.logicalAddress) %></a></td>
|
|
30
30
|
<td><%= device.measured ? '✓' : '✗' %></td>
|
|
31
31
|
<td><%= device.relay ? 'ON' : 'OFF' %></td>
|
|
32
32
|
</tr>
|
package/server/views/footer.ejs
CHANGED
package/server/views/head.ejs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<meta charset="UTF-8">
|
|
2
|
-
<link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
|
|
3
2
|
<title>Duotecno Gateway</title>
|
|
4
3
|
|
|
5
4
|
<!--Let browser know website is optimized for mobile-->
|
|
6
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
7
|
-
<link rel="shortcut icon" href="
|
|
8
|
-
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
6
|
+
<link rel="shortcut icon" href="<%= faviconDataUri %>" type="image/x-icon" />
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
<!-- Materialize CSS/JS, our layout CSS and the Material Icons webfont are all merged into
|
|
9
|
+
this one cached bundle, loaded blocking (not defer/async) so it can inject a <style>
|
|
10
|
+
element before the body is parsed -- keeps a page load down to 2 requests total. -->
|
|
11
|
+
<script src="<%= bundleUrl %>"></script>
|
package/server/views/homekit.ejs
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
<%- include('/views/nav', this); -%>
|
|
9
9
|
|
|
10
|
-
<form method="POST" action="
|
|
10
|
+
<form method="POST" action="<%= basePath %>/homekit">
|
|
11
11
|
<input type="hidden" name="daction" value="save">
|
|
12
12
|
<h1>
|
|
13
13
|
Homekit
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
</form>
|
|
37
37
|
<div class="center-align row" >
|
|
38
|
-
<img src="
|
|
38
|
+
<img src="<%= basePath %>/images/<%= config.bridge.pin %>.jpg?x=<%= Math.random() %>" style="width: calc(100% - 30px); max-width: 400px; margin: 0 15px">
|
|
39
39
|
</div>
|
|
40
40
|
<%- include('/views/footer'); -%>
|
|
41
41
|
</body>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
<%- include('/views/nav', this); -%>
|
|
9
9
|
|
|
10
|
-
<form method="POST" action="
|
|
10
|
+
<form method="POST" action="<%= basePath %>/links">
|
|
11
11
|
<h1>
|
|
12
12
|
Links
|
|
13
13
|
<button class="right btn waves-effect waves-light" type="submit" name="action" value="add">Add link</button>
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
<tbody>
|
|
24
24
|
<% for (let inx in links) { let link = links[inx]; %>
|
|
25
25
|
<tr>
|
|
26
|
-
<td><a href="
|
|
27
|
-
<td><a href="
|
|
28
|
-
<td><a href="
|
|
29
|
-
<td><a href="
|
|
26
|
+
<td><a href="<%= basePath %>/links/edit/<%= inx %>"><%= link.name %></a></td>
|
|
27
|
+
<td><a href="<%= basePath %>/links/edit/<%= inx %>"><%= link.accName %></a></td>
|
|
28
|
+
<td><a href="<%= basePath %>/links/edit/<%= inx %>"><%= link.unit?.name || "--" %></a></td>
|
|
29
|
+
<td><a href="<%= basePath %>/links/edit/<%= inx %>"><%= hex(link.logicalNodeAddress) %>/<%= hex(link.logicalAddress) %></a></td>
|
|
30
30
|
<!--td>
|
|
31
31
|
<div class="switch">
|
|
32
32
|
<label>Off
|
package/server/views/login.ejs
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
<nav>
|
|
9
9
|
<div class="nav-wrapper">
|
|
10
|
-
<a href="
|
|
11
|
-
|
|
10
|
+
<a href="<%= basePath %>/" class="brand-logo left" style="display: flex; align-items: center; gap: 20px; margin: 2px 0 0 2px">
|
|
11
|
+
<%- logoWhite %>
|
|
12
12
|
<div style="display: flex; flex-direction: column; line-height: 1.2; margin-top: 12px">
|
|
13
13
|
<span style="font-size: 1.3rem; font-weight: bolder;">Duotecno Gateway</span>
|
|
14
14
|
<span style="font-size: 0.7rem; font-weight: 300;">Configuration Interface</span>
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
</p>
|
|
24
24
|
<% } %>
|
|
25
25
|
|
|
26
|
-
<form method="post" action="
|
|
26
|
+
<form method="post" action="<%= basePath %>/login">
|
|
27
27
|
<input type="hidden" name="daction" value="login" />
|
|
28
28
|
|
|
29
29
|
<h1>
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<body>
|
|
9
9
|
<%- include('/views/nav', this); -%>
|
|
10
10
|
|
|
11
|
-
<form method="POST" action="
|
|
11
|
+
<form method="POST" action="<%= basePath %>/masters">
|
|
12
12
|
<input type="hidden" name="daction" value="save">
|
|
13
13
|
<h1>
|
|
14
14
|
Master
|
|
@@ -77,11 +77,11 @@
|
|
|
77
77
|
<span><%= node.isNew %></span>
|
|
78
78
|
</label></td>
|
|
79
79
|
<td>
|
|
80
|
-
<a href="
|
|
80
|
+
<a href="<%= basePath %>/units/<%= config.address %>:<%= config.port %>/<%= node.logicalAddress %>"><span><%= node.getName() %></span></a><br>
|
|
81
81
|
<span class="grey-text"><small>Physical: <%= hex(node.physicalAddress) %></small></span>
|
|
82
82
|
</td>
|
|
83
83
|
<td>
|
|
84
|
-
<a href="
|
|
84
|
+
<a href="<%= basePath %>/units/<%= config.address %>:<%= config.port %>/<%= node.logicalAddress %>"><span><%= node.units.length %></span></a><br>
|
|
85
85
|
<input name="name_<%= node.logicalAddress %>" type="hidden" value="<%= node.getName() %>">
|
|
86
86
|
<span class="grey-text"><small>Logical: <%= hex(node.logicalAddress) %></small></span>
|
|
87
87
|
</td>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
<%- include('/views/nav', this); -%>
|
|
9
9
|
|
|
10
|
-
<form method="POST" action="
|
|
10
|
+
<form method="POST" action="<%= basePath %>/masters/new">
|
|
11
11
|
<h1>
|
|
12
12
|
Masters
|
|
13
13
|
<button class="right btn waves-effect waves-light" type="submit" name="action" value="new">Add Master</button>
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
<tbody>
|
|
27
27
|
<% for (let master of masters) { if (master) { %>
|
|
28
28
|
<tr>
|
|
29
|
-
<td><a href="
|
|
30
|
-
<td><a href="
|
|
31
|
-
<td><a href="
|
|
32
|
-
<td><a href="
|
|
33
|
-
<td><a href="
|
|
29
|
+
<td><a href="<%= basePath %>/masters/edit/<%= master.config.address %>:<%= master.config.port %>"><%= master.config.name %></a><br><%= datetime(master.date) %></td>
|
|
30
|
+
<td><a href="<%= basePath %>/masters/edit/<%= master.config.address %>:<%= master.config.port %>"><%= master.config.address %></a></td>
|
|
31
|
+
<td><a href="<%= basePath %>/masters/edit/<%= master.config.address %>:<%= master.config.port %>"><%= master.nodes.length %></a></td>
|
|
32
|
+
<td><a href="<%= basePath %>/masters/close/<%= master.config.address %>:<%= master.config.port %>">close connection</a></td>
|
|
33
|
+
<td><a href="<%= basePath %>/masters/edit/<%= master.config.address %>:<%= master.config.port %>"><%= master.protocol %></a></td>
|
|
34
34
|
</tr>
|
|
35
35
|
<% }} %>
|
|
36
36
|
</tbody>
|
package/server/views/nav.ejs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<nav>
|
|
2
2
|
<div class="nav-wrapper">
|
|
3
|
-
<a href="
|
|
4
|
-
|
|
3
|
+
<a href="<%= basePath %>/" class="brand-logo left" style="display: flex; align-items: center; gap: 20px; margin: 2px 0 0 2px">
|
|
4
|
+
<%- logoWhite %>
|
|
5
5
|
<div style="display: flex; flex-direction: column; line-height: 1.2; margin-top: 12px">
|
|
6
6
|
<span style="font-size: 1.3rem; font-weight: bolder;">Duotecno Gateway</span>
|
|
7
7
|
<span style="font-size: 0.7rem; font-weight: 300;">Configuration Interface</span>
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
|
|
14
14
|
<!-- Desktop Menu -->
|
|
15
15
|
<ul class="right hide-on-med-and-down">
|
|
16
|
-
<li <% if (request === "masters") { %>class="active"<% } %>><a href="
|
|
17
|
-
<li <% if (request === "services") { %>class="active"<% } %>><a href="
|
|
18
|
-
<li <% if (request === "proxy") { %>class="active"<% } %>><a href="
|
|
19
|
-
<li <% if (request === "links") { %>class="active"<% } %>><a href="
|
|
20
|
-
<li <% if (request === "devices") { %>class="active"<% } %>><a href="
|
|
21
|
-
<% if (hasSmappee) { %><li <% if ((request === "power") && (type === "smappee")) { %>class="active"<% } %>><a href="
|
|
22
|
-
<% if (hasP1) { %><li <% if ((request === "power") && (type === "p1")) { %>class="active"<% } %>><a href="
|
|
23
|
-
<% if (hasShelly) { %><li <% if ((request === "power") && (type === "shelly")) { %>class="active"<% } %>><a href="
|
|
24
|
-
<li <% if (request === "switches") { %>class="active"<% } %>><a href="
|
|
25
|
-
<li <% if (request === "settings") { %>class="active"<% } %>><a href="
|
|
16
|
+
<li <% if (request === "masters") { %>class="active"<% } %>><a href="<%= basePath %>/masters">Masters</a></li>
|
|
17
|
+
<li <% if (request === "services") { %>class="active"<% } %>><a href="<%= basePath %>/services">Services</a></li>
|
|
18
|
+
<li <% if (request === "proxy") { %>class="active"<% } %>><a href="<%= basePath %>/proxy">Proxy</a></li>
|
|
19
|
+
<li <% if (request === "links") { %>class="active"<% } %>><a href="<%= basePath %>/links">Links</a></li>
|
|
20
|
+
<li <% if (request === "devices") { %>class="active"<% } %>><a href="<%= basePath %>/devices">Devices</a></li>
|
|
21
|
+
<% if (hasSmappee) { %><li <% if ((request === "power") && (type === "smappee")) { %>class="active"<% } %>><a href="<%= basePath %>/power?type=smappee">Smappee</a></li><% } %>
|
|
22
|
+
<% if (hasP1) { %><li <% if ((request === "power") && (type === "p1")) { %>class="active"<% } %>><a href="<%= basePath %>/power?type=p1">P1</a></li><% } %>
|
|
23
|
+
<% if (hasShelly) { %><li <% if ((request === "power") && (type === "shelly")) { %>class="active"<% } %>><a href="<%= basePath %>/power?type=shelly">Shelly</a></li><% } %>
|
|
24
|
+
<li <% if (request === "switches") { %>class="active"<% } %>><a href="<%= basePath %>/switches">Switches</a></li>
|
|
25
|
+
<li <% if (request === "settings") { %>class="active"<% } %>><a href="<%= basePath %>/settings">Settings</a></li>
|
|
26
26
|
</ul>
|
|
27
27
|
</div>
|
|
28
28
|
</nav>
|
|
@@ -33,19 +33,19 @@
|
|
|
33
33
|
<div class="background blue darken-2"></div>
|
|
34
34
|
<span class="white-text name">Duotecno Gateway</span>
|
|
35
35
|
</div></li>
|
|
36
|
-
<li <% if (request === "masters") { %>class="active"<% } %>><a href="
|
|
37
|
-
<li <% if (request === "services") { %>class="active"<% } %>><a href="
|
|
36
|
+
<li <% if (request === "masters") { %>class="active"<% } %>><a href="<%= basePath %>/masters">Masters</a></li>
|
|
37
|
+
<li <% if (request === "services") { %>class="active"<% } %>><a href="<%= basePath %>/services">Services</a></li>
|
|
38
38
|
<li><div class="divider"></div></li>
|
|
39
|
-
<li <% if (request === "devices") { %>class="active"<% } %>><a href="
|
|
40
|
-
<li <% if (request === "links") { %>class="active"<% } %>><a href="
|
|
41
|
-
<li <% if (request === "switches") { %>class="active"<% } %>><a href="
|
|
39
|
+
<li <% if (request === "devices") { %>class="active"<% } %>><a href="<%= basePath %>/devices">Devices</a></li>
|
|
40
|
+
<li <% if (request === "links") { %>class="active"<% } %>><a href="<%= basePath %>/links">Links</a></li>
|
|
41
|
+
<li <% if (request === "switches") { %>class="active"<% } %>><a href="<%= basePath %>/switches">Switches</a></li>
|
|
42
42
|
<li><div class="divider"></div></li>
|
|
43
|
-
<% if (hasSmappee) { %><li <% if ((request === "power") && (type === "smappee")) { %>class="active"<% } %>><a href="
|
|
44
|
-
<% if (hasP1) { %><li <% if ((request === "power") && (type === "p1")) { %>class="active"<% } %>><a href="
|
|
45
|
-
<% if (hasShelly) { %><li <% if ((request === "power") && (type === "shelly")) { %>class="active"<% } %>><a href="
|
|
43
|
+
<% if (hasSmappee) { %><li <% if ((request === "power") && (type === "smappee")) { %>class="active"<% } %>><a href="<%= basePath %>/power?type=smappee">Smappee</a></li><% } %>
|
|
44
|
+
<% if (hasP1) { %><li <% if ((request === "power") && (type === "p1")) { %>class="active"<% } %>><a href="<%= basePath %>/power?type=p1">P1 Meter</a></li><% } %>
|
|
45
|
+
<% if (hasShelly) { %><li <% if ((request === "power") && (type === "shelly")) { %>class="active"<% } %>><a href="<%= basePath %>/power?type=shelly">Shelly PM</a></li><% } %>
|
|
46
46
|
<li><div class="divider"></div></li>
|
|
47
|
-
<li <% if (request === "proxy") { %>class="active"<% } %>><a href="
|
|
48
|
-
<li <% if (request === "settings") { %>class="active"<% } %>><a href="
|
|
47
|
+
<li <% if (request === "proxy") { %>class="active"<% } %>><a href="<%= basePath %>/proxy">Proxy</a></li>
|
|
48
|
+
<li <% if (request === "settings") { %>class="active"<% } %>><a href="<%= basePath %>/settings">Settings</a></li>
|
|
49
49
|
</ul>
|
|
50
50
|
|
|
51
51
|
<% if (notReady) { %>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
<%- include('/views/nav', this); -%>
|
|
9
9
|
|
|
10
|
-
<form method="POST" action="
|
|
10
|
+
<form method="POST" action="<%= basePath %>/units">
|
|
11
11
|
<input type="hidden" name="master" value="<%= masterAddress %>">
|
|
12
12
|
<input type="hidden" name="port" value="<%= masterPort %>">
|
|
13
13
|
<input type="hidden" name="node" value="<%= node.logicalAddress %>">
|
|
@@ -16,16 +16,16 @@
|
|
|
16
16
|
<span class="grey-text"><small>Physical = <%= hex(node.physicalAddress) %> - Logical = <%= hex(node.logicalAddress) %></small></span>
|
|
17
17
|
<button class="right btn waves-effect waves-light" type="submit" name="action" value="cancel">Back</button>
|
|
18
18
|
<button class="right btn waves-effect waves-light" type="submit" name="action" value="save">Save</button>
|
|
19
|
-
<a href="
|
|
19
|
+
<a href="<%= basePath %>/units/<%= masterAddress %>:<%= masterPort %>/<%= node.logicalAddress %>?sortOnAddr=<%= sortOnAddr ? 'Y' : 'N' %>" class="right btn waves-effect waves-light">Refresh</a>
|
|
20
20
|
</h1>
|
|
21
21
|
|
|
22
22
|
<div class="right">
|
|
23
23
|
<label>Sort on: </label>
|
|
24
24
|
<% if (sortOnAddr == 'Y') { %>
|
|
25
25
|
on address |
|
|
26
|
-
<a href="
|
|
26
|
+
<a href="<%= basePath %>/units/<%= masterAddress %>:<%= masterPort %>/<%= node.logicalAddress %>?sortOnAddr=N">on name</a>
|
|
27
27
|
<% } else { %>
|
|
28
|
-
<a href="
|
|
28
|
+
<a href="<%= basePath %>/units/<%= masterAddress %>:<%= masterPort %>/<%= node.logicalAddress %>?sortOnAddr=Y">on address</a> |
|
|
29
29
|
on name
|
|
30
30
|
<% } %>
|
|
31
31
|
</div>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
<%- include('/views/nav', this); -%>
|
|
9
9
|
|
|
10
|
-
<form method="POST" action="
|
|
10
|
+
<form method="POST" action="<%= basePath %>/power">
|
|
11
11
|
<input type="hidden" name="daction" value="bchange">
|
|
12
12
|
<input type="hidden" name="id" value="<%= id %>">
|
|
13
13
|
<input type="hidden" name="type" value="<%= type %>">
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
<%- include('/views/nav', this); -%>
|
|
9
9
|
|
|
10
|
-
<form method="POST" action="
|
|
10
|
+
<form method="POST" action="<%= basePath %>/power">
|
|
11
11
|
<input type="hidden" name="daction" value="change">
|
|
12
12
|
<input type="hidden" name="id" value="<%= id %>">
|
|
13
13
|
<input type="hidden" name="type" value="<%= type %>">
|
package/server/views/power.ejs
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
<%- include('/views/nav', this); -%>
|
|
9
9
|
|
|
10
|
-
<form method="POST" action="
|
|
10
|
+
<form method="POST" action="<%= basePath %>/power">
|
|
11
11
|
<input type="hidden" name="daction" value="save">
|
|
12
12
|
<input type="hidden" name="type" value="<%= type %>">
|
|
13
13
|
<h1>
|
|
@@ -54,21 +54,21 @@
|
|
|
54
54
|
<tbody>
|
|
55
55
|
<% for (let inx in rules) { let rule = rules[inx]; %>
|
|
56
56
|
<tr>
|
|
57
|
-
<td><a href="
|
|
57
|
+
<td><a href="<%= basePath %>/power/rule/<%= inx %>?type=<%= type%>"><%= rule.type %></a></td>
|
|
58
58
|
<td><% if (rule.type == "power") { %>
|
|
59
|
-
<a href="
|
|
59
|
+
<a href="<%= basePath %>/power/rule/<%= inx %>?type=<%= type%>"><%= rule.channel %></a>
|
|
60
60
|
<% } else { %>
|
|
61
61
|
export
|
|
62
62
|
<% } %>
|
|
63
63
|
</td>
|
|
64
|
-
<td><a href="
|
|
64
|
+
<td><a href="<%= basePath %>/power/rule/<%= inx %>?type=<%= type%>">
|
|
65
65
|
<%= (
|
|
66
66
|
(rule.current == 2) ? 'high' : (
|
|
67
67
|
(rule.current == 1) ? 'mid' : (
|
|
68
68
|
(rule.current == 0) ? 'low' : '--'
|
|
69
69
|
))) %></a></td>
|
|
70
|
-
<td><a href="
|
|
71
|
-
<td style="text-align: center"><a href="
|
|
70
|
+
<td><a href="<%= basePath %>/power/rule/<%= inx %>?type=<%= type%>"><%= ((rule.power) ? rule.power : '-') %></a></td>
|
|
71
|
+
<td style="text-align: center"><a href="<%= basePath %>/power/rule/<%= inx %>?type=<%= type%>">... <%= rule.low %> ... <%= rule.high %> ...</a></td>
|
|
72
72
|
<td><%= hex(rule.actions[0].logicalNodeAddress) %>;<%= hex(rule.actions[0].logicalAddress) %></td>
|
|
73
73
|
</tr>
|
|
74
74
|
<% } %>
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
<table style="width: 75%; min-width: 350px">
|
|
83
83
|
<tr><th>Id</th><th>Channels</th><th>Value</th><th>Register</th></tr>
|
|
84
84
|
<% for (let inx in bindings) { const b = bindings[inx] %>
|
|
85
|
-
<tr><th><a href="
|
|
85
|
+
<tr><th><a href="<%= basePath %>/power/binding/<%= inx %>?type=<%= type%>">Binding <%= inx %></a></th>
|
|
86
86
|
<td><%= b.channel %></td><td><%= b.value %></td>
|
|
87
87
|
<td><%= b.register %></td></tr>
|
|
88
88
|
<% } %>
|
package/server/views/proxy.ejs
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
<%- include('/views/nav', this); -%>
|
|
9
9
|
|
|
10
|
-
<form method="POST" action="
|
|
10
|
+
<form method="POST" action="<%= basePath %>/proxy" style="padding-bottom: 0">
|
|
11
11
|
<input type="hidden" name="daction" value="save">
|
|
12
12
|
<h1>
|
|
13
13
|
Proxy Config
|
|
@@ -38,30 +38,40 @@
|
|
|
38
38
|
</div>
|
|
39
39
|
|
|
40
40
|
<h2 style="margin-top: 3rem; font-size: 1.5rem; font-weight: 500;">
|
|
41
|
-
<i class="material-icons left" style="vertical-align: middle;">
|
|
42
|
-
|
|
41
|
+
<i class="material-icons left" style="vertical-align: middle;">badge</i>
|
|
42
|
+
Installation
|
|
43
43
|
</h2>
|
|
44
44
|
<p class="grey-text" style="margin-bottom: 2rem;">
|
|
45
|
-
|
|
45
|
+
Registered names on the cloud server follow the pattern
|
|
46
|
+
<code>[installation id].[node number].[protocol]:[port]</code>.
|
|
46
47
|
</p>
|
|
47
48
|
|
|
48
49
|
<div class="row" style="margin-top: 1rem;">
|
|
49
|
-
<div class="input-field col
|
|
50
|
-
<label for="
|
|
51
|
-
<input placeholder="john-doe.duotecno.be" id="
|
|
52
|
-
value="<%= config.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
<div class="input-field col s8">
|
|
51
|
+
<label for="installationId">Installation ID</label>
|
|
52
|
+
<input placeholder="john-doe.duotecno.be" id="installationId" name="installationId" type="text"
|
|
53
|
+
value="<%= config.installationId %>">
|
|
54
|
+
</div>
|
|
55
|
+
<div class="input-field col s4">
|
|
56
|
+
<label for="nodeNumber">Node number (hex)</label>
|
|
57
|
+
<input placeholder="0xff" id="nodeNumber" name="nodeNumber" type="text"
|
|
58
|
+
value="<%= hex(config.nodeNumber !== undefined ? config.nodeNumber : 0xff) %>">
|
|
59
|
+
<span class="helper-text">Reserved node, unused on the Duotecno bus (0xff is fine).</span>
|
|
58
60
|
</div>
|
|
59
61
|
</div>
|
|
60
62
|
|
|
61
|
-
<
|
|
63
|
+
<h2 style="margin-top: 3rem; font-size: 1.5rem; font-weight: 500;">
|
|
64
|
+
<i class="material-icons left" style="vertical-align: middle;">home</i>
|
|
65
|
+
Master Device
|
|
66
|
+
</h2>
|
|
67
|
+
<p class="grey-text" style="margin-bottom: 2rem;">
|
|
68
|
+
Configure your local master device with 2 ports.</small>
|
|
69
|
+
</p>
|
|
70
|
+
|
|
71
|
+
<div class="row" style="margin-top: 1rem;">
|
|
62
72
|
<div class="input-field col s12">
|
|
63
73
|
<label for="masterAddress">IP Address</label>
|
|
64
|
-
<input placeholder="192.168.0.97" id="masterAddress" name="masterAddress" type="text"
|
|
74
|
+
<input placeholder="192.168.0.97" id="masterAddress" name="masterAddress" type="text"
|
|
65
75
|
value="<%= config.masterAddress %>">
|
|
66
76
|
</div>
|
|
67
77
|
</div>
|
|
@@ -75,9 +85,10 @@
|
|
|
75
85
|
</label>
|
|
76
86
|
</p>
|
|
77
87
|
<div class="input-field">
|
|
78
|
-
<input placeholder="5001" id="masterPort" name="masterPort" type="number"
|
|
88
|
+
<input placeholder="5001" id="masterPort" name="masterPort" type="number"
|
|
79
89
|
value="<%= config.masterPort || 5001 %>">
|
|
80
90
|
</div>
|
|
91
|
+
<span class="helper-text"><small><%= deviceIds.tcp %></small></span>
|
|
81
92
|
</div>
|
|
82
93
|
<div class="col s6">
|
|
83
94
|
<p>
|
|
@@ -87,15 +98,32 @@
|
|
|
87
98
|
</label>
|
|
88
99
|
</p>
|
|
89
100
|
<div class="input-field">
|
|
90
|
-
<input placeholder="8080" id="masterConfigPort" name="masterConfigPort" type="number"
|
|
101
|
+
<input placeholder="8080" id="masterConfigPort" name="masterConfigPort" type="number"
|
|
91
102
|
value="<%= config.masterConfigPort || 8080 %>">
|
|
92
103
|
</div>
|
|
104
|
+
<span class="helper-text"><small><%= deviceIds.configHttp %></small></span>
|
|
93
105
|
</div>
|
|
94
106
|
</div>
|
|
95
107
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
108
|
+
<h2 style="margin-top: 3rem; font-size: 1.5rem; font-weight: 500;">
|
|
109
|
+
<i class="material-icons left" style="vertical-align: middle;">public</i>
|
|
110
|
+
Gateway Web UI
|
|
111
|
+
</h2>
|
|
112
|
+
<p class="grey-text" style="margin-bottom: 2rem;">
|
|
113
|
+
Reach this configuration interface itself through the cloud server, at
|
|
114
|
+
<code>https://<%= config.cloudServer %>/connect/<%= deviceIds.http %>/</code>.
|
|
115
|
+
</p>
|
|
116
|
+
|
|
117
|
+
<div class="row" style="margin-top: 1rem;">
|
|
118
|
+
<div class="col s12">
|
|
119
|
+
<label>
|
|
120
|
+
<input type="checkbox" class="filled-in" id="httpEnabled" name="httpEnabled" value="Y"
|
|
121
|
+
<%= config.httpEnabled ? "checked" : "" %> />
|
|
122
|
+
<span><strong>Register to Cloud server</strong></span>
|
|
123
|
+
</label>
|
|
124
|
+
<span class="helper-text"><small><%= deviceIds.http %></small></span>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
99
127
|
|
|
100
128
|
</form>
|
|
101
129
|
|
|
@@ -131,7 +159,7 @@
|
|
|
131
159
|
<p>The gateway is still running, but may not be discoverable via mDNS hostname.</p>
|
|
132
160
|
<p class="grey-text">Solutions:</p>
|
|
133
161
|
<ul class="grey-text">
|
|
134
|
-
<li>Change the mDNS name in <a href="
|
|
162
|
+
<li>Change the mDNS name in <a href="<%= basePath %>/settings">Settings</a></li>
|
|
135
163
|
<li>Stop other devices/services using the same name</li>
|
|
136
164
|
<li>Access the gateway using IP address instead</li>
|
|
137
165
|
</ul>
|
|
@@ -190,11 +218,14 @@
|
|
|
190
218
|
<% } else if (conn.deviceStatus.connected) { %>
|
|
191
219
|
<span class="green-text">✓ Connected</span><br>
|
|
192
220
|
<small><%= conn.master %>:<%= conn.masterPort %></small>
|
|
193
|
-
<% } else if (conn.master) { %>
|
|
221
|
+
<% } else if (!conn.master) { %>
|
|
222
|
+
<span class="grey-text">Not configured</span>
|
|
223
|
+
<% } else if (!conn.deviceStatus.lastAttempt) { %>
|
|
224
|
+
<span class="orange-text">Waiting for a client</span><br>
|
|
225
|
+
<small><%= conn.master %>:<%= conn.masterPort %> — not attempted yet, this tunnel is free and unused</small>
|
|
226
|
+
<% } else { %>
|
|
194
227
|
<span class="red-text">✗ Disconnected</span><br>
|
|
195
228
|
<small><%= conn.master %>:<%= conn.masterPort %></small>
|
|
196
|
-
<% } else { %>
|
|
197
|
-
<span class="grey-text">Not configured</span>
|
|
198
229
|
<% } %>
|
|
199
230
|
</td>
|
|
200
231
|
<td>
|
package/server/views/scripts.ejs
CHANGED
|
@@ -1,46 +1,7 @@
|
|
|
1
|
-
<script type="text/javascript" src="/files/min.js"></script>
|
|
2
|
-
|
|
3
1
|
<script type="text/javascript">
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// Initialize all Materialize components
|
|
10
|
-
M.AutoInit();
|
|
11
|
-
|
|
12
|
-
// Explicitly initialize sidenav for mobile menu
|
|
13
|
-
const sidenavElems = document.querySelectorAll('.sidenav');
|
|
14
|
-
M.Sidenav.init(sidenavElems, {
|
|
15
|
-
edge: 'right',
|
|
16
|
-
draggable: true
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const msg = `<%= (typeof message === 'undefined') ? '' : message %>`;
|
|
20
|
-
if (msg) M.toast({html: msg});
|
|
21
|
-
console.log("Ready to rock & roll");
|
|
2
|
+
// Materialize, hex()/ajax() and SmartSocketInit() itself come from the shared bundle
|
|
3
|
+
// loaded in <head> -- only the per-request message needs to travel with this page.
|
|
4
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
5
|
+
SmartSocketInit(<%- JSON.stringify((typeof message === 'undefined') ? '' : message) %>);
|
|
22
6
|
}, false);
|
|
23
|
-
|
|
24
|
-
document.addEventListener("keyup", function(e) {
|
|
25
|
-
if (e.key == "Enter") {
|
|
26
|
-
e.preventDefault();
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
function hex(val) {
|
|
31
|
-
const num = parseInt(val, 10);
|
|
32
|
-
if (isNaN(num)) return "0x0";
|
|
33
|
-
return "0x" + num.toString(16);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function ajax(url, success) {
|
|
37
|
-
var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
|
|
38
|
-
xhr.open('GET', url);
|
|
39
|
-
xhr.onreadystatechange = function() {
|
|
40
|
-
if (xhr.readyState>3 && xhr.status==200) success(xhr.responseText);
|
|
41
|
-
};
|
|
42
|
-
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
|
43
|
-
xhr.send();
|
|
44
|
-
return xhr;
|
|
45
|
-
}
|
|
46
7
|
</script>
|