Finish up route list

This commit is contained in:
Garth Vander Houwen 2024-04-14 14:51:59 -07:00
parent 50f2ce5ece
commit 0f26c3c8eb
23 changed files with 820 additions and 179 deletions

View file

@ -286,6 +286,7 @@
DD23D9AB2B7133F6003F5CBE /* MeshtasticDataModelV 25.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 25.xcdatamodel"; sourceTree = "<group>"; };
DD2553562855B02500E55709 /* LoRaConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoRaConfig.swift; sourceTree = "<group>"; };
DD2553582855B52700E55709 /* PositionConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionConfig.swift; sourceTree = "<group>"; };
DD268D8C2BCC7D11008073AE /* MeshtasticDataModelV 35.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 35.xcdatamodel"; sourceTree = "<group>"; };
DD295CE92B323ED9002CC4AC /* MeshtasticDataModelV22.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV22.xcdatamodel; sourceTree = "<group>"; };
DD2AD8A7296D2DF9001FF0E7 /* MapViewSwiftUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewSwiftUI.swift; sourceTree = "<group>"; };
DD2CC2E52ABFE04E00EDFDA7 /* MeshtasticDataModelV19.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV19.xcdatamodel; sourceTree = "<group>"; };
@ -1815,6 +1816,7 @@
DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
DD268D8C2BCC7D11008073AE /* MeshtasticDataModelV 35.xcdatamodel */,
DDDBC87C2BC65682001E8DF7 /* MeshtasticDataModelV 34.xcdatamodel */,
DDF45C382BC46B16005ED5F2 /* MeshtasticDataModelV33.xcdatamodel */,
DD9681A22BBB22BE00FD2C47 /* MeshtasticDataModelV32.xcdatamodel */,
@ -1850,7 +1852,7 @@
DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */,
DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */,
);
currentVersion = DDDBC87C2BC65682001E8DF7 /* MeshtasticDataModelV 34.xcdatamodel */;
currentVersion = DD268D8C2BCC7D11008073AE /* MeshtasticDataModelV 35.xcdatamodel */;
name = Meshtastic.xcdatamodeld;
path = Meshtastic/Meshtastic.xcdatamodeld;
sourceTree = "<group>";

View file

@ -8,7 +8,7 @@
import Foundation
extension Date {
func formattedDate(format: String) -> String {
let dateformat = DateFormatter()
dateformat.dateFormat = format
@ -18,4 +18,15 @@ extension Date {
return "unknown.age".localized
}
}
func relativeTimeOfDay() -> String {
let hour = Calendar.current.component(.hour, from: self)
switch hour {
case 6..<12 : return "relativetimeofday.morning".localized
case 12 : return "relativetimeofday.midday".localized
case 13..<17 : return "relativetimeofday.afternoon".localized
case 17..<22 : return "relativetimeofday.evening".localized
default: return "relativetimeofday.nighttime".localized
}
}
}

View file

@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>MeshtasticDataModelV 34.xcdatamodel</string>
<string>MeshtasticDataModelV 35.xcdatamodel</string>
</dict>
</plist>

View file

@ -326,7 +326,7 @@
<relationship name="rangeTestConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="rangeTestConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="RouteEntity" representedClassName="RouteEntity" syncable="YES" codeGenerationType="class">
<attribute name="color" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="color" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="id" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>

View file

@ -0,0 +1,455 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22757" systemVersion="23E224" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="AmbientLightingConfigEntity" representedClassName="AmbientLightingConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="blue" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="current" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="green" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ledState" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="red" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="ambientLightingConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="ambientLightingConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="BluetoothConfigEntity" representedClassName="BluetoothConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="fixedPin" optional="YES" attributeType="Integer 32" defaultValueString="123456" usesScalarValueType="YES"/>
<attribute name="mode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="bluetoothConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="bluetoothConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="CannedMessageConfigEntity" representedClassName="CannedMessageConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="inputbrokerEventCcw" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="inputbrokerEventCw" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="inputbrokerEventPress" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="inputbrokerPinA" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="inputbrokerPinB" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
<attribute name="inputbrokerPinPress" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
<attribute name="messages" optional="YES" attributeType="String" minValueString="0" maxValueString="198"/>
<attribute name="rotary1Enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="sendBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="updown1Enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<relationship name="cannedMessagesConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="cannedMessageConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="ChannelEntity" representedClassName="ChannelEntity" syncable="YES" codeGenerationType="class">
<attribute name="downlinkEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="id" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="index" attributeType="Integer 32" minValueString="0" maxValueString="13" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="mute" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="name" optional="YES" attributeType="String"/>
<attribute name="positionPrecision" optional="YES" attributeType="Integer 32" defaultValueString="32" usesScalarValueType="YES"/>
<attribute name="psk" optional="YES" attributeType="Binary"/>
<attribute name="role" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="uplinkEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<relationship name="myInfoChannel" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="channels" inverseEntity="MyInfoEntity"/>
<fetchedProperty name="allPrivateMessages" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="channel == $FETCH_SOURCE.index &amp;&amp; toUser == nil AND isEmoji == false"/>
</fetchedProperty>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="index"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="DetectionSensorConfigEntity" representedClassName="DetectionSensorConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="detectionTriggeredHigh" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="minimumBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="monitorPin" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="name" optional="YES" attributeType="String"/>
<attribute name="sendBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="stateBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="usePullup" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<relationship name="detectionSensorConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="detectionSensorConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="DeviceConfigEntity" representedClassName="DeviceConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="buttonGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="buzzerGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="debugLogEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="disableTripleClick" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="doubleTapAsButtonPress" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="isManaged" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="nodeInfoBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="rebroadcastMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="role" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="serialEnabled" optional="YES" attributeType="Boolean" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="tzdef" optional="YES" attributeType="String"/>
<relationship name="deviceConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="deviceConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="DeviceMetadataEntity" representedClassName="DeviceMetadataEntity" syncable="YES" codeGenerationType="class">
<attribute name="canShutdown" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="deviceStateVersion" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="firmwareVersion" optional="YES" attributeType="String"/>
<attribute name="hasBluetooth" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="hasEthernet" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="hasWifi" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="hwModel" optional="YES" attributeType="String"/>
<attribute name="positionFlags" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="role" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="metadataNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="metadata" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="DisplayConfigEntity" representedClassName="DisplayConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="compassNorthTop" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="displayMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="flipScreen" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="gpsFormat" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="headingBold" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="oledType" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="screenCarouselInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="screenOnSeconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="units" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="wakeOnTapOrMotion" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<relationship name="displayConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="displayConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="ExternalNotificationConfigEntity" representedClassName="ExternalNotificationConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="active" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertBellBuzzer" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertBellVibra" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertMessage" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertMessageBuzzer" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="alertMessageVibra" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="nagTimeout" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="output" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="outputBuzzer" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="outputMilliseconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="outputVibra" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="useI2SAsBuzzer" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="usePWM" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<relationship name="externalNotificationConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="externalNotificationConfig" inverseEntity="NodeInfoEntity"/>
<fetchedProperty name="fetchedProperty" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="ExternalNotificationConfigEntity"/>
</fetchedProperty>
</entity>
<entity name="LocationEntity" representedClassName="LocationEntity" syncable="YES" codeGenerationType="class">
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="heading" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="id" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
<attribute name="latitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="longitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="speed" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="routeLocation" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RouteEntity" inverseName="locations" inverseEntity="RouteEntity"/>
</entity>
<entity name="LoRaConfigEntity" representedClassName="LoRaConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="bandwidth" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="channelNum" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="codingRate" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="frequencyOffset" optional="YES" attributeType="Float" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="hopLimit" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ignoreMqtt" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="modemPreset" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="overrideDutyCycle" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="overrideFrequency" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="regionCode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="spreadFactor" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="sx126xRxBoostedGain" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="txEnabled" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="txPower" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="usePreset" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<relationship name="loRaConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="loRaConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="MessageEntity" representedClassName="MessageEntity" syncable="YES" codeGenerationType="class">
<attribute name="ackError" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ackSNR" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="ackTimestamp" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="admin" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="adminDescription" optional="YES" attributeType="String"/>
<attribute name="channel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="isEmoji" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="messageId" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="messagePayload" optional="YES" attributeType="String" defaultValueString=""/>
<attribute name="messagePayloadMarkdown" optional="YES" attributeType="String"/>
<attribute name="messageTimestamp" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="portNum" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="read" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="realACK" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="receivedACK" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="receivedTimestamp" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="replyID" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<relationship name="fromUser" optional="YES" maxCount="1" deletionRule="Nullify" ordered="YES" destinationEntity="UserEntity" inverseName="sentMessages" inverseEntity="UserEntity"/>
<relationship name="toUser" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="UserEntity" inverseName="receivedMessages" inverseEntity="UserEntity"/>
<fetchedProperty name="tapbacks" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="replyID == $FETCH_SOURCE.messageId AND isEmoji == true"/>
</fetchedProperty>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="messageId"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="MQTTConfigEntity" representedClassName="MQTTConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="address" optional="YES" attributeType="String" maxValueString="30"/>
<attribute name="enabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="encryptionEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="jsonEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="mapPositionPrecision" optional="YES" attributeType="Integer 32" defaultValueString="13" usesScalarValueType="YES"/>
<attribute name="mapPublishIntervalSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="mapReportingEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="password" optional="YES" attributeType="String" maxValueString="30"/>
<attribute name="proxyToClientEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="root" optional="YES" attributeType="String" defaultValueString="msh"/>
<attribute name="tlsEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="username" optional="YES" attributeType="String" maxValueString="30"/>
<relationship name="mqttConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="mqttConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="MyInfoEntity" representedClassName="MyInfoEntity" syncable="YES" codeGenerationType="class">
<attribute name="adminIndex" optional="YES" attributeType="Integer 32" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="bleName" optional="YES" attributeType="String"/>
<attribute name="minAppVersion" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="myNodeNum" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="peripheralId" optional="YES" attributeType="String"/>
<attribute name="rebootCount" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="channels" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="ChannelEntity" inverseName="myInfoChannel" inverseEntity="ChannelEntity"/>
<relationship name="myInfoNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="myInfo" inverseEntity="NodeInfoEntity"/>
<fetchedProperty name="allMessages" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="toUser == nil"/>
</fetchedProperty>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="myNodeNum"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="NetworkConfigEntity" representedClassName="NetworkConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="dns" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ethEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="gateway" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ip" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="ntpServer" optional="YES" attributeType="String"/>
<attribute name="subnet" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="wifiEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="wifiMode" optional="YES" attributeType="Integer 32" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="wifiPsk" optional="YES" attributeType="String" minValueString="0" maxValueString="60"/>
<attribute name="wifiSsid" optional="YES" attributeType="String" minValueString="0" maxValueString="30"/>
<relationship name="networkConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="networkConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="NodeInfoEntity" representedClassName="NodeInfoEntity" syncable="YES" codeGenerationType="class">
<attribute name="bleName" optional="YES" attributeType="String"/>
<attribute name="channel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="favorite" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="hopsAway" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="id" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="lastHeard" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="peripheralId" optional="YES" attributeType="String"/>
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="viaMqtt" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<relationship name="ambientLightingConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="AmbientLightingConfigEntity" inverseName="ambientLightingConfigNode" inverseEntity="AmbientLightingConfigEntity"/>
<relationship name="bluetoothConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="BluetoothConfigEntity" inverseName="bluetoothConfigNode" inverseEntity="BluetoothConfigEntity"/>
<relationship name="cannedMessageConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="CannedMessageConfigEntity" inverseName="cannedMessagesConfigNode" inverseEntity="CannedMessageConfigEntity"/>
<relationship name="detectionSensorConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="DetectionSensorConfigEntity" inverseName="detectionSensorConfigNode" inverseEntity="DetectionSensorConfigEntity"/>
<relationship name="deviceConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="DeviceConfigEntity" inverseName="deviceConfigNode" inverseEntity="DeviceConfigEntity"/>
<relationship name="displayConfig" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="DisplayConfigEntity" inverseName="displayConfigNode" inverseEntity="DisplayConfigEntity"/>
<relationship name="externalNotificationConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="ExternalNotificationConfigEntity" inverseName="externalNotificationConfigNode" inverseEntity="ExternalNotificationConfigEntity"/>
<relationship name="loRaConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="LoRaConfigEntity" inverseName="loRaConfigNode" inverseEntity="LoRaConfigEntity"/>
<relationship name="metadata" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DeviceMetadataEntity" inverseName="metadataNode" inverseEntity="DeviceMetadataEntity"/>
<relationship name="mqttConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MQTTConfigEntity" inverseName="mqttConfigNode" inverseEntity="MQTTConfigEntity"/>
<relationship name="myInfo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="myInfoNode" inverseEntity="MyInfoEntity"/>
<relationship name="networkConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NetworkConfigEntity" inverseName="networkConfigNode" inverseEntity="NetworkConfigEntity"/>
<relationship name="pax" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="PaxCounterEntity" inverseName="paxNode" inverseEntity="PaxCounterEntity"/>
<relationship name="paxCounterConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PaxCounterConfigEntity" inverseName="paxCounterConfigNode" inverseEntity="PaxCounterConfigEntity"/>
<relationship name="positionConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PositionConfigEntity" inverseName="positionConfigNode" inverseEntity="PositionConfigEntity"/>
<relationship name="positions" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="PositionEntity" inverseName="nodePosition" inverseEntity="PositionEntity"/>
<relationship name="powerConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PowerConfigEntity" inverseName="powerConfigNode" inverseEntity="PowerConfigEntity"/>
<relationship name="rangeTestConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RangeTestConfigEntity" inverseName="rangeTestConfigNode" inverseEntity="RangeTestConfigEntity"/>
<relationship name="rtttlConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RTTTLConfigEntity" inverseName="rtttlConfigNode" inverseEntity="RTTTLConfigEntity"/>
<relationship name="serialConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="SerialConfigEntity" inverseName="serialConfigNode" inverseEntity="SerialConfigEntity"/>
<relationship name="storeForwardConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreForwardConfigEntity" inverseName="storeForwardConfigNode" inverseEntity="StoreForwardConfigEntity"/>
<relationship name="telemetries" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TelemetryEntity" inverseName="nodeTelemetry" inverseEntity="TelemetryEntity"/>
<relationship name="telemetryConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TelemetryConfigEntity" inverseName="telemetryConfigNode" inverseEntity="TelemetryConfigEntity"/>
<relationship name="traceRoutes" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TraceRouteEntity" inverseName="node" inverseEntity="TraceRouteEntity"/>
<relationship name="user" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="UserEntity" inverseName="userNode" inverseEntity="UserEntity"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="num"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<entity name="PaxCounterConfigEntity" representedClassName="PaxCounterConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="paxcounterUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="paxCounterConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="paxCounterConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="PaxCounterEntity" representedClassName="PaxCounterEntity" syncable="YES" codeGenerationType="class">
<attribute name="ble" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="uptime" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="wifi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="paxNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="pax" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="PositionConfigEntity" representedClassName="PositionConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="broadcastSmartMinimumDistance" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="broadcastSmartMinimumIntervalSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="deviceGpsEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="fixedPosition" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="gpsAttemptTime" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="gpsEnGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="gpsMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="gpsUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="positionBroadcastSeconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="positionFlags" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="rxGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="smartPositionEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="txGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="positionConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="positionConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="PositionEntity" representedClassName="PositionEntity" syncable="YES" codeGenerationType="class">
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="heading" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="latest" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="latitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="longitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="precisionBits" optional="YES" attributeType="Integer 32" defaultValueString="32" usesScalarValueType="YES"/>
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="satsInView" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="seqNo" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="speed" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="nodePosition" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="positions" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="PowerConfigEntity" representedClassName="PowerConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="adcMultiplierOverride" optional="YES" attributeType="Float" usesScalarValueType="YES"/>
<attribute name="deviceBatteryInaAddress" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="isPowerSaving" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="lsSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="minWakeSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="onBatteryShutdownAfterSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="waitBluetoothSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="powerConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="powerConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="RangeTestConfigEntity" representedClassName="RangeTestConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="save" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="sender" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
<relationship name="rangeTestConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="rangeTestConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="RouteEntity" representedClassName="RouteEntity" syncable="YES" codeGenerationType="class">
<attribute name="color" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="id" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="name" optional="YES" attributeType="String"/>
<attribute name="notes" optional="YES" attributeType="String"/>
<relationship name="locations" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="LocationEntity" inverseName="routeLocation" inverseEntity="LocationEntity"/>
</entity>
<entity name="RTTTLConfigEntity" representedClassName="RTTTLConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="ringtone" optional="YES" attributeType="String" maxValueString="228" defaultValueString=""/>
<relationship name="rtttlConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="rtttlConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="SerialConfigEntity" representedClassName="SerialConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="baudRate" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="echo" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="mode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="overrideConsoleSerialPort" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="rxd" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="timeout" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="txd" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="serialConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="serialConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="StoreForwardConfigEntity" representedClassName="StoreForwardConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="enabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="heartbeat" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
<attribute name="historyReturnMax" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="historyReturnWindow" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="isRouter" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="lastHeartbeat" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="lastRequest" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="records" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="storeForwardConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="storeForwardConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="TelemetryConfigEntity" representedClassName="TelemetryConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="deviceUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="environmentDisplayFahrenheit" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="environmentMeasurementEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="environmentScreenEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="environmentUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="powerMeasurementEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="powerScreenEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="powerUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<relationship name="telemetryConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="telemetryConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="TelemetryEntity" representedClassName="TelemetryEntity" syncable="YES" codeGenerationType="class">
<attribute name="airUtilTx" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="barometricPressure" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="batteryLevel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="channelUtilization" optional="YES" attributeType="Float" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="current" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="gasResistance" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="iaq" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="metricsType" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="relativeHumidity" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="temperature" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="voltage" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<relationship name="nodeTelemetry" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="telemetries" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="TraceRouteEntity" representedClassName="TraceRouteEntity" syncable="YES" codeGenerationType="class">
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="hasPositions" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="id" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="latitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="longitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="num" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="response" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="route" optional="YES" attributeType="Transformable" customClassName="[UInt32]"/>
<attribute name="routeText" optional="YES" attributeType="String"/>
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="hops" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TraceRouteHopEntity" inverseName="traceRoute" inverseEntity="TraceRouteHopEntity"/>
<relationship name="node" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="traceRoutes" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="TraceRouteHopEntity" representedClassName="TraceRouteHopEntity" syncable="YES" codeGenerationType="class">
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="latitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="longitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="name" optional="YES" attributeType="String"/>
<attribute name="num" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="time" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="traceRoute" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TraceRouteEntity" inverseName="hops" inverseEntity="TraceRouteEntity"/>
</entity>
<entity name="UserEntity" representedClassName="UserEntity" syncable="YES" codeGenerationType="class">
<attribute name="hwModel" attributeType="String"/>
<attribute name="isLicensed" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="lastMessage" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="longName" attributeType="String"/>
<attribute name="mute" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="numString" optional="YES" attributeType="String"/>
<attribute name="role" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="shortName" attributeType="String"/>
<attribute name="userId" attributeType="String"/>
<relationship name="receivedMessages" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="MessageEntity" inverseName="toUser" inverseEntity="MessageEntity"/>
<relationship name="sentMessages" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="MessageEntity" inverseName="fromUser" inverseEntity="MessageEntity"/>
<relationship name="userNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="user" inverseEntity="NodeInfoEntity"/>
<fetchedProperty name="adminMessages" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="(fromUser.num == $FETCH_SOURCE.num) AND isEmoji == false AND admin = true"/>
</fetchedProperty>
<fetchedProperty name="allMessages" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="((toUser.num == $FETCH_SOURCE.num) OR (fromUser.num == $FETCH_SOURCE.num)) AND toUser != nil AND fromUser != nil AND isEmoji == false AND admin = false AND portNum != 10 "/>
</fetchedProperty>
<fetchedProperty name="detectionSensorMessages" optional="YES">
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="(fromUser.num == $FETCH_SOURCE.num) AND portNum = 10"/>
</fetchedProperty>
</entity>
<entity name="WaypointEntity" representedClassName="WaypointEntity" syncable="YES" codeGenerationType="class">
<attribute name="created" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="expire" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="icon" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="id" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="lastUpdated" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="latitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="locked" attributeType="Integer 64" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="longDescription" optional="YES" attributeType="String" maxValueString="100"/>
<attribute name="longitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="name" attributeType="String" minValueString="1" maxValueString="30"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="id"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
</model>

View file

@ -924,7 +924,7 @@ struct AdminMessage {
extension AdminMessage.ConfigType: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [AdminMessage.ConfigType] = [
static let allCases: [AdminMessage.ConfigType] = [
.deviceConfig,
.positionConfig,
.powerConfig,
@ -937,7 +937,7 @@ extension AdminMessage.ConfigType: CaseIterable {
extension AdminMessage.ModuleConfigType: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [AdminMessage.ModuleConfigType] = [
static let allCases: [AdminMessage.ModuleConfigType] = [
.mqttConfig,
.serialConfig,
.extnotifConfig,

View file

@ -75,7 +75,15 @@ extension ChannelSet: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
var _settings: [ChannelSettings] = []
var _loraConfig: Config.LoRaConfig? = nil
static let defaultInstance = _StorageClass()
#if swift(>=5.10)
// This property is used as the initial default value for new instances of the type.
// The type itself is protecting the reference to its storage via CoW semantics.
// This will force a copy to be made of this reference when the first mutation occurs;
// hence, it is safe to mark this as `nonisolated(unsafe)`.
static nonisolated(unsafe) let defaultInstance = _StorageClass()
#else
static let defaultInstance = _StorageClass()
#endif
private init() {}

View file

@ -136,7 +136,7 @@ enum Team: SwiftProtobuf.Enum {
extension Team: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Team] = [
static let allCases: [Team] = [
.unspecifedColor,
.white,
.yellow,
@ -239,7 +239,7 @@ enum MemberRole: SwiftProtobuf.Enum {
extension MemberRole: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [MemberRole] = [
static let allCases: [MemberRole] = [
.unspecifed,
.teamMember,
.teamLead,

View file

@ -215,7 +215,7 @@ struct Channel {
extension Channel.Role: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Channel.Role] = [
static let allCases: [Channel.Role] = [
.disabled,
.primary,
.secondary,

View file

@ -1387,7 +1387,7 @@ struct Config {
extension Config.DeviceConfig.Role: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.DeviceConfig.Role] = [
static let allCases: [Config.DeviceConfig.Role] = [
.client,
.clientMute,
.router,
@ -1404,7 +1404,7 @@ extension Config.DeviceConfig.Role: CaseIterable {
extension Config.DeviceConfig.RebroadcastMode: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.DeviceConfig.RebroadcastMode] = [
static let allCases: [Config.DeviceConfig.RebroadcastMode] = [
.all,
.allSkipDecoding,
.localOnly,
@ -1414,7 +1414,7 @@ extension Config.DeviceConfig.RebroadcastMode: CaseIterable {
extension Config.PositionConfig.PositionFlags: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.PositionConfig.PositionFlags] = [
static let allCases: [Config.PositionConfig.PositionFlags] = [
.unset,
.altitude,
.altitudeMsl,
@ -1431,7 +1431,7 @@ extension Config.PositionConfig.PositionFlags: CaseIterable {
extension Config.PositionConfig.GpsMode: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.PositionConfig.GpsMode] = [
static let allCases: [Config.PositionConfig.GpsMode] = [
.disabled,
.enabled,
.notPresent,
@ -1440,7 +1440,7 @@ extension Config.PositionConfig.GpsMode: CaseIterable {
extension Config.NetworkConfig.AddressMode: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.NetworkConfig.AddressMode] = [
static let allCases: [Config.NetworkConfig.AddressMode] = [
.dhcp,
.static,
]
@ -1448,7 +1448,7 @@ extension Config.NetworkConfig.AddressMode: CaseIterable {
extension Config.DisplayConfig.GpsCoordinateFormat: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [
static let allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [
.dec,
.dms,
.utm,
@ -1460,7 +1460,7 @@ extension Config.DisplayConfig.GpsCoordinateFormat: CaseIterable {
extension Config.DisplayConfig.DisplayUnits: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.DisplayConfig.DisplayUnits] = [
static let allCases: [Config.DisplayConfig.DisplayUnits] = [
.metric,
.imperial,
]
@ -1468,7 +1468,7 @@ extension Config.DisplayConfig.DisplayUnits: CaseIterable {
extension Config.DisplayConfig.OledType: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.DisplayConfig.OledType] = [
static let allCases: [Config.DisplayConfig.OledType] = [
.oledAuto,
.oledSsd1306,
.oledSh1106,
@ -1478,7 +1478,7 @@ extension Config.DisplayConfig.OledType: CaseIterable {
extension Config.DisplayConfig.DisplayMode: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.DisplayConfig.DisplayMode] = [
static let allCases: [Config.DisplayConfig.DisplayMode] = [
.default,
.twocolor,
.inverted,
@ -1488,7 +1488,7 @@ extension Config.DisplayConfig.DisplayMode: CaseIterable {
extension Config.LoRaConfig.RegionCode: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.LoRaConfig.RegionCode] = [
static let allCases: [Config.LoRaConfig.RegionCode] = [
.unset,
.us,
.eu433,
@ -1513,7 +1513,7 @@ extension Config.LoRaConfig.RegionCode: CaseIterable {
extension Config.LoRaConfig.ModemPreset: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.LoRaConfig.ModemPreset] = [
static let allCases: [Config.LoRaConfig.ModemPreset] = [
.longFast,
.longSlow,
.veryLongSlow,
@ -1527,7 +1527,7 @@ extension Config.LoRaConfig.ModemPreset: CaseIterable {
extension Config.BluetoothConfig.PairingMode: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.BluetoothConfig.PairingMode] = [
static let allCases: [Config.BluetoothConfig.PairingMode] = [
.randomPin,
.fixedPin,
.noPin,

View file

@ -66,7 +66,7 @@ enum ScreenFonts: SwiftProtobuf.Enum {
extension ScreenFonts: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [ScreenFonts] = [
static let allCases: [ScreenFonts] = [
.fontSmall,
.fontMedium,
.fontLarge,
@ -509,7 +509,15 @@ extension NodeInfoLite: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
var _hopsAway: UInt32 = 0
var _isFavorite: Bool = false
static let defaultInstance = _StorageClass()
#if swift(>=5.10)
// This property is used as the initial default value for new instances of the type.
// The type itself is protecting the reference to its storage via CoW semantics.
// This will force a copy to be made of this reference when the first mutation occurs;
// hence, it is safe to mark this as `nonisolated(unsafe)`.
static nonisolated(unsafe) let defaultInstance = _StorageClass()
#else
static let defaultInstance = _StorageClass()
#endif
private init() {}
@ -649,7 +657,15 @@ extension DeviceState: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
var _nodeRemoteHardwarePins: [NodeRemoteHardwarePin] = []
var _nodeDbLite: [NodeInfoLite] = []
static let defaultInstance = _StorageClass()
#if swift(>=5.10)
// This property is used as the initial default value for new instances of the type.
// The type itself is protecting the reference to its storage via CoW semantics.
// This will force a copy to be made of this reference when the first mutation occurs;
// hence, it is safe to mark this as `nonisolated(unsafe)`.
static nonisolated(unsafe) let defaultInstance = _StorageClass()
#else
static let defaultInstance = _StorageClass()
#endif
private init() {}

View file

@ -314,7 +314,15 @@ extension LocalConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementati
var _bluetooth: Config.BluetoothConfig? = nil
var _version: UInt32 = 0
static let defaultInstance = _StorageClass()
#if swift(>=5.10)
// This property is used as the initial default value for new instances of the type.
// The type itself is protecting the reference to its storage via CoW semantics.
// This will force a copy to be made of this reference when the first mutation occurs;
// hence, it is safe to mark this as `nonisolated(unsafe)`.
static nonisolated(unsafe) let defaultInstance = _StorageClass()
#else
static let defaultInstance = _StorageClass()
#endif
private init() {}
@ -450,7 +458,15 @@ extension LocalModuleConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
var _paxcounter: ModuleConfig.PaxcounterConfig? = nil
var _version: UInt32 = 0
static let defaultInstance = _StorageClass()
#if swift(>=5.10)
// This property is used as the initial default value for new instances of the type.
// The type itself is protecting the reference to its storage via CoW semantics.
// This will force a copy to be made of this reference when the first mutation occurs;
// hence, it is safe to mark this as `nonisolated(unsafe)`.
static nonisolated(unsafe) let defaultInstance = _StorageClass()
#else
static let defaultInstance = _StorageClass()
#endif
private init() {}

View file

@ -408,7 +408,7 @@ enum HardwareModel: SwiftProtobuf.Enum {
extension HardwareModel: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [HardwareModel] = [
static let allCases: [HardwareModel] = [
.unset,
.tloraV2,
.tloraV1,
@ -514,7 +514,7 @@ enum Constants: SwiftProtobuf.Enum {
extension Constants: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Constants] = [
static let allCases: [Constants] = [
.zero,
.dataPayloadLen,
]
@ -627,7 +627,7 @@ enum CriticalErrorCode: SwiftProtobuf.Enum {
extension CriticalErrorCode: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [CriticalErrorCode] = [
static let allCases: [CriticalErrorCode] = [
.none,
.txWatchdog,
.sleepEnterWait,
@ -946,7 +946,7 @@ struct Position {
extension Position.LocSource: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Position.LocSource] = [
static let allCases: [Position.LocSource] = [
.locUnset,
.locManual,
.locInternal,
@ -956,7 +956,7 @@ extension Position.LocSource: CaseIterable {
extension Position.AltSource: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Position.AltSource] = [
static let allCases: [Position.AltSource] = [
.altUnset,
.altManual,
.altInternal,
@ -1237,7 +1237,7 @@ struct Routing {
extension Routing.Error: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Routing.Error] = [
static let allCases: [Routing.Error] = [
.none,
.noRoute,
.gotNak,
@ -1755,7 +1755,7 @@ struct MeshPacket {
extension MeshPacket.Priority: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [MeshPacket.Priority] = [
static let allCases: [MeshPacket.Priority] = [
.unset,
.min,
.background,
@ -1768,7 +1768,7 @@ extension MeshPacket.Priority: CaseIterable {
extension MeshPacket.Delayed: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [MeshPacket.Delayed] = [
static let allCases: [MeshPacket.Delayed] = [
.noDelay,
.broadcast,
.direct,
@ -2022,7 +2022,7 @@ struct LogRecord {
extension LogRecord.Level: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [LogRecord.Level] = [
static let allCases: [LogRecord.Level] = [
.unset,
.critical,
.error,
@ -2843,7 +2843,15 @@ extension Position: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
var _seqNumber: UInt32 = 0
var _precisionBits: UInt32 = 0
static let defaultInstance = _StorageClass()
#if swift(>=5.10)
// This property is used as the initial default value for new instances of the type.
// The type itself is protecting the reference to its storage via CoW semantics.
// This will force a copy to be made of this reference when the first mutation occurs;
// hence, it is safe to mark this as `nonisolated(unsafe)`.
static nonisolated(unsafe) let defaultInstance = _StorageClass()
#else
static let defaultInstance = _StorageClass()
#endif
private init() {}
@ -3505,7 +3513,15 @@ extension MeshPacket: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementatio
var _viaMqtt: Bool = false
var _hopStart: UInt32 = 0
static let defaultInstance = _StorageClass()
#if swift(>=5.10)
// This property is used as the initial default value for new instances of the type.
// The type itself is protecting the reference to its storage via CoW semantics.
// This will force a copy to be made of this reference when the first mutation occurs;
// hence, it is safe to mark this as `nonisolated(unsafe)`.
static nonisolated(unsafe) let defaultInstance = _StorageClass()
#else
static let defaultInstance = _StorageClass()
#endif
private init() {}
@ -3717,7 +3733,15 @@ extension NodeInfo: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
var _hopsAway: UInt32 = 0
var _isFavorite: Bool = false
static let defaultInstance = _StorageClass()
#if swift(>=5.10)
// This property is used as the initial default value for new instances of the type.
// The type itself is protecting the reference to its storage via CoW semantics.
// This will force a copy to be made of this reference when the first mutation occurs;
// hence, it is safe to mark this as `nonisolated(unsafe)`.
static nonisolated(unsafe) let defaultInstance = _StorageClass()
#else
static let defaultInstance = _StorageClass()
#endif
private init() {}
@ -4009,7 +4033,15 @@ extension FromRadio: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementation
var _id: UInt32 = 0
var _payloadVariant: FromRadio.OneOf_PayloadVariant?
static let defaultInstance = _StorageClass()
#if swift(>=5.10)
// This property is used as the initial default value for new instances of the type.
// The type itself is protecting the reference to its storage via CoW semantics.
// This will force a copy to be made of this reference when the first mutation occurs;
// hence, it is safe to mark this as `nonisolated(unsafe)`.
static nonisolated(unsafe) let defaultInstance = _StorageClass()
#else
static let defaultInstance = _StorageClass()
#endif
private init() {}

View file

@ -64,7 +64,7 @@ enum RemoteHardwarePinType: SwiftProtobuf.Enum {
extension RemoteHardwarePinType: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [RemoteHardwarePinType] = [
static let allCases: [RemoteHardwarePinType] = [
.unknown,
.digitalRead,
.digitalWrite,
@ -1152,7 +1152,7 @@ struct ModuleConfig {
extension ModuleConfig.AudioConfig.Audio_Baud: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [
static let allCases: [ModuleConfig.AudioConfig.Audio_Baud] = [
.codec2Default,
.codec23200,
.codec22400,
@ -1167,7 +1167,7 @@ extension ModuleConfig.AudioConfig.Audio_Baud: CaseIterable {
extension ModuleConfig.SerialConfig.Serial_Baud: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [
static let allCases: [ModuleConfig.SerialConfig.Serial_Baud] = [
.baudDefault,
.baud110,
.baud300,
@ -1189,7 +1189,7 @@ extension ModuleConfig.SerialConfig.Serial_Baud: CaseIterable {
extension ModuleConfig.SerialConfig.Serial_Mode: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [
static let allCases: [ModuleConfig.SerialConfig.Serial_Mode] = [
.default,
.simple,
.proto,
@ -1201,7 +1201,7 @@ extension ModuleConfig.SerialConfig.Serial_Mode: CaseIterable {
extension ModuleConfig.CannedMessageConfig.InputEventChar: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [
static let allCases: [ModuleConfig.CannedMessageConfig.InputEventChar] = [
.none,
.up,
.down,

View file

@ -277,7 +277,7 @@ enum PortNum: SwiftProtobuf.Enum {
extension PortNum: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [PortNum] = [
static let allCases: [PortNum] = [
.unknownApp,
.textMessageApp,
.remoteHardwareApp,

View file

@ -119,7 +119,7 @@ struct HardwareMessage {
extension HardwareMessage.TypeEnum: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [HardwareMessage.TypeEnum] = [
static let allCases: [HardwareMessage.TypeEnum] = [
.unset,
.writeGpios,
.watchGpios,

View file

@ -344,7 +344,7 @@ struct StoreAndForward {
extension StoreAndForward.RequestResponse: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [StoreAndForward.RequestResponse] = [
static let allCases: [StoreAndForward.RequestResponse] = [
.unset,
.routerError,
.routerHeartbeat,

View file

@ -144,7 +144,7 @@ enum TelemetrySensorType: SwiftProtobuf.Enum {
extension TelemetrySensorType: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [TelemetrySensorType] = [
static let allCases: [TelemetrySensorType] = [
.sensorUnset,
.bme280,
.bme680,
@ -189,6 +189,10 @@ struct DeviceMetrics {
/// Percent of airtime for transmission used within the last hour.
var airUtilTx: Float = 0
///
/// How long the device has been running since the last reboot (in seconds)
var uptimeSeconds: UInt32 = 0
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
@ -473,6 +477,7 @@ extension DeviceMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
2: .same(proto: "voltage"),
3: .standard(proto: "channel_utilization"),
4: .standard(proto: "air_util_tx"),
5: .standard(proto: "uptime_seconds"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@ -485,6 +490,7 @@ extension DeviceMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
case 2: try { try decoder.decodeSingularFloatField(value: &self.voltage) }()
case 3: try { try decoder.decodeSingularFloatField(value: &self.channelUtilization) }()
case 4: try { try decoder.decodeSingularFloatField(value: &self.airUtilTx) }()
case 5: try { try decoder.decodeSingularUInt32Field(value: &self.uptimeSeconds) }()
default: break
}
}
@ -503,6 +509,9 @@ extension DeviceMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
if self.airUtilTx != 0 {
try visitor.visitSingularFloatField(value: self.airUtilTx, fieldNumber: 4)
}
if self.uptimeSeconds != 0 {
try visitor.visitSingularUInt32Field(value: self.uptimeSeconds, fieldNumber: 5)
}
try unknownFields.traverse(visitor: &visitor)
}
@ -511,6 +520,7 @@ extension DeviceMetrics: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementa
if lhs.voltage != rhs.voltage {return false}
if lhs.channelUtilization != rhs.channelUtilization {return false}
if lhs.airUtilTx != rhs.airUtilTx {return false}
if lhs.uptimeSeconds != rhs.uptimeSeconds {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}

View file

@ -88,7 +88,7 @@ struct XModem {
extension XModem.Control: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [XModem.Control] = [
static let allCases: [XModem.Control] = [
.nul,
.soh,
.stx,

View file

@ -158,10 +158,10 @@ struct RouteRecorder: View {
locationsHandler.locationsArray.removeAll()
locationsHandler.recordingStarted = Date()
let newRoute = RouteEntity(context: context)
newRoute.name = String("Route Recording")
newRoute.date = Date()
newRoute.name = "\(newRoute.date?.relativeTimeOfDay() ?? "morning".localized) hike"
newRoute.id = Int32.random(in: Int32(Int8.max) ... Int32.max)
newRoute.color = Int64(UIColor.random.hex)
newRoute.date = Date()
newRoute.enabled = false
color = Color(UIColor(hex: UInt32(newRoute.color)))
self.recording = newRoute

View file

@ -21,89 +21,95 @@ struct Routes: View {
@State var isExporting = false
@State var exportString = ""
@State var hasChanges = false
@State var name = ""
@State var notes = ""
@State var enabled = true
@State var color = Color(red: 51, green: 199, blue: 88)
@FetchRequest(sortDescriptors: [NSSortDescriptor(key: "enabled", ascending: false), NSSortDescriptor(key: "name", ascending: true), NSSortDescriptor(key: "date", ascending: false)], animation: .default)
var routes: FetchedResults<RouteEntity>
var body: some View {
VStack {
Button("Import Route") {
importing = true
}
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.controlSize(.large)
.padding()
.alert(isPresented: $isShowingBadFileAlert) {
Alert(title: Text("Not a valid route file"), message: Text("Your route file must have both Latitude and Longitude columns and headers."), dismissButton: .default(Text("OK")))
}
.fileImporter(
isPresented: $importing,
allowedContentTypes: [.commaSeparatedText],
allowsMultipleSelection: false
) { result in
do {
guard let selectedFile: URL = try result.get().first else { return }
guard selectedFile.startAccessingSecurityScopedResource() else {
return
}
if selectedRoute == nil {
Button("Import Route") {
importing = true
}
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.controlSize(.large)
.padding()
.alert(isPresented: $isShowingBadFileAlert) {
Alert(title: Text("Not a valid route file"), message: Text("Your route file must have both Latitude and Longitude columns and headers."), dismissButton: .default(Text("OK")))
}
.fileImporter(
isPresented: $importing,
allowedContentTypes: [.commaSeparatedText],
allowsMultipleSelection: false
) { result in
do {
guard let fileContent = String(data: try Data(contentsOf: selectedFile), encoding: .utf8) else { return }
let routeName = selectedFile.lastPathComponent.dropLast(4)
let lines = fileContent.components(separatedBy: "\n")
let headers = lines.first?.components(separatedBy: ",")
var latIndex = -1
var longIndex = -1
for index in headers!.indices {
print("\(index): \( headers![index])")
if headers![index].trimmingCharacters(in: .whitespaces) == "Latitude" {
latIndex = index
} else if headers![index].trimmingCharacters(in: .whitespaces) == "Longitude" {
longIndex = index
}
guard let selectedFile: URL = try result.get().first else { return }
guard selectedFile.startAccessingSecurityScopedResource() else {
return
}
if latIndex >= 0 && longIndex >= 0 {
let newRoute = RouteEntity(context: context)
newRoute.name = String(routeName)
newRoute.id = Int32.random(in: Int32(Int8.max) ... Int32.max)
newRoute.color = Int64(UIColor.random.hex)
newRoute.date = Date()
newRoute.enabled = true
var newLocations = [LocationEntity]()
lines.dropFirst().forEach { line in
let data = line.components(separatedBy: ",")
if data.count > 1 {
let latitude = latIndex >= 0 ? data[latIndex].trimmingCharacters(in: .whitespaces) : "0"
let longitude = longIndex >= 0 ? data[longIndex].trimmingCharacters(in: .whitespaces) : "0"
let loc = LocationEntity(context: context)
loc.latitudeI = Int32((Double(latitude) ?? 0) * 1e7)
loc.longitudeI = Int32((Double(longitude) ?? 0) * 1e7)
newLocations.append(loc)
print("Longitude: \(longitude) Latitude: \(latitude)")
do {
guard let fileContent = String(data: try Data(contentsOf: selectedFile), encoding: .utf8) else { return }
let routeName = selectedFile.lastPathComponent.dropLast(4)
let lines = fileContent.components(separatedBy: "\n")
let headers = lines.first?.components(separatedBy: ",")
var latIndex = -1
var longIndex = -1
for index in headers!.indices {
print("\(index): \( headers![index])")
if headers![index].trimmingCharacters(in: .whitespaces) == "Latitude" {
latIndex = index
} else if headers![index].trimmingCharacters(in: .whitespaces) == "Longitude" {
longIndex = index
}
}
newRoute.locations? = NSOrderedSet(array: newLocations)
do {
try context.save()
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
if latIndex >= 0 && longIndex >= 0 {
let newRoute = RouteEntity(context: context)
newRoute.name = String(routeName)
newRoute.id = Int32.random(in: Int32(Int8.max) ... Int32.max)
newRoute.color = Int64(UIColor.random.hex)
newRoute.date = Date()
newRoute.enabled = true
var newLocations = [LocationEntity]()
lines.dropFirst().forEach { line in
let data = line.components(separatedBy: ",")
if data.count > 1 {
let latitude = latIndex >= 0 ? data[latIndex].trimmingCharacters(in: .whitespaces) : "0"
let longitude = longIndex >= 0 ? data[longIndex].trimmingCharacters(in: .whitespaces) : "0"
let loc = LocationEntity(context: context)
loc.latitudeI = Int32((Double(latitude) ?? 0) * 1e7)
loc.longitudeI = Int32((Double(longitude) ?? 0) * 1e7)
newLocations.append(loc)
print("Longitude: \(longitude) Latitude: \(latitude)")
}
}
newRoute.locations? = NSOrderedSet(array: newLocations)
do {
try context.save()
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
isShowingBadFileAlert = true
}
} else {
isShowingBadFileAlert = true
}
} else {
isShowingBadFileAlert = true
} catch {
print("error: \(error)") // to do deal with errors
}
} catch {
print("error: \(error)") // to do deal with errors
print("CSV Import Error")
}
} catch {
print("CSV Import Error")
}
}
VStack {
List(routes, id: \.self, selection: $selectedRoute) { route in
let routeColor = Color(UIColor(hex: route.color >= 0 ? UInt32(route.color) : 0))
Label {
@ -153,72 +159,152 @@ struct Routes: View {
}
.listStyle(.plain)
}
.navigationTitle("Route List")
VStack {
if selectedRoute != nil {
let locationArray = selectedRoute?.locations?.array as? [LocationEntity] ?? []
let lineCoords = locationArray.compactMap({(location) -> CLLocationCoordinate2D in
return location.locationCoordinate ?? LocationHelper.DefaultLocation
})
Map() {
Annotation("Start", coordinate: lineCoords.first ?? LocationHelper.DefaultLocation) {
ZStack {
Circle()
.fill(Color(.green))
.strokeBorder(.white, lineWidth: 3)
.frame(width: 15, height: 15)
} else {
VStack {
if selectedRoute != nil {
let locationArray = selectedRoute?.locations?.array as? [LocationEntity] ?? []
let lineCoords = locationArray.compactMap({(location) -> CLLocationCoordinate2D in
return location.locationCoordinate ?? LocationHelper.DefaultLocation
})
Form {
HStack {
Text("Name")
Spacer()
TextField(
"Name",
text: $name,
axis: .vertical
)
.foregroundColor(Color.gray)
.onChange(of: name, perform: { _ in
let totalBytes = name.utf8.count
// Only mess with the value if it is too big
if totalBytes > 100 {
name = String(name.dropLast())
}
})
}
Toggle("Enabled", isOn: $enabled)
.toggleStyle(.switch)
ColorPicker("Color", selection: $color, supportsOpacity: false)
.padding(5)
TextField(
"Notes",
text: $notes,
axis: .vertical
)
.lineLimit(4...6)
.foregroundColor(Color.gray)
}
.annotationTitles(.automatic)
Annotation("Finish", coordinate: lineCoords.last ?? LocationHelper.DefaultLocation) {
ZStack {
Circle()
.fill(Color(.black))
.strokeBorder(.white, lineWidth: 3)
.frame(width: 15, height: 15)
.onAppear {
name = selectedRoute?.name ?? "unknown".localized
notes = selectedRoute?.notes ?? ""
enabled = selectedRoute?.enabled ?? false
color = Color(UIColor(hex: UInt32(selectedRoute?.color ?? 0)))
hasChanges = false
}
HStack {
Button("cancel", role: .cancel) {
selectedRoute = nil
}
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.controlSize(.large)
Button("save") {
selectedRoute?.name = name
selectedRoute?.notes = notes
selectedRoute?.enabled = enabled
selectedRoute?.color = Int64(UIColor(color).hex)
do {
try context.save()
selectedRoute = nil
print("💾 Saved a route")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Saving RouteEntity from the Route Editor \(nsError)")
}
}
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.controlSize(.large)
.disabled(!hasChanges)
}
.annotationTitles(.automatic)
let solid = StrokeStyle(
lineWidth: 3,
lineCap: .round, lineJoin: .round
)
MapPolyline(coordinates: lineCoords)
.stroke(Color(UIColor(hex: UInt32(selectedRoute?.color ?? 0))), style: solid)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.safeAreaInset(edge: .bottom, alignment: UIDevice.current.userInterfaceIdiom == .phone ? .leading : .trailing) {
Button {
exportString = routeToCsvFile(locations: selectedRoute!.locations!.array as? [LocationEntity] ?? [])
isExporting = true
} label: {
Label("save", systemImage: "square.and.arrow.down")
.onChange(of: name) { newName in
hasChanges = true
}
.onChange(of: notes) { newNotes in
hasChanges = true
}
.onChange(of: enabled) { newEnabled in
hasChanges = true
}
.onChange(of: color) { newColor in
hasChanges = true
}
Map() {
Annotation("Start", coordinate: lineCoords.first ?? LocationHelper.DefaultLocation) {
ZStack {
Circle()
.fill(Color(.green))
.strokeBorder(.white, lineWidth: 3)
.frame(width: 15, height: 15)
}
}
.annotationTitles(.automatic)
Annotation("Finish", coordinate: lineCoords.last ?? LocationHelper.DefaultLocation) {
ZStack {
Circle()
.fill(Color(.black))
.strokeBorder(.white, lineWidth: 3)
.frame(width: 15, height: 15)
}
}
.annotationTitles(.automatic)
let solid = StrokeStyle(
lineWidth: 3,
lineCap: .round, lineJoin: .round
)
MapPolyline(coordinates: lineCoords)
.stroke(Color(UIColor(hex: UInt32(selectedRoute?.color ?? 0))), style: solid)
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
.safeAreaInset(edge: .bottom, alignment: UIDevice.current.userInterfaceIdiom == .phone ? .leading : .trailing) {
Button {
exportString = routeToCsvFile(locations: selectedRoute!.locations!.array as? [LocationEntity] ?? [])
isExporting = true
} label: {
Label("export", systemImage: "square.and.arrow.down")
}
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.controlSize(.large)
.padding(.bottom)
.padding(.leading)
}
.buttonStyle(.bordered)
.buttonBorderShape(.capsule)
.controlSize(.large)
.padding(.bottom)
.padding(.leading)
}
}
}.navigationTitle(" \(selectedRoute?.name ?? "Unknown Route") \(selectedRoute?.locations?.count ?? 0) points")
.fileExporter(
isPresented: $isExporting,
document: CsvDocument(emptyCsv: exportString),
contentType: .commaSeparatedText,
defaultFilename: String("\(selectedRoute?.name ?? "Route") Log"),
onCompletion: { result in
if case .success = result {
print("Route log download succeeded.")
self.isExporting = false
} else {
print("Route log download failed: \(result).")
}
}
)
}
}
.fileExporter(
isPresented: $isExporting,
document: CsvDocument(emptyCsv: exportString),
contentType: .commaSeparatedText,
defaultFilename: String("\(selectedRoute?.name ?? "Route") Log"),
onCompletion: { result in
if case .success = result {
print("Route log download succeeded.")
self.isExporting = false
} else {
print("Route log download failed: \(result).")
}
}
)
.navigationTitle(selectedRoute != nil ? name : "Route List")
.navigationBarTitleDisplayMode(.inline)
}
}

View file

@ -278,6 +278,11 @@
"reboot.node"="Reboot node?";
"received.ack"="Received Ack";
"received.ack.real"="Recipient Ack";
"relativetimeofday.morning"="Morning";
"relativetimeofday.midday"="Midday";
"relativetimeofday.afternoon"="Afternoon";
"relativetimeofday.evening"="Evening";
"relativetimeofday.nighttime"="Nighttime";
"resume"="Resume";
"ringtone"="Ringtone";
"ringtone.config"="Ringtone Config";

@ -1 +1 @@
Subproject commit 22cbd0d4cfafa4b8c1e64517e06edc2d7a22cca9
Subproject commit f92900c5f884b04388fb7abf61d4df66783015e4