diff --git a/app/Admin/Controllers/DeviceController.php b/app/Admin/Controllers/DeviceController.php index 8d50696..4540edf 100644 --- a/app/Admin/Controllers/DeviceController.php +++ b/app/Admin/Controllers/DeviceController.php @@ -2,7 +2,7 @@ namespace App\Admin\Controllers; -use Slowlyo\OwlAdmin\Renderers\{Button, Form, Page, TableColumn, TextControl, Json, Component, CRUDTable, Card, Video, DateRangeControl, Mapping}; +use Slowlyo\OwlAdmin\Renderers\{Button, Form, Page, TableColumn, TextControl, Json, Component, CRUDTable, Card, Video, InputDatetimeRange, DateTimeControl, Mapping, SelectControl}; use Slowlyo\OwlAdmin\Controllers\AdminController; use App\Services\Admin\DeviceService; use App\Admin\Components; @@ -152,7 +152,7 @@ class DeviceController extends AdminController ->headerToolbar([]) ->filter($this->baseFilter()->actions([])->body([ amisMake()->SelectControl('monitor_mode', '点位名称')->size('md')->options($query->toArray())->selectFirst(true), - DateRangeControl::make()->name('date')->label('日期')->maxDate('now')->size('md'), + InputDatetimeRange::make()->name('date')->label('日期')->maxDate('now')->size('md'), Button::make()->label(__('admin.reset'))->actionType('clear-and-submit'), Component::make()->setType('submit')->label(__('admin.search'))->level('primary'), ])) diff --git a/app/Console/Commands/DeviceLogSyncCommand.php b/app/Console/Commands/DeviceLogSyncCommand.php index 8a900ea..02bc61c 100644 --- a/app/Console/Commands/DeviceLogSyncCommand.php +++ b/app/Console/Commands/DeviceLogSyncCommand.php @@ -5,7 +5,6 @@ namespace App\Console\Commands; use App\Models\Device; use App\Services\DeviceLogService; use Illuminate\Console\Command; -use Illuminate\Support\Carbon; use Throwable; class DeviceLogSyncCommand extends Command @@ -64,7 +63,13 @@ class DeviceLogSyncCommand extends Command /** @var \Illuminate\Database\Eloquent\Collection */ $devices = Device::with(['factory'])->poweredBy($factory)->get(); + /** @var \App\Models\Device */ foreach ($devices as $device) { + // 忽略通风设备 + if ($device->isTypeAir()) { + continue; + } + $this->info('=========================================='); $this->info('设备编号: ' . $device->sn); $this->info('设备名称: ' . $device->name); diff --git a/app/Http/Controllers/Callback/LinkosCallbackController.php b/app/Http/Controllers/Callback/LinkosCallbackController.php index 1ccabcf..d3d2938 100644 --- a/app/Http/Controllers/Callback/LinkosCallbackController.php +++ b/app/Http/Controllers/Callback/LinkosCallbackController.php @@ -10,7 +10,7 @@ class LinkosCallbackController extends Controller { public function __invoke(Request $request) { - logger()->info('linkos callback parameters -------->', $request->input()); + logger()->debug('linkos callback parameters -------->', $request->input()); if ($request->filled('notify_type')) { switch ($request->notify_type) { diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 359e510..d05436b 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -7,7 +7,7 @@ use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Validation\ValidatesRequests; use Illuminate\Routing\Controller as BaseController; use Illuminate\Pagination\LengthAwarePaginator; -use Illuminate\Http\Resources\Json\ResourceCollection ; +use Illuminate\Http\Resources\Json\ResourceCollection; use Illuminate\Support\Arr; class Controller extends BaseController @@ -16,7 +16,7 @@ class Controller extends BaseController public function json($data, $code = 0, $message = '') { - if ($data instanceof ResourceCollection ) { + if ($data instanceof ResourceCollection) { $data = $data->resource; } $result = ['data' => $data ?: '', 'status' => $code, 'msg' => $message]; diff --git a/app/Iot/Linkos/HttpClient.php b/app/Iot/Linkos/HttpClient.php index 1b01273..7900a4e 100644 --- a/app/Iot/Linkos/HttpClient.php +++ b/app/Iot/Linkos/HttpClient.php @@ -26,7 +26,7 @@ class HttpClient * @param int $perPage * @return array */ - public function getDeviceFlowList(string $deviceId, Carbon $start, Carbon $end, int $page = 1, int $perPage = 50): array + public function deviceFlowList(string $deviceId, Carbon $start, Carbon $end, int $page = 1, int $perPage = 50): array { $result = $this->post('/api/deviceFlow/v1/list', [ 'device_id' => $deviceId, @@ -38,9 +38,60 @@ class HttpClient ], ]); + if (data_get($result, 'success') !== true) { + throw new RuntimeException(data_get($result, 'msg', '出错啦!')); + } + return $result['data']; } + /** + * 设备数据下行 + * + * @param string $deviceId + * @param string $service + * @param array $data + * @param boolean $confirm + * @param boolean $clear + * @param boolean $schedule + * @return array + */ + public function deviceDataDownlink(string $deviceId, string $service, array $data = [], bool $confirm = true, bool $clear = true, bool $schedule = false): array + { + return $this->post('/api/down', [ + 'device_id' => $deviceId, + 'service_id' => $service, + 'parameter' => $data, + 'clear' => (int) $clear, + 'schedule' => (int) $schedule, + 'confirm' => (int) $confirm, + ]); + } + + /** + * 获取设备最新属性数据 + */ + public function getDeviceStatus(string $deviceId, array $props): array + { + $result = $this->get('/api/deviceStatus/v1/getDeviceStatus', [ + 'deviceCode' => $deviceId, + 'prop' => implode(",", $props), + ]); + + if (data_get($result, 'success') !== true) { + throw new RuntimeException(data_get($result, 'msg', '出错啦!')); + } + + return $result['data']; + } + + public function get(string $url, array $query = []): array + { + return $this->request('GET', $url, [ + 'query' => $query, + ]); + } + /** * @param string $url * @param array $data @@ -77,13 +128,7 @@ class HttpClient 'Signature' => $this->sign(compact('nonce', 'timestamp')), ])->baseUrl(self::ENDPOINT_URL)->send($method, $url, $options); - $result = $response->throw()->json(); - - if (data_get($result, 'success') !== true) { - throw new RuntimeException(data_get($result, 'msg', '出错啦!')); - } - - return $result; + return $response->throw()->json(); } /** diff --git a/app/Models/Device.php b/app/Models/Device.php index 0afe60b..4ed8252 100644 --- a/app/Models/Device.php +++ b/app/Models/Device.php @@ -87,4 +87,9 @@ class Device extends Model { return $this->type === static::TYPE_METEOROLOGICAL; } + + public function isTypeAir(): bool + { + return $this->type === static::TYPE_AIR; + } } diff --git a/app/Services/Admin/DeviceService.php b/app/Services/Admin/DeviceService.php index f13b16c..8d4cd0b 100644 --- a/app/Services/Admin/DeviceService.php +++ b/app/Services/Admin/DeviceService.php @@ -36,9 +36,11 @@ class DeviceService extends BaseService $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) { - $url .= '?start=' . date('Y-m-d', $start) . '&end=' . data('Y-m-d', $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); } @@ -276,75 +278,75 @@ class DeviceService extends BaseService public function meteorologicalControAir(Device $device, MeteorologicalReport $log, Carbon $reportedAt) { - if($log->wasChanged('box_temperature') || $log->wasChanged('box_humidity')){//如果温度或者湿度发生变化; + //如果温度或者湿度发生变化; + 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(); - } - //获取当前设备关联监测点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(); - $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(); - //遍历地点,是否有通风设备; - foreach($regions as $region){ - $monitorModes = $region->monitorModes()->where('type', MonitorMode::TYPE_AIR)->get(); - foreach($monitorModes as $monitor){ - $_device = $monitor->devices()->first(); - $config = $_device?->extends ?? []; + $config = $_device?->extends ?? []; - $fieldNameMap = MonitorMode::fieldMap(Device::TYPE_METEOROLOGICAL); - $fieldUnitMap = MonitorMode::fieldUnitMap(Device::TYPE_METEOROLOGICAL); + $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'] && !$this->getAirStatus($device)){//如果判定成功,且设备当前是关闭状态 - $msg = ''; - $column = $res['keys'][0]; - if(strpos($column, ',')){//看是否是并联条件 - $_columns = explode(',',$column); - foreach($_columns as $cc){ - $msg.= $fieldNameMap[$cc].'达到'.$log->$cc.$fieldUnitMap[$cc].'值,且'; + $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].'值'; } - - $msg = mb_substr($msg, 0, -2); - }else{ - $msg = $fieldNameMap[$column].'达到'.$log->$column.$fieldUnitMap[$column].'值'; + $this->openAir($_device, $msg); } - $this->openAir($device, $msg); } - } - if($config && $config['close_is_enable'] ){ - $rule = $config['close_config']; - $res = $this->verifyRule($rule, $log); - - if($res['status'] && !$this->getAirStatus($device)){//如果判定成功,且设备当前是关闭状态 - $msg = ''; - $column = $res['keys'][0]; - if(strpos($column, ',')){//看是否是并联条件 - $_columns = explode(',',$column); - foreach($_columns as $cc){ - $msg.= $fieldNameMap[$cc].'达到'.$log->$cc.$fieldUnitMap[$cc].'值,且'; + 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].'值'; } - - $msg = mb_substr($msg, 0, -2); - }else{ - $msg = $fieldNameMap[$column].'达到'.$log->$column.$fieldUnitMap[$column].'值'; + $this->closeAir($_device, $msg); } - $this->closeAir($device, $msg); } } } } - - //开关控制; } + public function verifyRule($rule, $log) { $res = [ @@ -370,7 +372,7 @@ class DeviceService extends BaseService $_keys = []; foreach($rule['children'] as $child){ $cRes = $this->verifyRule($child, $log); - if($cRes){ + if($cRes && $cRes['status']){ $_keys = array_merge($_keys, $cRes['keys']); continue; }else{ @@ -421,7 +423,16 @@ class DeviceService extends BaseService */ public function getAirStatus(Device $device) { - dd(app(HttpClient::class)->getDeviceStatus($device->sn, ["switch_state"])); + 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; } @@ -441,7 +452,7 @@ class DeviceService extends BaseService ]); //编号,-todo // $httpClient = app(HttpClient::class); - // dd($httpClient->deviceDataDownlink($device->sn, 'switch_control', ['switch_state' => 0])); + // dd($httpClient->deviceDataDownlink($device->sn, 'switch_control', ['switch_state' => 1])); return ; } @@ -458,10 +469,9 @@ class DeviceService extends BaseService 'type' => 2, 'content' => $msg, ]); - dd('关闭通风'); //编号, // $httpClient = app(HttpClient::class); - // dd($httpClient->deviceDataDownlink($device->sn, 'switch_control', ['switch_state' => 1])); + // dd($httpClient->deviceDataDownlink($device->sn, 'switch_control', ['switch_state' => 0])); return ; } } diff --git a/app/Services/DeviceLogService.php b/app/Services/DeviceLogService.php index 876eb92..fdb2c28 100644 --- a/app/Services/DeviceLogService.php +++ b/app/Services/DeviceLogService.php @@ -41,7 +41,7 @@ class DeviceLogService $perPage = 50; do { - $data = $httpClient->getDeviceFlowList( + $data = $httpClient->deviceFlowList( $device->sn, $start, $end, $page, $perPage ); @@ -56,74 +56,25 @@ class DeviceLogService continue; } - if ($device->isTypeSoil()) { - // 如果包含气象设备监测字段,则跳过 - if (Arr::hasAny($item['data'], [ - 'day_rainfall', - 'accumulate_rainfall', - 'potassium_content', - 'moment_rainfall', - 'pm10_concentration', - 'pm25_concentration', - 'box_noise', - 'box_carbon', - 'box_humidity', - 'box_pressure', - 'box_temperature', - 'box_illumination', - 'wind_power', - 'wind_speed', - 'wind_degree', - 'wind_direction', - ])) { - continue; - } - } elseif ($device->isTypeMeteorological()) { - // 如果包含土壤设备监测字段,则跳过 - if (Arr::hasAny($item['data'], [ - 'nitrogen_content', - 'phosphorus_content', - 'potassium_content', - 'conductivity', - 'soil_humidity', - 'soil_temperature', - ])) { - continue; - } - } - - if ( - $device->isTypeSoil() && Arr::hasAny($item['data'], [ - - ]) - ) { - - } elseif ( - $device->isTypeMeteorological() && - Arr::hasAny( - $item['data'], - [ - 'nitrogen_content', - 'phosphorus_content', - 'potassium_content', - 'conductivity', - 'soil_humidity', - 'soil_temperature', - ] - ) - ) { - continue; - } - - $isSoilMonitoring = Arr::hasAny($item['data'], [ - 'soil_humidity', - 'soil_temperature', - 'nitrogen_content', - 'potassium_content', - 'phosphorus_content', - ]); - - if (($device->isTypeSoil() && ! $isSoilMonitoring) || (! $device->isTypeSoil() && $isSoilMonitoring)) { + // 如果多合一气象监测器包含土壤监控时,需过滤掉气象监控的数据 + if ($device->isTypeSoil() && Arr::hasAny($item['data'], [ + 'current_rainfall', + 'day_rainfall', + 'accumulate_rainfall', + 'moment_rainfall', + 'pm10_concentration', + 'pm25_concentration', + 'box_illumination', + 'box_pressure', + 'box_carbon', + 'box_temperature', + 'box_humidity', + 'box_noise', + 'wind_degree', + 'wind_direction', + 'wind_power', + 'wind_speed', + ])) { continue; } @@ -498,6 +449,10 @@ class DeviceLogService switch ($key) { case 'wind_samples': $attributes['wind_degree'] = value(function (array $windSamples) { + if (empty($windSamples)) { + return null; + } + $x = 0; $y = 0; @@ -527,6 +482,10 @@ class DeviceLogService }, $item); $attributes['wind_direction'] = value(function ($windDegree) { + if (is_null($windDegree)) { + return null; + } + if ($windDegree >= 22.5 && $windDegree < 67.5) { return MeteorologicalDailyReport::WIND_DIRECTION_NORTHEAST; } elseif ($windDegree >= 67.5 && $windDegree < 112.5) {