Commit 84c20201 authored by Drew Devereux's avatar Drew Devereux
Browse files

Merge branch 'state_machine' into 'master'

State management

See merge request ska-telescope/lmc-base-classes!18
parents d12da018 ecf3a5f9
......@@ -258,7 +258,7 @@ contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
generated-members=target|logger
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
......
release=0.5.4
tag=lmcbaseclasses-0.5.4
release=0.6.0
tag=lmcbaseclasses-0.6.0
......@@ -25,6 +25,36 @@ The lmc-base-classe repository contains set of eight classes as mentioned in SKA
## Version History
#### 0.6.0
- Breaking change: State management
- SKABaseDevice implements a simple state machine with states
`DISABLED`, `OFF`, `ON`, `INIT` and `FAULT`, along with transitions
between them.
- SKASubarray implements full subarray state machine in accordance
with ADR-8 (the underlying state model supports all states and
transitions, including transitions through transient states; the
subarray device uses this state model but currently provide a
simple, purely synchronous implementation)
- Base classes provide subclassing code hooks that separate management
of device state from other device functionality. Thus, subclasses
are encouraged to leave state management in the care of the base
classes by:
- leaving `init_device()` alone and placing their (stateless)
initialisation code in the `do()` method of the `InitCommand` object instead. The base `init_device()` implementation will ensure that
the `do()` method is called, whilst ensuring state is managed e.g.
the device is put into state `IDLE` beforehand, and put into the
right state afterwards.
- leaving commands like `Configure()` alone and placing their
(stateless) implementation code in `ConfigureCommand.do()`
instead. This applies to all commands that affect device state:
`Off()`, `On()`, `AssignResources()`, `ReleaseResources()`,
`ReleaseAllResources()`, `Configure()`, `Scan()`, `EndScan()`,
`End()`, `Abort()`, `Reset()`, `Restart()`.
- leaving the base device to handle reads from and writes to the
state attributes `adminMode`, `obsState` and device `state`. For
example, do not call `Device.set_state()` directly; and do not
override methods like `write_adminMode()`.
#### 0.5.4
- Remove `ObsState` command from SKACapability, SKAObsDevice and SKASubarray Pogo XMI files. It should not
have been included - the `obsState` attribute provides this information. The command was not in the Python
......
SKA Commands
============================================
.. toctree::
:maxdepth: 2
.. automodule:: ska.base.commands
:members:
:undoc-members:
......@@ -6,6 +6,13 @@
SKA Subarray
============================================
The SKA Subarray device implements the observation state machine as defined
in ADR-8:
.. image:: images/ADR-8.png
:width: 400
:alt: Diagram of the observation state machine showing states and transitions
.. toctree::
:maxdepth: 2
......
......@@ -21,6 +21,7 @@ Welcome to LMC Base Classes documentation!
Device: SKA Subarray<SKASubarray>
SKA Control Model<Control_Model>
SKA Commands<Commands>
Indices and tables
==================
......
......@@ -100,7 +100,7 @@
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="true" concrete="true" concreteHere="false"/>
</commands>
......
......@@ -55,7 +55,7 @@
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
......
......@@ -68,7 +68,7 @@
<type xsi:type="pogoDsl:UShortType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
......@@ -77,7 +77,7 @@
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="true" concrete="true"/>
</commands>
......
......@@ -46,8 +46,8 @@
<argin description="Logging level for selected devices:&#xA;(0=OFF, 1=FATAL, 2=ERROR, 3=WARNING, 4=INFO, 5=DEBUG).&#xA;Example: [[4, 5], ['my/dev/1', 'my/dev/2']].">
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argin>
<argout description="No output arguments">
<type xsi:type="pogoDsl:VoidType"/>
<argout description="">
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
......@@ -65,7 +65,7 @@
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="true" concrete="true"/>
</commands>
......
......@@ -78,7 +78,7 @@
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="true" concrete="true"/>
</commands>
......
......@@ -56,7 +56,7 @@
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="true" concrete="true"/>
</commands>
......@@ -65,13 +65,17 @@
<dataReadyEvent fire="false" libCheckCriteria="true"/>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
<properties description="Observing State" label="" unit="" standardUnit="" displayUnit="" format="" maxValue="" minValue="" maxAlarm="" minAlarm="" maxWarning="" minWarning="" deltaTime="" deltaValue=""/>
<enumLabels>EMPTY</enumLabels>
<enumLabels>RESOURCING</enumLabels>
<enumLabels>IDLE</enumLabels>
<enumLabels>CONFIGURING</enumLabels>
<enumLabels>READY</enumLabels>
<enumLabels>SCANNING</enumLabels>
<enumLabels>PAUSED</enumLabels>
<enumLabels>ABORTING</enumLabels>
<enumLabels>ABORTED</enumLabels>
<enumLabels>RESETTING</enumLabels>
<enumLabels>FAULT</enumLabels>
<enumLabels>RESTARTING</enumLabels>
</attributes>
<attributes name="obsMode" attType="Scalar" rwType="READ" displayLevel="OPERATOR" polledPeriod="1000" maxX="" maxY="" allocReadMember="true" isDynamic="false">
<dataType xsi:type="pogoDsl:EnumType"/>
......
<?xml version="1.0" encoding="ASCII"?>
<pogoDsl:PogoSystem xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:pogoDsl="http://www.esrf.fr/tango/pogo/PogoDsl">
<classes name="SKASubarray" pogoRevision="9.6">
<description description="SubArray handling device" title="SKASubarray" sourcePath="/home/tango/src/lmc-base-classes/pogo" language="PythonHL" filestogenerate="XMI file,Code files,Python Package,Protected Regions" license="none" copyright="" hasMandatoryProperty="false" hasConcreteProperty="true" hasAbstractCommand="false" hasAbstractAttribute="false">
<description description="SubArray handling device" title="SKASubarray" sourcePath="/home/tango/src/lmc-base-classes/pogo" language="PythonHL" filestogenerate="XMI file" license="none" copyright="" hasMandatoryProperty="false" hasConcreteProperty="true" hasAbstractCommand="false" hasAbstractAttribute="false">
<inheritances classname="Device_Impl" sourcePath=""/>
<inheritances classname="SKAObsDevice" sourcePath="./"/>
<identification contact="at ska.ac.za - cam" author="cam" emailDomain="ska.ac.za" classFamily="SkaBase" siteSpecific="" platform="All Platforms" bus="Not Applicable" manufacturer="none" reference=""/>
......@@ -37,34 +37,16 @@
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="ConfigureCapability" description="Configures number of instances for each capability. If the capability exists, &#xA;it increments the configured instances by the number of instances requested, &#xA;otherwise an exception will be raised.&#xA;Note: The two lists arguments must be of equal length or an exception will be raised." execMethod="configure_capability" displayLevel="OPERATOR" polledPeriod="0" isDynamic="false">
<argin description="[Number of instances to add][Capability types]">
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="DeconfigureAllCapabilities" description="Deconfigure all instances of the given Capability type. If the capability type does not exist an exception will be raised, &#xA;otherwise it sets the configured instances for that capability type to zero." execMethod="deconfigure_all_capabilities" displayLevel="OPERATOR" polledPeriod="0" isDynamic="false">
<argin description="Capability type">
<commands name="Configure" description="Configures the scan for this subarray" execMethod="configure" displayLevel="OPERATOR" polledPeriod="0" isDynamic="false">
<argin description="The scan configuration, formatted as a JSON string">
<type xsi:type="pogoDsl:StringType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="DeconfigureCapability" description="Deconfigures a given number of instances for each capability. If the capability exists, &#xA;it decrements the configured instances by the number of instances requested,&#xA;otherwise an exceptioin will be raised.&#xA;Note: The two lists arguments must be of equal length or an exception will be raised" execMethod="deconfigure_capability" displayLevel="OPERATOR" polledPeriod="0" isDynamic="false">
<argin description="[Number of instances to remove][Capability types]">
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
......@@ -99,35 +81,26 @@
<argin description="List of Resources to add to subarray.">
<type xsi:type="pogoDsl:StringArrayType"/>
</argin>
<argout description="A list of Resources added to the subarray.">
<type xsi:type="pogoDsl:StringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="EndSB" description="Change obsState to IDLE." execMethod="end_sb" displayLevel="OPERATOR" polledPeriod="0" isDynamic="false">
<argin description="">
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="EndScan" description="Terminate scan." execMethod="end_scan" displayLevel="OPERATOR" polledPeriod="0" isDynamic="false">
<commands name="End" description="Change obsState to IDLE." execMethod="end" displayLevel="OPERATOR" polledPeriod="0" isDynamic="false">
<argin description="">
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="Pause" description="Pause scan." execMethod="pause" displayLevel="OPERATOR" polledPeriod="0" isDynamic="false">
<commands name="EndScan" description="Terminate scan." execMethod="end_scan" displayLevel="OPERATOR" polledPeriod="0" isDynamic="false">
<argin description="">
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
......@@ -135,8 +108,8 @@
<argin description="">
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="List of resources removed from the subarray.">
<type xsi:type="pogoDsl:StringArrayType"/>
<argout description="">
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
......@@ -144,8 +117,8 @@
<argin description="List of resources to remove from the subarray.">
<type xsi:type="pogoDsl:StringArrayType"/>
</argin>
<argout description="List of resources removed from the subarray.">
<type xsi:type="pogoDsl:StringArrayType"/>
<argout description="">
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
......@@ -154,16 +127,25 @@
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="true" concrete="true" concreteHere="false"/>
</commands>
<commands name="Resume" description="Resume scan." execMethod="resume" displayLevel="OPERATOR" polledPeriod="0" isDynamic="false">
<commands name="ObsReset" description="Reset observation state machine to its default state" execMethod="obsreset" displayLevel="OPERATOR" polledPeriod="0">
<argin description="">
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
<commands name="Restart" description="Restart the observation state machine" execMethod="restart" displayLevel="OPERATOR" polledPeriod="0">
<argin description="">
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
......@@ -172,7 +154,7 @@
<type xsi:type="pogoDsl:StringArrayType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="false" concrete="true" concreteHere="true"/>
</commands>
......@@ -293,7 +275,7 @@
<states name="DISABLE" description="The device cannot be switched ON for an external reason. E.g. the power supply has its door open, the safety conditions are not satisfactory to allow the device to operate.">
<status abstract="false" inherited="true" concrete="true"/>
</states>
<preferences docHome="./doc_html" makefileHome="/usr/local/share/pogo/preferences"/>
<preferences docHome="./doc_html" makefileHome="$(TANGO_HOME)"/>
<overlodedPollPeriodObject name="adminMode" type="attribute" pollPeriod="0"/>
<overlodedPollPeriodObject name="configurationDelayExpected" type="attribute" pollPeriod="0"/>
<overlodedPollPeriodObject name="configurationProgress" type="attribute" pollPeriod="0"/>
......
......@@ -60,7 +60,7 @@
<type xsi:type="pogoDsl:VoidType"/>
</argin>
<argout description="">
<type xsi:type="pogoDsl:VoidType"/>
<type xsi:type="pogoDsl:LongStringArrayType"/>
</argout>
<status abstract="false" inherited="true" concrete="true"/>
</commands>
......
__all__ = (
"commands",
"control_model",
"SKAAlarmHandler",
"SKABaseDevice",
"SKABaseDevice", "SKABaseDeviceStateModel",
"SKACapability",
"SKALogger",
"SKAMaster",
"SKAObsDevice",
"SKASubarray",
"SKATelState"
"SKAObsDevice", "SKAObsDeviceStateModel",
"SKASubarray", "SKASubarrayStateModel", "SKASubarrayResourceManager",
"SKATelState",
)
# Note: order of imports is important - start with lowest in the hierarchy
# SKABaseDevice, and then classes that inherit from it
from .base_device import SKABaseDevice
from .base_device import SKABaseDevice, SKABaseDeviceStateModel
from .alarm_handler_device import SKAAlarmHandler
from .logger_device import SKALogger
from .master_device import SKAMaster
from .tel_state_device import SKATelState
# SKAObsDevice, and then classes that inherit from it
from .obs_device import SKAObsDevice
from .obs_device import SKAObsDevice, SKAObsDeviceStateModel
from .capability_device import SKACapability
from .subarray_device import SKASubarray
from .subarray_device import (
SKASubarray, SKASubarrayStateModel, SKASubarrayResourceManager
)
......@@ -4,23 +4,21 @@
#
#
#
""" SKAAlarmHandler
A generic base device for Alarms for SKA. It exposes SKA alarms and SKA alerts as TANGO attributes.
SKA Alarms and SKA/Element Alerts are rules-based configurable conditions that can be defined over multiple
attribute values and quality factors, and are separate from the "built-in" TANGO attribute alarms.
"""
This module implements SKAAlarmHandler, a generic base device for Alarms
for SKA. It exposes SKA alarms and SKA alerts as TANGO attributes. SKA
Alarms and SKA/Element Alerts are rules-based configurable conditions
that can be defined over multiple attribute values and quality factors,
and are separate from the "built-in" TANGO attribute alarms.
"""
# PROTECTED REGION ID(SKAAlarmHandler.additionnal_import) ENABLED START #
# Standard imports
import os
import sys
# Tango imports
from tango import DebugIt
from tango.server import run, attribute, command, device_property
# SKA specific imports
from . import SKABaseDevice, release
from ska.base import SKABaseDevice
from ska.base.commands import BaseCommand
# PROTECTED REGION END # // SKAAlarmHandler.additionnal_import
......@@ -91,13 +89,31 @@ class SKAAlarmHandler(SKABaseDevice):
# General methods
# ---------------
def init_device(self):
SKABaseDevice.init_device(self)
self._build_state = '{}, {}, {}'.format(release.name, release.version,
release.description)
self._version_id = release.version
# PROTECTED REGION ID(SKAAlarmHandler.init_device) ENABLED START #
# PROTECTED REGION END # // SKAAlarmHandler.init_device
def init_command_objects(self):
"""
Sets up the command objects
"""
super().init_command_objects()
self.register_command_object(
"GetAlarmRule",
self.GetAlarmRuleCommand(self, self.state_model, self.logger)
)
self.register_command_object(
"GetAlarmData",
self.GetAlarmDataCommand(self, self.state_model, self.logger)
)
self.register_command_object(
"GetAlarmAdditionalInfo",
self.GetAlarmAdditionalInfoCommand(self, self.state_model, self.logger)
)
self.register_command_object(
"GetAlarmStats",
self.GetAlarmStatsCommand(self, self.state_model, self.logger)
)
self.register_command_object(
"GetAlertStats",
self.GetAlertStatsCommand(self, self.state_model, self.logger)
)
def always_executed_hook(self):
# PROTECTED REGION ID(SKAAlarmHandler.always_executed_hook) ENABLED START #
......@@ -180,16 +196,88 @@ class SKAAlarmHandler(SKABaseDevice):
# Commands
# --------
class GetAlarmRuleCommand(BaseCommand):
"""
A class for the SKAAlarmHandler's GetAlarmRule() command.
"""
def do(self, argin):
"""
Stateless hook for SKAAlarmHandler GetAlarmRule() command.
:return: Alarm configuration info: rule, actions, etc.
:rtype: JSON string
"""
return ""
class GetAlarmDataCommand(BaseCommand):
"""
A class for the SKAAlarmHandler's GetAlarmData() command.
"""
def do(self, argin):
"""
Stateless hook for SKAAlarmHandler GetAlarmData() command.
:return: Alarm data
:rtype: JSON string
"""
return ""
class GetAlarmAdditionalInfoCommand(BaseCommand):
"""
A class for the SKAAlarmHandler's GetAlarmAdditionalInfo()
command.
"""
def do(self, argin):
"""
Stateless hook for SKAAlarmHandler GetAlarmAdditionalInfo()
command.
:return: Alarm additional info
:rtype: JSON string
"""
return ""
class GetAlarmStatsCommand(BaseCommand):
"""
A class for the SKAAlarmHandler's GetAlarmStats() command.
"""
def do(self):
"""
Stateless hook for SKAAlarmHandler GetAlarmStats() command.
:return: Alarm stats
:rtype: JSON string
"""
return ""
class GetAlertStatsCommand(BaseCommand):
"""
A class for the SKAAlarmHandler's GetAlertStats() command.
"""
def do(self):
"""
Stateless hook for SKAAlarmHandler GetAlertStats() command.
:return: Alert stats
:rtype: JSON string
"""
return ""
@command(dtype_in='str', doc_in="Alarm name", dtype_out='str', doc_out="JSON string",)
@DebugIt()
def GetAlarmRule(self, argin):
# PROTECTED REGION ID(SKAAlarmHandler.GetAlarmRule) ENABLED START #
"""
Get all configuration info of the alarm, e.g. rule, defined action, etc.
To modify behaviour for this command, modify the do() method of
the command class.
:param argin: Name of the alarm
:return: JSON string containing configuration information of the alarm
"""
return ""
command = self.get_command_object("GetAlarmRule")
return command(argin)
# PROTECTED REGION END # // SKAAlarmHandler.GetAlarmRule
@command(dtype_in='str', doc_in="Alarm name", dtype_out='str', doc_out="JSON string",)
......@@ -199,10 +287,15 @@ class SKAAlarmHandler(SKABaseDevice):
"""
Get list of current value, quality factor and status of
all attributes participating in the alarm rule.
To modify behaviour for this command, modify the do() method of
the command class.
:param argin: Name of the alarm
:return: JSON string containing alarm data
"""
return ""
command = self.get_command_object("GetAlarmData")
return command(argin)
# PROTECTED REGION END # // SKAAlarmHandler.GetAlarmData
@command(dtype_in='str', doc_in="Alarm name", dtype_out='str', doc_out="JSON string", )
......@@ -211,10 +304,15 @@ class SKAAlarmHandler(SKABaseDevice):
# PROTECTED REGION ID(SKAAlarmHandler.GetAlarmAdditionalInfo) ENABLED START #
"""
Get additional alarm information.
To modify behaviour for this command, modify the do() method of
the command class.
:param argin: Name of the alarm
:return: JSON string containing additional alarm information
"""
return ""
command = self.get_command_object("GetAlarmAdditionalInfo")
return command(argin)
# PROTECTED REGION END # // SKAAlarmHandler.GetAlarmAdditionalInfo
@command(dtype_out='str', doc_out="JSON string",)
......@@ -223,9 +321,14 @@ class SKAAlarmHandler(SKABaseDevice):
# PROTECTED REGION ID(SKAAlarmHandler.GetAlarmStats) ENABLED START #
"""
Get current alarm stats.
To modify behaviour for this command, modify the do() method of
the command class.
:return: JSON string containing alarm statistics
"""
return ""
command = self.get_command_object("GetAlarmStats")
return command()
# PROTECTED REGION END # // SKAAlarmHandler.GetAlarmStats
@command(dtype_out='str', doc_out="JSON string",)
......@@ -234,9 +337,14 @@ class SKAAlarmHandler(SKABaseDevice):
# PROTECTED REGION ID(SKAAlarmHandler.GetAlertStats) ENABLED START #
"""
Get current alert stats.
To modify behaviour for this command, modify the do() method of
the command class.
:return: JSON string containing alert statistics
"""
return ""
command = self.get_command_object("GetAlertStats")
return command()
# PROTECTED REGION END # // SKAAlarmHandler.GetAlertStats
# ----------
......@@ -255,5 +363,6 @@ def main(args=None, **kwargs):
return run((SKAAlarmHandler,), args=args, **kwargs)
# PROTECTED REGION END # // SKAAlarmHandler.main
if __name__ == '__main__':
main()