# NixOS Support This project includes a NixOS service module that allows you to run MeshCore Packet Capture as a systemd service on NixOS. ## Quick Start ### Recommended Configuration (Let'sMesh Analyzer) This configuration uploads packets to both Let's Mesh Analyzer servers (US and EU) for redundancy, plus an optional third MQTT broker for your own infrastructure: Add this to your `/etc/nixos/configuration.nix`: ```nix { imports = [ (builtins.fetchTarball "https://github.com/agessaman/meshcore-packet-capture/archive/main.tar.gz") ]; services.meshcore-packet-capture = { enable = true; connectionType = "ble"; # or "serial" or "tcp" # Connection settings (choose one based on connectionType) # For BLE: # bleAddress = "AA:BB:CC:DD:EE:FF"; # optional: specific device address # bleDeviceName = "MeshCore Device"; # optional: device name to scan for # For Serial: # serialPorts = [ "/dev/ttyUSB0" "/dev/ttyUSB1" ]; # list of ports to try # For TCP: # tcpHost = "localhost"; # TCP server hostname # tcpPort = 5000; # TCP server port # Let'sMesh Analyzer - US Server mqtt1 = { enabled = true; server = "mqtt-us-v1.letsmesh.net"; port = 443; transport = "websockets"; useTLS = true; useAuthToken = true; tokenAudience = "mqtt-us-v1.letsmesh.net"; keepalive = 120; }; # Let'sMesh Analyzer - EU Server mqtt2 = { enabled = true; server = "mqtt-eu-v1.letsmesh.net"; port = 443; transport = "websockets"; useTLS = true; useAuthToken = true; tokenAudience = "mqtt-eu-v1.letsmesh.net"; keepalive = 120; }; # Optional: Your own MQTT broker (uncomment and configure as needed) # mqtt3 = { # enabled = true; # server = "mqtt.example.com"; # port = 1883; # username = "your_username"; # password = "your_password"; # # or use TLS: # # port = 8883; # # useTLS = true; # }; # Device private key for Let'sMesh authentication # The script automatically fetches the private key from the device if it supports # ENABLE_PRIVATE_KEY_EXPORT. Only provide these if automatic fetching fails: # privateKeyFile = "/path/to/your/private/key/file"; # OR # privateKey = "your_private_key_hex_string"; # Optional: Owner information for Let'sMesh Analyzer # ownerPublicKey = "YOUR_64_CHAR_HEX_PUBLIC_KEY"; # 64 hex characters # ownerEmail = "your.email@example.com"; # Email for Let'sMesh Analyzer # Optional: IATA code for topic templates iata = "SEA"; # Replace with your IATA code }; } ``` Then rebuild your system: ```bash sudo nixos-rebuild switch ``` **Note:** For Let'sMesh Analyzer authentication, you need your device's private key. See the [Authentication](#authentication) section below for details. ### Custom MQTT Broker Configuration If you prefer to use your own MQTT broker instead of (or in addition to) Let'sMesh Analyzer: ```nix services.meshcore-packet-capture = { enable = true; connectionType = "ble"; mqtt1 = { enabled = true; server = "mqtt.example.com"; port = 1883; # or 8883 for TLS username = "your_username"; password = "your_password"; # Optional: Enable TLS # useTLS = true; # tlsVerify = true; }; }; ``` ## Using with Flakes If you're using Nix Flakes, add this to your `flake.nix`: ```nix { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; meshcore-packet-capture = { url = "github:agessaman/meshcore-packet-capture"; inputs.nixpkgs.follows = "nixpkgs"; }; }; outputs = { self, nixpkgs, meshcore-packet-capture }: { nixosConfigurations.your-hostname = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; modules = [ meshcore-packet-capture.nixosModules.default { services.meshcore-packet-capture = { enable = true; package = meshcore-packet-capture.packages.${system}.default; connectionType = "ble"; # Let'sMesh Analyzer - US Server mqtt1 = { enabled = true; server = "mqtt-us-v1.letsmesh.net"; port = 443; transport = "websockets"; useTLS = true; useAuthToken = true; tokenAudience = "mqtt-us-v1.letsmesh.net"; keepalive = 120; }; # Let'sMesh Analyzer - EU Server mqtt2 = { enabled = true; server = "mqtt-eu-v1.letsmesh.net"; port = 443; transport = "websockets"; useTLS = true; useAuthToken = true; tokenAudience = "mqtt-eu-v1.letsmesh.net"; keepalive = 120; }; # Device private key is automatically fetched from the device # Only set these if automatic fetching fails: # privateKeyFile = "/path/to/your/private/key/file"; # privateKey = "your_private_key_hex_string"; # Optional: Owner information for Let'sMesh Analyzer # ownerPublicKey = "YOUR_64_CHAR_HEX_PUBLIC_KEY"; # ownerEmail = "your.email@example.com"; iata = "SEA"; }; } ]; }; }; } ``` ## Configuration Options ### Connection Settings ```nix services.meshcore-packet-capture = { connectionType = "ble"; # or "serial" or "tcp" bleAddress = "AA:BB:CC:DD:EE:FF"; # optional bleDeviceName = "MeshCore Device"; # optional serialPorts = [ "/dev/ttyUSB0" "/dev/ttyUSB1" ]; # for serial connection tcpHost = "localhost"; # for TCP connection tcpPort = 5000; # for TCP connection timeout = 30; maxConnectionRetries = 5; # 0 = infinite connectionRetryDelay = 5; healthCheckInterval = 30; }; ``` ### MQTT Brokers You can configure up to 4 MQTT brokers. Here's an example with Let'sMesh Analyzer (recommended) plus a custom broker: ```nix services.meshcore-packet-capture = { # Let'sMesh Analyzer - US Server mqtt1 = { enabled = true; server = "mqtt-us-v1.letsmesh.net"; port = 443; transport = "websockets"; useTLS = true; useAuthToken = true; tokenAudience = "mqtt-us-v1.letsmesh.net"; keepalive = 120; }; # Let'sMesh Analyzer - EU Server (for redundancy) mqtt2 = { enabled = true; server = "mqtt-eu-v1.letsmesh.net"; port = 443; transport = "websockets"; useTLS = true; useAuthToken = true; tokenAudience = "mqtt-eu-v1.letsmesh.net"; keepalive = 120; }; # Your own MQTT broker (optional) mqtt3 = { enabled = true; server = "mqtt.example.com"; port = 1883; # or 8883 for TLS username = "user"; password = "pass"; transport = "tcp"; # or "websockets" useTLS = false; # set to true for TLS tlsVerify = true; qos = 0; retain = false; keepalive = 60; # Optional topic overrides topicStatus = "meshcore/status"; topicPackets = "meshcore/packets"; topicRaw = "meshcore/raw"; }; # mqtt4 can be configured similarly }; ``` ### Authentication For username/password authentication: ```nix services.meshcore-packet-capture = { mqtt1 = { username = "your_username"; password = "your_password"; }; }; ``` For JWT token authentication: ```nix services.meshcore-packet-capture = { mqtt1 = { useAuthToken = true; tokenAudience = "mqtt.example.com"; }; # Private key is automatically fetched from the device if it supports ENABLE_PRIVATE_KEY_EXPORT # Only provide these if automatic fetching fails: # privateKey = "your_private_key_hex_string"; # OR # privateKeyFile = "/path/to/private/key/file"; }; ``` ### Other Settings ```nix services.meshcore-packet-capture = { logLevel = "INFO"; # DEBUG, INFO, WARNING, ERROR, CRITICAL verbose = false; debug = false; enableMqtt = true; maxMqttRetries = 5; # 0 = infinite mqttRetryDelay = 5; exitOnReconnectFail = true; iata = "SEA"; # For topic templates origin = "My Device"; advertIntervalHours = 11; # 0 = disabled uploadPacketTypes = [ 0 1 2 ]; # Filter packet types, null = all rfDataTimeout = 15.0; outputFile = null; # Optional output file path # privateKeyFile = "/path/to/private/key/file"; # Only if auto-fetch fails # privateKey = "hex_string"; # Only if auto-fetch fails ownerPublicKey = null; # Optional: 64 hex character owner public key ownerEmail = null; # Optional: Owner email for Let'sMesh Analyzer dataDir = "/var/lib/meshcore-packet-capture"; user = "meshcore"; group = "meshcore"; }; ``` ## Permissions The service automatically adds the service user to the `bluetooth` and `dialout` groups for BLE and serial port access. ## Development To enter a development shell with all dependencies: ```bash nix develop ``` ## Troubleshooting ### Package not found If you get an error about `meshcore` package not being found, you may need to update the hash in `nix/packages.nix`. The first time you build, Nix will tell you the correct hash to use. ### BLE not working Ensure that: 1. Bluetooth is enabled: `services.bluetooth.enable = true;` 2. The service user has proper permissions (automatically handled) 3. Your Bluetooth adapter is properly configured ### Serial port not accessible Ensure that: 1. The device exists: `ls -l /dev/ttyUSB0` 2. The service user is in the `dialout` group (automatically handled) 3. You've specified the correct port in `serialPorts` ### Service logs View service logs with: ```bash journalctl -u meshcore-packet-capture -f ``` ## Building the Package To build just the package (without installing as a service): ```bash nix build ``` The package will be available at `./result/bin/meshcore-packet-capture`.