homebridge-intratone 0.5.0 → 0.5.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.
- package/CHANGELOG.md +11 -0
- package/homebridge-ui/public/index.html +75 -43
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `homebridge-intratone`. Versions follow [semver](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## [0.5.1] - 2026-11-12
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- The **Regenerate device ID** button did nothing: the settings UI runs in a sandboxed iframe
|
|
10
|
+
without `allow-modals`, so the `window.confirm()` it used was blocked. It now confirms inline.
|
|
11
|
+
- The settings page left a large empty area and a prominent "Device identity" block. The device-ID
|
|
12
|
+
tools are now a compact, collapsed **Device ID (advanced)** section, and the page resizes to its
|
|
13
|
+
content so there is no empty space.
|
|
14
|
+
|
|
5
15
|
## [0.5.0] - 2026-11-12
|
|
6
16
|
|
|
7
17
|
### Added
|
|
@@ -165,6 +175,7 @@ two-way audio are out of scope.
|
|
|
165
175
|
masked.
|
|
166
176
|
- MIT license.
|
|
167
177
|
|
|
178
|
+
[0.5.1]: https://github.com/jtoucas-DIMO/Homebridge-Intratone/releases/tag/v0.5.1
|
|
168
179
|
[0.5.0]: https://github.com/jtoucas-DIMO/Homebridge-Intratone/releases/tag/v0.5.0
|
|
169
180
|
[0.4.2]: https://github.com/jtoucas-DIMO/Homebridge-Intratone/releases/tag/v0.4.2
|
|
170
181
|
[0.4.1]: https://github.com/jtoucas-DIMO/Homebridge-Intratone/releases/tag/v0.4.1
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
<!-- Custom settings page for homebridge-config-ui-x.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<div id="intratone-doors" class="mb-
|
|
7
|
-
<div id="intratone-device"
|
|
2
|
+
Adds a rename-your-doors list, and a collapsed "Device ID" advanced area with a Regenerate
|
|
3
|
+
button. The standard form (phone number, service, Advanced) is shown via showSchemaForm().
|
|
4
|
+
Note: the UI runs in a sandboxed iframe without allow-modals, so window.confirm/alert are
|
|
5
|
+
blocked — confirmation is done inline. -->
|
|
6
|
+
<div id="intratone-doors" class="mb-2"></div>
|
|
7
|
+
<div id="intratone-device"></div>
|
|
8
8
|
|
|
9
9
|
<script>
|
|
10
10
|
let started = false;
|
|
11
|
+
let block = { platform: 'Intratone', name: 'Intratone' };
|
|
12
|
+
|
|
13
|
+
function fit() {
|
|
14
|
+
try {
|
|
15
|
+
if (typeof homebridge.fixScrollHeight === 'function') {
|
|
16
|
+
homebridge.fixScrollHeight();
|
|
17
|
+
}
|
|
18
|
+
} catch (e) { /* ignore */ }
|
|
19
|
+
}
|
|
11
20
|
|
|
12
21
|
async function init() {
|
|
13
22
|
if (started) {
|
|
@@ -18,11 +27,9 @@
|
|
|
18
27
|
const doors = document.getElementById('intratone-doors');
|
|
19
28
|
const device = document.getElementById('intratone-device');
|
|
20
29
|
|
|
21
|
-
let block;
|
|
22
30
|
try {
|
|
23
31
|
let configs = await homebridge.getPluginConfig();
|
|
24
32
|
if (!configs.length) {
|
|
25
|
-
// config-ui-x renders the schema form only once a config block exists.
|
|
26
33
|
await homebridge.updatePluginConfig([{ platform: 'Intratone', name: 'Intratone' }]);
|
|
27
34
|
configs = await homebridge.getPluginConfig();
|
|
28
35
|
}
|
|
@@ -32,8 +39,8 @@
|
|
|
32
39
|
return;
|
|
33
40
|
}
|
|
34
41
|
|
|
35
|
-
// Fill the Advanced "Device ID" field with the effective id so it is not blank
|
|
36
|
-
// phone number set
|
|
42
|
+
// Fill the Advanced "Device ID" field with the effective id so it is not blank (needs the
|
|
43
|
+
// phone number set; harmless to skip before then).
|
|
37
44
|
try {
|
|
38
45
|
if (!block.device_id) {
|
|
39
46
|
const info = await homebridge.request('/device', { config: block });
|
|
@@ -43,7 +50,7 @@
|
|
|
43
50
|
}
|
|
44
51
|
}
|
|
45
52
|
} catch (error) {
|
|
46
|
-
// No phone number yet
|
|
53
|
+
// No phone number yet — leave Device ID blank for now.
|
|
47
54
|
}
|
|
48
55
|
|
|
49
56
|
try {
|
|
@@ -52,8 +59,6 @@
|
|
|
52
59
|
console.error('showSchemaForm failed', error);
|
|
53
60
|
}
|
|
54
61
|
|
|
55
|
-
renderDeviceTools(device, block);
|
|
56
|
-
|
|
57
62
|
let accesses;
|
|
58
63
|
try {
|
|
59
64
|
homebridge.showSpinner();
|
|
@@ -63,15 +68,17 @@
|
|
|
63
68
|
} finally {
|
|
64
69
|
homebridge.hideSpinner();
|
|
65
70
|
}
|
|
66
|
-
renderDoors(doors,
|
|
71
|
+
renderDoors(doors, accesses);
|
|
72
|
+
renderDeviceTools(device);
|
|
73
|
+
fit();
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
homebridge.addEventListener('ready', init);
|
|
70
77
|
setTimeout(init, 1500);
|
|
71
78
|
|
|
72
|
-
function note(parent, text) {
|
|
79
|
+
function note(parent, text, cls) {
|
|
73
80
|
const p = document.createElement('p');
|
|
74
|
-
p.className = 'help-block text-muted';
|
|
81
|
+
p.className = (cls || 'help-block text-muted') + ' mb-1';
|
|
75
82
|
p.textContent = text;
|
|
76
83
|
parent.appendChild(p);
|
|
77
84
|
}
|
|
@@ -86,30 +93,53 @@
|
|
|
86
93
|
}).toUpperCase();
|
|
87
94
|
}
|
|
88
95
|
|
|
89
|
-
function renderDeviceTools(container
|
|
96
|
+
function renderDeviceTools(container) {
|
|
90
97
|
container.innerHTML = '';
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
const details = document.createElement('details');
|
|
99
|
+
details.addEventListener('toggle', fit);
|
|
100
|
+
|
|
101
|
+
const summary = document.createElement('summary');
|
|
102
|
+
summary.textContent = 'Device ID (advanced)';
|
|
103
|
+
summary.style.cursor = 'pointer';
|
|
104
|
+
details.appendChild(summary);
|
|
105
|
+
|
|
106
|
+
note(details, 'Generate a new device identity. A new device will NOT open the 4G doors until you claim the key (which revokes the phone) or set the ID back. The ID in use is shown in Advanced → Device ID.');
|
|
107
|
+
|
|
108
|
+
const bar = document.createElement('div');
|
|
109
|
+
const regen = document.createElement('button');
|
|
110
|
+
regen.type = 'button';
|
|
111
|
+
regen.className = 'btn btn-secondary btn-sm';
|
|
112
|
+
regen.textContent = 'Regenerate device ID';
|
|
113
|
+
regen.addEventListener('click', () => {
|
|
104
114
|
const id = newUuid();
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
115
|
+
bar.innerHTML = '';
|
|
116
|
+
note(bar, 'Set new device ID ' + id + '?', 'text-danger');
|
|
117
|
+
const yes = document.createElement('button');
|
|
118
|
+
yes.type = 'button';
|
|
119
|
+
yes.className = 'btn btn-danger btn-sm mr-2';
|
|
120
|
+
yes.textContent = 'Confirm';
|
|
121
|
+
yes.addEventListener('click', () => {
|
|
122
|
+
block.device_id = id;
|
|
123
|
+
homebridge.updatePluginConfig([block]);
|
|
124
|
+
homebridge.toast.success('New device ID set. Press Save, then restart the Intratone child bridge.', 'Device ID');
|
|
125
|
+
renderDeviceTools(container);
|
|
126
|
+
fit();
|
|
127
|
+
});
|
|
128
|
+
const no = document.createElement('button');
|
|
129
|
+
no.type = 'button';
|
|
130
|
+
no.className = 'btn btn-link btn-sm';
|
|
131
|
+
no.textContent = 'Cancel';
|
|
132
|
+
no.addEventListener('click', () => { renderDeviceTools(container); fit(); });
|
|
133
|
+
bar.appendChild(yes);
|
|
134
|
+
bar.appendChild(no);
|
|
135
|
+
fit();
|
|
108
136
|
});
|
|
109
|
-
|
|
137
|
+
bar.appendChild(regen);
|
|
138
|
+
details.appendChild(bar);
|
|
139
|
+
container.appendChild(details);
|
|
110
140
|
}
|
|
111
141
|
|
|
112
|
-
function overridesFromConfig(
|
|
142
|
+
function overridesFromConfig() {
|
|
113
143
|
const map = {};
|
|
114
144
|
for (const entry of (block.access_names || [])) {
|
|
115
145
|
if (entry && entry.access_id) {
|
|
@@ -119,7 +149,7 @@
|
|
|
119
149
|
return map;
|
|
120
150
|
}
|
|
121
151
|
|
|
122
|
-
function saveOverrides(
|
|
152
|
+
function saveOverrides(map) {
|
|
123
153
|
const list = Object.keys(map)
|
|
124
154
|
.filter((id) => (map[id] || '').trim())
|
|
125
155
|
.map((id) => ({ access_id: id, name: map[id].trim() }));
|
|
@@ -131,30 +161,32 @@
|
|
|
131
161
|
homebridge.updatePluginConfig([block]);
|
|
132
162
|
}
|
|
133
163
|
|
|
134
|
-
function renderDoors(container,
|
|
164
|
+
function renderDoors(container, accesses) {
|
|
135
165
|
container.innerHTML = '';
|
|
136
166
|
const title = document.createElement('h5');
|
|
137
167
|
title.textContent = 'Your doors';
|
|
168
|
+
title.className = 'mb-1';
|
|
138
169
|
container.appendChild(title);
|
|
139
170
|
|
|
140
171
|
if (!accesses || accesses.error) {
|
|
141
172
|
const reason = accesses && accesses.error ? accesses.error : 'unavailable';
|
|
142
|
-
note(container, 'Could not list your doors (' + reason + '). Set the phone number below and Save first
|
|
173
|
+
note(container, 'Could not list your doors (' + reason + '). Set the phone number below and Save first; unnamed doors keep their detected names in the Home app.');
|
|
143
174
|
return;
|
|
144
175
|
}
|
|
145
176
|
|
|
146
177
|
const list = accesses.openable || [];
|
|
147
|
-
const map = overridesFromConfig(
|
|
178
|
+
const map = overridesFromConfig();
|
|
148
179
|
|
|
149
180
|
note(container, list.length
|
|
150
|
-
? 'Type a name to show it in the Home app, then press Save. Renaming an existing door re-adds it
|
|
151
|
-
: 'No openable doors detected yet.
|
|
181
|
+
? 'Type a name to show it in the Home app, then press Save. Renaming an existing door re-adds it (it may briefly lose its room/automations).'
|
|
182
|
+
: 'No openable doors detected yet.');
|
|
152
183
|
|
|
153
184
|
for (const door of list) {
|
|
154
185
|
const group = document.createElement('div');
|
|
155
|
-
group.className = 'form-group';
|
|
186
|
+
group.className = 'form-group mb-2';
|
|
156
187
|
|
|
157
188
|
const label = document.createElement('label');
|
|
189
|
+
label.className = 'mb-1';
|
|
158
190
|
const where = door.residence ? door.residence + ' / ' : '';
|
|
159
191
|
label.textContent = where + door.name + ' (id ' + door.id + ')';
|
|
160
192
|
group.appendChild(label);
|
|
@@ -166,7 +198,7 @@
|
|
|
166
198
|
input.value = map[door.id] || '';
|
|
167
199
|
input.addEventListener('input', () => {
|
|
168
200
|
map[door.id] = input.value;
|
|
169
|
-
saveOverrides(
|
|
201
|
+
saveOverrides(map);
|
|
170
202
|
});
|
|
171
203
|
group.appendChild(input);
|
|
172
204
|
container.appendChild(group);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-intratone",
|
|
3
3
|
"displayName": "Intratone",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.1",
|
|
5
5
|
"description": "Unofficial Homebridge plugin to open Intratone / Cogelec doors and gates from HomeKit and Matter (remote open, no doorbell).",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "jtoucas-DIMO",
|