diff --git a/Makefile b/Makefile index 22b2866bb53321933dc8b11f2a3d48c3517ce46f..8c613cd2285167d70ff8c28fedfa4d22848d3129 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,12 @@ .DEFAULT_GOAL := default LIBSO=1 -export LIBSO darknet: git submodule init git submodule update default: darknet - $(MAKE) -C darknet - -.PHONY: default + $(MAKE) LIBSO=$(LIBSO) -C darknet +.PHONY: default darknet diff --git a/farmbot_yolo/client.py b/farmbot_yolo/client.py index 45d5f9b8cdcad40e231044a67c5318ffe1069cc4..296fcc467546b1e1da63d8072ff47207e96f3698 100755 --- a/farmbot_yolo/client.py +++ b/farmbot_yolo/client.py @@ -1,297 +1,12 @@ -<<<<<<<< HEAD:farmbot_yolo/client.py -''' -Communicate with the server at the manufacturer -Not useful for the local drive script -''' -import paho.mqtt.client as mqtt -import json -import time -from uuid import uuid4 # 通用唯一标识符 ( Universally Unique Identifier ) -import logging #日志模块 - -# values over max (and under min) will be clipped -MAX_X = 2400 -MAX_Y = 1200 -MAX_Z = 469 # TODO test this one! - -def coord(x, y, z): - return {"kind": "coordinate", "args": {"x": x, "y": y, "z": z}} # 返回json 嵌套对象 - -def move_request(x, y, z): - return {"kind": "rpc_request", # 返回 json对象,对象内含数组 - "args": {"label": ""}, - "body": [{"kind": "move_absolute", - "args": {"location": coord(x, y, z), - "offset": coord(0, 0, 0), - "speed": 100}}]} - -def take_photo_request(): - return {"kind": "rpc_request", - "args": {"label": ""}, #label空着是为了在blocking_request中填上uuid,唯一识别码 - "body": [{"kind": "take_photo", "args": {}}]} - -def clip(v, min_v, max_v): - if v < min_v: return min_v - if v > max_v: return max_v - return v - -class FarmbotClient(object): - - def __init__(self, device_id, token): - - self.device_id = device_id - self.client = mqtt.Client() # 类元素继承了另一个对象 - self.client.username_pw_set(self.device_id, token) #传入 用户名和密码 - self.client.on_connect = self._on_connect #??? - self.client.on_message = self._on_message - - logging.basicConfig(level=logging.DEBUG, - format="%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s", - filename='farmbot_client.log', - filemode='a') - console = logging.StreamHandler() - console.setLevel(logging.INFO) - console.setFormatter(logging.Formatter("%(asctime)s\t%(message)s")) - logging.getLogger('').addHandler(console) - - self.connected = False - self.client.connect("clever-octopus.rmq.cloudamqp.com", 1883, 60) #前面的url要运行按README.md中request_token.py 后面俩是TCP Port, Websocket Port - self.client.loop_start() - # 初始化函数里就会连接到服务器上,所以每次实例化一个新的client时,就已经连上了 - - - def shutdown(self): - self.client.disconnect() - self.client.loop_stop() - - def move(self, x, y, z): - x = clip(x, 0, MAX_X) - y = clip(y, 0, MAX_Y) - z = clip(z, 0, MAX_Z) - status_ok = self._blocking_request(move_request(x, y, z)) # 发请求 - logging.info("MOVE (%s,%s,%s) [%s]", x, y, z, status_ok) #存日志,包括执行了什么“move x y z +返回值 ” - - def take_photo(self): - # TODO: is this enough? it's issue a request for the photo, but is the actual capture async? - status_ok = self._blocking_request(take_photo_request()) - logging.info("TAKE_PHOTO [%s]", status_ok) - - def _blocking_request(self, request, retries_remaining=3): - if retries_remaining==0: - logging.error("< blocking request [%s] OUT OF RETRIES", request) #尝试3次,然后在日志中记录错误 - return False - - self._wait_for_connection() #在哪定义的? - - # assign a new uuid for this attempt - self.pending_uuid = str(uuid4()) - request['args']['label'] = self.pending_uuid #接收move_request函数的json对象 - logging.debug("> blocking request [%s] retries=%d", request, retries_remaining) - - # send request off 发送请求 - self.rpc_status = None - self.client.publish("bot/" + self.device_id + "/from_clients", json.dumps(request)) - - # wait for response - timeout_counter = 600 # ~1min 等待1s - while self.rpc_status is None: #这个self.rpc_status 是应答的flag - time.sleep(0.1) - timeout_counter -= 1 - if timeout_counter == 0: - logging.warn("< blocking request TIMEOUT [%s]", request) #时间到了,无应答 - return self._blocking_request(request, retries_remaining-1) - self.pending_uuid = None - - # if it's ok, we're done! - if self.rpc_status == 'rpc_ok': - logging.debug("< blocking request OK [%s]", request) - return True - - # if it's not ok, wait a bit and retry - if self.rpc_status == 'rpc_error': - logging.warn("< blocking request ERROR [%s]", request) - time.sleep(1) - return self._blocking_request(request, retries_remaining-1) - - # unexpected state (???) - msg = "unexpected rpc_status [%s]" % self.rpc_status - logging.error(msg) - raise Exception(msg) - - - def _wait_for_connection(self): - # TODO: better way to do all this async event driven rather than with polling :/ - timeout_counter = 600 # ~1min - while not self.connected: #用一个self.connected判断连上了没有,若没连上,等待 - time.sleep(0.1) - timeout_counter -= 1 - if timeout_counter == 0: - raise Exception("unable to connect") - - def _on_connect(self, client, userdata, flags, rc): - logging.debug("> _on_connect") - self.client.subscribe("bot/" + self.device_id + "/from_device") - self.connected = True - logging.debug("< _on_connect") - - def _on_message(self, client, userdata, msg): - resp = json.loads(msg.payload.decode()) - if resp['args']['label'] != 'ping': - logging.debug("> _on_message [%s] [%s]", msg.topic, resp) - if msg.topic.endswith("/from_device") and resp['args']['label'] == self.pending_uuid: - self.rpc_status = resp['kind'] -|||||||| 90c14bb:src/client.py -''' -Communicate with the server at the manufacturer -Not useful for the local drive script -''' -import paho.mqtt.client as mqtt -import json -import time -from uuid import uuid4 # 通用唯一标识符 ( Universally Unique Identifier ) -import logging #日志模块 - -# values over max (and under min) will be clipped -MAX_X = 2400 -MAX_Y = 1200 -MAX_Z = 469 # TODO test this one! - -def coord(x, y, z): - return {"kind": "coordinate", "args": {"x": x, "y": y, "z": z}} # 返回json 嵌套对象 +"""Communicate with the server at the manufacturer. -def move_request(x, y, z): - return {"kind": "rpc_request", # 返回 json对象,对象内含数组 - "args": {"label": ""}, - "body": [{"kind": "move_absolute", - "args": {"location": coord(x, y, z), - "offset": coord(0, 0, 0), - "speed": 100}}]} - -def take_photo_request(): - return {"kind": "rpc_request", - "args": {"label": ""}, #label空着是为了在blocking_request中填上uuid,唯一识别码 - "body": [{"kind": "take_photo", "args": {}}]} - -def clip(v, min_v, max_v): - if v < min_v: return min_v - if v > max_v: return max_v - return v - -class FarmbotClient(object): - - def __init__(self, device_id, token): - - self.device_id = device_id - self.client = mqtt.Client() # 类元素继承了另一个对象 - self.client.username_pw_set(self.device_id, token) #传入 用户名和密码 - self.client.on_connect = self._on_connect #??? - self.client.on_message = self._on_message - - logging.basicConfig(level=logging.DEBUG, - format="%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s", - filename='farmbot_client.log', - filemode='a') - console = logging.StreamHandler() - console.setLevel(logging.INFO) - console.setFormatter(logging.Formatter("%(asctime)s\t%(message)s")) - logging.getLogger('').addHandler(console) - - self.connected = False - self.client.connect("clever-octopus.rmq.cloudamqp.com", 1883, 60) #前面的url要运行按README.md中request_token.py 后面俩是TCP Port, Websocket Port - self.client.loop_start() - # 初始化函数里就会连接到服务器上,所以每次实例化一个新的client时,就已经连上了 - - - def shutdown(self): - self.client.disconnect() - self.client.loop_stop() - - def move(self, x, y, z): - x = clip(x, 0, MAX_X) - y = clip(y, 0, MAX_Y) - z = clip(z, 0, MAX_Z) - status_ok = self._blocking_request(move_request(x, y, z)) # 发请求 - logging.info("MOVE (%s,%s,%s) [%s]", x, y, z, status_ok) #存日志,包括执行了什么“move x y z +返回值 ” - - def take_photo(self): - # TODO: is this enough? it's issue a request for the photo, but is the actual capture async? - status_ok = self._blocking_request(take_photo_request()) - logging.info("TAKE_PHOTO [%s]", status_ok) - - def _blocking_request(self, request, retries_remaining=3): - if retries_remaining==0: - logging.error("< blocking request [%s] OUT OF RETRIES", request) #尝试3次,然后在日志中记录错误 - return False - - self._wait_for_connection() #在哪定义的? - - # assign a new uuid for this attempt - self.pending_uuid = str(uuid4()) - request['args']['label'] = self.pending_uuid #接收move_request函数的json对象 - logging.debug("> blocking request [%s] retries=%d", request, retries_remaining) - - # send request off 发送请求 - self.rpc_status = None - self.client.publish("bot/" + self.device_id + "/from_clients", json.dumps(request)) - - # wait for response - timeout_counter = 600 # ~1min 等待1s - while self.rpc_status is None: #这个self.rpc_status 是应答的flag - time.sleep(0.1) - timeout_counter -= 1 - if timeout_counter == 0: - logging.warn("< blocking request TIMEOUT [%s]", request) #时间到了,无应答 - return self._blocking_request(request, retries_remaining-1) - self.pending_uuid = None - - # if it's ok, we're done! - if self.rpc_status == 'rpc_ok': - logging.debug("< blocking request OK [%s]", request) - return True - - # if it's not ok, wait a bit and retry - if self.rpc_status == 'rpc_error': - logging.warn("< blocking request ERROR [%s]", request) - time.sleep(1) - return self._blocking_request(request, retries_remaining-1) - - # unexpected state (???) - msg = "unexpected rpc_status [%s]" % self.rpc_status - logging.error(msg) - raise Exception(msg) - - - def _wait_for_connection(self): - # TODO: better way to do all this async event driven rather than with polling :/ - timeout_counter = 600 # ~1min - while not self.connected: #用一个self.connected判断连上了没有,若没连上,等待 - time.sleep(0.1) - timeout_counter -= 1 - if timeout_counter == 0: - raise Exception("unable to connect") - - def _on_connect(self, client, userdata, flags, rc): - logging.debug("> _on_connect") - self.client.subscribe("bot/" + self.device_id + "/from_device") - self.connected = True - logging.debug("< _on_connect") - - def _on_message(self, client, userdata, msg): - resp = json.loads(msg.payload.decode()) - if resp['args']['label'] != 'ping': - logging.debug("> _on_message [%s] [%s]", msg.topic, resp) - if msg.topic.endswith("/from_device") and resp['args']['label'] == self.pending_uuid: - self.rpc_status = resp['kind'] -======== -''' -Communicate with the server at the manufacturer Not useful for the local drive script -''' +""" import paho.mqtt.client as mqtt import json import time -from uuid import uuid4 # 通用唯一标识符 ( Universally Unique Identifier ) -import logging #日志模块 +from uuid import uuid4 # 通用唯一标识符 ( Universally Unique Identifier ) +import logging # 日志模块 # values over max (and under min) will be clipped MAX_X = 2400 @@ -300,185 +15,231 @@ MAX_Z = 469 # TODO test this one! def coord(x, y, z): - return {"kind": "coordinate", "args": {"x": x, "y": y, "z": z}} # 返回json 嵌套对象 + return {"kind": "coordinate", "args": {"x": x, "y": y, "z": z}} # 返回json 嵌套对象 + def move_request(x, y, z): - return {"kind": "rpc_request", # 返回 json对象,对象内含数组 - "args": {"label": ""}, - "body": [{"kind": "move_absolute", - "args": {"location": coord(x, y, z), - "offset": coord(0, 0, 0), - "speed": 100}}]} + return { + "kind": "rpc_request", # 返回 json对象,对象内含数组 + "args": {"label": ""}, + "body": [ + { + "kind": "move_absolute", + "args": { + "location": coord(x, y, z), + "offset": coord(0, 0, 0), + "speed": 100, + }, + } + ], + } -def read_pin_request(pin_number, pin_mode="digital"): - modes = {"digital": 0, "analog": 1} - if pin_mode != "digital": - raise NotImplementedError() +def read_pin_request(pin_number, pin_mode="digital"): + modes = {"digital": 0, "analog": 1} + + if pin_mode != "digital": + raise NotImplementedError() + + return { + "kind": "rpc_request", + "args": {"label": ""}, + "body": [ + { + "kind": "read_pin", + "args": { + "label": "pin" + str(pin_number), + "pin_mode": modes[pin_mode] or (modes["digital"]), + "pin_number": pin_number, + }, + } + ], + } - return {"kind": "rpc_request", - "args": {"label": ""}, - "body": [{"kind": "read_pin", - "args": { - "label": "pin" + str(pin_number), - "pin_mode": modes[pin_mode] or (modes["digital"]), - "pin_number": pin_number - }}]} def write_pin_request(pin_number, pin_value, pin_mode="digital"): - modes = {"digital": 0, "analog": 1} - - if pin_mode != "digital": - raise NotImplementedError() - - return {"kind": "rpc_request", - "args": {"label": ""}, - "body": [{"kind": "write_pin", - "args": { - "pin_mode": modes[pin_mode] or (modes["digital"]), - "pin_number": pin_number, - "pin_value": pin_value - } - } - ] - } + modes = {"digital": 0, "analog": 1} + + if pin_mode != "digital": + raise NotImplementedError() + + return { + "kind": "rpc_request", + "args": {"label": ""}, + "body": [ + { + "kind": "write_pin", + "args": { + "pin_mode": modes[pin_mode] or (modes["digital"]), + "pin_number": pin_number, + "pin_value": pin_value, + }, + } + ], + } + def toggle_pin_request(pin_number): - return {"kind": "rpc_request", - "args": {"label": ""}, - "body": [{"kind": "toggle_pin", - "args": { - "pin_number": pin_number, - } - } - ] - } + return { + "kind": "rpc_request", + "args": {"label": ""}, + "body": [ + { + "kind": "toggle_pin", + "args": { + "pin_number": pin_number, + }, + } + ], + } + def take_photo_request(): - return {"kind": "rpc_request", - "args": {"label": ""}, #label空着是为了在blocking_request中填上uuid,唯一识别码 - "body": [{"kind": "take_photo", "args": {}}]} + return { + "kind": "rpc_request", + "args": {"label": ""}, # label空着是为了在blocking_request中填上uuid,唯一识别码 + "body": [{"kind": "take_photo", "args": {}}], + } + def clip(v, min_v, max_v): - if v < min_v: return min_v - if v > max_v: return max_v - return v + if v < min_v: + return min_v + if v > max_v: + return max_v + return v -class FarmbotClient(object): - def __init__(self, device_id, token): - - self.device_id = device_id - self.client = mqtt.Client() # 类元素继承了另一个对象 - self.client.username_pw_set(self.device_id, token) #传入 用户名和密码 - self.client.on_connect = self._on_connect #??? - self.client.on_message = self._on_message - - logging.basicConfig(level=logging.DEBUG, - format="%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s", - filename='farmbot_client.log', - filemode='a') - console = logging.StreamHandler() - console.setLevel(logging.INFO) - console.setFormatter(logging.Formatter("%(asctime)s\t%(message)s")) - logging.getLogger('').addHandler(console) - - self.connected = False - self.client.connect("clever-octopus.rmq.cloudamqp.com", 1883, 60) #前面的url要运行按README.md中request_token.py 后面俩是TCP Port, Websocket Port - self.client.loop_start() - # 初始化函数里就会连接到服务器上,所以每次实例化一个新的client时,就已经连上了 - - - def shutdown(self): - self.client.disconnect() - self.client.loop_stop() - - def move(self, x, y, z): - x = clip(x, 0, MAX_X) - y = clip(y, 0, MAX_Y) - z = clip(z, 0, MAX_Z) - status_ok = self._blocking_request(move_request(x, y, z)) # 发请求 - logging.info("MOVE (%s,%s,%s) [%s]", x, y, z, status_ok) #存日志,包括执行了什么“move x y z +返回值 ” - - def take_photo(self): - # TODO: is this enough? it's issue a request for the photo, but is the actual capture async? - status_ok = self._blocking_request(take_photo_request()) - logging.info("TAKE_PHOTO [%s]", status_ok) - - def read_pin(self, pin_number, pin_mode="digital"): - status_ok = self._blocking_request(read_pin_request(pin_number, pin_mode=pin_mode)) - logging.info(f"READ PIN (pin_number: {pin_number}) [{status_ok}]") - - def write_pin(self, pin_number, pin_value, pin_mode="digital"): - status_ok = self._blocking_request(write_pin_request(pin_number, pin_value, pin_mode=pin_mode)) - logging.info(f"WRITE PIN (pin_number: {pin_number}, pin_value: {pin_value}) [{status_ok}]") - - def toggle_pin(self, pin_number): - status_ok = self._blocking_request(toggle_pin_request(pin_number)) - logging.info(f"TOGGLE PIN (pin_number: {pin_number}) [{status_ok}]") - - def _blocking_request(self, request, retries_remaining=3): - if retries_remaining==0: - logging.error("< blocking request [%s] OUT OF RETRIES", request) #尝试3次,然后在日志中记录错误 - return False - - self._wait_for_connection() #在哪定义的? - - # assign a new uuid for this attempt - self.pending_uuid = str(uuid4()) - request['args']['label'] = self.pending_uuid #接收move_request函数的json对象 - logging.debug("> blocking request [%s] retries=%d", request, retries_remaining) - - # send request off 发送请求 - self.rpc_status = None - self.client.publish("bot/" + self.device_id + "/from_clients", json.dumps(request)) - - # wait for response - timeout_counter = 600 # ~1min 等待1s - while self.rpc_status is None: #这个self.rpc_status 是应答的flag - time.sleep(0.1) - timeout_counter -= 1 - if timeout_counter == 0: - logging.warn("< blocking request TIMEOUT [%s]", request) #时间到了,无应答 - return self._blocking_request(request, retries_remaining-1) - self.pending_uuid = None - - # if it's ok, we're done! - if self.rpc_status == 'rpc_ok': - logging.debug("< blocking request OK [%s]", request) - return True - - # if it's not ok, wait a bit and retry - if self.rpc_status == 'rpc_error': - logging.warn("< blocking request ERROR [%s]", request) - time.sleep(1) - return self._blocking_request(request, retries_remaining-1) - - # unexpected state (???) - msg = "unexpected rpc_status [%s]" % self.rpc_status - logging.error(msg) - raise Exception(msg) - - - def _wait_for_connection(self): - # TODO: better way to do all this async event driven rather than with polling :/ - timeout_counter = 600 # ~1min - while not self.connected: #用一个self.connected判断连上了没有,若没连上,等待 - time.sleep(0.1) - timeout_counter -= 1 - if timeout_counter == 0: - raise Exception("unable to connect") - - def _on_connect(self, client, userdata, flags, rc): - logging.debug("> _on_connect") - self.client.subscribe("bot/" + self.device_id + "/from_device") - self.connected = True - logging.debug("< _on_connect") - - def _on_message(self, client, userdata, msg): - resp = json.loads(msg.payload.decode()) - if resp['args']['label'] != 'ping': - logging.debug("> _on_message [%s] [%s]", msg.topic, resp) - if msg.topic.endswith("/from_device") and resp['args']['label'] == self.pending_uuid: - self.rpc_status = resp['kind'] ->>>>>>>> master:src/utils/client.py +class FarmbotClient(object): + def __init__(self, device_id, token): + + self.device_id = device_id + self.client = mqtt.Client() # 类元素继承了另一个对象 + self.client.username_pw_set(self.device_id, token) # 传入 用户名和密码 + self.client.on_connect = self._on_connect # ??? + self.client.on_message = self._on_message + + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s", + filename="farmbot_client.log", + filemode="a", + ) + console = logging.StreamHandler() + console.setLevel(logging.INFO) + console.setFormatter(logging.Formatter("%(asctime)s\t%(message)s")) + logging.getLogger("").addHandler(console) + + self.connected = False + self.client.connect( + "clever-octopus.rmq.cloudamqp.com", 1883, 60 + ) # 前面的url要运行按README.md中request_token.py 后面俩是TCP Port, Websocket Port + self.client.loop_start() + # 初始化函数里就会连接到服务器上,所以每次实例化一个新的client时,就已经连上了 + + def shutdown(self): + self.client.disconnect() + self.client.loop_stop() + + def move(self, x, y, z): + x = clip(x, 0, MAX_X) + y = clip(y, 0, MAX_Y) + z = clip(z, 0, MAX_Z) + status_ok = self._blocking_request(move_request(x, y, z)) # 发请求 + logging.info( + "MOVE (%s,%s,%s) [%s]", x, y, z, status_ok + ) # 存日志,包括执行了什么“move x y z +返回值 ” + + def take_photo(self): + # TODO: is this enough? it's issue a request for the photo, but is the actual capture async? + status_ok = self._blocking_request(take_photo_request()) + logging.info("TAKE_PHOTO [%s]", status_ok) + + def read_pin(self, pin_number, pin_mode="digital"): + status_ok = self._blocking_request( + read_pin_request(pin_number, pin_mode=pin_mode) + ) + logging.info(f"READ PIN (pin_number: {pin_number}) [{status_ok}]") + + def write_pin(self, pin_number, pin_value, pin_mode="digital"): + status_ok = self._blocking_request( + write_pin_request(pin_number, pin_value, pin_mode=pin_mode) + ) + logging.info( + f"WRITE PIN (pin_number: {pin_number}, pin_value: {pin_value}) [{status_ok}]" + ) + + def toggle_pin(self, pin_number): + status_ok = self._blocking_request(toggle_pin_request(pin_number)) + logging.info(f"TOGGLE PIN (pin_number: {pin_number}) [{status_ok}]") + + def _blocking_request(self, request, retries_remaining=3): + if retries_remaining == 0: + logging.error( + "< blocking request [%s] OUT OF RETRIES", request + ) # 尝试3次,然后在日志中记录错误 + return False + + self._wait_for_connection() # 在哪定义的? + + # assign a new uuid for this attempt + self.pending_uuid = str(uuid4()) + request["args"]["label"] = self.pending_uuid # 接收move_request函数的json对象 + logging.debug("> blocking request [%s] retries=%d", request, retries_remaining) + + # send request off 发送请求 + self.rpc_status = None + self.client.publish( + "bot/" + self.device_id + "/from_clients", json.dumps(request) + ) + + # wait for response + timeout_counter = 600 # ~1min 等待1s + while self.rpc_status is None: # 这个self.rpc_status 是应答的flag + time.sleep(0.1) + timeout_counter -= 1 + if timeout_counter == 0: + logging.warn("< blocking request TIMEOUT [%s]", request) # 时间到了,无应答 + return self._blocking_request(request, retries_remaining - 1) + self.pending_uuid = None + + # if it's ok, we're done! + if self.rpc_status == "rpc_ok": + logging.debug("< blocking request OK [%s]", request) + return True + + # if it's not ok, wait a bit and retry + if self.rpc_status == "rpc_error": + logging.warn("< blocking request ERROR [%s]", request) + time.sleep(1) + return self._blocking_request(request, retries_remaining - 1) + + # unexpected state (???) + msg = "unexpected rpc_status [%s]" % self.rpc_status + logging.error(msg) + raise Exception(msg) + + def _wait_for_connection(self): + # TODO: better way to do all this async event driven rather than with polling :/ + timeout_counter = 600 # ~1min + while not self.connected: # 用一个self.connected判断连上了没有,若没连上,等待 + time.sleep(0.1) + timeout_counter -= 1 + if timeout_counter == 0: + raise Exception("unable to connect") + + def _on_connect(self, client, userdata, flags, rc): + logging.debug("> _on_connect") + self.client.subscribe("bot/" + self.device_id + "/from_device") + self.connected = True + logging.debug("< _on_connect") + + def _on_message(self, client, userdata, msg): + resp = json.loads(msg.payload.decode()) + if resp["args"]["label"] != "ping": + logging.debug("> _on_message [%s] [%s]", msg.topic, resp) + if ( + msg.topic.endswith("/from_device") + and resp["args"]["label"] == self.pending_uuid + ): + self.rpc_status = resp["kind"]