count = 1; $tcp_worker->onWorkerStart = function($worker){ }; $tcp_worker->onConnect = function($connection){ $this->onConnect($connection); }; $tcp_worker->onMessage = function($connection,$data){ $this->onMessage($connection,$data); }; $tcp_worker->onClose = function($connection){ $this->onClose($connection); }; //实例化信号处理类 $this->rfid_proto = new Rlgs\Proto\RfidStation2(); $this->rchy_alarm_list = Redis("rchy_alarm_list","queue"); $this->redis_vsignal = Redis("rchy_vsignal_{no}","zset")->prefix('rchy_vsignal_'); //$this->cache = \Rchy\Cache\RedisCache::getInstance(); Workerman\Worker::runAll();//保持运行 } private function onMessage( $connection, $data ){ $connection->m_packet .= $data; } private function onConnect( $connection ){ echo PHP_EOL . $connection->id . ' connected'. PHP_EOL; } private function onClose( $connection ){ //记录数据包文本 $packet_text = $this->rfid_proto->tcp_hex2str($connection->m_packet,true) ; //$this->rfid_proto->tcp_log($connection->id . ' closed ' . $packet_text); //echo 'packet_text => '.$packet_text.PHP_EOL; //解析消息体 $packet = $this->rfid_proto->tcp_str2bin($packet_text); $result = $this->rfid_proto->tcp_unpack_msg($packet); if(! $result['Success'] ){ echo 'unpack packet failed'.PHP_EOL; $this->rfid_proto->decode_error_log('unpack_fail','unpack packet failed ,result : '.json_encode($result)); return; } //echo 'decode_data => '.json_encode($result).PHP_EOL; //记录基站数据包 //$this->rfid_proto->decode_packet_log($result['StationCode'],$result['StationCode'].' => '.$packet_text); if (!$result['StationCode']){ echo 'StationCode is empty!'.PHP_EOL; $this->rfid_proto->decode_error_log('unpack_fail','StationCode is empty! '); return false; } if (!$result['VehicleList']){ echo 'VehicleList is empty!'.PHP_EOL; return ; } //检查是否有效基站 $station_info = \Rchy\Cache\RedisCache::getStationInfo($result['StationCode']); if(!$station_info){ $this->rfid_proto->decode_error_log('unpack_fail','getStationInfo failed ,StationCode : '.$result['StationCode']); return false; } //更新车主标签时间 echo '======= updateRfidTime start ======='.$connection->id.PHP_EOL; $this->updateRfidTime($result); echo '======= updateRfidTime over ======='.$connection->id.PHP_EOL; //添加报警 echo '======= addAlarm start ======='.$connection->id.PHP_EOL; $this->addAlarm($result); echo '======= addAlarm over ======='.$connection->id.PHP_EOL; /* //轨迹包redis主库 $redis_raw_packet = Redis("fdqu_raw_packet","queue"); $redis_raw_packet->push($packet_text); //数据解包 $result = $this->unpackMsg($packet_text); //生成车辆轨迹日志 $this->addTcpLog($result); */ } private function addTcpLog( $result ){ //一个基站一个日志文件 $this->rfid_proto->station_route_log('tcp',$result); //一个车辆一个日志文件 $this->rfid_proto->vehicle_route_log('tcp',$result); } private function unpackMsg( $packet_text ){ $packet = $this->rfid_proto->tcp_str2bin($packet_text); if(!$packet){ echo 'parse packet failed.'.PHP_EOL; $this->rfid_proto->tcp_error_log('parse_fail','parse packet failed ,packet_text : '.$packet_text); return false; } $result = $this->rfid_proto->tcp_unpack_msg($packet); if(! $result['Success'] ){ echo 'unpack fail: ' . $result['Message'].PHP_EOL; $this->rfid_proto->tcp_error_log('unpack_fail',$result); return false; } return $result; } private function addAlarm( $result ){ //获取当前所有车主rfid的rssi数据 $chezhu_rfids = array(); foreach ($result['VehicleList'] as $key => $row){ $chezhu_info = \Rchy\Cache\RedisCache::getCheZhuInfo($row['VehicleNumber']); if(!$chezhu_info){ continue; } $chezhu_rfids[$row['VehicleNumber']]['Rssi'] = $row['rssi']; $chezhu_rfids[$row['VehicleNumber']]['SignalCount'] = $row['SignalCount']; } //var_dump($result['VehicleList']); foreach ($result['VehicleList'] as $key => $row){ $row['StationCode'] = $result['StationCode']; if (!$row['VehicleNumber']){ echo 'VehicleNumber empty!'.PHP_EOL; continue; } //获取车辆信息 $vehicle_info = \Rchy\Cache\RedisCache::getVehicleInfo($row['VehicleNumber']); //车辆不存在跳过 if (!$vehicle_info){ //echo 'vehicle not existed, vehilce_number = '.$row['VehicleNumber'].', rssi = '.$row['rssi'].PHP_EOL; continue; } //未绑定车主rfid跳过 if (!$vehicle_info['CheZhuRfid']){ echo 'vehicle not kaihu, vehilce_number: '.$row['VehicleNumber'].', rssi = '.$row['rssi'].PHP_EOL; continue; } echo 'VehicleNumber: '.$row['VehicleNumber'].',rssi = '.$row['rssi'].PHP_EOL; //车辆标签 $vehicle_no = strtolower($row['VehicleNumber']); //末次信号(改用本地缓存了) //$last_signal_info = $this->redis_vsignal->table($vehicle_no)->max(); //获取最近一段时间内所有rssi,求均值 $avgRssi = $this->getAvgRssi($row); if($avgRssi === false){ echo 'getAvgRssi failed! VehicleNumber = '.$row['VehicleNumber'].PHP_EOL; continue; } //车辆rssi信号弱的,过滤掉,防止收到车信号的时候,没有收到车主信号,从而误报 if ($avgRssi > C('rcgjfw.车辆标签_rssi阀值')){ echo 'avgRssi > '.C('rcgjfw.车辆标签_rssi阀值').', avgRssi = '.$avgRssi.', VehicleNumber = '.$row['VehicleNumber'].PHP_EOL; continue; } //有效信号加入到 rchy_vsignal_{no} 表 $signal = array( 'StationCode' => $row['StationCode'], 'Rssi' => $row['rssi'], 'Timestamp' => $row['Timestamp'] ); //获取最近一次的信号信息 $last_signal_info = S('last_signal_info'.$row['VehicleNumber']); //更新最近一次的信号信息 S('last_signal_info'.$row['VehicleNumber'], $signal, 24*60*60); $alarm_info = array(); $alarm_info['VehicleNumber'] = $row['VehicleNumber']; $alarm_info['AlarmTime'] = time(); $alarm_info['OnlineTime'] = $row['OnlineTime']; $alarm_info['VehicleRssi'] = $row['rssi']; $alarm_info['VehicleSignalCount'] = $row['SignalCount']; $alarm_info['CheZhuRssi'] = $chezhu_rfids[$vehicle_info['CheZhuRfid']]['Rssi'];//车主或者授权车主信号强度,这里还需要完善 $alarm_info['CheZhuSignalCount'] = $chezhu_rfids[$vehicle_info['CheZhuRfid']]['SignalCount']; $alarm_info['StationCode'] = $row['StationCode']; //检查车辆经过时,在限定的时间内,是否有接收到任一授权标签信号 $is_stolen = $this->checkVehicleStatus($vehicle_info['CheZhuRfid'], $row); $cur_time = time(); //检查是否被盗报警 if ( $is_stolen ){ $alarm_info['AlarmType'] = \Rchy\Enum\AlarmType::STOLEN; //上次被盗告警时间 $latest_stolen_alarm_time = S('latest_stolen_alarm_time_'.$row['VehicleNumber']); //避免频繁告警检测 if ($latest_stolen_alarm_time && $cur_time - $latest_stolen_alarm_time <= C('rcgjfw.被盗告警_间隔时间')){ echo '车辆'.$row['VehicleNumber'].'刚被盗告警过,跳过告警! latest_stolen_alarm_time = '.$latest_stolen_alarm_time.', cur_time = '.$cur_time.PHP_EOL; return ; } echo 'VehicleNumber:'.$row['VehicleNumber'].', 告警类型: 被盗告警'.PHP_EOL; //更新本次被盗告警时间 S('latest_stolen_alarm_time_'.$row['VehicleNumber'], $cur_time); }else{ //上次告警时间 $latest_pass_alarm_time = S('latest_pass_alarm_time_'.$row['VehicleNumber']); //避免频繁告警检测 if ($latest_pass_alarm_time && $cur_time - $latest_pass_alarm_time <= C('rcgjfw.过车告警_间隔时间')){ echo '车辆'.$row['VehicleNumber'].'刚过车告警过,跳过! 已过车告警'.$pass_alarm_count.'次, latest_pass_alarm_time = '.$latest_pass_alarm_time.', cur_time = '.$cur_time.PHP_EOL; return ; } $alarm_info['AlarmType'] = \Rchy\Enum\AlarmType::PASS; echo 'pass_alarm_count = '.$pass_alarm_count.', last_chezhu_signal_time = '.$last_signal_info['Timestamp'].', now = '.$row['Timestamp']. PHP_EOL; echo 'VehicleNumber:'.$row['VehicleNumber'].', 告警类型: 过车告警'.PHP_EOL; //记录本次过车告警时间 S('latest_pass_alarm_time_'.$row['VehicleNumber'], $cur_time); } $this->rchy_alarm_list->push(json_encode($alarm_info)); echo '添加告警成功, VehicleNumber:'.$row['VehicleNumber'].', AlarmType: '.$alarm_info['AlarmType'].PHP_EOL; //echo 'alarm_info: '.json_encode($alarm_info).PHP_EOL; } } private function updateRfidTime( $result ){ foreach($result['VehicleList'] as $key => $row){ $row['StationCode'] = $result['StationCode']; if(!$row['VehicleNumber']){ //echo 'VehicleNumber not existed, VehicleNumber: '.$row['VehicleNumber'].PHP_EOL; continue; } //检查车主标签是否有效,无效跳过,有效的更新上报信息 $vehicle_info = \Rchy\Cache\RedisCache::getCheZhuInfo($row['VehicleNumber']); if(!$vehicle_info){ continue; } echo 'CheZhuRfid = '.$row['VehicleNumber'].', rssi = '.$row['rssi'].', time:'.date('Y-m-d H:i:s',$row['Timestamp']).PHP_EOL; //如果基站时间不准确,用服务器时间 if($row['Timestamp'] < time()-3600){ $row['Timestamp'] = time(); } //获取最近一段时间内所有rssi,求均值 $avgRssi = $this->getAvgRssi($row); if($avgRssi === false){ echo 'getAvgRssi failed! CheZhuRfid = '.$row['VehicleNumber'].PHP_EOL; continue; } //检查车主标签rssi,过滤掉弱信号 if ($avgRssi > C('rcgjfw.车主标签_rssi阀值')){ echo 'avgRssi > '.C('rcgjfw.车主标签_rssi阀值').', avgRssi = '.$avgRssi.', CheZhuRfid = '.$row['VehicleNumber'].PHP_EOL; continue; } echo 'avgRssi = '.$avgRssi.', CheZhuRfid = '.$row['VehicleNumber'].PHP_EOL; $info = array( 'Timestamp' => $row['Timestamp'], 'StationCode' => $row['StationCode'], 'Rssi' => $row['rssi'] ); //更新车主RFID上报信息 S('last_chezhu_rfid_'.$row['VehicleNumber'], $info, 60*60*24); //echo 'last_chezhu_rfid_'.$row['VehicleNumber'] .PHP_EOL; //var_dump(S('last_chezhu_rfid_'.$row['VehicleNumber'])); //echo '更新车主标签上报信息成功,CheZhuRfid: '.$row['VehicleNumber'].', 上报时间:'.date('Y-m-d H:i:s',$row['Timestamp']).', rssi: '.$row['rssi'].PHP_EOL; } } private function checkVehicleStatus( $chezhu_rfid, $row ){ if(!$chezhu_rfid){ echo 'checkVehicleStatus failed, chezhu_rfid is empty!'.PHP_EOL; return false; } if(!$row){ echo 'checkVehicleStatus failed, row is empty!'.PHP_EOL; return false; } //获取车辆已授权车主标签 $all_rfids = \Rchy\Cache\RedisCache::getVehicleAuthors($row['VehicleNumber']); if(!$all_rfids){ $all_rfids = array(); } //加入车主标签 if(!in_array($chezhu_rfid,$all_rfids)){ array_push($all_rfids,$chezhu_rfid); } $is_stolen = true; foreach ($all_rfids as $rfid){ //获取授权车主标签上报信息 $last_rfid_info = S('last_chezhu_rfid_'.$rfid); //var_dump($last_rfid_info); $last_rfid_time = $last_rfid_info['Timestamp']; $rfid_pass_station = $last_rfid_info['StationCode']; echo 'chezhu_rfid = '.$rfid.', now = '.$row['Timestamp'].', last_rfid_time = '.$last_rfid_time.', rfid_pass_station = '. $rfid_pass_station . PHP_EOL; //车辆和授权车主同时出现在同一个小区门口,则认为是过车告警 if ( $last_rfid_time && abs($row['Timestamp']-$last_rfid_time) < C('rcgjfw.人车标签_允许的最大时间差') && $rfid_pass_station == $row['StationCode']){ $is_stolen = false; break; } } echo 'all_rfids:'.PHP_EOL; var_dump($all_rfids); return $is_stolen; } private function checkVehicleDirection( $vehicle_no, $now ){ //开发中。。。 return false; if(!$vehicle_no){ echo 'checkVehicleDirection failed, vehicle_no is empty!'.PHP_EOL; return false; } if(!$now){ echo 'checkVehicleDirection failed, now is empty!'.PHP_EOL; return false; } //获取最近一段时间内的信号 $cond = array($now-60,$now); $signal_list = $this->redis_vsignal->table($vehicle_no)->where($cond)->select(); //查询结果默认是按时间升序,这里翻转一下 $signal_list = array_reverse($signal_list); if(!$signal_list){ echo 'checkVehicleDirection failed,signal_list is empty!'.PHP_EOL; return false; } //最后一个信号点所在的基站 $last_station = $signal_list[0]['StationCode']; if(!$last_station){ echo 'checkVehicleDirection failed,last_station is empty!'.PHP_EOL; return false; } //获取一段时间内同一基站连续的几个信号强度点 $rssi_list = array(); foreach($signal_list as $key=>$row){ $signal = json_decode($key,true); if(!$signal){ echo 'json_decode error'.PHP_EOL; return false; } if($last_station != $signal['StationCode']){ echo 'is not the last_station rssi,stop push! last_station = '.$last_station.', cur_station = '.$signal['StationCode'].PHP_EOL; break; } $rssi_list[] = $signal['rssi']; } if( count($rssi_list)<3 ){ echo 'checkVehicleDirection failed,count($rssi_list)<3 !! count($rssi_list) = '.count($rssi_list).PHP_EOL; return false; } //<信号一直递增或者一直递减的,车辆方向暂时不好判断> //判断车辆rssi信号强度是否递减(此时,时间是降序) $is_rssi_decrease = $this->isRssiDecrease($rssi_list, count($rssi_list)); if($is_rssi_decrease){ echo '检测到车辆rssi信号强度递增,车辆正在靠近基站!StationCode = '.$last_station.PHP_EOL; return false; } //如果rssi先逐渐增强,后逐渐减弱,且峰值右侧第一个信号大于峰值左侧第一个信号,则认为是进入小区 //如果rssi先逐渐增强,后逐渐减弱,且峰值右侧第一个信号小于峰值左侧第一个信号,则认为是走出小区 echo '判断不出车辆运动方向!VehicleNumber = '. $vehicle_no .PHP_EOL; return false; } private function isRssiDecrease( $arr, $len ){ if ($len == 1) return true; return ($arr[$len - 2] >= $arr[$len - 1]) && $this->isRssiDecrease($arr, $len-1); } private function isRssiDrab( $arr, $len ){ if(!$arr){ echo 'isRssiDrab failed, arr is empty!!'.PHP_EOL; return false; } if(!$len){ echo 'isRssiDrab failed, len is empty!!'.PHP_EOL; return false; } if($this->isRssiIncrease($arr, $len)){ echo 'rssi increase'.PHP_EOL; return true; } if($this->isRssiDecrease($arr, $len)){ echo 'rssi decrease'.PHP_EOL; return true; } echo 'rssi is not drab '.PHP_EOL; return false; } private function isRssiIncrease( $arr, $len ){ if ($len == 1) return true; return ($arr[$len - 2] <= $arr[$len - 1]) && $this->isRssiIncrease($arr, $len-1); } private function getAvgRssi( $data ){ $rfid = $data['VehicleNumber']; if(!$rfid){ echo 'getAvgRssi failed ,VehicleNumber not existed!'.PHP_EOL; return false; } $station_code = $data['StationCode']; if(!$station_code){ echo 'getAvgRssi failed ,StationCode not existed!'.PHP_EOL; return false; } $key = $station_code.'_'.$rfid; //添加新车辆轨迹点 $route_point = array('Rfid'=>$rfid,'Time'=>$data['Timestamp'],'Rssi'=>$data['rssi']); $signal_data = array(json_encode($route_point) => $data['Timestamp']); $this->redis_vsignal->table($key)->add($signal_data); //查询时间窗内,所有rssi $interval = C('rcgjfw.信号均值_采集时间窗'); if(!$interval){ $interval = 4; } $start = $data['Timestamp']-$interval; $where = array( $start,$data['Timestamp']); $list = $this->redis_vsignal->table($key)->where($where)->select(); //计算平均值 $sum = 0; $count = 0; $info = array(); foreach($list as $signal => $time){ $signal = json_decode($signal,true); $sum += $signal['Rssi']; $count++; $info[$time] = $signal['Rssi']; } echo 'key:'.$key.', rssi_pool:'.json_encode($info).PHP_EOL; if(!$count){ echo 'getAvgRssi failed ,rssi_pool empty!'.PHP_EOL; return false; } $avgRssi = round($sum/$count); echo 'rfid: '.$rfid.', station_code: '.$station_code.', avgRssi = '.$avgRssi.PHP_EOL; return $avgRssi; } }