# Meshtastic Client (WIP)
Elixir client for Meshtastic devices. Connects over TCP to send and receive mesh network messages using Protobuf.
## Installation
Add to your `mix.exs`:
```elixir
def deps do
[
{:meshtastic_client, "~> 0.1.0"}
]
end
```
Then run `mix deps.get` to install.
## Quick Start
```elixir
# Connect to your device
{:ok, conn} = MeshtasticClient.connect(type: :tcp, host: "192.168.1.100")
# Subscribe to incoming messages
MeshtasticClient.subscribe(conn)
# Send a message to the mesh
MeshtasticClient.send_text(conn, "Hello from Elixir!")
# Collect messages
messages = MeshtasticClient.collect_messages(timeout: 5000)
IO.inspect(messages)
```
See the `examples/` directory for more usage patterns.
> [!NOTE]
> Protobuf client is generated automatically but not all features are available on the Elixir client
## Setup
This library uses Meshtastic's protobuf definitions. You'll need `protoc` installed to generate the Elixir modules:
```bash
# Fedora/RHEL
sudo dnf install protobuf-compiler protobuf-devel
# Ubuntu/Debian
sudo apt-get install protobuf-compiler protobuf-devel
# macOS
brew install protobuf
```
Install the Elixir protobuf plugin:
```bash
mix escript.install hex protobuf 0.14.0
```
The protobuf files are in `priv/protos/`. Generate modules using the Mix task:
```bash
mix protobuf.gen
```
To regenerate all modules from scratch:
```bash
mix protobuf.gen --clean
```
## Connections
### TCP
Most Meshtastic devices expose TCP on port 4403:
```elixir
{:ok, conn} = MeshtasticClient.connect(
type: :tcp,
host: "192.168.1.100",
port: 4403 # default
)
```
### Serial & BLE
Not implemented yet.
## Sending Messages
### Text Messages
```elixir
# Broadcast to all nodes
MeshtasticClient.send_text(conn, "Hello mesh!")
# Send to specific node
MeshtasticClient.send_text(conn, "Direct message", to: 0x12345678, want_ack: true)
# Send on channel 1
MeshtasticClient.send_text(conn, "Channel message", channel: 1)
```
### Position Updates
```elixir
MeshtasticClient.send_position(conn,
latitude: 37.7749,
longitude: -122.4194,
altitude: 15
)
```
## Receiving Messages
Two approaches: collect or stream.
### Collect Messages
Gather messages for a set time:
```elixir
MeshtasticClient.subscribe(conn)
messages = MeshtasticClient.collect_messages(timeout: 5000, count: 10)
Enum.each(messages, &IO.inspect/1)
```
### Stream Messages
Handle messages as they arrive:
```elixir
MeshtasticClient.subscribe(conn)
receive do
{:meshtastic_message, %{payload_variant: {:packet, packet}}} ->
IO.puts("Got packet: #{inspect(packet)}")
end
```
## Device Info
Request configuration and node details:
```elixir
# Triggers config response messages
MeshtasticClient.get_config(conn)
# Same as get_config
MeshtasticClient.get_node_info(conn)
```
These functions send requests; responses arrive as messages you receive via subscription.
## Client architecture
- `MeshtasticClient` - Public API
- `MeshtasticClient.Connection` - TCP connection manager (GenServer)
- `MeshtasticClient.Message` - Message encoding/framing
- `Meshtastic.*` - Generated protobuf structs (mesh.proto, config.proto, etc.)
## Message Types
When you receive messages, check the `payload_variant` field:
```elixir
case message.payload_variant do
{:my_info, info} -> # Device node info
{:node_info, node} -> # Other node discovered
{:packet, packet} -> # Mesh packet (text, telemetry, etc.)
{:config, config} -> # Device config
{:channel, channel} -> # Channel settings
_ -> # Other message types
end
```
## References
- [Meshtastic docs](https://meshtastic.org/docs/)
- [Protobuf specs](https://buf.build/meshtastic/protobufs)
- [Protocol details](https://github.com/meshtastic/protobufs)