meshtastic 0.0.41 → 0.0.43

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94567b95fcf287b1a47b7af7ea3efb4b6f15a5a0daf81137127b6f5dede9a8fd
4
- data.tar.gz: aa07f4271ac1cb1953492ab508f2f8f4f2c7c0c51fb306195b096b950b917c25
3
+ metadata.gz: 105d223bd94e02d4473ac5fd66ed0b8dc7eef73d44578eb427fc3d55eb51ae21
4
+ data.tar.gz: 216a3957a439408579d1d7b48dd552d394885bbc09b8dc3410d776e4c1eb37d6
5
5
  SHA512:
6
- metadata.gz: 77093a3977ef63ad7c15d255c679771e5fe02448741147acbc608f19c057d9b9f8f47fe214e0f0a2799cca331726450f978bbda99248fb5d3f592e4d37b09a43
7
- data.tar.gz: 4c617b139c876db4b3fff9f4357fba3785972e47e88e85a9a9a1656db8c5ced40e42699b737aa7b84f3cc86ced3f66480a3def02e6e1a2272bdd23ac70d82858
6
+ metadata.gz: 1381a13cff943403ef269c5a349529ab9c2f12e3a3af5b3e88c589f7fd427a6e45b23543251449e1d520471fdf5f6c8a11c55c56bfc24553dc2b02db7ace28d9
7
+ data.tar.gz: 01d01863635a22c2d3c42ace2a34076c4094ece8ef9629f08ae0e8da7c0a98bbc5815db26e2e4063fa462619caf710938628a8cd086f62411d1cd885017665a4
data/Gemfile CHANGED
@@ -13,7 +13,7 @@ gemspec
13
13
  # to review these custom flags (e.g. pg, serialport, etc).
14
14
  gem 'bundler', '>=2.5.3'
15
15
  gem 'bundle-audit', '0.1.0'
16
- gem 'geocoder', '1.8.2'
16
+ gem 'geocoder', '1.8.3'
17
17
  gem 'google-protobuf', '3.21.12'
18
18
  gem 'mqtt', '0.6.0'
19
19
  gem 'rake', '13.2.1'
@@ -21,7 +21,7 @@ gem 'rdoc', '6.6.3.1'
21
21
  gem 'rspec', '3.13.0'
22
22
  gem 'rubocop', '1.63.4'
23
23
  gem 'rubocop-rake', '0.6.0'
24
- gem 'rubocop-rspec', '2.29.1'
24
+ gem 'rubocop-rspec', '2.29.2'
25
25
  gem 'rvm', '1.11.3.9'
26
26
  gem 'tty-prompt', '0.23.1'
27
27
  gem 'yard', '0.9.36'
@@ -63,6 +63,96 @@ module Meshtastic
63
63
  raise e
64
64
  end
65
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
119
+ # Unsure if this is the correct protobuf object
120
+ # decoder = Meshtastic::MqttClientProxyMessage
121
+ decoder = Meshtastic::Data
122
+ when :TELEMETRY_APP
123
+ decoder = Meshtastic::Telemetry
124
+ when :TRACEROUTE_APP
125
+ decoder = Meshtastic::RouteDiscovery
126
+ when :WAYPOINT_APP
127
+ decoder = Meshtastic::Waypoint
128
+ # when :ZPS_APP
129
+ # decoder = Meshtastic::Zps
130
+ end
131
+ payload = decoder.decode(payload).to_h
132
+ if payload.keys.include?(:latitude_i) && payload.keys.include?(:longitude_i)
133
+ lat = payload[:latitude_i] * 0.0000001
134
+ lon = payload[:longitude_i] * 0.0000001
135
+ payload[:latitude] = lat
136
+ payload[:longitude] = lon
137
+ if gps_metadata
138
+ gps_search_resp = Meshtastic.gps_search(lat: lat, lon: lon)
139
+ payload[:gps_metadata] = gps_search_resp
140
+ end
141
+ end
142
+
143
+ if payload.keys.include?(:macaddr)
144
+ mac_hex_arr = payload[:macaddr].bytes.map { |byte| byte.to_s(16).rjust(2, '0') }
145
+ mac_str = mac_hex_arr.join(':')
146
+ payload[:macaddr] = mac_str
147
+ end
148
+
149
+ payload
150
+ rescue Google::Protobuf::ParseError
151
+ payload
152
+ rescue StandardError => e
153
+ raise e
154
+ end
155
+
66
156
  # Supported Method Parameters::
67
157
  # Meshtastic::MQQT.subscribe(
68
158
  # mqtt_obj: 'required - mqtt_obj returned from #connect method'
@@ -72,7 +162,8 @@ module Meshtastic
72
162
  # psks: 'optional - hash of :channel => psk key value pairs (default: { LongFast: "AQ==" })',
73
163
  # qos: 'optional - quality of service (default: 0)',
74
164
  # filter: 'optional - comma-delimited string(s) to filter on in message (default: nil)',
75
- # gps_metadata: 'optional - include GPS metadata in output (default: false)'
165
+ # gps_metadata: 'optional - include GPS metadata in output (default: false)',
166
+ # include_raw: 'optional - include raw packet data in output (default: false)'
76
167
  # )
77
168
 
78
169
  public_class_method def self.subscribe(opts = {})
@@ -93,6 +184,7 @@ module Meshtastic
93
184
  json = opts[:json] ||= false
94
185
  filter = opts[:filter]
95
186
  gps_metadata = opts[:gps_metadata] ||= false
187
+ include_raw = opts[:include_raw] ||= false
96
188
 
97
189
  # NOTE: Use MQTT Explorer for topic discovery
98
190
  full_topic = "#{root_topic}/#{region}/#{channel}"
@@ -101,7 +193,7 @@ module Meshtastic
101
193
 
102
194
  filter_arr = filter.to_s.split(',').map(&:strip)
103
195
  mqtt_obj.get_packet do |packet_bytes|
104
- # raw_packet = packet_bytes.to_s.b
196
+ raw_packet = packet_bytes.to_s.b if include_raw
105
197
  raw_topic = packet_bytes.topic ||= ''
106
198
  raw_payload = packet_bytes.payload ||= ''
107
199
 
@@ -123,10 +215,10 @@ module Meshtastic
123
215
  message[:node_id_from] = "!#{message[:from].to_i.to_s(16)}"
124
216
  message[:node_id_to] = "!#{message[:to].to_i.to_s(16)}"
125
217
 
218
+ # If encrypted_message is not nil, then decrypt
219
+ # the message prior to decoding.
126
220
  encrypted_message = message[:encrypted]
127
- # If encrypted_message is not nil, then decrypt the message
128
221
  if encrypted_message.to_s.length.positive?
129
-
130
222
  packet_id = message[:id]
131
223
  packet_from = message[:from]
132
224
 
@@ -135,8 +227,8 @@ module Meshtastic
135
227
  nonce = "#{nonce_packet_id}#{nonce_from_node}".b
136
228
 
137
229
  psk = psks[:LongFast]
138
- target_chanel = decoded_payload_hash[:channel_id].to_s.to_sym
139
- psk = psks[target_chanel] if psks.keys.include?(target_chanel)
230
+ target_channel = decoded_payload_hash[:channel_id].to_s.to_sym
231
+ psk = psks[target_channel] if psks.keys.include?(target_channel)
140
232
  dec_psk = Base64.strict_decode64(psk)
141
233
 
142
234
  cipher = OpenSSL::Cipher.new('AES-128-CTR')
@@ -146,99 +238,22 @@ module Meshtastic
146
238
  cipher.iv = nonce
147
239
 
148
240
  decrypted = cipher.update(encrypted_message) + cipher.final
149
- message[:decrypted] = decrypted
241
+ message[:decoded] = Meshtastic::Data.decode(decrypted).to_h
242
+ message[:encrypted] = :decrypted
150
243
  end
151
244
 
152
245
  if message[:decoded]
246
+ # payload = Meshtastic::Data.decode(message[:decoded][:payload]).to_h
153
247
  payload = message[:decoded][:payload]
154
-
155
248
  msg_type = message[:decoded][:portnum]
156
- case msg_type
157
- when :ADMIN_APP
158
- pb_obj = Meshtastic::AdminMessage.decode(payload)
159
- when :ATAK_FORWARDER, :ATAK_PLUGIN
160
- pb_obj = Meshtastic::TAKPacket.decode(payload)
161
- # when :AUDIO_APP
162
- # pb_obj = Meshtastic::Audio.decode(payload)
163
- when :DETECTION_SENSOR_APP
164
- pb_obj = Meshtastic::DeviceState.decode(payload)
165
- # when :IP_TUNNEL_APP
166
- # pb_obj = Meshtastic::IpTunnel.decode(payload)
167
- when :MAP_REPORT_APP
168
- pb_obj = Meshtastic::MapReport.decode(payload)
169
- # when :MAX
170
- # pb_obj = Meshtastic::Max.decode(payload)
171
- when :NEIGHBORINFO_APP
172
- pb_obj = Meshtastic::NeighborInfo.decode(payload)
173
- when :NODEINFO_APP
174
- pb_obj = Meshtastic::User.decode(payload)
175
- when :PAXCOUNTER_APP
176
- pb_obj = Meshtastic::Paxcount.decode(payload)
177
- when :POSITION_APP
178
- pb_obj = Meshtastic::Position.decode(payload)
179
- # when :PRIVATE_APP
180
- # pb_obj = Meshtastic::Private.decode(payload)
181
- when :RANGE_TEST_APP
182
- # Unsure if this is the correct protobuf object
183
- pb_obj = Meshtastic::FromRadio.decode(payload)
184
- when :REMOTE_HARDWARE_APP
185
- pb_obj = Meshtastic::HardwareMessage.decode(payload)
186
- # when :REPLY_APP
187
- # pb_obj = Meshtastic::Reply.decode(payload)
188
- when :ROUTING_APP
189
- pb_obj = Meshtastic::Routing.decode(payload)
190
- when :SERIAL_APP
191
- pb_obj = Meshtastic::SerialConnectionStatus.decode(payload)
192
- when :SIMULATOR_APP,
193
- :TEXT_MESSAGE_COMPRESSED_APP
194
- # Unsure if this is the correct protobuf object
195
- # for TEXT_MESSAGE_COMPRESSED_APP
196
- pb_obj = Meshtastic::Compressed.decode(payload)
197
- when :STORE_FORWARD_APP
198
- pb_obj = Meshtastic::StoreAndForward.decode(payload)
199
- when :TEXT_MESSAGE_APP
200
- # Unsure if this is the correct protobuf object
201
- # pb_obj = Meshtastic::MqttClientProxyMessage.decode(payload)
202
- pb_obj = Meshtastic::Data.decode(payload)
203
- when :TELEMETRY_APP
204
- pb_obj = Meshtastic::Telemetry.decode(payload)
205
- when :TRACEROUTE_APP
206
- pb_obj = Meshtastic::RouteDiscovery.decode(payload)
207
- # when :UNKNOWN_APP
208
- # pb_obj = Meshtastic.Unknown.decode(payload)
209
- when :WAYPOINT_APP
210
- pb_obj = Meshtastic::Waypoint.decode(payload)
211
- # when :ZPS_APP
212
- # pb_obj = Meshtastic::Zps.decode(payload)
213
- else
214
- puts "WARNING: Unknown message type: #{msg_type}"
215
- end
216
- # Overwrite the payload with the decoded protobuf object
217
- # message[:decoded][:payload] = pb_obj.to_h unless msg_type == :TRACEROUTE_APP
218
- message[:decoded][:payload] = pb_obj.to_h
219
- if message[:decoded][:payload].keys.include?(:latitude_i) &&
220
- message[:decoded][:payload].keys.include?(:longitude_i) &&
221
- gps_metadata
222
-
223
- latitude = pb_obj.to_h[:latitude_i] * 0.0000001
224
- longitude = pb_obj.to_h[:longitude_i] * 0.0000001
225
- message[:decoded][:payload][:gps_metadata] = gps_search(
226
- lat: latitude,
227
- lon: longitude
228
- ).first.data
229
- end
230
-
231
- # If we there's a mac address, make it look like one.
232
- if message[:decoded][:payload].keys.include?(:macaddr)
233
- macaddr = message[:decoded][:payload][:macaddr]
234
- macaddr_fmt = macaddr.bytes.map { |byte| byte.to_s(16).rjust(2, '0') }.join(':')
235
- message[:decoded][:payload][:macaddr] = macaddr_fmt
236
- end
237
- # puts pb_obj.public_methods
238
- # message[:decoded][:pb_obj] = pb_obj
249
+ message[:decoded][:payload] = decode_payload(
250
+ payload: payload,
251
+ msg_type: msg_type,
252
+ gps_metadata: gps_metadata
253
+ )
239
254
  end
240
255
 
241
- # message[:raw_packet] = raw_packet if block_given?
256
+ message[:raw_packet] = raw_packet if include_raw
242
257
  decoded_payload_hash[:packet] = message
243
258
  unless block_given?
244
259
  message[:stdout] = 'pretty'
@@ -249,8 +264,11 @@ module Meshtastic
249
264
  ArgumentError => e
250
265
 
251
266
  message[:decrypted] = e.message if e.message.include?('key must be')
267
+ message[:decrypted] = 'unable to decrypt - psk?' if e.message.include?('occurred during parsing')
252
268
  decoded_payload_hash[:packet] = message
253
269
  unless block_given?
270
+ puts "WARNING: #{e.inspect} - MSG IS >>>"
271
+ # puts e.backtrace
254
272
  message[:stdout] = 'inspect'
255
273
  stdout_message = decoded_payload_hash.inspect
256
274
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Meshtastic
4
- VERSION = '0.0.41'
4
+ VERSION = '0.0.43'
5
5
  end
data/lib/meshtastic.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  # Plugin used to interact with Meshtastic nodes
4
4
  module Meshtastic
5
+ require 'base64'
5
6
  # Protocol Buffers for Meshtastic
6
7
  require 'meshtastic/admin_pb'
7
8
  require 'nanopb_pb'
@@ -25,6 +26,7 @@ module Meshtastic
25
26
  require 'meshtastic/telemetry_pb'
26
27
  require 'meshtastic/version'
27
28
  require 'meshtastic/xmodem_pb'
29
+ require 'openssl'
28
30
 
29
31
  autoload :Admin, 'meshtastic/admin'
30
32
  autoload :Apponly, 'meshtastic/apponly'
@@ -47,6 +49,191 @@ module Meshtastic
47
49
  autoload :Telemetry, 'meshtastic/telemetry'
48
50
  autoload :Xmodem, 'meshtastic/xmodem'
49
51
 
52
+ # Supported Method Parameters::
53
+ # Meshtastic.send_text(
54
+ # from_id: 'optional - Source ID (Default: 0)',
55
+ # dest_id: 'optional - Destination ID (Default: 0xFFFFFFFF)',
56
+ # text: 'optional - Text Message (Default: SYN)',
57
+ # want_ack: 'optional - Want Acknowledgement (Default: false)',
58
+ # want_response: 'optional - Want Response (Default: false)',
59
+ # hop_limit: 'optional - Hop Limit (Default: 3)',
60
+ # on_response: 'optional - Callback on Response',
61
+ # psk: 'optional - Pre-Shared Key if Encrypted (Default: nil)'
62
+ # )
63
+ public_class_method def self.send_text(opts = {})
64
+ # Send a text message to a node
65
+ from_id = opts[:from_id].to_i
66
+ dest_id = opts[:dest_id] ||= 0xFFFFFFFF
67
+ text = opts[:text] ||= 'SYN'
68
+ want_ack = opts[:want_ack] ||= false
69
+ want_response = opts[:want_response] ||= false
70
+ hop_limit = opts[:hop_limit] ||= 3
71
+ on_response = opts[:on_response]
72
+ psk = opts[:psk]
73
+
74
+ # TODO: verify text length validity
75
+ max_txt_len = Meshtastic::Constants::DATA_PAYLOAD_LEN
76
+ raise "ERROR: Text Length > #{max_txt_len} Bytes" if text.length > max_txt_len
77
+
78
+ port_num = Meshtastic::PortNum::TEXT_MESSAGE_APP
79
+
80
+ data = Meshtastic::Data.new
81
+ data.payload = text
82
+ data.portnum = port_num
83
+ data.want_response = want_response
84
+ puts data.to_h
85
+
86
+ send_data(
87
+ from_id: from_id,
88
+ dest_id: dest_id,
89
+ data: data,
90
+ want_ack: want_ack,
91
+ want_response: want_response,
92
+ hop_limit: hop_limit,
93
+ port_num: port_num,
94
+ on_response: on_response,
95
+ psk: psk
96
+ )
97
+ rescue StandardError => e
98
+ raise e
99
+ end
100
+
101
+ # Supported Method Parameters::
102
+ # Meshtastic.send_data(
103
+ # from_id: 'optional - Source ID (Default: 0)',
104
+ # dest_id: 'optional - Destination ID (Default: 0xFFFFFFFF)',
105
+ # data: 'required - Data to Send',
106
+ # want_ack: 'optional - Want Acknowledgement (Default: false)',
107
+ # hop_limit: 'optional - Hop Limit (Default: 3)',
108
+ # port_num: 'optional - (Default: Meshtastic::PortNum::PRIVATE_APP)',
109
+ # psk: 'optional - Pre-Shared Key if Encrypted (Default: nil)'
110
+ # )
111
+ public_class_method def self.send_data(opts = {})
112
+ # Send a text message to a node
113
+ from_id = opts[:from_id].to_i
114
+ dest_id = opts[:dest_id] ||= 0xFFFFFFFF
115
+ data = opts[:data]
116
+ want_ack = opts[:want_ack] ||= false
117
+ hop_limit = opts[:hop_limit] ||= 3
118
+ port_num = opts[:port_num] ||= Meshtastic::PortNum::PRIVATE_APP
119
+ max_port_num = Meshtastic::PortNum::MAX
120
+ raise "ERROR: Invalid port_num" unless port_num.positive? && port_num < max_port_num
121
+
122
+ psk = opts[:psk]
123
+
124
+ data_len = data.payload.length
125
+ max_len = Meshtastic::Constants::DATA_PAYLOAD_LEN
126
+ raise "ERROR: Data Length > #{max_len} Bytes" if data_len > max_len
127
+
128
+ mesh_packet = Meshtastic::MeshPacket.new
129
+ mesh_packet.decoded = data
130
+
131
+ send_packet(
132
+ mesh_packet: mesh_packet,
133
+ from_id: from_id,
134
+ dest_id: dest_id,
135
+ want_ack: want_ack,
136
+ hop_limit: hop_limit,
137
+ psk: psk
138
+ )
139
+ rescue StandardError => e
140
+ raise e
141
+ end
142
+
143
+ # Supported Method Parameters::
144
+ # Meshtastic.send_packet(
145
+ # mesh_packet: 'required - Mesh Packet to Send',
146
+ # from_id: 'optional - Source ID (Default: 0)',
147
+ # dest_id: 'optional - Destination ID (Default: 0xFFFFFFFF)',
148
+ # want_ack: 'optional - Want Acknowledgement (Default: false)',
149
+ # hop_limit: 'optional - Hop Limit (Default: 3)',
150
+ # psk: 'optional - Pre-Shared Key if Encrypted (Default: nil)'
151
+ # )
152
+ public_class_method def self.send_packet(opts = {})
153
+ mesh_packet = opts[:mesh_packet]
154
+ from_id = opts[:from_id] ||= 0
155
+ dest_id = opts[:dest_id] ||= 0xFFFFFFFF
156
+ want_ack = opts[:want_ack] ||= false
157
+ hop_limit = opts[:hop_limit] ||= 3
158
+ psk = opts[:psk]
159
+
160
+ # my_info = Meshtastic::FromRadio.my_info
161
+ # wait_connected if dest_id != my_info.my_node_num && my_info.is_a(Meshtastic::Deviceonly::MyInfo)
162
+
163
+ node_num = dest_id
164
+ node_num_hex = dest_id.bytes.map { |b| b.to_s(16).rjust(2, '0') }.join if dest_id.is_a?(String)
165
+ node_num = node_num_hex.to_i(16) if node_num_hex
166
+
167
+ mesh_packet.from = from_id
168
+ mesh_packet.to = node_num
169
+ mesh_packet.want_ack = want_ack
170
+ mesh_packet.hop_limit = hop_limit
171
+
172
+ mesh_packet.id = generate_packet_id if mesh_packet.id.zero?
173
+
174
+ if psk
175
+ nonce_packet_id = [mesh_packet.id].pack('V').ljust(8, "\x00")
176
+ nonce_from_node = [from_id].pack('V').ljust(8, "\x00")
177
+ nonce = "#{nonce_packet_id}#{nonce_from_node}".b
178
+
179
+ dec_psk = Base64.strict_decode64(psk)
180
+ cipher = OpenSSL::Cipher.new('AES-128-CTR')
181
+ cipher = OpenSSL::Cipher.new('AES-256-CTR') if dec_psk.length == 32
182
+ cipher.encrypt
183
+ cipher.key = dec_psk
184
+ cipher.iv = nonce
185
+
186
+ decrypted_payload = mesh_packet.decoded.to_s
187
+ encrypted_payload = cipher.update(decrypted_payload) + cipher.final
188
+
189
+ mesh_packet.encrypted = encrypted_payload
190
+ end
191
+ # puts mesh_packet.to_h
192
+
193
+ # to_radio = Meshtastic::ToRadio.new
194
+ # to_radio.packet = mesh_packet
195
+ # send_to_radio(to_radio: to_radio)
196
+
197
+ mesh_packet
198
+ rescue StandardError => e
199
+ raise e
200
+ end
201
+
202
+ # Supported Method Parameters::
203
+ # packet_id = Meshtastic.generate_packet_id(
204
+ # last_packet_id: 'optional - Last Packet ID (Default: 0)'
205
+ # )
206
+ public_class_method def self.generate_packet_id(opts = {})
207
+ last_packet_id = opts[:last_packet_id] ||= 0
208
+
209
+ packet_id = last_packet_id + 1 if last_packet_id.positive?
210
+ packet_id = rand(2**32) if last_packet_id.zero?
211
+
212
+ packet_id
213
+ end
214
+
215
+ # Supported Method Parameters::
216
+ # Meshtastic.send_to_radio(
217
+ # to_radio: 'required - ToRadio Message to Send'
218
+ # )
219
+ public_class_method def self.send_to_radio(opts = {})
220
+ to_radio = opts[:to_radio]
221
+
222
+ raise 'ERROR: Invalid ToRadio Message' unless to_radio.is_a?(Meshtastic::ToRadio)
223
+
224
+ to_radio.to_proto
225
+ rescue StandardError => e
226
+ raise e
227
+ end
228
+
229
+ # Author(s):: 0day Inc. <support@0dayinc.com>
230
+
231
+ public_class_method def self.authors
232
+ "AUTHOR(S):
233
+ 0day Inc. <support@0dayinc.com>
234
+ "
235
+ end
236
+
50
237
  # Display a List of Every Meshtastic Module
51
238
 
52
239
  public_class_method def self.help
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meshtastic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.41
4
+ version: 0.0.43
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-02 00:00:00.000000000 Z
11
+ date: 2024-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - '='
46
46
  - !ruby/object:Gem::Version
47
- version: 1.8.2
47
+ version: 1.8.3
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - '='
53
53
  - !ruby/object:Gem::Version
54
- version: 1.8.2
54
+ version: 1.8.3
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: google-protobuf
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -156,14 +156,14 @@ dependencies:
156
156
  requirements:
157
157
  - - '='
158
158
  - !ruby/object:Gem::Version
159
- version: 2.29.1
159
+ version: 2.29.2
160
160
  type: :runtime
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
164
  - - '='
165
165
  - !ruby/object:Gem::Version
166
- version: 2.29.1
166
+ version: 2.29.2
167
167
  - !ruby/object:Gem::Dependency
168
168
  name: rvm
169
169
  requirement: !ruby/object:Gem::Requirement