homebridge-smartsystem 6.8.13 → 7.0.1

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.
Files changed (75) hide show
  1. package/.vscode/launch.json +15 -4
  2. package/MIXINS-GUIDE.md +210 -0
  3. package/README.md +32 -0
  4. package/SETTINGS-UPDATE.md +195 -0
  5. package/TESTING-GUIDE.md +220 -0
  6. package/WEBSOCKET-API.md +303 -0
  7. package/accessories/accessory.js +20 -4
  8. package/accessories/accessory.ts +19 -4
  9. package/accessories/bulb.js +0 -5
  10. package/accessories/bulb.ts +1 -5
  11. package/accessories/dimmer.js +11 -3
  12. package/accessories/dimmer.ts +11 -4
  13. package/accessories/garagedoor.js +19 -9
  14. package/accessories/garagedoor.ts +21 -9
  15. package/accessories/lock.js +11 -3
  16. package/accessories/lock.ts +10 -3
  17. package/accessories/temperature.js +10 -2
  18. package/accessories/temperature.ts +9 -2
  19. package/accessories/windowcovering.js +30 -14
  20. package/accessories/windowcovering.ts +29 -15
  21. package/config.json +57 -19
  22. package/duotecno/types.js +48 -2
  23. package/duotecno/types.ts +75 -1
  24. package/package.json +12 -4
  25. package/raspberry-pi-setup.sh +80 -0
  26. package/server/HA-API.js +4 -1
  27. package/server/HA-API.ts +4 -1
  28. package/server/HB.js +6 -1
  29. package/server/HB.ts +5 -1
  30. package/server/mDNS.js +168 -0
  31. package/server/mDNS.ts +198 -0
  32. package/server/platform.js +7 -0
  33. package/server/platform.ts +8 -0
  34. package/server/proxy.js +58 -19
  35. package/server/proxy.ts +31 -3
  36. package/server/smartapp.js +397 -18
  37. package/server/smartapp.ts +432 -20
  38. package/server/socapp.js +2 -1
  39. package/server/socapp.ts +2 -1
  40. package/server/views/assets/Duotecno_logo_black.svg +10 -0
  41. package/server/views/assets/Duotecno_logo_white.svg +10 -0
  42. package/server/views/device-details.ejs +139 -0
  43. package/server/views/device-list.ejs +44 -0
  44. package/server/views/footer.ejs +0 -1
  45. package/server/views/head.ejs +9 -0
  46. package/server/views/homekit.ejs +2 -9
  47. package/server/views/link-details.ejs +2 -15
  48. package/server/views/link-list.ejs +2 -9
  49. package/server/views/login.ejs +8 -9
  50. package/server/views/master-detail.ejs +3 -9
  51. package/server/views/master-list.ejs +3 -10
  52. package/server/views/nav.ejs +44 -11
  53. package/server/views/node-details.ejs +1 -8
  54. package/server/views/power-binding.ejs +3 -10
  55. package/server/views/power-rule.ejs +3 -10
  56. package/server/views/power.ejs +8 -15
  57. package/server/views/proxy.ejs +1 -8
  58. package/server/views/scripts.ejs +10 -0
  59. package/server/views/service-list.ejs +2 -9
  60. package/server/views/settings.ejs +61 -22
  61. package/server/views/style.ejs +49 -5
  62. package/server/views/switch-details.ejs +2 -9
  63. package/server/views/switch-list.ejs +2 -9
  64. package/server/webapp.js +150 -11
  65. package/server/webapp.ts +166 -14
  66. package/{index.spec.js → testHB.js} +1 -1
  67. package/{run.js → testProxy.js} +2 -2
  68. package/{run.ts → testProxy.ts} +1 -1
  69. package/testWS.js +137 -0
  70. package/testWS.ts +174 -0
  71. package/run9998.js +0 -7
  72. package/run9998.ts +0 -6
  73. package/run9999.js +0 -7
  74. package/run9999.ts +0 -6
  75. /package/{index.spec.ts → testHB.ts} +0 -0
@@ -0,0 +1,139 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <%- include('/views/head'); -%>
5
+ </head>
6
+
7
+ <body>
8
+ <%- include('/views/nav', this); -%>
9
+
10
+ <form method="POST" action="/devices">
11
+ <input type="hidden" name="daction" value="save">
12
+ <input type="hidden" name="id" value="<%= id %>">
13
+ <h1>
14
+ Device #<%= id+1 %>
15
+ <button class="right btn waves-effect waves-light" type="submit" name="action" value="cancel">Back</button>
16
+ <button class="right btn waves-effect waves-light" type="submit" name="action" value="delete">Delete</button>
17
+ <button class="right btn waves-effect waves-light" type="submit" name="action" value="change">Save</button>
18
+ </h1>
19
+
20
+ <div class="row">
21
+ <div class="input-field col s12">
22
+ <input placeholder="Device Name" id="name" name="name" type="text"
23
+ value="<%= (device.name) %>">
24
+ <label for="name">Name</label>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="row">
29
+ <div class="input-field col s5">
30
+ <select name="master" id="master">
31
+ <% for (let m of masters) { %>
32
+ <option value="<%= m.getURL() %>" <%= (m.same(device.masterAddress, device.masterPort)) ? "selected" : "" %>><%= m.getURL() %></option>
33
+ <% } %>
34
+ </select>
35
+ <label for="master">Master of device unit</label>
36
+ </div>
37
+ </div>
38
+
39
+ <div class="row">
40
+ <div class="input-field col s5">
41
+ <input placeholder="0" id="unit" name="unit" type="text"
42
+ value="<%= hex(device.logicalNodeAddress) %>;<%= hex(device.logicalAddress) %><%= (device.unitName) ? (' (' + device.unitName + ')') : '' %>">
43
+ <label for="unit">Duotecno node;unit (example: 0xfc;0x12) or search unit name</label>
44
+ </div>
45
+ <div class="input-field col s5">
46
+ <select name="unitSelector" id="unitSelector">
47
+ <option value="">Select a unit</option>
48
+ <% for (let u of units) { %>
49
+ <option value="<%= u.node.master.getURL()+"-"+u.logicalNodeAddress+"/"+u.logicalAddress %>"
50
+ <%= ((u.node.master.config.address == device.masterAddress) && (u.node.master.config.port == device.masterPort) && (u.logicalNodeAddress == device.logicalNodeAddress) && (u.logicalAddress == device.logicalAddress)) ? "selected" : "" %>
51
+ ><%= u.name %></option>
52
+ <% } %>
53
+ </select>
54
+ <label for="unitSelector">or Pick a unit</label>
55
+ </div>
56
+ </div>
57
+
58
+ <div class="row">
59
+ <div class="input-field col s6">
60
+ <select name="powerSource" id="powerSource">
61
+ <option value="none" <%= (!device.powerSource || device.powerSource === 'none') ? 'selected' : '' %>>Non-measured (Estimated)</option>
62
+ <option value="p1" <%= (device.powerSource === 'p1') ? 'selected' : '' %>>P1 Meter</option>
63
+ <option value="shelly" <%= (device.powerSource === 'shelly') ? 'selected' : '' %>>Shelly PM</option>
64
+ <option value="smappee" <%= (device.powerSource === 'smappee') ? 'selected' : '' %>>Smappee</option>
65
+ </select>
66
+ <label for="powerSource">Power Source</label>
67
+ </div>
68
+ </div>
69
+
70
+ <div class="row" id="channelRow" style="display: <%= (device.powerSource && device.powerSource !== 'none') ? 'block' : 'none' %>">
71
+ <div class="input-field col s6">
72
+ <input placeholder="Channel/Register" id="powerChannel" name="powerChannel" type="text"
73
+ value="<%= device.powerChannel || '' %>">
74
+ <label for="powerChannel">Power Channel (e.g., "0", "0+1+2")</label>
75
+ </div>
76
+ </div>
77
+
78
+ <div class="row" id="estimatedRow" style="display: <%= (!device.powerSource || device.powerSource === 'none') ? 'block' : 'none' %>">
79
+ <div class="input-field col s6">
80
+ <input placeholder="Estimated Power (W)" id="estimatedPower" name="estimatedPower" type="number"
81
+ value="<%= device.estimatedPower || 0 %>">
82
+ <label for="estimatedPower">Estimated Power (Watts)</label>
83
+ </div>
84
+ </div>
85
+
86
+ <div class="row">
87
+ <div class="input-field col s6">
88
+ <input placeholder="Device ID (auto-calculated)" id="deviceId" name="deviceId" type="text"
89
+ value="<%= device.id %>" readonly>
90
+ <label for="deviceId">Device ID (node * 256 + unit)</label>
91
+ </div>
92
+ </div>
93
+
94
+ </form>
95
+ <%- include('/views/footer'); -%>
96
+
97
+ </body>
98
+
99
+ <%- include('/views/scripts'); -%>
100
+ <script>
101
+ const select = document.getElementById("unitSelector");
102
+ if (select) {
103
+ select.addEventListener("change", function() {
104
+ const parts = this.value.split("-");
105
+ const unitParts = parts[1].split("/");
106
+ const node = parseInt(unitParts[0]);
107
+ const unit = parseInt(unitParts[1]);
108
+
109
+ document.getElementById("unit").value = hex(node) + ";" + hex(unit);
110
+ document.getElementById("master").value = parts[0];
111
+
112
+ // Update device ID
113
+ const deviceId = (node * 256) + unit;
114
+ document.getElementById("deviceId").value = deviceId;
115
+ });
116
+ }
117
+
118
+ // Power source selection
119
+ const powerSourceSelect = document.getElementById("powerSource");
120
+ if (powerSourceSelect) {
121
+ powerSourceSelect.addEventListener("change", function() {
122
+ const channelRow = document.getElementById("channelRow");
123
+ const estimatedRow = document.getElementById("estimatedRow");
124
+
125
+ if (this.value === "none") {
126
+ channelRow.style.display = "none";
127
+ estimatedRow.style.display = "block";
128
+ } else {
129
+ channelRow.style.display = "block";
130
+ estimatedRow.style.display = "none";
131
+ }
132
+ });
133
+ }
134
+
135
+ function hex(nr) {
136
+ return "0x" + nr.toString(16).padStart(2, '0');
137
+ }
138
+ </script>
139
+ </html>
@@ -0,0 +1,44 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <%- include('/views/head'); -%>
5
+ </head>
6
+
7
+ <body>
8
+ <%- include('/views/nav', this); -%>
9
+
10
+ <form method="POST" action="/devices">
11
+ <h1>
12
+ Devices
13
+ <button class="right btn waves-effect waves-light" type="submit" name="action" value="add">Add device</button>
14
+ </h1>
15
+
16
+ <table>
17
+ <thead>
18
+ <tr>
19
+ <th>Name</th><th>ID</th><th>Duotecno Unit</th><th>node/unit</th><th>Measured</th><th>Relay</th>
20
+ </tr>
21
+ </thead>
22
+
23
+ <tbody>
24
+ <% for (let inx in devices) { let device = devices[inx]; %>
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>
30
+ <td><%= device.measured ? '✓' : '✗' %></td>
31
+ <td><%= device.relay ? 'ON' : 'OFF' %></td>
32
+ </tr>
33
+ <% } %>
34
+ </tbody>
35
+ </table>
36
+
37
+ </form>
38
+
39
+ <%- include('/views/footer'); -%>
40
+ </body>
41
+
42
+ <%- include('/views/scripts'); -%>
43
+
44
+ </html>
@@ -1,5 +1,4 @@
1
1
  <footer class="page-footer">
2
- <style> .page-footer a { float: left; margin-left: 10px; color: white; } </style>
3
2
  <p>
4
3
  <a href="/login/logout">Log out</a>
5
4
  Johan Coppieters - Duotecno, 2019-<%= year %> - v<%= version %>
@@ -0,0 +1,9 @@
1
+ <meta charset="UTF-8">
2
+ <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
3
+
4
+ <!--Let browser know website is optimized for mobile-->
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
7
+ <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
8
+
9
+ <%- include('/views/style'); -%>
@@ -1,18 +1,11 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
5
-
6
- <!--Let browser know website is optimized for mobile-->
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
8
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
9
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
-
11
- <%- include('/views/style'); -%>
4
+ <%- include('/views/head'); -%>
12
5
  </head>
13
6
 
14
7
  <body>
15
- <%- include('/views/nav'); -%>
8
+ <%- include('/views/nav', this); -%>
16
9
 
17
10
  <form method="POST" action="/homekit">
18
11
  <input type="hidden" name="daction" value="save">
@@ -1,20 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
5
-
6
- <!--Let browser know website is optimized for mobile-->
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
8
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
9
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
-
11
- <%- include('/views/style'); -%>
12
- <style>
13
- div.select-wrapper input.select-dropdown {
14
- font-size: 16px !important;
15
- height: 3rem !important;
16
- }
17
- </style>
4
+ <%- include('/views/head'); -%>
18
5
  </head>
19
6
 
20
7
  <body>
@@ -24,7 +11,7 @@
24
11
  <input type="hidden" name="daction" value="save">
25
12
  <input type="hidden" name="id" value="<%= id %>">
26
13
  <h1>
27
- Link #<%= id %>
14
+ Link #<%= id+1 %>
28
15
  <button class="right btn waves-effect waves-light" type="submit" name="action" value="cancel">Back</button>
29
16
  <button class="right btn waves-effect waves-light" type="submit" name="action" value="delete">Delete</button>
30
17
  <button class="right btn waves-effect waves-light" type="submit" name="action" value="change">Save</button>
@@ -1,18 +1,11 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
5
-
6
- <!--Let browser know website is optimized for mobile-->
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
8
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
9
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
-
11
- <%- include('/views/style'); -%>
4
+ <%- include('/views/head'); -%>
12
5
  </head>
13
6
 
14
7
  <body>
15
- <%- include('/views/nav'); -%>
8
+ <%- include('/views/nav', this); -%>
16
9
 
17
10
  <form method="POST" action="/links">
18
11
  <h1>
@@ -1,20 +1,19 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
5
-
6
- <!--Let browser know website is optimized for mobile-->
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
8
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
9
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
-
11
- <%- include('/views/style'); -%>
4
+ <%- include('/views/head'); -%>
12
5
  </head>
13
6
 
14
7
  <body>
15
8
  <nav>
16
9
  <div class="nav-wrapper">
17
- <a href="/" target=_blank class="brand-logo hide-on-small-only">Duotecno</a>
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">
12
+ <div style="display: flex; flex-direction: column; line-height: 1.2; margin-top: 12px">
13
+ <span style="font-size: 1.3rem; font-weight: bolder;">Duotecno Gateway</span>
14
+ <span style="font-size: 0.7rem; font-weight: 300;">Configuration Interface</span>
15
+ </div>
16
+ </a>
18
17
  </div>
19
18
  </nav>
20
19
 
@@ -1,19 +1,13 @@
1
1
 
2
-
3
2
  <!DOCTYPE html>
4
3
  <html>
5
4
  <head>
6
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
7
-
8
- <!--Let browser know website is optimized for mobile-->
9
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
10
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
11
-
12
- <%- include('/views/style'); -%>
5
+ <%- include('/views/head'); -%>
13
6
  </head>
14
7
 
15
8
  <body>
16
- <%- include('/views/nav'); -%>
9
+ <%- include('/views/nav', this); -%>
10
+
17
11
  <form method="POST" action="/masters">
18
12
  <input type="hidden" name="daction" value="save">
19
13
  <h1>
@@ -1,19 +1,12 @@
1
-
2
-
3
1
  <!DOCTYPE html>
4
2
  <html>
5
3
  <head>
6
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
7
-
8
- <!--Let browser know website is optimized for mobile-->
9
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
10
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
11
-
12
- <%- include('/views/style'); -%>
4
+ <%- include('/views/head'); -%>
13
5
  </head>
14
6
 
15
7
  <body>
16
- <%- include('/views/nav'); -%>
8
+ <%- include('/views/nav', this); -%>
9
+
17
10
  <form method="POST" action="/masters/new">
18
11
  <h1>
19
12
  Masters
@@ -1,20 +1,53 @@
1
1
  <nav>
2
2
  <div class="nav-wrapper">
3
- <a href="/index.html" target=_blank class="brand-logo hide-on-small-only">Duotecno</a>
4
- <ul id="nav-mobile" class="right">
5
- <li <%= (request === "masters") ? 'class="active"' : '' %></li><a href="/masters">Masters</a></li>
6
- <li <%= (request === "services") ? 'class="active"' : '' %></li><a href="/services">Services</a></li>
7
- <li <%= (request === "proxy") ? 'class="active"' : '' %></li><a href="/proxy">Proxy</a></li>
8
- <li <%= (request === "links") ? 'class="active"' : '' %></li><a href="/links">Links</a></li>
9
- <% if (hasSmappee) { %><li <%= ((request === "power") && (type === "smappee")) ? 'class="active"' : '' %></li><a href="/power?type=smappee">Smappee</a></li><% } %>
10
- <% if (hasP1) { %><li <%= ((request === "power") && (type === "p1")) ? 'class="active"' : '' %></li><a href="/power?type=p1">P1</a></li><% } %>
11
- <% if (hasShelly) { %><li <%= ((request === "power") && (type === "shelly")) ? 'class="active"' : '' %></li><a href="/power?type=shelly">Shelly PM</a></li><% } %>
12
- <li <%= (request === "switches") ? 'class="active"' : '' %></li><a href="/switches">Switches</a></li>
13
- <!-- li <%= (request === "settings") ? 'class="active"' : '' %></li><a href="/settings">Settings</a></li -->
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">
5
+ <div style="display: flex; flex-direction: column; line-height: 1.2; margin-top: 12px">
6
+ <span style="font-size: 1.3rem; font-weight: bolder;">Duotecno Gateway</span>
7
+ <span style="font-size: 0.7rem; font-weight: 300;">Configuration Interface</span>
8
+ </div>
9
+ </a>
10
+
11
+ <!-- Hamburger Menu Icon (Mobile Only) -->
12
+ <a href="#" data-target="mobile-menu" class="sidenav-trigger right"><i class="material-icons">menu</i></a>
13
+
14
+ <!-- Desktop Menu -->
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>
14
26
  </ul>
15
27
  </div>
16
28
  </nav>
17
29
 
30
+ <!-- Mobile Slide-out Menu -->
31
+ <ul class="sidenav" id="mobile-menu">
32
+ <li><div class="user-view">
33
+ <div class="background blue darken-2"></div>
34
+ <span class="white-text name">Duotecno Gateway</span>
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>
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>
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><% } %>
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>
49
+ </ul>
50
+
18
51
  <% if (notReady) { %>
19
52
  <h2>Not ready</h2>
20
53
  <div>
@@ -1,14 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
5
-
6
- <!--Let browser know website is optimized for mobile-->
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
8
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
9
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
-
11
- <%- include('/views/style'); -%>
4
+ <%- include('/views/head'); -%>
12
5
  </head>
13
6
 
14
7
  <body>
@@ -1,18 +1,11 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
5
-
6
- <!--Let browser know website is optimized for mobile-->
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
8
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
9
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
-
11
- <%- include('/views/style'); -%>
4
+ <%- include('/views/head'); -%>
12
5
  </head>
13
6
 
14
7
  <body>
15
- <%- include('/views/nav'); -%>
8
+ <%- include('/views/nav', this); -%>
16
9
 
17
10
  <form method="POST" action="/power">
18
11
  <input type="hidden" name="daction" value="bchange">
@@ -20,7 +13,7 @@
20
13
  <input type="hidden" name="type" value="<%= type %>">
21
14
 
22
15
  <h1>
23
- Binding #<%= id %>
16
+ Binding #<%= id+1 %>
24
17
  <button class="right btn waves-effect waves-light" type="submit" name="action" value="cancel">Back</button>
25
18
  <button class="right btn waves-effect waves-light" type="submit" name="action" value="bdelete">Delete</button>
26
19
  <button class="right btn waves-effect waves-light" type="submit" name="action" value="bchange">Save</button>
@@ -1,25 +1,18 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
5
-
6
- <!--Let browser know website is optimized for mobile-->
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
8
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
9
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
-
11
- <%- include('/views/style'); -%>
4
+ <%- include('/views/head'); -%>
12
5
  </head>
13
6
 
14
7
  <body>
15
- <%- include('/views/nav'); -%>
8
+ <%- include('/views/nav', this); -%>
16
9
 
17
10
  <form method="POST" action="/power">
18
11
  <input type="hidden" name="daction" value="change">
19
12
  <input type="hidden" name="id" value="<%= id %>">
20
13
  <input type="hidden" name="type" value="<%= type %>">
21
14
  <h1>
22
- Power rule #<%= id %>
15
+ Power rule #<%= id+1 %>
23
16
  <button class="right btn waves-effect waves-light" type="submit" name="action" value="cancel">Back</button>
24
17
  <button class="right btn waves-effect waves-light" type="submit" name="action" value="delete">Delete</button>
25
18
  <button class="right btn waves-effect waves-light" type="submit" name="action" value="change">Save</button>
@@ -1,31 +1,24 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
5
-
6
- <!--Let browser know website is optimized for mobile-->
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
8
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
9
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
-
11
- <%- include('/views/style'); -%>
4
+ <%- include('/views/head'); -%>
12
5
  </head>
13
6
 
14
7
  <body>
15
- <%- include('/views/nav'); -%>
8
+ <%- include('/views/nav', this); -%>
16
9
 
17
10
  <form method="POST" action="/power">
18
11
  <input type="hidden" name="daction" value="save">
19
12
  <input type="hidden" name="type" value="<%= type %>">
20
13
  <h1>
21
- Power measuring - <%= type %>
14
+ Power measuring - <%= cap(type) %>
22
15
  <button class="right btn waves-effect waves-light" type="submit" name="action" value="save">Save</button>
23
16
  </h1>
24
17
 
25
18
  <div class="row">
26
19
  <div class="input-field col s12">
27
20
  <input placeholder="xx.xx.xx.xx" id="address" name="address" type="text" value="<%= config.address %>">
28
- <label for="address">Address</label>
21
+ <label for="address"><%= cap(type) %> Address</label>
29
22
  </div>
30
23
  </div>
31
24
 
@@ -33,7 +26,7 @@
33
26
  <div class="row">
34
27
  <div class="input-field col s12">
35
28
  <input id="uid" name="uid" type="text" value="<%= config.uid %>">
36
- <label for="uid">UID</label>
29
+ <label for="uid"><%= cap(type) %> UID</label>
37
30
  </div>
38
31
  </div>
39
32
  <% } %>
@@ -42,7 +35,7 @@
42
35
  <div class="row">
43
36
  <div class="input-field col s12">
44
37
  <input placeholder="xx.xx.xx.xx, ..." id="addresses" name="addresses" type="text" value="<%= config.addresses %>">
45
- <label for="addresses">Addresses (komma separated)</label>
38
+ <label for="addresses">Extra <%= type %> addresses (komma separated)</label>
46
39
  </div>
47
40
  </div>
48
41
  <% } %>
@@ -54,7 +47,7 @@
54
47
  <thead>
55
48
  <tr>
56
49
  <th>Type</th><th>Channel</th><th>Result</th><th>Power</th>
57
- <th>Low...Mid...High</th><th>Current Unit</th>
50
+ <th style="text-align: center">Low ... Mid ... High</th><th>Current Unit</th>
58
51
  </tr>
59
52
  </thead>
60
53
 
@@ -75,7 +68,7 @@
75
68
  (rule.current == 0) ? 'low' : '--'
76
69
  ))) %></a></td>
77
70
  <td><a href="/power/rule/<%= inx %>?type=<%= type%>"><%= ((rule.power) ? rule.power : '-') %></a></td>
78
- <td><a href="/power/rule/<%= inx %>?type=<%= type%>">...<%= rule.low %>...<%= rule.high %>...</a></td>
71
+ <td style="text-align: center"><a href="/power/rule/<%= inx %>?type=<%= type%>">... <%= rule.low %> ... <%= rule.high %> ...</a></td>
79
72
  <td><%= hex(rule.actions[0].logicalNodeAddress) %>;<%= hex(rule.actions[0].logicalAddress) %></td>
80
73
  </tr>
81
74
  <% } %>
@@ -1,14 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
5
-
6
- <!--Let browser know website is optimized for mobile-->
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
8
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
9
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
-
11
- <%- include('/views/style'); -%>
4
+ <%- include('/views/head'); -%>
12
5
  </head>
13
6
 
14
7
  <body>
@@ -5,7 +5,17 @@
5
5
  Array.prototype.forEach.call(document.getElementsByClassName("indeterminate"), element => {
6
6
  element.indeterminate = true;
7
7
  });
8
+
9
+ // Initialize all Materialize components
8
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
+
9
19
  const msg = `<%= (typeof message === 'undefined') ? '' : message %>`;
10
20
  if (msg) M.toast({html: msg});
11
21
  console.log("Ready to rock & roll");
@@ -1,18 +1,11 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <head>
4
- <link type="text/css" rel="stylesheet" href="/files/min.css" media="screen,projection"/>
5
-
6
- <!--Let browser know website is optimized for mobile-->
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
8
- <link rel="shortcut icon" href="/files/favicon.ico" type="image/x-icon" />
9
- <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
10
-
11
- <%- include('/views/style'); -%>
4
+ <%- include('/views/head'); -%>
12
5
  </head>
13
6
 
14
7
  <body>
15
- <%- include('/views/nav'); -%>
8
+ <%- include('/views/nav', this); -%>
16
9
 
17
10
  <form method="POST" action="/units/save">
18
11
  <h1>