mirror of
https://github.com/richonguzman/LoRa_APRS_iGate.git
synced 2026-07-04 17:01:29 +02:00
map con estaciones
This commit is contained in:
@@ -96,7 +96,6 @@ body{background:var(--msh-bg);color:var(--msh-text);font-family:"Inter",system-u
|
||||
d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8m8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1"
|
||||
/>
|
||||
</svg></span><span class="label">Station</span></button>
|
||||
<button class="side-link" type="button" data-target="sec-maps"><span class="side-ico"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16"><path d="M15.817.113A.5.5 0 0 1 16 .5v14a.5.5 0 0 1-.402.49l-5 1a.5.5 0 0 1-.196 0L5.5 15.01l-4.902.98A.5.5 0 0 1 0 15.5v-14a.5.5 0 0 1 .402-.49l5-1a.5.5 0 0 1 .196 0L10.5.99l4.902-.98a.5.5 0 0 1 .415.103M10 1.91l-4-.8v12.98l4 .8zm1 12.98 4-.8V1.11l-4 .8zm-6-.8V1.11l-4 .8v12.98z"/></svg></span><span class="label">Maps</span></button>
|
||||
<button class="side-link" type="button" data-target="sec-beaconing"><span class="side-ico"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16"><path d="M15.964.686a.5.5 0 0 0-.65-.65L.767 5.855H.766l-.452.18a.5.5 0 0 0-.082.887l.41.26.001.002 4.995 3.178 3.178 4.995.002.002.26.41a.5.5 0 0 0 .886-.083zm-1.833 1.89L6.637 10.07l-.215-.338a.5.5 0 0 0-.154-.154l-.338-.215 7.494-7.494 1.178-.471z"/></svg></span><span class="label">Beaconing</span></button>
|
||||
<button class="side-link" type="button" data-target="sec-connectivity"><span class="side-ico"><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -184,6 +183,7 @@ body{background:var(--msh-bg);color:var(--msh-text);font-family:"Inter",system-u
|
||||
<button class="side-link" type="button" data-target="sec-administration"><span class="side-ico"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16"><path d="M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"/></svg></span><span class="label">Administration</span></button>
|
||||
<button class="side-link" type="button" data-target="sec-about"><span class="side-ico"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16"><path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2"/></svg></span><span class="label">About / Info</span></button>
|
||||
<div class="side-sep"></div>
|
||||
<button class="side-link" type="button" data-target="sec-maps"><span class="side-ico"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16"><path d="M15.817.113A.5.5 0 0 1 16 .5v14a.5.5 0 0 1-.402.49l-5 1a.5.5 0 0 1-.196 0L5.5 15.01l-4.902.98A.5.5 0 0 1 0 15.5v-14a.5.5 0 0 1 .402-.49l5-1a.5.5 0 0 1 .196 0L10.5.99l4.902-.98a.5.5 0 0 1 .415.103M10 1.91l-4-.8v12.98l4 .8zm1 12.98 4-.8V1.11l-4 .8zm-6-.8V1.11l-4 .8v12.98z"/></svg></span><span class="label">Map</span></button>
|
||||
<button class="side-link" type="button" id="rpToggle"><span class="side-ico"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5m-3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2m0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2m0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2"/></svg></span><span class="label">Received Packets</span></button>
|
||||
<a href="/received-packets" id="rpDummy" style="display:none" aria-hidden="true"></a>
|
||||
<a class="side-link side-ota" href="/update"><span class="side-ico"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 16 16"><path d="M8 2a5.53 5.53 0 0 0-3.594 1.342c-.766.66-1.321 1.52-1.464 2.383C1.266 6.095 0 7.555 0 9.318 0 11.366 1.708 13 3.781 13h8.906C14.502 13 16 11.57 16 9.773c0-1.636-1.242-2.969-2.834-3.194C12.923 3.999 10.69 2 8 2m2.354 5.146a.5.5 0 0 1-.708.708L8.5 6.707V10.5a.5.5 0 0 1-1 0V6.707L6.354 7.854a.5.5 0 1 1-.708-.708l2-2a.5.5 0 0 1 .708 0z"/></svg></span><span class="label">Update OTA</span></a>
|
||||
@@ -218,7 +218,7 @@ body{background:var(--msh-bg);color:var(--msh-text);font-family:"Inter",system-u
|
||||
<div class="col-12">
|
||||
<h3>Stations Map</h3>
|
||||
<div id="map" style="height:70vh;border-radius:14px;"></div>
|
||||
<small>Needs internet (OpenStreetMap tiles). Updates every 15 seconds.</small>
|
||||
<small>Needs internet (OpenStreetMap tiles). Updates every 15 seconds. Stations heard in the last hour.</small>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -670,7 +670,13 @@ function loadMapStations(stations) {
|
||||
+ `<br>RSSI ${s.RSSI} / SNR ${s.SNR}`
|
||||
+ `<br>Packets: ${s.count}`;
|
||||
|
||||
L.marker([s.lat, s.lon]).bindPopup(popup).addTo(mapMarkers);
|
||||
L.circleMarker([s.lat, s.lon], {
|
||||
radius: 6,
|
||||
color: "#1d6fe0", // borde
|
||||
weight: 2,
|
||||
fillColor: "#3b8cff", // relleno
|
||||
fillOpacity: 0.9
|
||||
}).bindPopup(popup).addTo(mapMarkers);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -22,7 +22,6 @@
|
||||
#include <Arduino.h>
|
||||
#include <vector>
|
||||
|
||||
#define MAX_MAP_STATIONS 50
|
||||
|
||||
struct MapStation {
|
||||
char callsign[10]; // "XX9XXX-NN" + null -> clave para deduplicar
|
||||
@@ -38,7 +37,7 @@ struct MapStation {
|
||||
|
||||
namespace MAP_Utils {
|
||||
|
||||
void upsert(const String& callsign, float latitude, float longitude, const String& symbol, int16_t rssi, float snr);
|
||||
void upsert(const String& callsign, float latitude, float longitude, const String& symbol, int rssi, float snr);
|
||||
String getStationsJson();
|
||||
|
||||
}
|
||||
|
||||
+7
-2
@@ -16,6 +16,7 @@
|
||||
* along with LoRa APRS iGate. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <APRSPacketLib.h>
|
||||
#include <RadioLib.h>
|
||||
#include "configuration.h"
|
||||
#include "network_manager.h"
|
||||
@@ -23,13 +24,12 @@
|
||||
#include "station_utils.h"
|
||||
#include "board_pinout.h"
|
||||
#include "syslog_utils.h"
|
||||
#include "map_utils.h"
|
||||
#include "ntp_utils.h"
|
||||
#include "display.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
|
||||
|
||||
extern Configuration Config;
|
||||
extern NetworkManager *networkManager;
|
||||
extern bool packetIsBeacon;
|
||||
@@ -280,6 +280,11 @@ namespace LoRa_Utils {
|
||||
receivedPacket.RSSI = rssi;
|
||||
receivedPacket.SNR = snr;
|
||||
receivedPackets.push_back(receivedPacket);
|
||||
|
||||
APRSPacket aprsPacket = APRSPacketLib::processReceivedPacket(packet.substring(3), rssi, snr, freqError);
|
||||
if (aprsPacket.type == 0 || aprsPacket.type == 4) { // 0 = GPS, 4 = Mic-E (los que traen posición)
|
||||
MAP_Utils::upsert(aprsPacket.sender, aprsPacket.latitude, aprsPacket.longitude, aprsPacket.overlay + aprsPacket.symbol, aprsPacket.rssi, aprsPacket.snr);
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.syslog.active && networkManager->isConnected()) {
|
||||
|
||||
+14
-1
@@ -20,6 +20,9 @@
|
||||
#include "map_utils.h"
|
||||
#include "ntp_utils.h"
|
||||
|
||||
#define MAX_MAP_STATIONS 50
|
||||
#define STATION_TTL_MS 3600000UL // 1 hora (en milisegundos)
|
||||
|
||||
|
||||
std::vector<MapStation> mapStations;
|
||||
|
||||
@@ -39,7 +42,7 @@ namespace MAP_Utils {
|
||||
|
||||
// Inserta una estacion nueva o actualiza la existente (dedup por callsign).
|
||||
// Llamar solo cuando el parser ya decodifico una posicion valida.
|
||||
void upsert(const String& callsign, float latitude, float longitude, const String& symbol, int16_t rssi, float snr) {
|
||||
void upsert(const String& callsign, float latitude, float longitude, const String& symbol, int rssi, float snr) {
|
||||
for (auto &s : mapStations) { // 1) ya existe -> actualizar
|
||||
if (callsign.equals(s.callsign)) {
|
||||
s.latitude = latitude;
|
||||
@@ -77,7 +80,17 @@ namespace MAP_Utils {
|
||||
mapStations.push_back(st);
|
||||
}
|
||||
|
||||
void purgeOldStations() {
|
||||
uint32_t now = millis();
|
||||
for (int i = (int)mapStations.size() - 1; i >= 0; i--) {
|
||||
if (now - mapStations[i].lastHeardMillis > STATION_TTL_MS) {
|
||||
mapStations.erase(mapStations.begin() + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getStationsJson() {
|
||||
purgeOldStations();
|
||||
JsonDocument data;
|
||||
|
||||
for (size_t i = 0; i < mapStations.size(); i++) {
|
||||
|
||||
Reference in New Issue
Block a user