Skip to content

Wrong MODEL_ID source: PRODUCT_CODE from /debug/config/info ≠ key prefix in /DWI/getInstantValues (mapping exists but is never matched) #41

@ryja81

Description

@ryja81

Summary

On a Vágner Pool KIT VA DOS BASIC Chlor — pH + ORP (Pt) (Czech rebrand of SEKO PoolDose / Kommander Spot),
python-pooldose==0.7.0 (shipped with Home Assistant Core 2025.11.3 as the pooldose integration) cannot decode any values
from the device, even though a matching mapping file is already present in the package.

Root cause is a two-step naming mismatch inside the device API itself, which the library doesn't compensate for:

  • GET /api/v1/debug/config/info returns DEVICES[0].PRODUCT_CODE = PDHC1H1HAR1V0
  • POST /api/v1/DWI/getInstantValues returns telemetry keys prefixed with PDPR1H1HAR1V0_FW539224_… (PDPR, not PDHC)

pooldose/client.py uses PRODUCT_CODE as MODEL_ID for both mapping-file lookup and the runtime prefix used to read
instant values, so neither step ever matches reality on this device.

Interestingly, the package already ships mappings/model_PDPR1H1HAR1V0_FW539224.json (22 entries), with conversion strings
hardcoded to |PDPR1H1HAR1V0_FW539224_LABEL_…|. The mapping was clearly authored with PDPR in mind — but client.py never picks
it up because it's keyed off PRODUCT_CODE.

Where in the code

Two related lines in client.py (v0.7.0):

# client.py: ~L161  (inside _load_device_info)
self.device_info["MODEL_ID"] = device.get("PRODUCT_CODE")   # → "PDHC1H1HAR1V0"

# client.py: ~L170
model_id = self.device_info.get("MODEL_ID")
fw_code  = self.device_info.get("FW_CODE")
self._mapping_info = await MappingInfo.load(str(model_id), str(fw_code))
# → tries to load model_PDHC1H1HAR1V0_FW539224.json — does not exist
# client.py: ~L259-262  (inside instant_values)
model_id = str(self.device_info.get("MODEL_ID", ""))   # → "PDHC1H1HAR1V0"
fw_code  = str(self.device_info.get("FW_CODE", ""))
prefix   = f"{model_id}_FW{fw_code}_"                  # → "PDHC1H1HAR1V0_FW539224_"
return ..., InstantValues(device_raw_data, mapping, prefix, ...)

InstantValues then does full_device_key = f"{self._prefix}{device_key}" (instant_values.py:159) → looks for keys like
PDHC1H1HAR1V0_FW539224_w_1f0io7hq6 in device_raw_data, but the box only ever sends PDPR1H1HAR1V0_FW539224_w_1f0io7hq6.

So even if the mapping file is renamed to model_PDHC1H1HAR1V0_FW539224.json, the prefix computed at runtime is still PDHC…,
and every device_raw_data.get(...) returns None.

Real diagnostic data from the device (LAN)

GET /api/v1/debug/config/info — DEVICE block (relevant fields):

DID:           012400003954_DEVICE
name:          VA DOS CONTROL
PRODUCT_CODE:  PDHC1H1HAR1V0      ← used as MODEL_ID by the lib
FW_CODE:       539224
release:       2.11
build:         1

POST /api/v1/DWI/getInstantValues — every key in devicedata.012400003954_DEVICE is prefixed PDPR1H1HAR1V0_FW539224_…, e.g.:

PDPR1H1HAR1V0_FW539224_w_1f0inr5mg     (current pH:    6.8)
PDPR1H1HAR1V0_FW539224_w_1f0invtg9     (current ORP:   755 mV)
PDPR1H1HAR1V0_FW539224_w_1f0io42cq     (current Cl:    0.2)
PDPR1H1HAR1V0_FW539224_w_1f0io7hq6     (water temp:    18.5 °C)
PDPR1H1HAR1V0_FW539224_w_1f0irf02j     (pH setpoint:   7.2)
PDPR1H1HAR1V0_FW539224_w_1f0ishl5i     (ORP setpoint:  700 mV)
…

Happy to paste the full payloads of both endpoints if it helps.

Error from HA log (debug enabled)

WARNING (MainThread) [pooldose.mappings.mapping_info] Error loading model mapping:
[Errno 2] No such file or directory:
'/usr/local/lib/python3.13/site-packages/pooldose/mappings/model_PDHC1H1HAR1V0_FW539224.json'

DEBUG  (MainThread) [homeassistant.components.pooldose.coordinator]
Finished fetching Pooldose data in 0.6 seconds (success: False)

Why I think PDHC vs PDPR is a SEKO firmware quirk, not a per-device misconfiguration

  • The shipped model_PDPR1H1HAR1V0_FW539224.json already hardcodes |PDPR1H1HAR1V0_FW539224_LABEL_…| strings inside its
    conversion maps. So the mapping author already had PDPR… payloads in front of them when writing the file.
  • Issue model_PDHC1H1HAR1V1_FW539224.json #13 describes a related mismatch (V1 in identification, V0 in values) on what looks like the same generation of hardware.
  • Two separate fields (the PRODUCT_CODE shown to the user/web UI vs. the per-key namespace inside getInstantValues) come out
    of two unrelated parts of the SEKO firmware. They were apparently never meant to agree.

Suggested fix (one of these, in increasing order of robustness)

  1. Derive the prefix from the actual telemetry payload, not from MODEL_ID. When fetching instant values, scan
    devicedata[device_id] for the longest common prefix that ends in _FW{fw_code}_, and use that for both the file lookup and the
    key prefix. This makes the lib resilient to any future SEKO renaming.

  2. Alias PDHC1H1HAR1V0PDPR1H1HAR1V0 for both file lookup and prefix. Cheap, fixes my device today; less robust if SEKO
    introduces yet another family code.

  3. Ship a PDHC1H1HAR1V0_FW539224.json whose internal conversion strings reference PDHC… AND change client.py to also
    rewrite the prefix → essentially a duplicated alias, more maintenance.

I'd suggest 1 (or 1 + 2 as belt and suspenders). Happy to send a PR if you'd prefer.

Workaround applied locally (verified)

Until upstream fix lands, monkey-patching _load_device_info in client.py:

# right after: self.device_info["MODEL_ID"] = device.get("PRODUCT_CODE")
if self.device_info["MODEL_ID"] == "PDHC1H1HAR1V0":
    self.device_info["MODEL_ID"] = "PDPR1H1HAR1V0"

This makes the lib (a) load the existing model_PDPR1H1HAR1V0_FW539224.json and (b) build a prefix that matches the real
getInstantValues keys. (Will report back once I've applied + restarted HA.)

Thanks for the great work on this integration!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions