From 015e10682fcdf32dab70fd7453a5d555d6fba25c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=9D=99?= Date: Sat, 6 May 2023 18:02:02 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AE=BE=E5=A4=87=E7=9B=91=E6=8E=A7=E6=8A=A5?= =?UTF-8?q?=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Commands/DeviceLogReportCommand.php | 197 ++++++++++++++++++ app/Models/MeteorologicalMonitoringReport.php | 36 ++++ app/Models/SoilMonitoringReport.php | 26 +++ app/Models/WaterQualityMonitoringReport.php | 26 +++ ...7_create_soil_monitoring_reports_table.php | 41 ++++ ...water_quality_monitoring_reports_table.php | 41 ++++ ...eteorological_monitoring_reports_table.php | 51 +++++ 7 files changed, 418 insertions(+) create mode 100644 app/Console/Commands/DeviceLogReportCommand.php create mode 100644 app/Models/MeteorologicalMonitoringReport.php create mode 100644 app/Models/SoilMonitoringReport.php create mode 100644 app/Models/WaterQualityMonitoringReport.php create mode 100644 database/migrations/2023_05_06_103057_create_soil_monitoring_reports_table.php create mode 100644 database/migrations/2023_05_06_103152_create_water_quality_monitoring_reports_table.php create mode 100644 database/migrations/2023_05_06_103216_create_meteorological_monitoring_reports_table.php diff --git a/app/Console/Commands/DeviceLogReportCommand.php b/app/Console/Commands/DeviceLogReportCommand.php new file mode 100644 index 0000000..369f217 --- /dev/null +++ b/app/Console/Commands/DeviceLogReportCommand.php @@ -0,0 +1,197 @@ +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(['factory'])->poweredBy($factory)->get(); + + foreach ($devices as $device) { + $this->createMonitoringReport($device); + } + + sleep($sleep); + }; + } + + protected function createMonitoringReport(Device $device) + { + switch ($device->factory?->key) { + case 'link-os': + $this->createLinkosDeviceMonitoringReport($device); + break; + } + } + + protected function createLinkosDeviceMonitoringReport(Device $device) + { + switch ($device->type) { + case Device::TYPE_SOIL: + $lastMonitoringReport = SoilMonitoringReport::where('device_id', $device->id) + ->latest('reported_at') + ->first(); + + $lastReportedAt = $lastMonitoringReport?->reported_at; + + $device->logs() + ->when($lastReportedAt, fn ($query, $lastReportedAt) => $query->where('reported_at', '>=', $lastReportedAt->reported_at)) + ->oldest('reported_at') + ->chunkById(500, function ($deviceLogs) use ($device, &$lastMonitoringReport) { + /** @var \App\Models\DeviceLog */ + foreach ($deviceLogs as $deviceLog) { + $monitoringReport = SoilMonitoringReport::firstOrCreate( + [ + 'device_id' => $device->id, + 'reported_at' => $deviceLog->reported_at->startOfHour(), + ], + Arr::except($lastMonitoringReport?->setHidden([])?->attributesToArray() ?: [], ['reported_at']) + ); + + foreach ([ + 'conductivity' => 'conductivity', + 'soil_humidity' => 'humidity', + 'soil_temperature' => 'temperature', + 'nitrogen_content' => 'n', + 'potassium_content' => 'k', + 'phosphorus_content' => 'p', + ] as $key => $attribute) { + if (! is_array($deviceLog->data) || ! array_key_exists($key, $deviceLog->data)) { + continue; + } + + $monitoringReport->{$attribute} = $deviceLog->data[$key]; + } + + $lastMonitoringReport = tap($monitoringReport)->save(); + } + }); + break; + + case Device::TYPE_WATER_QUALITY: + $lastMonitoringReport = WaterQualityMonitoringReport::where('device_id', $device->id) + ->latest('reported_at') + ->first(); + + $lastReportedAt = $lastMonitoringReport?->reported_at; + + $device->logs() + ->when($lastReportedAt, fn ($query, $lastReportedAt) => $query->where('reported_at', '>=', $lastReportedAt->reported_at)) + ->oldest('reported_at') + ->chunkById(500, function ($deviceLogs) use ($device, &$lastMonitoringReport) { + /** @var \App\Models\DeviceLog */ + foreach ($deviceLogs as $deviceLog) { + $monitoringReport = WaterQualityMonitoringReport::firstOrCreate( + [ + 'device_id' => $device->id, + 'reported_at' => $deviceLog->reported_at->startOfHour(), + ], + Arr::except($lastMonitoringReport?->setHidden([])?->attributesToArray() ?: [], ['reported_at']) + ); + + foreach ([ + 'chlorine' => 'chlorine', + 'conductivity' => 'conductivity', + 'oxygen' => 'oxygen', + 'ph' => 'ph', + 'temp' => 'temperature', + 'turbidity' => 'turbidity', + ] as $key => $attribute) { + if (! is_array($deviceLog->data) || ! array_key_exists($key, $deviceLog->data)) { + continue; + } + + $monitoringReport->{$attribute} = $deviceLog->data[$key]; + } + + $lastMonitoringReport = tap($monitoringReport)->save(); + } + }); + break; + + case Device::TYPE_METEOROLOGICAL: + $lastMonitoringReport = MeteorologicalMonitoringReport::where('device_id', $device->id) + ->latest('reported_at') + ->first(); + + $lastReportedAt = $lastMonitoringReport?->reported_at; + + $device->logs() + ->when($lastReportedAt, fn ($query, $lastReportedAt) => $query->where('reported_at', '>=', $lastReportedAt->reported_at)) + ->oldest('reported_at') + ->chunkById(500, function ($deviceLogs) use ($device, &$lastMonitoringReport) { + /** @var \App\Models\DeviceLog */ + foreach ($deviceLogs as $deviceLog) { + $monitoringReport = MeteorologicalMonitoringReport::firstOrCreate( + [ + 'device_id' => $device->id, + 'reported_at' => $deviceLog->reported_at->startOfHour(), + ], + Arr::except($lastMonitoringReport?->setHidden([])?->attributesToArray() ?: [], ['reported_at']) + ); + + foreach ([ + 'current_rainfall' => 'today_rainfall', + 'day_rainfall' => 'yesterday_rainfall', + 'accumulate_rainfall' => 'accumulate_rainfall', + 'moment_rainfall' => 'moment_rainfall', + 'pm10_concentration' => 'pm10', + 'pm25_concentration' => 'pm25', + 'box_illumination' => 'box_illumination', + 'box_pressure' => 'box_pressure', + 'box_carbon' => 'box_co2', + 'box_temperature' => 'box_temperature', + 'box_humidity' => 'box_humidity', + 'box_noise' => 'box_noise', + 'wind_degree' => 'wind_degree', + 'wind_direction' => 'wind_direction', + 'wind_power' => 'wind_power', + 'wind_speed' => 'wind_speed', + ] as $key => $attribute) { + if (! is_array($deviceLog->data) || ! array_key_exists($key, $deviceLog->data)) { + continue; + } + + $monitoringReport->{$attribute} = $deviceLog->data[$key]; + } + + $lastMonitoringReport = tap($monitoringReport)->save(); + } + }); + break; + } + } +} diff --git a/app/Models/MeteorologicalMonitoringReport.php b/app/Models/MeteorologicalMonitoringReport.php new file mode 100644 index 0000000..904425f --- /dev/null +++ b/app/Models/MeteorologicalMonitoringReport.php @@ -0,0 +1,36 @@ + 'datetime' + ]; + + protected $fillable = [ + 'device_id', + 'today_rainfall', + 'yesterday_rainfall', + 'accumulate_rainfall', + 'moment_rainfall', + 'pm10', + 'pm25', + 'box_illumination', + 'box_pressure', + 'box_co2', + 'box_temperature', + 'box_humidity', + 'box_noise', + 'wind_degree', + 'wind_direction', + 'wind_power', + 'wind_speed', + 'reported_at', + ]; +} diff --git a/app/Models/SoilMonitoringReport.php b/app/Models/SoilMonitoringReport.php new file mode 100644 index 0000000..bdba671 --- /dev/null +++ b/app/Models/SoilMonitoringReport.php @@ -0,0 +1,26 @@ + 'datetime', + ]; + + protected $fillable = [ + 'device_id', + 'temperature', + 'humidity', + 'n', + 'p', + 'k', + 'conductivity', + 'reported_at', + ]; +} diff --git a/app/Models/WaterQualityMonitoringReport.php b/app/Models/WaterQualityMonitoringReport.php new file mode 100644 index 0000000..b943b45 --- /dev/null +++ b/app/Models/WaterQualityMonitoringReport.php @@ -0,0 +1,26 @@ + 'datetime' + ]; + + protected $fillable = [ + 'device_id', + 'chlorine', + 'conductivity', + 'oxygen', + 'ph', + 'temperature', + 'turbidity', + 'reported_at', + ]; +} diff --git a/database/migrations/2023_05_06_103057_create_soil_monitoring_reports_table.php b/database/migrations/2023_05_06_103057_create_soil_monitoring_reports_table.php new file mode 100644 index 0000000..daee1b2 --- /dev/null +++ b/database/migrations/2023_05_06_103057_create_soil_monitoring_reports_table.php @@ -0,0 +1,41 @@ +id(); + $table->unsignedBigInteger('device_id')->comment('设备ID'); + $table->decimal('temperature', 8, 2)->nullable()->comment('温度(单位: ℃)'); + $table->decimal('humidity', 8, 2)->nullable()->comment('湿度(单位: %RH)'); + $table->integer('n')->nullable()->comment('氮 (单位: mg/kg)'); + $table->integer('p')->nullable()->comment('磷 (单位: mg/kg)'); + $table->integer('k')->nullable()->comment('钾 (单位: mg/kg)'); + $table->decimal('conductivity', 8, 2)->nullable()->comment('电导率(单位: us/cm)'); + $table->timestamp('reported_at')->comment('报告时间(小时),示例: 2023-05-01 01:00:00'); + $table->timestamps(); + + $table->unique(['device_id', 'reported_at']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('soil_monitoring_reports'); + } +}; diff --git a/database/migrations/2023_05_06_103152_create_water_quality_monitoring_reports_table.php b/database/migrations/2023_05_06_103152_create_water_quality_monitoring_reports_table.php new file mode 100644 index 0000000..ac51ed3 --- /dev/null +++ b/database/migrations/2023_05_06_103152_create_water_quality_monitoring_reports_table.php @@ -0,0 +1,41 @@ +id(); + $table->unsignedBigInteger('device_id')->comment('设备ID'); + $table->decimal('chlorine', 8, 2)->nullable()->comment('余氯(单位: mg/L)'); + $table->decimal('conductivity', 8, 2)->nullable()->comment('电导率(单位: us/cm)'); + $table->decimal('oxygen', 8, 2)->nullable()->comment('溶解氧(单位: mg/L)'); + $table->decimal('ph', 8, 2)->nullable()->comment('PH'); + $table->decimal('temperature', 8, 2)->nullable()->comment('温度(单位: ℃)'); + $table->decimal('turbidity', 8, 2)->nullable()->comment('浊度(单位: NTU)'); + $table->timestamp('reported_at')->comment('报告时间(小时),示例: 2023-05-01 01:00:00'); + $table->timestamps(); + + $table->unique(['device_id', 'reported_at']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('water_quality_monitoring_reports'); + } +}; diff --git a/database/migrations/2023_05_06_103216_create_meteorological_monitoring_reports_table.php b/database/migrations/2023_05_06_103216_create_meteorological_monitoring_reports_table.php new file mode 100644 index 0000000..1c46fc3 --- /dev/null +++ b/database/migrations/2023_05_06_103216_create_meteorological_monitoring_reports_table.php @@ -0,0 +1,51 @@ +id(); + $table->unsignedBigInteger('device_id'); + $table->decimal('today_rainfall', 8, 2)->nullable()->comment('今日积雨量 (单位: mm)'); + $table->decimal('yesterday_rainfall', 8, 2)->nullable()->comment('昨日积雨量 (单位: mm)'); + $table->decimal('accumulate_rainfall', 8, 2)->nullable()->comment('累积雨量 (单位: mm)'); + $table->decimal('moment_rainfall', 8, 2)->nullable()->comment('瞬时雨量 (单位: mm)'); + $table->decimal('pm10', 8, 2)->nullable()->comment('PM10浓度 (单位: ug/m3)'); + $table->decimal('pm25', 8, 2)->nullable()->comment('PM2.5浓度 (单位: ug/m3)'); + $table->decimal('box_illumination', 10, 2)->nullable()->comment('百叶箱光照度 (单位: Lux)'); + $table->decimal('box_pressure', 8, 2)->nullable()->comment('百叶箱大气压力 (单位: Kpa)'); + $table->decimal('box_co2', 8, 2)->nullable()->comment('百叶箱CO2浓度 (单位: ppm)'); + $table->decimal('box_temperature', 8, 2)->nullable()->comment('百叶箱温度 (单位: ℃)'); + $table->decimal('box_humidity', 8, 2)->nullable()->comment('百叶箱湿度 (单位: %RH)'); + $table->decimal('box_noise', 8, 2)->nullable()->comment('百叶箱噪声 (单位: db)'); + $table->integer('wind_degree')->nullable()->comment('风向度数'); + $table->tinyInteger('wind_direction')->nullable()->comment('风向: 0 北风, 1 东北风, 2 东风, 3 东南风, 4 南风, 5 西南风, 6 西风, 7 西北风'); + $table->integer('wind_power')->nullable()->comment('风力 (单位: 级)'); + $table->decimal('wind_speed', 8, 2)->nullable()->comment('风速 (单位: m/s)'); + $table->timestamp('reported_at')->comment('报告时间(小时),示例: 2023-05-01 01:00:00'); + $table->timestamps(); + + $table->unique(['device_id', 'reported_at']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('meteorological_monitoring_reports'); + } +};