Module: Meshtastic

Defined in:
lib/meshtastic.rb,
lib/meshtastic/atak.rb,
lib/meshtastic/mesh.rb,
lib/meshtastic/mqtt.rb,
lib/meshtastic/admin.rb,
lib/meshtastic/rtttl.rb,
lib/meshtastic/config.rb,
lib/meshtastic/xmodem.rb,
lib/meshtastic/apponly.rb,
lib/meshtastic/atak_pb.rb,
lib/meshtastic/channel.rb,
lib/meshtastic/mesh_pb.rb,
lib/meshtastic/mqtt_pb.rb,
lib/meshtastic/version.rb,
lib/meshtastic/admin_pb.rb,
lib/meshtastic/paxcount.rb,
lib/meshtastic/portnums.rb,
lib/meshtastic/rtttl_pb.rb,
lib/meshtastic/config_pb.rb,
lib/meshtastic/localonly.rb,
lib/meshtastic/telemetry.rb,
lib/meshtastic/xmodem_pb.rb,
lib/meshtastic/apponly_pb.rb,
lib/meshtastic/channel_pb.rb,
lib/meshtastic/clientonly.rb,
lib/meshtastic/deviceonly.rb,
lib/meshtastic/paxcount_pb.rb,
lib/meshtastic/portnums_pb.rb,
lib/meshtastic/localonly_pb.rb,
lib/meshtastic/storeforward.rb,
lib/meshtastic/telemetry_pb.rb,
lib/meshtastic/clientonly_pb.rb,
lib/meshtastic/deviceonly_pb.rb,
lib/meshtastic/module_config.rb,
lib/meshtastic/cannedmessages.rb,
lib/meshtastic/remote_hardware.rb,
lib/meshtastic/storeforward_pb.rb,
lib/meshtastic/module_config_pb.rb,
lib/meshtastic/cannedmessages_pb.rb,
lib/meshtastic/connection_status.rb,
lib/meshtastic/remote_hardware_pb.rb,
lib/meshtastic/connection_status_pb.rb

Overview

Plugin used to interact with Meshtastic nodes

Defined Under Namespace

Modules: ATAK, Admin, Apponly, Cannedmessages, Channel, Clientonly, Config, ConnectionStatus, Deviceonly, Localonly, MQTT, Mesh, ModuleConfig, Paxcount, Portnums, RTTTL, RemoteHardware, Storeforward, Telemetry, Xmodem

Constant Summary collapse

TAKPacket =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.TAKPacket").msgclass
GeoChat =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.GeoChat").msgclass
Group =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Group").msgclass
Status =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Status").msgclass
Contact =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Contact").msgclass
PLI =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.PLI").msgclass
Team =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Team").enummodule
MemberRole =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.MemberRole").enummodule
Position =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Position").msgclass
User =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.User").msgclass
RouteDiscovery =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.RouteDiscovery").msgclass
Routing =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Routing").msgclass
Data =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Data").msgclass
Waypoint =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Waypoint").msgclass
MqttClientProxyMessage =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.MqttClientProxyMessage").msgclass
MeshPacket =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.MeshPacket").msgclass
NodeInfo =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.NodeInfo").msgclass
MyNodeInfo =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.MyNodeInfo").msgclass
LogRecord =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.LogRecord").msgclass
QueueStatus =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.QueueStatus").msgclass
FromRadio =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.FromRadio").msgclass
ToRadio =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.ToRadio").msgclass
Compressed =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Compressed").msgclass
NeighborInfo =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.NeighborInfo").msgclass
Neighbor =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Neighbor").msgclass
DeviceMetadata =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.DeviceMetadata").msgclass
Heartbeat =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Heartbeat").msgclass
NodeRemoteHardwarePin =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.NodeRemoteHardwarePin").msgclass
HardwareModel =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.HardwareModel").enummodule
Constants =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Constants").enummodule
CriticalErrorCode =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.CriticalErrorCode").enummodule
ServiceEnvelope =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.ServiceEnvelope").msgclass
MapReport =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.MapReport").msgclass
VERSION =
'0.0.43'
AdminMessage =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.AdminMessage").msgclass
HamParameters =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.HamParameters").msgclass
NodeRemoteHardwarePinsResponse =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.NodeRemoteHardwarePinsResponse").msgclass
RTTTLConfig =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.RTTTLConfig").msgclass
XModem =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.XModem").msgclass
ChannelSet =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.ChannelSet").msgclass
ChannelSettings =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.ChannelSettings").msgclass
ModuleSettings =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.ModuleSettings").msgclass
PortNum =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.PortNum").enummodule
LocalConfig =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.LocalConfig").msgclass
LocalModuleConfig =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.LocalModuleConfig").msgclass
DeviceMetrics =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.DeviceMetrics").msgclass
EnvironmentMetrics =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.EnvironmentMetrics").msgclass
PowerMetrics =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.PowerMetrics").msgclass
AirQualityMetrics =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.AirQualityMetrics").msgclass
TelemetrySensorType =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.TelemetrySensorType").enummodule
DeviceProfile =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.DeviceProfile").msgclass
PositionLite =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.PositionLite").msgclass
NodeInfoLite =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.NodeInfoLite").msgclass
DeviceState =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.DeviceState").msgclass
ChannelFile =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.ChannelFile").msgclass
OEMStore =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.OEMStore").msgclass
ScreenFonts =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.ScreenFonts").enummodule
StoreAndForward =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.StoreAndForward").msgclass
RemoteHardwarePin =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.RemoteHardwarePin").msgclass
RemoteHardwarePinType =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.RemoteHardwarePinType").enummodule
CannedMessageModuleConfig =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.CannedMessageModuleConfig").msgclass
HardwareMessage =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.HardwareMessage").msgclass
DeviceConnectionStatus =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.DeviceConnectionStatus").msgclass
WifiConnectionStatus =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.WifiConnectionStatus").msgclass
EthernetConnectionStatus =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.EthernetConnectionStatus").msgclass
NetworkConnectionStatus =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.NetworkConnectionStatus").msgclass
BluetoothConnectionStatus =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.BluetoothConnectionStatus").msgclass
SerialConnectionStatus =
::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.SerialConnectionStatus").msgclass

Class Method Summary collapse

Class Method Details

.authorsObject

Author(s)

0day Inc. <[email protected]>



231
232
233
234
235
# File 'lib/meshtastic.rb', line 231

public_class_method def self.authors
  "AUTHOR(S):
    0day Inc. <[email protected]>
  "
end

.generate_packet_id(opts = {}) ⇒ Object

Supported Method Parameters

packet_id = Meshtastic.generate_packet_id(

last_packet_id: 'optional - Last Packet ID (Default: 0)'

)



206
207
208
209
210
211
212
213
# File 'lib/meshtastic.rb', line 206

public_class_method def self.generate_packet_id(opts = {})
  last_packet_id = opts[:last_packet_id] ||= 0

  packet_id = last_packet_id + 1 if last_packet_id.positive?
  packet_id = rand(2**32) if last_packet_id.zero?

  packet_id
end

.helpObject

Display a List of Every Meshtastic Module



239
240
241
# File 'lib/meshtastic.rb', line 239

public_class_method def self.help
  constants.sort
end

.send_data(opts = {}) ⇒ Object

Supported Method Parameters

Meshtastic.send_data(

from_id: 'optional - Source ID (Default: 0)',
dest_id: 'optional - Destination ID (Default: 0xFFFFFFFF)',
data: 'required - Data to Send',
want_ack: 'optional - Want Acknowledgement (Default: false)',
hop_limit: 'optional - Hop Limit (Default: 3)',
port_num: 'optional - (Default: Meshtastic::PortNum::PRIVATE_APP)',
psk: 'optional - Pre-Shared Key if Encrypted (Default: nil)'

)



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/meshtastic.rb', line 111

public_class_method def self.send_data(opts = {})
  # Send a text message to a node
  from_id = opts[:from_id].to_i
  dest_id = opts[:dest_id] ||= 0xFFFFFFFF
  data = opts[:data]
  want_ack = opts[:want_ack] ||= false
  hop_limit = opts[:hop_limit] ||= 3
  port_num = opts[:port_num] ||= Meshtastic::PortNum::PRIVATE_APP
  max_port_num = Meshtastic::PortNum::MAX
  raise "ERROR: Invalid port_num" unless port_num.positive? && port_num < max_port_num

  psk = opts[:psk]

  data_len = data.payload.length
  max_len = Meshtastic::Constants::DATA_PAYLOAD_LEN
  raise "ERROR: Data Length > #{max_len} Bytes" if data_len > max_len

  mesh_packet = Meshtastic::MeshPacket.new
  mesh_packet.decoded = data

  send_packet(
    mesh_packet: mesh_packet,
    from_id: from_id,
    dest_id: dest_id,
    want_ack: want_ack,
    hop_limit: hop_limit,
    psk: psk
  )
rescue StandardError => e
  raise e
end

.send_packet(opts = {}) ⇒ Object

Supported Method Parameters

Meshtastic.send_packet(

mesh_packet: 'required - Mesh Packet to Send',
from_id: 'optional - Source ID (Default: 0)',
dest_id: 'optional - Destination ID (Default: 0xFFFFFFFF)',
want_ack: 'optional - Want Acknowledgement (Default: false)',
hop_limit: 'optional - Hop Limit (Default: 3)',
psk: 'optional - Pre-Shared Key if Encrypted (Default: nil)'

)



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/meshtastic.rb', line 152

public_class_method def self.send_packet(opts = {})
  mesh_packet = opts[:mesh_packet]
  from_id = opts[:from_id] ||= 0
  dest_id = opts[:dest_id] ||= 0xFFFFFFFF
  want_ack = opts[:want_ack] ||= false
  hop_limit = opts[:hop_limit] ||= 3
  psk = opts[:psk]

  # my_info = Meshtastic::FromRadio.my_info
  # wait_connected if dest_id != my_info.my_node_num && my_info.is_a(Meshtastic::Deviceonly::MyInfo)
  
  node_num = dest_id
  node_num_hex = dest_id.bytes.map { |b| b.to_s(16).rjust(2, '0') }.join if dest_id.is_a?(String)
  node_num = node_num_hex.to_i(16) if node_num_hex

  mesh_packet.from = from_id
  mesh_packet.to = node_num
  mesh_packet.want_ack = want_ack
  mesh_packet.hop_limit = hop_limit

  mesh_packet.id = generate_packet_id if mesh_packet.id.zero?

  if psk
    nonce_packet_id = [mesh_packet.id].pack('V').ljust(8, "\x00")
    nonce_from_node = [from_id].pack('V').ljust(8, "\x00")
    nonce = "#{nonce_packet_id}#{nonce_from_node}".b

    dec_psk = Base64.strict_decode64(psk)
    cipher = OpenSSL::Cipher.new('AES-128-CTR')
    cipher = OpenSSL::Cipher.new('AES-256-CTR') if dec_psk.length == 32
    cipher.encrypt
    cipher.key = dec_psk
    cipher.iv = nonce

    decrypted_payload = mesh_packet.decoded.to_s
    encrypted_payload = cipher.update(decrypted_payload) + cipher.final

    mesh_packet.encrypted = encrypted_payload
  end
  # puts mesh_packet.to_h

  # to_radio = Meshtastic::ToRadio.new
  # to_radio.packet = mesh_packet
  # send_to_radio(to_radio: to_radio)

  mesh_packet
rescue StandardError => e
  raise e
end

.send_text(opts = {}) ⇒ Object

Supported Method Parameters

Meshtastic.send_text(

from_id: 'optional - Source ID (Default: 0)',
dest_id: 'optional - Destination ID (Default: 0xFFFFFFFF)',
text: 'optional - Text Message (Default: SYN)',
want_ack: 'optional - Want Acknowledgement (Default: false)',
want_response: 'optional - Want Response (Default: false)',
hop_limit: 'optional - Hop Limit (Default: 3)',
on_response: 'optional - Callback on Response',
psk: 'optional - Pre-Shared Key if Encrypted (Default: nil)'

)



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/meshtastic.rb', line 63

public_class_method def self.send_text(opts = {})
  # Send a text message to a node
  from_id = opts[:from_id].to_i
  dest_id = opts[:dest_id] ||= 0xFFFFFFFF
  text = opts[:text] ||= 'SYN'
  want_ack = opts[:want_ack] ||= false
  want_response = opts[:want_response] ||= false
  hop_limit = opts[:hop_limit] ||= 3
  on_response = opts[:on_response]
  psk = opts[:psk]
  
  # TODO: verify text length validity
  max_txt_len = Meshtastic::Constants::DATA_PAYLOAD_LEN
  raise "ERROR: Text Length > #{max_txt_len} Bytes" if text.length > max_txt_len

  port_num = Meshtastic::PortNum::TEXT_MESSAGE_APP

  data = Meshtastic::Data.new
  data.payload = text
  data.portnum = port_num
  data.want_response = want_response
  puts data.to_h

  send_data(
    from_id: from_id,
    dest_id: dest_id,
    data: data,
    want_ack: want_ack,
    want_response: want_response,
    hop_limit: hop_limit,
    port_num: port_num,
    on_response: on_response,
    psk: psk
  )
rescue StandardError => e
  raise e
end

.send_to_radio(opts = {}) ⇒ Object

Supported Method Parameters

Meshtastic.send_to_radio(

to_radio: 'required - ToRadio Message to Send'

)



219
220
221
222
223
224
225
226
227
# File 'lib/meshtastic.rb', line 219

public_class_method def self.send_to_radio(opts = {})
  to_radio = opts[:to_radio]

  raise 'ERROR: Invalid ToRadio Message' unless to_radio.is_a?(Meshtastic::ToRadio)

  to_radio.to_proto
rescue StandardError => e
  raise e
end