Skip to content

Commit

Permalink
Add Alarm Viewpoint support
Browse files Browse the repository at this point in the history
  • Loading branch information
slominskir committed Jun 12, 2024
1 parent 4eca423 commit be4a4d9
Show file tree
Hide file tree
Showing 9 changed files with 225 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/jaws_libp/avro/schema-registry.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[
{"file": "avro/schemas/AlarmViewpoint.avsc", "subject": "alarm-viewpoints-value", "references": []},
{"file": "avro/schemas/AlarmCategory.avsc", "subject": "alarm-categories-value", "references": []},
{"file": "avro/schemas/AlarmLocation.avsc", "subject": "alarm-locations-value", "references": []},
{"file": "avro/schemas/DisabledOverride.avsc", "subject": "disabled-override", "references": []},
Expand Down
35 changes: 35 additions & 0 deletions src/jaws_libp/avro/schemas/AlarmViewpoint.avsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"type": "record",
"name": "AlarmViewpoint",
"namespace": "org.jlab.jaws.entity",
"doc": "Value of a named viewpoint",
"fields": [
{
"name": "location",
"type": {
"type": "array",
"items" : "string",
"default": []
},
"doc": "The location names"
},
{
"name": "category",
"type": {
"type": "array",
"items" : "string",
"default": []
},
"doc": "The category names"
},
{
"name": "alarmclass",
"type": {
"type": "array",
"items" : "string",
"default": []
},
"doc": "The alarmclass names"
}
]
}
48 changes: 45 additions & 3 deletions src/jaws_libp/avro/serde.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
SerializationContext

from ..entities import AlarmCategory, AlarmLocation, AlarmPriority, ChannelErrorActivation, NoActivation, \
Source, AlarmInstance, AlarmActivationUnion, Activation, \
Source, AlarmInstance, AlarmActivationUnion, Activation, AlarmViewpoint, \
EPICSActivation, NoteActivation, DisabledOverride, FilteredOverride, LatchedOverride, MaskedOverride, \
OnDelayedOverride, OffDelayedOverride, ShelvedOverride, AlarmOverrideUnion, OverriddenAlarmType, AlarmOverrideKey, \
ShelvedReason, EPICSSEVR, EPICSSTAT, UnionEncoding, CALCSource, EPICSSource, AlarmClass, \
Expand Down Expand Up @@ -347,7 +347,7 @@ def __init__(self, schema_registry_client: SchemaRegistryClient, avro_conf: Dict

super().__init__(schema_registry_client, schema, UnionEncoding.DICT_WITH_TYPE, avro_conf)

def to_dict(self, data: AlarmLocation) -> Dict[str, str]:
def to_dict(self, data: AlarmCategory) -> Dict[str, str]:
"""
Converts AlarmCategory to a dict.
Expand All @@ -358,7 +358,7 @@ def to_dict(self, data: AlarmLocation) -> Dict[str, str]:
"team": data.team
}

def from_dict(self, data: Dict[str, str]) -> AlarmLocation:
def from_dict(self, data: Dict[str, str]) -> AlarmCategory:
"""
Converts a dict to AlarmCategory.
Expand Down Expand Up @@ -1234,3 +1234,45 @@ def from_dict(self, data: Dict[str, Any]) -> IntermediateMonolog:
return IntermediateMonolog(self._effective_registration_serde.from_dict(data['registration']),
self._effective_notification_serde.from_dict(data['notification']),
self._processor_transition_serde.from_dict(data['transitions']))


class ViewpointSerde(RegistryAvroSerde):
"""
Provides AlarmViewpoint serde utilities
"""

def __init__(self, schema_registry_client: SchemaRegistryClient, avro_conf: Dict = None):
"""
Create a new ViewpointSerde.
:param schema_registry_client: The SchemaRegistryClient
:param avro_conf: configuration for avro serde
"""
schema_bytes = pkgutil.get_data("jaws_libp", "avro/schemas/AlarmViewpoint.avsc")
schema_str = schema_bytes.decode('utf-8')

schema = Schema(schema_str, "AVRO", [])

super().__init__(schema_registry_client, schema, UnionEncoding.DICT_WITH_TYPE, avro_conf)

def to_dict(self, data: AlarmViewpoint) -> Dict[str, str]:
"""
Converts AlarmViewpoint to a dict.
:param data: The AlarmViewpoint
:return: A dict
"""
return {
"location": data.location,
"category": data.category,
"alarmclass": data.alarmclass
}

def from_dict(self, data: Dict[str, str]) -> AlarmViewpoint:
"""
Converts a dict to AlarmViewpoint.
:param data: The dict
:return: The AlarmViewpoint
"""
return AlarmViewpoint(data['location'], data['category'], data['alarmclass'])
1 change: 1 addition & 0 deletions src/jaws_libp/avro/topics.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"alarm-instances",
"alarm-locations",
"alarm-overrides",
"alarm-viewpoints",
"intermediate-registration",
"intermediate-activation",
"intermediate-latch",
Expand Down
44 changes: 43 additions & 1 deletion src/jaws_libp/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
from psutil import Process

from .avro.serde import CategorySerde, LocationSerde, OverrideKeySerde, OverrideSerde, EffectiveRegistrationSerde, \
StringSerde, Serde, EffectiveAlarmSerde, EffectiveNotificationSerde, ClassSerde, ActivationSerde, InstanceSerde
StringSerde, Serde, EffectiveAlarmSerde, EffectiveNotificationSerde, ClassSerde, ActivationSerde, InstanceSerde, \
ViewpointSerde
from .entities import UnionEncoding
from .eventsource import EventSourceListener, EventSourceTable
from .scripts import DEFAULT_BOOTSTRAP_SERVERS
Expand Down Expand Up @@ -529,6 +530,30 @@ def __init__(self, client_name: str):
super().__init__(config)


class ViewpointConsumer(JAWSConsumer):
"""
Consumer for JAWS Viewpoint messages.
"""
def __init__(self, client_name: str):
"""
Create a new Consumer.
:param client_name: The name of the client application
"""
schema_registry_client = get_registry_client()
key_serde = StringSerde()
value_serde = ViewpointSerde(schema_registry_client)

config = {
'topic': 'alarm-viewpoints',
'client.name': client_name,
'key.serde': key_serde,
'value.serde': value_serde
}

super().__init__(config)


class ActivationProducer(JAWSProducer):
"""
Producer for JAWS Activation messages.
Expand Down Expand Up @@ -680,3 +705,20 @@ def __init__(self, client_name: str):
value_serde = OverrideSerde(schema_registry_client)

super().__init__('alarm-overrides', client_name, key_serde, value_serde)


class ViewportProducer(JAWSProducer):
"""
Producer for JAWS Viewport messages.
"""
def __init__(self, client_name: str):
"""
Create a new Producer.
:param client_name: The name of the client application
"""
schema_registry_client = get_registry_client()
key_serde = StringSerde()
value_serde = ViewpointSerde(schema_registry_client)

super().__init__('alarm-viewpoints', client_name, key_serde, value_serde)
18 changes: 17 additions & 1 deletion src/jaws_libp/console.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from tabulate import tabulate
from .clients import JAWSConsumer, CategoryConsumer, ActivationConsumer, LocationConsumer, OverrideConsumer, \
InstanceConsumer, EffectiveRegistrationConsumer, EffectiveAlarmConsumer, EffectiveNotificationConsumer, \
ClassConsumer
ClassConsumer, ViewpointConsumer
from .eventsource import EventSourceListener


Expand Down Expand Up @@ -323,3 +323,19 @@ def __init__(self, client_name: str):
super().__init__(consumer, ["Alarm Name", "Override Type", "Value"], lambda msg: [msg.key().name,
msg.key().type.name,
msg.value()])


class ViewpointConsoleConsumer(ConsoleConsumer):
"""
ConsoleConsumer for JAWS Viewpoint messages.
"""
def __init__(self, client_name: str):
"""
Create a new Consumer.
:param client_name: The name of the client application
"""
consumer = ViewpointConsumer(client_name)

super().__init__(consumer, ["Viewpoint Name", "Location", "Category", "AlarmClass"],
lambda msg: [msg.key(), msg.value().location, msg.value().category, msg.value().alarmclass])
14 changes: 14 additions & 0 deletions src/jaws_libp/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from typing import Union, Optional, List
from functools import total_ordering


class AlarmPriority(Enum):
"""
Alarm Priority
Expand Down Expand Up @@ -156,6 +157,19 @@ class AlarmLocation:
"""Parent Location or null if top-level"""


@dataclass
class AlarmViewpoint:
"""
Alarm Viewpoint.
"""
location: List[str]
"""The Alarm Location names"""
category: List[str]
"""The Alarm Category names"""
alarmclass: List[str]
"""The Alarm Class names"""


@dataclass
class Activation:
"""
Expand Down
27 changes: 27 additions & 0 deletions src/jaws_libp/scripts/client/list_viewpoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env python3

"""
Lists the alarm viewpoints.
"""

import click
from ...console import ViewpointConsoleConsumer


# pylint: disable=missing-function-docstring,no-value-for-parameter
@click.command()
@click.option('--monitor', is_flag=True, help="Monitor indefinitely")
@click.option('--nometa', is_flag=True, help="Exclude audit headers and timestamp")
@click.option('--export', is_flag=True, help="Dump records in AVRO JSON format")
def list_viewpoints(monitor, nometa, export) -> None:
consumer = ViewpointConsoleConsumer('list_viewpoints.py')

consumer.consume_then_done(monitor, nometa, export)


def click_main() -> None:
list_viewpoints()


if __name__ == "__main__":
click_main()
42 changes: 42 additions & 0 deletions src/jaws_libp/scripts/client/set_viewpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#!/usr/bin/env python3

"""
Set alarm viewpoint.
"""

import click

from ...clients import ViewpointProducer
from ...entities import AlarmViewpoint


# pylint: disable=missing-function-docstring,no-value-for-parameter
@click.command()
@click.option('--file', is_flag=True,
help="Imports a file of key=value pairs (one per line) where the key is viewpoint name and value is "
"AlarmViewpoint JSON")
@click.option('--unset', is_flag=True, help="Remove the viewpoint")
@click.argument('name')
@click.option('--location', '-l', help="Name of location", multiple=True)
def set_viewpoint(file, unset, name, location, category, alarmclass) -> None:
producer = ViewpointProducer('set_viewpoint.py')

key = name

if file:
producer.import_records(name)
else:
if unset:
value = None
else:
value = AlarmViewpoint(location, category, alarmclass)

producer.send(key, value)


def click_main() -> None:
set_viewpoint()


if __name__ == "__main__":
click_main()

0 comments on commit be4a4d9

Please sign in to comment.