listQuery(); $items = (clone $query)->paginate(request()->input('perPage', 20))->items(); $base = settings()->get('rtsp_url'); if (request('_type') == Device::TYPE_MONITOR) { $history = request('_mode') === 'history'; $date = explode(',', request('date')); $start = data_get($date, 0); $end = data_get($date, 1); foreach ($items as &$item) { $url = data_get($item->extends, $history ? 'rtsp_history' : 'rtsp_url'); $src = null; if ($base && $url) { // 查看历史监控 &starttime=2023_02_02_14_00_00&endtime=2023_02_02_15_00_00 if ($history && $start && $end) { $start_format = Carbon::createFromTimestamp($start)->format('Y_m_d_H_i_s'); $end_format = Carbon::createFromTimestamp($end)->format('Y_m_d_H_i_s'); $url .= (str_contains($url, '?') ? '&' : '?') .'starttime=' . $start_format . '&endtime=' . $end_format; } $src = $base . base64_encode($url); } $item->src = $src; } } $total = (clone $query)->count(); return compact('items', 'total'); } /** * 根据时间,处理X轴横坐标 */ public function makeChartXkeys($startTime = null, $endTime = null){ $diffDays = 0; $day = date('Y-m-d'); $xKeys = []; if($startTime && $endTime){ $startDay = Carbon::parse($startTime); $endDay = Carbon::parse($endTime); if($startDay->format('Y-m-d') == $endDay->format('Y-m-d')){//判断是否同一天 $day = $startDay->format('Y-m-d'); }else{ $diffDays = $startDay->diffInDays($endDay, false); } } $xKeys = []; if($diffDays){ for ($i = 0; $i<=$diffDays; $i++) { $xKeys[] =(clone $startDay)->addDays($i)->startOfDay()->format('Y-m-d'); } }else{ //调整截至到当前小时 $th = $startDay->format('H'); $eh = $endDay->format('H');; if($day == date('Y-m-d')){ if($eh > date('H')){ $eh = date('H'); } } for ($i = $th; $i < ($eh+1); $i++) { $xKeys[] = str_pad($i, 2, '0', STR_PAD_LEFT).':00'; } } return array($day, $diffDays, $xKeys); } public function getMonitorModeDeviceChartConfig($monitorMode, $startTime, $endTime, $columnNum = 3) { list($day, $diffDays, $xKeys) = $this->makeChartXkeys($startTime, $endTime); switch($monitorMode->type){ case MonitorMode::TYPE_METEOROLOGICAL: $dayliyReportQuery = MeteorologicalDailyReport::query(); $reportQuery = MeteorologicalReport::query(); $fieldNameMap = MonitorMode::fieldMap(MonitorMode::TYPE_METEOROLOGICAL); $fieldUnitMap = MonitorMode::fieldUnitMap(MonitorMode::TYPE_METEOROLOGICAL); break; case MonitorMode::TYPE_SOIL: $dayliyReportQuery = SoilDailyReport::query(); $reportQuery = SoilReport::query(); $fieldNameMap = MonitorMode::fieldMap(MonitorMode::TYPE_SOIL); $fieldUnitMap = MonitorMode::fieldUnitMap(MonitorMode::TYPE_SOIL); break; } $monitorMode->load('devices'); $configData = $fieldMap = []; foreach($monitorMode->devices as $device){ $_fields = explode(',', $device->pivot->fields); if($diffDays) { $modelQuery = $dayliyReportQuery->whereBetween('reported_at', [$startTime, $endTime]); }else{ $modelQuery = $reportQuery->whereDate('reported_at', $day); } if($modelQuery){ $datalist = $modelQuery->where('device_id', $device->id)->get()->keyBy('reported_at')->toArray(); } //组装数据; foreach($_fields as $field){ $_data = []; foreach($xKeys as $key){ if(!$diffDays) { $key = date('Y-m-d').' '. $key.':00'; }else{ $key .= ' 00:00:00'; } $_data[] = $datalist[$key][$field] ?? 0; } $fieldMap[$field] = [ 'name' => $fieldNameMap[$field], 'unit' => $fieldUnitMap[$field], 'data' => $_data ]; } } $k = 0; $chartArr = []; foreach($fieldMap as $key => $field){ $k++; //特殊字段,特殊统计图; switch($key){ //点状图; case 'wind_direction': $yData = ['北风','东北风','东风','东南风','南风','西南风','西风','西北风']; $_chartCard = amisMake()->Card()->body( amisMake()->Chart()->config( Components::make()->chartScatterConfig($field['name'], $xKeys, [ 'name'=> $field['name'], 'type' => 'scatter', 'symbolSize' => 15, 'data' => array_map(function($item)use($yData){ return $yData[$item]; },$field['data']), 'color' => '#91CC75', ], $yData ) ) ); break; //柱状图; case 'box_noise': case 'pm10': case 'pm25': case 'box_co2': $_chartCard = amisMake()->Card()->body( amisMake()->Chart()->config( Components::make()->chartLineBarConfig($field['name'], $xKeys, [ [ 'name'=> $field['name'], 'type' => 'bar', 'data' => $field['data'], 'color' => '#91CC75', 'unit' => $field['unit'] ] ]) ) ); break; default://折线图 $_chartCard = amisMake()->Card()->body( amisMake()->Chart()->config( Components::make()->chartLineBarConfig($field['name'], $xKeys, [ [ 'name'=> $field['name'], 'type' => 'line', 'data' => $field['data'], 'color' => '#91CC75', 'unit' => $field['unit'] ] ]) ) ); break; } if($k%$columnNum != 0){ $_chartCard->className('m-r'); } $chartArr[] = $_chartCard; } $i = 0; $len = round(count($chartArr)/$columnNum); for($i; $i<=$len; $i++){ $configData[] = \amisMake()->grid()->columns([ amisMake()->Flex()->items(array_splice($chartArr, 0, $columnNum)), ]); } return $configData; } public function getMonitorModeDeviceData($monitorMode, $startTime, $endTime) { list($day, $diffDays, $xKeys) = $this->makeChartXkeys($startTime, $endTime); switch($monitorMode->type){ case MonitorMode::TYPE_METEOROLOGICAL: $dayliyReportQuery = MeteorologicalDailyReport::query(); $reportQuery = MeteorologicalReport::query(); $fieldNameMap = MonitorMode::fieldMap(MonitorMode::TYPE_METEOROLOGICAL); $fieldUnitMap = MonitorMode::fieldUnitMap(MonitorMode::TYPE_METEOROLOGICAL); break; case MonitorMode::TYPE_SOIL: $dayliyReportQuery = SoilDailyReport::query(); $reportQuery = SoilReport::query(); $fieldNameMap = MonitorMode::fieldMap(MonitorMode::TYPE_SOIL); $fieldUnitMap = MonitorMode::fieldUnitMap(MonitorMode::TYPE_SOIL); break; } $monitorMode->load('devices'); $fieldMap = []; foreach($monitorMode->devices as $device){ $_fields = explode(',', $device->pivot->fields); if($diffDays) { $modelQuery = $dayliyReportQuery->whereBetween('reported_at', [$startTime, $endTime]); }else{ $modelQuery = $reportQuery->whereDate('reported_at', $day); } if($modelQuery){ $datalist = $modelQuery->where('device_id', $device->id)->get()->keyBy('reported_at')->toArray(); } //组装数据; foreach($_fields as $field){ $_data = []; foreach($xKeys as $key){ if(!$diffDays) { $key = date('Y-m-d').' '. $key.':00'; }else{ $key .= ' 00:00:00'; } $_data[] = $datalist[$key][$field] ?? 0; } $fieldMap[$field] = [ 'name' => $fieldNameMap[$field], 'unit' => $fieldUnitMap[$field], 'data' => $_data, 'xkeys'=> $xKeys ]; } } return $fieldMap; } public function meteorologicalControAir(Device $device, MeteorologicalReport $log, Carbon $reportedAt) { //如果温度或者湿度发生变化; if($log->wasChanged('box_temperature') || $log->wasChanged('box_humidity')){ //获取当前设备关联监测点IDs; $monitorIds = MonitorDevice::where('device_id', $device->id)->pluck('monitor_id')->toArray(); $regionIds = RegionMonitor::where('monitor_id', $monitorIds)->pluck('region_id')->toArray(); $regions = Region::whereIn('id', $regionIds)->whereHas('monitorModes', function($q){ return $q->where('type', MonitorMode::TYPE_AIR); })->get(); //遍历地点,是否有通风设备; foreach($regions as $region){ $monitorModes = $region->monitorModes()->where('type', MonitorMode::TYPE_AIR)->get(); foreach($monitorModes as $monitor){ $_device = $monitor->devices()->where('type', Device::TYPE_AIR)->first(); $config = $_device?->extends ?? []; $fieldNameMap = MonitorMode::fieldMap(Device::TYPE_METEOROLOGICAL); $fieldUnitMap = MonitorMode::fieldUnitMap(Device::TYPE_METEOROLOGICAL); $airState = $this->getAirStatus($_device); //开启了自动开启配置 if($config && $config['open_is_enable'] ){ $rule = $config['open_config']; $res = $this->verifyRule($rule, $log); if($res['status'] && !$airState){//如果判定成功,且设备当前是关闭状态 $msg = ''; $column = $res['keys'][0]; if(strpos($column, ',')){//看是否是并联条件 $_columns = explode(',',$column); foreach($_columns as $cc){ $msg.= $fieldNameMap[$cc].'达到'.$log->$cc.$fieldUnitMap[$cc].'值,且'; } $msg = mb_substr($msg, 0, -2); }else{ $msg = $fieldNameMap[$column].'达到'.$log->$column.$fieldUnitMap[$column].'值'; } $this->openAir($_device, $msg); } } if($config && $config['close_is_enable'] ){ $rule = $config['close_config']; $res = $this->verifyRule($rule, $log); if($res['status'] && $airState){//如果判定成功,且设备当前是开启状态 $msg = ''; $column = $res['keys'][0]; if(strpos($column, ',')){//看是否是并联条件 $_columns = explode(',',$column); foreach($_columns as $cc){ $msg.= $fieldNameMap[$cc].'达到'.$log->$cc.$fieldUnitMap[$cc].'值,且'; } $msg = mb_substr($msg, 0, -2); }else{ $msg = $fieldNameMap[$column].'达到'.$log->$column.$fieldUnitMap[$column].'值'; } $this->closeAir($_device, $msg); } } } } } } public function verifyRule($rule, $log) { $res = [ 'status' => false, 'keys' => [] ]; if(isset($rule['conjunction'])){//多条件 switch($rule['conjunction']){ case 'or': if(isset($rule['children'])){ foreach($rule['children'] as $child){ $cRes = $this->verifyRule($child, $log); if($cRes && $cRes['status']){ $res['status'] = true; $res['keys'] = array_merge($res['keys'], $cRes['keys']); return $res; } } } break; case 'and': if(isset($rule['children'])){ $_keys = []; foreach($rule['children'] as $child){ $cRes = $this->verifyRule($child, $log); if($cRes && $cRes['status']){ $_keys = array_merge($_keys, $cRes['keys']); continue; }else{ $res['status'] = false; return $res; } } $res['status'] = true; $res['keys'][] = implode(',', $_keys); } break; } }else{//单条件 $key = $rule['left']['field'] ?? ''; $value = $log->$key ?? null; switch($rule['op']){ case 'less': break; if($value < $rule['right']){ $res['status'] = true; $res['keys'][] = $key; } case 'less_or_equal': if($value <= $rule['right']){ $res['status'] = true; $res['keys'][] = $key; } break; case 'greater': if($value > $rule['right']){ $res['status'] = true; $res['keys'][] = $key; } break; case 'greater_or_equal': if($value >= $rule['right']){ $res['status'] = true; $res['keys'][] = $key; } break; } } return $res; } /** * 获取通风设备当前状态 */ public function getAirStatus(Device $device) { if($device->type != Device::TYPE_AIR){ return false; } $res = app(HttpClient::class)->getDeviceStatus($device->sn, ["switch_state"]); if($res && isset($res[0])){ if($res[0]['value'] == 1){ return true; } } return false; } /** * 开启通风设备 */ public function openAir(Device $device, string $msg) { if($device->type != Device::TYPE_AIR){ return ; } //记录触发日志 AirLog::create([ 'device_id' => $device->id, 'type' => 1, 'content' => $msg, ]); //编号,-todo // $httpClient = app(HttpClient::class); // dd($httpClient->deviceDataDownlink($device->sn, 'switch_control', ['switch_state' => 1])); return ; } /** * 关闭通风设备 */ public function closeAir(Device $device, string $msg) { if($device->type != Device::TYPE_AIR){ return ; } AirLog::create([ 'device_id' => $device->id, 'type' => 2, 'content' => $msg, ]); //编号, // $httpClient = app(HttpClient::class); // dd($httpClient->deviceDataDownlink($device->sn, 'switch_control', ['switch_state' => 0])); return ; } }