SatelliteLocationTransform.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Mead
  5. * Date: 2019/9/3
  6. * Time: 8:05 PM
  7. */
  8. namespace App\Servers\Weikemu\Transforms;
  9. use App\Handlers\BatteryHandler;
  10. use App\Handlers\BikeStatusInfoSyncHandler;
  11. use App\Handlers\ConvertHandler;
  12. use App\Handlers\MapHandler;
  13. use App\Maps\BikeMap;
  14. use App\Models\AreaTraitModel;
  15. use App\Models\BatteryTraitModel;
  16. use App\Models\BoxSettingTraitModel;
  17. use App\Models\LocationLosTraitModel;
  18. use App\Models\OrderTraitModel;
  19. use App\Models\WarningLogTraitModel;
  20. use App\Servers\BaseServer;
  21. use App\Servers\Weikemu\BikeControl;
  22. use App\Servers\Weikemu\Maps\VideoMap;
  23. use App\Servers\Weikemu\Models\CacheLogTraitModel;
  24. /**
  25. * 卫星位置报文
  26. * Class LoginServer
  27. * @package App\Servers
  28. */
  29. class SatelliteLocationTransform extends BaseServer
  30. {
  31. use BoxSettingTraitModel, WarningLogTraitModel, BatteryTraitModel, LocationLosTraitModel, OrderTraitModel, AreaTraitModel, CacheLogTraitModel;
  32. /**
  33. * 处理设备序列号
  34. * @param $no
  35. * @return bool|string
  36. * User: Mead
  37. */
  38. private static function box_no($no)
  39. {
  40. return substr($no, 0, 9);
  41. }
  42. public function main($body)
  43. {
  44. $data = $this->decode($body);
  45. // 位置信息
  46. // $bike_no = $_SESSION['bike_no'];
  47. // $box_no = $data['box_no'];
  48. // if (!$bike_no) return [];
  49. $location = [
  50. 'order_id' => 0,
  51. 'bike_id' => 0,
  52. 'area_id' => 0,
  53. 'type' => 'no',
  54. 'is_rent' => 0
  55. ];
  56. $battery_power = $data['battery_voltage'];
  57. $i = count($data['locations']);
  58. $last_location = [
  59. 'lat' => $data['locations'][$i - 1]['location_latitude'],
  60. 'lng' => $data['locations'][$i - 1]['location_longitude'],
  61. ];
  62. $last_location = (new MapHandler())->wgs84togcj02($last_location['lng'], $last_location['lat']);
  63. $last_location = [
  64. 'lat' => $last_location[1],
  65. 'lng' => $last_location[0],
  66. ];
  67. //过滤同一时候多包
  68. if ($_SESSION['last_box_location_time'] == $data['box_time']) {
  69. return $this->response();
  70. }
  71. $_SESSION['last_box_location_time'] = $data['box_time'];
  72. $bike_no = $_SESSION['bike_no'];
  73. $box_no = $_SESSION['box_no'];
  74. //车位位置更新redis
  75. $this->cacheJsonLog("NOW_LOCATION:{$bike_no}", [
  76. 'lat' => $last_location['lat'],
  77. 'lng' => $last_location['lng'],
  78. 'mileage' => 0,
  79. 'time' => time()
  80. ]);
  81. $cols = [];
  82. // 验证位置是否正常
  83. if ($last_location['lat'] >= 3) {
  84. $cols['last_location'] = json_encode($last_location, true);
  85. $cols['last_location_time'] = date('Y-m-d H:i:s');
  86. } else {
  87. //位置数据为0,说明车可能在房内
  88. if ($this->is_throw_num_time($data['box_no'], 'location_error', 10, 60)) {
  89. // 发出警告
  90. self::warningLocationError($bike_no, $box_no, $data, $body, "SatelliteLocation");
  91. }
  92. return $this->response();
  93. }
  94. if ($data['status']['order_status']) {
  95. // 电车打开
  96. // 获取用户信息
  97. $order = (new BikeStatusInfoSyncHandler($this->redis))->getRideBikeOrderInfo($bike_no);
  98. if ($order) {
  99. //是否有电量信息
  100. if (array_key_exists('is_rent', $order)) {
  101. $location['is_rent'] = $order['is_rent'];
  102. }
  103. // 订单信息
  104. if (array_key_exists('id', $order)) {
  105. $location['order_id'] = $order['id'];
  106. $location['area_id'] = $order['area_id'];
  107. }
  108. if (array_key_exists('bike_id', $order)) {
  109. $location['bike_id'] = $order['bike_id'];
  110. }
  111. $location['type'] = BikeStatusInfoSyncHandler::ROLE_USER;
  112. if ($order['role'] === BikeStatusInfoSyncHandler::ROLE_USER) {
  113. if ($location['is_rent']) {
  114. //租车
  115. if ($order['is_close_bike'] && $data['status']['bike_lock'] == 1) {
  116. //关车之后没有关上,强制锁车
  117. self::log($box_no, 'LOCATION_FOUCE_CLOSE_BIKE', self::$LOG_COMMON);
  118. BikeControl::closeLock($data['box_no']);
  119. }
  120. } else {
  121. // 临时停车没有关锁
  122. if ($order['is_temporary_close'] && $data['status']['bike_lock'] == 1) {
  123. self::log($box_no, 'LOCATION_FOUCE_TEMPORARY_CLOSE_BIKE', self::$LOG_COMMON);
  124. BikeControl::temporaryCloseLock($data['box_no']);
  125. }
  126. }
  127. //用户正常骑行订单
  128. if ($last_location['lat'] > 0) {//判断是否在骑行区域内
  129. // 判断后台是否设置超速区域播报语音
  130. if ($order['is_out_area_lost_electric']) {
  131. $is_out_status = $this->isOutArea($last_location['lat'], $last_location['lng'], $order['area_id'], $data['box_no']);
  132. if (!$is_out_status['is_out_area']) {//播报语言
  133. self::log('超区域');
  134. if ($this->is_throw_num_time($data['box_no'], 'is_out_area_nearby', 3, 0.5)) {
  135. self::log('播报语音');
  136. if (!$is_out_status['is_out_area_nearby']) {
  137. //断电播放
  138. BikeControl::playVoice($data['box_no'], VideoMap::VIDEO_BATTERY_EDGE);
  139. } else {
  140. //超出运营区
  141. BikeControl::playVoice($data['box_no'], VideoMap::VIDEO_GO_BEYOND);
  142. }
  143. }
  144. if (!$is_out_status['is_out_area_nearby']) {
  145. //失能
  146. echo '要失能';
  147. if ($this->is_throw_num_time($data['box_no'], 'is_out_area_nearby', 2, 1)) {
  148. if ((!$this->redis->exists('bike_out_area_open_electric_' . $bike_no)) || $data['status']['bike_lock']) {
  149. echo '失能';
  150. self::log($box_no, 'LOCATION_BIKE_OUT_AREA_LOSE', self::$LOG_COMMON);
  151. BikeControl::outAreaLoseElectric($data['box_no'], VideoMap::VIDEO_POWER_FAILURE);
  152. $this->redis->set('bike_out_area_' . $bike_no, 1, 60);
  153. }
  154. }
  155. } else {
  156. //供能
  157. if ($this->redis->exists('bike_out_area_' . $bike_no)) {
  158. self::log($box_no, 'LOCATION_BIKE_OUT_AREA_ADD', self::$LOG_COMMON);
  159. BikeControl::outAreaGetElectric($data['box_no']);
  160. $this->redis->del('bike_out_area' . $bike_no);
  161. $this->redis->set('bike_out_area_open_electric_' . $bike_no, 1, 120);
  162. }
  163. }
  164. } else {
  165. //供能
  166. if ($this->redis->exists('bike_out_area_' . $bike_no)) {
  167. self::log($box_no, 'LOCATION_BIKE_OUT_AREA_ADD', self::$LOG_COMMON);
  168. BikeControl::outAreaGetElectric($data['box_no']);
  169. $this->redis->del('bike_out_area' . $bike_no);
  170. $this->redis->set('bike_out_area_open_electric_' . $bike_no, 1, 120);
  171. }
  172. }
  173. }
  174. }
  175. //电量过低自动关车
  176. //是否低电关电车
  177. if ($order['is_low_electric_close_bike']) {
  178. if ($battery_power <= 10) {
  179. if ($this->is_throw_num_time($data['box_no'], 'is_low_battery', 3, 0.5)) {
  180. self::log('低电语音');
  181. BikeControl::playVoice($data['box_no'], VideoMap::VIDEO_LOW_POWER);
  182. }
  183. if ($this->is_throw_num_time($data['box_no'], 'battery_low', 40, 5)) {
  184. $status = json_decode(file_get_contents(Config['close_order_api_url'] . "&box_no={$box_no}&bike_no={$bike_no}&type=电量低&position=3"), true);
  185. self::log($box_no, 'LOCATION_BATTERY_LOW_AUTO_ORDER', self::$LOG_COMMON);
  186. }
  187. }
  188. }
  189. } else if ($order['role'] === BikeStatusInfoSyncHandler::ROLE_WORKER) {
  190. //运维骑行订单
  191. // 订单信息
  192. $location['type'] = BikeStatusInfoSyncHandler::ROLE_WORKER;
  193. } else if ($order['role'] === BikeStatusInfoSyncHandler::ROLE_BIND) {
  194. $location['type'] = BikeStatusInfoSyncHandler::ROLE_BIND;
  195. } else if ($order['role'] === BikeStatusInfoSyncHandler::ROLE_SERVER) {
  196. //系统本身操作
  197. $location['type'] = BikeStatusInfoSyncHandler::ROLE_SERVER;
  198. } else {
  199. self::log($box_no, 'LOCATION_CLOSE_BIKE_NO_USER_TYPE', self::$LOG_COMMON);
  200. BikeControl::closeLock($data['box_no']);
  201. }
  202. } else {
  203. //处理晚到的数据
  204. // $next_log = $this->byTimeGetOrder($data['box_time'], $box_no);
  205. // if ($next_log) {
  206. // $re = $this->byIdAndIsRentAndTime($next_log['order_id'], $next_log['is_rent'], $data['box_time']);
  207. // if ($re) {
  208. // $location['is_rent'] = $next_log['is_rent'];
  209. // $location['order_id'] = $next_log['order_id'];
  210. // $location['area_id'] = $next_log['area_id'];
  211. // $location['bike_id'] = $next_log['bike_id'];
  212. // $location['type'] = BikeStatusInfoSyncHandler::ROLE_USER;
  213. // }
  214. // } else {
  215. //// //非法骑行
  216. // $num = $this->redis->incr('bike:illegal:open:' . $bike_no, 1);
  217. // $this->redis->expire('bike:illegal:open:' . $bike_no, 120);
  218. // self::log($box_no, 'LOCATION_CLOSE_BIKE_NO_ORDER', self::$LOG_COMMON);
  219. // BikeControl::closeLock($data['box_no']);
  220. //
  221. // if ($num > 5) {
  222. // if (!$this->is_ep_min($box_no, 'illegal_location', 20)) {
  223. // $this->warningFF($bike_no, $data['box_no'], $data, $body);
  224. // }
  225. // }
  226. // }
  227. }
  228. if (!$this->is_ep_min($box_no, 'update_battery', 5)) {
  229. $cols['battery_power'] = $battery_power;
  230. $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_OK;
  231. if ($cols['battery_power'] <= self::$max_ride_v) {
  232. $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_LOW;
  233. //30分钟插一次报警信息
  234. if (!$this->is_ep_min($box_no, 'warning_log_battery', 30)) {
  235. $this->warningLogBatteryLow($bike_no, $data['box_no'], ['battery_power' => $cols['battery_power']], $body, 'satelliteLocation');
  236. }
  237. }
  238. }
  239. // 更新车的位置信息(非骑行状态)
  240. if (count($cols) && !$this->is_ep_min($box_no, 'update_ride_bike_location', 1)) {
  241. // $this->db->update('bikes')->where('box_no = ' . (string)$data['box_no'])->cols($cols)->query();
  242. $this->db->update('bikes')->where("box_no = '{$box_no}'")->cols($cols)->query();
  243. }
  244. } else {
  245. // 车静止状态
  246. if ($data['status']['bike_lock']) {
  247. BikeControl::closeLock($data['box_no']);
  248. }
  249. if (!$this->is_ep_min($box_no, 'update_stop_bike_battery', 15)) {
  250. $cols['battery_power'] = $battery_power;
  251. $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_OK;
  252. if ($cols['battery_power'] <= self::$max_ride_v) {
  253. $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_LOW;
  254. //30分钟插一次报警信息
  255. // if (!$this->is_ep_min($box_no, 'warning_log_battery', 30)) {
  256. $this->warningLogBatteryLow($bike_no, $data['box_no'], ['battery_power' => $cols['battery_power']], $body, 'location');
  257. // }
  258. }
  259. } else {
  260. // $openBatteryKey = "cache:open_battery:{$box_no}";
  261. // if ($this->redis->exists($openBatteryKey)) {
  262. // $cols['battery_power'] = $battery_power;
  263. // $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_OK;
  264. // if ($cols['battery_power'] <= self::$max_ride_v) {
  265. // $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_LOW;
  266. // }
  267. // }
  268. }
  269. // 更新车的位置信息(非骑行状态)
  270. // if (count($cols) && !$this->is_ep_min($box_no, 'update_bike_location', 10)) {
  271. // $this->db->update('bikes')->where('box_no = ' . $data['box_no'])->cols($cols)->query();
  272. // } else {
  273. // //换电池及时更新电量
  274. // $openBatteryKey = "cache:open_battery:{$box_no}";
  275. // if ($this->redis->exists($openBatteryKey)) {
  276. // $cols['battery_power'] = $battery_power;
  277. // $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_OK;
  278. // if ($cols['battery_power'] <= self::$max_ride_v) {
  279. // $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_LOW;
  280. // }
  281. // $this->db->update('bikes')->where('box_no = ' . $data['box_no'])->cols($cols)->query();
  282. // }
  283. // }
  284. // $this->db->update('bikes')->where('box_no = ' . (string)$data['box_no'])->cols($cols)->query();
  285. $this->db->update('bikes')->where("box_no = '{$box_no}'")->cols($cols)->query();
  286. if (($last_location['lat'] > 0)) {
  287. // 修改车的位置
  288. $is_location_ex = $this->redis->geopos(BikeStatusInfoSyncHandler::REDIS_BIKE_LOCATION_TAG, $bike_no)[0];
  289. if ((count($is_location_ex) !== 0)) {
  290. $this->redis->geoadd(BikeStatusInfoSyncHandler::REDIS_BIKE_LOCATION_TAG, $last_location['lng'], $last_location['lat'], $bike_no);
  291. }
  292. }
  293. }
  294. $day = date("Ymd");
  295. foreach ($data['locations'] as $v) {
  296. $lnglat = (new MapHandler())->wgs84togcj02($v['location_longitude'], $v['location_latitude']);
  297. $this->mongo->location_logs->insertOne([
  298. 'bike_no' => $bike_no,
  299. 'box_no' => $data['box_no'],
  300. 'order_id' => $location['order_id'],
  301. 'bike_id' => $location['bike_id'],
  302. 'area_id' => $location['area_id'],
  303. 'latitude' => $lnglat[1],
  304. 'longitude' => $lnglat[0],
  305. 'speed' => $v['location_speed']['speed'],
  306. 'battery_power' => $battery_power,
  307. 'mileage' => $data['kilometers'] ?? 0,
  308. 'is_riding' => $data['status']['order_status'] ?? 0,
  309. 'is_yundong' => $data['status']['rear_wheel_motion'] ?? 0,
  310. 'type' => $location['type'],
  311. 'is_rent' => $location['is_rent'],
  312. 'created_at' => date('Y-m-d H:i:s'),
  313. 'box_time' => $data['box_time'],
  314. 'status' => 1,
  315. 'source' => 'satelliteLocation',
  316. 'day' => $day
  317. ]);
  318. break;
  319. }
  320. return $this->response();
  321. }
  322. /**
  323. * 解析装载的状态消息
  324. * @param $body
  325. * @return array
  326. * User: Mead
  327. */
  328. private function decode($body)
  329. {
  330. $top34Data = $this->decodeWeiKeMuTop34($body);
  331. $i = 34;
  332. // 点类型 与 是否超速
  333. $location_type = self::stitching($body, $i, 1); // i=34
  334. $i += 1;
  335. // 信息组数
  336. $message_num = hexdec(self::stitching($body, $i, 1)); // i=35
  337. $i += 1;
  338. // 第一组样点对应时间
  339. $first_location_time = self::stitching($body, $i, 4); // i=36
  340. $i += 4;
  341. // 第一组样点对应维度
  342. $first_location_latitude = hexdec(self::stitching($body, $i, 4));// i=40
  343. $i += 4;
  344. // 第一组样点对应经度
  345. $first_location_longitude = hexdec(self::stitching($body, $i, 4));// i=44
  346. $i += 4;
  347. // 第一组样点速度
  348. $first_location_speed = self::stitching($body, $i, 1);// i=48
  349. $i += 1;
  350. // 第一组样点ACC状态、方向、卫星数
  351. $first_location_acc = self::stitching($body, $i, 1);// i=49
  352. $i += 1;
  353. // 第一个点
  354. $first_location = [
  355. 'location_time' => $this->decodeTime($first_location_time),
  356. 'location_latitude' => bcdiv($first_location_latitude, 1000000.0, 8),
  357. 'location_longitude' => bcdiv($first_location_longitude, 1000000.0, 8),
  358. 'location_speed' => self::handleLocationSpeed($first_location_speed),
  359. 'location_acc' => self::handleLocationACC($first_location_acc),
  360. ];
  361. // 第x个点的速度 1<= x <= hexdec($message_num)
  362. // 假设为第三个点的
  363. $locations[0] = $first_location;
  364. // 最后一个点
  365. $last_location = [];
  366. if ($message_num > 1) {
  367. //最后一组样点与第一个样点时间差值
  368. $last_location_time = self::stitching($body, $i, 2);// i=50
  369. $i += 2;
  370. // 最后一组样点与第一个样点维度差值
  371. $last_location_latitude = self::stitching($body, $i, 2);// i=52
  372. $i += 2;
  373. // 最后一组样点与第一个样点经度差值
  374. $last_location_longitude = self::stitching($body, $i, 2);// i=54
  375. $i += 2;
  376. // 最后一组样点速度
  377. $last_location_speed = self::stitching($body, $i, 1);// i=56
  378. $i += 1;
  379. // 最后一组样点ACC
  380. $last_location_acc = self::stitching($body, $i, 1);// i=57
  381. $i += 1;
  382. $last_location = [
  383. 'location_time' => $this->decodeTime(dechex(hexdec($first_location_time) + self::handleI2($last_location_time))),
  384. 'location_latitude' => bcdiv($first_location_latitude + self::handleI2($last_location_latitude), 1000000, 8),
  385. 'location_longitude' => bcdiv($first_location_longitude + self::handleI2($last_location_longitude), 1000000.0, 8),
  386. 'location_speed' => self::handleLocationSpeed($last_location_speed),
  387. 'location_acc' => self::handleLocationACC($last_location_acc),
  388. ];
  389. }
  390. if ($message_num > 2) {
  391. $ylocation = [
  392. 'location_time' => hexdec($first_location_time),
  393. 'location_latitude' => $first_location_latitude,
  394. 'location_longitude' => $first_location_longitude,
  395. 'location_speed' => self::handleLocationSpeed($first_location_speed),
  396. 'location_acc' => self::handleLocationACC($first_location_acc),
  397. ];
  398. for ($x = 1; $x < ($message_num - 1); $x++) {
  399. $x_location_speed = self::stitching($body, $i, 1);// i=58
  400. $i += 1;
  401. $x_location_acc = self::stitching($body, $i, 1);// i=59
  402. $i += 1;
  403. // n 与 n-1的时间差值
  404. $x_location_time = self::stitching($body, $i, 2);// $i =60
  405. $i += 2;
  406. // n与n-1 的维度差值
  407. $x_location_latitude = self::stitching($body, $i, 2);// 62
  408. $i += 2;
  409. // n与n-1的经度差值
  410. $x_location_longitude = self::stitching($body, $i, 2);// 64
  411. $i += 2;
  412. $time = $ylocation['location_time'] + hexdec($x_location_time);
  413. $lat = $ylocation['location_latitude'] + self::handleI2($x_location_latitude);
  414. $lng = $ylocation['location_longitude'] + self::handleI2($x_location_longitude);
  415. $locations[$x] = [
  416. 'location_time' => date('Y-m-d H:i:s', $time),
  417. 'location_latitude' => bcdiv($lat, 1000000, 8),
  418. 'location_longitude' => bcdiv($lng, 1000000, 8),
  419. 'location_speed' => self::handleLocationSpeed($x_location_speed),
  420. 'location_acc' => self::handleLocationACC($x_location_acc),
  421. ];
  422. $ylocation = [
  423. 'location_time' => $time,
  424. 'location_latitude' => $lat,
  425. 'location_longitude' => $lng,
  426. ];
  427. }
  428. }
  429. if ($message_num > 1) {
  430. $locations[] = $last_location;
  431. }
  432. return array_merge($top34Data, [
  433. 'location_type' => self::handleLocationType($location_type),
  434. 'message_num' => $message_num,
  435. 'first_location' => $first_location,
  436. 'last_location' => $last_location,
  437. 'locations' => $locations
  438. ]);
  439. }
  440. /**
  441. * 解析速度
  442. *
  443. * @param $location_speed
  444. * @return array
  445. * @author Fx
  446. *
  447. */
  448. private static function handleLocationSpeed($location_speed)
  449. {
  450. // self::dd('Speed==>');
  451. // self::dd($location_speed);
  452. $data = self::handleU1($location_speed);
  453. // self::dd($data);
  454. $is_speeding = $data[7];
  455. $speed = implode('', array_slice($data, 0, 7));
  456. return [
  457. 'is_speeding' => $is_speeding, //1:超速 0:否
  458. 'speed' => bindec($speed) * 2// 量化单位2km/h,范围 0~127
  459. ];
  460. }
  461. private static function handleLocationACC($locationACC)
  462. {
  463. // self::dd('ACC==>');
  464. // self::dd($locationACC);
  465. $data = self::handleU1($locationACC);
  466. // self::dd($data);
  467. // 卫星数
  468. $satellites = bindec(implode('', array_slice($data, 0, 4)));
  469. // 方向
  470. $directions = [
  471. '000' => '正北',
  472. '001' => '东北',
  473. '010' => '正东',
  474. '011' => '东南',
  475. '100' => '正南',
  476. '101' => '西南',
  477. '110' => '正西',
  478. '111' => '西北',
  479. ];
  480. $direction = implode('', array_slice($data, 4, 3));
  481. // ACC状态 1:ACC接通;0:ACC断开
  482. $acc_status = $data[7];
  483. return [
  484. 'satellites' => $satellites,
  485. 'direction' => $directions[$direction] ?? '',
  486. 'acc_status' => $acc_status,
  487. ];
  488. }
  489. /**
  490. * 解析点类型
  491. *
  492. * @param $location_type
  493. * @return array|mixed
  494. * @author Fx
  495. *
  496. */
  497. private static function handleLocationType($location_type)
  498. {
  499. $data = self::handleU1($location_type);
  500. return [
  501. 'location_type' => $data[5],// 1.静态位置标示;0.正常的轨迹点
  502. 'is_speeding' => $data[4] //超速指示,当该数据包持续6个点速度超速时,该位为1
  503. ];
  504. }
  505. /**
  506. * 状态响应
  507. * @param $login_type
  508. * @return array
  509. * User: Mead
  510. */
  511. public function response($login_type = '00')
  512. {
  513. $body = [
  514. '5b',
  515. '0000'
  516. ];
  517. return $body;
  518. }
  519. /**
  520. * 判断是否在骑行区
  521. * @param $lat
  522. * @param $lng
  523. * @param $box_no
  524. * User: Mead
  525. */
  526. private function isOutArea($lat, $lng, $area_id = false, $box_no = false)
  527. {
  528. $location = [
  529. 'latitude' => $lat,
  530. 'longitude' => $lng,
  531. ];
  532. if (!$area_id) $area_id = $this->byBoxNoGetAreaId($box_no);
  533. $area = $this->byAreaIdGetArea($area_id);
  534. $fences = $area['area_fence'];
  535. $centre = $area['area_centre'];
  536. $radius = $area['area_radius'];
  537. $area_fushe_fence = $area['area_fushe_fence'];
  538. // 判断是否在骑行区域
  539. $ConvertHandler = (new ConvertHandler());
  540. $is_out_area = $ConvertHandler->is_point_in_polygon($location, $fences);
  541. // 判断是否骑出辐射范围
  542. $is_out_area_nearby = true;
  543. if (!$is_out_area) {
  544. $is_out_area_nearby = $ConvertHandler->is_point_in_polygon($location, $area_fushe_fence);
  545. }
  546. return [
  547. 'is_out_area' => $is_out_area,
  548. 'is_out_area_nearby' => $is_out_area_nearby
  549. ];
  550. }
  551. }