Skip to content

fix(plc-modbus): RegisterData model strips named VFD register fields → diagnosis reads zeros #161

@Mikecranesync

Description

@Mikecranesync

Summary

RegisterData in services/plc-modbus/backend/models/plc_models.py declares the wrong field names. It still uses the placeholder fields register_101register_105 instead of the named VFD telemetry fields that plc_connection.py actually produces. Because Pydantic v2 silently drops unknown fields, the named values are stripped from the /api/plc/io response and replaced with the 0 defaults.

Where

  • Bug site: services/plc-modbus/backend/models/plc_models.py:65-73 (class RegisterData)
  • Source of truth (correct): services/plc-modbus/backend/services/plc_connection.py:44-51 (REGISTER_NAMES) and :187-191 (read_io() builds the dict from REGISTER_NAMES)
  • Where it's wrapped: services/plc-modbus/backend/routes/plc.py:51-57 (IOResponse(registers=io_data["registers"], ...))

Root cause

read_io() returns:

register_data = {ItemCount, ConveyorHz, MotorCurrentX10, MotorTempX10, VFDStatus, ErrorCode}

but the model only accepts:

class RegisterData(BaseModel):
    ItemCount: int = 0
    register_101: int = 0
    register_102: int = 0
    register_103: int = 0
    register_104: int = 0
    register_105: int = 0

Pydantic v2 ignores extra fields by default, so ConveyorHz/MotorCurrentX10/MotorTempX10/VFDStatus/ErrorCode are dropped and the response returns register_101..105 = 0.

Impact

  • GET /api/plc/io returns zeros for all VFD registers (101–105).
  • services/diagnosis/main.py format_plc_io_for_llm() reads the named fields (ConveyorHz, MotorCurrentX10, etc.) — so the AI diagnosis receives 0 for every VFD value and has no live machine data.
  • Blocks V2 (Machine Awareness) end-to-end and any "current state — which assets are running right now" demo.

Confirmed correct elsewhere

plc_connection.py REGISTER_NAMES, mock_plc.py register constants, and diagnosis/main.py all use the named fields. Only RegisterData is stale. (Note: the services/plc-modbus/CLAUDE.md sidecar register table is also stale — still lists 101–105 as "unused" — and should be refreshed as part of the fix.)

Proposed fix

Rename the RegisterData fields to match REGISTER_NAMES:

class RegisterData(BaseModel):
    """Holding registers (100-105) — From A to B scene + VFD telemetry."""
    ItemCount: int = 0        # 100: items that reached SensorEnd
    ConveyorHz: int = 0       # 101: conveyor VFD frequency (Hz)
    MotorCurrentX10: int = 0  # 102: motor current x10 (amps = value/10)
    MotorTempX10: int = 0     # 103: motor temperature x10 (degC = value/10)
    VFDStatus: int = 0        # 104: 0=idle, 1=running, 2=fault
    ErrorCode: int = 0        # 105: 0=none,1=overload,2=overheat,3=sensor-fail,4=jam,7=e-stop

Acceptance criteria

  • GET /api/plc/io (mock mode) returns non-zero named VFD fields when the mock has VFD activity.
  • diagnosis receives live VFD values (no longer all 0).
  • Existing plc-modbus test suite (162 tests) stays green; add a regression test asserting named fields survive serialization.

Identified during the FactoryLM ↔ MIRA ↔ Walker DT-2026 alignment analysis (docs/dt-factorylm-alignment.md).

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