diff --git a/Localizable.xcstrings b/Localizable.xcstrings index 6f513769..8fa566e8 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -5,28 +5,100 @@ }, "\t%@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "\t%@" + } + } + } }, " %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + } + } }, " %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + } + } }, " Whether or not use INPUT_PULLUP mode for GPIO pin. Only applicable if the board uses pull-up resistors on the pin" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Да ли желите да користите режим INPUT_PULLUP за GPIO пин. Применљиво само ако плоча користи pull-up отпорнике на пиновима" + } + } + } }, ": %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : ": %@" + } + } + } }, ": %d" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : ": %d" + } + } + } }, "(Re)define PIN_GPS_EN for your board." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "(Поново)дефинишите PIN_GPS_EN за своју плочу." + } + } + } }, "%@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@" + } + } + } + }, + "%@ - %@" : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@ - %2$@" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ - %2$@" + } + } + } }, "%@ - %@ - %@" : { "localizations" : { @@ -35,24 +107,52 @@ "state" : "new", "value" : "%1$@ - %2$@ - %3$@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ - %2$@ - %3$@" + } } } }, - "%@ - %d Hops Towards %d Hops Back" : { + "%@ - %@ Towards %@ Back" : { "localizations" : { "en" : { "stringUnit" : { "state" : "new", - "value" : "%1$@ - %2$d Hops Towards %3$d Hops Back" + "value" : "%1$@ - %2$@ Towards %3$@ Back" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ - %2$@ Одлазних скокова %3$@ Долазних скокова" } } } }, "%@ - 1 Hop" : { - + "extractionState" : "stale", + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ - 1 Скок" + } + } + } }, "%@ - Direct" : { - + "extractionState" : "stale", + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ - Директно" + } + } + } }, "%@ - No Response" : { "localizations" : { @@ -61,6 +161,12 @@ "state" : "translated", "value" : "%@ - Keine Antwort" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ - Нема одговора" + } } } }, @@ -71,6 +177,12 @@ "state" : "translated", "value" : "%@ - Nicht gesendet" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ - Није послато" + } } } }, @@ -81,6 +193,12 @@ "state" : "new", "value" : "%1$@ (%2$@)" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ (%2$@)" + } } } }, @@ -91,6 +209,12 @@ "state" : "new", "value" : "%1$@ %2$@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$@" + } } } }, @@ -101,6 +225,12 @@ "state" : "new", "value" : "%1$@ %2$lld" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ %2$lld" + } } } }, @@ -111,6 +241,12 @@ "state" : "translated", "value" : "%@ entfernt" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ удаљено" + } } } }, @@ -121,17 +257,54 @@ "state" : "new", "value" : "%1$@ can be up to %2$@ bytes long." } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@ може имати до %2$@ бајтова." + } } } }, "%@ Channels?" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ Канали?" + } + } + } }, "%@ config data was requested over the admin channel but no response has been returned from the remote node." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ конфигурациони подаци су затражени преко административног канала, али никакав одговор није враћен са удаљеног чвора." + } + } + } }, "%@ dB" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ dB" + } + } + } + }, + "%@ hPa" : { + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ hPa" + } + } + } }, "%@, %@" : { "localizations" : { @@ -140,6 +313,12 @@ "state" : "new", "value" : "%1$@, %2$@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@" + } } } }, @@ -150,26 +329,132 @@ "state" : "new", "value" : "%1$@: %2$lld / %3$lld" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$lld / %3$lld" + } } } }, "%@%%" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@%%" + } + } + } }, "%@°F" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@°F" + } + } + } }, "%d" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d" + } + } + } + }, + "%d Hops" : { + "localizations" : { + "en" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d Hop" + } + }, + "other" : { + "stringUnit" : { + "state" : "new", + "value" : "%d Hops" + } + }, + "zero" : { + "stringUnit" : { + "state" : "translated", + "value" : "Direct" + } + } + } + } + }, + "sr" : { + "variations" : { + "plural" : { + "few" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d скокова" + } + }, + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d скок" + } + }, + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d скокова" + } + }, + "zero" : { + "stringUnit" : { + "state" : "translated", + "value" : "Директно" + } + } + } + } + } + } }, "%d%%" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%d%%" + } + } + } }, "%lf" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lf" + } + } + } }, "%lld" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld" + } + } + } }, "%lld or less hops away" : { "localizations" : { @@ -178,17 +463,44 @@ "state" : "translated", "value" : "%lld oder weniger Hops entfernt" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld или мање скокова" + } } } }, "%lld Readings Total" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Укупно %lld читања" + } + } + } }, "%lld Total Detection Events" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Укупно %lld догађаја детекције" + } + } + } }, "%lld%%" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld%%" + } + } + } }, "%llddb Transmit Power" : { "localizations" : { @@ -197,6 +509,12 @@ "state" : "translated", "value" : "%llddb Übertragungsleistung" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%llddb снага преноса" + } } } }, @@ -207,47 +525,144 @@ "state" : "translated", "value" : "%llddBm Übertragungsleistung" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%llddBm снага преноса" + } } } }, "< 1%" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "< 1%" + } + } + } }, "🦕 End of life Version 🦖 ☄️" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "🦕 Верзија за крај живота 🦖 ☄" + } + } + } }, "1 byte" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "1 byte" + } + } + } }, "1 hop away" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "1 hop away" + } + } + } }, "7" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "7" + } + } + } }, "8" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "8" + } + } + } }, "25" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "25" + } + } + } }, "50" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "50" + } + } + } }, "75" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "75" + } + } + } }, "100" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "100" + } + } + } }, "128 bit" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "128 bit" + } + } + } }, "256 bit" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "256 bit" + } + } + } }, "A Trace Route was sent, no response has been received." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Трејсрут је послат, али одговор није примљен." + } + } + } }, "about" : { "localizations" : { @@ -293,6 +708,12 @@ "value" : "Om" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "О" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -351,6 +772,12 @@ "value" : "Om Meshtastic" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "О Мештастику" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -372,17 +799,44 @@ "state" : "translated", "value" : "Genauigkeit %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прецизност %@" + } } } }, "Ack SNR: %@ dB" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ack SNR: %@ dB" + } + } + } }, "Ack Time: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ack време: %@" + } + } + } }, "Acknowledged by another node" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Потврђен од стране другог чвора" + } + } + } }, "Actions" : { "localizations" : { @@ -391,6 +845,12 @@ "state" : "translated", "value" : "Aktionen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Акције" + } } } }, @@ -401,6 +861,12 @@ "state" : "translated", "value" : "Aktiv" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Активан" + } } } }, @@ -448,6 +914,12 @@ "value" : "Activity" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Активност" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -469,14 +941,34 @@ "state" : "translated", "value" : "Aktivität" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Активност" + } } } }, "Add Channel" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Додај канал" + } + } + } }, "Add Channels" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Додај канале" + } + } + } }, "Add to favorites" : { "localizations" : { @@ -485,14 +977,34 @@ "state" : "translated", "value" : "Zu Favoriten hinzufügen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Додај у омиљене" + } } } }, "Additional help" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Додатна помоћ" + } + } + } }, "Address" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Адреса" + } + } + } }, "admin" : { "extractionState" : "migrated", @@ -539,6 +1051,12 @@ "value" : "Administratör" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Админ" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -554,9 +1072,17 @@ } }, "Admin & Direct Message Keys" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Админ и кључеви директних порука" + } + } + } }, "admin.log" : { + "comment" : "On Serbian language Admin and Administrator are the same as in English, but in sentences like this we use the longer version always.", "extractionState" : "manual", "localizations" : { "de" : { @@ -601,6 +1127,12 @@ "value" : "Administratörsmeddelandelogg" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дневник администраторских порука" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -616,21 +1148,57 @@ } }, "Administration" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Администрација" + } + } + } }, "Advanced" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Напредно" + } + } + } }, "Advanced Device GPS" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Напредне поставке GPS уређаја" + } + } + } }, "Advanced GPIO Options" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Напредне GPIO опције" + } + } + } }, "Advanced Position Flags" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Напредне поставке позиционих заставица" + } + } + } }, "ago" : { + "comment" : "Three hours ago = Три сата пре", "extractionState" : "manual", "localizations" : { "de" : { @@ -675,6 +1243,12 @@ "value" : "sedan" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "пре" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -733,6 +1307,12 @@ "value" : "Sändningstid" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Време емитовања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -748,31 +1328,94 @@ } }, "Airtime" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Време емитовања" + } + } + } }, "Airtime %@%%" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Време емитовања %@%%" + } + } + } }, "Alert" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Узбуна" + } + } + } }, "Alert GPIO buzzer when receiving a bell" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Упозорите GPIO зујалицу када примите звоно" + } + } + } }, "Alert GPIO buzzer when receiving a message" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Упозорите GPIO зујалицу када примите поруку" + } + } + } }, "Alert GPIO vibra motor when receiving a bell" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Упозорите GPIO вибра мотор када примите звоно" + } + } + } }, "Alert GPIO vibra motor when receiving a message" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Упозорите GPIO вибра мотор када примите поруку" + } + } + } }, "Alert when receiving a bell" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Упозори када примиш звоно" + } + } + } }, "Alert when receiving a message" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Упозори када примиш поруку" + } + } + } }, "All" : { "localizations" : { @@ -781,20 +1424,54 @@ "state" : "translated", "value" : "Alle" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сви" + } } } }, "All device and app data will be deleted." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сви подаци о уређају и апликацији ће бити избрисани." + } + } + } }, "Allow incoming device control over the insecure legacy admin channel." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дозволите контролу долазног уређаја над небезбедним старим администраторским каналом." + } + } + } }, "Allow Position Requests" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дозволи захтеве позиција" + } + } + } }, "Alt" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Висина" + } + } + } }, "Altitude" : { "localizations" : { @@ -803,6 +1480,12 @@ "state" : "translated", "value" : "Höhe" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Висина" + } } } }, @@ -813,14 +1496,34 @@ "state" : "translated", "value" : "Höhe %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Висина %@" + } } } }, "Altitude Geoidal Separation" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Висинска геоидна сепарација" + } + } + } }, "Altitude is Mean Sea Level" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Надморска висина је средњи ниво мора" + } + } + } }, "Always point north" : { "localizations" : { @@ -829,6 +1532,12 @@ "state" : "translated", "value" : "Immer nach Norden zeigen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Увек усмеравајте на север" + } } } }, @@ -877,6 +1586,12 @@ "value" : "Alltid på" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Увек укључен" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -935,6 +1650,12 @@ "value" : "Omgivningsbelysning" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Амбијентално осветљење" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -993,6 +1714,12 @@ "value" : "Konfiguration av omgivningsbelysning" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања амбијенталног осветљења" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1014,23 +1741,64 @@ "state" : "translated", "value" : "Ein quelloffenes, netzunabhängiges, dezentrales Mesh-Netzwerk, das auf kostengünstigen, stromsparenden Funkgeräten läuft." } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Отворена, off-grid, децентрализована, меш мрежа која ради на приступачним радио уређајима мале снаге." + } } } }, "Any missed messages will be delivered again." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Све пропуштене поруке ће бити поново испоручене." + } + } + } }, "App Data" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подаци апликације" + } + } + } }, "App Files" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Фајлови апликације" + } + } + } }, "App Settings" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања апликације" + } + } + } }, "Apple Apps" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Епл апликације" + } + } + } }, "Approximate Location" : { "localizations" : { @@ -1039,6 +1807,12 @@ "state" : "translated", "value" : "Ungefährer Standort" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Приближна локација" + } } } }, @@ -1086,6 +1860,12 @@ "value" : "Appinställningar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања апликације" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1145,6 +1925,12 @@ "value" : "New Node Notifications" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Обавештења о новим чворовима" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1204,6 +1990,12 @@ "value" : "Dela plats" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подели информације о локацији" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1263,6 +2055,12 @@ "value" : "Smart position" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Паметно позиционирање" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1278,7 +2076,14 @@ } }, "Are you sure you want to delete this message?" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Да ли си сигуран да желиш да обришеш ову поруку?" + } + } + } }, "Are you sure you want to factory reset the node?" : { "localizations" : { @@ -1287,6 +2092,12 @@ "state" : "translated", "value" : "Bist du sicher dass du den Knoten auf die Werkseinstellungen zurücksetzen willst?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Да ли си стигуран да желиш да вратиш овај чвор на фабричка подешавања?" + } } } }, @@ -1334,6 +2145,12 @@ "value" : "Är du säker?" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Да ли си сигуран?" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1393,6 +2210,12 @@ "value" : "ASCII-kompatibel" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ASCII способан" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1452,6 +2275,12 @@ "value" : "Automatisk upptäckt" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Аутоматска детекција" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1467,10 +2296,24 @@ } }, "Automatically toggles to the next page on the screen like a carousel, based the specified interval." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Аутоматски се пребацује на следећу страницу на екрану као карусел, на основу наведеног интервала." + } + } + } }, "Available modem presets, default is Long Fast." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Доступна унапред подешена подешавања модема, подразумевана је Long Fast." + } + } + } }, "available.radios" : { "localizations" : { @@ -1516,6 +2359,12 @@ "value" : "Tillgängliga radioapparater" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Доступни радио уређаји" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1531,10 +2380,24 @@ } }, "Backup Database" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Резервна база података" + } + } + } }, "Bad" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Лош" + } + } + } }, "Bandwidth" : { "localizations" : { @@ -1543,20 +2406,54 @@ "state" : "translated", "value" : "Bandbreite" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Проток" + } } } }, "Bar" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bar" + } + } + } }, "Bar Series" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bar серија" + } + } + } }, "Barometric Pressure" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Барометарски притисак" + } + } + } }, "Battery Level %" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ниво батерије у %" + } + } + } }, "battery.level" : { "localizations" : { @@ -1602,6 +2499,12 @@ "value" : "Batterinivå" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ниво батерије" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1617,13 +2520,34 @@ } }, "Baud" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Baud" + } + } + } }, "BLE RSSI: %lld" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "BLE RSSI: %lld" + } + } + } }, "BLE: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "BLE: %@" + } + } + } }, "ble.connection.timeout %d %@" : { "extractionState" : "migrated", @@ -1670,6 +2594,12 @@ "value" : "Anslutningen misslyckades efter %d försök att ansluta till %@. Du kan behöva glömma din enhet under Inställningar > Bluetooth." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Веза није успела након %d покушаја да се повеже са %@. Можда ћете морати да заборавите уређај у Подешавања > Блутут." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1684,6 +2614,23 @@ } } }, + "ble.errorcode.6" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The connection has timed out unexpectedly." + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Веза је неочекивано истекла." + } + } + } + }, "ble.errorcode.6 %@" : { "extractionState" : "migrated", "localizations" : { @@ -1729,6 +2676,12 @@ "value" : "%@ Appen kommer automatiskt att återansluta till den föredragna radion om den kommer inom räckhåll igen." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ Апликација ће се аутоматски поново повезати са жељеним радиом ако се врати у домет." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1743,6 +2696,23 @@ } } }, + "ble.errorcode.14" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Peer removed pairing information." + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Радио уређај је уклонио информације о упаривању." + } + } + } + }, "ble.errorcode.14 %@" : { "extractionState" : "migrated", "localizations" : { @@ -1788,6 +2758,12 @@ "value" : "%@ Detta fel kan vanligtvis inte åtgärdas utan att glömma enheten under Inställningar > Bluetooth och återansluta till radion." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ Ова грешка обично не може да се поправи без заборављања уређаја испод подешавања > Блутут и поново повезивање са радиом." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1847,6 +2823,12 @@ "value" : "%@ Försök att ansluta igen och kontrollera PIN-koden noggrant." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "%@ Покушајте поново да се повежете и пажљиво проверите ПИН." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1905,6 +2887,12 @@ "value" : "BLE-namn" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "BLE назив" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -1963,6 +2951,12 @@ "value" : "Bluetooth" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Блутут" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2021,6 +3015,12 @@ "value" : "Bluetooth-konfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Блутут подешавања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2079,6 +3079,12 @@ "value" : "Fast PIN" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Фиксни ПИН" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2138,6 +3144,12 @@ "value" : "Ingen PIN (Bara fungerar)" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема ПИН-а (само ради)" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2197,6 +3209,12 @@ "value" : "Slumpmässig PIN" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Насумичан ПИН" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2255,6 +3273,12 @@ "value" : "Bluetooth är avstängt" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Блутут је искључен" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2313,6 +3337,12 @@ "value" : "Parläge" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мод упаривања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2371,6 +3401,12 @@ "value" : "BLE-PIN måste vara 6 siffror lång." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "BLE пин мора имати 6 цифара." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2386,16 +3422,44 @@ } }, "Broadcast Interval" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Интервал емитовања" + } + } + } }, "Button GPIO" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дугме GPIO" + } + } + } }, "Buy Complete Radios" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Купите готове радио уређаје" + } + } + } }, "Buzzer GPIO" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Звучни сигнал GPIO" + } + } + } }, "bytes" : { "extractionState" : "migrated", @@ -2442,6 +3506,12 @@ "value" : "Bytes" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Бајтова" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2457,10 +3527,24 @@ } }, "Call Sign" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Позивни знак" + } + } + } }, "Call Sign must not be empty" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Позивни знак не може бити празан" + } + } + } }, "cancel" : { "localizations" : { @@ -2506,6 +3590,12 @@ "value" : "Avbryt" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Откажи" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2527,6 +3617,12 @@ "state" : "translated", "value" : "Abbrechen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Откажи" + } } } }, @@ -2574,6 +3670,12 @@ "value" : "Fördefinierade meddelanden" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Унапред припремљене поруке" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2632,6 +3734,12 @@ "value" : "Konfiguration av fördefinierade meddelanden" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања унапред припремљених порука" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2691,6 +3799,12 @@ "value" : "M5 Stack Card KB / RAK Keypad" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "M5 стек картица KB / RAK тастатура" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2750,6 +3864,12 @@ "value" : "Manuell konfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ручна конфигурација" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2809,6 +3929,12 @@ "value" : "RAK Rotary Encoder-modul" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "RAK Rotary енкодер модул" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2824,7 +3950,14 @@ } }, "Carousel Interval" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Интервал карусела" + } + } + } }, "Categories" : { "localizations" : { @@ -2833,6 +3966,12 @@ "state" : "translated", "value" : "Kategorien" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Категорије" + } } } }, @@ -2880,6 +4019,12 @@ "value" : "Kanal" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канал" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -2901,47 +4046,144 @@ "state" : "translated", "value" : "Kanal" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канал" + } } } }, "Channel 0 Included" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канал 0 укључен" + } + } + } }, "Channel 1 Included" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канал 1 укључен" + } + } + } }, "Channel 2 Included" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канал 2 укључен" + } + } + } }, "Channel 3 Included" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канал 3 укључен" + } + } + } }, "Channel 4 Included" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канал 4 укључен" + } + } + } }, "Channel 5 Included" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канал 5 укључен" + } + } + } }, "Channel 6 Included" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канал 6 укључен" + } + } + } }, "Channel 7 Included" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канал 7 укључен" + } + } + } }, "channel details" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "детаљи канала" + } + } + } }, "Channel Name" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Назив канала" + } + } + } }, "Channel number must be between 0 and 7." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Број канала мора бити између 0 и 7." + } + } + } }, "Channel Role" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Улога канала" + } + } + } }, "Channel Utilization %@%% " : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Искоришћеност канала %@%%" + } + } + } }, "channel.role.disabled" : { "extractionState" : "migrated", @@ -2988,6 +4230,12 @@ "value" : "Inaktiverad" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Онемогућено" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3047,6 +4295,12 @@ "value" : "Primär" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Примарни" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3106,6 +4360,12 @@ "value" : "Sekundär" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Секундарни" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3164,6 +4424,12 @@ "value" : "Kanalutnyttjande" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Искоришћеност канала" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3222,6 +4488,12 @@ "value" : "Kanaler" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канали" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3237,16 +4509,37 @@ } }, "Channels being added from the QR code did not save. When adding channels the names must be unique." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Канали који се додају из КР кода нису сачувани. Приликом додавања канала имена морају бити јединствена." + } + } + } }, "Chart" : { }, "CHG" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "CHG" + } + } + } }, "Clear" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Очисти" + } + } + } }, "clear.app.data" : { "localizations" : { @@ -3292,6 +4585,12 @@ "value" : "Rensa appdata" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Очисти податке апликације" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3350,6 +4649,12 @@ "value" : "Rensa" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Очисти" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3365,19 +4670,54 @@ } }, "Client" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Клијент" + } + } + } }, "Client History" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Историја клијената" + } + } + } }, "Client History Request Sent" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтев за историју клијента је послат" + } + } + } }, "Client options" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опције клијента" + } + } + } }, "Clockwise Rotary Event" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ротациони догађај у смеру казаљке на сату" + } + } + } }, "close" : { "localizations" : { @@ -3423,6 +4763,12 @@ "value" : "Stäng" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Затвори" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3438,7 +4784,14 @@ } }, "Coding Rate" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Стопа кодирања" + } + } + } }, "Color" : { "localizations" : { @@ -3447,6 +4800,12 @@ "state" : "translated", "value" : "Farbe" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Боја" + } } } }, @@ -3494,6 +4853,12 @@ "value" : "Kommunicerar med enheten..." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Комуницирање са уређајем. ." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3549,6 +4914,12 @@ "value" : "När aktiverad räknar PAX-räknarmodulen antalet personer som passerar med WiFi och Bluetooth. Både WiFi och Bluetooth måste vara aktiverade för att PAX-räknaren ska fungera." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Када је омогућен, модул бројача пролазника броји број људи који пролазе користећи ВајФај и Блутут. И ВајФај и Блутут морају бити онемогућени да би бројач пролазника радио." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3601,6 +4972,12 @@ "value" : "PAX Räknare" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Бројач пролазника" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3653,6 +5030,12 @@ "value" : "PAX Räknare Konfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања бројача пролазника" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3705,6 +5088,12 @@ "value" : "Uppdateringsintervall" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Интервал ажурирања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3757,6 +5146,12 @@ "value" : "Hur ofta vi kan skicka ett meddelande till mesh-nätverket när personer upptäcks." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Колико често можемо послати поруку мрежи када се открију људи." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3809,6 +5204,12 @@ "value" : "Multiplikator" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мултипликатор" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3861,6 +5262,12 @@ "value" : "ADC-överskrivning" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Преписивање ADC-а" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3908,6 +5315,12 @@ "value" : "Intervall för Ljussömn" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Интервал благог спавања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -3955,6 +5368,12 @@ "value" : "Minsta Väckningsintervall" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Минимални интервал будног стања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4007,6 +5426,12 @@ "value" : "Strömsparläge" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уштеда енергије" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4053,6 +5478,12 @@ "value" : "Sätter allt i viloläge så mycket som möjligt, för spårnings- och sensorläge kommer detta också inkludera LoRa-radion. Använd inte denna inställning om du vill använda din enhet med mobilappar eller använder en enhet utan en användarknapp." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Спаваће све што је више могуће, за улогу трагача и сензора ово ће укључивати и лора радио. Не користите ово подешавање ако желите да користите свој уређај са мобилним апликацијама или користите уређај без корисничког дугмета." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4105,6 +5536,12 @@ "value" : "Batteri" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Батерија" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4158,6 +5595,12 @@ "value" : "Sömn" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Стане спавања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4210,6 +5653,12 @@ "value" : "Ström" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Снага" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4262,6 +5711,12 @@ "value" : "Efter" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Након" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4314,6 +5769,12 @@ "value" : "Stäng av vid Strömförlust" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Искључи уређај при губитку напајања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4366,6 +5827,12 @@ "value" : "Strömkonfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања напајња" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4419,6 +5886,12 @@ "value" : "Bluetooth Stängs Av Efter" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Блутут се искључује након" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4472,6 +5945,12 @@ "value" : "RTTTL Ringsignal" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "RTTTL мелодија звона" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4518,6 +5997,12 @@ "value" : "Ringsignalöverföringsspråk (RTTTL) Ringsignalsträng som används av stödda buzzers i externa notifikationer." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Језик преноса мелдоије звона (RTTTL) Стринг мелодије звона који користе подржани звучни сигнали у спољним обавештењима." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4564,6 +6049,12 @@ "value" : "Språk för Överföring av Ringsignal" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Језик преноса мелодије звона" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4616,6 +6107,12 @@ "value" : "Ringsignalskonfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација звона" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4674,6 +6171,12 @@ "value" : "Efter att konfigurationsvärdena sparats kommer noden att starta om." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Након што сачувате вредности конфигурације, чвор ће се поново покренути." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4689,10 +6192,24 @@ } }, "Configuration for: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација за: %@" + } + } + } }, "Configuration Presets" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Унапред подешене конфигурације" + } + } + } }, "Configure" : { "localizations" : { @@ -4701,6 +6218,12 @@ "state" : "translated", "value" : "Konfigurieren" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигуриши" + } } } }, @@ -4711,6 +6234,12 @@ "state" : "translated", "value" : "Verbunden mit einem Knoten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Повежите се са чвором" + } } } }, @@ -4758,6 +6287,12 @@ "value" : "Bluetooth Ansluten" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Блутут повезан" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4779,6 +6314,12 @@ "state" : "translated", "value" : "Verbunden mit Knoten %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Повезани чвор %@" + } } } }, @@ -4826,6 +6367,12 @@ "value" : "Ansluten Radio" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Повезани радио" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4884,6 +6431,12 @@ "value" : "Ansluter..." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Повезујем се . ." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -4905,6 +6458,12 @@ "state" : "translated", "value" : "Verbindungsversuch %lld von 10" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Покушај повезивања %lld од 10" + } } } }, @@ -4953,6 +6512,12 @@ "value" : "Kontakter" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Контакти" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5012,6 +6577,12 @@ "value" : "Kontakter (%@)" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Контакти (%@)" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5027,10 +6598,24 @@ } }, "Control Type" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тип контроле" + } + } + } }, "Controls the blinking LED on the device. For most devices this will control one of the up to 4 LEDS, the charger and GPS LEDs are not controllable." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Контролише трептајући ЛЕД на уређају. За већину уређаја ово ће контролисати један од до максималних 4 ЛЕД, ЛЕД пуњења и ГПС ЛЕД диоде се не могу контролисати." + } + } + } }, "Convex Hull" : { "localizations" : { @@ -5039,6 +6624,12 @@ "state" : "translated", "value" : "Konvexe Hülle" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конвексна љуштура" + } } } }, @@ -5049,6 +6640,12 @@ "state" : "translated", "value" : "Koordinate" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Координате" + } } } }, @@ -5065,6 +6662,12 @@ "state" : "new", "value" : "Coordinate %1$@, %2$@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Координате %1$@, %2$@" + } } } }, @@ -5075,6 +6678,12 @@ "state" : "translated", "value" : "Koordinaten:" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Координате:" + } } } }, @@ -5122,6 +6731,12 @@ "value" : "Kopiera" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Копирај" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5143,11 +6758,24 @@ "state" : "translated", "value" : "Knoten nicht gefunden" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Није могуће наћи чвор" + } } } }, "Counter Clockwise Rotary Event" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ротациони догађај у смеру супротном од казаљке на сату" + } + } + } }, "Create Waypoint" : { "localizations" : { @@ -5156,6 +6784,12 @@ "state" : "translated", "value" : "Wegpunkt erstellen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Креирајте путну тачку" + } } } }, @@ -5166,6 +6800,12 @@ "state" : "translated", "value" : "Erstellt: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Креирано : %@" + } } } }, @@ -5214,6 +6854,12 @@ "value" : "Aktuell" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренутни" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5235,6 +6881,12 @@ "state" : "translated", "value" : "Aktuelle Firmware Version: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренутна верзија фирмвера: %@" + } } } }, @@ -5251,6 +6903,12 @@ "state" : "new", "value" : "Current Firmware Version: %1$@, Latest Firmware Version: %2$@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренутна верзија фирмвера: %1$@, најновија верзија фирмвера: %2$@" + } } } }, @@ -5261,11 +6919,35 @@ "state" : "translated", "value" : "Aktuell: %lld" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренутно: %lld" + } } } }, "Currently the reccomended way to update ESP32 devices is using the web flasher on a desktop computer from a chrome based browser. It does not work on mobile devices or over BLE." : { - + "extractionState" : "stale", + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренутно препоручени начин за ажурирање ЕСП32 уређаја је коришћење веб флешера на десктоп рачунару из прегледача заснованог на хрому. Не ради на мобилним уређајима или преко BLE-а." + } + } + } + }, + "Currently the recommended way to update ESP32 devices is using the web flasher on a desktop computer from a chrome based browser. It does not work on mobile devices or over BLE." : { + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тренутно препоручени начин за ажурирање ЕСП32 уређаја је коришћење веб флешера на десктоп рачунару из прегледача заснованог на хрому. Не ради на мобилним уређајима или преко BLE-а." + } + } + } }, "Date" : { "localizations" : { @@ -5274,17 +6956,44 @@ "state" : "translated", "value" : "Datum" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Датум" + } } } }, "Debug" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дебагуј" + } + } + } }, "Debug Logs" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дебаг логови" + } + } + } }, "Debug Logs%@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Debug логови%@" + } + } + } }, "default" : { "extractionState" : "migrated", @@ -5331,6 +7040,12 @@ "value" : "Standard" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подразумевано" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5352,6 +7067,29 @@ "state" : "translated", "value" : "Standard" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подразумевано" + } + } + } + }, + "default.128x64.screen.layout" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Default 128x64 screen layout" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подразумевани изглед екрана 128x64" + } } } }, @@ -5399,6 +7137,12 @@ "value" : "Ta bort" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Обриши" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5414,19 +7158,54 @@ } }, "Delete all environment metrics?" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Желите ли да избришете све показатеље окружења?" + } + } + } }, "Delete all map tiles?" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Избрисати све плочице мапе?" + } + } + } }, "Delete all positions?" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Избрисати све позиције?" + } + } + } }, "Delete Message" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Обриши поруку" + } + } + } }, "Delete Messages" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Обриши поруке" + } + } + } }, "Delete Node" : { "localizations" : { @@ -5435,6 +7214,12 @@ "state" : "translated", "value" : "Knoten löschen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Обриши чвор" + } } } }, @@ -5445,26 +7230,74 @@ "state" : "translated", "value" : "Knoten löschen?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Обрисати чвор?" + } } } }, "Description" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опис" + } + } + } }, "Description must be less than 100 bytes" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опис мора бити испод 100 бајтова" + } + } + } }, "Detection" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Откривање" + } + } + } }, "Detection event" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Догађај откривања" + } + } + } }, "Detection Sensor Log" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Логови сензора откривања" + } + } + } }, "Detection sensor messages are received as text messages. If you enable notifications you will recieve a notification for each detection message received and a corresponding unread message badge." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поруке сензора за откривање се примају као текстуалне поруке. Ако омогућите обавештења, добићете обавештење за сваку примљену поруку за откривање и одговарајућу значку непрочитане поруке." + } + } + } }, "detection.sensor" : { "localizations" : { @@ -5510,6 +7343,12 @@ "value" : "Detektionssensor" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сензор откривања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5555,6 +7394,12 @@ "state" : "translated", "value" : "Konfiguration av Detektionssensor" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања ензора откривања" + } } } }, @@ -5589,11 +7434,24 @@ "state" : "translated", "value" : "Logg för Detektionssensor" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Логови сензора откривања" + } } } }, "Developers" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Програмери" + } + } + } }, "device" : { "localizations" : { @@ -5639,6 +7497,12 @@ "value" : "Enhet" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уређај" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5660,17 +7524,44 @@ "state" : "translated", "value" : "Geräte-GPS" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPS уређај" + } } } }, "Device is managed by a mesh administrator, the user is unable to access any of the device settings." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уређајем управља администратор мреже, корисник не може да приступи ниједном подешавању уређаја." + } + } + } }, "Device Metrics" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Метрика уређаја" + } + } + } }, "Device Metrics Log" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Логови метрике уређаја" + } + } + } }, "Device Model: %@" : { "localizations" : { @@ -5679,14 +7570,34 @@ "state" : "translated", "value" : "Gerätemodell: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Модел уређаја: %@" + } } } }, "Device Role" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Улога уређаја" + } + } + } }, "Device Screen" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Екран уређаја" + } + } + } }, "device.config" : { "localizations" : { @@ -5732,6 +7643,12 @@ "value" : "Enhetskonfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања уређаја" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5784,6 +7701,12 @@ "value" : "Enhetsinställningar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања уређаја" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5836,6 +7759,12 @@ "value" : "Ta bort alla enhetsmätvärden?" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Избришите све метрике уређаја?" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5894,6 +7823,12 @@ "value" : "Logg för Enhetsmätvärden" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Логови метрике уређаја" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -5953,6 +7888,12 @@ "value" : "Appansluten eller fristående meddelandeenhet." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Апликација повезана или самостални уређај за размену порука." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6012,6 +7953,12 @@ "value" : "Enhet som endast sänder ut när det behövs för stealth eller energibesparing." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уређај који емитује само по потреби ради прикривености или уштеде енергије." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6071,6 +8018,12 @@ "value" : "Enhet som inte vidarebefordrar paket från andra enheter." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уређај који не прослеђује пакете примљене од других уређаја." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6130,6 +8083,12 @@ "value" : "Sänder regelbundet ut plats som meddelande till standardkanalen för att underlätta återhämtning av enheten." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Редовно емитује локацију као поруку подразумеваном каналу ради помоћи при проналаску уређаја." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6144,6 +8103,193 @@ } } }, + "device.role.name.client" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Client" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Клијент" + } + } + } + }, + "device.role.name.clientHidden" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Client Hidden" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Скривени клијент" + } + } + } + }, + "device.role.name.clientMute" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Client Mute" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Клијент мутиран" + } + } + } + }, + "device.role.name.lostAndFound" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Lost and Found" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Изгубљено и нађено" + } + } + } + }, + "device.role.name.repeater" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Repeater" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поновљач" + } + } + } + }, + "device.role.name.router" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Router" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Рутер" + } + } + } + }, + "device.role.name.routerClient" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Router & Client" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Рутер и клијент" + } + } + } + }, + "device.role.name.sensor" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Sensor" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сензор" + } + } + } + }, + "device.role.name.tak" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "TAK" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "TAK" + } + } + } + }, + "device.role.name.takTracker" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "TAK Tracker" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ТАК Трекер" + } + } + } + }, + "device.role.name.tracker" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tracker" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Трекер" + } + } + } + }, "device.role.repeater" : { "extractionState" : "migrated", "localizations" : { @@ -6189,6 +8335,12 @@ "value" : "Infrastrukturnod för att utöka nätverkstäckningen genom att vidarebefordra meddelanden med minimal overhead. Syns inte i Noder-listan." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Инфраструктурни чвор само на торњу или врху планине. Није намењен за кровове или мобилне чворове. Прослеђује поруке уз минимално оптерећење. Није видљив у листи чворова." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "needs_review", @@ -6248,6 +8400,12 @@ "value" : "Infrastrukturnod för att utöka nätverkstäckningen genom att vidarebefordra meddelanden. Synlig i Noder-listan." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Инфраструктурни чвор само на торњу или врху планине. Не користи се за кровове или мобилне чворове. Потребна му је изузетна покривеност. Видљиво на листи чворова." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "needs_review", @@ -6307,6 +8465,12 @@ "value" : "Kombination av både ROUTER och CLIENT. Inte för mobila enheter." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Застарело. Користи клијент ролу." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "needs_review", @@ -6366,6 +8530,12 @@ "value" : "Sänder ut telemetripaket som prioritet." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Емитује телеметријске пакете као приоритет." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6425,6 +8595,12 @@ "value" : "Optimerad för kommunikation med ATAK-systemet, minskar rutinutsändningar." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Оптимизован за комуникацију са ATAK системом, смањује рутинске емисије." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6484,6 +8660,12 @@ "value" : "Aktiverar automatiska TAK PLI-utsändningar och minskar rutinutsändningar." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омогућава аутоматске TAK PLI емисије и смањује рутинске емисије." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6543,6 +8725,12 @@ "value" : "Sänder ut GPS-positionspaket som prioritet." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Емитује пакете са GPS позицијом као приоритет." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6558,7 +8746,14 @@ } }, "Dilution of precision (DOP) PDOP used by default" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Разређење прецизности (DOP) PDOP се користи као подразумевано" + } + } + } }, "Direct" : { "localizations" : { @@ -6567,17 +8762,44 @@ "state" : "translated", "value" : "Direkt" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Директно" + } } } }, "Direct Message Help" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Помоћ за директне поруке" + } + } + } }, "Direct messages are using the new public key infrastructure for encryption. Requires firmware version 2.5 or greater." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Директне поруке користе нову инфраструктуру јавних кључева за енкрипцију. Захтева верзију фирмвера 2.5 или новију." + } + } + } }, "Direct messages are using the shared key for the channel." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Директне поруке користе дељени кључ за канал." + } + } + } }, "direct.messages" : { "localizations" : { @@ -6623,6 +8845,12 @@ "value" : "Direktmeddelanden" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Директне поруке" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6644,6 +8872,12 @@ "state" : "translated", "value" : "Ausgeschaltet" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Онемогућено" + } } } }, @@ -6691,6 +8925,12 @@ "value" : "Koppla från" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прекините везу" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6749,6 +8989,12 @@ "value" : "Stäng" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Отпусти" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6807,6 +9053,12 @@ "value" : "Skärm" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Приказ" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6822,13 +9074,34 @@ } }, "Display Fahrenheit" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Приказ фаренхајта" + } + } + } }, "Display Mode" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Режим приказа" + } + } + } }, "Display Units" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Јединице приказа" + } + } + } }, "display.config" : { "localizations" : { @@ -6868,6 +9141,12 @@ "value" : "Skärmkonfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања приказа" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6927,6 +9206,12 @@ "value" : "Distans" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Раздаљина" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -6948,32 +9233,87 @@ "state" : "translated", "value" : "Distanz" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Раздаљина" + } } } }, "Documentation" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Документација" + } + } + } }, "Done" : { }, "Double Tap as Button" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Двоструки додир као дугме" + } + } + } }, "Downlink Enabled" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дозвољен даунлинк" + } + } + } }, "Drag & Drop Firmware Update" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ажурирање фирмвера методом превуци-и-испусти" + } + } + } }, "Drag & Drop Firmware Update Documentation" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Документација ажурирања фирмвера методом превуци-и-испусти" + } + } + } }, "Drag & Drop is the recommended way to update firmware for NRF devices. If your iPhone or iPad is USB-C it will work with your regular USB-C charging cable, for lightning devices you need the Apple Lightning to USB camera adaptor." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Превуци-и-испусти је препоручен начин за ажурирање фирмвера на NRF уређајима. Ако ваш iPhone или iPad има USB-C, радиће са вашим уобичајеним USB-C каблом за пуњење. За уређаје са Lightning портом потребан је Apple Lightning to USB адаптер за камеру." + } + } + } }, "Drop Pin in Maps" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Постави ознаку на мапама" + } + } + } }, "echo" : { "localizations" : { @@ -7019,6 +9359,12 @@ "value" : "Eko" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ехо" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -7034,10 +9380,24 @@ } }, "Editing Waypoint" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уређивање путне тачке" + } + } + } }, "Elev. Gain" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Повећање надморске висине" + } + } + } }, "email.address" : { "extractionState" : "manual", @@ -7084,6 +9444,12 @@ "value" : "E-postadress" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Имејл адреса" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -7099,13 +9465,34 @@ } }, "Emoji" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Емоџи" + } + } + } }, "Empty" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Празно" + } + } + } }, "Enable Notifications" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омогући обавештења" + } + } + } }, "enabled" : { "localizations" : { @@ -7151,6 +9538,12 @@ "value" : "Aktiverad" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омогућено" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -7166,22 +9559,64 @@ } }, "Enables devices with native I2S audio output to use the RTTTL over speaker like a buzzer. T-Watch S3 and T-Deck for example have this capability." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омогућава уређајима са изворним I2S аудио излазом да користе РТТТЛ преко звучника као звучник. Т-Ватцх СКСНУМКС и Т-Децк на пример имају ову могућност." + } + } + } }, "Enables the detection sensor module, it needs to be enabled on both the node with the sensor, and any nodes that you want to receive detection sensor text messages or view the detection sensor log and chart." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омогућава модул сензора детекције. Потребно је да буде омогућен и на чвору са сензором, и на свим чворовима које желите да примате текстуалне поруке сензора детекције или да видите дневник и графикон сензора детекције." + } + } + } }, "Enables the store and forward module. Store and forward must be enabled on both client and router devices." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омогућава модул за чување и пренос. Чување и пренос мора бити омогућено на оба уређаја, клијенту и рутеру." + } + } + } }, "Enabling Ethernet will disable the bluetooth connection to the app." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омогућавање етернета ће онемогућити блутут везу са апликацијом." + } + } + } }, "Enabling WiFi will disable the bluetooth connection to the app." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омогућавање ВајФаја ће онемогућити блутут везу са апликацијом." + } + } + } }, "Encoder Press Event" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Догађај притиска енкодера" + } + } + } }, "encrypted" : { "localizations" : { @@ -7227,6 +9662,12 @@ "value" : "Krypterad" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Шифровано" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -7248,11 +9689,24 @@ "state" : "translated", "value" : "Verschlüsselt" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Шифровано" + } } } }, "Encryption Enabled" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омогућено шифровање" + } + } + } }, "Enter DFU Mode" : { "localizations" : { @@ -7261,11 +9715,24 @@ "state" : "translated", "value" : "DFÜ-Modus aktivieren" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уђите у DFU режим" + } } } }, "environment" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "окружење" + } + } + } }, "Environment" : { "localizations" : { @@ -7274,11 +9741,24 @@ "state" : "translated", "value" : "Umgebung" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Окружење" + } } } }, "Environment Metrics Log" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дневник метрика окружења" + } + } + } }, "Erase all app data?" : { "localizations" : { @@ -7287,6 +9767,12 @@ "state" : "translated", "value" : "Alle App-Daten löschen?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Избрисати све податке апликације?" + } } } }, @@ -7297,32 +9783,94 @@ "state" : "translated", "value" : "Alle Geräte- und App-Daten löschen?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Избрисати све податке уређаја и апликације?" + } } } }, "Error: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Грешка: %@" + } + } + } }, "ESP 32 OTA update is a work in progress, click the button below to send your device a reboot into ota admin message." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ESP32 OTA ажурирање је у развоју, кликните на дугме испод да бисте послали уређају поруку за поновно покретање у OTA администраторски режим." + } + } + } }, "ESP32 Device Firmware Update" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ажурирање фирмвера за ESP32 уређај" + } + } + } }, "Ethernet Options" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Етернет опције" + } + } + } }, "Exchange Positions" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Размени локације" + } + } + } }, "Expire" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Истиче" + } + } + } }, "Expires" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Истиче" + } + } + } }, "Expires: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Истиче: %@" + } + } + } }, "export" : { "localizations" : { @@ -7368,6 +9916,12 @@ "value" : "Export" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Извоз" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -7426,6 +9980,12 @@ "value" : "Extern Notifikation" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Спољна обавештења" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -7484,6 +10044,12 @@ "value" : "Konfiguration av Extern Notifikation" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавање спољних обавештења" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -7505,6 +10071,12 @@ "state" : "translated", "value" : "Werkseinstellungen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ресетовање на фабричка подешавања" + } } } }, @@ -7515,17 +10087,44 @@ "state" : "translated", "value" : "Gerät und App auf Werkseinstellungen zurücksetzen?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вратите уређај и апликацију на фабричка подешавања?" + } } } }, "Failed to encode message content" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Неуспело кодирање садржаја поруке" + } + } + } }, "Failed to get a valid position to exchange" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добијање важеће позиције за размену није успело" + } + } + } }, "Failed to get a valid position to exchange." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добијање важеће позиције за размену није успело." + } + } + } }, "Favorite" : { "localizations" : { @@ -7534,6 +10133,12 @@ "state" : "translated", "value" : "Favorit" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омиљени" + } } } }, @@ -7544,11 +10149,24 @@ "state" : "translated", "value" : "Favoriten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омиљени" + } } } }, "Favorites and nodes with recent messages show up at the top of the contact list." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омиљени чворови и чворови са недавно примљеним порукама појављују се на врху листе контаката." + } + } + } }, "Fetch the latest position of a cetain node" : { "localizations" : { @@ -7557,14 +10175,34 @@ "state" : "translated", "value" : "Letzte Position eines Knotens holen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Преузмите најновију позицију одређеног чвора" + } } } }, "Fifteen Minutes" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Петнаест минута" + } + } + } }, "File Storage" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Складиште података" + } + } + } }, "Find a contact" : { "localizations" : { @@ -7573,6 +10211,12 @@ "state" : "translated", "value" : "Kontakt suchen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пронађи контакт" + } } } }, @@ -7583,6 +10227,12 @@ "state" : "translated", "value" : "Einen Knoten finden" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пронађи чвор" + } } } }, @@ -7630,6 +10280,12 @@ "value" : "Avsluta" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Заврши" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -7651,11 +10307,24 @@ "state" : "translated", "value" : "Firmware" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Фирмвер" + } } } }, "Firmware update docs" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Документи за ажурирање фирмвера" + } + } + } }, "Firmware Updates" : { "localizations" : { @@ -7664,6 +10333,12 @@ "state" : "translated", "value" : "Firmwareaktualisierungen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ажурирања фирмвера" + } } } }, @@ -7711,6 +10386,12 @@ "value" : "Firmwareversion" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Верзија фирмвера" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -7770,6 +10451,12 @@ "value" : "Okänd Firmwareversion upptäckt, kan inte ansluta till enheten." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Откривена је неподржана верзија фирмвера, није могуће повезати са уређајем." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -7785,7 +10472,14 @@ } }, "First heard" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прво откривање" + } + } + } }, "Five Minutes" : { "localizations" : { @@ -7794,20 +10488,54 @@ "state" : "translated", "value" : "Fünf Minuten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пет минута" + } } } }, "Fixed Position" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Фиксна локација" + } + } + } }, "Flip Screen" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Окрени екран" + } + } + } }, "Flip screen vertically" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Окрени екран вертикално" + } + } + } }, "For all Mqtt functionality other than the map report you must also set uplink and downlink for each channel you want to bridge over Mqtt." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "За сву MQTT функционалност осим извештаја на мапи, такође морате подесити uplink и downlink за сваки канал који желите да прележете преко MQTT-а.”" + } + } + } }, "For everyone" : { "localizations" : { @@ -7816,6 +10544,12 @@ "state" : "translated", "value" : "Für alle" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "За све" + } } } }, @@ -7826,6 +10560,12 @@ "state" : "translated", "value" : "Für mich" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "За мене" + } } } }, @@ -7836,20 +10576,54 @@ "state" : "translated", "value" : "Frequenz" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Фреквенција" + } } } }, "Frequency Override" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Измена фреквенције" + } + } + } }, "Frequency Slot" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Фреквенцијски слот" + } + } + } }, "Friendly name" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пријатељски назив" + } + } + } }, "Friendly name used to format message sent to mesh. Example: A name \"Motion\" would result in a message \"Motion detected\"" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пријатељски назив који се користи за форматирање поруке послате на мрежу. На пример: Назив „Motion” довео би до поруке „Motion detected”." + } + } + } }, "gas" : { "extractionState" : "manual", @@ -7896,6 +10670,12 @@ "value" : "Gas" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Гас" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -7949,6 +10729,12 @@ "value" : "Gasmotstånd" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Отпорност на гас" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8007,6 +10793,12 @@ "value" : "Generera QR-kod" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Генерисање QR кода" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8022,7 +10814,14 @@ } }, "Get custom waterproof solar and detection sensor router nodes, aluminium desktop nodes and rugged handsets." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Набавите прилагођене водоотпорне соларне и детекционе сензорске рутер чворове, алуминијумске десктоп чворове и издржљиве мобилне уређаје." + } + } + } }, "Get Node Position" : { "localizations" : { @@ -8031,47 +10830,144 @@ "state" : "translated", "value" : "Knotenposition ermitteln" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добави позицију чвора" + } } } }, "Get NRF DFU from the App Store" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Преузмите NRF DFU из App Store-а" + } + } + } }, "Get the latest alpha firmware" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добави најновији алфа фирмвер" + } + } + } }, "Get the latest stable firmware" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добави најновији стабилни фирмвер" + } + } + } }, "GPIO" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPIO" + } + } + } }, "GPIO Output Duration" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Трајање GPIO излаза" + } + } + } }, "GPIO pin for rotary encoder A port." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPIO пин за A порт ротационог енкодера." + } + } + } }, "GPIO pin for rotary encoder B port." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPIO пин за Б порт ротационог енкодера." + } + } + } }, "GPIO pin for rotary encoder Press port." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPIO пин за порт клика ротационог енкодера." + } + } + } }, "GPIO Pin to monitor" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPIO пин за надгледање" + } + } + } }, "GPS EN GPIO" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPS EN GPIO" + } + } + } }, "GPS Format" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPS формат" + } + } + } }, "GPS Receive GPIO" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPS пријем GPIO" + } + } + } }, "GPS Transmit GPIO" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPS предаја GPIO" + } + } + } }, "gpsformat.dec" : { "extractionState" : "migrated", @@ -8118,6 +11014,12 @@ "value" : "Decimalgrader" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Формат децималних степени" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8177,6 +11079,12 @@ "value" : "Grader Minuter Sekunder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Степени Минути Секунде" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8236,6 +11144,12 @@ "value" : "Militärt rutnätsreferenssystem" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Војни референтни систем мреже" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8295,6 +11209,12 @@ "value" : "Öppen Platskod (även känd som Pluskoder)" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Отворени код локације (тј. Плус кодови)" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8354,6 +11274,12 @@ "value" : "Ordnance Survey Rutnätsreferens" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Референца мреже Орданс Сурвеја" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8413,6 +11339,12 @@ "value" : "Universal Transversal Mercator" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Универзални трансверзални Меркаторов пројекат" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8465,6 +11397,12 @@ "state" : "translated", "value" : "Inaktiverad" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Онемогућен" + } } } }, @@ -8506,6 +11444,12 @@ "state" : "translated", "value" : "Aktiverad" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Омогућен" + } } } }, @@ -8541,6 +11485,12 @@ "state" : "translated", "value" : "Inte närvarande" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Није пристуно" + } } } }, @@ -8551,20 +11501,54 @@ "state" : "translated", "value" : "Gruppennachricht" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Групна порука" + } } } }, "Gusts %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Јаки удари ветра %@" + } + } + } }, "Hardware" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Хардвер" + } + } + } }, "Heading" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Смер" + } + } + } }, "Heading: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Смер: %@" + } + } + } }, "heard" : { "extractionState" : "migrated", @@ -8611,6 +11595,12 @@ "value" : "Hörd" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Чуо" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8670,6 +11660,12 @@ "value" : "Senast Hörd" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прво откривање" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8685,13 +11681,34 @@ } }, "Help with App Development" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Помози при развоју апликације" + } + } + } }, "Hide alerts" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сакриј упозорења" + } + } + } }, "Hide Alerts" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сакриј алертове" + } + } + } }, "HIGH" : { "localizations" : { @@ -8700,14 +11717,34 @@ "state" : "translated", "value" : "HOCH" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ВИСОК" + } } } }, "History Return Max" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Максимални повратак историје" + } + } + } }, "History Return Window" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Временски прозор поврата историје" + } + } + } }, "Hops Away" : { "localizations" : { @@ -8716,6 +11753,12 @@ "state" : "translated", "value" : "Hops Entfernt" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Скокови удаљености" + } } } }, @@ -8726,6 +11769,12 @@ "state" : "translated", "value" : "Hops Entfernt %d" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Удаљено %d скокова" + } } } }, @@ -8736,6 +11785,12 @@ "state" : "translated", "value" : "Hops Entfernt:" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Скокови удаљености:" + } } } }, @@ -8746,6 +11801,12 @@ "state" : "translated", "value" : "Hops Entfernt: %d" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Скокови удаљености: %d" + } } } }, @@ -8756,29 +11817,84 @@ "state" : "translated", "value" : "Stunde" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сат" + } } } }, "Hourly Duty Cycle" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Натпросечни циклус дужности по сату" + } + } + } }, "How long the screen remains on after the user button is pressed or messages are received." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Колико дуго екран остаје укључен након притиска корисничког дугмета или пријема порука." + } + } + } }, "How often device metrics are sent out over the mesh. Default is 30 minutes." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Колико често се метрике уређаја шаљу преко мреже. Подразумевано је 30 минута." + } + } + } }, "How often power metrics are sent out over the mesh. Default is 30 minutes." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Колико често се метрике снаге шаљу преко мреже. Подразумевано је 30 минута." + } + } + } }, "How often sensor metrics are sent out over the mesh. Default is 30 minutes." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Колико често се метрике сензора шаљу преко мреже. Подразумевано је 30 минута." + } + } + } }, "How often should we try to get a GPS position." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Колико често треба да покушамо да добијемо GPS позицију." + } + } + } }, "How often to send detection sensor state to mesh regardless of detection. Default is Never." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Колико често да пошаљете стање сензора детекције у мрежу, без обзира на детекцију. Подразумевано је да се не шаље никада." + } + } + } }, "How to update Firmware" : { "localizations" : { @@ -8787,11 +11903,24 @@ "state" : "translated", "value" : "Wie wird die Firmware aktualisiert" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Како да ажурираш фирмвер" + } } } }, "Hum" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Влажност" + } + } + } }, "Humidity" : { "localizations" : { @@ -8800,6 +11929,12 @@ "state" : "translated", "value" : "Luftfeuchtigkeit" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Влажност" + } } } }, @@ -8810,6 +11945,12 @@ "state" : "translated", "value" : "LUFTFEUCHTIGKEIT" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ВЛАЖНОСТ" + } } } }, @@ -8858,6 +11999,12 @@ "value" : "Hybrid" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Хибридни" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8917,6 +12064,12 @@ "value" : "Hybrid Flygöversikt" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Хибридни надлет" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -8932,37 +12085,134 @@ } }, "IAQ" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "IAQ" + } + } + } }, "IAQ " : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "IAQ" + } + } + } }, "IAQ %lld" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "IAQ %lld" + } + } + } }, "Icon" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Иконица" + } + } + } }, "If DOP is set, use HDOP / VDOP values instead of PDOP" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ако је DOP постављен, користите HDOP / VDOP вредности уместо PDOP-а" + } + } + } }, "If enabled, the 'output' Pin will be pulled active high, disabled means active low." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ако је омогућено, 'output' пин ће бити активиран на високом нивоу, а ако је онемогућено, биће активиран на ниском нивоу." + } + } + } }, "If it is hard to access your device's reset button enter DFU mode here." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ако је тешко приступити дугмету за ресетовање уређаја, уђите у DFU режим овде." + } + } + } }, "If set, any packets you send will be echoed back to your device." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ако је подешено, сви пакети које пошаљете ће бити враћени (ехо) назад на ваш уређај." + } + } + } }, "If the default region topic is too busy you can choose a more local topic." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ако је подразумевана тема региона превише заузета можете изабрати више локалну тему." + } + } + } }, "Ignore MQTT" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Игнориши MQTT" + } + } + } + }, + "Ignore Node" : { + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Игнориши чвор" + } + } + } + }, + "Ignored" : { + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Игнорисан" + } + } + } }, "Import Route" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Увозна рута" + } + } + } }, "include" : { "localizations" : { @@ -9008,6 +12258,12 @@ "value" : "Inkludera" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Укључите" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9023,7 +12279,7 @@ } }, "incomplete" : { - "extractionState" : "migrated", + "extractionState" : "manual", "localizations" : { "de" : { "stringUnit" : { @@ -9061,6 +12317,12 @@ "value" : "Incomplete" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Недовршен" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9076,10 +12338,24 @@ } }, "Indoor Air Quality" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Квалитет ваздуха у затвореном простору" + } + } + } }, "Indoor Air Quality (IAQ)" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Квалитет ваздуха у затвореном простору (IAQ)" + } + } + } }, "inputevent.back" : { "extractionState" : "migrated", @@ -9126,6 +12402,12 @@ "value" : "Bakåt" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Назад" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9185,6 +12467,12 @@ "value" : "Avbryt" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Откажи" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9244,6 +12532,12 @@ "value" : "Ner" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Доле" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9303,6 +12597,12 @@ "value" : "Vänster" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Лево" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9362,6 +12662,12 @@ "value" : "Ingen" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ништа" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9421,6 +12727,12 @@ "value" : "Höger" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Десно" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9480,6 +12792,12 @@ "value" : "Välj" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Изабери" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9539,6 +12857,12 @@ "value" : "Upp" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Горе" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9554,7 +12878,14 @@ } }, "Inputs" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Улази" + } + } + } }, "interval.eighteen.hours" : { "extractionState" : "migrated", @@ -9601,6 +12932,12 @@ "value" : "Arton Timmar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Осамнаест сати" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9618,6 +12955,12 @@ "interval.eventytwo.hours" : { "extractionState" : "manual", "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Двадесет и два сата" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9677,6 +13020,12 @@ "value" : "Femton Minuter" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Петнаест минута" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9736,6 +13085,12 @@ "value" : "Femton Sekunder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Петнаест секунди" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9795,6 +13150,12 @@ "value" : "Fem Timmar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пет сати" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9854,6 +13215,12 @@ "value" : "Fem Minuter" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пет минута" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9913,6 +13280,12 @@ "value" : "Fem Sekunder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пет секунди" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -9971,6 +13344,12 @@ "state" : "translated", "value" : "Fyrtioåtta Timmar" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Четртесет и осам сати" + } } } }, @@ -10019,6 +13398,12 @@ "value" : "Fyrtiofem Sekunder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Четрдесет и пет секунди" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10078,6 +13463,12 @@ "value" : "Fyra Timmar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Четири сата" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10137,6 +13528,12 @@ "value" : "Fyra Sekunder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Четири секунде" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10196,6 +13593,12 @@ "value" : "En Timme" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Један сат" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10255,6 +13658,12 @@ "value" : "En Minut" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Један минут" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10314,6 +13723,12 @@ "value" : "En Sekund" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Један секунд" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10372,6 +13787,12 @@ "state" : "translated", "value" : "Sjuttiotvå Timmar" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Седамдесет и два сата" + } } } }, @@ -10420,6 +13841,12 @@ "value" : "Sex Timmar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Шест сати" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10479,6 +13906,12 @@ "value" : "Tio Minuter" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Десет минута" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10538,6 +13971,12 @@ "value" : "Tio Sekunder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Десет секунди" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10597,6 +14036,12 @@ "value" : "Trettio Minuter" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пола сата" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10656,6 +14101,12 @@ "value" : "Trettio Sekunder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тридесет секунди" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10715,6 +14166,12 @@ "value" : "Trettiosex Timmar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тридесет и шест сати" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10774,6 +14231,12 @@ "value" : "Tre Timmar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Три сата" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10833,6 +14296,12 @@ "value" : "Tre Sekunder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Три секунде" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10892,6 +14361,12 @@ "value" : "Tolv Timmar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дванаест сати" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -10951,6 +14426,12 @@ "value" : "Tjugo Sekunder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Двадесет секунди" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11010,6 +14491,12 @@ "value" : "Tjugofem Sekunder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Двадесет пет секунди" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11069,6 +14556,12 @@ "value" : "Tjugofyra Timmar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Двадесет четири сата" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11128,6 +14621,12 @@ "value" : "Två Timmar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Два сата" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11187,6 +14686,12 @@ "value" : "Två Minuter" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Два минута" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11246,6 +14751,12 @@ "value" : "Två Sekunder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Две секунде" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11260,28 +14771,42 @@ } } }, - "interval.tyeight.hours" : { + "inverted.top.bar.for.2.color.display" : { "extractionState" : "manual", "localizations" : { - "zh-Hans" : { + "en" : { "stringUnit" : { "state" : "translated", - "value" : "四十八小时小时" + "value" : "Inverted top bar for 2 Color display" } }, - "zh-Hant-TW" : { + "sr" : { "stringUnit" : { "state" : "translated", - "value" : "四十八小时小時" + "value" : "Обрнута горња трака за екран у 2 боје" } } } }, "JSON Enabled" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "JSON омогућен" + } + } + } }, "JSON mode is a limited, unencrypted MQTT output for locally integrating with home assistant" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "JSON режим је ограничен, нешифрован MQTT излаз за локалну интеграцију са Home Assistant-ом." + } + } + } }, "Key" : { "localizations" : { @@ -11290,11 +14815,24 @@ "state" : "translated", "value" : "Taste" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Кључ" + } } } }, "Key Mapping" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мапирање кључева" + } + } + } }, "Key Size" : { "localizations" : { @@ -11303,6 +14841,12 @@ "state" : "translated", "value" : "Tastengröße" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Величина кључа" + } } } }, @@ -11351,6 +14895,12 @@ "value" : "Tangentbordstyp" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тип тастатуре" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11372,6 +14922,12 @@ "state" : "translated", "value" : "Zuletzt gehört" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Последње откривање" + } } } }, @@ -11382,29 +14938,84 @@ "state" : "translated", "value" : "Breitengrad" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ширина" + } } } }, "LED Heartbeat" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "LED срчани откуцаји" + } + } + } }, "LED State" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "LED статус" + } + } + } }, "Legacy Administration" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Стари начин администрације" + } + } + } }, "Licensed Operator" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Лиценцирани оператор" + } + } + } }, "Limit all periodic broadcast intervals especially telemetry and position. If you need to increase hops, do it on nodes at the edges, not the ones in the middle. MQTT is not advised when you are duty cycle restricted because the gateway node is then doing all the work." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ограничите све периодичне интервале емитовања, посебно телеметрију и позицију. Ако је потребно повећати број скокова, то радите на чворовима на ивицама, а не на оним у средини. MQTT није препоручен када сте ограничени циклусом дужности јер у том случају чвор-рутер ради сав посао." + } + } + } }, "Line Series" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Линијска серија" + } + } + } }, "Loading Logs. . ." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Учитавам логове. . ." + } + } + } }, "Location" : { "localizations" : { @@ -11413,6 +15024,12 @@ "state" : "translated", "value" : "Standort" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Локација:" + } } } }, @@ -11423,6 +15040,12 @@ "state" : "translated", "value" : "Standrot:" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Локација:" + } } } }, @@ -11433,11 +15056,24 @@ "state" : "translated", "value" : "Gesperrt" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Закључан" + } } } }, "Log Levels" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нивои логова" + } + } + } }, "log.category" : { "localizations" : { @@ -11477,6 +15113,12 @@ "value" : "Category" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Категорија" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11529,6 +15171,12 @@ "value" : "Level" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ниво" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11581,6 +15229,12 @@ "value" : "Message" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Порука" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11634,6 +15288,12 @@ "value" : "Process" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Процес" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11687,6 +15347,12 @@ "value" : "Subsystem" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подсистем" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11739,6 +15405,12 @@ "value" : "Time" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Време" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11797,6 +15469,12 @@ "value" : "Loggning" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Логовање" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11812,10 +15490,24 @@ } }, "Logs" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Логови" + } + } + } }, "Logs:" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Логови:" + } + } + } }, "Long Name" : { "localizations" : { @@ -11824,6 +15516,12 @@ "state" : "translated", "value" : "Langer Name" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дуго име" + } } } }, @@ -11834,11 +15532,24 @@ "state" : "translated", "value" : "Langer Name: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дуго име: %@" + } } } }, "Long press to favorite or mute the contact or delete a conversation." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дугим притиском на чвор из листе означите као омиљени или искључите звук контакта или обришите разговор." + } + } + } }, "Longitude" : { "localizations" : { @@ -11847,6 +15558,12 @@ "state" : "translated", "value" : "Längengrad" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дужина" + } } } }, @@ -11894,6 +15611,12 @@ "value" : "LoRa" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "LoRA" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11952,6 +15675,12 @@ "value" : "LoRa Konfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "LoRA подешавања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -11966,11 +15695,93 @@ } } }, + "lora.signal.strength.bad" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Bad" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Лош" + } + } + } + }, + "lora.signal.strength.fair" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fair" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прихватљив" + } + } + } + }, + "lora.signal.strength.good" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Good" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добар" + } + } + } + }, + "lora.signal.strength.none" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "None" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Без" + } + } + } + }, "LOW" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "НИЗАК" + } + } + } }, "Managed Device" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Управљани уређај" + } + } + } }, "map" : { "localizations" : { @@ -12016,6 +15827,12 @@ "value" : "Mesh Karta" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мапа меша" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12037,17 +15854,44 @@ "state" : "translated", "value" : "Kartenoptionen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опције мапе" + } } } }, "Map Publish Interval" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Интервал објављивања мапе" + } + } + } }, "Map Report" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Извештај мапе" + } + } + } }, "Map Tile Data" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подаци плочица мапе" + } + } + } }, "map.centering" : { "extractionState" : "manual", @@ -12088,6 +15932,12 @@ "value" : "Centreringsläge" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Режим центрирања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12141,6 +15991,12 @@ "value" : "Automatisk Centrering" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Аутоматско поновно центрирање" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12194,6 +16050,12 @@ "value" : "Radera Alla Kartplattor" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Обриши све плочице мапе" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12253,6 +16115,12 @@ "value" : "Standardtyp" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подразумевани тип" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12312,6 +16180,12 @@ "value" : "Använd Äldre Mesh Karta" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Користите легаси мрежну мапу" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12371,6 +16245,12 @@ "value" : "Spårningsläge för användare" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мод праћења корисника" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12430,6 +16310,12 @@ "value" : "Följ" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прати" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12489,6 +16375,12 @@ "value" : "Följ med riktning" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прати са правцем" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12548,6 +16440,12 @@ "value" : "Ingen" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ни један" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12563,7 +16461,14 @@ } }, "Mesh activity update" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ажурирање активности мреже" + } + } + } }, "mesh.live.activity" : { "localizations" : { @@ -12609,6 +16514,12 @@ "value" : "Mesh Live Aktivitet" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Активности мреже уживо" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12667,6 +16578,12 @@ "value" : "Mesh-logg" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Логови мреже" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12720,6 +16637,12 @@ "value" : "Konfiguration för omgivningsbelysningsmodulen mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Примљена конфигурација модула амбијенталног осветљења: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12779,6 +16702,12 @@ "value" : "Bluetooth-konfiguration mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Примљена конфигурација блутута: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12832,6 +16761,12 @@ "value" : "Konfiguration för modulen med fördefinierade meddelanden mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација модула за унапред припремљене поруке примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12885,6 +16820,12 @@ "value" : "Begärda meddelanden för modulen med fördefinierade meddelanden för nod: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтеване поруке модула за унапред припремљене поруке за чвор: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12938,6 +16879,12 @@ "value" : "Mottagna meddelanden för fördefinierade meddelanden För: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Примљене поруке за унапред припремљене поруке за: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -12991,6 +16938,12 @@ "value" : "Skickade en kanal för: %@ Kanalindex %d" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Послат је канал за: %@ Индекс канала %d" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13044,6 +16997,12 @@ "value" : "Konfiguration för detektionssensormodulen mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација модула за сензор детекције примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13103,6 +17062,12 @@ "value" : "Enhetskonfiguration mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Примљена конфигурација уређаја: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13162,6 +17127,12 @@ "value" : "Metadata för enhet mottagen från: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Метаподаци уређаја примљени од: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13221,6 +17192,12 @@ "value" : "Begär metadata för enhet för %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтевање метаподатака уређаја за %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13280,6 +17257,12 @@ "value" : "Skärmkonfiguration mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Примљена конфигурација приказа: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13333,6 +17316,12 @@ "value" : "Konfiguration för modulen för externa notifikationer mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација модула за екстерне нотификације примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13392,6 +17381,12 @@ "value" : "LoRa-konfiguration mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација LoRA примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13451,6 +17446,12 @@ "value" : "Skickade en LoRa.Konfiguration för: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Послата LoRA конфигурација за: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13510,6 +17511,12 @@ "value" : "MQTT-modulkonfiguration mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација MQTT модула примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13569,6 +17576,12 @@ "value" : "Min info mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Моје информације примљене: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13628,6 +17641,12 @@ "value" : "Nätverkskonfiguration mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација мреже примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13687,6 +17706,12 @@ "value" : "Nodinformation mottagen för: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Информације о чвору примљене за: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13740,6 +17765,12 @@ "value" : "PAX-räknarmeddelande mottaget från: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Порука PAX бројача примљена од: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13774,6 +17805,12 @@ "state" : "translated", "value" : "PAX-räknarkonfiguration mottagen: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација PAX бројача примљена: %@" + } } } }, @@ -13822,6 +17859,12 @@ "value" : "Positionskonfiguration mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација позиције примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13881,6 +17924,12 @@ "value" : "Positionspaket mottaget från nod: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пакет позиције примљен од чвора: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -13915,6 +17964,12 @@ "state" : "translated", "value" : "Strömkonfiguration mottagen: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација напајања примљена: %@" + } } } }, @@ -13963,6 +18018,12 @@ "value" : "Konfiguration för räckviddstestmodulen mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација модула теста домета примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14022,6 +18083,12 @@ "value" : "Konfiguration för RTTTL-ringsignal mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација RTTTL мелодије примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14081,6 +18148,12 @@ "value" : "Routing mottagen för RequestID: %@ Ack Status: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Рутирање примљено за ИД захтева: %@ Статус потврде: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14140,6 +18213,12 @@ "value" : "Seriekonfigurationsmodul mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација серијског модула примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14199,6 +18278,12 @@ "value" : "Skickade ett positionspaket från Apple-enhetens GPS till nod: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Позициони пакет послат са Епл уређаја на чвор: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14252,6 +18337,12 @@ "value" : "Konfiguration för Store & Forward-modulen mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација модула за чување и прослеђивање примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14311,6 +18402,12 @@ "value" : "Telemetrimodulkonfiguration mottagen: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација модула телеметрије примљена: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14370,6 +18467,12 @@ "value" : "Telemetri mottagen för: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Телеметрија примљена за: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14429,6 +18532,12 @@ "value" : "Meddelande mottaget från textmeddelandeappen." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Порука примљена из апликације за текстуалне поруке." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14488,6 +18597,12 @@ "value" : "Misslyckades med att skicka meddelande, inte korrekt ansluten till %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Слање поруке није успело, није правилно повезано са: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14547,6 +18662,12 @@ "value" : "Skickade meddelande %@ från %@ till %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Порука послата %@ са %@ на %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14606,6 +18727,12 @@ "value" : "Spårruttförfrågan skickad till nod: %@ mottogs direkt." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтев за тражење путања послат на чвор: %@ је примљен директно." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14665,6 +18792,12 @@ "value" : "Spårruttförfrågan returnerade: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтев за тражење путања враћен: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14724,6 +18857,12 @@ "value" : "Skickade en spårruttförfrågan till nod: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтев за тражење путања послат на чвор: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14777,6 +18916,12 @@ "value" : "Utfärdar Want Config till %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Издавање захтева за конфигурацију на: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14836,6 +18981,12 @@ "value" : "Vägpunktspaket mottaget från nod: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пакет са тачкама пута примљен од чвора: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14895,6 +19046,12 @@ "value" : "Skickade en vägpunktspaket från: %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пакет са тачкама пута послат од: %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14916,11 +19073,24 @@ "state" : "translated", "value" : "Meshtastic Knoten %@ hat Kanäle mit dir geteilt" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Meshtastic чвор %@ је поделио канале са вама." + } } } }, "Meshtastic® Copyright Meshtastic LLC" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Meshtastic® Ауторска права Meshtastic LLC" + } + } + } }, "message" : { "localizations" : { @@ -14966,6 +19136,12 @@ "value" : "Meddelande" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Порука" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -14987,6 +19163,12 @@ "state" : "translated", "value" : "Nachricht" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Порука" + } } } }, @@ -14997,11 +19179,24 @@ "state" : "translated", "value" : "Nachrichteninhalt überschreitet 200 Bytes." } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Садржај поруке премашује 200 бајтова." + } } } }, "Message Status Options" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опције статуса поруке" + } + } + } }, "message.details" : { "localizations" : { @@ -15047,6 +19242,12 @@ "value" : "Meddelandedetaljer" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Детаљи поруке" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15105,6 +19306,12 @@ "value" : "Meddelanden" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поруке" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15126,6 +19333,12 @@ "state" : "translated", "value" : "Nachrichten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поруке" + } } } }, @@ -15136,6 +19349,12 @@ "state" : "translated", "value" : "Nachrichten getrennt mit |" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поруке се раздвајају са |" + } } } }, @@ -15149,6 +19368,12 @@ "state" : "translated", "value" : "Minimum Distanz" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Минимум раздаљине" + } } } }, @@ -15159,14 +19384,34 @@ "state" : "translated", "value" : "Minimum Intervall" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Минимални интервал" + } } } }, "Minimum time between detection broadcasts" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Минимално време између емитовања детекције" + } + } + } }, "Mininum time between detection broadcasts. Default is 45 seconds." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Минимално време између емитовања детекције. Подразумевано је 45 секунди." + } + } + } }, "mode" : { "localizations" : { @@ -15212,6 +19457,12 @@ "value" : "Läge" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мод" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15226,6 +19477,16 @@ } } }, + "Model" : { + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Модел" + } + } + } + }, "module.configuration" : { "localizations" : { "de" : { @@ -15270,6 +19531,12 @@ "value" : "Modulkonfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација модула" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15328,6 +19595,12 @@ "value" : "MQTT" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "MQTT" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15343,7 +19616,14 @@ } }, "MQTT" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "MQTT" + } + } + } }, "mqtt.clientproxy" : { "localizations" : { @@ -15389,6 +19669,12 @@ "value" : "MQTT-klientproxy" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "MQTT посредник клијента" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15447,6 +19733,12 @@ "value" : "MQTT-konfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "MQTT подешавања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15506,6 +19798,12 @@ "value" : "Anslut till MQTT" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Повежи се на MQTT" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15565,6 +19863,12 @@ "value" : "Koppla från MQTT" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Развежи се од MQTT" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15623,6 +19927,12 @@ "value" : "Användarnamn" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Корисничко име" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15638,10 +19948,24 @@ } }, "Must be a single emoji" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мора бити један емотикон" + } + } + } }, "Nag timeout" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Период чекања је истекао" + } + } + } }, "name" : { "localizations" : { @@ -15687,6 +20011,12 @@ "value" : "Namn" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Име" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15708,6 +20038,12 @@ "state" : "translated", "value" : "Name" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Име" + } } } }, @@ -15718,11 +20054,24 @@ "state" : "translated", "value" : "Name muss kürzer als 30 Bytes sein" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Име мора бити краће од 30 бајтова" + } } } }, "Nearby Topics" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Теме у окружењу" + } + } + } }, "network" : { "localizations" : { @@ -15768,6 +20117,12 @@ "value" : "Nätverk" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мрежа" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15783,10 +20138,24 @@ } }, "Network Status Orange" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Статус мреже: Наранџаст" + } + } + } }, "Network Status Red" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Статус мреже: Црвен" + } + } + } }, "network.config" : { "localizations" : { @@ -15832,6 +20201,12 @@ "value" : "Nätverkskonfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација мреже" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15853,6 +20228,34 @@ "state" : "translated", "value" : "Nie" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Никада" + } + } + } + }, + "New Node" : { + "extractionState" : "manual", + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нови чвор" + } + } + } + }, + "New Node has been discovered" : { + "extractionState" : "manual", + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Откривен је нови чвор" + } } } }, @@ -15863,6 +20266,12 @@ "state" : "translated", "value" : "Neuere Firmware ist verfügbar" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нова верзија фирмвера је доступна" + } } } }, @@ -15873,14 +20282,34 @@ "state" : "translated", "value" : "Kein verbundener Knoten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема повезаног чвора" + } } } }, "No Device Metrics" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема метрика уређаја." + } + } + } }, "No Environment Metrics" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема метрика окружења" + } + } + } }, "No Positions" : { "localizations" : { @@ -15889,6 +20318,12 @@ "state" : "translated", "value" : "Keine Positionen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема позиција" + } } } }, @@ -15937,6 +20372,12 @@ "value" : "Inga Meshtastic-noder hittades" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема пронађених Мештастик чворова" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -15958,6 +20399,12 @@ "state" : "translated", "value" : "Knoten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Чвор" + } } } }, @@ -15968,6 +20415,12 @@ "state" : "new", "value" : "Node Core Data Backup %1$@/%2$@ - %3$@ - %4$@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Резервна копија података језгра чвора %1$@/%2$@ - %3$@ - %4$@" + } } } }, @@ -15978,6 +20431,12 @@ "state" : "translated", "value" : "Knoten hat keine Position" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Чвор нема позиције" + } } } }, @@ -15988,11 +20447,24 @@ "state" : "translated", "value" : "Knoten Historie" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Историја чвора" + } } } }, "Node Info Broadcast Interval" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Интервал емитовања информација о чвору" + } + } + } }, "Node Map" : { "localizations" : { @@ -16001,6 +20473,12 @@ "state" : "translated", "value" : "Knotenkarte" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мапа чворова" + } } } }, @@ -16011,6 +20489,12 @@ "state" : "translated", "value" : "Knotennummer" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Број чвора" + } } } }, @@ -16059,6 +20543,12 @@ "value" : "upp till %@ bort" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "удаљено до максималних %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -16111,6 +20601,12 @@ "value" : "Noder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Чворови" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -16170,6 +20666,12 @@ "value" : "Noder (%@)" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Чворови (%@)" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -16185,7 +20687,14 @@ } }, "Not a valid route file" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Није валидна датотека путања" + } + } + } }, "not.connected" : { "localizations" : { @@ -16231,6 +20740,12 @@ "value" : "Ingen enhet ansluten" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема повезаних уређаја" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -16252,6 +20767,12 @@ "state" : "translated", "value" : "Knoten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Белешке" + } } } }, @@ -16262,6 +20783,12 @@ "state" : "translated", "value" : "Anzahl: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Број: %@" + } } } }, @@ -16272,6 +20799,12 @@ "state" : "translated", "value" : "Anzahl Hops" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Број хопова" + } } } }, @@ -16282,6 +20815,12 @@ "state" : "translated", "value" : "Anzahl Einträge" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Број записа" + } } } }, @@ -16292,6 +20831,12 @@ "state" : "translated", "value" : "Anzahl Satelliten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Број сателита" + } } } }, @@ -16340,6 +20885,12 @@ "value" : "Siffror och skiljetecken" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Бројеви и интерпункција" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -16399,6 +20950,12 @@ "value" : "Av" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Искључен" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -16458,6 +21015,12 @@ "value" : "Offline" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ван мреже" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -16479,11 +21042,24 @@ "state" : "translated", "value" : "Ok" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ОК" + } } } }, "Ok to MQTT" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Позитиван за MQTT" + } + } + } }, "OLED Type" : { "localizations" : { @@ -16492,6 +21068,12 @@ "state" : "translated", "value" : "OLED Typ" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тип OLED-а" + } } } }, @@ -16540,6 +21122,12 @@ "value" : "Endast vid uppstart" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Само при покретању" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -16555,7 +21143,14 @@ } }, "Onboarding for licensed operators requires firmware 2.0.20 or greater. Make sure to refer to your local regulations and contact the local amateur frequency coordinators with questions." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Увођење за лиценциране оператере захтева фирмвер верзије 2.0.20 или новије. Уверите се да се придржавате локалних прописа и обратите се локалним координаторима за аматерске фреквенције са питањима." + } + } + } }, "One Hour" : { "localizations" : { @@ -16564,6 +21159,12 @@ "state" : "translated", "value" : "Eine Stunde" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Један сат" + } } } }, @@ -16574,6 +21175,12 @@ "state" : "translated", "value" : "Eine Minute" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Једна минута" + } } } }, @@ -16584,6 +21191,12 @@ "state" : "translated", "value" : "Online" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "На мрежи" + } } } }, @@ -16594,14 +21207,51 @@ "state" : "translated", "value" : "Einstellungen öffnen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Отвори подешавања" + } + } + } + }, + "optimized.for.2.color.displays" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Optimized for 2 color displays" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Оптимизовано за двобојне дисплеје" + } } } }, "Optional fields to include when assembling position messages. the more fields are included, the larger the message will be - leading to longer airtime and a higher risk of packet loss" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опциони поља за укључивање при склапању порука о позицији. Што више поља је укључено, порука ће бити већа, што доводи до дужег времена емитовања и већег ризика од губитка пакета" + } + } + } }, "Optional GPIO" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опциони GPIO" + } + } + } }, "options" : { "localizations" : { @@ -16647,6 +21297,12 @@ "value" : "Alternativ" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опције" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -16668,35 +21324,104 @@ "state" : "translated", "value" : "Optionen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опције" + } } } }, "OS Log Entry Details" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Детаљи уноса ОС дневника" + } + } + } }, "OTA Updates are not supported on the this NRF Device." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ОТА ажурирања нису подржана на овом NRF уређају." + } + } + } }, "OTA Updates are not supported on your platform." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ОТА ажурирања нису подржана на вашој платформи." + } + } + } }, "Other data sources" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Остали извори података" + } + } + } }, "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Излаз дебаговања уживо преко серијског интерфејса, прегледајте и извозите логове уређаја са редукованим позицијама преко блутута." + } + } + } }, "Output pin buzzer GPIO " : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Излазни пин за зујалицу GPIO" + } + } + } }, "Output pin GPIO" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Излазни пин GPIO" + } + } + } }, "Output pin vibra GPIO" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Излазни пин за вибрацију GPIO" + } + } + } }, "Override automatic OLED screen detection." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Премаши аутоматско откривање OLED екрана." + } + } + } }, "password" : { "localizations" : { @@ -16742,6 +21467,12 @@ "value" : "Lösenord" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Лозинка" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -16800,6 +21531,12 @@ "value" : "Pausa" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Паузирај" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -16833,6 +21570,12 @@ "state" : "translated", "value" : "BLE" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "БЛЕ" + } } } }, @@ -16855,6 +21598,12 @@ "state" : "translated", "value" : "Inga loggar för PAX-räknare" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема логова PAX бројача" + } } } }, @@ -16877,6 +21626,12 @@ "state" : "translated", "value" : "Radera all paxdata?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Избриши све PAX податке?" + } } } }, @@ -16899,6 +21654,12 @@ "state" : "translated", "value" : "PAX-räknarens logg" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Логови PAX бројача" + } } } }, @@ -16921,6 +21682,12 @@ "state" : "translated", "value" : "Totalt PAX" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Укупно PAX" + } } } }, @@ -16943,6 +21710,12 @@ "state" : "translated", "value" : "WiFi" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ВајФај" + } } } }, @@ -16953,6 +21726,12 @@ "state" : "translated", "value" : "Verbundenen Knoten auf Werkseinstellungen zurücksetzen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Изврши фабричко ресетовање чвора на који сте повезани" + } } } }, @@ -17000,6 +21779,12 @@ "value" : "Telefon-GPS" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPS телефона" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17059,6 +21844,12 @@ "value" : "Hur ofta din telefon skickar din plats till enheten, platsuppdateringar till mesh-nätverket hanteras av enheten." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Колико често ваш телефон шаље вашу локацију уређају, ажурирања локације на мрежу се управљају од стране уређаја." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17074,13 +21865,34 @@ } }, "Pin %lld" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пин %lld" + } + } + } }, "Pin A" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пин А" + } + } + } }, "Pin B" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пин Б" + } + } + } }, "PKI based node administration, requires firmware version 2.5+" : { "localizations" : { @@ -17089,14 +21901,34 @@ "state" : "translated", "value" : "PKI-basierte Knotenadministration, benötigt Firmware Version 2.5+" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Администрација чвора заснована на PKI захтева фирмвер верзију 2.5 или новију" + } } } }, "Please connect to a radio to configure settings." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Молимо вас да се повежете на радио да бисте конфигурисали подешавања." + } + } + } }, "Points of Interest" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тачке интересовања" + } + } + } }, "position" : { "localizations" : { @@ -17142,6 +21974,12 @@ "value" : "Position" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Позиција" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17157,22 +21995,64 @@ } }, "Position Exchange Failed" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Неуспела размена позиција" + } + } + } }, "Position Exchange Requested" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтевана размена позиција" + } + } + } }, "Position Flags" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Заставице позиције" + } + } + } }, "Position Log" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Логови позиција" + } + } + } }, "Position Log %lld Points" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дневник позиција %lld тачака" + } + } + } }, "Position Packet" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пакети позиција" + } + } + } }, "Position Sent" : { "localizations" : { @@ -17181,6 +22061,12 @@ "state" : "translated", "value" : "Position gesendet" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Позиција послата" + } } } }, @@ -17228,6 +22114,12 @@ "value" : "Positionskonfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања позиције" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17268,26 +22160,74 @@ "state" : "translated", "value" : "Inom %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "У кругу %@" + } } } }, "Positions Enabled" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Позиционирање укључено" + } + } + } }, "Positions will be provided by your device GPS, if you select disabled or not present you can set a fixed position." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Позиције ће бити обезбеђене путем GPS-а вашег уређаја. Ако одаберете опцију „онемогућено“ или „није присутно“, можете подесити фиксну позицију." + } + } + } }, "Power Metrics" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мерни подаци о снази" + } + } + } }, "Power Off" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Искључи" + } + } + } }, "Power Options" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опције снаге" + } + } + } }, "Power Screen" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Снага екрана" + } + } + } }, "Powered" : { "localizations" : { @@ -17296,6 +22236,12 @@ "state" : "translated", "value" : "Angeschaltet" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Напајано" + } } } }, @@ -17306,6 +22252,12 @@ "state" : "translated", "value" : "Genaue Position" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прецизне локације" + } } } }, @@ -17354,6 +22306,12 @@ "value" : "Föredragen Radio" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Преферирани радио" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17369,10 +22327,24 @@ } }, "Presets" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Унапред подешено" + } + } + } }, "Press Pin" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Притисни пин" + } + } + } }, "PRESSURE" : { "localizations" : { @@ -17381,35 +22353,115 @@ "state" : "translated", "value" : "DRUCK" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ПРИТИСАК" + } } } }, "Primary" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Основни" + } + } + } }, "Primary Admin Key" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Основни административни кључ" + } + } + } }, "Primary GPIO" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Основни GPIO" + } + } + } }, "Private Key" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Приватни кључ" + } + } + } }, "Project information" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Информације о пројекту" + } + } + } }, "Public Key" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Јавни кључ" + } + } + } }, "Public Key Encryption" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Шифровање јавним кљулем" + } + } + } }, "Public Key Mismatch" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Неслагање јавних кључева" + } + } + } }, "PWD" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "PWD" + } + } + } + }, + "Radio Disconnected" : { + "extractionState" : "manual", + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Радио веза је прекинута" + } + } + } }, "radio.configuration" : { "localizations" : { @@ -17455,6 +22507,12 @@ "value" : "Radioinställningar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација радио уређаја" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17513,6 +22571,12 @@ "value" : "Räckviddstest" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тест домета" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17572,6 +22636,12 @@ "value" : "Blockera räckviddstest" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тест домета блока" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17630,6 +22700,12 @@ "value" : "Konfiguration av räckviddstest" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација теста домета" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17688,6 +22764,12 @@ "value" : "Starta om" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поновно покретање" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17709,6 +22791,12 @@ "state" : "translated", "value" : "Knoten neustarten?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поново покрени чвор?" + } } } }, @@ -17756,6 +22844,12 @@ "value" : "Starta om nod?" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поново покрени чвор?" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17771,10 +22865,24 @@ } }, "Rebroadcast Mode" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Режим реемитовања" + } + } + } }, "Receive data (rxd) GPIO pin" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пријемни податак (rxd) GPIO пин" + } + } + } }, "received.ack" : { "localizations" : { @@ -17820,6 +22928,12 @@ "value" : "Mottaget kvitto" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Примљен ACK" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17878,6 +22992,12 @@ "value" : "Mottagarkvitto" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прималац ACK" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -17899,11 +23019,24 @@ "state" : "translated", "value" : "Route aufzeichnen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Снимање руте" + } } } }, "Refresh device metadata" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Освежи метаподатке уређаја" + } + } + } }, "Region" : { "localizations" : { @@ -17912,6 +23045,12 @@ "state" : "translated", "value" : "Region" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Регион" + } } } }, @@ -17935,6 +23074,12 @@ "state" : "translated", "value" : "Tarde" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пре подне" + } } } }, @@ -17958,6 +23103,12 @@ "state" : "translated", "value" : "Noite" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вече" + } } } }, @@ -17981,6 +23132,12 @@ "state" : "translated", "value" : "Meio-dia" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подне" + } } } }, @@ -18004,6 +23161,12 @@ "state" : "translated", "value" : "Manhã" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Јутро" + } } } }, @@ -18027,20 +23190,54 @@ "state" : "translated", "value" : "Noite" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ноћ" + } } } }, "Release Notes" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Белешке о издању" + } + } + } }, "Remote administration for: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Даљинска администрација за: %@" + } + } + } }, "Remote Legacy Admin: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Администрација застарелих система на даљину: %@" + } + } + } }, "Remote PKI Admin: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Администрација PKI на даљину: %@" + } + } + } }, "Remove" : { "localizations" : { @@ -18049,6 +23246,12 @@ "state" : "translated", "value" : "Entfernen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уклони" + } } } }, @@ -18059,11 +23262,34 @@ "state" : "translated", "value" : "Von Favoriten entfernen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уклони из омиљених" + } + } + } + }, + "Remove from ignored" : { + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уклони из игнорисаних" + } } } }, "Replace Channels" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Замени канале" + } + } + } }, "reply" : { "localizations" : { @@ -18109,6 +23335,12 @@ "value" : "Svara" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Одговори" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -18124,13 +23356,34 @@ } }, "Request Legacy Admin: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтевај администрацију застарелих система: %@" + } + } + } }, "Request PKI Admin: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтевај PKI администрацију: %@" + } + } + } }, "Requires that there be an accelerometer on your device." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтева да уређај има акцелерометар." + } + } + } }, "Reset App Settings" : { "localizations" : { @@ -18139,6 +23392,12 @@ "state" : "translated", "value" : "App-Einstellungen zurücksetzen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ресетовање подешавања апликације" + } } } }, @@ -18149,6 +23408,12 @@ "state" : "translated", "value" : "Knotendatenbank zurücksetzen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ресетовање базе чворова (NodeDB)" + } } } }, @@ -18159,6 +23424,12 @@ "state" : "translated", "value" : "Neustarten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поновно покретање" + } } } }, @@ -18169,6 +23440,12 @@ "state" : "translated", "value" : "Verbundenen Knoten neustarten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поновно покретање на чвор на који сте повезани" + } } } }, @@ -18179,6 +23456,12 @@ "state" : "translated", "value" : "Wiederherstellen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Обнова" + } } } }, @@ -18226,6 +23509,12 @@ "value" : "Återuppta" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Настави" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -18247,6 +23536,12 @@ "state" : "translated", "value" : "App bewerten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Оцените апликацију" + } } } }, @@ -18294,6 +23589,12 @@ "value" : "Ringsignal" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мелодија звона" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -18353,6 +23654,12 @@ "value" : "Ringsignalsinställningar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавање мелодије звона" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -18374,6 +23681,12 @@ "state" : "translated", "value" : "Rolle" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Улога" + } } } }, @@ -18384,6 +23697,12 @@ "state" : "translated", "value" : "Rolle: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Улога: %@" + } } } }, @@ -18394,23 +23713,64 @@ "state" : "translated", "value" : "Rollen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Улоге" + } } } }, "Root Topic" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Корен тема" + } + } + } }, "Rotary 1" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ротациони 1" + } + } + } }, "Route Back: %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Путања назад: %@" + } + } + } }, "Route Lines" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Линије руте" + } + } + } }, "Route recording paused" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Снимање руте паузирано" + } + } + } }, "Route: %@" : { "localizations" : { @@ -18419,6 +23779,12 @@ "state" : "translated", "value" : "Route: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Рута: %@" + } } } }, @@ -18466,6 +23832,12 @@ "value" : "Ruttinspelare" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Снимач руте" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -18481,10 +23853,24 @@ } }, "Router" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Рутер" + } + } + } }, "Router Options" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опције рутера" + } + } + } }, "routes" : { "localizations" : { @@ -18530,6 +23916,12 @@ "value" : "Rutter" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Руте" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -18564,6 +23956,12 @@ "state" : "translated", "value" : "Passeio de Bicicleta" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вожња бицикле" + } } } }, @@ -18587,6 +23985,12 @@ "state" : "translated", "value" : "Conduzir" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вожња аута" + } } } }, @@ -18610,6 +24014,12 @@ "state" : "translated", "value" : "Passeio de Bicicleta" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "тура бициклом" + } } } }, @@ -18633,6 +24043,12 @@ "state" : "translated", "value" : "Conduzir" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "вожња" + } } } }, @@ -18656,6 +24072,12 @@ "state" : "translated", "value" : "Caminhar na Montanha" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "планинарње" + } } } }, @@ -18673,6 +24095,12 @@ "state" : "translated", "value" : "Caminhar overland" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вожња преко копна" + } } } }, @@ -18696,6 +24124,12 @@ "state" : "translated", "value" : "Passeio de esqui" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ски тура" + } } } }, @@ -18719,6 +24153,12 @@ "state" : "translated", "value" : "Caminhar" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "шетња" + } } } }, @@ -18742,6 +24182,12 @@ "state" : "translated", "value" : "Caminhada na Montanha" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Планинарење" + } } } }, @@ -18759,6 +24205,12 @@ "state" : "translated", "value" : "Overlanding" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Оверлендинг" + } } } }, @@ -18782,6 +24234,12 @@ "state" : "translated", "value" : "Esqui" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Скијање" + } } } }, @@ -18805,6 +24263,12 @@ "state" : "translated", "value" : "Caminhada" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Шетња" + } } } }, @@ -18853,6 +24317,12 @@ "value" : "Bekräftad" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Потврђено" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -18912,6 +24382,12 @@ "value" : "Felaktig begäran" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Лош захтев" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -18971,6 +24447,12 @@ "value" : "Regionala sändningsgränsen nådd" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Достигнут регионални лимит радног циклуса" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19030,6 +24512,12 @@ "value" : "Mottog ett negativt kvitto" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Примљено негативно признање" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19089,6 +24577,12 @@ "value" : "Max antal omsändningar nått" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Достигнут максималан број поновних слања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19148,6 +24642,12 @@ "value" : "Ingen kanal" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема канала" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19207,6 +24707,12 @@ "value" : "Inget gränssnitt" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема интерфејса" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19266,6 +24772,12 @@ "value" : "Inget svar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема одговора" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19325,6 +24837,12 @@ "value" : "Ingen rutt" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нема руте" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19384,6 +24902,12 @@ "value" : "Inte auktoriserad" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Није ауторизовано" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19412,6 +24936,12 @@ "state" : "translated", "value" : "Encrypted Send Failed" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Шифровано слање није успело" + } } } }, @@ -19429,6 +24959,12 @@ "state" : "translated", "value" : "Unknown Public Key" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Непознат јавни кључ" + } } } }, @@ -19477,6 +25013,12 @@ "value" : "Tidsgräns överskriden" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Време истекло" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19536,6 +25078,12 @@ "value" : "Paketet är för stort" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пакет је превелики" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19551,16 +25099,44 @@ } }, "RSSI %@ dBm" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "RSSI %@ dBm" + } + } + } }, "RSSI %ddB" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "RSSI %ddB" + } + } + } }, "RSSI %llddB" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "RSSI %llddB" + } + } + } }, "RX Boosted Gain" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Појачање пријемника" + } + } + } }, "satellite" : { "extractionState" : "migrated", @@ -19607,6 +25183,12 @@ "value" : "Satellit" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сателит" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19666,6 +25248,12 @@ "value" : "Satellitöverflygning" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прелет сателита" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19687,6 +25275,12 @@ "state" : "translated", "value" : "Satelliten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сателита" + } } } }, @@ -19697,6 +25291,12 @@ "state" : "translated", "value" : "Satelliten Schätzung %lld" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Процена броја сателита %lld" + } } } }, @@ -19707,6 +25307,12 @@ "state" : "translated", "value" : "Satelliten in Sicht: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сателити на видику: %@" + } } } }, @@ -19754,6 +25360,12 @@ "value" : "Spara" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сачувај" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19775,6 +25387,12 @@ "state" : "translated", "value" : "Speichern" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сачувај" + } } } }, @@ -19785,6 +25403,12 @@ "state" : "translated", "value" : "Benutzerkonfiguration nach %@ speichern?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сачувати корисничу конфигурацију за %@?" + } } } }, @@ -19833,6 +25457,12 @@ "value" : "Spara konfiguration för %@" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сачувати конфигурацију за %@" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -19848,10 +25478,24 @@ } }, "Saves a CSV with the range test message details, currently only available on ESP32 devices with a web server." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Снима CSV са детаљима порука теста домета, тренутно доступно само на ESP32 уређајима са веб сервером." + } + } + } }, "Screen on for" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Екран укључен за" + } + } + } }, "Search" : { "localizations" : { @@ -19860,17 +25504,44 @@ "state" : "translated", "value" : "Suchen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Претражи" + } } } }, "Second" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Други" + } + } + } }, "Secondary" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Секундарни" + } + } + } }, "Secondary Admin Key" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Секундарни административни кључ" + } + } + } }, "Security" : { "localizations" : { @@ -19879,6 +25550,12 @@ "state" : "translated", "value" : "Sicherheit" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сигурност" + } } } }, @@ -19889,11 +25566,24 @@ "state" : "translated", "value" : "Sicherheitskonfiguration" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сигурносна подешавања" + } } } }, "Security Config Settings require a firmware version 2.5+" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сигурносна подешавања захтевају фирмвер верзију 2.5+" + } + } + } }, "Select a channel" : { "localizations" : { @@ -19902,17 +25592,44 @@ "state" : "translated", "value" : "Kanal wählen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Одабери канал" + } } } }, "Select a conversation" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Изабери разговор" + } + } + } }, "Select a conversation type" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Изабери тип разговора" + } + } + } }, "Select a Trace Route" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Изабери пут праћења кроз мрежу" + } + } + } }, "select.contact" : { "extractionState" : "manual", @@ -19959,6 +25676,12 @@ "value" : "Välj en kontakt" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Одабери контакт" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20018,6 +25741,12 @@ "value" : "Välj ett alternativ från menyn" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Изабери ставку из менија" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20076,6 +25805,12 @@ "value" : "Välj en nod" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Одабери чвор" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20097,6 +25832,12 @@ "state" : "translated", "value" : "Senden" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пошаљи" + } } } }, @@ -20107,6 +25848,12 @@ "state" : "translated", "value" : "Sende ${messageContent} an ${channelNumber}" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пошаљи ${messageContent} на ${channelNumber}" + } } } }, @@ -20117,14 +25864,34 @@ "state" : "translated", "value" : "Gruppennachricht senden" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пошаљи групну поруку" + } } } }, "Send a message to a certain meshtastic channel" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пошаљи поруку на одређени месхтастичан канал" + } + } + } }, "Send a position on the primary channel when the user button is triple clicked." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пошаљи позицију на примарном каналу када се корисничко дугме три пута кликне." + } + } + } }, "Send a shutdown to the node you are connected to" : { "localizations" : { @@ -20133,6 +25900,12 @@ "state" : "translated", "value" : "Herunterfahren an verbundenen Knoten senden" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пошаљи искључење чвору на који си повезан" + } } } }, @@ -20143,11 +25916,24 @@ "state" : "translated", "value" : "Wegpunkt senden" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пошаљи тачку путање" + } } } }, "Send ASCII bell with alert message. Useful for triggering external notification on bell." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пошаљи ASCII звона са поруком упозорења. Корисно за покретање спољашњег обавештења на звону." + } + } + } }, "Send Bell" : { "localizations" : { @@ -20156,26 +25942,74 @@ "state" : "translated", "value" : "Sende Glocke" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пошаљи звоно" + } } } }, "Send Reboot OTA" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пошаљи сигнал поновног покретања (OTA)" + } + } + } }, "Sender Interval" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Инерварл пошиљаоца" + } + } + } }, "Sensor Metrics" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Метрике сензора" + } + } + } }, "Sensor options" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опције сензора" + } + } + } }, "Sensor Options" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опције сензора" + } + } + } }, "Sent out to other nodes on the mesh to allow them to compute a shared secret key." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Послато другим чворовима на меш мрежи како би им омогућило да израчунају заједнички тајни кључ." + } + } + } }, "Sequence number" : { "localizations" : { @@ -20184,6 +26018,12 @@ "state" : "translated", "value" : "Sequenznummer" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Број секвенце" + } } } }, @@ -20194,6 +26034,12 @@ "state" : "translated", "value" : "Sequenz: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Секвенца: %@" + } } } }, @@ -20241,6 +26087,12 @@ "value" : "Serie" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Серијска веза" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20256,10 +26108,24 @@ } }, "Serial Console" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Серијска конзола" + } + } + } }, "Serial Console over the Stream API." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Серијска конзола преко Stream API-ја." + } + } + } }, "serial.config" : { "localizations" : { @@ -20305,6 +26171,12 @@ "value" : "Seriekonfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања серијске везе" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20364,6 +26236,12 @@ "value" : "Standard" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Основни" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20423,6 +26301,12 @@ "value" : "NMEA-positioner" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "NMEA позиције" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20482,6 +26366,12 @@ "value" : "Protobufs" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Протобафови" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20541,6 +26431,12 @@ "value" : "Enkel" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Једноставни" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20600,6 +26496,12 @@ "value" : "Textmeddelande" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Текстуална порука" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20624,6 +26526,12 @@ "state" : "translated", "value" : "Server" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сервер" + } } } }, @@ -20634,14 +26542,34 @@ "state" : "translated", "value" : "Serveradresse" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Адреса сервера" + } } } }, "Set" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подеси" + } + } + } }, "Set the GPIO pins for RXD and TXD." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подеси GPIO пинове за RXD и TXD." + } + } + } }, "set.region" : { "localizations" : { @@ -20687,6 +26615,12 @@ "value" : "Ställ in LoRa-region" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подеси LoRA регион" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20702,7 +26636,14 @@ } }, "Sets the maximum number of hops, default is 3. Increasing hops also increases congestion and should be used carefully. O hop broadcast messages will not get ACKs." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешава максималан број скокова. Подразумевано је 3, а повећање броја одобрених скокова такође повећава загушење и треба га користити опрезно. Поруке емитоване са 0 скокова неће добити потврде пријема (ACK)." + } + } + } }, "settings" : { "localizations" : { @@ -20748,6 +26689,12 @@ "value" : "Inställningar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подешавања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20769,6 +26716,12 @@ "state" : "translated", "value" : "QR Code & Link teilen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дели QR код и линк" + } } } }, @@ -20816,6 +26769,12 @@ "value" : "Dela QR-kod" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дели QR код" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20875,6 +26834,12 @@ "value" : "Dela position" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подели позицију" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -20896,6 +26861,12 @@ "state" : "translated", "value" : "Gemeinsamer Schlüssel" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дељени кључ" + } } } }, @@ -20906,6 +26877,12 @@ "state" : "translated", "value" : "Kurzname" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Кратко име" + } } } }, @@ -20916,6 +26893,12 @@ "state" : "translated", "value" : "Kurzname: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Кратко име: %@" + } } } }, @@ -20926,6 +26909,12 @@ "state" : "translated", "value" : "Zeige Alarme" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прикажи узбуне" + } } } }, @@ -20936,6 +26925,12 @@ "state" : "translated", "value" : "Zeige Alarme" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прикажи узбуне" + } } } }, @@ -20946,6 +26941,12 @@ "state" : "translated", "value" : "Zeige Knoten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прикажи чворове" + } } } }, @@ -20956,6 +26957,12 @@ "state" : "translated", "value" : "Zeige auf dem Gerätebildschirm" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прикажи на екрану уређаја" + } } } }, @@ -20966,6 +26973,12 @@ "state" : "translated", "value" : "Zeige auf der Netzwerkkarte." } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прикажи на мапи меш мреже." + } } } }, @@ -20976,6 +26989,12 @@ "state" : "translated", "value" : "Zeige Wegpunkte" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Прикажи тачке путање" + } } } }, @@ -20986,6 +27005,12 @@ "state" : "translated", "value" : "Herunterfahren" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Искључи" + } } } }, @@ -20996,6 +27021,12 @@ "state" : "translated", "value" : "Knoten herunterfahren?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Искључити чвор?" + } } } }, @@ -21006,26 +27037,74 @@ "state" : "translated", "value" : "Knoten herunterfahren?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Искључити чвор?" + } } } }, "Signal %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Сигнал %@" + } + } + } }, "Smart Position" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Паметно позиционирање" + } + } + } }, "SNR" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "SNR" + } + } + } }, "SNR %@ dB" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "SNR %@ dB" + } + } + } }, "SNR %@dB" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "SNR %@dB" + } + } + } }, "Specifies how long the monitored GPIO should output." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Одређује колико дуго треба да траје излазни сигнал надзираног GPIO-а." + } + } + } }, "Speed" : { "localizations" : { @@ -21034,6 +27113,12 @@ "state" : "translated", "value" : "Geschwindigkeit" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Брзина" + } } } }, @@ -21044,6 +27129,12 @@ "state" : "translated", "value" : "Geschwindigkeit %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Брзина %@" + } } } }, @@ -21054,11 +27145,24 @@ "state" : "translated", "value" : "Geschwindigkeit: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Брзина: %@" + } } } }, "Spread Factor" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Фактор ширења" + } + } + } }, "ssid" : { "localizations" : { @@ -21104,6 +27208,12 @@ "value" : "SSID" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "SSID" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21163,6 +27273,12 @@ "value" : "Standard" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Стандардно" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21222,6 +27338,12 @@ "value" : "Standard Muted" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Стандардно мутирано" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21280,6 +27402,12 @@ "value" : "Start" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Почетак" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21295,13 +27423,34 @@ } }, "State Broadcast Interval" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Интервал емитовања стања" + } + } + } }, "Store and forward clients can request history from routers on the network." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Клијенти за складиштење и прослеђивање могу затражити историју од рутера на мрежи." + } + } + } }, "Store and forward router devices require a ESP32 device with PSRAM." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Рутер за складиштење и прослеђивање захтева ESP32 уређај са PSRAM." + } + } + } }, "storeforward" : { "localizations" : { @@ -21347,6 +27496,12 @@ "value" : "Lagra & Videresänd" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Складиштење и прослеђивање" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21405,6 +27560,12 @@ "value" : "Konfiguration för Lagra & Videresänd" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација за складиштење и прослеђивање" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21463,6 +27624,12 @@ "value" : "Skicka hjärtslag" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пошаљи откуцај срца" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21521,6 +27688,12 @@ "value" : "Prenumererar på mesh" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Повезано са меш мрежом" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21542,11 +27715,24 @@ "state" : "translated", "value" : "Unterstützt" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подржан" + } } } }, "Supported I2C Connected sensors will be detected automatically, sensors are BMP280, BME280, BME680, MCP9808, INA219, INA260, LPS22 and SHTC3." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Подржани I2C повезани сензори ће бити аутоматски детектовани. Сензори су: BMP280, BME280, BME680, MCP9808, INA219, INA260, LPS22 и SHTC3." + } + } + } }, "Table" : { @@ -21595,6 +27781,12 @@ "value" : "Svarsreaktion" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Реакција додиром" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21654,6 +27846,12 @@ "value" : "Utropstecken" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Узвичник" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21713,6 +27911,12 @@ "value" : "HaHa" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Хахаха" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21772,6 +27976,12 @@ "value" : "Hjärta" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Срце" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21831,6 +28041,12 @@ "value" : "Bajs" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Кака" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21890,6 +28106,12 @@ "value" : "Frågetecken" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Знак питања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -21949,6 +28171,12 @@ "value" : "Tummen ner" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Палац доле" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22008,6 +28236,12 @@ "value" : "Tummen upp" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Лајк" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22067,6 +28301,12 @@ "value" : "Vinka" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Махање" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22081,6 +28321,57 @@ } } }, + "telementry.hazardous" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Hazardous" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опасно" + } + } + } + }, + "telementry.unhealthy" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unhealthy" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нездраво" + } + } + } + }, + "telementry.veryUnhealthy" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Very Unhealthy" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Веома нездраво" + } + } + } + }, "telemetry" : { "localizations" : { "de" : { @@ -22125,6 +28416,12 @@ "value" : "Telemetri (Sensorer)" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Телеметрија (сензори)" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22183,6 +28480,12 @@ "value" : "Telemetriinställningar" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Конфигурација телеметрије" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22197,6 +28500,57 @@ } } }, + "telemetry.good" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Good" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Добро" + } + } + } + }, + "telemetry.moderate" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Moderate" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Умерено" + } + } + } + }, + "telemetry.sensitive" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Unhealthy for Sensitive Groups" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Нездраво за осетљиве групе" + } + } + } + }, "Temp" : { "localizations" : { "de" : { @@ -22204,6 +28558,12 @@ "state" : "translated", "value" : "Temp" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Темп." + } } } }, @@ -22214,6 +28574,12 @@ "state" : "translated", "value" : "Temperatur" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Температура" + } } } }, @@ -22224,17 +28590,61 @@ "state" : "translated", "value" : "Zehn Minuten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Десет пинута" + } } } }, "Tertiary Admin Key" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Терцијарни административни кључ" + } + } + } + }, + "tft.full.color.displays" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "TFT Full Color Displays" + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "TFT екрани у пуној боји" + } + } + } }, "The amount of time to wait before we consider your packet as done." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Време чекања пре него што сматрамо да је ваш пакет завршен." + } + } + } }, "The compass heading on the screen outside of the circle will always point north." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Смер компаса на екрану изван круга увек ће указивати на север." + } + } + } }, "The dew point is %@ right now." : { "localizations" : { @@ -22243,56 +28653,185 @@ "state" : "translated", "value" : "Der Taupunkt ist gerade %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тачка росе тренутно износи %@." + } } } }, "The fastest that position updates will be sent if the minimum distance has been satisfied" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Најбржа брзина којом ће се ажурирати позиција уколико је задовољен минимални услов за растојање." + } + } + } }, "The format used to display GPS coordinates on the device screen." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Формат који се користи за приказивање GPS координата на екрану уређаја." + } + } + } }, "The last 4 of the device MAC address will be appended to the short name to set the device's BLE Name. Short name can be up to 4 bytes long." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Последња 4 знака MAC адресе уређаја ће бити додата кратком имену како би се подесило BLE име уређаја. Кратко име може бити до 4 бајта дуго." + } + } + } }, "The maximum interval that can elapse without a node broadcasting a position" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Максимални интервал који може протећи без да чвор емитује позицију." + } + } + } }, "The Meshtastic Apple apps support firmware version %@ and above." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Мештастик апликације за Епл уређаје подржавају верзију фирмвера %@ и новије." + } + } + } }, "The minimum distance change in meters to be considered for a smart position broadcast." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Минимална промена растојања у метрима која ће се узети у обзир за паметно емитовање позиције." + } + } + } }, "The most recent public key for this node does not match the previously recorded key. You can delete the node and let it exchange keys again, but this also may indicate a more serious security problem. Contact the user through another trusted channel to determine if the key change was due to a factory reset or other intentional action." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Најновији јавни кључ за овај чвор се не подудара са претходно снимљеним кључем. Можете избрисати чвор и дозволити му да поново размени кључеве, али ово такође може указивати на озбиљнији безбедносни проблем. Контактирајте корисника преко другог поузданог канала како бисте утврдили да ли је промена кључа резултат фабричког ресетовања или друге намерне акције." + } + } + } }, "The primary public key authorized to send admin messages to this node." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Примарни јавни кључ овлашћен за слање административних порука овом чвору." + } + } + } }, "The public key does not match the recorded key. You may delete the node and let it exchange keys again, but this may indicate a more serious security problem. Contact the user through another trusted channel, to determine if the key change was due to a factory reset or other intentional action." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Јавни кључ се не подудара са снимљеним кључем. Можете избрисати чвор и дозволити му да поново размени кључеве, али ово може указивати на озбиљнији безбедносни проблем. Контактирајте корисника преко другог поузданог канала како бисте утврдили да ли је промена кључа резултат фабричког ресетовања или друге намерне акције." + } + } + } }, "The region where you will be using your radios." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Регион у коме ћете користити ваше радио уређаје." + } + } + } }, "The root topic to use for MQTT." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Корен тема која ће се користити за MQTT." + } + } + } }, "The secondary public key authorized to send admin messages to this node." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Секундарни јавни кључ овлашћен за слање административних порука овом чвору." + } + } + } + }, + "The specified device has disconnected from us" : { + "extractionState" : "manual", + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Наведени уређај је прекинуо везу са нама" + } + } + } }, "The state of the LED (on/off)" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Стање LED диоде (укључено/искључено)" + } + } + } }, "The tertiary public key authorized to send admin messages to this node." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Терцијарни јавни кључ овлашћен за слање административних порука овом чвору." + } + } + } }, "There has been no response to a request for device metadata over the admin channel for this node." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Није било одговора на захтев за метаподатке уређаја преко административног канала за овај чвор." + } + } + } }, "These settings will %@ channels. The current LoRa Config will be replaced, if there are substantial changes to the LoRa config the device will reboot" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ова подешавања ће %@ канале. Тренутна LoRA конфигурација ће бити замењена. Ако дође до значајних промена у LoRA конфигурацији, уређај ће се поново покренути." + } + } + } }, "Thirty Minutes" : { "localizations" : { @@ -22301,23 +28840,64 @@ "state" : "translated", "value" : "Dreißig Minuten" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тридесет минута" + } } } }, "This conversation will be deleted." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Овај разговор ће бити обрисан." + } + } + } }, "This could take a while, response will appear in the trace route log for the node it was sent to." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ово може потрајати. Одговор ће се појавити у евиденцији трасе праћења за чвор којем је послат." + } + } + } }, "This could take a while. The response will appear in the trace route log for the node it was sent to." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ово може потрајати. Одговор ће се појавити у евиденцији трасе праћења за чвор којем је послат." + } + } + } }, "This determines the actual frequency you are transmitting on in the band. If set to 0 this value will be calculated automatically based on the primary channel name." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ово одређује стварну фреквенцију на којој преносите у опсегу. Ако је постављено на 0, ова вредност ће се аутоматски израчунати на основу назива примарног канала." + } + } + } }, "This device will send out range test messages on the selected interval." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Овај уређај ће слати поруке за тестирање домета у одабраном интервалу." + } + } + } }, "This message was likely not delivered." : { "localizations" : { @@ -22326,14 +28906,34 @@ "state" : "translated", "value" : "Diese Nachricht wurde höchstwahrscheinlich nicht übermittelt." } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ова порука вероватно није била примљена." + } } } }, "This will disable fixed position and remove the currently set position." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ово ће онемогућити фиксну позицију и уклонити тренутно постављену позицију." + } + } + } }, "This will send a current position from your phone and enable fixed position." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ово ће послати тренутну позицију са вашег телефона и омогућити фиксну позицију." + } + } + } }, "Time" : { "localizations" : { @@ -22342,6 +28942,12 @@ "state" : "translated", "value" : "Zeit" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Време" + } } } }, @@ -22352,6 +28958,12 @@ "state" : "translated", "value" : "Zeitstempel" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Временски жиг" + } } } }, @@ -22362,6 +28974,12 @@ "state" : "translated", "value" : "Zeitzone" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Временска зона" + } } } }, @@ -22372,6 +28990,12 @@ "state" : "translated", "value" : "Zeitzone für Daten auf dem Gerätebildschirm und Log." } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Временска зона за датуме на екрану уређаја и у евиденцији." + } } } }, @@ -22419,6 +29043,12 @@ "value" : "Tidsgräns överskriden" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Временско ограничење" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22477,6 +29107,12 @@ "value" : "Tidsstämpel" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Временска ознака" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22492,7 +29128,14 @@ } }, "Timing & Format" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Време и формат" + } + } + } }, "tip.bluetooth.connect.message" : { "localizations" : { @@ -22538,6 +29181,12 @@ "value" : "Visar information för LoRa-radion ansluten via bluetooth. Du kan svepa åt vänster för att koppla från radion och långtryck för att visa statistik eller starta liveaktivitet." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Приказује информације за LoRA радио повезан преко Блутута. Можете превући лево да бисте одспојили радио и дуго притиснути да бисте погледали статистику или започели активност у реалном времену." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22596,6 +29245,12 @@ "value" : "Ansluten Radio" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Радио повезан" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22654,6 +29309,12 @@ "value" : "Administratörskanal upptäckt: Välj en nod från rullgardinsmenyn för att hantera anslutna eller fjärranslutna enheter." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Детектован админ канал: Изаберите чвор из падајућег менија да бисте управљали повезаним или удаљеним уређајима." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22712,6 +29373,12 @@ "value" : "Administratörskanal" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Административни канал" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22770,6 +29437,12 @@ "value" : "De flesta data i ditt mesh-nätverk skickas över primärkanalen. Du kan ställa in sekundära kanaler för att skapa ytterligare meddelandegrupper skyddade av sin egen nyckel. Tips för kanalkonfiguration" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Већина података на вашој мрежи шаље се преко примарног канала. Можете подесити секундарне канале како бисте креирали додатне групе за размену порука, које су обезбеђене сопственим кључем. [Савети за конфигурацију канала](https://meshtastic.org/docs/configuration/tips/)" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22828,6 +29501,12 @@ "value" : "Hantera Kanaler" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Управљај каналима" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22886,6 +29565,12 @@ "value" : "En Meshtastic QR-kod innehåller LoRa-konfigurationen och kanalvärden som behövs för kommunikation. De flesta aktiviteter i mesh-nätverket sker på den obligatoriska primärkanalen. Om du inte delar din primärkanal blir din första delade kanal primärkanalen på det andra nätverket. Andra kanaler är för privata grupper, varje med sin egen nyckel." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "QR код за Мештастик садржи LoRA конфигурацију и вредности канала које су потребне радијима за комуникацију. Можете поделити потпуну конфигурацију канала користећи опцију „Замени канале“, а ако изаберете „Додај канале“, ваши делени канали ће бити додати каналима на примајућем радију." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -22944,6 +29629,12 @@ "value" : "Dela Meshtastic-kanaler" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Дељење Мештастик канала" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23002,6 +29693,12 @@ "value" : "Du kan skicka och ta emot kanalmeddelanden (gruppchatt) och direkta meddelanden. Från alla meddelanden kan du långtrycka för att se tillgängliga åtgärder som kopiera, svara, tapback och radera samt leveransdetaljer." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Можете слати и примати поруке у каналима (групним четовима) и директне поруке. Из било које поруке можете дуго притиснути да бисте видели доступне радње као што су копирање, одговор, реакција и брисање, као и детаље о испоруци." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23060,6 +29757,12 @@ "value" : "Meddelanden" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Поруке" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23075,7 +29778,25 @@ } }, "TLS Enabled" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "TLS укључен" + } + } + } + }, + "Topic: %@" : { + "extractionState" : "manual", + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тема: %@" + } + } + } }, "Total" : { "localizations" : { @@ -23084,14 +29805,34 @@ "state" : "translated", "value" : "Total" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Укупно" + } } } }, "Trace Route" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Праћење руте" + } + } + } }, "Trace Route Log" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Лог праћења руте комуникације" + } + } + } }, "Trace route received directly by %@ with a SNR of %@ dB" : { "localizations" : { @@ -23100,20 +29841,54 @@ "state" : "new", "value" : "Trace route received directly by %1$@ with a SNR of %2$@ dB" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтев за праћење руте комуникације директно примљен од %1$@ са SNR од %2$@ dB." + } } } }, "Trace Route Sent" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтев за праћење руте комуникације послат." + } + } + } }, "Trace route sent to %@" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтев за праћење руте комуникације послат до %@." + } + } + } }, "Trace route to %@ was not sent." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Захтев за праћење руте комуникације до %@ није послат." + } + } + } }, "Trace Route was rate limited. You can send a trace route a maximum of once every thirty seconds." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Праћење руте комуникације је било ограничено по брзини. Можете послати захтев за праћење руте комуникације највише једном у сваких тридесет секунди." + } + } + } }, "Traffic" : { "localizations" : { @@ -23122,23 +29897,64 @@ "state" : "translated", "value" : "Verkehr" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Саобраћај" + } } } }, "Transmit data (txd) GPIO pin" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "GPIO pin за трансмисију података (txd)" + } + } + } }, "Transmit Enabled" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Трансмитер укључен" + } + } + } }, "Treat double tap on supported accelerometers as a user button press." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Третирај двоструки додир на подржаним акцелераметрима као притисак корисничког дугмета." + } + } + } }, "TriggerType" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Тип покретача" + } + } + } }, "Triple Click Ad Hoc Ping" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Троструки клик за Ad Hoc пинг" + } + } + } }, "Try Again" : { "localizations" : { @@ -23147,6 +29963,12 @@ "state" : "translated", "value" : "Erneut versuchen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Покушај поново" + } } } }, @@ -23195,6 +30017,12 @@ "value" : "Twitter" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "X.com" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23210,13 +30038,34 @@ } }, "Two Hours" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Два сата" + } + } + } }, "Un-Favorite" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уклони са фаворита" + } + } + } }, "Units displayed on the device screen" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Јединице приказане на екрану уређаја" + } + } + } }, "unknown" : { "localizations" : { @@ -23262,6 +30111,12 @@ "value" : "Okänd" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Непознато" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23320,6 +30175,12 @@ "value" : "Okänd ålder" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Непозната старост" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23378,6 +30239,12 @@ "value" : "Återställ" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Уклони" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23393,13 +30260,34 @@ } }, "Unsupported" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Није подржано" + } + } + } }, "Up Down 1" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Горе Доле 1" + } + } + } }, "Update Interval" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Интервал ажурирања" + } + } + } }, "update.firmware" : { "localizations" : { @@ -23445,6 +30333,12 @@ "value" : "Uppdatera din firmware" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ажурирај твој фирмвер" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23503,6 +30397,12 @@ "value" : "Uppdateringsintervall" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Интервал ажурирања" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23518,7 +30418,14 @@ } }, "Updated Node Stats Data." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ажурирани подаци о статистици чвора." + } + } + } }, "Updated: %@" : { "localizations" : { @@ -23527,11 +30434,24 @@ "state" : "translated", "value" : "Aktualisiert: %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ажуриран: %@" + } } } }, "Uplink Enabled" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Укључен узлазни канал" + } + } + } }, "uptime" : { "localizations" : { @@ -23558,23 +30478,64 @@ "state" : "translated", "value" : "Drifttid" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Време рада" + } } } }, "Use a PWM output (like the RAK Buzzer) for tunes instead of an on/off output. This will ignore the output, output duration and active settings and use the device config buzzer GPIO option instead." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Користи PWM излаз (као што је RAK звучник) за мелодије уместо укључивања/искључивања излаза. Ово ће игнорисати подешавања излаза, трајање излаза и активна подешавања и користити подешавање GPIO опције звучника у конфигурацији уређаја." + } + } + } }, "Use I2S As Buzzer" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Користи I2S као звучник" + } + } + } }, "Use Preset" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Користи предефинисано подешавање" + } + } + } }, "Use PWM Buzzer" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Користи PWM звучник" + } + } + } }, "Used to create a shared key with a remote device." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Користи се за креирање заједничког кључа са удаљеним уређајем." + } + } + } }, "user" : { "localizations" : { @@ -23620,6 +30581,12 @@ "value" : "Användare" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Корисник" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23635,13 +30602,45 @@ } }, "User Config" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Корисничка подешавања" + } + } + } }, "User Details" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Кориснички детаљи" + } + } + } }, "User Id" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ИД корисника" + } + } + } + }, + "User Initiated Disconnect" : { + "extractionState" : "manual", + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Корисник је покренуо прекид везе" + } + } + } }, "user.details" : { "extractionState" : "manual", @@ -23688,6 +30687,12 @@ "value" : "Användaruppgifter" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Кориснички детаљи" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23703,10 +30708,24 @@ } }, "Uses pullup resistor" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Користи pull-up отпорник" + } + } + } }, "Utilizes the network connection on your phone to connect to MQTT." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Користи мрежну везу на вашем телефону за повезивање са MQTT." + } + } + } }, "Vehicle heading" : { "localizations" : { @@ -23715,6 +30734,12 @@ "state" : "translated", "value" : "Fahrzeugsteuerkurs" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Правац возила" + } } } }, @@ -23725,21 +30750,30 @@ "state" : "translated", "value" : "Fahrzeuggeschwindigkeit" } - } - } - }, - "Version %@ includes breaking changes to devices and the client apps. Only nodes version %@ and above are supported." : { - "localizations" : { - "en" : { + }, + "sr" : { "stringUnit" : { - "state" : "new", - "value" : "Version %1$@ includes breaking changes to devices and the client apps. Only nodes version %2$@ and above are supported." + "state" : "translated", + "value" : "Брзина возила" } } } }, - "Version 1.2 End of life (EOL) Info" : { - + "Version %@ includes substantial network optimizations and extensive changes to devices and client apps. Only nodes version %@ and above are supported." : { + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Version %1$@ includes substantial network optimizations and extensive changes to devices and client apps. Only nodes version %2$@ and above are supported." + } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Верзија %1$@ укључује значајне оптимизације мреже и обимне измене уређаја и клијентских апликација. Подржане су само верзије чворова %2$@ и новије." + } + } + } }, "Version: %@ (%@) " : { "localizations" : { @@ -23754,6 +30788,12 @@ "state" : "new", "value" : "Version: %1$@ (%2$@) " } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Верзија: %1$@ (%2$@) " + } } } }, @@ -23764,6 +30804,12 @@ "state" : "translated", "value" : "Via Lora" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Преко LoRA" + } } } }, @@ -23774,6 +30820,12 @@ "state" : "translated", "value" : "Via Mqtt" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Преко MQTT-а" + } } } }, @@ -23821,6 +30873,12 @@ "value" : "Spänning" } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Напон" + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23842,6 +30900,12 @@ "state" : "translated", "value" : "Volt %@" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Волти %@" + } } } }, @@ -23889,6 +30953,12 @@ "value" : "Väntar..." } }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Чекам. . ." + } + }, "zh-Hans" : { "stringUnit" : { "state" : "translated", @@ -23904,10 +30974,24 @@ } }, "Waiting to be acknowledged. . ." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Чека се на потврду пријема..." + } + } + } }, "Wake Screen on tap or motion" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Пробуди екран додиром или покретом" + } + } + } }, "Waypoint Options" : { "localizations" : { @@ -23916,6 +31000,12 @@ "state" : "translated", "value" : "Wegpunktoptionen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опције за тачке пута" + } } } }, @@ -23926,14 +31016,34 @@ "state" : "translated", "value" : "Wetterverhältnisse" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Временски услови" + } } } }, "Web Flasher" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Веб флашер" + } + } + } }, "Website" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Вебсајт" + } + } + } }, "What does the lock mean?" : { "localizations" : { @@ -23942,6 +31052,12 @@ "state" : "translated", "value" : "Was bedeutet das Schloß?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Шта значи закључавање?" + } } } }, @@ -23952,14 +31068,34 @@ "state" : "translated", "value" : "Was ist Meshtastic?" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Шта је Мештастик?" + } } } }, "What licensed operator mode does:\n* Sets the node name to your call sign \n* Broadcasts node info every 10 minutes \n* Overrides frequency, dutycycle and tx power \n* Disables encryption" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Шта ради режим лиценцираног оператера:\n* Поставља име чвора на ваш позивни знак\n* Емитује информације о чвору сваких 10 минута\n* Превазилази фреквенцију, циклус рада и излазну снагу\n* Онемогућава енкрипцију" + } + } + } }, "When using in GPIO mode, keep the output on for this long. " : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Када користите у GPIO режиму, задржите излаз укључен овако дуго." + } + } + } }, "WiFi Options" : { "localizations" : { @@ -23968,6 +31104,12 @@ "state" : "translated", "value" : "WiFi Optionen" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Опције вајфаја" + } } } }, @@ -23978,6 +31120,12 @@ "state" : "translated", "value" : "WIND" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "ВЕТАР" + } } } }, @@ -23988,6 +31136,12 @@ "state" : "translated", "value" : "Windrichtung" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Правац ветра" + } } } }, @@ -23998,11 +31152,24 @@ "state" : "translated", "value" : "Windgeschwindigkeit" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Брзина ветра" + } } } }, "x" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "x" + } + } + } }, "X: %@, Y: %d" : { "localizations" : { @@ -24011,6 +31178,12 @@ "state" : "new", "value" : "X: %1$@, Y: %2$d" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "X: %1$@, Y: %2$d" + } } } }, @@ -24021,6 +31194,12 @@ "state" : "new", "value" : "X: %1$@, Y: %2$f" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "X: %1$@, Y: %2$f" + } } } }, @@ -24031,11 +31210,24 @@ "state" : "new", "value" : "X: %1$@, Y: %2$lld" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "X: %1$@, Y: %2$lld" + } } } }, "y" : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "y" + } + } + } }, "Yesterday" : { "localizations" : { @@ -24044,14 +31236,34 @@ "state" : "translated", "value" : "Gestern" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Јуче" + } } } }, "You can also update your Meshtastic device over bluetooth using the Nordic DFU app." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Такође можете ажурирати свој Мештастик уређај преко блутута користећи Nordic DFU апликацију." + } + } + } }, "Your current location will be set as the fixed position and broadcast over the mesh on the position interval." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ваша тренутна позиција ће бити постављена као фиксна позиција и емитована преко мреже на интервалу позиције." + } + } + } }, "Your Firmware is up to date" : { "localizations" : { @@ -24060,23 +31272,64 @@ "state" : "translated", "value" : "Deine Firmware ist aktuell" } + }, + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ваш фирмвер је на најновијој верзији" + } } } }, "Your MQTT Server must support TLS. Not available via the public mqtt server." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ваш MQTT сервер мора подржавати TLS. Није доступно преко јавног MQTT сервера." + } + } + } }, "Your position has been sent with a request for a response with their position. You will receive a notification when a position is returned." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ваша позиција је послата са захтевом за одговор са њиховом позицијом. Добићете обавештење када се позиција врати." + } + } + } }, "Your region has a %lld%% duty cycle. MQTT is not advised when you are duty cycle restricted, the extra traffic will quickly overwhelm your LoRa mesh." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ваш регион има %lld%% циклус рада. MQTT се не препоручује када сте ограничени циклусом рада, јер ће додатни саобраћај брзо преоптеретити вашу LoRa мрежу." + } + } + } }, "Your region has a %lld%% hourly duty cycle, your radio will stop sending packets when it reaches the hourly limit." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ваш регион има %lld%% радни циклус по сату, ваш радио ће престати да шаље пакете када достигне ограничење по сату." + } + } + } }, "Your route file must have both Latitude and Longitude columns and headers." : { - + "localizations" : { + "sr" : { + "stringUnit" : { + "state" : "translated", + "value" : "Ваша датотека руте мора имати колоне и заглавља и ширину и дужину." + } + } + } } }, "version" : "1.0" diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 8f80a7b3..13eec2e1 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -222,6 +222,7 @@ DDDE5A1129AFE69700490C6C /* MeshActivityAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDE5A0F29AFE69700490C6C /* MeshActivityAttributes.swift */; }; DDDE5A1329AFEAB900490C6C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDDE5A1229AFEAB900490C6C /* Assets.xcassets */; }; DDDE5A1429AFEAB900490C6C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DDDE5A1229AFEAB900490C6C /* Assets.xcassets */; }; + DDDFE73F2D0D48FF0044463C /* IgnoreNodeButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDDFE73E2D0D48FF0044463C /* IgnoreNodeButton.swift */; }; DDE0F7C5295F77B700B8AAB3 /* AppSettingsEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE0F7C4295F77B700B8AAB3 /* AppSettingsEnums.swift */; }; DDE5B4042B2279A700FCDD05 /* TraceRouteLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE5B4032B2279A700FCDD05 /* TraceRouteLog.swift */; }; DDE9659C2B1C3B6A00531070 /* RouteRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDE9659B2B1C3B6A00531070 /* RouteRecorder.swift */; }; @@ -520,6 +521,8 @@ DDDE5A0F29AFE69700490C6C /* MeshActivityAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshActivityAttributes.swift; sourceTree = ""; }; DDDE5A1229AFEAB900490C6C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; DDDEE5E229DBE43E00A8E078 /* MeshtasticDataModelV11.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV11.xcdatamodel; sourceTree = ""; }; + DDDFE73E2D0D48FF0044463C /* IgnoreNodeButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IgnoreNodeButton.swift; sourceTree = ""; }; + DDDFE7402D0D4A070044463C /* MeshtasticDataModelV 47.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 47.xcdatamodel"; sourceTree = ""; }; DDE0F7C4295F77B700B8AAB3 /* AppSettingsEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSettingsEnums.swift; sourceTree = ""; }; DDE5B4032B2279A700FCDD05 /* TraceRouteLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TraceRouteLog.swift; sourceTree = ""; }; DDE5B4052B227E3200FCDD05 /* TraceRouteEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TraceRouteEntityExtension.swift; sourceTree = ""; }; @@ -590,6 +593,7 @@ 251926882C3BAF2E00249DF5 /* Actions */ = { isa = PBXGroup; children = ( + DDDFE73E2D0D48FF0044463C /* IgnoreNodeButton.swift */, 251926842C3BA97800249DF5 /* FavoriteNodeButton.swift */, 251926892C3BB1B200249DF5 /* ExchangePositionsButton.swift */, 251926862C3BAE2200249DF5 /* NodeAlertsButton.swift */, @@ -1236,6 +1240,7 @@ "zh-Hant-TW", se, "pt-PT", + sr, ); mainGroup = DDC2E14B26CE248E0042C5E4; packageReferences = ( @@ -1349,6 +1354,7 @@ 6D825E622C34786C008DBEE4 /* CommonRegex.swift in Sources */, DD913639270DFF4C00D7ACF3 /* LocalNotificationManager.swift in Sources */, DDDB444C29F8AAA600EE2349 /* Color.swift in Sources */, + DDDFE73F2D0D48FF0044463C /* IgnoreNodeButton.swift in Sources */, DDB8F4122A9EE5DD00230ECE /* UserList.swift in Sources */, DDB75A0F2A05920E006ED576 /* FileManager.swift in Sources */, DD3D17E02C3FB67200561584 /* LocalWeatherConditions.swift in Sources */, @@ -1568,7 +1574,7 @@ ENABLE_USER_SCRIPT_SANDBOXING = YES; GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.5; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.MeshtasticTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1591,7 +1597,7 @@ DEVELOPMENT_TEAM = GCH7VS5Y9R; GCC_C_LANGUAGE_STANDARD = gnu17; GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.5; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.MeshtasticTests; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1748,7 +1754,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.10; + MARKETING_VERSION = 2.5.13; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1782,7 +1788,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 2.5.10; + MARKETING_VERSION = 2.5.13; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTS_MACCATALYST = YES; @@ -1808,13 +1814,13 @@ INFOPLIST_FILE = Widgets/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Widgets; INFOPLIST_KEY_NSHumanReadableCopyright = ""; - IPHONEOS_DEPLOYMENT_TARGET = 16.6; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.10; + MARKETING_VERSION = 2.5.13; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1841,13 +1847,13 @@ INFOPLIST_FILE = Widgets/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Widgets; INFOPLIST_KEY_NSHumanReadableCopyright = ""; - IPHONEOS_DEPLOYMENT_TARGET = 16.6; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 2.5.10; + MARKETING_VERSION = 2.5.13; PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1959,6 +1965,7 @@ DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + DDDFE7402D0D4A070044463C /* MeshtasticDataModelV 47.xcdatamodel */, DD0BE30C2CB785D8000BA445 /* MeshtasticDataModelV 46.xcdatamodel */, DD6D5A342CA13BA600ED3032 /* MeshtasticDataModelV 45.xcdatamodel */, DD7CF8DA2C93663C008BD10E /* MeshtasticDataModelV 44.xcdatamodel */, @@ -2006,7 +2013,7 @@ DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */, DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */, ); - currentVersion = DD0BE30C2CB785D8000BA445 /* MeshtasticDataModelV 46.xcdatamodel */; + currentVersion = DDDFE7402D0D4A070044463C /* MeshtasticDataModelV 47.xcdatamodel */; name = Meshtastic.xcdatamodeld; path = Meshtastic/Meshtastic.xcdatamodeld; sourceTree = ""; diff --git a/Meshtastic/Assets.xcassets/TLORABOARD.imageset/Contents.json b/Meshtastic/Assets.xcassets/HELTECHT62.imageset/Contents.json similarity index 51% rename from Meshtastic/Assets.xcassets/TLORABOARD.imageset/Contents.json rename to Meshtastic/Assets.xcassets/HELTECHT62.imageset/Contents.json index f8356864..418dd7fe 100644 --- a/Meshtastic/Assets.xcassets/TLORABOARD.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/HELTECHT62.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "LILYGO-TTGO-LoRa32-V2-1-1-6-Version-433-868-915Mhz-ESP32-LoRa-OLED-0-96.jpg_Q90.jpg_.webp.png", + "filename" : "heltec-ht62-esp32c3-sx1262.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/HELTECHT62.imageset/heltec-ht62-esp32c3-sx1262.svg b/Meshtastic/Assets.xcassets/HELTECHT62.imageset/heltec-ht62-esp32c3-sx1262.svg new file mode 100644 index 00000000..c52534ef --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECHT62.imageset/heltec-ht62-esp32c3-sx1262.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/HELTECMESHNODET114.imageset/Contents.json b/Meshtastic/Assets.xcassets/HELTECMESHNODET114.imageset/Contents.json new file mode 100644 index 00000000..a4f550b7 --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECMESHNODET114.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "heltec-mesh-node-t114-case.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/HELTECMESHNODET114.imageset/heltec-mesh-node-t114-case.svg b/Meshtastic/Assets.xcassets/HELTECMESHNODET114.imageset/heltec-mesh-node-t114-case.svg new file mode 100644 index 00000000..b2abe639 --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECMESHNODET114.imageset/heltec-mesh-node-t114-case.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/HELTECV3.imageset/Contents.json b/Meshtastic/Assets.xcassets/HELTECV3.imageset/Contents.json index 98595042..42c0472b 100644 --- a/Meshtastic/Assets.xcassets/HELTECV3.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/HELTECV3.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Heltec_turq.png", + "filename" : "heltec-v3-case.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/HELTECV3.imageset/Heltec_turq.png b/Meshtastic/Assets.xcassets/HELTECV3.imageset/Heltec_turq.png deleted file mode 100644 index c4454bcc..00000000 Binary files a/Meshtastic/Assets.xcassets/HELTECV3.imageset/Heltec_turq.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/HELTECV3.imageset/heltec-v3-case.svg b/Meshtastic/Assets.xcassets/HELTECV3.imageset/heltec-v3-case.svg new file mode 100644 index 00000000..1b1d3c55 --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECV3.imageset/heltec-v3-case.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE213.imageset/Contents.json b/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE213.imageset/Contents.json new file mode 100644 index 00000000..687a7da9 --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE213.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "heltec-vision-master-e213.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE213.imageset/heltec-vision-master-e213.svg b/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE213.imageset/heltec-vision-master-e213.svg new file mode 100644 index 00000000..2c1cca09 --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE213.imageset/heltec-vision-master-e213.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE290.imageset/Contents.json b/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE290.imageset/Contents.json new file mode 100644 index 00000000..13ddda16 --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE290.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "heltec-vision-master-e290.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE290.imageset/heltec-vision-master-e290.svg b/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE290.imageset/heltec-vision-master-e290.svg new file mode 100644 index 00000000..ca7d296a --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECVISIONMASTERE290.imageset/heltec-vision-master-e290.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Contents.json b/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Contents.json index 1a8d07dc..a1a7444e 100644 --- a/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Paper-Meshtastic-2 copy.jpg", + "filename" : "heltec-wireless-paper.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Paper-Meshtastic-2 copy.jpg b/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Paper-Meshtastic-2 copy.jpg deleted file mode 100644 index 36692599..00000000 Binary files a/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/Paper-Meshtastic-2 copy.jpg and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/heltec-wireless-paper.svg b/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/heltec-wireless-paper.svg new file mode 100644 index 00000000..cb3f188d --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECWIRELESSPAPER.imageset/heltec-wireless-paper.svg @@ -0,0 +1 @@ + diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/Contents.json b/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/Contents.json index 3b6b227c..d13152fe 100644 --- a/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "images.png", + "filename" : "heltec-wireless-tracker.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/heltec-wireless-tracker.svg b/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/heltec-wireless-tracker.svg new file mode 100644 index 00000000..a5392595 --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/heltec-wireless-tracker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/images.png b/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/images.png deleted file mode 100644 index 4e9336c5..00000000 Binary files a/Meshtastic/Assets.xcassets/HELTECWIRELESSTRACKER.imageset/images.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/Contents.json b/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/Contents.json index aed717e4..dea94fc1 100644 --- a/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "heltecwsl.png", + "filename" : "heltec-wsl-v3.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltec-wsl-v3.svg b/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltec-wsl-v3.svg new file mode 100644 index 00000000..1741223e --- /dev/null +++ b/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltec-wsl-v3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltecwsl.png b/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltecwsl.png deleted file mode 100644 index 8881d0e1..00000000 Binary files a/Meshtastic/Assets.xcassets/HELTECWSLV3.imageset/heltecwsl.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/LILYGOTBEAMS3CORE.imageset/Contents.json b/Meshtastic/Assets.xcassets/LILYGOTBEAMS3CORE.imageset/Contents.json index 892d20eb..1febc627 100644 --- a/Meshtastic/Assets.xcassets/LILYGOTBEAMS3CORE.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/LILYGOTBEAMS3CORE.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "tbeam_supreme.png", + "filename" : "tbeam-s3-core.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/LILYGOTBEAMS3CORE.imageset/tbeam-s3-core.svg b/Meshtastic/Assets.xcassets/LILYGOTBEAMS3CORE.imageset/tbeam-s3-core.svg new file mode 100644 index 00000000..f42e6d2c --- /dev/null +++ b/Meshtastic/Assets.xcassets/LILYGOTBEAMS3CORE.imageset/tbeam-s3-core.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/LILYGOTBEAMS3CORE.imageset/tbeam_supreme.png b/Meshtastic/Assets.xcassets/LILYGOTBEAMS3CORE.imageset/tbeam_supreme.png deleted file mode 100644 index 6a618653..00000000 Binary files a/Meshtastic/Assets.xcassets/LILYGOTBEAMS3CORE.imageset/tbeam_supreme.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/NANOG2ULTRA.imageset/Contents.json b/Meshtastic/Assets.xcassets/NANOG2ULTRA.imageset/Contents.json index 2f074381..fe8b1d15 100644 --- a/Meshtastic/Assets.xcassets/NANOG2ULTRA.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/NANOG2ULTRA.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "nano_g2_ultra_product_image.jpg", + "filename" : "nano-g2-ultra.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/NANOG2ULTRA.imageset/nano-g2-ultra.svg b/Meshtastic/Assets.xcassets/NANOG2ULTRA.imageset/nano-g2-ultra.svg new file mode 100644 index 00000000..6dbe47af --- /dev/null +++ b/Meshtastic/Assets.xcassets/NANOG2ULTRA.imageset/nano-g2-ultra.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/NANOG2ULTRA.imageset/nano_g2_ultra_product_image.jpg b/Meshtastic/Assets.xcassets/NANOG2ULTRA.imageset/nano_g2_ultra_product_image.jpg deleted file mode 100644 index 18f2b472..00000000 Binary files a/Meshtastic/Assets.xcassets/NANOG2ULTRA.imageset/nano_g2_ultra_product_image.jpg and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/RAK11200.imageset/Contents.json b/Meshtastic/Assets.xcassets/PROMICRO.imageset/Contents.json similarity index 75% rename from Meshtastic/Assets.xcassets/RAK11200.imageset/Contents.json rename to Meshtastic/Assets.xcassets/PROMICRO.imageset/Contents.json index ed6c2585..0fbd5109 100644 --- a/Meshtastic/Assets.xcassets/RAK11200.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/PROMICRO.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "RAK_DEV_KIT-2.jpg", + "filename" : "promicro.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/PROMICRO.imageset/promicro.svg b/Meshtastic/Assets.xcassets/PROMICRO.imageset/promicro.svg new file mode 100644 index 00000000..3dc26021 --- /dev/null +++ b/Meshtastic/Assets.xcassets/PROMICRO.imageset/promicro.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/RAK11200.imageset/RAK_DEV_KIT-2.jpg b/Meshtastic/Assets.xcassets/RAK11200.imageset/RAK_DEV_KIT-2.jpg deleted file mode 100644 index 9300bed0..00000000 Binary files a/Meshtastic/Assets.xcassets/RAK11200.imageset/RAK_DEV_KIT-2.jpg and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/TLORAV1.imageset/Contents.json b/Meshtastic/Assets.xcassets/RAK11310.imageset/Contents.json similarity index 75% rename from Meshtastic/Assets.xcassets/TLORAV1.imageset/Contents.json rename to Meshtastic/Assets.xcassets/RAK11310.imageset/Contents.json index 093c722d..3046b536 100644 --- a/Meshtastic/Assets.xcassets/TLORAV1.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/RAK11310.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "TLORA_olive 1.png", + "filename" : "rak11310.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/RAK11310.imageset/rak11310.svg b/Meshtastic/Assets.xcassets/RAK11310.imageset/rak11310.svg new file mode 100644 index 00000000..8c5ce28e --- /dev/null +++ b/Meshtastic/Assets.xcassets/RAK11310.imageset/rak11310.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/RAK4631.imageset/Contents.json b/Meshtastic/Assets.xcassets/RAK4631.imageset/Contents.json index feb2e6c0..60b17db3 100644 --- a/Meshtastic/Assets.xcassets/RAK4631.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/RAK4631.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "RAK 4.png", + "filename" : "rak4631_case.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/RAK4631.imageset/RAK 4.png b/Meshtastic/Assets.xcassets/RAK4631.imageset/RAK 4.png deleted file mode 100644 index e34322b8..00000000 Binary files a/Meshtastic/Assets.xcassets/RAK4631.imageset/RAK 4.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/RAK4631.imageset/rak4631_case.svg b/Meshtastic/Assets.xcassets/RAK4631.imageset/rak4631_case.svg new file mode 100644 index 00000000..a0b2bbb8 --- /dev/null +++ b/Meshtastic/Assets.xcassets/RAK4631.imageset/rak4631_case.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/RPIPICO.imageset/Contents.json b/Meshtastic/Assets.xcassets/RPIPICO.imageset/Contents.json new file mode 100644 index 00000000..87088506 --- /dev/null +++ b/Meshtastic/Assets.xcassets/RPIPICO.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "pico.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/RPIPICO.imageset/pico.svg b/Meshtastic/Assets.xcassets/RPIPICO.imageset/pico.svg new file mode 100644 index 00000000..82ce6526 --- /dev/null +++ b/Meshtastic/Assets.xcassets/RPIPICO.imageset/pico.svg @@ -0,0 +1,2956 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Meshtastic/Assets.xcassets/SEEEDXIAOS3.imageset/Contents.json b/Meshtastic/Assets.xcassets/SEEEDXIAOS3.imageset/Contents.json new file mode 100644 index 00000000..fdd4019e --- /dev/null +++ b/Meshtastic/Assets.xcassets/SEEEDXIAOS3.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "seeed-xiao-s3.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/SEEEDXIAOS3.imageset/seeed-xiao-s3.svg b/Meshtastic/Assets.xcassets/SEEEDXIAOS3.imageset/seeed-xiao-s3.svg new file mode 100644 index 00000000..04e97fe0 --- /dev/null +++ b/Meshtastic/Assets.xcassets/SEEEDXIAOS3.imageset/seeed-xiao-s3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/SENSECAPINDICATOR.imageset/Contents.json b/Meshtastic/Assets.xcassets/SENSECAPINDICATOR.imageset/Contents.json new file mode 100644 index 00000000..3870939e --- /dev/null +++ b/Meshtastic/Assets.xcassets/SENSECAPINDICATOR.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "seeed-sensecap-indicator.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/SENSECAPINDICATOR.imageset/seeed-sensecap-indicator.svg b/Meshtastic/Assets.xcassets/SENSECAPINDICATOR.imageset/seeed-sensecap-indicator.svg new file mode 100644 index 00000000..f7bf9db0 --- /dev/null +++ b/Meshtastic/Assets.xcassets/SENSECAPINDICATOR.imageset/seeed-sensecap-indicator.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/STATIONG2.imageset/Contents.json b/Meshtastic/Assets.xcassets/STATIONG2.imageset/Contents.json new file mode 100644 index 00000000..dc823045 --- /dev/null +++ b/Meshtastic/Assets.xcassets/STATIONG2.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "station-g2.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/STATIONG2.imageset/station-g2.svg b/Meshtastic/Assets.xcassets/STATIONG2.imageset/station-g2.svg new file mode 100644 index 00000000..8d2e0aed --- /dev/null +++ b/Meshtastic/Assets.xcassets/STATIONG2.imageset/station-g2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TBEAM.imageset/Contents.json b/Meshtastic/Assets.xcassets/TBEAM.imageset/Contents.json index 64a09f22..0ecd041c 100644 --- a/Meshtastic/Assets.xcassets/TBEAM.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/TBEAM.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "tbeam.png", + "filename" : "tbeam.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/TBEAM.imageset/tbeam.png b/Meshtastic/Assets.xcassets/TBEAM.imageset/tbeam.png deleted file mode 100644 index 75fec7be..00000000 Binary files a/Meshtastic/Assets.xcassets/TBEAM.imageset/tbeam.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/TBEAM.imageset/tbeam.svg b/Meshtastic/Assets.xcassets/TBEAM.imageset/tbeam.svg new file mode 100644 index 00000000..cd0475c6 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TBEAM.imageset/tbeam.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TDECK.imageset/Contents.json b/Meshtastic/Assets.xcassets/TDECK.imageset/Contents.json new file mode 100644 index 00000000..b8451344 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TDECK.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "t-deck.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/TDECK.imageset/t-deck.svg b/Meshtastic/Assets.xcassets/TDECK.imageset/t-deck.svg new file mode 100644 index 00000000..cdc53c5d --- /dev/null +++ b/Meshtastic/Assets.xcassets/TDECK.imageset/t-deck.svg @@ -0,0 +1 @@ +QWERTYIUPOASDFGHKJLaltZXCVBMN \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TECHO.imageset/Contents.json b/Meshtastic/Assets.xcassets/TECHO.imageset/Contents.json index f380b7af..e1adcf61 100644 --- a/Meshtastic/Assets.xcassets/TECHO.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/TECHO.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "LILYGO-TTGO-SoftRF-T-Echo-NRF52840-LoRa-SX1262-433-868-915MHz-Wireless-Module-L76K-GPS-1.png", + "filename" : "t-echo.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/TECHO.imageset/LILYGO-TTGO-SoftRF-T-Echo-NRF52840-LoRa-SX1262-433-868-915MHz-Wireless-Module-L76K-GPS-1.png b/Meshtastic/Assets.xcassets/TECHO.imageset/LILYGO-TTGO-SoftRF-T-Echo-NRF52840-LoRa-SX1262-433-868-915MHz-Wireless-Module-L76K-GPS-1.png deleted file mode 100644 index 7b2f9f96..00000000 Binary files a/Meshtastic/Assets.xcassets/TECHO.imageset/LILYGO-TTGO-SoftRF-T-Echo-NRF52840-LoRa-SX1262-433-868-915MHz-Wireless-Module-L76K-GPS-1.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/TECHO.imageset/t-echo.svg b/Meshtastic/Assets.xcassets/TECHO.imageset/t-echo.svg new file mode 100644 index 00000000..e178a50f --- /dev/null +++ b/Meshtastic/Assets.xcassets/TECHO.imageset/t-echo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TLORABOARD.imageset/LILYGO-TTGO-LoRa32-V2-1-1-6-Version-433-868-915Mhz-ESP32-LoRa-OLED-0-96.jpg_Q90.jpg_.webp.png b/Meshtastic/Assets.xcassets/TLORABOARD.imageset/LILYGO-TTGO-LoRa32-V2-1-1-6-Version-433-868-915Mhz-ESP32-LoRa-OLED-0-96.jpg_Q90.jpg_.webp.png deleted file mode 100644 index ff3da639..00000000 Binary files a/Meshtastic/Assets.xcassets/TLORABOARD.imageset/LILYGO-TTGO-LoRa32-V2-1-1-6-Version-433-868-915Mhz-ESP32-LoRa-OLED-0-96.jpg_Q90.jpg_.webp.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/TLORAC6.imageset/Contents.json b/Meshtastic/Assets.xcassets/TLORAC6.imageset/Contents.json new file mode 100644 index 00000000..593dc16e --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAC6.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "tlora-c6.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/TLORAC6.imageset/tlora-c6.svg b/Meshtastic/Assets.xcassets/TLORAC6.imageset/tlora-c6.svg new file mode 100644 index 00000000..8b626638 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAC6.imageset/tlora-c6.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TLORAT3S3EPAPER.imageset/Contents.json b/Meshtastic/Assets.xcassets/TLORAT3S3EPAPER.imageset/Contents.json new file mode 100644 index 00000000..33fb9c78 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAT3S3EPAPER.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "tlora-t3s3-epaper.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/TLORAT3S3EPAPER.imageset/tlora-t3s3-epaper.svg b/Meshtastic/Assets.xcassets/TLORAT3S3EPAPER.imageset/tlora-t3s3-epaper.svg new file mode 100644 index 00000000..6f2e8452 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAT3S3EPAPER.imageset/tlora-t3s3-epaper.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/Contents.json b/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/Contents.json new file mode 100644 index 00000000..a5716fc8 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "tlora-t3s3-v1.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/tlora-t3s3-v1.svg b/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/tlora-t3s3-v1.svg new file mode 100644 index 00000000..1f8847d4 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAT3S3V1.imageset/tlora-t3s3-v1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TLORAV1.imageset/TLORA_olive 1.png b/Meshtastic/Assets.xcassets/TLORAV1.imageset/TLORA_olive 1.png deleted file mode 100644 index e8980a2c..00000000 Binary files a/Meshtastic/Assets.xcassets/TLORAV1.imageset/TLORA_olive 1.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/TLORAV2116.imageset/Contents.json b/Meshtastic/Assets.xcassets/TLORAV2116.imageset/Contents.json new file mode 100644 index 00000000..eb286609 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAV2116.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "tlora-v2-1-1_6.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/TLORAV2116.imageset/tlora-v2-1-1_6.svg b/Meshtastic/Assets.xcassets/TLORAV2116.imageset/tlora-v2-1-1_6.svg new file mode 100644 index 00000000..dbe36ef5 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAV2116.imageset/tlora-v2-1-1_6.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TLORAV2118.imageset/Contents.json b/Meshtastic/Assets.xcassets/TLORAV2118.imageset/Contents.json new file mode 100644 index 00000000..c7aff831 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAV2118.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "tlora-v2-1-1_8.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/TLORAV2118.imageset/tlora-v2-1-1_8.svg b/Meshtastic/Assets.xcassets/TLORAV2118.imageset/tlora-v2-1-1_8.svg new file mode 100644 index 00000000..dbe36ef5 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TLORAV2118.imageset/tlora-v2-1-1_8.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TRACKERT1000E.imageset/Contents.json b/Meshtastic/Assets.xcassets/TRACKERT1000E.imageset/Contents.json new file mode 100644 index 00000000..e966c95f --- /dev/null +++ b/Meshtastic/Assets.xcassets/TRACKERT1000E.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "tracker-t1000-e.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/TRACKERT1000E.imageset/tracker-t1000-e.svg b/Meshtastic/Assets.xcassets/TRACKERT1000E.imageset/tracker-t1000-e.svg new file mode 100644 index 00000000..6f7a06c9 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TRACKERT1000E.imageset/tracker-t1000-e.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/TWATCHS3.imageset/Contents.json b/Meshtastic/Assets.xcassets/TWATCHS3.imageset/Contents.json new file mode 100644 index 00000000..baffc648 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TWATCHS3.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "t-watch-s3.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/TWATCHS3.imageset/t-watch-s3.svg b/Meshtastic/Assets.xcassets/TWATCHS3.imageset/t-watch-s3.svg new file mode 100644 index 00000000..19084c19 --- /dev/null +++ b/Meshtastic/Assets.xcassets/TWATCHS3.imageset/t-watch-s3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/UNSET.imageset/Contents.json b/Meshtastic/Assets.xcassets/UNSET.imageset/Contents.json index 04be44d5..4508d9cd 100644 --- a/Meshtastic/Assets.xcassets/UNSET.imageset/Contents.json +++ b/Meshtastic/Assets.xcassets/UNSET.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "play_store_icon_114px-2.png", + "filename" : "unknown.svg", "idiom" : "universal" } ], diff --git a/Meshtastic/Assets.xcassets/UNSET.imageset/play_store_icon_114px-2.png b/Meshtastic/Assets.xcassets/UNSET.imageset/play_store_icon_114px-2.png deleted file mode 100644 index 79cf0e00..00000000 Binary files a/Meshtastic/Assets.xcassets/UNSET.imageset/play_store_icon_114px-2.png and /dev/null differ diff --git a/Meshtastic/Assets.xcassets/UNSET.imageset/unknown.svg b/Meshtastic/Assets.xcassets/UNSET.imageset/unknown.svg new file mode 100644 index 00000000..3b0a0744 --- /dev/null +++ b/Meshtastic/Assets.xcassets/UNSET.imageset/unknown.svg @@ -0,0 +1,129 @@ + + diff --git a/Meshtastic/Assets.xcassets/WIOWM1110.imageset/Contents.json b/Meshtastic/Assets.xcassets/WIOWM1110.imageset/Contents.json new file mode 100644 index 00000000..706f7fc3 --- /dev/null +++ b/Meshtastic/Assets.xcassets/WIOWM1110.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "wio-tracker-wm1110.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/WIOWM1110.imageset/wio-tracker-wm1110.svg b/Meshtastic/Assets.xcassets/WIOWM1110.imageset/wio-tracker-wm1110.svg new file mode 100644 index 00000000..15ace5c5 --- /dev/null +++ b/Meshtastic/Assets.xcassets/WIOWM1110.imageset/wio-tracker-wm1110.svg @@ -0,0 +1 @@ +LoRaWI FILEDRESETGNSSBLE \ No newline at end of file diff --git a/Meshtastic/Assets.xcassets/WISMESHTAP.imageset/Contents.json b/Meshtastic/Assets.xcassets/WISMESHTAP.imageset/Contents.json new file mode 100644 index 00000000..85d43a9b --- /dev/null +++ b/Meshtastic/Assets.xcassets/WISMESHTAP.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "rak-wismeshtap.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Meshtastic/Assets.xcassets/WISMESHTAP.imageset/rak-wismeshtap.svg b/Meshtastic/Assets.xcassets/WISMESHTAP.imageset/rak-wismeshtap.svg new file mode 100644 index 00000000..34e77876 --- /dev/null +++ b/Meshtastic/Assets.xcassets/WISMESHTAP.imageset/rak-wismeshtap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Meshtastic/Enums/DeviceEnums.swift b/Meshtastic/Enums/DeviceEnums.swift index 5c980da0..2128fafa 100644 --- a/Meshtastic/Enums/DeviceEnums.swift +++ b/Meshtastic/Enums/DeviceEnums.swift @@ -27,27 +27,27 @@ enum DeviceRoles: Int, CaseIterable, Identifiable { var name: String { switch self { case .client: - return "Client" + return "device.role.name.client".localized case .clientMute: - return "Client Mute" + return "device.role.name.clientMute".localized case .router: - return "Router" + return "device.role.name.router".localized case .routerClient: - return "Router & Client" + return "device.role.name.routerClient".localized case .repeater: - return "Repeater" + return "device.role.name.repeater".localized case .tracker: - return "Tracker" + return "device.role.name.tracker".localized case .sensor: - return "Sensor" + return "device.role.name.sensor".localized case .tak: - return "TAK" + return "device.role.name.tak".localized case .takTracker: - return "TAK Tracker" + return "device.role.name.takTracker".localized case .clientHidden: - return "Client Hidden" + return "device.role.name.clientHidden".localized case .lostAndFound: - return "Lost and Found" + return "device.role.name.lostAndFound".localized } } diff --git a/Meshtastic/Enums/DisplayEnums.swift b/Meshtastic/Enums/DisplayEnums.swift index a540a9d2..8959668a 100644 --- a/Meshtastic/Enums/DisplayEnums.swift +++ b/Meshtastic/Enums/DisplayEnums.swift @@ -149,13 +149,13 @@ enum DisplayModes: Int, CaseIterable, Identifiable { var description: String { switch self { case .defaultMode: - return "Default 128x64 screen layout" + return "default.128x64.screen.layout".localized case .twoColor: - return "Optimized for 2 color displays" + return "optimized.for.2.color.displays".localized case .inverted: - return "Inverted top bar for 2 Color display" + return "inverted.top.bar.for.2.color.display".localized case .color: - return "TFT Full Color Displays" + return "tft.full.color.displays".localized } } func protoEnumValue() -> Config.DisplayConfig.DisplayMode { diff --git a/Meshtastic/Enums/LoraConfigEnums.swift b/Meshtastic/Enums/LoraConfigEnums.swift index 2a2d7090..deccde0f 100644 --- a/Meshtastic/Enums/LoraConfigEnums.swift +++ b/Meshtastic/Enums/LoraConfigEnums.swift @@ -176,6 +176,54 @@ enum RegionCodes: Int, CaseIterable, Identifiable { return 100 } } + var isCountry: Bool { + switch self { + case .unset: + return false + case .us: + return true + case .eu433: + return false + case .eu868: + return false + case .cn: + return true + case .jp: + return true + case .anz: + return false + case .kr: + return true + case .tw: + return true + case .ru: + return true + case .in: + return true + case .nz865: + return true + case .th: + return true + case .ua433: + return true + case .ua868: + return true + case .lora24: + return false + case .my433: + return true + case .my919: + return true + case .sg923: + return true + case .ph433: + return true + case .ph868: + return true + case .ph915: + return true + } + } func protoEnumValue() -> Config.LoRaConfig.RegionCode { switch self { diff --git a/Meshtastic/Enums/TelemetryEnums.swift b/Meshtastic/Enums/TelemetryEnums.swift index 213d6963..68d65961 100644 --- a/Meshtastic/Enums/TelemetryEnums.swift +++ b/Meshtastic/Enums/TelemetryEnums.swift @@ -20,17 +20,17 @@ enum Aqi: Int, CaseIterable, Identifiable { var description: String { switch self { case .good: - return "Good" + return "telemetry.good".localized case .moderate: - return "Moderate" + return "telemetry.moderate".localized case .sensitive: - return "Unhealthy for Sensitive Groups" + return "telemetry.sensitive".localized case .unhealthy: - return "Unhealthy" + return "telementry.unhealthy".localized case .veryUnhealthy: - return "Very Unhealthy" + return "telementry.veryUnhealthy".localized case .hazardous: - return "Hazardous" + return "telementry.hazardous".localized } } var color: Color { diff --git a/Meshtastic/Extensions/CoreData/UserEntityExtension.swift b/Meshtastic/Extensions/CoreData/UserEntityExtension.swift index 8c49b322..57681fd7 100644 --- a/Meshtastic/Extensions/CoreData/UserEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/UserEntityExtension.swift @@ -33,48 +33,79 @@ extension UserEntity { let unreadMessages = messageList.filter { ($0 as AnyObject).read == false } return unreadMessages.count } - + /// SVG Images for Vendors who are signed project backers var hardwareImage: String? { guard let hwModel else { return nil } switch hwModel { - case "HELTECV1", "HELTECV3", "HELTECV20", "HELTECV21": + /// Heltec + case "HELTECHT62": + return "HELTECHT62" + case "HELTECMESHNODET114": + return "HELTECMESHNODET114" + case "HELTECV3": return "HELTECV3" + case "HELTECVISIONMASTERE213": + return "HELTECVISIONMASTERE213" + case "HELTECVISIONMASTERE290": + return "HELTECVISIONMASTERE290" case "HELTECWIRELESSPAPER", "HELTECWIRELESSPAPERV10": return "HELTECWIRELESSPAPER" case "HELTECWIRELESSTRACKER", "HELTECWIRELESSTRACKERV10": return "HELTECWIRELESSTRACKER" case "HELTECWSLV3": return "HELTECWSLV3" - case "LILYGOTBEAMSCORE": + /// LilyGO + case "TDECK": + return "TDECK" + case "TECHO": + return "TECHO" + case "TWATCHS3": + return "TWATCHS3" + case "LILYGOTBEAMS3CORE": return "LILYGOTBEAMS3CORE" + case "TBEAM", "TBEAM_V0P7": + return "TBEAM" + case "TLORAC6": + return "TLORAC6" + case "TLORAT3S3EPAPER": + return "TLORAT3S3EPAPER" + case "TLORAT3S3V1": + return "TLORAT3S3V1" + case "TLORAV2116": + return "TLORAV2116" + case "TLORAV2118": + return "TLORAV2118" + /// Seeed Studio + case "SENSECAPINDICATOR": + return "SENSECAPINDICATOR" + case "TRACKERT1000E": + return "TRACKERT1000E" + case "SEEEDXIAOS3": + return "SEEEDXIAOS3" + case "WIOWM1110": + return "WIOWM1110" + /// RAK Wireless + case "RAK4631": + return "RAK4631" + case "RAK11310": + return "RAK11310" + case "WISMESHTAP": + return "WISMESHTAP" + /// B&Q Consulting case "NANOG1", "NANOG1EXPLORER": return "NANOG1" case "NANOG2ULTRA": return "NANOG2ULTRA" - case "RAK4631": - return "RAK4631" - case "RAK11200": - return "RAK11200" - case "SOLAR_NODE": - return "SOLAR_NODE" - case "STATIONG1": - return "STATIONG1" - case "ТВЕАМ", "TBEAMVOP7": - return "ТВЕАМ" - case "TECHO": - return "TECHO" - case "TLORAV1", "TLORAV11P3": - return "TLORAV1" - case "TLORAV2", "TLORAT3S3", "TLORAV211P6", "TLORAV211P8": - return "TLORABOARD" - case "UNPHONE": - return "UNPHONE" + case "STATIONG2": + return "STATIONG2" + /// DIY Devices + case "RPIPICO": + return "RPIPICO" default: return "UNSET" } } } - public func createUser(num: Int64, context: NSManagedObjectContext) -> UserEntity { let newUser = UserEntity(context: context) newUser.num = Int64(num) diff --git a/Meshtastic/Extensions/String.swift b/Meshtastic/Extensions/String.swift index 4e840a98..b97ad1c5 100644 --- a/Meshtastic/Extensions/String.swift +++ b/Meshtastic/Extensions/String.swift @@ -61,11 +61,10 @@ extension String { } func camelCaseToWords() -> String { - return unicodeScalars.dropFirst().reduce(String(prefix(1))) { - return CharacterSet.uppercaseLetters.contains($1) - ? $0 + " " + String($1) - : $0 + String($1) - } + return self + .replacingOccurrences(of: "([a-z])([A-Z](?=[A-Z])[a-z]*)", with: "$1 $2", options: .regularExpression) + .replacingOccurrences(of: "([A-Z])([A-Z][a-z])", with: "$1 $2", options: .regularExpression) + .replacingOccurrences(of: "([a-z])([A-Z][a-z])", with: "$1 $2", options: .regularExpression) } var length: Int { diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index bb707885..5484f74a 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -27,7 +27,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate @Published var automaticallyReconnect: Bool = true @Published var mqttProxyConnected: Bool = false @Published var mqttError: String = "" - public var minimumVersion = "2.0.0" + public var minimumVersion = "2.3.2" public var connectedVersion: String public var isConnecting: Bool = false public var isConnected: Bool = false @@ -242,14 +242,14 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate if errorCode == 6 { // CBError.Code.connectionTimeout The connection has timed out unexpectedly. // Happens when device is manually reset / powered off lastConnectionError = "🚨" + String.localizedStringWithFormat("ble.errorcode.6 %@".localized, e.localizedDescription) - Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)") + Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown".localized, privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)") } else if errorCode == 7 { // CBError.Code.peripheralDisconnected The specified device has disconnected from us. // Seems to be what is received when a tbeam sleeps, immediately recconnecting does not work. if UserDefaults.preferredPeripheralId == peripheral.identifier.uuidString { manager.notifications = [ Notification( id: (peripheral.identifier.uuidString), - title: "Radio Disconnected", + title: "Radio Disconnected".localized, subtitle: "\(peripheral.name ?? "unknown".localized)", content: e.localizedDescription, target: "bluetooth", @@ -258,18 +258,18 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate ] manager.schedule() } - lastConnectionError = "🚨 \(e.localizedDescription)" - Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)") + lastConnectionError = "🚨 \("The specified device has disconnected from us".localized)" + Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown".localized, privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)") } else if errorCode == 14 { // Peer removed pairing information // Forgetting and reconnecting seems to be necessary so we need to show the user an error telling them to do that lastConnectionError = "🚨 " + String.localizedStringWithFormat("ble.errorcode.14 %@".localized, e.localizedDescription) - Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown") Error Code: \(errorCode, privacy: .public) Error: \(self.lastConnectionError, privacy: .public)") + Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown".localized) Error Code: \(errorCode, privacy: .public) Error: \(self.lastConnectionError, privacy: .public)") } else { if UserDefaults.preferredPeripheralId == peripheral.identifier.uuidString { manager.notifications = [ Notification( id: (peripheral.identifier.uuidString), - title: "Radio Disconnected", + title: "Radio Disconnected".localized, subtitle: "\(peripheral.name ?? "unknown".localized)", content: e.localizedDescription, target: "bluetooth", @@ -279,12 +279,12 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate manager.schedule() } lastConnectionError = "🚨 \(e.localizedDescription)" - Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)") + Logger.services.error("🚨 [BLE] Disconnected: \(peripheral.name ?? "Unknown".localized, privacy: .public) Error Code: \(errorCode, privacy: .public) Error: \(e.localizedDescription, privacy: .public)") } } else { // Disconnected without error which indicates user intent to disconnect // Happens when swiping to disconnect - Logger.services.info("ℹ️ [BLE] Disconnected: \(peripheral.name ?? "Unknown", privacy: .public): User Initiated Disconnect") + Logger.services.info("ℹ️ [BLE] Disconnected: \(peripheral.name ?? "Unknown".localized, privacy: .public): \(String(describing: "User Initiated Disconnect".localized))") } // Start a scan so the disconnected peripheral is moved to the peripherals[] if it is awake self.startScanning() @@ -988,6 +988,8 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate MeshLogger.log("🕸️ MESH PACKET received for ATAK Plugin App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") case .powerstressApp: MeshLogger.log("🕸️ MESH PACKET received for Power Stress App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") + case .alertApp: + MeshLogger.log("🕸️ MESH PACKET received for Alert App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") } if decodedInfo.configCompleteID != 0 && decodedInfo.configCompleteID == configNonce { @@ -1895,6 +1897,64 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate return false } + public func setIgnoredNode(node: NodeInfoEntity, connectedNodeNum: Int64) -> Bool { + var adminPacket = AdminMessage() + adminPacket.setIgnoredNode = UInt32(node.num) + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = UInt32(connectedNodeNum) + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Bool { + var adminPacket = AdminMessage() + adminPacket.removeIgnoredNode = UInt32(node.num) + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = UInt32(connectedNodeNum) + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Int64 { var adminPacket = AdminMessage() adminPacket.setHamMode = ham diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index a5cfa7ba..fd9ffb8e 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -270,6 +270,7 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje newNode.num = Int64(nodeInfo.num) newNode.channel = Int32(nodeInfo.channel) newNode.favorite = nodeInfo.isFavorite + newNode.ignored = nodeInfo.isIgnored newNode.hopsAway = Int32(nodeInfo.hopsAway) if nodeInfo.hasDeviceMetrics { @@ -358,6 +359,7 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje fetchedNode[0].snr = nodeInfo.snr fetchedNode[0].channel = Int32(nodeInfo.channel) fetchedNode[0].favorite = nodeInfo.isFavorite + fetchedNode[0].ignored = nodeInfo.isIgnored fetchedNode[0].hopsAway = Int32(nodeInfo.hopsAway) if nodeInfo.hasUser { @@ -772,7 +774,8 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage } } } else if telemetry.metricsType == 4 { - // Update our live activity if there is one running, not available on mac iOS >= 16.2 + // Update our live activity if there is one running, not available on mac +#if !targetEnvironment(macCatalyst) #if canImport(ActivityKit) let fifteenMinutesLater = Calendar.current.date(byAdding: .minute, value: (Int(15) ), to: Date())! @@ -801,6 +804,7 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage Logger.services.debug("Updated live activity.") } } +#endif #endif } } catch { @@ -876,6 +880,9 @@ func textMessageAppPacket( if fetchedUsers.first(where: { $0.num == packet.to }) != nil && packet.to != Constants.maximumNodeNum { if !storeForwardBroadcast { newMessage.toUser = fetchedUsers.first(where: { $0.num == packet.to }) + } else { + /// Make a new to user if they are unknown + newMessage.toUser = createUser(num: Int64(truncatingIfNeeded: packet.to), context: context) } } if fetchedUsers.first(where: { $0.num == packet.from }) != nil { @@ -903,11 +910,14 @@ func textMessageAppPacket( newMessage.fromUser?.publicKey = packet.publicKey } } - if packet.rxTime > 0 { - newMessage.fromUser?.userNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) - } else { - newMessage.fromUser?.userNode?.lastHeard = Date() - } + } else { + /// Make a new from user if they are unknown + newMessage.fromUser = createUser(num: Int64(truncatingIfNeeded: packet.from), context: context) + } + if packet.rxTime > 0 { + newMessage.fromUser?.userNode?.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime))) + } else { + newMessage.fromUser?.userNode?.lastHeard = Date() } newMessage.messagePayload = messageText newMessage.messagePayloadMarkdown = generateMessageMarkdown(message: messageText!) diff --git a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion index 6d376a5f..3581f63f 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion +++ b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - MeshtasticDataModelV 46.xcdatamodel + MeshtasticDataModelV 47.xcdatamodel diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 47.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 47.xcdatamodel/contents new file mode 100644 index 00000000..095149bd --- /dev/null +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 47.xcdatamodel/contents @@ -0,0 +1,485 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 9feecf6d..edc21605 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -199,9 +199,9 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) manager.notifications = [ Notification( id: (UUID().uuidString), - title: "New Node", + title: "New Node".localized, subtitle: "\(newUser.longName ?? "unknown".localized)", - content: "New Node has been discovered", + content: "New Node has been discovered".localized, target: "nodes", path: "meshtastic:///nodes?nodenum=\(newUser.num)" ) @@ -832,9 +832,9 @@ func upsertSecurityConfigPacket(config: Config.SecurityConfig, nodeNum: Int64, s if config.adminKey.count > 0 { fetchedNode[0].securityConfig?.adminKey = config.adminKey[0] if config.adminKey.count > 1 { - fetchedNode[0].securityConfig?.adminKey = config.adminKey[1] + fetchedNode[0].securityConfig?.adminKey2 = config.adminKey[1] } else if config.adminKey.count > 2 { - fetchedNode[0].securityConfig?.adminKey = config.adminKey[2] + fetchedNode[0].securityConfig?.adminKey3 = config.adminKey[2] } } fetchedNode[0].securityConfig?.isManaged = config.isManaged diff --git a/Meshtastic/Resources/DeviceHardware.json b/Meshtastic/Resources/DeviceHardware.json index 5e0135b9..a4a6949c 100644 --- a/Meshtastic/Resources/DeviceHardware.json +++ b/Meshtastic/Resources/DeviceHardware.json @@ -86,7 +86,8 @@ ], "images": [ "t-echo.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 8, @@ -113,7 +114,8 @@ "images": [ "rak4631.svg", "rak4631_case.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 10, @@ -139,7 +141,7 @@ }, { "hwModel": 12, - "hwModelSlug": "TBEAM_S3_CORE", + "hwModelSlug": "LILYGO_TBEAM_S3_CORE", "platformioTarget": "tbeam-s3-core", "architecture": "esp32-s3", "activelySupported": true, @@ -150,7 +152,8 @@ ], "images": [ "tbeam-s3-core.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 13, @@ -204,7 +207,8 @@ ], "images": [ "tlora-t3s3-v1.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 16, @@ -219,7 +223,8 @@ ], "images": [ "tlora-t3s3-epaper.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 17, @@ -243,6 +248,10 @@ "displayName": "Nano G2 Ultra", "tags": [ "B&Q" + ], + "requiresDfu": true, + "images": [ + "nano-g2-ultra.svg" ] }, { @@ -258,7 +267,8 @@ ], "images": [ "wio-tracker-wm1110.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 25, @@ -282,7 +292,11 @@ "displayName": "RAK WisBlock 11310", "tags": [ "RAK" - ] + ], + "images": [ + "rak11310.svg" + ], + "requiresDfu": true }, { "hwModel": 29, @@ -294,7 +308,8 @@ "displayName": "Canary One", "tags": [ "Canary" - ] + ], + "requiresDfu": true }, { "hwModel": 30, @@ -306,7 +321,8 @@ "displayName": "RP2040 LoRa", "tags": [ "Waveshare" - ] + ], + "requiresDfu": true }, { "hwModel": 31, @@ -318,6 +334,10 @@ "displayName": "Station G2", "tags": [ "B&Q" + ], + "requiresDfu": true, + "images": [ + "station-g2.svg" ] }, { @@ -330,6 +350,9 @@ "displayName": "DIY V1", "tags": [ "DIY" + ], + "images": [ + "diy.svg" ] }, { @@ -407,8 +430,12 @@ "supportLevel": 3, "displayName": "Raspberry Pi Pico", "tags": [ - "Raspberry Pi", + "RPi", "DIY" + ], + "requiresDfu": true, + "images": [ + "pico.svg" ] }, { @@ -420,8 +447,12 @@ "supportLevel": 3, "displayName": "Raspberry Pi Pico W", "tags": [ - "Raspberry Pi", + "RPi", "DIY" + ], + "requiresDfu": true, + "images": [ + "rpipicow.svg" ] }, { @@ -437,19 +468,21 @@ ], "images": [ "heltec-wireless-tracker.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 58, "hwModelSlug": "HELTEC_WIRELESS_TRACKER_V1_0", "platformioTarget": "heltec-wireless-tracker-V1-0", "architecture": "esp32-s3", - "activelySupported": true, + "activelySupported": false, "supportLevel": 3, "displayName": "Heltec Wireless Tracker V1.0", "images": [ "heltec-wireless-tracker.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 49, @@ -479,7 +512,8 @@ ], "images": [ "t-deck.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 51, @@ -525,7 +559,7 @@ "hwModelSlug": "HELTEC_WIRELESS_PAPER_V1_0", "platformioTarget": "heltec-wireless-paper-v1_0", "architecture": "esp32-s3", - "activelySupported": true, + "activelySupported": false, "supportLevel": 3, "tags": [ "Heltec" @@ -542,7 +576,8 @@ "architecture": "esp32-s3", "activelySupported": true, "supportLevel": 3, - "displayName": "unPhone" + "displayName": "unPhone", + "requiresDfu": true }, { "hwModel": 48, @@ -551,7 +586,8 @@ "architecture": "esp32-s3", "activelySupported": true, "supportLevel": 3, - "displayName": "TrackSenger (small TFT)" + "displayName": "TrackSenger (small TFT)", + "requiresDfu": true }, { "hwModel": 48, @@ -560,7 +596,8 @@ "architecture": "esp32-s3", "activelySupported": true, "supportLevel": 3, - "displayName": "TrackSenger (big TFT)" + "displayName": "TrackSenger (big TFT)", + "requiresDfu": true }, { "hwModel": 48, @@ -581,7 +618,8 @@ "displayName": "EBYTE EoRa-S3", "tags": [ "EByte" - ] + ], + "requiresDfu": true }, { "hwModel": 64, @@ -608,7 +646,8 @@ ], "images": [ "heltec-vision-master-t190.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 67, @@ -623,7 +662,8 @@ ], "images": [ "heltec-vision-master-e213.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 68, @@ -638,7 +678,8 @@ ], "images": [ "heltec-vision-master-e290.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 69, @@ -654,7 +695,8 @@ "images": [ "heltec-mesh-node-t114.svg", "heltec-mesh-node-t114-case.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 70, @@ -684,7 +726,8 @@ ], "images": [ "tracker-t1000-e.svg" - ] + ], + "requiresDfu": true }, { "hwModel": 72, @@ -699,6 +742,23 @@ ], "images": [ "seeed-xiao-s3.svg" - ] + ], + "requiresDfu": true + }, + { + "hwModel": 84, + "hwModelSlug": "WISMESH_TAP", + "platformioTarget": "rak_wismeshtap", + "architecture": "nrf52840", + "activelySupported": false, + "supportLevel": 1, + "displayName": "RAK WisMesh Tap", + "tags": [ + "RAK" + ], + "images": [ + "rak-wismeshtap.svg" + ], + "requiresDfu": true } ] diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index be466530..a424cbf0 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -324,7 +324,8 @@ struct Connect: View { } } } - #if canImport(ActivityKit) +#if !targetEnvironment(macCatalyst) +#if canImport(ActivityKit) func startNodeActivity() { liveActivityStarted = true // 15 Minutes Local Stats Interval @@ -367,8 +368,8 @@ struct Connect: View { } } } - #endif - +#endif +#endif func didDismissSheet() { bleManager.disconnectPeripheral(reconnect: false) } diff --git a/Meshtastic/Views/Bluetooth/InvalidVersion.swift b/Meshtastic/Views/Bluetooth/InvalidVersion.swift index 9c0cca78..ba94e7c1 100644 --- a/Meshtastic/Views/Bluetooth/InvalidVersion.swift +++ b/Meshtastic/Views/Bluetooth/InvalidVersion.swift @@ -41,11 +41,9 @@ struct InvalidVersion: View { .font(.title3) .foregroundColor(.orange) .padding(.bottom) - Text("Version \(minimumVersion) includes breaking changes to devices and the client apps. Only nodes version \(minimumVersion) and above are supported.") + Text("Version \(minimumVersion) includes substantial network optimizations and extensive changes to devices and client apps. Only nodes version \(minimumVersion) and above are supported.") .font(.callout) .padding([.leading, .trailing, .bottom]) - Link("Version 1.2 End of life (EOL) Info", destination: URL(string: "https://meshtastic.org/docs/1.2-End-of-life/")!) - .font(.callout) #if targetEnvironment(macCatalyst) Button { diff --git a/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift b/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift index 03735ae2..688dcc24 100644 --- a/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift +++ b/Meshtastic/Views/Helpers/LoRaSignalStrengthIndicator.swift @@ -47,13 +47,13 @@ enum LoRaSignalStrength: Int { var description: String { switch self { case .none: - return "None" + return "lora.signal.strength.none".localized case .bad: - return "Bad" + return "lora.signal.strength.bad".localized case .fair: - return "Fair" + return "lora.signal.strength.fair".localized case .good: - return "Good" + return "lora.signal.strength.good".localized } } } diff --git a/Meshtastic/Views/Helpers/MQTTIcon.swift b/Meshtastic/Views/Helpers/MQTTIcon.swift index 79821dd1..914c6043 100644 --- a/Meshtastic/Views/Helpers/MQTTIcon.swift +++ b/Meshtastic/Views/Helpers/MQTTIcon.swift @@ -27,7 +27,7 @@ struct MQTTIcon: View { .symbolRenderingMode(.hierarchical) }.popover(isPresented: self.$isPopoverOpen, arrowEdge: .bottom, content: { VStack(spacing: 0.5) { - Text("Topic: " + topic) + Text("Topic: \(topic)".localized) .padding(20) Button("close", action: { self.isPopoverOpen = false }).padding([.bottom], 20) } diff --git a/Meshtastic/Views/Messages/UserList.swift b/Meshtastic/Views/Messages/UserList.swift index 14c826ed..0496a51e 100644 --- a/Meshtastic/Views/Messages/UserList.swift +++ b/Meshtastic/Views/Messages/UserList.swift @@ -20,6 +20,7 @@ struct UserList: View { @State private var isOnline = false @State private var isPkiEncrypted = false @State private var isFavorite = false + @State private var isIgnored = false @State private var isEnvironment = false @State private var distanceFilter = false @State private var maxDistance: Double = 800000 @@ -44,7 +45,7 @@ struct UserList: View { NSSortDescriptor(key: "pkiEncrypted", ascending: false), NSSortDescriptor(key: "userNode.lastHeard", ascending: false), NSSortDescriptor(key: "longName", ascending: true)], - predicate: NSPredicate(format: "longName != ''"), + predicate: NSPredicate(format: "userNode.ignored == false && longName != ''"), animation: .default ) var users: FetchedResults @@ -194,7 +195,7 @@ struct UserList: View { .listStyle(.plain) .navigationTitle(String.localizedStringWithFormat("contacts %@".localized, String(users.count == 0 ? 0 : users.count))) .sheet(isPresented: $editingFilters) { - NodeListFilter(filterTitle: "Contact Filters", viaLora: $viaLora, viaMqtt: $viaMqtt, isOnline: $isOnline, isPkiEncrypted: $isPkiEncrypted, isFavorite: $isFavorite, isEnvironment: $isEnvironment, distanceFilter: $distanceFilter, maximumDistance: $maxDistance, hopsAway: $hopsAway, roleFilter: $roleFilter, deviceRoles: $deviceRoles) + NodeListFilter(filterTitle: "Contact Filters", viaLora: $viaLora, viaMqtt: $viaMqtt, isOnline: $isOnline, isPkiEncrypted: $isPkiEncrypted, isFavorite: $isFavorite, isIgnored: $isIgnored, isEnvironment: $isEnvironment, distanceFilter: $distanceFilter, maximumDistance: $maxDistance, hopsAway: $hopsAway, roleFilter: $roleFilter, deviceRoles: $deviceRoles) } .sheet(isPresented: $showingHelp) { DirectMessagesHelp() diff --git a/Meshtastic/Views/Nodes/Helpers/Actions/IgnoreNodeButton.swift b/Meshtastic/Views/Nodes/Helpers/Actions/IgnoreNodeButton.swift new file mode 100644 index 00000000..0ec05164 --- /dev/null +++ b/Meshtastic/Views/Nodes/Helpers/Actions/IgnoreNodeButton.swift @@ -0,0 +1,45 @@ +import CoreData +import OSLog +import SwiftUI + +struct IgnoreNodeButton: View { + var bleManager: BLEManager + var context: NSManagedObjectContext + + @ObservedObject + var node: NodeInfoEntity + + var body: some View { + Button { + guard let connectedNodeNum = bleManager.connectedPeripheral?.num else { return } + let success = if node.ignored { + bleManager.removeIgnoredNode( + node: node, + connectedNodeNum: Int64(connectedNodeNum) + ) + } else { + bleManager.setIgnoredNode( + node: node, + connectedNodeNum: Int64(connectedNodeNum) + ) + } + if success { + node.ignored = !node.ignored + do { + try context.save() + } catch { + context.rollback() + Logger.data.error("Save Ignored Node Error") + } + Logger.data.debug("Ignored a node") + } + } label: { + Label { + Text(node.ignored ? "Remove from ignored" : "Ignore Node") + } icon: { + Image(systemName: node.ignored ? "minus.circle.fill" : "minus.circle") + .symbolRenderingMode(.multicolor) + } + } + } +} diff --git a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift index d37638a2..e92aefa8 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeDetail.swift @@ -16,6 +16,9 @@ struct NodeDetail: View { formatter.unitsStyle = .full return formatter }() + var modemPreset: ModemPresets = ModemPresets( + rawValue: UserDefaults.modemPreset + ) ?? ModemPresets.longFast @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager @@ -44,6 +47,34 @@ struct NodeDetail: View { NodeInfoItem(node: node) } Section("Node") { + HStack(alignment: .center) { + Spacer() + CircleText( + text: node.user?.shortName ?? "?", + color: Color(UIColor(hex: UInt32(node.num))), + circleSize: 75 + ) + if node.snr != 0 && !node.viaMqtt && node.hopsAway == 0 { + Spacer() + VStack { + let signalStrength = getLoRaSignalStrength(snr: node.snr, rssi: node.rssi, preset: modemPreset) + LoRaSignalStrengthIndicator(signalStrength: signalStrength) + Text("Signal \(signalStrength.description)").font(.footnote) + Text("SNR \(String(format: "%.2f", node.snr))dB") + .foregroundColor(getSnrColor(snr: node.snr, preset: modemPreset)) + .font(.caption) + Text("RSSI \(node.rssi)dB") + .foregroundColor(getRssiColor(rssi: node.rssi)) + .font(.caption) + } + } + if node.telemetries?.count ?? 0 > 0 { + Spacer() + BatteryGauge(node: node) + } + Spacer() + } + .listRowSeparator(.hidden) if let user = node.user { if !user.keyMatch { Label { diff --git a/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift b/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift index e0da484e..9f3b8105 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeInfoItem.swift @@ -12,61 +12,71 @@ import MapKit struct NodeInfoItem: View { @ObservedObject var node: NodeInfoEntity - - var modemPreset: ModemPresets = ModemPresets( - rawValue: UserDefaults.modemPreset - ) ?? ModemPresets.longFast + @State private var currentDevice: DeviceHardware? var body: some View { + if let user = node.user { ViewThatFits(in: .horizontal) { - VStack { - if let user = node.user { - HStack(alignment: .center) { - if user.hwModel != "UNSET" { - Image(user.hardwareImage ?? "UNSET") + HStack { + Spacer() + if user.hwModel != "UNSET" { + VStack(alignment: .center) { + Spacer() + Image(systemName: currentDevice?.activelySupported ?? false ? "checkmark.seal.fill" : "x.circle") .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 65, height: 65) - .cornerRadius(5) - Text(String(node.user?.hwDisplayName ?? (node.user?.hwModel ?? "unset".localized))) - .font(.callout) - } else { - Image(systemName: "person.crop.circle.badge.questionmark") - .resizable() - .aspectRatio(contentMode: .fit) - .frame(width: 65, height: 65) - .cornerRadius(5) - Text(String("incomplete".localized)) + .aspectRatio(contentMode: .fill) + .frame(width: 75, height: 75) + .foregroundStyle(currentDevice?.activelySupported ?? false ? .green : .red) + Text( currentDevice?.activelySupported ?? false ? "Supported" : "Unsupported") + .foregroundStyle(.gray) .font(.callout) } + Spacer() + } + VStack(alignment: .center) { + HStack { + if user.hardwareImage != "UNSET" { + Image(user.hardwareImage ?? "UNSET") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(maxHeight: 150) + .cornerRadius(5) + } else { + Image(systemName: "person.crop.circle.badge.questionmark") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 75, height: 75) + .cornerRadius(5) + } + } + } + Spacer() + } + .onAppear { + Api().loadDeviceHardwareData { (hw) in + for device in hw { + let currentHardware = node.user?.hwModel ?? "UNSET" + let deviceString = device.hwModelSlug.replacingOccurrences(of: "_", with: "").uppercased() + if deviceString == currentHardware { + currentDevice = device + } + } } } - HStack(alignment: .center) { - Spacer() - CircleText( - text: node.user?.shortName ?? "?", - color: Color(UIColor(hex: UInt32(node.num))), - circleSize: 75 - ) - if node.snr != 0 && !node.viaMqtt && node.hopsAway == 0 { - Spacer() - VStack { - let signalStrength = getLoRaSignalStrength(snr: node.snr, rssi: node.rssi, preset: modemPreset) - LoRaSignalStrengthIndicator(signalStrength: signalStrength) - Text("Signal \(signalStrength.description)").font(.footnote) - Text("SNR \(String(format: "%.2f", node.snr))dB") - .foregroundColor(getSnrColor(snr: node.snr, preset: modemPreset)) - .font(.caption) - Text("RSSI \(node.rssi)dB") - .foregroundColor(getRssiColor(rssi: node.rssi)) - .font(.caption) - } - } - if node.telemetries?.count ?? 0 > 0 { - Spacer() - BatteryGauge(node: node) - } - Spacer() + } + .listRowSeparator(.hidden) + HStack { + Label { + Text("Model") + } icon: { + Image(systemName: "flipphone") + .symbolRenderingMode(.hierarchical) + } + Spacer() + if user.hwModel != "UNSET" { + Text(String(node.user?.hwDisplayName ?? (node.user?.hwModel ?? "unset".localized))) + } else { + Text(String("incomplete".localized)) } } } diff --git a/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift b/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift index 210e58d1..454b3607 100644 --- a/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift +++ b/Meshtastic/Views/Nodes/Helpers/NodeListFilter.swift @@ -17,6 +17,7 @@ struct NodeListFilter: View { @Binding var isOnline: Bool @Binding var isPkiEncrypted: Bool @Binding var isFavorite: Bool + @Binding var isIgnored: Bool @Binding var isEnvironment: Bool @Binding var distanceFilter: Bool @Binding var maximumDistance: Double @@ -90,6 +91,18 @@ struct NodeListFilter: View { } .toggleStyle(SwitchToggleStyle(tint: .accentColor)) .listRowSeparator(.visible) + Toggle(isOn: $isIgnored) { + + Label { + Text("Ignored") + } icon: { + + Image(systemName: "minus.circle.fill") + .symbolRenderingMode(.multicolor) + } + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + .listRowSeparator(.visible) if filterTitle == "Node Filters" { Toggle(isOn: $isEnvironment) { diff --git a/Meshtastic/Views/Nodes/MeshMap.swift b/Meshtastic/Views/Nodes/MeshMap.swift index 447f6fdd..65928ba3 100644 --- a/Meshtastic/Views/Nodes/MeshMap.swift +++ b/Meshtastic/Views/Nodes/MeshMap.swift @@ -46,6 +46,7 @@ struct MeshMap: View { @State private var isOnline = false @State private var isPkiEncrypted = false @State private var isFavorite = false + @State private var isIgnored = false @State private var isEnvironment = false @State private var distanceFilter = false @State private var maxDistance: Double = 800000 @@ -161,6 +162,7 @@ struct MeshMap: View { isOnline: $isOnline, isPkiEncrypted: $isPkiEncrypted, isFavorite: $isFavorite, + isIgnored: $isIgnored, isEnvironment: $isEnvironment, distanceFilter: $distanceFilter, maximumDistance: $maxDistance, diff --git a/Meshtastic/Views/Nodes/NodeList.swift b/Meshtastic/Views/Nodes/NodeList.swift index 756f1179..6f031018 100644 --- a/Meshtastic/Views/Nodes/NodeList.swift +++ b/Meshtastic/Views/Nodes/NodeList.swift @@ -26,6 +26,7 @@ struct NodeList: View { @State private var isOnline = false @State private var isPkiEncrypted = false @State private var isFavorite = false + @State private var isIgnored = false @State private var isEnvironment = false @State private var distanceFilter = false @State private var maxDistance: Double = 800000 @@ -40,6 +41,7 @@ struct NodeList: View { var boolFilters: [Bool] {[ isFavorite, + isIgnored, isOnline, isPkiEncrypted, isEnvironment, @@ -53,6 +55,7 @@ struct NodeList: View { @FetchRequest( sortDescriptors: [ + NSSortDescriptor(key: "ignored", ascending: true), NSSortDescriptor(key: "favorite", ascending: false), NSSortDescriptor(key: "lastHeard", ascending: false), NSSortDescriptor(key: "user.longName", ascending: true) @@ -132,6 +135,11 @@ struct NodeList: View { } label: { Label("Exchange Positions", systemImage: "arrow.triangle.2.circlepath") } + IgnoreNodeButton( + bleManager: bleManager, + context: context, + node: node + ) Button(role: .destructive) { deleteNodeId = node.num isPresentingDeleteNodeAlert = true @@ -164,6 +172,7 @@ struct NodeList: View { isOnline: $isOnline, isPkiEncrypted: $isPkiEncrypted, isFavorite: $isFavorite, + isIgnored: $isIgnored, isEnvironment: $isEnvironment, distanceFilter: $distanceFilter, maximumDistance: $maxDistance, @@ -392,6 +401,14 @@ struct NodeList: View { let isFavoritePredicate = NSPredicate(format: "favorite == YES") predicates.append(isFavoritePredicate) } + /// Ignored + if isIgnored { + let isIgnoredPredicate = NSPredicate(format: "ignored == YES") + predicates.append(isIgnoredPredicate) + } else if !isIgnored { + let isIgnoredPredicate = NSPredicate(format: "ignored == NO") + predicates.append(isIgnoredPredicate) + } /// Environment if isEnvironment { let environmentPredicate = NSPredicate(format: "SUBQUERY(telemetries, $tel, $tel.metricsType == 1).@count > 0") diff --git a/Meshtastic/Views/Nodes/TraceRouteLog.swift b/Meshtastic/Views/Nodes/TraceRouteLog.swift index f1095ad5..dd4223f7 100644 --- a/Meshtastic/Views/Nodes/TraceRouteLog.swift +++ b/Meshtastic/Views/Nodes/TraceRouteLog.swift @@ -37,20 +37,21 @@ struct TraceRouteLog: View { VStack { List(node.traceRoutes?.reversed() as? [TraceRouteEntity] ?? [], id: \.self, selection: $selectedRoute) { route in Label { - if route.response && route.hopsTowards == 0 { - Text("\(route.time?.formatted() ?? "unknown".localized) - Direct") - .font(.caption) - } else if route.response && route.hopsTowards == 1 { - Text("\(route.time?.formatted() ?? "unknown".localized) - 1 Hop") + let routeTime = route.time?.formatted() ?? "unknown".localized + if route.response && route.hopsTowards == route.hopsBack { + let hopString = String(localized: "\(route.hopsTowards) Hops") + Text("\(routeTime) - \(hopString)") .font(.caption) } else if route.response { - Text("\(route.time?.formatted() ?? "unknown".localized) - \(route.hopsTowards) Hops Towards \(route.hopsBack) Hops Back") + let hopTowardsString = String(localized: "\(route.hopsTowards) Hops") + let hopBackString = String(localized: "\(route.hopsBack) Hops") + Text("\(routeTime) - \(hopTowardsString) Towards \(hopBackString) Back") .font(.caption) } else if route.sent { - Text("\(route.time?.formatted() ?? "unknown".localized) - No Response") + Text("\(routeTime) - No Response") .font(.caption) } else { - Text("\(route.time?.formatted() ?? "unknown".localized) - Not Sent") + Text("\(routeTime) - Not Sent") .font(.caption) } } icon: { diff --git a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift index 37f989a5..d57dacba 100644 --- a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift +++ b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift @@ -103,7 +103,7 @@ struct BluetoothConfig: View { .onFirstAppear { // Need to request a BluetoothConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty bluetooth config") + let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -111,10 +111,12 @@ struct BluetoothConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.bluetoothConfig == nil { + Logger.mesh.info("⚙️ Empty or expired bluetooth config requesting via PKI admin") _ = bleManager.requestBluetoothConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty bluetooth config") _ = bleManager.requestBluetoothConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/DeviceConfig.swift b/Meshtastic/Views/Settings/Config/DeviceConfig.swift index f5fca283..da2978cf 100644 --- a/Meshtastic/Views/Settings/Config/DeviceConfig.swift +++ b/Meshtastic/Views/Settings/Config/DeviceConfig.swift @@ -78,7 +78,7 @@ struct DeviceConfig: View { .toggleStyle(SwitchToggleStyle(tint: .accentColor)) Toggle(isOn: $tripleClickAsAdHocPing) { - Label("Triple Click Ad Hoc Ping", systemImage: "map.pin") + Label("Triple Click Ad Hoc Ping", systemImage: "mappin") Text("Send a position on the primary channel when the user button is triple clicked.") } .toggleStyle(SwitchToggleStyle(tint: .accentColor)) @@ -229,7 +229,6 @@ struct DeviceConfig: View { .onFirstAppear { // Need to request a DeviceConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty device config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -237,11 +236,13 @@ struct DeviceConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.deviceConfig == nil { + Logger.mesh.info("⚙️ Empty or expired device config requesting via PKI admin") _ = bleManager.requestDeviceConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { if node.deviceConfig == nil { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty device config") _ = bleManager.requestDeviceConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/DisplayConfig.swift b/Meshtastic/Views/Settings/Config/DisplayConfig.swift index 07975419..88839956 100644 --- a/Meshtastic/Views/Settings/Config/DisplayConfig.swift +++ b/Meshtastic/Views/Settings/Config/DisplayConfig.swift @@ -166,7 +166,6 @@ struct DisplayConfig: View { .onFirstAppear { // Need to request a DisplayConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty display config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -174,10 +173,12 @@ struct DisplayConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.displayConfig == nil { + Logger.mesh.info("⚙️ Empty or expired display config requesting via PKI admin") _ = bleManager.requestDisplayConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty display config") _ = bleManager.requestDisplayConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/LoRaConfig.swift b/Meshtastic/Views/Settings/Config/LoRaConfig.swift index 4c12c598..51461cf0 100644 --- a/Meshtastic/Views/Settings/Config/LoRaConfig.swift +++ b/Meshtastic/Views/Settings/Config/LoRaConfig.swift @@ -241,7 +241,6 @@ struct LoRaConfig: View { .onFirstAppear { // Need to request a LoRaConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty lora config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -249,10 +248,13 @@ struct LoRaConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.loRaConfig == nil { + Logger.mesh.info("⚙️ Empty or expired lora config requesting via PKI admin") + _ = bleManager.requestLoRaConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty lora config") _ = bleManager.requestLoRaConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift b/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift index fc82a4ca..62340da8 100644 --- a/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/AmbientLightingConfig.swift @@ -88,7 +88,6 @@ struct AmbientLightingConfig: View { .onFirstAppear { // Need to request a Ambient Lighting Config from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty ambient lighting config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -96,10 +95,12 @@ struct AmbientLightingConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.ambientLightingConfig == nil { + Logger.mesh.info("⚙️ Empty or expired ambient lighting module config requesting via PKI admin") _ = bleManager.requestAmbientLightingConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty ambient lighting module config") _ = bleManager.requestAmbientLightingConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift index 4f580b2a..b5dfee63 100644 --- a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift @@ -236,7 +236,6 @@ struct CannedMessagesConfig: View { .onFirstAppear { // Need to request a CannedMessagesModuleConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty canned message config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -244,10 +243,12 @@ struct CannedMessagesConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.cannedMessageConfig == nil { + Logger.mesh.info("⚙️ Empty or expired canned messages module config requesting via PKI admin") _ = bleManager.requestCannedMessagesModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty canned messages module config") _ = bleManager.requestCannedMessagesModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift b/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift index aff3dfea..59ee4f3f 100644 --- a/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift @@ -194,7 +194,6 @@ struct DetectionSensorConfig: View { .onFirstAppear { // Need to request a DetectionSensorModuleConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty detection sensor config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -202,10 +201,12 @@ struct DetectionSensorConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.detectionSensorConfig == nil { + Logger.mesh.info("⚙️ Empty or expired detection sensor module config requesting via PKI admin") _ = bleManager.requestDetectionSensorModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty detection sensor module config") _ = bleManager.requestDetectionSensorModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift index a0f14c7f..9602c44b 100644 --- a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift @@ -202,7 +202,6 @@ struct ExternalNotificationConfig: View { .onFirstAppear { // Need to request a ExternalNotificationModuleConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty external notificaiton module config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -210,10 +209,12 @@ struct ExternalNotificationConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.externalNotificationConfig == nil { + Logger.mesh.info("⚙️ Empty or expired external notificaiton module config requesting via PKI admin") _ = bleManager.requestExternalNotificationModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty external notificaiton module config") _ = bleManager.requestExternalNotificationModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift index 224fd43c..fc93e6f9 100644 --- a/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/MQTTConfig.swift @@ -322,7 +322,6 @@ struct MQTTConfig: View { .onFirstAppear { // Need to request a MqttModuleConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty mqtt module config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -330,10 +329,12 @@ struct MQTTConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.mqttConfig == nil { + Logger.mesh.info("⚙️ Empty or expired mqtt module config requesting via PKI admin") _ = bleManager.requestMqttModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty mqtt module config") _ = bleManager.requestMqttModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } @@ -346,8 +347,8 @@ struct MQTTConfig: View { nearbyTopics = [] let geocoder = CLGeocoder() if LocationsHandler.shared.locationsArray.count > 0 { - let region = RegionCodes(rawValue: Int(node?.loRaConfig?.regionCode ?? 0))?.topic - defaultTopic = "msh/" + (region ?? "UNSET") + let region = RegionCodes(rawValue: Int(node?.loRaConfig?.regionCode ?? 0)) + defaultTopic = "msh/" + (region?.topic ?? "UNSET") geocoder.reverseGeocodeLocation(LocationsHandler.shared.locationsArray.first!, completionHandler: {(placemarks, error) in if let error { Logger.services.error("Failed to reverse geocode location: \(error.localizedDescription)") @@ -356,8 +357,8 @@ struct MQTTConfig: View { if let placemarks = placemarks, let placemark = placemarks.first { let cc = locale.region?.identifier ?? "UNK" - /// Country Topic unless you are US - if placemark.isoCountryCode ?? "unknown" != cc { + /// Country Topic unless your region is a country + if !(region?.isCountry ?? false) { let countryTopic = defaultTopic + "/" + (placemark.isoCountryCode ?? "") if !countryTopic.isEmpty { nearbyTopics.append(countryTopic) diff --git a/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift b/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift index 2fd97646..24af3504 100644 --- a/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/PaxCounterConfig.swift @@ -61,7 +61,6 @@ struct PaxCounterConfig: View { .onFirstAppear { // Need to request a PaxCounterModuleConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty pax counter module config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -69,10 +68,12 @@ struct PaxCounterConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.paxCounterConfig == nil { + Logger.mesh.info("⚙️ Empty or expired pax counter module config requesting via PKI admin") _ = bleManager.requestPaxCounterModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty pax counter module config") _ = bleManager.requestPaxCounterModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift index ae4797fc..979eb736 100644 --- a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift @@ -84,7 +84,6 @@ struct RangeTestConfig: View { .onFirstAppear { // Need to request a RangeTestModuleConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty range test module config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -92,10 +91,12 @@ struct RangeTestConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.rangeTestConfig == nil { + Logger.mesh.info("⚙️ Empty or expired range test module config requesting via PKI admin") _ = bleManager.requestRangeTestModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty range test module config") _ = bleManager.requestRangeTestModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/Module/RtttlConfig.swift b/Meshtastic/Views/Settings/Config/Module/RtttlConfig.swift index 2e0931a7..b81e2348 100644 --- a/Meshtastic/Views/Settings/Config/Module/RtttlConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/RtttlConfig.swift @@ -75,7 +75,6 @@ struct RtttlConfig: View { .onFirstAppear { // Need to request a RtttlConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty range test module config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -83,10 +82,12 @@ struct RtttlConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.rtttlConfig == nil { + Logger.mesh.info("⚙️ Empty or expired ringtone module config requesting via PKI admin") _ = bleManager.requestRtttlConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty ringtone module config") _ = bleManager.requestRtttlConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift b/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift index a7fd5bdb..fd2c0c99 100644 --- a/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/SerialConfig.swift @@ -139,7 +139,6 @@ struct SerialConfig: View { .onFirstAppear { // Need to request a SerialModuleConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty serial module config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -147,10 +146,12 @@ struct SerialConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.serialConfig == nil { + Logger.mesh.info("⚙️ Empty or expired serial module config requesting via PKI admin") _ = bleManager.requestSerialModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty serial module config") _ = bleManager.requestSerialModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift index d90ea3fb..9c247acf 100644 --- a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift @@ -149,7 +149,6 @@ struct StoreForwardConfig: View { .onFirstAppear { // Need to request a StoreForwardModuleConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty store & forward module config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -157,10 +156,12 @@ struct StoreForwardConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.storeForwardConfig == nil { + Logger.mesh.info("⚙️ Empty or expired store & forward module config requesting via PKI admin") _ = bleManager.requestStoreAndForwardModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty store & forward module config") _ = bleManager.requestStoreAndForwardModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift b/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift index 4ba39834..ad173dae 100644 --- a/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift @@ -137,7 +137,6 @@ struct TelemetryConfig: View { .onFirstAppear { // Need to request a TelemetryModuleConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty telemetry module config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -145,10 +144,12 @@ struct TelemetryConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.telemetryConfig == nil { + Logger.mesh.info("⚙️ Empty or expired telemetry module config requesting via PKI admin") _ = bleManager.requestTelemetryModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty telemetry module config") _ = bleManager.requestTelemetryModuleConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/NetworkConfig.swift b/Meshtastic/Views/Settings/Config/NetworkConfig.swift index 8cebde85..84f48c41 100644 --- a/Meshtastic/Views/Settings/Config/NetworkConfig.swift +++ b/Meshtastic/Views/Settings/Config/NetworkConfig.swift @@ -133,7 +133,6 @@ struct NetworkConfig: View { .onFirstAppear { // Need to request a NetworkConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty network config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -141,10 +140,12 @@ struct NetworkConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.networkConfig == nil { + Logger.mesh.info("⚙️ Empty or expired network config requesting via PKI admin") _ = bleManager.requestNetworkConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty network config") _ = bleManager.requestNetworkConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/PositionConfig.swift b/Meshtastic/Views/Settings/Config/PositionConfig.swift index 451ac02d..f963b02b 100644 --- a/Meshtastic/Views/Settings/Config/PositionConfig.swift +++ b/Meshtastic/Views/Settings/Config/PositionConfig.swift @@ -410,7 +410,6 @@ struct PositionConfig: View { supportedVersion = bleManager.connectedVersion == "0.0.0" || self.minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(bleManager.connectedVersion, options: .numeric) == .orderedSame // Need to request a NetworkConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty position config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -418,10 +417,12 @@ struct PositionConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.positionConfig == nil { + Logger.mesh.info("⚙️ Empty or expired position config requesting via PKI admin") _ = bleManager.requestPositionConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty position config") _ = bleManager.requestPositionConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/PowerConfig.swift b/Meshtastic/Views/Settings/Config/PowerConfig.swift index 822fd1e0..e9f7c0e5 100644 --- a/Meshtastic/Views/Settings/Config/PowerConfig.swift +++ b/Meshtastic/Views/Settings/Config/PowerConfig.swift @@ -130,7 +130,7 @@ struct PowerConfig: View { } // Need to request a NetworkConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty power config") + let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -138,10 +138,12 @@ struct PowerConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.powerConfig == nil { + Logger.mesh.info("⚙️ Empty or expired power config requesting via PKI admin") _ = bleManager.requestPowerConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty power config") _ = bleManager.requestPowerConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 5fb391b3..6f16c8ff 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -85,7 +85,7 @@ struct SecurityConfig: View { .font(idiom == .phone ? .caption : .callout) Divider() Label("Tertiary Admin Key", systemImage: "key.viewfinder") - SecureInput("Tertiary Admin Key", text: $adminKey3, isValid: $hasValidAdminKey2) + SecureInput("Tertiary Admin Key", text: $adminKey3, isValid: $hasValidAdminKey3) .background( RoundedRectangle(cornerRadius: 10.0) .stroke(hasValidAdminKey3 ? Color.clear : Color.red, lineWidth: 2.0) @@ -198,7 +198,6 @@ struct SecurityConfig: View { .onFirstAppear { // Need to request a DeviceConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { - Logger.mesh.info("empty security config") let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context) if let connectedNode { if node.num != connectedNode.num { @@ -206,11 +205,13 @@ struct SecurityConfig: View { /// 2.5 Administration with session passkey let expiration = node.sessionExpiration ?? Date() if expiration < Date() || node.securityConfig == nil { + Logger.mesh.info("⚙️ Empty or expired security config requesting via PKI admin") _ = bleManager.requestSecurityConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } else { if node.deviceConfig == nil { /// Legacy Administration + Logger.mesh.info("☠️ Using insecure legacy admin, empty security config") _ = bleManager.requestSecurityConfig(fromUser: connectedNode.user!, toUser: node.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) } } diff --git a/Meshtastic/Views/Settings/Firmware.swift b/Meshtastic/Views/Settings/Firmware.swift index 9962e69d..76922d54 100644 --- a/Meshtastic/Views/Settings/Firmware.swift +++ b/Meshtastic/Views/Settings/Firmware.swift @@ -148,7 +148,7 @@ struct Firmware: View { VStack(alignment: .leading) { Text("ESP32 Device Firmware Update") .font(.title3) - Text("Currently the reccomended way to update ESP32 devices is using the web flasher on a desktop computer from a chrome based browser. It does not work on mobile devices or over BLE.") + Text("Currently the recommended way to update ESP32 devices is using the web flasher on a desktop computer from a chrome based browser. It does not work on mobile devices or over BLE.") .font(.caption) Link("Web Flasher", destination: URL(string: "https://flash.meshtastic.org")!) .font(.callout) @@ -185,7 +185,7 @@ struct Firmware: View { } .padding() .padding(.bottom, 5) - .onAppear { + .onFirstAppear { Api().loadDeviceHardwareData { (hw) in for device in hw { let currentHardware = node?.user?.hwModel ?? "UNSET" diff --git a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift index 9e7fe0c5..15510b87 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/admin.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/admin.proto @@ -24,7 +25,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// This message is handled by the Admin module and is responsible for all settings/channel read/write operations. /// This message is used to do settings operations to both remote AND local nodes. /// (Prior to 1.2 these operations were done via special ToRadio operations) -public struct AdminMessage { +public struct AdminMessage: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -416,6 +417,26 @@ public struct AdminMessage { set {payloadVariant = .storeUiConfig(newValue)} } + /// + /// Set specified node-num to be ignored on the NodeDB on the device + public var setIgnoredNode: UInt32 { + get { + if case .setIgnoredNode(let v)? = payloadVariant {return v} + return 0 + } + set {payloadVariant = .setIgnoredNode(newValue)} + } + + /// + /// Set specified node-num to be un-ignored on the NodeDB on the device + public var removeIgnoredNode: UInt32 { + get { + if case .removeIgnoredNode(let v)? = payloadVariant {return v} + return 0 + } + set {payloadVariant = .removeIgnoredNode(newValue)} + } + /// /// Begins an edit transaction for config, module config, owner, and channel settings changes /// This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) @@ -513,7 +534,7 @@ public struct AdminMessage { /// /// TODO: REPLACE - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Send the specified channel in the response to this message /// NOTE: This field is sent with the channel index + 1 (to ensure we never try to send 'zero' - which protobufs treats as not present) @@ -633,6 +654,12 @@ public struct AdminMessage { /// Tell the node to store UI data persistently. case storeUiConfig(DeviceUIConfig) /// + /// Set specified node-num to be ignored on the NodeDB on the device + case setIgnoredNode(UInt32) + /// + /// Set specified node-num to be un-ignored on the NodeDB on the device + case removeIgnoredNode(UInt32) + /// /// Begins an edit transaction for config, module config, owner, and channel settings changes /// This will delay the standard *implicit* save to the file system and subsequent reboot behavior until committed (commit_edit_settings) case beginEditSettings(Bool) @@ -663,205 +690,11 @@ public struct AdminMessage { /// Tell the node to reset the nodedb. case nodedbReset(Int32) - #if !swift(>=4.1) - public static func ==(lhs: AdminMessage.OneOf_PayloadVariant, rhs: AdminMessage.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.getChannelRequest, .getChannelRequest): return { - guard case .getChannelRequest(let l) = lhs, case .getChannelRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getChannelResponse, .getChannelResponse): return { - guard case .getChannelResponse(let l) = lhs, case .getChannelResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getOwnerRequest, .getOwnerRequest): return { - guard case .getOwnerRequest(let l) = lhs, case .getOwnerRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getOwnerResponse, .getOwnerResponse): return { - guard case .getOwnerResponse(let l) = lhs, case .getOwnerResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getConfigRequest, .getConfigRequest): return { - guard case .getConfigRequest(let l) = lhs, case .getConfigRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getConfigResponse, .getConfigResponse): return { - guard case .getConfigResponse(let l) = lhs, case .getConfigResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getModuleConfigRequest, .getModuleConfigRequest): return { - guard case .getModuleConfigRequest(let l) = lhs, case .getModuleConfigRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getModuleConfigResponse, .getModuleConfigResponse): return { - guard case .getModuleConfigResponse(let l) = lhs, case .getModuleConfigResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getCannedMessageModuleMessagesRequest, .getCannedMessageModuleMessagesRequest): return { - guard case .getCannedMessageModuleMessagesRequest(let l) = lhs, case .getCannedMessageModuleMessagesRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getCannedMessageModuleMessagesResponse, .getCannedMessageModuleMessagesResponse): return { - guard case .getCannedMessageModuleMessagesResponse(let l) = lhs, case .getCannedMessageModuleMessagesResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceMetadataRequest, .getDeviceMetadataRequest): return { - guard case .getDeviceMetadataRequest(let l) = lhs, case .getDeviceMetadataRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceMetadataResponse, .getDeviceMetadataResponse): return { - guard case .getDeviceMetadataResponse(let l) = lhs, case .getDeviceMetadataResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getRingtoneRequest, .getRingtoneRequest): return { - guard case .getRingtoneRequest(let l) = lhs, case .getRingtoneRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getRingtoneResponse, .getRingtoneResponse): return { - guard case .getRingtoneResponse(let l) = lhs, case .getRingtoneResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceConnectionStatusRequest, .getDeviceConnectionStatusRequest): return { - guard case .getDeviceConnectionStatusRequest(let l) = lhs, case .getDeviceConnectionStatusRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getDeviceConnectionStatusResponse, .getDeviceConnectionStatusResponse): return { - guard case .getDeviceConnectionStatusResponse(let l) = lhs, case .getDeviceConnectionStatusResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setHamMode, .setHamMode): return { - guard case .setHamMode(let l) = lhs, case .setHamMode(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getNodeRemoteHardwarePinsRequest, .getNodeRemoteHardwarePinsRequest): return { - guard case .getNodeRemoteHardwarePinsRequest(let l) = lhs, case .getNodeRemoteHardwarePinsRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getNodeRemoteHardwarePinsResponse, .getNodeRemoteHardwarePinsResponse): return { - guard case .getNodeRemoteHardwarePinsResponse(let l) = lhs, case .getNodeRemoteHardwarePinsResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.enterDfuModeRequest, .enterDfuModeRequest): return { - guard case .enterDfuModeRequest(let l) = lhs, case .enterDfuModeRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.deleteFileRequest, .deleteFileRequest): return { - guard case .deleteFileRequest(let l) = lhs, case .deleteFileRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setScale, .setScale): return { - guard case .setScale(let l) = lhs, case .setScale(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setOwner, .setOwner): return { - guard case .setOwner(let l) = lhs, case .setOwner(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setChannel, .setChannel): return { - guard case .setChannel(let l) = lhs, case .setChannel(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setConfig, .setConfig): return { - guard case .setConfig(let l) = lhs, case .setConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setModuleConfig, .setModuleConfig): return { - guard case .setModuleConfig(let l) = lhs, case .setModuleConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setCannedMessageModuleMessages, .setCannedMessageModuleMessages): return { - guard case .setCannedMessageModuleMessages(let l) = lhs, case .setCannedMessageModuleMessages(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setRingtoneMessage, .setRingtoneMessage): return { - guard case .setRingtoneMessage(let l) = lhs, case .setRingtoneMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.removeByNodenum, .removeByNodenum): return { - guard case .removeByNodenum(let l) = lhs, case .removeByNodenum(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setFavoriteNode, .setFavoriteNode): return { - guard case .setFavoriteNode(let l) = lhs, case .setFavoriteNode(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.removeFavoriteNode, .removeFavoriteNode): return { - guard case .removeFavoriteNode(let l) = lhs, case .removeFavoriteNode(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setFixedPosition, .setFixedPosition): return { - guard case .setFixedPosition(let l) = lhs, case .setFixedPosition(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.removeFixedPosition, .removeFixedPosition): return { - guard case .removeFixedPosition(let l) = lhs, case .removeFixedPosition(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.setTimeOnly, .setTimeOnly): return { - guard case .setTimeOnly(let l) = lhs, case .setTimeOnly(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getUiConfigRequest, .getUiConfigRequest): return { - guard case .getUiConfigRequest(let l) = lhs, case .getUiConfigRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.getUiConfigResponse, .getUiConfigResponse): return { - guard case .getUiConfigResponse(let l) = lhs, case .getUiConfigResponse(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.storeUiConfig, .storeUiConfig): return { - guard case .storeUiConfig(let l) = lhs, case .storeUiConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.beginEditSettings, .beginEditSettings): return { - guard case .beginEditSettings(let l) = lhs, case .beginEditSettings(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.commitEditSettings, .commitEditSettings): return { - guard case .commitEditSettings(let l) = lhs, case .commitEditSettings(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.factoryResetDevice, .factoryResetDevice): return { - guard case .factoryResetDevice(let l) = lhs, case .factoryResetDevice(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rebootOtaSeconds, .rebootOtaSeconds): return { - guard case .rebootOtaSeconds(let l) = lhs, case .rebootOtaSeconds(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.exitSimulator, .exitSimulator): return { - guard case .exitSimulator(let l) = lhs, case .exitSimulator(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rebootSeconds, .rebootSeconds): return { - guard case .rebootSeconds(let l) = lhs, case .rebootSeconds(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.shutdownSeconds, .shutdownSeconds): return { - guard case .shutdownSeconds(let l) = lhs, case .shutdownSeconds(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.factoryResetConfig, .factoryResetConfig): return { - guard case .factoryResetConfig(let l) = lhs, case .factoryResetConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.nodedbReset, .nodedbReset): return { - guard case .nodedbReset(let l) = lhs, case .nodedbReset(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// TODO: REPLACE - public enum ConfigType: SwiftProtobuf.Enum { + public enum ConfigType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -938,11 +771,25 @@ public struct AdminMessage { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [AdminMessage.ConfigType] = [ + .deviceConfig, + .positionConfig, + .powerConfig, + .networkConfig, + .displayConfig, + .loraConfig, + .bluetoothConfig, + .securityConfig, + .sessionkeyConfig, + .deviceuiConfig, + ] + } /// /// TODO: REPLACE - public enum ModuleConfigType: SwiftProtobuf.Enum { + public enum ModuleConfigType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1040,53 +887,31 @@ public struct AdminMessage { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [AdminMessage.ModuleConfigType] = [ + .mqttConfig, + .serialConfig, + .extnotifConfig, + .storeforwardConfig, + .rangetestConfig, + .telemetryConfig, + .cannedmsgConfig, + .audioConfig, + .remotehardwareConfig, + .neighborinfoConfig, + .ambientlightingConfig, + .detectionsensorConfig, + .paxcounterConfig, + ] + } public init() {} } -#if swift(>=4.2) - -extension AdminMessage.ConfigType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [AdminMessage.ConfigType] = [ - .deviceConfig, - .positionConfig, - .powerConfig, - .networkConfig, - .displayConfig, - .loraConfig, - .bluetoothConfig, - .securityConfig, - .sessionkeyConfig, - .deviceuiConfig, - ] -} - -extension AdminMessage.ModuleConfigType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [AdminMessage.ModuleConfigType] = [ - .mqttConfig, - .serialConfig, - .extnotifConfig, - .storeforwardConfig, - .rangetestConfig, - .telemetryConfig, - .cannedmsgConfig, - .audioConfig, - .remotehardwareConfig, - .neighborinfoConfig, - .ambientlightingConfig, - .detectionsensorConfig, - .paxcounterConfig, - ] -} - -#endif // swift(>=4.2) - /// /// Parameters for setting up Meshtastic for ameteur radio usage -public struct HamParameters { +public struct HamParameters: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1116,7 +941,7 @@ public struct HamParameters { /// /// Response envelope for node_remote_hardware_pins -public struct NodeRemoteHardwarePinsResponse { +public struct NodeRemoteHardwarePinsResponse: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1130,15 +955,6 @@ public struct NodeRemoteHardwarePinsResponse { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension AdminMessage: @unchecked Sendable {} -extension AdminMessage.OneOf_PayloadVariant: @unchecked Sendable {} -extension AdminMessage.ConfigType: @unchecked Sendable {} -extension AdminMessage.ModuleConfigType: @unchecked Sendable {} -extension HamParameters: @unchecked Sendable {} -extension NodeRemoteHardwarePinsResponse: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -1184,6 +1000,8 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat 44: .standard(proto: "get_ui_config_request"), 45: .standard(proto: "get_ui_config_response"), 46: .standard(proto: "store_ui_config"), + 47: .standard(proto: "set_ignored_node"), + 48: .standard(proto: "remove_ignored_node"), 64: .standard(proto: "begin_edit_settings"), 65: .standard(proto: "commit_edit_settings"), 94: .standard(proto: "factory_reset_device"), @@ -1572,6 +1390,22 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat self.payloadVariant = .storeUiConfig(v) } }() + case 47: try { + var v: UInt32? + try decoder.decodeSingularUInt32Field(value: &v) + if let v = v { + if self.payloadVariant != nil {try decoder.handleConflictingOneOf()} + self.payloadVariant = .setIgnoredNode(v) + } + }() + case 48: try { + var v: UInt32? + try decoder.decodeSingularUInt32Field(value: &v) + if let v = v { + if self.payloadVariant != nil {try decoder.handleConflictingOneOf()} + self.payloadVariant = .removeIgnoredNode(v) + } + }() case 64: try { var v: Bool? try decoder.decodeSingularBoolField(value: &v) @@ -1804,6 +1638,14 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat guard case .storeUiConfig(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularMessageField(value: v, fieldNumber: 46) }() + case .setIgnoredNode?: try { + guard case .setIgnoredNode(let v)? = self.payloadVariant else { preconditionFailure() } + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 47) + }() + case .removeIgnoredNode?: try { + guard case .removeIgnoredNode(let v)? = self.payloadVariant else { preconditionFailure() } + try visitor.visitSingularUInt32Field(value: v, fieldNumber: 48) + }() case .beginEditSettings?: try { guard case .beginEditSettings(let v)? = self.payloadVariant else { preconditionFailure() } try visitor.visitSingularBoolField(value: v, fieldNumber: 64) @@ -1920,7 +1762,7 @@ extension HamParameters: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if self.txPower != 0 { try visitor.visitSingularInt32Field(value: self.txPower, fieldNumber: 2) } - if self.frequency != 0 { + if self.frequency.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.frequency, fieldNumber: 3) } if !self.shortName.isEmpty { diff --git a/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift index 0457077c..52dac5ca 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/apponly.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/apponly.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -26,7 +26,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// 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 -public struct ChannelSet { +public struct ChannelSet: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -53,10 +53,6 @@ public struct ChannelSet { fileprivate var _loraConfig: Config.LoRaConfig? = nil } -#if swift(>=5.5) && canImport(_Concurrency) -extension ChannelSet: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift index 867648a9..06d6af88 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/atak.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/atak.proto @@ -20,7 +21,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum Team: SwiftProtobuf.Enum { +public enum Team: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -130,11 +131,6 @@ public enum Team: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension Team: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Team] = [ .unspecifedColor, @@ -153,13 +149,12 @@ extension Team: CaseIterable { .darkGreen, .brown, ] -} -#endif // swift(>=4.2) +} /// /// Role of the group member -public enum MemberRole: SwiftProtobuf.Enum { +public enum MemberRole: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -233,11 +228,6 @@ public enum MemberRole: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension MemberRole: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [MemberRole] = [ .unspecifed, @@ -250,13 +240,12 @@ extension MemberRole: CaseIterable { .rto, .k9, ] -} -#endif // swift(>=4.2) +} /// /// Packets for the official ATAK Plugin -public struct TAKPacket { +public struct TAKPacket: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -337,7 +326,7 @@ public struct TAKPacket { /// /// The payload of the packet - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, @unchecked Sendable { /// /// TAK position report case pli(PLI) @@ -349,28 +338,6 @@ public struct TAKPacket { /// May be compressed / truncated by the sender (EUD) case detail(Data) - #if !swift(>=4.1) - public static func ==(lhs: TAKPacket.OneOf_PayloadVariant, rhs: TAKPacket.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.pli, .pli): return { - guard case .pli(let l) = lhs, case .pli(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.chat, .chat): return { - guard case .chat(let l) = lhs, case .chat(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.detail, .detail): return { - guard case .detail(let l) = lhs, case .detail(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -382,7 +349,7 @@ public struct TAKPacket { /// /// ATAK GeoChat message -public struct GeoChat { +public struct GeoChat: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -424,7 +391,7 @@ public struct GeoChat { /// /// ATAK Group /// <__group role='Team Member' name='Cyan'/> -public struct Group { +public struct Group: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -446,7 +413,7 @@ public struct Group { /// /// ATAK EUD Status /// -public struct Status { +public struct Status: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -463,7 +430,7 @@ public struct Status { /// /// ATAK Contact /// -public struct Contact { +public struct Contact: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -483,7 +450,7 @@ public struct Contact { /// /// Position Location Information from ATAK -public struct PLI { +public struct PLI: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -515,18 +482,6 @@ public struct PLI { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension Team: @unchecked Sendable {} -extension MemberRole: @unchecked Sendable {} -extension TAKPacket: @unchecked Sendable {} -extension TAKPacket.OneOf_PayloadVariant: @unchecked Sendable {} -extension GeoChat: @unchecked Sendable {} -extension Group: @unchecked Sendable {} -extension Status: @unchecked Sendable {} -extension Contact: @unchecked Sendable {} -extension PLI: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift index 1b8c84de..ce1f0503 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/cannedmessages.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/cannedmessages.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Canned message module configuration. -public struct CannedMessageModuleConfig { +public struct CannedMessageModuleConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -36,10 +36,6 @@ public struct CannedMessageModuleConfig { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension CannedMessageModuleConfig: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift index 5b9c7e49..180cd698 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/channel.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/channel.proto @@ -36,13 +37,15 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// 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 -public struct ChannelSettings { +public struct ChannelSettings: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. /// /// Deprecated in favor of LoraConfig.channel_num + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var channelNum: UInt32 = 0 /// @@ -111,7 +114,7 @@ public struct ChannelSettings { /// /// This message is specifically for modules to store per-channel configuration data. -public struct ModuleSettings { +public struct ModuleSettings: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -132,7 +135,7 @@ public struct ModuleSettings { /// /// A pair of a channel number, mode and the (sharable) settings for that channel -public struct Channel { +public struct Channel: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -170,7 +173,7 @@ public struct Channel { /// 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) - public enum Role: SwiftProtobuf.Enum { + public enum Role: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -209,6 +212,13 @@ public struct Channel { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Channel.Role] = [ + .disabled, + .primary, + .secondary, + ] + } public init() {} @@ -216,26 +226,6 @@ public struct Channel { fileprivate var _settings: ChannelSettings? = nil } -#if swift(>=4.2) - -extension Channel.Role: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Channel.Role] = [ - .disabled, - .primary, - .secondary, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension ChannelSettings: @unchecked Sendable {} -extension ModuleSettings: @unchecked Sendable {} -extension Channel: @unchecked Sendable {} -extension Channel.Role: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift index f89a8e3c..d72c0ae1 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/clientonly.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/clientonly.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -23,7 +23,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// This abstraction is used to contain any configuration for provisioning a node on any client. /// It is useful for importing and exporting configurations. -public struct DeviceProfile { +public struct DeviceProfile: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -130,10 +130,6 @@ public struct DeviceProfile { fileprivate var _cannedMessages: String? = nil } -#if swift(>=5.5) && canImport(_Concurrency) -extension DeviceProfile: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift index 49f405f1..c8c90be7 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/config.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/config.proto @@ -20,7 +21,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct Config { +public struct Config: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -113,7 +114,7 @@ public struct Config { /// /// Payload Variant - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { case device(Config.DeviceConfig) case position(Config.PositionConfig) case power(Config.PowerConfig) @@ -125,61 +126,11 @@ public struct Config { case sessionkey(Config.SessionkeyConfig) case deviceUi(DeviceUIConfig) - #if !swift(>=4.1) - public static func ==(lhs: Config.OneOf_PayloadVariant, rhs: Config.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.device, .device): return { - guard case .device(let l) = lhs, case .device(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.position, .position): return { - guard case .position(let l) = lhs, case .position(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.power, .power): return { - guard case .power(let l) = lhs, case .power(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.network, .network): return { - guard case .network(let l) = lhs, case .network(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.display, .display): return { - guard case .display(let l) = lhs, case .display(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.lora, .lora): return { - guard case .lora(let l) = lhs, case .lora(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.bluetooth, .bluetooth): return { - guard case .bluetooth(let l) = lhs, case .bluetooth(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.security, .security): return { - guard case .security(let l) = lhs, case .security(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.sessionkey, .sessionkey): return { - guard case .sessionkey(let l) = lhs, case .sessionkey(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.deviceUi, .deviceUi): return { - guard case .deviceUi(let l) = lhs, case .deviceUi(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// Configuration - public struct DeviceConfig { + public struct DeviceConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -191,6 +142,8 @@ public struct Config { /// /// Disabling this will disable the SerialConsole by not initilizing the StreamAPI /// Moved to SecurityConfig + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var serialEnabled: Bool = false /// @@ -220,6 +173,8 @@ public struct Config { /// If true, device is considered to be "managed" by a mesh administrator /// Clients should then limit available configuration and administrative options inside the user interface /// Moved to SecurityConfig + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var isManaged: Bool = false /// @@ -238,7 +193,7 @@ public struct Config { /// /// Defines the device's role on the Mesh network - public enum Role: SwiftProtobuf.Enum { + public enum Role: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -256,6 +211,8 @@ public struct Config { /// The wifi radio and the oled screen will be put to sleep. /// This mode may still potentially have higher power usage due to it's preference in message rebroadcasting on the mesh. case router // = 2 + + /// NOTE: This enum value was marked as deprecated in the .proto file case routerClient // = 3 /// @@ -346,11 +303,26 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DeviceConfig.Role] = [ + .client, + .clientMute, + .router, + .routerClient, + .repeater, + .tracker, + .sensor, + .tak, + .clientHidden, + .lostAndFound, + .takTracker, + ] + } /// /// Defines the device's behavior for how messages are rebroadcast - public enum RebroadcastMode: SwiftProtobuf.Enum { + public enum RebroadcastMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -411,6 +383,16 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DeviceConfig.RebroadcastMode] = [ + .all, + .allSkipDecoding, + .localOnly, + .knownOnly, + .none, + .corePortnumsOnly, + ] + } public init() {} @@ -418,7 +400,7 @@ public struct Config { /// /// Position Config - public struct PositionConfig { + public struct PositionConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -440,6 +422,8 @@ public struct Config { /// /// Is GPS enabled for this node? + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var gpsEnabled: Bool = false /// @@ -450,6 +434,8 @@ public struct Config { /// /// Deprecated in favor of using smart / regular broadcast intervals as implicit attempt time + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var gpsAttemptTime: UInt32 = 0 /// @@ -490,7 +476,7 @@ public struct Config { /// are always included (also time if GPS-synced) /// NOTE: the more fields are included, the larger the message will be - /// leading to longer airtime and a higher risk of packet loss - public enum PositionFlags: SwiftProtobuf.Enum { + public enum PositionFlags: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -580,9 +566,24 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.PositionConfig.PositionFlags] = [ + .unset, + .altitude, + .altitudeMsl, + .geoidalSeparation, + .dop, + .hvdop, + .satinview, + .seqNo, + .timestamp, + .heading, + .speed, + ] + } - public enum GpsMode: SwiftProtobuf.Enum { + public enum GpsMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -620,6 +621,13 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.PositionConfig.GpsMode] = [ + .disabled, + .enabled, + .notPresent, + ] + } public init() {} @@ -628,7 +636,7 @@ public struct Config { /// /// Power Config\ /// See [Power Config](/docs/settings/config/power) for additional power config details. - public struct PowerConfig { + public struct PowerConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -688,7 +696,7 @@ public struct Config { /// /// Network Config - public struct NetworkConfig { + public struct NetworkConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -735,7 +743,7 @@ public struct Config { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum AddressMode: SwiftProtobuf.Enum { + public enum AddressMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -767,9 +775,15 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.NetworkConfig.AddressMode] = [ + .dhcp, + .static, + ] + } - public struct IpV4Config { + public struct IpV4Config: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -802,7 +816,7 @@ public struct Config { /// /// Display Config - public struct DisplayConfig { + public struct DisplayConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -858,7 +872,7 @@ public struct Config { /// /// How the GPS coordinates are displayed on the OLED screen. - public enum GpsCoordinateFormat: SwiftProtobuf.Enum { + public enum GpsCoordinateFormat: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -921,11 +935,21 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [ + .dec, + .dms, + .utm, + .mgrs, + .olc, + .osgr, + ] + } /// /// Unit display preference - public enum DisplayUnits: SwiftProtobuf.Enum { + public enum DisplayUnits: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -957,11 +981,17 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.DisplayUnits] = [ + .metric, + .imperial, + ] + } /// /// Override OLED outo detect with this if it fails. - public enum OledType: SwiftProtobuf.Enum { + public enum OledType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1005,9 +1035,17 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.OledType] = [ + .oledAuto, + .oledSsd1306, + .oledSh1106, + .oledSh1107, + ] + } - public enum DisplayMode: SwiftProtobuf.Enum { + public enum DisplayMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1051,9 +1089,17 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.DisplayMode] = [ + .default, + .twocolor, + .inverted, + .color, + ] + } - public enum CompassOrientation: SwiftProtobuf.Enum { + public enum CompassOrientation: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1121,6 +1167,18 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.DisplayConfig.CompassOrientation] = [ + .degrees0, + .degrees90, + .degrees180, + .degrees270, + .degrees0Inverted, + .degrees90Inverted, + .degrees180Inverted, + .degrees270Inverted, + ] + } public init() {} @@ -1128,7 +1186,7 @@ public struct Config { /// /// Lora Config - public struct LoRaConfig { + public struct LoRaConfig: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1292,7 +1350,7 @@ public struct Config { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum RegionCode: SwiftProtobuf.Enum { + public enum RegionCode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1444,12 +1502,38 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.LoRaConfig.RegionCode] = [ + .unset, + .us, + .eu433, + .eu868, + .cn, + .jp, + .anz, + .kr, + .tw, + .ru, + .in, + .nz865, + .th, + .lora24, + .ua433, + .ua868, + .my433, + .my919, + .sg923, + .ph433, + .ph868, + .ph915, + ] + } /// /// Standard predefined channel settings /// Note: these mappings must match ModemPreset Choice in the device code. - public enum ModemPreset: SwiftProtobuf.Enum { + public enum ModemPreset: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1463,6 +1547,8 @@ public struct Config { /// /// Very Long Range - Slow /// Deprecated in 2.5: Works only with txco and is unusably slow + /// + /// NOTE: This enum value was marked as deprecated in the .proto file case veryLongSlow // = 2 /// @@ -1526,6 +1612,19 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.LoRaConfig.ModemPreset] = [ + .longFast, + .longSlow, + .veryLongSlow, + .mediumSlow, + .mediumFast, + .shortSlow, + .shortFast, + .longModerate, + .shortTurbo, + ] + } public init() {} @@ -1533,7 +1632,7 @@ public struct Config { fileprivate var _storage = _StorageClass.defaultInstance } - public struct BluetoothConfig { + public struct BluetoothConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1552,7 +1651,7 @@ public struct Config { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum PairingMode: SwiftProtobuf.Enum { + public enum PairingMode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1590,12 +1689,19 @@ public struct Config { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Config.BluetoothConfig.PairingMode] = [ + .randomPin, + .fixedPin, + .noPin, + ] + } public init() {} } - public struct SecurityConfig { + public struct SecurityConfig: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1639,7 +1745,7 @@ public struct Config { /// /// Blank config request, strictly for getting the session key - public struct SessionkeyConfig { + public struct SessionkeyConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1652,207 +1758,6 @@ public struct Config { public init() {} } -#if swift(>=4.2) - -extension Config.DeviceConfig.Role: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DeviceConfig.Role] = [ - .client, - .clientMute, - .router, - .routerClient, - .repeater, - .tracker, - .sensor, - .tak, - .clientHidden, - .lostAndFound, - .takTracker, - ] -} - -extension Config.DeviceConfig.RebroadcastMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DeviceConfig.RebroadcastMode] = [ - .all, - .allSkipDecoding, - .localOnly, - .knownOnly, - .none, - .corePortnumsOnly, - ] -} - -extension Config.PositionConfig.PositionFlags: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.PositionConfig.PositionFlags] = [ - .unset, - .altitude, - .altitudeMsl, - .geoidalSeparation, - .dop, - .hvdop, - .satinview, - .seqNo, - .timestamp, - .heading, - .speed, - ] -} - -extension Config.PositionConfig.GpsMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.PositionConfig.GpsMode] = [ - .disabled, - .enabled, - .notPresent, - ] -} - -extension Config.NetworkConfig.AddressMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.NetworkConfig.AddressMode] = [ - .dhcp, - .static, - ] -} - -extension Config.DisplayConfig.GpsCoordinateFormat: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [ - .dec, - .dms, - .utm, - .mgrs, - .olc, - .osgr, - ] -} - -extension Config.DisplayConfig.DisplayUnits: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.DisplayUnits] = [ - .metric, - .imperial, - ] -} - -extension Config.DisplayConfig.OledType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.OledType] = [ - .oledAuto, - .oledSsd1306, - .oledSh1106, - .oledSh1107, - ] -} - -extension Config.DisplayConfig.DisplayMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.DisplayMode] = [ - .default, - .twocolor, - .inverted, - .color, - ] -} - -extension Config.DisplayConfig.CompassOrientation: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.DisplayConfig.CompassOrientation] = [ - .degrees0, - .degrees90, - .degrees180, - .degrees270, - .degrees0Inverted, - .degrees90Inverted, - .degrees180Inverted, - .degrees270Inverted, - ] -} - -extension Config.LoRaConfig.RegionCode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.LoRaConfig.RegionCode] = [ - .unset, - .us, - .eu433, - .eu868, - .cn, - .jp, - .anz, - .kr, - .tw, - .ru, - .in, - .nz865, - .th, - .lora24, - .ua433, - .ua868, - .my433, - .my919, - .sg923, - .ph433, - .ph868, - .ph915, - ] -} - -extension Config.LoRaConfig.ModemPreset: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.LoRaConfig.ModemPreset] = [ - .longFast, - .longSlow, - .veryLongSlow, - .mediumSlow, - .mediumFast, - .shortSlow, - .shortFast, - .longModerate, - .shortTurbo, - ] -} - -extension Config.BluetoothConfig.PairingMode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Config.BluetoothConfig.PairingMode] = [ - .randomPin, - .fixedPin, - .noPin, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension Config: @unchecked Sendable {} -extension Config.OneOf_PayloadVariant: @unchecked Sendable {} -extension Config.DeviceConfig: @unchecked Sendable {} -extension Config.DeviceConfig.Role: @unchecked Sendable {} -extension Config.DeviceConfig.RebroadcastMode: @unchecked Sendable {} -extension Config.PositionConfig: @unchecked Sendable {} -extension Config.PositionConfig.PositionFlags: @unchecked Sendable {} -extension Config.PositionConfig.GpsMode: @unchecked Sendable {} -extension Config.PowerConfig: @unchecked Sendable {} -extension Config.NetworkConfig: @unchecked Sendable {} -extension Config.NetworkConfig.AddressMode: @unchecked Sendable {} -extension Config.NetworkConfig.IpV4Config: @unchecked Sendable {} -extension Config.DisplayConfig: @unchecked Sendable {} -extension Config.DisplayConfig.GpsCoordinateFormat: @unchecked Sendable {} -extension Config.DisplayConfig.DisplayUnits: @unchecked Sendable {} -extension Config.DisplayConfig.OledType: @unchecked Sendable {} -extension Config.DisplayConfig.DisplayMode: @unchecked Sendable {} -extension Config.DisplayConfig.CompassOrientation: @unchecked Sendable {} -extension Config.LoRaConfig: @unchecked Sendable {} -extension Config.LoRaConfig.RegionCode: @unchecked Sendable {} -extension Config.LoRaConfig.ModemPreset: @unchecked Sendable {} -extension Config.BluetoothConfig: @unchecked Sendable {} -extension Config.BluetoothConfig.PairingMode: @unchecked Sendable {} -extension Config.SecurityConfig: @unchecked Sendable {} -extension Config.SessionkeyConfig: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -2359,7 +2264,7 @@ extension Config.PowerConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if self.onBatteryShutdownAfterSecs != 0 { try visitor.visitSingularUInt32Field(value: self.onBatteryShutdownAfterSecs, fieldNumber: 2) } - if self.adcMultiplierOverride != 0 { + if self.adcMultiplierOverride.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.adcMultiplierOverride, fieldNumber: 3) } if self.waitBluetoothSecs != 0 { @@ -2807,7 +2712,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._codingRate != 0 { try visitor.visitSingularUInt32Field(value: _storage._codingRate, fieldNumber: 5) } - if _storage._frequencyOffset != 0 { + if _storage._frequencyOffset.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._frequencyOffset, fieldNumber: 6) } if _storage._region != .unset { @@ -2831,7 +2736,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem if _storage._sx126XRxBoostedGain != false { try visitor.visitSingularBoolField(value: _storage._sx126XRxBoostedGain, fieldNumber: 13) } - if _storage._overrideFrequency != 0 { + if _storage._overrideFrequency.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._overrideFrequency, fieldNumber: 14) } if _storage._paFanDisabled != false { @@ -3048,8 +2953,8 @@ extension Config.SessionkeyConfig: SwiftProtobuf.Message, SwiftProtobuf._Message public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let _ = try decoder.nextFieldNumber() { - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { diff --git a/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift index a2ec180e..6847c0e3 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/connection_status.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/connection_status.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct DeviceConnectionStatus { +public struct DeviceConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -81,7 +81,7 @@ public struct DeviceConnectionStatus { /// /// WiFi connection status -public struct WifiConnectionStatus { +public struct WifiConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -114,7 +114,7 @@ public struct WifiConnectionStatus { /// /// Ethernet connection status -public struct EthernetConnectionStatus { +public struct EthernetConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -139,7 +139,7 @@ public struct EthernetConnectionStatus { /// /// Ethernet or WiFi connection status -public struct NetworkConnectionStatus { +public struct NetworkConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -167,7 +167,7 @@ public struct NetworkConnectionStatus { /// /// Bluetooth connection status -public struct BluetoothConnectionStatus { +public struct BluetoothConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -191,7 +191,7 @@ public struct BluetoothConnectionStatus { /// /// Serial connection status -public struct SerialConnectionStatus { +public struct SerialConnectionStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -209,15 +209,6 @@ public struct SerialConnectionStatus { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension DeviceConnectionStatus: @unchecked Sendable {} -extension WifiConnectionStatus: @unchecked Sendable {} -extension EthernetConnectionStatus: @unchecked Sendable {} -extension NetworkConnectionStatus: @unchecked Sendable {} -extension BluetoothConnectionStatus: @unchecked Sendable {} -extension SerialConnectionStatus: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/device_ui.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/device_ui.pb.swift index f677d644..82c6e834 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/device_ui.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/device_ui.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/device_ui.proto @@ -20,7 +21,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum Theme: SwiftProtobuf.Enum { +public enum Theme: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -58,24 +59,18 @@ public enum Theme: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension Theme: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Theme] = [ .dark, .light, .red, ] -} -#endif // swift(>=4.2) +} /// /// Localization -public enum Language: SwiftProtobuf.Enum { +public enum Language: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -134,6 +129,10 @@ public enum Language: SwiftProtobuf.Enum { /// Greek case greek // = 13 + /// + /// Norwegian + case norwegian // = 14 + /// /// Simplified Chinese (experimental) case simplifiedChinese // = 30 @@ -163,6 +162,7 @@ public enum Language: SwiftProtobuf.Enum { case 11: self = .russian case 12: self = .dutch case 13: self = .greek + case 14: self = .norwegian case 30: self = .simplifiedChinese case 31: self = .traditionalChinese default: self = .UNRECOGNIZED(rawValue) @@ -185,17 +185,13 @@ public enum Language: SwiftProtobuf.Enum { case .russian: return 11 case .dutch: return 12 case .greek: return 13 + case .norwegian: return 14 case .simplifiedChinese: return 30 case .traditionalChinese: return 31 case .UNRECOGNIZED(let i): return i } } -} - -#if swift(>=4.2) - -extension Language: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Language] = [ .english, @@ -212,14 +208,14 @@ extension Language: CaseIterable { .russian, .dutch, .greek, + .norwegian, .simplifiedChinese, .traditionalChinese, ] + } -#endif // swift(>=4.2) - -public struct DeviceUIConfig { +public struct DeviceUIConfig: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -315,6 +311,13 @@ public struct DeviceUIConfig { /// Clears the value of `nodeHighlight`. Subsequent reads from it will return its default value. public mutating func clearNodeHighlight() {_uniqueStorage()._nodeHighlight = nil} + /// + /// 8 integers for screen calibration data + public var calibrationData: Data { + get {return _storage._calibrationData} + set {_uniqueStorage()._calibrationData = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -322,7 +325,7 @@ public struct DeviceUIConfig { fileprivate var _storage = _StorageClass.defaultInstance } -public struct NodeFilter { +public struct NodeFilter: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -356,7 +359,7 @@ public struct NodeFilter { public init() {} } -public struct NodeHighlight { +public struct NodeHighlight: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -386,14 +389,6 @@ public struct NodeHighlight { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension Theme: @unchecked Sendable {} -extension Language: @unchecked Sendable {} -extension DeviceUIConfig: @unchecked Sendable {} -extension NodeFilter: @unchecked Sendable {} -extension NodeHighlight: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -422,6 +417,7 @@ extension Language: SwiftProtobuf._ProtoNameProviding { 11: .same(proto: "RUSSIAN"), 12: .same(proto: "DUTCH"), 13: .same(proto: "GREEK"), + 14: .same(proto: "NORWEGIAN"), 30: .same(proto: "SIMPLIFIED_CHINESE"), 31: .same(proto: "TRADITIONAL_CHINESE"), ] @@ -443,6 +439,7 @@ extension DeviceUIConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement 11: .same(proto: "language"), 12: .standard(proto: "node_filter"), 13: .standard(proto: "node_highlight"), + 14: .standard(proto: "calibration_data"), ] fileprivate class _StorageClass { @@ -459,6 +456,7 @@ extension DeviceUIConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement var _language: Language = .english var _nodeFilter: NodeFilter? = nil var _nodeHighlight: NodeHighlight? = nil + var _calibrationData: Data = Data() #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -486,6 +484,7 @@ extension DeviceUIConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement _language = source._language _nodeFilter = source._nodeFilter _nodeHighlight = source._nodeHighlight + _calibrationData = source._calibrationData } } @@ -517,6 +516,7 @@ extension DeviceUIConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement case 11: try { try decoder.decodeSingularEnumField(value: &_storage._language) }() case 12: try { try decoder.decodeSingularMessageField(value: &_storage._nodeFilter) }() case 13: try { try decoder.decodeSingularMessageField(value: &_storage._nodeHighlight) }() + case 14: try { try decoder.decodeSingularBytesField(value: &_storage._calibrationData) }() default: break } } @@ -568,6 +568,9 @@ extension DeviceUIConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement try { if let v = _storage._nodeHighlight { try visitor.visitSingularMessageField(value: v, fieldNumber: 13) } }() + if !_storage._calibrationData.isEmpty { + try visitor.visitSingularBytesField(value: _storage._calibrationData, fieldNumber: 14) + } } try unknownFields.traverse(visitor: &visitor) } @@ -590,6 +593,7 @@ extension DeviceUIConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplement if _storage._language != rhs_storage._language {return false} if _storage._nodeFilter != rhs_storage._nodeFilter {return false} if _storage._nodeHighlight != rhs_storage._nodeHighlight {return false} + if _storage._calibrationData != rhs_storage._calibrationData {return false} return true } if !storagesAreEqual {return false} diff --git a/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift index 3349c2c9..a8f57eaf 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/deviceonly.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/deviceonly.proto @@ -22,7 +23,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Position with static location information only for NodeDBLite -public struct PositionLite { +public struct PositionLite: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -57,13 +58,15 @@ public struct PositionLite { public init() {} } -public struct UserLite { +public struct UserLite: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. /// /// This is the addr of the radio. + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var macaddr: Data = Data() /// @@ -102,7 +105,7 @@ public struct UserLite { public init() {} } -public struct NodeInfoLite { +public struct NodeInfoLite: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -196,6 +199,21 @@ public struct NodeInfoLite { set {_uniqueStorage()._isFavorite = newValue} } + /// + /// True if node is in our ignored list + /// Persists between NodeDB internal clean ups + public var isIgnored: Bool { + get {return _storage._isIgnored} + set {_uniqueStorage()._isIgnored = newValue} + } + + /// + /// Last byte of the node number of the node that should be used as the next hop to reach this node. + public var nextHop: UInt32 { + get {return _storage._nextHop} + set {_uniqueStorage()._nextHop = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -209,7 +227,7 @@ public struct NodeInfoLite { /// 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 -public struct DeviceState { +public struct DeviceState: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -269,6 +287,8 @@ public struct DeviceState { /// Used only during development. /// Indicates developer is testing and changes should never be saved to flash. /// Deprecated in 2.3.1 + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var noSave: Bool { get {return _storage._noSave} set {_uniqueStorage()._noSave = newValue} @@ -317,7 +337,7 @@ public struct DeviceState { /// /// The on-disk saved channels -public struct ChannelFile { +public struct ChannelFile: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -337,14 +357,6 @@ public struct ChannelFile { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension PositionLite: @unchecked Sendable {} -extension UserLite: @unchecked Sendable {} -extension NodeInfoLite: @unchecked Sendable {} -extension DeviceState: @unchecked Sendable {} -extension ChannelFile: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -486,6 +498,8 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat 8: .standard(proto: "via_mqtt"), 9: .standard(proto: "hops_away"), 10: .standard(proto: "is_favorite"), + 11: .standard(proto: "is_ignored"), + 12: .standard(proto: "next_hop"), ] fileprivate class _StorageClass { @@ -499,6 +513,8 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat var _viaMqtt: Bool = false var _hopsAway: UInt32? = nil var _isFavorite: Bool = false + var _isIgnored: Bool = false + var _nextHop: UInt32 = 0 #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -523,6 +539,8 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat _viaMqtt = source._viaMqtt _hopsAway = source._hopsAway _isFavorite = source._isFavorite + _isIgnored = source._isIgnored + _nextHop = source._nextHop } } @@ -551,6 +569,8 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat case 8: try { try decoder.decodeSingularBoolField(value: &_storage._viaMqtt) }() case 9: try { try decoder.decodeSingularUInt32Field(value: &_storage._hopsAway) }() case 10: try { try decoder.decodeSingularBoolField(value: &_storage._isFavorite) }() + case 11: try { try decoder.decodeSingularBoolField(value: &_storage._isIgnored) }() + case 12: try { try decoder.decodeSingularUInt32Field(value: &_storage._nextHop) }() default: break } } @@ -572,7 +592,7 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat try { if let v = _storage._position { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() - if _storage._snr != 0 { + if _storage._snr.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4) } if _storage._lastHeard != 0 { @@ -593,6 +613,12 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat if _storage._isFavorite != false { try visitor.visitSingularBoolField(value: _storage._isFavorite, fieldNumber: 10) } + if _storage._isIgnored != false { + try visitor.visitSingularBoolField(value: _storage._isIgnored, fieldNumber: 11) + } + if _storage._nextHop != 0 { + try visitor.visitSingularUInt32Field(value: _storage._nextHop, fieldNumber: 12) + } } try unknownFields.traverse(visitor: &visitor) } @@ -612,6 +638,8 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat if _storage._viaMqtt != rhs_storage._viaMqtt {return false} if _storage._hopsAway != rhs_storage._hopsAway {return false} if _storage._isFavorite != rhs_storage._isFavorite {return false} + if _storage._isIgnored != rhs_storage._isIgnored {return false} + if _storage._nextHop != rhs_storage._nextHop {return false} return true } if !storagesAreEqual {return false} diff --git a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift index 0af27466..c3356286 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/localonly.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/localonly.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct LocalConfig { +public struct LocalConfig: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -129,7 +129,7 @@ public struct LocalConfig { fileprivate var _storage = _StorageClass.defaultInstance } -public struct LocalModuleConfig { +public struct LocalModuleConfig: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -293,11 +293,6 @@ public struct LocalModuleConfig { fileprivate var _storage = _StorageClass.defaultInstance } -#if swift(>=5.5) && canImport(_Concurrency) -extension LocalConfig: @unchecked Sendable {} -extension LocalModuleConfig: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift index 154d8a6b..72ba0edc 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mesh.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/mesh.proto @@ -25,7 +26,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// 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 . -public enum HardwareModel: SwiftProtobuf.Enum { +public enum HardwareModel: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -380,6 +381,23 @@ public enum HardwareModel: SwiftProtobuf.Enum { /// Lilygo TLora-C6 with the new ESP32-C6 MCU case tloraC6 // = 83 + /// + /// WisMesh Tap + /// RAK-4631 w/ TFT in injection modled case + case wismeshTap // = 84 + + /// + /// Similar to PORTDUINO but used by Routastic devices, this is not any + /// particular device and does not run Meshtastic's code but supports + /// the same frame format. + /// Runs on linux, see https://github.com/Jorropo/routastic + case routastic // = 85 + + /// + /// Mesh-Tab, esp32 based + /// https://github.com/valzzu/Mesh-Tab + case meshTab // = 86 + /// /// ------------------------------------------------------------------------------------------------------------------------------------------ /// 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. @@ -477,6 +495,9 @@ public enum HardwareModel: SwiftProtobuf.Enum { case 81: self = .seeedXiaoS3 case 82: self = .ms24Sf1 case 83: self = .tloraC6 + case 84: self = .wismeshTap + case 85: self = .routastic + case 86: self = .meshTab case 255: self = .privateHw default: self = .UNRECOGNIZED(rawValue) } @@ -568,16 +589,14 @@ public enum HardwareModel: SwiftProtobuf.Enum { case .seeedXiaoS3: return 81 case .ms24Sf1: return 82 case .tloraC6: return 83 + case .wismeshTap: return 84 + case .routastic: return 85 + case .meshTab: return 86 case .privateHw: return 255 case .UNRECOGNIZED(let i): return i } } -} - -#if swift(>=4.2) - -extension HardwareModel: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [HardwareModel] = [ .unset, @@ -664,15 +683,17 @@ extension HardwareModel: CaseIterable { .seeedXiaoS3, .ms24Sf1, .tloraC6, + .wismeshTap, + .routastic, + .meshTab, .privateHw, ] -} -#endif // swift(>=4.2) +} /// /// Shared constants between device and phone -public enum Constants: SwiftProtobuf.Enum { +public enum Constants: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -684,7 +705,7 @@ public enum Constants: SwiftProtobuf.Enum { /// 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 - case dataPayloadLen // = 237 + case dataPayloadLen // = 233 case UNRECOGNIZED(Int) public init() { @@ -694,7 +715,7 @@ public enum Constants: SwiftProtobuf.Enum { public init?(rawValue: Int) { switch rawValue { case 0: self = .zero - case 237: self = .dataPayloadLen + case 233: self = .dataPayloadLen default: self = .UNRECOGNIZED(rawValue) } } @@ -702,31 +723,25 @@ public enum Constants: SwiftProtobuf.Enum { public var rawValue: Int { switch self { case .zero: return 0 - case .dataPayloadLen: return 237 + case .dataPayloadLen: return 233 case .UNRECOGNIZED(let i): return i } } -} - -#if swift(>=4.2) - -extension Constants: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [Constants] = [ .zero, .dataPayloadLen, ] -} -#endif // swift(>=4.2) +} /// /// 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. -public enum CriticalErrorCode: SwiftProtobuf.Enum { +public enum CriticalErrorCode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -835,11 +850,6 @@ public enum CriticalErrorCode: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension CriticalErrorCode: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [CriticalErrorCode] = [ .none, @@ -857,15 +867,14 @@ extension CriticalErrorCode: CaseIterable { .flashCorruptionRecoverable, .flashCorruptionUnrecoverable, ] -} -#endif // swift(>=4.2) +} /// /// Enum for modules excluded from a device's configuration. /// Each value represents a ModuleConfigType that can be toggled as excluded /// by setting its corresponding bit in the `excluded_modules` bitmask field. -public enum ExcludedModules: SwiftProtobuf.Enum { +public enum ExcludedModules: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -969,11 +978,6 @@ public enum ExcludedModules: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension ExcludedModules: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [ExcludedModules] = [ .excludedNone, @@ -991,13 +995,12 @@ extension ExcludedModules: CaseIterable { .detectionsensorConfig, .paxcounterConfig, ] -} -#endif // swift(>=4.2) +} /// /// A GPS Position -public struct Position { +public struct Position: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1214,7 +1217,7 @@ public struct Position { /// /// How the location was acquired: manual, onboard GPS, external (EUD) GPS - public enum LocSource: SwiftProtobuf.Enum { + public enum LocSource: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1258,12 +1261,20 @@ public struct Position { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Position.LocSource] = [ + .locUnset, + .locManual, + .locInternal, + .locExternal, + ] + } /// /// How the altitude was acquired: manual, GPS int/ext, etc /// Default: same as location_source if present - public enum AltSource: SwiftProtobuf.Enum { + public enum AltSource: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1313,6 +1324,15 @@ public struct Position { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Position.AltSource] = [ + .altUnset, + .altManual, + .altInternal, + .altExternal, + .altBarometric, + ] + } public init() {} @@ -1320,31 +1340,6 @@ public struct Position { fileprivate var _storage = _StorageClass.defaultInstance } -#if swift(>=4.2) - -extension Position.LocSource: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Position.LocSource] = [ - .locUnset, - .locManual, - .locInternal, - .locExternal, - ] -} - -extension Position.AltSource: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Position.AltSource] = [ - .altUnset, - .altManual, - .altInternal, - .altExternal, - .altBarometric, - ] -} - -#endif // swift(>=4.2) - /// /// 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. @@ -1366,7 +1361,7 @@ extension Position.AltSource: CaseIterable { /// A few nodenums are reserved and will never be requested: /// 0xff - broadcast /// 0 through 3 - for future use -public struct User { +public struct User: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1391,6 +1386,8 @@ public struct User { /// Deprecated in Meshtastic 2.1.x /// This is the addr of the radio. /// Not populated by the phone, but added by the esp32 when broadcasting + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var macaddr: Data = Data() /// @@ -1422,7 +1419,7 @@ public struct User { /// /// A message used in a traceroute -public struct RouteDiscovery { +public struct RouteDiscovery: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1450,7 +1447,7 @@ public struct RouteDiscovery { /// /// A Routing control Data packet handled by the routing module -public struct Routing { +public struct Routing: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1490,7 +1487,7 @@ public struct Routing { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Variant: Equatable { + public enum OneOf_Variant: Equatable, Sendable { /// /// A route request going from the requester case routeRequest(RouteDiscovery) @@ -1502,34 +1499,12 @@ public struct Routing { /// in addition to ack.fail_id to provide details on the type of failure). case errorReason(Routing.Error) - #if !swift(>=4.1) - public static func ==(lhs: Routing.OneOf_Variant, rhs: Routing.OneOf_Variant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.routeRequest, .routeRequest): return { - guard case .routeRequest(let l) = lhs, case .routeRequest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.routeReply, .routeReply): return { - guard case .routeReply(let l) = lhs, case .routeReply(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.errorReason, .errorReason): return { - guard case .errorReason(let l) = lhs, case .errorReason(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// 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). - public enum Error: SwiftProtobuf.Enum { + public enum Error: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1647,42 +1622,36 @@ public struct Routing { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [Routing.Error] = [ + .none, + .noRoute, + .gotNak, + .timeout, + .noInterface, + .maxRetransmit, + .noChannel, + .tooLarge, + .noResponse, + .dutyCycleLimit, + .badRequest, + .notAuthorized, + .pkiFailed, + .pkiUnknownPubkey, + .adminBadSessionKey, + .adminPublicKeyUnauthorized, + ] + } public init() {} } -#if swift(>=4.2) - -extension Routing.Error: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [Routing.Error] = [ - .none, - .noRoute, - .gotNak, - .timeout, - .noInterface, - .maxRetransmit, - .noChannel, - .tooLarge, - .noResponse, - .dutyCycleLimit, - .badRequest, - .notAuthorized, - .pkiFailed, - .pkiUnknownPubkey, - .adminBadSessionKey, - .adminPublicKeyUnauthorized, - ] -} - -#endif // swift(>=4.2) - /// /// (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) -public struct DataMessage { +public struct DataMessage: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1749,7 +1718,7 @@ public struct DataMessage { /// /// Waypoint message, used to share arbitrary locations across the mesh -public struct Waypoint { +public struct Waypoint: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1811,7 +1780,7 @@ public struct Waypoint { /// /// This message will be proxied over the PhoneAPI for the client to deliver to the MQTT server -public struct MqttClientProxyMessage { +public struct MqttClientProxyMessage: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1852,7 +1821,7 @@ public struct MqttClientProxyMessage { /// /// The actual service envelope payload or text for mqtt pub / sub - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, @unchecked Sendable { /// /// Bytes case data(Data) @@ -1860,24 +1829,6 @@ public struct MqttClientProxyMessage { /// Text case text(String) - #if !swift(>=4.1) - public static func ==(lhs: MqttClientProxyMessage.OneOf_PayloadVariant, rhs: MqttClientProxyMessage.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.data, .data): return { - guard case .data(let l) = lhs, case .data(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.text, .text): return { - guard case .text(let l) = lhs, case .text(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -1887,7 +1838,7 @@ public struct MqttClientProxyMessage { /// A packet envelope sent/received over the mesh /// only payload_variant 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. -public struct MeshPacket { +public struct MeshPacket: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2021,6 +1972,8 @@ public struct MeshPacket { /// /// Describe if this message is delayed + /// + /// NOTE: This field was marked as deprecated in the .proto file. public var delayed: MeshPacket.Delayed { get {return _storage._delayed} set {_uniqueStorage()._delayed = newValue} @@ -2055,9 +2008,25 @@ public struct MeshPacket { set {_uniqueStorage()._pkiEncrypted = newValue} } + /// + /// Last byte of the node number of the node that should be used as the next hop in routing. + /// Set by the firmware internally, clients are not supposed to set this. + public var nextHop: UInt32 { + get {return _storage._nextHop} + set {_uniqueStorage()._nextHop = newValue} + } + + /// + /// Last byte of the node number of the node that will relay/relayed this packet. + /// Set by the firmware internally, clients are not supposed to set this. + public var relayNode: UInt32 { + get {return _storage._relayNode} + set {_uniqueStorage()._relayNode = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, @unchecked Sendable { /// /// TODO: REPLACE case decoded(DataMessage) @@ -2065,24 +2034,6 @@ public struct MeshPacket { /// TODO: REPLACE case encrypted(Data) - #if !swift(>=4.1) - public static func ==(lhs: MeshPacket.OneOf_PayloadVariant, rhs: MeshPacket.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.decoded, .decoded): return { - guard case .decoded(let l) = lhs, case .decoded(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.encrypted, .encrypted): return { - guard case .encrypted(let l) = lhs, case .encrypted(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// @@ -2104,7 +2055,7 @@ public struct MeshPacket { /// 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. - public enum Priority: SwiftProtobuf.Enum { + public enum Priority: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -2138,6 +2089,10 @@ public struct MeshPacket { /// Higher priority for specific message types (portnums) to distinguish between other reliable packets. case high // = 100 + /// + /// Higher priority alert message used for critical alerts which take priority over other reliable packets. + case alert // = 110 + /// /// Ack/naks are sent with very high priority to ensure that retransmission /// stops as soon as possible @@ -2161,6 +2116,7 @@ public struct MeshPacket { case 70: self = .reliable case 80: self = .response case 100: self = .high + case 110: self = .alert case 120: self = .ack case 127: self = .max default: self = .UNRECOGNIZED(rawValue) @@ -2176,17 +2132,32 @@ public struct MeshPacket { case .reliable: return 70 case .response: return 80 case .high: return 100 + case .alert: return 110 case .ack: return 120 case .max: return 127 case .UNRECOGNIZED(let i): return i } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [MeshPacket.Priority] = [ + .unset, + .min, + .background, + .default, + .reliable, + .response, + .high, + .alert, + .ack, + .max, + ] + } /// /// Identify if this is a delayed packet - public enum Delayed: SwiftProtobuf.Enum { + public enum Delayed: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -2224,6 +2195,13 @@ public struct MeshPacket { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [MeshPacket.Delayed] = [ + .noDelay, + .broadcast, + .direct, + ] + } public init() {} @@ -2231,34 +2209,6 @@ public struct MeshPacket { fileprivate var _storage = _StorageClass.defaultInstance } -#if swift(>=4.2) - -extension MeshPacket.Priority: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [MeshPacket.Priority] = [ - .unset, - .min, - .background, - .default, - .reliable, - .response, - .high, - .ack, - .max, - ] -} - -extension MeshPacket.Delayed: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [MeshPacket.Delayed] = [ - .noDelay, - .broadcast, - .direct, - ] -} - -#endif // swift(>=4.2) - /// /// The bluetooth to device link: /// Old BTLE protocol docs from TODO, merge in above and make real docs... @@ -2276,7 +2226,7 @@ extension MeshPacket.Delayed: CaseIterable { /// 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 -public struct NodeInfo { +public struct NodeInfo: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2370,6 +2320,14 @@ public struct NodeInfo { set {_uniqueStorage()._isFavorite = newValue} } + /// + /// True if node is in our ignored list + /// Persists between NodeDB internal clean ups + public var isIgnored: Bool { + get {return _storage._isIgnored} + set {_uniqueStorage()._isIgnored = newValue} + } + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -2381,7 +2339,7 @@ public struct NodeInfo { /// 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. -public struct MyNodeInfo { +public struct MyNodeInfo: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2420,7 +2378,7 @@ public struct MyNodeInfo { /// 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. -public struct LogRecord { +public struct LogRecord: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2445,7 +2403,7 @@ public struct LogRecord { /// /// Log levels, chosen to match python logging conventions. - public enum Level: SwiftProtobuf.Enum { + public enum Level: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -2507,29 +2465,23 @@ public struct LogRecord { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [LogRecord.Level] = [ + .unset, + .critical, + .error, + .warning, + .info, + .debug, + .trace, + ] + } public init() {} } -#if swift(>=4.2) - -extension LogRecord.Level: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [LogRecord.Level] = [ - .unset, - .critical, - .error, - .warning, - .info, - .debug, - .trace, - ] -} - -#endif // swift(>=4.2) - -public struct QueueStatus { +public struct QueueStatus: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2556,7 +2508,7 @@ public struct QueueStatus { /// 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. -public struct FromRadio { +public struct FromRadio: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2742,7 +2694,7 @@ public struct FromRadio { /// /// Log levels, chosen to match python logging conventions. - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Log levels, chosen to match python logging conventions. case packet(MeshPacket) @@ -2800,80 +2752,6 @@ public struct FromRadio { /// Persistent data for device-ui case deviceuiConfig(DeviceUIConfig) - #if !swift(>=4.1) - public static func ==(lhs: FromRadio.OneOf_PayloadVariant, rhs: FromRadio.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.packet, .packet): return { - guard case .packet(let l) = lhs, case .packet(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.myInfo, .myInfo): return { - guard case .myInfo(let l) = lhs, case .myInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.nodeInfo, .nodeInfo): return { - guard case .nodeInfo(let l) = lhs, case .nodeInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.config, .config): return { - guard case .config(let l) = lhs, case .config(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.logRecord, .logRecord): return { - guard case .logRecord(let l) = lhs, case .logRecord(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.configCompleteID, .configCompleteID): return { - guard case .configCompleteID(let l) = lhs, case .configCompleteID(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rebooted, .rebooted): return { - guard case .rebooted(let l) = lhs, case .rebooted(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.moduleConfig, .moduleConfig): return { - guard case .moduleConfig(let l) = lhs, case .moduleConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.channel, .channel): return { - guard case .channel(let l) = lhs, case .channel(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.queueStatus, .queueStatus): return { - guard case .queueStatus(let l) = lhs, case .queueStatus(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.xmodemPacket, .xmodemPacket): return { - guard case .xmodemPacket(let l) = lhs, case .xmodemPacket(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.metadata, .metadata): return { - guard case .metadata(let l) = lhs, case .metadata(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.mqttClientProxyMessage, .mqttClientProxyMessage): return { - guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.fileInfo, .fileInfo): return { - guard case .fileInfo(let l) = lhs, case .fileInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.clientNotification, .clientNotification): return { - guard case .clientNotification(let l) = lhs, case .clientNotification(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.deviceuiConfig, .deviceuiConfig): return { - guard case .deviceuiConfig(let l) = lhs, case .deviceuiConfig(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -2884,7 +2762,7 @@ public struct FromRadio { /// To be used for important messages that should to be displayed to the user /// in the form of push notifications or validation messages when saving /// invalid configuration. -public struct ClientNotification { +public struct ClientNotification: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2921,7 +2799,7 @@ public struct ClientNotification { /// /// Individual File info for the device -public struct FileInfo { +public struct FileInfo: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -2942,7 +2820,7 @@ public struct FileInfo { /// /// Packets/commands to the radio will be written (reliably) to the toRadio characteristic. /// Once the write completes the phone can assume it is handled. -public struct ToRadio { +public struct ToRadio: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -3022,7 +2900,7 @@ public struct ToRadio { /// /// Log levels, chosen to match python logging conventions. - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Send this packet on the mesh case packet(MeshPacket) @@ -3049,40 +2927,6 @@ public struct ToRadio { /// Heartbeat message (used to keep the device connection awake on serial) case heartbeat(Heartbeat) - #if !swift(>=4.1) - public static func ==(lhs: ToRadio.OneOf_PayloadVariant, rhs: ToRadio.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.packet, .packet): return { - guard case .packet(let l) = lhs, case .packet(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.wantConfigID, .wantConfigID): return { - guard case .wantConfigID(let l) = lhs, case .wantConfigID(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.disconnect, .disconnect): return { - guard case .disconnect(let l) = lhs, case .disconnect(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.xmodemPacket, .xmodemPacket): return { - guard case .xmodemPacket(let l) = lhs, case .xmodemPacket(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.mqttClientProxyMessage, .mqttClientProxyMessage): return { - guard case .mqttClientProxyMessage(let l) = lhs, case .mqttClientProxyMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.heartbeat, .heartbeat): return { - guard case .heartbeat(let l) = lhs, case .heartbeat(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -3090,7 +2934,7 @@ public struct ToRadio { /// /// Compressed message payload -public struct Compressed { +public struct Compressed: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -3110,7 +2954,7 @@ public struct Compressed { /// /// Full info on edges for a single node -public struct NeighborInfo { +public struct NeighborInfo: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -3138,7 +2982,7 @@ public struct NeighborInfo { /// /// A single edge in the mesh -public struct Neighbor { +public struct Neighbor: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -3168,7 +3012,7 @@ public struct Neighbor { /// /// Device metadata response -public struct DeviceMetadata { +public struct DeviceMetadata: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -3230,7 +3074,7 @@ public struct DeviceMetadata { /// /// A heartbeat message is sent to the node from the client to keep the connection alive. /// This is currently only needed to keep serial connections alive, but can be used by any PhoneAPI. -public struct Heartbeat { +public struct Heartbeat: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -3242,7 +3086,7 @@ public struct Heartbeat { /// /// RemoteHardwarePins associated with a node -public struct NodeRemoteHardwarePin { +public struct NodeRemoteHardwarePin: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -3269,7 +3113,7 @@ public struct NodeRemoteHardwarePin { fileprivate var _pin: RemoteHardwarePin? = nil } -public struct ChunkedPayload { +public struct ChunkedPayload: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -3297,7 +3141,7 @@ public struct ChunkedPayload { /// /// Wrapper message for broken repeated oneof support -public struct resend_chunks { +public struct resend_chunks: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -3311,7 +3155,7 @@ public struct resend_chunks { /// /// Responses to a ChunkedPayload request -public struct ChunkedPayloadResponse { +public struct ChunkedPayloadResponse: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -3354,7 +3198,7 @@ public struct ChunkedPayloadResponse { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// Request to transfer chunked payload case requestTransfer(Bool) @@ -3365,77 +3209,11 @@ public struct ChunkedPayloadResponse { /// Request missing indexes in the chunked payload case resendChunks(resend_chunks) - #if !swift(>=4.1) - public static func ==(lhs: ChunkedPayloadResponse.OneOf_PayloadVariant, rhs: ChunkedPayloadResponse.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.requestTransfer, .requestTransfer): return { - guard case .requestTransfer(let l) = lhs, case .requestTransfer(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.acceptTransfer, .acceptTransfer): return { - guard case .acceptTransfer(let l) = lhs, case .acceptTransfer(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.resendChunks, .resendChunks): return { - guard case .resendChunks(let l) = lhs, case .resendChunks(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension HardwareModel: @unchecked Sendable {} -extension Constants: @unchecked Sendable {} -extension CriticalErrorCode: @unchecked Sendable {} -extension ExcludedModules: @unchecked Sendable {} -extension Position: @unchecked Sendable {} -extension Position.LocSource: @unchecked Sendable {} -extension Position.AltSource: @unchecked Sendable {} -extension User: @unchecked Sendable {} -extension RouteDiscovery: @unchecked Sendable {} -extension Routing: @unchecked Sendable {} -extension Routing.OneOf_Variant: @unchecked Sendable {} -extension Routing.Error: @unchecked Sendable {} -extension DataMessage: @unchecked Sendable {} -extension Waypoint: @unchecked Sendable {} -extension MqttClientProxyMessage: @unchecked Sendable {} -extension MqttClientProxyMessage.OneOf_PayloadVariant: @unchecked Sendable {} -extension MeshPacket: @unchecked Sendable {} -extension MeshPacket.OneOf_PayloadVariant: @unchecked Sendable {} -extension MeshPacket.Priority: @unchecked Sendable {} -extension MeshPacket.Delayed: @unchecked Sendable {} -extension NodeInfo: @unchecked Sendable {} -extension MyNodeInfo: @unchecked Sendable {} -extension LogRecord: @unchecked Sendable {} -extension LogRecord.Level: @unchecked Sendable {} -extension QueueStatus: @unchecked Sendable {} -extension FromRadio: @unchecked Sendable {} -extension FromRadio.OneOf_PayloadVariant: @unchecked Sendable {} -extension ClientNotification: @unchecked Sendable {} -extension FileInfo: @unchecked Sendable {} -extension ToRadio: @unchecked Sendable {} -extension ToRadio.OneOf_PayloadVariant: @unchecked Sendable {} -extension Compressed: @unchecked Sendable {} -extension NeighborInfo: @unchecked Sendable {} -extension Neighbor: @unchecked Sendable {} -extension DeviceMetadata: @unchecked Sendable {} -extension Heartbeat: @unchecked Sendable {} -extension NodeRemoteHardwarePin: @unchecked Sendable {} -extension ChunkedPayload: @unchecked Sendable {} -extension resend_chunks: @unchecked Sendable {} -extension ChunkedPayloadResponse: @unchecked Sendable {} -extension ChunkedPayloadResponse.OneOf_PayloadVariant: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -3526,6 +3304,9 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding { 81: .same(proto: "SEEED_XIAO_S3"), 82: .same(proto: "MS24SF1"), 83: .same(proto: "TLORA_C6"), + 84: .same(proto: "WISMESH_TAP"), + 85: .same(proto: "ROUTASTIC"), + 86: .same(proto: "MESH_TAB"), 255: .same(proto: "PRIVATE_HW"), ] } @@ -3533,7 +3314,7 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding { extension Constants: SwiftProtobuf._ProtoNameProviding { public static let _protobuf_nameMap: SwiftProtobuf._NameMap = [ 0: .same(proto: "ZERO"), - 237: .same(proto: "DATA_PAYLOAD_LEN"), + 233: .same(proto: "DATA_PAYLOAD_LEN"), ] } @@ -4328,6 +4109,8 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio 15: .standard(proto: "hop_start"), 16: .standard(proto: "public_key"), 17: .standard(proto: "pki_encrypted"), + 18: .standard(proto: "next_hop"), + 19: .standard(proto: "relay_node"), ] fileprivate class _StorageClass { @@ -4347,6 +4130,8 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio var _hopStart: UInt32 = 0 var _publicKey: Data = Data() var _pkiEncrypted: Bool = false + var _nextHop: UInt32 = 0 + var _relayNode: UInt32 = 0 #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -4377,6 +4162,8 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio _hopStart = source._hopStart _publicKey = source._publicKey _pkiEncrypted = source._pkiEncrypted + _nextHop = source._nextHop + _relayNode = source._relayNode } } @@ -4431,6 +4218,8 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio case 15: try { try decoder.decodeSingularUInt32Field(value: &_storage._hopStart) }() case 16: try { try decoder.decodeSingularBytesField(value: &_storage._publicKey) }() case 17: try { try decoder.decodeSingularBoolField(value: &_storage._pkiEncrypted) }() + case 18: try { try decoder.decodeSingularUInt32Field(value: &_storage._nextHop) }() + case 19: try { try decoder.decodeSingularUInt32Field(value: &_storage._relayNode) }() default: break } } @@ -4469,7 +4258,7 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if _storage._rxTime != 0 { try visitor.visitSingularFixed32Field(value: _storage._rxTime, fieldNumber: 7) } - if _storage._rxSnr != 0 { + if _storage._rxSnr.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._rxSnr, fieldNumber: 8) } if _storage._hopLimit != 0 { @@ -4499,6 +4288,12 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if _storage._pkiEncrypted != false { try visitor.visitSingularBoolField(value: _storage._pkiEncrypted, fieldNumber: 17) } + if _storage._nextHop != 0 { + try visitor.visitSingularUInt32Field(value: _storage._nextHop, fieldNumber: 18) + } + if _storage._relayNode != 0 { + try visitor.visitSingularUInt32Field(value: _storage._relayNode, fieldNumber: 19) + } } try unknownFields.traverse(visitor: &visitor) } @@ -4524,6 +4319,8 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if _storage._hopStart != rhs_storage._hopStart {return false} if _storage._publicKey != rhs_storage._publicKey {return false} if _storage._pkiEncrypted != rhs_storage._pkiEncrypted {return false} + if _storage._nextHop != rhs_storage._nextHop {return false} + if _storage._relayNode != rhs_storage._relayNode {return false} return true } if !storagesAreEqual {return false} @@ -4542,6 +4339,7 @@ extension MeshPacket.Priority: SwiftProtobuf._ProtoNameProviding { 70: .same(proto: "RELIABLE"), 80: .same(proto: "RESPONSE"), 100: .same(proto: "HIGH"), + 110: .same(proto: "ALERT"), 120: .same(proto: "ACK"), 127: .same(proto: "MAX"), ] @@ -4568,6 +4366,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB 8: .standard(proto: "via_mqtt"), 9: .standard(proto: "hops_away"), 10: .standard(proto: "is_favorite"), + 11: .standard(proto: "is_ignored"), ] fileprivate class _StorageClass { @@ -4581,6 +4380,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB var _viaMqtt: Bool = false var _hopsAway: UInt32? = nil var _isFavorite: Bool = false + var _isIgnored: Bool = false #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -4605,6 +4405,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB _viaMqtt = source._viaMqtt _hopsAway = source._hopsAway _isFavorite = source._isFavorite + _isIgnored = source._isIgnored } } @@ -4633,6 +4434,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB case 8: try { try decoder.decodeSingularBoolField(value: &_storage._viaMqtt) }() case 9: try { try decoder.decodeSingularUInt32Field(value: &_storage._hopsAway) }() case 10: try { try decoder.decodeSingularBoolField(value: &_storage._isFavorite) }() + case 11: try { try decoder.decodeSingularBoolField(value: &_storage._isIgnored) }() default: break } } @@ -4654,7 +4456,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB try { if let v = _storage._position { try visitor.visitSingularMessageField(value: v, fieldNumber: 3) } }() - if _storage._snr != 0 { + if _storage._snr.bitPattern != 0 { try visitor.visitSingularFloatField(value: _storage._snr, fieldNumber: 4) } if _storage._lastHeard != 0 { @@ -4675,6 +4477,9 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB if _storage._isFavorite != false { try visitor.visitSingularBoolField(value: _storage._isFavorite, fieldNumber: 10) } + if _storage._isIgnored != false { + try visitor.visitSingularBoolField(value: _storage._isIgnored, fieldNumber: 11) + } } try unknownFields.traverse(visitor: &visitor) } @@ -4694,6 +4499,7 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB if _storage._viaMqtt != rhs_storage._viaMqtt {return false} if _storage._hopsAway != rhs_storage._hopsAway {return false} if _storage._isFavorite != rhs_storage._isFavorite {return false} + if _storage._isIgnored != rhs_storage._isIgnored {return false} return true } if !storagesAreEqual {return false} @@ -5529,7 +5335,7 @@ extension Neighbor: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB if self.nodeID != 0 { try visitor.visitSingularUInt32Field(value: self.nodeID, fieldNumber: 1) } - if self.snr != 0 { + if self.snr.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.snr, fieldNumber: 2) } if self.lastRxTime != 0 { @@ -5654,8 +5460,8 @@ extension Heartbeat: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let _ = try decoder.nextFieldNumber() { - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { diff --git a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift index 4238811f..2cb3291b 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/module_config.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/module_config.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -20,7 +20,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public enum RemoteHardwarePinType: SwiftProtobuf.Enum { +public enum RemoteHardwarePinType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -58,24 +58,18 @@ public enum RemoteHardwarePinType: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension RemoteHardwarePinType: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [RemoteHardwarePinType] = [ .unknown, .digitalRead, .digitalWrite, ] -} -#endif // swift(>=4.2) +} /// /// Module Config -public struct ModuleConfig { +public struct ModuleConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -218,7 +212,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public enum OneOf_PayloadVariant: Equatable { + public enum OneOf_PayloadVariant: Equatable, Sendable { /// /// TODO: REPLACE case mqtt(ModuleConfig.MQTTConfig) @@ -259,73 +253,11 @@ public struct ModuleConfig { /// TODO: REPLACE case paxcounter(ModuleConfig.PaxcounterConfig) - #if !swift(>=4.1) - public static func ==(lhs: ModuleConfig.OneOf_PayloadVariant, rhs: ModuleConfig.OneOf_PayloadVariant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.mqtt, .mqtt): return { - guard case .mqtt(let l) = lhs, case .mqtt(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.serial, .serial): return { - guard case .serial(let l) = lhs, case .serial(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.externalNotification, .externalNotification): return { - guard case .externalNotification(let l) = lhs, case .externalNotification(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.storeForward, .storeForward): return { - guard case .storeForward(let l) = lhs, case .storeForward(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.rangeTest, .rangeTest): return { - guard case .rangeTest(let l) = lhs, case .rangeTest(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.telemetry, .telemetry): return { - guard case .telemetry(let l) = lhs, case .telemetry(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.cannedMessage, .cannedMessage): return { - guard case .cannedMessage(let l) = lhs, case .cannedMessage(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.audio, .audio): return { - guard case .audio(let l) = lhs, case .audio(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.remoteHardware, .remoteHardware): return { - guard case .remoteHardware(let l) = lhs, case .remoteHardware(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.neighborInfo, .neighborInfo): return { - guard case .neighborInfo(let l) = lhs, case .neighborInfo(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.ambientLighting, .ambientLighting): return { - guard case .ambientLighting(let l) = lhs, case .ambientLighting(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.detectionSensor, .detectionSensor): return { - guard case .detectionSensor(let l) = lhs, case .detectionSensor(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.paxcounter, .paxcounter): return { - guard case .paxcounter(let l) = lhs, case .paxcounter(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// MQTT Client Config - public struct MQTTConfig { + public struct MQTTConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -400,7 +332,7 @@ public struct ModuleConfig { /// /// Settings for reporting unencrypted information about our node to a map via MQTT - public struct MapReportSettings { + public struct MapReportSettings: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -420,7 +352,7 @@ public struct ModuleConfig { /// /// RemoteHardwareModule Config - public struct RemoteHardwareConfig { + public struct RemoteHardwareConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -444,7 +376,7 @@ public struct ModuleConfig { /// /// NeighborInfoModule Config - public struct NeighborInfoConfig { + public struct NeighborInfoConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -470,7 +402,7 @@ public struct ModuleConfig { /// /// Detection Sensor Module Config - public struct DetectionSensorConfig { + public struct DetectionSensorConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -517,7 +449,7 @@ public struct ModuleConfig { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum TriggerType: SwiftProtobuf.Enum { + public enum TriggerType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// Event is triggered if pin is low @@ -569,6 +501,16 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.DetectionSensorConfig.TriggerType] = [ + .logicLow, + .logicHigh, + .fallingEdge, + .risingEdge, + .eitherEdgeActiveLow, + .eitherEdgeActiveHigh, + ] + } public init() {} @@ -576,7 +518,7 @@ public struct ModuleConfig { /// /// Audio Config for codec2 voice - public struct AudioConfig { + public struct AudioConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -613,7 +555,7 @@ public struct ModuleConfig { /// /// Baudrate for codec2 voice - public enum Audio_Baud: SwiftProtobuf.Enum { + public enum Audio_Baud: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case codec2Default // = 0 case codec23200 // = 1 @@ -660,6 +602,19 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [ + .codec2Default, + .codec23200, + .codec22400, + .codec21600, + .codec21400, + .codec21300, + .codec21200, + .codec2700, + .codec2700B, + ] + } public init() {} @@ -667,7 +622,7 @@ public struct ModuleConfig { /// /// Config for the Paxcounter Module - public struct PaxcounterConfig { + public struct PaxcounterConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -693,7 +648,7 @@ public struct ModuleConfig { /// /// Serial Config - public struct SerialConfig { + public struct SerialConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -736,7 +691,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public enum Serial_Baud: SwiftProtobuf.Enum { + public enum Serial_Baud: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case baudDefault // = 0 case baud110 // = 1 @@ -804,11 +759,31 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [ + .baudDefault, + .baud110, + .baud300, + .baud600, + .baud1200, + .baud2400, + .baud4800, + .baud9600, + .baud19200, + .baud38400, + .baud57600, + .baud115200, + .baud230400, + .baud460800, + .baud576000, + .baud921600, + ] + } /// /// TODO: REPLACE - public enum Serial_Mode: SwiftProtobuf.Enum { + public enum Serial_Mode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case `default` // = 0 case simple // = 1 @@ -853,6 +828,17 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [ + .default, + .simple, + .proto, + .textmsg, + .nmea, + .caltopo, + .ws85, + ] + } public init() {} @@ -860,7 +846,7 @@ public struct ModuleConfig { /// /// External Notifications Config - public struct ExternalNotificationConfig { + public struct ExternalNotificationConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -943,7 +929,7 @@ public struct ModuleConfig { /// /// Store and Forward Module Config - public struct StoreForwardConfig { + public struct StoreForwardConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -979,7 +965,7 @@ public struct ModuleConfig { /// /// Preferences for the RangeTestModule - public struct RangeTestConfig { + public struct RangeTestConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1004,7 +990,7 @@ public struct ModuleConfig { /// /// Configuration for both device and environment metrics - public struct TelemetryConfig { + public struct TelemetryConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1073,7 +1059,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public struct CannedMessageConfig { + public struct CannedMessageConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1128,7 +1114,7 @@ public struct ModuleConfig { /// /// TODO: REPLACE - public enum InputEventChar: SwiftProtobuf.Enum { + public enum InputEventChar: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -1196,6 +1182,18 @@ public struct ModuleConfig { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [ + .none, + .up, + .down, + .left, + .right, + .select, + .back, + .cancel, + ] + } public init() {} @@ -1204,7 +1202,7 @@ public struct ModuleConfig { /// ///Ambient Lighting Module - Settings for control of onboard LEDs to allow users to adjust the brightness levels and respective color levels. ///Initially created for the RAK14001 RGB LED module. - public struct AmbientLightingConfig { + public struct AmbientLightingConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1237,89 +1235,9 @@ public struct ModuleConfig { public init() {} } -#if swift(>=4.2) - -extension ModuleConfig.DetectionSensorConfig.TriggerType: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.DetectionSensorConfig.TriggerType] = [ - .logicLow, - .logicHigh, - .fallingEdge, - .risingEdge, - .eitherEdgeActiveLow, - .eitherEdgeActiveHigh, - ] -} - -extension ModuleConfig.AudioConfig.Audio_Baud: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [ - .codec2Default, - .codec23200, - .codec22400, - .codec21600, - .codec21400, - .codec21300, - .codec21200, - .codec2700, - .codec2700B, - ] -} - -extension ModuleConfig.SerialConfig.Serial_Baud: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [ - .baudDefault, - .baud110, - .baud300, - .baud600, - .baud1200, - .baud2400, - .baud4800, - .baud9600, - .baud19200, - .baud38400, - .baud57600, - .baud115200, - .baud230400, - .baud460800, - .baud576000, - .baud921600, - ] -} - -extension ModuleConfig.SerialConfig.Serial_Mode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [ - .default, - .simple, - .proto, - .textmsg, - .nmea, - .caltopo, - .ws85, - ] -} - -extension ModuleConfig.CannedMessageConfig.InputEventChar: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [ - .none, - .up, - .down, - .left, - .right, - .select, - .back, - .cancel, - ] -} - -#endif // swift(>=4.2) - /// /// A GPIO pin definition for remote hardware module -public struct RemoteHardwarePin { +public struct RemoteHardwarePin: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1341,32 +1259,6 @@ public struct RemoteHardwarePin { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension RemoteHardwarePinType: @unchecked Sendable {} -extension ModuleConfig: @unchecked Sendable {} -extension ModuleConfig.OneOf_PayloadVariant: @unchecked Sendable {} -extension ModuleConfig.MQTTConfig: @unchecked Sendable {} -extension ModuleConfig.MapReportSettings: @unchecked Sendable {} -extension ModuleConfig.RemoteHardwareConfig: @unchecked Sendable {} -extension ModuleConfig.NeighborInfoConfig: @unchecked Sendable {} -extension ModuleConfig.DetectionSensorConfig: @unchecked Sendable {} -extension ModuleConfig.DetectionSensorConfig.TriggerType: @unchecked Sendable {} -extension ModuleConfig.AudioConfig: @unchecked Sendable {} -extension ModuleConfig.AudioConfig.Audio_Baud: @unchecked Sendable {} -extension ModuleConfig.PaxcounterConfig: @unchecked Sendable {} -extension ModuleConfig.SerialConfig: @unchecked Sendable {} -extension ModuleConfig.SerialConfig.Serial_Baud: @unchecked Sendable {} -extension ModuleConfig.SerialConfig.Serial_Mode: @unchecked Sendable {} -extension ModuleConfig.ExternalNotificationConfig: @unchecked Sendable {} -extension ModuleConfig.StoreForwardConfig: @unchecked Sendable {} -extension ModuleConfig.RangeTestConfig: @unchecked Sendable {} -extension ModuleConfig.TelemetryConfig: @unchecked Sendable {} -extension ModuleConfig.CannedMessageConfig: @unchecked Sendable {} -extension ModuleConfig.CannedMessageConfig.InputEventChar: @unchecked Sendable {} -extension ModuleConfig.AmbientLightingConfig: @unchecked Sendable {} -extension RemoteHardwarePin: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift index efe6cdd5..006fd9c8 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/mqtt.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/mqtt.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// This message wraps a MeshPacket with extra metadata about the sender and how it arrived. -public struct ServiceEnvelope { +public struct ServiceEnvelope: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -57,7 +57,7 @@ public struct ServiceEnvelope { /// /// Information about a node intended to be reported unencrypted to a map using MQTT. -public struct MapReport { +public struct MapReport: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -121,11 +121,6 @@ public struct MapReport { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension ServiceEnvelope: @unchecked Sendable {} -extension MapReport: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift index cf8aa463..e24ed371 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/paxcount.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/paxcount.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// TODO: REPLACE -public struct Paxcount { +public struct Paxcount: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -44,10 +44,6 @@ public struct Paxcount { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension Paxcount: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift index dd7e036f..79dfd7f1 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/portnums.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/portnums.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -33,7 +33,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// 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. -public enum PortNum: SwiftProtobuf.Enum { +public enum PortNum: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -107,6 +107,10 @@ public enum PortNum: SwiftProtobuf.Enum { /// NOTE: This portnum traffic is not sent to the public MQTT starting at firmware version 2.2.9 case detectionSensorApp // = 10 + /// + /// Same as Text Message but used for critical alerts. + case alertApp // = 11 + /// /// Provides a 'ping' service that replies to any packet it receives. /// Also serves as a small example module. @@ -222,6 +226,7 @@ public enum PortNum: SwiftProtobuf.Enum { case 8: self = .waypointApp case 9: self = .audioApp case 10: self = .detectionSensorApp + case 11: self = .alertApp case 32: self = .replyApp case 33: self = .ipTunnelApp case 34: self = .paxcounterApp @@ -256,6 +261,7 @@ public enum PortNum: SwiftProtobuf.Enum { case .waypointApp: return 8 case .audioApp: return 9 case .detectionSensorApp: return 10 + case .alertApp: return 11 case .replyApp: return 32 case .ipTunnelApp: return 33 case .paxcounterApp: return 34 @@ -277,11 +283,6 @@ public enum PortNum: SwiftProtobuf.Enum { } } -} - -#if swift(>=4.2) - -extension PortNum: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [PortNum] = [ .unknownApp, @@ -295,6 +296,7 @@ extension PortNum: CaseIterable { .waypointApp, .audioApp, .detectionSensorApp, + .alertApp, .replyApp, .ipTunnelApp, .paxcounterApp, @@ -313,14 +315,9 @@ extension PortNum: CaseIterable { .atakForwarder, .max, ] + } -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension PortNum: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. extension PortNum: SwiftProtobuf._ProtoNameProviding { @@ -336,6 +333,7 @@ extension PortNum: SwiftProtobuf._ProtoNameProviding { 8: .same(proto: "WAYPOINT_APP"), 9: .same(proto: "AUDIO_APP"), 10: .same(proto: "DETECTION_SENSOR_APP"), + 11: .same(proto: "ALERT_APP"), 32: .same(proto: "REPLY_APP"), 33: .same(proto: "IP_TUNNEL_APP"), 34: .same(proto: "PAXCOUNTER_APP"), diff --git a/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift index 5f51e948..58c21701 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/powermon.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/powermon.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// 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) -public struct PowerMon { +public struct PowerMon: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -31,7 +31,7 @@ public struct PowerMon { /// 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. - public enum State: SwiftProtobuf.Enum { + public enum State: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case none // = 0 case cpuDeepSleep // = 1 @@ -104,37 +104,31 @@ public struct PowerMon { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [PowerMon.State] = [ + .none, + .cpuDeepSleep, + .cpuLightSleep, + .vext1On, + .loraRxon, + .loraTxon, + .loraRxactive, + .btOn, + .ledOn, + .screenOn, + .screenDrawing, + .wifiOn, + .gpsActive, + ] + } public init() {} } -#if swift(>=4.2) - -extension PowerMon.State: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [PowerMon.State] = [ - .none, - .cpuDeepSleep, - .cpuLightSleep, - .vext1On, - .loraRxon, - .loraTxon, - .loraRxactive, - .btOn, - .ledOn, - .screenOn, - .screenDrawing, - .wifiOn, - .gpsActive, - ] -} - -#endif // swift(>=4.2) - /// /// PowerStress testing support via the C++ PowerStress module -public struct PowerStressMessage { +public struct PowerStressMessage: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -151,7 +145,7 @@ public struct PowerStressMessage { /// 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 - public enum Opcode: SwiftProtobuf.Enum { + public enum Opcode: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -272,48 +266,35 @@ public struct PowerStressMessage { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [PowerStressMessage.Opcode] = [ + .unset, + .printInfo, + .forceQuiet, + .endQuiet, + .screenOn, + .screenOff, + .cpuIdle, + .cpuDeepsleep, + .cpuFullon, + .ledOn, + .ledOff, + .loraOff, + .loraTx, + .loraRx, + .btOff, + .btOn, + .wifiOff, + .wifiOn, + .gpsOff, + .gpsOn, + ] + } public init() {} } -#if swift(>=4.2) - -extension PowerStressMessage.Opcode: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [PowerStressMessage.Opcode] = [ - .unset, - .printInfo, - .forceQuiet, - .endQuiet, - .screenOn, - .screenOff, - .cpuIdle, - .cpuDeepsleep, - .cpuFullon, - .ledOn, - .ledOff, - .loraOff, - .loraTx, - .loraRx, - .btOff, - .btOn, - .wifiOff, - .wifiOn, - .gpsOff, - .gpsOn, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension PowerMon: @unchecked Sendable {} -extension PowerMon.State: @unchecked Sendable {} -extension PowerStressMessage: @unchecked Sendable {} -extension PowerStressMessage.Opcode: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -323,8 +304,8 @@ extension PowerMon: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB public static let _protobuf_nameMap = SwiftProtobuf._NameMap() public mutating func decodeMessage(decoder: inout D) throws { - while let _ = try decoder.nextFieldNumber() { - } + // Load everything into unknown fields + while try decoder.nextFieldNumber() != nil {} } public func traverse(visitor: inout V) throws { @@ -379,7 +360,7 @@ extension PowerStressMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if self.cmd != .unset { try visitor.visitSingularEnumField(value: self.cmd, fieldNumber: 1) } - if self.numSeconds != 0 { + if self.numSeconds.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.numSeconds, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) diff --git a/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift index ac6eeb26..d23dc07b 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/remote_hardware.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/remote_hardware.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -30,7 +30,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// 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?) -public struct HardwareMessage { +public struct HardwareMessage: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -52,7 +52,7 @@ public struct HardwareMessage { /// /// TODO: REPLACE - public enum TypeEnum: SwiftProtobuf.Enum { + public enum TypeEnum: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -110,32 +110,21 @@ public struct HardwareMessage { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [HardwareMessage.TypeEnum] = [ + .unset, + .writeGpios, + .watchGpios, + .gpiosChanged, + .readGpios, + .readGpiosReply, + ] + } public init() {} } -#if swift(>=4.2) - -extension HardwareMessage.TypeEnum: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [HardwareMessage.TypeEnum] = [ - .unset, - .writeGpios, - .watchGpios, - .gpiosChanged, - .readGpios, - .readGpiosReply, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension HardwareMessage: @unchecked Sendable {} -extension HardwareMessage.TypeEnum: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift index 6fdf3208..38d0c880 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/rtttl.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/rtttl.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Canned message module configuration. -public struct RTTTLConfig { +public struct RTTTLConfig: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -36,10 +36,6 @@ public struct RTTTLConfig { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension RTTTLConfig: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift index 54efa77b..deb96569 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/storeforward.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/storeforward.proto @@ -22,7 +23,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// TODO: REPLACE -public struct StoreAndForward { +public struct StoreAndForward: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -79,7 +80,7 @@ public struct StoreAndForward { /// /// TODO: REPLACE - public enum OneOf_Variant: Equatable { + public enum OneOf_Variant: Equatable, @unchecked Sendable { /// /// TODO: REPLACE case stats(StoreAndForward.Statistics) @@ -93,38 +94,12 @@ public struct StoreAndForward { /// Text from history message. case text(Data) - #if !swift(>=4.1) - public static func ==(lhs: StoreAndForward.OneOf_Variant, rhs: StoreAndForward.OneOf_Variant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.stats, .stats): return { - guard case .stats(let l) = lhs, case .stats(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.history, .history): return { - guard case .history(let l) = lhs, case .history(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.heartbeat, .heartbeat): return { - guard case .heartbeat(let l) = lhs, case .heartbeat(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.text, .text): return { - guard case .text(let l) = lhs, case .text(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } /// /// 001 - 063 = From Router /// 064 - 127 = From Client - public enum RequestResponse: SwiftProtobuf.Enum { + public enum RequestResponse: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -242,11 +217,31 @@ public struct StoreAndForward { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [StoreAndForward.RequestResponse] = [ + .unset, + .routerError, + .routerHeartbeat, + .routerPing, + .routerPong, + .routerBusy, + .routerHistory, + .routerStats, + .routerTextDirect, + .routerTextBroadcast, + .clientError, + .clientHistory, + .clientStats, + .clientPing, + .clientPong, + .clientAbort, + ] + } /// /// TODO: REPLACE - public struct Statistics { + public struct Statistics: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -294,7 +289,7 @@ public struct StoreAndForward { /// /// TODO: REPLACE - public struct History { + public struct History: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -319,7 +314,7 @@ public struct StoreAndForward { /// /// TODO: REPLACE - public struct Heartbeat { + public struct Heartbeat: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -340,41 +335,6 @@ public struct StoreAndForward { public init() {} } -#if swift(>=4.2) - -extension StoreAndForward.RequestResponse: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [StoreAndForward.RequestResponse] = [ - .unset, - .routerError, - .routerHeartbeat, - .routerPing, - .routerPong, - .routerBusy, - .routerHistory, - .routerStats, - .routerTextDirect, - .routerTextBroadcast, - .clientError, - .clientHistory, - .clientStats, - .clientPing, - .clientPong, - .clientAbort, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension StoreAndForward: @unchecked Sendable {} -extension StoreAndForward.OneOf_Variant: @unchecked Sendable {} -extension StoreAndForward.RequestResponse: @unchecked Sendable {} -extension StoreAndForward.Statistics: @unchecked Sendable {} -extension StoreAndForward.History: @unchecked Sendable {} -extension StoreAndForward.Heartbeat: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift index e67b5272..737ebf95 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/telemetry.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/telemetry.proto @@ -7,7 +8,6 @@ // For information on using the generated types, please see the documentation: // https://github.com/apple/swift-protobuf/ -import Foundation import SwiftProtobuf // If the compiler emits an error on this type, it is because this file @@ -22,7 +22,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP /// /// Supported I2C Sensors for telemetry in Meshtastic -public enum TelemetrySensorType: SwiftProtobuf.Enum { +public enum TelemetrySensorType: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int /// @@ -156,6 +156,14 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { /// /// SCD40/SCD41 CO2, humidity, temperature sensor case scd4X // = 32 + + /// + /// ClimateGuard RadSens, radiation, Geiger-Muller Tube + case radsens // = 33 + + /// + /// High accuracy current and voltage + case ina226 // = 34 case UNRECOGNIZED(Int) public init() { @@ -197,6 +205,8 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { case 30: self = .max30102 case 31: self = .mlx90614 case 32: self = .scd4X + case 33: self = .radsens + case 34: self = .ina226 default: self = .UNRECOGNIZED(rawValue) } } @@ -236,15 +246,12 @@ public enum TelemetrySensorType: SwiftProtobuf.Enum { case .max30102: return 30 case .mlx90614: return 31 case .scd4X: return 32 + case .radsens: return 33 + case .ina226: return 34 case .UNRECOGNIZED(let i): return i } } -} - -#if swift(>=4.2) - -extension TelemetrySensorType: CaseIterable { // The compiler won't synthesize support with the UNRECOGNIZED case. public static let allCases: [TelemetrySensorType] = [ .sensorUnset, @@ -280,14 +287,15 @@ extension TelemetrySensorType: CaseIterable { .max30102, .mlx90614, .scd4X, + .radsens, + .ina226, ] -} -#endif // swift(>=4.2) +} /// /// Key native device metrics such as battery level -public struct DeviceMetrics { +public struct DeviceMetrics: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -360,7 +368,7 @@ public struct DeviceMetrics { /// /// Weather station or other environmental metrics -public struct EnvironmentMetrics { +public struct EnvironmentMetrics: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -554,6 +562,17 @@ public struct EnvironmentMetrics { /// Clears the value of `windLull`. Subsequent reads from it will return its default value. public mutating func clearWindLull() {_uniqueStorage()._windLull = nil} + /// + /// Radiation in µR/h + public var radiation: Float { + get {return _storage._radiation ?? 0} + set {_uniqueStorage()._radiation = newValue} + } + /// Returns true if `radiation` has been explicitly set. + public var hasRadiation: Bool {return _storage._radiation != nil} + /// Clears the value of `radiation`. Subsequent reads from it will return its default value. + public mutating func clearRadiation() {_uniqueStorage()._radiation = nil} + public var unknownFields = SwiftProtobuf.UnknownStorage() public init() {} @@ -563,7 +582,7 @@ public struct EnvironmentMetrics { /// /// Power Metrics (voltage / current / etc) -public struct PowerMetrics { +public struct PowerMetrics: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -648,7 +667,7 @@ public struct PowerMetrics { /// /// Air quality metrics -public struct AirQualityMetrics { +public struct AirQualityMetrics: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -817,7 +836,7 @@ public struct AirQualityMetrics { /// /// Local device mesh statistics -public struct LocalStats { +public struct LocalStats: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -875,7 +894,7 @@ public struct LocalStats { /// /// Health telemetry metrics -public struct HealthMetrics { +public struct HealthMetrics: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -924,7 +943,7 @@ public struct HealthMetrics { /// /// Types of Measurements the telemetry module is equipped to handle -public struct Telemetry { +public struct Telemetry: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -997,7 +1016,7 @@ public struct Telemetry { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum OneOf_Variant: Equatable { + public enum OneOf_Variant: Equatable, Sendable { /// /// Key native device metrics such as battery level case deviceMetrics(DeviceMetrics) @@ -1017,40 +1036,6 @@ public struct Telemetry { /// Health telemetry metrics case healthMetrics(HealthMetrics) - #if !swift(>=4.1) - public static func ==(lhs: Telemetry.OneOf_Variant, rhs: Telemetry.OneOf_Variant) -> Bool { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch (lhs, rhs) { - case (.deviceMetrics, .deviceMetrics): return { - guard case .deviceMetrics(let l) = lhs, case .deviceMetrics(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.environmentMetrics, .environmentMetrics): return { - guard case .environmentMetrics(let l) = lhs, case .environmentMetrics(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.airQualityMetrics, .airQualityMetrics): return { - guard case .airQualityMetrics(let l) = lhs, case .airQualityMetrics(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.powerMetrics, .powerMetrics): return { - guard case .powerMetrics(let l) = lhs, case .powerMetrics(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.localStats, .localStats): return { - guard case .localStats(let l) = lhs, case .localStats(let r) = rhs else { preconditionFailure() } - return l == r - }() - case (.healthMetrics, .healthMetrics): return { - guard case .healthMetrics(let l) = lhs, case .healthMetrics(let r) = rhs else { preconditionFailure() } - return l == r - }() - default: return false - } - } - #endif } public init() {} @@ -1058,7 +1043,7 @@ public struct Telemetry { /// /// NAU7802 Telemetry configuration, for saving to flash -public struct Nau7802Config { +public struct Nau7802Config: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -1076,19 +1061,6 @@ public struct Nau7802Config { public init() {} } -#if swift(>=5.5) && canImport(_Concurrency) -extension TelemetrySensorType: @unchecked Sendable {} -extension DeviceMetrics: @unchecked Sendable {} -extension EnvironmentMetrics: @unchecked Sendable {} -extension PowerMetrics: @unchecked Sendable {} -extension AirQualityMetrics: @unchecked Sendable {} -extension LocalStats: @unchecked Sendable {} -extension HealthMetrics: @unchecked Sendable {} -extension Telemetry: @unchecked Sendable {} -extension Telemetry.OneOf_Variant: @unchecked Sendable {} -extension Nau7802Config: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" @@ -1128,6 +1100,8 @@ extension TelemetrySensorType: SwiftProtobuf._ProtoNameProviding { 30: .same(proto: "MAX30102"), 31: .same(proto: "MLX90614"), 32: .same(proto: "SCD4X"), + 33: .same(proto: "RADSENS"), + 34: .same(proto: "INA226"), ] } @@ -1211,6 +1185,7 @@ extension EnvironmentMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImple 15: .same(proto: "weight"), 16: .standard(proto: "wind_gust"), 17: .standard(proto: "wind_lull"), + 18: .same(proto: "radiation"), ] fileprivate class _StorageClass { @@ -1231,6 +1206,7 @@ extension EnvironmentMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImple var _weight: Float? = nil var _windGust: Float? = nil var _windLull: Float? = nil + var _radiation: Float? = nil #if swift(>=5.10) // This property is used as the initial default value for new instances of the type. @@ -1262,6 +1238,7 @@ extension EnvironmentMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImple _weight = source._weight _windGust = source._windGust _windLull = source._windLull + _radiation = source._radiation } } @@ -1297,6 +1274,7 @@ extension EnvironmentMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImple case 15: try { try decoder.decodeSingularFloatField(value: &_storage._weight) }() case 16: try { try decoder.decodeSingularFloatField(value: &_storage._windGust) }() case 17: try { try decoder.decodeSingularFloatField(value: &_storage._windLull) }() + case 18: try { try decoder.decodeSingularFloatField(value: &_storage._radiation) }() default: break } } @@ -1360,6 +1338,9 @@ extension EnvironmentMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImple try { if let v = _storage._windLull { try visitor.visitSingularFloatField(value: v, fieldNumber: 17) } }() + try { if let v = _storage._radiation { + try visitor.visitSingularFloatField(value: v, fieldNumber: 18) + } }() } try unknownFields.traverse(visitor: &visitor) } @@ -1386,6 +1367,7 @@ extension EnvironmentMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImple if _storage._weight != rhs_storage._weight {return false} if _storage._windGust != rhs_storage._windGust {return false} if _storage._windLull != rhs_storage._windLull {return false} + if _storage._radiation != rhs_storage._radiation {return false} return true } if !storagesAreEqual {return false} @@ -1611,10 +1593,10 @@ extension LocalStats: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio if self.uptimeSeconds != 0 { try visitor.visitSingularUInt32Field(value: self.uptimeSeconds, fieldNumber: 1) } - if self.channelUtilization != 0 { + if self.channelUtilization.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.channelUtilization, fieldNumber: 2) } - if self.airUtilTx != 0 { + if self.airUtilTx.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.airUtilTx, fieldNumber: 3) } if self.numPacketsTx != 0 { @@ -1881,7 +1863,7 @@ extension Nau7802Config: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa if self.zeroOffset != 0 { try visitor.visitSingularInt32Field(value: self.zeroOffset, fieldNumber: 1) } - if self.calibrationFactor != 0 { + if self.calibrationFactor.bitPattern != 0 { try visitor.visitSingularFloatField(value: self.calibrationFactor, fieldNumber: 2) } try unknownFields.traverse(visitor: &visitor) diff --git a/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift b/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift index 1f41fe0b..46907a58 100644 --- a/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift +++ b/MeshtasticProtobufs/Sources/meshtastic/xmodem.pb.swift @@ -1,5 +1,6 @@ // DO NOT EDIT. // swift-format-ignore-file +// swiftlint:disable all // // Generated by the Swift generator plugin for the protocol buffer compiler. // Source: meshtastic/xmodem.proto @@ -20,7 +21,7 @@ fileprivate struct _GeneratedWithProtocGenSwiftVersion: SwiftProtobuf.ProtobufAP typealias Version = _2 } -public struct XModem { +public struct XModem: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. @@ -35,7 +36,7 @@ public struct XModem { public var unknownFields = SwiftProtobuf.UnknownStorage() - public enum Control: SwiftProtobuf.Enum { + public enum Control: SwiftProtobuf.Enum, Swift.CaseIterable { public typealias RawValue = Int case nul // = 0 case soh // = 1 @@ -79,34 +80,23 @@ public struct XModem { } } + // The compiler won't synthesize support with the UNRECOGNIZED case. + public static let allCases: [XModem.Control] = [ + .nul, + .soh, + .stx, + .eot, + .ack, + .nak, + .can, + .ctrlz, + ] + } public init() {} } -#if swift(>=4.2) - -extension XModem.Control: CaseIterable { - // The compiler won't synthesize support with the UNRECOGNIZED case. - public static let allCases: [XModem.Control] = [ - .nul, - .soh, - .stx, - .eot, - .ack, - .nak, - .can, - .ctrlz, - ] -} - -#endif // swift(>=4.2) - -#if swift(>=5.5) && canImport(_Concurrency) -extension XModem: @unchecked Sendable {} -extension XModem.Control: @unchecked Sendable {} -#endif // swift(>=5.5) && canImport(_Concurrency) - // MARK: - Code below here is support for the SwiftProtobuf runtime. fileprivate let _protobuf_package = "meshtastic" diff --git a/Widgets/MeshActivityAttributes.swift b/Widgets/MeshActivityAttributes.swift index 876b75de..37376531 100644 --- a/Widgets/MeshActivityAttributes.swift +++ b/Widgets/MeshActivityAttributes.swift @@ -4,7 +4,7 @@ // // Created by Garth Vander Houwen on 3/1/23. // - +#if !targetEnvironment(macCatalyst) #if canImport(ActivityKit) import ActivityKit @@ -36,3 +36,4 @@ struct MeshActivityAttributes: ActivityAttributes { var name: String } #endif +#endif diff --git a/protobufs b/protobufs index 04f21f5c..2cffaf53 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 04f21f5c7238b8e02f794d9282c4786752634b3c +Subproject commit 2cffaf53e3faf1b6e41a8b8f05312f2f893be413