diff --git a/api/get_radar_data.php b/api/get_radar_data.php
new file mode 100644
index 0000000..f579372
--- /dev/null
+++ b/api/get_radar_data.php
@@ -0,0 +1,21 @@
+ 'Not connected. Please set Channel ID and API Key.']);
+ exit;
+}
+
+$data = fetch_thingspeak_data($channel_id, $api_key, 50); // Fetch more points for better clustering
+
+if ($data && !empty($data['feeds'])) {
+ echo json_encode($data['feeds']);
+} else {
+ echo json_encode(['error' => 'Failed to fetch data from ThingSpeak.']);
+}
diff --git a/assets/css/custom.css b/assets/css/custom.css
new file mode 100644
index 0000000..0286675
--- /dev/null
+++ b/assets/css/custom.css
@@ -0,0 +1,34 @@
+
+body {
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+ background-color: #F8F9FA;
+}
+
+.navbar-brand {
+ font-weight: 600;
+}
+
+.card {
+ border-radius: 0.5rem;
+ box-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
+}
+
+.form-control:focus {
+ box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
+}
+
+.btn-primary {
+ background-image: linear-gradient(to right, #0D6EFD, #0D47A1);
+ border: none;
+}
+
+@keyframes fadeIn {
+ from {
+ opacity: 0;
+ transform: translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
diff --git a/assets/js/main.js b/assets/js/main.js
new file mode 100644
index 0000000..e6254c4
--- /dev/null
+++ b/assets/js/main.js
@@ -0,0 +1,174 @@
+document.addEventListener('DOMContentLoaded', function() {
+ const radarCanvas = document.getElementById('radarCanvas');
+ if (radarCanvas) {
+ updateRadarData();
+ setInterval(updateRadarData, 5000); // Update every 5 seconds
+ }
+});
+
+function updateRadarData() {
+ fetch('api/get_radar_data.php')
+ .then(response => response.json())
+ .then(data => {
+ if (data && !data.error) {
+ const feeds = data;
+ checkProximity(feeds, 0.5);
+ drawRadar(feeds);
+ updateObjectsTable(feeds);
+ } else {
+ console.error('Error fetching radar data:', data ? data.error : 'No data received');
+ }
+ })
+ .catch(error => {
+ console.error('Failed to fetch or parse radar data:', error);
+ });
+}
+
+function toCartesian(angle, distance, canvas) {
+ const centerX = canvas.width / 2;
+ const centerY = canvas.height / 2;
+ const maxCanvasDistance = Math.min(centerX, centerY) * 0.9;
+ const MAX_REAL_WORLD_METERS = 5;
+
+ const distanceInMeters = distance / 100;
+ const normalizedDistance = (distanceInMeters / MAX_REAL_WORLD_METERS) * maxCanvasDistance;
+ const angleRad = (angle - 90) * (Math.PI / 180);
+ const x = centerX + normalizedDistance * Math.cos(angleRad);
+ const y = centerY + normalizedDistance * Math.sin(angleRad);
+ return { x, y };
+}
+
+function updateObjectsTable(feeds) {
+ const tableBody = document.getElementById('objectsTableBody');
+ if (!tableBody) return;
+
+ tableBody.innerHTML = '';
+
+ feeds.forEach((feed, index) => {
+ const row = document.createElement('tr');
+ row.style.animation = `fadeIn 0.5s ease-in-out ${index * 0.1}s both`;
+
+ const idCell = document.createElement('td');
+ idCell.textContent = feed.entry_id;
+ row.appendChild(idCell);
+
+ const distanceCell = document.createElement('td');
+ const distanceInMeters = parseFloat(feed.field2) / 100;
+ distanceCell.textContent = distanceInMeters.toFixed(2);
+ row.appendChild(distanceCell);
+
+ const angleCell = document.createElement('td');
+ angleCell.textContent = parseFloat(feed.field1).toFixed(2);
+ row.appendChild(angleCell);
+
+ const timeCell = document.createElement('td');
+ timeCell.textContent = new Date(feed.created_at).toLocaleTimeString();
+ row.appendChild(timeCell);
+
+ tableBody.appendChild(row);
+ });
+}
+
+function checkProximity(feeds, distanceThreshold) {
+ const alertElement = document.getElementById('proximityAlert');
+ const distanceElement = document.getElementById('closestDistance');
+ if (!alertElement || !distanceElement) return;
+
+ let minDistance = Infinity;
+ let isClose = false;
+
+ feeds.forEach(feed => {
+ const distanceInMeters = parseFloat(feed.field2) / 100;
+ if (distanceInMeters < minDistance) {
+ minDistance = distanceInMeters;
+ }
+ if (distanceInMeters < distanceThreshold) {
+ isClose = true;
+ }
+ });
+
+ if (isClose) {
+ distanceElement.textContent = minDistance.toFixed(2);
+ alertElement.classList.remove('d-none');
+ } else {
+ alertElement.classList.add('d-none');
+ }
+}
+
+function drawRadar(feeds) {
+ const canvas = document.getElementById('radarCanvas');
+ if(!canvas) return;
+ const ctx = canvas.getContext('2d');
+ const width = canvas.width;
+ const height = canvas.height;
+ const centerX = width / 2;
+ const centerY = height / 2;
+ const maxDistance = Math.min(centerX, centerY) * 0.9;
+
+ ctx.fillStyle = '#0b1220';
+ ctx.fillRect(0, 0, width, height);
+ ctx.strokeStyle = 'rgba(0, 255, 213, 0.3)';
+ ctx.lineWidth = 1;
+
+ for (let i = 1; i <= 4; i++) {
+ ctx.beginPath();
+ ctx.arc(centerX, centerY, maxDistance * (i / 4), 0, 2 * Math.PI);
+ ctx.stroke();
+ }
+ ctx.beginPath();
+ ctx.moveTo(centerX, 0);
+ ctx.lineTo(centerX, height);
+ ctx.moveTo(0, centerY);
+ ctx.lineTo(width, centerY);
+ ctx.stroke();
+
+ feeds.forEach((feed, index) => {
+ const angle = parseFloat(feed.field1);
+ const distance = parseFloat(feed.field2);
+
+ if (!isNaN(angle) && !isNaN(distance)) {
+ const { x, y } = toCartesian(angle, distance, canvas);
+
+ // Animation
+ let radius = 0;
+ let alpha = 0;
+ const targetRadius = 5;
+ const animationDuration = 500;
+ const startTime = Date.now();
+
+ function animateDot() {
+ const elapsedTime = Date.now() - startTime;
+ const progress = Math.min(elapsedTime / animationDuration, 1);
+
+ radius = targetRadius * progress;
+ alpha = progress;
+
+ ctx.fillStyle = `rgba(33, 150, 243, ${alpha})`;
+ ctx.beginPath();
+ ctx.arc(x, y, radius, 0, 2 * Math.PI);
+ ctx.fill();
+
+ if (progress < 1) {
+ requestAnimationFrame(animateDot);
+ }
+ }
+
+ setTimeout(animateDot, index * 100);
+ }
+ });
+}
+
+(function () {
+ 'use strict'
+ var forms = document.querySelectorAll('.needs-validation')
+ Array.prototype.slice.call(forms)
+ .forEach(function (form) {
+ form.addEventListener('submit', function (event) {
+ if (!form.checkValidity()) {
+ event.preventDefault()
+ event.stopPropagation()
+ }
+ form.classList.add('was-validated')
+ }, false)
+ })
+})();
\ No newline at end of file
diff --git a/connect.php b/connect.php
new file mode 100644
index 0000000..9c003a0
--- /dev/null
+++ b/connect.php
@@ -0,0 +1,72 @@
+Success! Your settings have been saved. You can now proceed to the dashboard.';
+ $message_type = 'success';
+ } else {
+ $message = 'Error! Please provide a valid Channel ID and Read API Key.';
+ $message_type = 'danger';
+ }
+}
+
+include 'partials/header.php';
+?>
+
+
+
+
+
+
+
Connect IoT Channel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dashboard.php b/dashboard.php
new file mode 100644
index 0000000..a0a0824
--- /dev/null
+++ b/dashboard.php
@@ -0,0 +1,75 @@
+
+
+
+
+
Dashboard
+
+
This is where the synchronized polar and Cartesian plots will be displayed.
+
+
+ Warning! An object is detected at a distance of units.
+
+
+
+
+
+
+
+
+
+
+ | ID |
+ Distance (m) |
+ Angle (°) |
+ Timestamp |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/includes/thingspeak.php b/includes/thingspeak.php
new file mode 100644
index 0000000..9e14985
--- /dev/null
+++ b/includes/thingspeak.php
@@ -0,0 +1,18 @@
+
\ No newline at end of file
diff --git a/index.php b/index.php
index 7205f3d..3481159 100644
--- a/index.php
+++ b/index.php
@@ -1,150 +1,25 @@
-
-
-
-
-
- New Style
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Analyzing your requirements and generating your website…
-
- Loading…
-
-
= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.
-
This page will update automatically as the plan is implemented.
-
Runtime: PHP = htmlspecialchars($phpVersion) ?> — UTC = htmlspecialchars($now) ?>
+
+
+
+
+

+
+
+
Monitor Real-Time IoT Data with Ease
+
+
+
-
-
-
-
+
+
+
\ No newline at end of file
diff --git a/partials/footer.php b/partials/footer.php
new file mode 100644
index 0000000..1b65623
--- /dev/null
+++ b/partials/footer.php
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+