decode($body); // 位置信息 // $bike_no = $_SESSION['bike_no']; // $box_no = $data['box_no']; // if (!$bike_no) return []; //过滤同一时候多包 if ($_SESSION['last_box_location_time'] == $data['time']) { return $this->response(); } $_SESSION['last_box_location_time'] = $data['time']; $bike_no = $_SESSION['bike_no']; $box_no = $_SESSION['box_no']; //车位位置更新redis $this->cacheJsonLog("NOW_LOCATION:{$bike_no}", [ 'lat' => $data['location']['lat'], 'lng' => $data['location']['lng'], 'mileage' => $data['bike']['bike_single_mileage'], 'time' => time() ]); $location = [ 'order_id' => 0, 'bike_id' => 0, 'area_id' => 0, 'type' => 'no', 'is_rent' => 0 ]; $battery_power = $data['battery_voltage']; self::log($data, 'Location', self::$LOG_COMMON); if (!$data['location_type']) { //基站 return $this->response(); } $last_location = [ 'lat' => $data['yjlx']['lngLat'][1], 'lng' => $data['yjlx']['lngLat'][0], ]; $cols = []; // 验证位置是否正常 if ($last_location['lat'] >= 3) { $cols['last_location'] = json_encode($last_location, true); $cols['last_location_time'] = date('Y-m-d H:i:s'); } else { //位置数据为0,说明车可能在房内 if ($this->is_throw_num_time($data['box_no'], 'location_error', 10, 60)) { // 发出警告 self::warningLocationError($bike_no, $box_no, $data, $body, "location"); } return $this->response(); } if ($data['status']['order_status']) { // 电车打开 // 获取用户信息 $order = (new BikeStatusInfoSyncHandler($this->redis))->getRideBikeOrderInfo($bike_no); if ($order) { //是否有电量信息 if (array_key_exists('is_rent', $order)) { $location['is_rent'] = $order['is_rent']; } // 订单信息 if (array_key_exists('id', $order)) { $location['order_id'] = $order['id']; $location['area_id'] = $order['area_id']; } if (array_key_exists('bike_id', $order)) { $location['bike_id'] = $order['bike_id']; } $location['type'] = BikeStatusInfoSyncHandler::ROLE_USER; if ($order['role'] === BikeStatusInfoSyncHandler::ROLE_USER) { if ($location['is_rent']) { //租车 if ($order['is_close_bike'] && $data['status']['bike_lock'] == 1) { //关车之后没有关上,强制锁车 self::log($box_no, 'LOCATION_FOUCE_CLOSE_BIKE', self::$LOG_COMMON); BikeControl::closeLock($data['box_no']); } } else { // 临时停车没有关锁 if ($order['is_temporary_close'] && $data['status']['bike_lock'] == 1) { self::log($box_no, 'LOCATION_FOUCE_TEMPORARY_CLOSE_BIKE', self::$LOG_COMMON); BikeControl::temporaryCloseLock($data['box_no']); } } //用户正常骑行订单 if ($last_location['lat'] > 0) {//判断是否在骑行区域内 // 判断后台是否设置超速区域播报语音 if ($order['is_out_area_lost_electric']) { $is_out_status = $this->isOutArea($last_location['lat'], $last_location['lng'], $order['area_id'], $data['box_no']); if (!$is_out_status['is_out_area']) {//播报语言 self::log('超区域'); if ($this->is_throw_num_time($data['box_no'], 'is_out_area_nearby', 3, 0.5)) { self::log('播报语音'); if (!$is_out_status['is_out_area_nearby']) { //断电播放 BikeControl::playVoice($data['box_no'], VideoMap::VIDEO_BATTERY_EDGE); } else { //超出运营区 BikeControl::playVoice($data['box_no'], VideoMap::VIDEO_GO_BEYOND); } } if (!$is_out_status['is_out_area_nearby']) { //失能 echo '要失能'; if ($this->is_throw_num_time($data['box_no'], 'is_out_area_nearby', 4, 1)) { if ((!$this->redis->exists('bike_out_area_open_electric_' . $bike_no)) || $data['status']['bike_lock']) { echo '失能'; self::log($box_no, 'LOCATION_BIKE_OUT_AREA_LOSE', self::$LOG_COMMON); BikeControl::outAreaLoseElectric($data['box_no'], VideoMap::VIDEO_POWER_FAILURE); $this->redis->set('bike_out_area_' . $bike_no, 1, 60); } } } else { //供能 if ($this->redis->exists('bike_out_area_' . $bike_no)) { self::log($box_no, 'LOCATION_BIKE_OUT_AREA_ADD', self::$LOG_COMMON); BikeControl::outAreaGetElectric($data['box_no']); $this->redis->del('bike_out_area' . $bike_no); $this->redis->set('bike_out_area_open_electric_' . $bike_no, 1, 120); } } } else { //供能 if ($this->redis->exists('bike_out_area_' . $bike_no)) { self::log($box_no, 'LOCATION_BIKE_OUT_AREA_ADD', self::$LOG_COMMON); BikeControl::outAreaGetElectric($data['box_no']); $this->redis->del('bike_out_area' . $bike_no); $this->redis->set('bike_out_area_open_electric_' . $bike_no, 1, 120); } } } } //电量过低自动关车 //是否低电关电车 if ($order['is_low_electric_close_bike']) { if ($battery_power <= 10) { if ($this->is_throw_num_time($data['box_no'], 'is_low_battery', 3, 0.5)) { self::log('低电语音'); BikeControl::playVoice($data['box_no'], VideoMap::VIDEO_LOW_POWER); } if ($this->is_throw_num_time($data['box_no'], 'battery_low', 40, 5)) { $status = json_decode(file_get_contents(Config['close_order_api_url'] . "&box_no={$box_no}&bike_no={$bike_no}&type=电量低&position=2"), true); self::log($box_no, 'LOCATION_BATTERY_LOW_AUTO_ORDER', self::$LOG_COMMON); } } } } else if ($order['role'] === BikeStatusInfoSyncHandler::ROLE_WORKER) { //运维骑行订单 // 订单信息 $location['type'] = BikeStatusInfoSyncHandler::ROLE_WORKER; } else if ($order['role'] === BikeStatusInfoSyncHandler::ROLE_BIND) { $location['type'] = BikeStatusInfoSyncHandler::ROLE_BIND; } else if ($order['role'] === BikeStatusInfoSyncHandler::ROLE_SERVER) { //系统本身操作 $location['type'] = BikeStatusInfoSyncHandler::ROLE_SERVER; } else { self::log($box_no, 'LOCATION_CLOSE_BIKE_NO_USER_TYPE', self::$LOG_COMMON); BikeControl::closeLock($data['box_no']); } } else { //处理晚到的数据 // $next_log = $this->byTimeGetOrder($data['box_time'], $box_no); // if ($next_log) { // $re = $this->byIdAndIsRentAndTime($next_log['order_id'], $next_log['is_rent'], $data['box_time']); // if ($re) { // $location['is_rent'] = $next_log['is_rent']; // $location['order_id'] = $next_log['order_id']; // $location['area_id'] = $next_log['area_id']; // $location['bike_id'] = $next_log['bike_id']; // $location['type'] = BikeStatusInfoSyncHandler::ROLE_USER; // } // } else { //// //非法骑行 // $num = $this->redis->incr('bike:illegal:open:' . $bike_no, 1); // $this->redis->expire('bike:illegal:open:' . $bike_no, 120); // self::log($box_no, 'LOCATION_CLOSE_BIKE_NO_ORDER', self::$LOG_COMMON); // BikeControl::closeLock($data['box_no']); // // if ($num > 5) { // if (!$this->is_ep_min($box_no, 'illegal_location', 20)) { // $this->warningFF($bike_no, $data['box_no'], $data, $body); // } // } // } } if (!$this->is_ep_min($box_no, 'update_battery', 5)) { $cols['battery_power'] = $battery_power; $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_OK; if ($cols['battery_power'] <= self::$max_ride_v) { $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_LOW; //30分钟插一次报警信息 if (!$this->is_ep_min($box_no, 'warning_log_battery', 30)) { $this->warningLogBatteryLow($bike_no, $data['box_no'], ['battery_power' => $cols['battery_power']], $body, 'location'); } } } // 更新车的位置信息(非骑行状态) if (count($cols) && !$this->is_ep_min($box_no, 'update_ride_bike_location', 1)) { // $this->db->update('bikes')->where('box_no = ' . (string)$data['box_no'])->cols($cols)->query(); $this->db->update('bikes')->where("box_no = '{$box_no}'")->cols($cols)->query(); } } else { // 车静止状态 if ($data['status']['bike_lock']) { BikeControl::closeLock($data['box_no']); } if (!$this->is_ep_min($box_no, 'update_stop_bike_battery', 15)) { $cols['battery_power'] = $battery_power; $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_OK; if ($cols['battery_power'] <= self::$max_ride_v) { $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_LOW; //30分钟插一次报警信息 // if (!$this->is_ep_min($box_no, 'warning_log_battery', 30)) { $this->warningLogBatteryLow($bike_no, $data['box_no'], ['battery_power' => $cols['battery_power']], $body, 'location'); // } } } else { // $openBatteryKey = "cache:open_battery:{$box_no}"; // if ($this->redis->exists($openBatteryKey)) { // $cols['battery_power'] = $battery_power; // $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_OK; // if ($cols['battery_power'] <= self::$max_ride_v) { // $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_LOW; // } // } } // 更新车的位置信息(非骑行状态) // if (count($cols) && !$this->is_ep_min($box_no, 'update_bike_location', 10)) { // $this->db->update('bikes')->where('box_no = ' . $data['box_no'])->cols($cols)->query(); // } else { // //换电池及时更新电量 // $openBatteryKey = "cache:open_battery:{$box_no}"; // if ($this->redis->exists($openBatteryKey)) { // $cols['battery_power'] = $battery_power; // $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_OK; // if ($cols['battery_power'] <= self::$max_ride_v) { // $cols['is_low_battery_power'] = BikeMap::BATTERY_POWER_LOW; // } // $this->db->update('bikes')->where('box_no = ' . $data['box_no'])->cols($cols)->query(); // } // } // $this->db->update('bikes')->where('box_no = ' . $data['box_no'])->cols($cols)->query(); $this->db->update('bikes')->where("box_no = '{$box_no}'")->cols($cols)->query(); if (($last_location['lat'] > 0)) { // 修改车的位置 $is_location_ex = $this->redis->geopos(BikeStatusInfoSyncHandler::REDIS_BIKE_LOCATION_TAG, $bike_no)[0]; if ((count($is_location_ex) !== 0)) { $this->redis->geoadd(BikeStatusInfoSyncHandler::REDIS_BIKE_LOCATION_TAG, $last_location['lng'], $last_location['lat'], $bike_no); } } } $this->mongo->location_logs->insertOne([ 'bike_no' => $bike_no, 'box_no' => $data['box_no'], 'order_id' => $location['order_id'], 'bike_id' => $location['bike_id'], 'area_id' => $location['area_id'], 'latitude' => $last_location['lat'], 'longitude' => $last_location['lng'], 'speed' => $data['yjlx']['speed'], 'battery_power' => $battery_power, 'mileage' => $data['bike']['bike_single_mileage'] ?? 0, 'is_riding' => $data['status']['order_status'] ?? 0, 'is_yundong' => $data['status']['rear_wheel_motion'] ?? 0, 'type' => $location['type'], 'is_rent' => $location['is_rent'], 'created_at' => date('Y-m-d H:i:s'), 'box_time' => $data['box_time'], 'status' => 1, 'source' => 'location', 'day' => date("Ymd") ]); return $this->response(); } /** * 解析装载的状态消息 * @param $body * @return array * User: Mead */ private function decode($body) { $top34Data = $this->decodeWeiKeMuTop34($body); $i = 34; $location_type = self::stitching($body, $i, 1); // i=34 $i += 1; $acc_status = self::stitching($body, $i, 1); // i=35 $i += 1; // 动态计算 $yjlx = self::stitching($body, $i, 14); // i=36 $yjlxData = []; if ($yjlx) { $yjlxData = self::handleYjlx($yjlx); } return array_merge($top34Data, [ 'location_type' => self::handleLocationType($location_type),//0为基站定位 1为卫星定位 'acc_status' => self::handleACCStatus($acc_status), 'yjlx' => $yjlxData, ]); } private static function handleYjlx($yjlx) { // echo '动态计算' . PHP_EOL; $i = 0; $time = substr($yjlx, $i, 8); // 时间 $i += 8; $latitude = hexdec(substr($yjlx, $i, 8)); // 维度 $i += 8; $longitude = hexdec(substr($yjlx, $i, 8)); // 经度 $i += 8; $speed = substr($yjlx, $i, 2); $i += 2; $acc = self::handleACCStatus(substr($yjlx, $i, 2)); $lnglat = (new MapHandler())->wgs84togcj02(self::formatCoordinate($longitude), self::formatCoordinate($latitude)); return [ 'time' => date('Y-m-d H:i:s', hexdec($time)), 'lngLat' => $lnglat, 'speed' => $speed, 'acc' => $acc, ]; } private static function handleACCStatus($acc_status) { $data = self::handleU1($acc_status); return [ 'activity' => $data[0], //1:动 0:静 'acc_status' => $data[1], // 1:ACC接通,0:ACC断开 ]; } private static function handleLocationType($location_type) { $data = self::handleU1($location_type); return $data[0]; } /** * 状态响应 * @param $login_type * @return array * User: Mead */ public function response($login_type = '00') { $body = [ '5b', '0000' ]; return $body; } /** * 判断是否在骑行区 * @param $lat * @param $lng * @param $box_no * User: Mead */ private function isOutArea($lat, $lng, $area_id = false, $box_no = false) { $location = [ 'latitude' => $lat, 'longitude' => $lng, ]; if (!$area_id) $area_id = $this->byBoxNoGetAreaId($box_no); $area = $this->byAreaIdGetArea($area_id); $fences = $area['area_fence']; $centre = $area['area_centre']; $radius = $area['area_radius']; $area_fushe_fence = $area['area_fushe_fence']; // 判断是否在骑行区域 $ConvertHandler = (new ConvertHandler()); $is_out_area = $ConvertHandler->is_point_in_polygon($location, $fences); // 判断是否骑出辐射范围 $is_out_area_nearby = true; if (!$is_out_area) { $is_out_area_nearby = $ConvertHandler->is_point_in_polygon($location, $area_fushe_fence); } return [ 'is_out_area' => $is_out_area, 'is_out_area_nearby' => $is_out_area_nearby ]; } }