def on_config_queue(self):
        OFFSET_NUM_PMU = 18
        OFFSET_CHNAMES = 46

        #self.logger.info('on_config_queue()')
        frame = self.config_queue.recv_pyobj()

        assert CommonFrame.extract_frame_type(frame) == 'cfg2'

        num_pmu, stn, idcode, fmt, phnmr, annmr, dgnmr = \
            struct.unpack_from('!H16sHHHHH', frame, OFFSET_NUM_PMU)
        assert num_pmu == 1  # cannot process multistream configs

        def str_clean(bstr):
            return bstr.decode('ascii').strip()

        n_channels = (phnmr + annmr + dgnmr * 16)
        ch_names_b = struct.unpack_from('16s' * n_channels, frame,
                                        OFFSET_CHNAMES)
        ch_names = [str_clean(ch_name) for ch_name in ch_names_b]

        config = {
            'station': str_clean(stn),
            'phasors': ch_names[0:phnmr],
            'analogs': ch_names[phnmr:phnmr + annmr],
            'digitals': ch_names[phnmr + annmr:]
        }

        self.c37config.send_pyobj((frame, config))
Beispiel #2
0
    def on_data_queue(self):
        """Processing incoming data frames (application specific).

        Note: This is not a generic implementation.

        The current (hard coded) packet format:
        Value format: (P;F;F;F) = 15
            Polar Float phasors, Float analog and Float frequency values

        [PHASOR0]  VAGPM: Voltage at phase A of Grid side
        [PHASOR1]  VBYPM: Voltage at phase B of Grid side
        [PHASOR2]  VCYPM: Voltage at phase C of Grid side
        [PHASOR3]  VASPM: Voltage at phase A of MicroGrid side
        [PHASOR4]  VBZPM: Voltage at phase B of MicroGrid side
        [PHASOR5]  VCZPM: Voltage at phase C of MicroGrid side
        [ANALOG0]  VAGM: Voltage at phase A of Grid side - Magnitude only
        [ANALOG1]  VAGA: Voltage at phase A of Grid side - Angle in degrees only
        [ANALOG2]  VASM: Voltage at phase A of MicroGrid side - Magnitude only
        [ANALOG3]  VASA: Voltage at phase A of MicroGrid side - Angle in degrees only
        [ANALOG4]  SLIP1: Slip Frequency
        [DIGITAL0] BRKPCCTR: BReaKer at PCC TRipping
        [DIGITAL1] RMB1: Remote Bit 1
        [DIGITAL2] RMB2: Remote Bit 2
        """
        OFFSET_SOC = 6
        OFFSET_VALUES = 16
        FMT_VALUES = '!ff ff ff ff ff ff f f f f f f f H'

        #self.logger.info('on_data_queue()')
        frame = self.data_queue.recv_pyobj()
        _, framesize = struct.unpack_from('!HH', frame, 0)
        assert CommonFrame.extract_frame_type(frame) == 'data'

        soc, fracsec = struct.unpack_from('!II', frame, OFFSET_SOC)
        timestamp = soc + float(fracsec & 0xffffff) / 0xffffff # assuming time_base

        (vagpm_m, vagpm_a, vbypm_m, vbypm_a, vcypm_m, vcypm_a,
         vaspm_m, vaspm_a, vbzpm_m, vbzpm_a, vczpm_m, vczpm_a,
         freq, rocof, vagm, vaga, vasm, vasa, slip1, digits) = \
                struct.unpack_from(FMT_VALUES, frame, OFFSET_VALUES)

        data = {'VAGPM': (vagpm_m, vagpm_a), 'VBYPM': (vbypm_m, vbypm_a), 'VCYPM': (vcypm_m, vcypm_a),
                'VASPM': (vaspm_m, vaspm_a), 'VBZPM': (vbzpm_m, vbzpm_a), 'VCZPM': (vczpm_m, vczpm_a),
                'VAGM': vagm, 'VAGA': vaga, 'VASM': vasm, 'VASA': vasa, 'SLIP1': slip1,
                'DIGITALS': digits, 'FREQ': freq, 'ROCOF': rocof,
                'timestamp': timestamp}

        self.c37data.send_pyobj((frame, data))
Beispiel #3
0
    def client_handler(self, client_info):
        address_info = '%s:%d' % (client_info.address[0],
                                  client_info.address[1])
        try:
            while True:

                command = None
                received_data = b''

                if self.terminated.is_set():
                    break

                readable, _, _ = select([client_info.socket], [], [],
                                        0)  # Check for client commands

                if readable:
                    """
                    Keep receiving until SYNC + FRAMESIZE is received, 4 bytes in total.
                    Should get this in first iteration. FRAMESIZE is needed to determine when one complete message
                    has been received.
                    """
                    while len(received_data) < 4:
                        received_data += client_info.socket.recv(
                            4 - len(received_data))

                    bytes_received = len(received_data)
                    total_frame_size = int.from_bytes(received_data[2:4],
                                                      byteorder='big',
                                                      signed=False)

                    # Keep receiving until every byte of that message is received
                    while bytes_received < total_frame_size:
                        message_chunk = client_info.socket.recv(
                            total_frame_size - bytes_received)
                        if not message_chunk:
                            break
                        received_data += message_chunk
                        bytes_received += len(message_chunk)

                    # If complete message is received try to decode it
                    if len(received_data) == total_frame_size:
                        try:
                            received_message = CommonFrame.convert2frame(
                                received_data)  # Try to decode received data

                            if isinstance(received_message, CommandFrame):
                                command = received_message.get_command()
                                self.logger.info(
                                    "[%d] - Received command: [%s] <- (%s)",
                                    self.pmu_id, command, address_info)
                            else:
                                self.logger.info(
                                    "[%d] - Received [%s] <- (%s)",
                                    self.pmu_id,
                                    type(received_message).__name__,
                                    address_info)
                        except FrameError:
                            self.logger.warning(
                                "[%d] - Received unknown message <- (%s)",
                                self.pmu_id, address_info)
                    else:
                        self.logger.warning(
                            "[%d] - Message not received completely <- (%s)",
                            self.pmu_id, address_info)

                if command:
                    if command == 'start':
                        while not client_info.buffer.empty():
                            client_info.buffer.get()
                        client_info.streaming.set()
                        self.logger.info("[%d] - Start sending -> (%s)",
                                         self.pmu_id, address_info)

                    elif command == 'stop':
                        client_info.streaming.clear()
                        self.logger.info("[%d] - Stop sending -> (%s)",
                                         self.pmu_id, address_info)

                    elif command == 'header':
                        self.logger.info(
                            "[%d] - Replying Header request -> (%s)",
                            self.pmu_id, address_info)
                        client_info.socket.sendall(self.header_frame)

                    elif command == 'cfg2':
                        self.logger.info(
                            "[%d] - Replying Configuration frame 2 request -> (%s)",
                            self.pmu_id, address_info)
                        client_info.socket.sendall(self.cfg_frame)

                    else:
                        self.logger.warn(
                            "[%d] - Unsupported request: %s from (%s)",
                            self.pmu_id, command, address_info)

                if client_info.streaming.is_set(
                ) and not client_info.buffer.empty():
                    self.logger.debug("[%d] - Sending data frame -> (%s)",
                                      self.pmu_id, address_info)
                    frame = client_info.buffer.get()
                    client_info.socket.sendall(frame)

        except Exception as e:
            self.logger.exception('Critical error in client_handler')
        finally:
            client_info.socket.close()
            self.clients.remove(client_info)
            self.logger.info("[%d] - Connection from %s has been closed.",
                             self.pmu_id, address_info)
    def on_data_queue(self):
        on_clock_start = time.time()
        """Processing incoming data frames (application specific).

        Note: This is not a generic implementation.

        The current (hard coded) packet format:
        Value format: (P;F;F;F) = 15
            Polar Float phasors, Float analog and Float frequency values

        [PHASOR0]  VAGPM: not used
        
        [f]        f:   C37frequency
        [df]       df:  C37frequency deviation
        
        [ANALOG0]  f1: frequency at DG1 output
        [ANALOG1]  f2: frequency at DG2 output
        [ANALOG2]  f3: frequency at DG3 output
        [ANALOG3]  f4: frequency at DG4 output
        [ANALOG4]  P1: active power at DG1 output
        [ANALOG5]  P2: active power at DG2 output
        [ANALOG6]  P3: active power at DG3 output
        [ANALOG7]  P4: active power at DG4 output
        [ANALOG8]  Q1: reactive power at DG1 output
        [ANALOG9]  Q2: reactive power at DG2 output
        [ANALOG10]  Q3: reactive power at DG3 output
        [ANALOG11]  Q4: reactive power at DG4 output
        [ANALOG12]  V2: Voltage at DG2 output
        
        [DIGITAL0] BRKPCCTR: BReaKer at PCC TRipping
        [DIGITAL1] RMB1: Remote Bit 1
        [DIGITAL2] RMB2: Remote Bit 2
        """
        OFFSET_SOC = 6
        OFFSET_VALUES = 16
        FMT_VALUES = '!ff ff ffff ffff ffff f H H'  #'!ff(phase angle and mag) ff(f and df) ffff ffff ffff f(13 analogs) H H(2 dig)'
        #self.logger.info('on_data_queue()')
        frame = self.data_queue.recv_pyobj()
        _, framesize = struct.unpack_from('!HH', frame, 0)
        assert CommonFrame.extract_frame_type(frame) == 'data'

        soc, fracsec = struct.unpack_from('!II', frame, OFFSET_SOC)
        timestamp = soc + float(fracsec
                                & 0xffffff) / 0xffffff  # assuming time_base

        (vagpm_m, vagpm_a, freq, rocof, f1, f2, f3, f4, P1, P2, P3, P4, Q1, Q2, Q3, Q4, V2,
         digits, digits1) = \
                struct.unpack_from(FMT_VALUES, frame, OFFSET_VALUES)

        #data = {'VAGPM': (vagpm_m, vagpm_a),
        #        'f1': f1, 'f2': f2, 'f3': f3, 'f4': f4, 'P1': P1, 'P2': P2, 'P3': P3, 'P4': P4,
        #        'Q1':Q1, 'Q2':Q2, 'Q3':Q3, 'Q4':Q4, 'V2':V2, 'DIGITALS': digits, 'DIGITALS1': digits1,
        #        'FREQ': freq, 'ROCOF': rocof,
        #        'timestamp': timestamp}
        data = {
            'start_time': on_clock_start,
            'mag_diff': P1,
            'angle_diff': P2,
            'DIGITALS': digits,
            'DIGITALS1': digits1
        }
        self.angle_diff = P2
        self.digitals1 = digits
        self.digitals2 = digits1
        self.c37data.send_pyobj(data)
Beispiel #5
0
    def on_data_queue(self):
        on_clock_start = time.time()
        """Processing incoming data frames (application specific).

        Note: This is not a generic implementation.

        The current (hard coded) packet format:
        Value format: (P;F;F;F) = 15
            Polar Float phasors, Float analog and Float frequency values

        [PHASOR0]  VAGPM: not used
        
        [f]        f:   C37frequency
        [df]       df:  C37frequency deviation
        
        [ANALOG0]  f1: frequency at DG1 output
        [ANALOG1]  f2: frequency at DG2 output
        [ANALOG2]  f3: frequency at DG3 output
        [ANALOG3]  f4: frequency at DG4 output
        [ANALOG4]  P1: active power at DG1 output
        [ANALOG5]  P2: active power at DG2 output
        [ANALOG6]  P3: active power at DG3 output
        [ANALOG7]  P4: active power at DG4 output
        [ANALOG8]  Q1: reactive power at DG1 output
        [ANALOG9]  Q2: reactive power at DG2 output
        [ANALOG10]  Q3: reactive power at DG3 output
        [ANALOG11]  Q4: reactive power at DG4 output
        [ANALOG12]  V2: Voltage at DG2 output
        
        [DIGITAL0] BRKPCCTR: BReaKer at PCC TRipping
        [DIGITAL1] RMB1: Remote Bit 1
        [DIGITAL2] RMB2: Remote Bit 2
        """
        OFFSET_SOC = 6
        OFFSET_VALUES = 16
        #FMT_VALUES = '!ff ff ffff ffff ffff f H H'  #'!ff(phase angle and mag) ff(f and df) ffff ffff ffff f(13 analogs) H H(2 dig)'
        FMT_VALUES = '!ff ff ff ff ff ff ff ffff f H'  #'!ff ff ff ff ff ff (phase angle and mag) ff(f and df) ffff f(13 analogs) H (1 dig)'
        #self.logger.info('on_data_queue()')
        frame = self.data_queue.recv_pyobj()
        _, framesize = struct.unpack_from('!HH', frame, 0)
        assert CommonFrame.extract_frame_type(frame) == 'data'

        soc, fracsec = struct.unpack_from('!II', frame, OFFSET_SOC)
        timestamp = soc + float(fracsec) / 1000000  # assuming time_base


        (vagpm_m, vagpm_a, vbypm_m, vbypm_a, vcypm_m, vcypm_a,
         vaspm_m, vaspm_a, vbzpm_m, vbzpm_a, vczpm_m, vczpm_a,
         freq, rocof, vagm, vaga, vasm, vasa, slip1, digits) = \
                struct.unpack_from(FMT_VALUES, frame, OFFSET_VALUES)

        #data = {'VAGPM': (vagpm_m, vagpm_a), 'VBYPM': (vbypm_m, vbypm_a), 'VCYPM': (vcypm_m, vcypm_a),
        #        'VASPM': (vaspm_m, vaspm_a), 'VBZPM': (vbzpm_m, vbzpm_a), 'VCZPM': (vczpm_m, vczpm_a),
        #        'VAGM': vagm, 'VAGA': vaga, 'VASM': vasm, 'VASA': vasa, 'SLIP1': slip1,
        #        'DIGITALS': digits, 'FREQ': freq, 'ROCOF': rocof,
        #        'timestamp': timestamp}

        self.angle_diff = vaga - vasa
        if (self.angle_diff > 180):
            self.angle_diff = self.angle_diff - 360
        elif (self.angle_diff < -180):
            self.angle_diff = self.angle_diff + 360

        self.mag_diff = (vagm - vasm) * 1000
        data = {
            'time_arrive': on_clock_start,
            'mag_diff': self.mag_diff,
            'angle_diff': self.angle_diff
        }
        self.relayc37data.send_pyobj(data)