Skip to content

Part 6: Alarms and Events

MTPPy2.0 implements an initial, code-based subset of the ModuleTypePackage:AlarmSet.Base profile. The implementation describes static alarm metadata in the generated MTP. Alarm condition evaluation remains the responsibility of the Process Orchestration Layer (POL).

Scope

Capability Status
Public static Alarm model Implemented
Registration with PEA.add_alarm() Implemented
AlarmSet.Base CAEX alarm description Implemented as an initial subset
AlarmGroup Generated internally, one group per referenced DataAssembly instance
AlarmMessage and AlarmText One static text per alarm
Boolean, integer, and string equality trigger Implemented
Alarm condition evaluation POL responsibility; not implemented in the PEA
Events Not implemented
PEA-managed alarms and alarm runtime state Not implemented
OPC UA Alarms & Conditions Not implemented

“Implemented” in this table means that the repository tests the described API and generator behavior. It does not claim complete AlarmSet.Base or Part 6 conformance.

Public model and registration contract

Alarm is the only public Part 6 model. There are no public Python AlarmSet or AlarmGroup classes in this first implementation. The generator derives the CAEX AlarmGroup, AlarmMessage, and AlarmText objects from each registered Alarm.

Alarm field Contract
tag_name Non-empty text and unique within PEA.alarms
data_assembly Existing DataAssembly instance
trigger Direct DataItem member of that exact DataAssembly instance
trigger_value Exact Python type and valid value range of the trigger DataItem
message Non-empty static operator text
ack_required Exact bool; exported as metadata only
severity Exact int in the inclusive range from 1 through 1000

The exact DataAssembly instance must be reachable through an existing PEA registration and serialization path, for example directly through PEA.add_data_assembly() or as a service-owned DataAssembly through PEA.add_service(). PEA.add_alarm() does not register it implicitly and rejects non-Alarm objects and duplicate alarm tag names. A reference to an unregistered DataAssembly is rejected when the MTP is generated, rather than emitting a dangling AlarmGroup.RefID.

The alarm itself is an immutable dataclass. Its referenced DataAssembly and DataItem remain mutable, so the generator calls Alarm.validate() again before serialization. This prevents a DataItem type or membership change made after alarm construction from producing invalid alarm metadata.

Supported trigger types

  • xs:boolean
  • xs:string
  • xs:byte, xs:unsignedByte
  • xs:short, xs:unsignedShort
  • xs:int, xs:unsignedInt
  • xs:long, xs:unsignedLong

Every integer trigger is checked against the range of its concrete W3C XML type. Python bool is not accepted as an integer. Float, double, date/time, URI, token, multiple-trigger expressions, and comparison operators other than equality with TriggerValue are not supported.

Code-based example

The trigger DataAssembly must be registered with the PEA. Use get_item() to pass the DataItem itself; mapping access such as level_high[BinView.V_] returns only its current value.

from mtppy.part3.data_assembly_set.indicator_elements.views.bin_view import BinView
from mtppy.part6.alarm_set.alarm import Alarm
from mtppy.pea.pea import PEA

pea = PEA()
level_high = BinView("LevelHigh")
pea.add_data_assembly(level_high)
pea.add_alarm(
    Alarm(
        tag_name="LevelHigh.Alarm",
        data_assembly=level_high,
        trigger=level_high.get_item(BinView.V_),
        trigger_value=True,
        message="Level is too high.",
        ack_required=True,
        severity=500,
    )
)

The complete executable registration example is available in examples/pea_alarm_base.py.

The example builds the Python model and registers the alarm. It deliberately does not start runtime services or connect to an external device. Manifest generation is covered by the generator tests.

Generator behavior

The implementation follows this sequence:

  1. Revalidate every registered alarm and reserve one CAEX ID per trigger DataItem object.
  2. Serialize registered DataAssemblies and add that ID to each alarm trigger attribute.
  3. Create exactly one CAEX AlarmGroup for each referenced DataAssembly object. Its generated name is <DataAssembly.tag_name>_AlarmGroup and is not configurable. Multiple alarms referencing the same object share the group.
  4. Create one AlarmMessage containing one AlarmText for every alarm.
  5. Create the Alarm inside its generated group and resolve RefID, Trigger, and MessageRef.
  6. Reject missing DataAssembly or trigger targets instead of serializing dangling links.

If the same DataAssembly object is registered through more than one existing PEA path, the alarm mapping retains the first serialized DataAssembly reference. This keeps AlarmGroup.RefID and Alarm.Trigger within the same serialized object graph.

flowchart LR
    Registry[PEA.alarms] --> Generator[MTPGenerator]
    Generator --> Group[AlarmGroup]
    Generator --> AlarmElement[Alarm]
    Generator --> Message[AlarmMessage / AlarmText]
    Group -- RefID --> Assembly[DataAssembly]
    AlarmElement -- Trigger --> Item[DataItem attribute ID]
    AlarmElement -- MessageRef --> Message
    AlarmElement -- TriggerValue --> Equality[POL equality evaluation]

Generated CAEX mapping

Generated object or attribute CAEX type or reference type Value or target
AlarmGroup MTPAlarmSUCLib/AlarmGroup One per referenced DataAssembly object
AlarmGroup.RefID MTPATLib/IDReferenceType/RefIDAttributeType DataAssembly RefID
Alarm MTPAlarmSUCLib/Alarm One per registered alarm
AckRequired xs:boolean Static alarm metadata
Severity xs:short Integer from 1 through 1000
Trigger MTPATLib/IDReferenceType/IDLinkAttributeType, xs:string CAEX ID of the trigger DataItem attribute
TriggerValue Concrete xs:* type of the DataItem Equality value evaluated by the POL
Classification AutomationMLBaseAttributeTypeLib/OrderedListType Empty container; values are not implemented
MessageRef MTPTextATLib/TextRefAttributeType, xs:string CAEX ID of the AlarmMessage
AlarmMessage MTPTextSUCLib/TextDefinition/AlarmMessage Container generated per alarm
AlarmText MTPTextSUCLib/TextDefinition/AlarmMessage/AlarmText Contains one static Text attribute

Generic AutomationML role requirements are appended to the generated group, alarm, message, and text objects. No AlarmMgmt, AlarmMgmtRef, IsManaged, or other Managed-alarm instance is generated.

The generated names are <alarm.tag_name> message for AlarmMessage and <alarm.tag_name>.Text for AlarmText.

The trigger DataItem attribute follows the existing generic serializer and remains xs:string for both static and linked values. If a PEA-hosted OPC UA node exists, its RefAttributeType and Value additionally form the existing ID link. The alarm value type belongs to TriggerValue, which therefore carries the concrete Boolean, integer, or string W3C type.

Runtime and OPC UA boundary

Alarm registration affects only manifest generation. It does not install DataItem callbacks, evaluate conditions, or change the PEA runtime path. AckRequired is metadata for the POL; it does not add an acknowledgement method or state to the Python object.

No separate alarm OPC UA node is created, and this feature does not connect to external OPC UA devices. If the existing PEA OPC UA server is initialized, the trigger DataItem keeps its normal link to the node hosted by that PEA server. The alarm adds only the CAEX trigger reference. The alarm implementation neither starts that server nor acts as an OPC UA client, and it does not read or subscribe to nodes. Without a started PEA server, the alarm remains a static MTP description.

Verification

The implementation is covered at four levels:

  • model tests for all fields, supported types, integer ranges, invalid values, DataItem ownership, and the absence of runtime callbacks;
  • PEA tests for registration, wrong types, and duplicate names;
  • generator tests for CAEX paths, reference targets, grouping, revalidation, multiple DataAssembly serialization paths, and Boolean/integer/string TriggerValue types;
  • a smoke test for the executable registration example.

The dedicated GitLab job runs the collocated src/mtppy/part6 tests and includes their coverage artifact in the combined report. A complete implementation and test inventory is available in the Part 6 implementation summary.

Open Part 6 TODOs

These TODOs are deliberately documented but not implemented in the first static port.

ID Open work Why it remains open
P6-TODO-01 Verify and conditionally emit the Part 6 profile declarations in AdditionalInformation. The shared template already advertises ModuleTypePackage:AlarmSet.Managed although no Managed content is generated. Changing shared template policy was outside the focused port.
P6-TODO-02 Perform a normative AlarmSet.Base review using the official specification and reference MTPs. Repository tests prove the implemented contract, not complete profile conformance. CAEX-XSD validity alone would also not prove MTP semantic conformance.
P6-TODO-03 Introduce explicit public AlarmSet/AlarmGroup models if required. The minimal API derives one fixed-name group per DataAssembly and cannot express custom names or multiple groups for one assembly.
P6-TODO-04 Add populated alarm classifications. The serializer currently emits only the ordered-list container defined by the repository template; classification terminology and public ownership need a target-native model and normative confirmation.
P6-TODO-05 Add multilingual alarm messages and default-language behavior. The first port intentionally uses one static text. A shared TextSet/language API is needed before adding fallback semantics.
P6-TODO-06 Support nested BaseFunction triggers, further data types, and richer conditions where the specification permits them. The current ownership rule deliberately accepts one direct Boolean, integer, or string DataItem and one equality value.
P6-TODO-07 Implement Part 6 events. The current public package exports only Alarm; event identity, payload, lifecycle, and serialization require a separate design.
P6-TODO-08 Design and implement PEA-managed alarms. AlarmMgmt, state/command encoding, acknowledgement, reset, delays, shelving, suppression, quality, lifecycle, thread safety, and callback fan-out require new target-native runtime infrastructure.
P6-TODO-09 Add Part 6 import, factory, and round-trip support if required by downstream tooling. The first increment covers code-based construction and export only.