Compare commits
44 Commits
f95a64535c
...
a81c6e0e64
| Author | SHA1 | Date |
|---|---|---|
|
|
a81c6e0e64 | |
|
|
a557c1c1ab | |
|
|
5fd786e6a6 | |
|
|
6cbb8c0336 | |
|
|
2cbf5314a5 | |
|
|
7137b11950 | |
|
|
d700385a1c | |
|
|
a73ba36aa9 | |
|
|
8cdf72150d | |
|
|
8bbe097382 | |
|
|
4358858f1f | |
|
|
261997d651 | |
|
|
74fc14fd90 | |
|
|
01a057bfc8 | |
|
|
a037f82a5f | |
|
|
a723e40d25 | |
|
|
b8dc7bb497 | |
|
|
bbe315f9df | |
|
|
fe42931606 | |
|
|
644b37da28 | |
|
|
c8ae7e78a9 | |
|
|
f365898601 | |
|
|
d6f424a38a | |
|
|
375d230460 | |
|
|
cd9a6bc3d0 | |
|
|
61dc022054 | |
|
|
83281649fb | |
|
|
84bb61ec7c | |
|
|
ffc2155e3f | |
|
|
97f3f89631 | |
|
|
550ea41ab7 | |
|
|
5c28b8c093 | |
|
|
f491a1bf84 | |
|
|
943099a5d3 | |
|
|
9c037037c6 | |
|
|
317622f0fc | |
|
|
31f0c0a88b | |
|
|
49df94fd0b | |
|
|
72a0b03412 | |
|
|
56226b84a6 | |
|
|
72f056cf04 | |
|
|
6e8b53e50d | |
|
|
7715f5213c | |
|
|
d304f30a52 |
|
|
@ -1,17 +1,16 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
namespace App\Console\Commands\BiAng;
|
||||
|
||||
use App\Enums\DeviceType;
|
||||
use App\Models\Device;
|
||||
use App\Models\InsecticidalLampDailyReport;
|
||||
use App\Models\InsecticidalLampReport;
|
||||
use App\Models\MeteorologicalMonitoringDailyLog;
|
||||
use App\Models\MeteorologicalMonitoringLog;
|
||||
use App\Models\SoilMonitoringDailyLog;
|
||||
use App\Models\SoilMonitoringLog;
|
||||
use App\Models\WaterQualityMonitoringDailyLog;
|
||||
use App\Models\WaterQualityMonitoringLog;
|
||||
use App\Services\BiAngDeviceLogService;
|
||||
use App\Services\DeviceLogService;
|
||||
use App\Services\BiAngDeviceService;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class DeviceLogDailyReportCommand extends Command
|
||||
|
|
@ -21,8 +20,7 @@ class DeviceLogDailyReportCommand extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'device-log:daily-report
|
||||
{factory}
|
||||
protected $signature = 'biang:device-log-daily-report
|
||||
{--sleep=300 : 监控报告生产后的休眠时间(秒)}';
|
||||
|
||||
/**
|
||||
|
|
@ -42,30 +40,21 @@ class DeviceLogDailyReportCommand extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
$factory = $this->argument('factory');
|
||||
|
||||
$sleep = (int) value(fn ($sleep) => is_numeric($sleep) ? $sleep : 300, $this->option('sleep'));
|
||||
|
||||
while (true) {
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$devices = Device::with(['supplier'])->supplierBy("device-supplier-{$factory}")->get();
|
||||
$devices = Device::supplierBy("device-supplier-biang")->get();
|
||||
|
||||
foreach ($devices as $device) {
|
||||
switch ($device->supplier?->key) {
|
||||
case 'device-supplier-biang':
|
||||
$this->createReportToBiAngDevice($device);
|
||||
break;
|
||||
}
|
||||
$this->createReport($device);
|
||||
}
|
||||
|
||||
sleep($sleep);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 linkos 设备报告
|
||||
*/
|
||||
protected function createReportToBiAngDevice(Device $device): void
|
||||
protected function createReport(Device $device): void
|
||||
{
|
||||
[$lastReportedAt, $latestReportedAt] = value(function (Device $device) {
|
||||
$lastReportedAt = null;
|
||||
|
|
@ -104,6 +93,22 @@ class DeviceLogDailyReportCommand extends Command
|
|||
->value('monitored_at');
|
||||
}
|
||||
break;
|
||||
|
||||
case DeviceType::InsecticidalLamp:
|
||||
$lastReportedAt = InsecticidalLampDailyReport::where('device_id', $device->id)
|
||||
->latest('reported_at')
|
||||
->value('reported_at');
|
||||
|
||||
$lastReportedAt ??= InsecticidalLampReport::where('device_id', $device->id)
|
||||
->oldest('reported_at')
|
||||
->value('reported_at');
|
||||
|
||||
if ($lastReportedAt) {
|
||||
$latestReportedAt = InsecticidalLampReport::where('device_id', $device->id)
|
||||
->latest('reported_at')
|
||||
->value('reported_at');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return [$lastReportedAt, $latestReportedAt];
|
||||
|
|
@ -113,7 +118,7 @@ class DeviceLogDailyReportCommand extends Command
|
|||
return;
|
||||
}
|
||||
|
||||
$service = new BiAngDeviceLogService();
|
||||
$service = new BiAngDeviceService();
|
||||
|
||||
/** @var \Carbon\Carbon */
|
||||
$startAt = $lastReportedAt->copy()->startOfDay();
|
||||
|
|
@ -1,13 +1,14 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
namespace App\Console\Commands\BiAng;
|
||||
|
||||
use App\Enums\DeviceType;
|
||||
use App\Models\Device;
|
||||
use App\Models\DeviceLog;
|
||||
use App\Models\InsecticidalLampReport;
|
||||
use App\Models\MeteorologicalMonitoringLog;
|
||||
use App\Models\SoilMonitoringLog;
|
||||
use App\Services\BiAngDeviceLogService;
|
||||
use App\Services\BiAngDeviceService;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class DeviceLogReportCommand extends Command
|
||||
|
|
@ -17,8 +18,7 @@ class DeviceLogReportCommand extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'device-log:report
|
||||
{factory}
|
||||
protected $signature = 'biang:device-log-report
|
||||
{--sleep=300 : 监控报告生产后的休眠时间(秒)}';
|
||||
|
||||
/**
|
||||
|
|
@ -38,20 +38,14 @@ class DeviceLogReportCommand extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
$factory = $this->argument('factory');
|
||||
|
||||
$sleep = (int) value(fn ($sleep) => is_numeric($sleep) ? $sleep : 300, $this->option('sleep'));
|
||||
|
||||
while (true) {
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$devices = Device::with(['supplier'])->supplierBy("device-supplier-{$factory}")->get();
|
||||
$devices = Device::supplierBy("device-supplier-biang")->get();
|
||||
|
||||
foreach ($devices as $device) {
|
||||
switch ($device->supplier?->key) {
|
||||
case 'device-supplier-biang':
|
||||
$this->createReportToBiAngDevice($device);
|
||||
break;
|
||||
}
|
||||
$this->createReport($device);
|
||||
}
|
||||
|
||||
sleep($sleep);
|
||||
|
|
@ -61,11 +55,12 @@ class DeviceLogReportCommand extends Command
|
|||
/**
|
||||
* 创建比昂设备报告
|
||||
*/
|
||||
protected function createReportToBiAngDevice(Device $device): void
|
||||
protected function createReport(Device $device): void
|
||||
{
|
||||
$lastReportedAt = match ($device->type) {
|
||||
DeviceType::Soil => SoilMonitoringLog::where('device_id', $device->id)->latest('monitored_at')->value('monitored_at'),
|
||||
DeviceType::Meteorological => MeteorologicalMonitoringLog::where('device_id', $device->id)->latest('monitored_at')->value('monitored_at'),
|
||||
DeviceType::InsecticidalLamp => InsecticidalLampReport::where('device_id', $device->id)->latest('reported_at')->value('reported_at'),
|
||||
default => null,
|
||||
};
|
||||
|
||||
|
|
@ -77,7 +72,7 @@ class DeviceLogReportCommand extends Command
|
|||
return;
|
||||
}
|
||||
|
||||
$service = new BiAngDeviceLogService();
|
||||
$service = new BiAngDeviceService();
|
||||
|
||||
/** @var \Carbon\Carbon */
|
||||
$startAt = $lastReportedAt->copy()->startOfHour();
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands\BiAng;
|
||||
|
||||
use App\Enums\DeviceStatus;
|
||||
use App\Enums\DeviceType;
|
||||
use App\Iot\BiAng\HttpClient;
|
||||
use App\Models\Device;
|
||||
use App\Models\DeviceLog;
|
||||
use App\Models\WormPhoto;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
class DeviceLogSyncCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'biang:device-log-sync
|
||||
{--sleep=60 : 设备数据同步完成后的休眠时间(秒)}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '按设备厂商同步数据';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$sleep = (int) value(fn ($sleep) => is_numeric($sleep) ? $sleep : 60, $this->option('sleep'));
|
||||
|
||||
while (true) {
|
||||
$this->sync();
|
||||
|
||||
sleep($sleep);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行同步
|
||||
*/
|
||||
protected function sync(): void
|
||||
{
|
||||
$now = now();
|
||||
|
||||
$this->info('------------------------------------------');
|
||||
$this->info('同步时间: '. $now);
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$devices = Device::with(['project'])
|
||||
->supplierBy("device-supplier-biang")
|
||||
->whereIn('status', [DeviceStatus::Online, DeviceStatus::Offline])
|
||||
->get();
|
||||
|
||||
/** @var \App\Models\Device */
|
||||
foreach ($devices as $device) {
|
||||
if (! in_array($device->type, [
|
||||
DeviceType::Soil,
|
||||
DeviceType::Meteorological,
|
||||
DeviceType::Worm,
|
||||
DeviceType::InsectSexLure,
|
||||
DeviceType::InsecticidalLamp,
|
||||
])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->info('==========================================');
|
||||
$this->info('设备编号: ' . $device->sn);
|
||||
$this->info('设备名称: ' . $device->name);
|
||||
$this->info('设备类型: ' . match ($device->type) {
|
||||
DeviceType::Soil => '土壤设备',
|
||||
DeviceType::Meteorological => '气象设备',
|
||||
DeviceType::Worm => '虫情设备',
|
||||
DeviceType::InsectSexLure => '昆虫性诱设备',
|
||||
DeviceType::InsecticidalLamp => '杀虫灯设备',
|
||||
});
|
||||
|
||||
try {
|
||||
$httpClient = $this->buildHttpClient($device);
|
||||
|
||||
switch ($device->type) {
|
||||
case DeviceType::Soil:
|
||||
$data = $httpClient->getLatestSoilReport($device->sn);
|
||||
|
||||
if (empty($data)) {
|
||||
$this->warn('设备数据为空');
|
||||
break;
|
||||
}
|
||||
|
||||
$log = DeviceLog::firstOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $data['time'],
|
||||
], [
|
||||
'data' => Arr::except($data, ['deviceId', 'time']),
|
||||
]);
|
||||
|
||||
$device->update([
|
||||
'status' => $now->copy()->subMinutes(60)->lt($log->reported_at) ? DeviceStatus::Online : DeviceStatus::Offline,
|
||||
]);
|
||||
break;
|
||||
|
||||
case DeviceType::Meteorological:
|
||||
$data = $httpClient->getLatestMeteorologicalReport($device->sn);
|
||||
|
||||
if (empty($data)) {
|
||||
$this->warn('设备数据为空');
|
||||
break;
|
||||
}
|
||||
|
||||
$log = DeviceLog::firstOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $data['time'],
|
||||
], [
|
||||
'data' => Arr::except($data, ['deviceId', 'time']),
|
||||
]);
|
||||
|
||||
$device->update([
|
||||
'status' => $now->copy()->subMinutes(60)->lt($log->reported_at) ? DeviceStatus::Online : DeviceStatus::Offline,
|
||||
]);
|
||||
break;
|
||||
|
||||
case DeviceType::InsecticidalLamp:
|
||||
$data = $httpClient->getLatestLampReport($device->sn);
|
||||
|
||||
if (empty($data)) {
|
||||
$this->warn('设备数据为空');
|
||||
break;
|
||||
}
|
||||
|
||||
$log = DeviceLog::firstOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $data['time'],
|
||||
], [
|
||||
'data' => Arr::except($data, ['deviceId', 'time']),
|
||||
]);
|
||||
|
||||
$device->update([
|
||||
'status' => $now->copy()->subMinutes(60)->lt($log->reported_at) ? DeviceStatus::Online : DeviceStatus::Offline,
|
||||
]);
|
||||
break;
|
||||
|
||||
case DeviceType::Worm:
|
||||
case DeviceType::InsectSexLure:
|
||||
$dir = "worm-photos/{$device->id}";
|
||||
|
||||
$disk = Storage::disk('public');
|
||||
|
||||
$data = $httpClient->getWormPhotos($device->sn, $now->copy()->subHours(24), $now);
|
||||
|
||||
if (empty($data)) {
|
||||
$this->warn('设备数据为空');
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($data['imgUrl'] as $item) {
|
||||
// 下载图片
|
||||
$name = md5($item['url']);
|
||||
if ($ext = pathinfo($item['url'], PATHINFO_EXTENSION)) {
|
||||
$name .= ".{$ext}";
|
||||
}
|
||||
|
||||
$path = "{$dir}/{$name}";
|
||||
|
||||
$disk = Storage::disk('public');
|
||||
if (! $disk->exists($path)) {
|
||||
$disk->put($path, file_get_contents($item['url']));
|
||||
}
|
||||
|
||||
WormPhoto::updateOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'uploaded_at' => $item['time'],
|
||||
], [
|
||||
'url' => $path,
|
||||
]);
|
||||
}
|
||||
|
||||
$device->update([
|
||||
'status' => count($data['imgUrl'] ?? []) > 0 ? DeviceStatus::Online : DeviceStatus::Offline,
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->info('同步成功!');
|
||||
} catch (Throwable $e) {
|
||||
report($e);
|
||||
|
||||
$this->error('同步失败: '. $e->getMessage());
|
||||
}
|
||||
|
||||
$this->info('==========================================');
|
||||
}
|
||||
|
||||
$this->info('------------------------------------------');
|
||||
$this->newLine();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 HTTP 客户端
|
||||
*/
|
||||
public function buildHttpClient(Device $device): HttpClient
|
||||
{
|
||||
$config = json_decode($device->project?->value, true);
|
||||
|
||||
if (! is_array($config)) {
|
||||
throw new RuntimeException('账户信息未找到');
|
||||
}
|
||||
|
||||
return new HttpClient($config['username'] ?? '', $config['password'] ?? '');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands\BiAng;
|
||||
|
||||
use App\Enums\DeviceStatus;
|
||||
use App\Enums\DeviceType;
|
||||
use App\Models\Device;
|
||||
use App\Models\WormReport;
|
||||
use App\Services\BiAngDeviceService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class WormStatisticsSyncCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'biang:worm-statistics-sync';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '虫情设备统计数据同步';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->sync();
|
||||
}
|
||||
|
||||
protected function sync(): void
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$devices = Device::with(['project'])
|
||||
->supplierBy('device-supplier-biang')
|
||||
->where('type', DeviceType::Worm)
|
||||
->whereIn('status', [DeviceStatus::Online, DeviceStatus::Offline])
|
||||
->get();
|
||||
|
||||
if ($devices->isEmpty()) {
|
||||
$this->warn('没有找到虫情设备');
|
||||
return;
|
||||
}
|
||||
|
||||
$today = today();
|
||||
|
||||
foreach ($devices as $device) {
|
||||
$this->info('==================================');
|
||||
|
||||
$latestReportedAt = WormReport::where('device_id', $device->id)->latest('reported_at')->value('reported_at');
|
||||
|
||||
$start = $latestReportedAt ? $latestReportedAt->copy() : $today->copy();
|
||||
|
||||
$days = $start->diffInDays($today, false);
|
||||
|
||||
if ($days > 179) {
|
||||
$end = $start->copy()->addDays(179);
|
||||
} else {
|
||||
if ($days < 2) {
|
||||
$start = $today->copy()->subDays(2);
|
||||
}
|
||||
$end = $today->copy();
|
||||
}
|
||||
$this->info('设备编号: '.$device->sn);
|
||||
$this->info('开始日期: '.$start->toDateString());
|
||||
$this->info('结束日期: '.$end->toDateString());
|
||||
|
||||
$statistics = (new BiAngDeviceService())->getWormStatistics($device, $start, $end);
|
||||
|
||||
foreach (data_get($statistics, 'data.records', []) as $item) {
|
||||
$data = collect(Arr::except($item, '日期'))->map(fn ($v, $k) => ['name' => $k, 'num' => $v]);
|
||||
|
||||
WormReport::updateOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $item['日期'],
|
||||
], [
|
||||
'agricultural_base_id' => $device->agricultural_base_id,
|
||||
'worm_num' => $data->sum('num'),
|
||||
'data' => $data->values(),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->info('==================================');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Enums\DeviceType;
|
||||
use App\Models\Device;
|
||||
use App\Services\BiAngDeviceLogService;
|
||||
use Illuminate\Console\Command;
|
||||
use Throwable;
|
||||
|
||||
class DeviceLogSyncCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'device-log:sync
|
||||
{factory}
|
||||
{--sleep=60 : 设备数据同步完成后的休眠时间(秒)}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '按设备厂商同步数据';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$factory = $this->argument('factory');
|
||||
|
||||
$sleep = (int) value(fn ($sleep) => is_numeric($sleep) ? $sleep : 60, $this->option('sleep'));
|
||||
|
||||
while (true) {
|
||||
$this->runSync($factory);
|
||||
|
||||
sleep($sleep);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行同步
|
||||
*/
|
||||
protected function runSync(string $factory): void
|
||||
{
|
||||
$end = now();
|
||||
$start = $end->copy()->subHours(1);
|
||||
|
||||
$this->info('------------------------------------------');
|
||||
$this->info('开始时间: '. $start);
|
||||
$this->info('结束时间: '. $end);
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$devices = Device::with(['supplier', 'project'])->supplierBy("device-supplier-{$factory}")->get();
|
||||
|
||||
/** @var \App\Models\Device */
|
||||
foreach ($devices as $device) {
|
||||
$this->info('==========================================');
|
||||
$this->info('设备编号: ' . $device->sn);
|
||||
$this->info('设备名称: ' . $device->name);
|
||||
$this->info('设备类型: ' . match ($device->type) {
|
||||
DeviceType::Soil => '土壤设备',
|
||||
DeviceType::WaterQuality => '水质设备',
|
||||
DeviceType::Meteorological => '气象设备',
|
||||
default => '其它',
|
||||
});
|
||||
|
||||
try {
|
||||
switch ($device->supplier?->key) {
|
||||
case 'device-supplier-biang':
|
||||
(new BiAngDeviceLogService())->sync($device);
|
||||
break;
|
||||
}
|
||||
|
||||
$this->info('同步成功!');
|
||||
} catch (Throwable $e) {
|
||||
report($e);
|
||||
|
||||
$this->error('同步失败: '. $e->getMessage());
|
||||
}
|
||||
|
||||
$this->info('==========================================');
|
||||
}
|
||||
|
||||
$this->info('------------------------------------------');
|
||||
$this->newLine();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands\Linkos;
|
||||
|
||||
use App\Enums\DeviceStatus;
|
||||
use App\Enums\DeviceType;
|
||||
use App\Iot\Linkos\FarmClient;
|
||||
use App\Models\Device;
|
||||
use App\Models\WormPhoto;
|
||||
use App\Models\WormReport;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Throwable;
|
||||
|
||||
class WormReportCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'linkos:worm-report';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'linkos 虫情设备数据同步';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->info('------------------------------------------');
|
||||
$this->info(now());
|
||||
try {
|
||||
$this->sync();
|
||||
} catch (Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
$this->info('------------------------------------------');
|
||||
}
|
||||
|
||||
protected function sync(): void
|
||||
{
|
||||
// 接口接口限制,每分钟最多访问6次,因此每次访问后需休眠10秒
|
||||
$client = new FarmClient('xunwang', 'qwer1234');
|
||||
|
||||
$now = now();
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$devices = Device::supplierBy('device-supplier-linkos')
|
||||
->where('type', DeviceType::Worm)
|
||||
->whereIn('status', [DeviceStatus::Online, DeviceStatus::Offline])
|
||||
->get();
|
||||
|
||||
if ($devices->isEmpty()) {
|
||||
$this->warn('没有找到虫情设备');
|
||||
return;
|
||||
}
|
||||
|
||||
$this->info('==================================');
|
||||
$this->info('尝试更新设备状态...');
|
||||
$realTimeData = $client->realTimeData($devices->pluck('sn')->all());
|
||||
foreach ($realTimeData as $item) {
|
||||
foreach ($devices as $device) {
|
||||
if ($item['deviceAddr'] != $device->sn) {
|
||||
continue;
|
||||
}
|
||||
// 更新设备状态
|
||||
$device->update([
|
||||
'state' => $item['status'] === 'online' ? DeviceStatus::Online : DeviceStatus::Offline,
|
||||
]);
|
||||
}
|
||||
}
|
||||
$this->info("设备状态更新完成");
|
||||
|
||||
$this->info('==================================');
|
||||
|
||||
$this->info('尝试同步虫情区域统计...');
|
||||
for ($i=2; $i > 0; $i--) {
|
||||
$reportedAt = $now->copy()->subDays($i);
|
||||
|
||||
$statistics = collect(
|
||||
$client->wormStatistics(
|
||||
'E05F10DAIB6F4I4977IB95FI82554A48DE7C',
|
||||
$reportedAt->copy()->startOfDay(),
|
||||
$reportedAt->copy()->endOfDay(),
|
||||
)
|
||||
)->mapWithKeys(fn ($item) => [$item['deviceAddr'] => $item['wornData']]);
|
||||
|
||||
foreach ($devices as $device) {
|
||||
$data = $statistics[$device->sn] ?? [];
|
||||
|
||||
WormReport::updateOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $reportedAt->toDateString(),
|
||||
], [
|
||||
'agricultural_base_id' => $device->agricultural_base_id,
|
||||
'worm_num' => collect($data)->sum('num'),
|
||||
'data' => $data,
|
||||
]);
|
||||
}
|
||||
}
|
||||
$this->info("同步虫情区域统计完成");
|
||||
|
||||
$this->info('==================================');
|
||||
|
||||
// 接口请求次数
|
||||
$requests = 4;
|
||||
|
||||
// 同步最近7天的分析报表记录
|
||||
$this->info('尝试同步分析报表记录...');
|
||||
foreach ($devices->pluck('sn') as $sn) {
|
||||
$data = $client->wormAnalyseData($sn, $now->copy()->subDays(7), $now, 1, 100);
|
||||
|
||||
foreach ($data['rows'] as $item) {
|
||||
foreach ($devices as $device) {
|
||||
if ($item['deviceAddr'] != $device->sn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$url = $item['analyseCoordUrl'] ?: $item['imagesUrl'];
|
||||
|
||||
// 下载图片
|
||||
$name = md5($url);
|
||||
if ($ext = pathinfo($url, PATHINFO_EXTENSION)) {
|
||||
$name .= ".{$ext}";
|
||||
}
|
||||
|
||||
$path = "worm-photos/{$device->id}/{$name}";
|
||||
|
||||
$disk = Storage::disk('public');
|
||||
if (! $disk->exists($path)) {
|
||||
$disk->put($path, file_get_contents($url));
|
||||
}
|
||||
|
||||
WormPhoto::updateOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'uploaded_at' => $item['createTime'],
|
||||
], [
|
||||
'url' => $path,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$requests++;
|
||||
// 接口请求频率: 每分钟6次
|
||||
if ($requests == 6) {
|
||||
$requests = 0;
|
||||
sleep(61);
|
||||
}
|
||||
}
|
||||
$this->info("同步分析报表记录完成");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Enums\DeviceType;
|
||||
use App\Models\Device;
|
||||
use App\Models\LinkosDeviceLog;
|
||||
use App\Services\LinkosDeviceLogService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class LinkosDeviceLogArchiveCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'linkos:device-log-archive';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'LinkOS 设备流水归档';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @param \App\Services\LinkosDeviceLogService $linkosDeviceLogService
|
||||
* @return int
|
||||
*/
|
||||
public function handle(LinkosDeviceLogService $linkosDeviceLogService)
|
||||
{
|
||||
$devices = Device::whereIn('type', [DeviceType::Meteorological, DeviceType::Soil, DeviceType::WaterQuality])->get();
|
||||
|
||||
// 物联平台目前只有水质监测设备和气象监测设备
|
||||
LinkosDeviceLog::orderBy('reported_at', 'asc')->lazy()->each(function ($log) use ($devices, $linkosDeviceLogService) {
|
||||
if (empty($log->data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($devices as $device) {
|
||||
if ($device->sn !== $log->device_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match ($device->type) {
|
||||
DeviceType::Soil => $linkosDeviceLogService->handleSoilMonitoringLog($device, $log->data, $log->reported_at),
|
||||
DeviceType::Meteorological => $linkosDeviceLogService->handleMeteorologicalMonitoringLog($device, $log->data, $log->reported_at),
|
||||
DeviceType::WaterQuality => $linkosDeviceLogService->handleWaterQualityMonitoringLog($device, $log->data, $log->reported_at),
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
$now = now();
|
||||
$date = Carbon::parse('2022-06-01');
|
||||
|
||||
while ($date->lt($now)) {
|
||||
foreach ($devices as $device) {
|
||||
match ($device->type) {
|
||||
DeviceType::Soil => $linkosDeviceLogService->handleSoilMonitoringDailyLog($device, $date),
|
||||
DeviceType::Meteorological => $linkosDeviceLogService->handleMeteorologicalMonitoringDailyLog($device, $date),
|
||||
DeviceType::WaterQuality => $linkosDeviceLogService->handleWaterQualityMonitoringDailyLog($device, $date),
|
||||
};
|
||||
}
|
||||
|
||||
$date->addDay();
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Exceptions\BizException;
|
||||
use App\Models\LinkosDeviceLog;
|
||||
use App\Services\LinkosService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class LinkosDeviceLogSyncCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'linkos:device-log-sync {device}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'LinkOS 设备流水同步';
|
||||
|
||||
/**
|
||||
* @var \App\Services\LinkosService
|
||||
*/
|
||||
protected $linkosService;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$now = now();
|
||||
|
||||
$device = $this->argument('device');
|
||||
|
||||
// 最近同步时间
|
||||
$lastDate = $this->getLastDate($device);
|
||||
|
||||
do {
|
||||
if ($lastDate === null) {
|
||||
$lastDate = Carbon::parse('2022-06-01');
|
||||
} else {
|
||||
$lastDate->addDay();
|
||||
}
|
||||
|
||||
$start = $lastDate->copy()->startOfDay();
|
||||
|
||||
if ($start->gt($now)) {
|
||||
throw new BizException('开始时间大约当前时间');
|
||||
}
|
||||
|
||||
$end = $lastDate->copy()->endOfDay();
|
||||
|
||||
if ($end->gt($now)) {
|
||||
$end = $now;
|
||||
}
|
||||
|
||||
$this->info('----------------------------------');
|
||||
$this->info('设备编号: '.$device);
|
||||
$this->info('开始时间: '.$start->toDateTimeString());
|
||||
$this->info('结束时间: '.$end->toDateTimeString());
|
||||
$this->info('开始同步');
|
||||
$this->info('...');
|
||||
$this->synchronize($device, $start, $end);
|
||||
$this->info('Done!');
|
||||
$this->info('----------------------------------');
|
||||
|
||||
if ($now->isSameDay($lastDate)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$this->setLastDate($device, $lastDate);
|
||||
} while (true);
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步设备历史数据
|
||||
*
|
||||
* @param string $device
|
||||
* @param \Carbon\Carbon $start
|
||||
* @param \Carbon\Carbon $end
|
||||
* @return void
|
||||
*/
|
||||
protected function synchronize(string $device, Carbon $start, Carbon $end)
|
||||
{
|
||||
// 分页页码
|
||||
$page = 0;
|
||||
// 每页条数
|
||||
$size = 50;
|
||||
// 开始时间戳
|
||||
$startTime = $start->unix() * 1000;
|
||||
// 结束时间戳
|
||||
$endTime = $end->unix() * 1000;
|
||||
|
||||
LinkosDeviceLog::where('device_id', $device)->whereBetween('reported_at', [$start, $end])->delete();
|
||||
|
||||
do {
|
||||
$result = retry(5, function () use ($device, $page, $size, $startTime, $endTime) {
|
||||
return $this->linkosService()->post('/deviceFlow/v1/list', [
|
||||
'device_id' => $device,
|
||||
'start_time' => $startTime,
|
||||
'end_time' => $endTime,
|
||||
'pageable' => [
|
||||
'page' => $page,
|
||||
'size' => $size,
|
||||
],
|
||||
]);
|
||||
}, 100);
|
||||
|
||||
$data = collect($result['data']['content']);
|
||||
|
||||
$count = $data->count();
|
||||
|
||||
if ($count === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
$time = now();
|
||||
|
||||
LinkosDeviceLog::insert(
|
||||
$data->map(function ($item) use ($time) {
|
||||
return [
|
||||
'device_id' => $item['device_id'],
|
||||
'device_unit' => $item['device_unit'],
|
||||
'device_category' => $item['device_category'],
|
||||
'data' => ! empty($item['data']) ? json_encode($item['data']) : '{}',
|
||||
'reported_at' => $item['createTime'],
|
||||
'created_at' => $time->toDateTimeString(),
|
||||
'updated_at' => $time->toDateTimeString(),
|
||||
];
|
||||
})->toArray()
|
||||
);
|
||||
|
||||
unset($result, $data);
|
||||
|
||||
$page++;
|
||||
} while ($count === $size);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \App\Services\LinkosService
|
||||
*/
|
||||
protected function linkosService(): LinkosService
|
||||
{
|
||||
if ($this->linkosService === null) {
|
||||
$this->linkosService = app(LinkosService::class);
|
||||
}
|
||||
|
||||
return $this->linkosService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备最后同步日期
|
||||
*
|
||||
* @param string $device
|
||||
* @return \Carbon\Carbon|null
|
||||
*/
|
||||
protected function getLastDate(string $device): ?Carbon
|
||||
{
|
||||
if (is_null($date = Cache::get($this->generateKey($device)))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Carbon::parse($date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置设备最后同步日期
|
||||
*
|
||||
* @param string $device
|
||||
* @param \Carbon\Carbon $date
|
||||
* @return void
|
||||
*/
|
||||
protected function setLastDate(string $device, Carbon $date): void
|
||||
{
|
||||
Cache::put($this->generateKey($device), $date->toDateString(), 86400);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $device
|
||||
* @return string
|
||||
*/
|
||||
protected function generateKey(string $device): string
|
||||
{
|
||||
return 'linkos_device_log:'.$device.'_last_sync_date';
|
||||
}
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Enums\DeviceStatus;
|
||||
use App\Enums\DeviceType;
|
||||
use App\Models\Device;
|
||||
use App\Models\SoilMonitoringLog;
|
||||
use App\Services\LinkosDeviceLogService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Throwable;
|
||||
|
||||
class SoilMonitoringLogFixCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'soil-monitoring-log:fix {hour? : 时间格式 Y-m-d H:i:s, 示例: 2022-11-11 00:00:00}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '修复土壤监控数据';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle(LinkosDeviceLogService $linkosDeviceLogService)
|
||||
{
|
||||
$time = now()->subHour()->startOfHour();
|
||||
|
||||
if ($hour = $this->argument('hour')) {
|
||||
$time = Carbon::createFromFormat('Y-m-d H:i:s', $hour)->startOfHour();
|
||||
}
|
||||
|
||||
$devices = Device::where('type', DeviceType::Soil)
|
||||
->where('status', DeviceStatus::Online)
|
||||
->get();
|
||||
|
||||
foreach ($devices as $device) {
|
||||
$last = SoilMonitoringLog::where('device_id', $device->id)
|
||||
->where('monitored_at', $time->copy()->subHour())
|
||||
->first();
|
||||
|
||||
if ($last === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$log = SoilMonitoringLog::firstOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'monitored_at' => $time,
|
||||
], [
|
||||
'agricultural_base_id' => $device->agricultural_base_id,
|
||||
]);
|
||||
|
||||
foreach ([
|
||||
'conductivity',
|
||||
'humidity',
|
||||
'temperature',
|
||||
'n',
|
||||
'p',
|
||||
'k',
|
||||
] as $key) {
|
||||
if (is_null($log->{$key})) {
|
||||
$log->{$key} = $last->{$key};
|
||||
}
|
||||
}
|
||||
|
||||
if ($log->isDirty()) {
|
||||
$log->is_filled = true;
|
||||
}
|
||||
|
||||
$log->save();
|
||||
|
||||
if ($log->wasChanged()) {
|
||||
$linkosDeviceLogService->handleSoilMonitoringDailyLog($device, $time);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Enums\DeviceStatus;
|
||||
use App\Enums\DeviceType;
|
||||
use App\Models\Device;
|
||||
use App\Models\WaterQualityMonitoringLog;
|
||||
use App\Services\LinkosDeviceLogService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Throwable;
|
||||
|
||||
class WaterQualityMonitoringLogFixCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'water-quality-monitoring-log:fix {hour? : 时间格式 Y-m-d H:i:s, 示例: 2022-11-11 00:00:00}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '修复水质监控数据';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle(LinkosDeviceLogService $linkosDeviceLogService)
|
||||
{
|
||||
$time = now()->subHour()->startOfHour();
|
||||
|
||||
if ($hour = $this->argument('hour')) {
|
||||
$time = Carbon::createFromFormat('Y-m-d H:i:s', $hour)->startOfHour();
|
||||
}
|
||||
|
||||
$devices = Device::where('type', DeviceType::WaterQuality)
|
||||
->where('status', DeviceStatus::Online)
|
||||
->get();
|
||||
|
||||
foreach ($devices as $device) {
|
||||
$last = WaterQualityMonitoringLog::where('device_id', $device->id)
|
||||
->where('monitored_at', $time->copy()->subHour())
|
||||
->first();
|
||||
|
||||
if ($last === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$log = WaterQualityMonitoringLog::firstOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'monitored_at' => $time,
|
||||
], [
|
||||
'agricultural_base_id' => $device->agricultural_base_id,
|
||||
]);
|
||||
|
||||
foreach ([
|
||||
'chlorine',
|
||||
'conductivity',
|
||||
'oxygen',
|
||||
'ph',
|
||||
'temperature',
|
||||
'turbidity',
|
||||
] as $key) {
|
||||
if (is_null($log->{$key})) {
|
||||
$log->{$key} = $last->{$key};
|
||||
}
|
||||
}
|
||||
|
||||
if ($log->isDirty()) {
|
||||
$log->is_filled = true;
|
||||
}
|
||||
|
||||
$log->save();
|
||||
|
||||
if ($log->wasChanged()) {
|
||||
$linkosDeviceLogService->handleWaterQualityMonitoringDailyLog($device, $time);
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands\YunFei;
|
||||
|
||||
use App\Enums\DeviceType;
|
||||
use App\Models\Device;
|
||||
use App\Models\InsecticidalLampDailyReport;
|
||||
use App\Models\InsecticidalLampReport;
|
||||
use App\Services\YunFeiDeviceService;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class DeviceLogDailyReportCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'yunfei:device-log-daily-report
|
||||
{--sleep=300 : 监控报告生产后的休眠时间(秒)}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '按设备厂商生成监控报告';
|
||||
|
||||
/**
|
||||
* @var \App\Services\DeviceLogService
|
||||
*/
|
||||
protected $deviceLogService;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$seconds = (int) value(fn ($seconds) => is_numeric($seconds) ? $seconds : 300, $this->option('sleep'));
|
||||
|
||||
while (true) {
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$devices = Device::supplierBy('device-supplier-yunfei')->get();
|
||||
|
||||
foreach ($devices as $device) {
|
||||
$this->createReport($device);
|
||||
}
|
||||
|
||||
sleep($seconds);
|
||||
};
|
||||
}
|
||||
|
||||
protected function createReport(Device $device): void
|
||||
{
|
||||
[$lastReportedAt, $latestReportedAt] = value(function (Device $device) {
|
||||
$lastReportedAt = null;
|
||||
|
||||
$latestReportedAt = null;
|
||||
|
||||
switch ($device->type) {
|
||||
case DeviceType::InsecticidalLamp:
|
||||
$lastReportedAt = InsecticidalLampDailyReport::where('device_id', $device->id)
|
||||
->latest('reported_at')
|
||||
->value('reported_at');
|
||||
|
||||
$lastReportedAt ??= InsecticidalLampReport::where('device_id', $device->id)
|
||||
->oldest('reported_at')
|
||||
->value('reported_at');
|
||||
|
||||
if ($lastReportedAt) {
|
||||
$latestReportedAt = InsecticidalLampReport::where('device_id', $device->id)
|
||||
->latest('reported_at')
|
||||
->value('reported_at');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return [$lastReportedAt, $latestReportedAt];
|
||||
}, $device);
|
||||
|
||||
if ($lastReportedAt === null || $latestReportedAt === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$service = new YunFeiDeviceService();
|
||||
|
||||
/** @var \Carbon\Carbon */
|
||||
$startAt = $lastReportedAt->copy()->startOfDay();
|
||||
|
||||
do {
|
||||
$service->createDailyReport($device, $startAt->copy());
|
||||
|
||||
$startAt->addDay();
|
||||
} while ($latestReportedAt->gte($startAt));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands\YunFei;
|
||||
|
||||
use App\Enums\DeviceType;
|
||||
use App\Models\Device;
|
||||
use App\Models\DeviceLog;
|
||||
use App\Models\InsecticidalLampReport;
|
||||
use App\Services\YunFeiDeviceService;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class DeviceLogReportCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'yunfei:device-log-report
|
||||
{--sleep=300 : 监控报告生产后的休眠时间(秒)}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '按设备厂商生成监控报告';
|
||||
|
||||
/**
|
||||
* @var \App\Services\DeviceLogService
|
||||
*/
|
||||
protected $deviceLogService;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$seconds = (int) value(fn ($seconds) => is_numeric($seconds) ? $seconds : 300, $this->option('sleep'));
|
||||
|
||||
while (true) {
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$devices = Device::supplierBy('device-supplier-yunfei')->get();
|
||||
|
||||
foreach ($devices as $device) {
|
||||
$this->createReport($device);
|
||||
}
|
||||
|
||||
sleep($seconds);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建比昂设备报告
|
||||
*/
|
||||
protected function createReport(Device $device): void
|
||||
{
|
||||
$lastReportedAt = match ($device->type) {
|
||||
DeviceType::InsecticidalLamp => InsecticidalLampReport::where('device_id', $device->id)->latest('reported_at')->value('reported_at'),
|
||||
default => null,
|
||||
};
|
||||
|
||||
if (is_null($lastReportedAt ??= DeviceLog::where('device_id', $device->id)->oldest('reported_at')->value('reported_at'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_null($latestReportedAt = DeviceLog::where('device_id', $device->id)->latest('reported_at')->value('reported_at'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$service = new YunFeiDeviceService();
|
||||
|
||||
/** @var \Carbon\Carbon */
|
||||
$startAt = $lastReportedAt->copy()->startOfHour();
|
||||
|
||||
do {
|
||||
$service->createReport($device, $startAt->copy());
|
||||
|
||||
$startAt->addHour();
|
||||
} while ($latestReportedAt->gte($startAt));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -15,12 +15,12 @@ class Kernel extends ConsoleKernel
|
|||
*/
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
$schedule->command(Commands\SoilMonitoringLogFixCommand::class)
|
||||
$schedule->command(Commands\BiAng\WormStatisticsSyncCommand::class)
|
||||
->hourly()
|
||||
->runInBackground();
|
||||
|
||||
$schedule->command(Commands\WaterQualityMonitoringLogFixCommand::class)
|
||||
->hourly()
|
||||
$schedule->command(Commands\Linkos\WormReportCommand::class)
|
||||
->hourlyAt(15)
|
||||
->runInBackground();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ enum DeviceType: int
|
|||
case Soil = 2; // 土壤设备
|
||||
case WaterQuality = 3; // 水质设备
|
||||
case Meteorological = 4; // 气象设备
|
||||
case Insect = 5; // 虫情设备
|
||||
case Worm = 5; // 虫情设备
|
||||
case InsectSexLure = 6; // 昆虫性诱设备
|
||||
case InsecticidalLamp = 7; // 杀虫灯设备
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
|
@ -28,7 +30,9 @@ enum DeviceType: int
|
|||
static::Soil->value => '土壤设备',
|
||||
static::WaterQuality->value => '水质设备',
|
||||
static::Meteorological->value => '气象设备',
|
||||
static::Insect->value => '虫情设备',
|
||||
static::Worm->value => '虫情设备',
|
||||
static::InsectSexLure->value => '昆虫性诱设备',
|
||||
static::InsecticidalLamp->value => '杀虫灯设备',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class BiAngException extends RuntimeException
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class LinkosFarmException extends RuntimeException
|
||||
{
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ class AdminPermissionController extends Controller
|
|||
$res[] = [
|
||||
'id' => $permission->id,
|
||||
'label' => $permission->name,
|
||||
'slug' => $permission->slug,
|
||||
'children' => $this->formatPermissionsTreeToArray($permission->children ?? []),
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use App\Enums\OperationType;
|
|||
use App\Helpers\Paginator;
|
||||
use App\Http\Requestes\AgriculturalBaseRequest;
|
||||
use App\Http\Resources\AgriculturalBaseResource;
|
||||
use App\Http\Resources\DeviceResource;
|
||||
use App\Models\AgriculturalBase;
|
||||
use App\Models\Device;
|
||||
use App\Services\OperationLogService;
|
||||
|
|
@ -126,9 +127,13 @@ class AgriculturalBaseController extends Controller
|
|||
{
|
||||
$deviceType = $request->input('device_type', DeviceType::Monitor);
|
||||
// $status = $request->input('status');
|
||||
$list = AgriculturalBase::filter($request->all())->whereHas('devices', function ($q) use ($deviceType) {
|
||||
$isRecommend = $request->input('is_recommended', 0) ?? 0;
|
||||
$list = AgriculturalBase::filter($request->all())->whereHas('devices', function ($q) use ($deviceType, $isRecommend) {
|
||||
if($deviceType == DeviceType::Monitor || $deviceType == 1){
|
||||
$q->where('is_recommend', 1)->where('status', 1);
|
||||
if($isRecommend){
|
||||
$q->where('is_recommend', 1);
|
||||
}
|
||||
$q->where('status', 1);
|
||||
}
|
||||
return $q->where('type', $deviceType);
|
||||
})->sort()->get();
|
||||
|
|
@ -138,9 +143,9 @@ class AgriculturalBaseController extends Controller
|
|||
|
||||
/**
|
||||
* 获取指定基地指定设备类型下所有监控点名称选项
|
||||
* device_type
|
||||
*/
|
||||
public function basePointList(AgriculturalBase $agriculturalBasic, Request $request){
|
||||
public function basePointList(AgriculturalBase $agriculturalBasic, Request $request)
|
||||
{
|
||||
$deviceType = $request->input('device_type', DeviceType::Meteorological);
|
||||
$list = Device::where([
|
||||
'agricultural_base_id' => $agriculturalBasic->id,
|
||||
|
|
@ -148,4 +153,11 @@ class AgriculturalBaseController extends Controller
|
|||
])->orderBy('sort', 'desc')->get()->pluck('monitoring_point', 'id')->toArray();
|
||||
return $this->json($list);
|
||||
}
|
||||
|
||||
public function basePoints(Request $request)
|
||||
{
|
||||
$devices = Device::filter($request->input())->orderBy('sort', 'desc')->get();
|
||||
|
||||
return DeviceResource::collection($devices);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\AdminUser;
|
||||
use App\Models\AdminPermission;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
|
|
@ -34,6 +35,12 @@ class AuthController extends Controller
|
|||
{
|
||||
$token = $user->createToken($name)->plainTextToken;
|
||||
|
||||
return $this->json(['token' => $token, 'info' => $user, 'permissions' => $user->permissionIds()]);
|
||||
$permissionsQuery = AdminPermission::query();
|
||||
if($user->id != 1){
|
||||
$permissions = $permissionsQuery->whereIn('id', $user->permissionIds());
|
||||
}
|
||||
$permissions = $permissionsQuery->pluck('slug')->toArray();
|
||||
|
||||
return $this->json(['token' => $token, 'info' => $user, 'permissions' => $user->permissionIds(), 'permissions_slug'=>$permissions]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Callback;
|
||||
|
||||
use App\Enums\DeviceStatus;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Device;
|
||||
use App\Models\DeviceLog;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class YunFeiController extends Controller
|
||||
{
|
||||
/**
|
||||
* 杀虫灯回调通知
|
||||
*/
|
||||
public function insecticidalLampNotify(Request $request)
|
||||
{
|
||||
logger()->debug('杀虫灯回调通知', $request->input());
|
||||
|
||||
$payload = $request->input('payload');
|
||||
|
||||
if (! isset($payload['ext'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$device = Device::supplierBy('device-supplier-yunfei')->where('sn', $payload['ext']['imei'])->first();
|
||||
|
||||
if ($device === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! in_array($device->status, [DeviceStatus::Online, DeviceStatus::Offline])) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($payload['cmd']) {
|
||||
case 'data':
|
||||
$device->update([
|
||||
'status' => DeviceStatus::Online,
|
||||
]);
|
||||
|
||||
DeviceLog::firstOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => Carbon::createFromFormat('YmdHis', $payload['ext']['stamp']),
|
||||
], [
|
||||
'data' => $payload['ext'],
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'offline':
|
||||
$device->update([
|
||||
'status' => DeviceStatus::Offline,
|
||||
]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测报灯回调通知
|
||||
*/
|
||||
public function wormNotify(Request $request)
|
||||
{
|
||||
logger()->debug('虫情设备回调通知', $request->input());
|
||||
|
||||
$payload = $request->input('payload');
|
||||
|
||||
if (! isset($payload['ext'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$device = Device::supplierBy('device-supplier-yunfei')->where('sn', $payload['ext']['imei'])->first();
|
||||
|
||||
if ($device === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! in_array($device->status, [DeviceStatus::Online, DeviceStatus::Offline])) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch ($payload['cmd']) {
|
||||
case 'data':
|
||||
$device->update([
|
||||
'status' => DeviceStatus::Online,
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'offline':
|
||||
$device->update([
|
||||
'status' => DeviceStatus::Offline,
|
||||
]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测报灯照片回调通知
|
||||
*/
|
||||
public function wormPhotoNotify(Request $request)
|
||||
{
|
||||
logger()->debug('虫情图片通知', $request->input());
|
||||
|
||||
$device = Device::supplierBy('device-supplier-yunfei')->where('sn', $request->input('imei'))->first();
|
||||
|
||||
if ($device === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! in_array($device->status, [DeviceStatus::Online, DeviceStatus::Offline])) {
|
||||
return;
|
||||
}
|
||||
|
||||
DeviceLog::firstOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => now(),
|
||||
], [
|
||||
'data' => $request->input(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,18 +8,25 @@ use App\Enums\OperationType;
|
|||
use App\Helpers\Paginator;
|
||||
use App\Http\Requestes\DeviceRequest;
|
||||
use App\Http\Resources\DeviceResource;
|
||||
use App\Http\Resources\WormPhotoResource;
|
||||
use App\Models\AgriculturalBase;
|
||||
use App\Models\Device;
|
||||
use App\Models\InsecticidalLampDailyReport;
|
||||
use App\Models\InsecticidalLampReport;
|
||||
use App\Models\MeteorologicalMonitoringDailyLog;
|
||||
use App\Models\MeteorologicalMonitoringLog;
|
||||
use App\Models\SoilMonitoringDailyLog;
|
||||
use App\Models\SoilMonitoringLog;
|
||||
use App\Models\WaterQualityMonitoringDailyLog;
|
||||
use App\Models\WaterQualityMonitoringLog;
|
||||
use App\Models\WormPhoto;
|
||||
use App\Models\WormReport;
|
||||
use App\Services\BiAngDeviceService;
|
||||
use App\Services\OperationLogService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Peidikeji\Setting\Models\Setting;
|
||||
|
||||
class DeviceController extends Controller
|
||||
|
|
@ -415,48 +422,46 @@ class DeviceController extends Controller
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询设备今天(按天),近一周(按天),近一个月(按天)
|
||||
*/
|
||||
public function timeZoneList(Request $request){
|
||||
$deviceId = $request->input('device_id');
|
||||
//不传开始时间,结束时间,则默认是查当天(按小时)
|
||||
$startTime = $request->input('start_time');
|
||||
$endTime = $request->input('end_time');
|
||||
$diffDays = 0;
|
||||
$day = date('Y-m-d');
|
||||
//如果传了开始时间和结束时间,计算中间天数
|
||||
if($startTime && $endTime){
|
||||
if($startTime == $endTime){//查询某一天
|
||||
$day = $startTime;
|
||||
}else{
|
||||
$startDay = Carbon::parse($startTime);
|
||||
$endDay = Carbon::parse($endTime);
|
||||
$diffDays = $startDay->diffInDays($endDay, false);
|
||||
public function timeZoneList(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'device_id' => ['bail', 'required'],
|
||||
'start_time' => ['bail', 'nullable', 'date_format:Y-m-d'],
|
||||
'end_time' => ['bail', 'nullable', 'date_format:Y-m-d'],
|
||||
]);
|
||||
|
||||
$isSameDay = true;
|
||||
|
||||
if ($request->filled('start_time') && $request->filled('end_time')) {
|
||||
$startTime = Carbon::parse($request->input('start_time'))->startOfDay();
|
||||
$endTime = Carbon::parse($request->input('end_time'))->startOfDay();
|
||||
|
||||
if ($startTime->gt($endTime)) {
|
||||
throw ValidationException::withMessages([
|
||||
'start_time' => ['开始时间不能大于结束时间'],
|
||||
]);
|
||||
}
|
||||
|
||||
// 如果开始时间和结束时间是同一天
|
||||
if ($startTime->eq($endTime)) {
|
||||
$endTime = $startTime->isToday() ? now() : $startTime->copy()->endOfDay();
|
||||
} else {
|
||||
$isSameDay = false;
|
||||
}
|
||||
} else {
|
||||
$endTime = now();
|
||||
$startTime = $endTime->copy()->startOfDay();
|
||||
}
|
||||
|
||||
$xKeys = [];
|
||||
if($diffDays){
|
||||
for ($i = 0; $i<=$diffDays; $i++) {
|
||||
$xKeys[] =(clone $startDay)->addDays($i)->startOfDay()->format('Y-m-d H:i:s');
|
||||
}
|
||||
}else{
|
||||
//调整截至到当前小时
|
||||
$h = 23;
|
||||
if($day == date('Y-m-d')){
|
||||
$h = date('H');
|
||||
}
|
||||
for ($i = 0; $i < ($h+1); $i++) {
|
||||
$xKeys[] = $day.' '.str_pad($i, 2, '0', STR_PAD_LEFT).':00:00';
|
||||
}
|
||||
}
|
||||
$device = Device::find($deviceId);
|
||||
$modelQuery = null;
|
||||
$getArr = [];
|
||||
$device = Device::findOrFail($request->input('device_id'));
|
||||
|
||||
$fields = [];
|
||||
$monitoringLogs = collect();
|
||||
|
||||
switch ($device->type) {
|
||||
case DeviceType::Meteorological://气象设备
|
||||
$getArr = [
|
||||
// 气象设备
|
||||
case DeviceType::Meteorological:
|
||||
$fields = [
|
||||
'wind_speed',
|
||||
'wind_direction',
|
||||
'wind_degree',
|
||||
|
|
@ -468,17 +473,34 @@ class DeviceController extends Controller
|
|||
'illumination',
|
||||
'pm25',
|
||||
'pm10',
|
||||
'rainfall',
|
||||
];
|
||||
if($diffDays) {
|
||||
$getArr[] = 'daily_rainfall';
|
||||
$modelQuery = MeteorologicalMonitoringDailyLog::query()->whereBetween('monitored_at', [$startTime, $endTime]);
|
||||
}else{
|
||||
$getArr[] = 'current_rainfall';
|
||||
$modelQuery = MeteorologicalMonitoringLog::query()->whereDate('monitored_at', $day);
|
||||
}
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
$monitoringLogs = (
|
||||
$isSameDay
|
||||
? MeteorologicalMonitoringLog::query()
|
||||
: MeteorologicalMonitoringDailyLog::query()
|
||||
)
|
||||
->where('device_id', $device->id)
|
||||
->whereBetween('monitored_at', [$startTime, $endTime])
|
||||
->get()
|
||||
->mapWithKeys(function ($item) use ($fields) {
|
||||
$key = $item->monitored_at->toDateTimeString();
|
||||
$data = collect($fields)->mapWithKeys(fn ($field) => [$field => $field !== 'rainfall' ? $item[$field] : null])->all();
|
||||
|
||||
if ($item instanceof MeteorologicalMonitoringDailyLog) {
|
||||
$data['rainfall'] = $item->daily_rainfall;
|
||||
} else {
|
||||
$data['rainfall'] = $item->current_rainfall;
|
||||
}
|
||||
|
||||
return [$key => $data];
|
||||
});
|
||||
break;
|
||||
case DeviceType::Soil://土壤设备
|
||||
$getArr = [
|
||||
|
||||
// 土壤设备
|
||||
case DeviceType::Soil:
|
||||
$fields = [
|
||||
'conductivity',
|
||||
'humidity',
|
||||
'temperature',
|
||||
|
|
@ -486,14 +508,25 @@ class DeviceController extends Controller
|
|||
'p',
|
||||
'k',
|
||||
];
|
||||
if($diffDays) {
|
||||
$modelQuery = SoilMonitoringDailyLog::query()->whereBetween('monitored_at', [$startTime, $endTime]);
|
||||
}else{
|
||||
$modelQuery = SoilMonitoringLog::query()->whereDate('monitored_at', $day);
|
||||
}
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
$monitoringLogs = (
|
||||
$isSameDay
|
||||
? SoilMonitoringLog::query()
|
||||
: SoilMonitoringDailyLog::query()
|
||||
)
|
||||
->where('device_id', $device->id)
|
||||
->whereBetween('monitored_at', [$startTime, $endTime])
|
||||
->get()
|
||||
->mapWithKeys(function ($item) use ($fields) {
|
||||
$key = $item->monitored_at->toDateTimeString();
|
||||
$data = collect($fields)->mapWithKeys(fn ($field) => [$field => $item[$field]])->all();
|
||||
return [$key => $data];
|
||||
});
|
||||
break;
|
||||
case DeviceType::WaterQuality://水质设备
|
||||
$getArr = [
|
||||
|
||||
// 水质设备
|
||||
case DeviceType::WaterQuality:
|
||||
$fields = [
|
||||
'chlorine',
|
||||
'conductivity',
|
||||
'oxygen',
|
||||
|
|
@ -501,62 +534,96 @@ class DeviceController extends Controller
|
|||
'temperature',
|
||||
'turbidity',
|
||||
];
|
||||
if($diffDays) {
|
||||
$modelQuery = WaterQualityMonitoringDailyLog::query()->whereBetween('monitored_at', [$startTime, $endTime]);
|
||||
}else{
|
||||
$modelQuery = WaterQualityMonitoringLog::query()->whereDate('monitored_at', $day);
|
||||
}
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
$monitoringLogs = (
|
||||
$isSameDay
|
||||
? WaterQualityMonitoringLog::query()
|
||||
: WaterQualityMonitoringDailyLog::query()
|
||||
)
|
||||
->where('device_id', $device->id)
|
||||
->whereBetween('monitored_at', [$startTime, $endTime])
|
||||
->get()
|
||||
->mapWithKeys(function ($item) use ($fields) {
|
||||
$key = $item->monitored_at->toDateTimeString();
|
||||
$data = collect($fields)->mapWithKeys(fn ($field) => [$field => $item[$field]])->all();
|
||||
return [$key => $data];
|
||||
});
|
||||
break;
|
||||
|
||||
// 杀虫灯
|
||||
case DeviceType::InsecticidalLamp:
|
||||
$fields = [
|
||||
'battery_vol',
|
||||
'killed_num',
|
||||
'air_temperature',
|
||||
'air_humidity',
|
||||
'charging_vol',
|
||||
'high_vol',
|
||||
];
|
||||
/** @var \Illuminate\Support\Collection */
|
||||
$monitoringLogs = (
|
||||
$isSameDay
|
||||
? InsecticidalLampReport::query()
|
||||
: InsecticidalLampDailyReport::query()
|
||||
)
|
||||
->where('device_id', $device->id)
|
||||
->whereBetween('reported_at', [$startTime, $endTime])
|
||||
->get()
|
||||
->mapWithKeys(function ($item) use ($fields) {
|
||||
$key = $item->reported_at->toDateTimeString();
|
||||
$data = collect($fields)->mapWithKeys(fn ($field) => [$field => $item[$field]])->all();
|
||||
return [$key => $data];
|
||||
});
|
||||
break;
|
||||
}
|
||||
if($modelQuery){
|
||||
$datalist = $modelQuery->where('device_id', $deviceId)->get()->keyBy('monitored_at')->toArray();
|
||||
}
|
||||
$data = [];
|
||||
foreach ($getArr as $column){
|
||||
$data[$column] = [];
|
||||
$_value = null;
|
||||
foreach($xKeys as $key){
|
||||
if($device->type == DeviceType::WaterQuality){//如果是水质设备,则写死假数据
|
||||
switch($column){
|
||||
case 'chlorine':
|
||||
$data[$column][$key] = 0.016;
|
||||
break;
|
||||
case 'conductivity':
|
||||
$data[$column][$key] = 563 ;//电导率
|
||||
break;
|
||||
case 'oxygen':
|
||||
$data[$column][$key] = 0.09;//含氧量
|
||||
break;
|
||||
case 'ph':
|
||||
$data[$column][$key] = rand(750, 770) / 100;
|
||||
break;
|
||||
case 'temperature':
|
||||
$data[$column][$key] = rand(2400, 2600) / 100;
|
||||
break;
|
||||
case 'turbidity':
|
||||
$data[$column][$key] = 0.33;
|
||||
break;
|
||||
|
||||
return $this->json(
|
||||
collect($fields)->mapWithKeys(function ($field) use ($device, $monitoringLogs, $isSameDay, $startTime, $endTime) {
|
||||
$data = [];
|
||||
|
||||
$beginTime = $startTime->copy();
|
||||
|
||||
do {
|
||||
$key = $beginTime->toDateTimeString();
|
||||
|
||||
$monitoringLog = $monitoringLogs->get($key);
|
||||
|
||||
if (is_null($monitoringLog)) {
|
||||
// 如果是水质设备,则写死假数据
|
||||
if($device->type == DeviceType::WaterQuality){
|
||||
switch($field){
|
||||
case 'chlorine':
|
||||
$data[$key] = 0.016;
|
||||
break;
|
||||
case 'conductivity':
|
||||
$data[$key] = rand(560, 565);//电导率
|
||||
break;
|
||||
case 'oxygen':
|
||||
$data[$key] = 0.09;//含氧量
|
||||
break;
|
||||
case 'ph':
|
||||
$data[$key] = rand(750, 770) / 100;
|
||||
break;
|
||||
case 'temperature':
|
||||
$data[$key] = rand(2400, 2600) / 100;
|
||||
break;
|
||||
case 'turbidity':
|
||||
$data[$key] = 0.33;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
$data[$key] = null;
|
||||
}
|
||||
} else {
|
||||
$data[$key] = $monitoringLog[$field];
|
||||
}
|
||||
}else{
|
||||
// if($datalist[$key][$column] ?? null){//如果存在数据则暂存该值
|
||||
// $_value = $datalist[$key][$column];
|
||||
// }
|
||||
// //判断是否超过离线时间;
|
||||
// if(true){//未超过, 判断和设备离线时间关系-todo
|
||||
// $data[$column][$key] = $_value;
|
||||
// }else{
|
||||
$data[$column][$key] = $datalist[$key][$column] ?? null;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
//强制统一气象降雨量,日和天字段不统一问题
|
||||
if(isset($data['daily_rainfall'])) {
|
||||
$data['rainfall'] = $data['daily_rainfall'];
|
||||
}elseif(isset($data['current_rainfall'])){
|
||||
$data['rainfall'] = $data['current_rainfall'];
|
||||
}
|
||||
return $this->json($data);
|
||||
|
||||
$isSameDay ? $beginTime->addHours(1) : $beginTime->addDays(1);
|
||||
} while ($beginTime->lte($endTime));
|
||||
|
||||
return [$field => $data];
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public function getFfmpegServiceIp(){
|
||||
|
|
@ -572,4 +639,90 @@ class DeviceController extends Controller
|
|||
|
||||
return $this->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 虫情统计
|
||||
*/
|
||||
public function wormStatics($id, Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'start_time' => ['bail', 'required_with:end_time', 'date_format:Y-m-d'],
|
||||
'end_time' => ['bail', 'required_with:start_time', 'date_format:Y-m-d'],
|
||||
], [], [
|
||||
'start_time' => '开始时间',
|
||||
'end_time' => '结束时间',
|
||||
]);
|
||||
|
||||
// 结束时间
|
||||
$endTime = $request->whenFilled(
|
||||
'end_time',
|
||||
fn ($time) => Carbon::parse($time)->startOfDay(),
|
||||
fn () => now()->startOfDay(),
|
||||
);
|
||||
// 开始时间
|
||||
$startTime = $request->whenFilled(
|
||||
'start_time',
|
||||
fn ($time) => Carbon::parse($time)->startOfDay(),
|
||||
fn () => $endTime->copy()->subDays(6),
|
||||
);
|
||||
|
||||
if ($startTime->gt($endTime)) {
|
||||
throw ValidationException::withMessages([
|
||||
'start_time' => ['开始时间不能大于结束时间'],
|
||||
]);
|
||||
}
|
||||
|
||||
$wormReports = WormReport::where('device_id', $id)
|
||||
->whereBetween('reported_at', [$startTime->toDateString(), $endTime->toDateString()])
|
||||
->pluck('worm_num', 'reported_at');
|
||||
|
||||
$data = [];
|
||||
|
||||
if ($startTime->lte($endTime)) {
|
||||
do {
|
||||
// 日期
|
||||
$date = $startTime->toDateString();
|
||||
|
||||
$data[$date] = $wormReports->get($date);
|
||||
|
||||
$startTime->addDay();
|
||||
} while ($startTime->lte($endTime));
|
||||
}
|
||||
|
||||
return $this->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 虫情图片
|
||||
*/
|
||||
public function wormPhotos($id, Request $request, BiAngDeviceService $biAngDeviceService)
|
||||
{
|
||||
$request->validate([
|
||||
'start_time' => ['bail', 'required_with:end_time', 'date_format:Y-m-d'],
|
||||
'end_time' => ['bail', 'required_with:start_time', 'date_format:Y-m-d'],
|
||||
], [], [
|
||||
'start_time' => '开始时间',
|
||||
'end_time' => '结束时间',
|
||||
]);
|
||||
|
||||
// 结束时间
|
||||
$endTime = $request->whenFilled(
|
||||
'end_time',
|
||||
fn ($time) => Carbon::parse($time)->endOfDay(),
|
||||
fn () => now()->endOfDay(),
|
||||
);
|
||||
// 开始时间
|
||||
$startTime = $request->whenFilled(
|
||||
'start_time',
|
||||
fn ($time) => Carbon::parse($time)->startOfDay(),
|
||||
fn () => $endTime->copy()->startOfDay(),
|
||||
);
|
||||
|
||||
$wormPhotos = WormPhoto::where('device_id', $id)
|
||||
->whereBetween('uploaded_at', [$startTime, $endTime])
|
||||
->latest('uploaded_at')
|
||||
->paginate($request->input('per_page', 20));
|
||||
|
||||
return WormPhotoResource::collection($wormPhotos);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class RiceShrimpFlowController extends Controller
|
|||
'createdBy' => $user,
|
||||
'updatedBy' => $user,
|
||||
])
|
||||
);
|
||||
)->additional(['message'=>'保存成功']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -98,7 +98,7 @@ class RiceShrimpFlowController extends Controller
|
|||
|
||||
return RiceShrimpFlowResource::make(
|
||||
$riceShrimpFlow->loadMissing(['createdBy', 'updatedBy'])
|
||||
);
|
||||
)->additional(['message'=>'更新成功']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -115,6 +115,6 @@ class RiceShrimpFlowController extends Controller
|
|||
|
||||
(new OperationLogService())->inLog(OperationType::Delete, '', $riceShrimpFlow);
|
||||
|
||||
return response()->json(null);
|
||||
return response()->json(['message'=>'删除成功']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ class RiceShrimpIndustryController extends Controller
|
|||
'createdBy' => $user,
|
||||
'updatedBy' => $user,
|
||||
])
|
||||
);
|
||||
)->additional(['message'=>'保存成功']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -104,7 +104,7 @@ class RiceShrimpIndustryController extends Controller
|
|||
|
||||
return RiceShrimpIndustryResource::make(
|
||||
$riceShrimpIndustry->loadMissing(['createdBy', 'updatedBy'])
|
||||
);
|
||||
)->additional(['message'=>'更新成功']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -121,6 +121,6 @@ class RiceShrimpIndustryController extends Controller
|
|||
|
||||
(new OperationLogService())->inLog(OperationType::Delete, '', $riceShrimpIndustry);
|
||||
|
||||
return response()->json(null);
|
||||
return response()->json(['message'=>'删除成功']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ class RiceShrimpPriceController extends Controller
|
|||
|
||||
(new OperationLogService())->inLog(OperationType::Create, '', $riceShrimpPrice, $request->input());
|
||||
|
||||
return RiceShrimpPriceResource::make($riceShrimpPrice);
|
||||
return RiceShrimpPriceResource::make($riceShrimpPrice)->additional(['message'=>'保存成功']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -93,7 +93,7 @@ class RiceShrimpPriceController extends Controller
|
|||
|
||||
return RiceShrimpPriceResource::make(
|
||||
$riceShrimpPrice->loadMissing(['createdBy', 'updatedBy'])
|
||||
);
|
||||
)->additional(['message'=>'更新成功']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -110,6 +110,6 @@ class RiceShrimpPriceController extends Controller
|
|||
|
||||
(new OperationLogService())->inLog(OperationType::Delete, '', $riceShrimpPrice);
|
||||
|
||||
return response()->json(null);
|
||||
return response()->json(['message'=>'删除成功']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ class RiceShrimpWeeklyPriceController extends Controller
|
|||
|
||||
(new OperationLogService())->inLog(OperationType::Create, '', $riceShrimpWeeklyPrice, $request->input());
|
||||
|
||||
return RiceShrimpWeeklyPriceResource::make($riceShrimpWeeklyPrice->loadMissing(['weekObj']));
|
||||
return RiceShrimpWeeklyPriceResource::make($riceShrimpWeeklyPrice->loadMissing(['weekObj']))->additional(['message'=>'保存成功']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -94,7 +94,7 @@ class RiceShrimpWeeklyPriceController extends Controller
|
|||
|
||||
return RiceShrimpWeeklyPriceResource::make(
|
||||
$riceShrimpWeeklyPrice->loadMissing(['createdBy', 'updatedBy', 'weekObj'])
|
||||
);
|
||||
)->additional(['message'=>'更新成功']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -111,6 +111,6 @@ class RiceShrimpWeeklyPriceController extends Controller
|
|||
|
||||
(new OperationLogService())->inLog(OperationType::Delete, '', $riceShrimpWeeklyPrice);
|
||||
|
||||
return response()->json(null);
|
||||
return response()->json(['message'=>'删除成功']);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,21 @@ namespace App\Http\Controllers;
|
|||
use App\Http\Requestes\RestPasswordRequest;
|
||||
use App\Services\OperationLogService;
|
||||
use App\Enums\OperationType;
|
||||
use App\Models\AdminPermission;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
public function info()
|
||||
{
|
||||
$user = auth('api')->user();
|
||||
|
||||
$permissionsQuery = AdminPermission::query();
|
||||
if($user->id != 1){
|
||||
$permissions = $permissionsQuery->whereIn('id', $user->permissionIds());
|
||||
}
|
||||
$permissions = $permissionsQuery->pluck('slug')->toArray();
|
||||
|
||||
return $this->json(['info' => $user, 'permissions' => $user->permissionIds()]);
|
||||
return $this->json(['info' => $user, 'permissions' => $user->permissionIds(), 'permissions_slug'=>$permissions]);
|
||||
}
|
||||
|
||||
public function resetPwd(RestPasswordRequest $request)
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class Kernel extends HttpKernel
|
|||
],
|
||||
|
||||
'api' => [
|
||||
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
|
||||
'throttle:600,1',
|
||||
\Illuminate\Routing\Middleware\SubstituteBindings::class,
|
||||
\App\Http\Middleware\FormatJsonResponse::class,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class WormPhotoResource extends JsonResource
|
||||
{
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'url' => $this->image_url,
|
||||
'time' => $this->uploaded_at->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace App\Iot\BiAng;
|
||||
|
||||
use App\Exceptions\BiAngException;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Str;
|
||||
|
|
@ -27,13 +28,7 @@ class HttpClient
|
|||
]
|
||||
);
|
||||
|
||||
if (data_get($result, 'code') === 200) {
|
||||
return $result['data'];
|
||||
}
|
||||
|
||||
throw new RuntimeException(
|
||||
sprintf("%s:%s", data_get($result, 'code', 500), data_get($result, 'msg', '出错啦!'))
|
||||
);
|
||||
return $result['data'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -48,13 +43,56 @@ class HttpClient
|
|||
]
|
||||
);
|
||||
|
||||
if (data_get($result, 'code') === 200) {
|
||||
return $result['data'];
|
||||
}
|
||||
return $result['data'] ?? [];
|
||||
}
|
||||
|
||||
throw new RuntimeException(
|
||||
sprintf("%s:%s", data_get($result, 'code', 500), data_get($result, 'msg', '出错啦!'))
|
||||
/**
|
||||
* 获取最新的杀虫灯数据
|
||||
*/
|
||||
public function getLatestLampReport(string $deviceId)
|
||||
{
|
||||
$result = $this->get(
|
||||
$this->apiUrl2('/open-api/open/getCurrentLampData'),
|
||||
[
|
||||
'deviceId' => $deviceId,
|
||||
]
|
||||
);
|
||||
|
||||
return $result['data'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 虫情设备/昆虫性诱设备 - 查询某个时间段内的图片
|
||||
*/
|
||||
public function getWormPhotos(string $deviceId, Carbon $start, Carbon $end)
|
||||
{
|
||||
$result = $this->get(
|
||||
$this->apiUrl('/api/open-api/open/getDevicePhotos'),
|
||||
[
|
||||
'deviceId' => $deviceId,
|
||||
'startTime' => $start->toDateString(),
|
||||
'endTime' => $end->toDateString(),
|
||||
]
|
||||
);
|
||||
|
||||
return $result['data'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 虫情设备 - (识别款)图片虫数识别统计
|
||||
*/
|
||||
public function getWormStatistics(string $deviceId, Carbon $start, Carbon $end)
|
||||
{
|
||||
$result = $this->get(
|
||||
$this->apiUrl('/api/open-api/open/getAllStatistics'),
|
||||
[
|
||||
'imei' => $deviceId,
|
||||
'startAt' => $start->toDateString(),
|
||||
'endAt' => $end->toDateString(),
|
||||
]
|
||||
);
|
||||
|
||||
return $result['data'] ?? [];
|
||||
}
|
||||
|
||||
public function get(string $url, array $query = []): array
|
||||
|
|
@ -108,7 +146,13 @@ class HttpClient
|
|||
'Content-Type' => 'application/json',
|
||||
])->send($method, $url, $options);
|
||||
|
||||
return $response->throw()->json();
|
||||
$result = $response->throw()->json();
|
||||
|
||||
if (data_get($result, 'code') === 200) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
throw new BiAngException($result['code'].':'.($result['msg']??'出错啦!'), 500);
|
||||
}
|
||||
|
||||
protected function apiUrl(string $path): string
|
||||
|
|
|
|||
|
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
namespace App\Iot\Linkos;
|
||||
|
||||
use App\Exceptions\LinkosFarmException;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class FarmClient
|
||||
{
|
||||
public const ENDPOINT_URL = 'http://api.farm.0531yun.cn';
|
||||
|
||||
/**
|
||||
* 授权令牌
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $token;
|
||||
|
||||
/**
|
||||
* 授权令牌有效期
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $expires;
|
||||
|
||||
public function __construct(
|
||||
protected readonly string $loginName,
|
||||
protected readonly string $loginPwd,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备列表
|
||||
*/
|
||||
public function devices(?string $groupId = null, ?string $deviceType = null): array
|
||||
{
|
||||
$result = $this->get('/api/v2.0/entrance/device/getsysUserDevice', [
|
||||
'groupId' => $groupId,
|
||||
'deviceType' => $deviceType,
|
||||
]);
|
||||
|
||||
return $result['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户区域
|
||||
*/
|
||||
public function groups(?string $groupName = null): array
|
||||
{
|
||||
$result = $this->get('/api/v2.0/entrance/group/getsysUserGroup', [
|
||||
'groupName' => $groupName,
|
||||
]);
|
||||
|
||||
return $result['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备实时数据
|
||||
*/
|
||||
public function realTimeData(array $devices = []): array
|
||||
{
|
||||
$result = $this->get('/api/v2.0/entrance/device/getRealTimeData', [
|
||||
'deviceAddrs' => implode(',', $devices),
|
||||
]);
|
||||
|
||||
return $result['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 虫情区域统计
|
||||
*/
|
||||
public function wormStatistics(string $groupId, Carbon $beginTime, Carbon $endTime): array
|
||||
{
|
||||
$result = $this->get('/api/v2.0/worm/deviceData/getWormStatisticsByGroup', [
|
||||
'groupId' => $groupId,
|
||||
'beginTime' => $beginTime->toDateTimeString(),
|
||||
'endTime' => $endTime->toDateTimeString(),
|
||||
]);
|
||||
|
||||
return $result['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 虫情设备分析报表
|
||||
*/
|
||||
public function wormAnalyseData(string $device, Carbon $beginTime, Carbon $endTime, int $pages, int $limit = 100): array
|
||||
{
|
||||
$result = $this->get('/api/v2.0/worm/deviceData/getWormDataList', [
|
||||
'deviceAddr' => $device,
|
||||
'beginTime' => $beginTime->toDateTimeString(),
|
||||
'endTime' => $endTime->toDateTimeString(),
|
||||
'pages' => $pages,
|
||||
'limit' => $limit,
|
||||
]);
|
||||
|
||||
return $result['data'];
|
||||
}
|
||||
|
||||
public function get(string $url, array $query = []): array
|
||||
{
|
||||
return $this->request('GET', $url, [
|
||||
'query' => $query,
|
||||
]);
|
||||
}
|
||||
|
||||
public function post(string $url, array $data = []): array
|
||||
{
|
||||
return $this->request('POST', $url, [
|
||||
'json' => $data,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function request(string $method, string $url, array $options = []): array
|
||||
{
|
||||
$headers = [
|
||||
'Content-Type' => 'application/json',
|
||||
];
|
||||
if ($url !== '/api/v2.0/entrance/user/userLogin') {
|
||||
$headers['token'] = $this->token();
|
||||
}
|
||||
|
||||
/** @var \Illuminate\Http\Client\Response */
|
||||
$response = Http::withHeaders($headers)->baseUrl(self::ENDPOINT_URL)->send($method, $url, $options);
|
||||
|
||||
$json = $response->throw()->json();
|
||||
|
||||
if (data_get($json, 'code') === 1000) {
|
||||
return $json;
|
||||
}
|
||||
|
||||
throw new LinkosFarmException(
|
||||
data_get($json, 'message', '出错啦'),
|
||||
data_get($json, 'code', 0),
|
||||
);
|
||||
}
|
||||
|
||||
protected function token(): string
|
||||
{
|
||||
if ($this->token && $this->expires > now()->unix() + 30) {
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
$result = $this->post('/api/v2.0/entrance/user/userLogin', [
|
||||
'loginName' => $this->loginName,
|
||||
'loginPwd' => $this->loginPwd,
|
||||
]);
|
||||
|
||||
$this->expires = $result['data']['expDate'];
|
||||
|
||||
return $this->token = $result['data']['token'];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class InsecticidalLampDailyReport extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $casts = [
|
||||
'reported_at' => 'date',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'device_id',
|
||||
'agricultural_base_id',
|
||||
'battery_vol',
|
||||
'killed_num',
|
||||
'air_temperature',
|
||||
'air_humidity',
|
||||
'charging_vol',
|
||||
'high_vol',
|
||||
'reported_at',
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class InsecticidalLampReport extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $casts = [
|
||||
'reported_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'device_id',
|
||||
'agricultural_base_id',
|
||||
'battery_vol',
|
||||
'killed_num',
|
||||
'air_temperature',
|
||||
'air_humidity',
|
||||
'charging_vol',
|
||||
'high_vol',
|
||||
'reported_at',
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class WormPhoto extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $casts = [
|
||||
'uploaded_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'device_id', 'url', 'uploaded_at',
|
||||
];
|
||||
|
||||
public function imageUrl(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function(mixed $value, array $attributes) {
|
||||
if (preg_match('/^https?:\/\//', $attributes['url']) > 0) {
|
||||
return $attributes['url'];
|
||||
}
|
||||
return Storage::disk('public')->url($attributes['url']);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class WormReport extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $casts = [
|
||||
'data' => 'json',
|
||||
'reported_at' => 'date',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'device_id', 'agricultural_base_id', 'worm_num', 'data', 'reported_at',
|
||||
];
|
||||
}
|
||||
|
|
@ -2,69 +2,48 @@
|
|||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Enums\DeviceStatus;
|
||||
use App\Enums\DeviceType;
|
||||
use App\Iot\BiAng\HttpClient as BiAngHttpClient;
|
||||
use App\Exceptions\BizException;
|
||||
use App\Iot\BiAng\HttpClient;
|
||||
use App\Models\Device;
|
||||
use App\Models\DeviceLog;
|
||||
use App\Models\InsecticidalLampDailyReport;
|
||||
use App\Models\InsecticidalLampReport;
|
||||
use App\Models\MeteorologicalMonitoringDailyLog;
|
||||
use App\Models\MeteorologicalMonitoringLog;
|
||||
use App\Models\SoilMonitoringDailyLog;
|
||||
use App\Models\SoilMonitoringLog;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class BiAngDeviceLogService
|
||||
class BiAngDeviceService
|
||||
{
|
||||
public function sync(Device $device): void
|
||||
/**
|
||||
* 虫情设备/昆虫性诱设备 - 查询某个时间段内的图片
|
||||
*/
|
||||
public function getWormPhotos(Device $device, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$config = json_decode($device->project?->value, true);
|
||||
if (! isset($config['username'], $config['password'])) {
|
||||
return;
|
||||
try {
|
||||
$httpClient = $this->buildHttpClient($device);
|
||||
} catch (BizException $e) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$httpClient = new BiAngHttpClient($config['username'], $config['password']);
|
||||
return $httpClient->getWormPhotos($device->sn, $start, $end);
|
||||
}
|
||||
|
||||
$data = null;
|
||||
|
||||
switch ($device->type) {
|
||||
case DeviceType::Soil:
|
||||
$data = $httpClient->getLatestSoilReport($device->sn);
|
||||
break;
|
||||
|
||||
case DeviceType::Meteorological:
|
||||
$data = $httpClient->getLatestMeteorologicalReport($device->sn);
|
||||
break;
|
||||
/**
|
||||
* 虫情设备 - (识别款)图片虫数识别统计
|
||||
*/
|
||||
public function getWormStatistics(Device $device, Carbon $start, Carbon $end): array
|
||||
{
|
||||
try {
|
||||
$httpClient = $this->buildHttpClient($device);
|
||||
} catch (BizException $e) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (is_array($data) && isset($data['time'])) {
|
||||
$log = DeviceLog::firstOrCreate([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $data['time'],
|
||||
], [
|
||||
'data' => Arr::except($data, ['deviceId', 'time']),
|
||||
]);
|
||||
|
||||
switch ($device->status) {
|
||||
case DeviceStatus::Online:
|
||||
// 如果设备数据在线时,最近60分钟内没有数据,则视为离线
|
||||
if (now()->subMinutes(60)->gt($log->reported_at)) {
|
||||
$device->update([
|
||||
'status' => DeviceStatus::Offline,
|
||||
]);
|
||||
}
|
||||
break;
|
||||
case DeviceStatus::Offline:
|
||||
// 如果设备数据离线时,最近60分钟内有数据,则视为在线
|
||||
if (now()->subMinutes(60)->lt($log->reported_at)) {
|
||||
$device->update([
|
||||
'status' => DeviceStatus::Online,
|
||||
]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $httpClient->getWormStatistics($device->sn, $start, $end);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -80,6 +59,10 @@ class BiAngDeviceLogService
|
|||
case DeviceType::Meteorological:
|
||||
$this->createMeteorologicalReport($device, $time);
|
||||
break;
|
||||
|
||||
case DeviceType::InsecticidalLamp:
|
||||
$this->createInsecticidalLampReport($device, $time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -239,6 +222,90 @@ class BiAngDeviceLogService
|
|||
$meteorologicalReport->fill($attributes)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建杀虫灯设备报告
|
||||
*/
|
||||
protected function createInsecticidalLampReport(Device $device, Carbon $time): void
|
||||
{
|
||||
$reportedAt = $time->copy()->startOfHour();
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$logs = DeviceLog::where('device_id', $device->id)
|
||||
->whereBetween('reported_at', [$reportedAt, $reportedAt->copy()->endOfHour()])
|
||||
->oldest('reported_at')
|
||||
->get();
|
||||
|
||||
if ($logs->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = value(function ($logs) {
|
||||
$data = [
|
||||
'vol' => ['sum' => 0, 'count' => 0],
|
||||
'sunVol' => ['sum' => 0, 'count' => 0],
|
||||
'dct' => ['sum' => 0, 'count' => 0],
|
||||
'temp' => ['sum' => 0, 'count' => 0],
|
||||
'humidity' => ['sum' => 0, 'count' => 0],
|
||||
'highVol' => ['sum' => 0, 'count' => 0],
|
||||
];
|
||||
|
||||
/** @var \App\Models\DeviceLog */
|
||||
foreach ($logs as $log) {
|
||||
if (! is_array($log->data)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($data as $k => $item) {
|
||||
$v = $log->data[$k] ?? null;
|
||||
|
||||
if (is_null($v)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item['sum'] = bcadd($item['sum'], $v, 2);
|
||||
$item['count']++;
|
||||
|
||||
$data[$k] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
|
||||
foreach ($data as $key => $item) {
|
||||
$attribute = match ($key) {
|
||||
'vol' => 'battery_vol',
|
||||
'sunVol' => 'charging_vol',
|
||||
'dct' => 'killed_num',
|
||||
'temp' => 'air_temperature',
|
||||
'humidity' => 'air_humidity',
|
||||
'highVol' => 'high_vol',
|
||||
};
|
||||
|
||||
if ($item['count'] > 0) {
|
||||
if ($attribute === 'killed_num') {
|
||||
$attributes[$attribute] = (int) $item['sum'];
|
||||
} else {
|
||||
$attributes[$attribute] = round(bcdiv($item['sum'], $item['count'], 2), 2);
|
||||
}
|
||||
} else {
|
||||
$attributes[$attribute] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}, $logs);
|
||||
|
||||
/** @var \App\Models\InsecticidalLampReport */
|
||||
$insecticidalLampReport = InsecticidalLampReport::firstOrNew([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $reportedAt,
|
||||
], [
|
||||
'agricultural_base_id' => $device->agricultural_base_id,
|
||||
]);
|
||||
|
||||
$insecticidalLampReport->fill($attributes)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建设备每日报告
|
||||
*/
|
||||
|
|
@ -252,6 +319,10 @@ class BiAngDeviceLogService
|
|||
case DeviceType::Soil:
|
||||
$this->createSoilDailyReport($device, $time);
|
||||
break;
|
||||
|
||||
case DeviceType::InsecticidalLamp:
|
||||
$this->createInsecticidalLampDailyReport($device, $time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -450,4 +521,84 @@ class BiAngDeviceLogService
|
|||
|
||||
$meteorologicalDailyReport->fill($attributes)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 杀虫灯每日报告
|
||||
*/
|
||||
protected function createInsecticidalLampDailyReport(Device $device, Carbon $date): void
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$insecticidalLampReports = InsecticidalLampReport::where('device_id', $device->id)
|
||||
->whereDate('reported_at', $date)
|
||||
->oldest('reported_at')
|
||||
->get();
|
||||
|
||||
if ($insecticidalLampReports->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = value(function ($insecticidalLampReports) {
|
||||
$data = [
|
||||
'killed_num' => ['sum' => 0, 'count' => 0],
|
||||
'battery_vol' => ['sum' => 0, 'count' => 0],
|
||||
'air_temperature' => ['sum' => 0, 'count' => 0],
|
||||
'air_humidity' => ['sum' => 0, 'count' => 0],
|
||||
'charging_vol' => ['sum' => 0, 'count' => 0],
|
||||
'high_vol' => ['sum' => 0, 'count' => 0],
|
||||
];
|
||||
|
||||
foreach ($insecticidalLampReports as $insecticidalLampReport) {
|
||||
foreach ($data as $k => $item) {
|
||||
if (is_null($v = $insecticidalLampReport->{$k})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item['sum'] = bcadd($item['sum'], $v, 2);
|
||||
$item['count']++;
|
||||
|
||||
$data[$k] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
|
||||
foreach ($data as $key => $item) {
|
||||
if ($item['count'] > 0) {
|
||||
if ($key === 'killed_num') {
|
||||
$attributes[$key] = (int) $item['sum'];
|
||||
} else {
|
||||
$attributes[$key] = round(bcdiv($item['sum'], $item['count'], 2), 2);
|
||||
}
|
||||
} else {
|
||||
$attributes[$key] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}, $insecticidalLampReports);
|
||||
|
||||
/** @var \App\Models\InsecticidalLampDailyReport */
|
||||
$insecticidalLampDailyReport = InsecticidalLampDailyReport::firstOrNew([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $date->format('Y-m-d'),
|
||||
], [
|
||||
'agricultural_base_id' => $device->agricultural_base_id,
|
||||
]);
|
||||
|
||||
$insecticidalLampDailyReport->fill($attributes)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 HTTP 客户端
|
||||
*/
|
||||
public function buildHttpClient(Device $device): HttpClient
|
||||
{
|
||||
$config = json_decode($device->project?->value, true);
|
||||
|
||||
if (! is_array($config)) {
|
||||
throw new BizException('账户信息未找到');
|
||||
}
|
||||
|
||||
return new HttpClient($config['username'] ?? '', $config['password'] ?? '');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Enums\DeviceType;
|
||||
use App\Models\Device;
|
||||
use App\Models\DeviceLog;
|
||||
use App\Models\InsecticidalLampDailyReport;
|
||||
use App\Models\InsecticidalLampReport;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class YunFeiDeviceService
|
||||
{
|
||||
/**
|
||||
* 创建设备报告
|
||||
*/
|
||||
public function createReport(Device $device, Carbon $time): void
|
||||
{
|
||||
switch ($device->type) {
|
||||
case DeviceType::InsecticidalLamp:
|
||||
$this->createInsecticidalLampReport($device, $time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建杀虫灯设备报告
|
||||
*/
|
||||
protected function createInsecticidalLampReport(Device $device, Carbon $time): void
|
||||
{
|
||||
$reportedAt = $time->copy()->startOfHour();
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$logs = DeviceLog::where('device_id', $device->id)
|
||||
->whereBetween('reported_at', [$reportedAt, $reportedAt->copy()->endOfHour()])
|
||||
->oldest('reported_at')
|
||||
->get();
|
||||
|
||||
if ($logs->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = value(function ($logs) {
|
||||
$data = [
|
||||
'battery_vol' => ['sum' => 0, 'count' => 0],
|
||||
'charging_vol' => ['sum' => 0, 'count' => 0],
|
||||
'killed_num' => ['sum' => 0, 'count' => 0],
|
||||
'air_temperature' => ['sum' => 0, 'count' => 0],
|
||||
'air_humidity' => ['sum' => 0, 'count' => 0],
|
||||
];
|
||||
|
||||
/** @var \App\Models\DeviceLog */
|
||||
foreach ($logs as $log) {
|
||||
if (! is_array($log->data)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($data as $key => $item) {
|
||||
switch ($key) {
|
||||
// 电池电压
|
||||
case 'battery_vol':
|
||||
if (! is_null($bv = Arr::get($log->data, 'bv'))) {
|
||||
$item['sum'] = bcadd($item['sum'], $bv, 2);
|
||||
$item['count'] += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
// 充电电压
|
||||
case 'charging_vol':
|
||||
if (! is_null($cv = Arr::get($log->data, 'cv'))) {
|
||||
$item['sum'] = bcadd($item['sum'], $cv, 2);
|
||||
$item['count'] += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
// 杀虫数
|
||||
case 'killed_num':
|
||||
if (! is_null($ct = Arr::get($log->data, 'ct'))) {
|
||||
$item['sum'] += $ct;
|
||||
$item['count'] += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
// 温度
|
||||
case 'air_temperature':
|
||||
if (! is_null($at = Arr::get($log->data, 'at'))) {
|
||||
$item['sum'] = bcadd($item['sum'], $at, 2);
|
||||
$item['count'] += 1;
|
||||
}
|
||||
break;
|
||||
|
||||
// 湿度
|
||||
case 'air_humidity':
|
||||
if (! is_null($ah = Arr::get($log->data, 'ah'))) {
|
||||
$item['sum'] = bcadd($item['sum'], $ah, 2);
|
||||
$item['count'] += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$data[$key] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
|
||||
foreach ($data as $key => $item) {
|
||||
if ($item['count'] > 0) {
|
||||
if ($key === 'killed_num') {
|
||||
$attributes[$key] = (int) $item['sum'];
|
||||
} else {
|
||||
$attributes[$key] = round(bcdiv($item['sum'], $item['count'], 2), 2);
|
||||
}
|
||||
} else {
|
||||
$attributes[$key] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}, $logs);
|
||||
|
||||
/** @var \App\Models\InsecticidalLampReport */
|
||||
$insecticidalLampReport = InsecticidalLampReport::firstOrNew([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $reportedAt,
|
||||
], [
|
||||
'agricultural_base_id' => $device->agricultural_base_id,
|
||||
]);
|
||||
|
||||
$insecticidalLampReport->fill($attributes)->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建设备每日报告
|
||||
*/
|
||||
public function createDailyReport(Device $device, Carbon $time): void
|
||||
{
|
||||
switch ($device->type) {
|
||||
case DeviceType::InsecticidalLamp:
|
||||
$this->createInsecticidalLampDailyReport($device, $time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 杀虫灯每日报告
|
||||
*/
|
||||
protected function createInsecticidalLampDailyReport(Device $device, Carbon $date): void
|
||||
{
|
||||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$insecticidalLampReports = InsecticidalLampReport::where('device_id', $device->id)
|
||||
->whereDate('reported_at', $date)
|
||||
->oldest('reported_at')
|
||||
->get();
|
||||
|
||||
if ($insecticidalLampReports->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = value(function ($insecticidalLampReports) {
|
||||
$data = [
|
||||
'battery_vol' => ['sum' => 0, 'count' => 0],
|
||||
'charging_vol' => ['sum' => 0, 'count' => 0],
|
||||
'killed_num' => ['sum' => 0, 'count' => 0],
|
||||
'air_temperature' => ['sum' => 0, 'count' => 0],
|
||||
'air_humidity' => ['sum' => 0, 'count' => 0],
|
||||
'high_vol' => ['sum' => 0, 'count' => 0],
|
||||
];
|
||||
|
||||
foreach ($insecticidalLampReports as $insecticidalLampReport) {
|
||||
foreach ($data as $k => $item) {
|
||||
if (is_null($v = $insecticidalLampReport->{$k})) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$item['sum'] = bcadd($item['sum'], $v, 2);
|
||||
$item['count']++;
|
||||
|
||||
$data[$k] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
|
||||
foreach ($data as $key => $item) {
|
||||
if ($item['count'] > 0) {
|
||||
if ($key === 'killed_num') {
|
||||
$attributes[$key] = (int) $item['sum'];
|
||||
} else {
|
||||
$attributes[$key] = round(bcdiv($item['sum'], $item['count'], 2), 2);
|
||||
}
|
||||
} else {
|
||||
$attributes[$key] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}, $insecticidalLampReports);
|
||||
|
||||
/** @var \App\Models\InsecticidalLampDailyReport */
|
||||
$insecticidalLampDailyReport = InsecticidalLampDailyReport::firstOrNew([
|
||||
'device_id' => $device->id,
|
||||
'reported_at' => $date->format('Y-m-d'),
|
||||
], [
|
||||
'agricultural_base_id' => $device->agricultural_base_id,
|
||||
]);
|
||||
|
||||
$insecticidalLampDailyReport->fill($attributes)->save();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('worm_reports', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('device_id');
|
||||
$table->unsignedBigInteger('agricultural_base_id')->comment('农业基地ID');
|
||||
$table->unsignedInteger('worm_num')->comment('虫子数量');
|
||||
$table->json('data')->nullable();
|
||||
$table->date('reported_at')->comment('报告日期');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('worm_reports');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('insecticidal_lamp_reports', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('device_id');
|
||||
$table->unsignedBigInteger('agricultural_base_id')->comment('农业基地ID');
|
||||
$table->double('battery_vol')->nullable()->comment('蓄电池电压');
|
||||
$table->unsignedInteger('killed_num')->default(0)->comment('杀虫数');
|
||||
$table->double('air_temperature')->nullable()->comment('大气气温');
|
||||
$table->double('air_humidity')->nullable()->comment('大气湿度');
|
||||
$table->double('charging_vol')->nullable()->comment('充电电压');
|
||||
$table->double('high_vol')->nullable()->comment('高压值');
|
||||
$table->timestamp('reported_at')->comment('监控日期');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('insecticidal_lamp_reports');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('insecticidal_lamp_daily_reports', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('device_id');
|
||||
$table->unsignedBigInteger('agricultural_base_id')->comment('农业基地ID');
|
||||
$table->double('battery_vol')->nullable()->comment('蓄电池电压');
|
||||
$table->unsignedInteger('killed_num')->default(0)->comment('杀虫数');
|
||||
$table->double('air_temperature')->nullable()->comment('大气气温');
|
||||
$table->double('air_humidity')->nullable()->comment('大气湿度');
|
||||
$table->double('charging_vol')->nullable()->comment('充电电压');
|
||||
$table->double('high_vol')->nullable()->comment('高压值');
|
||||
$table->date('reported_at')->comment('监控日期');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('insecticidal_lamp_reports');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('worm_photos', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->unsignedBigInteger('device_id');
|
||||
$table->text('url')->nullable();
|
||||
$table->timestamp('uploaded_at')->comment('上传时间');
|
||||
$table->timestamps();
|
||||
|
||||
$table->index('uploaded_at');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('worm_photos');
|
||||
}
|
||||
};
|
||||
|
|
@ -15,46 +15,112 @@ class EndpointPermissionSeeder extends Seeder
|
|||
public function run()
|
||||
{
|
||||
$permissions = [
|
||||
'endpoint' => ['name' => '系统权限', 'curd' => false, 'in_path' => true, 'children' => [
|
||||
'monitor_data' => ['name' => '监测数据管理', 'curd' => false, 'children' => [
|
||||
'weather' => ['name' => '气象管理', 'curd' => ['index']],
|
||||
'camera' => ['name' => '智能监控', 'curd' => ['index']],
|
||||
'soil' => ['name' => '土壤监控', 'curd' => ['index'], 'children' => ['setting' => '设置', 'setting_edit' => '更新设置']],
|
||||
'water' => ['name' => '水质监控', 'curd' => ['index'], 'children' => ['setting' => '设置', 'setting_edit' => '更新设置']],
|
||||
]],
|
||||
'base_data' => ['name' => '基础数据管理', 'curd' => false, 'children' => [
|
||||
'citydata_statistics' => ['name' => '全市基础数据', 'curd' => ['index', 'edit']],
|
||||
//全市基础数据
|
||||
'agricultural_basic' => ['name' => '基地数据', 'curd' => true],
|
||||
'town_street' => ['name' => '城镇数据', 'curd' => ['index', 'edit']],
|
||||
//农作物数据
|
||||
'crops' => ['name' => '基地农作物', 'curd' => true],
|
||||
'town_crops' => ['name' => '镇街农作物', 'curd' => true],
|
||||
//农作物产量
|
||||
'crops_output' => ['name' => '基地产量', 'curd' => true],
|
||||
'town_crops_output' => ['name' => '镇街产量', 'curd' => true],
|
||||
// 'crops_flow' => ['name' => '农产品流向', 'curd' => true],
|
||||
// 'crops_price' => ['name' => '农产品价格走势', 'curd' => ['index'], 'children' => ['is_enable' => '自动监测开关']],
|
||||
]],
|
||||
'industry_data' => ['name' => '重点产业', 'curd' => false, 'children' => [
|
||||
'rice_shrimp_prices' => ['name' => '稻虾价格', 'curd' => true],
|
||||
'rice_shrimp_weekly_prices' => ['name' => '稻虾每周价格', 'curd' => true],
|
||||
'rice_shrimp_industries' => ['name' => '稻虾产业', 'curd' => true],
|
||||
'rice_shrimp_flows' => ['name' => '稻虾走向', 'curd' => true],
|
||||
'materiels' => ['name' => '大宗物资', 'curd' => true],
|
||||
]],
|
||||
'device_data' => ['name' => '设备管理', 'curd' => false, 'children' => [
|
||||
'device' => ['name' => '设备管理', 'curd' => true],
|
||||
]],
|
||||
'manage' => ['name' => '系统管理', 'curd' => false, 'children' => [
|
||||
'admin_users' => ['name' => '管理员管理', 'curd' => true, 'children' => [
|
||||
'edit_password' => '修改密码', 'enable' => '启用/禁用',
|
||||
'endpoint' => [
|
||||
'name' => '系统权限',
|
||||
'curd' => false,
|
||||
'in_path' => true,
|
||||
'children' => [
|
||||
'data_dashboard' => [
|
||||
'name' => '数据看板',
|
||||
'curd' => false,
|
||||
],
|
||||
'monitor_data' => [
|
||||
'name' => '监测数据管理',
|
||||
'curd' => false,
|
||||
'children' => [
|
||||
'weather' => ['name' => '气象管理', 'curd' => ['index']],
|
||||
'camera' => ['name' => '智能监控', 'curd' => ['index']],
|
||||
'soil' => [
|
||||
'name' => '土壤监控',
|
||||
'curd' => ['index'],
|
||||
'children' => [
|
||||
'setting' => '设置',
|
||||
'setting_edit' => '更新设置'
|
||||
],
|
||||
],
|
||||
'water' => [
|
||||
'name' => '水质监控',
|
||||
'curd' => ['index'],
|
||||
'children' => [
|
||||
'setting' => '设置',
|
||||
'setting_edit' => '更新设置',
|
||||
],
|
||||
],
|
||||
'insect' => ['name' => '昆虫性诱监测', 'curd' => ['index']],
|
||||
'worm_statics' => ['name' => '虫情监测', 'curd' => ['index']],
|
||||
'insecticidal_lamp' => ['name' => '杀虫灯监测', 'curd' => ['index']],
|
||||
],
|
||||
],
|
||||
'base_data' => [
|
||||
'name' => '基础数据管理',
|
||||
'curd' => false,
|
||||
'children' => [
|
||||
'citydata_statistics' => [
|
||||
'name' => '全市基础数据',
|
||||
'curd' => false,
|
||||
'children'=>[
|
||||
'town_street' => [
|
||||
'name' => '城镇数据',
|
||||
'curd' => ['index', 'edit'],
|
||||
'children'=>[
|
||||
'base_statistics'=>'市基础数据',
|
||||
'base_statistics_edit'=>'修改市基础数据'
|
||||
]
|
||||
],
|
||||
//全市基础数据
|
||||
'agricultural_basic' => ['name' => '基地数据', 'curd' => true],
|
||||
],
|
||||
],
|
||||
//农作物数据
|
||||
'citydata_crops' =>['name'=>'农作物数据','curd'=>false, 'children'=>[
|
||||
'town_crops' => ['name' => '城镇农作物', 'curd' => true],
|
||||
'crops' => ['name' => '基地农作物', 'curd' => true],
|
||||
]],
|
||||
//农作物产量
|
||||
'citydata_output'=>['name'=>'农作物产量','curd'=>false, 'children'=>[
|
||||
'town_crops_output' => ['name' => '城镇产量', 'curd' => true],
|
||||
'crops_output' => ['name' => '基地产量', 'curd' => true],
|
||||
]],
|
||||
// 重点产业
|
||||
'industry_data' => [
|
||||
'name' => '重点产业',
|
||||
'curd' => false,
|
||||
'children' => [
|
||||
'rice_shrimp_prices' => ['name' => '稻虾价格', 'curd' => true],
|
||||
'rice_shrimp_weekly_prices' => ['name' => '稻虾每周价格', 'curd' => true],
|
||||
'rice_shrimp_industries' => ['name' => '稻虾产业', 'curd' => true],
|
||||
'rice_shrimp_flows' => ['name' => '稻虾走向', 'curd' => true],
|
||||
'materiels' => ['name' => '大宗物资', 'curd' => true],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
'device_data' => [
|
||||
'name' => '设备管理',
|
||||
'curd' => false,
|
||||
'children' => [
|
||||
'device' => ['name' => '设备管理', 'curd' => true],
|
||||
'warnings' => ['name' => '警报明细', 'curd' => false,'children'=>['mark'=>'标记'],
|
||||
],
|
||||
]],
|
||||
'admin_roles' => ['name' => '角色管理', 'curd' => true],
|
||||
'operation_log' => ['name' => '操作日志', 'curd' => ['index']],
|
||||
'friend_links' => ['name' => '友情链接', 'curd' => true]
|
||||
]],
|
||||
]]
|
||||
'manage' => [
|
||||
'name' => '系统管理',
|
||||
'curd' => false,
|
||||
'children' => [
|
||||
'admin_roles' => ['name' => '角色管理', 'curd' => true],
|
||||
'admin_users' => [
|
||||
'name' => '账号管理',
|
||||
'curd' => true,
|
||||
'children' => [
|
||||
'edit_password' => '修改密码', 'enable' => '启用/禁用',
|
||||
]
|
||||
],
|
||||
'operation_log' => ['name' => '系统日志', 'curd' => ['index']],
|
||||
'friend_links' => ['name' => '友情链接', 'curd' => true],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
$this->createPermissionData($permissions);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ class KeywordsTableSeeder extends Seeder
|
|||
'list' => [
|
||||
['key' => 'device-supplier-linkos', 'name' => '慧联无限', 'value' => ''],
|
||||
['key' => 'device-supplier-biang', 'name' => '比昂', 'value' => ''],
|
||||
['key' => 'device-supplier-yunfei', 'name' => '云飞', 'value' => ''],
|
||||
['key' => 'device-supplier-other', 'name' => '其它', 'value' => ''],
|
||||
],
|
||||
],
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ use Illuminate\Support\Facades\Route;
|
|||
|
||||
Route::post('auth/login', [AuthController::class, 'login']);
|
||||
|
||||
Route::group(['middleware' => 'auth:sanctum'], function () {
|
||||
Route::group([
|
||||
'middleware' => ['auth:sanctum'],
|
||||
], function () {
|
||||
|
||||
Route::post('web/upload', [WebController::class, 'upload']);
|
||||
|
||||
|
|
@ -39,6 +41,7 @@ Route::group(['middleware' => 'auth:sanctum'], function () {
|
|||
Route::apiResource('town-street', AgriculturalBaseController::class)->names('town_street');//镇街
|
||||
Route::get('agricultural-device-basic', [AgriculturalBaseController::class, 'deviceBase'])->name('agricultural_basic.device_bases'); //通过设备类型查询基地
|
||||
Route::get('agricultural-device-point/{agricultural_basic}', [AgriculturalBaseController::class, 'basePointList']);//获取基地对应监控点
|
||||
Route::get('agricultural-device-points', [AgriculturalBaseController::class, 'basePoints']);
|
||||
|
||||
//农作物
|
||||
Route::apiResource('crops', CropController::class)->names('crops');//基地农作物
|
||||
|
|
@ -54,6 +57,8 @@ Route::group(['middleware' => 'auth:sanctum'], function () {
|
|||
Route::apiResource('crop-flows', CropFlowController::class)->names('crops_flow');
|
||||
//设备管理
|
||||
Route::apiResource('devices', DeviceController::class)->names('device');
|
||||
Route::get('devices/{device}/worm-statics', [DeviceController::class, 'wormStatics']);
|
||||
Route::get('devices/{device}/worm-photos', [DeviceController::class, 'wormPhotos']);
|
||||
Route::put('devices-update-recommend/{device}', [DeviceController::class, 'updateRecommendStatus']);
|
||||
Route::get('devices-num', [DeviceController::class, 'typeStatusNum'])->name('device.type_status_num');
|
||||
Route::get('monitoring-data', [DeviceController::class, 'timeZoneList']);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
<?php
|
||||
|
||||
use App\Http\Controllers\Callback\LinkosController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use App\Http\Middleware\ApiCustomToken;
|
||||
use App\Http\Controllers\Callback\YunFeiController;
|
||||
use App\Http\Controllers\ThirdApi\SendSmsController;
|
||||
use App\Http\Middleware\ApiCustomToken;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::post('callback/linkos', LinkosController::class);
|
||||
Route::post('callback/yunfei/insecticidal-lamp-notify', [YunFeiController::class, 'insecticidalLampNotify']);
|
||||
Route::post('callback/yunfei/worm-notify', [YunFeiController::class, 'wormNotify']);
|
||||
Route::post('callback/yunfei/worm-photo-notify', [YunFeiController::class, 'wormPhotoNotify']);
|
||||
|
||||
Route::group(['prefix'=>'third'], function(){
|
||||
Route::middleware([ApiCustomToken::class])->group(function(){
|
||||
|
|
|
|||
Loading…
Reference in New Issue