v0.15.6
This commit is contained in:
@@ -1538,6 +1538,34 @@ legend {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.local-discovery-row {
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.local-discovery-head {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.local-discovery-head > input[type="checkbox"] {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.local-discovery-head > label {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
min-width: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.local-discovery-head > .badge {
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
* {
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: color-mix(in srgb, var(--accent) 42%, var(--surface-2)) var(--surface-muted);
|
||||
|
||||
+5
-7
@@ -1263,8 +1263,7 @@
|
||||
<h2 data-i18n="discovery.title">Discover GREE devices</h2><button type="button" data-close
|
||||
data-ui-icon="close"></button>
|
||||
</div>
|
||||
<p class="field-note" data-i18n="discovery.help">Auto searches both AES-ECB and AES-GCM devices. Multiple passes
|
||||
improve discovery when several Wi-Fi modules answer the same broadcast.</p>
|
||||
<p class="field-note" data-i18n="discovery.help">Auto accepts both AES-ECB and AES-GCM devices. Selecting V1 or V2 accepts and binds only that protocol. Multiple passes improve discovery when several Wi-Fi modules answer the same broadcast.</p>
|
||||
<label><span data-i18n="discovery.protocol">Discovery protocol</span><select name="protocol_version">
|
||||
<option value="0" data-i18n="devices.protocolAuto">Auto (V1 + V2)</option>
|
||||
<option value="1">V1 AES-ECB</option>
|
||||
@@ -1282,15 +1281,14 @@
|
||||
<dialog id="discoveryNamesDialog">
|
||||
<form method="dialog" id="discoveryNamesForm" class="dialog-form">
|
||||
<div class="dialog-head">
|
||||
<h2 data-i18n="discovery.nameDevices">Name discovered devices</h2><button type="button" data-close
|
||||
<h2 data-i18n="discovery.nameDevices">Discovered local devices</h2><button type="button" data-close
|
||||
data-ui-icon="close"></button>
|
||||
</div>
|
||||
<p class="field-note" data-i18n="discovery.nameDevicesHelp">Give each new unit a friendly room name. The technical
|
||||
model and MAC remain available in diagnostics.</p>
|
||||
<p class="field-note" data-i18n="discovery.nameDevicesHelp">Select the units you want to add. MAC address, IP address and detected protocol are shown for every result.</p>
|
||||
<div id="discoveryNamesList" class="discovery-name-list"></div>
|
||||
<div class="form-actions"><button type="button" class="secondary" data-close
|
||||
data-i18n="actions.later">Later</button><button class="primary" type="submit"
|
||||
data-i18n="actions.save">Save</button></div>
|
||||
data-i18n="actions.cancel">Cancel</button><button class="primary" type="submit"
|
||||
data-i18n="discovery.addSelected">Add selected</button></div>
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ const app = {
|
||||
simulationScope: 'units', simulationTarget: 'all', standaloneSimulation: false, dashboardTab: 'main', settingsTab: 'app', systemSnapshotAt: Date.now(),
|
||||
pingMonitor: { targetId: '', all: false, running: false, timer: null, inFlight: false, samples: {} },
|
||||
flowDraft: null, flowSelectedNodeId: null, flowSelectedNodeIds: [], flowConnectFrom: null, flowDirty: false, flowZoom: 1,
|
||||
localDiscoveryCandidates: [],
|
||||
};
|
||||
try { app.savedCharts = JSON.parse(localStorage.getItem('gree_controller_saved_charts') || '[]'); } catch (_) { app.savedCharts = []; }
|
||||
|
||||
|
||||
@@ -366,22 +366,39 @@ $('#tokenForm').addEventListener('submit', async event => {
|
||||
$('#discoverForm').addEventListener('submit', async event => {
|
||||
event.preventDefault(); const form = event.currentTarget, raw = Object.fromEntries(new FormData(form));
|
||||
await runFormTask(form, async () => {
|
||||
const result = await api('/api/discovery', { method: 'POST', body: { protocol_version: Number(raw.protocol_version), passes: Number(raw.passes), timeout_ms: Number(raw.timeout_ms) } });
|
||||
form.closest('dialog').close(); await loadBootstrap(); toast(tr('toast.found', { count: result.count })); showDiscoveryNames(result.new_device_ids || []);
|
||||
const protocolVersion = Number(raw.protocol_version);
|
||||
const result = await api('/api/discovery/scan', { method: 'POST', body: { protocol_version: protocolVersion, passes: Number(raw.passes), timeout_ms: Number(raw.timeout_ms) } });
|
||||
form.closest('dialog').close();
|
||||
toast(tr('toast.found', { count: result.count }));
|
||||
showDiscoveryNames(result.devices || []);
|
||||
}, { busyKey: 'actions.discovering' });
|
||||
});
|
||||
|
||||
$('#discoveryNamesForm').addEventListener('submit', async event => {
|
||||
event.preventDefault();
|
||||
const form = event.currentTarget;
|
||||
const inputs = $$('input[data-device-id]', form);
|
||||
const selected = $$('[data-discovery-select]:checked', form);
|
||||
if (!selected.length) {
|
||||
toast(tr('discovery.selectAtLeastOne'), true);
|
||||
return;
|
||||
}
|
||||
await runFormTask(form, async () => {
|
||||
const updated = await Promise.all(inputs.map(input => api(`/api/devices/${encodeURIComponent(input.dataset.deviceId)}`, { method: 'PATCH', body: { name: input.value.trim() } })));
|
||||
updated.forEach(updateDevice);
|
||||
const devices = selected.map(input => {
|
||||
const index = Number(input.dataset.discoveryIndex);
|
||||
const candidate = app.localDiscoveryCandidates[index];
|
||||
const nameInput = $(`[data-discovery-name="${index}"]`, form);
|
||||
return { ...candidate, name: String(nameInput?.value || candidate?.name || '').trim() };
|
||||
}).filter(Boolean);
|
||||
const result = await api('/api/discovery/add', {
|
||||
method: 'POST',
|
||||
body: { devices },
|
||||
});
|
||||
await loadBootstrap();
|
||||
form.closest('dialog').close();
|
||||
app.localDiscoveryCandidates = [];
|
||||
renderAll();
|
||||
toast(tr('common.saved'));
|
||||
});
|
||||
toast(tr('discovery.addedCount', { count: result.count }));
|
||||
}, { validate: false });
|
||||
});
|
||||
|
||||
$('#renameDeviceForm').addEventListener('submit', async event => {
|
||||
|
||||
@@ -469,16 +469,27 @@ function beginInlineTemperatureEdit(target) {
|
||||
input.addEventListener('blur', () => finish(true), { once: true });
|
||||
}
|
||||
|
||||
function showDiscoveryNames(ids) {
|
||||
const wanted = new Set(Array.isArray(ids) ? ids : []);
|
||||
const devices = app.devices.filter(device => wanted.has(device.id));
|
||||
if (!devices.length) return;
|
||||
function showDiscoveryNames(devices) {
|
||||
const items = Array.isArray(devices) ? devices : [];
|
||||
app.localDiscoveryCandidates = items.map(item => ({ ...item }));
|
||||
const list = $('#discoveryNamesList');
|
||||
list.innerHTML = devices.map(device => `
|
||||
<label class="discovery-name-row">
|
||||
<span><strong>${esc(device.model || 'GREE')}</strong><small>${esc(device.ip)} · ${esc(device.mac)} · ${device.protocol_version === 2 ? 'V2 GCM' : 'V1 ECB'}</small></span>
|
||||
<input data-device-id="${esc(device.id)}" maxlength="80" required value="${esc(device.name)}">
|
||||
</label>`).join('');
|
||||
if (!list) return;
|
||||
list.innerHTML = items.length ? items.map((device, index) => {
|
||||
const alreadyAdded = device.already_added === true;
|
||||
const protocol = Number(device.protocol_version) === 2 ? 'V2 AES-GCM' : 'V1 AES-ECB';
|
||||
const selectorId = `local-discovery-${index}`;
|
||||
return `<div class="discovery-name-row local-discovery-row">
|
||||
<div class="local-discovery-head">
|
||||
<input type="checkbox" id="${esc(selectorId)}" data-discovery-select data-discovery-index="${index}" ${alreadyAdded ? 'disabled' : 'checked'}>
|
||||
<label for="${esc(selectorId)}">
|
||||
<strong>${esc(device.model || device.name || 'GREE')}</strong>
|
||||
<small>IP ${esc(device.ip || '—')} · MAC ${esc(device.mac || '—')} · ${esc(protocol)}</small>
|
||||
</label>
|
||||
${alreadyAdded ? `<span class="badge">${esc(tr('discovery.alreadyAdded'))}</span>` : ''}
|
||||
</div>
|
||||
<input data-discovery-name="${index}" maxlength="80" value="${esc(device.name || device.model || 'GREE')}" ${alreadyAdded ? 'disabled' : ''} aria-label="${esc(tr('common.name'))}">
|
||||
</div>`;
|
||||
}).join('') : `<div class="empty"><strong>${esc(tr('discovery.empty'))}</strong><span>${esc(tr('discovery.emptyHint'))}</span></div>`;
|
||||
openDialog('discoveryNamesDialog');
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user