From d19c071814c5d675a91499720cf567b4cb251db2 Mon Sep 17 00:00:00 2001 From: Will Bradley Date: Sat, 11 Oct 2025 21:05:39 -0700 Subject: [PATCH] basic working --- .env.example | 1 + .env.meshtastic | 27 +++++++++++++++++++++++++++ public/css/style.css | 12 ++++++++++++ public/index.html | 13 +++---------- public/js/app.js | 8 ++++---- src/config/config.js | 1 + src/mqtt/client.js | 16 +++++++--------- src/routes/api.js | 4 ++-- 8 files changed, 57 insertions(+), 25 deletions(-) create mode 100644 .env.meshtastic diff --git a/.env.example b/.env.example index 27cd91e..9176b82 100644 --- a/.env.example +++ b/.env.example @@ -11,6 +11,7 @@ MQTT_PORT=1883 MQTT_USERNAME=meshdev MQTT_PASSWORD=large4cats MQTT_TOPIC=msh/US/# +MQTT_PUB_TOPIC="msh/US/2/json/mqtt/" # Optional: If you have your own MQTT broker # MQTT_BROKER=mqtt://your-broker.com diff --git a/.env.meshtastic b/.env.meshtastic new file mode 100644 index 0000000..1d01595 --- /dev/null +++ b/.env.meshtastic @@ -0,0 +1,27 @@ +# Server Configuration +PORT=3000 +NODE_ENV=development + +# Session Secret +SESSION_SECRET=test-secret-for-development-only + +# MQTT Configuration (Meshtastic Public Broker) +MQTT_BROKER=mqtt://mqtt.meshtastic.org +MQTT_PORT=1883 +MQTT_USERNAME=meshdev +MQTT_PASSWORD=large4cats +MQTT_TOPIC=# +MQTT_PUB_TOPIC="msh/US/2/json/mqtt/" + +# Data Retention (in days) +DATA_RETENTION_DAYS=30 + +# Cron schedule for automatic data purging (daily at 2 AM) +PURGE_CRON_SCHEDULE=0 2 * * * + +# Logging +LOG_LEVEL=info + +# Rate Limiting +RATE_LIMIT_WINDOW_MS=900000 +RATE_LIMIT_MAX_REQUESTS=1000 diff --git a/public/css/style.css b/public/css/style.css index 62216bd..83a20aa 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -114,6 +114,18 @@ body { font-size: 0.875rem; } +.data-last-received { + display: flex; + align-items: center; + gap: 0.25rem; + font-size: 0.875rem; + color: var(--text-secondary); +} + +.data-label { + opacity: 0.7; +} + /* Navigation Tabs */ .nav-tabs { background: var(--surface-color); diff --git a/public/index.html b/public/index.html index 36220ee..c033224 100644 --- a/public/index.html +++ b/public/index.html @@ -43,7 +43,7 @@ MQTT - Last data: 0s ago + Last data: 0s ago @@ -115,15 +115,8 @@
- +
diff --git a/public/js/app.js b/public/js/app.js index 520a2bd..3905b40 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -173,10 +173,10 @@ const api = { return this.request(`/api/messages?limit=${limit}`); }, - async sendMessage(text, channel = 0) { + async sendMessage(from, text) { return this.request('/api/messages/send', { method: 'POST', - body: JSON.stringify({ text, channel }) + body: JSON.stringify({ text, from }) }); }, @@ -546,10 +546,10 @@ document.getElementById('send-message-form')?.addEventListener('submit', async ( e.preventDefault(); const text = document.getElementById('message-text').value; - const channel = parseInt(document.getElementById('message-channel').value); + const from = parseInt(document.getElementById('message-from').value); try { - await api.sendMessage(text, channel); + await api.sendMessage(text, from); document.getElementById('message-text').value = ''; // Reload messages after a short delay diff --git a/src/config/config.js b/src/config/config.js index c493685..613d283 100644 --- a/src/config/config.js +++ b/src/config/config.js @@ -26,6 +26,7 @@ module.exports = { username: process.env.MQTT_USERNAME || 'meshdev', password: process.env.MQTT_PASSWORD || 'large4cats', topic: process.env.MQTT_TOPIC || 'msh/US/#', + pubTopic: process.env.MQTT_PUB_TOPIC || 'msh/US/2/json/mqtt/', // The ending / is apparently critical options: { clientId: `meshtastic-dashboard-${Math.random().toString(16).substr(2, 8)}`, clean: true, diff --git a/src/mqtt/client.js b/src/mqtt/client.js index 5a14a97..80a2ed9 100644 --- a/src/mqtt/client.js +++ b/src/mqtt/client.js @@ -88,8 +88,8 @@ class MeshtasticMQTTClient { try { const { from, to, channel, id, sender } = payload; - // Extract node ID (convert to hex string if it's a number) - const fromNode = sender || (from ? `!${from.toString(16).padStart(8, '0')}` : null); + // Extract node ID (convert to hex string if it's a number, fallback to sender if none + const fromNode = from ? `!${from.toString(16).padStart(8, '0')}` : sender; const toNode = to ? `!${to.toString(16).padStart(8, '0')}` : null; // Handle different message types based on actual JSON structure @@ -344,18 +344,16 @@ class MeshtasticMQTTClient { } // Send a text message - async sendTextMessage(text, channel = 0) { + async sendTextMessage(from, text) { try { const message = JSON.stringify({ - type: 'text', - text, - channel, - timestamp: Date.now() + from: from, + type: 'sendtext', + payload: text }); // Publish to the appropriate topic - const baseTopic = config.mqtt.topic.replace('/#', ''); - await this.publish(`${baseTopic}/2/json/mqtt`, message); + await this.publish(config.mqtt.pubTopic, message); return true; } catch (error) { diff --git a/src/routes/api.js b/src/routes/api.js index 2331a7c..d45deee 100644 --- a/src/routes/api.js +++ b/src/routes/api.js @@ -169,13 +169,13 @@ router.get('/messages/node/:nodeId', requireAuth, (req, res) => { // Send a message router.post('/messages/send', requireAuth, async (req, res) => { try { - const { text, channel } = req.body; + const { text, from } = req.body; if (!text) { return res.status(400).json({ error: 'Message text required' }); } - await mqttClient.sendTextMessage(text, channel || 0); + await mqttClient.sendTextMessage(text, from || 0); // Log activity logActivity(req.session.userId, 'send_message', text, req.ip);