Skip to content

Commit 0ce7900

Browse files
committed
docs(re): record the cloud attribute table, load base, and the fault namespace
Static RE of the stock dump, no bus tap needed. Three things worth having: * Load base 0x9b6d0000 (address = base + file_offset). Derived by pointer analysis: 77 of 77 attribute-name strings resolve under this base and no other, and it reproduces the getter addresses already cited in section 5a. This was never written down, and without it no static RE on this dump is reproducible. * The attribute name blob (file 0x13730a) and its 12-byte-stride lookup table (file 0x137e34), which carry the Hisense cloud attribute namespace the ConnectLife app speaks. * The 27 f_e_* fault attributes behind the app's Self diagnostics screen, and the observation that they are almost certainly bit-packed into the 160-byte status frame we already poll once a second. If so, a diagnostics feature needs the bit map, not new polling. Also corrects a claim made earlier today: t_8heat and t_8c_heater_onoff both exist, so 8 C frost-guard heat IS commandable by the stock module. Its absence from the app is a UI choice, not a protocol limit. Section 7.5 deliberately records what is NOT established. meta0 looks like a (byte, bit) position for the fault entries, but duplicate values, a non-uniform layout across attribute types, and a direct conflict with the known adjacency of eco/turbo in status byte 35 all refute that reading. Written down so the next reader does not re-derive the same wrong answer. Assisted-by: AI
1 parent 5cca112 commit 0ce7900

1 file changed

Lines changed: 103 additions & 0 deletions

File tree

reverse-engineering/docs/10-stock-fw-init-and-comms.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,3 +476,106 @@ and the full loop closes end-to-end — commissioned onto the Matter fabric, `Lo
476476
Standalone setpoint writes (`OccupiedCooling/HeatingSetpoint`) return IM `0x86` (a cluster
477477
deadband/limit constraint); the setpoint also rides the mode `0x65` at byte19. Build-by-build
478478
v3→v4→v5 debugging detail is in git history.
479+
480+
## 7. Cloud attribute table (`t_*` / `f_*` / `f_e_*`) [PROVEN location, 2026-07-19]
481+
482+
The module carries the full Hisense **cloud attribute** namespace as a name blob plus a
483+
lookup table. This is the vocabulary the ConnectLife app speaks, and it is the source of the
484+
app's "Self diagnostics" screen. Found by string+pointer analysis of `dumps/w41h1_dump1.bin`
485+
(local-only, gitignored); no bus tap required.
486+
487+
### 7.1 Load base [PROVEN]
488+
489+
**`base = 0x9b6d0000`**, so `address = 0x9b6d0000 + file_offset`.
490+
491+
Derived by taking every attribute-name string offset, scanning the image for 32-bit LE words
492+
that could be pointers to them, and keeping the base with the most consistent hits:
493+
**77 of 77** names are referenced under this base and no other. Cross-checks against the
494+
addresses already in §5a hold: the `ac_8heat` getter `0x9b6f0ee6` maps to file `0x20ee6`,
495+
inside the code region.
496+
497+
This base was not previously written down. It is what makes any further static RE on this
498+
dump reproducible, so record it before anything else.
499+
500+
### 7.2 Name blob and lookup table [PROVEN]
501+
502+
| item | file offset | address |
503+
|---|---|---|
504+
| attribute-name string blob | `0x13730a` .. `0x137700` | `0x9b80730a` .. |
505+
| attribute lookup table | starts `0x137e34` | `0x9b807e34` |
506+
507+
Table entries are **12 bytes**: `[meta0: u32 LE][meta1: u32 LE][name_ptr: u32 LE]`, where
508+
`name_ptr` points into the blob. Walking the table yields 66 entries before the name-pointer
509+
sanity check fails.
510+
511+
**The `meta0` encoding is NOT yet decoded.** See §7.5 before assuming anything about it.
512+
513+
### 7.3 The fault namespace: what "Self diagnostics" reads [PROVEN names]
514+
515+
27 `f_e_*` (fault/error) attributes exist. The app's four categories are a bucketing of these:
516+
517+
| app category | attributes |
518+
|---|---|
519+
| Sensors | `f_e_intemp` `f_e_incoiltemp` `f_e_outtemp` `f_e_outcoiltemp` `f_e_outgastemp` `f_e_tubetemp` `f_e_inhumidity` `f_e_wetsensor` `f_e_temp` |
520+
| Communications | `f_e_incom` `f_e_inwifi` `f_e_push` |
521+
| Motors | `f_e_infanmotor` `f_e_pump` `f_e_arkgrille` `f_e_upmachine` `f_e_dwmachine` |
522+
| Others | `f_e_ineeprom` `f_e_outeeprom` `f_e_inkeys` `f_e_indisplay` `f_e_inele` `f_e_invzero` `f_e_filterclean` `f_e_waterfull` `f_e_over_cold` `f_e_over_hot` `f_e_dwmachine` |
523+
524+
(The category mapping is inferred from the names, not read out of the firmware. The names
525+
themselves are `[PROVEN]`.)
526+
527+
These are almost certainly bit-packed into the 160-byte status frame we already receive once
528+
per second, which means **no new polling is needed to build a diagnostics feature**, only the
529+
bit map.
530+
531+
### 7.4 Settable attributes worth noting [PROVEN names]
532+
533+
The `t_` prefix marks a settable attribute. Two matter for open issues:
534+
535+
* **`t_8heat`** and **`t_8c_heater_onoff`** both exist. 8 °C frost-guard heat therefore **is**
536+
commandable by the stock module. An earlier note in this session claimed no command verb
537+
existed for it; that was wrong, and the absence of an 8 °C control in the ConnectLife app is
538+
a UI choice, not a protocol limit.
539+
* `t_dimmer` exists alongside the display on/off control, which is the likely path to the
540+
panel-brightness *level* (the 2-bit `ac_power_display`), currently out of scope.
541+
542+
The table also names capabilities this unit probably does not implement: `t_fresh_air`,
543+
`f_co2_value`, `f_co2_level`, `t_onekey_selfclean`, `t_indoor_selfclean`,
544+
`t_outdoor_selfclean`, `t_hp_lock_onoff`, `t_ht_lock_onoff`, `t_heat_control_logic`,
545+
`t_interlock_onoff`, `t_demand_response`. Per the design rule in `docs/11 §5.1`, gate on the
546+
capability flags at runtime rather than deleting these paths.
547+
548+
### 7.5 What is NOT established, and the trap in it
549+
550+
`meta0` is **not** a plain (byte, bit) frame position. The tempting read is that byte 2 is an
551+
offset and byte 3 a bit index, because the fault entries look orderly:
552+
553+
```
554+
f_e_incoiltemp 00 00 18 0f f_e_inkeys 00 00 19 0f
555+
f_e_inhumidity 00 00 18 0e f_e_inwifi 00 00 19 0e
556+
f_e_infanmotor 00 00 18 0d f_e_inele 00 00 19 0d
557+
```
558+
559+
Three things block that reading:
560+
561+
1. **Duplicates.** `f_e_arkgrille` and `f_e_dwmachine` are both `00 00 18 0b`;
562+
`f_e_invzero` and `f_e_over_cold` are both `00 00 18 0a`. Two faults cannot share one bit.
563+
2. **Non-uniform layout.** Entries such as `t_temp` (`03 03 03 0b`) and `t_fan_speed`
564+
(`08 01 0b 09`) use bytes 0 and 1, which every `f_e_*` entry leaves zero. So `meta0` is at
565+
least two different shapes, probably keyed by type.
566+
3. **Anchor conflict.** `t_eco` is `00 00 8c 80` while `t_super` (turbo) is `14 05 15 0a`, yet
567+
eco and turbo are known to be **adjacent bits in status byte 35**. A position encoding that
568+
puts them far apart is refuted by hardware we already trust.
569+
570+
The duplicates most likely mean the walk crossed into a **second capability template**
571+
(`docs/11` documents multiple templates in flash), so the table bounds are themselves
572+
unconfirmed.
573+
574+
### 7.6 Next step
575+
576+
Extend the §5a method to the fault attributes: disassemble the getters and read the
577+
`(status byte, bitmask)` pairs out of the code, exactly as was done for the `ac_*` capability
578+
flags. §5a already gives the pattern and the neighbouring addresses
579+
(`0x9b6f0d0a`, `0x9b6f0ee6`), and §7.1 now gives the base needed to navigate there.
580+
581+
Do **not** infer fault bit positions from `meta0` alone until §7.5 is resolved.

0 commit comments

Comments
 (0)