41 Commits

Author SHA1 Message Date
pablorevilla-meshtastic 992296b0c1 Work on new Traceroute page 2026-07-02 15:01:24 -07:00
pablorevilla-meshtastic e2adb73fea map changes and other fixes 2026-06-25 17:19:35 -07:00
pablorevilla-meshtastic 5386f39611 report change 2026-06-11 16:16:08 -07:00
pablorevilla-meshtastic 2175fcb44d remove some of the changes 2026-06-11 14:49:26 -07:00
pablorevilla-meshtastic c16e19336a more fixes 2026-06-08 12:02:20 -07:00
pablorevilla-meshtastic 7f5b50b6f3 Fix timezone or health report 2026-06-08 11:59:20 -07:00
pablorevilla-meshtastic dff2ea0249 change 2026-06-04 17:16:11 -07:00
pablorevilla-meshtastic 029d22ff9c report of cleanup status on health page 2026-06-04 17:14:43 -07:00
pablorevilla-meshtastic 02c77dcca8 change the versio n number and release date for the next release 2026-05-29 14:39:04 -07:00
pablorevilla-meshtastic d4f6a8ba9b fixed bug in top.html now it shows all channels as a option 2026-05-29 14:30:44 -07:00
SMLunchen 31ca098de5 fix: don't overwrite Node.channel from MAP_REPORT_APP if already set (#147)
NODEINFO_APP is the better / authoritative source for a nodes primary channel.
MAP_REPORT_APP packets can arrive on a different MQTT uplink channel and
are unconditionally overwriting the channel set by NODEINFO, causing
nodes to appear on the wrong channel in the map and channel filters.

now MAP_REPORT_APP only sets Node.channel when it is not (yetw) known,
making it a fallback rather than an override.
2026-05-29 14:12:42 -07:00
pablorevilla-meshtastic 794502d63f Merge branch '3.0.7' 2026-05-29 14:06:17 -07:00
pablorevilla-meshtastic ad4785baec Document version 3.0.7 2026-05-29 14:05:16 -07:00
pablorevilla-meshtastic 493fadf0d2 updated protobuf 2026-05-29 13:39:04 -07:00
pablorevilla-meshtastic db04f4dc9f made changes 2026-05-25 09:07:59 -07:00
pablorevilla-meshtastic 2ecaaae2a9 more changes 2026-05-24 11:01:45 -07:00
pablorevilla-meshtastic 7cafefb59b added hop count the the reliablility report. 2026-05-24 10:59:25 -07:00
pablorevilla-meshtastic 85cd05177e added filter for extending the range of active nodes to nodelist 2026-05-23 09:59:25 -07:00
pablorevilla-meshtastic 69150b2efc add node to nodelist 2026-05-23 09:53:21 -07:00
pablorevilla-meshtastic 4695537291 show all nodes in db 2026-05-23 09:03:32 -07:00
pablorevilla-meshtastic f1ad6333dd more updates 2026-05-20 07:05:40 -07:00
pablorevilla-meshtastic 1089cfd256 work on reliablility page 2026-05-20 06:59:37 -07:00
pablorevilla-meshtastic 2ae4483e1f Added map to relaiablity report 2026-05-19 16:49:49 -07:00
pablorevilla-meshtastic fb2c947a14 fix error with QR code not loading node's role 2026-05-19 16:21:30 -07:00
pablorevilla-meshtastic ac161e5764 Made node colors in map persistent to reboot. 2026-05-19 14:17:51 -07:00
Pablo Revilla 1f606e5fa0 Update README.md 2026-05-19 10:29:30 -07:00
pablorevilla-meshtastic c1a9bb63c7 update README.md 2026-05-19 10:27:11 -07:00
pablorevilla-meshtastic 29e5b36dbf Added scale to the maps. 2026-05-19 09:42:02 -07:00
pablorevilla-meshtastic 671af01e0b ADDED new cleanup to the keys table 2026-05-14 14:54:03 -07:00
pablorevilla-meshtastic 82323a8783 changes to calculations 2026-05-14 07:40:04 -07:00
pablorevilla-meshtastic 98549e05b9 updates to filtering 2026-05-13 12:10:57 -07:00
pablorevilla-meshtastic 1fafb344de CHANGE NAME FROM reach to reliability 2026-05-12 20:06:35 -07:00
pablorevilla-meshtastic 0368259bf7 update reach.html 2026-05-12 20:00:51 -07:00
pablorevilla-meshtastic c54c2e9f8d fix search 2026-05-12 19:45:56 -07:00
pablorevilla-meshtastic 96fa6b3063 version update 2026-05-12 19:43:09 -07:00
pablorevilla-meshtastic 15e105b3fc more changes 2026-05-12 19:39:14 -07:00
pablorevilla-meshtastic 1f83de5698 reach.html updated with new content and formatting. 2026-05-12 19:34:26 -07:00
pablorevilla-meshtastic 660c7e60bc update design and test 2026-05-12 19:26:20 -07:00
pablorevilla-meshtastic 4656a9a939 add reach.html 2026-05-12 19:21:08 -07:00
pablorevilla-meshtastic 3a5881975c new changes 2026-05-12 18:08:05 -07:00
pablorevilla-meshtastic 0fdf771980 Add reach report page 2026-05-12 17:30:36 -07:00
74 changed files with 6286 additions and 14081 deletions
+1
View File
@@ -22,6 +22,7 @@ meshview-web.pid
/table_details.py
config.ini
*.log
*.status.json
# Screenshots
screenshots/*
+1 -1
View File
@@ -52,7 +52,7 @@ Unacceptable behavior includes harassment, insults, hate speech, personal attack
---
## I Want to Contribute
## I Want to Contribute!
### Legal Notice
By contributing to Meshview, you agree that:
+15
View File
@@ -4,6 +4,21 @@
The project serves as a real-time monitoring and diagnostic tool for the Meshtastic mesh network. It provides detailed insights into network activity, including message traffic, node positions, and telemetry data.
### Version 3.0.7 — May 2026
- Reliability report: added a dedicated reliability page for checking how well a selected node is heard across the mesh, including heard/missed status, packet counts, hop counts, gateway tables, and a map view.
- Node list/map UX: added node list filtering for wider active-node ranges, included all database nodes where appropriate, and made map node colors persistent across reboots.
- QR/API fixes: corrected QR code generation when a node role is missing or unavailable.
- Database cleanup: removed stored node public key data and added the Alembic migration to drop `node.public_key`.
- Protobufs: refreshed Meshtastic protobuf Python modules to upstream commit
- Tooling: improved the protobuf updater so it supports raw commit SHAs, the newer upstream `meshtastic/*.proto` layout, generated `.pyi` stubs, and the vendored `nanopb`/`serial_hal` outputs.
### Version 3.0.6 — March 2026
- Daily snapshots: added the `daily_snapshot` table, scheduled snapshot capture, and `/api/snapshots/daily` for historical node, packet, and gateway counts.
- Stats/UI: expanded stats views with snapshot data and added channel filters to Chat and Firehose.
- Map/node fixes: corrected node location handling, map popup behavior, packet page display, and node list sorting.
- Ingestion/API reliability: improved duplicate `PacketSeen` handling, guarded invalid node info packets, and made traceroute/edge APIs more tolerant of decode failures.
- Language support: added Russian translations.
### Version 3.0.5 — February 2026
- **IMPORTANT:** the predicted coverage feature requires the extra `pyitm` dependency. If it is not installed, the coverage API will return 503.
- Ubuntu install (inside the venv): `./env/bin/pip install pyitm`
@@ -0,0 +1,43 @@
"""Drop node_public_key table
Revision ID: e8f2c4b6d9a1
Revises: c6b1d8f2a9e3
Create Date: 2026-05-25 00:00:00.000000
"""
from collections.abc import Sequence
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision: str = "e8f2c4b6d9a1"
down_revision: str | None = "c6b1d8f2a9e3"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
op.drop_index("idx_node_public_key_public_key", table_name="node_public_key")
op.drop_index("idx_node_public_key_node_id", table_name="node_public_key")
op.drop_table("node_public_key")
def downgrade() -> None:
op.create_table(
"node_public_key",
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
sa.Column("node_id", sa.BigInteger(), nullable=False),
sa.Column("public_key", sa.String(), nullable=False),
sa.Column("first_seen_us", sa.BigInteger(), nullable=True),
sa.Column("last_seen_us", sa.BigInteger(), nullable=True),
)
op.create_index("idx_node_public_key_node_id", "node_public_key", ["node_id"], unique=False)
op.create_index(
"idx_node_public_key_public_key",
"node_public_key",
["public_key"],
unique=False,
)
+43
View File
@@ -368,6 +368,49 @@ Response Example
"timestamp": "2025-07-22T12:45:00+00:00",
"version": "3.0.3",
"git_revision": "abc1234",
"cleanup": {
"enabled": true,
"days_to_keep": 14,
"scheduled_time": "02:00",
"vacuum": false,
"status": "ok",
"status_file": "dbcleanup.status.json",
"last_run": {
"status": "ok",
"started_at": "2026-06-04T09:00:00+00:00",
"completed_at": "2026-06-04T09:00:03+00:00",
"cutoff_at": "2026-05-21T09:00:00+00:00",
"days_to_keep": 14,
"vacuum_requested": false,
"vacuum_completed": false,
"rows_deleted": {
"packet": 1200,
"packet_seen": 3400,
"traceroute": 42,
"node": 3
},
"error": null
}
},
"backup": {
"enabled": true,
"backup_dir": "./backups",
"scheduled_time": "02:00",
"status": "ok",
"status_file": "dbbackup.status.json",
"last_run": {
"status": "ok",
"started_at": "2026-06-04T09:00:00+00:00",
"completed_at": "2026-06-04T09:00:02+00:00",
"backup_dir": "./backups",
"database_path": "packets.db",
"backup_file": "backups/packets_backup_20260604_090000.db.gz",
"original_size_bytes": 12939444,
"compressed_size_bytes": 4211560,
"compression_percent": 67.5,
"error": null
}
},
"database": "connected",
"database_size": "12.34 MB",
"database_size_bytes": 12939444
+1 -1
View File
@@ -1 +1 @@
cb1f89372a70b0d4b4f8caf05aec28de8d4a13e0
9ab4a1d08cb833d897aee2367013318718391f2f
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/apponly.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -17,12 +17,12 @@ from meshtastic.protobuf import config_pb2 as meshtastic_dot_protobuf_dot_config
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!meshtastic/protobuf/apponly.proto\x12\x13meshtastic.protobuf\x1a!meshtastic/protobuf/channel.proto\x1a meshtastic/protobuf/config.proto\"\x81\x01\n\nChannelSet\x12\x36\n\x08settings\x18\x01 \x03(\x0b\x32$.meshtastic.protobuf.ChannelSettings\x12;\n\x0blora_config\x18\x02 \x01(\x0b\x32&.meshtastic.protobuf.Config.LoRaConfigBc\n\x14org.meshtastic.protoB\rAppOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.apponly_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.apponly_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\rAppOnlyProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_CHANNELSET']._serialized_start=128
_globals['_CHANNELSET']._serialized_end=257
_CHANNELSET._serialized_start=128
_CHANNELSET._serialized_end=257
# @@protoc_insertion_point(module_scope)
+14 -50
View File
@@ -1,52 +1,16 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from meshtastic.protobuf import channel_pb2 as _channel_pb2
from meshtastic.protobuf import config_pb2 as _config_pb2
from google.protobuf.internal import containers as _containers
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
import builtins
import collections.abc
import google.protobuf.descriptor
import google.protobuf.internal.containers
import google.protobuf.message
import meshtastic.protobuf.channel_pb2
import meshtastic.protobuf.config_pb2
import typing
DESCRIPTOR: _descriptor.FileDescriptor
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
@typing.final
class ChannelSet(google.protobuf.message.Message):
"""
This is the most compact possible representation for a set of channels.
It includes only one PRIMARY channel (which must be first) and
any SECONDARY channels.
No DISABLED channels are included.
This abstraction is used only on the the 'app side' of the world (ie python, javascript and android etc) to show a group of Channels as a (long) URL
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
SETTINGS_FIELD_NUMBER: builtins.int
LORA_CONFIG_FIELD_NUMBER: builtins.int
@property
def settings(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[meshtastic.protobuf.channel_pb2.ChannelSettings]:
"""
Channel list with settings
"""
@property
def lora_config(self) -> meshtastic.protobuf.config_pb2.Config.LoRaConfig:
"""
LoRa config
"""
def __init__(
self,
*,
settings: collections.abc.Iterable[meshtastic.protobuf.channel_pb2.ChannelSettings] | None = ...,
lora_config: meshtastic.protobuf.config_pb2.Config.LoRaConfig | None = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["lora_config", b"lora_config"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["lora_config", b"lora_config", "settings", b"settings"]) -> None: ...
global___ChannelSet = ChannelSet
class ChannelSet(_message.Message):
__slots__ = ["lora_config", "settings"]
LORA_CONFIG_FIELD_NUMBER: _ClassVar[int]
SETTINGS_FIELD_NUMBER: _ClassVar[int]
lora_config: _config_pb2.Config.LoRaConfig
settings: _containers.RepeatedCompositeFieldContainer[_channel_pb2.ChannelSettings]
def __init__(self, settings: _Optional[_Iterable[_Union[_channel_pb2.ChannelSettings, _Mapping]]] = ..., lora_config: _Optional[_Union[_config_pb2.Config.LoRaConfig, _Mapping]] = ...) -> None: ...
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/cannedmessages.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,12 +15,12 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n(meshtastic/protobuf/cannedmessages.proto\x12\x13meshtastic.protobuf\"-\n\x19\x43\x61nnedMessageModuleConfig\x12\x10\n\x08messages\x18\x01 \x01(\tBo\n\x14org.meshtastic.protoB\x19\x43\x61nnedMessageConfigProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.cannedmessages_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.cannedmessages_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\031CannedMessageConfigProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_CANNEDMESSAGEMODULECONFIG']._serialized_start=65
_globals['_CANNEDMESSAGEMODULECONFIG']._serialized_end=110
_CANNEDMESSAGEMODULECONFIG._serialized_start=65
_CANNEDMESSAGEMODULECONFIG._serialized_end=110
# @@protoc_insertion_point(module_scope)
+9 -31
View File
@@ -1,33 +1,11 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Optional as _Optional
import builtins
import google.protobuf.descriptor
import google.protobuf.message
import typing
DESCRIPTOR: _descriptor.FileDescriptor
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
@typing.final
class CannedMessageModuleConfig(google.protobuf.message.Message):
"""
Canned message module configuration.
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
MESSAGES_FIELD_NUMBER: builtins.int
messages: builtins.str
"""
Predefined messages for canned message module separated by '|' characters.
"""
def __init__(
self,
*,
messages: builtins.str = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["messages", b"messages"]) -> None: ...
global___CannedMessageModuleConfig = CannedMessageModuleConfig
class CannedMessageModuleConfig(_message.Message):
__slots__ = ["messages"]
MESSAGES_FIELD_NUMBER: _ClassVar[int]
messages: str
def __init__(self, messages: _Optional[str] = ...) -> None: ...
+12 -12
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/channel.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,20 +15,20 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n!meshtastic/protobuf/channel.proto\x12\x13meshtastic.protobuf\"\xc1\x01\n\x0f\x43hannelSettings\x12\x17\n\x0b\x63hannel_num\x18\x01 \x01(\rB\x02\x18\x01\x12\x0b\n\x03psk\x18\x02 \x01(\x0c\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\n\n\x02id\x18\x04 \x01(\x07\x12\x16\n\x0euplink_enabled\x18\x05 \x01(\x08\x12\x18\n\x10\x64ownlink_enabled\x18\x06 \x01(\x08\x12<\n\x0fmodule_settings\x18\x07 \x01(\x0b\x32#.meshtastic.protobuf.ModuleSettings\">\n\x0eModuleSettings\x12\x1a\n\x12position_precision\x18\x01 \x01(\r\x12\x10\n\x08is_muted\x18\x02 \x01(\x08\"\xb3\x01\n\x07\x43hannel\x12\r\n\x05index\x18\x01 \x01(\x05\x12\x36\n\x08settings\x18\x02 \x01(\x0b\x32$.meshtastic.protobuf.ChannelSettings\x12/\n\x04role\x18\x03 \x01(\x0e\x32!.meshtastic.protobuf.Channel.Role\"0\n\x04Role\x12\x0c\n\x08\x44ISABLED\x10\x00\x12\x0b\n\x07PRIMARY\x10\x01\x12\r\n\tSECONDARY\x10\x02\x42\x63\n\x14org.meshtastic.protoB\rChannelProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.channel_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.channel_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\rChannelProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_CHANNELSETTINGS.fields_by_name['channel_num']._options = None
_CHANNELSETTINGS.fields_by_name['channel_num']._serialized_options = b'\030\001'
_globals['_CHANNELSETTINGS']._serialized_start=59
_globals['_CHANNELSETTINGS']._serialized_end=252
_globals['_MODULESETTINGS']._serialized_start=254
_globals['_MODULESETTINGS']._serialized_end=316
_globals['_CHANNEL']._serialized_start=319
_globals['_CHANNEL']._serialized_end=498
_globals['_CHANNEL_ROLE']._serialized_start=450
_globals['_CHANNEL_ROLE']._serialized_end=498
_CHANNELSETTINGS._serialized_start=59
_CHANNELSETTINGS._serialized_end=252
_MODULESETTINGS._serialized_start=254
_MODULESETTINGS._serialized_end=316
_CHANNEL._serialized_start=319
_CHANNEL._serialized_end=498
_CHANNEL_ROLE._serialized_start=450
_CHANNEL_ROLE._serialized_end=498
# @@protoc_insertion_point(module_scope)
+43 -230
View File
@@ -1,234 +1,47 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
import builtins
import google.protobuf.descriptor
import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
import sys
import typing
DESCRIPTOR: _descriptor.FileDescriptor
if sys.version_info >= (3, 10):
import typing as typing_extensions
else:
import typing_extensions
class Channel(_message.Message):
__slots__ = ["index", "role", "settings"]
class Role(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
DISABLED: Channel.Role
INDEX_FIELD_NUMBER: _ClassVar[int]
PRIMARY: Channel.Role
ROLE_FIELD_NUMBER: _ClassVar[int]
SECONDARY: Channel.Role
SETTINGS_FIELD_NUMBER: _ClassVar[int]
index: int
role: Channel.Role
settings: ChannelSettings
def __init__(self, index: _Optional[int] = ..., settings: _Optional[_Union[ChannelSettings, _Mapping]] = ..., role: _Optional[_Union[Channel.Role, str]] = ...) -> None: ...
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
class ChannelSettings(_message.Message):
__slots__ = ["channel_num", "downlink_enabled", "id", "module_settings", "name", "psk", "uplink_enabled"]
CHANNEL_NUM_FIELD_NUMBER: _ClassVar[int]
DOWNLINK_ENABLED_FIELD_NUMBER: _ClassVar[int]
ID_FIELD_NUMBER: _ClassVar[int]
MODULE_SETTINGS_FIELD_NUMBER: _ClassVar[int]
NAME_FIELD_NUMBER: _ClassVar[int]
PSK_FIELD_NUMBER: _ClassVar[int]
UPLINK_ENABLED_FIELD_NUMBER: _ClassVar[int]
channel_num: int
downlink_enabled: bool
id: int
module_settings: ModuleSettings
name: str
psk: bytes
uplink_enabled: bool
def __init__(self, channel_num: _Optional[int] = ..., psk: _Optional[bytes] = ..., name: _Optional[str] = ..., id: _Optional[int] = ..., uplink_enabled: bool = ..., downlink_enabled: bool = ..., module_settings: _Optional[_Union[ModuleSettings, _Mapping]] = ...) -> None: ...
@typing.final
class ChannelSettings(google.protobuf.message.Message):
"""
This information can be encoded as a QRcode/url so that other users can configure
their radio to join the same channel.
A note about how channel names are shown to users: channelname-X
poundsymbol is a prefix used to indicate this is a channel name (idea from @professr).
Where X is a letter from A-Z (base 26) representing a hash of the PSK for this
channel - so that if the user changes anything about the channel (which does
force a new PSK) this letter will also change. Thus preventing user confusion if
two friends try to type in a channel name of "BobsChan" and then can't talk
because their PSKs will be different.
The PSK is hashed into this letter by "0x41 + [xor all bytes of the psk ] modulo 26"
This also allows the option of someday if people have the PSK off (zero), the
users COULD type in a channel name and be able to talk.
FIXME: Add description of multi-channel support and how primary vs secondary channels are used.
FIXME: explain how apps use channels for security.
explain how remote settings and remote gpio are managed as an example
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
CHANNEL_NUM_FIELD_NUMBER: builtins.int
PSK_FIELD_NUMBER: builtins.int
NAME_FIELD_NUMBER: builtins.int
ID_FIELD_NUMBER: builtins.int
UPLINK_ENABLED_FIELD_NUMBER: builtins.int
DOWNLINK_ENABLED_FIELD_NUMBER: builtins.int
MODULE_SETTINGS_FIELD_NUMBER: builtins.int
channel_num: builtins.int
"""
Deprecated in favor of LoraConfig.channel_num
"""
psk: builtins.bytes
"""
A simple pre-shared key for now for crypto.
Must be either 0 bytes (no crypto), 16 bytes (AES128), or 32 bytes (AES256).
A special shorthand is used for 1 byte long psks.
These psks should be treated as only minimally secure,
because they are listed in this source code.
Those bytes are mapped using the following scheme:
`0` = No crypto
`1` = The special "default" channel key: {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59, 0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01}
`2` through 10 = The default channel key, except with 1 through 9 added to the last byte.
Shown to user as simple1 through 10
"""
name: builtins.str
"""
A SHORT name that will be packed into the URL.
Less than 12 bytes.
Something for end users to call the channel
If this is the empty string it is assumed that this channel
is the special (minimally secure) "Default"channel.
In user interfaces it should be rendered as a local language translation of "X".
For channel_num hashing empty string will be treated as "X".
Where "X" is selected based on the English words listed above for ModemPreset
"""
id: builtins.int
"""
Used to construct a globally unique channel ID.
The full globally unique ID will be: "name.id" where ID is shown as base36.
Assuming that the number of meshtastic users is below 20K (true for a long time)
the chance of this 64 bit random number colliding with anyone else is super low.
And the penalty for collision is low as well, it just means that anyone trying to decrypt channel messages might need to
try multiple candidate channels.
Any time a non wire compatible change is made to a channel, this field should be regenerated.
There are a small number of 'special' globally known (and fairly) insecure standard channels.
Those channels do not have a numeric id included in the settings, but instead it is pulled from
a table of well known IDs.
(see Well Known Channels FIXME)
"""
uplink_enabled: builtins.bool
"""
If true, messages on the mesh will be sent to the *public* internet by any gateway ndoe
"""
downlink_enabled: builtins.bool
"""
If true, messages seen on the internet will be forwarded to the local mesh.
"""
@property
def module_settings(self) -> global___ModuleSettings:
"""
Per-channel module settings.
"""
def __init__(
self,
*,
channel_num: builtins.int = ...,
psk: builtins.bytes = ...,
name: builtins.str = ...,
id: builtins.int = ...,
uplink_enabled: builtins.bool = ...,
downlink_enabled: builtins.bool = ...,
module_settings: global___ModuleSettings | None = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["module_settings", b"module_settings"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["channel_num", b"channel_num", "downlink_enabled", b"downlink_enabled", "id", b"id", "module_settings", b"module_settings", "name", b"name", "psk", b"psk", "uplink_enabled", b"uplink_enabled"]) -> None: ...
global___ChannelSettings = ChannelSettings
@typing.final
class ModuleSettings(google.protobuf.message.Message):
"""
This message is specifically for modules to store per-channel configuration data.
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
POSITION_PRECISION_FIELD_NUMBER: builtins.int
IS_MUTED_FIELD_NUMBER: builtins.int
position_precision: builtins.int
"""
Bits of precision for the location sent in position packets.
"""
is_muted: builtins.bool
"""
Controls whether or not the client / device should mute the current channel
Useful for noisy public channels you don't necessarily want to disable
"""
def __init__(
self,
*,
position_precision: builtins.int = ...,
is_muted: builtins.bool = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["is_muted", b"is_muted", "position_precision", b"position_precision"]) -> None: ...
global___ModuleSettings = ModuleSettings
@typing.final
class Channel(google.protobuf.message.Message):
"""
A pair of a channel number, mode and the (sharable) settings for that channel
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
class _Role:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _RoleEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[Channel._Role.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
DISABLED: Channel._Role.ValueType # 0
"""
This channel is not in use right now
"""
PRIMARY: Channel._Role.ValueType # 1
"""
This channel is used to set the frequency for the radio - all other enabled channels must be SECONDARY
"""
SECONDARY: Channel._Role.ValueType # 2
"""
Secondary channels are only used for encryption/decryption/authentication purposes.
Their radio settings (freq etc) are ignored, only psk is used.
"""
class Role(_Role, metaclass=_RoleEnumTypeWrapper):
"""
How this channel is being used (or not).
Note: this field is an enum to give us options for the future.
In particular, someday we might make a 'SCANNING' option.
SCANNING channels could have different frequencies and the radio would
occasionally check that freq to see if anything is being transmitted.
For devices that have multiple physical radios attached, we could keep multiple PRIMARY/SCANNING channels active at once to allow
cross band routing as needed.
If a device has only a single radio (the common case) only one channel can be PRIMARY at a time
(but any number of SECONDARY channels can't be sent received on that common frequency)
"""
DISABLED: Channel.Role.ValueType # 0
"""
This channel is not in use right now
"""
PRIMARY: Channel.Role.ValueType # 1
"""
This channel is used to set the frequency for the radio - all other enabled channels must be SECONDARY
"""
SECONDARY: Channel.Role.ValueType # 2
"""
Secondary channels are only used for encryption/decryption/authentication purposes.
Their radio settings (freq etc) are ignored, only psk is used.
"""
INDEX_FIELD_NUMBER: builtins.int
SETTINGS_FIELD_NUMBER: builtins.int
ROLE_FIELD_NUMBER: builtins.int
index: builtins.int
"""
The index of this channel in the channel table (from 0 to MAX_NUM_CHANNELS-1)
(Someday - not currently implemented) An index of -1 could be used to mean "set by name",
in which case the target node will find and set the channel by settings.name.
"""
role: global___Channel.Role.ValueType
"""
TODO: REPLACE
"""
@property
def settings(self) -> global___ChannelSettings:
"""
The new settings, or NULL to disable that channel
"""
def __init__(
self,
*,
index: builtins.int = ...,
settings: global___ChannelSettings | None = ...,
role: global___Channel.Role.ValueType = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["settings", b"settings"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["index", b"index", "role", b"role", "settings", b"settings"]) -> None: ...
global___Channel = Channel
class ModuleSettings(_message.Message):
__slots__ = ["is_muted", "position_precision"]
IS_MUTED_FIELD_NUMBER: _ClassVar[int]
POSITION_PRECISION_FIELD_NUMBER: _ClassVar[int]
is_muted: bool
position_precision: int
def __init__(self, position_precision: _Optional[int] = ..., is_muted: bool = ...) -> None: ...
+6 -6
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/clientonly.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -17,12 +17,12 @@ from meshtastic.protobuf import mesh_pb2 as meshtastic_dot_protobuf_dot_mesh__pb
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$meshtastic/protobuf/clientonly.proto\x12\x13meshtastic.protobuf\x1a#meshtastic/protobuf/localonly.proto\x1a\x1emeshtastic/protobuf/mesh.proto\"\xc4\x03\n\rDeviceProfile\x12\x16\n\tlong_name\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x17\n\nshort_name\x18\x02 \x01(\tH\x01\x88\x01\x01\x12\x18\n\x0b\x63hannel_url\x18\x03 \x01(\tH\x02\x88\x01\x01\x12\x35\n\x06\x63onfig\x18\x04 \x01(\x0b\x32 .meshtastic.protobuf.LocalConfigH\x03\x88\x01\x01\x12\x42\n\rmodule_config\x18\x05 \x01(\x0b\x32&.meshtastic.protobuf.LocalModuleConfigH\x04\x88\x01\x01\x12:\n\x0e\x66ixed_position\x18\x06 \x01(\x0b\x32\x1d.meshtastic.protobuf.PositionH\x05\x88\x01\x01\x12\x15\n\x08ringtone\x18\x07 \x01(\tH\x06\x88\x01\x01\x12\x1c\n\x0f\x63\x61nned_messages\x18\x08 \x01(\tH\x07\x88\x01\x01\x42\x0c\n\n_long_nameB\r\n\x0b_short_nameB\x0e\n\x0c_channel_urlB\t\n\x07_configB\x10\n\x0e_module_configB\x11\n\x0f_fixed_positionB\x0b\n\t_ringtoneB\x12\n\x10_canned_messagesBf\n\x14org.meshtastic.protoB\x10\x43lientOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.clientonly_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.clientonly_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\020ClientOnlyProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_DEVICEPROFILE']._serialized_start=131
_globals['_DEVICEPROFILE']._serialized_end=583
_DEVICEPROFILE._serialized_start=131
_DEVICEPROFILE._serialized_end=583
# @@protoc_insertion_point(module_scope)
+25 -99
View File
@@ -1,101 +1,27 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from meshtastic.protobuf import localonly_pb2 as _localonly_pb2
from meshtastic.protobuf import mesh_pb2 as _mesh_pb2
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
import builtins
import google.protobuf.descriptor
import google.protobuf.message
import meshtastic.protobuf.localonly_pb2
import meshtastic.protobuf.mesh_pb2
import typing
DESCRIPTOR: _descriptor.FileDescriptor
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
@typing.final
class DeviceProfile(google.protobuf.message.Message):
"""
This abstraction is used to contain any configuration for provisioning a node on any client.
It is useful for importing and exporting configurations.
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
LONG_NAME_FIELD_NUMBER: builtins.int
SHORT_NAME_FIELD_NUMBER: builtins.int
CHANNEL_URL_FIELD_NUMBER: builtins.int
CONFIG_FIELD_NUMBER: builtins.int
MODULE_CONFIG_FIELD_NUMBER: builtins.int
FIXED_POSITION_FIELD_NUMBER: builtins.int
RINGTONE_FIELD_NUMBER: builtins.int
CANNED_MESSAGES_FIELD_NUMBER: builtins.int
long_name: builtins.str
"""
Long name for the node
"""
short_name: builtins.str
"""
Short name of the node
"""
channel_url: builtins.str
"""
The url of the channels from our node
"""
ringtone: builtins.str
"""
Ringtone for ExternalNotification
"""
canned_messages: builtins.str
"""
Predefined messages for CannedMessage
"""
@property
def config(self) -> meshtastic.protobuf.localonly_pb2.LocalConfig:
"""
The Config of the node
"""
@property
def module_config(self) -> meshtastic.protobuf.localonly_pb2.LocalModuleConfig:
"""
The ModuleConfig of the node
"""
@property
def fixed_position(self) -> meshtastic.protobuf.mesh_pb2.Position:
"""
Fixed position data
"""
def __init__(
self,
*,
long_name: builtins.str | None = ...,
short_name: builtins.str | None = ...,
channel_url: builtins.str | None = ...,
config: meshtastic.protobuf.localonly_pb2.LocalConfig | None = ...,
module_config: meshtastic.protobuf.localonly_pb2.LocalModuleConfig | None = ...,
fixed_position: meshtastic.protobuf.mesh_pb2.Position | None = ...,
ringtone: builtins.str | None = ...,
canned_messages: builtins.str | None = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["_canned_messages", b"_canned_messages", "_channel_url", b"_channel_url", "_config", b"_config", "_fixed_position", b"_fixed_position", "_long_name", b"_long_name", "_module_config", b"_module_config", "_ringtone", b"_ringtone", "_short_name", b"_short_name", "canned_messages", b"canned_messages", "channel_url", b"channel_url", "config", b"config", "fixed_position", b"fixed_position", "long_name", b"long_name", "module_config", b"module_config", "ringtone", b"ringtone", "short_name", b"short_name"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["_canned_messages", b"_canned_messages", "_channel_url", b"_channel_url", "_config", b"_config", "_fixed_position", b"_fixed_position", "_long_name", b"_long_name", "_module_config", b"_module_config", "_ringtone", b"_ringtone", "_short_name", b"_short_name", "canned_messages", b"canned_messages", "channel_url", b"channel_url", "config", b"config", "fixed_position", b"fixed_position", "long_name", b"long_name", "module_config", b"module_config", "ringtone", b"ringtone", "short_name", b"short_name"]) -> None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_canned_messages", b"_canned_messages"]) -> typing.Literal["canned_messages"] | None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_channel_url", b"_channel_url"]) -> typing.Literal["channel_url"] | None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_config", b"_config"]) -> typing.Literal["config"] | None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_fixed_position", b"_fixed_position"]) -> typing.Literal["fixed_position"] | None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_long_name", b"_long_name"]) -> typing.Literal["long_name"] | None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_module_config", b"_module_config"]) -> typing.Literal["module_config"] | None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_ringtone", b"_ringtone"]) -> typing.Literal["ringtone"] | None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_short_name", b"_short_name"]) -> typing.Literal["short_name"] | None: ...
global___DeviceProfile = DeviceProfile
class DeviceProfile(_message.Message):
__slots__ = ["canned_messages", "channel_url", "config", "fixed_position", "long_name", "module_config", "ringtone", "short_name"]
CANNED_MESSAGES_FIELD_NUMBER: _ClassVar[int]
CHANNEL_URL_FIELD_NUMBER: _ClassVar[int]
CONFIG_FIELD_NUMBER: _ClassVar[int]
FIXED_POSITION_FIELD_NUMBER: _ClassVar[int]
LONG_NAME_FIELD_NUMBER: _ClassVar[int]
MODULE_CONFIG_FIELD_NUMBER: _ClassVar[int]
RINGTONE_FIELD_NUMBER: _ClassVar[int]
SHORT_NAME_FIELD_NUMBER: _ClassVar[int]
canned_messages: str
channel_url: str
config: _localonly_pb2.LocalConfig
fixed_position: _mesh_pb2.Position
long_name: str
module_config: _localonly_pb2.LocalModuleConfig
ringtone: str
short_name: str
def __init__(self, long_name: _Optional[str] = ..., short_name: _Optional[str] = ..., channel_url: _Optional[str] = ..., config: _Optional[_Union[_localonly_pb2.LocalConfig, _Mapping]] = ..., module_config: _Optional[_Union[_localonly_pb2.LocalModuleConfig, _Mapping]] = ..., fixed_position: _Optional[_Union[_mesh_pb2.Position, _Mapping]] = ..., ringtone: _Optional[str] = ..., canned_messages: _Optional[str] = ...) -> None: ...
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/connection_status.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,22 +15,22 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n+meshtastic/protobuf/connection_status.proto\x12\x13meshtastic.protobuf\"\xd5\x02\n\x16\x44\x65viceConnectionStatus\x12<\n\x04wifi\x18\x01 \x01(\x0b\x32).meshtastic.protobuf.WifiConnectionStatusH\x00\x88\x01\x01\x12\x44\n\x08\x65thernet\x18\x02 \x01(\x0b\x32-.meshtastic.protobuf.EthernetConnectionStatusH\x01\x88\x01\x01\x12\x46\n\tbluetooth\x18\x03 \x01(\x0b\x32..meshtastic.protobuf.BluetoothConnectionStatusH\x02\x88\x01\x01\x12@\n\x06serial\x18\x04 \x01(\x0b\x32+.meshtastic.protobuf.SerialConnectionStatusH\x03\x88\x01\x01\x42\x07\n\x05_wifiB\x0b\n\t_ethernetB\x0c\n\n_bluetoothB\t\n\x07_serial\"p\n\x14WifiConnectionStatus\x12<\n\x06status\x18\x01 \x01(\x0b\x32,.meshtastic.protobuf.NetworkConnectionStatus\x12\x0c\n\x04ssid\x18\x02 \x01(\t\x12\x0c\n\x04rssi\x18\x03 \x01(\x05\"X\n\x18\x45thernetConnectionStatus\x12<\n\x06status\x18\x01 \x01(\x0b\x32,.meshtastic.protobuf.NetworkConnectionStatus\"{\n\x17NetworkConnectionStatus\x12\x12\n\nip_address\x18\x01 \x01(\x07\x12\x14\n\x0cis_connected\x18\x02 \x01(\x08\x12\x19\n\x11is_mqtt_connected\x18\x03 \x01(\x08\x12\x1b\n\x13is_syslog_connected\x18\x04 \x01(\x08\"L\n\x19\x42luetoothConnectionStatus\x12\x0b\n\x03pin\x18\x01 \x01(\r\x12\x0c\n\x04rssi\x18\x02 \x01(\x05\x12\x14\n\x0cis_connected\x18\x03 \x01(\x08\"<\n\x16SerialConnectionStatus\x12\x0c\n\x04\x62\x61ud\x18\x01 \x01(\r\x12\x14\n\x0cis_connected\x18\x02 \x01(\x08\x42\x66\n\x14org.meshtastic.protoB\x10\x43onnStatusProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.connection_status_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.connection_status_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\020ConnStatusProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_DEVICECONNECTIONSTATUS']._serialized_start=69
_globals['_DEVICECONNECTIONSTATUS']._serialized_end=410
_globals['_WIFICONNECTIONSTATUS']._serialized_start=412
_globals['_WIFICONNECTIONSTATUS']._serialized_end=524
_globals['_ETHERNETCONNECTIONSTATUS']._serialized_start=526
_globals['_ETHERNETCONNECTIONSTATUS']._serialized_end=614
_globals['_NETWORKCONNECTIONSTATUS']._serialized_start=616
_globals['_NETWORKCONNECTIONSTATUS']._serialized_end=739
_globals['_BLUETOOTHCONNECTIONSTATUS']._serialized_start=741
_globals['_BLUETOOTHCONNECTIONSTATUS']._serialized_end=817
_globals['_SERIALCONNECTIONSTATUS']._serialized_start=819
_globals['_SERIALCONNECTIONSTATUS']._serialized_end=879
_DEVICECONNECTIONSTATUS._serialized_start=69
_DEVICECONNECTIONSTATUS._serialized_end=410
_WIFICONNECTIONSTATUS._serialized_start=412
_WIFICONNECTIONSTATUS._serialized_end=524
_ETHERNETCONNECTIONSTATUS._serialized_start=526
_ETHERNETCONNECTIONSTATUS._serialized_end=614
_NETWORKCONNECTIONSTATUS._serialized_start=616
_NETWORKCONNECTIONSTATUS._serialized_end=739
_BLUETOOTHCONNECTIONSTATUS._serialized_start=741
_BLUETOOTHCONNECTIONSTATUS._serialized_end=817
_SERIALCONNECTIONSTATUS._serialized_start=819
_SERIALCONNECTIONSTATUS._serialized_end=879
# @@protoc_insertion_point(module_scope)
+56 -221
View File
@@ -1,228 +1,63 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
import builtins
import google.protobuf.descriptor
import google.protobuf.message
import typing
DESCRIPTOR: _descriptor.FileDescriptor
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
class BluetoothConnectionStatus(_message.Message):
__slots__ = ["is_connected", "pin", "rssi"]
IS_CONNECTED_FIELD_NUMBER: _ClassVar[int]
PIN_FIELD_NUMBER: _ClassVar[int]
RSSI_FIELD_NUMBER: _ClassVar[int]
is_connected: bool
pin: int
rssi: int
def __init__(self, pin: _Optional[int] = ..., rssi: _Optional[int] = ..., is_connected: bool = ...) -> None: ...
@typing.final
class DeviceConnectionStatus(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
class DeviceConnectionStatus(_message.Message):
__slots__ = ["bluetooth", "ethernet", "serial", "wifi"]
BLUETOOTH_FIELD_NUMBER: _ClassVar[int]
ETHERNET_FIELD_NUMBER: _ClassVar[int]
SERIAL_FIELD_NUMBER: _ClassVar[int]
WIFI_FIELD_NUMBER: _ClassVar[int]
bluetooth: BluetoothConnectionStatus
ethernet: EthernetConnectionStatus
serial: SerialConnectionStatus
wifi: WifiConnectionStatus
def __init__(self, wifi: _Optional[_Union[WifiConnectionStatus, _Mapping]] = ..., ethernet: _Optional[_Union[EthernetConnectionStatus, _Mapping]] = ..., bluetooth: _Optional[_Union[BluetoothConnectionStatus, _Mapping]] = ..., serial: _Optional[_Union[SerialConnectionStatus, _Mapping]] = ...) -> None: ...
WIFI_FIELD_NUMBER: builtins.int
ETHERNET_FIELD_NUMBER: builtins.int
BLUETOOTH_FIELD_NUMBER: builtins.int
SERIAL_FIELD_NUMBER: builtins.int
@property
def wifi(self) -> global___WifiConnectionStatus:
"""
WiFi Status
"""
class EthernetConnectionStatus(_message.Message):
__slots__ = ["status"]
STATUS_FIELD_NUMBER: _ClassVar[int]
status: NetworkConnectionStatus
def __init__(self, status: _Optional[_Union[NetworkConnectionStatus, _Mapping]] = ...) -> None: ...
@property
def ethernet(self) -> global___EthernetConnectionStatus:
"""
WiFi Status
"""
class NetworkConnectionStatus(_message.Message):
__slots__ = ["ip_address", "is_connected", "is_mqtt_connected", "is_syslog_connected"]
IP_ADDRESS_FIELD_NUMBER: _ClassVar[int]
IS_CONNECTED_FIELD_NUMBER: _ClassVar[int]
IS_MQTT_CONNECTED_FIELD_NUMBER: _ClassVar[int]
IS_SYSLOG_CONNECTED_FIELD_NUMBER: _ClassVar[int]
ip_address: int
is_connected: bool
is_mqtt_connected: bool
is_syslog_connected: bool
def __init__(self, ip_address: _Optional[int] = ..., is_connected: bool = ..., is_mqtt_connected: bool = ..., is_syslog_connected: bool = ...) -> None: ...
@property
def bluetooth(self) -> global___BluetoothConnectionStatus:
"""
Bluetooth Status
"""
class SerialConnectionStatus(_message.Message):
__slots__ = ["baud", "is_connected"]
BAUD_FIELD_NUMBER: _ClassVar[int]
IS_CONNECTED_FIELD_NUMBER: _ClassVar[int]
baud: int
is_connected: bool
def __init__(self, baud: _Optional[int] = ..., is_connected: bool = ...) -> None: ...
@property
def serial(self) -> global___SerialConnectionStatus:
"""
Serial Status
"""
def __init__(
self,
*,
wifi: global___WifiConnectionStatus | None = ...,
ethernet: global___EthernetConnectionStatus | None = ...,
bluetooth: global___BluetoothConnectionStatus | None = ...,
serial: global___SerialConnectionStatus | None = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["_bluetooth", b"_bluetooth", "_ethernet", b"_ethernet", "_serial", b"_serial", "_wifi", b"_wifi", "bluetooth", b"bluetooth", "ethernet", b"ethernet", "serial", b"serial", "wifi", b"wifi"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["_bluetooth", b"_bluetooth", "_ethernet", b"_ethernet", "_serial", b"_serial", "_wifi", b"_wifi", "bluetooth", b"bluetooth", "ethernet", b"ethernet", "serial", b"serial", "wifi", b"wifi"]) -> None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_bluetooth", b"_bluetooth"]) -> typing.Literal["bluetooth"] | None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_ethernet", b"_ethernet"]) -> typing.Literal["ethernet"] | None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_serial", b"_serial"]) -> typing.Literal["serial"] | None: ...
@typing.overload
def WhichOneof(self, oneof_group: typing.Literal["_wifi", b"_wifi"]) -> typing.Literal["wifi"] | None: ...
global___DeviceConnectionStatus = DeviceConnectionStatus
@typing.final
class WifiConnectionStatus(google.protobuf.message.Message):
"""
WiFi connection status
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
STATUS_FIELD_NUMBER: builtins.int
SSID_FIELD_NUMBER: builtins.int
RSSI_FIELD_NUMBER: builtins.int
ssid: builtins.str
"""
WiFi access point SSID
"""
rssi: builtins.int
"""
RSSI of wireless connection
"""
@property
def status(self) -> global___NetworkConnectionStatus:
"""
Connection status
"""
def __init__(
self,
*,
status: global___NetworkConnectionStatus | None = ...,
ssid: builtins.str = ...,
rssi: builtins.int = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["status", b"status"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["rssi", b"rssi", "ssid", b"ssid", "status", b"status"]) -> None: ...
global___WifiConnectionStatus = WifiConnectionStatus
@typing.final
class EthernetConnectionStatus(google.protobuf.message.Message):
"""
Ethernet connection status
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
STATUS_FIELD_NUMBER: builtins.int
@property
def status(self) -> global___NetworkConnectionStatus:
"""
Connection status
"""
def __init__(
self,
*,
status: global___NetworkConnectionStatus | None = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["status", b"status"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["status", b"status"]) -> None: ...
global___EthernetConnectionStatus = EthernetConnectionStatus
@typing.final
class NetworkConnectionStatus(google.protobuf.message.Message):
"""
Ethernet or WiFi connection status
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
IP_ADDRESS_FIELD_NUMBER: builtins.int
IS_CONNECTED_FIELD_NUMBER: builtins.int
IS_MQTT_CONNECTED_FIELD_NUMBER: builtins.int
IS_SYSLOG_CONNECTED_FIELD_NUMBER: builtins.int
ip_address: builtins.int
"""
IP address of device
"""
is_connected: builtins.bool
"""
Whether the device has an active connection or not
"""
is_mqtt_connected: builtins.bool
"""
Whether the device has an active connection to an MQTT broker or not
"""
is_syslog_connected: builtins.bool
"""
Whether the device is actively remote syslogging or not
"""
def __init__(
self,
*,
ip_address: builtins.int = ...,
is_connected: builtins.bool = ...,
is_mqtt_connected: builtins.bool = ...,
is_syslog_connected: builtins.bool = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["ip_address", b"ip_address", "is_connected", b"is_connected", "is_mqtt_connected", b"is_mqtt_connected", "is_syslog_connected", b"is_syslog_connected"]) -> None: ...
global___NetworkConnectionStatus = NetworkConnectionStatus
@typing.final
class BluetoothConnectionStatus(google.protobuf.message.Message):
"""
Bluetooth connection status
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
PIN_FIELD_NUMBER: builtins.int
RSSI_FIELD_NUMBER: builtins.int
IS_CONNECTED_FIELD_NUMBER: builtins.int
pin: builtins.int
"""
The pairing PIN for bluetooth
"""
rssi: builtins.int
"""
RSSI of bluetooth connection
"""
is_connected: builtins.bool
"""
Whether the device has an active connection or not
"""
def __init__(
self,
*,
pin: builtins.int = ...,
rssi: builtins.int = ...,
is_connected: builtins.bool = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["is_connected", b"is_connected", "pin", b"pin", "rssi", b"rssi"]) -> None: ...
global___BluetoothConnectionStatus = BluetoothConnectionStatus
@typing.final
class SerialConnectionStatus(google.protobuf.message.Message):
"""
Serial connection status
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
BAUD_FIELD_NUMBER: builtins.int
IS_CONNECTED_FIELD_NUMBER: builtins.int
baud: builtins.int
"""
Serial baud rate
"""
is_connected: builtins.bool
"""
Whether the device has an active connection or not
"""
def __init__(
self,
*,
baud: builtins.int = ...,
is_connected: builtins.bool = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["baud", b"baud", "is_connected", b"is_connected"]) -> None: ...
global___SerialConnectionStatus = SerialConnectionStatus
class WifiConnectionStatus(_message.Message):
__slots__ = ["rssi", "ssid", "status"]
RSSI_FIELD_NUMBER: _ClassVar[int]
SSID_FIELD_NUMBER: _ClassVar[int]
STATUS_FIELD_NUMBER: _ClassVar[int]
rssi: int
ssid: str
status: NetworkConnectionStatus
def __init__(self, status: _Optional[_Union[NetworkConnectionStatus, _Mapping]] = ..., ssid: _Optional[str] = ..., rssi: _Optional[int] = ...) -> None: ...
+22 -22
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/device_ui.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,28 +15,28 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n#meshtastic/protobuf/device_ui.proto\x12\x13meshtastic.protobuf\"\xff\x05\n\x0e\x44\x65viceUIConfig\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x19\n\x11screen_brightness\x18\x02 \x01(\r\x12\x16\n\x0escreen_timeout\x18\x03 \x01(\r\x12\x13\n\x0bscreen_lock\x18\x04 \x01(\x08\x12\x15\n\rsettings_lock\x18\x05 \x01(\x08\x12\x10\n\x08pin_code\x18\x06 \x01(\r\x12)\n\x05theme\x18\x07 \x01(\x0e\x32\x1a.meshtastic.protobuf.Theme\x12\x15\n\ralert_enabled\x18\x08 \x01(\x08\x12\x16\n\x0e\x62\x61nner_enabled\x18\t \x01(\x08\x12\x14\n\x0cring_tone_id\x18\n \x01(\r\x12/\n\x08language\x18\x0b \x01(\x0e\x32\x1d.meshtastic.protobuf.Language\x12\x34\n\x0bnode_filter\x18\x0c \x01(\x0b\x32\x1f.meshtastic.protobuf.NodeFilter\x12:\n\x0enode_highlight\x18\r \x01(\x0b\x32\".meshtastic.protobuf.NodeHighlight\x12\x18\n\x10\x63\x61libration_data\x18\x0e \x01(\x0c\x12*\n\x08map_data\x18\x0f \x01(\x0b\x32\x18.meshtastic.protobuf.Map\x12\x36\n\x0c\x63ompass_mode\x18\x10 \x01(\x0e\x32 .meshtastic.protobuf.CompassMode\x12\x18\n\x10screen_rgb_color\x18\x11 \x01(\r\x12\x1b\n\x13is_clockface_analog\x18\x12 \x01(\x08\x12K\n\ngps_format\x18\x13 \x01(\x0e\x32\x37.meshtastic.protobuf.DeviceUIConfig.GpsCoordinateFormat\"V\n\x13GpsCoordinateFormat\x12\x07\n\x03\x44\x45\x43\x10\x00\x12\x07\n\x03\x44MS\x10\x01\x12\x07\n\x03UTM\x10\x02\x12\x08\n\x04MGRS\x10\x03\x12\x07\n\x03OLC\x10\x04\x12\x08\n\x04OSGR\x10\x05\x12\x07\n\x03MLS\x10\x06\"\xa7\x01\n\nNodeFilter\x12\x16\n\x0eunknown_switch\x18\x01 \x01(\x08\x12\x16\n\x0eoffline_switch\x18\x02 \x01(\x08\x12\x19\n\x11public_key_switch\x18\x03 \x01(\x08\x12\x11\n\thops_away\x18\x04 \x01(\x05\x12\x17\n\x0fposition_switch\x18\x05 \x01(\x08\x12\x11\n\tnode_name\x18\x06 \x01(\t\x12\x0f\n\x07\x63hannel\x18\x07 \x01(\x05\"~\n\rNodeHighlight\x12\x13\n\x0b\x63hat_switch\x18\x01 \x01(\x08\x12\x17\n\x0fposition_switch\x18\x02 \x01(\x08\x12\x18\n\x10telemetry_switch\x18\x03 \x01(\x08\x12\x12\n\niaq_switch\x18\x04 \x01(\x08\x12\x11\n\tnode_name\x18\x05 \x01(\t\"=\n\x08GeoPoint\x12\x0c\n\x04zoom\x18\x01 \x01(\x05\x12\x10\n\x08latitude\x18\x02 \x01(\x05\x12\x11\n\tlongitude\x18\x03 \x01(\x05\"U\n\x03Map\x12+\n\x04home\x18\x01 \x01(\x0b\x32\x1d.meshtastic.protobuf.GeoPoint\x12\r\n\x05style\x18\x02 \x01(\t\x12\x12\n\nfollow_gps\x18\x03 \x01(\x08*>\n\x0b\x43ompassMode\x12\x0b\n\x07\x44YNAMIC\x10\x00\x12\x0e\n\nFIXED_RING\x10\x01\x12\x12\n\x0e\x46REEZE_HEADING\x10\x02*%\n\x05Theme\x12\x08\n\x04\x44\x41RK\x10\x00\x12\t\n\x05LIGHT\x10\x01\x12\x07\n\x03RED\x10\x02*\xc0\x02\n\x08Language\x12\x0b\n\x07\x45NGLISH\x10\x00\x12\n\n\x06\x46RENCH\x10\x01\x12\n\n\x06GERMAN\x10\x02\x12\x0b\n\x07ITALIAN\x10\x03\x12\x0e\n\nPORTUGUESE\x10\x04\x12\x0b\n\x07SPANISH\x10\x05\x12\x0b\n\x07SWEDISH\x10\x06\x12\x0b\n\x07\x46INNISH\x10\x07\x12\n\n\x06POLISH\x10\x08\x12\x0b\n\x07TURKISH\x10\t\x12\x0b\n\x07SERBIAN\x10\n\x12\x0b\n\x07RUSSIAN\x10\x0b\x12\t\n\x05\x44UTCH\x10\x0c\x12\t\n\x05GREEK\x10\r\x12\r\n\tNORWEGIAN\x10\x0e\x12\r\n\tSLOVENIAN\x10\x0f\x12\r\n\tUKRAINIAN\x10\x10\x12\r\n\tBULGARIAN\x10\x11\x12\t\n\x05\x43ZECH\x10\x12\x12\n\n\x06\x44\x41NISH\x10\x13\x12\x16\n\x12SIMPLIFIED_CHINESE\x10\x1e\x12\x17\n\x13TRADITIONAL_CHINESE\x10\x1f\x42\x64\n\x14org.meshtastic.protoB\x0e\x44\x65viceUIProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.device_ui_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.device_ui_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\016DeviceUIProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_COMPASSMODE']._serialized_start=1278
_globals['_COMPASSMODE']._serialized_end=1340
_globals['_THEME']._serialized_start=1342
_globals['_THEME']._serialized_end=1379
_globals['_LANGUAGE']._serialized_start=1382
_globals['_LANGUAGE']._serialized_end=1702
_globals['_DEVICEUICONFIG']._serialized_start=61
_globals['_DEVICEUICONFIG']._serialized_end=828
_globals['_DEVICEUICONFIG_GPSCOORDINATEFORMAT']._serialized_start=742
_globals['_DEVICEUICONFIG_GPSCOORDINATEFORMAT']._serialized_end=828
_globals['_NODEFILTER']._serialized_start=831
_globals['_NODEFILTER']._serialized_end=998
_globals['_NODEHIGHLIGHT']._serialized_start=1000
_globals['_NODEHIGHLIGHT']._serialized_end=1126
_globals['_GEOPOINT']._serialized_start=1128
_globals['_GEOPOINT']._serialized_end=1189
_globals['_MAP']._serialized_start=1191
_globals['_MAP']._serialized_end=1276
_COMPASSMODE._serialized_start=1278
_COMPASSMODE._serialized_end=1340
_THEME._serialized_start=1342
_THEME._serialized_end=1379
_LANGUAGE._serialized_start=1382
_LANGUAGE._serialized_end=1702
_DEVICEUICONFIG._serialized_start=61
_DEVICEUICONFIG._serialized_end=828
_DEVICEUICONFIG_GPSCOORDINATEFORMAT._serialized_start=742
_DEVICEUICONFIG_GPSCOORDINATEFORMAT._serialized_end=828
_NODEFILTER._serialized_start=831
_NODEFILTER._serialized_end=998
_NODEHIGHLIGHT._serialized_start=1000
_NODEHIGHLIGHT._serialized_end=1126
_GEOPOINT._serialized_start=1128
_GEOPOINT._serialized_end=1189
_MAP._serialized_start=1191
_MAP._serialized_end=1276
# @@protoc_insertion_point(module_scope)
+137 -640
View File
@@ -1,649 +1,146 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
import builtins
import google.protobuf.descriptor
import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
import sys
import typing
BULGARIAN: Language
CZECH: Language
DANISH: Language
DARK: Theme
DESCRIPTOR: _descriptor.FileDescriptor
DUTCH: Language
DYNAMIC: CompassMode
ENGLISH: Language
FINNISH: Language
FIXED_RING: CompassMode
FREEZE_HEADING: CompassMode
FRENCH: Language
GERMAN: Language
GREEK: Language
ITALIAN: Language
LIGHT: Theme
NORWEGIAN: Language
POLISH: Language
PORTUGUESE: Language
RED: Theme
RUSSIAN: Language
SERBIAN: Language
SIMPLIFIED_CHINESE: Language
SLOVENIAN: Language
SPANISH: Language
SWEDISH: Language
TRADITIONAL_CHINESE: Language
TURKISH: Language
UKRAINIAN: Language
if sys.version_info >= (3, 10):
import typing as typing_extensions
else:
import typing_extensions
class DeviceUIConfig(_message.Message):
__slots__ = ["alert_enabled", "banner_enabled", "calibration_data", "compass_mode", "gps_format", "is_clockface_analog", "language", "map_data", "node_filter", "node_highlight", "pin_code", "ring_tone_id", "screen_brightness", "screen_lock", "screen_rgb_color", "screen_timeout", "settings_lock", "theme", "version"]
class GpsCoordinateFormat(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
ALERT_ENABLED_FIELD_NUMBER: _ClassVar[int]
BANNER_ENABLED_FIELD_NUMBER: _ClassVar[int]
CALIBRATION_DATA_FIELD_NUMBER: _ClassVar[int]
COMPASS_MODE_FIELD_NUMBER: _ClassVar[int]
DEC: DeviceUIConfig.GpsCoordinateFormat
DMS: DeviceUIConfig.GpsCoordinateFormat
GPS_FORMAT_FIELD_NUMBER: _ClassVar[int]
IS_CLOCKFACE_ANALOG_FIELD_NUMBER: _ClassVar[int]
LANGUAGE_FIELD_NUMBER: _ClassVar[int]
MAP_DATA_FIELD_NUMBER: _ClassVar[int]
MGRS: DeviceUIConfig.GpsCoordinateFormat
MLS: DeviceUIConfig.GpsCoordinateFormat
NODE_FILTER_FIELD_NUMBER: _ClassVar[int]
NODE_HIGHLIGHT_FIELD_NUMBER: _ClassVar[int]
OLC: DeviceUIConfig.GpsCoordinateFormat
OSGR: DeviceUIConfig.GpsCoordinateFormat
PIN_CODE_FIELD_NUMBER: _ClassVar[int]
RING_TONE_ID_FIELD_NUMBER: _ClassVar[int]
SCREEN_BRIGHTNESS_FIELD_NUMBER: _ClassVar[int]
SCREEN_LOCK_FIELD_NUMBER: _ClassVar[int]
SCREEN_RGB_COLOR_FIELD_NUMBER: _ClassVar[int]
SCREEN_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
SETTINGS_LOCK_FIELD_NUMBER: _ClassVar[int]
THEME_FIELD_NUMBER: _ClassVar[int]
UTM: DeviceUIConfig.GpsCoordinateFormat
VERSION_FIELD_NUMBER: _ClassVar[int]
alert_enabled: bool
banner_enabled: bool
calibration_data: bytes
compass_mode: CompassMode
gps_format: DeviceUIConfig.GpsCoordinateFormat
is_clockface_analog: bool
language: Language
map_data: Map
node_filter: NodeFilter
node_highlight: NodeHighlight
pin_code: int
ring_tone_id: int
screen_brightness: int
screen_lock: bool
screen_rgb_color: int
screen_timeout: int
settings_lock: bool
theme: Theme
version: int
def __init__(self, version: _Optional[int] = ..., screen_brightness: _Optional[int] = ..., screen_timeout: _Optional[int] = ..., screen_lock: bool = ..., settings_lock: bool = ..., pin_code: _Optional[int] = ..., theme: _Optional[_Union[Theme, str]] = ..., alert_enabled: bool = ..., banner_enabled: bool = ..., ring_tone_id: _Optional[int] = ..., language: _Optional[_Union[Language, str]] = ..., node_filter: _Optional[_Union[NodeFilter, _Mapping]] = ..., node_highlight: _Optional[_Union[NodeHighlight, _Mapping]] = ..., calibration_data: _Optional[bytes] = ..., map_data: _Optional[_Union[Map, _Mapping]] = ..., compass_mode: _Optional[_Union[CompassMode, str]] = ..., screen_rgb_color: _Optional[int] = ..., is_clockface_analog: bool = ..., gps_format: _Optional[_Union[DeviceUIConfig.GpsCoordinateFormat, str]] = ...) -> None: ...
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
class GeoPoint(_message.Message):
__slots__ = ["latitude", "longitude", "zoom"]
LATITUDE_FIELD_NUMBER: _ClassVar[int]
LONGITUDE_FIELD_NUMBER: _ClassVar[int]
ZOOM_FIELD_NUMBER: _ClassVar[int]
latitude: int
longitude: int
zoom: int
def __init__(self, zoom: _Optional[int] = ..., latitude: _Optional[int] = ..., longitude: _Optional[int] = ...) -> None: ...
class _CompassMode:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class Map(_message.Message):
__slots__ = ["follow_gps", "home", "style"]
FOLLOW_GPS_FIELD_NUMBER: _ClassVar[int]
HOME_FIELD_NUMBER: _ClassVar[int]
STYLE_FIELD_NUMBER: _ClassVar[int]
follow_gps: bool
home: GeoPoint
style: str
def __init__(self, home: _Optional[_Union[GeoPoint, _Mapping]] = ..., style: _Optional[str] = ..., follow_gps: bool = ...) -> None: ...
class _CompassModeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_CompassMode.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
DYNAMIC: _CompassMode.ValueType # 0
"""
Compass with dynamic ring and heading
"""
FIXED_RING: _CompassMode.ValueType # 1
"""
Compass with fixed ring and heading
"""
FREEZE_HEADING: _CompassMode.ValueType # 2
"""
Compass with heading and freeze option
"""
class NodeFilter(_message.Message):
__slots__ = ["channel", "hops_away", "node_name", "offline_switch", "position_switch", "public_key_switch", "unknown_switch"]
CHANNEL_FIELD_NUMBER: _ClassVar[int]
HOPS_AWAY_FIELD_NUMBER: _ClassVar[int]
NODE_NAME_FIELD_NUMBER: _ClassVar[int]
OFFLINE_SWITCH_FIELD_NUMBER: _ClassVar[int]
POSITION_SWITCH_FIELD_NUMBER: _ClassVar[int]
PUBLIC_KEY_SWITCH_FIELD_NUMBER: _ClassVar[int]
UNKNOWN_SWITCH_FIELD_NUMBER: _ClassVar[int]
channel: int
hops_away: int
node_name: str
offline_switch: bool
position_switch: bool
public_key_switch: bool
unknown_switch: bool
def __init__(self, unknown_switch: bool = ..., offline_switch: bool = ..., public_key_switch: bool = ..., hops_away: _Optional[int] = ..., position_switch: bool = ..., node_name: _Optional[str] = ..., channel: _Optional[int] = ...) -> None: ...
class CompassMode(_CompassMode, metaclass=_CompassModeEnumTypeWrapper): ...
class NodeHighlight(_message.Message):
__slots__ = ["chat_switch", "iaq_switch", "node_name", "position_switch", "telemetry_switch"]
CHAT_SWITCH_FIELD_NUMBER: _ClassVar[int]
IAQ_SWITCH_FIELD_NUMBER: _ClassVar[int]
NODE_NAME_FIELD_NUMBER: _ClassVar[int]
POSITION_SWITCH_FIELD_NUMBER: _ClassVar[int]
TELEMETRY_SWITCH_FIELD_NUMBER: _ClassVar[int]
chat_switch: bool
iaq_switch: bool
node_name: str
position_switch: bool
telemetry_switch: bool
def __init__(self, chat_switch: bool = ..., position_switch: bool = ..., telemetry_switch: bool = ..., iaq_switch: bool = ..., node_name: _Optional[str] = ...) -> None: ...
DYNAMIC: CompassMode.ValueType # 0
"""
Compass with dynamic ring and heading
"""
FIXED_RING: CompassMode.ValueType # 1
"""
Compass with fixed ring and heading
"""
FREEZE_HEADING: CompassMode.ValueType # 2
"""
Compass with heading and freeze option
"""
global___CompassMode = CompassMode
class CompassMode(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
class _Theme:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class Theme(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
class _ThemeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_Theme.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
DARK: _Theme.ValueType # 0
"""
Dark
"""
LIGHT: _Theme.ValueType # 1
"""
Light
"""
RED: _Theme.ValueType # 2
"""
Red
"""
class Theme(_Theme, metaclass=_ThemeEnumTypeWrapper): ...
DARK: Theme.ValueType # 0
"""
Dark
"""
LIGHT: Theme.ValueType # 1
"""
Light
"""
RED: Theme.ValueType # 2
"""
Red
"""
global___Theme = Theme
class _Language:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _LanguageEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_Language.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
ENGLISH: _Language.ValueType # 0
"""
English
"""
FRENCH: _Language.ValueType # 1
"""
French
"""
GERMAN: _Language.ValueType # 2
"""
German
"""
ITALIAN: _Language.ValueType # 3
"""
Italian
"""
PORTUGUESE: _Language.ValueType # 4
"""
Portuguese
"""
SPANISH: _Language.ValueType # 5
"""
Spanish
"""
SWEDISH: _Language.ValueType # 6
"""
Swedish
"""
FINNISH: _Language.ValueType # 7
"""
Finnish
"""
POLISH: _Language.ValueType # 8
"""
Polish
"""
TURKISH: _Language.ValueType # 9
"""
Turkish
"""
SERBIAN: _Language.ValueType # 10
"""
Serbian
"""
RUSSIAN: _Language.ValueType # 11
"""
Russian
"""
DUTCH: _Language.ValueType # 12
"""
Dutch
"""
GREEK: _Language.ValueType # 13
"""
Greek
"""
NORWEGIAN: _Language.ValueType # 14
"""
Norwegian
"""
SLOVENIAN: _Language.ValueType # 15
"""
Slovenian
"""
UKRAINIAN: _Language.ValueType # 16
"""
Ukrainian
"""
BULGARIAN: _Language.ValueType # 17
"""
Bulgarian
"""
CZECH: _Language.ValueType # 18
"""
Czech
"""
DANISH: _Language.ValueType # 19
"""
Danish
"""
SIMPLIFIED_CHINESE: _Language.ValueType # 30
"""
Simplified Chinese (experimental)
"""
TRADITIONAL_CHINESE: _Language.ValueType # 31
"""
Traditional Chinese (experimental)
"""
class Language(_Language, metaclass=_LanguageEnumTypeWrapper):
"""
Localization
"""
ENGLISH: Language.ValueType # 0
"""
English
"""
FRENCH: Language.ValueType # 1
"""
French
"""
GERMAN: Language.ValueType # 2
"""
German
"""
ITALIAN: Language.ValueType # 3
"""
Italian
"""
PORTUGUESE: Language.ValueType # 4
"""
Portuguese
"""
SPANISH: Language.ValueType # 5
"""
Spanish
"""
SWEDISH: Language.ValueType # 6
"""
Swedish
"""
FINNISH: Language.ValueType # 7
"""
Finnish
"""
POLISH: Language.ValueType # 8
"""
Polish
"""
TURKISH: Language.ValueType # 9
"""
Turkish
"""
SERBIAN: Language.ValueType # 10
"""
Serbian
"""
RUSSIAN: Language.ValueType # 11
"""
Russian
"""
DUTCH: Language.ValueType # 12
"""
Dutch
"""
GREEK: Language.ValueType # 13
"""
Greek
"""
NORWEGIAN: Language.ValueType # 14
"""
Norwegian
"""
SLOVENIAN: Language.ValueType # 15
"""
Slovenian
"""
UKRAINIAN: Language.ValueType # 16
"""
Ukrainian
"""
BULGARIAN: Language.ValueType # 17
"""
Bulgarian
"""
CZECH: Language.ValueType # 18
"""
Czech
"""
DANISH: Language.ValueType # 19
"""
Danish
"""
SIMPLIFIED_CHINESE: Language.ValueType # 30
"""
Simplified Chinese (experimental)
"""
TRADITIONAL_CHINESE: Language.ValueType # 31
"""
Traditional Chinese (experimental)
"""
global___Language = Language
@typing.final
class DeviceUIConfig(google.protobuf.message.Message):
"""
Protobuf structures for device-ui persistency
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
class _GpsCoordinateFormat:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _GpsCoordinateFormatEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[DeviceUIConfig._GpsCoordinateFormat.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
DEC: DeviceUIConfig._GpsCoordinateFormat.ValueType # 0
"""
GPS coordinates are displayed in the normal decimal degrees format:
DD.DDDDDD DDD.DDDDDD
"""
DMS: DeviceUIConfig._GpsCoordinateFormat.ValueType # 1
"""
GPS coordinates are displayed in the degrees minutes seconds format:
DD°MM'SS"C DDD°MM'SS"C, where C is the compass point representing the locations quadrant
"""
UTM: DeviceUIConfig._GpsCoordinateFormat.ValueType # 2
"""
Universal Transverse Mercator format:
ZZB EEEEEE NNNNNNN, where Z is zone, B is band, E is easting, N is northing
"""
MGRS: DeviceUIConfig._GpsCoordinateFormat.ValueType # 3
"""
Military Grid Reference System format:
ZZB CD EEEEE NNNNN, where Z is zone, B is band, C is the east 100k square, D is the north 100k square,
E is easting, N is northing
"""
OLC: DeviceUIConfig._GpsCoordinateFormat.ValueType # 4
"""
Open Location Code (aka Plus Codes).
"""
OSGR: DeviceUIConfig._GpsCoordinateFormat.ValueType # 5
"""
Ordnance Survey Grid Reference (the National Grid System of the UK).
Format: AB EEEEE NNNNN, where A is the east 100k square, B is the north 100k square,
E is the easting, N is the northing
"""
MLS: DeviceUIConfig._GpsCoordinateFormat.ValueType # 6
"""
Maidenhead Locator System
Described here: https://en.wikipedia.org/wiki/Maidenhead_Locator_System
"""
class GpsCoordinateFormat(_GpsCoordinateFormat, metaclass=_GpsCoordinateFormatEnumTypeWrapper):
"""
How the GPS coordinates are displayed on the OLED screen.
"""
DEC: DeviceUIConfig.GpsCoordinateFormat.ValueType # 0
"""
GPS coordinates are displayed in the normal decimal degrees format:
DD.DDDDDD DDD.DDDDDD
"""
DMS: DeviceUIConfig.GpsCoordinateFormat.ValueType # 1
"""
GPS coordinates are displayed in the degrees minutes seconds format:
DD°MM'SS"C DDD°MM'SS"C, where C is the compass point representing the locations quadrant
"""
UTM: DeviceUIConfig.GpsCoordinateFormat.ValueType # 2
"""
Universal Transverse Mercator format:
ZZB EEEEEE NNNNNNN, where Z is zone, B is band, E is easting, N is northing
"""
MGRS: DeviceUIConfig.GpsCoordinateFormat.ValueType # 3
"""
Military Grid Reference System format:
ZZB CD EEEEE NNNNN, where Z is zone, B is band, C is the east 100k square, D is the north 100k square,
E is easting, N is northing
"""
OLC: DeviceUIConfig.GpsCoordinateFormat.ValueType # 4
"""
Open Location Code (aka Plus Codes).
"""
OSGR: DeviceUIConfig.GpsCoordinateFormat.ValueType # 5
"""
Ordnance Survey Grid Reference (the National Grid System of the UK).
Format: AB EEEEE NNNNN, where A is the east 100k square, B is the north 100k square,
E is the easting, N is the northing
"""
MLS: DeviceUIConfig.GpsCoordinateFormat.ValueType # 6
"""
Maidenhead Locator System
Described here: https://en.wikipedia.org/wiki/Maidenhead_Locator_System
"""
VERSION_FIELD_NUMBER: builtins.int
SCREEN_BRIGHTNESS_FIELD_NUMBER: builtins.int
SCREEN_TIMEOUT_FIELD_NUMBER: builtins.int
SCREEN_LOCK_FIELD_NUMBER: builtins.int
SETTINGS_LOCK_FIELD_NUMBER: builtins.int
PIN_CODE_FIELD_NUMBER: builtins.int
THEME_FIELD_NUMBER: builtins.int
ALERT_ENABLED_FIELD_NUMBER: builtins.int
BANNER_ENABLED_FIELD_NUMBER: builtins.int
RING_TONE_ID_FIELD_NUMBER: builtins.int
LANGUAGE_FIELD_NUMBER: builtins.int
NODE_FILTER_FIELD_NUMBER: builtins.int
NODE_HIGHLIGHT_FIELD_NUMBER: builtins.int
CALIBRATION_DATA_FIELD_NUMBER: builtins.int
MAP_DATA_FIELD_NUMBER: builtins.int
COMPASS_MODE_FIELD_NUMBER: builtins.int
SCREEN_RGB_COLOR_FIELD_NUMBER: builtins.int
IS_CLOCKFACE_ANALOG_FIELD_NUMBER: builtins.int
GPS_FORMAT_FIELD_NUMBER: builtins.int
version: builtins.int
"""
A version integer used to invalidate saved files when we make incompatible changes.
"""
screen_brightness: builtins.int
"""
TFT display brightness 1..255
"""
screen_timeout: builtins.int
"""
Screen timeout 0..900
"""
screen_lock: builtins.bool
"""
Screen/Settings lock enabled
"""
settings_lock: builtins.bool
pin_code: builtins.int
theme: global___Theme.ValueType
"""
Color theme
"""
alert_enabled: builtins.bool
"""
Audible message, banner and ring tone
"""
banner_enabled: builtins.bool
ring_tone_id: builtins.int
language: global___Language.ValueType
"""
Localization
"""
calibration_data: builtins.bytes
"""
8 integers for screen calibration data
"""
compass_mode: global___CompassMode.ValueType
"""
Compass mode
"""
screen_rgb_color: builtins.int
"""
RGB color for BaseUI
0xRRGGBB format, e.g. 0xFF0000 for red
"""
is_clockface_analog: builtins.bool
"""
Clockface analog style
true for analog clockface, false for digital clockface
"""
gps_format: global___DeviceUIConfig.GpsCoordinateFormat.ValueType
"""
How the GPS coordinates are formatted on the OLED screen.
"""
@property
def node_filter(self) -> global___NodeFilter:
"""
Node list filter
"""
@property
def node_highlight(self) -> global___NodeHighlight:
"""
Node list highlightening
"""
@property
def map_data(self) -> global___Map:
"""
Map related data
"""
def __init__(
self,
*,
version: builtins.int = ...,
screen_brightness: builtins.int = ...,
screen_timeout: builtins.int = ...,
screen_lock: builtins.bool = ...,
settings_lock: builtins.bool = ...,
pin_code: builtins.int = ...,
theme: global___Theme.ValueType = ...,
alert_enabled: builtins.bool = ...,
banner_enabled: builtins.bool = ...,
ring_tone_id: builtins.int = ...,
language: global___Language.ValueType = ...,
node_filter: global___NodeFilter | None = ...,
node_highlight: global___NodeHighlight | None = ...,
calibration_data: builtins.bytes = ...,
map_data: global___Map | None = ...,
compass_mode: global___CompassMode.ValueType = ...,
screen_rgb_color: builtins.int = ...,
is_clockface_analog: builtins.bool = ...,
gps_format: global___DeviceUIConfig.GpsCoordinateFormat.ValueType = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["map_data", b"map_data", "node_filter", b"node_filter", "node_highlight", b"node_highlight"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["alert_enabled", b"alert_enabled", "banner_enabled", b"banner_enabled", "calibration_data", b"calibration_data", "compass_mode", b"compass_mode", "gps_format", b"gps_format", "is_clockface_analog", b"is_clockface_analog", "language", b"language", "map_data", b"map_data", "node_filter", b"node_filter", "node_highlight", b"node_highlight", "pin_code", b"pin_code", "ring_tone_id", b"ring_tone_id", "screen_brightness", b"screen_brightness", "screen_lock", b"screen_lock", "screen_rgb_color", b"screen_rgb_color", "screen_timeout", b"screen_timeout", "settings_lock", b"settings_lock", "theme", b"theme", "version", b"version"]) -> None: ...
global___DeviceUIConfig = DeviceUIConfig
@typing.final
class NodeFilter(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
UNKNOWN_SWITCH_FIELD_NUMBER: builtins.int
OFFLINE_SWITCH_FIELD_NUMBER: builtins.int
PUBLIC_KEY_SWITCH_FIELD_NUMBER: builtins.int
HOPS_AWAY_FIELD_NUMBER: builtins.int
POSITION_SWITCH_FIELD_NUMBER: builtins.int
NODE_NAME_FIELD_NUMBER: builtins.int
CHANNEL_FIELD_NUMBER: builtins.int
unknown_switch: builtins.bool
"""
Filter unknown nodes
"""
offline_switch: builtins.bool
"""
Filter offline nodes
"""
public_key_switch: builtins.bool
"""
Filter nodes w/o public key
"""
hops_away: builtins.int
"""
Filter based on hops away
"""
position_switch: builtins.bool
"""
Filter nodes w/o position
"""
node_name: builtins.str
"""
Filter nodes by matching name string
"""
channel: builtins.int
"""
Filter based on channel
"""
def __init__(
self,
*,
unknown_switch: builtins.bool = ...,
offline_switch: builtins.bool = ...,
public_key_switch: builtins.bool = ...,
hops_away: builtins.int = ...,
position_switch: builtins.bool = ...,
node_name: builtins.str = ...,
channel: builtins.int = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["channel", b"channel", "hops_away", b"hops_away", "node_name", b"node_name", "offline_switch", b"offline_switch", "position_switch", b"position_switch", "public_key_switch", b"public_key_switch", "unknown_switch", b"unknown_switch"]) -> None: ...
global___NodeFilter = NodeFilter
@typing.final
class NodeHighlight(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
CHAT_SWITCH_FIELD_NUMBER: builtins.int
POSITION_SWITCH_FIELD_NUMBER: builtins.int
TELEMETRY_SWITCH_FIELD_NUMBER: builtins.int
IAQ_SWITCH_FIELD_NUMBER: builtins.int
NODE_NAME_FIELD_NUMBER: builtins.int
chat_switch: builtins.bool
"""
Hightlight nodes w/ active chat
"""
position_switch: builtins.bool
"""
Highlight nodes w/ position
"""
telemetry_switch: builtins.bool
"""
Highlight nodes w/ telemetry data
"""
iaq_switch: builtins.bool
"""
Highlight nodes w/ iaq data
"""
node_name: builtins.str
"""
Highlight nodes by matching name string
"""
def __init__(
self,
*,
chat_switch: builtins.bool = ...,
position_switch: builtins.bool = ...,
telemetry_switch: builtins.bool = ...,
iaq_switch: builtins.bool = ...,
node_name: builtins.str = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["chat_switch", b"chat_switch", "iaq_switch", b"iaq_switch", "node_name", b"node_name", "position_switch", b"position_switch", "telemetry_switch", b"telemetry_switch"]) -> None: ...
global___NodeHighlight = NodeHighlight
@typing.final
class GeoPoint(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
ZOOM_FIELD_NUMBER: builtins.int
LATITUDE_FIELD_NUMBER: builtins.int
LONGITUDE_FIELD_NUMBER: builtins.int
zoom: builtins.int
"""
Zoom level
"""
latitude: builtins.int
"""
Coordinate: latitude
"""
longitude: builtins.int
"""
Coordinate: longitude
"""
def __init__(
self,
*,
zoom: builtins.int = ...,
latitude: builtins.int = ...,
longitude: builtins.int = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["latitude", b"latitude", "longitude", b"longitude", "zoom", b"zoom"]) -> None: ...
global___GeoPoint = GeoPoint
@typing.final
class Map(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
HOME_FIELD_NUMBER: builtins.int
STYLE_FIELD_NUMBER: builtins.int
FOLLOW_GPS_FIELD_NUMBER: builtins.int
style: builtins.str
"""
Map tile style
"""
follow_gps: builtins.bool
"""
Map scroll follows GPS
"""
@property
def home(self) -> global___GeoPoint:
"""
Home coordinates
"""
def __init__(
self,
*,
home: global___GeoPoint | None = ...,
style: builtins.str = ...,
follow_gps: builtins.bool = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["home", b"home"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["follow_gps", b"follow_gps", "home", b"home", "style", b"style"]) -> None: ...
global___Map = Map
class Language(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
+18 -18
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/deviceonly.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -21,10 +21,10 @@ from meshtastic.protobuf import nanopb_pb2 as meshtastic_dot_protobuf_dot_nanopb
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$meshtastic/protobuf/deviceonly.proto\x12\x13meshtastic.protobuf\x1a!meshtastic/protobuf/channel.proto\x1a meshtastic/protobuf/config.proto\x1a#meshtastic/protobuf/localonly.proto\x1a\x1emeshtastic/protobuf/mesh.proto\x1a#meshtastic/protobuf/telemetry.proto\x1a meshtastic/protobuf/nanopb.proto\"\x99\x01\n\x0cPositionLite\x12\x12\n\nlatitude_i\x18\x01 \x01(\x0f\x12\x13\n\x0blongitude_i\x18\x02 \x01(\x0f\x12\x10\n\x08\x61ltitude\x18\x03 \x01(\x05\x12\x0c\n\x04time\x18\x04 \x01(\x07\x12@\n\x0flocation_source\x18\x05 \x01(\x0e\x32\'.meshtastic.protobuf.Position.LocSource\"\x94\x02\n\x08UserLite\x12\x13\n\x07macaddr\x18\x01 \x01(\x0c\x42\x02\x18\x01\x12\x11\n\tlong_name\x18\x02 \x01(\t\x12\x12\n\nshort_name\x18\x03 \x01(\t\x12\x34\n\x08hw_model\x18\x04 \x01(\x0e\x32\".meshtastic.protobuf.HardwareModel\x12\x13\n\x0bis_licensed\x18\x05 \x01(\x08\x12;\n\x04role\x18\x06 \x01(\x0e\x32-.meshtastic.protobuf.Config.DeviceConfig.Role\x12\x12\n\npublic_key\x18\x07 \x01(\x0c\x12\x1c\n\x0fis_unmessagable\x18\t \x01(\x08H\x00\x88\x01\x01\x42\x12\n\x10_is_unmessagable\"\xf0\x02\n\x0cNodeInfoLite\x12\x0b\n\x03num\x18\x01 \x01(\r\x12+\n\x04user\x18\x02 \x01(\x0b\x32\x1d.meshtastic.protobuf.UserLite\x12\x33\n\x08position\x18\x03 \x01(\x0b\x32!.meshtastic.protobuf.PositionLite\x12\x0b\n\x03snr\x18\x04 \x01(\x02\x12\x12\n\nlast_heard\x18\x05 \x01(\x07\x12:\n\x0e\x64\x65vice_metrics\x18\x06 \x01(\x0b\x32\".meshtastic.protobuf.DeviceMetrics\x12\x0f\n\x07\x63hannel\x18\x07 \x01(\r\x12\x10\n\x08via_mqtt\x18\x08 \x01(\x08\x12\x16\n\thops_away\x18\t \x01(\rH\x00\x88\x01\x01\x12\x13\n\x0bis_favorite\x18\n \x01(\x08\x12\x12\n\nis_ignored\x18\x0b \x01(\x08\x12\x10\n\x08next_hop\x18\x0c \x01(\r\x12\x10\n\x08\x62itfield\x18\r \x01(\rB\x0c\n\n_hops_away\"\xa1\x03\n\x0b\x44\x65viceState\x12\x30\n\x07my_node\x18\x02 \x01(\x0b\x32\x1f.meshtastic.protobuf.MyNodeInfo\x12(\n\x05owner\x18\x03 \x01(\x0b\x32\x19.meshtastic.protobuf.User\x12\x36\n\rreceive_queue\x18\x05 \x03(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12\x0f\n\x07version\x18\x08 \x01(\r\x12\x38\n\x0frx_text_message\x18\x07 \x01(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12\x13\n\x07no_save\x18\t \x01(\x08\x42\x02\x18\x01\x12\x19\n\rdid_gps_reset\x18\x0b \x01(\x08\x42\x02\x18\x01\x12\x34\n\x0brx_waypoint\x18\x0c \x01(\x0b\x32\x1f.meshtastic.protobuf.MeshPacket\x12M\n\x19node_remote_hardware_pins\x18\r \x03(\x0b\x32*.meshtastic.protobuf.NodeRemoteHardwarePin\"}\n\x0cNodeDatabase\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\\\n\x05nodes\x18\x02 \x03(\x0b\x32!.meshtastic.protobuf.NodeInfoLiteB*\x92?\'\x92\x01$std::vector<meshtastic_NodeInfoLite>\"N\n\x0b\x43hannelFile\x12.\n\x08\x63hannels\x18\x01 \x03(\x0b\x32\x1c.meshtastic.protobuf.Channel\x12\x0f\n\x07version\x18\x02 \x01(\r\"\x86\x02\n\x11\x42\x61\x63kupPreferences\x12\x0f\n\x07version\x18\x01 \x01(\r\x12\x11\n\ttimestamp\x18\x02 \x01(\x07\x12\x30\n\x06\x63onfig\x18\x03 \x01(\x0b\x32 .meshtastic.protobuf.LocalConfig\x12=\n\rmodule_config\x18\x04 \x01(\x0b\x32&.meshtastic.protobuf.LocalModuleConfig\x12\x32\n\x08\x63hannels\x18\x05 \x01(\x0b\x32 .meshtastic.protobuf.ChannelFile\x12(\n\x05owner\x18\x06 \x01(\x0b\x32\x19.meshtastic.protobuf.UserBn\n\x14org.meshtastic.protoB\nDeviceOnlyZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x92?\x0b\xc2\x01\x08<vector>b\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.deviceonly_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.deviceonly_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\nDeviceOnlyZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000\222?\013\302\001\010<vector>'
_USERLITE.fields_by_name['macaddr']._options = None
@@ -35,18 +35,18 @@ if _descriptor._USE_C_DESCRIPTORS == False:
_DEVICESTATE.fields_by_name['did_gps_reset']._serialized_options = b'\030\001'
_NODEDATABASE.fields_by_name['nodes']._options = None
_NODEDATABASE.fields_by_name['nodes']._serialized_options = b'\222?\'\222\001$std::vector<meshtastic_NodeInfoLite>'
_globals['_POSITIONLITE']._serialized_start=271
_globals['_POSITIONLITE']._serialized_end=424
_globals['_USERLITE']._serialized_start=427
_globals['_USERLITE']._serialized_end=703
_globals['_NODEINFOLITE']._serialized_start=706
_globals['_NODEINFOLITE']._serialized_end=1074
_globals['_DEVICESTATE']._serialized_start=1077
_globals['_DEVICESTATE']._serialized_end=1494
_globals['_NODEDATABASE']._serialized_start=1496
_globals['_NODEDATABASE']._serialized_end=1621
_globals['_CHANNELFILE']._serialized_start=1623
_globals['_CHANNELFILE']._serialized_end=1701
_globals['_BACKUPPREFERENCES']._serialized_start=1704
_globals['_BACKUPPREFERENCES']._serialized_end=1966
_POSITIONLITE._serialized_start=271
_POSITIONLITE._serialized_end=424
_USERLITE._serialized_start=427
_USERLITE._serialized_end=703
_NODEINFOLITE._serialized_start=706
_NODEINFOLITE._serialized_end=1074
_DEVICESTATE._serialized_start=1077
_DEVICESTATE._serialized_end=1494
_NODEDATABASE._serialized_start=1496
_NODEDATABASE._serialized_end=1621
_CHANNELFILE._serialized_start=1623
_CHANNELFILE._serialized_end=1701
_BACKUPPREFERENCES._serialized_start=1704
_BACKUPPREFERENCES._serialized_end=1966
# @@protoc_insertion_point(module_scope)
+122 -450
View File
@@ -1,458 +1,130 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from meshtastic.protobuf import channel_pb2 as _channel_pb2
from meshtastic.protobuf import config_pb2 as _config_pb2
from meshtastic.protobuf import localonly_pb2 as _localonly_pb2
from meshtastic.protobuf import mesh_pb2 as _mesh_pb2
from meshtastic.protobuf import telemetry_pb2 as _telemetry_pb2
from meshtastic.protobuf import nanopb_pb2 as _nanopb_pb2
from google.protobuf.internal import containers as _containers
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union
import builtins
import collections.abc
import google.protobuf.descriptor
import google.protobuf.internal.containers
import google.protobuf.message
import meshtastic.protobuf.channel_pb2
import meshtastic.protobuf.config_pb2
import meshtastic.protobuf.localonly_pb2
import meshtastic.protobuf.mesh_pb2
import meshtastic.protobuf.telemetry_pb2
import typing
DESCRIPTOR: _descriptor.FileDescriptor
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
class BackupPreferences(_message.Message):
__slots__ = ["channels", "config", "module_config", "owner", "timestamp", "version"]
CHANNELS_FIELD_NUMBER: _ClassVar[int]
CONFIG_FIELD_NUMBER: _ClassVar[int]
MODULE_CONFIG_FIELD_NUMBER: _ClassVar[int]
OWNER_FIELD_NUMBER: _ClassVar[int]
TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
VERSION_FIELD_NUMBER: _ClassVar[int]
channels: ChannelFile
config: _localonly_pb2.LocalConfig
module_config: _localonly_pb2.LocalModuleConfig
owner: _mesh_pb2.User
timestamp: int
version: int
def __init__(self, version: _Optional[int] = ..., timestamp: _Optional[int] = ..., config: _Optional[_Union[_localonly_pb2.LocalConfig, _Mapping]] = ..., module_config: _Optional[_Union[_localonly_pb2.LocalModuleConfig, _Mapping]] = ..., channels: _Optional[_Union[ChannelFile, _Mapping]] = ..., owner: _Optional[_Union[_mesh_pb2.User, _Mapping]] = ...) -> None: ...
@typing.final
class PositionLite(google.protobuf.message.Message):
"""
Position with static location information only for NodeDBLite
"""
class ChannelFile(_message.Message):
__slots__ = ["channels", "version"]
CHANNELS_FIELD_NUMBER: _ClassVar[int]
VERSION_FIELD_NUMBER: _ClassVar[int]
channels: _containers.RepeatedCompositeFieldContainer[_channel_pb2.Channel]
version: int
def __init__(self, channels: _Optional[_Iterable[_Union[_channel_pb2.Channel, _Mapping]]] = ..., version: _Optional[int] = ...) -> None: ...
DESCRIPTOR: google.protobuf.descriptor.Descriptor
class DeviceState(_message.Message):
__slots__ = ["did_gps_reset", "my_node", "no_save", "node_remote_hardware_pins", "owner", "receive_queue", "rx_text_message", "rx_waypoint", "version"]
DID_GPS_RESET_FIELD_NUMBER: _ClassVar[int]
MY_NODE_FIELD_NUMBER: _ClassVar[int]
NODE_REMOTE_HARDWARE_PINS_FIELD_NUMBER: _ClassVar[int]
NO_SAVE_FIELD_NUMBER: _ClassVar[int]
OWNER_FIELD_NUMBER: _ClassVar[int]
RECEIVE_QUEUE_FIELD_NUMBER: _ClassVar[int]
RX_TEXT_MESSAGE_FIELD_NUMBER: _ClassVar[int]
RX_WAYPOINT_FIELD_NUMBER: _ClassVar[int]
VERSION_FIELD_NUMBER: _ClassVar[int]
did_gps_reset: bool
my_node: _mesh_pb2.MyNodeInfo
no_save: bool
node_remote_hardware_pins: _containers.RepeatedCompositeFieldContainer[_mesh_pb2.NodeRemoteHardwarePin]
owner: _mesh_pb2.User
receive_queue: _containers.RepeatedCompositeFieldContainer[_mesh_pb2.MeshPacket]
rx_text_message: _mesh_pb2.MeshPacket
rx_waypoint: _mesh_pb2.MeshPacket
version: int
def __init__(self, my_node: _Optional[_Union[_mesh_pb2.MyNodeInfo, _Mapping]] = ..., owner: _Optional[_Union[_mesh_pb2.User, _Mapping]] = ..., receive_queue: _Optional[_Iterable[_Union[_mesh_pb2.MeshPacket, _Mapping]]] = ..., version: _Optional[int] = ..., rx_text_message: _Optional[_Union[_mesh_pb2.MeshPacket, _Mapping]] = ..., no_save: bool = ..., did_gps_reset: bool = ..., rx_waypoint: _Optional[_Union[_mesh_pb2.MeshPacket, _Mapping]] = ..., node_remote_hardware_pins: _Optional[_Iterable[_Union[_mesh_pb2.NodeRemoteHardwarePin, _Mapping]]] = ...) -> None: ...
LATITUDE_I_FIELD_NUMBER: builtins.int
LONGITUDE_I_FIELD_NUMBER: builtins.int
ALTITUDE_FIELD_NUMBER: builtins.int
TIME_FIELD_NUMBER: builtins.int
LOCATION_SOURCE_FIELD_NUMBER: builtins.int
latitude_i: builtins.int
"""
The new preferred location encoding, multiply by 1e-7 to get degrees
in floating point
"""
longitude_i: builtins.int
"""
TODO: REPLACE
"""
altitude: builtins.int
"""
In meters above MSL (but see issue #359)
"""
time: builtins.int
"""
This is usually not sent over the mesh (to save space), but it is sent
from the phone so that the local device can set its RTC If it is sent over
the mesh (because there are devices on the mesh without GPS), it will only
be sent by devices which has a hardware GPS clock.
seconds since 1970
"""
location_source: meshtastic.protobuf.mesh_pb2.Position.LocSource.ValueType
"""
TODO: REPLACE
"""
def __init__(
self,
*,
latitude_i: builtins.int = ...,
longitude_i: builtins.int = ...,
altitude: builtins.int = ...,
time: builtins.int = ...,
location_source: meshtastic.protobuf.mesh_pb2.Position.LocSource.ValueType = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["altitude", b"altitude", "latitude_i", b"latitude_i", "location_source", b"location_source", "longitude_i", b"longitude_i", "time", b"time"]) -> None: ...
class NodeDatabase(_message.Message):
__slots__ = ["nodes", "version"]
NODES_FIELD_NUMBER: _ClassVar[int]
VERSION_FIELD_NUMBER: _ClassVar[int]
nodes: _containers.RepeatedCompositeFieldContainer[NodeInfoLite]
version: int
def __init__(self, version: _Optional[int] = ..., nodes: _Optional[_Iterable[_Union[NodeInfoLite, _Mapping]]] = ...) -> None: ...
global___PositionLite = PositionLite
class NodeInfoLite(_message.Message):
__slots__ = ["bitfield", "channel", "device_metrics", "hops_away", "is_favorite", "is_ignored", "last_heard", "next_hop", "num", "position", "snr", "user", "via_mqtt"]
BITFIELD_FIELD_NUMBER: _ClassVar[int]
CHANNEL_FIELD_NUMBER: _ClassVar[int]
DEVICE_METRICS_FIELD_NUMBER: _ClassVar[int]
HOPS_AWAY_FIELD_NUMBER: _ClassVar[int]
IS_FAVORITE_FIELD_NUMBER: _ClassVar[int]
IS_IGNORED_FIELD_NUMBER: _ClassVar[int]
LAST_HEARD_FIELD_NUMBER: _ClassVar[int]
NEXT_HOP_FIELD_NUMBER: _ClassVar[int]
NUM_FIELD_NUMBER: _ClassVar[int]
POSITION_FIELD_NUMBER: _ClassVar[int]
SNR_FIELD_NUMBER: _ClassVar[int]
USER_FIELD_NUMBER: _ClassVar[int]
VIA_MQTT_FIELD_NUMBER: _ClassVar[int]
bitfield: int
channel: int
device_metrics: _telemetry_pb2.DeviceMetrics
hops_away: int
is_favorite: bool
is_ignored: bool
last_heard: int
next_hop: int
num: int
position: PositionLite
snr: float
user: UserLite
via_mqtt: bool
def __init__(self, num: _Optional[int] = ..., user: _Optional[_Union[UserLite, _Mapping]] = ..., position: _Optional[_Union[PositionLite, _Mapping]] = ..., snr: _Optional[float] = ..., last_heard: _Optional[int] = ..., device_metrics: _Optional[_Union[_telemetry_pb2.DeviceMetrics, _Mapping]] = ..., channel: _Optional[int] = ..., via_mqtt: bool = ..., hops_away: _Optional[int] = ..., is_favorite: bool = ..., is_ignored: bool = ..., next_hop: _Optional[int] = ..., bitfield: _Optional[int] = ...) -> None: ...
@typing.final
class UserLite(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
class PositionLite(_message.Message):
__slots__ = ["altitude", "latitude_i", "location_source", "longitude_i", "time"]
ALTITUDE_FIELD_NUMBER: _ClassVar[int]
LATITUDE_I_FIELD_NUMBER: _ClassVar[int]
LOCATION_SOURCE_FIELD_NUMBER: _ClassVar[int]
LONGITUDE_I_FIELD_NUMBER: _ClassVar[int]
TIME_FIELD_NUMBER: _ClassVar[int]
altitude: int
latitude_i: int
location_source: _mesh_pb2.Position.LocSource
longitude_i: int
time: int
def __init__(self, latitude_i: _Optional[int] = ..., longitude_i: _Optional[int] = ..., altitude: _Optional[int] = ..., time: _Optional[int] = ..., location_source: _Optional[_Union[_mesh_pb2.Position.LocSource, str]] = ...) -> None: ...
MACADDR_FIELD_NUMBER: builtins.int
LONG_NAME_FIELD_NUMBER: builtins.int
SHORT_NAME_FIELD_NUMBER: builtins.int
HW_MODEL_FIELD_NUMBER: builtins.int
IS_LICENSED_FIELD_NUMBER: builtins.int
ROLE_FIELD_NUMBER: builtins.int
PUBLIC_KEY_FIELD_NUMBER: builtins.int
IS_UNMESSAGABLE_FIELD_NUMBER: builtins.int
macaddr: builtins.bytes
"""
This is the addr of the radio.
"""
long_name: builtins.str
"""
A full name for this user, i.e. "Kevin Hester"
"""
short_name: builtins.str
"""
A VERY short name, ideally two characters.
Suitable for a tiny OLED screen
"""
hw_model: meshtastic.protobuf.mesh_pb2.HardwareModel.ValueType
"""
TBEAM, HELTEC, etc...
Starting in 1.2.11 moved to hw_model enum in the NodeInfo object.
Apps will still need the string here for older builds
(so OTA update can find the right image), but if the enum is available it will be used instead.
"""
is_licensed: builtins.bool
"""
In some regions Ham radio operators have different bandwidth limitations than others.
If this user is a licensed operator, set this flag.
Also, "long_name" should be their licence number.
"""
role: meshtastic.protobuf.config_pb2.Config.DeviceConfig.Role.ValueType
"""
Indicates that the user's role in the mesh
"""
public_key: builtins.bytes
"""
The public key of the user's device.
This is sent out to other nodes on the mesh to allow them to compute a shared secret key.
"""
is_unmessagable: builtins.bool
"""
Whether or not the node can be messaged
"""
def __init__(
self,
*,
macaddr: builtins.bytes = ...,
long_name: builtins.str = ...,
short_name: builtins.str = ...,
hw_model: meshtastic.protobuf.mesh_pb2.HardwareModel.ValueType = ...,
is_licensed: builtins.bool = ...,
role: meshtastic.protobuf.config_pb2.Config.DeviceConfig.Role.ValueType = ...,
public_key: builtins.bytes = ...,
is_unmessagable: builtins.bool | None = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["_is_unmessagable", b"_is_unmessagable", "is_unmessagable", b"is_unmessagable"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["_is_unmessagable", b"_is_unmessagable", "hw_model", b"hw_model", "is_licensed", b"is_licensed", "is_unmessagable", b"is_unmessagable", "long_name", b"long_name", "macaddr", b"macaddr", "public_key", b"public_key", "role", b"role", "short_name", b"short_name"]) -> None: ...
def WhichOneof(self, oneof_group: typing.Literal["_is_unmessagable", b"_is_unmessagable"]) -> typing.Literal["is_unmessagable"] | None: ...
global___UserLite = UserLite
@typing.final
class NodeInfoLite(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
NUM_FIELD_NUMBER: builtins.int
USER_FIELD_NUMBER: builtins.int
POSITION_FIELD_NUMBER: builtins.int
SNR_FIELD_NUMBER: builtins.int
LAST_HEARD_FIELD_NUMBER: builtins.int
DEVICE_METRICS_FIELD_NUMBER: builtins.int
CHANNEL_FIELD_NUMBER: builtins.int
VIA_MQTT_FIELD_NUMBER: builtins.int
HOPS_AWAY_FIELD_NUMBER: builtins.int
IS_FAVORITE_FIELD_NUMBER: builtins.int
IS_IGNORED_FIELD_NUMBER: builtins.int
NEXT_HOP_FIELD_NUMBER: builtins.int
BITFIELD_FIELD_NUMBER: builtins.int
num: builtins.int
"""
The node number
"""
snr: builtins.float
"""
Returns the Signal-to-noise ratio (SNR) of the last received message,
as measured by the receiver. Return SNR of the last received message in dB
"""
last_heard: builtins.int
"""
Set to indicate the last time we received a packet from this node
"""
channel: builtins.int
"""
local channel index we heard that node on. Only populated if its not the default channel.
"""
via_mqtt: builtins.bool
"""
True if we witnessed the node over MQTT instead of LoRA transport
"""
hops_away: builtins.int
"""
Number of hops away from us this node is (0 if direct neighbor)
"""
is_favorite: builtins.bool
"""
True if node is in our favorites list
Persists between NodeDB internal clean ups
"""
is_ignored: builtins.bool
"""
True if node is in our ignored list
Persists between NodeDB internal clean ups
"""
next_hop: builtins.int
"""
Last byte of the node number of the node that should be used as the next hop to reach this node.
"""
bitfield: builtins.int
"""
Bitfield for storing booleans.
LSB 0 is_key_manually_verified
"""
@property
def user(self) -> global___UserLite:
"""
The user info for this node
"""
@property
def position(self) -> global___PositionLite:
"""
This position data. Note: before 1.2.14 we would also store the last time we've heard from this node in position.time, that is no longer true.
Position.time now indicates the last time we received a POSITION from that node.
"""
@property
def device_metrics(self) -> meshtastic.protobuf.telemetry_pb2.DeviceMetrics:
"""
The latest device metrics for the node.
"""
def __init__(
self,
*,
num: builtins.int = ...,
user: global___UserLite | None = ...,
position: global___PositionLite | None = ...,
snr: builtins.float = ...,
last_heard: builtins.int = ...,
device_metrics: meshtastic.protobuf.telemetry_pb2.DeviceMetrics | None = ...,
channel: builtins.int = ...,
via_mqtt: builtins.bool = ...,
hops_away: builtins.int | None = ...,
is_favorite: builtins.bool = ...,
is_ignored: builtins.bool = ...,
next_hop: builtins.int = ...,
bitfield: builtins.int = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["_hops_away", b"_hops_away", "device_metrics", b"device_metrics", "hops_away", b"hops_away", "position", b"position", "user", b"user"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["_hops_away", b"_hops_away", "bitfield", b"bitfield", "channel", b"channel", "device_metrics", b"device_metrics", "hops_away", b"hops_away", "is_favorite", b"is_favorite", "is_ignored", b"is_ignored", "last_heard", b"last_heard", "next_hop", b"next_hop", "num", b"num", "position", b"position", "snr", b"snr", "user", b"user", "via_mqtt", b"via_mqtt"]) -> None: ...
def WhichOneof(self, oneof_group: typing.Literal["_hops_away", b"_hops_away"]) -> typing.Literal["hops_away"] | None: ...
global___NodeInfoLite = NodeInfoLite
@typing.final
class DeviceState(google.protobuf.message.Message):
"""
This message is never sent over the wire, but it is used for serializing DB
state to flash in the device code
FIXME, since we write this each time we enter deep sleep (and have infinite
flash) it would be better to use some sort of append only data structure for
the receive queue and use the preferences store for the other stuff
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
MY_NODE_FIELD_NUMBER: builtins.int
OWNER_FIELD_NUMBER: builtins.int
RECEIVE_QUEUE_FIELD_NUMBER: builtins.int
VERSION_FIELD_NUMBER: builtins.int
RX_TEXT_MESSAGE_FIELD_NUMBER: builtins.int
NO_SAVE_FIELD_NUMBER: builtins.int
DID_GPS_RESET_FIELD_NUMBER: builtins.int
RX_WAYPOINT_FIELD_NUMBER: builtins.int
NODE_REMOTE_HARDWARE_PINS_FIELD_NUMBER: builtins.int
version: builtins.int
"""
A version integer used to invalidate old save files when we make
incompatible changes This integer is set at build time and is private to
NodeDB.cpp in the device code.
"""
no_save: builtins.bool
"""
Used only during development.
Indicates developer is testing and changes should never be saved to flash.
Deprecated in 2.3.1
"""
did_gps_reset: builtins.bool
"""
Previously used to manage GPS factory resets.
Deprecated in 2.5.23
"""
@property
def my_node(self) -> meshtastic.protobuf.mesh_pb2.MyNodeInfo:
"""
Read only settings/info about this node
"""
@property
def owner(self) -> meshtastic.protobuf.mesh_pb2.User:
"""
My owner info
"""
@property
def receive_queue(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[meshtastic.protobuf.mesh_pb2.MeshPacket]:
"""
Received packets saved for delivery to the phone
"""
@property
def rx_text_message(self) -> meshtastic.protobuf.mesh_pb2.MeshPacket:
"""
We keep the last received text message (only) stored in the device flash,
so we can show it on the screen.
Might be null
"""
@property
def rx_waypoint(self) -> meshtastic.protobuf.mesh_pb2.MeshPacket:
"""
We keep the last received waypoint stored in the device flash,
so we can show it on the screen.
Might be null
"""
@property
def node_remote_hardware_pins(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[meshtastic.protobuf.mesh_pb2.NodeRemoteHardwarePin]:
"""
The mesh's nodes with their available gpio pins for RemoteHardware module
"""
def __init__(
self,
*,
my_node: meshtastic.protobuf.mesh_pb2.MyNodeInfo | None = ...,
owner: meshtastic.protobuf.mesh_pb2.User | None = ...,
receive_queue: collections.abc.Iterable[meshtastic.protobuf.mesh_pb2.MeshPacket] | None = ...,
version: builtins.int = ...,
rx_text_message: meshtastic.protobuf.mesh_pb2.MeshPacket | None = ...,
no_save: builtins.bool = ...,
did_gps_reset: builtins.bool = ...,
rx_waypoint: meshtastic.protobuf.mesh_pb2.MeshPacket | None = ...,
node_remote_hardware_pins: collections.abc.Iterable[meshtastic.protobuf.mesh_pb2.NodeRemoteHardwarePin] | None = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["my_node", b"my_node", "owner", b"owner", "rx_text_message", b"rx_text_message", "rx_waypoint", b"rx_waypoint"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["did_gps_reset", b"did_gps_reset", "my_node", b"my_node", "no_save", b"no_save", "node_remote_hardware_pins", b"node_remote_hardware_pins", "owner", b"owner", "receive_queue", b"receive_queue", "rx_text_message", b"rx_text_message", "rx_waypoint", b"rx_waypoint", "version", b"version"]) -> None: ...
global___DeviceState = DeviceState
@typing.final
class NodeDatabase(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
VERSION_FIELD_NUMBER: builtins.int
NODES_FIELD_NUMBER: builtins.int
version: builtins.int
"""
A version integer used to invalidate old save files when we make
incompatible changes This integer is set at build time and is private to
NodeDB.cpp in the device code.
"""
@property
def nodes(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___NodeInfoLite]:
"""
New lite version of NodeDB to decrease memory footprint
"""
def __init__(
self,
*,
version: builtins.int = ...,
nodes: collections.abc.Iterable[global___NodeInfoLite] | None = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["nodes", b"nodes", "version", b"version"]) -> None: ...
global___NodeDatabase = NodeDatabase
@typing.final
class ChannelFile(google.protobuf.message.Message):
"""
The on-disk saved channels
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
CHANNELS_FIELD_NUMBER: builtins.int
VERSION_FIELD_NUMBER: builtins.int
version: builtins.int
"""
A version integer used to invalidate old save files when we make
incompatible changes This integer is set at build time and is private to
NodeDB.cpp in the device code.
"""
@property
def channels(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[meshtastic.protobuf.channel_pb2.Channel]:
"""
The channels our node knows about
"""
def __init__(
self,
*,
channels: collections.abc.Iterable[meshtastic.protobuf.channel_pb2.Channel] | None = ...,
version: builtins.int = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["channels", b"channels", "version", b"version"]) -> None: ...
global___ChannelFile = ChannelFile
@typing.final
class BackupPreferences(google.protobuf.message.Message):
"""
The on-disk backup of the node's preferences
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
VERSION_FIELD_NUMBER: builtins.int
TIMESTAMP_FIELD_NUMBER: builtins.int
CONFIG_FIELD_NUMBER: builtins.int
MODULE_CONFIG_FIELD_NUMBER: builtins.int
CHANNELS_FIELD_NUMBER: builtins.int
OWNER_FIELD_NUMBER: builtins.int
version: builtins.int
"""
The version of the backup
"""
timestamp: builtins.int
"""
The timestamp of the backup (if node has time)
"""
@property
def config(self) -> meshtastic.protobuf.localonly_pb2.LocalConfig:
"""
The node's configuration
"""
@property
def module_config(self) -> meshtastic.protobuf.localonly_pb2.LocalModuleConfig:
"""
The node's module configuration
"""
@property
def channels(self) -> global___ChannelFile:
"""
The node's channels
"""
@property
def owner(self) -> meshtastic.protobuf.mesh_pb2.User:
"""
The node's user (owner) information
"""
def __init__(
self,
*,
version: builtins.int = ...,
timestamp: builtins.int = ...,
config: meshtastic.protobuf.localonly_pb2.LocalConfig | None = ...,
module_config: meshtastic.protobuf.localonly_pb2.LocalModuleConfig | None = ...,
channels: global___ChannelFile | None = ...,
owner: meshtastic.protobuf.mesh_pb2.User | None = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["channels", b"channels", "config", b"config", "module_config", b"module_config", "owner", b"owner"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["channels", b"channels", "config", b"config", "module_config", b"module_config", "owner", b"owner", "timestamp", b"timestamp", "version", b"version"]) -> None: ...
global___BackupPreferences = BackupPreferences
class UserLite(_message.Message):
__slots__ = ["hw_model", "is_licensed", "is_unmessagable", "long_name", "macaddr", "public_key", "role", "short_name"]
HW_MODEL_FIELD_NUMBER: _ClassVar[int]
IS_LICENSED_FIELD_NUMBER: _ClassVar[int]
IS_UNMESSAGABLE_FIELD_NUMBER: _ClassVar[int]
LONG_NAME_FIELD_NUMBER: _ClassVar[int]
MACADDR_FIELD_NUMBER: _ClassVar[int]
PUBLIC_KEY_FIELD_NUMBER: _ClassVar[int]
ROLE_FIELD_NUMBER: _ClassVar[int]
SHORT_NAME_FIELD_NUMBER: _ClassVar[int]
hw_model: _mesh_pb2.HardwareModel
is_licensed: bool
is_unmessagable: bool
long_name: str
macaddr: bytes
public_key: bytes
role: _config_pb2.Config.DeviceConfig.Role
short_name: str
def __init__(self, macaddr: _Optional[bytes] = ..., long_name: _Optional[str] = ..., short_name: _Optional[str] = ..., hw_model: _Optional[_Union[_mesh_pb2.HardwareModel, str]] = ..., is_licensed: bool = ..., role: _Optional[_Union[_config_pb2.Config.DeviceConfig.Role, str]] = ..., public_key: _Optional[bytes] = ..., is_unmessagable: bool = ...) -> None: ...
+10 -10
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/interdevice.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,16 +15,16 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n%meshtastic/protobuf/interdevice.proto\x12\x13meshtastic.protobuf\"s\n\nSensorData\x12.\n\x04type\x18\x01 \x01(\x0e\x32 .meshtastic.protobuf.MessageType\x12\x15\n\x0b\x66loat_value\x18\x02 \x01(\x02H\x00\x12\x16\n\x0cuint32_value\x18\x03 \x01(\rH\x00\x42\x06\n\x04\x64\x61ta\"_\n\x12InterdeviceMessage\x12\x0e\n\x04nmea\x18\x01 \x01(\tH\x00\x12\x31\n\x06sensor\x18\x02 \x01(\x0b\x32\x1f.meshtastic.protobuf.SensorDataH\x00\x42\x06\n\x04\x64\x61ta*\xd5\x01\n\x0bMessageType\x12\x07\n\x03\x41\x43K\x10\x00\x12\x15\n\x10\x43OLLECT_INTERVAL\x10\xa0\x01\x12\x0c\n\x07\x42\x45\x45P_ON\x10\xa1\x01\x12\r\n\x08\x42\x45\x45P_OFF\x10\xa2\x01\x12\r\n\x08SHUTDOWN\x10\xa3\x01\x12\r\n\x08POWER_ON\x10\xa4\x01\x12\x0f\n\nSCD41_TEMP\x10\xb0\x01\x12\x13\n\x0eSCD41_HUMIDITY\x10\xb1\x01\x12\x0e\n\tSCD41_CO2\x10\xb2\x01\x12\x0f\n\nAHT20_TEMP\x10\xb3\x01\x12\x13\n\x0e\x41HT20_HUMIDITY\x10\xb4\x01\x12\x0f\n\nTVOC_INDEX\x10\xb5\x01\x42g\n\x14org.meshtastic.protoB\x11InterdeviceProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.interdevice_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.interdevice_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\021InterdeviceProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_MESSAGETYPE']._serialized_start=277
_globals['_MESSAGETYPE']._serialized_end=490
_globals['_SENSORDATA']._serialized_start=62
_globals['_SENSORDATA']._serialized_end=177
_globals['_INTERDEVICEMESSAGE']._serialized_start=179
_globals['_INTERDEVICEMESSAGE']._serialized_end=274
_MESSAGETYPE._serialized_start=277
_MESSAGETYPE._serialized_end=490
_SENSORDATA._serialized_start=62
_SENSORDATA._serialized_end=177
_INTERDEVICEMESSAGE._serialized_start=179
_INTERDEVICEMESSAGE._serialized_end=274
# @@protoc_insertion_point(module_scope)
+35 -101
View File
@@ -1,105 +1,39 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
import builtins
import google.protobuf.descriptor
import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
import sys
import typing
ACK: MessageType
AHT20_HUMIDITY: MessageType
AHT20_TEMP: MessageType
BEEP_OFF: MessageType
BEEP_ON: MessageType
COLLECT_INTERVAL: MessageType
DESCRIPTOR: _descriptor.FileDescriptor
POWER_ON: MessageType
SCD41_CO2: MessageType
SCD41_HUMIDITY: MessageType
SCD41_TEMP: MessageType
SHUTDOWN: MessageType
TVOC_INDEX: MessageType
if sys.version_info >= (3, 10):
import typing as typing_extensions
else:
import typing_extensions
class InterdeviceMessage(_message.Message):
__slots__ = ["nmea", "sensor"]
NMEA_FIELD_NUMBER: _ClassVar[int]
SENSOR_FIELD_NUMBER: _ClassVar[int]
nmea: str
sensor: SensorData
def __init__(self, nmea: _Optional[str] = ..., sensor: _Optional[_Union[SensorData, _Mapping]] = ...) -> None: ...
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
class SensorData(_message.Message):
__slots__ = ["float_value", "type", "uint32_value"]
FLOAT_VALUE_FIELD_NUMBER: _ClassVar[int]
TYPE_FIELD_NUMBER: _ClassVar[int]
UINT32_VALUE_FIELD_NUMBER: _ClassVar[int]
float_value: float
type: MessageType
uint32_value: int
def __init__(self, type: _Optional[_Union[MessageType, str]] = ..., float_value: _Optional[float] = ..., uint32_value: _Optional[int] = ...) -> None: ...
class _MessageType:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _MessageTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_MessageType.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
ACK: _MessageType.ValueType # 0
COLLECT_INTERVAL: _MessageType.ValueType # 160
"""in ms"""
BEEP_ON: _MessageType.ValueType # 161
"""duration ms"""
BEEP_OFF: _MessageType.ValueType # 162
"""cancel prematurely"""
SHUTDOWN: _MessageType.ValueType # 163
POWER_ON: _MessageType.ValueType # 164
SCD41_TEMP: _MessageType.ValueType # 176
SCD41_HUMIDITY: _MessageType.ValueType # 177
SCD41_CO2: _MessageType.ValueType # 178
AHT20_TEMP: _MessageType.ValueType # 179
AHT20_HUMIDITY: _MessageType.ValueType # 180
TVOC_INDEX: _MessageType.ValueType # 181
class MessageType(_MessageType, metaclass=_MessageTypeEnumTypeWrapper):
"""encapsulate up to 1k of NMEA string data"""
ACK: MessageType.ValueType # 0
COLLECT_INTERVAL: MessageType.ValueType # 160
"""in ms"""
BEEP_ON: MessageType.ValueType # 161
"""duration ms"""
BEEP_OFF: MessageType.ValueType # 162
"""cancel prematurely"""
SHUTDOWN: MessageType.ValueType # 163
POWER_ON: MessageType.ValueType # 164
SCD41_TEMP: MessageType.ValueType # 176
SCD41_HUMIDITY: MessageType.ValueType # 177
SCD41_CO2: MessageType.ValueType # 178
AHT20_TEMP: MessageType.ValueType # 179
AHT20_HUMIDITY: MessageType.ValueType # 180
TVOC_INDEX: MessageType.ValueType # 181
global___MessageType = MessageType
@typing.final
class SensorData(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
TYPE_FIELD_NUMBER: builtins.int
FLOAT_VALUE_FIELD_NUMBER: builtins.int
UINT32_VALUE_FIELD_NUMBER: builtins.int
type: global___MessageType.ValueType
"""The message type"""
float_value: builtins.float
uint32_value: builtins.int
def __init__(
self,
*,
type: global___MessageType.ValueType = ...,
float_value: builtins.float = ...,
uint32_value: builtins.int = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["data", b"data", "float_value", b"float_value", "uint32_value", b"uint32_value"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["data", b"data", "float_value", b"float_value", "type", b"type", "uint32_value", b"uint32_value"]) -> None: ...
def WhichOneof(self, oneof_group: typing.Literal["data", b"data"]) -> typing.Literal["float_value", "uint32_value"] | None: ...
global___SensorData = SensorData
@typing.final
class InterdeviceMessage(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
NMEA_FIELD_NUMBER: builtins.int
SENSOR_FIELD_NUMBER: builtins.int
nmea: builtins.str
@property
def sensor(self) -> global___SensorData: ...
def __init__(
self,
*,
nmea: builtins.str = ...,
sensor: global___SensorData | None = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["data", b"data", "nmea", b"nmea", "sensor", b"sensor"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["data", b"data", "nmea", b"nmea", "sensor", b"sensor"]) -> None: ...
def WhichOneof(self, oneof_group: typing.Literal["data", b"data"]) -> typing.Literal["nmea", "sensor"] | None: ...
global___InterdeviceMessage = InterdeviceMessage
class MessageType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
+9 -9
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/localonly.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,16 +15,16 @@ from meshtastic.protobuf import config_pb2 as meshtastic_dot_protobuf_dot_config
from meshtastic.protobuf import module_config_pb2 as meshtastic_dot_protobuf_dot_module__config__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n#meshtastic/protobuf/localonly.proto\x12\x13meshtastic.protobuf\x1a meshtastic/protobuf/config.proto\x1a\'meshtastic/protobuf/module_config.proto\"\xfa\x03\n\x0bLocalConfig\x12\x38\n\x06\x64\x65vice\x18\x01 \x01(\x0b\x32(.meshtastic.protobuf.Config.DeviceConfig\x12<\n\x08position\x18\x02 \x01(\x0b\x32*.meshtastic.protobuf.Config.PositionConfig\x12\x36\n\x05power\x18\x03 \x01(\x0b\x32\'.meshtastic.protobuf.Config.PowerConfig\x12:\n\x07network\x18\x04 \x01(\x0b\x32).meshtastic.protobuf.Config.NetworkConfig\x12:\n\x07\x64isplay\x18\x05 \x01(\x0b\x32).meshtastic.protobuf.Config.DisplayConfig\x12\x34\n\x04lora\x18\x06 \x01(\x0b\x32&.meshtastic.protobuf.Config.LoRaConfig\x12>\n\tbluetooth\x18\x07 \x01(\x0b\x32+.meshtastic.protobuf.Config.BluetoothConfig\x12\x0f\n\x07version\x18\x08 \x01(\r\x12<\n\x08security\x18\t \x01(\x0b\x32*.meshtastic.protobuf.Config.SecurityConfig\"\xf0\x07\n\x11LocalModuleConfig\x12:\n\x04mqtt\x18\x01 \x01(\x0b\x32,.meshtastic.protobuf.ModuleConfig.MQTTConfig\x12>\n\x06serial\x18\x02 \x01(\x0b\x32..meshtastic.protobuf.ModuleConfig.SerialConfig\x12[\n\x15\x65xternal_notification\x18\x03 \x01(\x0b\x32<.meshtastic.protobuf.ModuleConfig.ExternalNotificationConfig\x12K\n\rstore_forward\x18\x04 \x01(\x0b\x32\x34.meshtastic.protobuf.ModuleConfig.StoreForwardConfig\x12\x45\n\nrange_test\x18\x05 \x01(\x0b\x32\x31.meshtastic.protobuf.ModuleConfig.RangeTestConfig\x12\x44\n\ttelemetry\x18\x06 \x01(\x0b\x32\x31.meshtastic.protobuf.ModuleConfig.TelemetryConfig\x12M\n\x0e\x63\x61nned_message\x18\x07 \x01(\x0b\x32\x35.meshtastic.protobuf.ModuleConfig.CannedMessageConfig\x12<\n\x05\x61udio\x18\t \x01(\x0b\x32-.meshtastic.protobuf.ModuleConfig.AudioConfig\x12O\n\x0fremote_hardware\x18\n \x01(\x0b\x32\x36.meshtastic.protobuf.ModuleConfig.RemoteHardwareConfig\x12K\n\rneighbor_info\x18\x0b \x01(\x0b\x32\x34.meshtastic.protobuf.ModuleConfig.NeighborInfoConfig\x12Q\n\x10\x61mbient_lighting\x18\x0c \x01(\x0b\x32\x37.meshtastic.protobuf.ModuleConfig.AmbientLightingConfig\x12Q\n\x10\x64\x65tection_sensor\x18\r \x01(\x0b\x32\x37.meshtastic.protobuf.ModuleConfig.DetectionSensorConfig\x12\x46\n\npaxcounter\x18\x0e \x01(\x0b\x32\x32.meshtastic.protobuf.ModuleConfig.PaxcounterConfig\x12\x0f\n\x07version\x18\x08 \x01(\rBe\n\x14org.meshtastic.protoB\x0fLocalOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n#meshtastic/protobuf/localonly.proto\x12\x13meshtastic.protobuf\x1a meshtastic/protobuf/config.proto\x1a\'meshtastic/protobuf/module_config.proto\"\xfa\x03\n\x0bLocalConfig\x12\x38\n\x06\x64\x65vice\x18\x01 \x01(\x0b\x32(.meshtastic.protobuf.Config.DeviceConfig\x12<\n\x08position\x18\x02 \x01(\x0b\x32*.meshtastic.protobuf.Config.PositionConfig\x12\x36\n\x05power\x18\x03 \x01(\x0b\x32\'.meshtastic.protobuf.Config.PowerConfig\x12:\n\x07network\x18\x04 \x01(\x0b\x32).meshtastic.protobuf.Config.NetworkConfig\x12:\n\x07\x64isplay\x18\x05 \x01(\x0b\x32).meshtastic.protobuf.Config.DisplayConfig\x12\x34\n\x04lora\x18\x06 \x01(\x0b\x32&.meshtastic.protobuf.Config.LoRaConfig\x12>\n\tbluetooth\x18\x07 \x01(\x0b\x32+.meshtastic.protobuf.Config.BluetoothConfig\x12\x0f\n\x07version\x18\x08 \x01(\r\x12<\n\x08security\x18\t \x01(\x0b\x32*.meshtastic.protobuf.Config.SecurityConfig\"\xcf\t\n\x11LocalModuleConfig\x12:\n\x04mqtt\x18\x01 \x01(\x0b\x32,.meshtastic.protobuf.ModuleConfig.MQTTConfig\x12>\n\x06serial\x18\x02 \x01(\x0b\x32..meshtastic.protobuf.ModuleConfig.SerialConfig\x12[\n\x15\x65xternal_notification\x18\x03 \x01(\x0b\x32<.meshtastic.protobuf.ModuleConfig.ExternalNotificationConfig\x12K\n\rstore_forward\x18\x04 \x01(\x0b\x32\x34.meshtastic.protobuf.ModuleConfig.StoreForwardConfig\x12\x45\n\nrange_test\x18\x05 \x01(\x0b\x32\x31.meshtastic.protobuf.ModuleConfig.RangeTestConfig\x12\x44\n\ttelemetry\x18\x06 \x01(\x0b\x32\x31.meshtastic.protobuf.ModuleConfig.TelemetryConfig\x12M\n\x0e\x63\x61nned_message\x18\x07 \x01(\x0b\x32\x35.meshtastic.protobuf.ModuleConfig.CannedMessageConfig\x12<\n\x05\x61udio\x18\t \x01(\x0b\x32-.meshtastic.protobuf.ModuleConfig.AudioConfig\x12O\n\x0fremote_hardware\x18\n \x01(\x0b\x32\x36.meshtastic.protobuf.ModuleConfig.RemoteHardwareConfig\x12K\n\rneighbor_info\x18\x0b \x01(\x0b\x32\x34.meshtastic.protobuf.ModuleConfig.NeighborInfoConfig\x12Q\n\x10\x61mbient_lighting\x18\x0c \x01(\x0b\x32\x37.meshtastic.protobuf.ModuleConfig.AmbientLightingConfig\x12Q\n\x10\x64\x65tection_sensor\x18\r \x01(\x0b\x32\x37.meshtastic.protobuf.ModuleConfig.DetectionSensorConfig\x12\x46\n\npaxcounter\x18\x0e \x01(\x0b\x32\x32.meshtastic.protobuf.ModuleConfig.PaxcounterConfig\x12L\n\rstatusmessage\x18\x0f \x01(\x0b\x32\x35.meshtastic.protobuf.ModuleConfig.StatusMessageConfig\x12U\n\x12traffic_management\x18\x10 \x01(\x0b\x32\x39.meshtastic.protobuf.ModuleConfig.TrafficManagementConfig\x12\x38\n\x03tak\x18\x11 \x01(\x0b\x32+.meshtastic.protobuf.ModuleConfig.TAKConfig\x12\x0f\n\x07version\x18\x08 \x01(\rBe\n\x14org.meshtastic.protoB\x0fLocalOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.localonly_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.localonly_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\017LocalOnlyProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_LOCALCONFIG']._serialized_start=136
_globals['_LOCALCONFIG']._serialized_end=642
_globals['_LOCALMODULECONFIG']._serialized_start=645
_globals['_LOCALMODULECONFIG']._serialized_end=1653
_LOCALCONFIG._serialized_start=136
_LOCALCONFIG._serialized_end=642
_LOCALMODULECONFIG._serialized_start=645
_LOCALMODULECONFIG._serialized_end=1876
# @@protoc_insertion_point(module_scope)
+64 -225
View File
@@ -1,228 +1,67 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from meshtastic.protobuf import config_pb2 as _config_pb2
from meshtastic.protobuf import module_config_pb2 as _module_config_pb2
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
import builtins
import google.protobuf.descriptor
import google.protobuf.message
import meshtastic.protobuf.config_pb2
import meshtastic.protobuf.module_config_pb2
import typing
DESCRIPTOR: _descriptor.FileDescriptor
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
class LocalConfig(_message.Message):
__slots__ = ["bluetooth", "device", "display", "lora", "network", "position", "power", "security", "version"]
BLUETOOTH_FIELD_NUMBER: _ClassVar[int]
DEVICE_FIELD_NUMBER: _ClassVar[int]
DISPLAY_FIELD_NUMBER: _ClassVar[int]
LORA_FIELD_NUMBER: _ClassVar[int]
NETWORK_FIELD_NUMBER: _ClassVar[int]
POSITION_FIELD_NUMBER: _ClassVar[int]
POWER_FIELD_NUMBER: _ClassVar[int]
SECURITY_FIELD_NUMBER: _ClassVar[int]
VERSION_FIELD_NUMBER: _ClassVar[int]
bluetooth: _config_pb2.Config.BluetoothConfig
device: _config_pb2.Config.DeviceConfig
display: _config_pb2.Config.DisplayConfig
lora: _config_pb2.Config.LoRaConfig
network: _config_pb2.Config.NetworkConfig
position: _config_pb2.Config.PositionConfig
power: _config_pb2.Config.PowerConfig
security: _config_pb2.Config.SecurityConfig
version: int
def __init__(self, device: _Optional[_Union[_config_pb2.Config.DeviceConfig, _Mapping]] = ..., position: _Optional[_Union[_config_pb2.Config.PositionConfig, _Mapping]] = ..., power: _Optional[_Union[_config_pb2.Config.PowerConfig, _Mapping]] = ..., network: _Optional[_Union[_config_pb2.Config.NetworkConfig, _Mapping]] = ..., display: _Optional[_Union[_config_pb2.Config.DisplayConfig, _Mapping]] = ..., lora: _Optional[_Union[_config_pb2.Config.LoRaConfig, _Mapping]] = ..., bluetooth: _Optional[_Union[_config_pb2.Config.BluetoothConfig, _Mapping]] = ..., version: _Optional[int] = ..., security: _Optional[_Union[_config_pb2.Config.SecurityConfig, _Mapping]] = ...) -> None: ...
@typing.final
class LocalConfig(google.protobuf.message.Message):
"""
Protobuf structures common to apponly.proto and deviceonly.proto
This is never sent over the wire, only for local use
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
DEVICE_FIELD_NUMBER: builtins.int
POSITION_FIELD_NUMBER: builtins.int
POWER_FIELD_NUMBER: builtins.int
NETWORK_FIELD_NUMBER: builtins.int
DISPLAY_FIELD_NUMBER: builtins.int
LORA_FIELD_NUMBER: builtins.int
BLUETOOTH_FIELD_NUMBER: builtins.int
VERSION_FIELD_NUMBER: builtins.int
SECURITY_FIELD_NUMBER: builtins.int
version: builtins.int
"""
A version integer used to invalidate old save files when we make
incompatible changes This integer is set at build time and is private to
NodeDB.cpp in the device code.
"""
@property
def device(self) -> meshtastic.protobuf.config_pb2.Config.DeviceConfig:
"""
The part of the config that is specific to the Device
"""
@property
def position(self) -> meshtastic.protobuf.config_pb2.Config.PositionConfig:
"""
The part of the config that is specific to the GPS Position
"""
@property
def power(self) -> meshtastic.protobuf.config_pb2.Config.PowerConfig:
"""
The part of the config that is specific to the Power settings
"""
@property
def network(self) -> meshtastic.protobuf.config_pb2.Config.NetworkConfig:
"""
The part of the config that is specific to the Wifi Settings
"""
@property
def display(self) -> meshtastic.protobuf.config_pb2.Config.DisplayConfig:
"""
The part of the config that is specific to the Display
"""
@property
def lora(self) -> meshtastic.protobuf.config_pb2.Config.LoRaConfig:
"""
The part of the config that is specific to the Lora Radio
"""
@property
def bluetooth(self) -> meshtastic.protobuf.config_pb2.Config.BluetoothConfig:
"""
The part of the config that is specific to the Bluetooth settings
"""
@property
def security(self) -> meshtastic.protobuf.config_pb2.Config.SecurityConfig:
"""
The part of the config that is specific to Security settings
"""
def __init__(
self,
*,
device: meshtastic.protobuf.config_pb2.Config.DeviceConfig | None = ...,
position: meshtastic.protobuf.config_pb2.Config.PositionConfig | None = ...,
power: meshtastic.protobuf.config_pb2.Config.PowerConfig | None = ...,
network: meshtastic.protobuf.config_pb2.Config.NetworkConfig | None = ...,
display: meshtastic.protobuf.config_pb2.Config.DisplayConfig | None = ...,
lora: meshtastic.protobuf.config_pb2.Config.LoRaConfig | None = ...,
bluetooth: meshtastic.protobuf.config_pb2.Config.BluetoothConfig | None = ...,
version: builtins.int = ...,
security: meshtastic.protobuf.config_pb2.Config.SecurityConfig | None = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["bluetooth", b"bluetooth", "device", b"device", "display", b"display", "lora", b"lora", "network", b"network", "position", b"position", "power", b"power", "security", b"security"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["bluetooth", b"bluetooth", "device", b"device", "display", b"display", "lora", b"lora", "network", b"network", "position", b"position", "power", b"power", "security", b"security", "version", b"version"]) -> None: ...
global___LocalConfig = LocalConfig
@typing.final
class LocalModuleConfig(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
MQTT_FIELD_NUMBER: builtins.int
SERIAL_FIELD_NUMBER: builtins.int
EXTERNAL_NOTIFICATION_FIELD_NUMBER: builtins.int
STORE_FORWARD_FIELD_NUMBER: builtins.int
RANGE_TEST_FIELD_NUMBER: builtins.int
TELEMETRY_FIELD_NUMBER: builtins.int
CANNED_MESSAGE_FIELD_NUMBER: builtins.int
AUDIO_FIELD_NUMBER: builtins.int
REMOTE_HARDWARE_FIELD_NUMBER: builtins.int
NEIGHBOR_INFO_FIELD_NUMBER: builtins.int
AMBIENT_LIGHTING_FIELD_NUMBER: builtins.int
DETECTION_SENSOR_FIELD_NUMBER: builtins.int
PAXCOUNTER_FIELD_NUMBER: builtins.int
VERSION_FIELD_NUMBER: builtins.int
version: builtins.int
"""
A version integer used to invalidate old save files when we make
incompatible changes This integer is set at build time and is private to
NodeDB.cpp in the device code.
"""
@property
def mqtt(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.MQTTConfig:
"""
The part of the config that is specific to the MQTT module
"""
@property
def serial(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.SerialConfig:
"""
The part of the config that is specific to the Serial module
"""
@property
def external_notification(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.ExternalNotificationConfig:
"""
The part of the config that is specific to the ExternalNotification module
"""
@property
def store_forward(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.StoreForwardConfig:
"""
The part of the config that is specific to the Store & Forward module
"""
@property
def range_test(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.RangeTestConfig:
"""
The part of the config that is specific to the RangeTest module
"""
@property
def telemetry(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.TelemetryConfig:
"""
The part of the config that is specific to the Telemetry module
"""
@property
def canned_message(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.CannedMessageConfig:
"""
The part of the config that is specific to the Canned Message module
"""
@property
def audio(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.AudioConfig:
"""
The part of the config that is specific to the Audio module
"""
@property
def remote_hardware(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.RemoteHardwareConfig:
"""
The part of the config that is specific to the Remote Hardware module
"""
@property
def neighbor_info(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.NeighborInfoConfig:
"""
The part of the config that is specific to the Neighbor Info module
"""
@property
def ambient_lighting(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.AmbientLightingConfig:
"""
The part of the config that is specific to the Ambient Lighting module
"""
@property
def detection_sensor(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.DetectionSensorConfig:
"""
The part of the config that is specific to the Detection Sensor module
"""
@property
def paxcounter(self) -> meshtastic.protobuf.module_config_pb2.ModuleConfig.PaxcounterConfig:
"""
Paxcounter Config
"""
def __init__(
self,
*,
mqtt: meshtastic.protobuf.module_config_pb2.ModuleConfig.MQTTConfig | None = ...,
serial: meshtastic.protobuf.module_config_pb2.ModuleConfig.SerialConfig | None = ...,
external_notification: meshtastic.protobuf.module_config_pb2.ModuleConfig.ExternalNotificationConfig | None = ...,
store_forward: meshtastic.protobuf.module_config_pb2.ModuleConfig.StoreForwardConfig | None = ...,
range_test: meshtastic.protobuf.module_config_pb2.ModuleConfig.RangeTestConfig | None = ...,
telemetry: meshtastic.protobuf.module_config_pb2.ModuleConfig.TelemetryConfig | None = ...,
canned_message: meshtastic.protobuf.module_config_pb2.ModuleConfig.CannedMessageConfig | None = ...,
audio: meshtastic.protobuf.module_config_pb2.ModuleConfig.AudioConfig | None = ...,
remote_hardware: meshtastic.protobuf.module_config_pb2.ModuleConfig.RemoteHardwareConfig | None = ...,
neighbor_info: meshtastic.protobuf.module_config_pb2.ModuleConfig.NeighborInfoConfig | None = ...,
ambient_lighting: meshtastic.protobuf.module_config_pb2.ModuleConfig.AmbientLightingConfig | None = ...,
detection_sensor: meshtastic.protobuf.module_config_pb2.ModuleConfig.DetectionSensorConfig | None = ...,
paxcounter: meshtastic.protobuf.module_config_pb2.ModuleConfig.PaxcounterConfig | None = ...,
version: builtins.int = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["ambient_lighting", b"ambient_lighting", "audio", b"audio", "canned_message", b"canned_message", "detection_sensor", b"detection_sensor", "external_notification", b"external_notification", "mqtt", b"mqtt", "neighbor_info", b"neighbor_info", "paxcounter", b"paxcounter", "range_test", b"range_test", "remote_hardware", b"remote_hardware", "serial", b"serial", "store_forward", b"store_forward", "telemetry", b"telemetry"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["ambient_lighting", b"ambient_lighting", "audio", b"audio", "canned_message", b"canned_message", "detection_sensor", b"detection_sensor", "external_notification", b"external_notification", "mqtt", b"mqtt", "neighbor_info", b"neighbor_info", "paxcounter", b"paxcounter", "range_test", b"range_test", "remote_hardware", b"remote_hardware", "serial", b"serial", "store_forward", b"store_forward", "telemetry", b"telemetry", "version", b"version"]) -> None: ...
global___LocalModuleConfig = LocalModuleConfig
class LocalModuleConfig(_message.Message):
__slots__ = ["ambient_lighting", "audio", "canned_message", "detection_sensor", "external_notification", "mqtt", "neighbor_info", "paxcounter", "range_test", "remote_hardware", "serial", "statusmessage", "store_forward", "tak", "telemetry", "traffic_management", "version"]
AMBIENT_LIGHTING_FIELD_NUMBER: _ClassVar[int]
AUDIO_FIELD_NUMBER: _ClassVar[int]
CANNED_MESSAGE_FIELD_NUMBER: _ClassVar[int]
DETECTION_SENSOR_FIELD_NUMBER: _ClassVar[int]
EXTERNAL_NOTIFICATION_FIELD_NUMBER: _ClassVar[int]
MQTT_FIELD_NUMBER: _ClassVar[int]
NEIGHBOR_INFO_FIELD_NUMBER: _ClassVar[int]
PAXCOUNTER_FIELD_NUMBER: _ClassVar[int]
RANGE_TEST_FIELD_NUMBER: _ClassVar[int]
REMOTE_HARDWARE_FIELD_NUMBER: _ClassVar[int]
SERIAL_FIELD_NUMBER: _ClassVar[int]
STATUSMESSAGE_FIELD_NUMBER: _ClassVar[int]
STORE_FORWARD_FIELD_NUMBER: _ClassVar[int]
TAK_FIELD_NUMBER: _ClassVar[int]
TELEMETRY_FIELD_NUMBER: _ClassVar[int]
TRAFFIC_MANAGEMENT_FIELD_NUMBER: _ClassVar[int]
VERSION_FIELD_NUMBER: _ClassVar[int]
ambient_lighting: _module_config_pb2.ModuleConfig.AmbientLightingConfig
audio: _module_config_pb2.ModuleConfig.AudioConfig
canned_message: _module_config_pb2.ModuleConfig.CannedMessageConfig
detection_sensor: _module_config_pb2.ModuleConfig.DetectionSensorConfig
external_notification: _module_config_pb2.ModuleConfig.ExternalNotificationConfig
mqtt: _module_config_pb2.ModuleConfig.MQTTConfig
neighbor_info: _module_config_pb2.ModuleConfig.NeighborInfoConfig
paxcounter: _module_config_pb2.ModuleConfig.PaxcounterConfig
range_test: _module_config_pb2.ModuleConfig.RangeTestConfig
remote_hardware: _module_config_pb2.ModuleConfig.RemoteHardwareConfig
serial: _module_config_pb2.ModuleConfig.SerialConfig
statusmessage: _module_config_pb2.ModuleConfig.StatusMessageConfig
store_forward: _module_config_pb2.ModuleConfig.StoreForwardConfig
tak: _module_config_pb2.ModuleConfig.TAKConfig
telemetry: _module_config_pb2.ModuleConfig.TelemetryConfig
traffic_management: _module_config_pb2.ModuleConfig.TrafficManagementConfig
version: int
def __init__(self, mqtt: _Optional[_Union[_module_config_pb2.ModuleConfig.MQTTConfig, _Mapping]] = ..., serial: _Optional[_Union[_module_config_pb2.ModuleConfig.SerialConfig, _Mapping]] = ..., external_notification: _Optional[_Union[_module_config_pb2.ModuleConfig.ExternalNotificationConfig, _Mapping]] = ..., store_forward: _Optional[_Union[_module_config_pb2.ModuleConfig.StoreForwardConfig, _Mapping]] = ..., range_test: _Optional[_Union[_module_config_pb2.ModuleConfig.RangeTestConfig, _Mapping]] = ..., telemetry: _Optional[_Union[_module_config_pb2.ModuleConfig.TelemetryConfig, _Mapping]] = ..., canned_message: _Optional[_Union[_module_config_pb2.ModuleConfig.CannedMessageConfig, _Mapping]] = ..., audio: _Optional[_Union[_module_config_pb2.ModuleConfig.AudioConfig, _Mapping]] = ..., remote_hardware: _Optional[_Union[_module_config_pb2.ModuleConfig.RemoteHardwareConfig, _Mapping]] = ..., neighbor_info: _Optional[_Union[_module_config_pb2.ModuleConfig.NeighborInfoConfig, _Mapping]] = ..., ambient_lighting: _Optional[_Union[_module_config_pb2.ModuleConfig.AmbientLightingConfig, _Mapping]] = ..., detection_sensor: _Optional[_Union[_module_config_pb2.ModuleConfig.DetectionSensorConfig, _Mapping]] = ..., paxcounter: _Optional[_Union[_module_config_pb2.ModuleConfig.PaxcounterConfig, _Mapping]] = ..., statusmessage: _Optional[_Union[_module_config_pb2.ModuleConfig.StatusMessageConfig, _Mapping]] = ..., traffic_management: _Optional[_Union[_module_config_pb2.ModuleConfig.TrafficManagementConfig, _Mapping]] = ..., tak: _Optional[_Union[_module_config_pb2.ModuleConfig.TAKConfig, _Mapping]] = ..., version: _Optional[int] = ...) -> None: ...
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/mqtt.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -17,14 +17,14 @@ from meshtastic.protobuf import mesh_pb2 as meshtastic_dot_protobuf_dot_mesh__pb
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1emeshtastic/protobuf/mqtt.proto\x12\x13meshtastic.protobuf\x1a meshtastic/protobuf/config.proto\x1a\x1emeshtastic/protobuf/mesh.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\"\x83\x04\n\tMapReport\x12\x11\n\tlong_name\x18\x01 \x01(\t\x12\x12\n\nshort_name\x18\x02 \x01(\t\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\x18\n\x10\x66irmware_version\x18\x05 \x01(\t\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\x1e\n\x16num_online_local_nodes\x18\r \x01(\r\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)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.mqtt_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.mqtt_pb2', globals())
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'
_globals['_SERVICEENVELOPE']._serialized_start=121
_globals['_SERVICEENVELOPE']._serialized_end=227
_globals['_MAPREPORT']._serialized_start=230
_globals['_MAPREPORT']._serialized_end=745
_SERVICEENVELOPE._serialized_start=121
_SERVICEENVELOPE._serialized_end=227
_MAPREPORT._serialized_start=230
_MAPREPORT._serialized_end=745
# @@protoc_insertion_point(module_scope)
+46 -152
View File
@@ -1,155 +1,49 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from meshtastic.protobuf import config_pb2 as _config_pb2
from meshtastic.protobuf import mesh_pb2 as _mesh_pb2
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
import builtins
import google.protobuf.descriptor
import google.protobuf.message
import meshtastic.protobuf.config_pb2
import meshtastic.protobuf.mesh_pb2
import typing
DESCRIPTOR: _descriptor.FileDescriptor
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
class MapReport(_message.Message):
__slots__ = ["altitude", "firmware_version", "has_default_channel", "has_opted_report_location", "hw_model", "latitude_i", "long_name", "longitude_i", "modem_preset", "num_online_local_nodes", "position_precision", "region", "role", "short_name"]
ALTITUDE_FIELD_NUMBER: _ClassVar[int]
FIRMWARE_VERSION_FIELD_NUMBER: _ClassVar[int]
HAS_DEFAULT_CHANNEL_FIELD_NUMBER: _ClassVar[int]
HAS_OPTED_REPORT_LOCATION_FIELD_NUMBER: _ClassVar[int]
HW_MODEL_FIELD_NUMBER: _ClassVar[int]
LATITUDE_I_FIELD_NUMBER: _ClassVar[int]
LONGITUDE_I_FIELD_NUMBER: _ClassVar[int]
LONG_NAME_FIELD_NUMBER: _ClassVar[int]
MODEM_PRESET_FIELD_NUMBER: _ClassVar[int]
NUM_ONLINE_LOCAL_NODES_FIELD_NUMBER: _ClassVar[int]
POSITION_PRECISION_FIELD_NUMBER: _ClassVar[int]
REGION_FIELD_NUMBER: _ClassVar[int]
ROLE_FIELD_NUMBER: _ClassVar[int]
SHORT_NAME_FIELD_NUMBER: _ClassVar[int]
altitude: int
firmware_version: str
has_default_channel: bool
has_opted_report_location: bool
hw_model: _mesh_pb2.HardwareModel
latitude_i: int
long_name: str
longitude_i: int
modem_preset: _config_pb2.Config.LoRaConfig.ModemPreset
num_online_local_nodes: int
position_precision: int
region: _config_pb2.Config.LoRaConfig.RegionCode
role: _config_pb2.Config.DeviceConfig.Role
short_name: str
def __init__(self, long_name: _Optional[str] = ..., short_name: _Optional[str] = ..., role: _Optional[_Union[_config_pb2.Config.DeviceConfig.Role, str]] = ..., hw_model: _Optional[_Union[_mesh_pb2.HardwareModel, str]] = ..., firmware_version: _Optional[str] = ..., region: _Optional[_Union[_config_pb2.Config.LoRaConfig.RegionCode, str]] = ..., modem_preset: _Optional[_Union[_config_pb2.Config.LoRaConfig.ModemPreset, str]] = ..., has_default_channel: bool = ..., latitude_i: _Optional[int] = ..., longitude_i: _Optional[int] = ..., altitude: _Optional[int] = ..., position_precision: _Optional[int] = ..., num_online_local_nodes: _Optional[int] = ..., has_opted_report_location: bool = ...) -> None: ...
@typing.final
class ServiceEnvelope(google.protobuf.message.Message):
"""
This message wraps a MeshPacket with extra metadata about the sender and how it arrived.
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
PACKET_FIELD_NUMBER: builtins.int
CHANNEL_ID_FIELD_NUMBER: builtins.int
GATEWAY_ID_FIELD_NUMBER: builtins.int
channel_id: builtins.str
"""
The global channel ID it was sent on
"""
gateway_id: builtins.str
"""
The sending gateway node ID. Can we use this to authenticate/prevent fake
nodeid impersonation for senders? - i.e. use gateway/mesh id (which is authenticated) + local node id as
the globally trusted nodenum
"""
@property
def packet(self) -> meshtastic.protobuf.mesh_pb2.MeshPacket:
"""
The (probably encrypted) packet
"""
def __init__(
self,
*,
packet: meshtastic.protobuf.mesh_pb2.MeshPacket | None = ...,
channel_id: builtins.str = ...,
gateway_id: builtins.str = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["packet", b"packet"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["channel_id", b"channel_id", "gateway_id", b"gateway_id", "packet", b"packet"]) -> None: ...
global___ServiceEnvelope = ServiceEnvelope
@typing.final
class MapReport(google.protobuf.message.Message):
"""
Information about a node intended to be reported unencrypted to a map using MQTT.
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
LONG_NAME_FIELD_NUMBER: builtins.int
SHORT_NAME_FIELD_NUMBER: builtins.int
ROLE_FIELD_NUMBER: builtins.int
HW_MODEL_FIELD_NUMBER: builtins.int
FIRMWARE_VERSION_FIELD_NUMBER: builtins.int
REGION_FIELD_NUMBER: builtins.int
MODEM_PRESET_FIELD_NUMBER: builtins.int
HAS_DEFAULT_CHANNEL_FIELD_NUMBER: builtins.int
LATITUDE_I_FIELD_NUMBER: builtins.int
LONGITUDE_I_FIELD_NUMBER: builtins.int
ALTITUDE_FIELD_NUMBER: builtins.int
POSITION_PRECISION_FIELD_NUMBER: builtins.int
NUM_ONLINE_LOCAL_NODES_FIELD_NUMBER: builtins.int
HAS_OPTED_REPORT_LOCATION_FIELD_NUMBER: builtins.int
long_name: builtins.str
"""
A full name for this user, i.e. "Kevin Hester"
"""
short_name: builtins.str
"""
A VERY short name, ideally two characters.
Suitable for a tiny OLED screen
"""
role: meshtastic.protobuf.config_pb2.Config.DeviceConfig.Role.ValueType
"""
Role of the node that applies specific settings for a particular use-case
"""
hw_model: meshtastic.protobuf.mesh_pb2.HardwareModel.ValueType
"""
Hardware model of the node, i.e. T-Beam, Heltec V3, etc...
"""
firmware_version: builtins.str
"""
Device firmware version string
"""
region: meshtastic.protobuf.config_pb2.Config.LoRaConfig.RegionCode.ValueType
"""
The region code for the radio (US, CN, EU433, etc...)
"""
modem_preset: meshtastic.protobuf.config_pb2.Config.LoRaConfig.ModemPreset.ValueType
"""
Modem preset used by the radio (LongFast, MediumSlow, etc...)
"""
has_default_channel: builtins.bool
"""
Whether the node has a channel with default PSK and name (LongFast, MediumSlow, etc...)
and it uses the default frequency slot given the region and modem preset.
"""
latitude_i: builtins.int
"""
Latitude: multiply by 1e-7 to get degrees in floating point
"""
longitude_i: builtins.int
"""
Longitude: multiply by 1e-7 to get degrees in floating point
"""
altitude: builtins.int
"""
Altitude in meters above MSL
"""
position_precision: builtins.int
"""
Indicates the bits of precision for latitude and longitude set by the sending node
"""
num_online_local_nodes: builtins.int
"""
Number of online nodes (heard in the last 2 hours) this node has in its list that were received locally (not via MQTT)
"""
has_opted_report_location: builtins.bool
"""
User has opted in to share their location (map report) with the mqtt server
Controlled by map_report.should_report_location
"""
def __init__(
self,
*,
long_name: builtins.str = ...,
short_name: builtins.str = ...,
role: meshtastic.protobuf.config_pb2.Config.DeviceConfig.Role.ValueType = ...,
hw_model: meshtastic.protobuf.mesh_pb2.HardwareModel.ValueType = ...,
firmware_version: builtins.str = ...,
region: meshtastic.protobuf.config_pb2.Config.LoRaConfig.RegionCode.ValueType = ...,
modem_preset: meshtastic.protobuf.config_pb2.Config.LoRaConfig.ModemPreset.ValueType = ...,
has_default_channel: builtins.bool = ...,
latitude_i: builtins.int = ...,
longitude_i: builtins.int = ...,
altitude: builtins.int = ...,
position_precision: builtins.int = ...,
num_online_local_nodes: builtins.int = ...,
has_opted_report_location: builtins.bool = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["altitude", b"altitude", "firmware_version", b"firmware_version", "has_default_channel", b"has_default_channel", "has_opted_report_location", b"has_opted_report_location", "hw_model", b"hw_model", "latitude_i", b"latitude_i", "long_name", b"long_name", "longitude_i", b"longitude_i", "modem_preset", b"modem_preset", "num_online_local_nodes", b"num_online_local_nodes", "position_precision", b"position_precision", "region", b"region", "role", b"role", "short_name", b"short_name"]) -> None: ...
global___MapReport = MapReport
class ServiceEnvelope(_message.Message):
__slots__ = ["channel_id", "gateway_id", "packet"]
CHANNEL_ID_FIELD_NUMBER: _ClassVar[int]
GATEWAY_ID_FIELD_NUMBER: _ClassVar[int]
PACKET_FIELD_NUMBER: _ClassVar[int]
channel_id: str
gateway_id: str
packet: _mesh_pb2.MeshPacket
def __init__(self, packet: _Optional[_Union[_mesh_pb2.MeshPacket, _Mapping]] = ..., channel_id: _Optional[str] = ..., gateway_id: _Optional[str] = ...) -> None: ...
+18 -14
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/nanopb.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -16,20 +16,24 @@ from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n meshtastic/protobuf/nanopb.proto\x1a google/protobuf/descriptor.proto\"\xa4\x07\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x12\n\nmax_length\x18\x0e \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12&\n\x08int_size\x18\x07 \x01(\x0e\x32\x08.IntSize:\nIS_DEFAULT\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true\x12\x1c\n\rpacked_struct\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0bpacked_enum\x18\n \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0cskip_message\x18\x06 \x01(\x08:\x05\x66\x61lse\x12\x18\n\tno_unions\x18\x08 \x01(\x08:\x05\x66\x61lse\x12\r\n\x05msgid\x18\t \x01(\r\x12\x1e\n\x0f\x61nonymous_oneof\x18\x0b \x01(\x08:\x05\x66\x61lse\x12\x15\n\x06proto3\x18\x0c \x01(\x08:\x05\x66\x61lse\x12#\n\x14proto3_singular_msgs\x18\x15 \x01(\x08:\x05\x66\x61lse\x12\x1d\n\x0e\x65num_to_string\x18\r \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0c\x66ixed_length\x18\x0f \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0b\x66ixed_count\x18\x10 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x0fsubmsg_callback\x18\x16 \x01(\x08:\x05\x66\x61lse\x12/\n\x0cmangle_names\x18\x11 \x01(\x0e\x32\x11.TypenameMangling:\x06M_NONE\x12(\n\x11\x63\x61llback_datatype\x18\x12 \x01(\t:\rpb_callback_t\x12\x34\n\x11\x63\x61llback_function\x18\x13 \x01(\t:\x19pb_default_field_callback\x12\x30\n\x0e\x64\x65scriptorsize\x18\x14 \x01(\x0e\x32\x0f.DescriptorSize:\x07\x44S_AUTO\x12\x1a\n\x0b\x64\x65\x66\x61ult_has\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x0f\n\x07include\x18\x18 \x03(\t\x12\x0f\n\x07\x65xclude\x18\x1a \x03(\t\x12\x0f\n\x07package\x18\x19 \x01(\t\x12\x41\n\rtype_override\x18\x1b \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x19\n\x0bsort_by_tag\x18\x1c \x01(\x08:\x04true\x12.\n\rfallback_type\x18\x1d \x01(\x0e\x32\n.FieldType:\x0b\x46T_CALLBACK*i\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\x0e\n\nFT_POINTER\x10\x04\x12\r\n\tFT_STATIC\x10\x02\x12\r\n\tFT_IGNORE\x10\x03\x12\r\n\tFT_INLINE\x10\x05*D\n\x07IntSize\x12\x0e\n\nIS_DEFAULT\x10\x00\x12\x08\n\x04IS_8\x10\x08\x12\t\n\x05IS_16\x10\x10\x12\t\n\x05IS_32\x10 \x12\t\n\x05IS_64\x10@*Z\n\x10TypenameMangling\x12\n\n\x06M_NONE\x10\x00\x12\x13\n\x0fM_STRIP_PACKAGE\x10\x01\x12\r\n\tM_FLATTEN\x10\x02\x12\x16\n\x12M_PACKAGE_INITIALS\x10\x03*E\n\x0e\x44\x65scriptorSize\x12\x0b\n\x07\x44S_AUTO\x10\x00\x12\x08\n\x04\x44S_1\x10\x01\x12\x08\n\x04\x44S_2\x10\x02\x12\x08\n\x04\x44S_4\x10\x04\x12\x08\n\x04\x44S_8\x10\x08:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptionsB>\n\x18\x66i.kapsi.koti.jpa.nanopbZ\"github.com/meshtastic/go/generated')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.nanopb_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.nanopb_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(nanopb_fileopt)
google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(nanopb_msgopt)
google_dot_protobuf_dot_descriptor__pb2.EnumOptions.RegisterExtension(nanopb_enumopt)
google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(nanopb)
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\030fi.kapsi.koti.jpa.nanopbZ\"github.com/meshtastic/go/generated'
_globals['_FIELDTYPE']._serialized_start=1005
_globals['_FIELDTYPE']._serialized_end=1110
_globals['_INTSIZE']._serialized_start=1112
_globals['_INTSIZE']._serialized_end=1180
_globals['_TYPENAMEMANGLING']._serialized_start=1182
_globals['_TYPENAMEMANGLING']._serialized_end=1272
_globals['_DESCRIPTORSIZE']._serialized_start=1274
_globals['_DESCRIPTORSIZE']._serialized_end=1343
_globals['_NANOPBOPTIONS']._serialized_start=71
_globals['_NANOPBOPTIONS']._serialized_end=1003
_FIELDTYPE._serialized_start=1005
_FIELDTYPE._serialized_end=1110
_INTSIZE._serialized_start=1112
_INTSIZE._serialized_end=1180
_TYPENAMEMANGLING._serialized_start=1182
_TYPENAMEMANGLING._serialized_end=1272
_DESCRIPTORSIZE._serialized_start=1274
_DESCRIPTORSIZE._serialized_end=1343
_NANOPBOPTIONS._serialized_start=71
_NANOPBOPTIONS._serialized_end=1003
# @@protoc_insertion_point(module_scope)
+104 -318
View File
@@ -1,324 +1,110 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
Custom options for defining:
- Maximum size of string/bytes
- Maximum number of elements in array
from google.protobuf import descriptor_pb2 as _descriptor_pb2
from google.protobuf.internal import containers as _containers
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Iterable as _Iterable, Optional as _Optional, Union as _Union
These are used by nanopb to generate statically allocable structures
for memory-limited environments.
"""
DESCRIPTOR: _descriptor.FileDescriptor
DS_1: DescriptorSize
DS_2: DescriptorSize
DS_4: DescriptorSize
DS_8: DescriptorSize
DS_AUTO: DescriptorSize
FT_CALLBACK: FieldType
FT_DEFAULT: FieldType
FT_IGNORE: FieldType
FT_INLINE: FieldType
FT_POINTER: FieldType
FT_STATIC: FieldType
IS_16: IntSize
IS_32: IntSize
IS_64: IntSize
IS_8: IntSize
IS_DEFAULT: IntSize
M_FLATTEN: TypenameMangling
M_NONE: TypenameMangling
M_PACKAGE_INITIALS: TypenameMangling
M_STRIP_PACKAGE: TypenameMangling
NANOPB_ENUMOPT_FIELD_NUMBER: _ClassVar[int]
NANOPB_FIELD_NUMBER: _ClassVar[int]
NANOPB_FILEOPT_FIELD_NUMBER: _ClassVar[int]
NANOPB_MSGOPT_FIELD_NUMBER: _ClassVar[int]
nanopb: _descriptor.FieldDescriptor
nanopb_enumopt: _descriptor.FieldDescriptor
nanopb_fileopt: _descriptor.FieldDescriptor
nanopb_msgopt: _descriptor.FieldDescriptor
import builtins
import collections.abc
import google.protobuf.descriptor
import google.protobuf.descriptor_pb2
import google.protobuf.internal.containers
import google.protobuf.internal.enum_type_wrapper
import google.protobuf.internal.extension_dict
import google.protobuf.message
import sys
import typing
class NanoPBOptions(_message.Message):
__slots__ = ["anonymous_oneof", "callback_datatype", "callback_function", "default_has", "descriptorsize", "enum_to_string", "exclude", "fallback_type", "fixed_count", "fixed_length", "include", "int_size", "long_names", "mangle_names", "max_count", "max_length", "max_size", "msgid", "no_unions", "package", "packed_enum", "packed_struct", "proto3", "proto3_singular_msgs", "skip_message", "sort_by_tag", "submsg_callback", "type", "type_override"]
ANONYMOUS_ONEOF_FIELD_NUMBER: _ClassVar[int]
CALLBACK_DATATYPE_FIELD_NUMBER: _ClassVar[int]
CALLBACK_FUNCTION_FIELD_NUMBER: _ClassVar[int]
DEFAULT_HAS_FIELD_NUMBER: _ClassVar[int]
DESCRIPTORSIZE_FIELD_NUMBER: _ClassVar[int]
ENUM_TO_STRING_FIELD_NUMBER: _ClassVar[int]
EXCLUDE_FIELD_NUMBER: _ClassVar[int]
FALLBACK_TYPE_FIELD_NUMBER: _ClassVar[int]
FIXED_COUNT_FIELD_NUMBER: _ClassVar[int]
FIXED_LENGTH_FIELD_NUMBER: _ClassVar[int]
INCLUDE_FIELD_NUMBER: _ClassVar[int]
INT_SIZE_FIELD_NUMBER: _ClassVar[int]
LONG_NAMES_FIELD_NUMBER: _ClassVar[int]
MANGLE_NAMES_FIELD_NUMBER: _ClassVar[int]
MAX_COUNT_FIELD_NUMBER: _ClassVar[int]
MAX_LENGTH_FIELD_NUMBER: _ClassVar[int]
MAX_SIZE_FIELD_NUMBER: _ClassVar[int]
MSGID_FIELD_NUMBER: _ClassVar[int]
NO_UNIONS_FIELD_NUMBER: _ClassVar[int]
PACKAGE_FIELD_NUMBER: _ClassVar[int]
PACKED_ENUM_FIELD_NUMBER: _ClassVar[int]
PACKED_STRUCT_FIELD_NUMBER: _ClassVar[int]
PROTO3_FIELD_NUMBER: _ClassVar[int]
PROTO3_SINGULAR_MSGS_FIELD_NUMBER: _ClassVar[int]
SKIP_MESSAGE_FIELD_NUMBER: _ClassVar[int]
SORT_BY_TAG_FIELD_NUMBER: _ClassVar[int]
SUBMSG_CALLBACK_FIELD_NUMBER: _ClassVar[int]
TYPE_FIELD_NUMBER: _ClassVar[int]
TYPE_OVERRIDE_FIELD_NUMBER: _ClassVar[int]
anonymous_oneof: bool
callback_datatype: str
callback_function: str
default_has: bool
descriptorsize: DescriptorSize
enum_to_string: bool
exclude: _containers.RepeatedScalarFieldContainer[str]
fallback_type: FieldType
fixed_count: bool
fixed_length: bool
include: _containers.RepeatedScalarFieldContainer[str]
int_size: IntSize
long_names: bool
mangle_names: TypenameMangling
max_count: int
max_length: int
max_size: int
msgid: int
no_unions: bool
package: str
packed_enum: bool
packed_struct: bool
proto3: bool
proto3_singular_msgs: bool
skip_message: bool
sort_by_tag: bool
submsg_callback: bool
type: FieldType
type_override: _descriptor_pb2.FieldDescriptorProto.Type
def __init__(self, max_size: _Optional[int] = ..., max_length: _Optional[int] = ..., max_count: _Optional[int] = ..., int_size: _Optional[_Union[IntSize, str]] = ..., type: _Optional[_Union[FieldType, str]] = ..., long_names: bool = ..., packed_struct: bool = ..., packed_enum: bool = ..., skip_message: bool = ..., no_unions: bool = ..., msgid: _Optional[int] = ..., anonymous_oneof: bool = ..., proto3: bool = ..., proto3_singular_msgs: bool = ..., enum_to_string: bool = ..., fixed_length: bool = ..., fixed_count: bool = ..., submsg_callback: bool = ..., mangle_names: _Optional[_Union[TypenameMangling, str]] = ..., callback_datatype: _Optional[str] = ..., callback_function: _Optional[str] = ..., descriptorsize: _Optional[_Union[DescriptorSize, str]] = ..., default_has: bool = ..., include: _Optional[_Iterable[str]] = ..., exclude: _Optional[_Iterable[str]] = ..., package: _Optional[str] = ..., type_override: _Optional[_Union[_descriptor_pb2.FieldDescriptorProto.Type, str]] = ..., sort_by_tag: bool = ..., fallback_type: _Optional[_Union[FieldType, str]] = ...) -> None: ...
if sys.version_info >= (3, 10):
import typing as typing_extensions
else:
import typing_extensions
class FieldType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
class IntSize(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
class _FieldType:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class TypenameMangling(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
class _FieldTypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_FieldType.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
FT_DEFAULT: _FieldType.ValueType # 0
"""Automatically decide field type, generate static field if possible."""
FT_CALLBACK: _FieldType.ValueType # 1
"""Always generate a callback field."""
FT_POINTER: _FieldType.ValueType # 4
"""Always generate a dynamically allocated field."""
FT_STATIC: _FieldType.ValueType # 2
"""Generate a static field or raise an exception if not possible."""
FT_IGNORE: _FieldType.ValueType # 3
"""Ignore the field completely."""
FT_INLINE: _FieldType.ValueType # 5
"""Legacy option, use the separate 'fixed_length' option instead"""
class FieldType(_FieldType, metaclass=_FieldTypeEnumTypeWrapper): ...
FT_DEFAULT: FieldType.ValueType # 0
"""Automatically decide field type, generate static field if possible."""
FT_CALLBACK: FieldType.ValueType # 1
"""Always generate a callback field."""
FT_POINTER: FieldType.ValueType # 4
"""Always generate a dynamically allocated field."""
FT_STATIC: FieldType.ValueType # 2
"""Generate a static field or raise an exception if not possible."""
FT_IGNORE: FieldType.ValueType # 3
"""Ignore the field completely."""
FT_INLINE: FieldType.ValueType # 5
"""Legacy option, use the separate 'fixed_length' option instead"""
global___FieldType = FieldType
class _IntSize:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _IntSizeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_IntSize.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
IS_DEFAULT: _IntSize.ValueType # 0
"""Default, 32/64bit based on type in .proto"""
IS_8: _IntSize.ValueType # 8
IS_16: _IntSize.ValueType # 16
IS_32: _IntSize.ValueType # 32
IS_64: _IntSize.ValueType # 64
class IntSize(_IntSize, metaclass=_IntSizeEnumTypeWrapper): ...
IS_DEFAULT: IntSize.ValueType # 0
"""Default, 32/64bit based on type in .proto"""
IS_8: IntSize.ValueType # 8
IS_16: IntSize.ValueType # 16
IS_32: IntSize.ValueType # 32
IS_64: IntSize.ValueType # 64
global___IntSize = IntSize
class _TypenameMangling:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _TypenameManglingEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_TypenameMangling.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
M_NONE: _TypenameMangling.ValueType # 0
"""Default, no typename mangling"""
M_STRIP_PACKAGE: _TypenameMangling.ValueType # 1
"""Strip current package name"""
M_FLATTEN: _TypenameMangling.ValueType # 2
"""Only use last path component"""
M_PACKAGE_INITIALS: _TypenameMangling.ValueType # 3
"""Replace the package name by the initials"""
class TypenameMangling(_TypenameMangling, metaclass=_TypenameManglingEnumTypeWrapper): ...
M_NONE: TypenameMangling.ValueType # 0
"""Default, no typename mangling"""
M_STRIP_PACKAGE: TypenameMangling.ValueType # 1
"""Strip current package name"""
M_FLATTEN: TypenameMangling.ValueType # 2
"""Only use last path component"""
M_PACKAGE_INITIALS: TypenameMangling.ValueType # 3
"""Replace the package name by the initials"""
global___TypenameMangling = TypenameMangling
class _DescriptorSize:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _DescriptorSizeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_DescriptorSize.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
DS_AUTO: _DescriptorSize.ValueType # 0
"""Select minimal size based on field type"""
DS_1: _DescriptorSize.ValueType # 1
"""1 word; up to 15 byte fields, no arrays"""
DS_2: _DescriptorSize.ValueType # 2
"""2 words; up to 4095 byte fields, 4095 entry arrays"""
DS_4: _DescriptorSize.ValueType # 4
"""4 words; up to 2^32-1 byte fields, 2^16-1 entry arrays"""
DS_8: _DescriptorSize.ValueType # 8
"""8 words; up to 2^32-1 entry arrays"""
class DescriptorSize(_DescriptorSize, metaclass=_DescriptorSizeEnumTypeWrapper): ...
DS_AUTO: DescriptorSize.ValueType # 0
"""Select minimal size based on field type"""
DS_1: DescriptorSize.ValueType # 1
"""1 word; up to 15 byte fields, no arrays"""
DS_2: DescriptorSize.ValueType # 2
"""2 words; up to 4095 byte fields, 4095 entry arrays"""
DS_4: DescriptorSize.ValueType # 4
"""4 words; up to 2^32-1 byte fields, 2^16-1 entry arrays"""
DS_8: DescriptorSize.ValueType # 8
"""8 words; up to 2^32-1 entry arrays"""
global___DescriptorSize = DescriptorSize
@typing.final
class NanoPBOptions(google.protobuf.message.Message):
"""This is the inner options message, which basically defines options for
a field. When it is used in message or file scope, it applies to all
fields.
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
MAX_SIZE_FIELD_NUMBER: builtins.int
MAX_LENGTH_FIELD_NUMBER: builtins.int
MAX_COUNT_FIELD_NUMBER: builtins.int
INT_SIZE_FIELD_NUMBER: builtins.int
TYPE_FIELD_NUMBER: builtins.int
LONG_NAMES_FIELD_NUMBER: builtins.int
PACKED_STRUCT_FIELD_NUMBER: builtins.int
PACKED_ENUM_FIELD_NUMBER: builtins.int
SKIP_MESSAGE_FIELD_NUMBER: builtins.int
NO_UNIONS_FIELD_NUMBER: builtins.int
MSGID_FIELD_NUMBER: builtins.int
ANONYMOUS_ONEOF_FIELD_NUMBER: builtins.int
PROTO3_FIELD_NUMBER: builtins.int
PROTO3_SINGULAR_MSGS_FIELD_NUMBER: builtins.int
ENUM_TO_STRING_FIELD_NUMBER: builtins.int
FIXED_LENGTH_FIELD_NUMBER: builtins.int
FIXED_COUNT_FIELD_NUMBER: builtins.int
SUBMSG_CALLBACK_FIELD_NUMBER: builtins.int
MANGLE_NAMES_FIELD_NUMBER: builtins.int
CALLBACK_DATATYPE_FIELD_NUMBER: builtins.int
CALLBACK_FUNCTION_FIELD_NUMBER: builtins.int
DESCRIPTORSIZE_FIELD_NUMBER: builtins.int
DEFAULT_HAS_FIELD_NUMBER: builtins.int
INCLUDE_FIELD_NUMBER: builtins.int
EXCLUDE_FIELD_NUMBER: builtins.int
PACKAGE_FIELD_NUMBER: builtins.int
TYPE_OVERRIDE_FIELD_NUMBER: builtins.int
SORT_BY_TAG_FIELD_NUMBER: builtins.int
FALLBACK_TYPE_FIELD_NUMBER: builtins.int
max_size: builtins.int
"""Allocated size for 'bytes' and 'string' fields.
For string fields, this should include the space for null terminator.
"""
max_length: builtins.int
"""Maximum length for 'string' fields. Setting this is equivalent
to setting max_size to a value of length+1.
"""
max_count: builtins.int
"""Allocated number of entries in arrays ('repeated' fields)"""
int_size: global___IntSize.ValueType
"""Size of integer fields. Can save some memory if you don't need
full 32 bits for the value.
"""
type: global___FieldType.ValueType
"""Force type of field (callback or static allocation)"""
long_names: builtins.bool
"""Use long names for enums, i.e. EnumName_EnumValue."""
packed_struct: builtins.bool
"""Add 'packed' attribute to generated structs.
Note: this cannot be used on CPUs that break on unaligned
accesses to variables.
"""
packed_enum: builtins.bool
"""Add 'packed' attribute to generated enums."""
skip_message: builtins.bool
"""Skip this message"""
no_unions: builtins.bool
"""Generate oneof fields as normal optional fields instead of union."""
msgid: builtins.int
"""integer type tag for a message"""
anonymous_oneof: builtins.bool
"""decode oneof as anonymous union"""
proto3: builtins.bool
"""Proto3 singular field does not generate a "has_" flag"""
proto3_singular_msgs: builtins.bool
"""Force proto3 messages to have no "has_" flag.
This was default behavior until nanopb-0.4.0.
"""
enum_to_string: builtins.bool
"""Generate an enum->string mapping function (can take up lots of space)."""
fixed_length: builtins.bool
"""Generate bytes arrays with fixed length"""
fixed_count: builtins.bool
"""Generate repeated field with fixed count"""
submsg_callback: builtins.bool
"""Generate message-level callback that is called before decoding submessages.
This can be used to set callback fields for submsgs inside oneofs.
"""
mangle_names: global___TypenameMangling.ValueType
"""Shorten or remove package names from type names.
This option applies only on the file level.
"""
callback_datatype: builtins.str
"""Data type for storage associated with callback fields."""
callback_function: builtins.str
"""Callback function used for encoding and decoding.
Prior to nanopb-0.4.0, the callback was specified in per-field pb_callback_t
structure. This is still supported, but does not work inside e.g. oneof or pointer
fields. Instead, a new method allows specifying a per-message callback that
will be called for all callback fields in a message type.
"""
descriptorsize: global___DescriptorSize.ValueType
"""Select the size of field descriptors. This option has to be defined
for the whole message, not per-field. Usually automatic selection is
ok, but if it results in compilation errors you can increase the field
size here.
"""
default_has: builtins.bool
"""Set default value for has_ fields."""
package: builtins.str
"""Package name that applies only for nanopb."""
type_override: google.protobuf.descriptor_pb2.FieldDescriptorProto.Type.ValueType
"""Override type of the field in generated C code. Only to be used with related field types"""
sort_by_tag: builtins.bool
"""Due to historical reasons, nanopb orders fields in structs by their tag number
instead of the order in .proto. Set this to false to keep the .proto order.
The default value will probably change to false in nanopb-0.5.0.
"""
fallback_type: global___FieldType.ValueType
"""Set the FT_DEFAULT field conversion strategy.
A field that can become a static member of a c struct (e.g. int, bool, etc)
will be a a static field.
Fields with dynamic length are converted to either a pointer or a callback.
"""
@property
def include(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
"""Extra files to include in generated `.pb.h`"""
@property
def exclude(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]:
"""Automatic includes to exclude from generated `.pb.h`
Same as nanopb_generator.py command line flag -x.
"""
def __init__(
self,
*,
max_size: builtins.int | None = ...,
max_length: builtins.int | None = ...,
max_count: builtins.int | None = ...,
int_size: global___IntSize.ValueType | None = ...,
type: global___FieldType.ValueType | None = ...,
long_names: builtins.bool | None = ...,
packed_struct: builtins.bool | None = ...,
packed_enum: builtins.bool | None = ...,
skip_message: builtins.bool | None = ...,
no_unions: builtins.bool | None = ...,
msgid: builtins.int | None = ...,
anonymous_oneof: builtins.bool | None = ...,
proto3: builtins.bool | None = ...,
proto3_singular_msgs: builtins.bool | None = ...,
enum_to_string: builtins.bool | None = ...,
fixed_length: builtins.bool | None = ...,
fixed_count: builtins.bool | None = ...,
submsg_callback: builtins.bool | None = ...,
mangle_names: global___TypenameMangling.ValueType | None = ...,
callback_datatype: builtins.str | None = ...,
callback_function: builtins.str | None = ...,
descriptorsize: global___DescriptorSize.ValueType | None = ...,
default_has: builtins.bool | None = ...,
include: collections.abc.Iterable[builtins.str] | None = ...,
exclude: collections.abc.Iterable[builtins.str] | None = ...,
package: builtins.str | None = ...,
type_override: google.protobuf.descriptor_pb2.FieldDescriptorProto.Type.ValueType | None = ...,
sort_by_tag: builtins.bool | None = ...,
fallback_type: global___FieldType.ValueType | None = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["anonymous_oneof", b"anonymous_oneof", "callback_datatype", b"callback_datatype", "callback_function", b"callback_function", "default_has", b"default_has", "descriptorsize", b"descriptorsize", "enum_to_string", b"enum_to_string", "fallback_type", b"fallback_type", "fixed_count", b"fixed_count", "fixed_length", b"fixed_length", "int_size", b"int_size", "long_names", b"long_names", "mangle_names", b"mangle_names", "max_count", b"max_count", "max_length", b"max_length", "max_size", b"max_size", "msgid", b"msgid", "no_unions", b"no_unions", "package", b"package", "packed_enum", b"packed_enum", "packed_struct", b"packed_struct", "proto3", b"proto3", "proto3_singular_msgs", b"proto3_singular_msgs", "skip_message", b"skip_message", "sort_by_tag", b"sort_by_tag", "submsg_callback", b"submsg_callback", "type", b"type", "type_override", b"type_override"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["anonymous_oneof", b"anonymous_oneof", "callback_datatype", b"callback_datatype", "callback_function", b"callback_function", "default_has", b"default_has", "descriptorsize", b"descriptorsize", "enum_to_string", b"enum_to_string", "exclude", b"exclude", "fallback_type", b"fallback_type", "fixed_count", b"fixed_count", "fixed_length", b"fixed_length", "include", b"include", "int_size", b"int_size", "long_names", b"long_names", "mangle_names", b"mangle_names", "max_count", b"max_count", "max_length", b"max_length", "max_size", b"max_size", "msgid", b"msgid", "no_unions", b"no_unions", "package", b"package", "packed_enum", b"packed_enum", "packed_struct", b"packed_struct", "proto3", b"proto3", "proto3_singular_msgs", b"proto3_singular_msgs", "skip_message", b"skip_message", "sort_by_tag", b"sort_by_tag", "submsg_callback", b"submsg_callback", "type", b"type", "type_override", b"type_override"]) -> None: ...
global___NanoPBOptions = NanoPBOptions
NANOPB_FILEOPT_FIELD_NUMBER: builtins.int
NANOPB_MSGOPT_FIELD_NUMBER: builtins.int
NANOPB_ENUMOPT_FIELD_NUMBER: builtins.int
NANOPB_FIELD_NUMBER: builtins.int
nanopb_fileopt: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.FileOptions, global___NanoPBOptions]
nanopb_msgopt: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, global___NanoPBOptions]
nanopb_enumopt: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.EnumOptions, global___NanoPBOptions]
nanopb: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.FieldOptions, global___NanoPBOptions]
class DescriptorSize(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
+6 -6
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/paxcount.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,12 +15,12 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"meshtastic/protobuf/paxcount.proto\x12\x13meshtastic.protobuf\"5\n\x08Paxcount\x12\x0c\n\x04wifi\x18\x01 \x01(\r\x12\x0b\n\x03\x62le\x18\x02 \x01(\r\x12\x0e\n\x06uptime\x18\x03 \x01(\rBd\n\x14org.meshtastic.protoB\x0ePaxcountProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.paxcount_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.paxcount_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\016PaxcountProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_PAXCOUNT']._serialized_start=59
_globals['_PAXCOUNT']._serialized_end=112
_PAXCOUNT._serialized_start=59
_PAXCOUNT._serialized_end=112
# @@protoc_insertion_point(module_scope)
+13 -43
View File
@@ -1,45 +1,15 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Optional as _Optional
import builtins
import google.protobuf.descriptor
import google.protobuf.message
import typing
DESCRIPTOR: _descriptor.FileDescriptor
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
@typing.final
class Paxcount(google.protobuf.message.Message):
"""
TODO: REPLACE
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
WIFI_FIELD_NUMBER: builtins.int
BLE_FIELD_NUMBER: builtins.int
UPTIME_FIELD_NUMBER: builtins.int
wifi: builtins.int
"""
seen Wifi devices
"""
ble: builtins.int
"""
Seen BLE devices
"""
uptime: builtins.int
"""
Uptime in seconds
"""
def __init__(
self,
*,
wifi: builtins.int = ...,
ble: builtins.int = ...,
uptime: builtins.int = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["ble", b"ble", "uptime", b"uptime", "wifi", b"wifi"]) -> None: ...
global___Paxcount = Paxcount
class Paxcount(_message.Message):
__slots__ = ["ble", "uptime", "wifi"]
BLE_FIELD_NUMBER: _ClassVar[int]
UPTIME_FIELD_NUMBER: _ClassVar[int]
WIFI_FIELD_NUMBER: _ClassVar[int]
ble: int
uptime: int
wifi: int
def __init__(self, wifi: _Optional[int] = ..., ble: _Optional[int] = ..., uptime: _Optional[int] = ...) -> None: ...
+7 -7
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/portnums.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -13,14 +13,14 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"meshtastic/protobuf/portnums.proto\x12\x13meshtastic.protobuf*\xf6\x04\n\x07PortNum\x12\x0f\n\x0bUNKNOWN_APP\x10\x00\x12\x14\n\x10TEXT_MESSAGE_APP\x10\x01\x12\x17\n\x13REMOTE_HARDWARE_APP\x10\x02\x12\x10\n\x0cPOSITION_APP\x10\x03\x12\x10\n\x0cNODEINFO_APP\x10\x04\x12\x0f\n\x0bROUTING_APP\x10\x05\x12\r\n\tADMIN_APP\x10\x06\x12\x1f\n\x1bTEXT_MESSAGE_COMPRESSED_APP\x10\x07\x12\x10\n\x0cWAYPOINT_APP\x10\x08\x12\r\n\tAUDIO_APP\x10\t\x12\x18\n\x14\x44\x45TECTION_SENSOR_APP\x10\n\x12\r\n\tALERT_APP\x10\x0b\x12\x18\n\x14KEY_VERIFICATION_APP\x10\x0c\x12\r\n\tREPLY_APP\x10 \x12\x11\n\rIP_TUNNEL_APP\x10!\x12\x12\n\x0ePAXCOUNTER_APP\x10\"\x12\x0e\n\nSERIAL_APP\x10@\x12\x15\n\x11STORE_FORWARD_APP\x10\x41\x12\x12\n\x0eRANGE_TEST_APP\x10\x42\x12\x11\n\rTELEMETRY_APP\x10\x43\x12\x0b\n\x07ZPS_APP\x10\x44\x12\x11\n\rSIMULATOR_APP\x10\x45\x12\x12\n\x0eTRACEROUTE_APP\x10\x46\x12\x14\n\x10NEIGHBORINFO_APP\x10G\x12\x0f\n\x0b\x41TAK_PLUGIN\x10H\x12\x12\n\x0eMAP_REPORT_APP\x10I\x12\x13\n\x0fPOWERSTRESS_APP\x10J\x12\x18\n\x14RETICULUM_TUNNEL_APP\x10L\x12\x0f\n\x0b\x43\x41YENNE_APP\x10M\x12\x10\n\x0bPRIVATE_APP\x10\x80\x02\x12\x13\n\x0e\x41TAK_FORWARDER\x10\x81\x02\x12\x08\n\x03MAX\x10\xff\x03\x42^\n\x14org.meshtastic.protoB\x08PortnumsZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"meshtastic/protobuf/portnums.proto\x12\x13meshtastic.protobuf*\xfd\x05\n\x07PortNum\x12\x0f\n\x0bUNKNOWN_APP\x10\x00\x12\x14\n\x10TEXT_MESSAGE_APP\x10\x01\x12\x17\n\x13REMOTE_HARDWARE_APP\x10\x02\x12\x10\n\x0cPOSITION_APP\x10\x03\x12\x10\n\x0cNODEINFO_APP\x10\x04\x12\x0f\n\x0bROUTING_APP\x10\x05\x12\r\n\tADMIN_APP\x10\x06\x12\x1f\n\x1bTEXT_MESSAGE_COMPRESSED_APP\x10\x07\x12\x10\n\x0cWAYPOINT_APP\x10\x08\x12\r\n\tAUDIO_APP\x10\t\x12\x18\n\x14\x44\x45TECTION_SENSOR_APP\x10\n\x12\r\n\tALERT_APP\x10\x0b\x12\x18\n\x14KEY_VERIFICATION_APP\x10\x0c\x12\x14\n\x10REMOTE_SHELL_APP\x10\r\x12\r\n\tREPLY_APP\x10 \x12\x11\n\rIP_TUNNEL_APP\x10!\x12\x12\n\x0ePAXCOUNTER_APP\x10\"\x12\x1e\n\x1aSTORE_FORWARD_PLUSPLUS_APP\x10#\x12\x13\n\x0fNODE_STATUS_APP\x10$\x12\x0e\n\nSERIAL_APP\x10@\x12\x15\n\x11STORE_FORWARD_APP\x10\x41\x12\x12\n\x0eRANGE_TEST_APP\x10\x42\x12\x11\n\rTELEMETRY_APP\x10\x43\x12\x0b\n\x07ZPS_APP\x10\x44\x12\x11\n\rSIMULATOR_APP\x10\x45\x12\x12\n\x0eTRACEROUTE_APP\x10\x46\x12\x14\n\x10NEIGHBORINFO_APP\x10G\x12\x0f\n\x0b\x41TAK_PLUGIN\x10H\x12\x12\n\x0eMAP_REPORT_APP\x10I\x12\x13\n\x0fPOWERSTRESS_APP\x10J\x12\x12\n\x0eLORAWAN_BRIDGE\x10K\x12\x18\n\x14RETICULUM_TUNNEL_APP\x10L\x12\x0f\n\x0b\x43\x41YENNE_APP\x10M\x12\x12\n\x0e\x41TAK_PLUGIN_V2\x10N\x12\x12\n\x0eGROUPALARM_APP\x10p\x12\x10\n\x0bPRIVATE_APP\x10\x80\x02\x12\x13\n\x0e\x41TAK_FORWARDER\x10\x81\x02\x12\x08\n\x03MAX\x10\xff\x03\x42^\n\x14org.meshtastic.protoB\x08PortnumsZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.portnums_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.portnums_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\010PortnumsZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_PORTNUM']._serialized_start=60
_globals['_PORTNUM']._serialized_end=690
_PORTNUM._serialized_start=60
_PORTNUM._serialized_end=825
# @@protoc_insertion_point(module_scope)
+44 -414
View File
@@ -1,416 +1,46 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from typing import ClassVar as _ClassVar
import builtins
import google.protobuf.descriptor
import google.protobuf.internal.enum_type_wrapper
import sys
import typing
ADMIN_APP: PortNum
ALERT_APP: PortNum
ATAK_FORWARDER: PortNum
ATAK_PLUGIN: PortNum
ATAK_PLUGIN_V2: PortNum
AUDIO_APP: PortNum
CAYENNE_APP: PortNum
DESCRIPTOR: _descriptor.FileDescriptor
DETECTION_SENSOR_APP: PortNum
GROUPALARM_APP: PortNum
IP_TUNNEL_APP: PortNum
KEY_VERIFICATION_APP: PortNum
LORAWAN_BRIDGE: PortNum
MAP_REPORT_APP: PortNum
MAX: PortNum
NEIGHBORINFO_APP: PortNum
NODEINFO_APP: PortNum
NODE_STATUS_APP: PortNum
PAXCOUNTER_APP: PortNum
POSITION_APP: PortNum
POWERSTRESS_APP: PortNum
PRIVATE_APP: PortNum
RANGE_TEST_APP: PortNum
REMOTE_HARDWARE_APP: PortNum
REMOTE_SHELL_APP: PortNum
REPLY_APP: PortNum
RETICULUM_TUNNEL_APP: PortNum
ROUTING_APP: PortNum
SERIAL_APP: PortNum
SIMULATOR_APP: PortNum
STORE_FORWARD_APP: PortNum
STORE_FORWARD_PLUSPLUS_APP: PortNum
TELEMETRY_APP: PortNum
TEXT_MESSAGE_APP: PortNum
TEXT_MESSAGE_COMPRESSED_APP: PortNum
TRACEROUTE_APP: PortNum
UNKNOWN_APP: PortNum
WAYPOINT_APP: PortNum
ZPS_APP: PortNum
if sys.version_info >= (3, 10):
import typing as typing_extensions
else:
import typing_extensions
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
class _PortNum:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _PortNumEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_PortNum.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
UNKNOWN_APP: _PortNum.ValueType # 0
"""
Deprecated: do not use in new code (formerly called OPAQUE)
A message sent from a device outside of the mesh, in a form the mesh does not understand
NOTE: This must be 0, because it is documented in IMeshService.aidl to be so
ENCODING: binary undefined
"""
TEXT_MESSAGE_APP: _PortNum.ValueType # 1
"""
A simple UTF-8 text message, which even the little micros in the mesh
can understand and show on their screen eventually in some circumstances
even signal might send messages in this form (see below)
ENCODING: UTF-8 Plaintext (?)
"""
REMOTE_HARDWARE_APP: _PortNum.ValueType # 2
"""
Reserved for built-in GPIO/example app.
See remote_hardware.proto/HardwareMessage for details on the message sent/received to this port number
ENCODING: Protobuf
"""
POSITION_APP: _PortNum.ValueType # 3
"""
The built-in position messaging app.
Payload is a Position message.
ENCODING: Protobuf
"""
NODEINFO_APP: _PortNum.ValueType # 4
"""
The built-in user info app.
Payload is a User message.
ENCODING: Protobuf
"""
ROUTING_APP: _PortNum.ValueType # 5
"""
Protocol control packets for mesh protocol use.
Payload is a Routing message.
ENCODING: Protobuf
"""
ADMIN_APP: _PortNum.ValueType # 6
"""
Admin control packets.
Payload is a AdminMessage message.
ENCODING: Protobuf
"""
TEXT_MESSAGE_COMPRESSED_APP: _PortNum.ValueType # 7
"""
Compressed TEXT_MESSAGE payloads.
ENCODING: UTF-8 Plaintext (?) with Unishox2 Compression
NOTE: The Device Firmware converts a TEXT_MESSAGE_APP to TEXT_MESSAGE_COMPRESSED_APP if the compressed
payload is shorter. There's no need for app developers to do this themselves. Also the firmware will decompress
any incoming TEXT_MESSAGE_COMPRESSED_APP payload and convert to TEXT_MESSAGE_APP.
"""
WAYPOINT_APP: _PortNum.ValueType # 8
"""
Waypoint payloads.
Payload is a Waypoint message.
ENCODING: Protobuf
"""
AUDIO_APP: _PortNum.ValueType # 9
"""
Audio Payloads.
Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now
ENCODING: codec2 audio frames
NOTE: audio frames contain a 3 byte header (0xc0 0xde 0xc2) and a one byte marker for the decompressed bitrate.
This marker comes from the 'moduleConfig.audio.bitrate' enum minus one.
"""
DETECTION_SENSOR_APP: _PortNum.ValueType # 10
"""
Same as Text Message but originating from Detection Sensor Module.
NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9
"""
ALERT_APP: _PortNum.ValueType # 11
"""
Same as Text Message but used for critical alerts.
"""
KEY_VERIFICATION_APP: _PortNum.ValueType # 12
"""
Module/port for handling key verification requests.
"""
REPLY_APP: _PortNum.ValueType # 32
"""
Provides a 'ping' service that replies to any packet it receives.
Also serves as a small example module.
ENCODING: ASCII Plaintext
"""
IP_TUNNEL_APP: _PortNum.ValueType # 33
"""
Used for the python IP tunnel feature
ENCODING: IP Packet. Handled by the python API, firmware ignores this one and pases on.
"""
PAXCOUNTER_APP: _PortNum.ValueType # 34
"""
Paxcounter lib included in the firmware
ENCODING: protobuf
"""
SERIAL_APP: _PortNum.ValueType # 64
"""
Provides a hardware serial interface to send and receive from the Meshtastic network.
Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic
network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network.
Maximum packet size of 240 bytes.
Module is disabled by default can be turned on by setting SERIAL_MODULE_ENABLED = 1 in SerialPlugh.cpp.
ENCODING: binary undefined
"""
STORE_FORWARD_APP: _PortNum.ValueType # 65
"""
STORE_FORWARD_APP (Work in Progress)
Maintained by Jm Casler (MC Hamster) : jm@casler.org
ENCODING: Protobuf
"""
RANGE_TEST_APP: _PortNum.ValueType # 66
"""
Optional port for messages for the range test module.
ENCODING: ASCII Plaintext
NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9
"""
TELEMETRY_APP: _PortNum.ValueType # 67
"""
Provides a format to send and receive telemetry data from the Meshtastic network.
Maintained by Charles Crossan (crossan007) : crossan007@gmail.com
ENCODING: Protobuf
"""
ZPS_APP: _PortNum.ValueType # 68
"""
Experimental tools for estimating node position without a GPS
Maintained by Github user a-f-G-U-C (a Meshtastic contributor)
Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS
ENCODING: arrays of int64 fields
"""
SIMULATOR_APP: _PortNum.ValueType # 69
"""
Used to let multiple instances of Linux native applications communicate
as if they did using their LoRa chip.
Maintained by GitHub user GUVWAF.
Project files at https://github.com/GUVWAF/Meshtasticator
ENCODING: Protobuf (?)
"""
TRACEROUTE_APP: _PortNum.ValueType # 70
"""
Provides a traceroute functionality to show the route a packet towards
a certain destination would take on the mesh. Contains a RouteDiscovery message as payload.
ENCODING: Protobuf
"""
NEIGHBORINFO_APP: _PortNum.ValueType # 71
"""
Aggregates edge info for the network by sending out a list of each node's neighbors
ENCODING: Protobuf
"""
ATAK_PLUGIN: _PortNum.ValueType # 72
"""
ATAK Plugin
Portnum for payloads from the official Meshtastic ATAK plugin
"""
MAP_REPORT_APP: _PortNum.ValueType # 73
"""
Provides unencrypted information about a node for consumption by a map via MQTT
"""
POWERSTRESS_APP: _PortNum.ValueType # 74
"""
PowerStress based monitoring support (for automated power consumption testing)
"""
RETICULUM_TUNNEL_APP: _PortNum.ValueType # 76
"""
Reticulum Network Stack Tunnel App
ENCODING: Fragmented RNS Packet. Handled by Meshtastic RNS interface
"""
CAYENNE_APP: _PortNum.ValueType # 77
"""
App for transporting Cayenne Low Power Payload, popular for LoRaWAN sensor nodes. Offers ability to send
arbitrary telemetry over meshtastic that is not covered by telemetry.proto
ENCODING: CayenneLLP
"""
PRIVATE_APP: _PortNum.ValueType # 256
"""
Private applications should use portnums >= 256.
To simplify initial development and testing you can use "PRIVATE_APP"
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh))
"""
ATAK_FORWARDER: _PortNum.ValueType # 257
"""
ATAK Forwarder Module https://github.com/paulmandal/atak-forwarder
ENCODING: libcotshrink
"""
MAX: _PortNum.ValueType # 511
"""
Currently we limit port nums to no higher than this value
"""
class PortNum(_PortNum, metaclass=_PortNumEnumTypeWrapper):
"""
For any new 'apps' that run on the device or via sister apps on phones/PCs they should pick and use a
unique 'portnum' for their application.
If you are making a new app using meshtastic, please send in a pull request to add your 'portnum' to this
master table.
PortNums should be assigned in the following range:
0-63 Core Meshtastic use, do not use for third party apps
64-127 Registered 3rd party apps, send in a pull request that adds a new entry to portnums.proto to register your application
256-511 Use one of these portnums for your private applications that you don't want to register publically
All other values are reserved.
Note: This was formerly a Type enum named 'typ' with the same id #
We have change to this 'portnum' based scheme for specifying app handlers for particular payloads.
This change is backwards compatible by treating the legacy OPAQUE/CLEAR_TEXT values identically.
"""
UNKNOWN_APP: PortNum.ValueType # 0
"""
Deprecated: do not use in new code (formerly called OPAQUE)
A message sent from a device outside of the mesh, in a form the mesh does not understand
NOTE: This must be 0, because it is documented in IMeshService.aidl to be so
ENCODING: binary undefined
"""
TEXT_MESSAGE_APP: PortNum.ValueType # 1
"""
A simple UTF-8 text message, which even the little micros in the mesh
can understand and show on their screen eventually in some circumstances
even signal might send messages in this form (see below)
ENCODING: UTF-8 Plaintext (?)
"""
REMOTE_HARDWARE_APP: PortNum.ValueType # 2
"""
Reserved for built-in GPIO/example app.
See remote_hardware.proto/HardwareMessage for details on the message sent/received to this port number
ENCODING: Protobuf
"""
POSITION_APP: PortNum.ValueType # 3
"""
The built-in position messaging app.
Payload is a Position message.
ENCODING: Protobuf
"""
NODEINFO_APP: PortNum.ValueType # 4
"""
The built-in user info app.
Payload is a User message.
ENCODING: Protobuf
"""
ROUTING_APP: PortNum.ValueType # 5
"""
Protocol control packets for mesh protocol use.
Payload is a Routing message.
ENCODING: Protobuf
"""
ADMIN_APP: PortNum.ValueType # 6
"""
Admin control packets.
Payload is a AdminMessage message.
ENCODING: Protobuf
"""
TEXT_MESSAGE_COMPRESSED_APP: PortNum.ValueType # 7
"""
Compressed TEXT_MESSAGE payloads.
ENCODING: UTF-8 Plaintext (?) with Unishox2 Compression
NOTE: The Device Firmware converts a TEXT_MESSAGE_APP to TEXT_MESSAGE_COMPRESSED_APP if the compressed
payload is shorter. There's no need for app developers to do this themselves. Also the firmware will decompress
any incoming TEXT_MESSAGE_COMPRESSED_APP payload and convert to TEXT_MESSAGE_APP.
"""
WAYPOINT_APP: PortNum.ValueType # 8
"""
Waypoint payloads.
Payload is a Waypoint message.
ENCODING: Protobuf
"""
AUDIO_APP: PortNum.ValueType # 9
"""
Audio Payloads.
Encapsulated codec2 packets. On 2.4 GHZ Bandwidths only for now
ENCODING: codec2 audio frames
NOTE: audio frames contain a 3 byte header (0xc0 0xde 0xc2) and a one byte marker for the decompressed bitrate.
This marker comes from the 'moduleConfig.audio.bitrate' enum minus one.
"""
DETECTION_SENSOR_APP: PortNum.ValueType # 10
"""
Same as Text Message but originating from Detection Sensor Module.
NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9
"""
ALERT_APP: PortNum.ValueType # 11
"""
Same as Text Message but used for critical alerts.
"""
KEY_VERIFICATION_APP: PortNum.ValueType # 12
"""
Module/port for handling key verification requests.
"""
REPLY_APP: PortNum.ValueType # 32
"""
Provides a 'ping' service that replies to any packet it receives.
Also serves as a small example module.
ENCODING: ASCII Plaintext
"""
IP_TUNNEL_APP: PortNum.ValueType # 33
"""
Used for the python IP tunnel feature
ENCODING: IP Packet. Handled by the python API, firmware ignores this one and pases on.
"""
PAXCOUNTER_APP: PortNum.ValueType # 34
"""
Paxcounter lib included in the firmware
ENCODING: protobuf
"""
SERIAL_APP: PortNum.ValueType # 64
"""
Provides a hardware serial interface to send and receive from the Meshtastic network.
Connect to the RX/TX pins of a device with 38400 8N1. Packets received from the Meshtastic
network is forwarded to the RX pin while sending a packet to TX will go out to the Mesh network.
Maximum packet size of 240 bytes.
Module is disabled by default can be turned on by setting SERIAL_MODULE_ENABLED = 1 in SerialPlugh.cpp.
ENCODING: binary undefined
"""
STORE_FORWARD_APP: PortNum.ValueType # 65
"""
STORE_FORWARD_APP (Work in Progress)
Maintained by Jm Casler (MC Hamster) : jm@casler.org
ENCODING: Protobuf
"""
RANGE_TEST_APP: PortNum.ValueType # 66
"""
Optional port for messages for the range test module.
ENCODING: ASCII Plaintext
NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9
"""
TELEMETRY_APP: PortNum.ValueType # 67
"""
Provides a format to send and receive telemetry data from the Meshtastic network.
Maintained by Charles Crossan (crossan007) : crossan007@gmail.com
ENCODING: Protobuf
"""
ZPS_APP: PortNum.ValueType # 68
"""
Experimental tools for estimating node position without a GPS
Maintained by Github user a-f-G-U-C (a Meshtastic contributor)
Project files at https://github.com/a-f-G-U-C/Meshtastic-ZPS
ENCODING: arrays of int64 fields
"""
SIMULATOR_APP: PortNum.ValueType # 69
"""
Used to let multiple instances of Linux native applications communicate
as if they did using their LoRa chip.
Maintained by GitHub user GUVWAF.
Project files at https://github.com/GUVWAF/Meshtasticator
ENCODING: Protobuf (?)
"""
TRACEROUTE_APP: PortNum.ValueType # 70
"""
Provides a traceroute functionality to show the route a packet towards
a certain destination would take on the mesh. Contains a RouteDiscovery message as payload.
ENCODING: Protobuf
"""
NEIGHBORINFO_APP: PortNum.ValueType # 71
"""
Aggregates edge info for the network by sending out a list of each node's neighbors
ENCODING: Protobuf
"""
ATAK_PLUGIN: PortNum.ValueType # 72
"""
ATAK Plugin
Portnum for payloads from the official Meshtastic ATAK plugin
"""
MAP_REPORT_APP: PortNum.ValueType # 73
"""
Provides unencrypted information about a node for consumption by a map via MQTT
"""
POWERSTRESS_APP: PortNum.ValueType # 74
"""
PowerStress based monitoring support (for automated power consumption testing)
"""
RETICULUM_TUNNEL_APP: PortNum.ValueType # 76
"""
Reticulum Network Stack Tunnel App
ENCODING: Fragmented RNS Packet. Handled by Meshtastic RNS interface
"""
CAYENNE_APP: PortNum.ValueType # 77
"""
App for transporting Cayenne Low Power Payload, popular for LoRaWAN sensor nodes. Offers ability to send
arbitrary telemetry over meshtastic that is not covered by telemetry.proto
ENCODING: CayenneLLP
"""
PRIVATE_APP: PortNum.ValueType # 256
"""
Private applications should use portnums >= 256.
To simplify initial development and testing you can use "PRIVATE_APP"
in your code without needing to rebuild protobuf files (via [regen-protos.sh](https://github.com/meshtastic/firmware/blob/master/bin/regen-protos.sh))
"""
ATAK_FORWARDER: PortNum.ValueType # 257
"""
ATAK Forwarder Module https://github.com/paulmandal/atak-forwarder
ENCODING: libcotshrink
"""
MAX: PortNum.ValueType # 511
"""
Currently we limit port nums to no higher than this value
"""
global___PortNum = PortNum
class PortNum(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
+12 -12
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/powermon.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,18 +15,18 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\"meshtastic/protobuf/powermon.proto\x12\x13meshtastic.protobuf\"\xe0\x01\n\x08PowerMon\"\xd3\x01\n\x05State\x12\x08\n\x04None\x10\x00\x12\x11\n\rCPU_DeepSleep\x10\x01\x12\x12\n\x0e\x43PU_LightSleep\x10\x02\x12\x0c\n\x08Vext1_On\x10\x04\x12\r\n\tLora_RXOn\x10\x08\x12\r\n\tLora_TXOn\x10\x10\x12\x11\n\rLora_RXActive\x10 \x12\t\n\x05\x42T_On\x10@\x12\x0b\n\x06LED_On\x10\x80\x01\x12\x0e\n\tScreen_On\x10\x80\x02\x12\x13\n\x0eScreen_Drawing\x10\x80\x04\x12\x0c\n\x07Wifi_On\x10\x80\x08\x12\x0f\n\nGPS_Active\x10\x80\x10\"\x88\x03\n\x12PowerStressMessage\x12;\n\x03\x63md\x18\x01 \x01(\x0e\x32..meshtastic.protobuf.PowerStressMessage.Opcode\x12\x13\n\x0bnum_seconds\x18\x02 \x01(\x02\"\x9f\x02\n\x06Opcode\x12\t\n\x05UNSET\x10\x00\x12\x0e\n\nPRINT_INFO\x10\x01\x12\x0f\n\x0b\x46ORCE_QUIET\x10\x02\x12\r\n\tEND_QUIET\x10\x03\x12\r\n\tSCREEN_ON\x10\x10\x12\x0e\n\nSCREEN_OFF\x10\x11\x12\x0c\n\x08\x43PU_IDLE\x10 \x12\x11\n\rCPU_DEEPSLEEP\x10!\x12\x0e\n\nCPU_FULLON\x10\"\x12\n\n\x06LED_ON\x10\x30\x12\x0b\n\x07LED_OFF\x10\x31\x12\x0c\n\x08LORA_OFF\x10@\x12\x0b\n\x07LORA_TX\x10\x41\x12\x0b\n\x07LORA_RX\x10\x42\x12\n\n\x06\x42T_OFF\x10P\x12\t\n\x05\x42T_ON\x10Q\x12\x0c\n\x08WIFI_OFF\x10`\x12\x0b\n\x07WIFI_ON\x10\x61\x12\x0b\n\x07GPS_OFF\x10p\x12\n\n\x06GPS_ON\x10qBd\n\x14org.meshtastic.protoB\x0ePowerMonProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.powermon_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.powermon_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\016PowerMonProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_POWERMON']._serialized_start=60
_globals['_POWERMON']._serialized_end=284
_globals['_POWERMON_STATE']._serialized_start=73
_globals['_POWERMON_STATE']._serialized_end=284
_globals['_POWERSTRESSMESSAGE']._serialized_start=287
_globals['_POWERSTRESSMESSAGE']._serialized_end=679
_globals['_POWERSTRESSMESSAGE_OPCODE']._serialized_start=392
_globals['_POWERSTRESSMESSAGE_OPCODE']._serialized_end=679
_POWERMON._serialized_start=60
_POWERMON._serialized_end=284
_POWERMON_STATE._serialized_start=73
_POWERMON_STATE._serialized_end=284
_POWERSTRESSMESSAGE._serialized_start=287
_POWERSTRESSMESSAGE._serialized_end=679
_POWERSTRESSMESSAGE_OPCODE._serialized_start=392
_POWERSTRESSMESSAGE_OPCODE._serialized_end=679
# @@protoc_insertion_point(module_scope)
+52 -218
View File
@@ -1,221 +1,55 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union
import builtins
import google.protobuf.descriptor
import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
import sys
import typing
DESCRIPTOR: _descriptor.FileDescriptor
if sys.version_info >= (3, 10):
import typing as typing_extensions
else:
import typing_extensions
class PowerMon(_message.Message):
__slots__ = []
class State(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
BT_On: PowerMon.State
CPU_DeepSleep: PowerMon.State
CPU_LightSleep: PowerMon.State
GPS_Active: PowerMon.State
LED_On: PowerMon.State
Lora_RXActive: PowerMon.State
Lora_RXOn: PowerMon.State
Lora_TXOn: PowerMon.State
None: PowerMon.State
Screen_Drawing: PowerMon.State
Screen_On: PowerMon.State
Vext1_On: PowerMon.State
Wifi_On: PowerMon.State
def __init__(self) -> None: ...
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
@typing.final
class PowerMon(google.protobuf.message.Message):
"""Note: There are no 'PowerMon' messages normally in use (PowerMons are sent only as structured logs - slogs).
But we wrap our State enum in this message to effectively nest a namespace (without our linter yelling at us)
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
class _State:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _StateEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[PowerMon._State.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
CPU_DeepSleep: PowerMon._State.ValueType # 1
CPU_LightSleep: PowerMon._State.ValueType # 2
Vext1_On: PowerMon._State.ValueType # 4
"""
The external Vext1 power is on. Many boards have auxillary power rails that the CPU turns on only
occasionally. In cases where that rail has multiple devices on it we usually want to have logging on
the state of that rail as an independent record.
For instance on the Heltec Tracker 1.1 board, this rail is the power source for the GPS and screen.
The log messages will be short and complete (see PowerMon.Event in the protobufs for details).
something like "S:PM:C,0x00001234,REASON" where the hex number is the bitmask of all current states.
(We use a bitmask for states so that if a log message gets lost it won't be fatal)
"""
Lora_RXOn: PowerMon._State.ValueType # 8
Lora_TXOn: PowerMon._State.ValueType # 16
Lora_RXActive: PowerMon._State.ValueType # 32
BT_On: PowerMon._State.ValueType # 64
LED_On: PowerMon._State.ValueType # 128
Screen_On: PowerMon._State.ValueType # 256
Screen_Drawing: PowerMon._State.ValueType # 512
Wifi_On: PowerMon._State.ValueType # 1024
GPS_Active: PowerMon._State.ValueType # 2048
"""
GPS is actively trying to find our location
See GPSPowerState for more details
"""
class State(_State, metaclass=_StateEnumTypeWrapper):
"""Any significant power changing event in meshtastic should be tagged with a powermon state transition.
If you are making new meshtastic features feel free to add new entries at the end of this definition.
"""
CPU_DeepSleep: PowerMon.State.ValueType # 1
CPU_LightSleep: PowerMon.State.ValueType # 2
Vext1_On: PowerMon.State.ValueType # 4
"""
The external Vext1 power is on. Many boards have auxillary power rails that the CPU turns on only
occasionally. In cases where that rail has multiple devices on it we usually want to have logging on
the state of that rail as an independent record.
For instance on the Heltec Tracker 1.1 board, this rail is the power source for the GPS and screen.
The log messages will be short and complete (see PowerMon.Event in the protobufs for details).
something like "S:PM:C,0x00001234,REASON" where the hex number is the bitmask of all current states.
(We use a bitmask for states so that if a log message gets lost it won't be fatal)
"""
Lora_RXOn: PowerMon.State.ValueType # 8
Lora_TXOn: PowerMon.State.ValueType # 16
Lora_RXActive: PowerMon.State.ValueType # 32
BT_On: PowerMon.State.ValueType # 64
LED_On: PowerMon.State.ValueType # 128
Screen_On: PowerMon.State.ValueType # 256
Screen_Drawing: PowerMon.State.ValueType # 512
Wifi_On: PowerMon.State.ValueType # 1024
GPS_Active: PowerMon.State.ValueType # 2048
"""
GPS is actively trying to find our location
See GPSPowerState for more details
"""
def __init__(
self,
) -> None: ...
global___PowerMon = PowerMon
@typing.final
class PowerStressMessage(google.protobuf.message.Message):
"""
PowerStress testing support via the C++ PowerStress module
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
class _Opcode:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _OpcodeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[PowerStressMessage._Opcode.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
UNSET: PowerStressMessage._Opcode.ValueType # 0
"""
Unset/unused
"""
PRINT_INFO: PowerStressMessage._Opcode.ValueType # 1
"""Print board version slog and send an ack that we are alive and ready to process commands"""
FORCE_QUIET: PowerStressMessage._Opcode.ValueType # 2
"""Try to turn off all automatic processing of packets, screen, sleeping, etc (to make it easier to measure in isolation)"""
END_QUIET: PowerStressMessage._Opcode.ValueType # 3
"""Stop powerstress processing - probably by just rebooting the board"""
SCREEN_ON: PowerStressMessage._Opcode.ValueType # 16
"""Turn the screen on"""
SCREEN_OFF: PowerStressMessage._Opcode.ValueType # 17
"""Turn the screen off"""
CPU_IDLE: PowerStressMessage._Opcode.ValueType # 32
"""Let the CPU run but we assume mostly idling for num_seconds"""
CPU_DEEPSLEEP: PowerStressMessage._Opcode.ValueType # 33
"""Force deep sleep for FIXME seconds"""
CPU_FULLON: PowerStressMessage._Opcode.ValueType # 34
"""Spin the CPU as fast as possible for num_seconds"""
LED_ON: PowerStressMessage._Opcode.ValueType # 48
"""Turn the LED on for num_seconds (and leave it on - for baseline power measurement purposes)"""
LED_OFF: PowerStressMessage._Opcode.ValueType # 49
"""Force the LED off for num_seconds"""
LORA_OFF: PowerStressMessage._Opcode.ValueType # 64
"""Completely turn off the LORA radio for num_seconds"""
LORA_TX: PowerStressMessage._Opcode.ValueType # 65
"""Send Lora packets for num_seconds"""
LORA_RX: PowerStressMessage._Opcode.ValueType # 66
"""Receive Lora packets for num_seconds (node will be mostly just listening, unless an external agent is helping stress this by sending packets on the current channel)"""
BT_OFF: PowerStressMessage._Opcode.ValueType # 80
"""Turn off the BT radio for num_seconds"""
BT_ON: PowerStressMessage._Opcode.ValueType # 81
"""Turn on the BT radio for num_seconds"""
WIFI_OFF: PowerStressMessage._Opcode.ValueType # 96
"""Turn off the WIFI radio for num_seconds"""
WIFI_ON: PowerStressMessage._Opcode.ValueType # 97
"""Turn on the WIFI radio for num_seconds"""
GPS_OFF: PowerStressMessage._Opcode.ValueType # 112
"""Turn off the GPS radio for num_seconds"""
GPS_ON: PowerStressMessage._Opcode.ValueType # 113
"""Turn on the GPS radio for num_seconds"""
class Opcode(_Opcode, metaclass=_OpcodeEnumTypeWrapper):
"""
What operation would we like the UUT to perform.
note: senders should probably set want_response in their request packets, so that they can know when the state
machine has started processing their request
"""
UNSET: PowerStressMessage.Opcode.ValueType # 0
"""
Unset/unused
"""
PRINT_INFO: PowerStressMessage.Opcode.ValueType # 1
"""Print board version slog and send an ack that we are alive and ready to process commands"""
FORCE_QUIET: PowerStressMessage.Opcode.ValueType # 2
"""Try to turn off all automatic processing of packets, screen, sleeping, etc (to make it easier to measure in isolation)"""
END_QUIET: PowerStressMessage.Opcode.ValueType # 3
"""Stop powerstress processing - probably by just rebooting the board"""
SCREEN_ON: PowerStressMessage.Opcode.ValueType # 16
"""Turn the screen on"""
SCREEN_OFF: PowerStressMessage.Opcode.ValueType # 17
"""Turn the screen off"""
CPU_IDLE: PowerStressMessage.Opcode.ValueType # 32
"""Let the CPU run but we assume mostly idling for num_seconds"""
CPU_DEEPSLEEP: PowerStressMessage.Opcode.ValueType # 33
"""Force deep sleep for FIXME seconds"""
CPU_FULLON: PowerStressMessage.Opcode.ValueType # 34
"""Spin the CPU as fast as possible for num_seconds"""
LED_ON: PowerStressMessage.Opcode.ValueType # 48
"""Turn the LED on for num_seconds (and leave it on - for baseline power measurement purposes)"""
LED_OFF: PowerStressMessage.Opcode.ValueType # 49
"""Force the LED off for num_seconds"""
LORA_OFF: PowerStressMessage.Opcode.ValueType # 64
"""Completely turn off the LORA radio for num_seconds"""
LORA_TX: PowerStressMessage.Opcode.ValueType # 65
"""Send Lora packets for num_seconds"""
LORA_RX: PowerStressMessage.Opcode.ValueType # 66
"""Receive Lora packets for num_seconds (node will be mostly just listening, unless an external agent is helping stress this by sending packets on the current channel)"""
BT_OFF: PowerStressMessage.Opcode.ValueType # 80
"""Turn off the BT radio for num_seconds"""
BT_ON: PowerStressMessage.Opcode.ValueType # 81
"""Turn on the BT radio for num_seconds"""
WIFI_OFF: PowerStressMessage.Opcode.ValueType # 96
"""Turn off the WIFI radio for num_seconds"""
WIFI_ON: PowerStressMessage.Opcode.ValueType # 97
"""Turn on the WIFI radio for num_seconds"""
GPS_OFF: PowerStressMessage.Opcode.ValueType # 112
"""Turn off the GPS radio for num_seconds"""
GPS_ON: PowerStressMessage.Opcode.ValueType # 113
"""Turn on the GPS radio for num_seconds"""
CMD_FIELD_NUMBER: builtins.int
NUM_SECONDS_FIELD_NUMBER: builtins.int
cmd: global___PowerStressMessage.Opcode.ValueType
"""
What type of HardwareMessage is this?
"""
num_seconds: builtins.float
def __init__(
self,
*,
cmd: global___PowerStressMessage.Opcode.ValueType = ...,
num_seconds: builtins.float = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["cmd", b"cmd", "num_seconds", b"num_seconds"]) -> None: ...
global___PowerStressMessage = PowerStressMessage
class PowerStressMessage(_message.Message):
__slots__ = ["cmd", "num_seconds"]
class Opcode(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
BT_OFF: PowerStressMessage.Opcode
BT_ON: PowerStressMessage.Opcode
CMD_FIELD_NUMBER: _ClassVar[int]
CPU_DEEPSLEEP: PowerStressMessage.Opcode
CPU_FULLON: PowerStressMessage.Opcode
CPU_IDLE: PowerStressMessage.Opcode
END_QUIET: PowerStressMessage.Opcode
FORCE_QUIET: PowerStressMessage.Opcode
GPS_OFF: PowerStressMessage.Opcode
GPS_ON: PowerStressMessage.Opcode
LED_OFF: PowerStressMessage.Opcode
LED_ON: PowerStressMessage.Opcode
LORA_OFF: PowerStressMessage.Opcode
LORA_RX: PowerStressMessage.Opcode
LORA_TX: PowerStressMessage.Opcode
NUM_SECONDS_FIELD_NUMBER: _ClassVar[int]
PRINT_INFO: PowerStressMessage.Opcode
SCREEN_OFF: PowerStressMessage.Opcode
SCREEN_ON: PowerStressMessage.Opcode
UNSET: PowerStressMessage.Opcode
WIFI_OFF: PowerStressMessage.Opcode
WIFI_ON: PowerStressMessage.Opcode
cmd: PowerStressMessage.Opcode
num_seconds: float
def __init__(self, cmd: _Optional[_Union[PowerStressMessage.Opcode, str]] = ..., num_seconds: _Optional[float] = ...) -> None: ...
+8 -8
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/remote_hardware.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,14 +15,14 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n)meshtastic/protobuf/remote_hardware.proto\x12\x13meshtastic.protobuf\"\xdf\x01\n\x0fHardwareMessage\x12\x37\n\x04type\x18\x01 \x01(\x0e\x32).meshtastic.protobuf.HardwareMessage.Type\x12\x11\n\tgpio_mask\x18\x02 \x01(\x04\x12\x12\n\ngpio_value\x18\x03 \x01(\x04\"l\n\x04Type\x12\t\n\x05UNSET\x10\x00\x12\x0f\n\x0bWRITE_GPIOS\x10\x01\x12\x0f\n\x0bWATCH_GPIOS\x10\x02\x12\x11\n\rGPIOS_CHANGED\x10\x03\x12\x0e\n\nREAD_GPIOS\x10\x04\x12\x14\n\x10READ_GPIOS_REPLY\x10\x05\x42\x64\n\x14org.meshtastic.protoB\x0eRemoteHardwareZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.remote_hardware_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.remote_hardware_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\016RemoteHardwareZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_HARDWAREMESSAGE']._serialized_start=67
_globals['_HARDWAREMESSAGE']._serialized_end=290
_globals['_HARDWAREMESSAGE_TYPE']._serialized_start=182
_globals['_HARDWAREMESSAGE_TYPE']._serialized_end=290
_HARDWAREMESSAGE._serialized_start=67
_HARDWAREMESSAGE._serialized_end=290
_HARDWAREMESSAGE_TYPE._serialized_start=182
_HARDWAREMESSAGE_TYPE._serialized_end=290
# @@protoc_insertion_point(module_scope)
+22 -124
View File
@@ -1,126 +1,24 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union
import builtins
import google.protobuf.descriptor
import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
import sys
import typing
DESCRIPTOR: _descriptor.FileDescriptor
if sys.version_info >= (3, 10):
import typing as typing_extensions
else:
import typing_extensions
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
@typing.final
class HardwareMessage(google.protobuf.message.Message):
"""
An example app to show off the module system. This message is used for
REMOTE_HARDWARE_APP PortNums.
Also provides easy remote access to any GPIO.
In the future other remote hardware operations can be added based on user interest
(i.e. serial output, spi/i2c input/output).
FIXME - currently this feature is turned on by default which is dangerous
because no security yet (beyond the channel mechanism).
It should be off by default and then protected based on some TBD mechanism
(a special channel once multichannel support is included?)
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
class _Type:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _TypeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[HardwareMessage._Type.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
UNSET: HardwareMessage._Type.ValueType # 0
"""
Unset/unused
"""
WRITE_GPIOS: HardwareMessage._Type.ValueType # 1
"""
Set gpio gpios based on gpio_mask/gpio_value
"""
WATCH_GPIOS: HardwareMessage._Type.ValueType # 2
"""
We are now interested in watching the gpio_mask gpios.
If the selected gpios change, please broadcast GPIOS_CHANGED.
Will implicitly change the gpios requested to be INPUT gpios.
"""
GPIOS_CHANGED: HardwareMessage._Type.ValueType # 3
"""
The gpios listed in gpio_mask have changed, the new values are listed in gpio_value
"""
READ_GPIOS: HardwareMessage._Type.ValueType # 4
"""
Read the gpios specified in gpio_mask, send back a READ_GPIOS_REPLY reply with gpio_value populated
"""
READ_GPIOS_REPLY: HardwareMessage._Type.ValueType # 5
"""
A reply to READ_GPIOS. gpio_mask and gpio_value will be populated
"""
class Type(_Type, metaclass=_TypeEnumTypeWrapper):
"""
TODO: REPLACE
"""
UNSET: HardwareMessage.Type.ValueType # 0
"""
Unset/unused
"""
WRITE_GPIOS: HardwareMessage.Type.ValueType # 1
"""
Set gpio gpios based on gpio_mask/gpio_value
"""
WATCH_GPIOS: HardwareMessage.Type.ValueType # 2
"""
We are now interested in watching the gpio_mask gpios.
If the selected gpios change, please broadcast GPIOS_CHANGED.
Will implicitly change the gpios requested to be INPUT gpios.
"""
GPIOS_CHANGED: HardwareMessage.Type.ValueType # 3
"""
The gpios listed in gpio_mask have changed, the new values are listed in gpio_value
"""
READ_GPIOS: HardwareMessage.Type.ValueType # 4
"""
Read the gpios specified in gpio_mask, send back a READ_GPIOS_REPLY reply with gpio_value populated
"""
READ_GPIOS_REPLY: HardwareMessage.Type.ValueType # 5
"""
A reply to READ_GPIOS. gpio_mask and gpio_value will be populated
"""
TYPE_FIELD_NUMBER: builtins.int
GPIO_MASK_FIELD_NUMBER: builtins.int
GPIO_VALUE_FIELD_NUMBER: builtins.int
type: global___HardwareMessage.Type.ValueType
"""
What type of HardwareMessage is this?
"""
gpio_mask: builtins.int
"""
What gpios are we changing. Not used for all MessageTypes, see MessageType for details
"""
gpio_value: builtins.int
"""
For gpios that were listed in gpio_mask as valid, what are the signal levels for those gpios.
Not used for all MessageTypes, see MessageType for details
"""
def __init__(
self,
*,
type: global___HardwareMessage.Type.ValueType = ...,
gpio_mask: builtins.int = ...,
gpio_value: builtins.int = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["gpio_mask", b"gpio_mask", "gpio_value", b"gpio_value", "type", b"type"]) -> None: ...
global___HardwareMessage = HardwareMessage
class HardwareMessage(_message.Message):
__slots__ = ["gpio_mask", "gpio_value", "type"]
class Type(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
GPIOS_CHANGED: HardwareMessage.Type
GPIO_MASK_FIELD_NUMBER: _ClassVar[int]
GPIO_VALUE_FIELD_NUMBER: _ClassVar[int]
READ_GPIOS: HardwareMessage.Type
READ_GPIOS_REPLY: HardwareMessage.Type
TYPE_FIELD_NUMBER: _ClassVar[int]
UNSET: HardwareMessage.Type
WATCH_GPIOS: HardwareMessage.Type
WRITE_GPIOS: HardwareMessage.Type
gpio_mask: int
gpio_value: int
type: HardwareMessage.Type
def __init__(self, type: _Optional[_Union[HardwareMessage.Type, str]] = ..., gpio_mask: _Optional[int] = ..., gpio_value: _Optional[int] = ...) -> None: ...
+6 -6
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/rtttl.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,12 +15,12 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1fmeshtastic/protobuf/rtttl.proto\x12\x13meshtastic.protobuf\"\x1f\n\x0bRTTTLConfig\x12\x10\n\x08ringtone\x18\x01 \x01(\tBg\n\x14org.meshtastic.protoB\x11RTTTLConfigProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.rtttl_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.rtttl_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\021RTTTLConfigProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_RTTTLCONFIG']._serialized_start=56
_globals['_RTTTLCONFIG']._serialized_end=87
_RTTTLCONFIG._serialized_start=56
_RTTTLCONFIG._serialized_end=87
# @@protoc_insertion_point(module_scope)
+9 -31
View File
@@ -1,33 +1,11 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Optional as _Optional
import builtins
import google.protobuf.descriptor
import google.protobuf.message
import typing
DESCRIPTOR: _descriptor.FileDescriptor
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
@typing.final
class RTTTLConfig(google.protobuf.message.Message):
"""
Canned message module configuration.
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
RINGTONE_FIELD_NUMBER: builtins.int
ringtone: builtins.str
"""
Ringtone for PWM Buzzer in RTTTL Format.
"""
def __init__(
self,
*,
ringtone: builtins.str = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["ringtone", b"ringtone"]) -> None: ...
global___RTTTLConfig = RTTTLConfig
class RTTTLConfig(_message.Message):
__slots__ = ["ringtone"]
RINGTONE_FIELD_NUMBER: _ClassVar[int]
ringtone: str
def __init__(self, ringtone: _Optional[str] = ...) -> None: ...
+32
View File
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/serial_hal.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n$meshtastic/protobuf/serial_hal.proto\x12\x13meshtastic.protobuf\"\xab\x02\n\x10SerialHalCommand\x12\x16\n\x0etransaction_id\x18\x01 \x01(\r\x12\x38\n\x04type\x18\x02 \x01(\x0e\x32*.meshtastic.protobuf.SerialHalCommand.Type\x12\x0b\n\x03pin\x18\x03 \x01(\r\x12\r\n\x05value\x18\x04 \x01(\r\x12\x0c\n\x04mode\x18\x05 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x06 \x01(\x0c\"\x8c\x01\n\x04Type\x12\t\n\x05UNSET\x10\x00\x12\x0c\n\x08PIN_MODE\x10\x01\x12\x11\n\rDIGITAL_WRITE\x10\x02\x12\x10\n\x0c\x44IGITAL_READ\x10\x03\x12\x14\n\x10\x41TTACH_INTERRUPT\x10\x04\x12\x14\n\x10\x44\x45TACH_INTERRUPT\x10\x05\x12\x10\n\x0cSPI_TRANSFER\x10\x06\x12\x08\n\x04NOOP\x10\x07\"\xd5\x01\n\x11SerialHalResponse\x12\x16\n\x0etransaction_id\x18\x01 \x01(\r\x12=\n\x06result\x18\x02 \x01(\x0e\x32-.meshtastic.protobuf.SerialHalResponse.Result\x12\r\n\x05value\x18\x03 \x01(\r\x12\x0c\n\x04\x64\x61ta\x18\x04 \x01(\x0c\x12\r\n\x05\x65rror\x18\x05 \x01(\t\"=\n\x06Result\x12\x06\n\x02OK\x10\x00\x12\t\n\x05\x45RROR\x10\x01\x12\x0f\n\x0b\x42\x41\x44_REQUEST\x10\x02\x12\x0f\n\x0bUNSUPPORTED\x10\x03\x42_\n\x14org.meshtastic.protoB\tSerialHalZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.serial_hal_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\tSerialHalZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_SERIALHALCOMMAND._serialized_start=62
_SERIALHALCOMMAND._serialized_end=361
_SERIALHALCOMMAND_TYPE._serialized_start=221
_SERIALHALCOMMAND_TYPE._serialized_end=361
_SERIALHALRESPONSE._serialized_start=364
_SERIALHALRESPONSE._serialized_end=577
_SERIALHALRESPONSE_RESULT._serialized_start=516
_SERIALHALRESPONSE_RESULT._serialized_end=577
# @@protoc_insertion_point(module_scope)
+52
View File
@@ -0,0 +1,52 @@
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union
DESCRIPTOR: _descriptor.FileDescriptor
class SerialHalCommand(_message.Message):
__slots__ = ["data", "mode", "pin", "transaction_id", "type", "value"]
class Type(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
ATTACH_INTERRUPT: SerialHalCommand.Type
DATA_FIELD_NUMBER: _ClassVar[int]
DETACH_INTERRUPT: SerialHalCommand.Type
DIGITAL_READ: SerialHalCommand.Type
DIGITAL_WRITE: SerialHalCommand.Type
MODE_FIELD_NUMBER: _ClassVar[int]
NOOP: SerialHalCommand.Type
PIN_FIELD_NUMBER: _ClassVar[int]
PIN_MODE: SerialHalCommand.Type
SPI_TRANSFER: SerialHalCommand.Type
TRANSACTION_ID_FIELD_NUMBER: _ClassVar[int]
TYPE_FIELD_NUMBER: _ClassVar[int]
UNSET: SerialHalCommand.Type
VALUE_FIELD_NUMBER: _ClassVar[int]
data: bytes
mode: int
pin: int
transaction_id: int
type: SerialHalCommand.Type
value: int
def __init__(self, transaction_id: _Optional[int] = ..., type: _Optional[_Union[SerialHalCommand.Type, str]] = ..., pin: _Optional[int] = ..., value: _Optional[int] = ..., mode: _Optional[int] = ..., data: _Optional[bytes] = ...) -> None: ...
class SerialHalResponse(_message.Message):
__slots__ = ["data", "error", "result", "transaction_id", "value"]
class Result(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
BAD_REQUEST: SerialHalResponse.Result
DATA_FIELD_NUMBER: _ClassVar[int]
ERROR: SerialHalResponse.Result
ERROR_FIELD_NUMBER: _ClassVar[int]
OK: SerialHalResponse.Result
RESULT_FIELD_NUMBER: _ClassVar[int]
TRANSACTION_ID_FIELD_NUMBER: _ClassVar[int]
UNSUPPORTED: SerialHalResponse.Result
VALUE_FIELD_NUMBER: _ClassVar[int]
data: bytes
error: str
result: SerialHalResponse.Result
transaction_id: int
value: int
def __init__(self, transaction_id: _Optional[int] = ..., result: _Optional[_Union[SerialHalResponse.Result, str]] = ..., value: _Optional[int] = ..., data: _Optional[bytes] = ..., error: _Optional[str] = ...) -> None: ...
+14 -14
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/storeforward.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,20 +15,20 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n&meshtastic/protobuf/storeforward.proto\x12\x13meshtastic.protobuf\"\xc0\x07\n\x0fStoreAndForward\x12@\n\x02rr\x18\x01 \x01(\x0e\x32\x34.meshtastic.protobuf.StoreAndForward.RequestResponse\x12@\n\x05stats\x18\x02 \x01(\x0b\x32/.meshtastic.protobuf.StoreAndForward.StatisticsH\x00\x12?\n\x07history\x18\x03 \x01(\x0b\x32,.meshtastic.protobuf.StoreAndForward.HistoryH\x00\x12\x43\n\theartbeat\x18\x04 \x01(\x0b\x32..meshtastic.protobuf.StoreAndForward.HeartbeatH\x00\x12\x0e\n\x04text\x18\x05 \x01(\x0cH\x00\x1a\xcd\x01\n\nStatistics\x12\x16\n\x0emessages_total\x18\x01 \x01(\r\x12\x16\n\x0emessages_saved\x18\x02 \x01(\r\x12\x14\n\x0cmessages_max\x18\x03 \x01(\r\x12\x0f\n\x07up_time\x18\x04 \x01(\r\x12\x10\n\x08requests\x18\x05 \x01(\r\x12\x18\n\x10requests_history\x18\x06 \x01(\r\x12\x11\n\theartbeat\x18\x07 \x01(\x08\x12\x12\n\nreturn_max\x18\x08 \x01(\r\x12\x15\n\rreturn_window\x18\t \x01(\r\x1aI\n\x07History\x12\x18\n\x10history_messages\x18\x01 \x01(\r\x12\x0e\n\x06window\x18\x02 \x01(\r\x12\x14\n\x0clast_request\x18\x03 \x01(\r\x1a.\n\tHeartbeat\x12\x0e\n\x06period\x18\x01 \x01(\r\x12\x11\n\tsecondary\x18\x02 \x01(\r\"\xbc\x02\n\x0fRequestResponse\x12\t\n\x05UNSET\x10\x00\x12\x10\n\x0cROUTER_ERROR\x10\x01\x12\x14\n\x10ROUTER_HEARTBEAT\x10\x02\x12\x0f\n\x0bROUTER_PING\x10\x03\x12\x0f\n\x0bROUTER_PONG\x10\x04\x12\x0f\n\x0bROUTER_BUSY\x10\x05\x12\x12\n\x0eROUTER_HISTORY\x10\x06\x12\x10\n\x0cROUTER_STATS\x10\x07\x12\x16\n\x12ROUTER_TEXT_DIRECT\x10\x08\x12\x19\n\x15ROUTER_TEXT_BROADCAST\x10\t\x12\x10\n\x0c\x43LIENT_ERROR\x10@\x12\x12\n\x0e\x43LIENT_HISTORY\x10\x41\x12\x10\n\x0c\x43LIENT_STATS\x10\x42\x12\x0f\n\x0b\x43LIENT_PING\x10\x43\x12\x0f\n\x0b\x43LIENT_PONG\x10\x44\x12\x10\n\x0c\x43LIENT_ABORT\x10jB\t\n\x07variantBk\n\x14org.meshtastic.protoB\x15StoreAndForwardProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.storeforward_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.storeforward_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\025StoreAndForwardProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_STOREANDFORWARD']._serialized_start=64
_globals['_STOREANDFORWARD']._serialized_end=1024
_globals['_STOREANDFORWARD_STATISTICS']._serialized_start=366
_globals['_STOREANDFORWARD_STATISTICS']._serialized_end=571
_globals['_STOREANDFORWARD_HISTORY']._serialized_start=573
_globals['_STOREANDFORWARD_HISTORY']._serialized_end=646
_globals['_STOREANDFORWARD_HEARTBEAT']._serialized_start=648
_globals['_STOREANDFORWARD_HEARTBEAT']._serialized_end=694
_globals['_STOREANDFORWARD_REQUESTRESPONSE']._serialized_start=697
_globals['_STOREANDFORWARD_REQUESTRESPONSE']._serialized_end=1013
_STOREANDFORWARD._serialized_start=64
_STOREANDFORWARD._serialized_end=1024
_STOREANDFORWARD_STATISTICS._serialized_start=366
_STOREANDFORWARD_STATISTICS._serialized_end=571
_STOREANDFORWARD_HISTORY._serialized_start=573
_STOREANDFORWARD_HISTORY._serialized_end=646
_STOREANDFORWARD_HEARTBEAT._serialized_start=648
_STOREANDFORWARD_HEARTBEAT._serialized_end=694
_STOREANDFORWARD_REQUESTRESPONSE._serialized_start=697
_STOREANDFORWARD_REQUESTRESPONSE._serialized_end=1013
# @@protoc_insertion_point(module_scope)
+73 -343
View File
@@ -1,345 +1,75 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Mapping as _Mapping, Optional as _Optional, Union as _Union
import builtins
import google.protobuf.descriptor
import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
import sys
import typing
DESCRIPTOR: _descriptor.FileDescriptor
if sys.version_info >= (3, 10):
import typing as typing_extensions
else:
import typing_extensions
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
@typing.final
class StoreAndForward(google.protobuf.message.Message):
"""
TODO: REPLACE
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
class _RequestResponse:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _RequestResponseEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[StoreAndForward._RequestResponse.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
UNSET: StoreAndForward._RequestResponse.ValueType # 0
"""
Unset/unused
"""
ROUTER_ERROR: StoreAndForward._RequestResponse.ValueType # 1
"""
Router is an in error state.
"""
ROUTER_HEARTBEAT: StoreAndForward._RequestResponse.ValueType # 2
"""
Router heartbeat
"""
ROUTER_PING: StoreAndForward._RequestResponse.ValueType # 3
"""
Router has requested the client respond. This can work as a
"are you there" message.
"""
ROUTER_PONG: StoreAndForward._RequestResponse.ValueType # 4
"""
The response to a "Ping"
"""
ROUTER_BUSY: StoreAndForward._RequestResponse.ValueType # 5
"""
Router is currently busy. Please try again later.
"""
ROUTER_HISTORY: StoreAndForward._RequestResponse.ValueType # 6
"""
Router is responding to a request for history.
"""
ROUTER_STATS: StoreAndForward._RequestResponse.ValueType # 7
"""
Router is responding to a request for stats.
"""
ROUTER_TEXT_DIRECT: StoreAndForward._RequestResponse.ValueType # 8
"""
Router sends a text message from its history that was a direct message.
"""
ROUTER_TEXT_BROADCAST: StoreAndForward._RequestResponse.ValueType # 9
"""
Router sends a text message from its history that was a broadcast.
"""
CLIENT_ERROR: StoreAndForward._RequestResponse.ValueType # 64
"""
Client is an in error state.
"""
CLIENT_HISTORY: StoreAndForward._RequestResponse.ValueType # 65
"""
Client has requested a replay from the router.
"""
CLIENT_STATS: StoreAndForward._RequestResponse.ValueType # 66
"""
Client has requested stats from the router.
"""
CLIENT_PING: StoreAndForward._RequestResponse.ValueType # 67
"""
Client has requested the router respond. This can work as a
"are you there" message.
"""
CLIENT_PONG: StoreAndForward._RequestResponse.ValueType # 68
"""
The response to a "Ping"
"""
CLIENT_ABORT: StoreAndForward._RequestResponse.ValueType # 106
"""
Client has requested that the router abort processing the client's request
"""
class RequestResponse(_RequestResponse, metaclass=_RequestResponseEnumTypeWrapper):
"""
001 - 063 = From Router
064 - 127 = From Client
"""
UNSET: StoreAndForward.RequestResponse.ValueType # 0
"""
Unset/unused
"""
ROUTER_ERROR: StoreAndForward.RequestResponse.ValueType # 1
"""
Router is an in error state.
"""
ROUTER_HEARTBEAT: StoreAndForward.RequestResponse.ValueType # 2
"""
Router heartbeat
"""
ROUTER_PING: StoreAndForward.RequestResponse.ValueType # 3
"""
Router has requested the client respond. This can work as a
"are you there" message.
"""
ROUTER_PONG: StoreAndForward.RequestResponse.ValueType # 4
"""
The response to a "Ping"
"""
ROUTER_BUSY: StoreAndForward.RequestResponse.ValueType # 5
"""
Router is currently busy. Please try again later.
"""
ROUTER_HISTORY: StoreAndForward.RequestResponse.ValueType # 6
"""
Router is responding to a request for history.
"""
ROUTER_STATS: StoreAndForward.RequestResponse.ValueType # 7
"""
Router is responding to a request for stats.
"""
ROUTER_TEXT_DIRECT: StoreAndForward.RequestResponse.ValueType # 8
"""
Router sends a text message from its history that was a direct message.
"""
ROUTER_TEXT_BROADCAST: StoreAndForward.RequestResponse.ValueType # 9
"""
Router sends a text message from its history that was a broadcast.
"""
CLIENT_ERROR: StoreAndForward.RequestResponse.ValueType # 64
"""
Client is an in error state.
"""
CLIENT_HISTORY: StoreAndForward.RequestResponse.ValueType # 65
"""
Client has requested a replay from the router.
"""
CLIENT_STATS: StoreAndForward.RequestResponse.ValueType # 66
"""
Client has requested stats from the router.
"""
CLIENT_PING: StoreAndForward.RequestResponse.ValueType # 67
"""
Client has requested the router respond. This can work as a
"are you there" message.
"""
CLIENT_PONG: StoreAndForward.RequestResponse.ValueType # 68
"""
The response to a "Ping"
"""
CLIENT_ABORT: StoreAndForward.RequestResponse.ValueType # 106
"""
Client has requested that the router abort processing the client's request
"""
@typing.final
class Statistics(google.protobuf.message.Message):
"""
TODO: REPLACE
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
MESSAGES_TOTAL_FIELD_NUMBER: builtins.int
MESSAGES_SAVED_FIELD_NUMBER: builtins.int
MESSAGES_MAX_FIELD_NUMBER: builtins.int
UP_TIME_FIELD_NUMBER: builtins.int
REQUESTS_FIELD_NUMBER: builtins.int
REQUESTS_HISTORY_FIELD_NUMBER: builtins.int
HEARTBEAT_FIELD_NUMBER: builtins.int
RETURN_MAX_FIELD_NUMBER: builtins.int
RETURN_WINDOW_FIELD_NUMBER: builtins.int
messages_total: builtins.int
"""
Number of messages we have ever seen
"""
messages_saved: builtins.int
"""
Number of messages we have currently saved our history.
"""
messages_max: builtins.int
"""
Maximum number of messages we will save
"""
up_time: builtins.int
"""
Router uptime in seconds
"""
requests: builtins.int
"""
Number of times any client sent a request to the S&F.
"""
requests_history: builtins.int
"""
Number of times the history was requested.
"""
heartbeat: builtins.bool
"""
Is the heartbeat enabled on the server?
"""
return_max: builtins.int
"""
Maximum number of messages the server will return.
"""
return_window: builtins.int
"""
Maximum history window in minutes the server will return messages from.
"""
def __init__(
self,
*,
messages_total: builtins.int = ...,
messages_saved: builtins.int = ...,
messages_max: builtins.int = ...,
up_time: builtins.int = ...,
requests: builtins.int = ...,
requests_history: builtins.int = ...,
heartbeat: builtins.bool = ...,
return_max: builtins.int = ...,
return_window: builtins.int = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["heartbeat", b"heartbeat", "messages_max", b"messages_max", "messages_saved", b"messages_saved", "messages_total", b"messages_total", "requests", b"requests", "requests_history", b"requests_history", "return_max", b"return_max", "return_window", b"return_window", "up_time", b"up_time"]) -> None: ...
@typing.final
class History(google.protobuf.message.Message):
"""
TODO: REPLACE
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
HISTORY_MESSAGES_FIELD_NUMBER: builtins.int
WINDOW_FIELD_NUMBER: builtins.int
LAST_REQUEST_FIELD_NUMBER: builtins.int
history_messages: builtins.int
"""
Number of that will be sent to the client
"""
window: builtins.int
"""
The window of messages that was used to filter the history client requested
"""
last_request: builtins.int
"""
Index in the packet history of the last message sent in a previous request to the server.
Will be sent to the client before sending the history and can be set in a subsequent request to avoid getting packets the server already sent to the client.
"""
def __init__(
self,
*,
history_messages: builtins.int = ...,
window: builtins.int = ...,
last_request: builtins.int = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["history_messages", b"history_messages", "last_request", b"last_request", "window", b"window"]) -> None: ...
@typing.final
class Heartbeat(google.protobuf.message.Message):
"""
TODO: REPLACE
"""
DESCRIPTOR: google.protobuf.descriptor.Descriptor
PERIOD_FIELD_NUMBER: builtins.int
SECONDARY_FIELD_NUMBER: builtins.int
period: builtins.int
"""
Period in seconds that the heartbeat is sent out that will be sent to the client
"""
secondary: builtins.int
"""
If set, this is not the primary Store & Forward router on the mesh
"""
def __init__(
self,
*,
period: builtins.int = ...,
secondary: builtins.int = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["period", b"period", "secondary", b"secondary"]) -> None: ...
RR_FIELD_NUMBER: builtins.int
STATS_FIELD_NUMBER: builtins.int
HISTORY_FIELD_NUMBER: builtins.int
HEARTBEAT_FIELD_NUMBER: builtins.int
TEXT_FIELD_NUMBER: builtins.int
rr: global___StoreAndForward.RequestResponse.ValueType
"""
TODO: REPLACE
"""
text: builtins.bytes
"""
Text from history message.
"""
@property
def stats(self) -> global___StoreAndForward.Statistics:
"""
TODO: REPLACE
"""
@property
def history(self) -> global___StoreAndForward.History:
"""
TODO: REPLACE
"""
@property
def heartbeat(self) -> global___StoreAndForward.Heartbeat:
"""
TODO: REPLACE
"""
def __init__(
self,
*,
rr: global___StoreAndForward.RequestResponse.ValueType = ...,
stats: global___StoreAndForward.Statistics | None = ...,
history: global___StoreAndForward.History | None = ...,
heartbeat: global___StoreAndForward.Heartbeat | None = ...,
text: builtins.bytes = ...,
) -> None: ...
def HasField(self, field_name: typing.Literal["heartbeat", b"heartbeat", "history", b"history", "stats", b"stats", "text", b"text", "variant", b"variant"]) -> builtins.bool: ...
def ClearField(self, field_name: typing.Literal["heartbeat", b"heartbeat", "history", b"history", "rr", b"rr", "stats", b"stats", "text", b"text", "variant", b"variant"]) -> None: ...
def WhichOneof(self, oneof_group: typing.Literal["variant", b"variant"]) -> typing.Literal["stats", "history", "heartbeat", "text"] | None: ...
global___StoreAndForward = StoreAndForward
class StoreAndForward(_message.Message):
__slots__ = ["heartbeat", "history", "rr", "stats", "text"]
class RequestResponse(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
class Heartbeat(_message.Message):
__slots__ = ["period", "secondary"]
PERIOD_FIELD_NUMBER: _ClassVar[int]
SECONDARY_FIELD_NUMBER: _ClassVar[int]
period: int
secondary: int
def __init__(self, period: _Optional[int] = ..., secondary: _Optional[int] = ...) -> None: ...
class History(_message.Message):
__slots__ = ["history_messages", "last_request", "window"]
HISTORY_MESSAGES_FIELD_NUMBER: _ClassVar[int]
LAST_REQUEST_FIELD_NUMBER: _ClassVar[int]
WINDOW_FIELD_NUMBER: _ClassVar[int]
history_messages: int
last_request: int
window: int
def __init__(self, history_messages: _Optional[int] = ..., window: _Optional[int] = ..., last_request: _Optional[int] = ...) -> None: ...
class Statistics(_message.Message):
__slots__ = ["heartbeat", "messages_max", "messages_saved", "messages_total", "requests", "requests_history", "return_max", "return_window", "up_time"]
HEARTBEAT_FIELD_NUMBER: _ClassVar[int]
MESSAGES_MAX_FIELD_NUMBER: _ClassVar[int]
MESSAGES_SAVED_FIELD_NUMBER: _ClassVar[int]
MESSAGES_TOTAL_FIELD_NUMBER: _ClassVar[int]
REQUESTS_FIELD_NUMBER: _ClassVar[int]
REQUESTS_HISTORY_FIELD_NUMBER: _ClassVar[int]
RETURN_MAX_FIELD_NUMBER: _ClassVar[int]
RETURN_WINDOW_FIELD_NUMBER: _ClassVar[int]
UP_TIME_FIELD_NUMBER: _ClassVar[int]
heartbeat: bool
messages_max: int
messages_saved: int
messages_total: int
requests: int
requests_history: int
return_max: int
return_window: int
up_time: int
def __init__(self, messages_total: _Optional[int] = ..., messages_saved: _Optional[int] = ..., messages_max: _Optional[int] = ..., up_time: _Optional[int] = ..., requests: _Optional[int] = ..., requests_history: _Optional[int] = ..., heartbeat: bool = ..., return_max: _Optional[int] = ..., return_window: _Optional[int] = ...) -> None: ...
CLIENT_ABORT: StoreAndForward.RequestResponse
CLIENT_ERROR: StoreAndForward.RequestResponse
CLIENT_HISTORY: StoreAndForward.RequestResponse
CLIENT_PING: StoreAndForward.RequestResponse
CLIENT_PONG: StoreAndForward.RequestResponse
CLIENT_STATS: StoreAndForward.RequestResponse
HEARTBEAT_FIELD_NUMBER: _ClassVar[int]
HISTORY_FIELD_NUMBER: _ClassVar[int]
ROUTER_BUSY: StoreAndForward.RequestResponse
ROUTER_ERROR: StoreAndForward.RequestResponse
ROUTER_HEARTBEAT: StoreAndForward.RequestResponse
ROUTER_HISTORY: StoreAndForward.RequestResponse
ROUTER_PING: StoreAndForward.RequestResponse
ROUTER_PONG: StoreAndForward.RequestResponse
ROUTER_STATS: StoreAndForward.RequestResponse
ROUTER_TEXT_BROADCAST: StoreAndForward.RequestResponse
ROUTER_TEXT_DIRECT: StoreAndForward.RequestResponse
RR_FIELD_NUMBER: _ClassVar[int]
STATS_FIELD_NUMBER: _ClassVar[int]
TEXT_FIELD_NUMBER: _ClassVar[int]
UNSET: StoreAndForward.RequestResponse
heartbeat: StoreAndForward.Heartbeat
history: StoreAndForward.History
rr: StoreAndForward.RequestResponse
stats: StoreAndForward.Statistics
text: bytes
def __init__(self, rr: _Optional[_Union[StoreAndForward.RequestResponse, str]] = ..., stats: _Optional[_Union[StoreAndForward.Statistics, _Mapping]] = ..., history: _Optional[_Union[StoreAndForward.History, _Mapping]] = ..., heartbeat: _Optional[_Union[StoreAndForward.Heartbeat, _Mapping]] = ..., text: _Optional[bytes] = ...) -> None: ...
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -2,10 +2,10 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: meshtastic/protobuf/xmodem.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
from google.protobuf.internal import builder as _builder
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
@@ -15,14 +15,14 @@ _sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n meshtastic/protobuf/xmodem.proto\x12\x13meshtastic.protobuf\"\xbf\x01\n\x06XModem\x12\x34\n\x07\x63ontrol\x18\x01 \x01(\x0e\x32#.meshtastic.protobuf.XModem.Control\x12\x0b\n\x03seq\x18\x02 \x01(\r\x12\r\n\x05\x63rc16\x18\x03 \x01(\r\x12\x0e\n\x06\x62uffer\x18\x04 \x01(\x0c\"S\n\x07\x43ontrol\x12\x07\n\x03NUL\x10\x00\x12\x07\n\x03SOH\x10\x01\x12\x07\n\x03STX\x10\x02\x12\x07\n\x03\x45OT\x10\x04\x12\x07\n\x03\x41\x43K\x10\x06\x12\x07\n\x03NAK\x10\x15\x12\x07\n\x03\x43\x41N\x10\x18\x12\t\n\x05\x43TRLZ\x10\x1a\x42\x62\n\x14org.meshtastic.protoB\x0cXmodemProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00\x62\x06proto3')
_globals = globals()
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.xmodem_pb2', _globals)
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'meshtastic.protobuf.xmodem_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\024org.meshtastic.protoB\014XmodemProtosZ\"github.com/meshtastic/go/generated\252\002\024Meshtastic.Protobufs\272\002\000'
_globals['_XMODEM']._serialized_start=58
_globals['_XMODEM']._serialized_end=249
_globals['_XMODEM_CONTROL']._serialized_start=166
_globals['_XMODEM_CONTROL']._serialized_end=249
_XMODEM._serialized_start=58
_XMODEM._serialized_end=249
_XMODEM_CONTROL._serialized_start=166
_XMODEM_CONTROL._serialized_end=249
# @@protoc_insertion_point(module_scope)
+26 -65
View File
@@ -1,67 +1,28 @@
"""
@generated by mypy-protobuf. Do not edit manually!
isort:skip_file
"""
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union
import builtins
import google.protobuf.descriptor
import google.protobuf.internal.enum_type_wrapper
import google.protobuf.message
import sys
import typing
DESCRIPTOR: _descriptor.FileDescriptor
if sys.version_info >= (3, 10):
import typing as typing_extensions
else:
import typing_extensions
DESCRIPTOR: google.protobuf.descriptor.FileDescriptor
@typing.final
class XModem(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor
class _Control:
ValueType = typing.NewType("ValueType", builtins.int)
V: typing_extensions.TypeAlias = ValueType
class _ControlEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[XModem._Control.ValueType], builtins.type):
DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor
NUL: XModem._Control.ValueType # 0
SOH: XModem._Control.ValueType # 1
STX: XModem._Control.ValueType # 2
EOT: XModem._Control.ValueType # 4
ACK: XModem._Control.ValueType # 6
NAK: XModem._Control.ValueType # 21
CAN: XModem._Control.ValueType # 24
CTRLZ: XModem._Control.ValueType # 26
class Control(_Control, metaclass=_ControlEnumTypeWrapper): ...
NUL: XModem.Control.ValueType # 0
SOH: XModem.Control.ValueType # 1
STX: XModem.Control.ValueType # 2
EOT: XModem.Control.ValueType # 4
ACK: XModem.Control.ValueType # 6
NAK: XModem.Control.ValueType # 21
CAN: XModem.Control.ValueType # 24
CTRLZ: XModem.Control.ValueType # 26
CONTROL_FIELD_NUMBER: builtins.int
SEQ_FIELD_NUMBER: builtins.int
CRC16_FIELD_NUMBER: builtins.int
BUFFER_FIELD_NUMBER: builtins.int
control: global___XModem.Control.ValueType
seq: builtins.int
crc16: builtins.int
buffer: builtins.bytes
def __init__(
self,
*,
control: global___XModem.Control.ValueType = ...,
seq: builtins.int = ...,
crc16: builtins.int = ...,
buffer: builtins.bytes = ...,
) -> None: ...
def ClearField(self, field_name: typing.Literal["buffer", b"buffer", "control", b"control", "crc16", b"crc16", "seq", b"seq"]) -> None: ...
global___XModem = XModem
class XModem(_message.Message):
__slots__ = ["buffer", "control", "crc16", "seq"]
class Control(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
__slots__ = []
ACK: XModem.Control
BUFFER_FIELD_NUMBER: _ClassVar[int]
CAN: XModem.Control
CONTROL_FIELD_NUMBER: _ClassVar[int]
CRC16_FIELD_NUMBER: _ClassVar[int]
CTRLZ: XModem.Control
EOT: XModem.Control
NAK: XModem.Control
NUL: XModem.Control
SEQ_FIELD_NUMBER: _ClassVar[int]
SOH: XModem.Control
STX: XModem.Control
buffer: bytes
control: XModem.Control
crc16: int
seq: int
def __init__(self, control: _Optional[_Union[XModem.Control, str]] = ..., seq: _Optional[int] = ..., crc16: _Optional[int] = ..., buffer: _Optional[bytes] = ...) -> None: ...
+2 -2
View File
@@ -3,8 +3,8 @@
import subprocess
from pathlib import Path
__version__ = "3.0.6"
__release_date__ = "2026-3-6"
__version__ = "3.0.8"
__release_date__ = "2026-5-12"
def get_git_revision():
+1 -1
View File
@@ -159,6 +159,7 @@
"times_seen": "Seen (24h)",
"avg_gateways": "Avg Gateways",
"showing_nodes": "Showing",
"all_channels": "All Channels",
"nodes_suffix": "nodes"
},
@@ -243,7 +244,6 @@
"share_contact_qr": "Share Contact QR",
"copy_url": "Copy URL",
"copied": "Copied!",
"potential_impersonation": "Potential Impersonation Detected",
"scan_qr_to_add": "Scan this QR code to add this node as a contact on another device."
},
"packet": {
+1 -1
View File
@@ -155,6 +155,7 @@
"times_seen": "Visto (24h)",
"avg_gateways": "Promedio de Gateways",
"showing_nodes": "Mostrando",
"all_channels": "Todos los Canales",
"nodes_suffix": "nodos"
},
@@ -229,7 +230,6 @@
"share_contact_qr": "Compartir contacto QR",
"copy_url": "Copiar URL",
"copied": "¡Copiado!",
"potential_impersonation": "Posible suplantación detectada",
"scan_qr_to_add": "Escanea este código QR para agregar este nodo como contacto en otro dispositivo."
},
+1 -1
View File
@@ -145,6 +145,7 @@
"times_seen": "Принято (24ч)",
"avg_gateways": "Среднее количество шлюзов",
"showing_nodes": "Показать",
"all_channels": "Все каналы",
"nodes_suffix": "ноды"
},
"nodegraph": {
@@ -224,7 +225,6 @@
"share_contact_qr": "Поделиться QR контакта",
"copy_url": "Копировать URL",
"copied": "Скопировано!",
"potential_impersonation": "Обнаружено возможное самозванство",
"scan_qr_to_add": "Отсканируйте этот QR-код, чтобы добавить эту ноду в качестве контакта на другом устройстве."
},
"packet": {
-15
View File
@@ -108,21 +108,6 @@ class Traceroute(Base):
)
class NodePublicKey(Base):
__tablename__ = "node_public_key"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
node_id: Mapped[int] = mapped_column(BigInteger, nullable=False)
public_key: Mapped[str] = mapped_column(nullable=False)
first_seen_us: Mapped[int] = mapped_column(BigInteger, nullable=True)
last_seen_us: Mapped[int] = mapped_column(BigInteger, nullable=True)
__table_args__ = (
Index("idx_node_public_key_node_id", "node_id"),
Index("idx_node_public_key_public_key", "public_key"),
)
class DailySnapshot(Base):
__tablename__ = "daily_snapshot"
+43 -32
View File
@@ -12,11 +12,39 @@ from meshtastic.protobuf.config_pb2 import Config
from meshtastic.protobuf.mesh_pb2 import HardwareModel
from meshtastic.protobuf.portnums_pb2 import PortNum
from meshview import decode_payload, mqtt_database
from meshview.models import DailySnapshot, Node, NodePublicKey, Packet, PacketSeen, Traceroute
from meshview.models import DailySnapshot, Node, Packet, PacketSeen, Traceroute
logger = logging.getLogger(__name__)
MQTT_GATEWAY_CACHE: set[int] = set()
UNKNOWN_NODE_NAME = "unknown name"
NODE_NAME_CONTROL_CHARS = re.compile(r"[\x00-\x1f\x7f]")
MQTT_DIRECT_NODE_ID = 1
def normalize_node_name(name: str) -> str:
name = name.strip()
if not name or NODE_NAME_CONTROL_CHARS.search(name):
return UNKNOWN_NODE_NAME
return name
def storage_packet_id(packet) -> int | None:
if packet.id:
return packet.id
if packet.decoded.portnum != PortNum.MAP_REPORT_APP:
return None
from_node_id = getattr(packet, "from", 0) or 0
now_us = int(time.time() * 1_000_000)
return -(now_us * 2048 + (from_node_id & 0x7FF))
def storage_to_node_id(packet) -> int:
if packet.decoded.portnum == PortNum.MAP_REPORT_APP:
return MQTT_DIRECT_NODE_ID
return packet.to
async def capture_daily_snapshot() -> None:
@@ -109,7 +137,8 @@ async def process_envelope(topic, env):
node.short_name = map_report.short_name
node.hw_model = hw_model
node.role = role
node.channel = env.channel_id
if not node.channel:
node.channel = env.channel_id
node.last_lat = map_report.latitude_i
node.last_long = map_report.longitude_i
node.firmware = map_report.firmware_version
@@ -137,20 +166,21 @@ async def process_envelope(topic, env):
await session.commit()
if not env.packet.id:
packet_id = storage_packet_id(env.packet)
if packet_id is None:
return
async with mqtt_database.async_session() as session:
# --- Packet insert with ON CONFLICT DO NOTHING
result = await session.execute(select(Packet).where(Packet.id == env.packet.id))
result = await session.execute(select(Packet).where(Packet.id == packet_id))
packet = result.scalar_one_or_none()
if not packet:
now_us = int(time.time() * 1_000_000)
packet_values = {
"id": env.packet.id,
"id": packet_id,
"portnum": env.packet.decoded.portnum,
"from_node_id": getattr(env.packet, "from"),
"to_node_id": env.packet.to,
"to_node_id": storage_to_node_id(env.packet),
"payload": env.packet.SerializeToString(),
"import_time_us": now_us,
"channel": env.channel_id,
@@ -198,7 +228,7 @@ async def process_envelope(topic, env):
now_us = int(time.time() * 1_000_000)
seen_values = {
"packet_id": env.packet.id,
"packet_id": packet_id,
"node_id": int(env.gateway_id[1:], 16),
"channel": env.channel_id,
"rx_time": env.packet.rx_time,
@@ -267,11 +297,13 @@ async def process_envelope(topic, env):
).scalar_one_or_none()
now_us = int(time.time() * 1_000_000)
long_name = normalize_node_name(user.long_name)
short_name = normalize_node_name(user.short_name)
if node:
node.node_id = node_id
node.long_name = user.long_name
node.short_name = user.short_name
node.long_name = long_name
node.short_name = short_name
node.hw_model = hw_model
node.role = role
node.channel = env.channel_id
@@ -282,8 +314,8 @@ async def process_envelope(topic, env):
node = Node(
id=user.id,
node_id=node_id,
long_name=user.long_name,
short_name=user.short_name,
long_name=long_name,
short_name=short_name,
hw_model=hw_model,
role=role,
channel=env.channel_id,
@@ -292,27 +324,6 @@ async def process_envelope(topic, env):
)
session.add(node)
if user.public_key:
public_key_hex = user.public_key.hex()
existing_key = (
await session.execute(
select(NodePublicKey).where(
NodePublicKey.node_id == node_id,
NodePublicKey.public_key == public_key_hex,
)
)
).scalar_one_or_none()
if existing_key:
existing_key.last_seen_us = now_us
else:
new_key = NodePublicKey(
node_id=node_id,
public_key=public_key_hex,
first_seen_us=now_us,
last_seen_us=now_us,
)
session.add(new_key)
except Exception as e:
print(f"Error processing NODEINFO_APP: {e}")
+12 -7
View File
@@ -241,7 +241,7 @@ function logPacketTimes(packet) {
const times = formatTimes(packet.import_time_us);
console.log(
"[firehose] packet time",
"id=" + packet.id,
"id=" + (packet.packet_id ?? packet.id),
"epoch_us=" + times.epoch,
"local=" + times.local,
"utc=" + times.utc
@@ -365,13 +365,21 @@ async function fetchUpdates() {
if (match) traceId = match[1];
inlineLinks += ` <a class="inline-link"
href="/graph/traceroute/${traceId}"
target="_blank">⮕</a>`;
href="/traceroute/${traceId}"
>⮕</a>`;
}
const safePayload = (pkt.payload || "")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;");
const packetIdCell = pkt.packet_id
? `<a href="/packet/${pkt.storage_id || pkt.id}"
style="text-decoration:underline; color:inherit;">
${pkt.packet_id}
</a>`
: pkt.portnum === 73
? `<span class="text-secondary" title="MQTT map report">Not at Packet</span>`
: `<span class="text-secondary" title="No Meshtastic packet ID"></span>`;
const html = `
<tr class="packet-row">
@@ -382,10 +390,7 @@ async function fetchUpdates() {
<td>
<span class="toggle-btn"></span>
<a href="/packet/${pkt.id}"
style="text-decoration:underline; color:inherit;">
${pkt.id}
</a>
${packetIdCell}
</td>
<td>${from}</td>
+165 -22
View File
@@ -148,6 +148,7 @@
<script src="https://unpkg.com/leaflet-polylinedecorator@1.6.0/dist/leaflet.polylinedecorator.js"
integrity="sha384-FhPn/2P/fJGhQLeNWDn9B/2Gml2bPOrKJwFqJXgR3xOPYxWg5mYQ5XZdhUSugZT0"
crossorigin></script>
<script src="https://unpkg.com/leaflet.heat/dist/leaflet-heat.js"></script>
<script src="/static/portmaps.js"></script>
<script>
@@ -188,25 +189,71 @@ function applyTranslationsMap(root = document) {
====================================================== */
var map = L.map('map');
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png',
{ maxZoom:19, attribution:'&copy; OpenStreetMap' }).addTo(map);
var baseLayers = {
"OpenStreetMap": L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '&copy; OpenStreetMap'
}),
"OpenTopoMap": L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
maxZoom: 17,
attribution: 'Map data: &copy; OpenStreetMap, SRTM | Map style: &copy; OpenTopoMap'
})
};
baseLayers["OpenStreetMap"].addTo(map);
L.control.scale({
position: 'bottomleft',
metric: true,
imperial: true
}).addTo(map);
var nodeLayer = L.layerGroup().addTo(map);
var edgeLayer = L.layerGroup().addTo(map);
var trafficHeatLayer = L.heatLayer([], {
radius: 34,
blur: 18,
maxZoom: 12,
minOpacity: 0.3,
gradient: {
0.2: "#0b1f4d",
0.45: "#12436b",
0.7: "#7f2704",
1.0: "#4d0000"
}
});
var overlayLayers = {
"Nodes": nodeLayer,
"Traffic HeatMap": trafficHeatLayer
};
L.control.layers(baseLayers, overlayLayers, { collapsed: false }).addTo(map);
// Data structures
var nodes = [], markers = {}, markerById = {}, nodeMap = new Map();
var edgeLayer = L.layerGroup().addTo(map), selectedNodeId = null;
var selectedNodeId = null;
var activeBlinks = new Map(), lastImportTime = null;
var mapInterval = 0;
var unmappedPackets = [];
var trafficHeatLoaded = false;
var trafficHeatLoading = false;
const UNMAPPED_LIMIT = 50;
const UNMAPPED_TTL_MS = 5000;
const portMap = window.PORT_LABEL_MAP;
const palette = ["#e6194b","#4363d8","#f58231","#911eb4","#46f0f0","#f032e6","#bcf60c","#fabebe",
"#008080","#e6beff","#9a6324","#fffac8","#800000","#aaffc3","#808000","#ffd8b1",
"#000075","#808080"];
const palette = ["#bcf60c","#fabebe","#e6beff","#9a6324","#fffac8","#800000","#aaffc3","#ffd8b1",
"#808080"];
const colorMap = new Map(); let nextColorIndex = 0;
const channelColorOverrides = {
longfast: "#4363d8",
longslow: "#000075",
verylongslow: "#808000",
mediumslow: "#008080",
mediumfast: "#e6194b",
shortslow: "#911eb4",
shortfast: "#f58231",
longmoderate: "#46f0f0",
shortturbo: "#f032e6"
};
const colorMap = new Map();
const channelSet = new Set();
map.on("popupopen", function (e) {
@@ -221,10 +268,17 @@ function timeAgoFromUs(us){
return d>0?d+"d":h>0?h+"h":m>0?m+"m":s+"s";
}
function normalizeChannelName(str){
return String(str || "Unknown").toLowerCase().replace(/[\s_-]+/g, "");
}
function hashToColor(str){
if(colorMap.has(str)) return colorMap.get(str);
const c = palette[nextColorIndex++ % palette.length];
colorMap.set(str,c);
const channel = String(str || "Unknown");
if(colorMap.has(channel)) return colorMap.get(channel);
const override = channelColorOverrides[normalizeChannelName(channel)];
const c = override || palette[Math.floor(hashToUnit(channel) * palette.length) % palette.length];
colorMap.set(channel,c);
return c;
}
@@ -366,6 +420,15 @@ document.addEventListener("visibilitychange",()=>{
document.hidden?stopPacketFetcher():startPacketFetcher();
});
map.on("overlayadd", e => {
if(e.layer === nodeLayer) updateNodeVisibility();
if(e.layer === trafficHeatLayer) loadTrafficHeat();
});
map.on("overlayremove", e => {
if(e.layer === nodeLayer) clearActiveBlinks();
});
async function waitForConfig() {
while (typeof window._siteConfigPromise === "undefined") {
await new Promise(r => setTimeout(r, 100));
@@ -447,6 +510,9 @@ fetch('/api/nodes?days_active=3')
renderNodesOnMap();
createChannelFilters();
if(map.hasLayer(trafficHeatLayer)){
loadTrafficHeat();
}
})
.catch(console.error);
@@ -467,7 +533,7 @@ function renderNodesOnMap(){
fillColor: color,
fillOpacity: 1,
weight: 0.7
}).addTo(map);
}).addTo(nodeLayer);
marker.nodeId = node.key;
marker.originalColor = color;
@@ -490,6 +556,56 @@ function renderNodesOnMap(){
setTimeout(() => applyTranslationsMap(), 50);
}
/* ======================================================
TRAFFIC HEAT LAYER
====================================================== */
async function loadTrafficHeat(){
if(trafficHeatLoaded || trafficHeatLoading) return;
if(nodeMap.size === 0) return;
trafficHeatLoading = true;
try {
const url = new URL("/api/packets", window.location.origin);
url.searchParams.set("limit", 1000);
const res = await fetch(url);
if(!res.ok) return;
const data = await res.json();
const counts = new Map();
(data.packets || []).forEach(pkt => {
const nodeId = pkt.from_node_id;
if(nodeId == null) return;
counts.set(nodeId, (counts.get(nodeId) || 0) + 1);
});
const maxCount = Math.max(...counts.values(), 0);
const heatPoints = [];
counts.forEach((count, nodeId) => {
const node = nodeMap.get(nodeId);
if(!node || isInvalidCoord(node)) return;
const markerLatLng = markerById[nodeId]?.getLatLng();
const lat = markerLatLng?.lat ?? node.lat;
const lng = markerLatLng?.lng ?? node.long;
const intensity = maxCount > 0 ? count / maxCount : 0;
heatPoints.push([lat, lng, Math.max(0.15, intensity)]);
});
trafficHeatLayer.setLatLngs(heatPoints);
trafficHeatLoaded = true;
} catch(err) {
console.error("Failed to load traffic heat layer:", err);
} finally {
trafficHeatLoading = false;
}
}
/* ======================================================
UNMAPPED PACKETS LIST
====================================================== */
@@ -628,13 +744,33 @@ function isTextPort(portnum){
return portnum === 1 || portnum === 7;
}
function isNodeVisibleForPackets(marker){
return map.hasLayer(nodeLayer) && nodeLayer.hasLayer(marker);
}
function clearBlinkForMarker(marker){
if(activeBlinks.has(marker)){
const interval = activeBlinks.get(marker);
clearInterval(interval);
activeBlinks.delete(marker);
}
marker.setStyle({ fillColor: marker.originalColor });
if(marker.tooltip){
map.removeLayer(marker.tooltip);
marker.tooltip = null;
}
}
function clearActiveBlinks(){
activeBlinks.forEach((interval, marker) => clearBlinkForMarker(marker));
activeBlinks.clear();
}
function blinkNode(marker,longName,portnum,payload){
if(!map.hasLayer(marker)) return;
if(!isNodeVisibleForPackets(marker)) return;
if(activeBlinks.has(marker)){
clearInterval(activeBlinks.get(marker));
marker.setStyle({ fillColor: marker.originalColor });
if(marker.tooltip) map.removeLayer(marker.tooltip);
clearBlinkForMarker(marker);
}
let blinkCount = 0;
@@ -662,19 +798,19 @@ function blinkNode(marker,longName,portnum,payload){
marker.tooltip = tooltip;
const interval = setInterval(()=>{
if(map.hasLayer(marker)){
if(isNodeVisibleForPackets(marker)){
marker.setStyle({
fillColor: blinkCount%2===0 ? 'yellow' : marker.originalColor
});
marker.bringToFront();
} else {
clearBlinkForMarker(marker);
return;
}
blinkCount++;
if(Date.now() - blinkStart > blinkDurationMs){
clearInterval(interval);
marker.setStyle({ fillColor: marker.originalColor });
map.removeLayer(tooltip);
activeBlinks.delete(marker);
clearBlinkForMarker(marker);
}
},500);
@@ -690,7 +826,7 @@ function createChannelFilters(){
const filterContainer = document.getElementById("filter-container");
const saved = JSON.parse(localStorage.getItem("mapFilters") || "{}");
channelSet.forEach(channel=>{
[...channelSet].sort((a, b) => a.localeCompare(b)).forEach(channel=>{
const cb=document.createElement("input");
cb.type="checkbox";
cb.className="filter-checkbox";
@@ -734,6 +870,8 @@ function saveFiltersToLocalStorage(){
}
function updateNodeVisibility(){
if(!map.hasLayer(nodeLayer)) return;
const routerOnly = document.getElementById("filter-routers-only").checked;
const mqttOnly = document.getElementById("filter-mqtt-only").checked;
const activeChannels = [...channelSet].filter(ch =>
@@ -748,7 +886,12 @@ function updateNodeVisibility(){
(!mqttOnly || n.is_mqtt_gateway) &&
activeChannels.includes(n.channel);
visible ? map.addLayer(marker) : map.removeLayer(marker);
if(visible){
nodeLayer.addLayer(marker);
} else {
clearBlinkForMarker(marker);
nodeLayer.removeLayer(marker);
}
}
});
}
+29 -60
View File
@@ -296,32 +296,6 @@
color:#fff;
}
/* --- Impersonation Warning --- */
.impersonation-warning {
background: rgba(239, 68, 68, 0.15);
border: 1px solid rgba(239, 68, 68, 0.4);
border-radius: 8px;
padding: 12px 16px;
margin-bottom: 14px;
display: flex;
align-items: flex-start;
gap: 10px;
}
.impersonation-warning .warning-icon {
font-size: 1.2rem;
}
.impersonation-warning .warning-content {
flex: 1;
}
.impersonation-warning .warning-title {
color: #f87171;
font-weight: bold;
margin-bottom: 4px;
}
.impersonation-warning .warning-text {
font-size: 0.85rem;
color: #ccc;
}
{% endblock %}
{% block body %}
@@ -340,6 +314,9 @@
<button onclick="showQrCode()" id="showQrBtn">
<span>🔳</span> <span data-translate-lang="show_qr_code">Show QR Code</span>
</button>
<button onclick="openReachReport()" id="reachReportBtn">
<span>📈</span> <span>Reliability</span>
</button>
<button onclick="toggleCoverage()" id="toggleCoverageBtn" disabled title="Location required for coverage">
<span>📡</span> <span data-translate-lang="toggle_coverage">Predicted Coverage</span>
</button>
@@ -348,15 +325,6 @@
</a>
</div>
<!-- Impersonation Warning -->
<div id="impersonationWarning" class="impersonation-warning" style="display:none;">
<span class="warning-icon">⚠️</span>
<div class="warning-content">
<div class="warning-title" data-translate-lang="potential_impersonation">Potential Impersonation Detected</div>
<div class="warning-text" id="impersonationText"></div>
</div>
</div>
<!-- Node Info -->
<div id="node-info" class="node-info">
<div class="node-info-col">
@@ -825,6 +793,11 @@ function initMap(){
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution:'&copy; OpenStreetMap'
}).addTo(map);
L.control.scale({
position: 'bottomleft',
metric: true,
imperial: true
}).addTo(map);
}
async function toggleCoverage() {
@@ -1098,18 +1071,24 @@ async function loadPackets(filters = {}) {
const match = pkt.payload?.match(/ID:\s*(\d+)/i);
if (match) traceId = match[1];
inlineLinks +=
` <a class="inline-link" href="/graph/traceroute/${traceId}" target="_blank"></a>`;
` <a class="inline-link" href="/traceroute/${traceId}" target="_blank"></a>`;
}
const sizeBytes = packetSizeBytes(pkt);
const packetIdCell = pkt.packet_id
? `<a href="/packet/${pkt.storage_id || pkt.id}"
style="text-decoration:underline; color:inherit;">
${pkt.packet_id}
</a>`
: pkt.portnum === 73
? `<span class="text-secondary" title="MQTT map report">Not a Packet</span>`
: `<span class="text-secondary" title="No Meshtastic packet ID"></span>`;
list.insertAdjacentHTML("afterbegin", `
<tr class="packet-row">
<td>${localTime}</td>
<td><span class="toggle-btn"></span>
<a href="/packet/${pkt.id}" style="text-decoration:underline; color:inherit;">
${pkt.id}
</a>
${packetIdCell}
</td>
<td>${fromCell}</td>
<td>${toCell}</td>
@@ -1629,8 +1608,7 @@ document.addEventListener("DOMContentLoaded", async () => {
requestAnimationFrame(async () => {
await loadNodeInfo();
// Load QR code URL and impersonation check
await loadNodeQrAndImpersonation();
await loadNodeQr();
// ✅ MAP MUST EXIST FIRST
if (!map) initMap();
@@ -1734,6 +1712,7 @@ async function loadNodeStats(nodeId) {
: "";
const portName = PORT_LABEL_MAP[pkt.portnum] || `Port ${pkt.portnum}`;
const displayPacketId = pkt.packet_id || (pkt.portnum === 73 ? "Not a Packet" : "");
// Escape quotes + line breaks for CSV safety
const payload = (pkt.payload || "")
@@ -1742,7 +1721,7 @@ async function loadNodeStats(nodeId) {
rows.push([
time,
pkt.id,
displayPacketId,
pkt.from_node_id,
pkt.to_node_id,
pkt.portnum,
@@ -1766,16 +1745,11 @@ async function loadNodeStats(nodeId) {
let currentMeshtasticUrl = "";
async function loadNodeQrAndImpersonation() {
async function loadNodeQr() {
const actionsDiv = document.getElementById("nodeActions");
const warningDiv = document.getElementById("impersonationWarning");
try {
const [qrRes, impRes] = await Promise.all([
fetch(`/api/node/${fromNodeId}/qr`),
fetch(`/api/node/${fromNodeId}/impersonation-check`)
]);
const qrRes = await fetch(`/api/node/${fromNodeId}/qr`);
const qrData = await qrRes.json();
if (qrRes.ok && qrData.meshtastic_url) {
currentMeshtasticUrl = qrData.meshtastic_url;
@@ -1783,19 +1757,9 @@ async function loadNodeQrAndImpersonation() {
} else {
actionsDiv.style.display = "none";
}
const impData = await impRes.json();
if (impRes.ok && impData.potential_impersonation) {
warningDiv.style.display = "flex";
document.getElementById("impersonationText").textContent =
impData.warning || `This node has sent ${impData.unique_public_key_count} different public keys. This could indicate impersonation.`;
} else {
warningDiv.style.display = "none";
}
} catch (err) {
console.error("Failed to load QR/impersonation data:", err);
console.error("Failed to load QR data:", err);
actionsDiv.style.display = "none";
warningDiv.style.display = "none";
}
}
@@ -1830,6 +1794,11 @@ function showQrCode() {
document.getElementById("qrModal").style.display = "flex";
}
function openReachReport() {
if (!fromNodeId) return;
window.location.href = `/reliability?node_id=${encodeURIComponent(fromNodeId)}`;
}
function closeQrModal() {
document.getElementById("qrModal").style.display = "none";
}
+48 -2
View File
@@ -103,6 +103,20 @@ select, .export-btn, .search-box, .clear-btn {
font-weight: bold;
color: white;
}
.node-list-note {
width: 80%;
margin: -4px auto 10px;
color: rgba(255, 255, 255, 0.68);
font-size: 0.9em;
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.node-list-note select {
padding: 3px 6px;
min-width: 70px;
}
.node-status {
margin-left: 10px;
padding: 2px 8px;
@@ -252,6 +266,15 @@ select, .export-btn, .search-box, .clear-btn {
<span data-translate-lang="nodes_suffix">nodes</span>
<span id="node-status" class="node-status" aria-live="polite"></span>
</div>
<div class="node-list-note">
<span>Showing nodes active in the last</span>
<select id="days-active-filter" aria-label="Days active">
{% for day in range(1, 15) %}
<option value="{{ day }}" {% if day == 3 %}selected{% endif %}>{{ day }}</option>
{% endfor %}
</select>
<span>days.</span>
</div>
<!-- Desktop table -->
<div id="node-list">
@@ -407,16 +430,18 @@ document.addEventListener("DOMContentLoaded", async function() {
const searchBox = document.getElementById("search-box");
const countSpan = document.getElementById("node-count");
const statusSpan = document.getElementById("node-status");
const daysActiveFilter = document.getElementById("days-active-filter");
const exportBtn = document.getElementById("export-btn");
const clearBtn = document.getElementById("clear-btn");
const favoritesBtn = document.getElementById("favorites-btn");
let lastIsMobile = (window.innerWidth <= 768);
try {
async function loadNodesForActiveDays() {
const daysActive = Number(daysActiveFilter.value) || 3;
setStatus("Loading nodes…");
await nextFrame();
const res = await fetch("/api/nodes?days_active=3");
const res = await fetch(`/api/nodes?days_active=${encodeURIComponent(daysActive)}`);
if (!res.ok) throw new Error("Failed to fetch nodes");
const data = await res.json();
@@ -447,6 +472,10 @@ document.addEventListener("DOMContentLoaded", async function() {
applyFilters(); // ensures initial sort + render uses same path
updateSortIcons();
setStatus("");
}
try {
await loadNodesForActiveDays();
} catch (err) {
tbody.innerHTML = `<tr>
<td colspan="11" style="text-align:center; color:red;">
@@ -460,6 +489,20 @@ document.addEventListener("DOMContentLoaded", async function() {
channelFilter.addEventListener("change", applyFilters);
hwFilter.addEventListener("change", applyFilters);
firmwareFilter.addEventListener("change", applyFilters);
daysActiveFilter.addEventListener("change", async () => {
try {
await loadNodesForActiveDays();
} catch (err) {
console.error("Failed to reload nodes:", err);
tbody.innerHTML = `<tr>
<td colspan="11" style="text-align:center; color:red;">
${nodelistTranslations.error_loading_nodes || "Error loading nodes"}
</td></tr>`;
mobileList.innerHTML = "";
countSpan.textContent = 0;
setStatus("");
}
});
// Debounced only for search typing
searchBox.addEventListener("input", debounce(applyFilters, 250));
@@ -526,12 +569,15 @@ document.addEventListener("DOMContentLoaded", async function() {
}
function fillSelect(select, values) {
const currentValue = select.value;
select.querySelectorAll("option:not(:first-child)").forEach(opt => opt.remove());
[...values].sort().forEach(v => {
const opt = document.createElement("option");
opt.value = v;
opt.textContent = v;
select.appendChild(opt);
});
select.value = values.has(currentValue) ? currentValue : "";
}
function toggleFavoritesFilter() {
+856
View File
@@ -0,0 +1,856 @@
{% extends "base.html" %}
{% block css %}
.reach-page {
max-width: 1200px;
margin: 0 auto;
padding: 0 16px;
}
.reach-header {
margin-bottom: 10px;
}
.reach-header h1 {
font-size: 1.35rem;
margin-bottom: 2px;
}
.reach-panel {
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 8px;
padding: 12px;
background: rgba(255, 255, 255, 0.04);
}
.reach-controls {
display: flex;
gap: 8px;
margin-top: 8px;
}
.reach-search {
min-width: 0;
flex: 0 1 420px;
}
.reach-search-label,
.reach-limit-label {
align-self: center;
white-space: nowrap;
color: rgba(255, 255, 255, 0.72);
font-size: 0.9rem;
}
.reach-limit-label {
margin-left: auto;
}
.reach-node-link {
align-self: center;
white-space: nowrap;
}
@media (max-width: 600px) {
.reach-controls {
flex-direction: column;
}
}
.reach-summary {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 8px;
margin-top: 10px;
}
.reach-metric {
border: 1px solid rgba(255, 255, 255, 0.12);
border-radius: 8px;
padding: 8px 10px;
background: rgba(0, 0, 0, 0.18);
}
.reach-metric-value {
font-size: 1.2rem;
line-height: 1.2;
}
.reach-table-wrap {
overflow-x: auto;
margin-top: 10px;
}
.reach-table {
width: 100%;
min-width: 760px;
font-size: 0.9rem;
}
.reach-map {
width: 100%;
height: 520px;
margin-top: 10px;
border: 1px solid rgba(255, 255, 255, 0.14);
border-radius: 8px;
overflow: hidden;
background: rgba(0, 0, 0, 0.18);
}
.reach-map-marker {
width: 34px;
height: 34px;
border: 2px solid #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 0.65rem;
font-weight: 800;
line-height: 1;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.75);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);
}
.reach-map-marker-source {
background: #111827;
font-size: 0.95rem;
}
.reach-gateway-panels {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
margin-top: 10px;
}
.reach-gateway-panel {
overflow-x: auto;
}
.reach-gateway-table {
min-width: 0;
}
.reach-table th,
.reach-table td {
vertical-align: top;
padding: 0.35rem 0.5rem;
}
.reach-count-bar-cell {
min-width: 180px;
}
.reach-count-bar-track {
position: relative;
height: 20px;
border-radius: 999px;
background: rgba(255, 255, 255, 0.12);
overflow: hidden;
}
.reach-count-bar-fill {
height: 100%;
min-width: 24px;
border-radius: inherit;
background: var(--reach-bar-color, #4ade80);
}
.reach-count-bar-value {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: flex-start;
padding-left: 8px;
font-family: monospace;
font-size: 0.85rem;
color: #fff;
font-weight: 700;
}
.reach-muted {
color: rgba(255, 255, 255, 0.62);
}
.reach-heard-link {
padding: 0;
border: 0;
background: transparent;
color: #8ab4f8;
text-decoration: underline;
cursor: pointer;
}
.port-tag {
display: inline-block;
padding: 1px 6px;
border-radius: 6px;
font-size: 0.75rem;
font-weight: 500;
color: #fff;
}
.reliability-modal {
display: none;
position: fixed;
inset: 0;
z-index: 5000;
align-items: center;
justify-content: center;
padding: 16px;
background: rgba(0, 0, 0, 0.72);
}
.reliability-modal.open {
display: flex;
}
.reliability-modal-panel {
width: min(760px, 100%);
max-height: min(720px, 92vh);
overflow: auto;
border: 1px solid rgba(255, 255, 255, 0.18);
border-radius: 8px;
background: #111827;
padding: 12px;
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.5);
}
.reliability-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 10px;
}
.reliability-modal-title {
font-size: 1rem;
font-weight: 600;
}
.reliability-status-heard {
color: #4ade80 !important;
font-weight: 700;
}
.reliability-status-missed {
color: #f87171 !important;
font-weight: 700;
}
.reliability-status-skipped {
color: #cbd5e1 !important;
font-weight: 700;
}
.reliability-row-skipped td {
text-decoration: line-through;
text-decoration-thickness: 1px;
color: rgba(255, 255, 255, 0.58) !important;
}
@media (max-width: 600px) {
.reach-gateway-panels {
grid-template-columns: 1fr;
}
}
{% endblock %}
{% block body %}
<main class="reach-page">
<div class="reach-header">
<h1>Reliability</h1>
<p class="text-secondary mb-0">
Review how often each gateway hears packets from a selected node. The report uses the
latest selected packet sample and calculates reliability as heard packets divided by packets
reviewed. The range table groups gateways by reliability bands, while the gateway list
shows each gateway's heard count and percentage for the same sample. Reliability is
calculated only from Text, Position, Node Info, and Telemetry packets; other packet types
are shown in packet details but skipped from the calculation.
</p>
</div>
<section class="reach-panel">
<form class="reach-controls" id="reach-search-form">
<label class="reach-search-label" for="reach-node-search">Search</label>
<input
class="form-control reach-search"
id="reach-node-search"
list="reach-node-options"
placeholder="Search node name or enter node ID"
autocomplete="off"
>
<datalist id="reach-node-options"></datalist>
<label class="reach-limit-label" for="reliability-packet-type">Packet type</label>
<select class="form-select" id="reliability-packet-type" style="max-width:150px;">
<option value="">All</option>
<option value="1" selected>Text</option>
<option value="3">Position</option>
<option value="4">Node Info</option>
<option value="67">Telemetry</option>
</select>
<label class="reach-limit-label" for="reach-packet-limit">Packets to review</label>
<select class="form-select" id="reach-packet-limit" style="max-width:110px;">
<option value="10">10</option>
<option value="20" selected>20</option>
<option value="30">30</option>
<option value="40">40</option>
<option value="50">50</option>
<option value="60">60</option>
<option value="70">70</option>
<option value="80">80</option>
<option value="90">90</option>
<option value="100">100</option>
</select>
<button class="btn btn-primary" type="submit">Load</button>
<a class="btn btn-outline-secondary reach-node-link" id="reach-node-link" href="/node/3530776522">
Back to Node
</a>
</form>
<div class="reach-table-wrap">
<table class="table table-dark table-sm table-striped reach-table">
<thead>
<tr>
<th>Reliability Bands</th>
<th>Gateway Count</th>
</tr>
</thead>
<tbody id="reach-bucket-body">
<tr>
<td colspan="2" class="reach-muted">Loading statistics...</td>
</tr>
</tbody>
</table>
</div>
<div id="reach-gateway-map" class="reach-map"></div>
<div class="reach-summary">
<div class="reach-metric">
<div class="text-secondary">Latest Packets</div>
<div class="reach-metric-value" id="reach-packet-count">...</div>
</div>
<div class="reach-metric">
<div class="text-secondary">Unique Gateways</div>
<div class="reach-metric-value" id="reach-gateway-count">...</div>
</div>
</div>
<div class="reach-gateway-panels">
<div class="reach-gateway-panel">
<table class="table table-dark table-sm table-striped reach-table reach-gateway-table">
<thead>
<tr>
<th>Gateway</th>
<th>Heard</th>
<th>Avg Hops</th>
<th>Reliability</th>
</tr>
</thead>
<tbody id="reach-packet-body-left">
<tr>
<td colspan="4" class="reach-muted">Loading packets...</td>
</tr>
</tbody>
</table>
</div>
<div class="reach-gateway-panel">
<table class="table table-dark table-sm table-striped reach-table reach-gateway-table">
<thead>
<tr>
<th>Gateway</th>
<th>Heard</th>
<th>Avg Hops</th>
<th>Reliability</th>
</tr>
</thead>
<tbody id="reach-packet-body-right">
<tr>
<td colspan="4" class="reach-muted">Loading packets...</td>
</tr>
</tbody>
</table>
</div>
</div>
</section>
</main>
<div class="reliability-modal" id="gateway-packet-modal" role="dialog" aria-modal="true" aria-labelledby="gateway-packet-title">
<div class="reliability-modal-panel">
<div class="reliability-modal-header">
<div class="reliability-modal-title" id="gateway-packet-title">Packet Details</div>
<button class="btn btn-sm btn-outline-light" type="button" onclick="closeGatewayPacketModal()">Close</button>
</div>
<div class="reach-table-wrap">
<table class="table table-dark table-sm table-striped reach-table">
<thead>
<tr>
<th>Packet</th>
<th>Time</th>
<th>Type</th>
<th>Hops</th>
<th>Status</th>
</tr>
</thead>
<tbody id="gateway-packet-body">
<tr>
<td colspan="5" class="reach-muted">No packet selected.</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<script src="/static/portmaps.js"></script>
<script>
const defaultReachNodeId = 3530776522;
const defaultReachPacketLimit = 20;
const initialReachNodeId = Number(new URLSearchParams(window.location.search).get("node_id")) || defaultReachNodeId;
let reachNodeId = initialReachNodeId;
let reachNodes = [];
let reliabilityGatewayDetails = new Map();
let reliabilityMap = null;
let reliabilityMapLayer = null;
const countedReliabilityPorts = new Set([1, 3, 4, 67]);
const reliabilityBuckets = [
{ label: "100%", color: "#22c55e", matches: row => row.percent === 100 },
{ label: "90-99%", color: "#84cc16", matches: row => row.percent >= 90 && row.percent < 100 },
{ label: "80-89%", color: "#eab308", matches: row => row.percent >= 80 && row.percent < 90 },
{ label: "70-79%", color: "#f97316", matches: row => row.percent >= 70 && row.percent < 80 },
{ label: "60-69%", color: "#ef4444", matches: row => row.percent >= 60 && row.percent < 70 },
{ label: "50-59%", color: "#991b1b", matches: row => row.percent >= 50 && row.percent < 60 },
];
function escapeHtml(value) {
return String(value ?? "")
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#39;");
}
function gatewayLabel(nodeId, nodesById) {
const node = nodesById.get(Number(nodeId));
const name = node?.long_name || node?.short_name;
return name ? `${name} (${nodeId})` : String(nodeId);
}
function nodeLink(nodeId, nodesById) {
return `<a href="/node/${encodeURIComponent(nodeId)}">${
escapeHtml(gatewayLabel(nodeId, nodesById))
}</a>`;
}
function nodeSearchLabel(node) {
const name = node.long_name || node.short_name || "Unnamed";
return `${name} (${node.node_id})`;
}
function formatPacketTime(us) {
if (!us) return "N/A";
return new Date(us / 1000).toLocaleString();
}
function packetTypeTag(portnum) {
const name = window.PORT_MAP?.[portnum] || "Unknown";
const color = window.PORT_COLORS?.[portnum] || "#6c757d";
return `
<span class="port-tag" style="background-color:${color}">
${escapeHtml(name)}
</span>
<span class="text-secondary">(${escapeHtml(portnum ?? "?")})</span>
`;
}
function packetSeenHopCount(row) {
const hopStart = Number(row?.hop_start ?? 0);
const hopLimit = Number(row?.hop_limit ?? 0);
return Math.max(0, hopStart - hopLimit);
}
function formatAverageHopCount(value) {
if (value === null || value === undefined || !Number.isFinite(value)) return "—";
const lower = Math.floor(value);
return value - lower === 0.5 ? lower : Math.round(value);
}
function formatAverageHopCountWithActual(value) {
if (value === null || value === undefined || !Number.isFinite(value)) return "—";
return `${formatAverageHopCount(value)} (${value.toFixed(1)})`;
}
function reliabilityBucketFor(row) {
return reliabilityBuckets.find(bucket => bucket.matches(row)) || null;
}
function nodeLatLng(node) {
if (!node?.last_lat || !node?.last_long) return null;
const lat = node.last_lat / 1e7;
const lon = node.last_long / 1e7;
if (!Number.isFinite(lat) || !Number.isFinite(lon) || lat === 0 || lon === 0) return null;
return [lat, lon];
}
function initReliabilityMap() {
if (reliabilityMap) return reliabilityMap;
reliabilityMap = L.map("reach-gateway-map", { preferCanvas: true }).setView([37.7749, -122.4194], 8);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "&copy; OpenStreetMap",
maxZoom: 19,
}).addTo(reliabilityMap);
L.control.scale({
position: "bottomleft",
metric: true,
imperial: true,
}).addTo(reliabilityMap);
reliabilityMapLayer = L.layerGroup().addTo(reliabilityMap);
return reliabilityMap;
}
function resetReliabilityMap() {
if (!reliabilityMap) initReliabilityMap();
reliabilityMapLayer.clearLayers();
requestAnimationFrame(() => reliabilityMap.invalidateSize());
}
function reachMapIcon(label, color, extraClass = "") {
return L.divIcon({
className: "",
iconSize: [34, 34],
iconAnchor: [17, 17],
popupAnchor: [0, -17],
html: `
<div class="reach-map-marker ${extraClass}" style="background:${color};">
${escapeHtml(label)}
</div>
`,
});
}
function renderReliabilityMap(gatewayRows, nodesById) {
if (!reliabilityMap) initReliabilityMap();
reliabilityMapLayer.clearLayers();
const bounds = [];
const sourceNode = nodesById.get(Number(reachNodeId));
const sourceLatLng = nodeLatLng(sourceNode);
if (sourceLatLng) {
L.marker(sourceLatLng, {
icon: reachMapIcon("TX", "#111827", "reach-map-marker-source"),
}).bindPopup(`<b>${escapeHtml(gatewayLabel(reachNodeId, nodesById))}</b><br>Selected Node`)
.addTo(reliabilityMapLayer);
bounds.push(sourceLatLng);
}
gatewayRows.forEach(row => {
const bucket = reliabilityBucketFor(row);
if (!bucket) return;
const node = nodesById.get(Number(row.nodeId));
const latLng = nodeLatLng(node);
if (!latLng) return;
L.marker(latLng, {
icon: reachMapIcon(`${Math.round(row.percent)}%`, bucket.color),
}).bindPopup(`
<b>${nodeLink(row.nodeId, nodesById)}</b><br>
Reliability: ${row.percent.toFixed(1)}% · Avg. hops ${formatAverageHopCountWithActual(row.avgHopCount)}<br>
Heard:
<button class="reach-heard-link" type="button" onclick="openGatewayPacketModal(${row.nodeId})">
${row.heardCount}
</button>
<span class="text-secondary">(${row.total})</span>
`).addTo(reliabilityMapLayer);
bounds.push(latLng);
});
requestAnimationFrame(() => {
reliabilityMap.invalidateSize();
if (bounds.length) {
reliabilityMap.fitBounds(bounds, { padding: [24, 24], maxZoom: 12 });
}
});
}
function isSkippedReliabilityPacket(packet) {
return !countedReliabilityPorts.has(Number(packet.portnum));
}
function openGatewayPacketModal(nodeId) {
const details = reliabilityGatewayDetails.get(Number(nodeId));
const titleEl = document.getElementById("gateway-packet-title");
const bodyEl = document.getElementById("gateway-packet-body");
const modalEl = document.getElementById("gateway-packet-modal");
if (!details) return;
titleEl.textContent = `${details.label}: ${details.heardCount} (${details.total}) packets heard`;
bodyEl.innerHTML = details.packets.map(packet => {
const statusClass = packet.skipped
? "reliability-status-skipped"
: packet.heard ? "reliability-status-heard" : "reliability-status-missed";
const statusText = packet.heard ? "Heard" : "Missed";
return `
<tr class="${packet.skipped ? "reliability-row-skipped" : ""}">
<td><a href="/packet/${packet.id}">${packet.id}</a></td>
<td>${escapeHtml(formatPacketTime(packet.import_time_us))}</td>
<td>${packetTypeTag(packet.portnum)}</td>
<td>${packet.hopCount ?? "—"}</td>
<td class="${statusClass}">${statusText}</td>
</tr>
`;
}).join("");
modalEl.classList.add("open");
}
function closeGatewayPacketModal() {
document.getElementById("gateway-packet-modal").classList.remove("open");
}
function parseNodeSearchValue(value) {
const trimmed = value.trim();
const parenthesizedId = trimmed.match(/\((\d+)\)\s*$/);
if (parenthesizedId) return Number(parenthesizedId[1]);
const rawId = trimmed.match(/^\d+$/);
if (rawId) return Number(trimmed);
const lower = trimmed.toLowerCase();
const node = reachNodes.find(n =>
(n.long_name || "").toLowerCase() === lower ||
(n.short_name || "").toLowerCase() === lower
);
return node ? Number(node.node_id) : null;
}
async function fetchJson(url) {
const res = await fetch(url);
if (!res.ok) {
throw new Error(`${url} returned ${res.status}`);
}
return res.json();
}
async function loadReachNodes() {
const data = await fetchJson("/api/nodes?days_active=3");
reachNodes = data.nodes || [];
const optionsEl = document.getElementById("reach-node-options");
optionsEl.innerHTML = reachNodes
.filter(node => node.node_id)
.map(node => `<option value="${escapeHtml(nodeSearchLabel(node))}"></option>`)
.join("");
return reachNodes;
}
async function loadReachReport(nodeId = reachNodeId) {
reachNodeId = Number(nodeId);
const packetLimit = Number(document.getElementById("reach-packet-limit").value) || defaultReachPacketLimit;
const packetType = document.getElementById("reliability-packet-type").value;
const packetCountEl = document.getElementById("reach-packet-count");
const gatewayCountEl = document.getElementById("reach-gateway-count");
const nodeLinkEl = document.getElementById("reach-node-link");
const bodyEls = [
document.getElementById("reach-packet-body-left"),
document.getElementById("reach-packet-body-right"),
];
const bucketBodyEl = document.getElementById("reach-bucket-body");
const setGatewayTables = html => {
bodyEls.forEach(el => {
el.innerHTML = html;
});
};
packetCountEl.textContent = "...";
gatewayCountEl.textContent = "...";
reliabilityGatewayDetails = new Map();
nodeLinkEl.href = `/node/${encodeURIComponent(reachNodeId)}`;
bucketBodyEl.innerHTML = '<tr><td colspan="2" class="reach-muted">Loading statistics...</td></tr>';
setGatewayTables('<tr><td colspan="4" class="reach-muted">Loading packets...</td></tr>');
resetReliabilityMap();
try {
const packetUrl = new URL("/api/packets", window.location.origin);
packetUrl.searchParams.set("from_node_id", reachNodeId);
packetUrl.searchParams.set("limit", packetLimit);
if (packetType) packetUrl.searchParams.set("portnum", packetType);
const [packetData] = await Promise.all([
fetchJson(packetUrl),
]);
const packets = packetData.packets || [];
const nodesById = new Map(reachNodes.map(node => [Number(node.node_id), node]));
packetCountEl.textContent = packets.length;
if (packets.length === 0) {
gatewayCountEl.textContent = "0";
bucketBodyEl.innerHTML = '<tr><td colspan="2" class="reach-muted">No packets found.</td></tr>';
setGatewayTables('<tr><td colspan="4" class="reach-muted">No packets found.</td></tr>');
resetReliabilityMap();
return;
}
const seenResults = await Promise.all(
packets.map(packet =>
fetchJson(`/api/packets_seen/${packet.id}`)
.then(data => ({ packet, seen: data.seen || [] }))
.catch(err => {
console.error("Failed to load packet seen rows", packet.id, err);
return { packet, seen: [], error: true };
})
)
);
const gatewayStats = new Map();
const reportResults = seenResults.filter(result => !isSkippedReliabilityPacket(result.packet));
reportResults.forEach(result => {
const seenByGateway = new Map();
result.seen.forEach(row => {
const nodeId = Number(row.node_id);
if (nodeId === reachNodeId || seenByGateway.has(nodeId)) return;
seenByGateway.set(nodeId, row);
});
seenByGateway.forEach((seenRow, nodeId) => {
const stats = gatewayStats.get(nodeId) || { heardCount: 0, hopTotal: 0 };
stats.heardCount += 1;
stats.hopTotal += packetSeenHopCount(seenRow);
gatewayStats.set(nodeId, stats);
});
});
const gatewayRows = [...gatewayStats.entries()]
.map(([nodeId, stats]) => ({
nodeId,
heardCount: stats.heardCount,
avgHopCount: stats.heardCount ? stats.hopTotal / stats.heardCount : null,
total: reportResults.length,
percent: reportResults.length ? (stats.heardCount / reportResults.length) * 100 : 0,
}))
.sort((a, b) => b.percent - a.percent || b.heardCount - a.heardCount || a.nodeId - b.nodeId);
gatewayCountEl.textContent = gatewayRows.length;
const bucketRows = reliabilityBuckets.map(bucket => ({
label: bucket.label,
color: bucket.color,
count: gatewayRows.filter(bucket.matches).length,
}));
const maxBucketCount = Math.max(...bucketRows.map(row => row.count), 1);
bucketBodyEl.innerHTML = bucketRows.map(row => {
const width = row.count > 0 ? Math.max((row.count / maxBucketCount) * 100, 8) : 0;
return `
<tr>
<td>${row.label}</td>
<td class="reach-count-bar-cell">
<div class="reach-count-bar-track">
<div class="reach-count-bar-fill" style="width:${width}%; --reach-bar-color:${row.color};"></div>
<div class="reach-count-bar-value">${row.count}</div>
</div>
</td>
</tr>
`;
}).join("");
const renderGatewayRows = rows => rows.length
? rows.map(row => `
<tr>
<td>${nodeLink(row.nodeId, nodesById)}</td>
<td>
<button class="reach-heard-link" type="button" onclick="openGatewayPacketModal(${row.nodeId})">
${row.heardCount}
</button>
<span class="text-secondary">(${reportResults.length})</span>
</td>
<td>${formatAverageHopCountWithActual(row.avgHopCount)}</td>
<td>${row.percent.toFixed(1)}%</td>
</tr>
`).join("")
: '<tr><td colspan="4" class="reach-muted">No gateways heard these packets.</td></tr>';
reliabilityGatewayDetails = new Map(gatewayRows.map(row => [
Number(row.nodeId),
{
label: gatewayLabel(row.nodeId, nodesById),
heardCount: row.heardCount,
total: reportResults.length,
packets: seenResults.map(result => {
const seenRow = result.seen.find(seen => Number(seen.node_id) === Number(row.nodeId));
return {
id: result.packet.id,
import_time_us: result.packet.import_time_us,
portnum: result.packet.portnum,
skipped: isSkippedReliabilityPacket(result.packet),
heard: Boolean(seenRow),
hopCount: seenRow ? packetSeenHopCount(seenRow) : null,
};
}),
}
]));
const splitIndex = Math.ceil(gatewayRows.length / 2);
bodyEls[0].innerHTML = renderGatewayRows(gatewayRows.slice(0, splitIndex));
bodyEls[1].innerHTML = gatewayRows.length > 1
? renderGatewayRows(gatewayRows.slice(splitIndex))
: '<tr><td colspan="4" class="reach-muted">No additional gateways.</td></tr>';
renderReliabilityMap(gatewayRows, nodesById);
} catch (err) {
console.error("Failed to load reach report:", err);
packetCountEl.textContent = "!";
gatewayCountEl.textContent = "!";
bucketBodyEl.innerHTML = '<tr><td colspan="2" class="text-danger">Failed to load statistics.</td></tr>';
setGatewayTables('<tr><td colspan="4" class="text-danger">Failed to load report.</td></tr>');
resetReliabilityMap();
}
}
document.addEventListener("DOMContentLoaded", async () => {
document.getElementById("gateway-packet-modal").addEventListener("click", event => {
if (event.target.id === "gateway-packet-modal") closeGatewayPacketModal();
});
document.getElementById("reach-search-form").addEventListener("submit", event => {
event.preventDefault();
const nodeId = parseNodeSearchValue(document.getElementById("reach-node-search").value);
if (!nodeId) {
document.getElementById("reach-bucket-body").innerHTML =
'<tr><td colspan="2" class="text-warning">Enter a valid node ID or select a node.</td></tr>';
document.getElementById("reach-packet-body-left").innerHTML =
'<tr><td colspan="4" class="text-warning">Enter a valid node ID or select a node.</td></tr>';
document.getElementById("reach-packet-body-right").innerHTML =
'<tr><td colspan="4" class="text-warning">Enter a valid node ID or select a node.</td></tr>';
return;
}
loadReachReport(nodeId);
});
try {
await loadReachNodes();
} catch (err) {
console.error("Failed to load node list:", err);
}
initReliabilityMap();
const searchEl = document.getElementById("reach-node-search");
searchEl.value = nodeSearchLabel(
reachNodes.find(node => Number(node.node_id) === initialReachNodeId) ||
{ node_id: initialReachNodeId, long_name: "Node" }
);
loadReachReport(initialReachNodeId);
});
</script>
{% endblock %}
+6 -1
View File
@@ -151,6 +151,11 @@ async function loadChannels() {
const sel = document.getElementById("channelFilter");
sel.innerHTML = "";
const allOpt = document.createElement("option");
allOpt.value = "";
allOpt.textContent = topTranslations.all_channels || "All channels";
sel.appendChild(allOpt);
for (const ch of data.channels || []) {
const opt = document.createElement("option");
opt.value = ch;
@@ -158,7 +163,7 @@ async function loadChannels() {
sel.appendChild(opt);
}
sel.value = "MediumFast";
sel.value = "";
}
/* ======================================================
+133 -11
View File
@@ -7,12 +7,53 @@
{% block css %}
#traceroute-graph {
width: 100%;
height: 85vh;
height: calc(100vh - 270px);
border: 1px solid #2a2f36;
background: linear-gradient(135deg, #0f1216 0%, #171b22 100%);
border-radius: 10px;
}
#traceroute-graph-wrap {
position: relative;
}
#traceroute-legend {
position: absolute;
right: 16px;
bottom: 16px;
z-index: 2;
display: grid;
gap: 8px;
padding: 10px 12px;
color: #d6dde6;
background: rgba(15, 18, 22, 0.88);
border: 1px solid #303743;
border-radius: 8px;
font-size: 13px;
}
.traceroute-legend-row {
display: grid;
grid-template-columns: 34px auto;
align-items: center;
gap: 8px;
white-space: nowrap;
}
.traceroute-legend-line {
height: 0;
border-top: 3px solid var(--line-color);
}
.traceroute-legend-line.muted {
border-top-width: 2px;
opacity: 0.55;
}
.traceroute-legend-line.dashed {
border-top-style: dashed;
}
#traceroute-meta {
padding: 12px 16px;
color: #c8d0da;
@@ -28,7 +69,23 @@
<div><b>Traceroute</b> <span id="traceroute-title"></span></div>
<div id="traceroute-error"></div>
</div>
<div id="traceroute-graph"></div>
<div id="traceroute-graph-wrap">
<div id="traceroute-graph"></div>
<div id="traceroute-legend" aria-label="Traceroute edge legend">
<div class="traceroute-legend-row">
<span class="traceroute-legend-line" style="--line-color: #34c759"></span>
<span>Winning forward</span>
</div>
<div class="traceroute-legend-row">
<span class="traceroute-legend-line dashed" style="--line-color: #ff3b30"></span>
<span>Reported reverse</span>
</div>
<div class="traceroute-legend-row">
<span class="traceroute-legend-line muted" style="--line-color: #7c858f"></span>
<span>Reported route</span>
</div>
</div>
</div>
<script>
const el = document.getElementById("traceroute-graph");
@@ -49,6 +106,33 @@ function addPathEdges(path, edges, style) {
}
}
function pathKey(path) {
return path.map(id => String(id)).join(">");
}
function addMissingEndpoints(path, startId, endId) {
const fullPath = path.map(id => String(id));
if (startId && (!fullPath.length || fullPath[0] !== startId)) {
fullPath.unshift(startId);
}
if (endId && (!fullPath.length || fullPath[fullPath.length - 1] !== endId)) {
fullPath.push(endId);
}
return fullPath;
}
function uniqueForwardPaths(data, originId, targetId) {
return (data?.unique_forward_paths || [])
.map(item => addMissingEndpoints(item.path || [], originId, targetId))
.filter(path => path.length > 1);
}
function uniqueReversePaths(data, originId, targetId) {
return (data?.unique_reverse_paths || [])
.map(path => addMissingEndpoints(path || [], targetId, null))
.filter(path => path.length > 1);
}
async function loadTraceroute() {
const packetId = packetIdFromPath();
document.getElementById("traceroute-title").textContent = `#${packetId}`;
@@ -73,26 +157,61 @@ async function loadTraceroute() {
const nodes = new Map();
const edges = [];
const forwardPaths = data?.winning_paths?.forward || [];
const reversePaths = data?.winning_paths?.reverse || [];
const originId = data?.packet?.from != null ? String(data.packet.from) : null;
const targetId = data?.packet?.to != null ? String(data.packet.to) : null;
const forwardPaths = (data?.winning_paths?.forward || []).map(path => path.map(id => String(id)));
const reversePaths = (data?.winning_paths?.reverse || []).map(path => path.map(id => String(id)));
const winningPathKeys = new Set([
...forwardPaths.map(pathKey),
...reversePaths.map(pathKey)
]);
const winningForwardNodeIds = new Set(forwardPaths.flat());
const hasWinningReversePath = reversePaths.some(path => path.length > 1);
const winningForwardPath = forwardPaths.find(path => path.length > 1);
const colorStartId = winningForwardPath ? winningForwardPath[0] : originId;
const colorEndId = winningForwardPath ? winningForwardPath[winningForwardPath.length - 1] : targetId;
const startNodeColor = hasWinningReversePath ? "#ff3b30" : "#34c759";
const endNodeColor = hasWinningReversePath ? "#34c759" : "#ff3b30";
uniqueForwardPaths(data, originId, targetId).forEach(path => {
if (winningPathKeys.has(pathKey(path))) {
return;
}
path.forEach(id => nodes.set(String(id), { name: String(id) }));
addPathEdges(path, edges, { color: "#7c858f", width: 1.5, opacity: 0.45 });
});
uniqueReversePaths(data, originId, targetId).forEach(path => {
if (winningPathKeys.has(pathKey(path))) {
return;
}
path.forEach(id => nodes.set(String(id), { name: String(id) }));
addPathEdges(path, edges, { color: "#7c858f", width: 1.5, opacity: 0.45, type: "dashed" });
});
forwardPaths.forEach(path => {
path.forEach(id => nodes.set(String(id), { name: String(id) }));
addPathEdges(path, edges, { color: "#ff5733", width: 3 });
addPathEdges(path, edges, { color: "#34c759", width: 3 });
});
reversePaths.forEach(path => {
path.forEach(id => nodes.set(String(id), { name: String(id) }));
addPathEdges(path, edges, { color: "#00c3ff", width: 2, type: "dashed" });
addPathEdges(path, edges, { color: "#ff3b30", width: 2, type: "dashed" });
});
const graphNodes = Array.from(nodes.values()).map(n => {
const isOrigin = originId && n.name === originId;
const isTarget = targetId && n.name === targetId;
const color = isOrigin ? "#ff3b30" : isTarget ? "#34c759" : "#8aa4c8";
const size = isOrigin || isTarget ? 44 : 36;
const isColorStart = colorStartId && n.name === colorStartId;
const isColorEnd = colorEndId && n.name === colorEndId;
const isWinningForwardNode = winningForwardNodeIds.has(n.name);
let color = "#3f454d";
if (isColorStart) {
color = startNodeColor;
} else if (isColorEnd) {
color = endNodeColor;
} else if (isWinningForwardNode) {
color = "#b88a2a";
}
const size = isColorStart || isColorEnd ? 44 : 36;
return {
id: n.name,
name: nodeShortNameById.get(n.name) || n.name,
@@ -104,7 +223,10 @@ async function loadTraceroute() {
fontWeight: "bold"
},
tooltip: {
formatter: () => nodeLongNameById.get(n.name) || n.name
formatter: () => {
const longName = nodeLongNameById.get(n.name) || n.name;
return longName === n.name ? n.name : `${longName} (${n.name})`;
}
}
};
});
+12
View File
@@ -53,6 +53,7 @@ class Packet:
"""UI-friendly packet wrapper for templates and API payloads."""
id: int
packet_id: int | None
from_node_id: int
from_node: models.Node
to_node_id: int
@@ -99,8 +100,13 @@ class Packet:
f'<a href="https://www.google.com/maps/search/?api=1&query={payload.latitude_i * 1e-7},{payload.longitude_i * 1e-7}" target="_blank">map</a>'
)
packet_id = None
if mesh_packet and mesh_packet.id:
packet_id = mesh_packet.id
return cls(
id=packet.id,
packet_id=packet_id,
from_node=packet.from_node,
from_node_id=packet.from_node_id,
to_node=packet.to_node,
@@ -259,6 +265,12 @@ async def map(request):
return web.Response(text=template.render(), content_type="text/html")
@routes.get("/reliability")
async def reliability(request):
template = env.get_template("reliability.html")
return web.Response(text=template.render(), content_type="text/html")
@routes.get("/nodelist")
async def nodelist(request):
template = env.get_template("nodelist.html")
+111 -47
View File
@@ -13,7 +13,7 @@ from meshtastic.protobuf.portnums_pb2 import PortNum
from meshview import database, decode_payload, store
from meshview.__version__ import __version__, _git_revision_short, get_version_info
from meshview.config import CONFIG
from meshview.models import DailySnapshot, Node, NodePublicKey
from meshview.models import DailySnapshot, Node
from meshview.models import Packet as PacketModel
from meshview.models import PacketSeen as PacketSeenModel
from meshview.radio.coverage import (
@@ -38,6 +38,96 @@ _LANG_CACHE = {}
routes = web.RouteTableDef()
def _config_bool(section: str, key: str, default: bool = False) -> bool:
return str(CONFIG.get(section, {}).get(key, default)).lower() in ("1", "true", "yes", "on")
def _config_int(section: str, key: str, default: int = 0) -> int:
try:
return int(CONFIG.get(section, {}).get(key, default))
except (TypeError, ValueError):
return default
def _config_str(section: str, key: str, default: str = "") -> str:
value = CONFIG.get(section, {}).get(key, default)
return str(value) if value is not None else default
def _cleanup_status_file() -> str:
cleanup_logfile = CONFIG.get("logging", {}).get("db_cleanup_logfile", "dbcleanup.log")
path_without_extension, _ = os.path.splitext(cleanup_logfile)
return f"{path_without_extension}.status.json"
def _backup_status_file() -> str:
cleanup_logfile = CONFIG.get("logging", {}).get("db_cleanup_logfile", "dbcleanup.log")
return os.path.join(os.path.dirname(cleanup_logfile), "dbbackup.status.json")
def _get_cleanup_health() -> dict:
cleanup_health = {
"enabled": _config_bool("cleanup", "enabled", False),
"days_to_keep": _config_int("cleanup", "days_to_keep", 14),
"scheduled_time": (
f"{_config_int('cleanup', 'hour', 2):02d}:{_config_int('cleanup', 'minute', 0):02d}"
),
"vacuum": _config_bool("cleanup", "vacuum", False),
"status": "disabled",
}
if cleanup_health["enabled"]:
cleanup_health["status"] = "unknown"
status_file = _cleanup_status_file()
cleanup_health["status_file"] = status_file
if not os.path.exists(status_file):
return cleanup_health
try:
with open(status_file, encoding="utf-8") as f:
last_run = json.load(f)
except Exception as e:
cleanup_health["status"] = "error"
cleanup_health["error"] = f"Unable to read cleanup status: {e}"
return cleanup_health
cleanup_health["status"] = last_run.get("status", cleanup_health["status"])
cleanup_health["last_run"] = last_run
return cleanup_health
def _get_backup_health() -> dict:
backup_hour = _config_int("cleanup", "backup_hour", _config_int("cleanup", "hour", 2))
backup_minute = _config_int("cleanup", "backup_minute", _config_int("cleanup", "minute", 0))
backup_health = {
"enabled": _config_bool("cleanup", "backup_enabled", False),
"backup_dir": _config_str("cleanup", "backup_dir", "./backups"),
"scheduled_time": f"{backup_hour:02d}:{backup_minute:02d}",
"status": "disabled",
}
if backup_health["enabled"]:
backup_health["status"] = "unknown"
status_file = _backup_status_file()
backup_health["status_file"] = status_file
if not os.path.exists(status_file):
return backup_health
try:
with open(status_file, encoding="utf-8") as f:
last_run = json.load(f)
except Exception as e:
backup_health["status"] = "error"
backup_health["error"] = f"Unable to read backup status: {e}"
return backup_health
backup_health["status"] = last_run.get("status", backup_health["status"])
backup_health["last_run"] = last_run
return backup_health
def _haversine_km(lat1, lon1, lat2, lon2):
r = 6371.0
phi1 = math.radians(lat1)
@@ -160,6 +250,8 @@ async def api_packets(request):
p = Packet.from_model(packet)
data = {
"id": p.id,
"storage_id": p.id,
"packet_id": p.packet_id,
"from_node_id": p.from_node_id,
"to_node_id": p.to_node_id,
"portnum": int(p.portnum) if p.portnum is not None else None,
@@ -249,6 +341,8 @@ async def api_packets(request):
for p in ui_packets:
packet_dict = {
"id": p.id,
"storage_id": p.id,
"packet_id": p.packet_id,
"import_time_us": p.import_time_us,
"channel": p.channel,
"from_node_id": p.from_node_id,
@@ -720,6 +814,8 @@ async def health_check(request):
"timestamp": datetime.datetime.now(datetime.UTC).isoformat(),
"version": __version__,
"git_revision": _git_revision_short,
"cleanup": _get_cleanup_health(),
"backup": _get_backup_health(),
}
# Check database connectivity
@@ -872,11 +968,10 @@ async def api_traceroute(request):
if tr["reverse_hops"]:
reverse_paths.append(r)
if tr["done"]:
if tr["reverse_hops"]:
if tr["forward_hops"]:
winning_forward_paths.append(f)
if tr["reverse_hops"]:
winning_reverse_paths.append(r)
winning_reverse_paths.append(r)
# Deduplicate
unique_forward_paths = sorted(set(forward_paths))
@@ -897,10 +992,10 @@ async def api_traceroute(request):
winning_forward_with_endpoints = []
for path in set(winning_forward_paths):
full_path = list(path)
if from_node_id is not None and (not full_path or full_path[0] != from_node_id):
full_path = [from_node_id, *full_path]
if to_node_id is not None and (not full_path or full_path[-1] != to_node_id):
full_path = [*full_path, to_node_id]
full_path = [to_node_id, *full_path]
if from_node_id is not None and (not full_path or full_path[-1] != from_node_id):
full_path = [*full_path, from_node_id]
winning_forward_with_endpoints.append(full_path)
winning_reverse_with_endpoints = []
@@ -908,8 +1003,6 @@ async def api_traceroute(request):
full_path = list(path)
if to_node_id is not None and (not full_path or full_path[0] != to_node_id):
full_path = [to_node_id, *full_path]
if from_node_id is not None and (not full_path or full_path[-1] != from_node_id):
full_path = [*full_path, from_node_id]
winning_reverse_with_endpoints.append(full_path)
winning_paths_json = {
@@ -1041,6 +1134,7 @@ async def api_node_qr(request):
try:
from meshtastic.protobuf.admin_pb2 import SharedContact
from meshtastic.protobuf.config_pb2 import Config
from meshtastic.protobuf.mesh_pb2 import User
user = User()
@@ -1058,6 +1152,13 @@ async def api_node_qr(request):
user.hw_model = hw_model_value
except (AttributeError, TypeError):
pass
if node.role:
try:
role_value = getattr(Config.DeviceConfig.Role, node.role.upper(), None)
if role_value is not None:
user.role = role_value
except (AttributeError, TypeError):
pass
contact = SharedContact()
contact.node_num = node_id
@@ -1077,6 +1178,7 @@ async def api_node_qr(request):
"node_id": node_id,
"long_name": node.long_name,
"short_name": node.short_name,
"role": node.role,
"meshtastic_url": meshtastic_url,
}
)
@@ -1088,44 +1190,6 @@ async def api_node_qr(request):
return web.json_response({"error": f"Failed to generate URL: {str(e)}"}, status=500)
@routes.get("/api/node/{node_id}/impersonation-check")
async def api_node_impersonation_check(request):
"""
Check if a node has multiple different public keys, which could indicate impersonation.
"""
try:
node_id_str = request.match_info["node_id"]
node_id = int(node_id_str, 0)
except (KeyError, ValueError):
return web.json_response({"error": "Invalid node_id"}, status=400)
try:
async with database.async_session() as session:
result = await session.execute(
select(NodePublicKey.public_key).where(NodePublicKey.node_id == node_id).distinct()
)
public_keys = result.scalars().all()
unique_key_count = len(public_keys)
return web.json_response(
{
"node_id": node_id,
"unique_public_key_count": unique_key_count,
"potential_impersonation": unique_key_count > 1,
"public_keys": public_keys
if unique_key_count <= 3
else public_keys[:3] + ["..."],
"warning": "Multiple different public keys detected. This node may be getting impersonated."
if unique_key_count > 1
else None,
}
)
except Exception as e:
logger.error(f"Error checking impersonation for node {node_id}: {e}")
return web.json_response({"error": "Failed to check impersonation"}, status=500)
@routes.get("/api/coverage/{node_id}")
async def api_coverage(request):
try:
+39
View File
@@ -0,0 +1,39 @@
# -*- coding: utf-8 -*-
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: nanopb.proto
"""Generated protocol buffer code."""
from google.protobuf.internal import builder as _builder
from google.protobuf import descriptor as _descriptor
from google.protobuf import descriptor_pool as _descriptor_pool
from google.protobuf import symbol_database as _symbol_database
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0cnanopb.proto\x1a google/protobuf/descriptor.proto\"\xa4\x07\n\rNanoPBOptions\x12\x10\n\x08max_size\x18\x01 \x01(\x05\x12\x12\n\nmax_length\x18\x0e \x01(\x05\x12\x11\n\tmax_count\x18\x02 \x01(\x05\x12&\n\x08int_size\x18\x07 \x01(\x0e\x32\x08.IntSize:\nIS_DEFAULT\x12$\n\x04type\x18\x03 \x01(\x0e\x32\n.FieldType:\nFT_DEFAULT\x12\x18\n\nlong_names\x18\x04 \x01(\x08:\x04true\x12\x1c\n\rpacked_struct\x18\x05 \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0bpacked_enum\x18\n \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0cskip_message\x18\x06 \x01(\x08:\x05\x66\x61lse\x12\x18\n\tno_unions\x18\x08 \x01(\x08:\x05\x66\x61lse\x12\r\n\x05msgid\x18\t \x01(\r\x12\x1e\n\x0f\x61nonymous_oneof\x18\x0b \x01(\x08:\x05\x66\x61lse\x12\x15\n\x06proto3\x18\x0c \x01(\x08:\x05\x66\x61lse\x12#\n\x14proto3_singular_msgs\x18\x15 \x01(\x08:\x05\x66\x61lse\x12\x1d\n\x0e\x65num_to_string\x18\r \x01(\x08:\x05\x66\x61lse\x12\x1b\n\x0c\x66ixed_length\x18\x0f \x01(\x08:\x05\x66\x61lse\x12\x1a\n\x0b\x66ixed_count\x18\x10 \x01(\x08:\x05\x66\x61lse\x12\x1e\n\x0fsubmsg_callback\x18\x16 \x01(\x08:\x05\x66\x61lse\x12/\n\x0cmangle_names\x18\x11 \x01(\x0e\x32\x11.TypenameMangling:\x06M_NONE\x12(\n\x11\x63\x61llback_datatype\x18\x12 \x01(\t:\rpb_callback_t\x12\x34\n\x11\x63\x61llback_function\x18\x13 \x01(\t:\x19pb_default_field_callback\x12\x30\n\x0e\x64\x65scriptorsize\x18\x14 \x01(\x0e\x32\x0f.DescriptorSize:\x07\x44S_AUTO\x12\x1a\n\x0b\x64\x65\x66\x61ult_has\x18\x17 \x01(\x08:\x05\x66\x61lse\x12\x0f\n\x07include\x18\x18 \x03(\t\x12\x0f\n\x07\x65xclude\x18\x1a \x03(\t\x12\x0f\n\x07package\x18\x19 \x01(\t\x12\x41\n\rtype_override\x18\x1b \x01(\x0e\x32*.google.protobuf.FieldDescriptorProto.Type\x12\x19\n\x0bsort_by_tag\x18\x1c \x01(\x08:\x04true\x12.\n\rfallback_type\x18\x1d \x01(\x0e\x32\n.FieldType:\x0b\x46T_CALLBACK*i\n\tFieldType\x12\x0e\n\nFT_DEFAULT\x10\x00\x12\x0f\n\x0b\x46T_CALLBACK\x10\x01\x12\x0e\n\nFT_POINTER\x10\x04\x12\r\n\tFT_STATIC\x10\x02\x12\r\n\tFT_IGNORE\x10\x03\x12\r\n\tFT_INLINE\x10\x05*D\n\x07IntSize\x12\x0e\n\nIS_DEFAULT\x10\x00\x12\x08\n\x04IS_8\x10\x08\x12\t\n\x05IS_16\x10\x10\x12\t\n\x05IS_32\x10 \x12\t\n\x05IS_64\x10@*Z\n\x10TypenameMangling\x12\n\n\x06M_NONE\x10\x00\x12\x13\n\x0fM_STRIP_PACKAGE\x10\x01\x12\r\n\tM_FLATTEN\x10\x02\x12\x16\n\x12M_PACKAGE_INITIALS\x10\x03*E\n\x0e\x44\x65scriptorSize\x12\x0b\n\x07\x44S_AUTO\x10\x00\x12\x08\n\x04\x44S_1\x10\x01\x12\x08\n\x04\x44S_2\x10\x02\x12\x08\n\x04\x44S_4\x10\x04\x12\x08\n\x04\x44S_8\x10\x08:E\n\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:G\n\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:E\n\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptions:>\n\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\x07 \x01(\x0b\x32\x0e.NanoPBOptionsB>\n\x18\x66i.kapsi.koti.jpa.nanopbZ\"github.com/meshtastic/go/generated')
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'nanopb_pb2', globals())
if _descriptor._USE_C_DESCRIPTORS == False:
google_dot_protobuf_dot_descriptor__pb2.FileOptions.RegisterExtension(nanopb_fileopt)
google_dot_protobuf_dot_descriptor__pb2.MessageOptions.RegisterExtension(nanopb_msgopt)
google_dot_protobuf_dot_descriptor__pb2.EnumOptions.RegisterExtension(nanopb_enumopt)
google_dot_protobuf_dot_descriptor__pb2.FieldOptions.RegisterExtension(nanopb)
DESCRIPTOR._options = None
DESCRIPTOR._serialized_options = b'\n\030fi.kapsi.koti.jpa.nanopbZ\"github.com/meshtastic/go/generated'
_FIELDTYPE._serialized_start=985
_FIELDTYPE._serialized_end=1090
_INTSIZE._serialized_start=1092
_INTSIZE._serialized_end=1160
_TYPENAMEMANGLING._serialized_start=1162
_TYPENAMEMANGLING._serialized_end=1252
_DESCRIPTORSIZE._serialized_start=1254
_DESCRIPTORSIZE._serialized_end=1323
_NANOPBOPTIONS._serialized_start=51
_NANOPBOPTIONS._serialized_end=983
# @@protoc_insertion_point(module_scope)
+43 -4
View File
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
import argparse
import re
import shutil
import subprocess
import sys
@@ -11,6 +12,39 @@ def run(cmd, cwd=None):
subprocess.run(cmd, cwd=cwd, check=True)
def clone_ref(repo, ref, tmp_path):
if re.fullmatch(r"[0-9a-fA-F]{40}", ref):
run(["git", "clone", "--no-checkout", "--depth", "1", repo, str(tmp_path)])
run(["git", "fetch", "--depth", "1", "origin", ref], cwd=tmp_path)
run(["git", "checkout", "--detach", "FETCH_HEAD"], cwd=tmp_path)
return
run(["git", "clone", "--depth", "1", "--branch", ref, repo, str(tmp_path)])
def stage_meshtastic_package(proto_root, tmp_path):
"""Map upstream meshtastic/*.proto files to Meshview's vendored package path."""
if proto_root != tmp_path / "meshtastic":
return tmp_path, proto_root
stage_root = tmp_path / "_meshview_proto_stage"
staged_proto_root = stage_root / "meshtastic" / "protobuf"
staged_proto_root.mkdir(parents=True, exist_ok=True)
for proto in sorted(proto_root.glob("*.proto")):
text = proto.read_text(encoding="utf-8")
text = text.replace('import "meshtastic/', 'import "meshtastic/protobuf/')
text = text.replace('import "nanopb.proto"', 'import "meshtastic/protobuf/nanopb.proto"')
text = text.replace("package meshtastic;", "package meshtastic.protobuf;")
(staged_proto_root / proto.name).write_text(text, encoding="utf-8")
nanopb = tmp_path / "nanopb.proto"
if nanopb.exists():
shutil.copy2(nanopb, staged_proto_root / "nanopb.proto")
return stage_root, staged_proto_root
def main():
parser = argparse.ArgumentParser(description="Update Meshtastic protobufs")
parser.add_argument(
@@ -36,7 +70,7 @@ def main():
with tempfile.TemporaryDirectory(prefix="meshtastic-protobufs-") as tmp:
tmp_path = Path(tmp)
print(f"Cloning {args.repo} ({args.ref}) into {tmp_path}...")
run(["git", "clone", "--depth", "1", "--branch", args.ref, args.repo, str(tmp_path)])
clone_ref(args.repo, args.ref, tmp_path)
upstream_rev = (
subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=tmp_path).decode().strip()
)
@@ -57,6 +91,7 @@ def main():
# Common locations in the meshtastic/protobufs repo
candidates = [
tmp_path / "meshtastic" / "protobuf",
tmp_path / "meshtastic",
tmp_path / "protobufs",
tmp_path / "protobuf",
tmp_path / "proto",
@@ -81,14 +116,17 @@ def main():
print(f"No .proto files found in {proto_root}", file=sys.stderr)
return 1
rel_protos = [str(p.relative_to(tmp_path)) for p in protos]
proto_base, proto_root = stage_meshtastic_package(proto_root, tmp_path)
protos = sorted(proto_root.glob("*.proto"))
rel_protos = [str(p.relative_to(proto_base)) for p in protos]
protoc = shutil.which("protoc")
if protoc:
cmd = [
protoc,
f"-I{tmp_path}",
f"-I{proto_base}",
f"--python_out={out_root}",
f"--pyi_out={out_root}",
*rel_protos,
]
print("Running protoc...")
@@ -107,8 +145,9 @@ def main():
sys.executable,
"-m",
"grpc_tools.protoc",
f"-I{tmp_path}",
f"-I{proto_base}",
f"--python_out={out_root}",
f"--pyi_out={out_root}",
*rel_protos,
]
print("Running grpc_tools.protoc...")
+92 -2
View File
@@ -33,6 +33,8 @@ file_handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(message)s')
file_handler.setFormatter(formatter)
cleanup_logger.addHandler(file_handler)
cleanup_status_file = str(Path(cleanup_logfile).with_suffix(".status.json"))
backup_status_file = str(Path(cleanup_logfile).with_name("dbbackup.status.json"))
# -------------------------
@@ -49,6 +51,32 @@ def get_int(config, section, key, default=0):
return default
def _rowcount(value):
return value if value is not None and value >= 0 else None
def write_cleanup_status(status: dict) -> None:
status_path = Path(cleanup_status_file)
tmp_path = status_path.with_suffix(f"{status_path.suffix}.tmp")
try:
with open(tmp_path, "w", encoding="utf-8") as f:
json.dump(status, f, indent=2)
tmp_path.replace(status_path)
except Exception as e:
cleanup_logger.warning(f"Failed to write cleanup status file: {e}")
def write_backup_status(status: dict) -> None:
status_path = Path(backup_status_file)
tmp_path = status_path.with_suffix(f"{status_path.suffix}.tmp")
try:
with open(tmp_path, "w", encoding="utf-8") as f:
json.dump(status, f, indent=2)
tmp_path.replace(status_path)
except Exception as e:
cleanup_logger.warning(f"Failed to write backup status file: {e}")
# -------------------------
# Shared DB lock
# -------------------------
@@ -66,19 +94,40 @@ async def backup_database(database_url: str, backup_dir: str = ".") -> None:
database_url: SQLAlchemy connection string
backup_dir: Directory to store backups (default: current directory)
"""
backup_status = {
"status": "running",
"started_at": datetime.datetime.now(datetime.UTC).isoformat(),
"completed_at": None,
"backup_dir": backup_dir,
"database_path": None,
"backup_file": None,
"original_size_bytes": None,
"compressed_size_bytes": None,
"compression_percent": None,
"error": None,
}
write_backup_status(backup_status)
try:
url = make_url(database_url)
if not url.drivername.startswith("sqlite"):
cleanup_logger.warning("Backup only supported for SQLite databases")
backup_status["status"] = "unsupported"
backup_status["error"] = "Backup only supported for SQLite databases"
return
if not url.database or url.database == ":memory:":
cleanup_logger.error("Could not extract database path from connection string")
backup_status["status"] = "error"
backup_status["error"] = "Could not extract database path from connection string"
return
db_file = Path(url.database)
backup_status["database_path"] = str(db_file)
if not db_file.exists():
cleanup_logger.error(f"Database file not found: {db_file}")
backup_status["status"] = "error"
backup_status["error"] = f"Database file not found: {db_file}"
return
# Create backup directory if it doesn't exist
@@ -89,6 +138,7 @@ async def backup_database(database_url: str, backup_dir: str = ".") -> None:
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
backup_filename = f"{db_file.stem}_backup_{timestamp}.db.gz"
backup_file = backup_path / backup_filename
backup_status["backup_file"] = str(backup_file)
cleanup_logger.info(f"Creating backup: {backup_file}")
@@ -98,9 +148,15 @@ async def backup_database(database_url: str, backup_dir: str = ".") -> None:
shutil.copyfileobj(f_in, f_out)
# Get file sizes for logging
original_size = db_file.stat().st_size / (1024 * 1024) # MB
compressed_size = backup_file.stat().st_size / (1024 * 1024) # MB
original_size_bytes = db_file.stat().st_size
compressed_size_bytes = backup_file.stat().st_size
original_size = original_size_bytes / (1024 * 1024) # MB
compressed_size = compressed_size_bytes / (1024 * 1024) # MB
compression_ratio = (1 - compressed_size / original_size) * 100 if original_size > 0 else 0
backup_status["original_size_bytes"] = original_size_bytes
backup_status["compressed_size_bytes"] = compressed_size_bytes
backup_status["compression_percent"] = round(compression_ratio, 1)
backup_status["status"] = "ok"
cleanup_logger.info(
f"Backup created successfully: {backup_file.name} "
@@ -110,6 +166,11 @@ async def backup_database(database_url: str, backup_dir: str = ".") -> None:
except Exception as e:
cleanup_logger.error(f"Error creating database backup: {e}")
backup_status["status"] = "error"
backup_status["error"] = str(e)
finally:
backup_status["completed_at"] = datetime.datetime.now(datetime.UTC).isoformat()
write_backup_status(backup_status)
# -------------------------
@@ -179,6 +240,24 @@ async def daily_cleanup_at(
).replace(tzinfo=None)
cutoff_us = int(cutoff_dt.timestamp() * 1_000_000)
cleanup_logger.info(f"Running cleanup for records older than {cutoff_dt.isoformat()}...")
rows_deleted = {
"packet": None,
"packet_seen": None,
"traceroute": None,
"node": None,
}
cleanup_status = {
"status": "running",
"started_at": datetime.datetime.now(datetime.UTC).isoformat(),
"completed_at": None,
"cutoff_at": cutoff_dt.replace(tzinfo=datetime.UTC).isoformat(),
"days_to_keep": days_to_keep,
"vacuum_requested": vacuum_db,
"vacuum_completed": False,
"rows_deleted": rows_deleted,
"error": None,
}
write_cleanup_status(cleanup_status)
try:
async with db_lock: # Pause ingestion
@@ -191,6 +270,7 @@ async def daily_cleanup_at(
result = await session.execute(
delete(models.Packet).where(models.Packet.import_time_us < cutoff_us)
)
rows_deleted["packet"] = _rowcount(result.rowcount)
cleanup_logger.info(f"Deleted {result.rowcount} rows from Packet")
# -------------------------
@@ -201,6 +281,7 @@ async def daily_cleanup_at(
models.PacketSeen.import_time_us < cutoff_us
)
)
rows_deleted["packet_seen"] = _rowcount(result.rowcount)
cleanup_logger.info(f"Deleted {result.rowcount} rows from PacketSeen")
# -------------------------
@@ -211,6 +292,7 @@ async def daily_cleanup_at(
models.Traceroute.import_time_us < cutoff_us
)
)
rows_deleted["traceroute"] = _rowcount(result.rowcount)
cleanup_logger.info(f"Deleted {result.rowcount} rows from Traceroute")
# -------------------------
@@ -219,6 +301,7 @@ async def daily_cleanup_at(
result = await session.execute(
delete(models.Node).where(models.Node.last_seen_us < cutoff_us)
)
rows_deleted["node"] = _rowcount(result.rowcount)
cleanup_logger.info(f"Deleted {result.rowcount} rows from Node")
await session.commit()
@@ -228,14 +311,21 @@ async def daily_cleanup_at(
async with mqtt_database.engine.begin() as conn:
await conn.exec_driver_sql("VACUUM;")
cleanup_logger.info("VACUUM completed.")
cleanup_status["vacuum_completed"] = True
elif vacuum_db:
cleanup_logger.info("VACUUM skipped (not supported for this database).")
cleanup_logger.info("Cleanup completed successfully.")
cleanup_logger.info("Ingestion resumed after cleanup.")
cleanup_status["status"] = "ok"
except Exception as e:
cleanup_logger.error(f"Error during cleanup: {e}")
cleanup_status["status"] = "error"
cleanup_status["error"] = str(e)
finally:
cleanup_status["completed_at"] = datetime.datetime.now(datetime.UTC).isoformat()
write_cleanup_status(cleanup_status)
# -------------------------