Repository navigation
Data loss & silent failure footguns: /sys/custom/*.LoxCC overlays wiped on push, PicoC Code attribute collapse, and TPDC sidecars #28
Description
While using lox-cli (v0.12.0) in a Config-as-Code workflow against a Miniserver Gen 2 (firmware 17.2.x), we identified three critical mechanics where lox config either silently overwrites user changes made in the Loxone App or silently disables embedded logic blocks.
Sharing the root causes and exact protocol mechanics below in case they are helpful for hardening lox-cli.
1. Live App/Web UI Custom Changes (/sys/custom/<UUID>.LoxCC) Are Ignored by download/pull and Wiped by push
Problem
When a user modifies configuration settings at runtime via the Loxone App or Web UI—such as adjusting lighting scenes/moods (LightController2), modifying timer schedules (DayTimer), adding/editing AutopilotRule blocks, or changing room comfort setpoints (IRoomControllerV2)—the Miniserver does not rewrite /prog/sps_<ver>_<timestamp>.zip.
Instead, the Miniserver writes an individual LoxCC-compressed XML fragment for each modified control block to:
/sys/custom/<UUID>.LoxCC
When a new /prog/sps_new.zip is uploaded and loaded on reboot/reload, the Miniserver logs:
Loading sps_new.zip - Remove old custom changes
and deletes all files in /sys/custom/ (assuming the uploader already merged them into sps0.LoxCC, which Loxone Config does during "Load from Miniserver" when the Miniserver logs Read config: combine custom changes).
Because lox config download / pull only downloads /prog/sps_*.zip and ignores /sys/custom/*.LoxCC:
lox config download/pullmisses all runtime App/UI adjustments made since the last full save.- Any subsequent
lox config push(orpatch) triggersRemove old custom changeson the Miniserver and permanently wipes all user scenes, timers, and rules sitting in/sys/custom/. - Even if
/sys/custom/is pulled at the start of an editing session, uploading a full XML snapshot later without a Just-In-Time pull + 3-way merge overwrites any App changes made in the interim.
Format of /sys/custom/<UUID>.LoxCC & Suggested Fix
Each /sys/custom/<UUID>.LoxCC file uses the standard 0xaabbccee LoxCC header/compression and decompresses to a standalone UTF-8 XML fragment for that single <C> element, e.g.:
<?xml version="1.0" encoding="utf-8"?>
<C Type="DayTimer" V="178" U="00000000-0000-0000-ffff000000000001" Title="Example Timer" ...>
<Co K="InputTrigger" U="00000000-0000-0000-ffff000000000002"/>
...
</C>To prevent data loss:
download/pull: After downloading the latest/prog/sps_*.zipand decompressingsps0.LoxCC, list/sys/custom/*.LoxCCvia FTP, decompress each overlay, and replace the matching<C ... U="<UUID>" ...>...</C>block in the base XML (or for a newly createdAutopilotRulewhose UUID is not yet in the base XML, insert it into<C Type="Page" ... SpNo="1">).push/patch: Immediately prior to compressing and uploadingsps_new.zip, fetch the live/prog/sps_*.zip+/sys/custom/*.LoxCCstate and perform a 3-way merge (base -> local_workingrebased ontolive_miniserver) so concurrent App changes are preserved rather than wiped.
2. Multiline PicoC (Code1 / Code4 / Code8 / Code16) Code="..." Collapse Silently Comments Out Entire C Programs
Problem
In released v0.12.0, running any XML-mutating subcommand (e.g. lox config room add, lox config add, lox config set-param, lox config wire-connector) parses and re-serializes the .Loxone XML via xml-rs, which normalizes \r\n newlines inside attribute values into spaces per W3C XML 1.0 Section 3.3.3.
For <C Type="Code16" ... Code="..."> (PicoC) blocks, it is standard practice for the C source in Code="..." to begin with a single-line // header comment on line 1:
// Custom RS485 / HVAC controller logic
char *buf = ...;
while (true) {
...
}When lox-cli collapses \r\n inside Code="..." into single spaces, the entire 150-line C program is concatenated onto line 1 behind the leading // comment. The resulting file still passes lox config validate with 0 errors and compiles cleanly on the Miniserver, silently turning the entire PicoC program into a no-op comment.
Suggested Fix
- Open PR fix(config_edit): stop write-back from adding CRs to multi-line attributes #22 (
fix(config_edit): stop write-back from adding CRs to multi-line attributes) addresses
/
attribute round-tripping inConfigEditor—it would be great to include a<C Type="Code16" Code="// header
int x = 1;
">test case in fix(config_edit): stop write-back from adding CRs to multi-line attributes #22's regression test suite and cut a release with that fix. - Additionally,
lox config validate/checkshould flag a warning or error if aCode1/Code4/Code8/Code16block has a single-lineCode="..."attribute starting with//(or >100 characters with 0 newlines).
3. Touch Pure Display Tree (TPDC, ControlType 544) Sidecar & Checksum Requirements (Related to #20)
Complementing the LoxAPP3.json and permissions.bin findings in #20, if lox-cli adds support for Touch Pure Display Tree switches (TreeDevice with SubType="32811" paired with a <C Type="TPDC"> block), four additional invariants are required for the physical screen to render:
- Bidirectional API Connector Loop (
FLG="1"):TPDC.OutputAPImust referenceOutputRef.AIwithFLG="1"(<In Input="<OutputRef_AI_UUID>" FLG="1" />), whileOutputRef.AIreferencesTPDC.OutputAPI, and the hardwareApiActor.IreferencesOutputRef.AQ. WithoutFLG="1"onOutputAPI, the device reports Online on the Tree bus but displays a blank screen.
- Sidecar Payload (
/prog/TPDISP/<TPDC_UUID>.json):- The screen carousel layout is stored both inside
sps_*.zipatTPDISP/<TPDC_UUID>.jsonand on the FTP filesystem at/prog/TPDISP/<TPDC_UUID>.json. - It uses a 3-line hybrid format:
- Line 0: JSON array of screen items (
[{"U":0,"T":484,...}]) +\n - Line 1:
0x03(ETX byte) + JSON array of referenced rooms +\n - Line 2:
0x03(ETX byte) + JSON array of referenced categories +\n
- Line 0: JSON array of screen items (
- The screen carousel layout is stored both inside
- Signed 32-Bit CRC32 Attributes on
<Displayconf>:<Displayconf CRCS="..." CRCR="..." CRCC="..." CRCI="0" ... CO="uuid0,uuid1,...">inside<C Type="TPDC">must contain the signed 32-bit integer representation ofzlib.crc32over Line 0 (CRCS), Line 1 without the leading0x03(CRCR), and Line 2 without the leading0x03(CRCC).
- Miniserver Built-In
<TechDoc>Schema (/sys/sys_THA.zip->tdc_DEV.xml):- As a useful reference for
lox blocks: the Miniserver stores Loxone's complete 522-block English<TechDoc>XML schema (tdc_DEV.xml, ~693 KB) inside/sys/sys_THA.zipon the FTP filesystem, including every block'sLxType, numericControlType,ShortLink, and allInput/Output/Parameterpins with defaults and units.
- As a useful reference for
Activity