Skip to content

Commit 6ba90d8

Browse files
authored
Feature/esp provision provider (#9)
* Brought over the ESPProvisionProvider branch from console-ios Added a fix on provisionDevice action in ORViewController * Better error handling in provision device when calling backend API * Added couple of TODOs * Update ignore list * Use latest license header version, see openremote/openremote#1441 * Error handling in case of missing keys from webapp messages * Add some more logging * Fix for SWIFT TASK CONTINUATION MISUSE warning * Formatting and move log before return * M1V1-64: Add indication whether exit provisioning was successful or not * Small clean-ups
1 parent a86bc2e commit 6ba90d8

22 files changed

+4407
-39
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ORLib.xcodeproj/project.xcworkspace/xcuserdata
2+
ORLib.xcodeproj/xcuserdata
3+
.swiftpm/xcode/xcuserdata

ORLib.xcodeproj/project.pbxproj

Lines changed: 113 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,23 @@
6060
91DD9FEE29102A5800912F79 /* test10.json in Resources */ = {isa = PBXBuildFile; fileRef = 91DD9FED2910280900912F79 /* test10.json */; };
6161
91DD9FF029102A8B00912F79 /* test11.json in Resources */ = {isa = PBXBuildFile; fileRef = 91DD9FEF29102A8B00912F79 /* test11.json */; };
6262
91DF424E299FA79600DFF85E /* test13.json in Resources */ = {isa = PBXBuildFile; fileRef = 91DF424D299FA79600DFF85E /* test13.json */; };
63+
91F2164A2D887B50008F9CA7 /* ESPProvision in Frameworks */ = {isa = PBXBuildFile; productRef = 91F216492D887B50008F9CA7 /* ESPProvision */; };
64+
91F2164D2D887B73008F9CA7 /* RandomPasswordGenerator in Frameworks */ = {isa = PBXBuildFile; productRef = 91F2164C2D887B73008F9CA7 /* RandomPasswordGenerator */; };
65+
91F2165A2D887BCF008F9CA7 /* LoopDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216542D887BCF008F9CA7 /* LoopDetector.swift */; };
66+
91F2165B2D887BCF008F9CA7 /* BatteryProvision.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F2164E2D887BCF008F9CA7 /* BatteryProvision.swift */; };
67+
91F2165C2D887BCF008F9CA7 /* ORConfigChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216552D887BCF008F9CA7 /* ORConfigChannel.swift */; };
68+
91F2165D2D887BCF008F9CA7 /* BatteryProvisionAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F2164F2D887BCF008F9CA7 /* BatteryProvisionAPI.swift */; };
69+
91F2165E2D887BCF008F9CA7 /* DeviceRegistry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216522D887BCF008F9CA7 /* DeviceRegistry.swift */; };
70+
91F2165F2D887BCF008F9CA7 /* ORESPDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216572D887BCF008F9CA7 /* ORESPDevice.swift */; };
71+
91F216602D887BCF008F9CA7 /* WifiProvisioner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216582D887BCF008F9CA7 /* WifiProvisioner.swift */; };
72+
91F216612D887BCF008F9CA7 /* ESPProvisionProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216532D887BCF008F9CA7 /* ESPProvisionProvider.swift */; };
73+
91F216622D887BCF008F9CA7 /* ORConfigChannelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216562D887BCF008F9CA7 /* ORConfigChannelProtocol.swift */; };
74+
91F216632D887BCF008F9CA7 /* DeviceConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216512D887BCF008F9CA7 /* DeviceConnection.swift */; };
75+
91F216642D887BCF008F9CA7 /* CallbackChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216502D887BCF008F9CA7 /* CallbackChannel.swift */; };
76+
91F216692D887C53008F9CA7 /* BatteryProvisionAPIMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216652D887C53008F9CA7 /* BatteryProvisionAPIMock.swift */; };
77+
91F2166A2D887C53008F9CA7 /* ESPProvisionProviderTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216662D887C53008F9CA7 /* ESPProvisionProviderTest.swift */; };
78+
91F2166B2D887C53008F9CA7 /* ORESPDeviceMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216682D887C53008F9CA7 /* ORESPDeviceMock.swift */; };
79+
91F2166C2D887C53008F9CA7 /* ORConfigChannelTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F216672D887C53008F9CA7 /* ORConfigChannelTest.swift */; };
6380
/* End PBXBuildFile section */
6481

6582
/* Begin PBXContainerItemProxy section */
@@ -143,13 +160,30 @@
143160
91DD9FED2910280900912F79 /* test10.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = test10.json; sourceTree = "<group>"; };
144161
91DD9FEF29102A8B00912F79 /* test11.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = test11.json; sourceTree = "<group>"; };
145162
91DF424D299FA79600DFF85E /* test13.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = test13.json; sourceTree = "<group>"; };
163+
91F2164E2D887BCF008F9CA7 /* BatteryProvision.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryProvision.swift; sourceTree = "<group>"; };
164+
91F2164F2D887BCF008F9CA7 /* BatteryProvisionAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryProvisionAPI.swift; sourceTree = "<group>"; };
165+
91F216502D887BCF008F9CA7 /* CallbackChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallbackChannel.swift; sourceTree = "<group>"; };
166+
91F216512D887BCF008F9CA7 /* DeviceConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceConnection.swift; sourceTree = "<group>"; };
167+
91F216522D887BCF008F9CA7 /* DeviceRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceRegistry.swift; sourceTree = "<group>"; };
168+
91F216532D887BCF008F9CA7 /* ESPProvisionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ESPProvisionProvider.swift; sourceTree = "<group>"; };
169+
91F216542D887BCF008F9CA7 /* LoopDetector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopDetector.swift; sourceTree = "<group>"; };
170+
91F216552D887BCF008F9CA7 /* ORConfigChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ORConfigChannel.swift; sourceTree = "<group>"; };
171+
91F216562D887BCF008F9CA7 /* ORConfigChannelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ORConfigChannelProtocol.swift; sourceTree = "<group>"; };
172+
91F216572D887BCF008F9CA7 /* ORESPDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ORESPDevice.swift; sourceTree = "<group>"; };
173+
91F216582D887BCF008F9CA7 /* WifiProvisioner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WifiProvisioner.swift; sourceTree = "<group>"; };
174+
91F216652D887C53008F9CA7 /* BatteryProvisionAPIMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryProvisionAPIMock.swift; sourceTree = "<group>"; };
175+
91F216662D887C53008F9CA7 /* ESPProvisionProviderTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ESPProvisionProviderTest.swift; sourceTree = "<group>"; };
176+
91F216672D887C53008F9CA7 /* ORConfigChannelTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ORConfigChannelTest.swift; sourceTree = "<group>"; };
177+
91F216682D887C53008F9CA7 /* ORESPDeviceMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ORESPDeviceMock.swift; sourceTree = "<group>"; };
146178
/* End PBXFileReference section */
147179

148180
/* Begin PBXFrameworksBuildPhase section */
149181
4CBDF2A72AE285E400C7D94C /* Frameworks */ = {
150182
isa = PBXFrameworksBuildPhase;
151183
buildActionMask = 2147483647;
152184
files = (
185+
91F2164D2D887B73008F9CA7 /* RandomPasswordGenerator in Frameworks */,
186+
91F2164A2D887B50008F9CA7 /* ESPProvision in Frameworks */,
153187
);
154188
runOnlyForDeploymentPostprocessing = 0;
155189
};
@@ -204,6 +238,7 @@
204238
4CF5D05127143F1F00D705BE /* ConsoleProviders */ = {
205239
isa = PBXGroup;
206240
children = (
241+
91F216592D887BCF008F9CA7 /* ESPProvision */,
207242
4CF5D05227143F1F00D705BE /* StorageProvider.swift */,
208243
4CF5D05327143F1F00D705BE /* GeofenceProvider.swift */,
209244
4CF5D05427143F1F00D705BE /* PushNotificationProvider.swift */,
@@ -300,12 +335,35 @@
300335
91A9A8FA28BF6A4900DF8928 /* ConfigManagerTest.swift */,
301336
91A9A90028BF6EA000DF8928 /* FileApiManager.swift */,
302337
91AA79F228D628E9005B9913 /* Fixture.swift */,
338+
91F216652D887C53008F9CA7 /* BatteryProvisionAPIMock.swift */,
339+
91F216662D887C53008F9CA7 /* ESPProvisionProviderTest.swift */,
340+
91F216672D887C53008F9CA7 /* ORConfigChannelTest.swift */,
341+
91F216682D887C53008F9CA7 /* ORESPDeviceMock.swift */,
342+
9154E29F2D9EB0D50055E565 /* ConfigManagerSwiftTest.swift */,
303343
9154E29F2D9EB0D50055E565 /* StringUtilsTest.swift */,
304344
9154E2A12D9EB3220055E565 /* URLTest.swift */,
305345
);
306346
path = Tests;
307347
sourceTree = "<group>";
308348
};
349+
91F216592D887BCF008F9CA7 /* ESPProvision */ = {
350+
isa = PBXGroup;
351+
children = (
352+
91F2164E2D887BCF008F9CA7 /* BatteryProvision.swift */,
353+
91F2164F2D887BCF008F9CA7 /* BatteryProvisionAPI.swift */,
354+
91F216502D887BCF008F9CA7 /* CallbackChannel.swift */,
355+
91F216512D887BCF008F9CA7 /* DeviceConnection.swift */,
356+
91F216522D887BCF008F9CA7 /* DeviceRegistry.swift */,
357+
91F216532D887BCF008F9CA7 /* ESPProvisionProvider.swift */,
358+
91F216542D887BCF008F9CA7 /* LoopDetector.swift */,
359+
91F216552D887BCF008F9CA7 /* ORConfigChannel.swift */,
360+
91F216562D887BCF008F9CA7 /* ORConfigChannelProtocol.swift */,
361+
91F216572D887BCF008F9CA7 /* ORESPDevice.swift */,
362+
91F216582D887BCF008F9CA7 /* WifiProvisioner.swift */,
363+
);
364+
path = ESPProvision;
365+
sourceTree = "<group>";
366+
};
309367
/* End PBXGroup section */
310368

311369
/* Begin PBXHeadersBuildPhase section */
@@ -384,6 +442,10 @@
384442
Base,
385443
);
386444
mainGroup = 4CF5D03E27143EEB00D705BE;
445+
packageReferences = (
446+
91F216482D887B50008F9CA7 /* XCRemoteSwiftPackageReference "esp-idf-provisioning-ios" */,
447+
91F2164B2D887B73008F9CA7 /* XCRemoteSwiftPackageReference "RandomPasswordGenerator" */,
448+
);
387449
productRefGroup = 4CF5D04827143EEC00D705BE /* Products */;
388450
projectDirPath = "";
389451
projectRoot = "";
@@ -447,6 +509,17 @@
447509
4CBDF2C72AE2869D00C7D94C /* ProjectConfig.swift in Sources */,
448510
4CBDF2C82AE2869D00C7D94C /* ORNotificationResource.swift in Sources */,
449511
4CBDF2C92AE2869D00C7D94C /* HttpApiManager.swift in Sources */,
512+
91F2165A2D887BCF008F9CA7 /* LoopDetector.swift in Sources */,
513+
91F2165B2D887BCF008F9CA7 /* BatteryProvision.swift in Sources */,
514+
91F2165C2D887BCF008F9CA7 /* ORConfigChannel.swift in Sources */,
515+
91F2165D2D887BCF008F9CA7 /* BatteryProvisionAPI.swift in Sources */,
516+
91F2165E2D887BCF008F9CA7 /* DeviceRegistry.swift in Sources */,
517+
91F2165F2D887BCF008F9CA7 /* ORESPDevice.swift in Sources */,
518+
91F216602D887BCF008F9CA7 /* WifiProvisioner.swift in Sources */,
519+
91F216612D887BCF008F9CA7 /* ESPProvisionProvider.swift in Sources */,
520+
91F216622D887BCF008F9CA7 /* ORConfigChannelProtocol.swift in Sources */,
521+
91F216632D887BCF008F9CA7 /* DeviceConnection.swift in Sources */,
522+
91F216642D887BCF008F9CA7 /* CallbackChannel.swift in Sources */,
450523
4CBDF2CA2AE2869D00C7D94C /* ApiManager.swift in Sources */,
451524
4CBDF2CB2AE2869D00C7D94C /* ORTextInput.swift in Sources */,
452525
4CBDF2CC2AE2869D00C7D94C /* ORViewController.swift in Sources */,
@@ -468,6 +541,10 @@
468541
isa = PBXSourcesBuildPhase;
469542
buildActionMask = 2147483647;
470543
files = (
544+
91F216692D887C53008F9CA7 /* BatteryProvisionAPIMock.swift in Sources */,
545+
91F2166A2D887C53008F9CA7 /* ESPProvisionProviderTest.swift in Sources */,
546+
91F2166B2D887C53008F9CA7 /* ORESPDeviceMock.swift in Sources */,
547+
91F2166C2D887C53008F9CA7 /* ORConfigChannelTest.swift in Sources */,
471548
91A9A90128BF6EA000DF8928 /* FileApiManager.swift in Sources */,
472549
9154E2A22D9EB3220055E565 /* URLTest.swift in Sources */,
473550
9154E2A02D9EB0D50055E565 /* StringUtilsTest.swift in Sources */,
@@ -506,7 +583,7 @@
506583
GENERATE_INFOPLIST_FILE = YES;
507584
INFOPLIST_KEY_NSHumanReadableCopyright = "";
508585
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
509-
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
586+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
510587
LD_RUNPATH_SEARCH_PATHS = (
511588
"$(inherited)",
512589
"@executable_path/Frameworks",
@@ -547,7 +624,7 @@
547624
GENERATE_INFOPLIST_FILE = YES;
548625
INFOPLIST_KEY_NSHumanReadableCopyright = "";
549626
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
550-
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
627+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
551628
LD_RUNPATH_SEARCH_PATHS = (
552629
"$(inherited)",
553630
"@executable_path/Frameworks",
@@ -697,7 +774,7 @@
697774
DEVELOPMENT_TEAM = 4AC88KZHJZ;
698775
GENERATE_INFOPLIST_FILE = YES;
699776
HEADER_SEARCH_PATHS = "";
700-
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
777+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
701778
MARKETING_VERSION = 1.0;
702779
PRODUCT_BUNDLE_IDENTIFIER = io.openremote.Tests;
703780
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -717,7 +794,7 @@
717794
DEVELOPMENT_TEAM = 4AC88KZHJZ;
718795
GENERATE_INFOPLIST_FILE = YES;
719796
HEADER_SEARCH_PATHS = "";
720-
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
797+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
721798
MARKETING_VERSION = 1.0;
722799
PRODUCT_BUNDLE_IDENTIFIER = io.openremote.Tests;
723800
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -759,6 +836,38 @@
759836
defaultConfigurationName = Release;
760837
};
761838
/* End XCConfigurationList section */
839+
840+
/* Begin XCRemoteSwiftPackageReference section */
841+
91F216482D887B50008F9CA7 /* XCRemoteSwiftPackageReference "esp-idf-provisioning-ios" */ = {
842+
isa = XCRemoteSwiftPackageReference;
843+
repositoryURL = "https://github.com/espressif/esp-idf-provisioning-ios.git";
844+
requirement = {
845+
kind = upToNextMajorVersion;
846+
minimumVersion = 3.0.2;
847+
};
848+
};
849+
91F2164B2D887B73008F9CA7 /* XCRemoteSwiftPackageReference "RandomPasswordGenerator" */ = {
850+
isa = XCRemoteSwiftPackageReference;
851+
repositoryURL = "https://github.com/yukanamori/RandomPasswordGenerator.git";
852+
requirement = {
853+
branch = main;
854+
kind = branch;
855+
};
856+
};
857+
/* End XCRemoteSwiftPackageReference section */
858+
859+
/* Begin XCSwiftPackageProductDependency section */
860+
91F216492D887B50008F9CA7 /* ESPProvision */ = {
861+
isa = XCSwiftPackageProductDependency;
862+
package = 91F216482D887B50008F9CA7 /* XCRemoteSwiftPackageReference "esp-idf-provisioning-ios" */;
863+
productName = ESPProvision;
864+
};
865+
91F2164C2D887B73008F9CA7 /* RandomPasswordGenerator */ = {
866+
isa = XCSwiftPackageProductDependency;
867+
package = 91F2164B2D887B73008F9CA7 /* XCRemoteSwiftPackageReference "RandomPasswordGenerator" */;
868+
productName = RandomPasswordGenerator;
869+
};
870+
/* End XCSwiftPackageProductDependency section */
762871
};
763872
rootObject = 4CF5D03F27143EEC00D705BE /* Project object */;
764873
}

ORLib.xcodeproj/xcuserdata/ebariaux.xcuserdatad/xcschemes/xcschememanagement.plist

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright 2025, OpenRemote Inc.
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU Affero General Public License as
6+
* published by the Free Software Foundation, either version 3 of the
7+
* License, or (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Affero General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU Affero General Public License
15+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
*
17+
* SPDX-License-Identifier: AGPL-3.0-or-later
18+
*/
19+
20+
import Foundation
21+
import os
22+
import RandomPasswordGenerator
23+
24+
protocol BatteryProvisionAPI {
25+
func provision(deviceId: String, password: String, token: String) async throws -> String
26+
}
27+
28+
class BatteryProvision {
29+
private static let logger = Logger(
30+
subsystem: Bundle.main.bundleIdentifier!,
31+
category: String(describing: ESPProvisionProvider.self)
32+
)
33+
34+
private var deviceConnection: DeviceConnection?
35+
var callbackChannel: CallbackChannel?
36+
37+
var apiURL: URL
38+
var batteryProvisionAPI: BatteryProvisionAPI
39+
40+
var backendConnectionTimeout: TimeInterval = 60
41+
42+
init (deviceConnection: DeviceConnection?, callbackChannel: CallbackChannel?, apiURL: URL) {
43+
self.deviceConnection = deviceConnection
44+
self.callbackChannel = callbackChannel
45+
self.apiURL = apiURL
46+
self.batteryProvisionAPI = BatteryProvisionAPIREST(apiURL: apiURL)
47+
}
48+
49+
public func provision(userToken: String) async {
50+
guard deviceConnection?.isConnected ?? false else {
51+
sendProvisionDeviceStatus(connected: false, error: .notConnected, errorMessage: "No connection established to device")
52+
return
53+
}
54+
55+
do {
56+
let deviceInfo = try await deviceConnection!.getDeviceInfo()
57+
Self.logger.info("Device ID retrieved from firmware: \(deviceInfo.deviceId)")
58+
59+
let password = try generatePassword()
60+
61+
let assetId = try await batteryProvisionAPI.provision(deviceId: deviceInfo.deviceId, password: password, token: userToken)
62+
let userName = deviceInfo.deviceId.lowercased(with: Locale(identifier: "en"))
63+
64+
try await deviceConnection!.sendOpenRemoteConfig(mqttBrokerUrl: mqttURL, mqttUser: userName, mqttPassword: password, assetId: assetId)
65+
66+
var status = BackendConnectionStatus.connecting
67+
// TODO: what about other status values ? Is status connecting while it connects ? or disconnected ? -> test with real device
68+
let startTime = Date.now
69+
while (status != .connected) {
70+
if Date.now.timeIntervalSince(startTime) > backendConnectionTimeout {
71+
sendProvisionDeviceStatus(connected: false, error: .timeoutError, errorMessage: "Timeout waiting for backend to get connected")
72+
return
73+
}
74+
status = try await deviceConnection!.getBackendConnectionStatus()
75+
Self.logger.info("ModuleOne reported connection status \(String(describing: status))")
76+
}
77+
78+
// TODO: review, if we're out of the loop, this is always true
79+
80+
if status == .connected {
81+
sendProvisionDeviceStatus(connected: true)
82+
}
83+
} catch let error as ESPProviderError {
84+
sendProvisionDeviceStatus(connected: false, error: error.errorCode, errorMessage: error.errorMessage)
85+
} catch let error as RandomPasswordGeneratorError {
86+
sendProvisionDeviceStatus(connected: false, error: .genericError, errorMessage: error.localizedDescription)
87+
} catch let error as BatteryProvisionAPIError {
88+
let (errorCode, errorMessage) = mapBatteryProvisionAPIError(error)
89+
sendProvisionDeviceStatus(connected: false, error: errorCode, errorMessage: errorMessage)
90+
} catch {
91+
sendProvisionDeviceStatus(connected: false, error: .genericError, errorMessage: error.localizedDescription)
92+
}
93+
}
94+
95+
private func mapBatteryProvisionAPIError(_ error: BatteryProvisionAPIError) -> (ESPProviderErrorCode, String?) {
96+
switch error {
97+
case .businessError, .unknownError:
98+
return (ESPProviderErrorCode.genericError, nil)
99+
case .genericError(let error):
100+
return (ESPProviderErrorCode.genericError, error.localizedDescription)
101+
case .unauthorized:
102+
return (ESPProviderErrorCode.securityError, nil)
103+
case .communicationError(let errorMessage):
104+
return (ESPProviderErrorCode.communicationError, errorMessage)
105+
}
106+
}
107+
108+
private func sendProvisionDeviceStatus(connected: Bool, error: ESPProviderErrorCode? = nil, errorMessage: String? = nil) {
109+
var data: [String: Any] = ["connected": connected]
110+
if let error {
111+
data["errorCode"] = error.rawValue
112+
}
113+
if let errorMessage {
114+
data["errorMessage"] = errorMessage
115+
}
116+
callbackChannel?.sendMessage(action: Actions.provisionDevice, data: data)
117+
}
118+
119+
private func generatePassword() throws -> String {
120+
// Using https://github.com/yukanamori/RandomPasswordGenerator.git
121+
let generator = RandomPasswordGenerator(length: 16, characterTypes: [.digits, .uppercase, .lowercase])
122+
return try generator.generate()
123+
}
124+
125+
private var mqttURL: String {
126+
// TODO: is this OK or do we want to get the mqtt url from the server
127+
128+
return "mqtts://\(apiURL.host ?? "localhost"):8883"
129+
}
130+
}

0 commit comments

Comments
 (0)