Skip to content

feat(mes): Week 2 — Modbus machine state reader service#140

Merged
Mikecranesync merged 1 commit into
mainfrom
feat/mes-week2-state-reader
Apr 16, 2026
Merged

feat(mes): Week 2 — Modbus machine state reader service#140
Mikecranesync merged 1 commit into
mainfrom
feat/mes-week2-state-reader

Conversation

@Mikecranesync
Copy link
Copy Markdown
Owner

Summary

  • Background asyncio poller reads plc-modbus HTTP API every 5s per configured line
  • Pure detect_state() function maps VFDStatus + ErrorCode registers → machine state
  • State transitions written to machine_states table (open/close rows)
  • In-memory cache — DB write only on transition, not every tick
  • Two new REST endpoints for live state visibility

Architecture

MES poller  →  GET http://plc-modbus:8001/api/plc/io
                      ↓
              detect_state(io_data)
              VFDStatus=1       → RUNNING
              VFDStatus=2 / EC  → DOWN + reason_code
              VFDStatus=0       → IDLE
              HTTP failure      → OFFLINE
                      ↓
              machine_states table (transition write only)

MES never touches Modbus TCP directly — fully decoupled from hardware.

New endpoints

GET /api/mes/lines              — list all configured lines
GET /api/mes/lines/{id}/state   — current state (cache → DB fallback)

ErrorCode → reason_code map

ErrorCode reason_code
1 OVERLOAD
2 OVERHEAT
3 SENSOR_FAIL
4 JAM
7 E_STOP

Test plan

  • pytest tests/test_machine_states.py -v21/21 passing (all mocked, no docker)
  • Full suite pytest tests/32/32 passing (Week 1 + Week 2, no regressions)
  • detect_state covers RUNNING, IDLE, DOWN (VFDStatus=2), DOWN (ErrorCode priority), empty IO, all 5 error codes + unmapped
  • is_transition covers None→any, same→same, different→different
  • fetch_io raises PLCOfflineError on ConnectError and HTTP>=400
  • Poller writes transition, skips on no-change, writes OFFLINE on PLCOfflineError

Related

🤖 Generated with Claude Code
via Happy

@Mikecranesync Mikecranesync changed the base branch from feat/mes-week1-db-schema to main April 16, 2026 04:06
Background asyncio poller reads plc-modbus HTTP API every 5s per line,
detects state transitions (RUNNING/DOWN/IDLE/OFFLINE), and writes them
to machine_states table. REST endpoints expose live state.

New:
- backend/services/plc_client.py   — async httpx wrapper for /api/plc/io
- backend/services/state_machine.py — pure detect_state() from IO snapshot
- backend/services/state_poller.py  — asyncio poll loop with in-memory cache
- backend/routes/lines.py           — GET /api/mes/lines, GET /lines/{id}/state
- tests/test_machine_states.py      — 21 unit tests, all mocked

State detection:
  VFDStatus=1              → RUNNING
  VFDStatus=2 / ErrorCode>0 → DOWN + reason_code (OVERLOAD/JAM/E_STOP/...)
  VFDStatus=0              → IDLE
  HTTP failure             → OFFLINE

Design: MES never touches Modbus TCP directly — all reads go through
the existing plc-modbus HTTP service (http://plc-modbus:8001).

Tests: 32/32 passing (21 Week 2 + 11 Week 1, no regressions)

Closes: Mikecranesync/MIRA#320

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
@Mikecranesync Mikecranesync force-pushed the feat/mes-week2-state-reader branch from cffaabe to 6b4689c Compare April 16, 2026 04:12
@Mikecranesync Mikecranesync merged commit f8391f9 into main Apr 16, 2026
1 check passed
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.

feat(mes): Week 2 — services/mes/ FastAPI skeleton + Modbus machine state reader

1 participant