462 lines
19 KiB
PHP
462 lines
19 KiB
PHP
@extends('dashboard.layouts.main')
|
|
|
|
@section('container')
|
|
|
|
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap4-toggle@3.6.1/css/bootstrap4-toggle.min.css" rel="stylesheet">
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap4-toggle@3.6.1/js/bootstrap4-toggle.min.js"></script>
|
|
|
|
<div class="container-fluid pt-4 px-4">
|
|
<!-- Input untuk memilih token Blynk -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h4>Kebun</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="input-group">
|
|
<span class="input-group-text">Pilih Kebun</span>
|
|
<select class="form-select" name="blynkTokenInput" id="blynkTokenInput">
|
|
<option value="">Nama Kebun</option>
|
|
@foreach($kebuns as $kebun)
|
|
<option value="{{ $kebun->blynk_token }}" data-name="{{ $kebun->name }}" data-location="{{ $kebun->location }}" data-deskripsi="{{ $kebun->deskripsi }}" data-owner="{{ $kebun->user->name }}">{{ $kebun->name }}</option>
|
|
@endforeach
|
|
</select>
|
|
<button id="btnPilih" class="btn btn-warning" type="button"><i class="bx bx-search"></i> Cari</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Garden Information -->
|
|
<div id="kebunInfo" class="card mb-4" style="display: none">
|
|
<div class="card-header">
|
|
<h4>Informasi Kebun</h4>
|
|
</div>
|
|
<div class="card-body rounded-bottom p-4">
|
|
<div class="d-flex align-items-center mb-3">
|
|
<i class="fa-solid fa-seedling me-3"></i>
|
|
<p class="mb-0"><strong>Nama Kebun:</strong> <span id="kebunName"></span></p>
|
|
</div>
|
|
<div class="d-flex align-items-center mb-3">
|
|
<i class="fa-solid fa-map-marker-alt me-3"></i>
|
|
<p class="mb-0"><strong>Lokasi Kebun:</strong> <span id="kebunLocation"></span></p>
|
|
</div>
|
|
<div class="d-flex align-items-center mb-3">
|
|
<i class="fa-solid fa-clipboard me-3"></i>
|
|
<p class="mb-0"><strong>Deskripsi:</strong> <span id="kebunDeskripsi"></span></p>
|
|
</div>
|
|
<div class="d-flex align-items-center mb-3">
|
|
<i class="fa-solid fa-user me-3"></i>
|
|
<p class="mb-0"><strong>Pemilik Kebun:</strong> <span id="kebunOwner"></span></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Monitoring RealTime -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h4>Monitoring RealTime</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row g-4">
|
|
@php
|
|
$monitoring = [
|
|
['icon' => 'fa-seedling', 'label' => 'Kelembaban Tanah', 'id' => 'sensor_soil', 'unit' => '%'],
|
|
['icon' => 'fa-arrow-up-from-water-pump', 'label' => 'Pompa Air', 'id' => 'relay', 'unit' => ''],
|
|
['icon' => 'fa-droplet', 'label' => 'Penyiraman', 'id' => 'penyiraman', 'unit' => ''],
|
|
['icon' => 'fa-water', 'label' => 'Tandon Air', 'id' => 'buzzer', 'unit' => '']
|
|
];
|
|
@endphp
|
|
@foreach ($monitoring as $item)
|
|
<div class="col-sm-6 col-xl-3">
|
|
<div class="bg-light rounded-pill d-flex align-items-center p-4">
|
|
<i class="fa-solid {{ $item['icon'] }} fa-2xl text-warning"></i>
|
|
<div class="ms-3 text-left">
|
|
<p class="mb-2">{{ $item['label'] }}</p>
|
|
<h6 class="mb-0"><span id="{{ $item['id'] }}"></span> {{ $item['unit'] }}</h6>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Monitoring Kontrol -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h4>Monitoring Kontrol</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row g-4">
|
|
@php
|
|
$controls = [
|
|
['icon' => 'fa-microchip', 'label' => 'Otomatis', 'id' => 'otomasi'],
|
|
['icon' => 'fa-gear', 'label' => 'Manual', 'id' => 'pompa'],
|
|
['icon' => 'fa-bell', 'label' => 'Tandon Air', 'id' => 'buzzer_switch']
|
|
];
|
|
@endphp
|
|
@foreach ($controls as $control)
|
|
<div class="col-sm-6 col-xl-3">
|
|
<div class="bg-light rounded-pill p-4">
|
|
<div class="form-group mb-0">
|
|
<i class="fa-solid {{ $control['icon'] }} fa-1xl text-warning"></i>
|
|
<label for="{{ $control['id'] }}">{{ $control['label'] }}</label>
|
|
@if ($control['id'] === 'pompa')
|
|
<input type="checkbox" checked data-toggle="toggle" data-on="On" data-off="Off" data-onstyle="primary" data-offstyle="danger" id="{{ $control['id'] }}" onchange="updatePompa()">
|
|
@else
|
|
<input type="checkbox" checked data-toggle="toggle" data-on="On" data-off="Off" data-onstyle="primary" data-offstyle="danger" id="{{ $control['id'] }}" onchange="updatePenyiraman()">
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Kontrol Kelembaban -->
|
|
<div id="kontrolKelembaban" class="card mb-4" style="display: none;">
|
|
<div class="card-header">
|
|
<h4>Kontrol Kelembaban</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row g-3">
|
|
@php
|
|
$sliders = [
|
|
['label' => 'Batas Awal', 'id' => 'batas_bawah'],
|
|
['label' => 'Batas Akhir', 'id' => 'batas_atas']
|
|
];
|
|
@endphp
|
|
@foreach ($sliders as $slider)
|
|
<div class="col-md-6">
|
|
<div class="card shadow-sm">
|
|
<div class="card-body">
|
|
<h6 class="card-title">{{ $slider['label'] }}</h6>
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<button class="btn btn-sm btn-outline-secondary" type="button" onclick="decreaseValue('{{ $slider['id'] }}')">-</button>
|
|
<input type="range" class="form-range custom-range flex-grow-1" id="{{ $slider['id'] }}" min="0" max="100" onchange="updatePenyiraman()">
|
|
<button class="btn btn-sm btn-outline-secondary" type="button" onclick="increaseValue('{{ $slider['id'] }}')">+</button>
|
|
</div>
|
|
<div class="text-center">
|
|
<output for="{{ $slider['id'] }}" id="{{ $slider['id'] }}_value" class="fs-6">0</output>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Riwayat Monitoring Terbaru -->
|
|
<div class="card mb-4">
|
|
<div class="card-header d-flex align-items-center justify-content-between">
|
|
<h4>Riwayat Monitoring Terbaru</h4>
|
|
<a href="/dashboard/controls" class="btn btn-warning">Lihat Semua</a>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
@if ($sensors->isEmpty())
|
|
<p class="text-center">Belum ada data</p>
|
|
@else
|
|
<table class="table text-start align-middle table-bordered table-hover mb-0">
|
|
<thead>
|
|
<tr class="text-dark">
|
|
<th scope="col">Tanggal</th>
|
|
<th scope="col">Pukul</th>
|
|
<th scope="col">Kelembaban Tanah</th>
|
|
<th scope="col">Tandon Air</th>
|
|
<th scope="col">Pompa Air</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($sensors as $data)
|
|
<tr>
|
|
<td>{{ $data->created_at->format('d M Y') }}</td>
|
|
<td>{{ $data->created_at->format('H:i') }}</td>
|
|
<td>{{ $data->calibrated_moisture }}%</td>
|
|
<td>{{ $data->buzzer_state ? 'Habis' : 'Penuh' }}</td>
|
|
<td>{{ $data->relay_state ? 'Hidup' : 'Mati' }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@include('dashboard.realtime')
|
|
<script>
|
|
let previousToken = localStorage.getItem('previousToken');
|
|
let pollingIntervalId = null;
|
|
let currentToken = null; // Store the current token globally
|
|
|
|
// Mengatur slider nilai dan output awal
|
|
const slider1 = document.getElementById('batas_bawah');
|
|
const output1 = document.getElementById('batas_bawah_value');
|
|
output1.textContent = slider1.value;
|
|
let lastSlider1Value = slider1.value;
|
|
slider1.oninput = function () {
|
|
output1.textContent = this.value;
|
|
};
|
|
slider1.onchange = function () {
|
|
if (this.value !== lastSlider1Value) {
|
|
lastSlider1Value = this.value;
|
|
updateBlynkPin(currentToken, 'v8', this.value);
|
|
}
|
|
};
|
|
|
|
const slider2 = document.getElementById('batas_atas');
|
|
const output2 = document.getElementById('batas_atas_value');
|
|
output2.textContent = slider2.value;
|
|
let lastSlider2Value = slider2.value;
|
|
slider2.oninput = function () {
|
|
output2.textContent = this.value;
|
|
};
|
|
slider2.onchange = function () {
|
|
if (this.value !== lastSlider2Value) {
|
|
lastSlider2Value = this.value;
|
|
updateBlynkPin(currentToken, 'v9', this.value);
|
|
}
|
|
};
|
|
|
|
function updateGardenInfo(token) {
|
|
const selectedOption = $('#blynkTokenInput option:selected');
|
|
$('#kebunName').text(selectedOption.data('name'));
|
|
$('#kebunLocation').text(selectedOption.data('location'));
|
|
$('#kebunDeskripsi').text(selectedOption.data('deskripsi'));
|
|
$('#kebunOwner').text(selectedOption.data('owner'));
|
|
$('#kebunInfo').show();
|
|
}
|
|
|
|
// Event listener untuk tombol Pilih
|
|
document.getElementById('btnPilih').addEventListener('click', function() {
|
|
var selectedToken = document.getElementById('blynkTokenInput').value;
|
|
|
|
if (selectedToken === "") {
|
|
resetBlynkDataToZero();
|
|
selectedToken = "Data Buatan";
|
|
}
|
|
|
|
if (selectedToken !== previousToken) {
|
|
console.log('Token Blynk yang baru dipilih:', selectedToken);
|
|
if (previousToken) {
|
|
localStorage.removeItem(previousToken);
|
|
}
|
|
localStorage.setItem('previousToken', selectedToken);
|
|
previousToken = selectedToken;
|
|
currentToken = selectedToken; // Update the current token
|
|
|
|
// Hapus interval polling sebelumnya jika ada
|
|
if (pollingIntervalId !== null) {
|
|
clearInterval(pollingIntervalId);
|
|
pollingIntervalId = null; // Set to null after clearing
|
|
}
|
|
|
|
updateBlynkData(selectedToken);
|
|
} else {
|
|
console.log('Token Blynk yang dipilih sama dengan token sebelumnya:', selectedToken);
|
|
}
|
|
updateGardenInfo(selectedToken);
|
|
// Update data pada saat pilihan berubah
|
|
updateBlynkValues(selectedToken);
|
|
// Mulai polling data jika token sebelumnya tersedia
|
|
if (previousToken) {
|
|
updateBlynkData(previousToken);
|
|
}
|
|
});
|
|
|
|
// Reset data Blynk ke nol
|
|
function resetBlynkDataToZero() {
|
|
console.log('Resetting Blynk data to 0');
|
|
document.getElementById('sensor_soil').textContent = '0';
|
|
document.getElementById('relay').textContent = 'Pompa Mati';
|
|
document.getElementById('penyiraman').textContent = 'Penyiraman Mati';
|
|
document.getElementById('buzzer').textContent = 'Penuh';
|
|
$('#otomasi').bootstrapToggle('off');
|
|
$('#pompa').bootstrapToggle('off');
|
|
$('#buzzer_switch').bootstrapToggle('off');
|
|
}
|
|
|
|
// Update data Blynk
|
|
function updateBlynkData(token) {
|
|
currentToken = token; // Ensure the current token is updated
|
|
const pollingInterval = 1000; // 1 detik
|
|
updateGardenInfo(token);
|
|
pollingIntervalId = setInterval(() => {
|
|
fetchBlynkData('v11', token, 'sensor_soil');
|
|
fetchBlynkData('v14', token, 'relay');
|
|
fetchBlynkData('v10', token, 'penyiraman');
|
|
fetchBlynkData('v15', token, 'buzzer');
|
|
fetchBlynkData('v6', token, 'otomasi', (value) => $('#otomasi').bootstrapToggle(value === '1' ? 'on' : 'off'));
|
|
fetchBlynkData('v7', token, 'pompa', (value) => $('#pompa').bootstrapToggle(value === '1' ? 'on' : 'off'));
|
|
fetchBlynkData('v13', token, 'buzzer_switch', (value) => $('#buzzer_switch').bootstrapToggle(value === '1' ? 'on' : 'off'));
|
|
}, pollingInterval);
|
|
fetchBlynkData('v8', token, 'batas_bawah', (value) => {
|
|
if (value !== slider1.value) {
|
|
slider1.value = value;
|
|
output1.textContent = value;
|
|
}
|
|
});
|
|
fetchBlynkData('v9', token, 'batas_atas', (value) => {
|
|
if (value !== slider2.value) {
|
|
slider2.value = value;
|
|
output2.textContent = value;
|
|
}
|
|
});
|
|
}
|
|
|
|
// Mendefinisikan variabel apiUrl
|
|
function fetchBlynkData(pin, token, elementId, transform = (value) => value) {
|
|
// Check if the token is still the current one before making the request
|
|
if (token !== currentToken) {
|
|
return;
|
|
}
|
|
|
|
const apiUrl = `https://blynk.cloud/external/api/get?token=${token}&pin=${pin}`;
|
|
fetch(apiUrl, { method: 'GET' })
|
|
.then(response => {
|
|
if (!response.ok) {
|
|
throw new Error('Network response was not ok');
|
|
}
|
|
return response.text();
|
|
})
|
|
.then(data => {
|
|
// Check if the token is still the current one before updating the DOM
|
|
if (token === currentToken) {
|
|
const transformedValue = transform(data);
|
|
document.getElementById(elementId).textContent = transformedValue;
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error(`Failed to fetch data for pin ${pin}:`, error);
|
|
});
|
|
}
|
|
|
|
// Update data pada saat pilihan berubah
|
|
function updateBlynkValues(token) {
|
|
getBlynkValue('v6', token);
|
|
getBlynkValue('v7', token);
|
|
getBlynkValue('v8', token);
|
|
getBlynkValue('v9', token);
|
|
getBlynkValue('v13', token);
|
|
getBlynkValueString('v11', token);
|
|
getBlynkValueString('v10', token);
|
|
getBlynkValueString('v14', token);
|
|
getBlynkValueString('v15', token);
|
|
}
|
|
|
|
// Event handler saat dokumen siap
|
|
$(document).ready(function() {
|
|
|
|
// Reset page state on refresh
|
|
$('#kebunInfo').hide();
|
|
$('#kontrolKelembaban').hide();
|
|
$('#blynkTokenInput').val('');
|
|
resetBlynkDataToZero();
|
|
|
|
$('#blynkTokenInput').on('change', function() {
|
|
const selectedToken = $(this).val();
|
|
updateBlynkData(selectedToken);
|
|
});
|
|
|
|
// Event handler untuk switch pompa
|
|
$('#pompa').change(function() {
|
|
let status = $(this).prop('checked') ? 'on' : 'off';
|
|
updatePompa();
|
|
});
|
|
|
|
// Event handler untuk switch otomasi
|
|
$('#otomasi').change(function() {
|
|
updatePenyiraman();
|
|
});
|
|
|
|
if (previousToken) {
|
|
updateBlynkData(previousToken);
|
|
}
|
|
});
|
|
// Update penyiraman berdasarkan status kontrol
|
|
function updatePompa() {
|
|
let token = localStorage.getItem('previousToken');
|
|
if (!token) {
|
|
console.error('Token Blynk tidak tersedia di local storage.');
|
|
return;
|
|
}
|
|
|
|
let pompaStatus = document.getElementById('pompa').checked ? 1 : 0;
|
|
updateBlynkPin(token, 'v7', pompaStatus);
|
|
}
|
|
|
|
// Update penyiraman berdasarkan status kontrol
|
|
function updatePenyiraman() {
|
|
let token = localStorage.getItem('previousToken');
|
|
if (!token) {
|
|
console.error('Token Blynk tidak tersedia di local storage.');
|
|
return;
|
|
}
|
|
|
|
let otomasiStatus = document.getElementById('otomasi').checked ? 1 : 0;
|
|
let buzzerStatus = document.getElementById('buzzer_switch').checked ? 1 : 0;
|
|
let batasBawah = document.getElementById('batas_bawah').value;
|
|
let batasAtas = document.getElementById('batas_atas').value;
|
|
|
|
updateBlynkPin(token, 'v6', otomasiStatus);
|
|
updateBlynkPin(token, 'v13', buzzerStatus);
|
|
updateBlynkPin(token, 'v8', batasBawah);
|
|
updateBlynkPin(token, 'v9', batasAtas);
|
|
|
|
if (otomasiStatus === 1) {
|
|
$('#kontrolKelembaban').show();
|
|
} else {
|
|
$('#kontrolKelembaban').hide();
|
|
}
|
|
}
|
|
|
|
function decreaseValue(id) {
|
|
var slider = document.getElementById(id);
|
|
var output = document.getElementById(id + '_value');
|
|
if (slider.value > 0) {
|
|
slider.value--;
|
|
output.value = slider.value;
|
|
}
|
|
updatePenyiraman();
|
|
}
|
|
|
|
function increaseValue(id) {
|
|
var slider = document.getElementById(id);
|
|
var output = document.getElementById(id + '_value');
|
|
if (slider.value < 100) {
|
|
slider.value++;
|
|
output.value = slider.value;
|
|
}
|
|
updatePenyiraman();
|
|
}
|
|
|
|
// Update status pin Blynk
|
|
function updateBlynkPin(token, pin, value) {
|
|
$.get(`https://blynk.cloud/external/api/update?token=${token}&${pin}=${value}`, function(response) {
|
|
console.log(`Pin ${pin} updated to ${value}`);
|
|
});
|
|
}
|
|
|
|
// Mendapatkan nilai Blynk
|
|
function getBlynkValue(pin, token) {
|
|
$.get(`https://blynk.cloud/external/api/get?token=${token}&pin=${pin}`, function(data) {
|
|
console.log(`Value from Blynk for pin ${pin}: ${data}`);
|
|
});
|
|
}
|
|
|
|
// Mendapatkan nilai string Blynk
|
|
function getBlynkValueString(pin, token) {
|
|
$.get(`https://blynk.cloud/external/api/get?token=${token}&pin=${pin}`, function(data) {
|
|
console.log(`Value from Blynk for pin ${pin}: ${data}`);
|
|
});
|
|
}
|
|
</script>
|
|
|
|
|
|
@endsection
|