Esempio n. 1
0
 def _cb_power_switch(self, oid: int, value: Union[str, float, bool]) -> None:
     '''
     Callback for power switch, both inventory and metrics.
     '''
     try:
         # rb485.u_l_grid[0]
         if oid == 0x93F976AB:
             self.readings.power_switch_readings.grid_voltage_l1 = ensure_type(value, float)
         # rb485.u_l_grid[1]
         elif oid == 0x7A9091EA:
             self.readings.power_switch_readings.grid_voltage_l2 = ensure_type(value, float)
         # rb485.u_l_grid[3]
         elif oid == 0x21EE7CBB:
             self.readings.power_switch_readings.grid_voltage_l3 = ensure_type(value, float)
         # rb485.f_grid[0]
         elif oid == 0x9558AD8A:
             self.readings.power_switch_readings.grid_frequency_l1 = ensure_type(value, float)
         # rb485.f_grid[1]
         elif oid == 0xFAE429C5:
             self.readings.power_switch_readings.grid_frequency_l2 = ensure_type(value, float)
         # rb485.f_grid[2]
         elif oid == 0x104EB6A:
             self.readings.power_switch_readings.grid_frequency_l3 = ensure_type(value, float)
         # rb485.f_wr[0]
         elif oid == 0x3B5F6B9D:
             self.readings.power_switch_readings.power_storage_frequency_l1 = ensure_type(value, float)
         # rb485.f_wr[1]
         elif oid == 0x6FD36B32:
             self.readings.power_switch_readings.power_storage_frequency_l2 = ensure_type(value, float)
         # rb485.f_wr[2]
         elif oid == 0x905F707B:
             self.readings.power_switch_readings.power_storage_frequency_l3 = ensure_type(value, float)
         else:
             log.warning('_cb_power_switch: unhandled oid 0x%X', oid)
     except TypeError:
         # oid is known at this point, as the else above catches unknowns without raising
         log.warning('Got wrong type %s for %s', type(value), R.get_by_id(oid).name)
 def __post_init__(self):
     self.object_infos = [
         REGISTRY.get_by_name(object_name)
         for object_name in self.object_names
     ]
Esempio n. 3
0
def main():
    ''' Main program '''
    packets = rdpcap(sys.argv[1])

    streams = dict()

    i = 0
    for name, stream in packets.sessions().items():
        print(f'Stream {i:4} {name} {stream} ', end='')
        length = 0
        streams[i] = dict()
        for k in stream:
            if TCP in k:
                if len(k[TCP].payload) > 0:
                    if k[TCP].sport == 8899 or k[TCP].dport == 8899:
                        payload = bytes(k[TCP].payload)

                        # skip AT+ keepalive and app serial "protocol switch" '2b3ce1'
                        if payload in [b'AT+\r', b'+<\xe1']:
                            continue
                        ptime = float(k.time)
                        if ptime not in streams[i]:
                            streams[i][ptime] = b''
                        streams[i][ptime] += payload
                        length += len(payload)
        print(f'{length} bytes')
        i += 1

    frame = None
    sid = 0
    for _, data in streams.items():
        print(f'\nNEW STREAM #{sid}\n')

        for timestamp, data_item in data.items():
            print(f'NEW INPUT: {datetime.fromtimestamp(timestamp):%Y-%m-%d %H:%M:%S.%f} | {data_item.hex()}')

            # frames should not cross segments (though it may be valid, but the devices haven't been observed doing
            # that). Sometimes, the device sends invalid data with a very high length field, causing the code to read
            # way byond the end of the actual data, causing it to miss frames until its length is satisfied. This way,
            # if the next segment starts with the typical 0x002b used by the devices, the current frame is dropped.
            # This way only on segment is lost.
            if frame and data_item[0:2] == b'\0+':
                print('Frame not complete at segment start, starting new frame.')
                print(f'command: {frame.command}, length: {frame.frame_length}, oid: 0x{frame.id:X}')
                frame = None

            while len(data_item) > 0:
                if not frame:
                    frame = ReceiveFrame()
                try:
                    i = frame.consume(data_item)
                except InvalidCommand as exc:
                    if frame.command == Command.EXTENSION:
                        print('Frame is an extension frame and we don\'t know how to parse it')
                    else:
                        print(f'Invalid command 0x{exc.command:x} received after consuming {exc.consumed_bytes} bytes')
                    i = exc.consumed_bytes
                except FrameCRCMismatch as exc:
                    print(f'CRC mismatch, got 0x{exc.received_crc:X} but calculated '
                          f'0x{exc.calculated_crc:X}. Buffer: {frame._buffer.hex()}')
                    i = exc.consumed_bytes
                except struct.error as exc:
                    print(f'skipping 2 bytes ahead as struct could not unpack: {str(exc)}')
                    i = 2
                    frame = ReceiveFrame()

                data_item = data_item[i:]
                print(f'frame consumed {i} bytes, {len(data_item)} remaining')
                if frame.complete():
                    if frame.id == 0:
                        print(f'Frame complete: {frame} Buffer: {frame._buffer.hex()}')
                    else:
                        print(f'Frame complete: {frame}')
                    try:
                        rid = R.get_by_id(frame.id)
                    except KeyError:
                        print('Could not find ID in registry')
                    else:
                        if frame.command == Command.READ:
                            print(f'Received read : {rid.name:40}')
                        else:
                            if frame.command in [Command.RESPONSE, Command.LONG_RESPONSE]:
                                dtype = rid.response_data_type
                            else:
                                dtype = rid.request_data_type
                            is_write = frame.command in [Command.WRITE, Command.LONG_WRITE]

                            try:
                                value = decode_value(dtype, frame.data)
                            except (struct.error, UnicodeDecodeError) as exc:
                                print(f'Could not decode value: {str(exc)}')
                                if is_write:
                                    print(f'Received write : {rid.name:40} type: {dtype.name:17} value: UNKNOWN')
                                else:
                                    print(f'Received reply : {rid.name:40} type: {dtype.name:17} value: UNKNOWN')
                            except KeyError:
                                print('Could not decode unknown type')
                                if is_write:
                                    print(f'Received write : {rid.name:40} value: 0x{frame.data.hex()}')
                                else:
                                    print(f'Received reply : {rid.name:40} value: 0x{frame.data.hex()}')
                            else:
                                if dtype == DataType.ENUM:
                                    try:
                                        value = rid.enum_str(value)
                                    except RctClientException as exc:
                                        print(f'ENUM mapping failed: {str(exc)}')
                                    except KeyError:
                                        print('ENUM value out of bounds')
                                if is_write:
                                    print(f'Received write : {rid.name:40} type: {dtype.name:17} value: {value}')
                                else:
                                    print(f'Received reply : {rid.name:40} type: {dtype.name:17} value: {value}')
                    frame = None
                    print()
            print('END OF INPUT-SEGMENT')
        sid += 1
Esempio n. 4
0
def main():
    packets = rdpcap(sys.argv[1])

    streams = dict()

    i = 0
    pl = b''
    for name, stream in packets.sessions().items():
        print(f'Stream {i:4} {name} {stream} ', end='')
        length = 0
        streams[i] = dict()
        for k in stream:
            if TCP in k:
                if len(k[TCP].payload) > 0:
                    if k[TCP].sport == 8899 or k[TCP].dport == 8899:
                        payload = bytes(k[TCP].payload)

                        # skip AT+ keepalive and app serial "protocol switch"
                        if payload == b'AT+\r' or payload == bytearray.fromhex(
                                '2b3ce1'):
                            continue
                        ptime = float(k.time)
                        if ptime not in streams[i]:
                            streams[i][ptime] = b''
                        streams[i][ptime] += payload
                        length += len(payload)
        print(f'{length} bytes')
        i += 1

    frame = None
    for _, data in streams.items():

        for ts, pl in data.items():

            while len(pl) > 0:
                if not frame:
                    frame = ReceiveFrame()
                try:
                    i = frame.consume(pl)
                except FrameCRCMismatch as exc:
                    if frame.command == Command.EXTENSION:
                        print(
                            'Frame is an extension frame and we don\'t know how to parse it'
                        )
                    else:
                        print(
                            f'Frame {frame.id} CRC mismatch, got 0x{exc.received_crc:X} but calculated '
                            f'0x{exc.calculated_crc:X}. Buffer: {frame._buffer.hex()}'
                        )
                    print(pl[0:2].hex())
                    if pl[0:2] == bytearray.fromhex('002b'):
                        i = 2
                    else:
                        i = exc.consumed_bytes
                pl = pl[i:]
                print(f'frame consumed {i} bytes, {len(pl)} remaining')
                if frame.complete():
                    if frame.id == 0:
                        print(
                            f'Frame complete: {frame} Buffer: {frame._buffer.hex()}'
                        )
                    else:
                        print(f'Frame complete: {frame}')
                    try:
                        rid = R.get_by_id(frame.id)
                    except KeyError:
                        print('Could not find ID in registry')
                    else:
                        if frame.command == Command.READ:
                            print(
                                f'Received read : {rid.index:4} {rid.name:40}')
                        else:
                            if frame.command in [
                                    Command.RESPONSE, Command.LONG_RESPONSE
                            ]:
                                dtype = rid.response_data_type
                            else:
                                dtype = rid.request_data_type
                            try:
                                value = decode_value(dtype, frame.data)
                            except struct.error as exc:
                                print(f'Could not decode value: {str(exc)}')
                                print(
                                    f'Received reply: {rid.index:4} {rid.name:40} type: {dtype.name:17} value: '
                                    'UNKNOWN')
                            except UnicodeDecodeError as exc:
                                print(f'Could not decode value: {str(exc)}')
                                print(
                                    f'Received reply: {rid.index:4} {rid.name:40} type: {dtype.name:17} value: '
                                    'UNKNOWN')
                            else:
                                if dtype == DataType.ENUM:
                                    try:
                                        value = rid.enum_str(value)
                                    except RctClientException as exc:
                                        print(
                                            f'ENUM mapping failed: {str(exc)}')
                                    except KeyError:
                                        print('ENUM value out of bounds')
                                print(
                                    f'Received reply: {rid.index:4} {rid.name:40} type: {dtype.name:17} value: '
                                    f'{value}')
                    frame = None
Esempio n. 5
0
    async def _write_object(self, reader: StreamReader, writer: StreamWriter,
                            object_id: int, value):
        oinfo = REGISTRY.get_by_id(object_id)
        object_name = oinfo.name
        payload = encode_value(oinfo.request_data_type, value)
        send_command_frame = SendFrame(command=Command.WRITE,
                                       id=object_id,
                                       payload=payload)

        self.logger.debug(
            "Writing RCT Power data (%s) for object %x (%s)...",
            str(value),
            object_id,
            object_name,
        )
        request_time = datetime.now()

        try:
            async with async_timeout.timeout(READ_TIMEOUT):
                await writer.drain()
                writer.write(send_command_frame.data)

                # loop until we return or time out
                while True:
                    response_frame = ReceiveFrame()

                    while not response_frame.complete() and not reader.at_eof(
                    ):
                        raw_response = await reader.read(1)

                        if len(raw_response) > 0:
                            response_frame.consume(raw_response)

                    if response_frame.complete():
                        response_object_info = REGISTRY.get_by_id(
                            response_frame.id)
                        data_type = response_object_info.response_data_type
                        received_object_name = response_object_info.name

                        # ignore, if this is not the answer to the latest request
                        if object_id != response_frame.id:
                            self.logger.debug(
                                "Mismatch of requested and received object ids: requested %x (%s), but received %x (%s)",
                                object_id,
                                object_name,
                                response_frame.id,
                                received_object_name,
                            )
                            continue

                        decoded_value: Union[
                            bool, bytes, float, int, str, Tuple[datetime,
                                                                Dict[datetime,
                                                                     int]],
                            Tuple[datetime,
                                  Dict[datetime,
                                       EventEntry]], ] = decode_value(
                                           data_type,
                                           response_frame.data)  # type: ignore

                        self.logger.debug(
                            "Decoded data for object %x (%s): %s",
                            response_frame.id,
                            received_object_name,
                            decoded_value,
                        )

                        return ValidApiResponse(
                            object_id=object_id,
                            object_name=object_name,
                            time=request_time,
                            value=decoded_value,
                        )
                    else:
                        self.logger.debug(
                            "Error decoding object %x (%s): %s",
                            object_id,
                            object_name,
                            response_frame.data,
                        )
                        return InvalidApiResponse(
                            object_id=object_id,
                            object_name=object_name,
                            time=request_time,
                            cause="INCOMPLETE",
                        )

        except TimeoutError as exc:
            self.logger.debug("Error reading object %x (%s): %s", object_id,
                              object_name, str(exc))
            return InvalidApiResponse(
                object_id=object_id,
                object_name=object_name,
                time=request_time,
                cause="OBJECT_READ_TIMEOUT",
            )
        except FrameCRCMismatch as exc:
            self.logger.debug("Error reading object %x (%s): %s", object_id,
                              object_name, str(exc))
            return InvalidApiResponse(
                object_id=object_id,
                object_name=object_name,
                time=request_time,
                cause="CRC_ERROR",
            )
        except FrameLengthExceeded as exc:
            self.logger.debug("Error reading object %x (%s): %s", object_id,
                              object_name, str(exc))
            return InvalidApiResponse(
                object_id=object_id,
                object_name=object_name,
                time=request_time,
                cause="FRAME_LENGTH_EXCEEDED",
            )
        except InvalidCommand as exc:
            self.logger.debug("Error reading object %x (%s): %s", object_id,
                              object_name, str(exc))
            return InvalidApiResponse(
                object_id=object_id,
                object_name=object_name,
                time=request_time,
                cause="INVALID_COMMAND",
            )
        except struct.error as exc:
            self.logger.debug("Error reading object %x (%s): %s", object_id,
                              object_name, str(exc))
            return InvalidApiResponse(
                object_id=object_id,
                object_name=object_name,
                time=request_time,
                cause="PARSING_ERROR",
            )
        except Exception as exc:
            self.logger.debug("Error reading object %x (%s): %s", object_id,
                              object_name, str(exc))
            return InvalidApiResponse(
                object_id=object_id,
                object_name=object_name,
                time=request_time,
                cause="UNKNOWN_ERROR",
            )