Ejemplo n.º 1
0
    async def _process_interrogate_activation(self, asdu):
        is_counter_interrogate = (asdu.type == _iec104.AsduType.C_CI_NA)

        try:
            if is_counter_interrogate:
                freeze = common.FreezeCode.READ
                freeze = asdu.ios[0].elements[0].freeze
                data = await aio.call(self._counter_interrogate_cb, self,
                                      asdu.address, freeze)

            else:
                data = await aio.call(self._interrogate_cb, self, asdu.address)

        except Exception as e:
            mlog.warning('interrogate error: %s', e, exc_info=e)
            data = None

        # TODO should check requested qualifier
        element = (_iec104.IOElement_C_CI_NA(5, freeze) if
                   is_counter_interrogate else _iec104.IOElement_C_IC_NA(20))
        io = _iec104.IO(address=0, time=None, elements=[element])

        self._transport.write(
            _iec104.ASDU(type=asdu.type,
                         cause=common.Cause.ACTIVATION_CONFIRMATION,
                         is_negative_confirm=data is None,
                         is_test=False,
                         originator_address=None,
                         address=asdu.address,
                         ios=[io]))

        if data is None:
            return

        data_cause = (common.Cause.INTERROGATED_COUNTER
                      if is_counter_interrogate else
                      common.Cause.INTERROGATED_STATION)
        for i in data:
            data_asdu = _asdu_from_data(i)
            data_asdu = data_asdu._replace(cause=data_cause)
            self._transport.write(data_asdu)

        self._transport.write(
            _iec104.ASDU(type=asdu.type,
                         cause=common.Cause.ACTIVATION_TERMINATION,
                         is_negative_confirm=False,
                         is_test=False,
                         originator_address=None,
                         address=asdu.address,
                         ios=[io]))
Ejemplo n.º 2
0
 async def _process_interrogate_deactivation(self, asdu):
     self._transport.write(
         _iec104.ASDU(type=asdu.type,
                      cause=common.Cause.DEACTIVATION_CONFIRMATION,
                      is_negative_confirm=True,
                      is_test=False,
                      originator_address=None,
                      address=asdu.address,
                      ios=asdu.ios))
Ejemplo n.º 3
0
    async def _process_command_deactivation(self, asdu):
        cmds = _asdu_to_commands(asdu)

        try:
            result = await aio.call(self._command_cb, self, cmds)

        except Exception as e:
            mlog.warning('command deactivation error: %s', e, exc_info=e)
            result = False

        self._transport.write(
            _iec104.ASDU(type=asdu.type,
                         cause=common.Cause.DEACTIVATION_CONFIRMATION,
                         is_negative_confirm=not result,
                         is_test=False,
                         originator_address=None,
                         address=asdu.address,
                         ios=asdu.ios))
Ejemplo n.º 4
0
    async def counter_interrogate(
        self,
        asdu_address: int = 0xFFFF,
        freeze: common.FreezeCode = common.FreezeCode.READ  # NOQA
    ) -> typing.List[common.Data]:
        """Interrogate remote device counters

        Asdu broadcast address 0xFFFF is not supported by all devices

        """
        element = _iec104.IOElement_C_CI_NA(request=5, freeze=freeze)
        io = _iec104.IO(address=0, elements=[element], time=None)
        asdu = _iec104.ASDU(type=_iec104.AsduType.C_CI_NA,
                            cause=common.Cause.ACTIVATION,
                            is_negative_confirm=False,
                            is_test=False,
                            originator_address=None,
                            address=asdu_address,
                            ios=[io])

        async with self._counter_interrogate_lock:
            if not self.is_open:
                raise ConnectionError()

            self._transport.write(asdu)
            self._counter_interrogate_queue = aio.Queue()

            try:
                data = collections.deque()
                async for i in self._counter_interrogate_queue:
                    data.extend(i)

            finally:
                self._counter_interrogate_queue = None

            if not self.is_open:
                raise ConnectionError()

            return list(data)
Ejemplo n.º 5
0
def _asdu_from_command(cmd):
    if isinstance(cmd.value, common.SingleValue):
        if cmd.time is None:
            asdu_type = _iec104.AsduType.C_SC_NA
            element_cls = _iec104.IOElement_C_SC_NA
        else:
            asdu_type = _iec104.AsduType.C_SC_TA
            element_cls = _iec104.IOElement_C_SC_TA

    elif isinstance(cmd.value, common.DoubleValue):
        if cmd.time is None:
            asdu_type = _iec104.AsduType.C_DC_NA
            element_cls = _iec104.IOElement_C_DC_NA
        else:
            asdu_type = _iec104.AsduType.C_DC_TA
            element_cls = _iec104.IOElement_C_DC_TA

    elif isinstance(cmd.value, common.RegulatingValue):
        if cmd.time is None:
            asdu_type = _iec104.AsduType.C_RC_NA
            element_cls = _iec104.IOElement_C_RC_NA
        else:
            asdu_type = _iec104.AsduType.C_RC_TA
            element_cls = _iec104.IOElement_C_RC_TA

    elif isinstance(cmd.value, common.NormalizedValue):
        if cmd.time is None:
            asdu_type = _iec104.AsduType.C_SE_NA
            element_cls = _iec104.IOElement_C_SE_NA
        else:
            asdu_type = _iec104.AsduType.C_SE_TA
            element_cls = _iec104.IOElement_C_SE_TA

    elif isinstance(cmd.value, common.ScaledValue):
        if cmd.time is None:
            asdu_type = _iec104.AsduType.C_SE_NB
            element_cls = _iec104.IOElement_C_SE_NB
        else:
            asdu_type = _iec104.AsduType.C_SE_TB
            element_cls = _iec104.IOElement_C_SE_TB

    elif isinstance(cmd.value, common.FloatingValue):
        if cmd.time is None:
            asdu_type = _iec104.AsduType.C_SE_NC
            element_cls = _iec104.IOElement_C_SE_NC
        else:
            asdu_type = _iec104.AsduType.C_SE_TC
            element_cls = _iec104.IOElement_C_SE_TC

    else:
        raise ValueError('unsupported command value type')

    if cmd.action == common.Action.EXECUTE:
        select = False
        cause = common.Cause.ACTIVATION

    elif cmd.action == common.Action.SELECT:
        select = True
        cause = common.Cause.ACTIVATION

    elif cmd.action == common.Action.CANCEL:
        select = False
        cause = common.Cause.DEACTIVATION

    else:
        raise ValueError('unsupported command action')

    element = element_cls(value=cmd.value,
                          select=select,
                          qualifier=cmd.qualifier)
    io = _iec104.IO(address=cmd.io_address, time=cmd.time, elements=[element])
    asdu = _iec104.ASDU(type=asdu_type,
                        cause=cause,
                        is_negative_confirm=False,
                        is_test=False,
                        originator_address=None,
                        address=cmd.asdu_address,
                        ios=[io])
    return asdu
Ejemplo n.º 6
0
def _asdu_from_data(data):
    if isinstance(data.value, common.SingleValue):
        if data.time is None:
            asdu_type = _iec104.AsduType.M_SP_NA
            element = _iec104.IOElement_M_SP_NA(data.value, data.quality)
        else:
            asdu_type = _iec104.AsduType.M_SP_TB
            element = _iec104.IOElement_M_SP_TB(data.value, data.quality)

    elif isinstance(data.value, common.DoubleValue):
        if data.time is None:
            asdu_type = _iec104.AsduType.M_DP_NA
            element = _iec104.IOElement_M_DP_NA(data.value, data.quality)
        else:
            asdu_type = _iec104.AsduType.M_DP_TB
            element = _iec104.IOElement_M_DP_TB(data.value, data.quality)

    elif isinstance(data.value, common.StepPositionValue):
        if data.time is None:
            asdu_type = _iec104.AsduType.M_ST_NA
            element = _iec104.IOElement_M_ST_NA(data.value, data.quality)
        else:
            asdu_type = _iec104.AsduType.M_ST_TB
            element = _iec104.IOElement_M_ST_TB(data.value, data.quality)

    elif isinstance(data.value, common.BitstringValue):
        if data.time is None:
            asdu_type = _iec104.AsduType.M_BO_NA
            element = _iec104.IOElement_M_BO_NA(data.value, data.quality)
        else:
            asdu_type = _iec104.AsduType.M_BO_TB
            element = _iec104.IOElement_M_BO_TB(data.value, data.quality)

    elif isinstance(data.value, common.NormalizedValue):
        if data.time is None:
            asdu_type = _iec104.AsduType.M_ME_NA
            element = _iec104.IOElement_M_ME_NA(data.value, data.quality)
        else:
            asdu_type = _iec104.AsduType.M_ME_TD
            element = _iec104.IOElement_M_ME_TD(data.value, data.quality)

    elif isinstance(data.value, common.ScaledValue):
        if data.time is None:
            asdu_type = _iec104.AsduType.M_ME_NB
            element = _iec104.IOElement_M_ME_NB(data.value, data.quality)
        else:
            asdu_type = _iec104.AsduType.M_ME_TE
            element = _iec104.IOElement_M_ME_TE(data.value, data.quality)

    elif isinstance(data.value, common.FloatingValue):
        if data.time is None:
            asdu_type = _iec104.AsduType.M_ME_NC
            element = _iec104.IOElement_M_ME_NC(data.value, data.quality)
        else:
            asdu_type = _iec104.AsduType.M_ME_TF
            element = _iec104.IOElement_M_ME_TF(data.value, data.quality)

    elif isinstance(data.value, common.BinaryCounterValue):
        if data.time is None:
            asdu_type = _iec104.AsduType.M_IT_NA
            element = _iec104.IOElement_M_IT_NA(data.value)
        else:
            asdu_type = _iec104.AsduType.M_IT_TB
            element = _iec104.IOElement_M_IT_TB(data.value)

    else:
        raise ValueError('unsupported command value type')

    io = _iec104.IO(address=data.io_address,
                    time=data.time,
                    elements=[element])
    asdu = _iec104.ASDU(type=asdu_type,
                        cause=data.cause,
                        is_negative_confirm=False,
                        is_test=data.is_test,
                        originator_address=None,
                        address=data.asdu_address,
                        ios=[io])
    return asdu