meshtastic 0.0.169 → 0.0.171
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.
- checksums.yaml +4 -4
- data/README.md +115 -5
- data/README.md.bak.20260709105815 +152 -0
- data/lib/meshtastic/mesh_interface.rb +30 -11
- data/lib/meshtastic/serial_interface.rb +496 -279
- data/lib/meshtastic/version.rb +1 -1
- data/spec/lib/meshtastic/serial_interface_spec.rb +72 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9c5cf87c010662bcc98b9738bc6e1a4692bc67ba03e9f9c92b57b31b8b9211c2
|
|
4
|
+
data.tar.gz: f35c8128b63a7152fbfc31aeeb1814a2b66637ab9d5c049d045f6eaea46456ac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bc536784d826a5be06cc4c2385e0573d0b8f67a5ddb4ce2edb2c6a90c1cfca366ff68fe03436360adda292247575a02fdef2a29b99b2e4f6c272a101b77f2183
|
|
7
|
+
data.tar.gz: 10c01895bf08c5a026bff5b465e0ab57d47d2a470bfeca990485eb61a6b66e1aaaccae66b329b21336523902413391ee0927c471f8b137eaeb96d406ecf32646
|
data/README.md
CHANGED
|
@@ -24,12 +24,16 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
|
24
24
|
|
|
25
25
|
## Usage
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
The primary interaction modules today are `Meshtastic::MQTT` (broker) and `Meshtastic::SerialInterface` (USB/UART). Examples for each follow.
|
|
28
|
+
|
|
29
|
+
### MQTT
|
|
30
|
+
|
|
31
|
+
To view MQTT messages, and include only messages containing `_APP` _and_ `LongFast` strings, use the following code:
|
|
28
32
|
|
|
29
33
|
```ruby
|
|
30
34
|
require 'meshtastic'
|
|
31
35
|
Meshtastic::MQTT.help
|
|
32
|
-
mqtt_obj =
|
|
36
|
+
mqtt_obj = Meshtastic::MQTT.connect
|
|
33
37
|
puts mqtt_obj.inspect
|
|
34
38
|
Meshtastic::MQTT.subscribe(
|
|
35
39
|
mqtt_obj: mqtt_obj,
|
|
@@ -41,7 +45,7 @@ This code will dump the contents of every message:
|
|
|
41
45
|
|
|
42
46
|
```ruby
|
|
43
47
|
require 'meshtastic'
|
|
44
|
-
mqtt_obj =
|
|
48
|
+
mqtt_obj = Meshtastic::MQTT.connect
|
|
45
49
|
Meshtastic::MQTT.subscribe(
|
|
46
50
|
mqtt_obj: mqtt_obj,
|
|
47
51
|
root_topic: 'msh',
|
|
@@ -57,7 +61,7 @@ Sending a message over MQTT:
|
|
|
57
61
|
|
|
58
62
|
```ruby
|
|
59
63
|
require 'meshtastic'
|
|
60
|
-
mqtt_obj =
|
|
64
|
+
mqtt_obj = Meshtastic::MQTT.connect
|
|
61
65
|
client_id = "!#{mqtt_obj.client_id}"
|
|
62
66
|
Meshtastic::MQTT.send_text(
|
|
63
67
|
mqtt_obj: mqtt_obj,
|
|
@@ -76,7 +80,7 @@ One of the "gotchas" when sending messages is ensuring you're sending over the p
|
|
|
76
80
|
|
|
77
81
|
```ruby
|
|
78
82
|
require 'meshtastic'
|
|
79
|
-
mqtt_obj =
|
|
83
|
+
mqtt_obj = Meshtastic::MQTT.connect
|
|
80
84
|
Meshtastic::MQTT.subscribe(
|
|
81
85
|
mqtt_obj: mqtt_obj,
|
|
82
86
|
root_topic: 'msh',
|
|
@@ -97,6 +101,112 @@ You should see something like this:
|
|
|
97
101
|
|
|
98
102
|
Note where is says `channel: 93`. This is the `channel` value required to send messages in this particular example.
|
|
99
103
|
|
|
104
|
+
### Serial Interface
|
|
105
|
+
|
|
106
|
+
Talk directly to a Meshtastic node over USB/UART (`/dev/ttyUSB*`, `/dev/ttyACM*`). Unlike MQTT, the radio owns channel crypto for serial: payloads are sent *decoded* and the device encrypts with its configured channel key.
|
|
107
|
+
|
|
108
|
+
To inspect available methods and open a serial session:
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
require 'meshtastic'
|
|
112
|
+
Meshtastic::SerialInterface.help
|
|
113
|
+
serial_obj = Meshtastic::SerialInterface.connect(
|
|
114
|
+
block_dev: '/dev/ttyUSB0', # or /dev/ttyACM0
|
|
115
|
+
baud: 115_200
|
|
116
|
+
)
|
|
117
|
+
puts serial_obj.inspect
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
This code will dump every FromRadio packet (blocks until CTRL+C):
|
|
121
|
+
|
|
122
|
+
```ruby
|
|
123
|
+
require 'meshtastic'
|
|
124
|
+
serial_obj = Meshtastic::SerialInterface.connect(
|
|
125
|
+
block_dev: '/dev/ttyUSB0',
|
|
126
|
+
baud: 115_200
|
|
127
|
+
)
|
|
128
|
+
Meshtastic::SerialInterface.subscribe(
|
|
129
|
+
serial_obj: serial_obj
|
|
130
|
+
) do |message|
|
|
131
|
+
puts message.inspect
|
|
132
|
+
end
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Filter with `include` / `exclude` (comma-delimited substrings), same idea as MQTT:
|
|
136
|
+
|
|
137
|
+
```ruby
|
|
138
|
+
require 'meshtastic'
|
|
139
|
+
serial_obj = Meshtastic::SerialInterface.connect(block_dev: '/dev/ttyUSB0')
|
|
140
|
+
Meshtastic::SerialInterface.subscribe(
|
|
141
|
+
serial_obj: serial_obj,
|
|
142
|
+
include: 'TEXT_MESSAGE_APP',
|
|
143
|
+
exclude: 'TELEMETRY_APP'
|
|
144
|
+
) do |message|
|
|
145
|
+
puts message.inspect
|
|
146
|
+
end
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Sending a message over serial:
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
require 'meshtastic'
|
|
153
|
+
serial_obj = Meshtastic::SerialInterface.connect(
|
|
154
|
+
block_dev: '/dev/ttyUSB0',
|
|
155
|
+
baud: 115_200
|
|
156
|
+
)
|
|
157
|
+
Meshtastic::SerialInterface.send_text(
|
|
158
|
+
serial_obj: serial_obj,
|
|
159
|
+
to: '!ffffffff', # broadcast; or a node id like '!f33ddad5'
|
|
160
|
+
channel: 0, # primary channel index on the radio
|
|
161
|
+
text: 'Hello over serial!'
|
|
162
|
+
)
|
|
163
|
+
Meshtastic::SerialInterface.disconnect(serial_obj: serial_obj)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
A typical end-to-end send + receive session looks like this (connect once, send, then subscribe):
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
require 'meshtastic'
|
|
170
|
+
|
|
171
|
+
serial_obj = Meshtastic::SerialInterface.connect(
|
|
172
|
+
block_dev: '/dev/ttyUSB0',
|
|
173
|
+
baud: 115_200
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Optional: give the device a moment to finish want_config / my_info
|
|
177
|
+
sleep 2
|
|
178
|
+
puts "local node: !#{serial_obj[:my_node_num].to_s(16)}" if serial_obj[:my_node_num]
|
|
179
|
+
|
|
180
|
+
Meshtastic::SerialInterface.send_text(
|
|
181
|
+
serial_obj: serial_obj,
|
|
182
|
+
to: '!ffffffff',
|
|
183
|
+
channel: 0,
|
|
184
|
+
text: 'Hello over serial!'
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Blocks; CTRL+C disconnects cleanly
|
|
188
|
+
Meshtastic::SerialInterface.subscribe(serial_obj: serial_obj) do |message|
|
|
189
|
+
puts message.inspect
|
|
190
|
+
end
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Non-blocking receive helpers (useful when you drive the loop yourself):
|
|
194
|
+
|
|
195
|
+
```ruby
|
|
196
|
+
# Pop one framed FromRadio (or nil on timeout)
|
|
197
|
+
fr = Meshtastic::SerialInterface.recv_from_radio(timeout: 2)
|
|
198
|
+
puts fr&.to_h
|
|
199
|
+
|
|
200
|
+
# Drain whatever is already queued
|
|
201
|
+
Meshtastic::SerialInterface.drain_from_radio.each { |fr| puts fr.to_h }
|
|
202
|
+
|
|
203
|
+
# Debug console / proto dumps collected by the RX thread
|
|
204
|
+
puts Meshtastic::SerialInterface.dump_stdout_data(type: :console)
|
|
205
|
+
puts Meshtastic::SerialInterface.dump_stdout_data(type: :proto).size
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
> **Note:** Serial path leaves mesh packets *decoded* and lets the radio encrypt with its configured channel key. The MQTT path still pre-encrypts with the PSK you supply via `psks:`. Channel index (`channel:`) on serial is the index configured on the *device*, not the MQTT channel hash.
|
|
209
|
+
|
|
100
210
|
## Contributing
|
|
101
211
|
|
|
102
212
|
Bug reports and pull requests are welcome on GitHub at https://github.com/0dayinc/meshtastic. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/0dayinc/meshtastic/blob/master/CODE_OF_CONDUCT.md).
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Meshtastic
|
|
2
|
+
|
|
3
|
+
Ruby gem for interfacing with Meshtastic nodes / network.
|
|
4
|
+
|
|
5
|
+
# Setting Expectations
|
|
6
|
+
|
|
7
|
+
This gem was created to support alt-comm capabilities w/in a security research framework known as [PWN](https://github.com/0dayInc/pwn). Contributors of this effort cannot guarantee full functionality or support for all Meshtastic features.
|
|
8
|
+
|
|
9
|
+
# Objectives
|
|
10
|
+
|
|
11
|
+
- Consume the latest [Meshtastic Protobof Specs](https://github.com/meshtastic/protobufs) and [auto-generate Ruby protobuf modules for Meshtastic](https://github.com/0dayInc/meshtastic/blob/master/AUTOGEN_meshtastic_protobufs.sh) using the `grpc_tools_ruby_protoc` command: `Complete`
|
|
12
|
+
- Integrate auto-generated Ruby protobuf modules into a working Ruby gem: `Complete`
|
|
13
|
+
- Scale out Meshtastic Ruby Modules for their respective protobufs within the meshtastic gem (e.g. Meshtastic::MQTTPB is auto-generated based on latest Meshtastic protobuf specs and extended via Meshtastic::MQTT for more MQTT interaction as desired): `Ongoing Effort`
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
18
|
+
|
|
19
|
+
$ bundle add meshtastic
|
|
20
|
+
|
|
21
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
22
|
+
|
|
23
|
+
$ gem install meshtastic
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
At the moment the only module available is `Meshtastic::MQTT`. To view MQTT messages, and include only messages containing `_APP` _and_ `LongFast` strings, use the following code:
|
|
28
|
+
|
|
29
|
+
```ruby
|
|
30
|
+
require 'meshtastic'
|
|
31
|
+
Meshtastic::MQTT.help
|
|
32
|
+
mqtt_obj = Meshastic::MQTT.connect
|
|
33
|
+
puts mqtt_obj.inspect
|
|
34
|
+
Meshtastic::MQTT.subscribe(
|
|
35
|
+
mqtt_obj: mqtt_obj,
|
|
36
|
+
include: '_APP, LongFast'
|
|
37
|
+
)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This code will dump the contents of every message:
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
require 'meshtastic'
|
|
44
|
+
mqtt_obj = Meshastic::MQTT.connect
|
|
45
|
+
Meshtastic::MQTT.subscribe(
|
|
46
|
+
mqtt_obj: mqtt_obj,
|
|
47
|
+
root_topic: 'msh',
|
|
48
|
+
region: 'US',
|
|
49
|
+
topic: '2/e/LongFast/#',
|
|
50
|
+
psks: { LongFast: 'AQ==' }
|
|
51
|
+
) do |message|
|
|
52
|
+
puts message.inspect
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Sending a message over MQTT:
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
require 'meshtastic'
|
|
60
|
+
mqtt_obj = Meshastic::MQTT.connect
|
|
61
|
+
client_id = "!#{mqtt_obj.client_id}"
|
|
62
|
+
Meshtastic::MQTT.send_text(
|
|
63
|
+
mqtt_obj: mqtt_obj,
|
|
64
|
+
from: client_id,
|
|
65
|
+
to: '!ffffffff',
|
|
66
|
+
root_topic: 'msh',
|
|
67
|
+
region: 'US',
|
|
68
|
+
topic: '2/e/LongFast/#',
|
|
69
|
+
channel: 93,
|
|
70
|
+
text: 'Hello, World!',
|
|
71
|
+
psks: { LongFast: 'AQ==' }
|
|
72
|
+
)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
One of the "gotchas" when sending messages is ensuring you're sending over the proper integer for the `channel` parameter. The best way to determine the proper `channel` value is by sending a test message from within the meshtastic app and then viewing the MQTT message similar to the following:
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
require 'meshtastic'
|
|
79
|
+
mqtt_obj = Meshastic::MQTT.connect
|
|
80
|
+
Meshtastic::MQTT.subscribe(
|
|
81
|
+
mqtt_obj: mqtt_obj,
|
|
82
|
+
root_topic: 'msh',
|
|
83
|
+
region: 'US',
|
|
84
|
+
topic: '2/e/LongFast/#',
|
|
85
|
+
psks: { LongFast: 'AQ==' },
|
|
86
|
+
include: '!YOUR_CLIENT_ID'
|
|
87
|
+
) do |message|
|
|
88
|
+
puts message.inspect
|
|
89
|
+
end
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
You should see something like this:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
{packet: {from: 4080917205, to: 4294967295, channel: 93, id: 1198634591, rx_time: 1738614021, rx_snr: 0.0, hop_limit: 3, want_ack: false, priority: :HIGH, rx_rssi: 0, delayed: :NO_DELAY, via_mqtt: false, hop_start: 3, public_key: "", pki_encrypted: false, next_hop: 0, relay_node: 0, tx_after: 0, decoded: {portnum: :TEXT_MESSAGE_APP, payload: "WHAT IS MY channel VALUE?", want_response: false, dest: 0, source: 0, request_id: 0, reply_id: 0, emoji: 0, bitfield: 0}, encrypted: :decrypted, topic: "msh/US/2/e/LongFast/!f33ddad5", node_id_from: "!f33ddad5", node_id_to: "!ffffffff", rx_time_utc: "2025-01-01 07:00:00 UTC"}, channel_id: "LongFast", gateway_id: "!f33ddad5"}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Note where is says `channel: 93`. This is the `channel` value required to send messages in this particular example.
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
## Serial Interface
|
|
102
|
+
|
|
103
|
+
Talk directly to a Meshtastic node over USB/UART (`/dev/ttyUSB*`, `/dev/ttyACM*`).
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
require 'meshtastic'
|
|
107
|
+
|
|
108
|
+
serial_obj = Meshtastic::SerialInterface.connect(
|
|
109
|
+
block_dev: '/dev/ttyUSB0', # or /dev/ttyACM0
|
|
110
|
+
baud: 115_200
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Send a text message (device applies channel PSK)
|
|
114
|
+
Meshtastic::SerialInterface.send_text(
|
|
115
|
+
serial_obj: serial_obj,
|
|
116
|
+
to: '!ffffffff',
|
|
117
|
+
channel: 0,
|
|
118
|
+
text: 'Hello over serial!'
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Subscribe to FromRadio packets (blocks; CTRL+C to stop)
|
|
122
|
+
Meshtastic::SerialInterface.subscribe(serial_obj: serial_obj) do |msg|
|
|
123
|
+
puts msg.inspect
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
Meshtastic::SerialInterface.disconnect(serial_obj: serial_obj)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Non-blocking helpers:
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
# Pop one framed FromRadio (or nil on timeout)
|
|
133
|
+
fr = Meshtastic::SerialInterface.recv_from_radio(timeout: 2)
|
|
134
|
+
puts fr&.to_h
|
|
135
|
+
|
|
136
|
+
# Drain whatever is already queued
|
|
137
|
+
Meshtastic::SerialInterface.drain_from_radio.each { |fr| puts fr.to_h }
|
|
138
|
+
|
|
139
|
+
# Debug console / proto dumps collected by the RX thread
|
|
140
|
+
puts Meshtastic::SerialInterface.dump_stdout_data(type: :console)
|
|
141
|
+
puts Meshtastic::SerialInterface.dump_stdout_data(type: :proto).size
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
> **Note:** Serial path leaves mesh packets *decoded* and lets the radio encrypt with its configured channel key. The MQTT path still pre-encrypts with the PSK you supply.
|
|
145
|
+
|
|
146
|
+
## Contributing
|
|
147
|
+
|
|
148
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/0dayinc/meshtastic. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/0dayinc/meshtastic/blob/master/CODE_OF_CONDUCT.md).
|
|
149
|
+
|
|
150
|
+
## Code of Conduct
|
|
151
|
+
|
|
152
|
+
Everyone interacting in the Meshtastic project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/0dayinc/meshtastic/blob/master/CODE_OF_CONDUCT.md).
|
|
@@ -213,10 +213,16 @@ module Meshtastic
|
|
|
213
213
|
hop_limit = opts[:hop_limit] ||= 3
|
|
214
214
|
|
|
215
215
|
public_psk = '1PG7OiApB1nwvP+rz05pAQ=='
|
|
216
|
-
|
|
217
|
-
|
|
216
|
+
# Explicit nil means "do not encrypt" (serial/radio path — device owns PSK).
|
|
217
|
+
if opts.key?(:psks) && opts[:psks].nil?
|
|
218
|
+
psks = nil
|
|
219
|
+
else
|
|
220
|
+
psks = opts[:psks] || { LongFast: public_psk }
|
|
221
|
+
raise 'ERROR: psks parameter must be a hash of :channel => psk key value pairs' unless psks.is_a?(Hash)
|
|
218
222
|
|
|
219
|
-
|
|
223
|
+
psks = psks.dup
|
|
224
|
+
psks[:LongFast] = public_psk if psks[:LongFast] == 'AQ=='
|
|
225
|
+
end
|
|
220
226
|
|
|
221
227
|
# my_info = Meshtastic::FromRadio.my_info
|
|
222
228
|
# wait_connected if to != my_info.my_node_num && my_info.is_a(Meshtastic::Deviceonly::MyInfo)
|
|
@@ -228,7 +234,10 @@ module Meshtastic
|
|
|
228
234
|
mesh_packet.hop_limit = hop_limit
|
|
229
235
|
mesh_packet.id = generate_packet_id(last_packet_id: last_packet_id)
|
|
230
236
|
|
|
231
|
-
|
|
237
|
+
# When psks is nil/empty, leave the packet decoded so the radio (serial/TCP)
|
|
238
|
+
# device can apply the channel PSK itself. MQTT callers must pass psks so the
|
|
239
|
+
# ServiceEnvelope payload is pre-encrypted for the mesh.
|
|
240
|
+
if psks && !psks.empty?
|
|
232
241
|
nonce_packet_id = [mesh_packet.id].pack('V').ljust(8, "\x00")
|
|
233
242
|
nonce_from_node = [from].pack('V').ljust(8, "\x00")
|
|
234
243
|
nonce = "#{nonce_packet_id}#{nonce_from_node}"
|
|
@@ -305,10 +314,15 @@ module Meshtastic
|
|
|
305
314
|
raise "ERROR: Invalid port_num" unless port_num.positive? && port_num < max_port_num
|
|
306
315
|
|
|
307
316
|
public_psk = '1PG7OiApB1nwvP+rz05pAQ=='
|
|
308
|
-
psks
|
|
309
|
-
|
|
317
|
+
if opts.key?(:psks) && opts[:psks].nil?
|
|
318
|
+
psks = nil
|
|
319
|
+
else
|
|
320
|
+
psks = opts[:psks] || { LongFast: public_psk }
|
|
321
|
+
raise 'ERROR: psks parameter must be a hash of :channel => psk key value pairs' unless psks.is_a?(Hash)
|
|
310
322
|
|
|
311
|
-
|
|
323
|
+
psks = psks.dup
|
|
324
|
+
psks[:LongFast] = public_psk if psks[:LongFast] == 'AQ=='
|
|
325
|
+
end
|
|
312
326
|
|
|
313
327
|
data_len = data.payload.length
|
|
314
328
|
max_len = Meshtastic::Constants::DATA_PAYLOAD_LEN
|
|
@@ -369,10 +383,15 @@ module Meshtastic
|
|
|
369
383
|
on_response = opts[:on_response]
|
|
370
384
|
|
|
371
385
|
public_psk = '1PG7OiApB1nwvP+rz05pAQ=='
|
|
372
|
-
psks
|
|
373
|
-
|
|
386
|
+
if opts.key?(:psks) && opts[:psks].nil?
|
|
387
|
+
psks = nil
|
|
388
|
+
else
|
|
389
|
+
psks = opts[:psks] || { LongFast: public_psk }
|
|
390
|
+
raise 'ERROR: psks parameter must be a hash of :channel => psk key value pairs' unless psks.is_a?(Hash)
|
|
374
391
|
|
|
375
|
-
|
|
392
|
+
psks = psks.dup
|
|
393
|
+
psks[:LongFast] = public_psk if psks[:LongFast] == 'AQ=='
|
|
394
|
+
end
|
|
376
395
|
|
|
377
396
|
# TODO: verify text length validity
|
|
378
397
|
max_txt_len = Meshtastic::Constants::DATA_PAYLOAD_LEN
|
|
@@ -381,7 +400,7 @@ module Meshtastic
|
|
|
381
400
|
port_num = Meshtastic::PortNum::TEXT_MESSAGE_APP
|
|
382
401
|
|
|
383
402
|
data = Meshtastic::Data.new
|
|
384
|
-
data.payload = text.force_encoding('ASCII-8BIT')
|
|
403
|
+
data.payload = text.to_s.dup.force_encoding('ASCII-8BIT')
|
|
385
404
|
data.portnum = port_num
|
|
386
405
|
data.want_response = want_response
|
|
387
406
|
# puts data.to_h
|