mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Merge pull request #139 from meshtastic/1_3_30_upgrades
Support new wifi config, update firmware version modal, prevent conne…
This commit is contained in:
commit
1f809eb5eb
9 changed files with 405 additions and 113 deletions
|
|
@ -150,6 +150,7 @@
|
|||
DD8ED9C328978D9D00B3B0AB /* MeshtasticDataModel v 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModel v 5.xcdatamodel"; sourceTree = "<group>"; };
|
||||
DD8ED9C42898D51F00B3B0AB /* WiFiConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WiFiConfig.swift; sourceTree = "<group>"; };
|
||||
DD8ED9C7289CE4B900B3B0AB /* RoutingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoutingError.swift; sourceTree = "<group>"; };
|
||||
DD8ED9C9289EA77E00B3B0AB /* MeshtasticDataModel v 6.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModel v 6.xcdatamodel"; sourceTree = "<group>"; };
|
||||
DD90860A26F645B700DC5189 /* Meshtastic.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Meshtastic.entitlements; sourceTree = "<group>"; };
|
||||
DD90860B26F684AF00DC5189 /* BatteryIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryIcon.swift; sourceTree = "<group>"; };
|
||||
DD90860D26F69BAE00DC5189 /* NodeMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeMap.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -892,7 +893,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3.30;
|
||||
MARKETING_VERSION = 1.3.32;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
|
|
@ -924,7 +925,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.3.30;
|
||||
MARKETING_VERSION = 1.3.32;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
|
|
@ -1097,13 +1098,14 @@
|
|||
DD9D8F2D2764403B00080993 /* Meshtastic.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
DD8ED9C9289EA77E00B3B0AB /* MeshtasticDataModel v 6.xcdatamodel */,
|
||||
DD8ED9C328978D9D00B3B0AB /* MeshtasticDataModel v 5.xcdatamodel */,
|
||||
DD619373285CC7D600E59241 /* MeshtasticDataModel v 4.xcdatamodel */,
|
||||
DDB2CC6F27F3F0AC009C5FCC /* MeshtasticDataModel v 3.xcdatamodel */,
|
||||
DD45C77427BD4EF80011784F /* MeshtasticDataModel v2.xcdatamodel */,
|
||||
DD9D8F2E2764403B00080993 /* CoreDataSample.xcdatamodel */,
|
||||
);
|
||||
currentVersion = DD8ED9C328978D9D00B3B0AB /* MeshtasticDataModel v 5.xcdatamodel */;
|
||||
currentVersion = DD8ED9C9289EA77E00B3B0AB /* MeshtasticDataModel v 6.xcdatamodel */;
|
||||
name = Meshtastic.xcdatamodeld;
|
||||
path = Meshtastic/Meshtastic.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
|
||||
@Published var connectedPeripheral: Peripheral!
|
||||
@Published var lastConnectionError: String
|
||||
@Published var lastConnnectionVersion: String
|
||||
@Published var connectedVersion: String
|
||||
|
||||
@Published var isSwitchedOn: Bool = false
|
||||
@Published var isScanning: Bool = false
|
||||
|
|
@ -77,7 +77,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
|
||||
//self.meshLoggingEnabled = UserDefaults.standard.object(forKey: "meshActivityLog") as? Bool ?? false
|
||||
self.lastConnectionError = ""
|
||||
self.lastConnnectionVersion = "0.0.0"
|
||||
self.connectedVersion = "0.0.0"
|
||||
super.init()
|
||||
// let bleQueue: DispatchQueue = DispatchQueue(label: "CentralManager")
|
||||
centralManager = CBCentralManager(delegate: self, queue: nil)
|
||||
|
|
@ -159,13 +159,15 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
if meshLoggingEnabled { MeshLogger.log("✅ BLE Connecting: \(peripheral.name ?? "Unknown")") }
|
||||
|
||||
stopScanning()
|
||||
|
||||
|
||||
if self.connectedPeripheral != nil {
|
||||
|
||||
if meshLoggingEnabled { MeshLogger.log("ℹ️ BLE Disconnecting from: \(self.connectedPeripheral.name) to connect to \(peripheral.name ?? "Unknown")") }
|
||||
self.disconnectPeripheral()
|
||||
}
|
||||
|
||||
|
||||
self.connectedVersion = "0.0.0"
|
||||
self.centralManager?.connect(peripheral)
|
||||
|
||||
// Use a timer to keep track of connecting peripherals, context to pass the radio name with the timer and the RunLoop to prevent
|
||||
|
|
@ -460,15 +462,20 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
|
||||
// MyInfo
|
||||
if decodedInfo.myInfo.isInitialized && decodedInfo.myInfo.myNodeNum > 0 {
|
||||
|
||||
let lastDotIndex = decodedInfo.myInfo.firmwareVersion.lastIndex(of: ".")
|
||||
var version = decodedInfo.myInfo.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: decodedInfo.myInfo.firmwareVersion))]
|
||||
|
||||
nowKnown = true
|
||||
connectedVersion = String(version)
|
||||
|
||||
let myInfo = myInfoPacket(myInfo: decodedInfo.myInfo, meshLogging: meshLoggingEnabled, context: context!)
|
||||
|
||||
if myInfo != nil {
|
||||
|
||||
self.connectedPeripheral.bitrate = myInfo!.bitrate
|
||||
self.connectedPeripheral.num = myInfo!.myNodeNum
|
||||
lastConnnectionVersion = myInfo?.firmwareVersion ?? myInfo!.firmwareVersion ?? "Unknown"
|
||||
|
||||
self.connectedPeripheral.firmwareVersion = myInfo!.firmwareVersion ?? "Unknown"
|
||||
self.connectedPeripheral.name = myInfo!.bleName ?? "Unknown"
|
||||
self.connectedPeripheral.longName = myInfo!.bleName ?? "Unknown"
|
||||
|
|
|
|||
|
|
@ -377,15 +377,13 @@ func localConfig (config: Config, meshlogging: Bool, context:NSManagedObjectCont
|
|||
|
||||
newWiFiConfig.ssid = ""
|
||||
newWiFiConfig.password = ""
|
||||
newWiFiConfig.apMode = false
|
||||
newWiFiConfig.apHidden = false
|
||||
newWiFiConfig.mode = 0
|
||||
|
||||
} else {
|
||||
|
||||
newWiFiConfig.ssid = config.wifi.ssid
|
||||
newWiFiConfig.password = config.wifi.psk
|
||||
newWiFiConfig.apMode = config.wifi.apMode
|
||||
newWiFiConfig.apHidden = config.wifi.apHidden
|
||||
newWiFiConfig.mode = Int32(config.wifi.mode.rawValue)
|
||||
}
|
||||
newWiFiConfig.num = fetchedNode[0].num
|
||||
fetchedNode[0].wiFiConfig = newWiFiConfig
|
||||
|
|
@ -396,15 +394,13 @@ func localConfig (config: Config, meshlogging: Bool, context:NSManagedObjectCont
|
|||
|
||||
fetchedNode[0].wiFiConfig?.ssid = ""
|
||||
fetchedNode[0].wiFiConfig?.password = ""
|
||||
fetchedNode[0].wiFiConfig?.apMode = false
|
||||
fetchedNode[0].wiFiConfig?.apHidden = false
|
||||
fetchedNode[0].wiFiConfig?.mode = 0
|
||||
|
||||
} else {
|
||||
|
||||
fetchedNode[0].wiFiConfig?.ssid = config.wifi.ssid
|
||||
fetchedNode[0].wiFiConfig?.password = config.wifi.psk
|
||||
fetchedNode[0].wiFiConfig?.apMode = config.wifi.apMode
|
||||
fetchedNode[0].wiFiConfig?.apHidden = config.wifi.apHidden
|
||||
fetchedNode[0].wiFiConfig?.mode = Int32(config.wifi.mode.rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
<dict>
|
||||
<key>com.apple.developer.associated-domains</key>
|
||||
<array>
|
||||
<string>applinks:meshtastic.org/E/*</string>
|
||||
<string>applinks:meshtastic.org/e/*</string>
|
||||
</array>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>_XCCurrentVersionName</key>
|
||||
<string>MeshtasticDataModel v 5.xcdatamodel</string>
|
||||
<string>MeshtasticDataModel v 6.xcdatamodel</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,221 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="20086" systemVersion="21G72" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<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="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<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="DeviceConfigEntity" representedClassName="DeviceConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="debugLogEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="num" attributeType="Integer 64" 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"/>
|
||||
<relationship name="deviceConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="deviceConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="DisplayConfigEntity" representedClassName="DisplayConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="gpsFormat" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="num" attributeType="Integer 64" 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"/>
|
||||
<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="alertMessage" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="output" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="outputMilliseconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="externalNotificationConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="externalNotificationConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="LoRaConfigEntity" representedClassName="LoRaConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="hopLimit" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="modemPreset" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="regionCode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="txPower" optional="YES" attributeType="Integer 32" defaultValueString="0" 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="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="messageTimestamp" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="receivedACK" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="replyID" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="fromUser" maxCount="1" deletionRule="Nullify" ordered="YES" destinationEntity="UserEntity" inverseName="sentMessages" inverseEntity="UserEntity"/>
|
||||
<relationship name="toUser" 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="MyInfoEntity" representedClassName="MyInfoEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="bitrate" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="bleName" optional="YES" attributeType="String"/>
|
||||
<attribute name="errorCount" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="firmwareVersion" attributeType="String"/>
|
||||
<attribute name="hasGps" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="hasWifi" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="maxChannels" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="messageTimeoutMsec" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="minAppVersion" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="myNodeNum" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="rebootCount" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="myInfoNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="myInfo" inverseEntity="NodeInfoEntity"/>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
<constraint value="myNodeNum"/>
|
||||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<entity name="NodeInfoEntity" representedClassName="NodeInfoEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="bleName" optional="YES" attributeType="String"/>
|
||||
<attribute name="id" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="lastHeard" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<relationship name="cannedMessageConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CannedMessageConfigEntity" inverseName="cannedMessagesConfigNode" inverseEntity="CannedMessageConfigEntity"/>
|
||||
<relationship name="deviceConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DeviceConfigEntity" inverseName="deviceConfigNode" inverseEntity="DeviceConfigEntity"/>
|
||||
<relationship name="displayConfig" optional="YES" maxCount="1" deletionRule="Nullify" 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="myInfo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="myInfoNode" inverseEntity="MyInfoEntity"/>
|
||||
<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="rangeTestConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RangeTestConfigEntity" inverseName="rangeTestConfigNode" inverseEntity="RangeTestConfigEntity"/>
|
||||
<relationship name="serialConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="SerialConfigEntity" inverseName="serialConfigNode" inverseEntity="SerialConfigEntity"/>
|
||||
<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="user" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="UserEntity" inverseName="userNode" inverseEntity="UserEntity"/>
|
||||
<relationship name="wiFiConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="WiFiConfigEntity" inverseName="wiFiConfigNode" inverseEntity="WiFiConfigEntity"/>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
<constraint value="num"/>
|
||||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<entity name="PositionConfigEntity" representedClassName="PositionConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<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="gpsUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="positionBroadcastSeconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="smartPositionEnabled" optional="YES" attributeType="Boolean" 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="latitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="longitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="satsInView" 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="RangeTestConfigEntity" representedClassName="RangeTestConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="num" attributeType="Integer 32" defaultValueString="0" 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="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="num" attributeType="Integer 64" defaultValueString="0" 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="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="num" attributeType="Integer 64" 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="metricsType" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="relativeHumidity" 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="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="longName" attributeType="String"/>
|
||||
<attribute name="macaddr" optional="YES" attributeType="Binary"/>
|
||||
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="shortName" attributeType="String"/>
|
||||
<attribute name="team" optional="YES" 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="(toUser.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 isEmoji == false AND admin = false"/>
|
||||
</fetchedProperty>
|
||||
</entity>
|
||||
<entity name="WiFiConfigEntity" representedClassName="WiFiConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="mode" optional="YES" attributeType="Integer 32" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="password" optional="YES" attributeType="String" minValueString="0" maxValueString="60"/>
|
||||
<attribute name="ssid" optional="YES" attributeType="String" minValueString="0" maxValueString="30"/>
|
||||
<relationship name="wiFiConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="wiFiConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="CannedMessageConfigEntity" positionX="45" positionY="144" width="128" height="209"/>
|
||||
<element name="DeviceConfigEntity" positionX="45" positionY="144" width="128" height="104"/>
|
||||
<element name="DisplayConfigEntity" positionX="54" positionY="153" width="128" height="104"/>
|
||||
<element name="ExternalNotificationConfigEntity" positionX="63" positionY="162" width="128" height="149"/>
|
||||
<element name="LoRaConfigEntity" positionX="45" positionY="144" width="128" height="119"/>
|
||||
<element name="MessageEntity" positionX="-36" positionY="63" width="128" height="245"/>
|
||||
<element name="MyInfoEntity" positionX="-18" positionY="81" width="128" height="209"/>
|
||||
<element name="NodeInfoEntity" positionX="-63" positionY="-18" width="128" height="314"/>
|
||||
<element name="PositionConfigEntity" positionX="63" positionY="162" width="128" height="149"/>
|
||||
<element name="PositionEntity" positionX="-54" positionY="54" width="128" height="119"/>
|
||||
<element name="RangeTestConfigEntity" positionX="72" positionY="171" width="128" height="104"/>
|
||||
<element name="SerialConfigEntity" positionX="54" positionY="153" width="128" height="164"/>
|
||||
<element name="TelemetryConfigEntity" positionX="72" positionY="171" width="128" height="134"/>
|
||||
<element name="TelemetryEntity" positionX="160" positionY="192" width="128" height="209"/>
|
||||
<element name="UserEntity" positionX="0" positionY="144" width="128" height="230"/>
|
||||
<element name="WiFiConfigEntity" positionX="45" positionY="144" width="128" height="119"/>
|
||||
</elements>
|
||||
</model>
|
||||
|
|
@ -509,6 +509,15 @@ struct Config {
|
|||
// `Message` and `Message+*Additions` files in the SwiftProtobuf library for
|
||||
// methods supported on all messages.
|
||||
|
||||
///
|
||||
/// Enable WiFi (disables Bluetooth)
|
||||
var enabled: Bool = false
|
||||
|
||||
///
|
||||
/// If set, this node will try to join the specified wifi network and
|
||||
/// acquire an address via DHCP
|
||||
var mode: Config.WiFiConfig.WiFiMode = .client
|
||||
|
||||
///
|
||||
/// If set, this node will try to join the specified wifi network and
|
||||
/// acquire an address via DHCP
|
||||
|
|
@ -518,21 +527,48 @@ struct Config {
|
|||
/// If set, will be use to authenticate to the named wifi
|
||||
var psk: String = String()
|
||||
|
||||
///
|
||||
/// If set, the node will operate as an AP (and DHCP server), otherwise it
|
||||
/// will be a station
|
||||
var apMode: Bool = false
|
||||
|
||||
///
|
||||
/// If set, the node AP will broadcast as a hidden SSID
|
||||
var apHidden: Bool = false
|
||||
|
||||
///
|
||||
/// If set, wifi is enabled. Previously done through setting ssid and psk
|
||||
var enabled: Bool = false
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
enum WiFiMode: SwiftProtobuf.Enum {
|
||||
typealias RawValue = Int
|
||||
|
||||
///
|
||||
/// This mode is used to connect to an external WiFi network
|
||||
case client // = 0
|
||||
|
||||
///
|
||||
/// In this mode the node will operate as an AP (and DHCP server)
|
||||
case accessPoint // = 1
|
||||
|
||||
///
|
||||
/// If set, the node AP will broadcast as a hidden SSID
|
||||
case accessPointHidden // = 2
|
||||
case UNRECOGNIZED(Int)
|
||||
|
||||
init() {
|
||||
self = .client
|
||||
}
|
||||
|
||||
init?(rawValue: Int) {
|
||||
switch rawValue {
|
||||
case 0: self = .client
|
||||
case 1: self = .accessPoint
|
||||
case 2: self = .accessPointHidden
|
||||
default: self = .UNRECOGNIZED(rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
var rawValue: Int {
|
||||
switch self {
|
||||
case .client: return 0
|
||||
case .accessPoint: return 1
|
||||
case .accessPointHidden: return 2
|
||||
case .UNRECOGNIZED(let i): return i
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
|
|
@ -557,6 +593,11 @@ struct Config {
|
|||
/// Potentially useful for devices without user buttons.
|
||||
var autoScreenCarouselSecs: UInt32 = 0
|
||||
|
||||
///
|
||||
/// If this is set, the displayed compass will always point north. if unset, the old behaviour
|
||||
/// (top of display is heading direction) is used.
|
||||
var compassNorthTop: Bool = false
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
///
|
||||
|
|
@ -920,6 +961,15 @@ extension Config.PowerConfig.ChargeCurrent: CaseIterable {
|
|||
]
|
||||
}
|
||||
|
||||
extension Config.WiFiConfig.WiFiMode: CaseIterable {
|
||||
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||
static var allCases: [Config.WiFiConfig.WiFiMode] = [
|
||||
.client,
|
||||
.accessPoint,
|
||||
.accessPointHidden,
|
||||
]
|
||||
}
|
||||
|
||||
extension Config.DisplayConfig.GpsCoordinateFormat: CaseIterable {
|
||||
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||
static var allCases: [Config.DisplayConfig.GpsCoordinateFormat] = [
|
||||
|
|
@ -976,6 +1026,7 @@ extension Config.PositionConfig.PositionFlags: @unchecked Sendable {}
|
|||
extension Config.PowerConfig: @unchecked Sendable {}
|
||||
extension Config.PowerConfig.ChargeCurrent: @unchecked Sendable {}
|
||||
extension Config.WiFiConfig: @unchecked Sendable {}
|
||||
extension Config.WiFiConfig.WiFiMode: @unchecked Sendable {}
|
||||
extension Config.DisplayConfig: @unchecked Sendable {}
|
||||
extension Config.DisplayConfig.GpsCoordinateFormat: @unchecked Sendable {}
|
||||
extension Config.LoRaConfig: @unchecked Sendable {}
|
||||
|
|
@ -1381,11 +1432,10 @@ extension Config.PowerConfig.ChargeCurrent: SwiftProtobuf._ProtoNameProviding {
|
|||
extension Config.WiFiConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = Config.protoMessageName + ".WiFiConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .same(proto: "ssid"),
|
||||
2: .same(proto: "psk"),
|
||||
3: .standard(proto: "ap_mode"),
|
||||
4: .standard(proto: "ap_hidden"),
|
||||
5: .same(proto: "enabled"),
|
||||
1: .same(proto: "enabled"),
|
||||
2: .same(proto: "mode"),
|
||||
3: .same(proto: "ssid"),
|
||||
4: .same(proto: "psk"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1394,52 +1444,56 @@ extension Config.WiFiConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
|
|||
// allocates stack space for every case branch when no optimizations are
|
||||
// enabled. https://github.com/apple/swift-protobuf/issues/1034
|
||||
switch fieldNumber {
|
||||
case 1: try { try decoder.decodeSingularStringField(value: &self.ssid) }()
|
||||
case 2: try { try decoder.decodeSingularStringField(value: &self.psk) }()
|
||||
case 3: try { try decoder.decodeSingularBoolField(value: &self.apMode) }()
|
||||
case 4: try { try decoder.decodeSingularBoolField(value: &self.apHidden) }()
|
||||
case 5: try { try decoder.decodeSingularBoolField(value: &self.enabled) }()
|
||||
case 1: try { try decoder.decodeSingularBoolField(value: &self.enabled) }()
|
||||
case 2: try { try decoder.decodeSingularEnumField(value: &self.mode) }()
|
||||
case 3: try { try decoder.decodeSingularStringField(value: &self.ssid) }()
|
||||
case 4: try { try decoder.decodeSingularStringField(value: &self.psk) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
|
||||
if self.enabled != false {
|
||||
try visitor.visitSingularBoolField(value: self.enabled, fieldNumber: 1)
|
||||
}
|
||||
if self.mode != .client {
|
||||
try visitor.visitSingularEnumField(value: self.mode, fieldNumber: 2)
|
||||
}
|
||||
if !self.ssid.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.ssid, fieldNumber: 1)
|
||||
try visitor.visitSingularStringField(value: self.ssid, fieldNumber: 3)
|
||||
}
|
||||
if !self.psk.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.psk, fieldNumber: 2)
|
||||
}
|
||||
if self.apMode != false {
|
||||
try visitor.visitSingularBoolField(value: self.apMode, fieldNumber: 3)
|
||||
}
|
||||
if self.apHidden != false {
|
||||
try visitor.visitSingularBoolField(value: self.apHidden, fieldNumber: 4)
|
||||
}
|
||||
if self.enabled != false {
|
||||
try visitor.visitSingularBoolField(value: self.enabled, fieldNumber: 5)
|
||||
try visitor.visitSingularStringField(value: self.psk, fieldNumber: 4)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
static func ==(lhs: Config.WiFiConfig, rhs: Config.WiFiConfig) -> Bool {
|
||||
if lhs.enabled != rhs.enabled {return false}
|
||||
if lhs.mode != rhs.mode {return false}
|
||||
if lhs.ssid != rhs.ssid {return false}
|
||||
if lhs.psk != rhs.psk {return false}
|
||||
if lhs.apMode != rhs.apMode {return false}
|
||||
if lhs.apHidden != rhs.apHidden {return false}
|
||||
if lhs.enabled != rhs.enabled {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension Config.WiFiConfig.WiFiMode: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "Client"),
|
||||
1: .same(proto: "AccessPoint"),
|
||||
2: .same(proto: "AccessPointHidden"),
|
||||
]
|
||||
}
|
||||
|
||||
extension Config.DisplayConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = Config.protoMessageName + ".DisplayConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
1: .standard(proto: "screen_on_secs"),
|
||||
2: .standard(proto: "gps_format"),
|
||||
3: .standard(proto: "auto_screen_carousel_secs"),
|
||||
4: .standard(proto: "compass_north_top"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1451,6 +1505,7 @@ extension Config.DisplayConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
|
|||
case 1: try { try decoder.decodeSingularUInt32Field(value: &self.screenOnSecs) }()
|
||||
case 2: try { try decoder.decodeSingularEnumField(value: &self.gpsFormat) }()
|
||||
case 3: try { try decoder.decodeSingularUInt32Field(value: &self.autoScreenCarouselSecs) }()
|
||||
case 4: try { try decoder.decodeSingularBoolField(value: &self.compassNorthTop) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
|
@ -1466,6 +1521,9 @@ extension Config.DisplayConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
|
|||
if self.autoScreenCarouselSecs != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.autoScreenCarouselSecs, fieldNumber: 3)
|
||||
}
|
||||
if self.compassNorthTop != false {
|
||||
try visitor.visitSingularBoolField(value: self.compassNorthTop, fieldNumber: 4)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
|
|
@ -1473,6 +1531,7 @@ extension Config.DisplayConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImp
|
|||
if lhs.screenOnSecs != rhs.screenOnSecs {return false}
|
||||
if lhs.gpsFormat != rhs.gpsFormat {return false}
|
||||
if lhs.autoScreenCarouselSecs != rhs.autoScreenCarouselSecs {return false}
|
||||
if lhs.compassNorthTop != rhs.compassNorthTop {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,12 @@ struct Connect: View {
|
|||
@EnvironmentObject var bleManager: BLEManager
|
||||
@EnvironmentObject var userSettings: UserSettings
|
||||
|
||||
@State private var showingVersionSheet = false
|
||||
|
||||
@State var initialLoad: Bool = true
|
||||
@State var isPreferredRadio: Bool = false
|
||||
|
||||
@State var firmwareVersion = "0.0.0"
|
||||
@State var minimumVersion = "1.3.30"
|
||||
@State var minimumVersion = "1.3.32"
|
||||
@State var invalidVersion = false
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
|
@ -267,23 +264,18 @@ struct Connect: View {
|
|||
|
||||
InvalidVersion(errorText: "1.3 ALPHA PREVIEW this version of the app supports only version \(minimumVersion) and above. Your device has been disconnected.")
|
||||
}
|
||||
|
||||
|
||||
.onChange(of: firmwareVersion) { iv in
|
||||
|
||||
.onChange(of: (self.bleManager.connectedVersion)) { ic in
|
||||
|
||||
bleManager.disconnectPeripheral()
|
||||
}
|
||||
.onChange(of: self.bleManager.isConnected) { ic in
|
||||
|
||||
firmwareVersion = bleManager.lastConnnectionVersion
|
||||
firmwareVersion = self.bleManager.connectedVersion
|
||||
let supportedVersion = firmwareVersion == "0.0.0" || minimumVersion.compare(firmwareVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(firmwareVersion, options: .numeric) == .orderedSame
|
||||
|
||||
invalidVersion = !supportedVersion
|
||||
|
||||
if invalidVersion {
|
||||
|
||||
bleManager.disconnectPeripheral()
|
||||
}
|
||||
|
||||
}
|
||||
.onAppear(perform: {
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,40 @@
|
|||
|
||||
import SwiftUI
|
||||
|
||||
enum WiFiModes: Int, CaseIterable, Identifiable {
|
||||
|
||||
case client = 0
|
||||
case accessPoint = 1
|
||||
case accessPointHidden = 2
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
get {
|
||||
switch self {
|
||||
case .client:
|
||||
return "Client"
|
||||
case .accessPoint:
|
||||
return "Software Access Point"
|
||||
case .accessPointHidden:
|
||||
return "Software Access Point (Hidden)"
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
func protoEnumValue() -> Config.WiFiConfig.WiFiMode {
|
||||
|
||||
switch self {
|
||||
|
||||
case .client:
|
||||
return Config.WiFiConfig.WiFiMode.client
|
||||
case .accessPoint:
|
||||
return Config.WiFiConfig.WiFiMode.accessPoint
|
||||
case .accessPointHidden:
|
||||
return Config.WiFiConfig.WiFiMode.accessPointHidden
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WiFiConfig: View {
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
|
|
@ -19,12 +53,9 @@ struct WiFiConfig: View {
|
|||
@State var hasChanges: Bool = false
|
||||
|
||||
@State var enabled = false
|
||||
|
||||
@State var ssid = ""
|
||||
@State var password = ""
|
||||
|
||||
@State var apMode = false
|
||||
@State var apHidden = false
|
||||
@State var mode = 0
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
|
@ -39,22 +70,35 @@ struct WiFiConfig: View {
|
|||
|
||||
Toggle(isOn: $enabled) {
|
||||
|
||||
Label("Enable", systemImage: "wifi")
|
||||
Label("Enabled", systemImage: "wifi")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
|
||||
Picker("Mode", selection: $mode ) {
|
||||
ForEach(WiFiModes.allCases) { lu in
|
||||
Text(lu.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
|
||||
}
|
||||
Section(header: Text("SSID & Password")) {
|
||||
|
||||
HStack {
|
||||
Label("SSID", systemImage: "network")
|
||||
TextField("SSID", text: $ssid)
|
||||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: ssid, perform: { value in
|
||||
|
||||
let totalBytes = ssid.utf8.count
|
||||
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 30 {
|
||||
if totalBytes > 32 {
|
||||
|
||||
let firstNBytes = Data(ssid.utf8.prefix(30))
|
||||
let firstNBytes = Data(ssid.utf8.prefix(32))
|
||||
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
|
||||
|
|
@ -66,20 +110,22 @@ struct WiFiConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
.disableAutocorrection(true)
|
||||
|
||||
|
||||
HStack {
|
||||
Label("Password", systemImage: "wallet.pass")
|
||||
TextField("Password", text: $password)
|
||||
.foregroundColor(.gray)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.onChange(of: password, perform: { value in
|
||||
|
||||
let totalBytes = password.utf8.count
|
||||
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > 60 {
|
||||
if totalBytes > 63 {
|
||||
|
||||
let firstNBytes = Data(ssid.utf8.prefix(60))
|
||||
let firstNBytes = Data(ssid.utf8.prefix(63))
|
||||
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
|
||||
|
|
@ -91,28 +137,6 @@ struct WiFiConfig: View {
|
|||
.foregroundColor(.gray)
|
||||
}
|
||||
.keyboardType(.default)
|
||||
.disableAutocorrection(true)
|
||||
|
||||
}
|
||||
Section(header: Text("Sofware Access Point")) {
|
||||
|
||||
Text("WiFi uses client mode by default, if Software Access Point(AP) is on the SSID and password will be used to access the AP at meshtastic.local.")
|
||||
.font(.caption)
|
||||
|
||||
Toggle(isOn: $apMode) {
|
||||
|
||||
Label("Soft AP Mode", systemImage: "externaldrive.fill.badge.wifi")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
if apMode {
|
||||
|
||||
Toggle(isOn: $apHidden) {
|
||||
|
||||
Label("Hidden SSID", systemImage: "eye.slash")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
}
|
||||
}
|
||||
}
|
||||
.disabled(!(node != nil && node!.myInfo?.hasWifi ?? false))
|
||||
|
|
@ -141,8 +165,7 @@ struct WiFiConfig: View {
|
|||
wifi.enabled = self.enabled
|
||||
wifi.ssid = self.ssid
|
||||
wifi.psk = self.password
|
||||
wifi.apMode = self.apMode
|
||||
wifi.apHidden = self.apHidden
|
||||
wifi.mode = WiFiModes(rawValue: self.mode)?.protoEnumValue() ?? WiFiModes.client.protoEnumValue()
|
||||
|
||||
let adminMessageId = bleManager.saveWiFiConfig(config: wifi, fromUser: node!.user!, toUser: node!.user!, wantResponse: true)
|
||||
|
||||
|
|
@ -174,9 +197,8 @@ struct WiFiConfig: View {
|
|||
self.enabled = (node!.wiFiConfig?.enabled ?? false)
|
||||
self.ssid = node!.wiFiConfig?.ssid ?? ""
|
||||
self.password = node!.wiFiConfig?.password ?? ""
|
||||
self.apMode = (node!.wiFiConfig?.apMode ?? false)
|
||||
self.apHidden = (node!.wiFiConfig?.apHidden ?? false)
|
||||
|
||||
self.mode = Int(node!.wiFiConfig?.mode ?? 0)
|
||||
|
||||
self.hasChanges = false
|
||||
self.initialLoad = false
|
||||
}
|
||||
|
|
@ -202,18 +224,11 @@ struct WiFiConfig: View {
|
|||
if newPassword != node!.wiFiConfig!.password { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: apMode) { newApMode in
|
||||
.onChange(of: mode) { newMode in
|
||||
|
||||
if node != nil && node!.wiFiConfig != nil {
|
||||
|
||||
if newApMode != node!.wiFiConfig!.apMode { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: apHidden) { newApHidden in
|
||||
|
||||
if node != nil && node!.wiFiConfig != nil {
|
||||
|
||||
if newApHidden != node!.wiFiConfig!.apHidden { hasChanges = true }
|
||||
if newMode != node!.wiFiConfig!.mode { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue