Esempio n. 1
0
    def implement_setpoint(self, bus_index, P, Q):
        """Implement a new setpoint.

        Parameters
        ----------
            bus_index : int
                Index of the bus to update.

            P : float
                New value for the active (P, in W) power.

            Q : float
                New value for the reactive (Q, in Var) power.

        """

        sock = socket(AF_INET, SOCK_DGRAM)
        message = {
            'type': 'implement_setpoint',
            'bus_index': bus_index,
            'P': P,
            'Q': Q
        }
        data = dump_json_data(message)
        sock.sendto(data, (self.grid_module_ip, self.grid_module_port))
Esempio n. 2
0
    def send(self):
        """Send the state of the battery to its RA.

        """
        sock = socket(AF_INET, SOCK_DGRAM)
        message = {
            'SoC_min': self._SoC,
            'SoC_max': self._SoC,
            'Idc': self._Idc,
            'P': self._P,
            'Q': self._Q
        }
        logger.info("Sending state to RA {}: {}".format(
            self._reply_addr, message))
        data = dump_json_data(message)
        sock.sendto(data, self._reply_addr)
Esempio n. 3
0
def reply(addr, state):
    """Reply to the resource agent with the PV's state.

    Parameters
    ----------
        addr : tuple
            Address of the RA.

        state : dict
            State of the UCPV.

    """
    message = {'P': state['P'], 'Q': state['Q']}
    logger.info("Sending setpoint (P = {}, Q = {}) to RA".format(
        message['P'], message['Q']))
    data = dump_json_data(message)
    sock = socket(AF_INET, SOCK_DGRAM)
    sock.sendto(data, addr)
Esempio n. 4
0
    def get_state(self, timeout_s=None):
        """Communicate with the grid module to retrieve the grid's state.

        If a timeout is specified and is exceeded, the GridAPI will attempt to
        return the previously known state.  If no state was known from history,
        then the timeout exception is simply re-raised.

        Parameters
        ----------
            timeout_s : float (optional, default None)
                Timeout in seconds for the UDP communication.

        Returns
        -------
            state : dict
                State of the grid.

        Raises
        ------
            timeout : socket.timeout
                Operation timed out and no state was known from history.

        """
        sock = socket(AF_INET, SOCK_DGRAM)
        sock.settimeout(timeout_s)
        message = {'type': 'request'}
        data = dump_json_data(message)

        try:
            sock.sendto(data, (self.grid_module_ip, self.grid_module_port))
            reply, _ = sock.recvfrom(BUFFER_LIMIT)
        except timeout as e:
            try:
                # Try to return the previous state in the case of a timeout.
                return self._state
            except AttributeError:
                # If impossible, re-raise the timeout exception.
                raise e

        self._state = load_json_data(reply)
        return self._state
Esempio n. 5
0
def reply(addr, state):
    """Reply to the resource agent with the Load's state.

    Parameters
    ----------
        addr : tuple
            Address of the RA.

        state : dict
            State of the Load.

    """
    message = {
        'P': -state['P'],  # Sign convention in COMMELEC agents is opposite.
        'Q': -state['Q']  # Sign convention in COMMELEC agents is opposite.
    }
    logger.info("Sending setpoint (P = {}, Q = {}) to RA".format(
        message['P'], message['Q']))
    data = dump_json_data(message)
    sock = socket(AF_INET, SOCK_DGRAM)
    sock.sendto(data, addr)
Esempio n. 6
0
def reply(addr, state, bus_index, msg_format):
    """Reply to the resource agent with the Load's state.

    Parameters
    ----------
        addr : tuple
            Address of the RA.

        state : dict
            State of the Load.

    """
    if msg_format == "cpp":
        measurement_array = [{'P': 0, 'Q': 0} for i in range(bus_index + 1)]
        measurement_array[bus_index] = {
            'P':
            -state['P'],  # Sign convention in COMMELEC agents is opposite.
            'Q': -state['Q']  # Sign convention in COMMELEC agents is opposite.
        }
        message = {"buses": measurement_array}
        logger.info(
            "Sending setpoint (P = {}, Q = {}) to RA (CPP executable format)".
            format(message["buses"][bus_index]['P'],
                   message["buses"][bus_index]['Q']))
    else:
        message = {
            'P':
            -state['P'],  # Sign convention in COMMELEC agents is opposite.
            'Q': -state['Q']  # Sign convention in COMMELEC agents is opposite.
        }
        logger.info(
            "Sending setpoint (P = {}, Q = {}) to RA (Labview executable format)"
            .format(message['P'], message['Q']))
    data = dump_json_data(message)
    sock = socket(AF_INET, SOCK_DGRAM)
    sock.sendto(data, addr)
Esempio n. 7
0
def main():

    # Parse the arguments.
    parser = ArgumentParser(
        description="Grid module that facilitates the operation of the grid.")
    parser.add_argument("config_path",
                        help="Path to the JSON config file for the grid",
                        nargs='?')
    parser.add_argument("log_path",
                        help="Path to the log directory for the grid",
                        nargs='?')
    parser.add_argument("grid_module_ip",
                        help="T-RECS (private) IP of the grid module where \
                        it listens for the messages from T-RECS resource models.",
                        nargs='?')
    parser.add_argument("grid_module_port",
                        help="Port where grid module listens for the \
                        messages from T-RECS resource models.",
                        nargs='?')
    parser.add_argument("--api_path",
                        help="Path to which the GridAPI will be pickled",
                        default='grid_api.pickle')
    args = parser.parse_args()

    # Load the configuration file.
    config = load_json_file(args.config_path, logger)

    # Inform the GridAPI of the grid module's address.
    api = GridAPI(args.grid_module_ip, int(args.grid_module_port))
    dump_api(api, args.api_path)
    kwargs = {'api_path': args.api_path}

    # Initialize a multiprocessing manager.
    with Manager() as manager:
        # Shared memory for the state.
        state = manager.dict()

        # Socket to listen for incoming messages.
        sock = socket(AF_INET, SOCK_DGRAM)
        sock.bind((args.grid_module_ip, int(args.grid_module_port)))

        # Handle update messages.
        message_queue = manager.Queue()
        state_queue = manager.Queue()

        Process(target=update_handler,
                args=(state, message_queue, state_queue, config['grid']),
                kwargs=kwargs).start()

        # Log generation.
        Process(target=log_generator,
                args=(state_queue, args.log_path)).start()

        # Wait for the child process to initialize the grid.
        while not state:
            continue

        while True:
            # The socket listens for messages that ask it to provide its state,
            # or implement a new setpoint.
            data, addr = sock.recvfrom(BUFFER_LIMIT)
            message = load_json_data(data)
            logger.info("Received message from {}: {}".format(addr, message))
            try:
                if message['type'] == 'request':
                    reply = {key: value for key, value in state.items()}
                    logger.info("Send state to {}: {}".format(addr, reply))
                    sock.sendto(dump_json_data(reply), addr)
                elif message['type'] == 'implement_setpoint':
                    logger.info("Implement setpoint: {}".format(message))
                    message_queue.put((message, datetime.now()))
                    logger.info("Queue size: {}".format(message_queue.qsize()))
                else:
                    logger.warn("Unknown message type: {}".format(
                        message['type']))
            except Exception as e:
                logger.warn("Bad message: {}".format(e))

    return 0
Esempio n. 8
0
def update(api, bus_indices, default_line_frequency, period, use_trace,
           trace_path, state_queue):
    """Update the state of the sensor.

    Parameters
    ----------
        api : GridAPI
            API to use to query the grid for the state.

        bus_indices : iterable
            Which buses to obtain the state for.

        default_line_frequency : float
            default value used for the Frequency of the line.

        period : float
            How often to update the information (in seconds).

        use_trace : boolean
            Define if the frequency is read from a trace or if a static value (default_line_frequency) is used

        trace_path : str
            file path of the frequency trace

        state_queue : multiprocessing.manager.Queue
            Queue in which the updated state will be put (for the log).

    Raises
    ------
        error : IOError
            Could not open the trace

        error : ValueError
            Wrong or missing value in the trace

    """

    # Load trace
    if use_trace:
        try:
            with open(trace_path, 'r') as f:
                reader_ = reader(f, quoting=QUOTE_NONNUMERIC)
                slack_line_frequency = list(reader_)

        except IOError as e:
            logger.error("Could not open {}: {}".format(
                slack_line_frequency, e))
            return 1
        except ValueError as e:
            logger.error("ValueError, wrong or missing value in {}: {}".format(
                slack_line_frequency, e))
            return 1
        except Exception as e:
            logger.error("Unexpected error", exc_info()[0])
            raise

        # normalize the timestamp of the trace
        first_freq_ts = slack_line_frequency[0][0]
        for i in range(0, len(slack_line_frequency)):
            slack_line_frequency[i][
                0] = slack_line_frequency[i][0] - first_freq_ts
        found = False
        end_trace_reach = False
        ptr_ID = -1

    line_frequency = default_line_frequency

    start_time = default_timer()

    global state, data
    bus_indices = frozenset(bus_indices)

    message = {}

    while True:

        try:
            new_state = api.get_state(period)
        except timeout as e:
            logger.warning(
                "Could not retrieve state from GridAPI: {}".format(e))
            continue

        logger.info("Retrieved state from GridAPI: {}".format(new_state))

        if state != new_state:
            # Update the state.
            state = new_state.copy()

            message = {'freq': line_frequency, 'buses': []}

            for bus_index, (P, Q, Vm, Va) in enumerate(
                    zip(state['P'], state['Q'], state['Vm'], state['Va'])):
                if bus_index not in bus_indices:
                    continue
                for phase_index, phase_shift in enumerate((0, 120, -120), 1):
                    phase_angle = radians(Va + phase_shift)
                    message['buses'].append(
                        make_entry(bus_index, phase_index, P / 3, Q / 3,
                                   Vm / sqrt(3) * cos(phase_angle),
                                   Vm / sqrt(3) * sin(phase_angle)))

        else:
            logger.info("State remained unchanged")

        if use_trace:
            found = False
            current_time = default_timer() - start_time
            delta = abs(current_time - slack_line_frequency[ptr_ID][0])

            while (not found and not end_trace_reach):

                # reach the end of the trace, take the last element as correct value
                if (ptr_ID + 1) >= len(slack_line_frequency):
                    end_trace_reach = True
                    # take the last entry
                    ptr_ID = -1
                    logger.info('End of trace reached')

                else:

                    next_delta = abs(current_time -
                                     slack_line_frequency[ptr_ID + 1][0])

                    # the closest value of current_time is at ptr_ID
                    if next_delta > delta:
                        found = True
                    else:
                        delta = next_delta
                        ptr_ID = ptr_ID + 1

            end_l = default_timer() - start_time
            logger.info('Time spend in nearest algo {}'.format(end_l -
                                                               current_time))

            line_frequency = slack_line_frequency[ptr_ID][1]

        message['freq'] = line_frequency
        data = dump_json_data(message)

        msg_copy = message.copy()
        msg_copy['Ts'] = datetime.now()
        state_queue.put(msg_copy)

        elapsed_time = default_timer() - start_time
        sleep(period - elapsed_time % period)