meshtastic 0.0.184 → 0.0.186
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/.rubocop_todo.yml +1 -0
- data/Gemfile +2 -1
- data/documentation/README.md +5 -0
- data/documentation/forwarder.md +149 -0
- data/documentation/mesh-interface.md +157 -1
- data/documentation/payload-formats.md +187 -0
- data/documentation/reticulum.md +89 -0
- data/lib/meshtastic/atak.rb +98 -13
- data/lib/meshtastic/atak_pb.rb +3 -1
- data/lib/meshtastic/config_pb.rb +1 -1
- data/lib/meshtastic/field_metadata_pb.rb +1 -1
- data/lib/meshtastic/forwarder.rb +190 -0
- data/lib/meshtastic/forwarder_pb.rb +77 -0
- data/lib/meshtastic/mesh_beacon_pb.rb +1 -1
- data/lib/meshtastic/mesh_interface.rb +115 -65
- data/lib/meshtastic/mesh_pb.rb +2 -1
- data/lib/meshtastic/module_config_pb.rb +1 -1
- data/lib/meshtastic/mqtt.rb +4 -34
- data/lib/meshtastic/payload_compression.rb +90 -0
- data/lib/meshtastic/payload_formats.rb +248 -0
- data/lib/meshtastic/reticulum.rb +71 -0
- data/lib/meshtastic/serial.rb +1 -19
- data/lib/meshtastic/telemetry_pb.rb +2 -2
- data/lib/meshtastic/unishox2.rb +467 -0
- data/lib/meshtastic/version.rb +1 -1
- data/lib/meshtastic.rb +4 -0
- data/meshtastic.gemspec +2 -0
- data/spec/lib/meshtastic/atak_spec.rb +50 -0
- data/spec/lib/meshtastic/bluetooth_spec.rb +14 -0
- data/spec/lib/meshtastic/forwarder_pb_spec.rb +11 -0
- data/spec/lib/meshtastic/forwarder_spec.rb +97 -0
- data/spec/lib/meshtastic/mesh_interface_spec.rb +169 -0
- data/spec/lib/meshtastic/mqtt_spec.rb +56 -0
- data/spec/lib/meshtastic/payload_compression_spec.rb +43 -0
- data/spec/lib/meshtastic/payload_formats_spec.rb +160 -0
- data/spec/lib/meshtastic/reticulum_spec.rb +91 -0
- data/spec/lib/meshtastic/serial_spec.rb +46 -0
- data/spec/lib/meshtastic/tcp_spec.rb +15 -0
- data/spec/lib/meshtastic/unishox2_spec.rb +34 -0
- data/spec/support/payload_fixtures.rb +123 -0
- data/spec/support/reticulum_fixtures.json +12 -0
- data/spec/support/tak_codec_fixtures.rb +4 -0
- data/spec/support/unishox_fixtures.rb +4 -0
- metadata +36 -3
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'ipaddr'
|
|
4
|
+
|
|
5
|
+
module Meshtastic
|
|
6
|
+
# Stateless binary application decoders; see documentation/payload-formats.md.
|
|
7
|
+
module PayloadFormats
|
|
8
|
+
PORTS = { AUDIO_APP: 9, IP_TUNNEL_APP: 33, ZPS_APP: 68, CAYENNE_APP: 77, LORA_OTA_APP: 79 }.freeze
|
|
9
|
+
LPP_TYPES = {
|
|
10
|
+
0 => [:digital_input, 1, false, 1, nil],
|
|
11
|
+
1 => [:digital_output, 1, false, 1, nil],
|
|
12
|
+
2 => [:analog_input, 2, true, 100, nil],
|
|
13
|
+
3 => [:analog_output, 2, true, 100, nil],
|
|
14
|
+
101 => [:illuminance, 2, false, 1, 'lux'],
|
|
15
|
+
102 => [:presence, 1, false, 1, nil],
|
|
16
|
+
103 => [:temperature, 2, true, 10, 'C'],
|
|
17
|
+
104 => [:relative_humidity, 1, false, 2, '%'],
|
|
18
|
+
113 => [:accelerometer, 6, true, 1000, 'g'],
|
|
19
|
+
115 => [:barometric_pressure, 2, false, 10, 'hPa'],
|
|
20
|
+
134 => [:gyrometer, 6, true, 100, 'degrees/s'],
|
|
21
|
+
136 => [:gps, 9, true, 1, nil]
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
public_class_method def self.decode(opts = {})
|
|
25
|
+
port = opts[:portnum]
|
|
26
|
+
port = PORTS[port.to_sym] if port.is_a?(String) || port.is_a?(Symbol)
|
|
27
|
+
raw = opts[:payload]
|
|
28
|
+
raise ArgumentError, 'payload must be a binary String' unless raw.is_a?(String)
|
|
29
|
+
|
|
30
|
+
raw = raw.b
|
|
31
|
+
result = { portnum: port, raw: raw }
|
|
32
|
+
parsed = case port
|
|
33
|
+
when 9 then audio(payload: raw)
|
|
34
|
+
when 33 then ip(payload: raw)
|
|
35
|
+
when 68 then zps(payload: raw, profile: opts[:zps_profile])
|
|
36
|
+
when 77 then cayenne(payload: raw)
|
|
37
|
+
when 79 then ota(payload: raw)
|
|
38
|
+
else { status: :unsupported, format: :opaque, error: 'no verified schema for this port' }
|
|
39
|
+
end
|
|
40
|
+
parsed.merge!(pcm_audio(audio: parsed)) if port == 9 && opts[:pcm] && parsed[:status] == :decoded
|
|
41
|
+
result.merge(parsed)
|
|
42
|
+
rescue ArgumentError => e
|
|
43
|
+
raise unless raw.is_a?(String)
|
|
44
|
+
|
|
45
|
+
result.merge(status: :malformed, error: e.message)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private_class_method def self.cayenne(opts = {})
|
|
49
|
+
raw = opts[:payload]
|
|
50
|
+
records = []
|
|
51
|
+
offset = 0
|
|
52
|
+
while offset < raw.bytesize
|
|
53
|
+
raise ArgumentError, 'truncated Cayenne channel/type' if raw.bytesize - offset < 2
|
|
54
|
+
|
|
55
|
+
channel, type = raw.byteslice(offset, 2).unpack('CC')
|
|
56
|
+
definition = LPP_TYPES[type]
|
|
57
|
+
unless definition
|
|
58
|
+
return { format: :cayenne_lpp, status: :unsupported, records: records,
|
|
59
|
+
error: "unknown Cayenne type #{type}", undecoded_offset: offset, remainder: raw.byteslice(offset..) }
|
|
60
|
+
end
|
|
61
|
+
name, length, signed, divisor, unit = definition
|
|
62
|
+
data = raw.byteslice(offset + 2, length)
|
|
63
|
+
raise ArgumentError, "truncated Cayenne #{name}" unless data && data.bytesize == length
|
|
64
|
+
|
|
65
|
+
width = length > 2 ? length / 3 : length
|
|
66
|
+
values = data.bytes.each_slice(width).map do |bytes|
|
|
67
|
+
value = bytes.reduce(0) { |memo, byte| (memo << 8) | byte }
|
|
68
|
+
value -= 1 << (width * 8) if signed && bytes.first >= 128
|
|
69
|
+
value.fdiv(divisor)
|
|
70
|
+
end
|
|
71
|
+
value = if type == 136
|
|
72
|
+
{ latitude: values[0] / 10_000, longitude: values[1] / 10_000, altitude: values[2] / 100 }
|
|
73
|
+
elsif length == 6
|
|
74
|
+
%i[x y z].zip(values).to_h
|
|
75
|
+
else
|
|
76
|
+
values.first
|
|
77
|
+
end
|
|
78
|
+
records << { channel: channel, type: type, name: name, value: value, unit: unit }
|
|
79
|
+
offset += length + 2
|
|
80
|
+
end
|
|
81
|
+
{ format: :cayenne_lpp, status: :decoded, records: records }
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private_class_method def self.zps(opts = {})
|
|
85
|
+
unless opts[:profile] == :esp32_legacy
|
|
86
|
+
return { format: :opaque, status: :unsupported,
|
|
87
|
+
error: 'ZPS has no stable port-68 schema; select zps_profile: :esp32_legacy only for that experimental dialect' }
|
|
88
|
+
end
|
|
89
|
+
raw = opts[:payload]
|
|
90
|
+
raise ArgumentError, 'experimental ZPS needs two header words and up to twenty uint64 records' unless (16..176).cover?(raw.bytesize) && (raw.bytesize % 8).zero?
|
|
91
|
+
|
|
92
|
+
words = raw.unpack('Q<*')
|
|
93
|
+
header, position = words.shift(2)
|
|
94
|
+
records = words.map do |word|
|
|
95
|
+
channel = (word >> 48) & 255
|
|
96
|
+
{ kind: channel == 255 ? :ble : :wifi, address: format('%012x', word & 0xffffffffffff).scan(/../).join(':'),
|
|
97
|
+
channel: channel, rssi: -(word >> 56) }
|
|
98
|
+
end
|
|
99
|
+
result = { format: :zps, status: :decoded, profile: :esp32_legacy, timestamp: header & 0xffffffff,
|
|
100
|
+
header_word: header, position_word: position, records: records }
|
|
101
|
+
if header.anybits?(0x800000000000)
|
|
102
|
+
longitude, latitude = [position].pack('Q<').unpack('l<2')
|
|
103
|
+
result[:position] = { latitude_i: latitude, longitude_i: longitude, pdop: (header >> 40) & 0x7f }
|
|
104
|
+
end
|
|
105
|
+
result
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private_class_method def self.ip(opts = {})
|
|
109
|
+
raw = opts[:payload]
|
|
110
|
+
raise ArgumentError, 'empty IP packet' if raw.empty?
|
|
111
|
+
|
|
112
|
+
version = raw.getbyte(0) >> 4
|
|
113
|
+
result = { format: :ip, status: :decoded, version: version }
|
|
114
|
+
case version
|
|
115
|
+
when 4
|
|
116
|
+
raise ArgumentError, 'truncated IPv4 header' if raw.bytesize < 20
|
|
117
|
+
|
|
118
|
+
header_length = (raw.getbyte(0) & 15) * 4
|
|
119
|
+
total_length = raw.byteslice(2, 2).unpack1('n')
|
|
120
|
+
raise ArgumentError, 'invalid IPv4 header/total length' unless header_length.between?(20, total_length) && raw.bytesize == total_length
|
|
121
|
+
|
|
122
|
+
flags_offset = raw.byteslice(6, 2).unpack1('n')
|
|
123
|
+
header = raw.byteslice(0, header_length)
|
|
124
|
+
sum = header.unpack('n*').sum
|
|
125
|
+
sum = (sum & 0xffff) + (sum >> 16) while sum > 0xffff
|
|
126
|
+
result.merge(header_length: header_length, total_length: total_length, dscp_ecn: raw.getbyte(1),
|
|
127
|
+
identification: raw.byteslice(4, 2).unpack1('n'), flags: flags_offset >> 13,
|
|
128
|
+
fragment_offset: (flags_offset & 0x1fff) * 8, ttl: raw.getbyte(8), protocol: raw.getbyte(9),
|
|
129
|
+
checksum: raw.byteslice(10, 2).unpack1('n'), header_checksum_valid: sum == 0xffff,
|
|
130
|
+
source: IPAddr.new_ntoh(raw.byteslice(12, 4)).to_s,
|
|
131
|
+
destination: IPAddr.new_ntoh(raw.byteslice(16, 4)).to_s,
|
|
132
|
+
options: raw.byteslice(20, header_length - 20), body: raw.byteslice(header_length..))
|
|
133
|
+
when 6
|
|
134
|
+
raise ArgumentError, 'truncated IPv6 header' if raw.bytesize < 40
|
|
135
|
+
|
|
136
|
+
length = raw.byteslice(4, 2).unpack1('n')
|
|
137
|
+
return result.merge(status: :unsupported, error: 'IPv6 jumbogram extension not decoded') if length.zero? && raw.bytesize > 40
|
|
138
|
+
raise ArgumentError, 'invalid IPv6 payload length' unless raw.bytesize == length + 40
|
|
139
|
+
|
|
140
|
+
first = raw.unpack1('N')
|
|
141
|
+
result.merge(header_length: 40, payload_length: length, total_length: length + 40,
|
|
142
|
+
traffic_class: (first >> 20) & 255, flow_label: first & 0xfffff,
|
|
143
|
+
next_header: raw.getbyte(6), hop_limit: raw.getbyte(7),
|
|
144
|
+
source: IPAddr.new_ntoh(raw.byteslice(8, 16)).to_s,
|
|
145
|
+
destination: IPAddr.new_ntoh(raw.byteslice(24, 16)).to_s, body: raw.byteslice(40..))
|
|
146
|
+
else
|
|
147
|
+
result.merge(status: :unsupported, error: 'unknown IP version')
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
private_class_method def self.audio(opts = {})
|
|
152
|
+
raw = opts[:payload]
|
|
153
|
+
raise ArgumentError, 'Codec2 needs C0 DE C2 magic and mode byte' unless raw.bytesize >= 4 && raw.byteslice(0, 3) == "\xC0\xDE\xC2".b
|
|
154
|
+
|
|
155
|
+
mode = raw.getbyte(3)
|
|
156
|
+
rates = [3200, 2400, 1600, 1400, 1300, 1200, 700, 700, 700]
|
|
157
|
+
bits = [64, 48, 64, 56, 52, 48, 28, 28, 28][mode]
|
|
158
|
+
result = { format: :codec2, mode: mode, pcm_decoded: false, encoded: raw.byteslice(4..) }
|
|
159
|
+
return result.merge(status: :unsupported, error: 'unknown Codec2 mode') unless bits
|
|
160
|
+
|
|
161
|
+
width = (bits + 7) / 8
|
|
162
|
+
raise ArgumentError, 'truncated Codec2 frame' unless (result[:encoded].bytesize % width).zero?
|
|
163
|
+
|
|
164
|
+
frames = result[:encoded].bytes.each_slice(width).map { |bytes| bytes.pack('C*') }
|
|
165
|
+
result.merge(status: :decoded, bitrate: rates[mode], bits_per_frame: bits, bytes_per_frame: width,
|
|
166
|
+
samples_per_frame: mode < 2 ? 160 : 320, sample_rate: 8000, frames: frames)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
private_class_method def self.pcm_audio(opts = {})
|
|
170
|
+
require 'fiddle'
|
|
171
|
+
|
|
172
|
+
audio = opts[:audio]
|
|
173
|
+
library = Fiddle.dlopen('libcodec2.so')
|
|
174
|
+
pointer = Fiddle::TYPE_VOIDP
|
|
175
|
+
integer = Fiddle::TYPE_INT
|
|
176
|
+
create = Fiddle::Function.new(library['codec2_create'], [integer], pointer)
|
|
177
|
+
destroy = Fiddle::Function.new(library['codec2_destroy'], [pointer], Fiddle::TYPE_VOID)
|
|
178
|
+
samples = Fiddle::Function.new(library['codec2_samples_per_frame'], [pointer], integer)
|
|
179
|
+
bits = Fiddle::Function.new(library['codec2_bits_per_frame'], [pointer], integer)
|
|
180
|
+
decode = Fiddle::Function.new(library['codec2_decode'], [pointer, pointer, pointer], Fiddle::TYPE_VOID)
|
|
181
|
+
context = create.call(audio[:mode])
|
|
182
|
+
return { pcm_decoded: false, pcm_error: 'installed libcodec2 does not support this mode' } if context.null?
|
|
183
|
+
|
|
184
|
+
return { pcm_decoded: false, pcm_error: 'native Codec2 geometry differs from wire profile' } unless samples.call(context) == audio[:samples_per_frame] && bits.call(context) == audio[:bits_per_frame]
|
|
185
|
+
|
|
186
|
+
pcm = audio[:frames].map do |frame|
|
|
187
|
+
buffer = "\0".b * (audio[:samples_per_frame] * 2)
|
|
188
|
+
decode.call(context, buffer, frame)
|
|
189
|
+
buffer.unpack('s*').pack('s<*')
|
|
190
|
+
end.join.b
|
|
191
|
+
{ pcm_decoded: true, pcm_encoding: :s16le, pcm: pcm }
|
|
192
|
+
rescue LoadError, StandardError => e
|
|
193
|
+
# Optional native decoding must never discard already decoded framing.
|
|
194
|
+
{ pcm_decoded: false, pcm_error: e.message }
|
|
195
|
+
ensure
|
|
196
|
+
destroy.call(context) if context && !context.null?
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
private_class_method def self.ota(opts = {})
|
|
200
|
+
raw = opts[:payload]
|
|
201
|
+
raise ArgumentError, 'OTA frame must contain 8..233 bytes' unless (8..233).cover?(raw.bytesize)
|
|
202
|
+
|
|
203
|
+
type, session, index, offset, total = raw.unpack('CCv3')
|
|
204
|
+
names = %i[unknown start manifest block proof request ack done abort load load_commit announce]
|
|
205
|
+
body = raw.byteslice(8..)
|
|
206
|
+
result = { format: :ota_common, status: :decoded, type: names[type] || :unknown,
|
|
207
|
+
type_id: type, session: session, index: index, offset: offset, total: total,
|
|
208
|
+
body: body, signature_verified: false }
|
|
209
|
+
case type
|
|
210
|
+
when 1
|
|
211
|
+
raise ArgumentError, 'OTA START needs 12 bytes' unless body.bytesize == 12
|
|
212
|
+
|
|
213
|
+
result[:start] = %i[block_size block_count payload_length manifest_length signature_length].zip(body.unpack('vvVvv')).to_h
|
|
214
|
+
when 2, 3, 4
|
|
215
|
+
raise ArgumentError, 'OTA fragment exceeds logical unit' if offset + body.bytesize > total
|
|
216
|
+
when 5, 6, 7, 8, 10
|
|
217
|
+
raise ArgumentError, 'OTA control frame has unexpected body' unless body.empty?
|
|
218
|
+
when 9
|
|
219
|
+
raise ArgumentError, 'OTA LOAD needs 8-byte prefix' if body.bytesize < 8
|
|
220
|
+
|
|
221
|
+
length, position = body.unpack('V2')
|
|
222
|
+
chunk = body.byteslice(8..)
|
|
223
|
+
raise ArgumentError, 'OTA LOAD chunk exceeds package' if position + chunk.bytesize > length
|
|
224
|
+
|
|
225
|
+
result[:load] = { total_length: length, offset: position, chunk: chunk }
|
|
226
|
+
else
|
|
227
|
+
result.merge!(status: :unsupported, error: 'OTA body schema not established for this frame type')
|
|
228
|
+
end
|
|
229
|
+
result
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
public_class_method def self.authors
|
|
233
|
+
'Meshtastic Ruby contributors'
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
public_class_method def self.help
|
|
237
|
+
puts "# Decode a binary application payload without modifying its bytes.
|
|
238
|
+
#{self}.decode(
|
|
239
|
+
portnum: 'required - numeric or named Meshtastic application port',
|
|
240
|
+
payload: 'required - raw binary application payload String',
|
|
241
|
+
pcm: 'optional - decode Codec2 to s16le audio using installed libcodec2; default false',
|
|
242
|
+
zps_profile: 'optional - select :esp32_legacy for the experimental little-endian ZPS dialect'
|
|
243
|
+
)
|
|
244
|
+
# Identify the module authors.
|
|
245
|
+
#{self}.authors"
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Meshtastic
|
|
4
|
+
# Framing for landandair/RNS_Over_Meshtastic, not an RNS plaintext decoder.
|
|
5
|
+
module Reticulum
|
|
6
|
+
public_class_method def self.decode_chunks(opts = {})
|
|
7
|
+
chunks = opts[:chunks]
|
|
8
|
+
limit = opts.fetch(:max_bytes, 564)
|
|
9
|
+
raise ArgumentError, 'Reticulum byte limit must be 1..564' unless limit.is_a?(Integer) && (1..564).cover?(limit)
|
|
10
|
+
raise ArgumentError, 'Reticulum requires 1..128 grouped chunks' unless chunks.is_a?(Array) && (1..128).cover?(chunks.length)
|
|
11
|
+
|
|
12
|
+
fragments = chunks.map { |payload| decode_packet(payload: payload) }.sort_by { |frame| frame[:index] }
|
|
13
|
+
raise ArgumentError, 'Reticulum control cannot be reassembled' unless fragments.all? { |frame| frame[:format] == :reticulum_fragment }
|
|
14
|
+
raise ArgumentError, 'Reticulum mixed message indexes' unless fragments.map { |frame| frame[:message_index] }.uniq.length == 1
|
|
15
|
+
raise ArgumentError, 'Reticulum duplicate or conflicting position' unless fragments.map { |frame| frame[:index] }.uniq.length == fragments.length
|
|
16
|
+
|
|
17
|
+
finals = fragments.select { |frame| frame[:final] }
|
|
18
|
+
raise ArgumentError, 'Reticulum missing or conflicting final count' unless finals.length == 1
|
|
19
|
+
|
|
20
|
+
count = finals.first[:count]
|
|
21
|
+
raise ArgumentError, 'Reticulum missing or out-of-range fragments' unless fragments.map { |frame| frame[:index] } == (1..count).to_a
|
|
22
|
+
raise ArgumentError, 'Reticulum reassembly exceeds byte limit' if fragments.sum { |frame| frame[:body].bytesize } > limit
|
|
23
|
+
|
|
24
|
+
{ format: :reticulum_packet, complete: true, message_index: fragments.first[:message_index],
|
|
25
|
+
count: fragments.last[:count], body: fragments.map { |frame| frame[:body] }.join.b,
|
|
26
|
+
raw_chunks: fragments.map { |frame| frame[:raw] }, fragments: fragments }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
public_class_method def self.authors
|
|
30
|
+
'0day Inc.; tunnel protocol: landandair/RNS_Over_Meshtastic'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
public_class_method def self.help
|
|
34
|
+
puts "USAGE:
|
|
35
|
+
# Decode one port 76 tunnel frame without inner RNS interpretation.
|
|
36
|
+
#{self}.decode_packet(
|
|
37
|
+
payload: 'required - binary String including the two-byte header or REQ prefix'
|
|
38
|
+
)
|
|
39
|
+
# Reassemble an explicitly isolated complete message without persistent state.
|
|
40
|
+
#{self}.decode_chunks(
|
|
41
|
+
chunks: 'required - array of wire Strings from one sender/channel/connection/message generation',
|
|
42
|
+
max_bytes: 'optional - aggregate body byte ceiling, integer 1..564, default 564'
|
|
43
|
+
)
|
|
44
|
+
# List authors and protocol attribution.
|
|
45
|
+
#{self}.authors
|
|
46
|
+
"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
public_class_method def self.decode_packet(opts = {})
|
|
50
|
+
payload = opts[:payload]
|
|
51
|
+
raise ArgumentError, 'Reticulum payload must be a binary String' unless payload.is_a?(String)
|
|
52
|
+
raise ArgumentError, 'Reticulum wire length must be 3..202 bytes' unless (3..202).cover?(payload.bytesize)
|
|
53
|
+
|
|
54
|
+
bytes = payload.b
|
|
55
|
+
request = bytes.start_with?('REQ')
|
|
56
|
+
raise ArgumentError, 'Reticulum REQ must contain exactly five bytes' if request && bytes.bytesize != 5
|
|
57
|
+
|
|
58
|
+
message_index, position = bytes.byteslice(request ? 3 : 0, 2).unpack('Cc')
|
|
59
|
+
raise ArgumentError, 'Reticulum position must not be zero' if position.zero?
|
|
60
|
+
|
|
61
|
+
if request
|
|
62
|
+
return { format: :reticulum_request, message_index: message_index, position: position,
|
|
63
|
+
index: position.abs, raw: bytes, complete: false }
|
|
64
|
+
end
|
|
65
|
+
{ format: :reticulum_fragment, message_index: message_index, position: position,
|
|
66
|
+
index: position.abs, count: position.negative? ? -position : nil,
|
|
67
|
+
final: position.negative?, complete: position == -1,
|
|
68
|
+
raw: bytes, body: bytes.byteslice(2..) }
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
data/lib/meshtastic/serial.rb
CHANGED
|
@@ -459,25 +459,7 @@ module Meshtastic
|
|
|
459
459
|
|
|
460
460
|
message[:public_key] = Base64.strict_encode64(message[:public_key]) if message[:public_key].to_s.length.positive? && !(message[:public_key].ascii_only? && message[:public_key] =~ %r{\A[A-Za-z0-9+/]+=*\z})
|
|
461
461
|
|
|
462
|
-
|
|
463
|
-
if encrypted_message.to_s.length.positive? && psks.any?
|
|
464
|
-
packet_id = message[:id]
|
|
465
|
-
packet_from = message[:from]
|
|
466
|
-
nonce_packet_id = [packet_id].pack('V').ljust(8, "\x00")
|
|
467
|
-
nonce_from_node = [packet_from].pack('V').ljust(8, "\x00")
|
|
468
|
-
nonce = "#{nonce_packet_id}#{nonce_from_node}"
|
|
469
|
-
|
|
470
|
-
psk = psks[:LongFast] || psks[psks.keys.first]
|
|
471
|
-
dec_psk = Base64.strict_decode64(psk)
|
|
472
|
-
|
|
473
|
-
cipher = OpenSSL::Cipher.new(dec_psk.length == 32 ? 'AES-256-CTR' : 'AES-128-CTR')
|
|
474
|
-
cipher.decrypt
|
|
475
|
-
cipher.key = dec_psk
|
|
476
|
-
cipher.iv = nonce
|
|
477
|
-
decrypted = cipher.update(encrypted_message) + cipher.final
|
|
478
|
-
message[:decoded] = Meshtastic::Data.decode(decrypted).to_h
|
|
479
|
-
message[:encrypted] = :decrypted
|
|
480
|
-
end
|
|
462
|
+
Meshtastic::MeshInterface.new.decrypt_packet(message: message, psks: psks)
|
|
481
463
|
|
|
482
464
|
if message[:decoded]
|
|
483
465
|
payload = message[:decoded][:payload]
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
require 'google/protobuf'
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
descriptor_data = "\n\x1ameshtastic/telemetry.proto\x12\nmeshtastic\"\xf3\x01\n\rDeviceMetrics\x12\x1a\n\rbattery_level\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07voltage\x18\x02 \x01(\x02H\x01\x88\x01\x01\x12 \n\x13\x63hannel_utilization\x18\x03 \x01(\x02H\x02\x88\x01\x01\x12\x18\n\x0b\x61ir_util_tx\x18\x04 \x01(\x02H\x03\x88\x01\x01\x12\x1b\n\x0euptime_seconds\x18\x05 \x01(\rH\x04\x88\x01\x01\x42\x10\n\x0e_battery_levelB\n\n\x08_voltageB\x16\n\x14_channel_utilizationB\x0e\n\x0c_air_util_txB\x11\n\x0f_uptime_seconds\"\xa9\x11\n\x12\x45nvironmentMetrics\x12\x18\n\x0btemperature\x18\x01 \x01(\x02H\x00\x88\x01\x01\x12\x1e\n\x11relative_humidity\x18\x02 \x01(\x02H\x01\x88\x01\x01\x12 \n\x13\x62\x61rometric_pressure\x18\x03 \x01(\x02H\x02\x88\x01\x01\x12\x1b\n\x0egas_resistance\x18\x04 \x01(\x02H\x03\x88\x01\x01\x12\x14\n\x07voltage\x18\x05 \x01(\x02H\x04\x88\x01\x01\x12\x14\n\x07\x63urrent\x18\x06 \x01(\x02H\x05\x88\x01\x01\x12\x10\n\x03iaq\x18\x07 \x01(\rH\x06\x88\x01\x01\x12\x15\n\x08\x64istance\x18\x08 \x01(\x02H\x07\x88\x01\x01\x12\x10\n\x03lux\x18\t \x01(\x02H\x08\x88\x01\x01\x12\x16\n\twhite_lux\x18\n \x01(\x02H\t\x88\x01\x01\x12\x13\n\x06ir_lux\x18\x0b \x01(\x02H\n\x88\x01\x01\x12\x13\n\x06uv_lux\x18\x0c \x01(\x02H\x0b\x88\x01\x01\x12\x1b\n\x0ewind_direction\x18\r \x01(\rH\x0c\x88\x01\x01\x12\x17\n\nwind_speed\x18\x0e \x01(\x02H\r\x88\x01\x01\x12\x13\n\x06weight\x18\x0f \x01(\x02H\x0e\x88\x01\x01\x12\x16\n\twind_gust\x18\x10 \x01(\x02H\x0f\x88\x01\x01\x12\x16\n\twind_lull\x18\x11 \x01(\x02H\x10\x88\x01\x01\x12\x16\n\tradiation\x18\x12 \x01(\x02H\x11\x88\x01\x01\x12\x18\n\x0brainfall_1h\x18\x13 \x01(\x02H\x12\x88\x01\x01\x12\x19\n\x0crainfall_24h\x18\x14 \x01(\x02H\x13\x88\x01\x01\x12\x1a\n\rsoil_moisture\x18\x15 \x01(\rH\x14\x88\x01\x01\x12\x1d\n\x10soil_temperature\x18\x16 \x01(\x02H\x15\x88\x01\x01\x12 \n\x14one_wire_temperature\x18\x17 \x03(\x02\x42\x02\x18\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch0\x18\x18 \x01(\x02H\x16\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch1\x18\x19 \x01(\x02H\x17\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch2\x18\x1a \x01(\x02H\x18\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch3\x18\x1b \x01(\x02H\x19\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch4\x18\x1c \x01(\x02H\x1a\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch5\x18\x1d \x01(\x02H\x1b\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch6\x18\x1e \x01(\x02H\x1c\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch7\x18\x1f \x01(\x02H\x1d\x88\x01\x01\x12%\n\x18one_wire_temperature_ch0\x18 \x01(\x02H\x1e\x88\x01\x01\x12%\n\x18one_wire_temperature_ch1\x18! \x01(\x02H\x1f\x88\x01\x01\x12%\n\x18one_wire_temperature_ch2\x18\" \x01(\x02H \x88\x01\x01\x12%\n\x18one_wire_temperature_ch3\x18# \x01(\x02H!\x88\x01\x01\x12%\n\x18one_wire_temperature_ch4\x18$ \x01(\x02H\"\x88\x01\x01\x12%\n\x18one_wire_temperature_ch5\x18% \x01(\x02H#\x88\x01\x01\x12%\n\x18one_wire_temperature_ch6\x18& \x01(\x02H$\x88\x01\x01\x12%\n\x18one_wire_temperature_ch7\x18\' \x01(\x02H%\x88\x01\x01\x12&\n\x19lightning_strike_count_1h\x18( \x01(\rH&\x88\x01\x01\x12\"\n\x15lightning_distance_km\x18) \x01(\x02H\'\x88\x01\x01\x42\x0e\n\x0c_temperatureB\x14\n\x12_relative_humidityB\x16\n\x14_barometric_pressureB\x11\n\x0f_gas_resistanceB\n\n\x08_voltageB\n\n\x08_currentB\x06\n\x04_iaqB\x0b\n\t_distanceB\x06\n\x04_luxB\x0c\n\n_white_luxB\t\n\x07_ir_luxB\t\n\x07_uv_luxB\x11\n\x0f_wind_directionB\r\n\x0b_wind_speedB\t\n\x07_weightB\x0c\n\n_wind_gustB\x0c\n\n_wind_lullB\x0c\n\n_radiationB\x0e\n\x0c_rainfall_1hB\x0f\n\r_rainfall_24hB\x10\n\x0e_soil_moistureB\x13\n\x11_soil_temperatureB\x12\n\x10_adc_voltage_ch0B\x12\n\x10_adc_voltage_ch1B\x12\n\x10_adc_voltage_ch2B\x12\n\x10_adc_voltage_ch3B\x12\n\x10_adc_voltage_ch4B\x12\n\x10_adc_voltage_ch5B\x12\n\x10_adc_voltage_ch6B\x12\n\x10_adc_voltage_ch7B\x1b\n\x19_one_wire_temperature_ch0B\x1b\n\x19_one_wire_temperature_ch1B\x1b\n\x19_one_wire_temperature_ch2B\x1b\n\x19_one_wire_temperature_ch3B\x1b\n\x19_one_wire_temperature_ch4B\x1b\n\x19_one_wire_temperature_ch5B\x1b\n\x19_one_wire_temperature_ch6B\x1b\n\x19_one_wire_temperature_ch7B\x1c\n\x1a_lightning_strike_count_1hB\x18\n\x16_lightning_distance_kmJ\x04\x08*\x10\x39R\x07soil_phR\x02phR\x17\x65lectrical_conductivityR\x08salinityR\x08nitrogenR\nphosphorusR\tpotassiumR\x10\x64issolved_oxygenR\x03orpR\x16\x63hemical_oxygen_demandR\tturbidityR\x07nitrateR\x08\x61mmoniumR\x19\x62iochemical_oxygen_demandR\x10solar_irradiance\"\x98\x05\n\x10SoilWaterMetrics\x12\x14\n\x07soil_ph\x18\x01 \x01(\x02H\x00\x88\x01\x01\x12\x0f\n\x02ph\x18\x02 \x01(\x02H\x01\x88\x01\x01\x12$\n\x17\x65lectrical_conductivity\x18\x03 \x01(\x02H\x02\x88\x01\x01\x12\x15\n\x08salinity\x18\x04 \x01(\x02H\x03\x88\x01\x01\x12\x15\n\x08nitrogen\x18\x05 \x01(\x02H\x04\x88\x01\x01\x12\x17\n\nphosphorus\x18\x06 \x01(\x02H\x05\x88\x01\x01\x12\x16\n\tpotassium\x18\x07 \x01(\x02H\x06\x88\x01\x01\x12\x1d\n\x10\x64issolved_oxygen\x18\x08 \x01(\x02H\x07\x88\x01\x01\x12\x10\n\x03orp\x18\t \x01(\x02H\x08\x88\x01\x01\x12#\n\x16\x63hemical_oxygen_demand\x18\n \x01(\x02H\t\x88\x01\x01\x12\x16\n\tturbidity\x18\x0b \x01(\x02H\n\x88\x01\x01\x12\x14\n\x07nitrate\x18\x0c \x01(\x02H\x0b\x88\x01\x01\x12\x15\n\x08\x61mmonium\x18\r \x01(\x02H\x0c\x88\x01\x01\x12&\n\x19\x62iochemical_oxygen_demand\x18\x0e \x01(\x02H\r\x88\x01\x01\x12\x1d\n\x10solar_irradiance\x18\x0f \x01(\x02H\x0e\x88\x01\x01\x42\n\n\x08_soil_phB\x05\n\x03_phB\x1a\n\x18_electrical_conductivityB\x0b\n\t_salinityB\x0b\n\t_nitrogenB\r\n\x0b_phosphorusB\x0c\n\n_potassiumB\x13\n\x11_dissolved_oxygenB\x06\n\x04_orpB\x19\n\x17_chemical_oxygen_demandB\x0c\n\n_turbidityB\n\n\x08_nitrateB\x0b\n\t_ammoniumB\x1c\n\x1a_biochemical_oxygen_demandB\x13\n\x11_solar_irradiance\"\xd6\x05\n\x0cPowerMetrics\x12\x18\n\x0b\x63h1_voltage\x18\x01 \x01(\x02H\x00\x88\x01\x01\x12\x18\n\x0b\x63h1_current\x18\x02 \x01(\x02H\x01\x88\x01\x01\x12\x18\n\x0b\x63h2_voltage\x18\x03 \x01(\x02H\x02\x88\x01\x01\x12\x18\n\x0b\x63h2_current\x18\x04 \x01(\x02H\x03\x88\x01\x01\x12\x18\n\x0b\x63h3_voltage\x18\x05 \x01(\x02H\x04\x88\x01\x01\x12\x18\n\x0b\x63h3_current\x18\x06 \x01(\x02H\x05\x88\x01\x01\x12\x1c\n\x0b\x63h4_voltage\x18\x07 \x01(\x02\x42\x02\x18\x01H\x06\x88\x01\x01\x12\x1c\n\x0b\x63h4_current\x18\x08 \x01(\x02\x42\x02\x18\x01H\x07\x88\x01\x01\x12\x1c\n\x0b\x63h5_voltage\x18\t \x01(\x02\x42\x02\x18\x01H\x08\x88\x01\x01\x12\x1c\n\x0b\x63h5_current\x18\n \x01(\x02\x42\x02\x18\x01H\t\x88\x01\x01\x12\x1c\n\x0b\x63h6_voltage\x18\x0b \x01(\x02\x42\x02\x18\x01H\n\x88\x01\x01\x12\x1c\n\x0b\x63h6_current\x18\x0c \x01(\x02\x42\x02\x18\x01H\x0b\x88\x01\x01\x12\x1c\n\x0b\x63h7_voltage\x18\r \x01(\x02\x42\x02\x18\x01H\x0c\x88\x01\x01\x12\x1c\n\x0b\x63h7_current\x18\x0e \x01(\x02\x42\x02\x18\x01H\r\x88\x01\x01\x12\x1c\n\x0b\x63h8_voltage\x18\x0f \x01(\x02\x42\x02\x18\x01H\x0e\x88\x01\x01\x12\x1c\n\x0b\x63h8_current\x18\x10 \x01(\x02\x42\x02\x18\x01H\x0f\x88\x01\x01\x42\x0e\n\x0c_ch1_voltageB\x0e\n\x0c_ch1_currentB\x0e\n\x0c_ch2_voltageB\x0e\n\x0c_ch2_currentB\x0e\n\x0c_ch3_voltageB\x0e\n\x0c_ch3_currentB\x0e\n\x0c_ch4_voltageB\x0e\n\x0c_ch4_currentB\x0e\n\x0c_ch5_voltageB\x0e\n\x0c_ch5_currentB\x0e\n\x0c_ch6_voltageB\x0e\n\x0c_ch6_currentB\x0e\n\x0c_ch7_voltageB\x0e\n\x0c_ch7_currentB\x0e\n\x0c_ch8_voltageB\x0e\n\x0c_ch8_current\"\xe3\t\n\x11\x41irQualityMetrics\x12\x1a\n\rpm10_standard\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x1a\n\rpm25_standard\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x1b\n\x0epm100_standard\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x1f\n\x12pm10_environmental\x18\x04 \x01(\rH\x03\x88\x01\x01\x12\x1f\n\x12pm25_environmental\x18\x05 \x01(\rH\x04\x88\x01\x01\x12 \n\x13pm100_environmental\x18\x06 \x01(\rH\x05\x88\x01\x01\x12\x1b\n\x0eparticles_03um\x18\x07 \x01(\rH\x06\x88\x01\x01\x12\x1b\n\x0eparticles_05um\x18\x08 \x01(\rH\x07\x88\x01\x01\x12\x1b\n\x0eparticles_10um\x18\t \x01(\rH\x08\x88\x01\x01\x12\x1b\n\x0eparticles_25um\x18\n \x01(\rH\t\x88\x01\x01\x12\x1b\n\x0eparticles_50um\x18\x0b \x01(\rH\n\x88\x01\x01\x12\x1c\n\x0fparticles_100um\x18\x0c \x01(\rH\x0b\x88\x01\x01\x12\x10\n\x03\x63o2\x18\r \x01(\rH\x0c\x88\x01\x01\x12\x1c\n\x0f\x63o2_temperature\x18\x0e \x01(\x02H\r\x88\x01\x01\x12\x19\n\x0c\x63o2_humidity\x18\x0f \x01(\x02H\x0e\x88\x01\x01\x12\x1e\n\x11\x66orm_formaldehyde\x18\x10 \x01(\x02H\x0f\x88\x01\x01\x12\x1a\n\rform_humidity\x18\x11 \x01(\x02H\x10\x88\x01\x01\x12\x1d\n\x10\x66orm_temperature\x18\x12 \x01(\x02H\x11\x88\x01\x01\x12\x1a\n\rpm40_standard\x18\x13 \x01(\rH\x12\x88\x01\x01\x12\x1b\n\x0eparticles_40um\x18\x14 \x01(\rH\x13\x88\x01\x01\x12\x1b\n\x0epm_temperature\x18\x15 \x01(\x02H\x14\x88\x01\x01\x12\x18\n\x0bpm_humidity\x18\x16 \x01(\x02H\x15\x88\x01\x01\x12\x17\n\npm_voc_idx\x18\x17 \x01(\x02H\x16\x88\x01\x01\x12\x17\n\npm_nox_idx\x18\x18 \x01(\x02H\x17\x88\x01\x01\x12\x1a\n\rparticles_tps\x18\x19 \x01(\x02H\x18\x88\x01\x01\x12\x1c\n\x0fpm_status_flags\x18\x1a \x01(\rH\x19\x88\x01\x01\x42\x10\n\x0e_pm10_standardB\x10\n\x0e_pm25_standardB\x11\n\x0f_pm100_standardB\x15\n\x13_pm10_environmentalB\x15\n\x13_pm25_environmentalB\x16\n\x14_pm100_environmentalB\x11\n\x0f_particles_03umB\x11\n\x0f_particles_05umB\x11\n\x0f_particles_10umB\x11\n\x0f_particles_25umB\x11\n\x0f_particles_50umB\x12\n\x10_particles_100umB\x06\n\x04_co2B\x12\n\x10_co2_temperatureB\x0f\n\r_co2_humidityB\x14\n\x12_form_formaldehydeB\x10\n\x0e_form_humidityB\x13\n\x11_form_temperatureB\x10\n\x0e_pm40_standardB\x11\n\x0f_particles_40umB\x11\n\x0f_pm_temperatureB\x0e\n\x0c_pm_humidityB\r\n\x0b_pm_voc_idxB\r\n\x0b_pm_nox_idxB\x10\n\x0e_particles_tpsB\x12\n\x10_pm_status_flags\"\xff\x02\n\nLocalStats\x12\x16\n\x0euptime_seconds\x18\x01 \x01(\r\x12\x1b\n\x13\x63hannel_utilization\x18\x02 \x01(\x02\x12\x13\n\x0b\x61ir_util_tx\x18\x03 \x01(\x02\x12\x16\n\x0enum_packets_tx\x18\x04 \x01(\r\x12\x16\n\x0enum_packets_rx\x18\x05 \x01(\r\x12\x1a\n\x12num_packets_rx_bad\x18\x06 \x01(\r\x12\x18\n\x10num_online_nodes\x18\x07 \x01(\r\x12\x17\n\x0fnum_total_nodes\x18\x08 \x01(\r\x12\x13\n\x0bnum_rx_dupe\x18\t \x01(\r\x12\x14\n\x0cnum_tx_relay\x18\n \x01(\r\x12\x1d\n\x15num_tx_relay_canceled\x18\x0b \x01(\r\x12\x18\n\x10heap_total_bytes\x18\x0c \x01(\r\x12\x17\n\x0fheap_free_bytes\x18\r \x01(\r\x12\x16\n\x0enum_tx_dropped\x18\x0e \x01(\r\x12\x13\n\x0bnoise_floor\x18\x0f \x01(\x05\"\xe4\x01\n\x16TrafficManagementStats\x12\x19\n\x11packets_inspected\x18\x01 \x01(\r\x12\x1c\n\x14position_dedup_drops\x18\x02 \x01(\r\x12\x1b\n\x13nodeinfo_cache_hits\x18\x03 \x01(\r\x12\x18\n\x10rate_limit_drops\x18\x04 \x01(\r\x12\x1c\n\x14unknown_packet_drops\x18\x05 \x01(\r\x12\x1d\n\x15hop_exhausted_packets\x18\x06 \x01(\r\x12\x1d\n\x15router_hops_preserved\x18\x07 \x01(\r\"{\n\rHealthMetrics\x12\x16\n\theart_bpm\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x11\n\x04spO2\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x18\n\x0btemperature\x18\x03 \x01(\x02H\x02\x88\x01\x01\x42\x0c\n\n_heart_bpmB\x07\n\x05_spO2B\x0e\n\x0c_temperature\"\x91\x02\n\x0bHostMetrics\x12\x16\n\x0euptime_seconds\x18\x01 \x01(\r\x12\x15\n\rfreemem_bytes\x18\x02 \x01(\x04\x12\x17\n\x0f\x64iskfree1_bytes\x18\x03 \x01(\x04\x12\x1c\n\x0f\x64iskfree2_bytes\x18\x04 \x01(\x04H\x00\x88\x01\x01\x12\x1c\n\x0f\x64iskfree3_bytes\x18\x05 \x01(\x04H\x01\x88\x01\x01\x12\r\n\x05load1\x18\x06 \x01(\r\x12\r\n\x05load5\x18\x07 \x01(\r\x12\x0e\n\x06load15\x18\x08 \x01(\r\x12\x18\n\x0buser_string\x18\t \x01(\tH\x02\x88\x01\x01\x42\x12\n\x10_diskfree2_bytesB\x12\n\x10_diskfree3_bytesB\x0e\n\x0c_user_string\"\xa2\x04\n\tTelemetry\x12\x0c\n\x04time\x18\x01 \x01(\x07\x12\x33\n\x0e\x64\x65vice_metrics\x18\x02 \x01(\x0b\x32\x19.meshtastic.DeviceMetricsH\x00\x12=\n\x13\x65nvironment_metrics\x18\x03 \x01(\x0b\x32\x1e.meshtastic.EnvironmentMetricsH\x00\x12<\n\x13\x61ir_quality_metrics\x18\x04 \x01(\x0b\x32\x1d.meshtastic.AirQualityMetricsH\x00\x12\x31\n\rpower_metrics\x18\x05 \x01(\x0b\x32\x18.meshtastic.PowerMetricsH\x00\x12-\n\x0blocal_stats\x18\x06 \x01(\x0b\x32\x16.meshtastic.LocalStatsH\x00\x12\x33\n\x0ehealth_metrics\x18\x07 \x01(\x0b\x32\x19.meshtastic.HealthMetricsH\x00\x12/\n\x0chost_metrics\x18\x08 \x01(\x0b\x32\x17.meshtastic.HostMetricsH\x00\x12\x46\n\x18traffic_management_stats\x18\t \x01(\x0b\x32\".meshtastic.TrafficManagementStatsH\x00\x12:\n\x12soil_water_metrics\x18\x0b \x01(\x0b\x32\x1c.meshtastic.SoilWaterMetricsH\x00\x42\t\n\x07variant\">\n\rNau7802Config\x12\x12\n\nzeroOffset\x18\x01 \x01(\x05\x12\x19\n\x11\x63\x61librationFactor\x18\x02 \x01(\x02\"%\n\x0c\x41S3935Config\x12\x15\n\rtuning_cap_pf\x18\x01 \x01(\r\"\xf0\x01\n\nSEN5XState\x12\x1a\n\x12last_cleaning_time\x18\x01 \x01(\r\x12\x1b\n\x13last_cleaning_valid\x18\x02 \x01(\x08\x12\x15\n\rone_shot_mode\x18\x03 \x01(\x08\x12\x1b\n\x0evoc_state_time\x18\x04 \x01(\rH\x00\x88\x01\x01\x12\x1c\n\x0fvoc_state_valid\x18\x05 \x01(\x08H\x01\x88\x01\x01\x12\x1c\n\x0fvoc_state_array\x18\x06 \x01(\x06H\x02\x88\x01\x01\x42\x11\n\x0f_voc_state_timeB\x12\n\x10_voc_state_validB\x12\n\x10_voc_state_array\"\xf0\x01\n\nSEN6XState\x12\x1a\n\x12last_cleaning_time\x18\x01 \x01(\r\x12\x1b\n\x13last_cleaning_valid\x18\x02 \x01(\x08\x12\x15\n\rone_shot_mode\x18\x03 \x01(\x08\x12\x1b\n\x0evoc_state_time\x18\x04 \x01(\rH\x00\x88\x01\x01\x12\x1c\n\x0fvoc_state_valid\x18\x05 \x01(\x08H\x01\x88\x01\x01\x12\x1c\n\x0fvoc_state_array\x18\x06 \x01(\x06H\x02\x88\x01\x01\x42\x11\n\x0f_voc_state_timeB\x12\n\x10_voc_state_validB\x12\n\x10_voc_state_array*\x9a\x06\n\x13TelemetrySensorType\x12\x10\n\x0cSENSOR_UNSET\x10\x00\x12\n\n\x06\x42ME280\x10\x01\x12\n\n\x06\x42ME680\x10\x02\x12\x0b\n\x07MCP9808\x10\x03\x12\n\n\x06INA260\x10\x04\x12\n\n\x06INA219\x10\x05\x12\n\n\x06\x42MP280\x10\x06\x12\r\n\x05SHTC3\x10\x07\x1a\x02\x08\x01\x12\t\n\x05LPS22\x10\x08\x12\x0b\n\x07QMC6310\x10\t\x12\x0b\n\x07QMI8658\x10\n\x12\x0c\n\x08QMC5883L\x10\x0b\x12\r\n\x05SHT31\x10\x0c\x1a\x02\x08\x01\x12\x0c\n\x08PMSA003I\x10\r\x12\x0b\n\x07INA3221\x10\x0e\x12\n\n\x06\x42MP085\x10\x0f\x12\x0c\n\x08RCWL9620\x10\x10\x12\r\n\x05SHT4X\x10\x11\x1a\x02\x08\x01\x12\x0c\n\x08VEML7700\x10\x12\x12\x0c\n\x08MLX90632\x10\x13\x12\x0b\n\x07OPT3001\x10\x14\x12\x0c\n\x08LTR390UV\x10\x15\x12\x0e\n\nTSL25911FN\x10\x16\x12\t\n\x05\x41HT10\x10\x17\x12\x10\n\x0c\x44\x46ROBOT_LARK\x10\x18\x12\x0b\n\x07NAU7802\x10\x19\x12\n\n\x06\x42MP3XX\x10\x1a\x12\x0c\n\x08ICM20948\x10\x1b\x12\x0c\n\x08MAX17048\x10\x1c\x12\x11\n\rCUSTOM_SENSOR\x10\x1d\x12\x0c\n\x08MAX30102\x10\x1e\x12\x0c\n\x08MLX90614\x10\x1f\x12\t\n\x05SCD4X\x10 \x12\x0b\n\x07RADSENS\x10!\x12\n\n\x06INA226\x10\"\x12\x10\n\x0c\x44\x46ROBOT_RAIN\x10#\x12\n\n\x06\x44PS310\x10$\x12\x0c\n\x08RAK12035\x10%\x12\x0c\n\x08MAX17261\x10&\x12\x0b\n\x07PCT2075\x10\'\x12\x0b\n\x07\x41\x44S1X15\x10(\x12\x0f\n\x0b\x41\x44S1X15_ALT\x10)\x12\t\n\x05SFA30\x10*\x12\t\n\x05SEN5X\x10+\x12\x0b\n\x07TSL2561\x10,\x12\n\n\x06\x42H1750\x10-\x12\x0b\n\x07HDC1080\x10.\x12\r\n\x05SHT21\x10/\x1a\x02\x08\x01\x12\t\n\x05STC31\x10\x30\x12\t\n\x05SCD30\x10\x31\x12\t\n\x05SHTXX\x10\x32\x12\n\n\x06\x44S248X\x10\x33\x12\r\n\tMMC5983MA\x10\x34\x12\r\n\tICM42607P\x10\x35\x12\t\n\x05SPA06\x10\x36\x12\n\n\x06HM330X\x10\x37\x12\t\n\x05SEN6X\x10\x38\x12\n\n\x06\x41S3935\x10\x39\x42\x65\n\x14org.meshtastic.protoB\x0fTelemetryProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3"
|
|
8
|
+
descriptor_data = "\n\x1ameshtastic/telemetry.proto\x12\nmeshtastic\"\xf3\x01\n\rDeviceMetrics\x12\x1a\n\rbattery_level\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x14\n\x07voltage\x18\x02 \x01(\x02H\x01\x88\x01\x01\x12 \n\x13\x63hannel_utilization\x18\x03 \x01(\x02H\x02\x88\x01\x01\x12\x18\n\x0b\x61ir_util_tx\x18\x04 \x01(\x02H\x03\x88\x01\x01\x12\x1b\n\x0euptime_seconds\x18\x05 \x01(\rH\x04\x88\x01\x01\x42\x10\n\x0e_battery_levelB\n\n\x08_voltageB\x16\n\x14_channel_utilizationB\x0e\n\x0c_air_util_txB\x11\n\x0f_uptime_seconds\"\xa9\x11\n\x12\x45nvironmentMetrics\x12\x18\n\x0btemperature\x18\x01 \x01(\x02H\x00\x88\x01\x01\x12\x1e\n\x11relative_humidity\x18\x02 \x01(\x02H\x01\x88\x01\x01\x12 \n\x13\x62\x61rometric_pressure\x18\x03 \x01(\x02H\x02\x88\x01\x01\x12\x1b\n\x0egas_resistance\x18\x04 \x01(\x02H\x03\x88\x01\x01\x12\x14\n\x07voltage\x18\x05 \x01(\x02H\x04\x88\x01\x01\x12\x14\n\x07\x63urrent\x18\x06 \x01(\x02H\x05\x88\x01\x01\x12\x10\n\x03iaq\x18\x07 \x01(\rH\x06\x88\x01\x01\x12\x15\n\x08\x64istance\x18\x08 \x01(\x02H\x07\x88\x01\x01\x12\x10\n\x03lux\x18\t \x01(\x02H\x08\x88\x01\x01\x12\x16\n\twhite_lux\x18\n \x01(\x02H\t\x88\x01\x01\x12\x13\n\x06ir_lux\x18\x0b \x01(\x02H\n\x88\x01\x01\x12\x13\n\x06uv_lux\x18\x0c \x01(\x02H\x0b\x88\x01\x01\x12\x1b\n\x0ewind_direction\x18\r \x01(\rH\x0c\x88\x01\x01\x12\x17\n\nwind_speed\x18\x0e \x01(\x02H\r\x88\x01\x01\x12\x13\n\x06weight\x18\x0f \x01(\x02H\x0e\x88\x01\x01\x12\x16\n\twind_gust\x18\x10 \x01(\x02H\x0f\x88\x01\x01\x12\x16\n\twind_lull\x18\x11 \x01(\x02H\x10\x88\x01\x01\x12\x16\n\tradiation\x18\x12 \x01(\x02H\x11\x88\x01\x01\x12\x18\n\x0brainfall_1h\x18\x13 \x01(\x02H\x12\x88\x01\x01\x12\x19\n\x0crainfall_24h\x18\x14 \x01(\x02H\x13\x88\x01\x01\x12\x1a\n\rsoil_moisture\x18\x15 \x01(\rH\x14\x88\x01\x01\x12\x1d\n\x10soil_temperature\x18\x16 \x01(\x02H\x15\x88\x01\x01\x12 \n\x14one_wire_temperature\x18\x17 \x03(\x02\x42\x02\x18\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch0\x18\x18 \x01(\x02H\x16\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch1\x18\x19 \x01(\x02H\x17\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch2\x18\x1a \x01(\x02H\x18\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch3\x18\x1b \x01(\x02H\x19\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch4\x18\x1c \x01(\x02H\x1a\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch5\x18\x1d \x01(\x02H\x1b\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch6\x18\x1e \x01(\x02H\x1c\x88\x01\x01\x12\x1c\n\x0f\x61\x64\x63_voltage_ch7\x18\x1f \x01(\x02H\x1d\x88\x01\x01\x12%\n\x18one_wire_temperature_ch0\x18 \x01(\x02H\x1e\x88\x01\x01\x12%\n\x18one_wire_temperature_ch1\x18! \x01(\x02H\x1f\x88\x01\x01\x12%\n\x18one_wire_temperature_ch2\x18\" \x01(\x02H \x88\x01\x01\x12%\n\x18one_wire_temperature_ch3\x18# \x01(\x02H!\x88\x01\x01\x12%\n\x18one_wire_temperature_ch4\x18$ \x01(\x02H\"\x88\x01\x01\x12%\n\x18one_wire_temperature_ch5\x18% \x01(\x02H#\x88\x01\x01\x12%\n\x18one_wire_temperature_ch6\x18& \x01(\x02H$\x88\x01\x01\x12%\n\x18one_wire_temperature_ch7\x18\' \x01(\x02H%\x88\x01\x01\x12&\n\x19lightning_strike_count_1h\x18( \x01(\rH&\x88\x01\x01\x12\"\n\x15lightning_distance_km\x18) \x01(\x02H\'\x88\x01\x01\x42\x0e\n\x0c_temperatureB\x14\n\x12_relative_humidityB\x16\n\x14_barometric_pressureB\x11\n\x0f_gas_resistanceB\n\n\x08_voltageB\n\n\x08_currentB\x06\n\x04_iaqB\x0b\n\t_distanceB\x06\n\x04_luxB\x0c\n\n_white_luxB\t\n\x07_ir_luxB\t\n\x07_uv_luxB\x11\n\x0f_wind_directionB\r\n\x0b_wind_speedB\t\n\x07_weightB\x0c\n\n_wind_gustB\x0c\n\n_wind_lullB\x0c\n\n_radiationB\x0e\n\x0c_rainfall_1hB\x0f\n\r_rainfall_24hB\x10\n\x0e_soil_moistureB\x13\n\x11_soil_temperatureB\x12\n\x10_adc_voltage_ch0B\x12\n\x10_adc_voltage_ch1B\x12\n\x10_adc_voltage_ch2B\x12\n\x10_adc_voltage_ch3B\x12\n\x10_adc_voltage_ch4B\x12\n\x10_adc_voltage_ch5B\x12\n\x10_adc_voltage_ch6B\x12\n\x10_adc_voltage_ch7B\x1b\n\x19_one_wire_temperature_ch0B\x1b\n\x19_one_wire_temperature_ch1B\x1b\n\x19_one_wire_temperature_ch2B\x1b\n\x19_one_wire_temperature_ch3B\x1b\n\x19_one_wire_temperature_ch4B\x1b\n\x19_one_wire_temperature_ch5B\x1b\n\x19_one_wire_temperature_ch6B\x1b\n\x19_one_wire_temperature_ch7B\x1c\n\x1a_lightning_strike_count_1hB\x18\n\x16_lightning_distance_kmJ\x04\x08*\x10\x39R\x07soil_phR\x02phR\x17\x65lectrical_conductivityR\x08salinityR\x08nitrogenR\nphosphorusR\tpotassiumR\x10\x64issolved_oxygenR\x03orpR\x16\x63hemical_oxygen_demandR\tturbidityR\x07nitrateR\x08\x61mmoniumR\x19\x62iochemical_oxygen_demandR\x10solar_irradiance\"\x98\x05\n\x10SoilWaterMetrics\x12\x14\n\x07soil_ph\x18\x01 \x01(\x02H\x00\x88\x01\x01\x12\x0f\n\x02ph\x18\x02 \x01(\x02H\x01\x88\x01\x01\x12$\n\x17\x65lectrical_conductivity\x18\x03 \x01(\x02H\x02\x88\x01\x01\x12\x15\n\x08salinity\x18\x04 \x01(\x02H\x03\x88\x01\x01\x12\x15\n\x08nitrogen\x18\x05 \x01(\x02H\x04\x88\x01\x01\x12\x17\n\nphosphorus\x18\x06 \x01(\x02H\x05\x88\x01\x01\x12\x16\n\tpotassium\x18\x07 \x01(\x02H\x06\x88\x01\x01\x12\x1d\n\x10\x64issolved_oxygen\x18\x08 \x01(\x02H\x07\x88\x01\x01\x12\x10\n\x03orp\x18\t \x01(\x02H\x08\x88\x01\x01\x12#\n\x16\x63hemical_oxygen_demand\x18\n \x01(\x02H\t\x88\x01\x01\x12\x16\n\tturbidity\x18\x0b \x01(\x02H\n\x88\x01\x01\x12\x14\n\x07nitrate\x18\x0c \x01(\x02H\x0b\x88\x01\x01\x12\x15\n\x08\x61mmonium\x18\r \x01(\x02H\x0c\x88\x01\x01\x12&\n\x19\x62iochemical_oxygen_demand\x18\x0e \x01(\x02H\r\x88\x01\x01\x12\x1d\n\x10solar_irradiance\x18\x0f \x01(\x02H\x0e\x88\x01\x01\x42\n\n\x08_soil_phB\x05\n\x03_phB\x1a\n\x18_electrical_conductivityB\x0b\n\t_salinityB\x0b\n\t_nitrogenB\r\n\x0b_phosphorusB\x0c\n\n_potassiumB\x13\n\x11_dissolved_oxygenB\x06\n\x04_orpB\x19\n\x17_chemical_oxygen_demandB\x0c\n\n_turbidityB\n\n\x08_nitrateB\x0b\n\t_ammoniumB\x1c\n\x1a_biochemical_oxygen_demandB\x13\n\x11_solar_irradiance\"\xd6\x05\n\x0cPowerMetrics\x12\x18\n\x0b\x63h1_voltage\x18\x01 \x01(\x02H\x00\x88\x01\x01\x12\x18\n\x0b\x63h1_current\x18\x02 \x01(\x02H\x01\x88\x01\x01\x12\x18\n\x0b\x63h2_voltage\x18\x03 \x01(\x02H\x02\x88\x01\x01\x12\x18\n\x0b\x63h2_current\x18\x04 \x01(\x02H\x03\x88\x01\x01\x12\x18\n\x0b\x63h3_voltage\x18\x05 \x01(\x02H\x04\x88\x01\x01\x12\x18\n\x0b\x63h3_current\x18\x06 \x01(\x02H\x05\x88\x01\x01\x12\x1c\n\x0b\x63h4_voltage\x18\x07 \x01(\x02\x42\x02\x18\x01H\x06\x88\x01\x01\x12\x1c\n\x0b\x63h4_current\x18\x08 \x01(\x02\x42\x02\x18\x01H\x07\x88\x01\x01\x12\x1c\n\x0b\x63h5_voltage\x18\t \x01(\x02\x42\x02\x18\x01H\x08\x88\x01\x01\x12\x1c\n\x0b\x63h5_current\x18\n \x01(\x02\x42\x02\x18\x01H\t\x88\x01\x01\x12\x1c\n\x0b\x63h6_voltage\x18\x0b \x01(\x02\x42\x02\x18\x01H\n\x88\x01\x01\x12\x1c\n\x0b\x63h6_current\x18\x0c \x01(\x02\x42\x02\x18\x01H\x0b\x88\x01\x01\x12\x1c\n\x0b\x63h7_voltage\x18\r \x01(\x02\x42\x02\x18\x01H\x0c\x88\x01\x01\x12\x1c\n\x0b\x63h7_current\x18\x0e \x01(\x02\x42\x02\x18\x01H\r\x88\x01\x01\x12\x1c\n\x0b\x63h8_voltage\x18\x0f \x01(\x02\x42\x02\x18\x01H\x0e\x88\x01\x01\x12\x1c\n\x0b\x63h8_current\x18\x10 \x01(\x02\x42\x02\x18\x01H\x0f\x88\x01\x01\x42\x0e\n\x0c_ch1_voltageB\x0e\n\x0c_ch1_currentB\x0e\n\x0c_ch2_voltageB\x0e\n\x0c_ch2_currentB\x0e\n\x0c_ch3_voltageB\x0e\n\x0c_ch3_currentB\x0e\n\x0c_ch4_voltageB\x0e\n\x0c_ch4_currentB\x0e\n\x0c_ch5_voltageB\x0e\n\x0c_ch5_currentB\x0e\n\x0c_ch6_voltageB\x0e\n\x0c_ch6_currentB\x0e\n\x0c_ch7_voltageB\x0e\n\x0c_ch7_currentB\x0e\n\x0c_ch8_voltageB\x0e\n\x0c_ch8_current\"\xe3\t\n\x11\x41irQualityMetrics\x12\x1a\n\rpm10_standard\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x1a\n\rpm25_standard\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x1b\n\x0epm100_standard\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x1f\n\x12pm10_environmental\x18\x04 \x01(\rH\x03\x88\x01\x01\x12\x1f\n\x12pm25_environmental\x18\x05 \x01(\rH\x04\x88\x01\x01\x12 \n\x13pm100_environmental\x18\x06 \x01(\rH\x05\x88\x01\x01\x12\x1b\n\x0eparticles_03um\x18\x07 \x01(\rH\x06\x88\x01\x01\x12\x1b\n\x0eparticles_05um\x18\x08 \x01(\rH\x07\x88\x01\x01\x12\x1b\n\x0eparticles_10um\x18\t \x01(\rH\x08\x88\x01\x01\x12\x1b\n\x0eparticles_25um\x18\n \x01(\rH\t\x88\x01\x01\x12\x1b\n\x0eparticles_50um\x18\x0b \x01(\rH\n\x88\x01\x01\x12\x1c\n\x0fparticles_100um\x18\x0c \x01(\rH\x0b\x88\x01\x01\x12\x10\n\x03\x63o2\x18\r \x01(\rH\x0c\x88\x01\x01\x12\x1c\n\x0f\x63o2_temperature\x18\x0e \x01(\x02H\r\x88\x01\x01\x12\x19\n\x0c\x63o2_humidity\x18\x0f \x01(\x02H\x0e\x88\x01\x01\x12\x1e\n\x11\x66orm_formaldehyde\x18\x10 \x01(\x02H\x0f\x88\x01\x01\x12\x1a\n\rform_humidity\x18\x11 \x01(\x02H\x10\x88\x01\x01\x12\x1d\n\x10\x66orm_temperature\x18\x12 \x01(\x02H\x11\x88\x01\x01\x12\x1a\n\rpm40_standard\x18\x13 \x01(\rH\x12\x88\x01\x01\x12\x1b\n\x0eparticles_40um\x18\x14 \x01(\rH\x13\x88\x01\x01\x12\x1b\n\x0epm_temperature\x18\x15 \x01(\x02H\x14\x88\x01\x01\x12\x18\n\x0bpm_humidity\x18\x16 \x01(\x02H\x15\x88\x01\x01\x12\x17\n\npm_voc_idx\x18\x17 \x01(\x02H\x16\x88\x01\x01\x12\x17\n\npm_nox_idx\x18\x18 \x01(\x02H\x17\x88\x01\x01\x12\x1a\n\rparticles_tps\x18\x19 \x01(\x02H\x18\x88\x01\x01\x12\x1c\n\x0fpm_status_flags\x18\x1a \x01(\rH\x19\x88\x01\x01\x42\x10\n\x0e_pm10_standardB\x10\n\x0e_pm25_standardB\x11\n\x0f_pm100_standardB\x15\n\x13_pm10_environmentalB\x15\n\x13_pm25_environmentalB\x16\n\x14_pm100_environmentalB\x11\n\x0f_particles_03umB\x11\n\x0f_particles_05umB\x11\n\x0f_particles_10umB\x11\n\x0f_particles_25umB\x11\n\x0f_particles_50umB\x12\n\x10_particles_100umB\x06\n\x04_co2B\x12\n\x10_co2_temperatureB\x0f\n\r_co2_humidityB\x14\n\x12_form_formaldehydeB\x10\n\x0e_form_humidityB\x13\n\x11_form_temperatureB\x10\n\x0e_pm40_standardB\x11\n\x0f_particles_40umB\x11\n\x0f_pm_temperatureB\x0e\n\x0c_pm_humidityB\r\n\x0b_pm_voc_idxB\r\n\x0b_pm_nox_idxB\x10\n\x0e_particles_tpsB\x12\n\x10_pm_status_flags\"\xff\x02\n\nLocalStats\x12\x16\n\x0euptime_seconds\x18\x01 \x01(\r\x12\x1b\n\x13\x63hannel_utilization\x18\x02 \x01(\x02\x12\x13\n\x0b\x61ir_util_tx\x18\x03 \x01(\x02\x12\x16\n\x0enum_packets_tx\x18\x04 \x01(\r\x12\x16\n\x0enum_packets_rx\x18\x05 \x01(\r\x12\x1a\n\x12num_packets_rx_bad\x18\x06 \x01(\r\x12\x18\n\x10num_online_nodes\x18\x07 \x01(\r\x12\x17\n\x0fnum_total_nodes\x18\x08 \x01(\r\x12\x13\n\x0bnum_rx_dupe\x18\t \x01(\r\x12\x14\n\x0cnum_tx_relay\x18\n \x01(\r\x12\x1d\n\x15num_tx_relay_canceled\x18\x0b \x01(\r\x12\x18\n\x10heap_total_bytes\x18\x0c \x01(\r\x12\x17\n\x0fheap_free_bytes\x18\r \x01(\r\x12\x16\n\x0enum_tx_dropped\x18\x0e \x01(\r\x12\x13\n\x0bnoise_floor\x18\x0f \x01(\x05\"\xe4\x01\n\x16TrafficManagementStats\x12\x19\n\x11packets_inspected\x18\x01 \x01(\r\x12\x1c\n\x14position_dedup_drops\x18\x02 \x01(\r\x12\x1b\n\x13nodeinfo_cache_hits\x18\x03 \x01(\r\x12\x18\n\x10rate_limit_drops\x18\x04 \x01(\r\x12\x1c\n\x14unknown_packet_drops\x18\x05 \x01(\r\x12\x1d\n\x15hop_exhausted_packets\x18\x06 \x01(\r\x12\x1d\n\x15router_hops_preserved\x18\x07 \x01(\r\"{\n\rHealthMetrics\x12\x16\n\theart_bpm\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x11\n\x04spO2\x18\x02 \x01(\rH\x01\x88\x01\x01\x12\x18\n\x0btemperature\x18\x03 \x01(\x02H\x02\x88\x01\x01\x42\x0c\n\n_heart_bpmB\x07\n\x05_spO2B\x0e\n\x0c_temperature\"\x91\x02\n\x0bHostMetrics\x12\x16\n\x0euptime_seconds\x18\x01 \x01(\r\x12\x15\n\rfreemem_bytes\x18\x02 \x01(\x04\x12\x17\n\x0f\x64iskfree1_bytes\x18\x03 \x01(\x04\x12\x1c\n\x0f\x64iskfree2_bytes\x18\x04 \x01(\x04H\x00\x88\x01\x01\x12\x1c\n\x0f\x64iskfree3_bytes\x18\x05 \x01(\x04H\x01\x88\x01\x01\x12\r\n\x05load1\x18\x06 \x01(\r\x12\r\n\x05load5\x18\x07 \x01(\r\x12\x0e\n\x06load15\x18\x08 \x01(\r\x12\x18\n\x0buser_string\x18\t \x01(\tH\x02\x88\x01\x01\x42\x12\n\x10_diskfree2_bytesB\x12\n\x10_diskfree3_bytesB\x0e\n\x0c_user_string\"\xa2\x04\n\tTelemetry\x12\x0c\n\x04time\x18\x01 \x01(\x07\x12\x33\n\x0e\x64\x65vice_metrics\x18\x02 \x01(\x0b\x32\x19.meshtastic.DeviceMetricsH\x00\x12=\n\x13\x65nvironment_metrics\x18\x03 \x01(\x0b\x32\x1e.meshtastic.EnvironmentMetricsH\x00\x12<\n\x13\x61ir_quality_metrics\x18\x04 \x01(\x0b\x32\x1d.meshtastic.AirQualityMetricsH\x00\x12\x31\n\rpower_metrics\x18\x05 \x01(\x0b\x32\x18.meshtastic.PowerMetricsH\x00\x12-\n\x0blocal_stats\x18\x06 \x01(\x0b\x32\x16.meshtastic.LocalStatsH\x00\x12\x33\n\x0ehealth_metrics\x18\x07 \x01(\x0b\x32\x19.meshtastic.HealthMetricsH\x00\x12/\n\x0chost_metrics\x18\x08 \x01(\x0b\x32\x17.meshtastic.HostMetricsH\x00\x12\x46\n\x18traffic_management_stats\x18\t \x01(\x0b\x32\".meshtastic.TrafficManagementStatsH\x00\x12:\n\x12soil_water_metrics\x18\x0b \x01(\x0b\x32\x1c.meshtastic.SoilWaterMetricsH\x00\x42\t\n\x07variant\">\n\rNau7802Config\x12\x12\n\nzeroOffset\x18\x01 \x01(\x05\x12\x19\n\x11\x63\x61librationFactor\x18\x02 \x01(\x02\"$\n\x0b\x41S3935State\x12\x15\n\rtuning_cap_pf\x18\x01 \x01(\r\"\xf0\x01\n\nSEN5XState\x12\x1a\n\x12last_cleaning_time\x18\x01 \x01(\r\x12\x1b\n\x13last_cleaning_valid\x18\x02 \x01(\x08\x12\x15\n\rone_shot_mode\x18\x03 \x01(\x08\x12\x1b\n\x0evoc_state_time\x18\x04 \x01(\rH\x00\x88\x01\x01\x12\x1c\n\x0fvoc_state_valid\x18\x05 \x01(\x08H\x01\x88\x01\x01\x12\x1c\n\x0fvoc_state_array\x18\x06 \x01(\x06H\x02\x88\x01\x01\x42\x11\n\x0f_voc_state_timeB\x12\n\x10_voc_state_validB\x12\n\x10_voc_state_array\"\xf0\x01\n\nSEN6XState\x12\x1a\n\x12last_cleaning_time\x18\x01 \x01(\r\x12\x1b\n\x13last_cleaning_valid\x18\x02 \x01(\x08\x12\x15\n\rone_shot_mode\x18\x03 \x01(\x08\x12\x1b\n\x0evoc_state_time\x18\x04 \x01(\rH\x00\x88\x01\x01\x12\x1c\n\x0fvoc_state_valid\x18\x05 \x01(\x08H\x01\x88\x01\x01\x12\x1c\n\x0fvoc_state_array\x18\x06 \x01(\x06H\x02\x88\x01\x01\x42\x11\n\x0f_voc_state_timeB\x12\n\x10_voc_state_validB\x12\n\x10_voc_state_array*\x9a\x06\n\x13TelemetrySensorType\x12\x10\n\x0cSENSOR_UNSET\x10\x00\x12\n\n\x06\x42ME280\x10\x01\x12\n\n\x06\x42ME680\x10\x02\x12\x0b\n\x07MCP9808\x10\x03\x12\n\n\x06INA260\x10\x04\x12\n\n\x06INA219\x10\x05\x12\n\n\x06\x42MP280\x10\x06\x12\r\n\x05SHTC3\x10\x07\x1a\x02\x08\x01\x12\t\n\x05LPS22\x10\x08\x12\x0b\n\x07QMC6310\x10\t\x12\x0b\n\x07QMI8658\x10\n\x12\x0c\n\x08QMC5883L\x10\x0b\x12\r\n\x05SHT31\x10\x0c\x1a\x02\x08\x01\x12\x0c\n\x08PMSA003I\x10\r\x12\x0b\n\x07INA3221\x10\x0e\x12\n\n\x06\x42MP085\x10\x0f\x12\x0c\n\x08RCWL9620\x10\x10\x12\r\n\x05SHT4X\x10\x11\x1a\x02\x08\x01\x12\x0c\n\x08VEML7700\x10\x12\x12\x0c\n\x08MLX90632\x10\x13\x12\x0b\n\x07OPT3001\x10\x14\x12\x0c\n\x08LTR390UV\x10\x15\x12\x0e\n\nTSL25911FN\x10\x16\x12\t\n\x05\x41HT10\x10\x17\x12\x10\n\x0c\x44\x46ROBOT_LARK\x10\x18\x12\x0b\n\x07NAU7802\x10\x19\x12\n\n\x06\x42MP3XX\x10\x1a\x12\x0c\n\x08ICM20948\x10\x1b\x12\x0c\n\x08MAX17048\x10\x1c\x12\x11\n\rCUSTOM_SENSOR\x10\x1d\x12\x0c\n\x08MAX30102\x10\x1e\x12\x0c\n\x08MLX90614\x10\x1f\x12\t\n\x05SCD4X\x10 \x12\x0b\n\x07RADSENS\x10!\x12\n\n\x06INA226\x10\"\x12\x10\n\x0c\x44\x46ROBOT_RAIN\x10#\x12\n\n\x06\x44PS310\x10$\x12\x0c\n\x08RAK12035\x10%\x12\x0c\n\x08MAX17261\x10&\x12\x0b\n\x07PCT2075\x10\'\x12\x0b\n\x07\x41\x44S1X15\x10(\x12\x0f\n\x0b\x41\x44S1X15_ALT\x10)\x12\t\n\x05SFA30\x10*\x12\t\n\x05SEN5X\x10+\x12\x0b\n\x07TSL2561\x10,\x12\n\n\x06\x42H1750\x10-\x12\x0b\n\x07HDC1080\x10.\x12\r\n\x05SHT21\x10/\x1a\x02\x08\x01\x12\t\n\x05STC31\x10\x30\x12\t\n\x05SCD30\x10\x31\x12\t\n\x05SHTXX\x10\x32\x12\n\n\x06\x44S248X\x10\x33\x12\r\n\tMMC5983MA\x10\x34\x12\r\n\tICM42607P\x10\x35\x12\t\n\x05SPA06\x10\x36\x12\n\n\x06HM330X\x10\x37\x12\t\n\x05SEN6X\x10\x38\x12\n\n\x06\x41S3935\x10\x39\x42\x65\n\x14org.meshtastic.protoB\x0fTelemetryProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3"
|
|
9
9
|
|
|
10
10
|
pool = ::Google::Protobuf::DescriptorPool.generated_pool
|
|
11
11
|
pool.add_serialized_file(descriptor_data)
|
|
@@ -22,7 +22,7 @@ module Meshtastic
|
|
|
22
22
|
HostMetrics = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.HostMetrics").msgclass
|
|
23
23
|
Telemetry = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Telemetry").msgclass
|
|
24
24
|
Nau7802Config = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.Nau7802Config").msgclass
|
|
25
|
-
|
|
25
|
+
AS3935State = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.AS3935State").msgclass
|
|
26
26
|
SEN5XState = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.SEN5XState").msgclass
|
|
27
27
|
SEN6XState = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.SEN6XState").msgclass
|
|
28
28
|
TelemetrySensorType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("meshtastic.TelemetrySensorType").enummodule
|