Beispiel #1
0
    def ConfigEdit(self, newconfig):
        """Check a new HMI configuration, and if it is OK, save it to
		disk and use it as the current HMI configuration.
		Parameters: newconfig (dict) = The new HMI configuration. 
		Returns: (list) = A list containing any error messages.
		"""

        # Get the time stamp for when we started.
        timestamp = time.time()

        # Create the new HMI tag configuration.
        self._HMINewTagconfig = HMIConfig.HMIConfig(self._ConfigFileName,
                                                    timestamp,
                                                    self.HMITagValidator)
        # Pass it the new configuration, and see if there were any errors.
        self._HMINewTagconfig.SetHMIConfig(newconfig)

        # Check if errors are present in the new configuration.
        ConfigOK = len(self._HMINewTagconfig.GetConfigErrors()) == 0

        if not ConfigOK:
            return self._HMINewTagconfig.GetConfigErrors()

        # Calculate the file signature.
        try:
            filesig = MonUtils.CalcFileSig(self._ConfigFileName)
        except:
            # File may not exist.
            filesig = 'N/A'

        # Calculate the new status parameters. We manage the status
        # parameters here rather than in the parser itself because
        # the HMI parser library is shared with other programs.
        self._NewConfigStatParams = self._SetConfigStatus(
            timestamp, filesig, ConfigOK)

        # If the new configuration is OK, we use it in place of the old one.
        self._HMICurrentTagconfig = self._HMINewTagconfig
        self._CurrentConfigStatParams = self._NewConfigStatParams

        # This handles encoding and decoding messages. We initialise it with
        # the name we want to use for the HMI server.
        self.HMIServerMsg = HMIMsg.HMIServerMessages(
            self._HMICurrentTagconfig.GetServerID())

        # Initialised the reserved tags handling with the client and protocol versions.
        self.HMIReservedTags = HMIAddr.HMIReservedTags(
            self._HMICurrentTagconfig.GetServerID(), _ProtocolVersion)

        # This handles converting MB-HMI tags to Modbus data table addresses.
        self.HMIData = HMIAddr.HMIData(
            self._HMIDataTable, self._HMICurrentTagconfig.GetConfigDict(),
            self.HMIReservedTags, self._HMICurrentTagconfig.GetEventConfig(),
            self._HMICurrentTagconfig.GetAlarmConfig())

        # Everything was OK, so there were no errors to report.
        return []
Beispiel #2
0
    def __init__(self):

        # Name to use for the configuration file.
        self._ConfigFileName = 'mbhmi.config'

        # Use a default server ID until we get another one.
        self._DefaultServerID = 'default server id'

        # This handles encoding and decoding messages. We initialise it with
        # the name we want to use for the HMI server.
        self.HMIServerMsg = HMIMsg.HMIServerMessages(self._DefaultServerID)

        # Initialised the reserved tags handling with the client and protocol versions.
        self.HMIReservedTags = HMIAddr.HMIReservedTags(self._DefaultServerID,
                                                       _ProtocolVersion)

        # This initialises the low level routines that read and write the actual data table.
        # These routines are protocol specific.
        self._HMIDataTable = HMIDataTable.HMIDataTable(MBDataTable.MemMap)

        # This handles converting MB-HMI tags to Modbus data table addresses.
        self.HMIData = HMIAddr.HMIData(self._HMIDataTable, {},
                                       self.HMIReservedTags, {}, {})

        # This object validates the protocol specific parameters.
        self.HMITagValidator = HMIConfigvalidator.HMIConfigValidator()

        # Create an initial default configuration. We give it an empty file name,
        # because we don't want to load the configuration just yet.
        timestamp = time.time()
        defaultconfig = HMIConfig.HMIConfig('', timestamp,
                                            self.HMITagValidator)
        # Reference to current tag configuration object.
        self._HMICurrentTagconfig = defaultconfig
        # Reference to new tag configuration object.
        self._HMINewTagconfig = defaultconfig

        # General configuration status parameters.
        self._NewConfigStatParams = self._SetConfigStatus(
            time.time(), 'N/A', False)
        self._CurrentConfigStatParams = self._SetConfigStatus(
            time.time(), 'N/A', False)

        # For server connection stats calculations.
        self._RequestCounter = []

        # For updating the status information.
        self._StatusInfo = None
Beispiel #3
0
    def LoadHMIConfig(self):
        """Load and validate the HMI configuration.
		"""

        # This object validates the protocol specific parameters.
        self._HMITagValidator = self._configvalidator.HMIConfigValidator()

        starttimestamp = '%s' % time.ctime()

        # Load and validate the parameter file.
        hmitagconfig = HMIConfig.HMIConfig('mbhmi.config', starttimestamp,
                                           self._HMITagValidator)
        hmitagconfig.ReadConfigFile()

        # Print any errors which were found.
        for errmsg in hmitagconfig.GetConfigErrors():
            print(errmsg)

        # This handles encoding and decoding messages.
        self.HMIServerMsg = HMIMsg.HMIServerMessages(
            hmitagconfig.GetServerID())

        # Initialise the reserved tags handling.
        hmireservedtags = HMIAddr.HMIReservedTags(
            hmitagconfig.GetClientVersion(), _ProtocolVersion)

        # This handles converting MB-HMI tags to data table addresses.
        self.HMIData = HMIAddr.HMIData(self._datatable,
                                       hmitagconfig.GetConfigDict(),
                                       hmireservedtags,
                                       hmitagconfig.GetEventConfig(),
                                       hmitagconfig.GetAlarmConfig())

        # This initialises the last (previous) state dictionaries of the
        # event and alarm handlers. This is required so they don't issue
        # spurious events and alarms on start up.
        self.HMIData.InitMessages()

        # Store the HMI configuration.
        StatusReporter.Report.SetHMIConfig(hmitagconfig.GetServerID(),
                                           hmitagconfig.GetClientVersion(),
                                           hmitagconfig.GetConfigDict(),
                                           hmitagconfig.GetEventConfig(),
                                           hmitagconfig.GetAlarmConfig(),
                                           hmitagconfig.GetConfigErrors())
Beispiel #4
0
    def render_POST(self, request):
        """ Process a POST and return a response. This will handle
		all the AJAX read and write requests for data.
		"""

        # Update the server rate counter stats for reporting.
        HMIData.ERPStatus.IncRequestCounter()

        # Get the JSON data from the content.
        recvjson = request.content.read()

        # No data?
        if len(recvjson) == 0:
            return HMIMsg.ServerErrorMessage()

        # Analyse the request and construct a response.
        # restricted = False, erpfilter = True
        respjson = HMIData._HandleMessage(recvjson, False, True)

        # Return the JSON response.
        return respjson
Beispiel #5
0
    def render_POST(self, request):
        """ Process a POST and return a response. This will handle
		all the AJAX read and write requests for data.
		"""

        # Update the server rate counter stats for reporting.
        HMIData.RHMIStatus.IncRequestCounter()

        # Get the JSON data from the message.
        try:
            recvjson = request.received_headers['cascadas']
        except:
            # The data wasn't found in the headers.
            return HMIMsg.ServerErrorMessage()

        # Analyse the request and construct a response.
        # restricted = True, erpfilter = False
        respjson = HMIData._HandleMessage(recvjson, True, False)

        # Return the JSON response.
        return respjson
Beispiel #6
0
def _HandleMessage(recvjson, restricted, erpfilter):
    """Handle a protocol message.
	Parameters: recvjson (string) = The received JSON message.
		restricted (boolean) = If true, write and alarm acknowledge attempts 
			will be filtered out. This is used to implement a read-only version
			of the protocol.
		erpfilter (boolean) = If true, a limited sub-set of the HMI protocol 
			is implemented. All alarm and event related commands are ignored,
			and read and write commands are filtered according to the ERP list 
			parameters in the configuration.
	Only select *ONE* of the restricted or erpfilter options, not both!
	Returns: (string) = The response JSON string.
	"""

    # Decode the message.
    try:
        (clientid, msgid, readlist, readnoclist, writevalues, readablereq,
         writablereq, eventrequest, alarmrequest, alarmackrequest,
         alarmhistoryrequest) = Msg.HMIServerMsg.HMIRequest(recvjson)
    except:
        # Couldn't decode the JSON string.
        return HMIMsg.ProtocolErrorMessage()

    # With the "restricted" version, all write attempts are suppressed.
    # Write commands will return an error.
    # Alarm acknowldgements are simply discarded.
    erpreaderrors = {}
    erpwriteerrors = {}
    if restricted:
        alarmackrequest = []
        writeerrors = dict([(x, 'writeprotected') for x in writevalues.keys()])
        writevalues = {}

    # The ERP filter allows a subset of the Cascadas protocol.
    elif erpfilter:
        readlist, writevalues, erpreaderrors, erpwriteerrors = _ERPFilter(
            readlist, writevalues)
        readablereq = {}
        writablereq = {}
        eventrequest = []
        alarmrequest = []
        alarmackrequest = []
        alarmhistoryrequest = []

    # Analyse the request and construct a response.
    try:
        # Write the data table.
        if (len(writevalues) > 0):
            writeerrors = Msg.HMIData.WriteDataTable(writevalues)
        else:
            writeerrors = {}

        # For ERP requests, combine the errors from the authorised and
        # unauthorised requests.
        if erpfilter:
            erpwriteerrors.update(writeerrors)
            writeerrors = erpwriteerrors

        # Read the data table.
        if (len(readlist) > 0):
            readresult, readerrors = Msg.HMIData.ReadDataTable(readlist)
        else:
            readresult = {}
            readerrors = {}

        # For ERP requests, combine the errors from the authorised and
        # unauthorised requests.
        if erpfilter:
            erpreaderrors.update(readerrors)
            readerrors = erpreaderrors

        # We don't support read with NOC.
        readnocresult = {}

        # Test the tags to see if they are readable.
        if (readablereq != {}):
            readableresp = Msg.HMIData.TestTags(readablereq, False)
        else:
            readableresp = {}

        # Test the tags to see if they are writable.
        if (writablereq != {}):
            writableresp = Msg.HMIData.TestTags(writablereq, True)
        else:
            writableresp = {}

        # Events.
        eventbuffer, eventerrors = Msg.HMIData.GetEvents(eventrequest)

        # Alarms.
        alarmresp, alarmerrors = Msg.HMIData.GetAlarms(alarmrequest)

        # Update the alarm acknowledge requests from the client. These
        # only need to be processed as they arrive.
        Msg.HMIData.AckAlarms(alarmackrequest, clientid)

        # Update the alarm history from the records.
        # Construct a response.
        alarmhistorybuffer, alarmhisterrors = Msg.HMIData.GetAlarmHistory(
            alarmhistoryrequest)

        # Determine if there were any command errors. Since we don't
        # support read with NOC, any attempt at that is a command error.
        if ((writeerrors != {}) or (readerrors != {})
                or (len(readnoclist) != 0) or (readableresp != {})
                or (writableresp != {}) or (eventerrors != {})
                or (alarmerrors != {}) or (alarmhisterrors != {})):
            serverstat = 'commanderror'
        else:
            # If not, then the server status is ok.
            serverstat = 'ok'

    except:
        # We couldn't use the request message, so we need to return a server error.
        return HMIMsg.ServerErrorMessage()

    # The time stampe is UTC (GMT).
    timestamp = time.time()

    # Construct the response.
    try:
        return Msg.HMIServerMsg.HMIResponse(
            msgid, serverstat, timestamp, readresult, readnocresult,
            readerrors, writeerrors, readableresp, writableresp, eventbuffer,
            eventerrors, alarmresp, alarmerrors, alarmhistorybuffer,
            alarmhisterrors)

    except:
        # We couldn't encode a proper response for some reason.
        print(_Msgs['hmiencodingerror'] % time.ctime())
        return HMIMsg.ServerErrorMessage()
Beispiel #7
0
    def MsgInit(self):
        """Initialise the configuration. This is done explicitly so that
		the main configuration system can call it when desired.
		"""

        # Get the time stamp for when we started.
        timestamp = time.time()

        # Calculate the file signature.
        try:
            filesig = MonUtils.CalcFileSig(self._ConfigFileName)
        except:
            # File may not exist.
            filesig = 'N/A'

        # Load the HMI tag configuration from disk.
        self._HMINewTagconfig = HMIConfig.HMIConfig(self._ConfigFileName,
                                                    timestamp,
                                                    self.HMITagValidator)
        self._HMINewTagconfig.ReadConfigFile()
        # Check if errors are present in the new configuration.
        ConfigOK = len(self._HMINewTagconfig.GetConfigErrors()) == 0

        # Calculate the new status parameters. We manage the status
        # parameters here rather than in the parser itself because
        # the HMI parser library is shared with other programs.
        self._NewConfigStatParams = self._SetConfigStatus(
            timestamp, filesig, ConfigOK)

        # If we don't have anything for the current configuration yet, then use
        # the one we just read, whether it is any good or not.
        if not self._HMICurrentTagconfig:
            self._HMICurrentTagconfig = self._HMINewTagconfig
            self._CurrentConfigStatParams = self._NewConfigStatParams

        # If the new configuration is OK, we use it in place of the old one.
        if not self._HMINewTagconfig.GetConfigErrors():
            self._HMICurrentTagconfig = self._HMINewTagconfig
            self._CurrentConfigStatParams = self._NewConfigStatParams

        # This handles encoding and decoding messages. We initialise it with
        # the name we want to use for the HMI server.
        self.HMIServerMsg = HMIMsg.HMIServerMessages(
            self._HMICurrentTagconfig.GetServerID())

        # Initialised the reserved tags handling with the client and protocol versions.
        self.HMIReservedTags = HMIAddr.HMIReservedTags(
            self._HMICurrentTagconfig.GetServerID(), _ProtocolVersion)

        # This handles converting MB-HMI tags to Modbus data table addresses.
        self.HMIData = HMIAddr.HMIData(
            self._HMIDataTable, self._HMICurrentTagconfig.GetConfigDict(),
            self.HMIReservedTags, self._HMICurrentTagconfig.GetEventConfig(),
            self._HMICurrentTagconfig.GetAlarmConfig())

        # This initialises the last (previous) state dictionaries of the
        # event and alarm handlers. This is required so they don't issue
        # spurious events and alarms on start up. We have to do this whenever
        # we re-initialise the parameters so we can update the monitored
        # events list.
        self.HMIData.InitMessages()
Beispiel #8
0
def HandleHMIMessage(recvjson):
    """Handle an HMI protocol message.
	Parameters: recvjson (string) = The received JSON message.
	Returns: (string) = The response JSON string.
	"""

    # Add the recieved message to the message buffer.
    StatusReporter.Report.AddHMIRequest(recvjson)

    # Decode the message.
    try:
        (clientid, msgid, readlist, readnoclist, writevalues, readablereq,
         writablereq, eventrequest, alarmrequest, alarmackrequest,
         alarmhistoryrequest) = HMIConf.HMIServerMsg.HMIRequest(recvjson)
    except:
        # Add the error response message to the message buffer.
        StatusReporter.Report.AddHMIResponse(HMIMsg.ProtocolErrorMessage())

        # Couldn't decode the JSON string.
        return HMIMsg.ProtocolErrorMessage()

    # Analyse the request and construct a response.
    try:
        # Write the data table.
        if (len(writevalues) > 0):
            writeerrors = HMIConf.HMIData.WriteDataTable(writevalues)
        else:
            writeerrors = {}

        # Read the data table.
        if (len(readlist) > 0):
            readresult, readerrors = HMIConf.HMIData.ReadDataTable(readlist)
        else:
            readresult = {}
            readerrors = {}

        # We don't support read with NOC.
        readnocresult = {}

        # Test the tags to see if they are readable.
        if (readablereq != {}):
            readableresp = HMIConf.HMIData.TestTags(readablereq, False)
        else:
            readableresp = {}

        # Test the tags to see if they are writable.
        if (writablereq != {}):
            writableresp = HMIConf.HMIData.TestTags(writablereq, True)
        else:
            writableresp = {}

        # Update the events from the data table. Our event scan rate
        # here is only as fast as the client asks for them.
        HMIConf.HMIData.UpdateEvents()
        # Construct a response.
        eventbuffer, eventerrors = HMIConf.HMIData.GetEvents(eventrequest)

        # Update the alarms from the data table. Our alarm scan rate
        # here is only as fast as the client asks for them.
        HMIConf.HMIData.UpdateAlarms()
        # Construct a response.
        alarmresp, alarmerrors = HMIConf.HMIData.GetAlarms(alarmrequest)

        # Update the alarm acknowledge requests from the client. These
        # only need to be processed as they arrive.
        HMIConf.HMIData.AckAlarms(alarmackrequest, clientid)

        # Update the alarm history from the records.
        # Construct a response.
        alarmhistorybuffer, alarmhisterrors = HMIConf.HMIData.GetAlarmHistory(
            alarmhistoryrequest)

        # Determine if there were any command errors. Since we don't
        # support read with NOC, any attempt at that is a command error.
        if ((writeerrors != {}) or (readerrors != {})
                or (len(readnoclist) != 0) or (readableresp != {})
                or (writableresp != {}) or (eventerrors != {})
                or (alarmerrors != {}) or (alarmhisterrors != {})):
            serverstat = 'commanderror'
        else:
            # If not, then the server status is ok.
            serverstat = 'ok'

    except:
        # Add the error response message to the message buffer.
        StatusReporter.Report.AddHMIResponse(HMIMsg.ServerErrorMessage())

        # We couldn't use the request message, so we need to return a server error.
        return HMIMsg.ServerErrorMessage()

    # The time stampe is UTC (GMT).
    timestamp = time.time()

    # Construct the response.
    try:
        sentjson = HMIConf.HMIServerMsg.HMIResponse(
            msgid, serverstat, timestamp, readresult, readnocresult,
            readerrors, writeerrors, readableresp, writableresp, eventbuffer,
            eventerrors, alarmresp, alarmerrors, alarmhistorybuffer,
            alarmhisterrors)

        # Add the response message to the message buffer.
        StatusReporter.Report.AddHMIResponse(sentjson)

        return sentjson

    except:
        # We couldn't encode a proper response for some reason.
        print('Error encoding MB-HMI response: %s' % time.ctime())

        # Add the error response message to the message buffer.
        StatusReporter.Report.AddHMIResponse(HMIMsg.ServerErrorMessage())

        return HMIMsg.ServerErrorMessage()