syntax = "proto3"; /* * Meshtastic protobufs * * For more information on protobufs (and tools to use them with the language of your choice) see * https://developers.google.com/protocol-buffers/docs/proto3 * * We are not placing any of these defs inside a package, because if you do the * resulting nanopb version is super verbose package mesh. * * Protobuf build instructions: * * To build java classes for reading writing: * protoc -I=. --java_out /tmp mesh.proto * * To generate Nanopb c code: * /home/kevinh/packages/nanopb-0.4.0-linux-x86/generator-bin/protoc --nanopb_out=/tmp -I=app/src/main/proto mesh.proto * * Nanopb binaries available here: https://jpa.kapsi.fi/nanopb/download/ use nanopb 0.4.0 */ option java_package = "com.geeksville.mesh"; option optimize_for = LITE_RUNTIME; option go_package = "github.com/meshtastic/gomeshproto"; import "portnums.proto"; import "telemetry.proto"; option java_outer_classname = "MeshProtos"; /* * a gps position */ message Position { /* * The new preferred location encoding, divide by 1e-7 to get degrees * in floating point */ sfixed32 latitude_i = 1; /* * TODO: REPLACE */ sfixed32 longitude_i = 2; /* * TODO: REMOTE/INTEGRATE * This is a special 'small' position update for lat/lon. * It encodes a signed 16 bit latitude in the upper 2 bytes, and a signed longitude in the lower 16 bits. * It is not currently implemented, but can be added in an automatically backwards compatible way later. * Note: ONLY microlatlon OR latitude_i, longitude_i are populated in any particular position. * A microdelta is always relative to the last received full position. * * fixed32 microlatlon = 3; */ /* * In meters above MSL (but see issue #359) */ int32 altitude = 3; /* * 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 */ fixed32 time = 9; /* * Precision positioning elements - optional and usually not included * ------------------------------------------------------------------ * TODO: REMOVE/INTEGRATE */ /* * How the location was acquired: manual, onboard GPS, external (EUD) GPS */ enum LocSource { /* * TODO: REPLACE */ LOCSRC_UNSPECIFIED = 0; /* * TODO: REPLACE */ LOCSRC_MANUAL_ENTRY = 1; /* * TODO: REPLACE */ LOCSRC_GPS_INTERNAL = 2; /* * TODO: REPLACE */ LOCSRC_GPS_EXTERNAL = 3; /* * More location sources can be added here when available: * GSM, radio beacons (BLE etc), location fingerprinting etc * TODO: REMOVE/INTEGRATE */ } /* * TODO: REPLACE */ LocSource location_source = 10; /* * How the altitude was acquired: manual, GPS int/ext, etc * Default: same as location_source if present */ enum AltSource { /* * TODO: REPLACE */ ALTSRC_UNSPECIFIED = 0; /* * TODO: REPLACE */ ALTSRC_MANUAL_ENTRY = 1; /* * TODO: REPLACE */ ALTSRC_GPS_INTERNAL = 2; /* * TODO: REPLACE */ ALTSRC_GPS_EXTERNAL = 3; /* * TODO: REPLACE */ ALTSRC_BAROMETRIC = 4; } /* * TODO: REPLACE */ AltSource altitude_source = 11; /* * Positional timestamp (actual timestamp of GPS solution) in integer epoch seconds */ fixed32 pos_timestamp = 12; /* * Pos. timestamp milliseconds adjustment (rarely available or required) */ int32 pos_time_millis = 13; /* * HAE altitude in meters - can be used instead of MSL altitude */ sint32 altitude_hae = 14; /* * Geoidal separation in meters */ sint32 alt_geoid_sep = 15; /* * Horizontal, Vertical and Position Dilution of Precision, in 1/100 units * - PDOP is sufficient for most cases * - for higher precision scenarios, HDOP and VDOP can be used instead, * in which case PDOP becomes redundant (PDOP=sqrt(HDOP^2 + VDOP^2)) * TODO: REMOVE/INTEGRATE */ uint32 PDOP = 16; /* * TODO: REPLACE */ uint32 HDOP = 17; /* * TODO: REPLACE */ uint32 VDOP = 18; /* * GPS accuracy (a hardware specific constant) in mm * multiplied with DOP to calculate positional accuracy * Default: "'bout three meters-ish" :) */ uint32 gps_accuracy = 19; /* * Ground speed in m/s and True North TRACK in 1/100 degrees * * Clarification of terms: * - "track" is the direction of motion (measured in horizontal plane) * - "heading" is where the fuselage points (measured in horizontal plane) * - "yaw" indicates a relative rotation about the vertical axis * TODO: REMOVE/INTEGRATE */ uint32 ground_speed = 20; /* * TODO: REPLACE */ uint32 ground_track = 21; /* * GPS fix quality (from NMEA GxGGA statement or similar) */ uint32 fix_quality = 22; /* * GPS fix type 2D/3D (from NMEA GxGSA statement) */ uint32 fix_type = 23; /* * GPS "Satellites in View" number */ uint32 sats_in_view = 24; /* * Sensor ID - in case multiple positioning sensors are being used */ uint32 sensor_id = 25; /* * Estimated/expected time (in seconds) until next update: * - if we update at fixed intervals of X seconds, use X * - if we update at dynamic intervals (based on relative movement etc), * but "AT LEAST every Y seconds", use Y */ uint32 pos_next_update = 40; /* * A sequence number, incremented with each Position message to help * detect lost updates if needed */ uint32 pos_seq_number = 41; /* * END precision positioning elements * TODO: REMOVE/INTEGRATE */ } /* * Note: these enum names must EXACTLY match the string used in the device * bin/build-all.sh script. * Because they will be used to find firmware filenames in the android app for OTA updates. * To match the old style filenames, _ is converted to -, p is converted to . */ enum HardwareModel { /* * TODO: REPLACE */ UNSET = 0; /* * TODO: REPLACE */ TLORA_V2 = 1; /* * TODO: REPLACE */ TLORA_V1 = 2; /* * TODO: REPLACE */ TLORA_V2_1_1p6 = 3; /* * TODO: REPLACE */ TBEAM = 4; /* * The original heltec WiFi_Lora_32_V2, which had battery voltage sensing hooked to GPIO 13 * (see HELTEC_V2 for the new version). */ HELTEC_V2_0 = 5; /* * TODO: REPLACE */ TBEAM0p7 = 6; /* * TODO: REPLACE */ T_ECHO = 7; /* * TODO: REPLACE */ TLORA_V1_1p3 = 8; /* * TODO: REPLACE */ RAK4631 = 9; /* * The new version of the heltec WiFi_Lora_32_V2 board that has battery sensing hooked to GPIO 37. * Sadly they did not update anything on the silkscreen to identify this board */ HELTEC_V2_1 = 10; /* * Ancient heltec WiFi_Lora_32 board */ HELTEC_V1 = 11; /* * Less common/prototype boards listed here (needs one more byte over the air) */ LORA_RELAY_V1 = 32; /* * TODO: REPLACE */ NRF52840DK = 33; /* * TODO: REPLACE */ PPR = 34; /* * TODO: REPLACE */ GENIEBLOCKS = 35; /* * TODO: REPLACE */ NRF52_UNKNOWN = 36; /* * TODO: REPLACE */ PORTDUINO = 37; /* * The simulator built into the android app */ ANDROID_SIM = 38; /* * Custom DIY device based on @NanoVHF schematics: https://github.com/NanoVHF/Meshtastic-DIY/tree/main/Schematics */ DIY_V1 = 39; /* * RAK WisBlock ESP32 core: https://docs.rakwireless.com/Product-Categories/WisBlock/RAK11200/Overview/ */ RAK11200 = 40; /* * Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits. */ PRIVATE_HW = 255; } /* * The team colors are based on the names of "friendly teams" in ATAK: * https://github.com/deptofdefense/AndroidTacticalAssaultKit-CIV/blob/master/atak/ATAK/app/src/main/assets/filters/team_filters.xml */ enum Team { /* * the default (unset) is "achromatic" (unaffiliated) */ CLEAR = 0; /* * TODO: REPLACE */ CYAN = 1; /* * TODO: REPLACE */ WHITE = 2; /* * TODO: REPLACE */ YELLOW = 3; /* * TODO: REPLACE */ ORANGE = 4; /* * TODO: REPLACE */ MAGENTA = 5; /* * TODO: REPLACE */ RED = 6; /* * TODO: REPLACE */ MAROON = 7; /* * TODO: REPLACE */ PURPLE = 8; /* * TODO: REPLACE */ DARK_BLUE = 9; /* * TODO: REPLACE */ BLUE = 10; /* * TODO: REPLACE */ TEAL = 11; /* * TODO: REPLACE */ GREEN = 12; /* * TODO: REPLACE */ DARK_GREEN = 13; /* * TODO: REPLACE */ BROWN = 14; } /* * Broadcast when a newly powered mesh node wants to find a node num it can use * Sent from the phone over bluetooth to set the user id for the owner of this node. * Also sent from nodes to each other when a new node signs on (so all clients can have this info) * * The algorithm is as follows: * when a node starts up, it broadcasts their user and the normal flow is for all * other nodes to reply with their User as well (so the new node can build its nodedb) * If a node ever receives a User (not just the first broadcast) message where * the sender node number equals our node number, that indicates a collision has * occurred and the following steps should happen: * * If the receiving node (that was already in the mesh)'s macaddr is LOWER than the * new User who just tried to sign in: it gets to keep its nodenum. * We send a broadcast message of OUR User (we use a broadcast so that the other node can * receive our message, considering we have the same id - it also serves to let * observers correct their nodedb) - this case is rare so it should be okay. * * If any node receives a User where the macaddr is GTE than their local macaddr, * they have been vetoed and should pick a new random nodenum (filtering against * whatever it knows about the nodedb) and rebroadcast their User. * * A few nodenums are reserved and will never be requested: * 0xff - broadcast * 0 through 3 - for future use */ message User { /* * A globally unique ID string for this user. * In the case of Signal that would mean +16504442323, for the default macaddr derived id it would be !<8 hexidecimal bytes>. * Note: app developers are encouraged to also use the following standard * node IDs "^all" (for broadcast), "^local" (for the locally connected node) */ string id = 1; /* * A full name for this user, i.e. "Kevin Hester" */ string long_name = 2; /* * A VERY short name, ideally two characters. * Suitable for a tiny OLED screen */ string short_name = 3; /* * This is the addr of the radio. * Not populated by the phone, but added by the esp32 when broadcasting */ bytes macaddr = 4; /* * 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. */ HardwareModel hw_model = 6; /* * 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. */ bool is_licensed = 7; /* * Participants in the same network can self-group into different teams. * Short-term this can be used to visually differentiate them on the map; * in the longer term it could also help users to semi-automatically * select or ignore messages according to team affiliation. * In total, 14 teams are defined (encoded in 4 bits) */ Team team = 8; /* * Transmit power at antenna connector, in decibel-milliwatt * An optional self-reported value useful in network planning, discovery * and positioning - along with ant_gain_dbi and ant_azimuth below */ uint32 tx_power_dbm = 10; /* * Antenna gain (applicable to both Tx and Rx), in decibel-isotropic */ uint32 ant_gain_dbi = 11; /* * Directional antenna true azimuth *if applicable*, in degrees (0-360) * Only applicable in case of stationary nodes with a directional antenna * Zero = not applicable (mobile or omni) or not specified * (use a value of 360 to indicate an antenna azimuth of zero degrees) */ uint32 ant_azimuth = 12; } /* * A message used in our Dynamic Source Routing protocol (RFC 4728 based) */ message RouteDiscovery { /* * The list of nodenums this packet has visited so far */ repeated fixed32 route = 2; } /* * A Routing control Data packet handled by the routing module */ message Routing { /* * A failure in delivering a message (usually used for routing control messages, but might be provided in addition to ack.fail_id to provide * details on the type of failure). */ enum Error { /* * This message is not a failure */ NONE = 0; /* * Our node doesn't have a route to the requested destination anymore. */ NO_ROUTE = 1; /* * We received a nak while trying to forward on your behalf */ GOT_NAK = 2; /* * TODO: REPLACE */ TIMEOUT = 3; /* * No suitable interface could be found for delivering this packet */ NO_INTERFACE = 4; /* * We reached the max retransmission count (typically for naive flood routing) */ MAX_RETRANSMIT = 5; /* * No suitable channel was found for sending this packet (i.e. was requested channel index disabled?) */ NO_CHANNEL = 6; /* * The packet was too big for sending (exceeds interface MTU after encoding) */ TOO_LARGE = 7; /* * The request had want_response set, the request reached the destination node, but no service on that node wants to send a response * (possibly due to bad channel permissions) */ NO_RESPONSE = 8; /* * The application layer service on the remote node received your request, but considered your request somehow invalid */ BAD_REQUEST = 32; /* * The application layer service on the remote node received your request, but considered your request not authorized * (i.e you did not send the request on the required bound channel) */ NOT_AUTHORIZED = 33; } oneof variant { /* * A route request going from the requester */ RouteDiscovery route_request = 1; /* * A route reply */ RouteDiscovery route_reply = 2; /* * A failure in delivering a message (usually used for routing control messages, but might be provided * in addition to ack.fail_id to provide details on the type of failure). */ Error error_reason = 3; } } /* * (Formerly called SubPacket) * The payload portion fo a packet, this is the actual bytes that are sent * inside a radio packet (because from/to are broken out by the comms library) */ message Data { /* * Formerly named typ and of type Type */ PortNum portnum = 1; /* * TODO: REPLACE */ bytes payload = 2; /* * Not normally used, but for testing a sender can request that recipient * responds in kind (i.e. if it received a position, it should unicast back it's position). * Note: that if you set this on a broadcast you will receive many replies. */ bool want_response = 3; /* * The address of the destination node. * This field is is filled in by the mesh radio device software, application * layer software should never need it. * RouteDiscovery messages _must_ populate this. * Other message types might need to if they are doing multihop routing. */ fixed32 dest = 4; /* * The address of the original sender for this message. * This field should _only_ be populated for reliable multihop packets (to keep * packets small). */ fixed32 source = 5; /* * Only used in routing or response messages. * Indicates the original message ID that this message is reporting failure on. (formerly called original_id) */ fixed32 request_id = 6; /* * If set, this message is intened to be a reply to a previously sent message with the defined id. */ fixed32 reply_id = 7; /* * Defaults to false. If true, then what is in the payload should be treated as an emoji like giving * a message a heart or poop emoji. */ bool is_tapback = 8; } /* * A packet envelope sent/received over the mesh * only payloadVariant is sent in the payload portion of the LORA packet. * The other fields are either not sent at all, or sent in the special 16 byte LORA header. */ message MeshPacket { /* * The priority of this message for sending. * Higher priorities are sent first (when managing the transmit queue). * This field is never sent over the air, it is only used internally inside of a local device node. * API clients (either on the local node or connected directly to the node) * can set this parameter if necessary. * * (values must be <= 127 to keep protobuf field to one byte in size. * * Detailed background on this field: * * I noticed a funny side effect of lora being so slow: Usually when making * a protocol there isn’t much need to use message priority to change the order * of transmission (because interfaces are fairly fast). * But for lora where packets can take a few seconds each, it is very important * to make sure that critical packets are sent ASAP. * In the case of meshtastic that means we want to send protocol acks as soon as possible * (to prevent unneeded retransmissions), we want routing messages to be sent next, * then messages marked as reliable and finally ‘background’ packets like periodic position updates. * * So I bit the bullet and implemented a new (internal - not sent over the air) * field in MeshPacket called ‘priority’. * And the transmission queue in the router object is now a priority queue. */ enum Priority { /* * Treated as Priority.DEFAULT */ UNSET = 0; /* * TODO: REPLACE */ MIN = 1; /* * Background position updates are sent with very low priority - * if the link is super congested they might not go out at all */ BACKGROUND = 10; /* * This priority is used for most messages that don't have a priority set */ DEFAULT = 64; /* * If priority is unset but the message is marked as want_ack, * assume it is important and use a slightly higher priority */ RELIABLE = 70; /* * Ack/naks are sent with very high priority to ensure that retransmission * stops as soon as possible */ ACK = 120; /* * TODO: REPLACE */ MAX = 127; } /* * Identify if this is a delayed packet */ enum Delayed { /* * If unset, the message is being sent in real time. */ NO_DELAY = 0; /* * The message is delayed and was originally a broadcast */ DELAYED_BROADCAST = 1; /* * The message is delayed and was originally a direct message */ DELAYED_DIRECT = 2; } /* * The sending node number. * Note: Our crypto implementation uses this field as well. * See [crypto](/docs/developers/firmware/encryption) for details. * FIXME - really should be fixed32 instead, this encoding only hurts the ble link though. */ fixed32 from = 1; /* * The (immediatSee Priority description for more details.y should be fixed32 instead, this encoding only * hurts the ble link though. */ fixed32 to = 2; /* * (Usually) If set, this indicates the index in the secondary_channels table that this packet was sent/received on. * If unset, packet was on the primary channel. * A particular node might know only a subset of channels in use on the mesh. * Therefore channel_index is inherently a local concept and meaningless to send between nodes. * Very briefly, while sending and receiving deep inside the device Router code, this field instead * contains the 'channel hash' instead of the index. * This 'trick' is only used while the payloadVariant is an 'encrypted'. */ uint32 channel = 3; /* * Internally to the mesh radios we will route SubPackets encrypted per [this](docs/developers/firmware/encryption). * However, when a particular node has the correct * key to decode a particular packet, it will decode the payload into a SubPacket protobuf structure. * Software outside of the device nodes will never encounter a packet where * "decoded" is not populated (i.e. any encryption/decryption happens before reaching the applications) * The numeric IDs for these fields were selected to keep backwards compatibility with old applications. */ oneof payloadVariant { /* * TODO: REPLACE */ Data decoded = 4; /* * TODO: REPLACE */ bytes encrypted = 5; } /* * A unique ID for this packet. * Always 0 for no-ack packets or non broadcast packets (and therefore take zero bytes of space). * Otherwise a unique ID for this packet, useful for flooding algorithms. * ID only needs to be unique on a _per sender_ basis, and it only * needs to be unique for a few minutes (long enough to last for the length of * any ACK or the completion of a mesh broadcast flood). * Note: Our crypto implementation uses this id as well. * See [crypto](/docs/developers/firmware/encryption) for details. * FIXME - really should be fixed32 instead, this encoding only * hurts the ble link though. */ fixed32 id = 6; /* * The time this message was received by the esp32 (secs since 1970). * Note: this field is _never_ sent on the radio link itself (to save space) Times * are typically not sent over the mesh, but they will be added to any Packet * (chain of SubPacket) sent to the phone (so the phone can know exact time of reception) */ fixed32 rx_time = 7; /* * *Never* sent over the radio links. * Set during reception to indicate the SNR of this packet. * Used to collect statistics on current link quality. */ float rx_snr = 8; /* * If unset treated as zero (no forwarding, send to adjacent nodes only) * if 1, allow hopping through one node, etc... * For our usecase real world topologies probably have a max of about 3. * This field is normally placed into a few of bits in the header. */ uint32 hop_limit = 10; /* * This packet is being sent as a reliable message, we would prefer it to arrive at the destination. * We would like to receive a ack packet in response. * Broadcasts messages treat this flag specially: Since acks for broadcasts would * rapidly flood the channel, the normal ack behavior is suppressed. * Instead, the original sender listens to see if at least one node is rebroadcasting this packet (because naive flooding algorithm). * If it hears that the odds (given typical LoRa topologies) the odds are very high that every node should eventually receive the message. * So FloodingRouter.cpp generates an implicit ack which is delivered to the original sender. * If after some time we don't hear anyone rebroadcast our packet, we will timeout and retransmit, using the regular resend logic. * Note: This flag is normally sent in a flag bit in the header when sent over the wire */ bool want_ack = 11; /* * The priority of this message for sending. * See MeshPacket.Priority description for more details. */ Priority priority = 12; /* * rssi of received packet. Only sent to phone for dispay purposes. */ int32 rx_rssi = 13; /* * Describe if this message is delayed */ Delayed delayed = 15; } /* * Shared constants between device and phone */ enum Constants { /* * First enum must be zero, and we are just using this enum to * pass int constants between two very different environments */ Unused = 0; /* * From mesh.options * note: this payload length is ONLY the bytes that are sent inside of the Data protobuf (excluding protobuf overhead). The 16 byte header is * outside of this envelope */ DATA_PAYLOAD_LEN = 237; } /* * The bluetooth to device link: * * Old BTLE protocol docs from TODO, merge in above and make real docs... * * use protocol buffers, and NanoPB * * messages from device to phone: * POSITION_UPDATE (..., time) * TEXT_RECEIVED(from, text, time) * OPAQUE_RECEIVED(from, payload, time) (for signal messages or other applications) * * messages from phone to device: * SET_MYID(id, human readable long, human readable short) (send down the unique ID * string used for this node, a human readable string shown for that id, and a very * short human readable string suitable for oled screen) SEND_OPAQUE(dest, payload) * (for signal messages or other applications) SEND_TEXT(dest, text) Get all * nodes() (returns list of nodes, with full info, last time seen, loc, battery * level etc) SET_CONFIG (switches device to a new set of radio params and * preshared key, drops all existing nodes, force our node to rejoin this new group) * * Full information about a node on the mesh */ message NodeInfo { /* * The node number */ uint32 num = 1; /* * The user info for this node */ User user = 2; /* * 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. */ Position position = 3; /* * 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 */ float snr = 4; /* * TODO: REMOVE/INTEGRATE * Returns the last measured frequency error. * The LoRa receiver estimates the frequency offset between the receiver * center frequency and that of the received LoRa signal. This function * returns the estimates offset (in Hz) of the last received message. * Caution: this measurement is not absolute, but is measured relative to the * local receiver's oscillator. Apparent errors may be due to the * transmitter, the receiver or both. \return The estimated center frequency * offset in Hz of the last received message. * int32 frequency_error = 6; * enum RouteState { * Invalid = 0; * Discovering = 1; * Valid = 2; * } * Not needed? * RouteState route = 4; */ /* * TODO: REMOVE/INTEGRATE * Not currently used (till full DSR deployment?) Our current preferred node node for routing - might be the same as num if * we are adjacent Or zero if we don't yet know a route to this node. * fixed32 next_hop = 5; */ /* * Set to indicate the last time we received a packet from this node */ fixed32 last_heard = 5; /* * The latest telemetry data for the node. */ Telemetry telemetry = 6; } /* * Error codes for critical errors * * The device might report these fault codes on the screen. * If you encounter a fault code, please post on the meshtastic.discourse.group * and we'll try to help. */ enum CriticalErrorCode { /* * TODO: REPLACE */ None = 0; /* * A software bug was detected while trying to send lora */ TxWatchdog = 1; /* * A software bug was detected on entry to sleep */ SleepEnterWait = 2; /* * No Lora radio hardware could be found */ NoRadio = 3; /* * Not normally used */ Unspecified = 4; /* * We failed while configuring a UBlox GPS */ UBloxInitFailed = 5; /* * This board was expected to have a power management chip and it is missing or broken */ NoAXP192 = 6; /* * The channel tried to set a radio setting which is not supported by this chipset, * radio comms settings are now undefined. */ InvalidRadioSetting = 7; /* * Radio transmit hardware failure. We sent data to the radio chip, but it didn't * reply with an interrupt. */ TransmitFailed = 8; /* * We detected that the main CPU voltage dropped below the minumum acceptable value */ Brownout = 9; /* Selftest of SX1262 radio chip failed */ SX1262Failure = 10; /* * A (likely software but possibly hardware) failure was detected while trying to send packets. * If this occurs on your board, please post in the forum so that we can ask you to collect some information to allow fixing this bug */ RadioSpiBug = 11; } /* * Unique local debugging info for this node * Note: we don't include position or the user info, because that will come in the * Sent to the phone in response to WantNodes. */ message MyNodeInfo { /* * Tells the phone what our node number is, default starting value is * lowbyte of macaddr, but it will be fixed if that is already in use */ uint32 my_node_num = 1; /* * Note: This flag merely means we detected a hardware GPS in our node. * Not the same as UserPreferences.location_sharing */ bool has_gps = 2; /* * The maximum number of 'software' channels that can be set on this node. */ uint32 max_channels = 15; /* * Deprecated! ONLY USED IN DEVICE CODE (for upgrading old 1.0 firmwares) DO NOT READ ELSEWHERE. * The region code for my radio (US, CN, etc...) * Note: This string is deprecated. * The 1.0 builds populate it based on the flashed firmware name. * But for newer builds this string will be unpopulated (missing/null). * For those builds you should instead look at the new read/write region enum in UserSettings * The format of this string was 1.0-US or 1.0-CN etc.. Or empty string if unset. */ string region = 4 [deprecated = true]; /* * 0.0.5 etc... */ string firmware_version = 6; /* * An error message we'd like to report back to the mothership through analytics. * It indicates a serious bug occurred on the device, the device coped with it, * but we still want to tell the devs about the bug. * This field will be cleared after the phone reads MyNodeInfo * (i.e. it will only be reported once) * a numeric error code to go with error message, zero means no error */ CriticalErrorCode error_code = 7; /* * A numeric error address (nonzero if available) */ uint32 error_address = 8; /* * The total number of errors this node has ever encountered * (well - since the last time we discarded preferences) */ uint32 error_count = 9; /* * The total number of reboots this node has ever encountered * (well - since the last time we discarded preferences) */ uint32 reboot_count = 10; /* * Calculated bitrate of the current channel (in Bytes Per Second) */ float bitrate = 11; /* * How long before we consider a message abandoned and we can clear our * caches of any messages in flight Normally quite large to handle the worst case * message delivery time, 5 minutes. * Formerly called FLOOD_EXPIRE_TIME in the device code */ uint32 message_timeout_msec = 13; /* * The minimum app version that can talk to this device. * Phone/PC apps should compare this to their build number and if too low tell the user they must update their app */ uint32 min_app_version = 14; /* * 24 time windows of 1hr each with the airtime transmitted out of the device per hour. */ repeated uint32 air_period_tx = 16; /* * 24 time windows of 1hr each with the airtime of valid packets for your mesh. */ repeated uint32 air_period_rx = 17; /* * Is the device wifi capable? */ bool has_wifi = 18; /* * Utilization for the current channel, including well formed TX, RX and malformed RX (aka noise). */ float channel_utilization = 19; /* * Percent of airtime for transmission used within the last hour. */ float air_util_tx = 20; } /* * Debug output from the device. * * To minimize the size of records inside the device code, if a time/source/level is not set * on the message it is assumed to be a continuation of the previously sent message. * This allows the device code to use fixed maxlen 64 byte strings for messages, * and then extend as needed by emitting multiple records. */ message LogRecord { /* * Log levels, chosen to match python logging conventions. */ enum Level { /* * Log levels, chosen to match python logging conventions. */ UNSET = 0; /* * Log levels, chosen to match python logging conventions. */ CRITICAL = 50; /* * Log levels, chosen to match python logging conventions. */ ERROR = 40; /* * Log levels, chosen to match python logging conventions. */ WARNING = 30; /* * Log levels, chosen to match python logging conventions. */ INFO = 20; /* * Log levels, chosen to match python logging conventions. */ DEBUG = 10; /* * Log levels, chosen to match python logging conventions. */ TRACE = 5; } /* * Log levels, chosen to match python logging conventions. */ string message = 1; /* * Seconds since 1970 - or 0 for unknown/unset */ fixed32 time = 2; /* * Usually based on thread name - if known */ string source = 3; /* * Not yet set */ Level level = 4; } /* * Packets from the radio to the phone will appear on the fromRadio characteristic. * It will support READ and NOTIFY. When a new packet arrives the device will BLE notify? * It will sit in that descriptor until consumed by the phone, * at which point the next item in the FIFO will be populated. */ message FromRadio { /* * In the <1.2 versions packet had ID 2, to prevent confusing old apps with our new packets, we've changed */ reserved 2; /* * In the <1.2 versions nodeinfo had ID 4, to prevent confusing old apps with our new packets, we've changed */ reserved 6; /* * The packet id, used to allow the phone to request missing read packets from the FIFO, * see our bluetooth docs */ uint32 id = 1; /* * Log levels, chosen to match python logging conventions. */ oneof payloadVariant { /* * Log levels, chosen to match python logging conventions. */ MeshPacket packet = 11; /* * Tells the phone what our node number is, can be -1 if we've not yet joined a mesh. * NOTE: This ID must not change - to keep (minimal) compatibility with <1.2 version of android apps. */ MyNodeInfo my_info = 3; /* * One packet is sent for each node in the on radio DB * starts over with the first node in our DB */ NodeInfo node_info = 4; /* * Set to send debug console output over our protobuf stream */ LogRecord log_record = 7; /* * Sent as true once the device has finished sending all of the responses to want_config * recipient should check if this ID matches our original request nonce, if * not, it means your config responses haven't started yet. * NOTE: This ID must not change - to keep (minimal) compatibility with <1.2 version of android apps. */ uint32 config_complete_id = 8; /* * Sent to tell clients the radio has just rebooted. * Set to true if present. * Not used on all transports, currently just used for the serial console. * NOTE: This ID must not change - to keep (minimal) compatibility with <1.2 version of android apps. */ bool rebooted = 9; } } /* * Packets/commands to the radio will be written (reliably) to the toRadio characteristic. * Once the write completes the phone can assume it is handled. */ message ToRadio { /* * Instead of sending want_config_id as a uint32, newer clients send this structure with information about the client. */ message PeerInfo { /* * The numeric version code for the client application, which in some cases are used to control device behavior (so the device can * make assumptions about who is using the API. */ uint32 app_version = 1; /* * True if the peer device can gateway MQTT packets. * If true, the device will not try to send packets to the internet directly, * instead it will pass the packets to the peer for dispatching. * This feature is optional, if set to false the device will assume the client can not gateway to MQTT. */ bool mqtt_gateway = 2; } /* * In the <1.2 versions packet had ID 2, to prevent confusing old apps with our new packets, we've changed. * 101-103 were used for set_radio, set_owner, set_channel */ reserved 1, 101, 102, 103; /* * Log levels, chosen to match python logging conventions. */ oneof payloadVariant { /* * Send this packet on the mesh */ MeshPacket packet = 2; /* * Information about the peer, sent after the phone sneds want_config_id. * Old clients do not send this, which is fine. */ PeerInfo peer_info = 3; /* * Phone wants radio to send full node db to the phone, This is * typically the first packet sent to the radio when the phone gets a * bluetooth connection. The radio will respond by sending back a * MyNodeInfo, a owner, a radio config and a series of * FromRadio.node_infos, and config_complete * the integer you write into this field will be reported back in the * config_complete_id response this allows clients to never be confused by * a stale old partially sent config. */ uint32 want_config_id = 100; /* * Tell API server we are disconnecting now. * This is useful for serial links where there is no hardware/protocol based notification that the client has dropped the link. * (Sending this message is optional for clients) */ bool disconnect = 104; } }