# `Meshcore.Commands.Device`
[🔗](https://github.com/nyannus/meshcore_ex/blob/v0.1.0/lib/meshcore/commands/device.ex#L1)

Commands that read or configure the companion device itself.

# `mc`

```elixir
@type mc() :: GenServer.server()
```

# `result`

```elixir
@type result() :: {:ok, Meshcore.Event.t()} | {:error, Meshcore.Event.t()}
```

# `confirm_factory_reset`

```elixir
@spec confirm_factory_reset(mc(), String.t()) :: result() | {:error, :invalid_token}
```

Step 2 of a factory reset. Returns `{:error, :invalid_token}` if `token` does
not match the pending one.

# `export_private_key`

```elixir
@spec export_private_key(mc()) :: result()
```

Exports the device's private key (`:private_key`, or `:disabled`).

# `get_allowed_repeat_freq`

```elixir
@spec get_allowed_repeat_freq(mc()) :: result()
```

Frequency ranges in which repeating is allowed.

# `get_bat`

```elixir
@spec get_bat(mc()) :: result()
```

Reads battery level (and storage use on newer firmware).

# `get_channel`

```elixir
@spec get_channel(mc(), 0..255) :: result()
```

Reads channel `channel_idx` (`:channel_info`).

# `get_custom_vars`

```elixir
@spec get_custom_vars(mc()) :: result()
```

Reads the custom variables (`:custom_vars`, a map of strings).

# `get_path_hash_mode`

```elixir
@spec get_path_hash_mode(mc()) :: non_neg_integer()
```

Reads the active path hash mode. Returns the integer directly (`0` when the
device does not report one), like the Python method.

# `get_self_telemetry`

```elixir
@spec get_self_telemetry(mc()) :: result()
```

Reads the device's own telemetry (`:telemetry_response`).

# `get_stats_core`

```elixir
@spec get_stats_core(mc()) :: result()
```

Core statistics (battery, uptime, errors, queue length).

# `get_stats_packets`

```elixir
@spec get_stats_packets(mc()) :: result()
```

Packet counters.

# `get_stats_radio`

```elixir
@spec get_stats_radio(mc()) :: result()
```

Radio statistics (noise floor, RSSI, SNR, airtime).

# `get_time`

```elixir
@spec get_time(mc()) :: result()
```

Reads the device clock.

# `get_tuning`

```elixir
@spec get_tuning(mc()) :: result()
```

Reads RX delay and airtime factor (`:tuning_params`).

# `has_connection`

```elixir
@spec has_connection(mc()) :: result()
```

Checks whether the device has an active connection (`CMD 28`).

# `import_private_key`

```elixir
@spec import_private_key(mc(), binary()) :: result()
```

Imports a 64 byte private key.

# `reboot`

```elixir
@spec reboot(mc()) :: result()
```

Reboots the device. Fire-and-forget, always returns `{:ok, _}` once sent.

# `request_factory_reset`

```elixir
@spec request_factory_reset(mc()) :: {:ok, String.t()}
```

Step 1 of a factory reset: returns a confirmation token.

The two-step flow is a client-side safety net; the firmware itself performs
no token check. Pass the token to `confirm_factory_reset/2`.

# `run_cli_command`

```elixir
@spec run_cli_command(mc(), String.t()) :: result()
```

Runs a CLI command on the device and returns its `:cli_reply`.

# `send_advert`

```elixir
@spec send_advert(mc(), boolean()) :: result()
```

Sends a self advertisement, optionally flooded.

# `send_appstart`

```elixir
@spec send_appstart(mc(), keyword()) :: result()
```

Sends `CMD_APP_START`, which initialises the session and returns the
device's `:self_info`. Options: `:timeout`.

# `send_device_query`

```elixir
@spec send_device_query(mc()) :: result()
```

Queries device info (`:device_info`: model, firmware, limits…).

# `send_raw_packet`

```elixir
@spec send_raw_packet(mc(), binary() | {:hex, String.t()}, 0..255) :: result()
```

Transmits a raw radio packet. `data` is raw bytes or `{:hex, string}`.

# `set_advert_loc_policy`

```elixir
@spec set_advert_loc_policy(mc(), 0..255) :: result()
```

Sets the advert location policy, keeping other parameters.

# `set_channel`

```elixir
@spec set_channel(mc(), 0..255, String.t(), binary() | nil) :: result()
```

Configures channel `channel_idx`.

When `channel_secret` is `nil` – or the name starts with `#` – the 16 byte
secret is derived as the first half of `SHA-256(name)` (public hashtag
channels). Raises `ArgumentError` if an explicit secret is not 16 bytes.

# `set_coords`

```elixir
@spec set_coords(mc(), float(), float()) :: result()
```

Sets the advertised coordinates.

# `set_custom_var`

```elixir
@spec set_custom_var(mc(), String.t(), String.t()) :: result()
```

Sets one custom variable.

# `set_devicepin`

```elixir
@spec set_devicepin(mc(), non_neg_integer()) :: result()
```

Sets the BLE pairing PIN.

# `set_manual_add_contacts`

```elixir
@spec set_manual_add_contacts(mc(), boolean()) :: result()
```

Enables or disables manual contact adding, keeping other parameters.

# `set_multi_acks`

```elixir
@spec set_multi_acks(mc(), 0..255) :: result()
```

Sets the multi-ack count, keeping other parameters.

# `set_name`

```elixir
@spec set_name(mc(), String.t()) :: result()
```

Sets the advertised node name.

# `set_other_params`

```elixir
@spec set_other_params(mc(), boolean(), 0..3, 0..3, 0..3, 0..255) :: result()
```

Legacy variant of `set_other_params_from_infos/2` without `multi_acks`.

# `set_other_params_from_infos`

```elixir
@spec set_other_params_from_infos(mc(), map()) :: result()
```

Writes the "other params" block from a map shaped like `:self_info`
(`:manual_add_contacts`, `:telemetry_mode_base|loc|env`, `:adv_loc_policy`,
`:multi_acks`).

# `set_path_hash_mode`

```elixir
@spec set_path_hash_mode(mc(), 0..2) :: result()
```

Sets the path hash mode (0 = 1 byte hashes, 1 = 2 bytes, 2 = 3 bytes).

# `set_radio`

```elixir
@spec set_radio(
  mc(),
  number(),
  number(),
  integer(),
  integer(),
  boolean() | integer() | nil
) :: result()
```

Sets the radio parameters: frequency (MHz), bandwidth (kHz), spreading
factor, coding rate and – on repeater-capable firmware – `repeat`.

# `set_telemetry_mode_base`

```elixir
@spec set_telemetry_mode_base(mc(), 0..3) :: result()
```

Sets the base telemetry mode (0-3), keeping other parameters.

# `set_telemetry_mode_env`

```elixir
@spec set_telemetry_mode_env(mc(), 0..3) :: result()
```

Sets the environment telemetry mode (0-3), keeping other parameters.

# `set_telemetry_mode_loc`

```elixir
@spec set_telemetry_mode_loc(mc(), 0..3) :: result()
```

Sets the location telemetry mode (0-3), keeping other parameters.

# `set_time`

```elixir
@spec set_time(mc(), non_neg_integer()) :: result()
```

Sets the device clock (Unix seconds).

# `set_tuning`

```elixir
@spec set_tuning(mc(), non_neg_integer(), non_neg_integer()) :: result()
```

Sets RX delay and airtime factor.

# `set_tx_power`

```elixir
@spec set_tx_power(mc(), non_neg_integer()) :: result()
```

Sets the transmit power in dBm.

# `sign`

```elixir
@spec sign(mc(), binary(), keyword()) :: result()
```

Signs `data` with the device key: `sign_start/1`, chunked `sign_data/2`,
`sign_finish/2`. Options: `:chunk_size` (default `120`), `:timeout`.

Returns the `:signature` event, or an error event (`reason: :data_too_large`
if `data` exceeds the device buffer).

# `sign_data`

```elixir
@spec sign_data(mc(), binary()) :: result()
```

Streams one chunk of data to sign.

A missing acknowledgement (timeout) is tolerated – the chunk was most likely
processed – and reported as `{:ok, ok_event}`, like the Python library.

# `sign_finish`

```elixir
@spec sign_finish(mc(), keyword()) :: result()
```

Finishes the signing session and returns the `:signature`.

Options: `:timeout` (default `max(3 × default_timeout, 15s)` plus a bonus
growing with `:data_size`), `:data_size`.

# `sign_start`

```elixir
@spec sign_start(mc()) :: result()
```

Starts a signing session; the reply carries `max_length`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
