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.
@@ -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 }
@@ -7,7 +7,7 @@
7
7
  <body>
8
8
  <%- include('/views/nav', this); -%>
9
9
 
10
- <form method="POST" action="/devices">
10
+ <form method="POST" action="<%= basePath %>/devices">
11
11
  <input type="hidden" name="daction" value="save">
12
12
  <input type="hidden" name="id" value="<%= id %>">
13
13
  <h1>
@@ -7,7 +7,7 @@
7
7
  <body>
8
8
  <%- include('/views/nav', this); -%>
9
9
 
10
- <form method="POST" action="/devices">
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="/devices/edit/<%= inx %>"><%= device.name %></a></td>
27
- <td><a href="/devices/edit/<%= inx %>"><%= device.id %></a></td>
28
- <td><a href="/devices/edit/<%= inx %>"><%= device.unit?.name || "--" %></a></td>
29
- <td><a href="/devices/edit/<%= inx %>"><%= hex(device.logicalNodeAddress) %>/<%= hex(device.logicalAddress) %></a></td>
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>
@@ -1,6 +1,6 @@
1
1
  <footer class="page-footer">
2
2
  <p>
3
- <a href="/login/logout">Log out</a>
3
+ <a href="<%= basePath %>/login/logout">Log out</a>
4
4
  Johan Coppieters - Duotecno, 2019-<%= year %> - v<%= version %>
5
5
  </p>
6
6
 
@@ -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="/files/favicon.ico" type="image/x-icon" />
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
- <%- include('/views/style'); -%>
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>
@@ -7,7 +7,7 @@
7
7
  <body>
8
8
  <%- include('/views/nav', this); -%>
9
9
 
10
- <form method="POST" action="/homekit">
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="/images/<%= config.bridge.pin %>.jpg?x=<%= Math.random() %>" style="width: calc(100% - 30px); max-width: 400px; margin: 0 15px">
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="/links">
10
+ <form method="POST" action="<%= basePath %>/links">
11
11
  <input type="hidden" name="daction" value="save">
12
12
  <input type="hidden" name="id" value="<%= id %>">
13
13
  <h1>
@@ -7,7 +7,7 @@
7
7
  <body>
8
8
  <%- include('/views/nav', this); -%>
9
9
 
10
- <form method="POST" action="/links">
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="/links/edit/<%= inx %>"><%= link.name %></a></td>
27
- <td><a href="/links/edit/<%= inx %>"><%= link.accName %></a></td>
28
- <td><a href="/links/edit/<%= inx %>"><%= link.unit?.name || "--" %></a></td>
29
- <td><a href="/links/edit/<%= inx %>"><%= hex(link.logicalNodeAddress) %>/<%= hex(link.logicalAddress) %></a></td>
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
@@ -7,8 +7,8 @@
7
7
  <body>
8
8
  <nav>
9
9
  <div class="nav-wrapper">
10
- <a href="/" class="brand-logo left" style="display: flex; align-items: center; gap: 20px; margin: 2px 0 0 2px">
11
- <img src="/files/Duotecno_logo_white.svg" alt="Duotecno" style="height: 46px; width: auto">
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="/login">
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="/masters">
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="/units/<%= config.address %>:<%= config.port %>/<%= node.logicalAddress %>"><span><%= node.getName() %></span></a><br>
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="/units/<%= config.address %>:<%= config.port %>/<%= node.logicalAddress %>"><span><%= node.units.length %></span></a><br>
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="/masters/new">
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="/masters/edit/<%= master.config.address %>:<%= master.config.port %>"><%= master.config.name %></a><br><%= datetime(master.date) %></td>
30
- <td><a href="/masters/edit/<%= master.config.address %>:<%= master.config.port %>"><%= master.config.address %></a></td>
31
- <td><a href="/masters/edit/<%= master.config.address %>:<%= master.config.port %>"><%= master.nodes.length %></a></td>
32
- <td><a href="/masters/close/<%= master.config.address %>:<%= master.config.port %>">close connection</a></td>
33
- <td><a href="/masters/edit/<%= master.config.address %>:<%= master.config.port %>"><%= master.protocol %></a></td>
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>
@@ -1,7 +1,7 @@
1
1
  <nav>
2
2
  <div class="nav-wrapper">
3
- <a href="/" class="brand-logo left" style="display: flex; align-items: center; gap: 20px; margin: 2px 0 0 2px">
4
- <img src="/files/Duotecno_logo_white.svg" alt="Duotecno" style="height: 46px; width: auto">
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="/masters">Masters</a></li>
17
- <li <% if (request === "services") { %>class="active"<% } %>><a href="/services">Services</a></li>
18
- <li <% if (request === "proxy") { %>class="active"<% } %>><a href="/proxy">Proxy</a></li>
19
- <li <% if (request === "links") { %>class="active"<% } %>><a href="/links">Links</a></li>
20
- <li <% if (request === "devices") { %>class="active"<% } %>><a href="/devices">Devices</a></li>
21
- <% if (hasSmappee) { %><li <% if ((request === "power") && (type === "smappee")) { %>class="active"<% } %>><a href="/power?type=smappee">Smappee</a></li><% } %>
22
- <% if (hasP1) { %><li <% if ((request === "power") && (type === "p1")) { %>class="active"<% } %>><a href="/power?type=p1">P1</a></li><% } %>
23
- <% if (hasShelly) { %><li <% if ((request === "power") && (type === "shelly")) { %>class="active"<% } %>><a href="/power?type=shelly">Shelly</a></li><% } %>
24
- <li <% if (request === "switches") { %>class="active"<% } %>><a href="/switches">Switches</a></li>
25
- <li <% if (request === "settings") { %>class="active"<% } %>><a href="/settings">Settings</a></li>
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="/masters">Masters</a></li>
37
- <li <% if (request === "services") { %>class="active"<% } %>><a href="/services">Services</a></li>
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="/devices">Devices</a></li>
40
- <li <% if (request === "links") { %>class="active"<% } %>><a href="/links">Links</a></li>
41
- <li <% if (request === "switches") { %>class="active"<% } %>><a href="/switches">Switches</a></li>
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="/power?type=smappee">Smappee</a></li><% } %>
44
- <% if (hasP1) { %><li <% if ((request === "power") && (type === "p1")) { %>class="active"<% } %>><a href="/power?type=p1">P1 Meter</a></li><% } %>
45
- <% if (hasShelly) { %><li <% if ((request === "power") && (type === "shelly")) { %>class="active"<% } %>><a href="/power?type=shelly">Shelly PM</a></li><% } %>
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="/proxy">Proxy</a></li>
48
- <li <% if (request === "settings") { %>class="active"<% } %>><a href="/settings">Settings</a></li>
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="/units">
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="/units/<%= masterAddress %>:<%= masterPort %>/<%= node.logicalAddress %>?sortOnAddr=<%= sortOnAddr ? 'Y' : 'N' %>" class="right btn waves-effect waves-light">Refresh</a>
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="/units/<%= masterAddress %>:<%= masterPort %>/<%= node.logicalAddress %>?sortOnAddr=N">on name</a>
26
+ <a href="<%= basePath %>/units/<%= masterAddress %>:<%= masterPort %>/<%= node.logicalAddress %>?sortOnAddr=N">on name</a>
27
27
  <% } else { %>
28
- <a href="/units/<%= masterAddress %>:<%= masterPort %>/<%= node.logicalAddress %>?sortOnAddr=Y">on address</a> |
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="/power">
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="/power">
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 %>">
@@ -7,7 +7,7 @@
7
7
  <body>
8
8
  <%- include('/views/nav', this); -%>
9
9
 
10
- <form method="POST" action="/power">
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="/power/rule/<%= inx %>?type=<%= type%>"><%= rule.type %></a></td>
57
+ <td><a href="<%= basePath %>/power/rule/<%= inx %>?type=<%= type%>"><%= rule.type %></a></td>
58
58
  <td><% if (rule.type == "power") { %>
59
- <a href="/power/rule/<%= inx %>?type=<%= type%>"><%= rule.channel %></a>
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="/power/rule/<%= inx %>?type=<%= type%>">
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="/power/rule/<%= inx %>?type=<%= type%>"><%= ((rule.power) ? rule.power : '-') %></a></td>
71
- <td style="text-align: center"><a href="/power/rule/<%= inx %>?type=<%= type%>">... <%= rule.low %> ... <%= rule.high %> ...</a></td>
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="/power/binding/<%= inx %>?type=<%= type%>">Binding <%= inx %></a></th>
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
  <% } %>
@@ -7,7 +7,7 @@
7
7
  <body>
8
8
  <%- include('/views/nav', this); -%>
9
9
 
10
- <form method="POST" action="/proxy" style="padding-bottom: 0">
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;">home</i>
42
- Master Device
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
- Configure your local master device with 2 ports.</small>
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 s12">
50
- <label for="uniqueId">Unique ID (without port)</label>
51
- <input placeholder="john-doe.duotecno.be" id="uniqueId" name="uniqueId" type="text"
52
- value="<%= config.uniqueId %>">
53
- <span class="helper-text">
54
- This ID is used for both connections:<br>
55
- • Websocket: [uniqueId]:5001<br>
56
- • Config API: [uniqueId]:8080<br>
57
- </span>
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
- <div class="row">
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
- <!-- Hidden fields for compatibility - these are no longer shown in UI -->
97
- <input type="hidden" name="configPort" value="<%= config.configPort || config.cloudPort %>">
98
- <input type="hidden" name="configUniqueId" value="<%= config.configUniqueId || '' %>">
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="/settings">Settings</a></li>
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 %> &mdash; 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>
@@ -1,46 +1,7 @@
1
- <script type="text/javascript" src="/files/min.js"></script>
2
-
3
1
  <script type="text/javascript">
4
- document.addEventListener('DOMContentLoaded', function() {
5
- Array.prototype.forEach.call(document.getElementsByClassName("indeterminate"), element => {
6
- element.indeterminate = true;
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>