Skip to content

Commit 3a6ef28

Browse files
committed
I gave NixOS support my best shot. I don't use it, so please feel free to send a PR if it doesn't work for you.
1 parent 8b3bf8f commit 3a6ef28

File tree

2 files changed

+363
-0
lines changed

2 files changed

+363
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,4 @@ Thumbs.db
7474

7575
# Testing directory (not committed to repo)
7676
tests/
77+
nixos-test/

NIXOS.md

Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
# NixOS Support
2+
3+
This project includes a NixOS service module that allows you to run MeshCore Packet Capture as a systemd service on NixOS.
4+
5+
## Quick Start
6+
7+
### Recommended Configuration (Let'sMesh Analyzer)
8+
9+
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:
10+
11+
Add this to your `/etc/nixos/configuration.nix`:
12+
13+
```nix
14+
{
15+
imports = [
16+
(builtins.fetchTarball "https://github.com/agessaman/meshcore-packet-capture/archive/main.tar.gz")
17+
];
18+
19+
services.meshcore-packet-capture = {
20+
enable = true;
21+
connectionType = "ble"; # or "serial" or "tcp"
22+
23+
# Connection settings (choose one based on connectionType)
24+
# For BLE:
25+
# bleAddress = "AA:BB:CC:DD:EE:FF"; # optional: specific device address
26+
# bleDeviceName = "MeshCore Device"; # optional: device name to scan for
27+
28+
# For Serial:
29+
# serialPorts = [ "/dev/ttyUSB0" "/dev/ttyUSB1" ]; # list of ports to try
30+
31+
# For TCP:
32+
# tcpHost = "localhost"; # TCP server hostname
33+
# tcpPort = 5000; # TCP server port
34+
35+
# Let'sMesh Analyzer - US Server
36+
mqtt1 = {
37+
enabled = true;
38+
server = "mqtt-us-v1.letsmesh.net";
39+
port = 443;
40+
transport = "websockets";
41+
useTLS = true;
42+
useAuthToken = true;
43+
tokenAudience = "mqtt-us-v1.letsmesh.net";
44+
keepalive = 120;
45+
};
46+
47+
# Let'sMesh Analyzer - EU Server
48+
mqtt2 = {
49+
enabled = true;
50+
server = "mqtt-eu-v1.letsmesh.net";
51+
port = 443;
52+
transport = "websockets";
53+
useTLS = true;
54+
useAuthToken = true;
55+
tokenAudience = "mqtt-eu-v1.letsmesh.net";
56+
keepalive = 120;
57+
};
58+
59+
# Optional: Your own MQTT broker (uncomment and configure as needed)
60+
# mqtt3 = {
61+
# enabled = true;
62+
# server = "mqtt.example.com";
63+
# port = 1883;
64+
# username = "your_username";
65+
# password = "your_password";
66+
# # or use TLS:
67+
# # port = 8883;
68+
# # useTLS = true;
69+
# };
70+
71+
# Device private key for Let'sMesh authentication
72+
# The script automatically fetches the private key from the device if it supports
73+
# ENABLE_PRIVATE_KEY_EXPORT. Only provide these if automatic fetching fails:
74+
# privateKeyFile = "/path/to/your/private/key/file";
75+
# OR
76+
# privateKey = "your_private_key_hex_string";
77+
78+
# Optional: Owner information for Let'sMesh Analyzer
79+
# ownerPublicKey = "YOUR_64_CHAR_HEX_PUBLIC_KEY"; # 64 hex characters
80+
# ownerEmail = "[email protected]"; # Email for Let'sMesh Analyzer
81+
82+
# Optional: IATA code for topic templates
83+
iata = "SEA"; # Replace with your IATA code
84+
};
85+
}
86+
```
87+
88+
Then rebuild your system:
89+
90+
```bash
91+
sudo nixos-rebuild switch
92+
```
93+
94+
**Note:** For Let'sMesh Analyzer authentication, you need your device's private key. See the [Authentication](#authentication) section below for details.
95+
96+
### Custom MQTT Broker Configuration
97+
98+
If you prefer to use your own MQTT broker instead of (or in addition to) Let'sMesh Analyzer:
99+
100+
```nix
101+
services.meshcore-packet-capture = {
102+
enable = true;
103+
connectionType = "ble";
104+
105+
mqtt1 = {
106+
enabled = true;
107+
server = "mqtt.example.com";
108+
port = 1883; # or 8883 for TLS
109+
username = "your_username";
110+
password = "your_password";
111+
# Optional: Enable TLS
112+
# useTLS = true;
113+
# tlsVerify = true;
114+
};
115+
};
116+
```
117+
118+
## Using with Flakes
119+
120+
If you're using Nix Flakes, add this to your `flake.nix`:
121+
122+
```nix
123+
{
124+
inputs = {
125+
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
126+
meshcore-packet-capture = {
127+
url = "github:agessaman/meshcore-packet-capture";
128+
inputs.nixpkgs.follows = "nixpkgs";
129+
};
130+
};
131+
132+
outputs = { self, nixpkgs, meshcore-packet-capture }: {
133+
nixosConfigurations.your-hostname = nixpkgs.lib.nixosSystem {
134+
system = "x86_64-linux";
135+
modules = [
136+
meshcore-packet-capture.nixosModules.default
137+
{
138+
services.meshcore-packet-capture = {
139+
enable = true;
140+
package = meshcore-packet-capture.packages.${system}.default;
141+
connectionType = "ble";
142+
143+
# Let'sMesh Analyzer - US Server
144+
mqtt1 = {
145+
enabled = true;
146+
server = "mqtt-us-v1.letsmesh.net";
147+
port = 443;
148+
transport = "websockets";
149+
useTLS = true;
150+
useAuthToken = true;
151+
tokenAudience = "mqtt-us-v1.letsmesh.net";
152+
keepalive = 120;
153+
};
154+
155+
# Let'sMesh Analyzer - EU Server
156+
mqtt2 = {
157+
enabled = true;
158+
server = "mqtt-eu-v1.letsmesh.net";
159+
port = 443;
160+
transport = "websockets";
161+
useTLS = true;
162+
useAuthToken = true;
163+
tokenAudience = "mqtt-eu-v1.letsmesh.net";
164+
keepalive = 120;
165+
};
166+
167+
# Device private key is automatically fetched from the device
168+
# Only set these if automatic fetching fails:
169+
# privateKeyFile = "/path/to/your/private/key/file";
170+
# privateKey = "your_private_key_hex_string";
171+
172+
# Optional: Owner information for Let'sMesh Analyzer
173+
# ownerPublicKey = "YOUR_64_CHAR_HEX_PUBLIC_KEY";
174+
# ownerEmail = "[email protected]";
175+
176+
iata = "SEA";
177+
};
178+
}
179+
];
180+
};
181+
};
182+
}
183+
```
184+
185+
## Configuration Options
186+
187+
### Connection Settings
188+
189+
```nix
190+
services.meshcore-packet-capture = {
191+
connectionType = "ble"; # or "serial" or "tcp"
192+
bleAddress = "AA:BB:CC:DD:EE:FF"; # optional
193+
bleDeviceName = "MeshCore Device"; # optional
194+
serialPorts = [ "/dev/ttyUSB0" "/dev/ttyUSB1" ]; # for serial connection
195+
tcpHost = "localhost"; # for TCP connection
196+
tcpPort = 5000; # for TCP connection
197+
timeout = 30;
198+
maxConnectionRetries = 5; # 0 = infinite
199+
connectionRetryDelay = 5;
200+
healthCheckInterval = 30;
201+
};
202+
```
203+
204+
### MQTT Brokers
205+
206+
You can configure up to 4 MQTT brokers. Here's an example with Let'sMesh Analyzer (recommended) plus a custom broker:
207+
208+
```nix
209+
services.meshcore-packet-capture = {
210+
# Let'sMesh Analyzer - US Server
211+
mqtt1 = {
212+
enabled = true;
213+
server = "mqtt-us-v1.letsmesh.net";
214+
port = 443;
215+
transport = "websockets";
216+
useTLS = true;
217+
useAuthToken = true;
218+
tokenAudience = "mqtt-us-v1.letsmesh.net";
219+
keepalive = 120;
220+
};
221+
222+
# Let'sMesh Analyzer - EU Server (for redundancy)
223+
mqtt2 = {
224+
enabled = true;
225+
server = "mqtt-eu-v1.letsmesh.net";
226+
port = 443;
227+
transport = "websockets";
228+
useTLS = true;
229+
useAuthToken = true;
230+
tokenAudience = "mqtt-eu-v1.letsmesh.net";
231+
keepalive = 120;
232+
};
233+
234+
# Your own MQTT broker (optional)
235+
mqtt3 = {
236+
enabled = true;
237+
server = "mqtt.example.com";
238+
port = 1883; # or 8883 for TLS
239+
username = "user";
240+
password = "pass";
241+
transport = "tcp"; # or "websockets"
242+
useTLS = false; # set to true for TLS
243+
tlsVerify = true;
244+
qos = 0;
245+
retain = false;
246+
keepalive = 60;
247+
# Optional topic overrides
248+
topicStatus = "meshcore/status";
249+
topicPackets = "meshcore/packets";
250+
topicRaw = "meshcore/raw";
251+
};
252+
253+
# mqtt4 can be configured similarly
254+
};
255+
```
256+
257+
### Authentication
258+
259+
For username/password authentication:
260+
261+
```nix
262+
services.meshcore-packet-capture = {
263+
mqtt1 = {
264+
username = "your_username";
265+
password = "your_password";
266+
};
267+
};
268+
```
269+
270+
For JWT token authentication:
271+
272+
```nix
273+
services.meshcore-packet-capture = {
274+
mqtt1 = {
275+
useAuthToken = true;
276+
tokenAudience = "mqtt.example.com";
277+
};
278+
# Private key is automatically fetched from the device if it supports ENABLE_PRIVATE_KEY_EXPORT
279+
# Only provide these if automatic fetching fails:
280+
# privateKey = "your_private_key_hex_string";
281+
# OR
282+
# privateKeyFile = "/path/to/private/key/file";
283+
};
284+
```
285+
286+
### Other Settings
287+
288+
```nix
289+
services.meshcore-packet-capture = {
290+
logLevel = "INFO"; # DEBUG, INFO, WARNING, ERROR, CRITICAL
291+
verbose = false;
292+
debug = false;
293+
enableMqtt = true;
294+
maxMqttRetries = 5; # 0 = infinite
295+
mqttRetryDelay = 5;
296+
exitOnReconnectFail = true;
297+
iata = "SEA"; # For topic templates
298+
origin = "My Device";
299+
advertIntervalHours = 11; # 0 = disabled
300+
uploadPacketTypes = [ 0 1 2 ]; # Filter packet types, null = all
301+
rfDataTimeout = 15.0;
302+
outputFile = null; # Optional output file path
303+
# privateKeyFile = "/path/to/private/key/file"; # Only if auto-fetch fails
304+
# privateKey = "hex_string"; # Only if auto-fetch fails
305+
ownerPublicKey = null; # Optional: 64 hex character owner public key
306+
ownerEmail = null; # Optional: Owner email for Let'sMesh Analyzer
307+
dataDir = "/var/lib/meshcore-packet-capture";
308+
user = "meshcore";
309+
group = "meshcore";
310+
};
311+
```
312+
313+
## Permissions
314+
315+
The service automatically adds the service user to the `bluetooth` and `dialout` groups for BLE and serial port access.
316+
317+
## Development
318+
319+
To enter a development shell with all dependencies:
320+
321+
```bash
322+
nix develop
323+
```
324+
325+
## Troubleshooting
326+
327+
### Package not found
328+
329+
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.
330+
331+
### BLE not working
332+
333+
Ensure that:
334+
1. Bluetooth is enabled: `services.bluetooth.enable = true;`
335+
2. The service user has proper permissions (automatically handled)
336+
3. Your Bluetooth adapter is properly configured
337+
338+
### Serial port not accessible
339+
340+
Ensure that:
341+
1. The device exists: `ls -l /dev/ttyUSB0`
342+
2. The service user is in the `dialout` group (automatically handled)
343+
3. You've specified the correct port in `serialPorts`
344+
345+
### Service logs
346+
347+
View service logs with:
348+
349+
```bash
350+
journalctl -u meshcore-packet-capture -f
351+
```
352+
353+
## Building the Package
354+
355+
To build just the package (without installing as a service):
356+
357+
```bash
358+
nix build
359+
```
360+
361+
The package will be available at `./result/bin/meshcore-packet-capture`.
362+

0 commit comments

Comments
 (0)