@@ -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
267321class GetDataError (Exception ):
268- """request error or response data is unexpected"""
322+ """request error or response data is unexpected"""
0 commit comments