decode($body); // self::log($data, 'LocationServer', self::$LOG_MAJOR); // if ($this->is_ep_sec($data['box_no'], 'reload_location', 10)) { // return $this->response(); // } // // $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() ]); $cols = []; // 验证位置是否正常 if ($data['location']['lat'] > 0) { $cols['last_location'] = json_encode($data['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(); } // 30 分钟更新一次 // $battery_power = $this->byVoltageGetElectric($data['bike']['battery_voltage']); $battery_power = $this->byVoltageGetElectric($data['bike']['battery_voltage'], $data['battery']['bike_soc']); $is_low_battery_power = BikeMap::BATTERY_POWER_OK; if ($battery_power <= self::$max_ride_v) { $is_low_battery_power = BikeMap::BATTERY_POWER_LOW; } // self::log($box_no . '===|' . $data['bike']['battery_voltage'] . '==>' . $battery_power, 'BP'); $location = [ 'order_id' => 0, 'bike_id' => 0, 'area_id' => 0, 'type' => 'no', 'is_rent' => 0 ]; // 判断是否接车状态 if ((!$data['bike']['status']['is_huanche'])) { //车运动状态 // 获取用户信息 $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']) { //关车之后没有关上,强制锁车 self::log($box_no, 'LOCATION_FOUCE_CLOSE_BIKE', self::$LOG_COMMON); BikeControl::closeLock($data['box_no']); } } else { //临时用车 // 临时停车没有关锁 if ($order['is_temporary_close']) { self::log($box_no, 'LOCATION_FOUCE_TEMPORARY_CLOSE_BIKE', self::$LOG_COMMON); BikeControl::temporaryCloseLock($data['box_no']); } } //用户正常骑行订单 if ($data['location']['lat'] > 0) {//判断是否在骑行区域内 // 判断后台是否设置超速区域播报语音 if ($order['is_out_area_lost_electric']) { $is_out_status = $this->isOutArea($data['location']['lat'], $data['location']['lng'], $order['area_id'], $data['box_no']); if (!$is_out_status['is_out_area']) {//播报语言 if (!$is_out_status['is_out_area_nearby']) { //断电播放 BikeControl::playVideo($data['box_no'], VideoMap::VIDEO_OUT_AREA_CLOSE_ELECTRIC); } else { //超出运营区 BikeControl::outAreaPlayVideo($data['box_no']); } if (!$is_out_status['is_out_area_nearby']) { //失能 echo '要失能'; if (!$this->redis->exists('bike_out_area_open_electric_' . $bike_no)) { echo '失能'; self::log($box_no, 'LOCATION_BIKE_OUT_AREA_LOSE', self::$LOG_COMMON); BikeControl::outAreaLoseElectric($data['box_no']); $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); } //在区域内断电 $is_in_parking_status = $this->isOutParkings($data['location']['lat'], $data['location']['lng'], $order['area_id'], $data['box_no']); // self::log($box_no . "|" . $order['area_id'] . "==>" . ($is_in_parking_status ? 1 : 0), "mead_in_parking", self::$LOG_COMMON); if ($is_in_parking_status) {//播报语言 //断电播放 BikeControl::playVideo($data['box_no'], VideoMap::VIDEO_OUT_AREA_CLOSE_ELECTRIC); if (!$this->redis->exists('bike_in_parking_open_electric_' . $bike_no)) { echo '失能'; self::log($box_no, 'LOCATION_BIKE_IN_Pariking_AREA_LOSE', self::$LOG_COMMON); BikeControl::outAreaLoseElectric($data['box_no']); $this->redis->set('bike_in_parking_area_' . $bike_no, 1, 60); } } else { //供能 if ($this->redis->exists('bike_in_parking_area_' . $bike_no)) { self::log($box_no, 'LOCATION_BIKE_IN_parking_AREA_ADD', self::$LOG_COMMON); BikeControl::outAreaGetElectric($data['box_no']); $this->redis->del('bike_in_parking_area_' . $bike_no); $this->redis->set('bike_in_parking_open_electric_' . $bike_no, 1, 120); } } } } } //电量过低自动关车 //是否低电关电车 if ($order['is_low_electric_close_bike']) { if ($battery_power <= 10) { BikeControl::playVideo($data['box_no'], VideoMap::VIDEO_NO_ELECTRIC); if ($this->is_throw_num_time($data['box_no'], 'battery_low', 50, 10)) { $status = json_decode(file_get_contents(Config['close_order_api_url'] . "&box_no={$box_no}&bike_no={$bike_no}&type=电量低"), 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; } elseif ($location['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 { if (strtotime($data['time']) >= (time() - 100)) { $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 = ' . $data['box_no'])->cols($cols)->query(); } } else { // 车静止状态 if (!$this->is_ep_min($box_no, 'update_stop_bike_battery', 30)) { $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'); // } } } $re = $this->updateBikeData($box_no, 'BikeStatus', [ 'battery_power' => $battery_power, 'is_low_battery_power' => $is_low_battery_power, ], $cols); if (!$re) { if (!$this->is_ep_min($box_no, 'update_bike_location', 20)) { $cols['battery_power'] = $battery_power; $cols['is_low_battery_power'] = $is_low_battery_power; $this->db->update('bikes')->where("box_no = '{$box_no}'")->cols($cols)->query(); } } else { $this->is_ep_min($box_no, 'update_bike_location', 20); } // // 更新车的位置信息(非骑行状态) // if (count($cols) && !$this->is_ep_min($box_no, 'update_bike_location', 20)) { // $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)) { // $this->db->update('bikes')->where('box_no = ' . $data['box_no'])->cols($cols)->query(); // } // } if (($data['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, $data['location']['lng'], $data['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' => $data['location']['lat'], 'longitude' => $data['location']['lng'], 'speed' => $data['bike']['speed'], 'battery_power' => $battery_power, 'mileage' => $data['bike']['bike_single_mileage'], 'is_riding' => $data['bike']['status']['is_ride'], 'is_yundong' => $data['bike']['status']['is_yundong'], 'type' => $location['type'], 'is_rent' => $location['is_rent'], 'created_at' => date('Y-m-d H:i:s'), 'box_time' => $data['time'], 'status' => 1, 'day' => date("Ymd") ]); return $this->response(); } /** * 判断是否在骑行区 * @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 ]; } /** * 是否在断电区域内 * @param $lat * @param $lng * @param $area_id * @param $box_no * @return bool */ private function isOutParkings($lat, $lng, $area_id = false, $box_no = false) { $location = [ 'latitude' => $lat, 'longitude' => $lng, ]; if (!$area_id) return false; $parkings = $this->byAreaIdGetDuanParkings($area_id); if (!is_array($parkings) || !count($parkings)) return false; // 判断是否在骑行区域 $ConvertHandler = (new ConvertHandler()); $status = false; foreach ($parkings as $parking) { $parking = json_decode($parking, true); $is_out_paring = $ConvertHandler->is_point_in_polygon($location, $parking); if ($is_out_paring) { $status = true; break; } } return $status; } /** * 解析装载的登录数据 * @param $body * @return array * User: Mead */ private function decode($body) { $i = 0; $box_no = $this->decodeBoxNo(self::stitching($body, $i, 5)); $i += 5; // 设备时间 $box_time = $this->decodeTime(self::stitching($body, $i, 4)); $i += 4; // 维度 $location_lat = self::stitching($body, $i, 4); $i += 4; // 经度 $location_lng = self::stitching($body, $i, 4); $i += 4; // 海报高度 // $location_height = self::stitching($body, $i, 2); $i += 2; //方位角 // $location_azimuth = self::stitching($body, $i, 1); $i += 1; // GPS速度 $location_speed = self::stitching($body, $i, 1); $i += 1; //信号状态 // $location_signal_status = self::stitching($body, $i, 2); $i += 2; // 基站 MCC // $station_mcc = self::stitching($body, $i, 2); $i += 2; // 基站 MNC // $station_mnc = self::stitching($body, $i, 2); $i += 2; // 基站 LAC // $station_lac = self::stitching($body, $i, 2); $i += 2; // 基站 CELLID // $station_cellid = self::stitching($body, $i, 2); $i += 2; // 车辆 相对SOC $bike_soc = hexdec(self::stitching($body, $i, 1)); $i += 1; // 车辆 可用剩余容量 $bike_battery_mb_free = self::stitching($body, $i, 2); $i += 2; // 车辆 SOH // $bike_soh = self::stitching($body, $i, 1); $i += 1; // 车辆 重放电次数 // $bike_charge_discharge_num = self::stitching($body, $i, 2); $i += 2; // 车辆 骑行电流 // $bike_ride_electric_current = self::stitching($body, $i, 1); $i += 1; // 车辆 控制器温度 // $bike_box_temperature = self::stitching($body, $i, 1); $i += 1; // 车辆 电瓶电压 $bike_battery_voltage = self::stitching($body, $i, 2); $i += 2; // 车辆 总里程 $bike_total_mileage = self::stitching($body, $i, 4); $i += 4; // 车辆 单次里程数 $bike_single_mileage = self::stitching($body, $i, 4); $i += 4; // 车辆 霍尔速度 $bike_speed = self::stitching($body, $i, 2); $i += 2; // 车辆 车辆状态 $bike_status = self::stitching($body, $i, 2); // 处理经纬度 list($lng, $lat) = $this->decodeLatAndLng($location_lat, $location_lng); // 处理车的状态 $bike_status = $this->decodeBikeStatus($bike_status); // 处理电压 $bike_battery_voltage = $this->decodeBatteryVoltage($bike_battery_voltage); return [ 'box_no' => $box_no, 'time' => $box_time, 'location' => [ 'lat' => $lat, 'lng' => $lng, 'speed' => $location_speed ], 'bike' => [ 'status' => $bike_status, 'speed' => hexdec($bike_speed), 'battery_voltage' => $bike_battery_voltage, 'bike_total_mileage' => hexdec($bike_total_mileage), 'bike_single_mileage' => hexdec($bike_single_mileage), ], 'battery' => [ 'bike_battery_mb_free' => $bike_battery_mb_free, 'bike_soc' => $bike_soc ] ]; } }