Adding SMV streams

Adding SMV streams

This page describes the steps to write a complete working configuration for receiving IEC 61850 Sampled Values (SMV) using the process_bus plugin together with the phasor plugin.

ℹ️
The process_bus plugin replaces the old smv_subscriber plugin. It supports single-interface and PRP dual-interface (IEC 62439-3) operation, and adds diagnostic datapoints for conf_rev mismatches, missing samples, and missing frames per LAN.

Manual configuration

Creating the configuration structure

We assume the process_bus plugin and the phasor plugin run in separate runtimes (publisher and subscriber).

        • process_bus_plugin.json
      • runtime.json
        • phasor_plugin.json
      • runtime.json
  • config.json
  • ui_config.json
  • Minimal runtime files:

    { "description": "Runtime for the process_bus plugin", "runtime_name": "publisher" }
    { "description": "Runtime for the phasor plugin", "runtime_name": "subscriber" }

    Minimal plugin skeleton files:

    {
        "use_concurrent_publisher": false,
        "plugin_name": "process_bus",
        "plugin_instance_name": "process_bus_plugin_ens2f0np0",
        "plugin_specific_config": {
            "ethernet_interfaces": [
                { "name": "ens2f0np0" }
            ],
            "smv_subscribers": []
        },
        "datapoint_subscriptions": [],
        "datapoint_publications": []
    }
    {
        "use_concurrent_publisher": false,
        "plugin_name": "phasor_plugin",
        "plugin_instance_name": "phasor_plugin",
        "plugin_specific_config": { "streams": [] },
        "datapoint_subscriptions": [],
        "datapoint_publications": []
    }


    Adding a data stream

    The example below adds one SMV stream: 3 currents + 3 voltages, 4800 samples/s, APPID 0x4001.

    ⚠️
    The svID in the SMV frame must match the smv_id field. By convention it equals the APPID as a lowercase hex string (e.g. APPID 0x4001 → svID "4001").

    Configure the process_bus plugin

    Add a subscriber entry to plugin_specific_config.smv_subscribers. The dataset array describes the IEC 61850 data objects in the frame; datapoint_mappings maps them to gateway datapoints by obj_ref string.

    smv_subscribers entry
    {
        "smv_id": "4001",
        "app_id": "4001",
        "sample_rate": 4800,
        "conf_rev": {
            "expected": 1
        },
        "dataset": [
            { "obj_ref": "IED1MU01/TCTR1.AmpSv.instMag.i", "type": "INT32"   },
            { "obj_ref": "IED1MU01/TCTR1.AmpSv.q",         "type": "Quality" },
            { "obj_ref": "IED1MU01/TCTR2.AmpSv.instMag.i", "type": "INT32"   },
            { "obj_ref": "IED1MU01/TCTR2.AmpSv.q",         "type": "Quality" },
            { "obj_ref": "IED1MU01/TCTR3.AmpSv.instMag.i", "type": "INT32"   },
            { "obj_ref": "IED1MU01/TCTR3.AmpSv.q",         "type": "Quality" },
            { "obj_ref": "IED1MU01/TVTR1.VolSv.instMag.i", "type": "INT32"   },
            { "obj_ref": "IED1MU01/TVTR1.VolSv.q",         "type": "Quality" },
            { "obj_ref": "IED1MU01/TVTR2.VolSv.instMag.i", "type": "INT32"   },
            { "obj_ref": "IED1MU01/TVTR2.VolSv.q",         "type": "Quality" },
            { "obj_ref": "IED1MU01/TVTR3.VolSv.instMag.i", "type": "INT32"   },
            { "obj_ref": "IED1MU01/TVTR3.VolSv.q",         "type": "Quality" }
        ],
        "datapoint_mappings": [
            { "datapoint": "smv_4001_current_a", "value_obj_ref": "IED1MU01/TCTR1.AmpSv.instMag.i", "quality_obj_ref": "IED1MU01/TCTR1.AmpSv.q" },
            { "datapoint": "smv_4001_current_b", "value_obj_ref": "IED1MU01/TCTR2.AmpSv.instMag.i", "quality_obj_ref": "IED1MU01/TCTR2.AmpSv.q" },
            { "datapoint": "smv_4001_current_c", "value_obj_ref": "IED1MU01/TCTR3.AmpSv.instMag.i", "quality_obj_ref": "IED1MU01/TCTR3.AmpSv.q" },
            { "datapoint": "smv_4001_voltage_a", "value_obj_ref": "IED1MU01/TVTR1.VolSv.instMag.i", "quality_obj_ref": "IED1MU01/TVTR1.VolSv.q" },
            { "datapoint": "smv_4001_voltage_b", "value_obj_ref": "IED1MU01/TVTR2.VolSv.instMag.i", "quality_obj_ref": "IED1MU01/TVTR2.VolSv.q" },
            { "datapoint": "smv_4001_voltage_c", "value_obj_ref": "IED1MU01/TVTR3.VolSv.instMag.i", "quality_obj_ref": "IED1MU01/TVTR3.VolSv.q" }
        ]
    }

    Then declare the published datapoints:

    "datapoint_publications": [
        { "name": "smv_4001_current_a" },
        { "name": "smv_4001_current_b" },
        { "name": "smv_4001_current_c" },
        { "name": "smv_4001_voltage_a" },
        { "name": "smv_4001_voltage_b" },
        { "name": "smv_4001_voltage_c" }
    ]
    Full process_bus_plugin.json
    {
        "use_concurrent_publisher": false,
        "plugin_name": "process_bus",
        "plugin_instance_name": "process_bus_plugin_ens2f0np0",
        "plugin_specific_config": {
            "ethernet_interfaces": [
                { "name": "ens2f0np0" }
            ],
            "smv_subscribers": [
                {
                    "smv_id": "4001",
                    "app_id": "4001",
                    "sample_rate": 4800,
                    "conf_rev": { "expected": 1 },
                    "dataset": [
                        { "obj_ref": "IED1MU01/TCTR1.AmpSv.instMag.i", "type": "INT32"   },
                        { "obj_ref": "IED1MU01/TCTR1.AmpSv.q",         "type": "Quality" },
                        { "obj_ref": "IED1MU01/TCTR2.AmpSv.instMag.i", "type": "INT32"   },
                        { "obj_ref": "IED1MU01/TCTR2.AmpSv.q",         "type": "Quality" },
                        { "obj_ref": "IED1MU01/TCTR3.AmpSv.instMag.i", "type": "INT32"   },
                        { "obj_ref": "IED1MU01/TCTR3.AmpSv.q",         "type": "Quality" },
                        { "obj_ref": "IED1MU01/TVTR1.VolSv.instMag.i", "type": "INT32"   },
                        { "obj_ref": "IED1MU01/TVTR1.VolSv.q",         "type": "Quality" },
                        { "obj_ref": "IED1MU01/TVTR2.VolSv.instMag.i", "type": "INT32"   },
                        { "obj_ref": "IED1MU01/TVTR2.VolSv.q",         "type": "Quality" },
                        { "obj_ref": "IED1MU01/TVTR3.VolSv.instMag.i", "type": "INT32"   },
                        { "obj_ref": "IED1MU01/TVTR3.VolSv.q",         "type": "Quality" }
                    ],
                    "datapoint_mappings": [
                        { "datapoint": "smv_4001_current_a", "value_obj_ref": "IED1MU01/TCTR1.AmpSv.instMag.i", "quality_obj_ref": "IED1MU01/TCTR1.AmpSv.q" },
                        { "datapoint": "smv_4001_current_b", "value_obj_ref": "IED1MU01/TCTR2.AmpSv.instMag.i", "quality_obj_ref": "IED1MU01/TCTR2.AmpSv.q" },
                        { "datapoint": "smv_4001_current_c", "value_obj_ref": "IED1MU01/TCTR3.AmpSv.instMag.i", "quality_obj_ref": "IED1MU01/TCTR3.AmpSv.q" },
                        { "datapoint": "smv_4001_voltage_a", "value_obj_ref": "IED1MU01/TVTR1.VolSv.instMag.i", "quality_obj_ref": "IED1MU01/TVTR1.VolSv.q" },
                        { "datapoint": "smv_4001_voltage_b", "value_obj_ref": "IED1MU01/TVTR2.VolSv.instMag.i", "quality_obj_ref": "IED1MU01/TVTR2.VolSv.q" },
                        { "datapoint": "smv_4001_voltage_c", "value_obj_ref": "IED1MU01/TVTR3.VolSv.instMag.i", "quality_obj_ref": "IED1MU01/TVTR3.VolSv.q" }
                    ]
                }
            ]
        },
        "datapoint_subscriptions": [],
        "datapoint_publications": [
            { "name": "smv_4001_current_a" },
            { "name": "smv_4001_current_b" },
            { "name": "smv_4001_current_c" },
            { "name": "smv_4001_voltage_a" },
            { "name": "smv_4001_voltage_b" },
            { "name": "smv_4001_voltage_c" }
        ]
    }

    For the full schema see process_bus plugin specification.

    Configure the Phasor plugin

    Map each raw datapoint to three output datapoints: RMS magnitude, phase angle, and frequency.

    Full phasor_plugin.json
    {
        "use_concurrent_publisher": false,
        "plugin_name": "phasor_plugin",
        "plugin_instance_name": "phasor_plugin",
        "plugin_specific_config": {
            "streams": [
                {
                    "smv_datapoint_name": "smv_4001_current_a",
                    "smv_sample_rate": 4800,
                    "smv_data_type": "INT32",
                    "phasor_frequency": 50,
                    "cycles_per_phasor_sample": 1,
                    "rms_datapoint_name":   "smv_4001_current_a_rms",
                    "freq_datapoint_name":  "smv_4001_current_a_freq",
                    "phase_datapoint_name": "smv_4001_current_a_phase"
                },
                {
                    "smv_datapoint_name": "smv_4001_current_b",
                    "smv_sample_rate": 4800,
                    "smv_data_type": "INT32",
                    "phasor_frequency": 50,
                    "cycles_per_phasor_sample": 1,
                    "rms_datapoint_name":   "smv_4001_current_b_rms",
                    "freq_datapoint_name":  "smv_4001_current_b_freq",
                    "phase_datapoint_name": "smv_4001_current_b_phase"
                },
                {
                    "smv_datapoint_name": "smv_4001_current_c",
                    "smv_sample_rate": 4800,
                    "smv_data_type": "INT32",
                    "phasor_frequency": 50,
                    "cycles_per_phasor_sample": 1,
                    "rms_datapoint_name":   "smv_4001_current_c_rms",
                    "freq_datapoint_name":  "smv_4001_current_c_freq",
                    "phase_datapoint_name": "smv_4001_current_c_phase"
                },
                {
                    "smv_datapoint_name": "smv_4001_voltage_a",
                    "smv_sample_rate": 4800,
                    "smv_data_type": "INT32",
                    "phasor_frequency": 50,
                    "cycles_per_phasor_sample": 1,
                    "rms_datapoint_name":   "smv_4001_voltage_a_rms",
                    "freq_datapoint_name":  "smv_4001_voltage_a_freq",
                    "phase_datapoint_name": "smv_4001_voltage_a_phase"
                },
                {
                    "smv_datapoint_name": "smv_4001_voltage_b",
                    "smv_sample_rate": 4800,
                    "smv_data_type": "INT32",
                    "phasor_frequency": 50,
                    "cycles_per_phasor_sample": 1,
                    "rms_datapoint_name":   "smv_4001_voltage_b_rms",
                    "freq_datapoint_name":  "smv_4001_voltage_b_freq",
                    "phase_datapoint_name": "smv_4001_voltage_b_phase"
                },
                {
                    "smv_datapoint_name": "smv_4001_voltage_c",
                    "smv_sample_rate": 4800,
                    "smv_data_type": "INT32",
                    "phasor_frequency": 50,
                    "cycles_per_phasor_sample": 1,
                    "rms_datapoint_name":   "smv_4001_voltage_c_rms",
                    "freq_datapoint_name":  "smv_4001_voltage_c_freq",
                    "phase_datapoint_name": "smv_4001_voltage_c_phase"
                }
            ]
        },
        "datapoint_subscriptions": [
            { "name": "smv_4001_current_a", "mode": "SYNC" },
            { "name": "smv_4001_current_b", "mode": "SYNC" },
            { "name": "smv_4001_current_c", "mode": "SYNC" },
            { "name": "smv_4001_voltage_a", "mode": "SYNC" },
            { "name": "smv_4001_voltage_b", "mode": "SYNC" },
            { "name": "smv_4001_voltage_c", "mode": "SYNC" }
        ],
        "datapoint_publications": [
            { "name": "smv_4001_current_a_rms"   },
            { "name": "smv_4001_current_a_freq"  },
            { "name": "smv_4001_current_a_phase" },
            { "name": "smv_4001_current_b_rms"   },
            { "name": "smv_4001_current_b_freq"  },
            { "name": "smv_4001_current_b_phase" },
            { "name": "smv_4001_current_c_rms"   },
            { "name": "smv_4001_current_c_freq"  },
            { "name": "smv_4001_current_c_phase" },
            { "name": "smv_4001_voltage_a_rms"   },
            { "name": "smv_4001_voltage_a_freq"  },
            { "name": "smv_4001_voltage_a_phase" },
            { "name": "smv_4001_voltage_b_rms"   },
            { "name": "smv_4001_voltage_b_freq"  },
            { "name": "smv_4001_voltage_b_phase" },
            { "name": "smv_4001_voltage_c_rms"   },
            { "name": "smv_4001_voltage_c_freq"  },
            { "name": "smv_4001_voltage_c_phase" }
        ]
    }

    For more details see Phasor plugin specification.

    Add datapoints to config.json

    All datapoints referenced in the plugin configs must be declared in config.json. Raw waveform datapoints should have a buffer_size equal to at least one cycle at the configured sample rate (1000 for 4800 Hz / 50 Hz).

    config.json
    {
        "datapoints": [
            { "name": "smv_4001_current_a",       "description": "Current A raw samples", "unit": "mA",  "buffer_size": 1000 },
            { "name": "smv_4001_current_b",       "description": "Current B raw samples", "unit": "mA",  "buffer_size": 1000 },
            { "name": "smv_4001_current_c",       "description": "Current C raw samples", "unit": "mA",  "buffer_size": 1000 },
            { "name": "smv_4001_voltage_a",       "description": "Voltage A raw samples", "unit": "V",   "buffer_size": 1000 },
            { "name": "smv_4001_voltage_b",       "description": "Voltage B raw samples", "unit": "V",   "buffer_size": 1000 },
            { "name": "smv_4001_voltage_c",       "description": "Voltage C raw samples", "unit": "V",   "buffer_size": 1000 },
            { "name": "smv_4001_current_a_rms",   "description": "Current A RMS",         "unit": "mA"  },
            { "name": "smv_4001_current_a_freq",  "description": "Current A frequency",   "unit": "Hz"  },
            { "name": "smv_4001_current_a_phase", "description": "Current A phase",       "unit": "rad" },
            { "name": "smv_4001_current_b_rms",   "description": "Current B RMS",         "unit": "mA"  },
            { "name": "smv_4001_current_b_freq",  "description": "Current B frequency",   "unit": "Hz"  },
            { "name": "smv_4001_current_b_phase", "description": "Current B phase",       "unit": "rad" },
            { "name": "smv_4001_current_c_rms",   "description": "Current C RMS",         "unit": "mA"  },
            { "name": "smv_4001_current_c_freq",  "description": "Current C frequency",   "unit": "Hz"  },
            { "name": "smv_4001_current_c_phase", "description": "Current C phase",       "unit": "rad" },
            { "name": "smv_4001_voltage_a_rms",   "description": "Voltage A RMS",         "unit": "V"   },
            { "name": "smv_4001_voltage_a_freq",  "description": "Voltage A frequency",   "unit": "Hz"  },
            { "name": "smv_4001_voltage_a_phase", "description": "Voltage A phase",       "unit": "rad" },
            { "name": "smv_4001_voltage_b_rms",   "description": "Voltage B RMS",         "unit": "V"   },
            { "name": "smv_4001_voltage_b_freq",  "description": "Voltage B frequency",   "unit": "Hz"  },
            { "name": "smv_4001_voltage_b_phase", "description": "Voltage B phase",       "unit": "rad" },
            { "name": "smv_4001_voltage_c_rms",   "description": "Voltage C RMS",         "unit": "V"   },
            { "name": "smv_4001_voltage_c_freq",  "description": "Voltage C frequency",   "unit": "Hz"  },
            { "name": "smv_4001_voltage_c_phase", "description": "Voltage C phase",       "unit": "rad" }
        ]
    }

    More details: Datapoint configuration specification.


    PRP redundancy

    PRP provides seamless failover by sending every SMV frame over two independent LANs. The process_bus plugin deduplicates frames using the sequence number, so each frame is published exactly once regardless of which LAN delivers it first. Per-LAN missing-frame counts are tracked independently.

    To enable PRP, provide two entries in ethernet_interfaces instead of one:

    "ethernet_interfaces": [
        { "name": "eth0", "on_missing_frame_datapoint": "missing_frames_eth0" },
        { "name": "eth1", "on_missing_frame_datapoint": "missing_frames_eth1" }
    ]

    The on_missing_frame_datapoint fields are optional but recommended: the plugin writes the number of frames that arrived on one LAN but not the other (within the deduplication window) to those datapoints. They are per-interface counters — one shared across all subscribers on that plugin instance.

    These datapoints must be added to config.json and datapoint_publications:

    { "name": "missing_frames_eth0", "description": "Missing frames on LAN A", "unit": "" },
    { "name": "missing_frames_eth1", "description": "Missing frames on LAN B", "unit": "" }

    Diagnostic datapoints

    The following optional diagnostic datapoints can be configured per SMV subscriber to monitor stream health.

    Missing samples

    on_missing_sample_datapoint is updated whenever expected samples are not received within a cycle. Useful for detecting merging unit issues or network congestion.

    {
        "smv_id": "4001",
        "app_id": "4001",
        "sample_rate": 4800,
        "conf_rev": { "expected": 1 },
        "on_missing_sample_datapoint": "smv_4001_missing_samples",
        "dataset": [ ... ],
        "datapoint_mappings": [ ... ]
    }

    Configuration revision mismatch

    conf_rev.on_conf_rev_mismatch_datapoint is set to a non-zero value when a received frame carries a confRev that does not match the configured expected value. This indicates the merging unit dataset definition has changed.

    "conf_rev": {
        "expected": 1,
        "on_conf_rev_mismatch_datapoint": "smv_4001_conf_rev_mismatch"
    }

    Complete example with all diagnostics

    The following shows a subscriber with all diagnostic datapoints enabled and PRP:

    process_bus_plugin.json (with PRP + diagnostics)
    {
        "use_concurrent_publisher": false,
        "plugin_name": "process_bus",
        "plugin_instance_name": "process_bus_plugin_eth0_eth1",
        "plugin_specific_config": {
            "ethernet_interfaces": [
                { "name": "eth0", "on_missing_frame_datapoint": "missing_frames_eth0" },
                { "name": "eth1", "on_missing_frame_datapoint": "missing_frames_eth1" }
            ],
            "smv_subscribers": [
                {
                    "smv_id": "4001",
                    "app_id": "4001",
                    "sample_rate": 4800,
                    "conf_rev": {
                        "expected": 1,
                        "on_conf_rev_mismatch_datapoint": "smv_4001_conf_rev_mismatch"
                    },
                    "on_missing_sample_datapoint": "smv_4001_missing_samples",
                    "dataset": [
                        { "obj_ref": "IED1MU01/TCTR1.AmpSv.instMag.i", "type": "INT32"   },
                        { "obj_ref": "IED1MU01/TCTR1.AmpSv.q",         "type": "Quality" },
                        { "obj_ref": "IED1MU01/TVTR1.VolSv.instMag.i", "type": "INT32"   },
                        { "obj_ref": "IED1MU01/TVTR1.VolSv.q",         "type": "Quality" }
                    ],
                    "datapoint_mappings": [
                        { "datapoint": "smv_4001_current_a", "value_obj_ref": "IED1MU01/TCTR1.AmpSv.instMag.i", "quality_obj_ref": "IED1MU01/TCTR1.AmpSv.q" },
                        { "datapoint": "smv_4001_voltage_a", "value_obj_ref": "IED1MU01/TVTR1.VolSv.instMag.i", "quality_obj_ref": "IED1MU01/TVTR1.VolSv.q" }
                    ]
                }
            ]
        },
        "datapoint_subscriptions": [],
        "datapoint_publications": [
            { "name": "missing_frames_eth0"          },
            { "name": "missing_frames_eth1"          },
            { "name": "smv_4001_current_a"           },
            { "name": "smv_4001_voltage_a"           },
            { "name": "smv_4001_conf_rev_mismatch"   },
            { "name": "smv_4001_missing_samples"     }
        ]
    }

    All diagnostic datapoints must be declared in config.json:

    { "name": "missing_frames_eth0",        "description": "Missing frames on LAN A", "unit": "" },
    { "name": "missing_frames_eth1",        "description": "Missing frames on LAN B", "unit": "" },
    { "name": "smv_4001_conf_rev_mismatch", "description": "confRev mismatch stream 4001", "unit": "" },
    { "name": "smv_4001_missing_samples",   "description": "Missing samples stream 4001",  "unit": "" }