Skip to content

Commit

Permalink
WIP on aider: 1b3b3b3 Add calibration page
Browse files Browse the repository at this point in the history
  • Loading branch information
DTTerastar committed Nov 20, 2024
1 parent 2624be0 commit 4b5e2fd
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.sh text eol=lf
18 changes: 18 additions & 0 deletions src/ui/src/lib/DeviceActions.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script>
import { onMount } from 'svelte';
import { calibrateById } from '$lib/urls'
export let col;
export let row;
// Add a function to handle the "Calibrate" button click
function handleCalibrate() {
calibrateById(row.id)
}
</script>

<div>
<button class="btn btn-sm bg-success-700 text-black" on:click|stopPropagation={handleCalibrate}>Calibrate</button>
</div>
4 changes: 3 additions & 1 deletion src/ui/src/lib/DevicesTable.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import DeviceActions from '$lib/DeviceActions.svelte';
import { devices } from '$lib/stores';
import type { Device } from '$lib/types';
import { createEventDispatcher } from 'svelte';
Expand All @@ -23,7 +24,8 @@
{ key: 'fixes', title: 'Fixes', value: (d) => d.fixes ?? 'n/a', sortable: true },
{ key: 'scale', title: 'Scale', value: (d) => d.scale?.toFixed(3) ?? 'n/a', sortable: true },
{ key: 'confidence', title: 'Confidence', value: (d) => d.confidence ?? 'n/a', sortable: true },
{ key: 'lastHit', title: 'LastHit', value: (d) => ((d.lastHit ?? '') == '' ? 'n/a' : ago(new Date(d.lastHit)) ?? 'n/a'), sortable: true }
{ key: 'lastHit', title: 'LastHit', value: (d) => ((d.lastHit ?? '') == '' ? 'n/a' : ago(new Date(d.lastHit)) ?? 'n/a'), sortable: true },
{ key: 'actions', title: '', renderComponent: { component: DeviceActions } }
];
function onRowClick(e) {
Expand Down
8 changes: 8 additions & 0 deletions src/ui/src/lib/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,11 @@ export function detail(d: Device | Node | null) {
if (isNode(d)) goto(`${base}/nodes/${d?.id}`);
else goto(`${base}/devices/${d?.id}`);
}

export function calibrate(d: Device | null) {
goto(`${base}/calibration/${d?.id}`);
}

export function calibrateById(id: string) {
goto(`${base}/calibration/${id}`);
}
184 changes: 184 additions & 0 deletions src/ui/src/routes/calibration/[deviceId]/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<script>
import { page } from '$app/stores';
import { devices } from '$lib/stores';
import Map from '$lib/Map.svelte';
import { onMount } from 'svelte';
let deviceId = $page.params.deviceId;
let selectedFloor = null;
let selectedSpot = null;
let nodeDistances = [];
let rssiValues = {};
let includedNodes = {};
let currentRssiAt1m = null;
let calculatedRssiAt1m = null;
let floors = [];
$: {
if ($devices) {
floors = [...new Set($devices.map(device => device.floor))];
}
}
onMount(async () => {
const response = await fetch(`/api/device/${deviceId}`);
const deviceData = await response.json();
currentRssiAt1m = deviceData.rssiAt1m;
});
function handleSpotSelection(event) {
selectedSpot = event.detail;
calculateDistances();
fetchRssiValues();
}
function calculateDistances() {
nodeDistances = $devices
.filter(device => device.floor === selectedFloor)
.map(device => ({
id: device.id,
distance: Math.sqrt(
Math.pow(device.x - selectedSpot.x, 2) +
Math.pow(device.y - selectedSpot.y, 2)
)
}));
includedNodes = Object.fromEntries(nodeDistances.map(node => [node.id, true]));
}
async function fetchRssiValues() {
const promises = nodeDistances.map(async (node) => {
const response = await fetch(`/api/node/${node.id}/rssi`);
const data = await response.json();
return { id: node.id, rssi: data.rssi };
});
const results = await Promise.all(promises);
rssiValues = Object.fromEntries(results.map(({ id, rssi }) => [id, rssi]));
updateCalculation();
}
function updateCalculation() {
const includedNodeData = nodeDistances.filter(node => includedNodes[node.id]);
if (includedNodeData.length === 0) {
calculatedRssiAt1m = null;
return;
}
const sumRssiAdjusted = includedNodeData.reduce((sum, node) => {
const rssi = rssiValues[node.id];
return sum + (rssi + 20 * Math.log10(node.distance));
}, 0);
calculatedRssiAt1m = sumRssiAdjusted / includedNodeData.length;
}
async function saveCalibration() {
const response = await fetch(`/api/device/${deviceId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ rssiAt1m: calculatedRssiAt1m }),
});
if (response.ok) {
currentRssiAt1m = calculatedRssiAt1m;
alert('Calibration saved successfully!');
} else {
alert('Failed to save calibration. Please try again.');
}
}
function toggleNodeInclusion(nodeId) {
includedNodes[nodeId] = !includedNodes[nodeId];
updateCalculation();
}
</script>

<h1>Calibration for Device {deviceId}</h1>

<select bind:value={selectedFloor}>
<option value={null}>Select a floor</option>
{#each floors as floor}
<option value={floor}>Floor {floor}</option>
{/each}
</select>

{#if selectedFloor}
<Map {selectedFloor} on:spotSelected={handleSpotSelection} />
{/if}

{#if selectedSpot}
<h2>Node Distances and RSSI Values</h2>
<table>
<thead>
<tr>
<th>Node ID</th>
<th>Distance (m)</th>
<th>RSSI</th>
<th>Include in Calculation</th>
</tr>
</thead>
<tbody>
{#each nodeDistances as node}
<tr>
<td>{node.id}</td>
<td>{node.distance.toFixed(2)}</td>
<td>{rssiValues[node.id] || 'N/A'}</td>
<td>
<input
type="checkbox"
checked={includedNodes[node.id]}
on:change={() => toggleNodeInclusion(node.id)}
/>
</td>
</tr>
{/each}
</tbody>
</table>

<h2>Calibration Results</h2>
<p>Current RSSI@1m: {currentRssiAt1m !== null ? currentRssiAt1m.toFixed(2) : 'N/A'} dBm</p>
<p>Calculated RSSI@1m: {calculatedRssiAt1m !== null ? calculatedRssiAt1m.toFixed(2) : 'N/A'} dBm</p>

<button on:click={saveCalibration} disabled={calculatedRssiAt1m === null}>
Save Calibration
</button>
{/if}

<style>
h1, h2 {
color: #333;
}
select, button {
margin: 10px 0;
padding: 5px;
}
table {
border-collapse: collapse;
width: 100%;
margin-bottom: 20px;
}
th, td {
border: 1px solid #ddd;
padding: 8px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
button {
background-color: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
}
button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
</style>

0 comments on commit 4b5e2fd

Please sign in to comment.