Merge branch 'develop' of gitea.hmily.club:liutk/internet-everythings-agricultural into develop
commit
b01e8e9aac
|
|
@ -13,6 +13,7 @@ use App\Models\MeteorologicalReport;
|
|||
use App\Models\MonitorMode;
|
||||
use App\Models\Region;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Services\MqttService;
|
||||
|
||||
class DeviceController extends AdminController
|
||||
{
|
||||
|
|
@ -279,7 +280,6 @@ class DeviceController extends AdminController
|
|||
amisMake()->Wrapper()->sm(6)->body([
|
||||
amisMake()->Panel()->title('智能开关设置')
|
||||
->labelWidth(100)
|
||||
->className('Panel--success')
|
||||
->body([
|
||||
\amisMake()->Form()->title('')->mode('horizontal')->body([
|
||||
amisMake()->FieldSetControl()->title('智能开启')->body([
|
||||
|
|
@ -325,7 +325,6 @@ class DeviceController extends AdminController
|
|||
]),
|
||||
amisMake()->Wrapper()->sm(6)->body([
|
||||
amisMake()->Panel()->title('开关记录')
|
||||
->className('Panel--success')
|
||||
->body([
|
||||
\amisMake()->Table()->title('')
|
||||
->data([
|
||||
|
|
@ -348,23 +347,79 @@ class DeviceController extends AdminController
|
|||
}
|
||||
|
||||
/**
|
||||
* 喷灌
|
||||
* 喷雾
|
||||
*/
|
||||
public function atomizingDetail(){
|
||||
$regionId = request()->input('region_id', 0);
|
||||
$config = null;
|
||||
$statusStr = '未知';
|
||||
if($regionId){
|
||||
$region = Region::find($regionId);
|
||||
if($region){
|
||||
$monitorMode = $region->monitorModes()->where('type', MonitorMode::TYPE_ATOMIZING)->first();
|
||||
$config = $monitorMode?->pivot->config ?? null;
|
||||
|
||||
if($monitorMode){
|
||||
//判断设备状态是否离线;
|
||||
$device = $monitorMode->devices()->first();
|
||||
if($device->state == Device::STATE_ONLINE){
|
||||
$res = (new MqttService())->getStatus();
|
||||
if($res['error']){
|
||||
switch($res['error']){
|
||||
case 1:
|
||||
$statusStr = '急停';
|
||||
break;
|
||||
case 2:
|
||||
$statusStr = '低水位报警';
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
if($res['is_running']){
|
||||
if($res['yv1']){
|
||||
$statusStr = '区域A运行中,喷雾量:'.$res['speed1'].'%';
|
||||
}elseif(['yv2']){
|
||||
$statusStr = '区域B运行中,喷雾量:'.$res['speed2'].'%';
|
||||
}
|
||||
}else{
|
||||
$statusStr = '未运行';
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$statusStr = Device::stateMap()[$device->state];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return amisMake()->Grid()->columns([
|
||||
amisMake()->Wrapper()->sm(6)->body([
|
||||
amisMake()->Panel()->title('智能喷灌设置')
|
||||
->subFormMode('horizontal')
|
||||
->labelWidth(80)
|
||||
->className('Panel--success')
|
||||
->body([
|
||||
\amisMake()->Form()->title('')->mode('horizontal')->body([
|
||||
amisMake()->FieldSetControl()->title('定时喷灌')->body([
|
||||
\amisMake()->Form()->title('')->mode('horizontal')
|
||||
->api([
|
||||
'method'=>'post',
|
||||
'url'=>admin_url('save-region-config').'/'.$regionId,
|
||||
'data'=>[
|
||||
'is_enable' => '${is_enable}',
|
||||
'config' => '${config}'
|
||||
]
|
||||
])
|
||||
->data($config ? json_decode($config) : [])
|
||||
->body([
|
||||
amisMake()->FieldSetControl()->title('当前状态')->body([
|
||||
amisMake()->TextControl('status', '状态')->value($statusStr),
|
||||
])->static(),
|
||||
amisMake()->FieldSetControl()->className('mt-10')->title('定时喷灌')->body([
|
||||
\amisMake()->SwitchControl()->name('is_enable')->label('开关'),
|
||||
\amisMake()->ArrayControl()->name('config')->label('定时')->items([
|
||||
amisMake()->ComboControl()->items([
|
||||
\amisMake()->InputTimeRange(),
|
||||
\amisMake()->TextControl()->name('input')->label('喷灌量')->labelWidth(30),
|
||||
amisMake()->SelectControl('value')->options([
|
||||
'a'=>'区域A','b'=>'区域B'
|
||||
]),
|
||||
\amisMake()->InputTimeRange()->name('time_zone'),
|
||||
Components::make()->decimalControl('input', '喷雾量%')->value(70)->percision(0)->step(1)->max(100)
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
|
|
@ -373,7 +428,6 @@ class DeviceController extends AdminController
|
|||
]),
|
||||
amisMake()->Wrapper()->sm(6)->body([
|
||||
amisMake()->Panel()->title('开关记录')
|
||||
->className('Panel--success')
|
||||
->body([
|
||||
\amisMake()->Table()->title('')
|
||||
->data([
|
||||
|
|
@ -394,4 +448,20 @@ class DeviceController extends AdminController
|
|||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
public function saveRegionConfig($id, Request $request)
|
||||
{
|
||||
if($id){
|
||||
$region = Region::find($id);
|
||||
if($region){
|
||||
$monitorMode = $region->monitorModes()->where('type', MonitorMode::TYPE_ATOMIZING)->first();
|
||||
$config = $request->input() ?? null;
|
||||
$res = $region->monitorModes()->updateExistingPivot($monitorMode->id, [
|
||||
'config' => $config,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->autoResponse($res, __('admin.save'));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ class MonitorModeController extends AdminController
|
|||
amisMake()->PickerControl('picker_devices', '喷雾设备')->visibleOn('data.type == '.MonitorMode::TYPE_ATOMIZING)
|
||||
->valueField('id')
|
||||
->labelField('name')
|
||||
->multiple(true)
|
||||
->multiple(false)//喷雾设备只能选择一个
|
||||
->size('lg')
|
||||
->source([
|
||||
'method' => 'get',
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ Route::group([
|
|||
|
||||
$router->post('custom-region-atomizing', '\App\Admin\Controllers\DeviceController@atomizingDetail');
|
||||
|
||||
$router->post('save-region-config/{id}', '\App\Admin\Controllers\DeviceController@saveRegionConfig');
|
||||
|
||||
//种植记录
|
||||
$router->resource('crop-plants', \App\Admin\Controllers\CropPlantController::class)->only(['index','store', 'edit', 'update', 'destroy']);
|
||||
$router->resource('crop-harvestes', \App\Admin\Controllers\CropHarvestController::class)->only(['index','store', 'edit', 'update', 'destroy']);
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ namespace App\Console\Commands;
|
|||
use App\Models\Device;
|
||||
use App\Services\DeviceLogService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Throwable;
|
||||
|
||||
class DeviceLogSyncCommand extends Command
|
||||
|
|
@ -64,7 +63,13 @@ class DeviceLogSyncCommand extends Command
|
|||
/** @var \Illuminate\Database\Eloquent\Collection */
|
||||
$devices = Device::with(['factory'])->poweredBy($factory)->get();
|
||||
|
||||
/** @var \App\Models\Device */
|
||||
foreach ($devices as $device) {
|
||||
// 忽略通风设备
|
||||
if ($device->isTypeAir()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->info('==========================================');
|
||||
$this->info('设备编号: ' . $device->sn);
|
||||
$this->info('设备名称: ' . $device->name);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class MqttPenwuPlan extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'mqtt:penwu-plan';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'MQTT 喷雾控制';//-todo
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
//获取所有喷雾监控点,对应的自动喷雾配置
|
||||
//获取当前时间(时,分)
|
||||
//判断该配置是否开启
|
||||
//判断当前该情况,并判断时间,决定开启,关闭,不作为;
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,7 @@ class LinkosCallbackController extends Controller
|
|||
{
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
logger()->info('linkos callback parameters -------->', $request->input());
|
||||
logger()->debug('linkos callback parameters -------->', $request->input());
|
||||
|
||||
if ($request->filled('notify_type')) {
|
||||
switch ($request->notify_type) {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class HttpClient
|
|||
* @param int $perPage
|
||||
* @return array
|
||||
*/
|
||||
public function getDeviceFlowList(string $deviceId, Carbon $start, Carbon $end, int $page = 1, int $perPage = 50): array
|
||||
public function deviceFlowList(string $deviceId, Carbon $start, Carbon $end, int $page = 1, int $perPage = 50): array
|
||||
{
|
||||
$result = $this->post('/api/deviceFlow/v1/list', [
|
||||
'device_id' => $deviceId,
|
||||
|
|
@ -38,9 +38,60 @@ class HttpClient
|
|||
],
|
||||
]);
|
||||
|
||||
if (data_get($result, 'success') !== true) {
|
||||
throw new RuntimeException(data_get($result, 'msg', '出错啦!'));
|
||||
}
|
||||
|
||||
return $result['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 设备数据下行
|
||||
*
|
||||
* @param string $deviceId
|
||||
* @param string $service
|
||||
* @param array $data
|
||||
* @param boolean $confirm
|
||||
* @param boolean $clear
|
||||
* @param boolean $schedule
|
||||
* @return array
|
||||
*/
|
||||
public function deviceDataDownlink(string $deviceId, string $service, array $data = [], bool $confirm = true, bool $clear = true, bool $schedule = false): array
|
||||
{
|
||||
return $this->post('/api/down', [
|
||||
'device_id' => $deviceId,
|
||||
'service_id' => $service,
|
||||
'parameter' => $data,
|
||||
'clear' => (int) $clear,
|
||||
'schedule' => (int) $schedule,
|
||||
'confirm' => (int) $confirm,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取设备最新属性数据
|
||||
*/
|
||||
public function getDeviceStatus(string $deviceId, array $props): array
|
||||
{
|
||||
$result = $this->get('/api/deviceStatus/v1/getDeviceStatus', [
|
||||
'deviceCode' => $deviceId,
|
||||
'prop' => implode(",", $props),
|
||||
]);
|
||||
|
||||
if (data_get($result, 'success') !== true) {
|
||||
throw new RuntimeException(data_get($result, 'msg', '出错啦!'));
|
||||
}
|
||||
|
||||
return $result['data'];
|
||||
}
|
||||
|
||||
public function get(string $url, array $query = []): array
|
||||
{
|
||||
return $this->request('GET', $url, [
|
||||
'query' => $query,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param array $data
|
||||
|
|
@ -77,13 +128,7 @@ class HttpClient
|
|||
'Signature' => $this->sign(compact('nonce', 'timestamp')),
|
||||
])->baseUrl(self::ENDPOINT_URL)->send($method, $url, $options);
|
||||
|
||||
$result = $response->throw()->json();
|
||||
|
||||
if (data_get($result, 'success') !== true) {
|
||||
throw new RuntimeException(data_get($result, 'msg', '出错啦!'));
|
||||
}
|
||||
|
||||
return $result;
|
||||
return $response->throw()->json();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -87,4 +87,9 @@ class Device extends Model
|
|||
{
|
||||
return $this->type === static::TYPE_METEOROLOGICAL;
|
||||
}
|
||||
|
||||
public function isTypeAir(): bool
|
||||
{
|
||||
return $this->type === static::TYPE_AIR;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class Region extends Model
|
|||
}
|
||||
|
||||
public function monitorModes(){
|
||||
return $this->belongsToMany(MonitorMode::class, RegionMonitor::class, 'region_id', 'monitor_id')->withTimestamps();
|
||||
return $this->belongsToMany(MonitorMode::class, RegionMonitor::class, 'region_id', 'monitor_id')->withTimestamps()->withPivot('config');
|
||||
}
|
||||
|
||||
// 种植记录
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class DeviceLogService
|
|||
$perPage = 50;
|
||||
|
||||
do {
|
||||
$data = $httpClient->getDeviceFlowList(
|
||||
$data = $httpClient->deviceFlowList(
|
||||
$device->sn, $start, $end, $page, $perPage
|
||||
);
|
||||
|
||||
|
|
@ -56,74 +56,25 @@ class DeviceLogService
|
|||
continue;
|
||||
}
|
||||
|
||||
if ($device->isTypeSoil()) {
|
||||
// 如果包含气象设备监测字段,则跳过
|
||||
if (Arr::hasAny($item['data'], [
|
||||
'day_rainfall',
|
||||
'accumulate_rainfall',
|
||||
'potassium_content',
|
||||
'moment_rainfall',
|
||||
'pm10_concentration',
|
||||
'pm25_concentration',
|
||||
'box_noise',
|
||||
'box_carbon',
|
||||
'box_humidity',
|
||||
'box_pressure',
|
||||
'box_temperature',
|
||||
'box_illumination',
|
||||
'wind_power',
|
||||
'wind_speed',
|
||||
'wind_degree',
|
||||
'wind_direction',
|
||||
])) {
|
||||
continue;
|
||||
}
|
||||
} elseif ($device->isTypeMeteorological()) {
|
||||
// 如果包含土壤设备监测字段,则跳过
|
||||
if (Arr::hasAny($item['data'], [
|
||||
'nitrogen_content',
|
||||
'phosphorus_content',
|
||||
'potassium_content',
|
||||
'conductivity',
|
||||
'soil_humidity',
|
||||
'soil_temperature',
|
||||
])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
$device->isTypeSoil() && Arr::hasAny($item['data'], [
|
||||
|
||||
])
|
||||
) {
|
||||
|
||||
} elseif (
|
||||
$device->isTypeMeteorological() &&
|
||||
Arr::hasAny(
|
||||
$item['data'],
|
||||
[
|
||||
'nitrogen_content',
|
||||
'phosphorus_content',
|
||||
'potassium_content',
|
||||
'conductivity',
|
||||
'soil_humidity',
|
||||
'soil_temperature',
|
||||
]
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$isSoilMonitoring = Arr::hasAny($item['data'], [
|
||||
'soil_humidity',
|
||||
'soil_temperature',
|
||||
'nitrogen_content',
|
||||
'potassium_content',
|
||||
'phosphorus_content',
|
||||
]);
|
||||
|
||||
if (($device->isTypeSoil() && ! $isSoilMonitoring) || (! $device->isTypeSoil() && $isSoilMonitoring)) {
|
||||
// 如果多合一气象监测器包含土壤监控时,需过滤掉气象监控的数据
|
||||
if ($device->isTypeSoil() && Arr::hasAny($item['data'], [
|
||||
'current_rainfall',
|
||||
'day_rainfall',
|
||||
'accumulate_rainfall',
|
||||
'moment_rainfall',
|
||||
'pm10_concentration',
|
||||
'pm25_concentration',
|
||||
'box_illumination',
|
||||
'box_pressure',
|
||||
'box_carbon',
|
||||
'box_temperature',
|
||||
'box_humidity',
|
||||
'box_noise',
|
||||
'wind_degree',
|
||||
'wind_direction',
|
||||
'wind_power',
|
||||
'wind_speed',
|
||||
])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -497,6 +448,10 @@ class DeviceLogService
|
|||
switch ($key) {
|
||||
case 'wind_samples':
|
||||
$attributes['wind_degree'] = value(function (array $windSamples) {
|
||||
if (empty($windSamples)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$x = 0;
|
||||
$y = 0;
|
||||
|
||||
|
|
@ -526,6 +481,10 @@ class DeviceLogService
|
|||
}, $item);
|
||||
|
||||
$attributes['wind_direction'] = value(function ($windDegree) {
|
||||
if (is_null($windDegree)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($windDegree >= 22.5 && $windDegree < 67.5) {
|
||||
return MeteorologicalDailyReport::WIND_DIRECTION_NORTHEAST;
|
||||
} elseif ($windDegree >= 67.5 && $windDegree < 112.5) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
class MqttService
|
||||
{
|
||||
|
||||
public function getStatus()
|
||||
{
|
||||
$res = Http::withHeaders([
|
||||
'Content-Type' => 'application/json;charset=UTF-8',
|
||||
])->get('http://36.133.205.221:92/status');
|
||||
return $res->json();
|
||||
}
|
||||
|
||||
public function mqttDo($parms)
|
||||
{
|
||||
$res = Http::withHeaders([
|
||||
'Content-Type' => 'application/json;charset=UTF-8',
|
||||
])->post('http://36.133.205.221:92/mqtt', $parms);
|
||||
return $res->json();
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启哪个区域,多大量
|
||||
*/
|
||||
public function open($quyu, $liang)
|
||||
{
|
||||
$parms = [
|
||||
'speed1' => 0,
|
||||
'speed2' => 0,
|
||||
'yv1' => 0,
|
||||
'yv2' => 0,
|
||||
];
|
||||
switch($quyu){
|
||||
case 'a':
|
||||
$parms['speed1'] = $liang;
|
||||
$parms['yv1'] = 1;
|
||||
break;
|
||||
case 'b':
|
||||
$parms['speed2'] = $liang;
|
||||
$parms['yv2'] = 1;
|
||||
break;
|
||||
}
|
||||
return $this->mqttDo($parms);
|
||||
}
|
||||
|
||||
public function close(){
|
||||
$parms = [
|
||||
'speed1' => 0,
|
||||
'speed2' => 0,
|
||||
'yv1' => 0,
|
||||
'yv2' => 0,
|
||||
];
|
||||
return $this->mqttDo($parms);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue