class ProgramCard extends HTMLElement { constructor() { super(); this.source = null; } connectedCallback() { this.innerHTML = `

Program

--Pump --

      
`; this.querySelector('#save').addEventListener('click', () => this.saveProgram()); this.querySelectorAll('input[name="programMode"]').forEach(input => input.addEventListener('change', () => this.saveProgram())); window.addEventListener('app:login', event => this.startEvents(event.detail.token)); if (window.App && window.App.token()) this.startEvents(window.App.token()); } disconnectedCallback() { this.stopEvents(); } startEvents(token) { this.stopEvents(); this.loadProgram(); if (!token || !window.EventSource) return; this.source = new EventSource('/api/temperature/events?token=' + encodeURIComponent(token)); this.source.addEventListener('temperature', event => { try { this.renderLiveTemperature(JSON.parse(event.data)); } catch (error) {} }); this.source.addEventListener('pump', event => { try { this.renderPump(JSON.parse(event.data)); } catch (error) {} }); this.source.addEventListener('program', event => { try { this.renderProgramChange(JSON.parse(event.data)); } catch (error) {} }); } stopEvents() { if (this.source) this.source.close(); this.source = null; } selectedMode() { const input = this.querySelector('input[name="programMode"]:checked'); return input ? input.value : 'off'; } renderSettings(json) { if (json.mode !== undefined) { const modeInput = this.querySelector('input[name="programMode"][value="' + json.mode + '"]'); if (modeInput) modeInput.checked = true; } if (json.targetTemperatureC !== undefined) this.querySelector('#target').value = Number(json.targetTemperatureC).toFixed(2); if (json.toleranceC !== undefined) this.querySelector('#threshold').value = Number(json.toleranceC).toFixed(2); if (json.maxRuntimeMinutes !== undefined) this.querySelector('#maxRuntime').value = String(Math.round(Number(json.maxRuntimeMinutes))); } renderLiveTemperature(json) { this.querySelector('#temp').textContent = json.sensorConnected && json.temperatureC !== null ? Number(json.temperatureC).toFixed(2) + ' C' : 'Sensor --'; } renderPump(json) { const enabled = json.enabled !== undefined ? json.enabled : json.pumpEnabled; if (enabled === undefined) return; this.querySelector('#pump').textContent = enabled ? 'Pump on' : 'Pump off'; } render(json) { this.renderSettings(json); this.renderLiveTemperature(json); this.renderPump(json); } renderProgramChange(json) { this.renderSettings(json); this.renderPump(json); } async loadProgram() { const text = await window.App.req('GET', '/api/program'); this.querySelector('#out').textContent = text; try { const json = JSON.parse(text); if (json.success) this.render(json); } catch (error) {} } async saveProgram() { const target = Number(this.querySelector('#target').value); const threshold = Number(this.querySelector('#threshold').value); const maxRuntime = Number(this.querySelector('#maxRuntime').value); const text = await window.App.req('POST', '/api/program', {mode: this.selectedMode(), targetTemperatureC: Number(target.toFixed(2)), toleranceC: Number(threshold.toFixed(2)), maxRuntimeMinutes: Math.round(maxRuntime)}); this.querySelector('#out').textContent = text; try { const json = JSON.parse(text); if (json.success) this.render(json); } catch (error) {} } } customElements.define('program-card', ProgramCard);