Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ DEMO_OUTPUT ?= $(DEMO_EVENTS_DIR)/$(DEMO_SCENARIO).jsonl
DEMO_EVENTS_STORE ?= $(DEMO_STORAGE_DIR)/$(DEMO_SCENARIO)_events.jsonl
DEMO_DEAD_LETTER ?= $(DEMO_STORAGE_DIR)/$(DEMO_SCENARIO)_dead_letter.jsonl
DEMO_SENTINEL_STATE_DIR ?= $(DEMO_STORAGE_DIR)/$(DEMO_SCENARIO)_sentinel
OPCUA_ENDPOINT ?= opc.tcp://localhost:4840/ofi/demo
OPCUA_POLL_COUNT ?= 6
OPCUA_POLL_INTERVAL ?= 1
OPCUA_EVENTS_STORE ?= .local/storage/opcua_demo_events.jsonl
PYTHONPATH := packages/factory-events:services/simulator:services/ingestion:services/process-sentinel:services/api
export PYTHONPATH

.PHONY: help setup dev dev-db simulate ingest sentinel-run demo demo-reset demo-data demo-ingest demo-sentinel-run demo-api-smoke api api-reload test test-unit test-integration test-contract test-e2e lint typecheck docs
.PHONY: help setup dev dev-db simulate ingest opcua-demo-ingest sentinel-run demo demo-reset demo-data demo-ingest demo-sentinel-run demo-api-smoke api api-reload test test-unit test-integration test-contract test-e2e lint typecheck docs

help:
@echo "Factory Intelligence Platform"
Expand All @@ -31,6 +35,7 @@ help:
@echo " make dev-db Start local PostgreSQL with Docker Compose"
@echo " make simulate Generate simulator JSONL events"
@echo " make ingest Validate and ingest simulator events"
@echo " make opcua-demo-ingest Poll the local demo OPC UA server into FactoryEvents"
@echo " make sentinel-run Run Process Sentinel over ingested events"
@echo " make demo Prepare and verify deterministic demo state"
@echo " make demo-reset Clear generated local demo files"
Expand Down Expand Up @@ -71,6 +76,9 @@ simulate:
ingest:
$(PYTHON) -m factory_ingestion.cli --input $(INPUT) --events-store $(EVENTS_STORE)

opcua-demo-ingest:
$(PYTHON) -m factory_ingestion.opcua_demo_worker --endpoint $(OPCUA_ENDPOINT) --events-store $(OPCUA_EVENTS_STORE) --poll-count $(OPCUA_POLL_COUNT) --poll-interval $(OPCUA_POLL_INTERVAL)

sentinel-run:
$(PYTHON) -m process_sentinel.cli --events-store $(EVENTS_STORE) --state-dir $(SENTINEL_STATE_DIR)

Expand Down
46 changes: 46 additions & 0 deletions docs/LEARNING_LOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,52 @@ This file should be updated by Codex after each meaningful change.
### What to learn next
```

## 2026-05-23 - OPC UA demo ingestion worker

### What changed

Added a demo-only OPC UA ingestion worker that polls the local OPC UA simulator
and writes normalized FactoryEvents to a JSONL event store.

### Why it matters

The demo OPC UA server can now feed the existing ingestion and Process Sentinel
path without adding a production OPC UA connector or browse-all-tags framework.

### How it works

The worker reads the configured demo namespace tags, builds work-order, batch,
process measurement, and quality measurement events, validates them through the
shared FactoryEvent models, and stores them with the existing `JsonlEventStore`.
The default six one-second polls are sized for local demo use without flooding
storage.

### How to run it

```bash
docker compose -f infra/docker/docker-compose.yml up --build opcua-simulator
make opcua-demo-ingest
```

### How to test it

```bash
.venv/bin/python -m pytest services/ingestion/tests/test_opcua_demo_worker.py
```

### Key files

- `services/ingestion/factory_ingestion/opcua_demo_worker.py`
- `services/ingestion/tests/test_opcua_demo_worker.py`
- `services/ingestion/README.md`
- `Makefile`

### What to learn next

Use the worker output as the source for a future demo smoke test that runs the
OPC UA simulator, polls values, and then runs Process Sentinel over the accepted
event store.

## 2026-05-22 - OPC UA demo drift controls

### What changed
Expand Down
3 changes: 3 additions & 0 deletions docs/demo/MANUFACTURER_DEMO_RUNBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,9 @@ tags to FactoryEvent process and quality events, see
For the Dockerized OPC UA demo simulator endpoint, startup command, and tag
list, see `services/simulator/README.md`.

For the demo OPC UA ingestion worker command, output path, polling interval, and
demo-only boundary, see `services/ingestion/README.md`.

For the screen-by-screen user goal, component, data dependency, safety language,
risk, and success-criteria map, see
`docs/demo/MANUFACTURER_DEMO_USER_JOURNEY.md`.
Expand Down
77 changes: 77 additions & 0 deletions services/ingestion/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,83 @@ The equivalent direct command is:
--dead-letter .local/storage/dead_letter.jsonl
```

## OPC UA Demo Ingestion Worker

The demo OPC UA ingestion worker polls the local simulator-backed OPC UA server
and writes normalized FactoryEvents to the same JSONL event store used by the
existing ingestion and Process Sentinel path. This is demo infrastructure, not a
production OPC UA connector, browse-all-tags implementation, certificate model,
or high-availability worker.

Start the demo OPC UA server in one terminal:

```bash
docker compose -f infra/docker/docker-compose.yml up --build opcua-simulator
```

Poll the demo tags into FactoryEvents from another terminal:

```bash
make opcua-demo-ingest
```

Default worker settings:

| Setting | Default |
| --- | --- |
| Endpoint | `opc.tcp://localhost:4840/ofi/demo` |
| Poll count | `6` |
| Poll interval | `1` second |
| Output path | `.local/storage/opcua_demo_events.jsonl` |

The default six one-second polls are compressed for the 8-10 minute demo. They
produce enough process and quality events to inspect locally without flooding
the JSONL store.

Useful command variants:

```bash
make opcua-demo-ingest \
OPCUA_ENDPOINT=opc.tcp://localhost:4840/ofi/demo \
OPCUA_POLL_COUNT=10 \
OPCUA_POLL_INTERVAL=1 \
OPCUA_EVENTS_STORE=.local/storage/opcua_demo_events.jsonl
```

The equivalent direct command is:

```bash
.venv/bin/python -m factory_ingestion.opcua_demo_worker \
--endpoint opc.tcp://localhost:4840/ofi/demo \
--poll-count 6 \
--poll-interval 1 \
--events-store .local/storage/opcua_demo_events.jsonl
```

The worker reads the configured demo namespace tags for Greenville Demo Site,
Line 2, Filler F-201, and Checkweigher CW-201. It writes:

- One work-order started event and one batch started event on the first poll so
product context is present in the accepted store.
- Process measurement events for `filler_f_201.fill_weight`,
`filler_f_201.filler_nozzle_pressure`, and `line_2.line_speed`.
- A quality measurement event for `Final Fill Weight`.

Expected summary:

```text
opc ua demo ingestion summary
endpoint: opc.tcp://localhost:4840/ofi/demo
poll_count: 6
poll_interval_seconds: 1
emitted_events: 26
accepted_output: .local/storage/opcua_demo_events.jsonl
demo_boundary: simulator-backed demo OPC UA source; not a production connector
```

If the OPC UA server is unavailable, the worker exits with a readable error
that includes the endpoint and the Docker Compose startup command.

## Accepted Event Storage

Accepted events are written to the local JSONL event store:
Expand Down
Loading
Loading