v0.14.1
This commit is contained in:
+137
-11
@@ -698,7 +698,7 @@ async function openDeviceDetails(id) {
|
||||
const device = app.devices.find(item => item.id === id); if (!device) return;
|
||||
const form = $('#deviceDetailsForm'); if (!form) return;
|
||||
form.reset();
|
||||
form.id.value = device.id;
|
||||
form.elements.id.value = device.id;
|
||||
form.name.value = device.name || '';
|
||||
form.energy_source.value = device.energy_source || 'auto';
|
||||
const title = $('#deviceDetailsTitle');
|
||||
@@ -707,10 +707,24 @@ async function openDeviceDetails(id) {
|
||||
if (meta) meta.innerHTML = device.connection_type === 'gree_cloud'
|
||||
? `<div><span>${esc(tr('devices.connection'))}</span><strong>GREE Cloud</strong></div><div><span>${esc(tr('devices.transport'))}</span><strong>MQTT / TLS</strong></div><div><span>${esc(tr('devices.cloudDeviceId'))}</span><strong>${esc(device.cloud_device_id || device.mac || '—')}</strong></div><div><span>MAC</span><strong>${esc(device.mac || '—')}</strong></div>`
|
||||
: `<div><span>${esc(tr('devices.connection'))}</span><strong>Local</strong></div><div><span>${esc(tr('devices.address'))}</span><strong>${esc(device.ip || '—')}:${esc(device.port || 7000)}</strong></div><div><span>MAC</span><strong>${esc(device.mac || '—')}</strong></div>`;
|
||||
|
||||
const installation = deviceInstallationForDevice(device.id);
|
||||
const groupNote = $('#deviceEnergyGroupNote');
|
||||
const groupOwnsEnergy = !!installation && (!!installation.energy_device_id || !!installation.ha_energy_entity_id);
|
||||
if (groupNote) {
|
||||
groupNote.hidden = !groupOwnsEnergy;
|
||||
groupNote.innerHTML = groupOwnsEnergy
|
||||
? `<span>${esc(deviceInstallationKindLabel(installation))}</span><strong>${esc(tr('devices.groupedEnergyNote', { name: installation.name, source: installationEnergySourceLabel(installation) }))}</strong>`
|
||||
: '';
|
||||
}
|
||||
|
||||
const source = form.energy_source;
|
||||
if (groupOwnsEnergy) source.value = installation.energy_source || 'auto';
|
||||
source.disabled = groupOwnsEnergy;
|
||||
const cloudOption = [...source.options].find(option => option.value === 'gree_cloud');
|
||||
if (cloudOption) cloudOption.disabled = device.capabilities?.energy_meter !== true;
|
||||
const sensorSelect = form.ha_energy_entity_id;
|
||||
sensorSelect.disabled = groupOwnsEnergy;
|
||||
sensorSelect.innerHTML = '<option value="">—</option>';
|
||||
try {
|
||||
const response = await api('/api/integrations/home-assistant/energy-sensors');
|
||||
@@ -723,23 +737,135 @@ async function openDeviceDetails(id) {
|
||||
option.dataset.stateClass = sensor.state_class || '';
|
||||
sensorSelect.append(option);
|
||||
}
|
||||
} catch (_) {
|
||||
// Home Assistant is optional; keep any already-saved entity available even when HA is offline.
|
||||
}
|
||||
if (device.ha_energy_entity_id && ![...sensorSelect.options].some(option => option.value === device.ha_energy_entity_id)) {
|
||||
} catch (_) { }
|
||||
const energyEntity = groupOwnsEnergy ? installation.ha_energy_entity_id : device.ha_energy_entity_id;
|
||||
const energyUnit = groupOwnsEnergy ? installation.ha_energy_unit : device.ha_energy_unit;
|
||||
const energyDeviceClass = groupOwnsEnergy ? installation.ha_energy_device_class : device.ha_energy_device_class;
|
||||
const energyStateClass = groupOwnsEnergy ? installation.ha_energy_state_class : device.ha_energy_state_class;
|
||||
if (energyEntity && ![...sensorSelect.options].some(option => option.value === energyEntity)) {
|
||||
const option = document.createElement('option');
|
||||
option.value = device.ha_energy_entity_id;
|
||||
option.textContent = device.ha_energy_entity_id;
|
||||
option.dataset.unit = device.ha_energy_unit || '';
|
||||
option.dataset.deviceClass = device.ha_energy_device_class || '';
|
||||
option.dataset.stateClass = device.ha_energy_state_class || '';
|
||||
option.value = energyEntity;
|
||||
option.textContent = energyEntity;
|
||||
option.dataset.unit = energyUnit || '';
|
||||
option.dataset.deviceClass = energyDeviceClass || '';
|
||||
option.dataset.stateClass = energyStateClass || '';
|
||||
sensorSelect.append(option);
|
||||
}
|
||||
sensorSelect.value = device.ha_energy_entity_id || '';
|
||||
sensorSelect.value = energyEntity || '';
|
||||
updateDeviceEnergySensorMeta();
|
||||
openDialog('deviceDetailsDialog');
|
||||
}
|
||||
|
||||
function renderDeviceGroupsDialogList() {
|
||||
const host = $('#deviceGroupsList'); if (!host) return;
|
||||
const groups = app.deviceGroups || [];
|
||||
host.innerHTML = groups.length ? groups.map(group => {
|
||||
const members = (group.device_ids || []).map(id => app.devices.find(device => device.id === id)?.name).filter(Boolean);
|
||||
return `<div class="installation-list-row"><button type="button" data-action="edit-device-group" data-id="${esc(group.id)}"><strong>${esc(group.name)}</strong><small>${esc(deviceInstallationKindLabel(group))} · ${esc(members.join(' · ') || '—')} · ${esc(installationEnergySourceLabel(group))}</small></button><div><button type="button" class="secondary" data-action="edit-device-group" data-id="${esc(group.id)}">${esc(tr('actions.edit'))}</button><button type="button" class="danger" data-action="delete-device-group" data-id="${esc(group.id)}">${esc(tr('actions.delete'))}</button></div></div>`;
|
||||
}).join('') : `<div class="empty"><strong>${esc(tr('devices.newInstallation'))}</strong><span>${esc(tr('devices.installationsHint'))}</span></div>`;
|
||||
}
|
||||
|
||||
function selectedDeviceGroupIds() {
|
||||
return $$('#deviceGroupDeviceChoices input[type="checkbox"]:checked').map(input => input.value);
|
||||
}
|
||||
|
||||
function syncDeviceGroupMemberSelects() {
|
||||
const form = $('#deviceGroupForm'); if (!form) return;
|
||||
const ids = selectedDeviceGroupIds();
|
||||
const energy = form.energy_device_id;
|
||||
const outdoor = form.outdoor_temperature_device_id;
|
||||
const oldEnergy = energy.value, oldOutdoor = outdoor.value;
|
||||
energy.innerHTML = '<option value="">—</option>' + ids.map(id => {
|
||||
const device = app.devices.find(item => item.id === id);
|
||||
if (!device) return '';
|
||||
const supported = device.connection_type === 'gree_cloud' && device.capabilities?.energy_meter === true;
|
||||
return `<option value="${esc(id)}" ${supported ? '' : 'disabled'}>${esc(device.name)}${supported ? '' : ' · —'}</option>`;
|
||||
}).join('');
|
||||
outdoor.innerHTML = `<option value="">${esc(tr('devices.noSharedOutdoor'))}</option>` + ids.map(id => {
|
||||
const device = app.devices.find(item => item.id === id);
|
||||
return device ? `<option value="${esc(id)}">${esc(device.name)}</option>` : '';
|
||||
}).join('');
|
||||
if ([...energy.options].some(option => option.value === oldEnergy && !option.disabled)) energy.value = oldEnergy;
|
||||
if ([...outdoor.options].some(option => option.value === oldOutdoor)) outdoor.value = oldOutdoor;
|
||||
}
|
||||
|
||||
function renderDeviceGroupDeviceChoices(selectedIds = []) {
|
||||
const form = $('#deviceGroupForm');
|
||||
const host = $('#deviceGroupDeviceChoices'); if (!form || !host) return;
|
||||
const currentId = form.elements.id.value;
|
||||
const occupied = new Map();
|
||||
for (const group of (app.deviceGroups || [])) {
|
||||
if (group.id === currentId) continue;
|
||||
for (const id of (group.device_ids || [])) occupied.set(id, group.name);
|
||||
}
|
||||
host.innerHTML = app.devices.map(device => {
|
||||
const owner = occupied.get(device.id);
|
||||
const checked = selectedIds.includes(device.id);
|
||||
return `<label class="check ${owner ? 'disabled' : ''}" title="${owner ? esc(owner) : ''}"><input type="checkbox" name="device_ids" value="${esc(device.id)}" ${checked ? 'checked' : ''} ${owner ? 'disabled' : ''}> <span>${esc(device.name)}${owner ? ` · ${esc(owner)}` : ''}</span></label>`;
|
||||
}).join('');
|
||||
syncDeviceGroupMemberSelects();
|
||||
}
|
||||
|
||||
async function loadDeviceGroupEnergySensors(group = null) {
|
||||
const form = $('#deviceGroupForm'); if (!form) return;
|
||||
const select = form.ha_energy_entity_id;
|
||||
select.innerHTML = '<option value="">—</option>';
|
||||
try {
|
||||
const response = await api('/api/integrations/home-assistant/energy-sensors');
|
||||
for (const sensor of (response.sensors || [])) {
|
||||
const option = document.createElement('option');
|
||||
option.value = sensor.entity_id;
|
||||
option.textContent = `${sensor.name || sensor.entity_id} · ${sensor.unit || ''}`;
|
||||
option.dataset.unit = sensor.unit || '';
|
||||
option.dataset.deviceClass = sensor.device_class || '';
|
||||
option.dataset.stateClass = sensor.state_class || '';
|
||||
select.append(option);
|
||||
}
|
||||
} catch (_) { }
|
||||
if (group?.ha_energy_entity_id && ![...select.options].some(option => option.value === group.ha_energy_entity_id)) {
|
||||
const option = document.createElement('option');
|
||||
option.value = group.ha_energy_entity_id;
|
||||
option.textContent = group.ha_energy_entity_id;
|
||||
option.dataset.unit = group.ha_energy_unit || '';
|
||||
option.dataset.deviceClass = group.ha_energy_device_class || '';
|
||||
option.dataset.stateClass = group.ha_energy_state_class || '';
|
||||
select.append(option);
|
||||
}
|
||||
select.value = group?.ha_energy_entity_id || '';
|
||||
updateDeviceGroupEnergySensorMeta();
|
||||
}
|
||||
|
||||
async function populateDeviceGroupForm(group = null) {
|
||||
const form = $('#deviceGroupForm'); if (!form) return;
|
||||
form.reset();
|
||||
form.elements.id.value = group?.id || '';
|
||||
form.name.value = group?.name || '';
|
||||
form.kind.value = group?.kind || 'split';
|
||||
form.energy_source.value = group?.energy_source || 'auto';
|
||||
renderDeviceGroupDeviceChoices(group?.device_ids || []);
|
||||
syncDeviceGroupMemberSelects();
|
||||
form.energy_device_id.value = group?.energy_device_id || '';
|
||||
form.outdoor_temperature_device_id.value = group?.outdoor_temperature_device_id || '';
|
||||
await loadDeviceGroupEnergySensors(group);
|
||||
}
|
||||
|
||||
async function openDeviceGroupsDialog(groupId = '') {
|
||||
renderDeviceGroupsDialogList();
|
||||
const group = groupId ? (app.deviceGroups || []).find(item => item.id === groupId) : null;
|
||||
await populateDeviceGroupForm(group || null);
|
||||
openDialog('deviceGroupsDialog');
|
||||
}
|
||||
|
||||
function updateDeviceGroupEnergySensorMeta() {
|
||||
const select = $('#deviceGroupForm')?.ha_energy_entity_id;
|
||||
const meta = $('#deviceGroupEnergySensorMeta');
|
||||
if (!select || !meta) return;
|
||||
const option = select.selectedOptions?.[0];
|
||||
meta.textContent = option?.value
|
||||
? `${option.value} · ${option.dataset.deviceClass || 'energy'} · ${option.dataset.stateClass || 'total'} · ${option.dataset.unit || 'kWh'}`
|
||||
: tr('energy.noHaSensor');
|
||||
}
|
||||
|
||||
function updateDeviceEnergySensorMeta() {
|
||||
const select = $('#deviceDetailsForm')?.ha_energy_entity_id;
|
||||
const meta = $('#deviceEnergySensorMeta');
|
||||
|
||||
Reference in New Issue
Block a user