Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 36 additions & 6 deletions src/components/Receiver.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@

<template>
<form novalidate>
<div class="row g-2 mb-2">
<div class="col-12">
<label for="rx_preset" class="form-label">Device Preset</label>
<select v-model="selectedPreset" @change="applyPreset" class="form-select form-select-sm" id="rx_preset">
<option v-for="device in meshtasticDevices" :key="device.id" :value="device">
{{ device.name }}
</option>
</select>
</div>
</div>

<div class="row g-2">
<div class="col-6">
<label for="rx_sensitivity" class="form-label">Sensitivity (dBm)</label>
<input v-model="receiver.rx_sensitivity" type="number" class="form-control form-control-sm" id="rx_sensitivity" required step="1" min="-150" max="-30" />
<input v-model="receiver.rx_sensitivity" @input="setCustom" type="number" class="form-control form-control-sm" id="rx_sensitivity" required step="1" min="-150" max="-30" />
<div class="invalid-feedback">Please enter a valid sensitivity.</div>
</div>
<div class="col-6">
Expand All @@ -16,7 +26,7 @@
<div class="row g-2 mt-2">
<div class="col-6">
<label for="rx_gain" class="form-label">Antenna Gain (dB)</label>
<input v-model="receiver.rx_gain" type="number" class="form-control form-control-sm" id="rx_gain" required min="0" max="30" step="0.1" />
<input v-model="receiver.rx_gain" @input="setCustom" type="number" class="form-control form-control-sm" id="rx_gain" required min="0" max="30" step="0.1" />
<div class="invalid-feedback">Gain must be a positive number.</div>
</div>
<div class="col-6">
Expand All @@ -29,6 +39,26 @@
</template>

<script setup lang="ts">
import { useStore } from '../store.ts'
const receiver = useStore().splatParams.receiver
</script>
import { ref } from 'vue';
import { useStore } from '../store.ts';
import { meshtasticDevices } from '../devicePresets.ts';

const store = useStore();
const receiver = store.splatParams.receiver;

// State for the dropdown
const selectedPreset = ref(meshtasticDevices[0]);

// Apply the preset values
const applyPreset = () => {
if (selectedPreset.value.id !== 'custom') {
receiver.rx_sensitivity = selectedPreset.value.rx_sensitivity!;
receiver.rx_gain = selectedPreset.value.rx_gain!;
}
};

// If a user manually changes a pre-filled field, flip dropdown back to "Custom"
const setCustom = () => {
selectedPreset.value = meshtasticDevices[0];
};
</script>
57 changes: 43 additions & 14 deletions src/components/Transmitter.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@

<template>
<form novalidate>
<div class="row g-2 mb-2">
<div class="col-12">
<label for="tx_preset" class="form-label">Device Preset</label>
<select v-model="selectedPreset" @change="applyPreset" class="form-select form-select-sm" id="tx_preset">
<option v-for="device in meshtasticDevices" :key="device.id" :value="device">
{{ device.name }}
</option>
</select>
</div>
</div>

<div class="row g-2">
<div class="col-12">
<label for="name" class="form-label">Site name</label>
<input v-model="transmitter.name" class="form-control form-control-sm" id="name" required data-bs-toggle="tooltip" title="Site Name" />
</div>
</div>
<div class="row g-2">

<div class="row g-2 mt-2">
<div class="col-6">
<label for="tx_lat" class="form-label">Latitude (degrees)</label>
<input v-model="transmitter.tx_lat" type="number" class="form-control form-control-sm" id="tx_lat" required min="-90" max="90" step="0.000001" data-bs-toggle="tooltip" title="Transmitter latitude in degrees (-90 to 90)." />
Expand All @@ -19,10 +30,11 @@
<div class="invalid-feedback">Please enter a valid longitude (-180 to 180).</div>
</div>
</div>

<div class="row g-2 mt-2">
<div class="col-6">
<label for="tx_power" class="form-label">Power (W)</label>
<input v-model="transmitter.tx_power" type="number" class="form-control form-control-sm" id="tx_power" required min="0" step="0.1" data-bs-toggle="tooltip" title="Transmitter power in watts (>0)." />
<input v-model="transmitter.tx_power" @input="setCustom" type="number" class="form-control form-control-sm" id="tx_power" required min="0" step="0.1" data-bs-toggle="tooltip" title="Transmitter power in watts (>0)." />
<div class="invalid-feedback">Power must be a positive number.</div>
</div>
<div class="col-6">
Expand All @@ -39,7 +51,7 @@
</div>
<div class="col-6">
<label for="tx_gain" class="form-label">Antenna Gain (dB)</label>
<input v-model="transmitter.tx_gain" type="number" class="form-control form-control-sm" id="tx_gain" required min="0" step="0.1" />
<input v-model="transmitter.tx_gain" @input="setCustom" type="number" class="form-control form-control-sm" id="tx_gain" required min="0" step="0.1" />
<div class="invalid-feedback">Gain must be a positive number.</div>
</div>
</div>
Expand All @@ -53,47 +65,64 @@
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';
import L from 'leaflet';
import * as bootstrap from 'bootstrap';
import { useStore } from '../store.ts'
import { onMounted } from 'vue';
import { redPinMarker } from '../layers.ts';
import { meshtasticDevices } from '../devicePresets.ts';

const store = useStore();
const transmitter = store.splatParams.transmitter;

// State for the dropdown
const selectedPreset = ref(meshtasticDevices[0]);

// Apply the preset values
const applyPreset = () => {
if (selectedPreset.value.id !== 'custom') {
transmitter.tx_power = selectedPreset.value.tx_power!;
transmitter.tx_gain = selectedPreset.value.tx_gain!;
}
};

// If a user manually changes a pre-filled field, flip dropdown back to "Custom"
const setCustom = () => {
selectedPreset.value = meshtasticDevices[0];
};

const centerMapOnTransmitter = () => {
if (!isNaN(transmitter.tx_lat) && !isNaN(transmitter.tx_lon)) {
store.map!.setView([transmitter.tx_lat, transmitter.tx_lon], store.map!.getZoom()); // Center map on the coordinates
store.map!.setView([transmitter.tx_lat, transmitter.tx_lon], store.map!.getZoom());
} else {
alert("Please enter valid Latitude and Longitude values.");
}
};

let popover = new bootstrap.Popover(document.createElement("input"), {
trigger: "manual",
});

const setWithMap = () => {
popover.show();
store.map!.once("click", function (e: any) {
let { lat, lng } = e.latlng; // Get clicked location coordinates
let { lat, lng } = e.latlng;
lng = ((((lng + 180) % 360) + 360) % 360) - 180;

store.setTxCoords(lat.toFixed(6), lng.toFixed(6)); // Update the store
store.setTxCoords(lat.toFixed(6), lng.toFixed(6));

// Remove the existing marker if it exists
if (store.currentMarker) {
store.map!.removeLayer(store.currentMarker as L.Marker);
}
// Add a new marker at the clicked location
store.currentMarker = L.marker([lat, lng], { icon: redPinMarker }).addTo(store.map as L.Map)
popover.hide(); // Hide the popover
popover.hide();
});
};

onMounted(() => {
popover = new bootstrap.Popover(document.getElementById("setWithMap") as Element, {
trigger: "manual",
});
store.initMap(); // Initialize the map
store.initMap();
});

</script>
</script>
Loading