Skip to content

fix(rooms): use the app's own RoomType→name strings; drop per-model overrides (#22)#48

Open
jgus wants to merge 2 commits into
sjmotew:masterfrom
jgus:fix/room-type-names
Open

fix(rooms): use the app's own RoomType→name strings; drop per-model overrides (#22)#48
jgus wants to merge 2 commits into
sjmotew:masterfrom
jgus:fix/room-type-names

Conversation

@jgus

@jgus jgus commented Jun 14, 2026

Copy link
Copy Markdown

Summary

Unnamed rooms were getting the wrong type label. The base ROOM_TYPE_NAMES table
was mis-derived (shifted from index 5 on — 5→Study, 8→Corridor, 11→Cloak Room…),
and a per-product_key override map had been bolted on to patch it. This replaces
both with the app's own room-type names, verified by reverse-engineering the Narwal app.

Addresses #22.

Evidence (from the decompiled app)

Room-type naming in the app is model-independent — there is nothing to override:

  1. One shared switch, keyed only on the enum. MapEnginei18nConfiger.roomTypei18nKey(int)
    takes just the RoomType int — no product_key/model/device/sn argument, and it
    reads no instance state. It maps the enum to map_room_name_* i18n keys.
  2. One shared enum. MapBaseType.RoomType has 16 constants; the switch handles them in
    value order 0–15.
  3. One shared localization. Those keys resolve through a single en-US.json in the app's
    shared app_res_config package — not per-model.
  4. Live-confirmed. A production Flow 2 matched the mapping at values 3/4/8/11
    (Living room, Kitchen, Dining room, Study).

The resulting table is taken verbatim from the app's en-US.json:

0 Room · 1 Master bedroom · 2 Secondary bedroom · 3 Living room · 4 Kitchen ·
5 Bathroom · 6 Toilet · 7 Balcony · 8 Dining room · 9 Closet · 10 Corridor ·
11 Study · 12 Kids' room · 13 Entertainment room · 14 Storage room · 15 Others

Changes

  • narwal_client/models.py (and the embedded custom_components/narwal/narwal_client/
    copy): set ROOM_TYPE_NAMES to the verbatim app strings; remove MODEL_ROOM_TYPE_OVERRIDES,
    the RoomInfo.model_key field, and the override lookup in display_name; drop the now-unused
    product_key parameter from MapData.from_response; fix the stale RoomInfo field-2 docstring
    (it still listed the old, wrong enum).
  • narwal_client/client.py (and embedded copy): get_map() no longer computes/passes a
    product_key to from_response.
  • tests/test_models.py: rewrite TestRoomInfoModelOverridesTestRoomInfoNames (the
    override premise is gone); assert the verbatim names, including values that were previously
    paraphrased.
  • tests/test_vacuum_segments.py: segment-name assertion updated (Toilet 2).

Testing

  • pytest tests/ — 166 passed.
  • Verified live on a Flow 2: HA showed a "rooms changed" remap and unnamed rooms now read the
    correct labels (Study, Dining room, …).

Footnote — localization (out of scope for this PR): the app ships these names in 23
locales, so the integration could later localize unnamed-room type labels to the user's Home
Assistant language. Some locales are untranslated stubs (e.g. pt-BR ships the keys
empty), so such a follow-up would need an English fallback. User-assigned room names are
unaffected — they pass through as-is regardless of language.

…verrides (sjmotew#22)

The base ROOM_TYPE_NAMES was mis-derived (shifted from index 5 on: 5→Study,
8→Corridor, 11→Cloak Room…), so unnamed rooms got the wrong type label, and a
per-product_key override map had been added to paper over it.

Reverse-engineering the app shows there is nothing to override — room-type naming
is model-independent:
- map_engine_i18n_configer.roomTypei18nKey(int) is a single switch keyed only on
  the RoomType enum (MapBaseType.RoomType, 16 constants); it takes no
  product_key/model/device argument and reads no instance state.
- It returns map_room_name_* keys resolved through one shared en-US.json in the
  app_res_config package — not per-model.
- Live Flow 2 data matched the mapping (values 3/4/8/11: Living room, Kitchen,
  Dining room, Study).

Adopt the app's exact en-US.json strings (e.g. "Living room", "Closet",
"Kids' room", "Entertainment room", "Storage room", "Others"), remove the
MODEL_ROOM_TYPE_OVERRIDES / model_key plumbing and the get_map product_key pass,
and fix the stale RoomInfo field-2 docstring (it still listed the old wrong enum).

Tests assert the verbatim names (including values that were previously
paraphrased); both client copies updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Jun 14, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes incorrect room-type labels for unnamed rooms by replacing the mis-derived ROOM_TYPE_NAMES table and the per-model override mechanism with the verbatim strings from the app's own en-US.json. The change is backed by decompiled-app evidence and live-confirmed on a Flow 2.

  • ROOM_TYPE_NAMES is now a ClassVar with the correct 16-entry table (fixing the previously shifted values at indices 5, 8, 10, 11); MODEL_ROOM_TYPE_OVERRIDES, model_key, and __post_init__ are all removed.
  • MapData.from_response and NarwalClient.get_map drop the now-unnecessary product_key parameter.
  • Tests are rewritten to assert all 16 verbatim names (including the previously wrong entries) and the Toilet 2 segment-name fixture is updated to match index 6's new value.

Confidence Score: 5/5

Safe to merge — the change is a straightforward table correction backed by decompiled-app evidence and live device verification, with all 16 enum values now explicitly tested.

The removal of the per-model override machinery is complete and consistent across both the library and embedded custom-component copies. The new ROOM_TYPE_NAMES table is a ClassVar with the verbatim app strings. All callers of from_response and display_name have been updated, no stale model_key references remain, and the rewritten tests cover every entry in the table including the four values that were previously wrong.

No files require special attention.

Important Files Changed

Filename Overview
narwal_client/models.py Removes model_key, MODEL_ROOM_TYPE_OVERRIDES, and post_init; promotes ROOM_TYPE_NAMES to ClassVar with the correct 16-entry verbatim table; simplifies display_name and from_response.
custom_components/narwal/narwal_client/models.py Identical changes to the embedded copy of models.py; both copies are in sync.
narwal_client/client.py Removes product_key extraction and passing to MapData.from_response; clean two-line simplification.
tests/test_models.py TestRoomInfoModelOverrides rewritten to TestRoomInfoNames; loop asserts all 16 verbatim names including the four previously-wrong values (5, 8, 10, 11); adds unknown-sub-type fallback test.
tests/test_vacuum_segments.py Single fixture update: room_sub_type=6 was 'Bathroom 2', correctly updated to 'Toilet 2' to match the new table.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[NarwalClient.get_map] -->|send_command| B[resp.data]
    B --> C[MapData.from_response\ndecoded]
    C -->|for each room in field 2.12| D[RoomInfo\nroom_id, name, room_sub_type,\ncategory, instance_index]
    D --> E{name set?}
    E -->|yes| F[return name]
    E -->|no| G[ROOM_TYPE_NAMES.get\nroom_sub_type, 'Room']
    G --> H{instance_index > 1?}
    H -->|yes| I[return 'BaseName N']
    H -->|no| J[return 'BaseName']
Loading

Reviews (2): Last reviewed commit: "Feedback addressed" | Re-trigger Greptile

Comment thread narwal_client/models.py Outdated
Comment thread custom_components/narwal/narwal_client/models.py Outdated
Comment thread tests/test_models.py Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant