Как использовать RPC с Volttron - PullRequest
3 голосов
/ 13 июня 2019

Я хотел бы использовать вызовы RPC в своем приложении Volttron, но я не могу заставить работать любой вызов. Все вызовы завершаются с ошибкой «нет маршрута к хосту»

<stderr> ERROR: Unreachable: VIP error (113): No route to host: rpcserver.agent_1

По сути, есть два агента: агент "сервер", который экспортирует процедуру RPC, и агент "клиент", который вызывает процедуру.

В агенте «сервер» я экспортировал метод класса агента следующим образом:

@RPC.export('setConfig')
def setConfig(self, config):
    self.config = config                       
    self.initialize_device()

Агент "client" вызывает экспортированный метод следующим образом:

self.vip.rpc.call(sender, 'setConfig', self.config[sender]).get()

Где «отправитель» - это VIP-идентификатор агента «сервера» (который оказывается «rpcserver.agent_1» и соответствует значению аргумента «отправитель» при получении сообщения pubsub от rpcserver.agent. I определили идентификатор как rpcserver.agent_ {n} в файле IDENTITY).

Мои вопросы: 1. Я делаю что-то явно неправильно или пропускаю какой-то шаг для правильной настройки подсистемы RPC? 2. Предполагается ли, что «равноправный» аргумент в self.vip.rpc.call(peer, method, ...) будет идентификатором агента? Это не ясно из документации (я пробовал другие варианты, такие как имя агента или uuid, но ни одна из них не работала)

Я использую volttron 5.1.0 в виртуальной машине Ubuntu.

Любая помощь в этом была бы очень признательна. С наилучшими пожеланиями

ОПИСАНИЕ:

Это для управляющего приложения, которое соединяет несколько устройств. Агенты загружаются динамически в зависимости от доступных устройств в сети. Я хотел бы попробовать RPC вместо использования только pubsub. Я уже довольно тщательно искал код и документацию Volttron для получения подробных сведений об API RPC, но пока безрезультатно.

Минимальный класс "сервер":

class rpcServerAgent(Agent):    
    def __init__(self, config, **kwargs):        
        super(rpcServerAgent, self).__init__(**kwargs)
        self.config = config

    @Core.receiver('onstart')
    def onstart(self, sender, **kwargs):                     
        self.vip.rpc.export(self.setConfig, name='setConfig')           # Also tried online exporting 

        # Ask the client to call the exported procedure
        myutils.publish(self, topic='rpc/test', message={})             # myutils.publish publishes the message on pubsub 


    @RPC.export('setConfig')
    def setConfig(self, config):
        self.config = config        
        self.initialize_device()
        myutils.publish(self, topic='rpc/clientready')

    def initialize_device(self):
        pass

Минимальный "клиентский" класс:

class rpcClientAgent(Agent):    
    def __init__(self, config, **kwargs):
        super(rpcClientAgent, self).__init__(**kwargs)        
        self.config = {'rpcclient.agent_1': {'a': 0, 'b': 1}}                   # dummy config for rpcclient.agent

    @Core.receiver('onstart')
    def onstart(self, sender, **kwargs):
        self.vip.pubsub.subscribe(peer='pubsub',
                                prefix='rpc',
                                callback=self.__handle_request__).get(timeout=5)      

    def call_RPC(self, sender):        
        sender = sender.strip()         # volttron adds a newline at the end        
        self.vip.rpc.call(sender, 'setConfig', self.config[sender]).get()       # assume that self.config[sender] is well-defined    

    @PubSub.subscribe('pubsub', 'rpc')
    def __handle_request__(self, peer, sender, bus, topic, headers, message):
        try:
            msg = json.loads(message)
        except:
            raise ValueError("failed to decode message")

        topics = topic.split('/')
        if len(topics) > 1:
            if topics[0] == 'rpc':                
                if topics[1] == 'test':                                                            
                    self.call_RPC(sender)

Ожидаемое поведение: вызывается экспортированная функция и публикуется сообщение pubsub с темой «rpc / clientready».

Фактическое поведение: сбой вызова RPc с ошибкой «Недоступен: ошибка VIP (113): нет маршрута к хосту: rpcclient.agent_1»

Редактировать В конце концов я обнаружил, что проблема заключалась в том, что имя агента внутри вольтрона заканчивалось символом '\ n'. Это произошло из-за того, что gedit автоматически добавил его, и, очевидно, строка не была очищена вольттроном.

1 Ответ

0 голосов
/ 02 июля 2019

С точки зрения того, как создать метод RPC, я бы сказал, что вы все сделали правильно (хотя это:

@RPC.export('setConfig')

может быть:

@RPC.export

, так как выне меняют имя метода).

С точки зрения выполнения вызовов RPC первый аргумент действительно должен быть идентификатором агента или адресом.

Если вы хотитесм. дополнительные примеры, ознакомьтесь с драйверами Modbus или Bacnet в службах / core / MasterDriverAgent / master_driver / interfaces.

Несколько других замечаний:

  • Хранилище конфигурации может бытьиспользуется для настройки конфигурации агента.Примеры этого можно найти в volttron / platform / agent / base_weather.py (а также во многих других агентах)

  • Хотя я не совсем знаком, похоже, что выПопытка сделать это может быть достигнуто путем использования функций главного драйвера.Я полагаю, что агент Market Service может поделиться некоторыми конструктивными особенностями с тем, что вы пытаетесь выполнить, его можно найти в services / core / MarketServiceAgent.

...