Skip to content

GonZo/LusoAPP

Repository files navigation

Companion App for the Portuguese MeshCore Community

MeshCore PT (lusoapp) is a Flutter companion app for MeshCore radios, built by and for the Portuguese amateur radio and mesh networking community.

Features

  • Channel Messaging — Send and receive messages on MeshCore channels
  • Private Chat — End-to-end encrypted 1:1 messaging via Ed25519/X25519
  • Radio Configuration — Full LoRa parameter control (frequency, bandwidth, SF, CR, TX power)
  • Contact Management — View and manage discovered mesh nodes (chat, repeaters, rooms, sensors)
  • BLE Connection — Connect to ESP32 and nRF52 MeshCore radios via Bluetooth Low Energy
  • Serial Connection — Connect via USB OTG serial (115200 8N1)
  • EU868 Presets — Quick radio presets compliant with Portuguese/EU regulations
  • Portuguese UI — Full Portuguese (Portugal) interface
  • Map View — Live GPS map of all contacts and mesh nodes (OpenStreetMap, no API key required)
  • Offline Map — Browse-cached tiles via flutter_map_tile_caching; tiles are stored automatically as you pan/zoom and served from disk when offline

Note on offline map caching: Tile caching is purely browse-based — tiles are saved as you explore the map while online and replayed when offline. There is no "download this area" bulk pre-download feature. This is intentional: OSM's tile server policy forbids bulk pre-downloading of regions.

Quick Start

Prerequisites

  • Flutter SDK >= 3.29.0
  • Android Studio or VS Code with Flutter extensions
  • A MeshCore radio (ESP32 or nRF52 based)

Build & Run

# Clone the repository
git clone <repo-url> lusoapp
cd lusoapp

# Get dependencies
flutter pub get

# Run on connected device
flutter run

# Build release APK
flutter build apk --release

Supported Platforms

Platform Transport Status
Android BLE + Serial Primary target
iOS BLE Planned
Windows Serial Planned
Linux Serial Planned

Architecture

lib/
├── main.dart                    # App entry point
├── protocol/                    # MeshCore protocol implementation
│   ├── kiss.dart                # KISS TNC framing
│   ├── commands.dart            # Command/response constants
│   ├── models.dart              # Data models (Contact, Message, RadioConfig)
│   ├── companion_encoder.dart   # App→Radio frame encoder
│   └── companion_decoder.dart   # Radio→App frame decoder
├── transport/                   # Communication layer
│   ├── radio_transport.dart     # Abstract transport interface
│   ├── ble_transport.dart       # BLE (Nordic UART) transport
│   └── serial_transport.dart    # USB Serial transport
├── services/
│   └── radio_service.dart       # High-level radio communication coordinator
├── providers/
│   └── radio_providers.dart     # Riverpod state management
└── ui/
    ├── theme.dart               # Material 3 dark/light theme
    ├── router.dart              # GoRouter navigation
    └── screens/
        ├── connect_screen.dart      # Device scan & connect
        ├── home_screen.dart         # Main shell with bottom nav
        ├── channel_chat_screen.dart # Channel messaging
        ├── private_chat_screen.dart # 1:1 private chat
        ├── contacts_screen.dart     # Contact list
        ├── radio_config_screen.dart # LoRa configuration
        └── settings_screen.dart     # App settings

Protocol Support

The app implements the MeshCore Companion Radio Protocol v3:

  • All App→Radio commands (APP_START, SEND_MSG, SEND_CHAN_MSG, GET_CONTACTS, SET_RADIO_PARAMS, etc.)
  • All Radio→App responses (SELF_INFO, CONTACT, CHANNEL_MSG_RECV_V3, etc.)
  • Unsolicited push notifications (ADVERT, MSG_WAITING, SEND_CONFIRMED, etc.)
  • BLE: Nordic UART Service (6E400001-B5A3-F393-E0A9-E50E24DCCA9E)
  • Serial: 115200 baud, 8N1, DTR+RTS

Regulatory Information

Default LoRa parameters comply with EU868 SRD regulations:

  • Frequency: 869.618 MHz
  • Bandwidth: 62.5 kHz
  • TX Power: 14 dBm ERP max
  • Duty Cycle: Users must respect 10% limits

Users are responsible for compliance with ANACOM regulations and amateur radio licence conditions.

Contributing

Contributions are welcome! Please see the ROADMAP.md for planned features and the project direction.

Translations

The app uses Flutter's built-in flutter_localizations / intl ARB pipeline.

File layout

lib/l10n/
├── app_pt.arb                  ← Template (source of truth, Portuguese PT)
├── app_en.arb                  ← English translation
├── app_es.arb                  ← Spanish translation
├── app_localizations.dart      ← Generated — do NOT edit by hand
├── app_localizations_pt.dart   ← Generated
├── app_localizations_en.dart   ← Generated
├── app_localizations_es.dart   ← Generated
└── l10n.dart                   ← BuildContext extension: context.l10n.<key>

Configuration lives in l10n.yaml (project root):

arb-dir: lib/l10n
template-arb-file: app_pt.arb   # PT is the template locale
output-localization-file: app_localizations.dart
output-dir: lib/l10n
nullable-getter: false

How to add or change a string

  1. Edit lib/l10n/app_pt.arb — add the new key and its Portuguese value.
    Keys follow the naming convention <screenOrGroup><PascalCaseName>, e.g. commonSave, navChannels, settingsTitle.

    "myNewKey": "Texto em português",
    "@myNewKey": {}
  2. Repeat for every other ARB file (app_en.arb, app_es.arb, …) adding the translated text for each locale.

  3. Regenerate the Dart classes:

    flutter gen-l10n

    This regenerates app_localizations.dart and all app_localizations_<locale>.dart files.
    Never edit those files manually — they are overwritten on every run.

  4. Use the string in code:

    import '../../l10n/l10n.dart';
    
    // Inside a Widget build method:
    Text(context.l10n.myNewKey)

How to add a new language

  1. Create lib/l10n/app_<locale>.arb — copy app_en.arb as a starting point and translate all values.
  2. Run flutter gen-l10n — the new locale is picked up automatically.
  3. No changes to pubspec.yaml or main.dart are needed; AppLocalizations.supportedLocales is generated from the ARB files.

Placeholders and plurals

Flutter ARB supports ICU message syntax. Example with a parameter:

"unreadCount": "{count} mensagens não lidas",
"@unreadCount": {
  "placeholders": {
    "count": { "type": "int" }
  }
}

Usage: context.l10n.unreadCount(42)

Scripts helper

# Regenerate translations (run from project root)
flutter gen-l10n

License

MIT License — see LICENSE for details.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors