Normalized DNP3 Control Event¶
Raw protocol detail is essential for engineering and forensics, but many operational consumers need device, asset, action, severity, and a readable description. The DNP3 normalizer enriches parsed events with an optional customer asset map.

Figure — Normalized DNP3 events preserve operation meaning, context, and decision outcome.
Representative decoded input¶
DNP3
source: 3
destination: 100
function: Direct Operate
object: Group 12 Variation 1
point: CROB 0
opcode: Latch On
Customer asset map¶
devices:
- dnp3_address: 3
name: SCADA Master
role: master
- dnp3_address: 100
name: North RTU
role: outstation
location: North Substation
point_maps:
outstation_100:
- point_key: "100:CROB:0"
asset_id: F12_BREAKER
asset_type: breaker
intent: F12 breaker control
critical: true
Representative normalized output¶
{
"timestamp": "2026-07-15T21:00:00Z",
"protocol": "dnp3",
"event_type": "control_command",
"category": "control",
"severity": "high",
"frame_number": 1842,
"network": {
"src_ip": "10.20.1.10",
"dst_ip": "10.20.2.100",
"src_port": 49152,
"dst_port": 20000
},
"industrial": {
"src_device_addr": 3,
"dst_device_addr": 100,
"src_device_name": "SCADA Master",
"dst_device_name": "North RTU",
"src_device_role": "master",
"dst_device_role": "outstation",
"dst_device_location": "North Substation",
"operation": "direct_operate",
"function_code": 5,
"function_name": "Direct Operate",
"asset_type": "breaker",
"asset_id": "F12_BREAKER",
"point_key": "100:CROB:0",
"point_type": "CROB",
"point_index": 0,
"intent": "F12 breaker control",
"action": "Close",
"critical": true
},
"description": "SCADA Master sent DIRECT OPERATE: Close command to F12_BREAKER (breaker) on North RTU — F12 breaker control",
"process_assets": [
{
"raw": {
"group": 12,
"variation": 1,
"index": 0,
"point_key": "100:CROB:0",
"point_type": "CROB",
"crob": {
"tcc": "Close",
"opcode": "Latch On",
"count": 1,
"on_time_ms": 0,
"off_time_ms": 0
}
},
"mapped": {
"found": true,
"asset_id": "F12_BREAKER",
"asset_type": "breaker",
"intent": "F12 breaker control",
"critical": true,
"label": "F12_BREAKER Close"
}
}
]
}
The schema also exposes structured process_assets containing raw group,
variation, index, value/state/CROB fields, quality, event time, and mapped asset data.
Unknown devices or points can be marked in discovery for asset-mapping review.
Operational uses¶
- SOC and control-room event review;
- asset-specific audit and reporting;
- investigation of critical commands;
- discovery of unmapped DNP3 devices and points;
- correlation with Rule Engine decisions in a downstream data platform.
See Industrial Event Normalization for the classification catalog, discovery workflow, operating modes, and reporting views.
Normalization does not replace the raw evidence. Retain the parsed protocol event and the normalized representation when forensic traceability is required.
Industrial Event Gallery¶
These representative DNP3 outputs show how L2Proxy turns parser-level detail into two complementary products:
- operational text that a control-room or OT-security user can understand quickly;
- filterable classification and asset fields for dashboards, alerts, reports, and SIEM rules.
The examples use customer-friendly asset names. Actual names, locations, criticality, units, and intent come from the deployed YAML asset map.
Compact views
Tag blocks below are concise projections of the event for readability. In the full
JSON event, asset fields are grouped under industrial, discovery flags under
discovery, and network fields under network; PostgreSQL stores the principal
fields as indexed columns for direct filtering.
1. Critical breaker Direct Operate¶
Technical observation
Operational text
SCADA Master sent DIRECT OPERATE: Close command to CB-101 (breaker) on RTU-South — F12 circuit breaker control
Filterable tags and context
{
"protocol": "dnp3",
"event_type": "control_command",
"category": "control",
"severity": "high",
"operation": "direct_operate",
"asset_id": "CB-101",
"asset_type": "breaker",
"point_type": "CROB",
"action": "Close",
"critical": true,
"alarm": false
}
Useful for: switching audit, critical-control notification, operator activity review, and correlation with an approved work order.
2. Select-Before-Operate sequence¶
The same asset can produce two separately classified records:
[SELECT]
SCADA Master sent SELECT: Close command to CB-101 (breaker) on RTU-South — F12 circuit breaker control
event_type=control_sequence category=control severity=medium
operation=select sequence=select_operate
[OPERATE]
SCADA Master sent OPERATE: Close command to CB-101 (breaker) on RTU-South — F12 circuit breaker control
event_type=control_command category=control severity=high
operation=operate sequence=select_operate
Useful for: reconstructing switching steps and placing the Rule Engine's stateful SBO accept/drop decision beside the operator-readable event history.
Classification is not correlation proof
sequence=select_operate identifies the DNP3 control workflow. Proof that a specific
Operate consumed a matching Select comes from the stateful Rule Engine policy.
3. Routine monitoring request¶
Operational text
Filterable tags
{
"event_type": "monitoring_read",
"category": "monitoring",
"severity": "low",
"operation": "read",
"point_type": "BI/AI"
}
Useful for: retaining an operational baseline while excluding routine polling from high-priority control and security views.
4. Unsolicited multi-asset status update¶
Operational text
RTU-South → SCADA Master: CB-101 [F12 breaker status] = CLOSED; REC-217 [Feeder 7 recloser status] = OPEN; BUS-VOLTAGE [11 kV bus] = 10.84 kV; (+1 unidentified points)
Filterable tags and context
{
"event_type": "unsolicited_event",
"category": "event",
"severity": "high",
"operation": "unsolicited_response",
"critical": true,
"unknown_point": true,
"process_assets": [
{"mapped": {"asset_id": "CB-101", "critical": true}},
{"mapped": {"asset_id": "REC-217"}},
{"mapped": {"asset_id": "BUS-VOLTAGE"}},
{"mapped": {"found": false}}
]
}
Useful for: situational awareness, spontaneous-change review, multi-point event display, and identifying incomplete point maps without hiding known asset updates.
5. RTU restart and time synchronization need¶
Operational text
Filterable tags
{
"event_type": "response",
"category": "response",
"severity": "critical",
"operation": "response",
"alarm": true,
"raw_details": {
"iin_flags": ["DEVICE_RESTART", "NEED_TIME"]
}
}
Useful for: unexpected RTU restart detection, post-restart health checks, time-sync operations, and correlation with maintenance or power events.
6. Lost communication quality on a process point¶
Operational text
Structured point evidence
{
"event_type": "response",
"category": "response",
"industrial": {
"asset_id": "PUMP-2-RUN",
"asset_type": "pump_status"
},
"process_assets": [
{
"raw": {
"point_type": "BI",
"state": false,
"quality": {
"online": false,
"comm_lost": true,
"restart": false
}
},
"mapped": {
"found": true,
"asset_id": "PUMP-2-RUN",
"intent": "Raw-water pump running feedback"
}
}
]
}
Useful for: separating an apparent process state from poor data quality. The event
preserves both the displayed state and the COMM_LOST evidence.
7. Analog over-range condition¶
Operational text
Filterable context
{
"event_type": "unsolicited_event",
"category": "event",
"severity": "high",
"asset_id": "TANK-LEVEL",
"asset_type": "level_measurement",
"value": 12.7,
"unit": "m",
"critical": true
}
Useful for: presenting measurement value, engineering unit, asset identity, and protocol quality together instead of emitting an unexplained numeric field.
8. Cold restart command¶
Operational text
Filterable tags
{
"event_type": "maintenance_command",
"category": "maintenance",
"severity": "critical",
"operation": "cold_restart"
}
Useful for: immediate OT-SOC review, maintenance-window verification, change audit, and investigation of an unexpected device restart.
9. Configuration change¶
Operational text
Filterable tags
{
"event_type": "configuration_change",
"category": "configuration",
"severity": "medium",
"operation": "write",
"function_code": 2,
"function_name": "Write"
}
Enable or Disable Unsolicited commands use the same configuration category with their
own operation names and a default low severity.
Useful for: configuration audit and comparison with approved engineering activity.
10. Unknown outstation and control point¶
Normalization does not fail when the asset map is incomplete.
Operational text
Discovery fields
{
"event_type": "control_command",
"category": "control",
"severity": "high",
"unknown_dst_device": true,
"unknown_point": true,
"dst_device_addr": 17,
"point_key": "17:CROB:0"
}
Useful for: detecting inventory gaps, newly introduced RTUs, undocumented points, and prioritizing asset-map completion. “Unknown” means absent from the customer map; it is a discovery signal, not by itself proof of malicious activity.
Example dashboard questions¶
The classification fields make direct operational queries possible:
-- Critical controls by asset
SELECT timestamp, src_device_name, dst_device_name, asset_id, action, description
FROM industrial_events
WHERE category = 'control' AND critical
ORDER BY timestamp DESC;
-- Device-health alarms
SELECT timestamp, src_device_name AS device, severity, description
FROM industrial_events
WHERE alarm AND severity = 'critical'
ORDER BY timestamp DESC;
-- Inventory gaps
SELECT * FROM asset_discovery_report ORDER BY occurrences DESC;
SELECT * FROM point_discovery_report ORDER BY occurrences DESC;
Observed deployment examples¶
The following patterns were observed in the live PostgreSQL deployment snapshot used to validate this documentation. Repeated rows were grouped so the examples represent operational patterns rather than a packet dump.
| Observed industrial text | Classification | Occurrences |
|---|---|---|
SCADA Master sent SELECT: Latch Off command to F12_BREAKER (feeder_breaker) on North RTU — F12 Feeder Breaker — Latch On=Close, Latch Off=Open |
control sequence · medium · critical asset | 32 |
SCADA Master sent OPERATE: Latch On command to F12_BREAKER (feeder_breaker) on North RTU — F12 Feeder Breaker — Latch On=Close, Latch Off=Open |
control command · high · critical asset | 4 |
SCADA Master sent OPERATE: Set=0 command to TR1 (power_transformer) on North RTU — TR1 OLTC tap position setpoint command |
control command · high | 3 |
SCADA Master sent Enable Unsolicited to North RTU |
configuration change · low | 2 |
East Recloser → SCADA Master: IIN: DEVICE_RESTART, NEED_TIME |
unsolicited event · critical · alarm | 1 |
South DER Controller → SCADA Master: IIN: DEVICE_RESTART, NEED_TIME |
unsolicited event · critical · alarm | 1 |
The same snapshot also contained large periodic responses with mapped breaker, relay,
bus-voltage, transformer-loading, temperature, tap-position, and communications-health
points plus unmapped points. These demonstrate why dashboards should summarize routine
polling while preserving the complete process_assets record for drill-down.
Interpretation boundary¶
The examples represent output supported by the current event model and DNP3 formatter; exact text depends on decoded fields and the customer's asset map. Severity and text normalization support triage and reporting. They do not replace Rule Engine policy, stateful validation, process interlocks, or the original parsed evidence.