Philips TV APIv6配对异常:/pair/grant请求返回HTTP 200 OK但JSON响应提示"INVALID_PIN"(自定义Android应用与Python脚本均复现)
Philips TV APIv6配对异常:/pair/grant请求返回HTTP 200 OK但JSON响应提示"INVALID_PIN"(自定义Android应用与Python脚本均复现)
我现在在给飞利浦43PUS8309/62型号的电视(基于安卓/Linux系统,API版本6)开发配对功能,分别用了Android(Java/Kotlin+OkHttp)和Python两种实现,但卡在了同一个地方,想请教大家有没有解决思路。
先给大家理一下我按照资料(包括网上的文档和一个Python参考脚本)实现的配对流程:
配对步骤
请求配对初始化
向/6/pair/request发送POST请求,Payload是:{ "scope": ["read", "write", "control"], "device": { "device_name": "...", "device_os": "...", "app_id": "...", "app_name": "...", "type": "native", "id": "CLIENT_GENERATED_ID" } }TV返回200 OK,JSON里包含
auth_key和timestamp,同时电视屏幕上会弹出PIN码。用户输入PIN后提交授权
向/6/pair/grant发送POST请求,这个请求有两个关键要求:- HTTP摘要认证:用户名是步骤1里的
CLIENT_GENERATED_ID,密码是步骤1返回的auth_key - JSON Payload:
{ "auth": { "pin": "USER_ENTERED_PIN", "auth_timestamp": TIMESTAMP_FROM_STEP_1, // 以数字类型发送 "auth_signature": "CALCULATED_HMAC_SIGNATURE", "auth_AppId": 1 // 数字类型 }, "device": { /* 和步骤1里完全一样的device对象 */ } }
其中
auth_signature的计算逻辑是:Base64.encode(UTF8_bytes( HexString( HMAC_SHA1(decoded_secret_key, UTF8_bytes(timestamp_string + pin_string)) ) ))
这里的secret_key是一个固定的Base64字符串,我已经正确解码后用于计算。- HTTP摘要认证:用户名是步骤1里的
遇到的问题
不管是Android应用还是Python脚本,都出现了同一个问题:
- 步骤1完全正常,能拿到
auth_key和timestamp,电视也弹出了PIN - 第一次发
/pair/grant的时候因为没加摘要头,返回401 Unauthorized,这符合预期 - 第二次带上正确计算的摘要认证头再发
/pair/grant,返回了200 OK,但JSON响应体却是:
也就是说,摘要认证过了,但PIN相关的参数被判定为无效,可我明明输入了电视上显示的正确PIN啊!{"error_id": "INVALID_PIN", "error_text": "Invalid authentication parameters"}
我已经排查验证过的点
为了定位问题,我已经逐一验证了这些内容:
- HTTP摘要认证是有效的:返回200 OK说明电视已经接受了摘要凭证,排除了认证本身的问题
- HMAC签名计算正确:我用相同的
timestamp、pin和secret_key分别在Java和Python里计算,得到的auth_signature完全一致(比如用timestamp="2527"、pin="8763",两者算出的Base64字符串都是ZTkwMWE4MTQyNDhmMzdkZDAzNWRjMjY1YzFmM2VlZWViM2JlYTgyNA==) - JSON Payload格式完全正确:
auth_timestamp是以数字类型发送的(Java用Long,Python用int)auth_AppId也是数字类型的1device对象和步骤1里完全一致,包括id是同一个客户端生成的ID
- 模仿官方应用参数:我抓了官方飞利浦电视遥控器APP的日志,把它的
device_name、app_name、app_id都抄到我的Payload里,结果还是一样的INVALID_PIN - 增加前置请求:按照官方APP的流程,在配对前先给
http://<TV_IP>:1925/system发了一个未认证的GET请求,之后再走1926端口的配对流程,问题依然存在
附上我的Python脚本关键片段
from __future__ import print_function, unicode_literals from base64 import b64encode, b64decode import json import requests import random import string from Crypto.Hash import SHA, HMAC # 用于HMAC-SHA1计算 from requests.auth import HTTPDigestAuth import sys # 固定的Secret Key(Base64格式),解码后用于HMAC计算 SECRET_KEY_BASE64 = "ZmVay1EQVFOaZhwQ4Kv81ypLAZNczV9sG4KkseXWn1NEk6cXmPKO/MCa9sryslvLCFMnNe4Z4CPXzToowvhHvA==" DECODED_SECRET_KEY_BYTES = b64decode(SECRET_KEY_BASE64) def create_device_id(): # 生成随机的客户端ID return ''.join(random.choices(string.ascii_uppercase + string.digits, k=16)) # 步骤1:请求配对初始化 def request_pairing(tv_ip, device_info): url = f"https://{tv_ip}:1926/6/pair/request" payload = { "scope": ["read", "write", "control"], "device": device_info } # 测试环境暂时禁用SSL警告 requests.packages.urllib3.disable_warnings() response = requests.post(url, json=payload, verify=False) if response.status_code == 200: return response.json() else: print(f"请求配对初始化失败:{response.status_code}") return None # 计算HMAC签名 def calculate_auth_signature(timestamp, pin): message = f"{timestamp}{pin}".encode('utf-8') hmac = HMAC.new(DECODED_SECRET_KEY_BYTES, message, SHA) hex_digest = hmac.hexdigest() # 转成UTF-8字节再Base64编码 return b64encode(hex_digest.encode('utf-8')).decode('utf-8') # 步骤2:提交PIN和授权 def grant_pairing(tv_ip, device_info, client_id, auth_key, timestamp, pin): url = f"https://{tv_ip}:1926/6/pair/grant" auth_signature = calculate_auth_signature(str(timestamp), pin) payload = { "auth": { "pin": pin, "auth_timestamp": int(timestamp), "auth_signature": auth_signature, "auth_AppId": 1 }, "device": device_info } # 构建摘要认证 digest_auth = HTTPDigestAuth(client_id, auth_key) requests.packages.urllib3.disable_warnings() response = requests.post(url, json=payload, auth=digest_auth, verify=False) print(f"授权请求状态码:{response.status_code}") print(f"授权响应内容:{response.text}") return response.json() # 主流程示例 if __name__ == "__main__": TV_IP = "192.168.1.100" # 替换成你的电视IP client_id = create_device_id() device_info = { "device_name": "MyTestDevice", "device_os": "Android 13", "app_id": "com.my.test.app", "app_name": "TestTVRemote", "type": "native", "id": client_id } # 步骤1 pairing_resp = request_pairing(TV_IP, device_info) if not pairing_resp: sys.exit(1) auth_key = pairing_resp['auth_key'] timestamp = pairing_resp['timestamp'] print(f"拿到auth_key: {auth_key}, timestamp: {timestamp}") # 等待用户输入PIN pin = input("请输入电视上显示的PIN码:") # 步骤2 grant_resp = grant_pairing(TV_IP, device_info, client_id, auth_key, timestamp, pin)
我已经卡了好几天了,所有能想到的点都查过了,还是不知道为什么会提示PIN无效,有没有做过同款电视配对的朋友遇到过类似问题?或者有没有我漏掉的细节没考虑到?
内容来源于stack exchange
相关产品推荐
相关产品推荐

