Skip to content

Commit b5e7081

Browse files
committed
Fix temperature unit double-conversion in web UI
The server already converts temperature registers to °F (value + unit) in /api/summary, but the client was also converting, producing double-converted values (e.g. 28°C -> 180.3°F instead of 82.4°F). - Factor server conversion into _convert_temperatures() and apply it to the WebSocket snapshot path too, so poll and WS are consistent. - Remove client-side conversion; display the server-provided unit field instead (unitOf helper + data-unit flag on prop()).
1 parent eb80537 commit b5e7081

2 files changed

Lines changed: 50 additions & 50 deletions

File tree

‎api/__init__.py‎

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -545,17 +545,7 @@ def api_summary():
545545
"unit": "V"
546546
}
547547
# Convert temperatures for display if configured in Fahrenheit
548-
cur.execute("SELECT value FROM lux_settings WHERE name = 'temperature_unit'")
549-
row = cur.fetchone()
550-
temp_unit = row[0] if row else "celsius"
551-
if temp_unit == "fahrenheit":
552-
for tkey in ("temp_inverter", "temp_battery", "temp_radiator_1", "temp_radiator_2"):
553-
if tkey in registers:
554-
c = registers[tkey]["value"]
555-
registers[tkey] = {
556-
"value": round(c * 9.0 / 5.0 + 32.0, 1),
557-
"unit": "°F",
558-
}
548+
_convert_temperatures(registers, cur)
559549

560550
# Human-readable working-mode label alongside the raw state code.
561551
if "state" in registers:
@@ -991,6 +981,27 @@ def api_storage():
991981

992982
_active_ws_clients: set = set()
993983

984+
_TEMP_KEYS = ("temp_inverter", "temp_battery", "temp_radiator_1", "temp_radiator_2")
985+
986+
987+
def _convert_temperatures(registers: dict, cur) -> None:
988+
"""Convert temperature registers to °F in-place when configured.
989+
990+
Reads the temperature_unit setting and rewrites the four temperature
991+
registers' value + unit so every API/WS path returns consistent units.
992+
"""
993+
cur.execute("SELECT value FROM lux_settings WHERE name = 'temperature_unit'")
994+
row = cur.fetchone()
995+
temp_unit = row[0] if row else "celsius"
996+
if temp_unit == "fahrenheit":
997+
for tkey in _TEMP_KEYS:
998+
if tkey in registers:
999+
c = registers[tkey]["value"]
1000+
registers[tkey] = {
1001+
"value": round(c * 9.0 / 5.0 + 32.0, 1),
1002+
"unit": "°F",
1003+
}
1004+
9941005

9951006
def _fetch_latest_snapshot() -> Optional[dict]:
9961007
"""Read the most recent snapshot from MariaDB."""
@@ -1012,6 +1023,8 @@ def _fetch_latest_snapshot() -> Optional[dict]:
10121023
row[0]: {"value": float(row[1]), "unit": row[2]}
10131024
for row in cur.fetchall()
10141025
}
1026+
# Convert temperatures for display if configured in Fahrenheit
1027+
_convert_temperatures(registers, cur)
10151028
# Human-readable working-mode label alongside the raw state code.
10161029
if "state" in registers:
10171030
registers["state_label"] = {

‎api/static/index.html‎

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -516,22 +516,6 @@ <h3>7-Day Schedule</h3>
516516
if (num === undefined || num === null || Number.isNaN(num)) return null;
517517
return Math.round(num).toString();
518518
}
519-
// Temperature unit preference (celsius default). Reads the live settings
520-
// object; returns the display suffix and a converter for raw °C values.
521-
function tempUnit() {
522-
const raw = settings.temperature_unit;
523-
const unit = (raw !== null && typeof raw === 'object') ? raw.value : raw;
524-
return (unit === 'fahrenheit') ? 'fahrenheit' : 'celsius';
525-
}
526-
function tempSuffix() {
527-
return tempUnit() === 'fahrenheit' ? ' °F' : ' °C';
528-
}
529-
function fmtTemp(celsius, digits=1) {
530-
if (celsius === undefined || celsius === null || Number.isNaN(celsius)) return null;
531-
const c = Number(celsius);
532-
const v = tempUnit() === 'fahrenheit' ? c * 9 / 5 + 32 : c;
533-
return fmt(v, digits);
534-
}
535519
function fmtTime(iso) {
536520
if (!iso) return '--';
537521
const d = new Date(iso);
@@ -542,6 +526,11 @@ <h3>7-Day Schedule</h3>
542526
const k = r.registers[key];
543527
return k && k.value !== undefined ? k.value : fallback;
544528
}
529+
function unitOf(r, key) {
530+
if (!r || !r.registers) return '';
531+
const k = r.registers[key];
532+
return k && k.unit ? k.unit : '';
533+
}
545534
async function fetchJson(url, options) {
546535
const res = await fetch(url, options);
547536
if (!res.ok) throw new Error(res.statusText);
@@ -562,7 +551,7 @@ <h3>7-Day Schedule</h3>
562551
const stateLabel = val(r,'state_label', null);
563552
setText('sa-inv-state', stateLabel !== null && stateLabel !== undefined ? stateLabel : state);
564553
const invTemp = val(r,'temp_inverter');
565-
setText('sa-inv-temp', invTemp !== undefined ? fmtTemp(invTemp) + tempSuffix() : null);
554+
setText('sa-inv-temp', invTemp !== undefined ? fmt(invTemp) + ' ' + unitOf(r,'temp_inverter') : null);
566555

567556
const pv1 = val(r,'pv1_power') || 0;
568557
const pv2 = val(r,'pv2_power') || 0;
@@ -665,9 +654,9 @@ <h3>7-Day Schedule</h3>
665654
const suffix = opts.suffix || '';
666655
const intAttr = opts.int ? 'data-int="1"' : '';
667656
const digitsAttr = opts.digits ? `data-digits="${opts.digits}"` : '';
668-
const tempAttr = opts.temp ? 'data-temp="1"' : '';
657+
const unitAttr = opts.unit ? 'data-unit="1"' : '';
669658
const suffixAttr = suffix ? `data-suffix="${suffix}"` : '';
670-
return `<div class="prop"><div class="prop-label">${label}</div><div class="prop-value" data-reg="${reg}" ${intAttr} ${digitsAttr} ${tempAttr} ${suffixAttr}>${suffix || '--'}</div></div>`;
659+
return `<div class="prop"><div class="prop-label">${label}</div><div class="prop-value" data-reg="${reg}" ${intAttr} ${digitsAttr} ${unitAttr} ${suffixAttr}>${suffix || '--'}</div></div>`;
671660
}
672661
function detailInverter(r) {
673662
return `<div class="detail-grid"><div class="card"><div class="card-section"><h3>Output</h3><div class="props">
@@ -686,10 +675,10 @@ <h3>7-Day Schedule</h3>
686675
${prop('Warning','warning_code_text')}
687676
${prop('Runtime','runtime',{suffix:' s', int:1})}
688677
</div></div></div><div class="card"><div class="card-section"><h3>Temperatures</h3><div class="props">
689-
${prop('Inverter','temp_inverter',{temp:1})}
690-
${prop('Battery','temp_battery',{temp:1})}
691-
${prop('Radiator 1','temp_radiator_1',{temp:1})}
692-
${prop('Radiator 2','temp_radiator_2',{temp:1})}
678+
${prop('Inverter','temp_inverter',{unit:1})}
679+
${prop('Battery','temp_battery',{unit:1})}
680+
${prop('Radiator 1','temp_radiator_1',{unit:1})}
681+
${prop('Radiator 2','temp_radiator_2',{unit:1})}
693682
</div></div></div></div>`;
694683
}
695684
function detailBattery(r) {
@@ -703,7 +692,7 @@ <h3>7-Day Schedule</h3>
703692
${prop('Power','battery_power',{suffix:' W', int:1})}
704693
${prop('Capacity','battery_capacity',{suffix:' Ah'})}
705694
${prop('Cycles','cycle_count',{int:1})}
706-
${prop('Temp','temp_battery',{temp:1})}
695+
${prop('Temp','temp_battery',{unit:1})}
707696
</div></div></div><div class="card"><div class="card-section"><h3>Cells</h3><div class="props">${cells}</div></div></div></div>`;
708697
}
709698
function detailGrid(r) {
@@ -741,11 +730,11 @@ <h3>7-Day Schedule</h3>
741730
}
742731
function detailEnvironment(r) {
743732
return `<div class="detail-grid"><div class="card"><div class="card-section"><h3>Environment</h3><div class="props">
744-
${prop('Inverter Temp','temp_inverter',{temp:1})}
745-
${prop('Battery Temp','temp_battery',{temp:1})}
746-
${prop('Radiator 1','temp_radiator_1',{temp:1})}
747-
${prop('Radiator 2','temp_radiator_2',{temp:1})}
748-
${prop('Outside Temp','temp_outside',{temp:1})}
733+
${prop('Inverter Temp','temp_inverter',{unit:1})}
734+
${prop('Battery Temp','temp_battery',{unit:1})}
735+
${prop('Radiator 1','temp_radiator_1',{unit:1})}
736+
${prop('Radiator 2','temp_radiator_2',{unit:1})}
737+
${prop('Outside Temp','temp_outside',{unit:1})}
749738
</div></div></div></div>`;
750739
}
751740

@@ -774,17 +763,15 @@ <h3>7-Day Schedule</h3>
774763
if (typeof v === 'string') {
775764
el.textContent = v || '—';
776765
} else {
777-
let text;
778-
if (el.dataset.temp) {
779-
text = fmtTemp(v);
780-
if (text !== null && text !== undefined) text += tempSuffix();
781-
} else {
782-
const fmtFn = el.dataset.int ? fmtInt : (el.dataset.digits ? (n=>fmt(n, Number(el.dataset.digits))) : fmt);
783-
text = fmtFn(v);
784-
if (text === null || text === undefined) text = '--';
785-
if (el.dataset.suffix) text += el.dataset.suffix;
786-
}
766+
const fmtFn = el.dataset.int ? fmtInt : (el.dataset.digits ? (n=>fmt(n, Number(el.dataset.digits))) : fmt);
767+
let text = fmtFn(v);
787768
if (text === null || text === undefined) text = '--';
769+
if (el.dataset.unit) {
770+
const u = unitOf(liveData, el.dataset.reg);
771+
if (u) text += ' ' + u;
772+
} else if (el.dataset.suffix) {
773+
text += el.dataset.suffix;
774+
}
788775
el.textContent = text;
789776
}
790777
}

0 commit comments

Comments
 (0)