我有一个来自Denon的多房间扬声器系统叫做Heos,我想用python脚本来控制它。要与多房间系统通信,我必须telnet到设备上的端口1255并发送如下命令:
heos://player/set_play_state?pid=player_id&state=play_state
回复是在json:
{
"heos": {
"command": " player/set_play_state ",
"result": "success",
"message": "pid='player_id'&state='play_state'"
}
}
我已成功使用python telnet lib发送如下的简单命令:
command = "heos://player/set_play_state?pid=player_id&state=play_state"
telnet.write(command.encode('ASCII') + b'\r\n')
但是,以可用格式恢复响应的最佳方法是什么?用telnet.read_until循环?我想结果和消息行回到一个干净的变量。
使用telnet与api通信的这种方法感觉有点脏。是否可以使用其他东西,例如socket?
提前致谢
API / CLI在此处记录:http://rn.dmglobal.com/euheos/HEOS_CLI_ProtocolSpecification.pdf
答案 0 :(得分:1)
虽然可以在这里使用loop_until()
,但它将取决于响应JSON的格式,并且依赖它可能是不明智的。
如果远程设备在发送响应后关闭了连接,那么简单的方法就是一个简单的
response = json.loads(telnet.read_all().decode())
如果它对更多命令保持打开状态,那么在您拥有完整的JSON对象之前,您需要继续接收。这是一种可能性,只是一直试图解析JSON,直到成功为止:
response = ''
while True:
response += telnet.read_some().decode()
try:
response = json.loads(response)
break
except ValueError:
pass
无论哪种方式,您的结果和消息都是response['heos']['result']
和response['heos']['message']
。
答案 1 :(得分:0)
FWIW,这是我的GitHub repo(受this repo启发)用于控制使用Python的HEOS扬声器。它使用与接受结果类似的方法,但是如果HEOS播放器忙,则另外等待。
def telnet_request(self, command, wait = True):
"""Execute a `command` and return the response(s)."""
command = self.heosurl + command
logging.debug("telnet request {}".format(command))
self.telnet.write(command.encode('ASCII') + b'\r\n')
response = b''
while True:
response += self.telnet.read_some()
try:
response = json.loads(response)
if not wait:
logging.debug("I accept the first response: {}".format(response))
break
# sometimes, I get a response with the message "under
# process". I might want to wait here
message = response.get("heos", {}).get("message", "")
if "command under process" not in message:
logging.debug("I assume this is the final response: {}".format(response))
break
logging.debug("Wait for the final response")
response = b'' # forget this message
except ValueError:
# response is not a complete JSON object
pass
except TypeError:
# response is not a complete JSON object
pass
if response.get("result") == "fail":
logging.warn(response)
return None
return response