meshtastic 0.0.178 → 0.0.180

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -175
  3. data/documentation/README.md +60 -0
  4. data/documentation/admin-channel.md +33 -0
  5. data/documentation/admin-config.md +28 -0
  6. data/documentation/admin-firmware.md +69 -0
  7. data/documentation/admin.md +55 -0
  8. data/documentation/apponly.md +22 -0
  9. data/documentation/atak.md +110 -0
  10. data/documentation/bluetooth-bluez.md +35 -0
  11. data/documentation/bluetooth.md +87 -0
  12. data/documentation/cannedmessages.md +25 -0
  13. data/documentation/channel.md +3 -0
  14. data/documentation/clientonly.md +21 -0
  15. data/documentation/config.md +3 -0
  16. data/documentation/connection-status.md +22 -0
  17. data/documentation/deviceonly.md +22 -0
  18. data/documentation/localonly.md +21 -0
  19. data/documentation/mesh-interface.md +52 -0
  20. data/documentation/meshtastic.md +45 -0
  21. data/documentation/module-config.md +26 -0
  22. data/documentation/mqtt.md +101 -0
  23. data/documentation/paxcount.md +25 -0
  24. data/documentation/portnums.md +67 -0
  25. data/documentation/position.md +34 -0
  26. data/documentation/protobufs.md +162 -0
  27. data/documentation/remote-hardware.md +33 -0
  28. data/documentation/rtttl.md +24 -0
  29. data/documentation/serial.md +78 -0
  30. data/documentation/storeforward.md +24 -0
  31. data/documentation/stream-interface.md +15 -0
  32. data/documentation/tcp.md +43 -0
  33. data/documentation/telemetry.md +32 -0
  34. data/documentation/traceroute.md +28 -0
  35. data/documentation/util.md +27 -0
  36. data/documentation/xmodem.md +22 -0
  37. data/lib/meshtastic/admin/channel.rb +90 -0
  38. data/lib/meshtastic/admin/config.rb +154 -0
  39. data/lib/meshtastic/admin/firmware.rb +173 -0
  40. data/lib/meshtastic/admin.rb +495 -7
  41. data/lib/meshtastic/apponly.rb +26 -8
  42. data/lib/meshtastic/atak.rb +298 -7
  43. data/lib/meshtastic/bluetooth/bluez.rb +20 -1
  44. data/lib/meshtastic/bluetooth.rb +70 -59
  45. data/lib/meshtastic/cannedmessages.rb +23 -8
  46. data/lib/meshtastic/channel.rb +3 -21
  47. data/lib/meshtastic/clientonly.rb +26 -8
  48. data/lib/meshtastic/config.rb +3 -21
  49. data/lib/meshtastic/connection_status.rb +13 -8
  50. data/lib/meshtastic/deviceonly.rb +23 -8
  51. data/lib/meshtastic/localonly.rb +23 -8
  52. data/lib/meshtastic/mesh_interface.rb +11 -0
  53. data/lib/meshtastic/module_config.rb +18 -9
  54. data/lib/meshtastic/mqtt.rb +72 -35
  55. data/lib/meshtastic/paxcount.rb +30 -9
  56. data/lib/meshtastic/portnums.rb +18 -8
  57. data/lib/meshtastic/position.rb +45 -0
  58. data/lib/meshtastic/remote_hardware.rb +50 -9
  59. data/lib/meshtastic/rtttl.rb +26 -8
  60. data/lib/meshtastic/serial.rb +81 -70
  61. data/lib/meshtastic/storeforward.rb +23 -8
  62. data/lib/meshtastic/stream_interface.rb +11 -0
  63. data/lib/meshtastic/tcp.rb +153 -0
  64. data/lib/meshtastic/telemetry.rb +27 -9
  65. data/lib/meshtastic/traceroute.rb +42 -0
  66. data/lib/meshtastic/util.rb +3 -1
  67. data/lib/meshtastic/version.rb +1 -1
  68. data/lib/meshtastic/xmodem.rb +17 -8
  69. data/lib/meshtastic.rb +46 -6
  70. data/spec/conventions_spec.rb +321 -0
  71. data/spec/lib/meshtastic/admin/channel_spec.rb +45 -0
  72. data/spec/lib/meshtastic/admin/config_spec.rb +48 -0
  73. data/spec/lib/meshtastic/admin/firmware_spec.rb +118 -0
  74. data/spec/lib/meshtastic/admin_pb_spec.rb +1 -1
  75. data/spec/lib/meshtastic/admin_spec.rb +79 -0
  76. data/spec/lib/meshtastic/apponly_pb_spec.rb +1 -1
  77. data/spec/lib/meshtastic/apponly_spec.rb +4 -0
  78. data/spec/lib/meshtastic/atak_pb_spec.rb +1 -1
  79. data/spec/lib/meshtastic/atak_spec.rb +147 -0
  80. data/spec/lib/meshtastic/bluetooth_spec.rb +1 -1
  81. data/spec/lib/meshtastic/cannedmessages_pb_spec.rb +1 -1
  82. data/spec/lib/meshtastic/cannedmessages_spec.rb +3 -0
  83. data/spec/lib/meshtastic/channel_pb_spec.rb +1 -1
  84. data/spec/lib/meshtastic/channel_spec.rb +3 -0
  85. data/spec/lib/meshtastic/clientonly_pb_spec.rb +1 -1
  86. data/spec/lib/meshtastic/clientonly_spec.rb +5 -0
  87. data/spec/lib/meshtastic/config_pb_spec.rb +1 -1
  88. data/spec/lib/meshtastic/config_spec.rb +4 -1
  89. data/spec/lib/meshtastic/connection_status_pb_spec.rb +1 -1
  90. data/spec/lib/meshtastic/connection_status_spec.rb +3 -0
  91. data/spec/lib/meshtastic/deviceonly_legacy_pb_spec.rb +1 -1
  92. data/spec/lib/meshtastic/deviceonly_pb_spec.rb +1 -1
  93. data/spec/lib/meshtastic/deviceonly_spec.rb +3 -0
  94. data/spec/lib/meshtastic/localonly_pb_spec.rb +1 -1
  95. data/spec/lib/meshtastic/localonly_spec.rb +3 -0
  96. data/spec/lib/meshtastic/mesh_beacon_pb_spec.rb +1 -1
  97. data/spec/lib/meshtastic/mesh_pb_spec.rb +1 -1
  98. data/spec/lib/meshtastic/module_config_pb_spec.rb +1 -1
  99. data/spec/lib/meshtastic/module_config_spec.rb +21 -0
  100. data/spec/lib/meshtastic/mqtt_pb_spec.rb +1 -1
  101. data/spec/lib/meshtastic/paxcount_pb_spec.rb +1 -1
  102. data/spec/lib/meshtastic/paxcount_spec.rb +23 -0
  103. data/spec/lib/meshtastic/portnums_pb_spec.rb +1 -1
  104. data/spec/lib/meshtastic/portnums_spec.rb +4 -0
  105. data/spec/lib/meshtastic/position_spec.rb +33 -0
  106. data/spec/lib/meshtastic/remote_hardware_pb_spec.rb +1 -1
  107. data/spec/lib/meshtastic/remote_hardware_spec.rb +24 -0
  108. data/spec/lib/meshtastic/rtttl_pb_spec.rb +1 -1
  109. data/spec/lib/meshtastic/rtttl_spec.rb +21 -0
  110. data/spec/lib/meshtastic/storeforward_pb_spec.rb +1 -1
  111. data/spec/lib/meshtastic/storeforward_spec.rb +21 -0
  112. data/spec/lib/meshtastic/tcp_spec.rb +48 -0
  113. data/spec/lib/meshtastic/telemetry_pb_spec.rb +1 -1
  114. data/spec/lib/meshtastic/telemetry_spec.rb +21 -0
  115. data/spec/lib/meshtastic/traceroute_spec.rb +27 -0
  116. data/spec/lib/meshtastic/xmodem_pb_spec.rb +1 -1
  117. data/spec/lib/meshtastic/xmodem_spec.rb +6 -1
  118. data/spec/lib/meshtastic_spec.rb +3 -0
  119. metadata +48 -1
@@ -0,0 +1,162 @@
1
+ # Generated protobuf types
2
+
3
+ These classes and enums come from `lib/meshtastic/*_pb.rb` (Meshtastic protobufs via `grpc_tools_ruby_protoc`). They live in the `Meshtastic` namespace. Typical API:
4
+
5
+ ```ruby
6
+ msg = Meshtastic::User.new(long_name: 'Node', short_name: 'N1')
7
+ bytes = msg.to_proto
8
+ again = Meshtastic::User.decode(bytes)
9
+ msg.to_h
10
+ ```
11
+
12
+ Enums: `Meshtastic::PortNum::TEXT_MESSAGE_APP`, `Meshtastic::PortNum.lookup(1)`, `Meshtastic::PortNum.resolve(:TEXT_MESSAGE_APP)`.
13
+
14
+ A few generated **classes** are reopened with extra class methods: `Channel`, `Config`, `ModuleConfig`, `Paxcount`, `Position`, `Telemetry`. Do not name those extras `send` or `encode`.
15
+
16
+ First-class wrappers for many of these types: [documentation index](README.md).
17
+
18
+ ## admin.proto
19
+
20
+ - Messages: `AdminMessage`, `AdminMessage::InputEvent`, `AdminMessage::OTAEvent`, `LockdownAuth`, `HamParameters`, `NodeRemoteHardwarePinsResponse`, `SharedContact`, `KeyVerificationAdmin`, `SensorConfig`, `SCD4X_config`, `SEN5X_config`, `SEN6X_config`, `SCD30_config`, `SHTXX_config`, `DS248X_config`, `AS3935_config`
21
+ - Enums: `AdminMessage::ConfigType`, `AdminMessage::ModuleConfigType`, `AdminMessage::BackupLocation`, `KeyVerificationAdmin::MessageType`, `OTAMode`
22
+
23
+ See [Admin](admin.md).
24
+
25
+ ## apponly.proto
26
+
27
+ - `ChannelSet` — [Apponly](apponly.md)
28
+
29
+ ## atak.proto
30
+
31
+ - Messages: `TAKPacket`, `GeoChat`, `Group`, `Status`, `Contact`, `PLI`, `AircraftTrack`, `CotGeoPoint`, `DrawnShape`, `Marker`, `RangeAndBearing`, `Route`, `Route::Link`, `CasevacReport`, `ZMistEntry`, `EmergencyAlert`, `TaskRequest`, `TAKEnvironment`, `SensorFov`, `TakTalkMessage`, `TakTalkRoomData`, `Marti`, `TAKPacketV2`
32
+ - Enums: `GeoChat::ReceiptType`, `DrawnShape::Kind`, `DrawnShape::StyleMode`, `Marker::Kind`, `Route::Method`, `Route::Direction`, `CasevacReport::Precedence`, `CasevacReport::HlzMarking`, `CasevacReport::Security`, `EmergencyAlert::Type`, `TaskRequest::Priority`, `TaskRequest::Status`, `SensorFov::SensorType`, `Team`, `MemberRole`, `CotHow`, `CotType`, `GeoPointSource`
33
+
34
+ See [ATAK](atak.md).
35
+
36
+ ## cannedmessages.proto
37
+
38
+ - `CannedMessageModuleConfig` — [Cannedmessages](cannedmessages.md)
39
+
40
+ ## channel.proto
41
+
42
+ - `ChannelSettings`, `ModuleSettings`, `Channel`, `Channel::Role` — [Channel](channel.md)
43
+
44
+ ## clientonly.proto
45
+
46
+ - `DeviceProfile` — [Clientonly](clientonly.md)
47
+
48
+ ## config.proto
49
+
50
+ - `Config` and nested `DeviceConfig`, `PositionConfig`, `PowerConfig`, `NetworkConfig`, `DisplayConfig`, `LoRaConfig`, `BluetoothConfig`, `SecurityConfig`, `SessionkeyConfig` plus their enums — [Config](config.md)
51
+
52
+ ## connection_status.proto
53
+
54
+ - `DeviceConnectionStatus`, `WifiConnectionStatus`, `EthernetConnectionStatus`, `NetworkConnectionStatus`, `BluetoothConnectionStatus`, `SerialConnectionStatus` — [ConnectionStatus](connection-status.md)
55
+
56
+ ## device_ui.proto
57
+
58
+ - `DeviceUIConfig`, `NodeFilter`, `NodeHighlight`, `GeoPoint`, `Map`
59
+ - Enums: `DeviceUIConfig::GpsCoordinateFormat`, `CompassMode`, `Theme`, `Language`
60
+
61
+ No dedicated wrapper; set via Admin `DEVICEUI_CONFIG` / `Config.device_ui`.
62
+
63
+ ## deviceonly.proto / deviceonly_legacy.proto
64
+
65
+ - `PositionLite`, `UserLite`, `NodeInfoLite`, `DeviceState`, `NodePositionEntry`, `NodeTelemetryEntry`, `NodeEnvironmentEntry`, `NodeStatusEntry`, `NodeDatabase`, `ChannelFile`, `BackupPreferences`
66
+ - Legacy: `NodeInfoLite_Legacy`, `NodeDatabase_Legacy`
67
+
68
+ See [Deviceonly](deviceonly.md).
69
+
70
+ ## interdevice.proto
71
+
72
+ - `FileTransfer`, `DirectoryListing`, `I2CTransaction`, `SdCardInfo`, `I2CResult`, `InterdeviceMessage`
73
+ - Enums: `SdCardInfo::CardType`, `SdCardInfo::FatType`, `I2CResult::Status`, `InterdeviceVersion`, `FileOperation`, `FileStatus`, `SdCommand`
74
+
75
+ No dedicated wrapper. Encode/decode the generated classes directly.
76
+
77
+ ## localonly.proto
78
+
79
+ - `LocalConfig`, `LocalModuleConfig` — [Localonly](localonly.md)
80
+
81
+ ## lorawan_bridge.proto
82
+
83
+ - `LoRaWANBridge` plus nested `Uplink`, `Downlink`, `PayloadChunk`, `TxResult`
84
+
85
+ No dedicated wrapper. Port `LORAWAN_BRIDGE` (75).
86
+
87
+ ## mesh_beacon.proto
88
+
89
+ - `MeshBeacon` — port `MESH_BEACON_APP` (37)
90
+
91
+ ## mesh.proto
92
+
93
+ Core radio types:
94
+
95
+ - `Position` ([Position](position.md)), `User`, `RouteDiscovery` ([Traceroute](traceroute.md)), `Routing`, `Data`, `KeyVerification`, `StoreForwardPlusPlus`, `RemoteShell`, `BoundingBox`, `Waypoint`, `StatusMessage`, `MqttClientProxyMessage`, `MeshPacket`, `NodeInfo`, `MyNodeInfo`, `LogRecord`, `QueueStatus`, `FromRadio`, `LockdownStatus`, `ClientNotification`, `KeyVerificationNumberInform`, `KeyVerificationNumberRequest`, `KeyVerificationFinal`, `DuplicatedPublicKey`, `LowEntropyKey`, `FileInfo`, `ToRadio`, `Compressed`, `NeighborInfo`, `Neighbor`, `DeviceMetadata`, `LoRaPresetGroup`, `LoRaRegionPresets`, `LoRaRegionPresetMap`, `Heartbeat`, `NodeRemoteHardwarePin`, `ChunkedPayload`, `resend_chunks`, `ChunkedPayloadResponse`
96
+ - Enums: `HardwareModel`, `Constants`, `CriticalErrorCode`, `FirmwareEdition`, `ExcludedModules`, plus nested enums on Position, Routing, MeshPacket, LogRecord, LockdownStatus, RemoteShell, StoreForwardPlusPlus
97
+
98
+ Serial/TCP frames carry `ToRadio` / `FromRadio`. MQTT publishes `ServiceEnvelope` wrapping `MeshPacket`.
99
+
100
+ ## module_config.proto
101
+
102
+ - `ModuleConfig` and nested MQTT/Serial/StoreForward/Telemetry/… configs — [ModuleConfig](module-config.md)
103
+ - `RemoteHardwarePin`, `RemoteHardwarePinType`
104
+
105
+ ## mqtt.proto
106
+
107
+ - `ServiceEnvelope`, `MapReport` — [MQTT](mqtt.md)
108
+
109
+ ## paxcount.proto
110
+
111
+ - `Paxcount` — [Paxcount](paxcount.md)
112
+
113
+ ## portnums.proto
114
+
115
+ - `PortNum` — [Portnums](portnums.md)
116
+
117
+ ## powermon.proto
118
+
119
+ - `PowerMon`, `PowerStressMessage` (and nested enums)
120
+
121
+ No dedicated wrapper. Port `POWERSTRESS_APP` (74).
122
+
123
+ ## remote_hardware.proto
124
+
125
+ - `HardwareMessage`, `HardwareMessage::Type` — [RemoteHardware](remote-hardware.md)
126
+
127
+ ## rtttl.proto
128
+
129
+ - `RTTTLConfig` — [RTTTL](rtttl.md)
130
+
131
+ ## serial_hal.proto
132
+
133
+ - `SerialHalCommand`, `SerialHalResponse`
134
+
135
+ GPIO serial HAL, not USB CDC. See [Serial](serial.md) for the USB Stream API.
136
+
137
+ ## storeforward.proto
138
+
139
+ - `StoreAndForward` plus `Statistics`, `History`, `Heartbeat`, `RequestResponse` — [Storeforward](storeforward.md)
140
+
141
+ ## telemetry.proto
142
+
143
+ - `Telemetry` ([Telemetry](telemetry.md)), `DeviceMetrics`, `EnvironmentMetrics`, `SoilWaterMetrics`, `PowerMetrics`, `AirQualityMetrics`, `LocalStats`, `TrafficManagementStats`, `HealthMetrics`, `HostMetrics`, `Nau7802Config`, `AS3935Config`, `SEN5XState`, `SEN6XState`, `TelemetrySensorType`
144
+
145
+ ## xmodem.proto
146
+
147
+ - `XModem`, `XModem::Control` — [Xmodem](xmodem.md)
148
+
149
+ ## nanopb
150
+
151
+ `require 'nanopb_pb'` is loaded with the gem. It is not a `Meshtastic::` module.
152
+
153
+ ## Example: inspect a type
154
+
155
+ ```ruby
156
+ require 'meshtastic'
157
+
158
+ Meshtastic::AdminMessage.descriptor.each { |f| puts f.name }
159
+ Meshtastic::PortNum.constants.sort
160
+ user = Meshtastic::User.new(long_name: 'Node', short_name: 'N1')
161
+ Meshtastic::User.decode(user.to_proto)
162
+ ```
@@ -0,0 +1,33 @@
1
+ # Meshtastic::RemoteHardware
2
+
3
+ GPIO control on `REMOTE_HARDWARE_APP` (port 2) using `Meshtastic::HardwareMessage`.
4
+
5
+ ## Methods
6
+
7
+ - `encode(type:, gpio_mask:, gpio_value:)`
8
+ - `send`
9
+ - `read_gpios(gpio_mask:)`
10
+ - `write_gpios(gpio_mask:, gpio_value:)`
11
+ - `watch_gpios(gpio_mask:)`
12
+ - `help` / `authors`
13
+
14
+ `type` values: `:UNSET`, `:WRITE_GPIOS`, `:WATCH_GPIOS`, `:GPIOS_CHANGED`, `:READ_GPIOS`, `:READ_GPIOS_REPLY`.
15
+
16
+ ## Example
17
+
18
+ ```ruby
19
+ Meshtastic::RemoteHardware.write_gpios(
20
+ serial_obj: serial_obj,
21
+ gpio_mask: 0x01,
22
+ gpio_value: 0x01
23
+ )
24
+
25
+ Meshtastic::RemoteHardware.read_gpios(serial_obj: serial_obj, gpio_mask: 0x01)
26
+ Meshtastic::RemoteHardware.watch_gpios(serial_obj: serial_obj, gpio_mask: 0x01)
27
+ ```
28
+
29
+ Enable the Remote Hardware module on the node and only drive pins the firmware exposes.
30
+
31
+ ## Related
32
+
33
+ - [Meshtastic::ModuleConfig](module-config.md)
@@ -0,0 +1,24 @@
1
+ # Meshtastic::RTTTL
2
+
3
+ Ringtone helpers. `encode` builds `RTTTLConfig`. `set` / `get` go through [Admin](admin.md) (`set_ringtone_message` / `get_ringtone_request`).
4
+
5
+ ## Methods
6
+
7
+ - `encode(ringtone:)`
8
+ - `set(serial_obj:, ringtone:)`
9
+ - `get(serial_obj:)`
10
+ - `help` / `authors`
11
+
12
+ ## Example
13
+
14
+ ```ruby
15
+ Meshtastic::RTTTL.set(
16
+ serial_obj: serial_obj,
17
+ ringtone: 'Mario:d=4,o=5,b=125:16e6'
18
+ )
19
+ Meshtastic::RTTTL.get(serial_obj: serial_obj)
20
+ ```
21
+
22
+ ## Related
23
+
24
+ - [Meshtastic::Admin](admin.md)
@@ -0,0 +1,78 @@
1
+ # Meshtastic::Serial
2
+
3
+ USB/UART Stream API. Framing is `[0x94][0xC3][len_hi][len_lo]` plus a `ToRadio` / `FromRadio` protobuf.
4
+
5
+ The radio applies channel crypto. Payloads go out decoded. `channel:` is the device channel index (usually `0`), not an MQTT hash.
6
+
7
+ ## Setup
8
+
9
+ Use the USB CDC port (`/dev/ttyACM*` or `/dev/ttyUSB*`). Enable Radio Configuration → Security → Serial Console (`security.serial_enabled`). That is not Module Configuration → Serial (`TEXTMSG` / `PROTO` on GPIO). Keep “Override Console Serial Port” off.
10
+
11
+ Do not open Serial and Bluetooth to the same radio at once.
12
+
13
+ ## Methods
14
+
15
+ - `connect(block_dev:, baud:, data_bits:, stop_bits:, parity:, debug_out:, want_config:)`
16
+ - `wait_for_config(serial_obj:, timeout:)` — raises `Timeout::Error` if handshake never completes
17
+ - `wake_up_device` — writes 32 × `START2`
18
+ - `request` — raw bytes
19
+ - `send_to_radio` — framed `ToRadio`
20
+ - `send_text` / `send_data`
21
+ - `recv_from_radio(timeout:)` — `0` polls, `nil` blocks, default `5`. Closed empty queue → `nil`. Unplug → `IOError`
22
+ - `drain_from_radio`
23
+ - `dump_stdout_data` / `flush_data` / `monitor_stdout` (`:proto` or `:console`)
24
+ - `subscribe` — blocking FromRadio loop
25
+ - `disconnect`
26
+ - `help` / `authors`
27
+
28
+ `send_text` / `send_data` return bytes written, not mesh delivery. `want_ack: true` asks for `ROUTING_APP` (`error_reason: NONE` means the local radio accepted the route). Incoming text is UTF-8 under `message[:packet][:decoded][:payload]`.
29
+
30
+ Call `wait_for_config` before using `my_node_num` or sending. Opening a port is not a completed handshake.
31
+
32
+ ## Send / receive
33
+
34
+ ```ruby
35
+ require 'meshtastic'
36
+
37
+ serial_obj = nil
38
+ begin
39
+ serial_obj = Meshtastic::Serial.connect(block_dev: '/dev/ttyACM0', baud: 115_200)
40
+ Meshtastic::Serial.wait_for_config(serial_obj: serial_obj, timeout: 10)
41
+ puts "local node: !#{serial_obj[:my_node_num].to_s(16)}"
42
+
43
+ Meshtastic::Serial.send_text(
44
+ serial_obj: serial_obj,
45
+ to: '!aabbccdd', # or '!ffffffff' for the shared channel
46
+ channel: 0,
47
+ text: 'Hello over serial!',
48
+ want_ack: true
49
+ )
50
+
51
+ Meshtastic::Serial.subscribe(
52
+ serial_obj: serial_obj,
53
+ include: 'TEXT_MESSAGE_APP'
54
+ ) do |message|
55
+ packet = message[:packet]
56
+ puts "#{packet[:node_id_from]}: #{packet.dig(:decoded, :payload)}"
57
+ end
58
+ ensure
59
+ Meshtastic::Serial.disconnect(serial_obj: serial_obj)
60
+ end
61
+ ```
62
+
63
+ Drive the loop yourself:
64
+
65
+ ```ruby
66
+ from_radio = Meshtastic::Serial.recv_from_radio(serial_obj: serial_obj, timeout: 0)
67
+ msgs = Meshtastic::Serial.drain_from_radio(serial_obj: serial_obj, max: 256)
68
+ ```
69
+
70
+ If `wait_for_config` times out, the USB path is up but the Stream API is not (wrong port, Serial Console disabled, or firmware not responding).
71
+
72
+ Default `block_dev` is `/dev/ttyUSB0`, baud `115200`, 8N1.
73
+
74
+ ## Related
75
+
76
+ - [Meshtastic::TCP](tcp.md) (same framing)
77
+ - [Meshtastic::Bluetooth](bluetooth.md)
78
+ - [Meshtastic::Admin](admin.md)
@@ -0,0 +1,24 @@
1
+ # Meshtastic::Storeforward
2
+
3
+ Sends `Meshtastic::StoreAndForward` on `STORE_FORWARD_APP` (port 65).
4
+
5
+ ## Methods
6
+
7
+ - `encode(rr:)` — request/response enum, default `:ROUTER_HEARTBEAT`
8
+ - `send`
9
+ - `help` / `authors`
10
+
11
+ `rr` includes values such as `:CLIENT_HISTORY`, `:ROUTER_HEARTBEAT`.
12
+
13
+ ## Example
14
+
15
+ ```ruby
16
+ Meshtastic::Storeforward.send(
17
+ serial_obj: serial_obj,
18
+ rr: :CLIENT_HISTORY
19
+ )
20
+ ```
21
+
22
+ ## Related
23
+
24
+ - [Meshtastic::ModuleConfig](module-config.md) (`:STOREFORWARD_CONFIG`)
@@ -0,0 +1,15 @@
1
+ # Meshtastic::StreamInterface
2
+
3
+ Abstract UART helper left from the Python client layout. Instantiating it raises unless a subclass sets `@stream` (or `no_proto: true`).
4
+
5
+ Use [Meshtastic::Serial](serial.md) for USB/UART.
6
+
7
+ ```ruby
8
+ # raises: StreamInterface is now abstract (to update existing code use Meshtastic::Serial instead)
9
+ Meshtastic::StreamInterface.new
10
+ ```
11
+
12
+ ## Related
13
+
14
+ - [Meshtastic::Serial](serial.md)
15
+ - [Meshtastic::TCP](tcp.md)
@@ -0,0 +1,43 @@
1
+ # Meshtastic::TCP
2
+
3
+ Same framed Stream API as [Serial](serial.md), over TCP. Firmware default port is `4403`. Use `tcp_obj:` instead of `serial_obj:`. Internally reuses Serial’s RX thread and framing.
4
+
5
+ ## Methods
6
+
7
+ - `connect(host:, port:, socket:, want_config:, debug_out:)` — `host` default `127.0.0.1`, `port` default `4403`. `socket:` is for tests.
8
+ - `wait_for_config`
9
+ - `send_text` / `send_data` / `send_to_radio`
10
+ - `recv_from_radio` / `drain_from_radio`
11
+ - `subscribe`
12
+ - `disconnect`
13
+ - `help` / `authors`
14
+
15
+ ## Send / receive
16
+
17
+ ```ruby
18
+ require 'meshtastic'
19
+
20
+ tcp_obj = nil
21
+ begin
22
+ tcp_obj = Meshtastic::TCP.connect(host: '192.0.2.10', port: 4403)
23
+ Meshtastic::TCP.wait_for_config(tcp_obj: tcp_obj, timeout: 10)
24
+ Meshtastic::TCP.send_text(
25
+ tcp_obj: tcp_obj,
26
+ to: '!ffffffff',
27
+ channel: 0,
28
+ text: 'Hello over TCP!'
29
+ )
30
+ Meshtastic::TCP.subscribe(tcp_obj: tcp_obj, include: 'TEXT_MESSAGE_APP') do |message|
31
+ puts message.dig(:packet, :decoded, :payload)
32
+ end
33
+ ensure
34
+ Meshtastic::TCP.disconnect(tcp_obj: tcp_obj)
35
+ end
36
+ ```
37
+
38
+ Enable TCP in radio network settings. Feature modules accept `tcp_obj:` the same way as `serial_obj:`.
39
+
40
+ ## Related
41
+
42
+ - [Meshtastic::Serial](serial.md)
43
+ - [Meshtastic::Admin](admin.md)
@@ -0,0 +1,32 @@
1
+ # Meshtastic::Telemetry
2
+
3
+ Reopens the generated `Meshtastic::Telemetry` protobuf class. Requests metrics on `TELEMETRY_APP` (port 67) with `want_response: true`.
4
+
5
+ Use `build` / `request`, not `send` / `encode`.
6
+
7
+ ## Methods
8
+
9
+ - `build(time:)`
10
+ - `request(serial_obj:, to:, ...)`
11
+ - `help` / `authors`
12
+
13
+ ## Example
14
+
15
+ ```ruby
16
+ Meshtastic::Telemetry.request(
17
+ serial_obj: serial_obj,
18
+ to: '!aabbccdd'
19
+ )
20
+
21
+ Meshtastic::Serial.subscribe(serial_obj: serial_obj, include: 'TELEMETRY_APP') do |message|
22
+ tel = Meshtastic::Telemetry.decode(message.dig(:packet, :decoded, :payload).to_s) rescue nil
23
+ p tel&.device_metrics
24
+ end
25
+ ```
26
+
27
+ Incoming payloads may include `device_metrics`, `environment_metrics`, `air_quality_metrics`, `power_metrics`, `local_stats`, `health_metrics`, `host_metrics`, `traffic_management_stats`, `soil_water_metrics`.
28
+
29
+ ## Related
30
+
31
+ - [Meshtastic::Position](position.md)
32
+ - [Meshtastic::Paxcount](paxcount.md)
@@ -0,0 +1,28 @@
1
+ # Meshtastic::Traceroute
2
+
3
+ Sends `RouteDiscovery` on `TRACEROUTE_APP` (port 70) with `want_response: true`.
4
+
5
+ ## Methods
6
+
7
+ - `encode(route:)` — optional hop list
8
+ - `send(serial_obj:, to:, ...)`
9
+ - `help` / `authors`
10
+
11
+ ## Example
12
+
13
+ ```ruby
14
+ Meshtastic::Traceroute.send(
15
+ serial_obj: serial_obj,
16
+ to: '!aabbccdd',
17
+ want_ack: true
18
+ )
19
+
20
+ Meshtastic::Serial.subscribe(serial_obj: serial_obj, include: 'TRACEROUTE_APP') do |message|
21
+ p message.dig(:packet, :decoded)
22
+ end
23
+ ```
24
+
25
+ ## Related
26
+
27
+ - [Meshtastic::Serial](serial.md)
28
+ - Protobuf: `RouteDiscovery`, `Routing` in [protobufs.md](protobufs.md)
@@ -0,0 +1,27 @@
1
+ # Meshtastic::Util
2
+
3
+ Small helpers used by [MeshInterface](mesh-interface.md).
4
+
5
+ ## `Meshtastic::Util::Acknowledgement`
6
+
7
+ Flags: `received_ack`, `received_nak`, `received_impl_ack`, `received_trace_route`, `received_telemetry`, `received_position`, `received_waypoint`. `#reset` clears them.
8
+
9
+ ## `Meshtastic::Util::Timeout`
10
+
11
+ `expire_timeout` (default 20 seconds), `expire_time`, `sleep_interval` (0.1). `#reset` sets `expire_time` from now.
12
+
13
+ ## Module methods
14
+
15
+ - `authors` / `help`
16
+
17
+ ```ruby
18
+ ack = Meshtastic::Util::Acknowledgement.new
19
+ ack.reset
20
+
21
+ t = Meshtastic::Util::Timeout.new(expire_timeout: 10)
22
+ t.reset
23
+ ```
24
+
25
+ ## Related
26
+
27
+ - [Meshtastic::MeshInterface](mesh-interface.md)
@@ -0,0 +1,22 @@
1
+ # Meshtastic::Xmodem
2
+
3
+ Builds `Meshtastic::XModem` packets (`xmodem.proto`). Distinct from the generated class `Meshtastic::XModem`.
4
+
5
+ ## Methods
6
+
7
+ - `encode(control:, seq:, buffer:)`
8
+ - `help` / `authors`
9
+
10
+ `control` includes `:SOH` and other `XModem::Control` values.
11
+
12
+ ## Example
13
+
14
+ ```ruby
15
+ packet = Meshtastic::Xmodem.encode(control: :SOH, seq: 1, buffer: 'A')
16
+ packet.control # => :SOH
17
+ packet.seq # => 1
18
+ ```
19
+
20
+ ## Related
21
+
22
+ - [Generated protobuf types](protobufs.md)
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'meshtastic/channel_pb'
4
+
5
+ module Meshtastic
6
+ module Admin
7
+ module Channel
8
+ public_class_method def self.build_settings(opts = {})
9
+ settings = opts[:settings] || Meshtastic::ChannelSettings.new
10
+ settings.name = opts[:name].to_s if opts[:name]
11
+ settings.psk = opts[:psk] if opts[:psk]
12
+ settings.channel_num = opts[:channel_num].to_i if opts[:channel_num]
13
+ settings.id = opts[:id].to_i if opts[:id]
14
+ settings.uplink_enabled = opts[:uplink_enabled] unless opts[:uplink_enabled].nil?
15
+ settings.downlink_enabled = opts[:downlink_enabled] unless opts[:downlink_enabled].nil?
16
+ settings.module_settings = opts[:module_settings] if opts[:module_settings]
17
+ settings.use_aead = opts[:use_aead] unless opts[:use_aead].nil?
18
+ settings
19
+ end
20
+
21
+ public_class_method def self.build(opts = {})
22
+ channel = opts[:channel] || Meshtastic::Channel.new
23
+ channel.index = opts[:index].to_i if opts[:index]
24
+ channel.role = opts[:role] if opts[:role]
25
+ channel.settings = opts[:settings] || build_settings(opts.merge({}))
26
+ channel
27
+ end
28
+
29
+ public_class_method def self.get(opts = {})
30
+ index = opts[:index]
31
+ index = 0 if index.nil?
32
+ Admin.get_channel(opts.merge(index: index))
33
+ end
34
+
35
+ public_class_method def self.set(opts = {})
36
+ channel = opts[:channel] || build(opts.merge({}))
37
+ merged = opts.merge(channel_settings: channel)
38
+ merged.delete(:channel)
39
+ Admin.set_channel(merged)
40
+ end
41
+
42
+ public_class_method def self.authors
43
+ "AUTHOR(S):\n 0day Inc. <support@0dayinc.com>\n "
44
+ end
45
+
46
+ public_class_method def self.help
47
+ puts "USAGE:
48
+ # Build ChannelSettings for a mesh channel.
49
+ #{self}.build_settings(
50
+ settings: 'optional - existing ChannelSettings protobuf to fill',
51
+ name: 'optional - channel name such as LongFast',
52
+ psk: 'optional - raw PSK bytes for the channel',
53
+ channel_num: 'optional - LoRa channel number',
54
+ id: 'optional - channel hash id',
55
+ uplink_enabled: 'optional - whether MQTT uplink is enabled',
56
+ downlink_enabled: 'optional - whether MQTT downlink is enabled',
57
+ module_settings: 'optional - ModuleSettings protobuf',
58
+ use_aead: 'optional - whether AEAD crypto is enabled'
59
+ )
60
+
61
+ # Build a Channel protobuf with index, role, and settings.
62
+ #{self}.build(
63
+ channel: 'optional - existing Channel protobuf to fill',
64
+ index: 'optional - channel slot index on the node',
65
+ role: 'optional - :PRIMARY, :SECONDARY, or :DISABLED',
66
+ settings: 'optional - ChannelSettings protobuf to attach'
67
+ )
68
+
69
+ # Request a channel slot from the node.
70
+ #{self}.get(
71
+ serial_obj: 'optional - serial handle from Meshtastic::Serial.connect',
72
+ index: 'optional - channel slot index to request (default: 0)'
73
+ )
74
+
75
+ # Write a channel slot on the node.
76
+ #{self}.set(
77
+ serial_obj: 'optional - serial handle from Meshtastic::Serial.connect',
78
+ channel: 'optional - Channel protobuf to write',
79
+ index: 'optional - channel slot index when building a channel',
80
+ role: 'optional - :PRIMARY, :SECONDARY, or :DISABLED',
81
+ settings: 'optional - ChannelSettings protobuf to attach'
82
+ )
83
+
84
+ # Print the AUTHOR(S) string for this module.
85
+ #{self}.authors
86
+ "
87
+ end
88
+ end
89
+ end
90
+ end