The MCA Edge Agent is the automated onboarding and configuration engine for the Motorcity Automated Systems (MCA) Legacy Machine Health Kit.
Operating strictly as a read-only diagnostic tool (similar to an automotive OBD-II scanner), this agent takes field photos of legacy industrial machinery and control cabinets, extracts hardware and protocol metadata using a multimodal LLM, and generates a validated JSON configuration bundle. That bundle automatically provisions the edge gateway's polling drivers, Unified Namespace (UNS) MQTT topics, deterministic OEE formulas, and operator downtime buttons in the MCA Progressive Web App (PWA).
- Zero-Write / Read-Only Isolation: The agent never generates PLC write commands or modifies existing machine ladder logic. All generated driver configurations are strictly locked to passive read-only polling (DF1, Modbus RTU/TCP, EtherNet/IP) or physical non-invasive I/O taps (split-core CT clamps, optical part counters, 24VDC stack-light relays).
- Deterministic Math Over LLM Guessing: The AI agent is used strictly for visual extraction, machine archetype classification, and structured configuration generation. Live OEE calculations (Availability × Performance × Quality) and state-machine timers are executed by a deterministic edge engine—never by an LLM.
- Human-in-the-Loop Gate:
Every generated configuration stages in a
PENDING_APPROVALstate for a 60-second technician review before being pushed to the edge gateway.
/edge_agent
├── README.md # Architecture and usage guide
├── requirements.txt # Python dependencies
├── agent.py # Main Vision-to-JSON extraction & classification pipeline
├── upload_server.py # Standalone onboarding API and native industrial HMI
├── validator.py # Pydantic schema enforcement & read-only safety checks
├── simulator/press_sim.py # Simulated stamping-press MQTT telemetry
├── simulator/multi_machine_sim.py # Multi-machine Edge Hub MQTT publisher
├── configs/ # One validated MachineProfile JSON per machine
├── deployed_configs/ # Human-approved configs partitioned by site_id
├── templates/ # Locked, deterministic Golden Archetype JSON templates
└── sample_inputs/ # Test nameplate and control panel photos for local validation
- Capture Field Inputs: Technician uploads photos of the machine nameplate, interior control cabinet, and wired gateway channels via the MCA Field PWA.
- Nameplate Extraction (
agent.py): Multimodal model is restricted to OCR/classification fields only: archetype, OEM, model, serial number, voltage, PLC family, and confidence notes. It cannot generate channel maps, debounce settings, downtime codes, or OEE parameters. - Golden Archetype Merge: The classified archetype selects one human-maintained template from
templates/.agent.pymerges only extracted metadata plus the requested machine ID, site ID, and sensor transport. Templates supply deterministic ideal cycle parameters, standard channels, debounce timers, and downtime reason codes. - Schema Validation (
validator.py): The merged profile is validated with Pydantic, enforcingread_only: truefor every channel and rejecting writable register configurations. - Provisioning Output: Exports
machine_config.jsonready for deployment to the edge gateway and PWA frontend.
The eight locked archetypes are stamping_press, cnc_mill,
injection_molder, hydraulic_press, conveyor_line,
bottling_filler_line, food_packaging_wrapper, and
industrial_oven_mixer. Each template defines fixed read-only channels,
debounce intervals, production parameters, and archetype-specific downtime
codes.
Changes to template channel maps, debounce times, or production parameters are
intentional code/configuration changes—not LLM output—and should be reviewed
and tested before deployment.
cd edge_agent
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txtCreate a .env file in /edge_agent:
LLM_API_KEY=your_api_key_here
LLM_PROVIDER=gemini
# Or use OPENAI_API_KEY / GEMINI_API_KEY for provider-specific keys.
MQTT_BROKER_HOST=localhost
MQTT_BROKER_PORT=1883python agent.py \
--nameplate ./sample_inputs/minster_nameplate.jpg \
--panel ./sample_inputs/slc500_cabinet.jpg \
--machine-id press_01 \
--sensor-transport wiredProfiles are saved as ./configs/{machine_id}.json. If --machine-id is
omitted, the agent creates a clean ID from the extracted OEM and model.
The agent defaults to Gemini; set LLM_PROVIDER=openai or pass
--provider openai to use OpenAI. Set GEMINI_API_KEY or OPENAI_API_KEY
(or the generic LLM_API_KEY), respectively. Model names can be overridden
with GEMINI_MODEL, OPENAI_MODEL, or --model. The extraction response is
validated against the strict NameplateExtraction model, merged with its
Golden Archetype Template, then validated against MachineProfile before it
is written.
Use --dry-run to generate a deterministic mock extraction and validate the
resulting profile without calling Gemini/OpenAI or requiring an API key.
python agent.py --dry-run --machine-id press_dry_run --site-id plant_01 --dry-run-archetype stamping_pressThis writes the merged config to ./configs/press_dry_run.json using a Minster
P2-100 fixture profile and the selected Golden Archetype Template. --dry-run
usefully smoke-tests profile generation in CI or local validation without any
external dependencies.
Run the standalone FastAPI server from the repository root:
python upload_server.pyOpen port 8000 in GitHub Codespaces. The technician onboarding page accepts a
mobile camera photo, selects an existing plant or creates a new site, and runs
the normal agent.py extraction and validation pipeline. The validated JSON
must then be explicitly approved by a human before it is written to
deployed_configs/{site_id}/{machine_id}.json. The seeded site is
highland_park_plant_01; omitted or default site IDs map to that tenant.
The site registry is persisted in deployed_configs/sites.json.
The floor dashboard is available at /dashboard?site_id=highland_park_plant_01.
Its fleet metrics and API telemetry are scoped to that site. Each approved
machine gets an in-process 1-second simulation worker using the existing
MachineSimulation and OEE calculator, with optional MQTT output to
mca/{site_id}/{machine_id}/status and
mca/{site_id}/{machine_id}/telemetry. Set MQTT_BROKER_HOST and
MQTT_BROKER_PORT to publish to a broker; the local HMI continues to show
simulated telemetry when MQTT is unavailable. The dashboard's demo toggle
controls workers only for its selected site.
Run the agent once per machine. Assign a unique ID and site ID for every
machine; --sensor-transport may be wired, wireless_900mhz, or
wireless_lorawan.
python agent.py --nameplate ./sample_inputs/minster_nameplate.jpg --panel ./sample_inputs/slc500_cabinet.jpg --machine-id press_01 --site-id plant_01 --sensor-transport wired
python agent.py --nameplate ./sample_inputs/haas_nameplate.jpg --panel ./sample_inputs/haas_panel.jpg --machine-id haas_03 --site-id plant_01 --sensor-transport wireless_900mhzUse --site-id to route each machine to its site's UNS tree (default: default).
With an MQTT broker running, start the Edge Hub publisher:
python simulator/multi_machine_sim.py --config-dir ./configsIt publishes retained status to mca/{site_id}/{machine_id}/status, JSON
telemetry to mca/{site_id}/{machine_id}/telemetry, and a retained fleet
manifest to mca/{site_id}/fleet/manifest. Invalid profiles are logged and
skipped; other valid machines continue publishing. MQTT broker settings use
MQTT_BROKER_HOST and MQTT_BROKER_PORT.
signal_filter.py provides configurable discrete-input debounce (50 ms for
counters and 250 ms for motor/stack-light transitions), median filtering for CT
spikes, and SENSOR_FAULT reporting for readings outside 0–500 A. oee.py
clamps Availability, Performance, Quality, and OEE to finite values in [0, 1].
Both simulator publishers durably queue outbound MQTT messages in the WAL-mode
edge_buffer.db; a background worker replays acknowledged messages FIFO in
batches of up to 50. The queue prunes oldest records at its 500 MiB default cap.
The multi-machine publisher also emits a 10-second retained heartbeat at
mca/{site_id}/hub/health and reports OFFLINE_SENSOR after 60 seconds without
a machine report. Run the safeguards suite with pytest -q tests/test_safeguards.py.
- Add automated register-map lookup for Allen-Bradley SLC 500 / MicroLogix DF1 serial tables.
- Add passive network discovery helper (
nmap/ EtherNet/IP CIP identity scanner) to assist photo extraction. - Build one-click config push endpoint to sync validated JSON directly to the edge gateway over WireGuard/HTTPS.