Skip to content

Commit 780b23e

Browse files
authored
修复automap gps获取数据签名错误
1 parent e925999 commit 780b23e

3 files changed

Lines changed: 186 additions & 74 deletions

File tree

custom_components/cloud_gps/autoamap_data_fetcher.py

Lines changed: 97 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -64,47 +64,84 @@ def __init__(self, hass, username, password, device_imei, location_key):
6464
self.address = {}
6565
self.lastgpstime = datetime.datetime.now()
6666

67-
# 使用自定义编码器的存储
6867
self._store = Store(
6968
hass,
7069
version=1,
7170
key=f"cloud_gps_{slugify(location_key)}",
7271
private=False,
73-
encoder=DateTimeEncoder # 使用自定义编码器
72+
encoder=DateTimeEncoder
7473
)
75-
76-
# 使用简单标志而不是立即加载
7774
self._persisted_data_loaded = False
7875

79-
headers = {
80-
'Host': 'ts.amap.com',
81-
'Accept': 'application/json',
82-
'sessionid': password.split("||")[1],
83-
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
84-
'Cookie': 'sessionid=' + password.split("||")[1],
85-
}
86-
self.session_autoamap.headers.update(headers)
76+
# 尝试解析 JSON 格式的新版 password
77+
try:
78+
self.amap_req_data = json.loads(self.password)
79+
except Exception:
80+
self.amap_req_data = None
81+
# 兼容老版本 || 的逻辑
82+
pwd_parts = self.password.split("||")
83+
session_id = pwd_parts[1] if len(pwd_parts) > 1 else ""
84+
headers = {
85+
'Host': 'ts.amap.com',
86+
'Accept': 'application/json',
87+
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
88+
'Cookie': f'sessionid={session_id}',
89+
}
90+
self.session_autoamap.headers.update(headers)
8791

8892
def _get_devices_info(self):
89-
url = str.format(AUTOAMAP_API_HOST + self.password.split("||")[0])
90-
p_data = self.password.split("||")[2]
91-
resp = self.session_autoamap.post(url, data=p_data).json()["data"]["carLinkInfoList"]
92-
return resp
93+
if self.amap_req_data:
94+
# === 新版完整 Header 还原逻辑 ===
95+
url = f"http://ts.amap.com{self.amap_req_data['url_path']}"
96+
97+
# 使用抓包里完整附带的所有 x-sign, x-t 等 Header
98+
headers = dict(self.amap_req_data['headers'])
99+
100+
# 必须剔除这些,防止与 requests 冲突
101+
for key in ["Content-Length", "content-length", "Host", "host", "Accept-Encoding"]:
102+
headers.pop(key, None)
103+
104+
raw_bytes = self.amap_req_data['body'].encode('utf-8')
105+
106+
try:
107+
response = self.session_autoamap.post(url, headers=headers, data=raw_bytes, timeout=15)
108+
response.raise_for_status()
109+
resp_json = response.json()
110+
111+
if "data" in resp_json and "carLinkInfoList" in resp_json["data"]:
112+
return resp_json["data"]["carLinkInfoList"]
113+
else:
114+
_LOGGER.error("高德机车 API 响应异常: %s", resp_json)
115+
return []
116+
except Exception as e:
117+
_LOGGER.error("高德机车 API 请求网络失败: %s", e)
118+
return []
119+
else:
120+
# === 老版兼容逻辑 ===
121+
pwd_parts = self.password.split("||")
122+
if len(pwd_parts) < 3: return []
123+
url = f"{AUTOAMAP_API_HOST}{pwd_parts[0]}"
124+
raw_bytes = pwd_parts[2].encode('utf-8')
125+
try:
126+
response = self.session_autoamap.post(url, data=raw_bytes, timeout=15)
127+
return response.json().get("data", {}).get("carLinkInfoList", [])
128+
except:
129+
return []
93130

94131

95132
def time_diff(self, timestamp):
96-
result = datetime.datetime.now() - datetime.datetime.fromtimestamp(timestamp)
97-
hours = int(result.seconds / 3600)
98-
minutes = int(result.seconds % 3600 / 60)
99-
seconds = result.seconds%3600%60
100-
if result.days > 0:
101-
return("{0}天{1}小时{2}分钟".format(result.days,hours,minutes))
102-
elif hours > 0:
103-
return("{0}小时{1}分钟".format(hours,minutes))
104-
elif minutes > 0:
105-
return("{0}分钟{1}秒".format(minutes,seconds))
106-
else:
107-
return("{0}秒".format(seconds))
133+
result = datetime.datetime.now() - datetime.datetime.fromtimestamp(timestamp)
134+
hours = int(result.seconds / 3600)
135+
minutes = int(result.seconds % 3600 / 60)
136+
seconds = result.seconds % 3600 % 60
137+
if result.days > 0:
138+
return f"{result.days}{hours}小时{minutes}分钟"
139+
elif hours > 0:
140+
return f"{hours}小时{minutes}分钟"
141+
elif minutes > 0:
142+
return f"{minutes}分钟{seconds}秒"
143+
else:
144+
return f"{seconds}秒"
108145

109146

110147
def get_distance(self, lat1, lng1, lat2, lng2):
@@ -156,14 +193,15 @@ async def get_data(self):
156193
await self._load_persisted_data()
157194
self._persisted_data_loaded = True
158195

196+
devicesinfodata = []
159197
try:
160-
async with timeout(10):
161-
devicesinfodata = await self.hass.async_add_executor_job(self._get_devices_info)
198+
async with timeout(15):
199+
devicesinfodata = await self.hass.async_add_executor_job(self._get_devices_info)
162200
_LOGGER.debug("高德机车 %s 最终数据结果: %s", self.device_imei, devicesinfodata)
163201
except ClientConnectorError as error:
164202
_LOGGER.error("高德机车 %s 连接错误: %s", self.device_imei, error)
165203
except asyncio.TimeoutError:
166-
_LOGGER.error("高德机车 %s 获取数据超时 (10秒)", self.device_imei)
204+
_LOGGER.error("高德机车 %s 获取数据超时 (15秒)", self.device_imei)
167205
except Exception as e:
168206
_LOGGER.error("高德机车 %s 未知错误: %s", self.device_imei, repr(e))
169207

@@ -176,16 +214,22 @@ async def get_data(self):
176214
if infodata.get("tid") == imei:
177215
self.deviceinfo[imei] = infodata
178216
self.deviceinfo[imei]["device_model"] = "高德地图车机版"
179-
self.deviceinfo[imei]["sw_version"] = infodata["sysInfo"]["autodiv"]
217+
# 使用 get 保护,防止 API 变化导致报错
218+
self.deviceinfo[imei]["sw_version"] = infodata.get("sysInfo", {}).get("autodiv", "unknown")
180219

181220
querytime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
182-
thislat = infodata["naviLocInfo"]["lat"]
183-
thislon = infodata["naviLocInfo"]["lon"]
221+
222+
# 保护经纬度获取
223+
navi_info = infodata.get("naviLocInfo", {})
224+
thislat = navi_info.get("lat", 0)
225+
thislon = navi_info.get("lon", 0)
226+
184227
lastlat = self.vardata[imei].get("lastlat",0)
185228
lastlon = self.vardata[imei].get("lastlon",0)
186229

187230
distance = self.get_distance(thislat, thislon, lastlat, lastlon)
188231
status = "停车"
232+
189233
if distance > 10:
190234
_LOGGER.debug("状态为运动: %s ,%s", thislat,thislon)
191235
status = "行驶"
@@ -194,12 +238,13 @@ async def get_data(self):
194238
self.vardata[imei]["speed"] = round((distance / distancetime * 3.6), 1)
195239
self.vardata[imei]["course"] = self.calculate_bearing(thislat, thislon, lastlat, lastlon)
196240
self.lastgpstime = datetime.datetime.now()
241+
197242
if self.vardata[imei].get("runorstop","run") == "stop":
198243
_LOGGER.debug("变成运动: %s ,%s", thislat,thislon)
199244
self.vardata[imei]["lastruntime"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
200245
self.vardata[imei]["runorstop"] = "run"
201246
self.vardata[imei]["lastlat"] = thislat
202-
self.vardata[imei]["lastlon"] = thislon
247+
self.vardata[imei]["lastlon"] = thislon
203248

204249
elif self.vardata[imei].get("runorstop","run") == "run":
205250
_LOGGER.debug("变成静止: %s ,%s", thislat,thislon)
@@ -208,15 +253,15 @@ async def get_data(self):
208253
self.vardata[imei]["runorstop"] = "stop"
209254
self.vardata[imei]["speed"] = 0
210255

211-
if infodata['naviStatus'] == 1:
256+
if infodata.get('naviStatus') == 1:
212257
naviStatus = "导航中"
213258
status = "导航中"
214259
else:
215260
naviStatus = "未导航"
216261

217-
if infodata["onlineStatus"] == 1:
262+
if infodata.get("onlineStatus") == 1:
218263
onlinestatus = "在线"
219-
elif infodata["onlineStatus"] == 0:
264+
elif infodata.get("onlineStatus") == 0:
220265
onlinestatus = "离线"
221266
status = "离线"
222267
else:
@@ -234,9 +279,10 @@ async def get_data(self):
234279
onlinestatus = self.vardata[imei].get("isonline","离线")
235280
laststoptime = self.vardata[imei].get("laststoptime","")
236281
lastruntime = self.vardata[imei].get("lastruntime","")
237-
runorstop = self.vardata[imei].get("runorstop","运动")
282+
runorstop = self.vardata[imei].get("runorstop","run")
238283
speed = self.vardata[imei].get("speed",0)
239284
course = self.vardata[imei].get("course",0)
285+
240286
await self._persist_data()
241287

242288
if laststoptime != "" and runorstop == "stop":
@@ -255,14 +301,22 @@ async def get_data(self):
255301
"parkingtime": parkingtime,
256302
"naviStatus": naviStatus,
257303
"onlinestatus": onlinestatus,
258-
"lastofflinetime":lastofflinetime,
259-
"lastonlinetime":lastonlinetime
304+
"lastofflinetime": lastofflinetime,
305+
"lastonlinetime": lastonlinetime
260306
}
261307

262-
self.trackerdata[imei] = {"location_key":self.location_key+imei,"deviceinfo":self.deviceinfo[imei],"thislat":thislat,"thislon":thislon,"imei":imei,"status":status,"attrs":attrs}
308+
self.trackerdata[imei] = {
309+
"location_key": self.location_key + imei,
310+
"deviceinfo": self.deviceinfo[imei],
311+
"thislat": thislat,
312+
"thislon": thislon,
313+
"imei": imei,
314+
"status": status,
315+
"attrs": attrs
316+
}
263317

264318
return self.trackerdata
265319

266320

267321
class GetDataError(Exception):
268-
"""request error or response data is unexpected"""
322+
"""request error or response data is unexpected"""

0 commit comments

Comments
 (0)