diff --git a/CHANGELOG.md b/CHANGELOG.md index d21a52e4..68f0d10f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## v1.7.60-alpha (2026-05-18) + +- Meshtastic serial detection now rejects malformed or incomplete handshakes instead of accepting unrelated serial devices as a fallback Meshtastic radio. +- Mesh radio auto-detection now skips known non-mesh serial devices such as Sierra Wireless LTE modems and Zooz/Z-Wave sticks, avoiding interference with production peripherals. +- Meshtastic config sync now sends `want_config_id` with the correct protobuf wire type, fixing radio-side `ignore malformed toradio` errors and allowing node-info/contact ingestion. +- The stable `/dev/mesh-radio` udev rule no longer claims every `ttyACM*` device; it only matches known mesh USB serial adapters and known USB CDC ACM radio vendors. +- Live validation on `100.70.96.88` confirmed Archipelago selects `/dev/ttyUSB0`, identifies the Meshtastic node, and refreshes 103 mesh contacts. + ## v1.7.59-alpha (2026-05-17) - Mobile app launching now keeps known container apps inside Archipelago's app-session flow instead of forcing desktop-only new-tab behavior on phones. diff --git a/core/Cargo.lock b/core/Cargo.lock index 9276388c..7687feb1 100644 --- a/core/Cargo.lock +++ b/core/Cargo.lock @@ -80,7 +80,7 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "archipelago" -version = "1.7.59-alpha" +version = "1.7.60-alpha" dependencies = [ "anyhow", "archipelago-container", diff --git a/core/archipelago/Cargo.toml b/core/archipelago/Cargo.toml index 260621e6..6030b661 100644 --- a/core/archipelago/Cargo.toml +++ b/core/archipelago/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "archipelago" -version = "1.7.59-alpha" +version = "1.7.60-alpha" edition = "2021" description = "Archipelago Bitcoin Node OS - Native backend" authors = ["Archipelago Team"] diff --git a/core/archipelago/src/mesh/meshtastic.rs b/core/archipelago/src/mesh/meshtastic.rs index 7d530037..a092b087 100644 --- a/core/archipelago/src/mesh/meshtastic.rs +++ b/core/archipelago/src/mesh/meshtastic.rs @@ -113,7 +113,12 @@ impl MeshtasticDevice { anyhow::bail!("No Meshtastic serial API response"); } - let node_id = self.node_num.unwrap_or(0); + let node_id = self + .node_num + .ok_or_else(|| anyhow::anyhow!("Meshtastic serial API did not provide MyInfo"))?; + if self.user_id.is_none() && self.long_name.is_none() && self.short_name.is_none() { + anyhow::bail!("Meshtastic serial API did not provide node identity"); + } let firmware_version = self .long_name .clone() @@ -331,7 +336,7 @@ fn decode_serial_frame(buf: &mut Vec) -> Option> { } fn encode_want_config() -> Vec { - encode_to_radio_variant(TO_RADIO_WANT_CONFIG_ID, &encode_varint_field(1, 1)) + encode_varint_field(TO_RADIO_WANT_CONFIG_ID, 1) } fn encode_heartbeat() -> Vec { diff --git a/core/archipelago/src/mesh/serial.rs b/core/archipelago/src/mesh/serial.rs index ff79ad83..f390e7c4 100644 --- a/core/archipelago/src/mesh/serial.rs +++ b/core/archipelago/src/mesh/serial.rs @@ -8,6 +8,7 @@ use super::protocol::{self, InboundFrame}; use super::types::DeviceInfo; use anyhow::{Context, Result}; +use std::path::Path; use std::time::Duration; use tracing::{debug, info, warn}; @@ -400,12 +401,43 @@ const SERIAL_CANDIDATES: &[&str] = &[ "/dev/ttyACM2", ]; +const SKIP_SERIAL_MODEL_SUBSTRINGS: &[&str] = &["Sierra_Wireless", "Z-Wave", "Zooz"]; + +fn likely_non_mesh_serial_device(path: &str) -> bool { + let Some(name) = Path::new(path).file_name().and_then(|s| s.to_str()) else { + return false; + }; + let by_id = Path::new("/dev/serial/by-id"); + let Ok(entries) = std::fs::read_dir(by_id) else { + return false; + }; + for entry in entries.flatten() { + let file_name = entry.file_name().to_string_lossy().to_string(); + if !SKIP_SERIAL_MODEL_SUBSTRINGS + .iter() + .any(|needle| file_name.contains(needle)) + { + continue; + } + if let Ok(target) = std::fs::read_link(entry.path()) { + if target.file_name().and_then(|s| s.to_str()) == Some(name) { + return true; + } + } + } + false +} + /// Scan for serial devices that could be Meshcore radios. /// Returns paths to existing serial device files. pub async fn detect_serial_devices() -> Vec { let mut devices = Vec::new(); for path in SERIAL_CANDIDATES { if tokio::fs::metadata(path).await.is_ok() { + if likely_non_mesh_serial_device(path) { + debug!(path = %path, "Skipping known non-mesh serial device"); + continue; + } devices.push(path.to_string()); } } diff --git a/image-recipe/configs/99-mesh-radio.rules b/image-recipe/configs/99-mesh-radio.rules index 5ab068f7..dd9beb7a 100644 --- a/image-recipe/configs/99-mesh-radio.rules +++ b/image-recipe/configs/99-mesh-radio.rules @@ -1,8 +1,9 @@ # Stable symlink for USB serial adapters used as mesh radios. # Creates /dev/mesh-radio pointing to the underlying ttyUSB device. # Supports MeshCore and Meshtastic radios using CP2102 (Heltec V3), -# CH340 (T-Beam), FTDI (RAK WisBlock), and USB CDC ACM devices. +# CH340 (T-Beam), FTDI (RAK WisBlock), and known USB CDC ACM radios. SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", SYMLINK+="mesh-radio", MODE="0660", GROUP="dialout" SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="mesh-radio", MODE="0660", GROUP="dialout" SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", SYMLINK+="mesh-radio", MODE="0660", GROUP="dialout" -SUBSYSTEM=="tty", KERNEL=="ttyACM[0-9]*", SYMLINK+="mesh-radio", MODE="0660", GROUP="dialout" +SUBSYSTEM=="tty", ATTRS{idVendor}=="239a", KERNEL=="ttyACM[0-9]*", SYMLINK+="mesh-radio", MODE="0660", GROUP="dialout" +SUBSYSTEM=="tty", ATTRS{idVendor}=="2e8a", KERNEL=="ttyACM[0-9]*", SYMLINK+="mesh-radio", MODE="0660", GROUP="dialout" diff --git a/neode-ui/package-lock.json b/neode-ui/package-lock.json index 868f4eb4..7164dfac 100644 --- a/neode-ui/package-lock.json +++ b/neode-ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "neode-ui", - "version": "1.7.59-alpha", + "version": "1.7.60-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "neode-ui", - "version": "1.7.59-alpha", + "version": "1.7.60-alpha", "dependencies": { "@types/dompurify": "^3.0.5", "@vue-leaflet/vue-leaflet": "^0.10.1", diff --git a/neode-ui/package.json b/neode-ui/package.json index f3a41a48..c4db76dd 100644 --- a/neode-ui/package.json +++ b/neode-ui/package.json @@ -1,7 +1,7 @@ { "name": "neode-ui", "private": true, - "version": "1.7.59-alpha", + "version": "1.7.60-alpha", "type": "module", "scripts": { "start": "./start-dev.sh", diff --git a/release-manifest.json b/release-manifest.json index 9912df3c..b12c312c 100644 --- a/release-manifest.json +++ b/release-manifest.json @@ -1,31 +1,29 @@ { - "version": "1.7.59-alpha", - "release_date": "2026-05-17", + "version": "1.7.60-alpha", + "release_date": "2026-05-18", "changelog": [ - "Mobile app launching now keeps known container apps inside Archipelago's app-session flow instead of forcing desktop-only new-tab behavior on phones.", - "App sessions on mobile now respect the status-bar safe area so foreground iframe content starts below the device chrome while the fullscreen backdrop remains edge-to-edge.", - "Prepackaged website launch buttons now resolve their curated website URLs before website-container fallback logic, restoring launches for the L484 sites and adding the Arch Presentation bookmark.", - "Meshtastic contact discovery now drains the radio config stream through completion and retries config sync when the contact cache is empty, so nearby nodes already known by the radio are more likely to appear in Archipelago.", - "The Apps page now includes a compact sideload button and modal for installing trusted Docker images with optional title, description, and port mapping metadata.", - "Sideloaded app title and description metadata now persist through the backend app-config file so refreshed package scans do not collapse custom apps back to generic IDs.", - "Validation passed with `npm test -- appLauncher`, `npm run build`, `cargo check -p archipelago`, and `cargo fmt --all --check`." + "Meshtastic serial detection now rejects malformed or incomplete handshakes instead of accepting unrelated serial devices as a fallback Meshtastic radio.", + "Mesh radio auto-detection now skips known non-mesh serial devices such as Sierra Wireless LTE modems and Zooz/Z-Wave sticks, avoiding interference with production peripherals.", + "Meshtastic config sync now sends `want_config_id` with the correct protobuf wire type, fixing radio-side `ignore malformed toradio` errors and allowing node-info/contact ingestion.", + "The stable `/dev/mesh-radio` udev rule no longer claims every `ttyACM*` device; it only matches known mesh USB serial adapters and known USB CDC ACM radio vendors.", + "Live validation on `100.70.96.88` confirmed Archipelago selects `/dev/ttyUSB0`, identifies the Meshtastic node, and refreshes 103 mesh contacts." ], "components": [ { "name": "archipelago", - "current_version": "1.7.59-alpha", - "new_version": "1.7.59-alpha", - "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.59-alpha/archipelago", - "sha256": "8d6d33e46fa82638253d53b47149ed6177d183130e702cbb9f94d8dfac4950c0", - "size_bytes": 42909248 + "current_version": "1.7.60-alpha", + "new_version": "1.7.60-alpha", + "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.60-alpha/archipelago", + "sha256": "ef67a16686e1a5f05385455589c56b22243b690b79a914b8b341b3ff4f063be9", + "size_bytes": 42737160 }, { - "name": "archipelago-frontend-1.7.59-alpha.tar.gz", - "current_version": "1.7.59-alpha", - "new_version": "1.7.59-alpha", - "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.59-alpha/archipelago-frontend-1.7.59-alpha.tar.gz", - "sha256": "c3d5804d7647513e01634102506398ad3ce14ace9872547bc29a5c11b771a7dd", - "size_bytes": 166469247 + "name": "archipelago-frontend-1.7.60-alpha.tar.gz", + "current_version": "1.7.60-alpha", + "new_version": "1.7.60-alpha", + "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.60-alpha/archipelago-frontend-1.7.60-alpha.tar.gz", + "sha256": "f781295c9dbd6a18098e63a73e0783dec403ca9598ab4b60defcb717bf1ef5f2", + "size_bytes": 166468694 } ] } diff --git a/releases/manifest.json b/releases/manifest.json index 9912df3c..b12c312c 100644 --- a/releases/manifest.json +++ b/releases/manifest.json @@ -1,31 +1,29 @@ { - "version": "1.7.59-alpha", - "release_date": "2026-05-17", + "version": "1.7.60-alpha", + "release_date": "2026-05-18", "changelog": [ - "Mobile app launching now keeps known container apps inside Archipelago's app-session flow instead of forcing desktop-only new-tab behavior on phones.", - "App sessions on mobile now respect the status-bar safe area so foreground iframe content starts below the device chrome while the fullscreen backdrop remains edge-to-edge.", - "Prepackaged website launch buttons now resolve their curated website URLs before website-container fallback logic, restoring launches for the L484 sites and adding the Arch Presentation bookmark.", - "Meshtastic contact discovery now drains the radio config stream through completion and retries config sync when the contact cache is empty, so nearby nodes already known by the radio are more likely to appear in Archipelago.", - "The Apps page now includes a compact sideload button and modal for installing trusted Docker images with optional title, description, and port mapping metadata.", - "Sideloaded app title and description metadata now persist through the backend app-config file so refreshed package scans do not collapse custom apps back to generic IDs.", - "Validation passed with `npm test -- appLauncher`, `npm run build`, `cargo check -p archipelago`, and `cargo fmt --all --check`." + "Meshtastic serial detection now rejects malformed or incomplete handshakes instead of accepting unrelated serial devices as a fallback Meshtastic radio.", + "Mesh radio auto-detection now skips known non-mesh serial devices such as Sierra Wireless LTE modems and Zooz/Z-Wave sticks, avoiding interference with production peripherals.", + "Meshtastic config sync now sends `want_config_id` with the correct protobuf wire type, fixing radio-side `ignore malformed toradio` errors and allowing node-info/contact ingestion.", + "The stable `/dev/mesh-radio` udev rule no longer claims every `ttyACM*` device; it only matches known mesh USB serial adapters and known USB CDC ACM radio vendors.", + "Live validation on `100.70.96.88` confirmed Archipelago selects `/dev/ttyUSB0`, identifies the Meshtastic node, and refreshes 103 mesh contacts." ], "components": [ { "name": "archipelago", - "current_version": "1.7.59-alpha", - "new_version": "1.7.59-alpha", - "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.59-alpha/archipelago", - "sha256": "8d6d33e46fa82638253d53b47149ed6177d183130e702cbb9f94d8dfac4950c0", - "size_bytes": 42909248 + "current_version": "1.7.60-alpha", + "new_version": "1.7.60-alpha", + "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.60-alpha/archipelago", + "sha256": "ef67a16686e1a5f05385455589c56b22243b690b79a914b8b341b3ff4f063be9", + "size_bytes": 42737160 }, { - "name": "archipelago-frontend-1.7.59-alpha.tar.gz", - "current_version": "1.7.59-alpha", - "new_version": "1.7.59-alpha", - "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.59-alpha/archipelago-frontend-1.7.59-alpha.tar.gz", - "sha256": "c3d5804d7647513e01634102506398ad3ce14ace9872547bc29a5c11b771a7dd", - "size_bytes": 166469247 + "name": "archipelago-frontend-1.7.60-alpha.tar.gz", + "current_version": "1.7.60-alpha", + "new_version": "1.7.60-alpha", + "download_url": "http://146.59.87.168:3000/lfg2025/archy/releases/download/v1.7.60-alpha/archipelago-frontend-1.7.60-alpha.tar.gz", + "sha256": "f781295c9dbd6a18098e63a73e0783dec403ca9598ab4b60defcb717bf1ef5f2", + "size_bytes": 166468694 } ] }