Merge pull request #980 from protobufs-v2.8.0

This commit is contained in:
Ian McEwen committed 2026-09-14 12:48:19 -07:00
commit be36666082
6 files changed
+68 -41

No files matched your search

+12
View File
@@ -26,6 +26,13 @@ from typing import Any, Dict, List, Tuple
# IntSize enum values from nanopb.proto
INT_SIZE_ENUM = {8: "IS_8", 16: "IS_16", 32: "IS_32", 64: "IS_64"}
# FieldType enum names from nanopb.proto. Only FT_IGNORE carries meaning for a
# Python client (the firmware omits the field entirely); the rest describe C
# storage class, but are passed through so the descriptor mirrors the .options.
FIELD_TYPE_ENUM = frozenset(
{"FT_DEFAULT", "FT_CALLBACK", "FT_POINTER", "FT_STATIC", "FT_IGNORE", "FT_INLINE"}
)
# Options that are valid proto FieldOptions and useful outside of C code generation.
# We skip C-only options (anonymous_oneof, no_unions, skip_message, packed_struct,
# packed_enum, mangle_names, callback_datatype, callback_function, descriptorsize,
@@ -36,6 +43,7 @@ FIELD_OPTIONS = frozenset(
"max_length",
"max_count",
"int_size",
"type",
"fixed_length",
"fixed_count",
"long_names",
@@ -122,6 +130,10 @@ def format_nanopb_opts(opts: Dict[str, Any]) -> str:
if k == "int_size":
enum_val = INT_SIZE_ENUM.get(v, f"IS_{v}")
parts.append(f"(nanopb).int_size = {enum_val}")
elif k == "type":
if v not in FIELD_TYPE_ENUM:
raise ValueError(f"unknown nanopb field type {v!r}")
parts.append(f"(nanopb).type = {v}")
elif isinstance(v, bool):
parts.append(f"(nanopb).{k} = {'true' if v else 'false'}")
else:
+10 -4
View File
@@ -16,7 +16,7 @@ from meshtastic.protobuf import mesh_pb2 as meshtastic_dot_protobuf_dot_mesh__pb
from meshtastic.protobuf import nanopb_pb2 as meshtastic_dot_protobuf_dot_nanopb__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1emeshtastic/protobuf/mqtt.proto\x12\x13meshtastic.protobuf\x1a meshtastic/protobuf/config.proto\x1a\x1emeshtastic/protobuf/mesh.proto\x1a meshtastic/protobuf/nanopb.proto\"j\n\x0fServiceEnvelope\x12/\n\x06packet\x18\x01 \x01(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12\x12\n\nchannel_id\x18\x02 \x01(\t\x12\x12\n\ngateway_id\x18\x03 \x01(\t\"\x9f\x04\n\tMapReport\x12\x18\n\tlong_name\x18\x01 \x01(\tB\x05\x92?\x02\x08\x19\x12\x19\n\nshort_name\x18\x02 \x01(\tB\x05\x92?\x02\x08\x05\x12;\n\x04role\x18\x03 \x01(\x0e\x32-.meshtastic.protobuf.Config.DeviceConfig.Role\x12\x34\n\x08hw_model\x18\x04 \x01(\x0e\x32\".meshtastic.protobuf.HardwareModel\x12\x1f\n\x10\x66irmware_version\x18\x05 \x01(\tB\x05\x92?\x02\x08\x12\x12\x41\n\x06region\x18\x06 \x01(\x0e\x32\x31.meshtastic.protobuf.Config.LoRaConfig.RegionCode\x12H\n\x0cmodem_preset\x18\x07 \x01(\x0e\x32\x32.meshtastic.protobuf.Config.LoRaConfig.ModemPreset\x12\x1b\n\x13has_default_channel\x18\x08 \x01(\x08\x12\x12\n\nlatitude_i\x18\t \x01(\x0f\x12\x13\n\x0blongitude_i\x18\n \x01(\x0f\x12\x10\n\x08\x61ltitude\x18\x0b \x01(\x05\x12\x1a\n\x12position_precision\x18\x0c \x01(\r\x12%\n\x16num_online_local_nodes\x18\r \x01(\rB\x05\x92?\x02\x38\x10\x12!\n\x19has_opted_report_location\x18\x0e \x01(\x08\x42`\n\x14org.meshtastic.protoB\nMQTTProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1emeshtastic/protobuf/mqtt.proto\x12\x13meshtastic.protobuf\x1a meshtastic/protobuf/config.proto\x1a\x1emeshtastic/protobuf/mesh.proto\x1a meshtastic/protobuf/nanopb.proto\"\x7f\n\x0fServiceEnvelope\x12\x36\n\x06packet\x18\x01 \x01(\x0b\x32\x1f.meshtastic.protobuf.MeshPacketB\x05\x92?\x02\x18\x04\x12\x19\n\nchannel_id\x18\x02 \x01(\tB\x05\x92?\x02\x18\x04\x12\x19\n\ngateway_id\x18\x03 \x01(\tB\x05\x92?\x02\x18\x04\"\x9f\x04\n\tMapReport\x12\x18\n\tlong_name\x18\x01 \x01(\tB\x05\x92?\x02\x08\x19\x12\x19\n\nshort_name\x18\x02 \x01(\tB\x05\x92?\x02\x08\x05\x12;\n\x04role\x18\x03 \x01(\x0e\x32-.meshtastic.protobuf.Config.DeviceConfig.Role\x12\x34\n\x08hw_model\x18\x04 \x01(\x0e\x32\".meshtastic.protobuf.HardwareModel\x12\x1f\n\x10\x66irmware_version\x18\x05 \x01(\tB\x05\x92?\x02\x08\x12\x12\x41\n\x06region\x18\x06 \x01(\x0e\x32\x31.meshtastic.protobuf.Config.LoRaConfig.RegionCode\x12H\n\x0cmodem_preset\x18\x07 \x01(\x0e\x32\x32.meshtastic.protobuf.Config.LoRaConfig.ModemPreset\x12\x1b\n\x13has_default_channel\x18\x08 \x01(\x08\x12\x12\n\nlatitude_i\x18\t \x01(\x0f\x12\x13\n\x0blongitude_i\x18\n \x01(\x0f\x12\x10\n\x08\x61ltitude\x18\x0b \x01(\x05\x12\x1a\n\x12position_precision\x18\x0c \x01(\r\x12%\n\x16num_online_local_nodes\x18\r \x01(\rB\x05\x92?\x02\x38\x10\x12!\n\x19has_opted_report_location\x18\x0e \x01(\x08\x42`\n\x14org.meshtastic.protoB\nMQTTProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -24,6 +24,12 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.mqtt_pb
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\nMQTTProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_SERVICEENVELOPE.fields_by_name['packet']._options = None
_SERVICEENVELOPE.fields_by_name['packet']._serialized_options = b'\222?\002\030\004'
_SERVICEENVELOPE.fields_by_name['channel_id']._options = None
_SERVICEENVELOPE.fields_by_name['channel_id']._serialized_options = b'\222?\002\030\004'
_SERVICEENVELOPE.fields_by_name['gateway_id']._options = None
_SERVICEENVELOPE.fields_by_name['gateway_id']._serialized_options = b'\222?\002\030\004'
_MAPREPORT.fields_by_name['long_name']._options = None
_MAPREPORT.fields_by_name['long_name']._serialized_options = b'\222?\002\010\031'
_MAPREPORT.fields_by_name['short_name']._options = None
@@ -33,7 +39,7 @@ if _descriptor._USE_C_DESCRIPTORS == False:
_MAPREPORT.fields_by_name['num_online_local_nodes']._options = None
_MAPREPORT.fields_by_name['num_online_local_nodes']._serialized_options = b'\222?\0028\020'
_globals['_SERVICEENVELOPE']._serialized_start=155
_globals['_SERVICEENVELOPE']._serialized_end=261
_globals['_MAPREPORT']._serialized_start=264
_globals['_MAPREPORT']._serialized_end=807
_globals['_SERVICEENVELOPE']._serialized_end=282
_globals['_MAPREPORT']._serialized_start=285
_globals['_MAPREPORT']._serialized_end=828
# @@protoc_insertion_point(module_scope)
+27 -27
View File
File diff suppressed because one or more lines are too long.
+11 -2
View File
@@ -21,6 +21,7 @@ from meshtastic.protobuf import (
atak_pb2,
config_pb2,
mesh_pb2,
mqtt_pb2,
nanopb_pb2,
telemetry_pb2,
)
@@ -640,7 +641,15 @@ def test_descriptor_multilevel_nested_route_link_uid():
@pytest.mark.unit
def test_descriptor_telemetry_environment_one_wire_temperature():
"""EnvironmentMetrics.one_wire_temperature has max_count = 8 from telemetry.options."""
"""EnvironmentMetrics.one_wire_temperature has type = FT_IGNORE from telemetry.options."""
env = telemetry_pb2.DESCRIPTOR.message_types_by_name["EnvironmentMetrics"]
opts = _field_opts(env, "one_wire_temperature")
assert opts.max_count == 8
assert opts.type == nanopb_pb2.FT_IGNORE
@pytest.mark.unit
def test_descriptor_mqtt_service_envelope_pointer_fields():
"""ServiceEnvelope fields carry type = FT_POINTER from mqtt.options."""
envelope = mqtt_pb2.DESCRIPTOR.message_types_by_name["ServiceEnvelope"]
for name in ("packet", "channel_id", "gateway_id"):
assert _field_opts(envelope, name).type == nanopb_pb2.FT_POINTER
@@ -12,11 +12,11 @@ def test_handleFromRadio_with_traffic_management_module_config():
"""Test _handleFromRadio with moduleConfig.traffic_management."""
iface = MeshInterface(noProto=True)
from_radio = mesh_pb2.FromRadio()
from_radio.moduleConfig.traffic_management.enabled = True
from_radio.moduleConfig.traffic_management.rate_limit_enabled = True
from_radio.moduleConfig.traffic_management.position_min_interval_secs = 30
from_radio.moduleConfig.traffic_management.rate_limit_window_secs = 60
iface._handleFromRadio(from_radio.SerializeToString())
assert iface.localNode.moduleConfig.traffic_management.enabled is True
assert iface.localNode.moduleConfig.traffic_management.rate_limit_enabled is True
assert iface.localNode.moduleConfig.traffic_management.position_min_interval_secs == 30
assert iface.localNode.moduleConfig.traffic_management.rate_limit_window_secs == 60
iface.close()
+4 -4
View File
@@ -1153,8 +1153,8 @@ def test_writeConfig_traffic_management():
"""Test writeConfig with traffic_management module config."""
iface = MagicMock(autospec=SerialInterface)
anode = Node(iface, 123, noProto=True)
anode.moduleConfig.traffic_management.enabled = True
anode.moduleConfig.traffic_management.rate_limit_enabled = True
anode.moduleConfig.traffic_management.position_min_interval_secs = 30
anode.moduleConfig.traffic_management.rate_limit_window_secs = 60
sent_admin = []
@@ -1167,8 +1167,8 @@ def test_writeConfig_traffic_management():
assert len(sent_admin) == 1
assert sent_admin[0].HasField("set_module_config")
assert sent_admin[0].set_module_config.HasField("traffic_management")
assert sent_admin[0].set_module_config.traffic_management.enabled is True
assert sent_admin[0].set_module_config.traffic_management.rate_limit_enabled is True
assert sent_admin[0].set_module_config.traffic_management.position_min_interval_secs == 30
assert sent_admin[0].set_module_config.traffic_management.rate_limit_window_secs == 60
# TODO