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
@@ -3,4 +3,83 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Admin do
6
+ def fake_serial_obj
7
+ written = +''.b
8
+ serial_conn = Object.new
9
+ serial_conn.define_singleton_method(:write) do |b|
10
+ written << b
11
+ b.bytesize
12
+ end
13
+ serial_conn.define_singleton_method(:flush) { true }
14
+ serial_conn.define_singleton_method(:closed?) { false }
15
+ serial_conn.define_singleton_method(:close) { true }
16
+ { serial_conn: serial_conn, written: written, my_node_num: 0xb0b }
17
+ end
18
+
19
+ def decode_admin(serial_obj)
20
+ frame = serial_obj[:written]
21
+ body = frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))
22
+ packet = Meshtastic::ToRadio.decode(body).packet
23
+ [packet, Meshtastic::AdminMessage.decode(packet.decoded.payload)]
24
+ end
25
+
26
+ it 'sends a reboot AdminMessage on ADMIN_APP' do
27
+ serial_obj = fake_serial_obj
28
+ described_class.reboot(serial_obj: serial_obj, seconds: 7)
29
+ packet, admin = decode_admin(serial_obj)
30
+ expect(packet.decoded.portnum).to eq(:ADMIN_APP)
31
+ expect(admin.reboot_seconds).to eq(7)
32
+ end
33
+
34
+ it 'sends a set_owner AdminMessage' do
35
+ serial_obj = fake_serial_obj
36
+ described_class.set_owner(serial_obj: serial_obj, long_name: 'Test Node', short_name: 'TN')
37
+ _packet, admin = decode_admin(serial_obj)
38
+ expect(admin.set_owner.long_name).to eq('Test Node')
39
+ expect(admin.set_owner.short_name).to eq('TN')
40
+ end
41
+
42
+ it 'covers remaining AdminMessage request fields' do
43
+ serial_obj = fake_serial_obj
44
+ examples = {
45
+ get_module_config: %i[get_module_config_request MQTT_CONFIG],
46
+ get_canned_messages: [:get_canned_message_module_messages_request, true],
47
+ get_device_metadata: [:get_device_metadata_request, true],
48
+ get_ringtone: [:get_ringtone_request, true],
49
+ get_device_connection_status: [:get_device_connection_status_request, true],
50
+ get_node_remote_hardware_pins: [:get_node_remote_hardware_pins_request, true],
51
+ get_ui_config: [:get_ui_config_request, true],
52
+ enter_dfu: [:enter_dfu_mode_request, true],
53
+ begin_edit: [:begin_edit_settings, true],
54
+ commit_edit: [:commit_edit_settings, true],
55
+ remove_fixed_position: [:remove_fixed_position, true],
56
+ exit_simulator: [:exit_simulator, true],
57
+ nodedb_reset: [:nodedb_reset, true]
58
+ }
59
+ examples.each do |meth, (field, expected)|
60
+ serial_obj[:written].clear
61
+ described_class.public_send(meth, serial_obj: serial_obj)
62
+ _packet, admin = decode_admin(serial_obj)
63
+ expect(admin.public_send(field)).to eq(expected), meth.to_s
64
+ end
65
+ end
66
+
67
+ it 'sends factory resets, file delete, favorites, and edit transactions' do
68
+ serial_obj = fake_serial_obj
69
+ described_class.factory_reset_config(serial_obj: serial_obj)
70
+ expect(decode_admin(serial_obj).last.factory_reset_config).to eq(1)
71
+ serial_obj[:written].clear
72
+ described_class.factory_reset_device(serial_obj: serial_obj)
73
+ expect(decode_admin(serial_obj).last.factory_reset_device).to eq(1)
74
+ serial_obj[:written].clear
75
+ described_class.delete_file(serial_obj: serial_obj, path: '/prefs.json')
76
+ expect(decode_admin(serial_obj).last.delete_file_request).to eq('/prefs.json')
77
+ serial_obj[:written].clear
78
+ described_class.set_favorite_node(serial_obj: serial_obj, node_num: 0xb0b)
79
+ expect(decode_admin(serial_obj).last.set_favorite_node).to eq(0xb0b)
80
+ end
81
+
82
+ it 'prints usage without raising' do
83
+ expect { described_class.help }.to output(/USAGE/).to_stdout
84
+ end
6
85
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::ApponlyPB do
5
+ describe Meshtastic::ChannelSet do
6
6
  end
@@ -3,4 +3,8 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Apponly do
6
+ it 'round-trips a ChannelSet' do
7
+ set = described_class.encode
8
+ expect(described_class.decode(bytes: set.to_proto)).to be_a(Meshtastic::ChannelSet)
9
+ end
6
10
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::ATAKPB do
5
+ describe Meshtastic::TAKPacket do
6
6
  end
@@ -3,4 +3,151 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::ATAK do
6
+ def fake_serial_obj
7
+ written = +''.b
8
+ serial_conn = Object.new
9
+ serial_conn.define_singleton_method(:write) do |b|
10
+ written << b
11
+ b.bytesize
12
+ end
13
+ serial_conn.define_singleton_method(:flush) { true }
14
+ serial_conn.define_singleton_method(:closed?) { false }
15
+ serial_conn.define_singleton_method(:close) { true }
16
+ { serial_conn: serial_conn, written: written, my_node_num: 0xb0b }
17
+ end
18
+
19
+ def decode_to_radio(serial_obj)
20
+ frame = serial_obj[:written]
21
+ body = frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))
22
+ Meshtastic::ToRadio.decode(body).packet
23
+ end
24
+
25
+ it 'encodes V1 GeoChat with contact, group, and status' do
26
+ packet = described_class.encode_v1(
27
+ message: 'ATAK chat',
28
+ to: 'ANDROID-aabbccdd',
29
+ callsign: 'ALPHA',
30
+ device_callsign: 'RADIO-1',
31
+ team: :Cyan,
32
+ role: :TeamMember,
33
+ battery: 87
34
+ )
35
+ expect(packet).to be_a(Meshtastic::TAKPacket)
36
+ expect(packet.chat.message).to eq('ATAK chat')
37
+ expect(packet.chat.to).to eq('ANDROID-aabbccdd')
38
+ expect(packet.contact.callsign).to eq('ALPHA')
39
+ expect(packet.group.team).to eq(:Cyan)
40
+ expect(packet.group.role).to eq(:TeamMember)
41
+ expect(packet.status.battery).to eq(87)
42
+ end
43
+
44
+ it 'encodes V1 PLI with 1e7-scaled coordinates' do
45
+ packet = described_class.encode_v1(
46
+ lat: 37.7749,
47
+ lon: -122.4194,
48
+ altitude: 12,
49
+ speed: 3,
50
+ course: 90
51
+ )
52
+ expect(packet.pli.latitude_i).to eq(377_749_000)
53
+ expect(packet.pli.longitude_i).to eq(-1_224_194_000)
54
+ expect(packet.pli.altitude).to eq(12)
55
+ expect(packet.pli.speed).to eq(3)
56
+ expect(packet.pli.course).to eq(90)
57
+ end
58
+
59
+ it 'sends V1 GeoChat on ATAK_PLUGIN' do
60
+ serial_obj = fake_serial_obj
61
+ described_class.send_chat(serial_obj: serial_obj, message: 'ATAK chat')
62
+ packet = decode_to_radio(serial_obj)
63
+ expect(packet.decoded.portnum).to eq(:ATAK_PLUGIN)
64
+ tak = Meshtastic::TAKPacket.decode(packet.decoded.payload)
65
+ expect(tak.chat.message).to eq('ATAK chat')
66
+ end
67
+
68
+ it 'sends V1 PLI on ATAK_PLUGIN' do
69
+ serial_obj = fake_serial_obj
70
+ described_class.send_pli(serial_obj: serial_obj, lat: 37.7749, lon: -122.4194)
71
+ packet = decode_to_radio(serial_obj)
72
+ expect(packet.decoded.portnum).to eq(:ATAK_PLUGIN)
73
+ tak = Meshtastic::TAKPacket.decode(packet.decoded.payload)
74
+ expect(tak.pli.latitude_i).to eq(377_749_000)
75
+ end
76
+
77
+ it 'encodes uncompressed V2 GeoChat wire frames with flags 0xFF' do
78
+ wire = described_class.encode_v2(
79
+ callsign: 'ALPHA',
80
+ team: :Cyan,
81
+ role: :TeamMember,
82
+ lat: 37.7749,
83
+ lon: -122.4194,
84
+ message: 'v2 chat'
85
+ )
86
+ expect(wire.getbyte(0)).to eq(0xFF)
87
+ v2 = Meshtastic::TAKPacketV2.decode(wire.byteslice(1..))
88
+ expect(v2.chat.message).to eq('v2 chat')
89
+ expect(v2.callsign).to eq('ALPHA')
90
+ expect(v2.latitude_i).to eq(377_749_000)
91
+ end
92
+
93
+ it 'round-trips V2 typed payloads' do
94
+ {
95
+ aircraft: Meshtastic::AircraftTrack.new(icao: 'ABC123', flight: 'N1'),
96
+ shape: Meshtastic::DrawnShape.new(kind: :Kind_Circle, major_cm: 1000),
97
+ marker: Meshtastic::Marker.new(kind: :Kind_Spot),
98
+ route: Meshtastic::Route.new(prefix: 'R1'),
99
+ casevac: Meshtastic::CasevacReport.new(title: 'CASEVAC'),
100
+ emergency: Meshtastic::EmergencyAlert.new(type: :Type_Alert911),
101
+ task: Meshtastic::TaskRequest.new(task_type: 'recon', note: 'look'),
102
+ taktalk: Meshtastic::TakTalkMessage.new(text: 'voice', chatroom_id: 'room1'),
103
+ taktalk_room: Meshtastic::TakTalkRoomData.new(room_id: 'room1', room_name: 'Ops'),
104
+ rab: Meshtastic::RangeAndBearing.new(range_cm: 500)
105
+ }.each do |field, value|
106
+ v2 = described_class.build_v2(field => value, callsign: 'ALPHA')
107
+ expect(v2.public_send(field)).to eq(value)
108
+ decoded = described_class.decode_v2(wire: described_class.wrap_v2(packet: v2))
109
+ expect(decoded.public_send(field).to_h).to eq(value.to_h)
110
+ end
111
+ end
112
+
113
+ it 'sends V2 packets on ATAK_PLUGIN_V2' do
114
+ serial_obj = fake_serial_obj
115
+ described_class.send_v2(serial_obj: serial_obj, message: 'v2 chat', callsign: 'ALPHA')
116
+ packet = decode_to_radio(serial_obj)
117
+ expect(packet.decoded.portnum).to eq(:ATAK_PLUGIN_V2)
118
+ decoded = described_class.decode_v2(payload: packet.decoded.payload)
119
+ expect(decoded.chat.message).to eq('v2 chat')
120
+ end
121
+
122
+ it 'zlib-compresses CoT XML on ATAK_FORWARDER' do
123
+ serial_obj = fake_serial_obj
124
+ cot = '<event type="b-m-p-s-m" uid="marker-1"><point lat="37.77" lon="-122.41"/></event>'
125
+ described_class.send_cot(serial_obj: serial_obj, cot: cot)
126
+ packet = decode_to_radio(serial_obj)
127
+ expect(packet.decoded.portnum).to eq(:ATAK_FORWARDER)
128
+ xml = described_class.decompress_cot(payload: packet.decoded.payload)
129
+ expect(xml).to include('marker-1')
130
+ end
131
+
132
+ it 'decodes inbound payloads by portnum' do
133
+ v1 = described_class.encode_v1(message: 'hi')
134
+ expect(described_class.decode(payload: v1.to_proto, portnum: :ATAK_PLUGIN).chat.message).to eq('hi')
135
+
136
+ v2 = described_class.encode_v2(message: 'v2')
137
+ expect(described_class.decode(payload: v2, portnum: :ATAK_PLUGIN_V2).chat.message).to eq('v2')
138
+
139
+ cot = described_class.compress_cot(cot: '<event uid="x"/>')
140
+ expect(described_class.decode(payload: cot, portnum: :ATAK_FORWARDER)).to include('uid="x"')
141
+ end
142
+
143
+ it 'keeps send as a V1 GeoChat alias' do
144
+ serial_obj = fake_serial_obj
145
+ described_class.send(serial_obj: serial_obj, message: 'ATAK chat')
146
+ packet = decode_to_radio(serial_obj)
147
+ expect(packet.decoded.portnum).to eq(:ATAK_PLUGIN)
148
+ end
149
+
150
+ it 'prints usage without raising' do
151
+ expect { described_class.help }.to output(/ATAK_PLUGIN_V2/).to_stdout
152
+ end
6
153
  end
@@ -136,7 +136,7 @@ describe Meshtastic::Bluetooth do
136
136
 
137
137
  it 'scans with the selected adapter and bounded discovery timeout' do
138
138
  devices = [{ address: 'AA:BB:CC:DD:EE:FF', name: 'Meshtastic_test', paired: true }]
139
- expect(described_class::BlueZ).to receive(:scan).with(adapter: 'hci1', timeout: 2).and_return(devices)
139
+ expect(described_class::BlueZ).to receive(:scan).with({ adapter: 'hci1', timeout: 2 }).and_return(devices)
140
140
  expect(described_class.scan(adapter: 'hci1', timeout: 2)).to eq(devices)
141
141
  end
142
142
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::CannedmessagesPB do
5
+ describe Meshtastic::CannedMessageModuleConfig do
6
6
  end
@@ -3,4 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Cannedmessages do
6
+ it 'encodes canned message lines' do
7
+ expect(described_class.encode(messages: "Yes\nNo").messages).to eq("Yes\nNo")
8
+ end
6
9
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::ChannelPB do
5
+ describe Meshtastic::ChannelSettings do
6
6
  end
@@ -3,4 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Channel do
6
+ it 'is the generated Channel protobuf' do
7
+ expect(described_class.new).to be_a(Google::Protobuf::MessageExts)
8
+ end
6
9
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::ClientonlyPB do
5
+ describe Meshtastic::DeviceProfile do
6
6
  end
@@ -3,4 +3,9 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Clientonly do
6
+ it 'encodes a DeviceProfile' do
7
+ profile = described_class.encode(long_name: 'Node', short_name: 'N1')
8
+ expect(profile.long_name).to eq('Node')
9
+ expect(profile.short_name).to eq('N1')
10
+ end
6
11
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::ClientonlyPB do
5
+ describe Meshtastic::Config do
6
6
  end
@@ -2,5 +2,8 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::Clientonly do
5
+ describe Meshtastic::Config do
6
+ it 'is the generated Config protobuf' do
7
+ expect(described_class.new).to be_a(Google::Protobuf::MessageExts)
8
+ end
6
9
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::ConnectionStatusPB do
5
+ describe Meshtastic::DeviceConnectionStatus do
6
6
  end
@@ -3,4 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::ConnectionStatus do
6
+ it 'decodes DeviceConnectionStatus bytes' do
7
+ expect(described_class.decode(bytes: Meshtastic::DeviceConnectionStatus.new.to_proto)).to be_a(Meshtastic::DeviceConnectionStatus)
8
+ end
6
9
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::DeviceonlyLegacyPB do
5
+ describe Meshtastic::NodeDatabase_Legacy do
6
6
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::DeviceonlyPB do
5
+ describe Meshtastic::DeviceState do
6
6
  end
@@ -3,4 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Deviceonly do
6
+ it 'decodes an empty DeviceState' do
7
+ expect(described_class.decode_state(bytes: Meshtastic::DeviceState.new.to_proto)).to be_a(Meshtastic::DeviceState)
8
+ end
6
9
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::LocalonlyPB do
5
+ describe Meshtastic::LocalConfig do
6
6
  end
@@ -3,4 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Localonly do
6
+ it 'decodes an empty LocalConfig' do
7
+ expect(described_class.decode_config(bytes: Meshtastic::LocalConfig.new.to_proto)).to be_a(Meshtastic::LocalConfig)
8
+ end
6
9
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::MeshBeaconPB do
5
+ describe Meshtastic::MeshBeacon do
6
6
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::MeshPB do
5
+ describe Meshtastic::MeshPacket do
6
6
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::ModuleConfigPB do
5
+ describe Meshtastic::ModuleConfig do
6
6
  end
@@ -3,4 +3,25 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::ModuleConfig do
6
+ def fake_serial_obj
7
+ written = +''.b
8
+ serial_conn = Object.new
9
+ serial_conn.define_singleton_method(:write) do |b|
10
+ written << b
11
+ b.bytesize
12
+ end
13
+ serial_conn.define_singleton_method(:flush) { true }
14
+ serial_conn.define_singleton_method(:closed?) { false }
15
+ serial_conn.define_singleton_method(:close) { true }
16
+ { serial_conn: serial_conn, written: written, my_node_num: 0xb0b }
17
+ end
18
+
19
+ it 'requests MQTT module config via Admin' do
20
+ serial_obj = fake_serial_obj
21
+ described_class.get(serial_obj: serial_obj, module_config_type: :MQTT_CONFIG)
22
+ frame = serial_obj[:written]
23
+ packet = Meshtastic::ToRadio.decode(frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))).packet
24
+ admin = Meshtastic::AdminMessage.decode(packet.decoded.payload)
25
+ expect(admin.get_module_config_request).to eq(:MQTT_CONFIG)
26
+ end
6
27
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::MQTTPB do
5
+ describe Meshtastic::ServiceEnvelope do
6
6
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::PaxcountPB do
5
+ describe Meshtastic::Paxcount do
6
6
  end
@@ -3,4 +3,27 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Paxcount do
6
+ def fake_serial_obj
7
+ written = +''.b
8
+ serial_conn = Object.new
9
+ serial_conn.define_singleton_method(:write) do |b|
10
+ written << b
11
+ b.bytesize
12
+ end
13
+ serial_conn.define_singleton_method(:flush) { true }
14
+ serial_conn.define_singleton_method(:closed?) { false }
15
+ serial_conn.define_singleton_method(:close) { true }
16
+ { serial_conn: serial_conn, written: written, my_node_num: 0xb0b }
17
+ end
18
+
19
+ it 'transmits PAXCOUNTER_APP counts' do
20
+ serial_obj = fake_serial_obj
21
+ described_class.transmit(serial_obj: serial_obj, wifi: 3, ble: 2)
22
+ frame = serial_obj[:written]
23
+ packet = Meshtastic::ToRadio.decode(frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))).packet
24
+ expect(packet.decoded.portnum).to eq(:PAXCOUNTER_APP)
25
+ count = Meshtastic::Paxcount.decode(packet.decoded.payload)
26
+ expect(count.wifi).to eq(3)
27
+ expect(count.ble).to eq(2)
28
+ end
6
29
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::PortnumsPB do
5
+ describe Meshtastic::PortNum do
6
6
  end
@@ -3,4 +3,8 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Portnums do
6
+ it 'resolves names and numbers' do
7
+ expect(described_class.lookup(value: :TEXT_MESSAGE_APP)).to eq(1)
8
+ expect(described_class.lookup(value: 1)).to eq(:TEXT_MESSAGE_APP)
9
+ end
6
10
  end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Meshtastic::Position do
6
+ def fake_serial_obj
7
+ written = +''.b
8
+ serial_conn = Object.new
9
+ serial_conn.define_singleton_method(:write) do |b|
10
+ written << b
11
+ b.bytesize
12
+ end
13
+ serial_conn.define_singleton_method(:flush) { true }
14
+ serial_conn.define_singleton_method(:closed?) { false }
15
+ serial_conn.define_singleton_method(:close) { true }
16
+ { serial_conn: serial_conn, written: written, my_node_num: 0xb0b }
17
+ end
18
+
19
+ it 'sends a POSITION_APP packet with scaled lat/lon' do
20
+ serial_obj = fake_serial_obj
21
+ described_class.transmit(serial_obj: serial_obj, lat: 37.7749, lon: -122.4194)
22
+ frame = serial_obj[:written]
23
+ packet = Meshtastic::ToRadio.decode(frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))).packet
24
+ expect(packet.decoded.portnum).to eq(:POSITION_APP)
25
+ position = Meshtastic::Position.decode(packet.decoded.payload)
26
+ expect(position.latitude_i).to eq(377_749_000)
27
+ expect(position.longitude_i).to eq(-1_224_194_000)
28
+ end
29
+
30
+ it 'prints usage without raising' do
31
+ expect { described_class.help }.to output(/USAGE/).to_stdout
32
+ end
33
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::RemoteHardwarePB do
5
+ describe Meshtastic::HardwareMessage do
6
6
  end
@@ -3,4 +3,28 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::RemoteHardware do
6
+ def fake_serial_obj
7
+ written = +''.b
8
+ serial_conn = Object.new
9
+ serial_conn.define_singleton_method(:write) do |b|
10
+ written << b
11
+ b.bytesize
12
+ end
13
+ serial_conn.define_singleton_method(:flush) { true }
14
+ serial_conn.define_singleton_method(:closed?) { false }
15
+ serial_conn.define_singleton_method(:close) { true }
16
+ { serial_conn: serial_conn, written: written, my_node_num: 0xb0b }
17
+ end
18
+
19
+ it 'writes GPIO bits on REMOTE_HARDWARE_APP' do
20
+ serial_obj = fake_serial_obj
21
+ described_class.write_gpios(serial_obj: serial_obj, gpio_mask: 0x01, gpio_value: 0x01)
22
+ frame = serial_obj[:written]
23
+ packet = Meshtastic::ToRadio.decode(frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))).packet
24
+ expect(packet.decoded.portnum).to eq(:REMOTE_HARDWARE_APP)
25
+ hw = Meshtastic::HardwareMessage.decode(packet.decoded.payload)
26
+ expect(hw.type).to eq(:WRITE_GPIOS)
27
+ expect(hw.gpio_mask).to eq(1)
28
+ expect(hw.gpio_value).to eq(1)
29
+ end
6
30
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::RTTTLPB do
5
+ describe Meshtastic::RTTTLConfig do
6
6
  end
@@ -3,4 +3,25 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::RTTTL do
6
+ def fake_serial_obj
7
+ written = +''.b
8
+ serial_conn = Object.new
9
+ serial_conn.define_singleton_method(:write) do |b|
10
+ written << b
11
+ b.bytesize
12
+ end
13
+ serial_conn.define_singleton_method(:flush) { true }
14
+ serial_conn.define_singleton_method(:closed?) { false }
15
+ serial_conn.define_singleton_method(:close) { true }
16
+ { serial_conn: serial_conn, written: written, my_node_num: 0xb0b }
17
+ end
18
+
19
+ it 'sets a ringtone via Admin' do
20
+ serial_obj = fake_serial_obj
21
+ described_class.set(serial_obj: serial_obj, ringtone: 'beep:d=4,o=5,b=120:16c6')
22
+ frame = serial_obj[:written]
23
+ packet = Meshtastic::ToRadio.decode(frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))).packet
24
+ admin = Meshtastic::AdminMessage.decode(packet.decoded.payload)
25
+ expect(admin.set_ringtone_message).to eq('beep:d=4,o=5,b=120:16c6')
26
+ end
6
27
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Meshtastic::StoreforwardPB do
5
+ describe Meshtastic::StoreAndForward do
6
6
  end
@@ -3,4 +3,25 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Meshtastic::Storeforward do
6
+ def fake_serial_obj
7
+ written = +''.b
8
+ serial_conn = Object.new
9
+ serial_conn.define_singleton_method(:write) do |b|
10
+ written << b
11
+ b.bytesize
12
+ end
13
+ serial_conn.define_singleton_method(:flush) { true }
14
+ serial_conn.define_singleton_method(:closed?) { false }
15
+ serial_conn.define_singleton_method(:close) { true }
16
+ { serial_conn: serial_conn, written: written, my_node_num: 0xb0b }
17
+ end
18
+
19
+ it 'sends STORE_FORWARD_APP history request' do
20
+ serial_obj = fake_serial_obj
21
+ described_class.send(serial_obj: serial_obj, rr: :CLIENT_HISTORY)
22
+ frame = serial_obj[:written]
23
+ packet = Meshtastic::ToRadio.decode(frame.byteslice(4, (frame.getbyte(2) << 8) + frame.getbyte(3))).packet
24
+ expect(packet.decoded.portnum).to eq(:STORE_FORWARD_APP)
25
+ expect(Meshtastic::StoreAndForward.decode(packet.decoded.payload).rr).to eq(:CLIENT_HISTORY)
26
+ end
6
27
  end