meshtastic 0.0.84 → 0.0.86
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/Gemfile +1 -1
- data/lib/meshtastic/mqtt.rb +11 -164
- data/lib/meshtastic/version.rb +1 -1
- data/lib/meshtastic.rb +156 -0
- data/meshtastic.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 708e04cee865ae3b9fdaee52fa9be682f6d2c57a2764b1b4ba43fb5b6cff0397
|
4
|
+
data.tar.gz: f4da627c0ae92fa039722bdd8e320cca5388a6158bd61b1acee2c4866de2b066
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cfc0314cdbd69e3b41a3f5caf6b8d094210d9d0e91022ce29ee536c6dc5d713bfc38a5aab31b9f74a28fe6f8c1c39d57c2889ba7c39db9ba547d947f1c1a83ae
|
7
|
+
data.tar.gz: 494de489ecf82f4927614bb82730c5dddb565155260f29dc29851fc9aee0be6f00272b801d991732934f7b351661ca97b63c2ca14b187a9033f8235f15ac315d
|
data/Gemfile
CHANGED
data/lib/meshtastic/mqtt.rb
CHANGED
@@ -19,7 +19,8 @@ module Meshtastic
|
|
19
19
|
# host: 'optional - mqtt host (default: mqtt.meshtastic.org)',
|
20
20
|
# port: 'optional - mqtt port (defaults: 1883)',
|
21
21
|
# username: 'optional - mqtt username (default: meshdev)',
|
22
|
-
# password: 'optional - (default: large4cats)'
|
22
|
+
# password: 'optional - (default: large4cats)',
|
23
|
+
# client_id: 'optional - client ID (default: random 4-byte hex string)'
|
23
24
|
# )
|
24
25
|
|
25
26
|
public_class_method def self.connect(opts = {})
|
@@ -28,148 +29,15 @@ module Meshtastic
|
|
28
29
|
port = opts[:port] ||= 1883
|
29
30
|
username = opts[:username] ||= 'meshdev'
|
30
31
|
password = opts[:password] ||= 'large4cats'
|
32
|
+
client_id = opts[:client_id] ||= SecureRandom.random_bytes(4).unpack1('H*').to_s
|
31
33
|
|
32
|
-
|
34
|
+
MQTTClient.connect(
|
33
35
|
host: host,
|
34
36
|
port: port,
|
35
37
|
username: username,
|
36
|
-
password: password
|
38
|
+
password: password,
|
39
|
+
client_id: client_id
|
37
40
|
)
|
38
|
-
|
39
|
-
mqtt_obj.client_id = SecureRandom.random_bytes(8).unpack1('H*')
|
40
|
-
|
41
|
-
mqtt_obj
|
42
|
-
rescue StandardError => e
|
43
|
-
raise e
|
44
|
-
end
|
45
|
-
|
46
|
-
# Supported Method Parameters::
|
47
|
-
# Meshtastic::MQQT.get_cipher_keys(
|
48
|
-
# psks: 'required - hash of channel / pre-shared key value pairs'
|
49
|
-
# )
|
50
|
-
|
51
|
-
private_class_method def self.get_cipher_keys(opts = {})
|
52
|
-
psks = opts[:psks]
|
53
|
-
|
54
|
-
psks.each_key do |key|
|
55
|
-
psk = psks[key]
|
56
|
-
padded_psk = psk.ljust(psk.length + ((4 - (psk.length % 4)) % 4), '=')
|
57
|
-
replaced_psk = padded_psk.gsub('-', '+').gsub('_', '/')
|
58
|
-
psks[key] = replaced_psk
|
59
|
-
end
|
60
|
-
|
61
|
-
psks
|
62
|
-
rescue StandardError => e
|
63
|
-
raise e
|
64
|
-
end
|
65
|
-
|
66
|
-
# Supported Method Parameters::
|
67
|
-
# Meshtastic::MQQT.decode_payload(
|
68
|
-
# payload: 'required - payload to recursively decode',
|
69
|
-
# msg_type: 'required - message type (e.g. :TEXT_MESSAGE_APP)',
|
70
|
-
# gps_metadata: 'optional - include GPS metadata in output (default: false)',
|
71
|
-
# )
|
72
|
-
|
73
|
-
public_class_method def self.decode_payload(opts = {})
|
74
|
-
payload = opts[:payload]
|
75
|
-
msg_type = opts[:msg_type]
|
76
|
-
gps_metadata = opts[:gps_metadata]
|
77
|
-
|
78
|
-
case msg_type
|
79
|
-
when :ADMIN_APP
|
80
|
-
decoder = Meshtastic::AdminMessage
|
81
|
-
when :ATAK_FORWARDER, :ATAK_PLUGIN
|
82
|
-
decoder = Meshtastic::TAKPacket
|
83
|
-
# when :AUDIO_APP
|
84
|
-
# decoder = Meshtastic::Audio
|
85
|
-
when :DETECTION_SENSOR_APP
|
86
|
-
decoder = Meshtastic::DeviceState
|
87
|
-
# when :IP_TUNNEL_APP
|
88
|
-
# decoder = Meshtastic::IpTunnel
|
89
|
-
when :MAP_REPORT_APP
|
90
|
-
decoder = Meshtastic::MapReport
|
91
|
-
# when :MAX
|
92
|
-
# decoder = Meshtastic::Max
|
93
|
-
when :NEIGHBORINFO_APP
|
94
|
-
decoder = Meshtastic::NeighborInfo
|
95
|
-
when :NODEINFO_APP
|
96
|
-
decoder = Meshtastic::User
|
97
|
-
when :PAXCOUNTER_APP
|
98
|
-
decoder = Meshtastic::Paxcount
|
99
|
-
when :POSITION_APP
|
100
|
-
decoder = Meshtastic::Position
|
101
|
-
# when :PRIVATE_APP
|
102
|
-
# decoder = Meshtastic::Private
|
103
|
-
when :RANGE_TEST_APP
|
104
|
-
# Unsure if this is the correct protobuf object
|
105
|
-
decoder = Meshtastic::FromRadio
|
106
|
-
when :REMOTE_HARDWARE_APP
|
107
|
-
decoder = Meshtastic::HardwareMessage
|
108
|
-
# when :REPLY_APP
|
109
|
-
# decoder = Meshtastic::Reply
|
110
|
-
when :ROUTING_APP
|
111
|
-
decoder = Meshtastic::Routing
|
112
|
-
when :SERIAL_APP
|
113
|
-
decoder = Meshtastic::SerialConnectionStatus
|
114
|
-
when :SIMULATOR_APP
|
115
|
-
decoder = Meshtastic::Compressed
|
116
|
-
when :STORE_FORWARD_APP
|
117
|
-
decoder = Meshtastic::StoreAndForward
|
118
|
-
when :TEXT_MESSAGE_APP, :UNKNOWN_APP
|
119
|
-
decoder = Meshtastic::Data
|
120
|
-
when :TELEMETRY_APP
|
121
|
-
decoder = Meshtastic::Telemetry
|
122
|
-
when :TRACEROUTE_APP
|
123
|
-
decoder = Meshtastic::RouteDiscovery
|
124
|
-
when :WAYPOINT_APP
|
125
|
-
decoder = Meshtastic::Waypoint
|
126
|
-
# when :ZPS_APP
|
127
|
-
# decoder = Meshtastic::Zps
|
128
|
-
else
|
129
|
-
puts "WARNING: Can't decode\n#{payload.inspect}\nw/ portnum: #{msg_type}"
|
130
|
-
return payload
|
131
|
-
end
|
132
|
-
|
133
|
-
payload = decoder.decode(payload).to_h
|
134
|
-
|
135
|
-
if payload.keys.include?(:latitude_i)
|
136
|
-
lat = payload[:latitude_i] * 0.0000001
|
137
|
-
payload[:latitude] = lat
|
138
|
-
end
|
139
|
-
|
140
|
-
if payload.keys.include?(:longitude_i)
|
141
|
-
lon = payload[:longitude_i] * 0.0000001
|
142
|
-
payload[:longitude] = lon
|
143
|
-
end
|
144
|
-
|
145
|
-
if payload.keys.include?(:macaddr)
|
146
|
-
mac_raw = payload[:macaddr]
|
147
|
-
mac_hex_arr = mac_raw.bytes.map { |byte| byte.to_s(16).rjust(2, '0') }
|
148
|
-
mac_hex_str = mac_hex_arr.join(':')
|
149
|
-
payload[:macaddr] = mac_hex_str
|
150
|
-
end
|
151
|
-
|
152
|
-
if payload.keys.include?(:time)
|
153
|
-
time_int = payload[:time]
|
154
|
-
if time_int.is_a?(Integer)
|
155
|
-
time_utc = Time.at(time_int).utc.to_s
|
156
|
-
payload[:time_utc] = time_utc
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
if gps_metadata && payload[:latitude] && payload[:longitude]
|
161
|
-
lat = payload[:latitude]
|
162
|
-
lon = payload[:longitude]
|
163
|
-
unless lat.zero? && lon.zero?
|
164
|
-
gps_search_resp = gps_search(lat: lat, lon: lon)
|
165
|
-
payload[:gps_metadata] = gps_search_resp
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
payload
|
170
|
-
rescue Encoding::CompatibilityError,
|
171
|
-
Google::Protobuf::ParseError
|
172
|
-
payload
|
173
41
|
rescue StandardError => e
|
174
42
|
raise e
|
175
43
|
end
|
@@ -199,7 +67,7 @@ module Meshtastic
|
|
199
67
|
raise 'ERROR: psks parameter must be a hash of :channel => psk key value pairs' unless psks.is_a?(Hash)
|
200
68
|
|
201
69
|
psks[:LongFast] = public_psk if psks[:LongFast] == 'AQ=='
|
202
|
-
psks = get_cipher_keys(psks: psks)
|
70
|
+
psks = Meshtastic.get_cipher_keys(psks: psks)
|
203
71
|
|
204
72
|
qos = opts[:qos] ||= 0
|
205
73
|
json = opts[:json] ||= false
|
@@ -279,7 +147,7 @@ module Meshtastic
|
|
279
147
|
# payload = Meshtastic::Data.decode(message[:decoded][:payload]).to_h
|
280
148
|
payload = message[:decoded][:payload]
|
281
149
|
msg_type = message[:decoded][:portnum]
|
282
|
-
message[:decoded][:payload] = decode_payload(
|
150
|
+
message[:decoded][:payload] = Meshtastic.decode_payload(
|
283
151
|
payload: payload,
|
284
152
|
msg_type: msg_type,
|
285
153
|
gps_metadata: gps_metadata
|
@@ -362,6 +230,7 @@ module Meshtastic
|
|
362
230
|
topic = opts[:topic] ||= 'msh/US/2/e/LongFast/#'
|
363
231
|
opts[:via] = :mqtt
|
364
232
|
|
233
|
+
# TODO: Implement chunked message to deal with large messages
|
365
234
|
protobuf_text = Meshtastic.send_text(opts)
|
366
235
|
|
367
236
|
mqtt_obj.publish(topic, protobuf_text)
|
@@ -369,24 +238,6 @@ module Meshtastic
|
|
369
238
|
raise e
|
370
239
|
end
|
371
240
|
|
372
|
-
# Supported Method Parameters::
|
373
|
-
# mqtt_obj = Meshtastic.gps_search(
|
374
|
-
# lat: 'required - latitude float (e.g. 37.7749)',
|
375
|
-
# lon: 'required - longitude float (e.g. -122.4194)',
|
376
|
-
# )
|
377
|
-
public_class_method def self.gps_search(opts = {})
|
378
|
-
lat = opts[:lat]
|
379
|
-
lon = opts[:lon]
|
380
|
-
|
381
|
-
raise 'ERROR: Latitude and Longitude are required' unless lat && lon
|
382
|
-
|
383
|
-
gps_arr = [lat.to_f, lon.to_f]
|
384
|
-
|
385
|
-
Geocoder.search(gps_arr).first.data
|
386
|
-
rescue StandardError => e
|
387
|
-
raise e
|
388
|
-
end
|
389
|
-
|
390
241
|
# Supported Method Parameters::
|
391
242
|
# mqtt_obj = Meshtastic.disconnect(
|
392
243
|
# mqtt_obj: 'required - mqtt_obj returned from #connect method'
|
@@ -416,7 +267,8 @@ module Meshtastic
|
|
416
267
|
host: 'optional - mqtt host (default: mqtt.meshtastic.org)',
|
417
268
|
port: 'optional - mqtt port (defaults: 1883)',
|
418
269
|
username: 'optional - mqtt username (default: meshdev)',
|
419
|
-
password: 'optional - (default: large4cats)'
|
270
|
+
password: 'optional - (default: large4cats)',
|
271
|
+
client_id: 'optional - client ID (default: random 8-byte hex string)'
|
420
272
|
)
|
421
273
|
|
422
274
|
#{self}.subscribe(
|
@@ -431,11 +283,6 @@ module Meshtastic
|
|
431
283
|
gps_metadata: 'optional - include GPS metadata in output (default: false)'
|
432
284
|
)
|
433
285
|
|
434
|
-
#{self}.gps_search(
|
435
|
-
lat: 'required - latitude float (e.g. 37.7749)',
|
436
|
-
lon: 'required - longitude float (e.g. -122.4194)',
|
437
|
-
)
|
438
|
-
|
439
286
|
#{self}.send_text(
|
440
287
|
mqtt_obj: 'required - mqtt_obj returned from #connect method',
|
441
288
|
from: ' required - From ID (String or Integer)',
|
data/lib/meshtastic/version.rb
CHANGED
data/lib/meshtastic.rb
CHANGED
@@ -282,6 +282,26 @@ module Meshtastic
|
|
282
282
|
packet_id
|
283
283
|
end
|
284
284
|
|
285
|
+
# Supported Method Parameters::
|
286
|
+
# Meshtastic.get_cipher_keys(
|
287
|
+
# psks: 'required - hash of channel / pre-shared key value pairs'
|
288
|
+
# )
|
289
|
+
|
290
|
+
public_class_method def self.get_cipher_keys(opts = {})
|
291
|
+
psks = opts[:psks]
|
292
|
+
|
293
|
+
psks.each_key do |key|
|
294
|
+
psk = psks[key]
|
295
|
+
padded_psk = psk.ljust(psk.length + ((4 - (psk.length % 4)) % 4), '=')
|
296
|
+
replaced_psk = padded_psk.gsub('-', '+').gsub('_', '/')
|
297
|
+
psks[key] = replaced_psk
|
298
|
+
end
|
299
|
+
|
300
|
+
psks
|
301
|
+
rescue StandardError => e
|
302
|
+
raise e
|
303
|
+
end
|
304
|
+
|
285
305
|
# Supported Method Parameters::
|
286
306
|
# Meshtastic.send_to_radio(
|
287
307
|
# to_radio: 'required - ToRadio Message to Send'
|
@@ -310,6 +330,135 @@ module Meshtastic
|
|
310
330
|
raise e
|
311
331
|
end
|
312
332
|
|
333
|
+
# Supported Method Parameters::
|
334
|
+
# Meshtastic.gps_search(
|
335
|
+
# lat: 'required - latitude float (e.g. 37.7749)',
|
336
|
+
# lon: 'required - longitude float (e.g. -122.4194)',
|
337
|
+
# )
|
338
|
+
public_class_method def self.gps_search(opts = {})
|
339
|
+
lat = opts[:lat]
|
340
|
+
lon = opts[:lon]
|
341
|
+
|
342
|
+
raise 'ERROR: Latitude and Longitude are required' unless lat && lon
|
343
|
+
|
344
|
+
gps_arr = [lat.to_f, lon.to_f]
|
345
|
+
|
346
|
+
Geocoder.search(gps_arr).first.data
|
347
|
+
rescue StandardError => e
|
348
|
+
raise e
|
349
|
+
end
|
350
|
+
|
351
|
+
# Supported Method Parameters::
|
352
|
+
# Meshtastic::MQQT.decode_payload(
|
353
|
+
# payload: 'required - payload to recursively decode',
|
354
|
+
# msg_type: 'required - message type (e.g. :TEXT_MESSAGE_APP)',
|
355
|
+
# gps_metadata: 'optional - include GPS metadata in output (default: false)',
|
356
|
+
# )
|
357
|
+
|
358
|
+
public_class_method def self.decode_payload(opts = {})
|
359
|
+
payload = opts[:payload]
|
360
|
+
msg_type = opts[:msg_type]
|
361
|
+
gps_metadata = opts[:gps_metadata]
|
362
|
+
|
363
|
+
case msg_type
|
364
|
+
when :ADMIN_APP
|
365
|
+
decoder = Meshtastic::AdminMessage
|
366
|
+
when :ATAK_FORWARDER, :ATAK_PLUGIN
|
367
|
+
decoder = Meshtastic::TAKPacket
|
368
|
+
# when :AUDIO_APP
|
369
|
+
# decoder = Meshtastic::Audio
|
370
|
+
when :DETECTION_SENSOR_APP
|
371
|
+
decoder = Meshtastic::DeviceState
|
372
|
+
# when :IP_TUNNEL_APP
|
373
|
+
# decoder = Meshtastic::IpTunnel
|
374
|
+
when :MAP_REPORT_APP
|
375
|
+
decoder = Meshtastic::MapReport
|
376
|
+
# when :MAX
|
377
|
+
# decoder = Meshtastic::Max
|
378
|
+
when :NEIGHBORINFO_APP
|
379
|
+
decoder = Meshtastic::NeighborInfo
|
380
|
+
when :NODEINFO_APP
|
381
|
+
decoder = Meshtastic::User
|
382
|
+
when :PAXCOUNTER_APP
|
383
|
+
decoder = Meshtastic::Paxcount
|
384
|
+
when :POSITION_APP
|
385
|
+
decoder = Meshtastic::Position
|
386
|
+
# when :PRIVATE_APP
|
387
|
+
# decoder = Meshtastic::Private
|
388
|
+
when :RANGE_TEST_APP
|
389
|
+
# Unsure if this is the correct protobuf object
|
390
|
+
decoder = Meshtastic::FromRadio
|
391
|
+
when :REMOTE_HARDWARE_APP
|
392
|
+
decoder = Meshtastic::HardwareMessage
|
393
|
+
# when :REPLY_APP
|
394
|
+
# decoder = Meshtastic::Reply
|
395
|
+
when :ROUTING_APP
|
396
|
+
decoder = Meshtastic::Routing
|
397
|
+
when :SERIAL_APP
|
398
|
+
decoder = Meshtastic::SerialConnectionStatus
|
399
|
+
when :SIMULATOR_APP
|
400
|
+
decoder = Meshtastic::Compressed
|
401
|
+
when :STORE_FORWARD_APP
|
402
|
+
decoder = Meshtastic::StoreAndForward
|
403
|
+
when :TEXT_MESSAGE_APP, :UNKNOWN_APP
|
404
|
+
decoder = Meshtastic::Data
|
405
|
+
when :TELEMETRY_APP
|
406
|
+
decoder = Meshtastic::Telemetry
|
407
|
+
when :TRACEROUTE_APP
|
408
|
+
decoder = Meshtastic::RouteDiscovery
|
409
|
+
when :WAYPOINT_APP
|
410
|
+
decoder = Meshtastic::Waypoint
|
411
|
+
# when :ZPS_APP
|
412
|
+
# decoder = Meshtastic::Zps
|
413
|
+
else
|
414
|
+
puts "WARNING: Can't decode\n#{payload.inspect}\nw/ portnum: #{msg_type}"
|
415
|
+
return payload
|
416
|
+
end
|
417
|
+
|
418
|
+
payload = decoder.decode(payload).to_h
|
419
|
+
|
420
|
+
if payload.keys.include?(:latitude_i)
|
421
|
+
lat = payload[:latitude_i] * 0.0000001
|
422
|
+
payload[:latitude] = lat
|
423
|
+
end
|
424
|
+
|
425
|
+
if payload.keys.include?(:longitude_i)
|
426
|
+
lon = payload[:longitude_i] * 0.0000001
|
427
|
+
payload[:longitude] = lon
|
428
|
+
end
|
429
|
+
|
430
|
+
if payload.keys.include?(:macaddr)
|
431
|
+
mac_raw = payload[:macaddr]
|
432
|
+
mac_hex_arr = mac_raw.bytes.map { |byte| byte.to_s(16).rjust(2, '0') }
|
433
|
+
mac_hex_str = mac_hex_arr.join(':')
|
434
|
+
payload[:macaddr] = mac_hex_str
|
435
|
+
end
|
436
|
+
|
437
|
+
if payload.keys.include?(:time)
|
438
|
+
time_int = payload[:time]
|
439
|
+
if time_int.is_a?(Integer)
|
440
|
+
time_utc = Time.at(time_int).utc.to_s
|
441
|
+
payload[:time_utc] = time_utc
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
if gps_metadata && payload[:latitude] && payload[:longitude]
|
446
|
+
lat = payload[:latitude]
|
447
|
+
lon = payload[:longitude]
|
448
|
+
unless lat.zero? && lon.zero?
|
449
|
+
gps_search_resp = gps_search(lat: lat, lon: lon)
|
450
|
+
payload[:gps_metadata] = gps_search_resp
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
payload
|
455
|
+
rescue Encoding::CompatibilityError,
|
456
|
+
Google::Protobuf::ParseError
|
457
|
+
payload
|
458
|
+
rescue StandardError => e
|
459
|
+
raise e
|
460
|
+
end
|
461
|
+
|
313
462
|
# Author(s):: 0day Inc. <support@0dayinc.com>
|
314
463
|
|
315
464
|
public_class_method def self.authors
|
@@ -322,5 +471,12 @@ module Meshtastic
|
|
322
471
|
|
323
472
|
public_class_method def self.help
|
324
473
|
constants.sort
|
474
|
+
|
475
|
+
# puts "USAGE:
|
476
|
+
# #{self}.gps_search(
|
477
|
+
# lat: 'required - latitude float (e.g. 37.7749)',
|
478
|
+
# lon: 'required - longitude float (e.g. -122.4194)',
|
479
|
+
# )
|
480
|
+
# "
|
325
481
|
end
|
326
482
|
end
|
data/meshtastic.gemspec
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: meshtastic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.86
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 0day Inc.
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-02-03 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: bundler
|
@@ -127,14 +127,14 @@ dependencies:
|
|
127
127
|
requirements:
|
128
128
|
- - ">="
|
129
129
|
- !ruby/object:Gem::Version
|
130
|
-
version: 1.71.
|
130
|
+
version: 1.71.1
|
131
131
|
type: :runtime
|
132
132
|
prerelease: false
|
133
133
|
version_requirements: !ruby/object:Gem::Requirement
|
134
134
|
requirements:
|
135
135
|
- - ">="
|
136
136
|
- !ruby/object:Gem::Version
|
137
|
-
version: 1.71.
|
137
|
+
version: 1.71.1
|
138
138
|
- !ruby/object:Gem::Dependency
|
139
139
|
name: rubocop-rake
|
140
140
|
requirement: !ruby/object:Gem::Requirement
|