Skip to content

Commit 0db40f8

Browse files
committed
fix(api): verify writes by read-back; honest save feedback
Two real problems fixed: 1. The API reported 'written: true' based on the dongle's echo, but the dongle can echo a write without forwarding it to the inverter. Now the API reads the register back after writing and only reports success when the value actually stuck. Invalid values (e.g. hour=30) now correctly return 502 'Modbus error response: code 53' instead of false success. 2. The schedule save button gave no visible feedback: the message element was at the bottom of the page (below the fold) and the inputs were never reloaded after save. Added a dedicated #schedule-msg element inside the schedule card, and reload the authoritative inverter values after save so the inputs reflect what actually stuck.
1 parent 5f0f988 commit 0db40f8

2 files changed

Lines changed: 31 additions & 2 deletions

File tree

‎api/__init__.py‎

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1168,6 +1168,7 @@ def api_automation_registers():
11681168
AUTOMATION_TYPES,
11691169
ALL_CONDITION_KINDS,
11701170
SETTING_NAME_TO_REGISTER,
1171+
_read_holding_register,
11711172
)
11721173

11731174

@@ -1674,7 +1675,31 @@ def api_holding_put(name: str, body: HoldingUpdate):
16741675
time.sleep(0.7)
16751676
if not ok:
16761677
raise HTTPException(502, f"Failed to write {name}: {msg}")
1677-
logger.info("Wrote holding register %s (address %d) = %d", name, reg, raw_value)
1678+
1679+
# VERIFY: the dongle can echo a write without actually forwarding it to
1680+
# the inverter. Read the register back and confirm it stuck before
1681+
# reporting success. This is the difference between "the dongle ACKed"
1682+
# and "the inverter actually applied it".
1683+
verified = False
1684+
for attempt in range(4):
1685+
rok, rval, rmsg = _read_holding_register(
1686+
dongle["dongle_host"],
1687+
dongle["dongle_port"],
1688+
dongle["datalog_serial"],
1689+
dongle["inverter_serial"],
1690+
reg,
1691+
)
1692+
if rok and rval == raw_value:
1693+
verified = True
1694+
break
1695+
time.sleep(0.5)
1696+
if not verified:
1697+
raise HTTPException(
1698+
502,
1699+
f"Write to {name} not confirmed on inverter (echoed but read-back mismatch)",
1700+
)
1701+
1702+
logger.info("Wrote holding register %s (address %d) = %d (verified)", name, reg, raw_value)
16781703
return {"name": name, "address": reg, "raw": raw_value, "written": True, "message": msg}
16791704

16801705

‎api/static/index.html‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ <h3>Timer Schedule</h3>
289289
<button class="btn" id="btn-save-schedule">Save Schedule</button>
290290
</div>
291291
<div id="schedule-editor"></div>
292+
<div id="schedule-msg" style="margin-top:0.75rem; font-size:0.9rem; font-weight:600;"></div>
292293
</div>
293294
</div>
294295

@@ -1035,7 +1036,7 @@ <h4 style="margin-bottom:0.5rem;">${g.title}</h4>
10351036
});
10361037
}
10371038
async function saveSchedule() {
1038-
const msg = document.getElementById('auto-msg');
1039+
const msg = document.getElementById('schedule-msg') || document.getElementById('auto-msg');
10391040
const el = document.getElementById('schedule-editor');
10401041
if (!el) return;
10411042
const values = {};
@@ -1088,6 +1089,9 @@ <h4 style="margin-bottom:0.5rem;">${g.title}</h4>
10881089
msg.textContent = `Value set — ${written} register${written === 1 ? '' : 's'} written.`;
10891090
msg.style.color = 'var(--green-color)';
10901091
}
1092+
// Reload the authoritative inverter values so the inputs reflect what
1093+
// actually stuck (the dongle can echo a write without applying it).
1094+
try { await loadAutomationSettings(); renderSchedule(); } catch (e) {}
10911095
} catch (e) {
10921096
msg.textContent = 'Error setting value: ' + e.message; msg.style.color = 'var(--red-color)';
10931097
}

0 commit comments

Comments
 (0)