@mentra/bluetooth-sdk 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +61 -42
- package/android/src/main/java/com/mentra/bluetoothsdk/BluetoothSdkModule.kt +20 -12
- package/android/src/main/java/com/mentra/bluetoothsdk/Bridge.kt +38 -12
- package/android/src/main/java/com/mentra/bluetoothsdk/DeviceStore.kt +2 -1
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothSdk.kt +45 -51
- package/android/src/main/java/com/mentra/bluetoothsdk/audio/AudioModels.kt +125 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/camera/CameraModels.kt +187 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/connection/ConnectionModels.kt +78 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/events/BluetoothEvents.kt +60 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/internal/MapParsing.kt +132 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/requests/DisplayRequests.kt +39 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/status/DeviceStatus.kt +605 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/status/RuntimeState.kt +199 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/status/WifiHotspotStatus.kt +173 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/streaming/StreamModels.kt +348 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/types/DeviceModels.kt +75 -0
- package/build/BluetoothSdk.types.d.ts +24 -7
- package/build/BluetoothSdk.types.d.ts.map +1 -1
- package/build/BluetoothSdk.types.js.map +1 -1
- package/build/_internal.d.ts +1 -1
- package/build/_internal.js +1 -1
- package/build/_internal.js.map +1 -1
- package/build/_private/BluetoothSdkModule.d.ts +5 -4
- package/build/_private/BluetoothSdkModule.d.ts.map +1 -1
- package/build/_private/BluetoothSdkModule.js +4 -1
- package/build/_private/BluetoothSdkModule.js.map +1 -1
- package/build/index.d.ts +4 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +81 -2
- package/build/index.js.map +1 -1
- package/build/react/index.d.ts +2 -2
- package/build/react/index.d.ts.map +1 -1
- package/build/react/index.js +1 -2
- package/build/react/index.js.map +1 -1
- package/build/react/useBluetoothStatus.js +1 -1
- package/build/react/useBluetoothStatus.js.map +1 -1
- package/build/react/useGlassesConnection.d.ts.map +1 -1
- package/build/react/useGlassesConnection.js +13 -0
- package/build/react/useGlassesConnection.js.map +1 -1
- package/build/react/useMentraBluetooth.d.ts +98 -0
- package/build/react/useMentraBluetooth.d.ts.map +1 -0
- package/build/react/useMentraBluetooth.js +156 -0
- package/build/react/useMentraBluetooth.js.map +1 -0
- package/ios/BluetoothSdkModule.swift +9 -9
- package/ios/Source/Audio/AudioModels.swift +159 -0
- package/ios/Source/Bridge.swift +42 -8
- package/ios/Source/Camera/CameraModels.swift +246 -0
- package/ios/Source/Connection/ScanSession.swift +27 -0
- package/ios/Source/DeviceManager.swift +0 -1
- package/ios/Source/DeviceStore.swift +2 -1
- package/ios/Source/Errors/BluetoothError.swift +19 -0
- package/ios/Source/Events/BluetoothEvents.swift +115 -0
- package/ios/Source/Internal/BluetoothAvailability.swift +58 -0
- package/ios/Source/Internal/ValueParsing.swift +90 -0
- package/ios/Source/MentraBluetoothSDK.swift +32 -2040
- package/ios/Source/Requests/DisplayRequests.swift +58 -0
- package/ios/Source/Status/DeviceStatus.swift +463 -0
- package/ios/Source/Status/RuntimeState.swift +350 -0
- package/ios/Source/Status/WifiHotspotStatus.swift +326 -0
- package/ios/Source/Streaming/StreamModels.swift +436 -0
- package/ios/Source/Types/DeviceModels.swift +134 -0
- package/ios/Source/sgcs/G2.swift +97 -36
- package/package.json +1 -1
- package/src/BluetoothSdk.types.ts +24 -7
- package/src/_internal.ts +1 -1
- package/src/_private/BluetoothSdkModule.ts +10 -5
- package/src/index.ts +93 -4
- package/src/react/index.ts +13 -11
- package/src/react/useBluetoothStatus.ts +1 -1
- package/src/react/useGlassesConnection.ts +15 -0
- package/src/react/useMentraBluetooth.ts +307 -0
- package/android/src/main/java/com/mentra/bluetoothsdk/MentraBluetoothModels.kt +0 -1725
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
public struct MentraBluetoothState: CustomStringConvertible {
|
|
4
|
+
public let glasses: GlassesRuntimeState
|
|
5
|
+
public let sdk: PhoneSdkRuntimeState
|
|
6
|
+
public let scan: BluetoothScanState
|
|
7
|
+
|
|
8
|
+
public init(glasses: GlassesRuntimeState, sdk: PhoneSdkRuntimeState, scan: BluetoothScanState) {
|
|
9
|
+
self.glasses = glasses
|
|
10
|
+
self.sdk = sdk
|
|
11
|
+
self.scan = scan
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
init(glassesStatus: GlassesStatus, bluetoothStatus: BluetoothStatus) {
|
|
15
|
+
glasses = GlassesRuntimeState(status: glassesStatus)
|
|
16
|
+
sdk = PhoneSdkRuntimeState(status: bluetoothStatus)
|
|
17
|
+
scan = BluetoothScanState(status: bluetoothStatus)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public var description: String {
|
|
21
|
+
"MentraBluetoothState(glasses: \(glasses), scan: \(scan))"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public struct GlassesBatteryState: Equatable, CustomStringConvertible {
|
|
26
|
+
public let charging: Bool
|
|
27
|
+
public let level: Int?
|
|
28
|
+
|
|
29
|
+
public init(charging: Bool, level: Int?) {
|
|
30
|
+
self.charging = charging
|
|
31
|
+
self.level = level
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public var description: String {
|
|
35
|
+
"GlassesBatteryState(level: \(level.map(String.init) ?? "unknown"), charging: \(charging))"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public struct ConnectedGlassesInfo: Equatable, CustomStringConvertible {
|
|
40
|
+
public let appVersion: String?
|
|
41
|
+
public let bluetoothName: String?
|
|
42
|
+
public let buildNumber: String?
|
|
43
|
+
public let color: String?
|
|
44
|
+
public let deviceModel: DeviceModel?
|
|
45
|
+
public let firmwareVersion: String?
|
|
46
|
+
public let serialNumber: String?
|
|
47
|
+
public let style: String?
|
|
48
|
+
|
|
49
|
+
public init(
|
|
50
|
+
appVersion: String?,
|
|
51
|
+
bluetoothName: String?,
|
|
52
|
+
buildNumber: String?,
|
|
53
|
+
color: String?,
|
|
54
|
+
deviceModel: DeviceModel?,
|
|
55
|
+
firmwareVersion: String?,
|
|
56
|
+
serialNumber: String?,
|
|
57
|
+
style: String?
|
|
58
|
+
) {
|
|
59
|
+
self.appVersion = appVersion
|
|
60
|
+
self.bluetoothName = bluetoothName
|
|
61
|
+
self.buildNumber = buildNumber
|
|
62
|
+
self.color = color
|
|
63
|
+
self.deviceModel = deviceModel
|
|
64
|
+
self.firmwareVersion = firmwareVersion
|
|
65
|
+
self.serialNumber = serialNumber
|
|
66
|
+
self.style = style
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public var description: String {
|
|
70
|
+
bluetoothName ?? serialNumber ?? deviceModel?.deviceType ?? "Connected glasses"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public enum FirmwareSource: String {
|
|
75
|
+
case app
|
|
76
|
+
case bes
|
|
77
|
+
case firmware
|
|
78
|
+
case mtk
|
|
79
|
+
case unknown
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public struct FirmwareInfo: Equatable, CustomStringConvertible {
|
|
83
|
+
public let appVersion: String?
|
|
84
|
+
public let buildNumber: String?
|
|
85
|
+
public let source: FirmwareSource
|
|
86
|
+
public let version: String?
|
|
87
|
+
|
|
88
|
+
public init(appVersion: String?, buildNumber: String?, source: FirmwareSource, version: String?) {
|
|
89
|
+
self.appVersion = appVersion
|
|
90
|
+
self.buildNumber = buildNumber
|
|
91
|
+
self.source = source
|
|
92
|
+
self.version = version
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public var description: String {
|
|
96
|
+
version ?? "Unknown firmware"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public struct SignalState: Equatable, CustomStringConvertible {
|
|
101
|
+
public let strengthDbm: Int?
|
|
102
|
+
public let updatedAt: Int?
|
|
103
|
+
|
|
104
|
+
public init(strengthDbm: Int?, updatedAt: Int?) {
|
|
105
|
+
self.strengthDbm = strengthDbm
|
|
106
|
+
self.updatedAt = updatedAt
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public var description: String {
|
|
110
|
+
strengthDbm.map { "\($0) dBm" } ?? "Unknown signal"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public enum GlassesRuntimeState: CustomStringConvertible {
|
|
115
|
+
case disconnected(connection: GlassesConnectionState)
|
|
116
|
+
case connected(
|
|
117
|
+
battery: GlassesBatteryState,
|
|
118
|
+
connection: GlassesConnectionState,
|
|
119
|
+
device: ConnectedGlassesInfo,
|
|
120
|
+
firmware: FirmwareInfo,
|
|
121
|
+
hotspot: HotspotStatus,
|
|
122
|
+
ready: Bool,
|
|
123
|
+
signal: SignalState,
|
|
124
|
+
wifi: WifiStatus
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
init(status: GlassesStatus) {
|
|
128
|
+
if !status.connected, status.connectionState != .connected {
|
|
129
|
+
self = .disconnected(connection: status.connectionState)
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
self = .connected(
|
|
134
|
+
battery: GlassesBatteryState(
|
|
135
|
+
charging: status.charging,
|
|
136
|
+
level: status.batteryLevel >= 0 ? status.batteryLevel : nil
|
|
137
|
+
),
|
|
138
|
+
connection: .connected,
|
|
139
|
+
device: ConnectedGlassesInfo(
|
|
140
|
+
appVersion: status.appVersion.nonEmpty,
|
|
141
|
+
bluetoothName: status.bluetoothName.nonEmpty,
|
|
142
|
+
buildNumber: status.buildNumber.nonEmpty,
|
|
143
|
+
color: status.color.nonEmpty,
|
|
144
|
+
deviceModel: status.deviceModel.nonEmpty.map(DeviceModel.fromDeviceType),
|
|
145
|
+
firmwareVersion: status.firmwareVersion.nonEmpty,
|
|
146
|
+
serialNumber: status.serialNumber.nonEmpty,
|
|
147
|
+
style: status.style.nonEmpty
|
|
148
|
+
),
|
|
149
|
+
firmware: FirmwareInfo(status: status),
|
|
150
|
+
hotspot: status.hotspot,
|
|
151
|
+
ready: status.fullyBooted,
|
|
152
|
+
signal: SignalState(
|
|
153
|
+
strengthDbm: status.signalStrength == -1 ? nil : status.signalStrength,
|
|
154
|
+
updatedAt: status.signalStrengthUpdatedAt <= 0 ? nil : status.signalStrengthUpdatedAt
|
|
155
|
+
),
|
|
156
|
+
wifi: status.wifi
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public var connected: Bool {
|
|
161
|
+
if case .connected = self {
|
|
162
|
+
return true
|
|
163
|
+
}
|
|
164
|
+
return false
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public var connection: GlassesConnectionState {
|
|
168
|
+
switch self {
|
|
169
|
+
case let .disconnected(connection):
|
|
170
|
+
connection
|
|
171
|
+
case let .connected(_, connection, _, _, _, _, _, _):
|
|
172
|
+
connection
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public var ready: Bool {
|
|
177
|
+
switch self {
|
|
178
|
+
case .disconnected:
|
|
179
|
+
false
|
|
180
|
+
case let .connected(_, _, _, _, _, ready, _, _):
|
|
181
|
+
ready
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public var battery: GlassesBatteryState? {
|
|
186
|
+
guard case let .connected(battery, _, _, _, _, _, _, _) = self else {
|
|
187
|
+
return nil
|
|
188
|
+
}
|
|
189
|
+
return battery
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
public var device: ConnectedGlassesInfo? {
|
|
193
|
+
guard case let .connected(_, _, device, _, _, _, _, _) = self else {
|
|
194
|
+
return nil
|
|
195
|
+
}
|
|
196
|
+
return device
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
public var firmware: FirmwareInfo? {
|
|
200
|
+
guard case let .connected(_, _, _, firmware, _, _, _, _) = self else {
|
|
201
|
+
return nil
|
|
202
|
+
}
|
|
203
|
+
return firmware
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public var hotspot: HotspotStatus? {
|
|
207
|
+
guard case let .connected(_, _, _, _, hotspot, _, _, _) = self else {
|
|
208
|
+
return nil
|
|
209
|
+
}
|
|
210
|
+
return hotspot
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
public var signal: SignalState? {
|
|
214
|
+
guard case let .connected(_, _, _, _, _, _, signal, _) = self else {
|
|
215
|
+
return nil
|
|
216
|
+
}
|
|
217
|
+
return signal
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
public var wifi: WifiStatus? {
|
|
221
|
+
guard case let .connected(_, _, _, _, _, _, _, wifi) = self else {
|
|
222
|
+
return nil
|
|
223
|
+
}
|
|
224
|
+
return wifi
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
public var description: String {
|
|
228
|
+
switch self {
|
|
229
|
+
case let .disconnected(connection):
|
|
230
|
+
"GlassesRuntimeState(\(connection.rawValue))"
|
|
231
|
+
case let .connected(_, _, device, _, _, ready, _, _):
|
|
232
|
+
"GlassesRuntimeState(connected: \(device), ready: \(ready))"
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
public struct GalleryModeState: Equatable {
|
|
238
|
+
public let desired: GalleryMode
|
|
239
|
+
|
|
240
|
+
public init(desired: GalleryMode) {
|
|
241
|
+
self.desired = desired
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
public enum MicMode: String {
|
|
246
|
+
case phone
|
|
247
|
+
case glasses
|
|
248
|
+
case bluetoothClassic
|
|
249
|
+
case bluetooth
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
public struct PhoneSdkRuntimeState: CustomStringConvertible {
|
|
253
|
+
public let currentMic: MicMode?
|
|
254
|
+
public let defaultDevice: Device?
|
|
255
|
+
public let galleryMode: GalleryModeState
|
|
256
|
+
public let lastLog: [String]
|
|
257
|
+
public let micRanking: [MicMode]
|
|
258
|
+
public let otherBluetoothConnected: Bool
|
|
259
|
+
public let searching: Bool
|
|
260
|
+
public let searchingController: Bool
|
|
261
|
+
public let systemMicUnavailable: Bool
|
|
262
|
+
public let wifiScanResults: [WifiScanResult]
|
|
263
|
+
|
|
264
|
+
public init(
|
|
265
|
+
currentMic: MicMode?,
|
|
266
|
+
defaultDevice: Device?,
|
|
267
|
+
galleryMode: GalleryModeState,
|
|
268
|
+
lastLog: [String],
|
|
269
|
+
micRanking: [MicMode],
|
|
270
|
+
otherBluetoothConnected: Bool,
|
|
271
|
+
searching: Bool,
|
|
272
|
+
searchingController: Bool,
|
|
273
|
+
systemMicUnavailable: Bool,
|
|
274
|
+
wifiScanResults: [WifiScanResult]
|
|
275
|
+
) {
|
|
276
|
+
self.currentMic = currentMic
|
|
277
|
+
self.defaultDevice = defaultDevice
|
|
278
|
+
self.galleryMode = galleryMode
|
|
279
|
+
self.lastLog = lastLog
|
|
280
|
+
self.micRanking = micRanking
|
|
281
|
+
self.otherBluetoothConnected = otherBluetoothConnected
|
|
282
|
+
self.searching = searching
|
|
283
|
+
self.searchingController = searchingController
|
|
284
|
+
self.systemMicUnavailable = systemMicUnavailable
|
|
285
|
+
self.wifiScanResults = wifiScanResults
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
init(status: BluetoothStatus) {
|
|
289
|
+
currentMic = MicMode(rawValue: status.currentMic)
|
|
290
|
+
defaultDevice = status.defaultDevice
|
|
291
|
+
galleryMode = GalleryModeState(desired: status.galleryModeAuto ? .auto : .manual)
|
|
292
|
+
lastLog = status.lastLog
|
|
293
|
+
micRanking = status.micRanking.compactMap(MicMode.init(rawValue:))
|
|
294
|
+
otherBluetoothConnected = status.otherBtConnected
|
|
295
|
+
searching = status.searching
|
|
296
|
+
searchingController = status.searchingController
|
|
297
|
+
systemMicUnavailable = status.systemMicUnavailable
|
|
298
|
+
wifiScanResults = status.wifiScanResults
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
public var description: String {
|
|
302
|
+
"PhoneSdkRuntimeState(searching: \(searching), currentMic: \(currentMic?.rawValue ?? "unknown"))"
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
public struct BluetoothScanState: CustomStringConvertible {
|
|
307
|
+
public let active: Bool
|
|
308
|
+
public let devices: [Device]
|
|
309
|
+
public let searchingController: Bool
|
|
310
|
+
|
|
311
|
+
public init(active: Bool, devices: [Device], searchingController: Bool) {
|
|
312
|
+
self.active = active
|
|
313
|
+
self.devices = devices
|
|
314
|
+
self.searchingController = searchingController
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
init(status: BluetoothStatus) {
|
|
318
|
+
active = status.searching
|
|
319
|
+
devices = status.searchResults
|
|
320
|
+
searchingController = status.searchingController
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
public var description: String {
|
|
324
|
+
"BluetoothScanState(active: \(active), devices: \(devices.count))"
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
private extension FirmwareInfo {
|
|
329
|
+
init(status: GlassesStatus) {
|
|
330
|
+
let sources: [(String, FirmwareSource)] = [
|
|
331
|
+
(status.firmwareVersion, .firmware),
|
|
332
|
+
(status.besFirmwareVersion, .bes),
|
|
333
|
+
(status.mtkFirmwareVersion, .mtk),
|
|
334
|
+
(status.appVersion, .app),
|
|
335
|
+
]
|
|
336
|
+
let match = sources.first { !$0.0.isEmpty }
|
|
337
|
+
self.init(
|
|
338
|
+
appVersion: status.appVersion.nonEmpty,
|
|
339
|
+
buildNumber: status.buildNumber.nonEmpty,
|
|
340
|
+
source: match?.1 ?? .unknown,
|
|
341
|
+
version: match?.0.nonEmpty
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
private extension String {
|
|
347
|
+
var nonEmpty: String? {
|
|
348
|
+
isEmpty ? nil : self
|
|
349
|
+
}
|
|
350
|
+
}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
public enum WifiStatus: CustomStringConvertible, Equatable {
|
|
4
|
+
public enum State: String {
|
|
5
|
+
case disconnected
|
|
6
|
+
case connected
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
case disconnected
|
|
10
|
+
case connected(ssid: String, localIp: String?)
|
|
11
|
+
|
|
12
|
+
private init?(connected: Bool, ssid: String?, localIp: String?) {
|
|
13
|
+
if connected {
|
|
14
|
+
guard
|
|
15
|
+
let ssid = ssid?.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
16
|
+
!ssid.isEmpty
|
|
17
|
+
else {
|
|
18
|
+
return nil
|
|
19
|
+
}
|
|
20
|
+
let trimmedLocalIp = localIp?.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
21
|
+
self = .connected(
|
|
22
|
+
ssid: ssid,
|
|
23
|
+
localIp: trimmedLocalIp?.isEmpty == false ? trimmedLocalIp : nil
|
|
24
|
+
)
|
|
25
|
+
} else {
|
|
26
|
+
self = .disconnected
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
init?(values: [String: Any]) {
|
|
31
|
+
if let nested = values["wifi"] as? [String: Any] {
|
|
32
|
+
guard let wifi = WifiStatus(values: nested) else {
|
|
33
|
+
return nil
|
|
34
|
+
}
|
|
35
|
+
self = wifi
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if let state = stringValue(values, "state")?.lowercased() {
|
|
40
|
+
switch state {
|
|
41
|
+
case State.connected.rawValue:
|
|
42
|
+
guard let wifi = WifiStatus(
|
|
43
|
+
connected: true,
|
|
44
|
+
ssid: nonEmptyStringValue(values, "ssid"),
|
|
45
|
+
localIp: nonEmptyStringValue(values, "localIp")
|
|
46
|
+
) else {
|
|
47
|
+
return nil
|
|
48
|
+
}
|
|
49
|
+
self = wifi
|
|
50
|
+
case State.disconnected.rawValue:
|
|
51
|
+
self = .disconnected
|
|
52
|
+
default:
|
|
53
|
+
return nil
|
|
54
|
+
}
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return nil
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static func fromStoreValues(_ values: [String: Any]) -> WifiStatus? {
|
|
62
|
+
guard let connected = boolValue(values, "wifiConnected") else { return nil }
|
|
63
|
+
return fromStoreFields(
|
|
64
|
+
connected: connected,
|
|
65
|
+
ssid: nonEmptyStringValue(values, "wifiSsid"),
|
|
66
|
+
localIp: nonEmptyStringValue(values, "wifiLocalIp")
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static func fromStoreFields(connected: Bool, ssid: String?, localIp: String?) -> WifiStatus? {
|
|
71
|
+
WifiStatus(connected: connected, ssid: ssid, localIp: localIp)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public var state: State {
|
|
75
|
+
switch self {
|
|
76
|
+
case .disconnected:
|
|
77
|
+
.disconnected
|
|
78
|
+
case .connected:
|
|
79
|
+
.connected
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
public var isConnected: Bool {
|
|
84
|
+
if case .connected = self {
|
|
85
|
+
return true
|
|
86
|
+
}
|
|
87
|
+
return false
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public var values: [String: Any] {
|
|
91
|
+
switch self {
|
|
92
|
+
case .disconnected:
|
|
93
|
+
return ["state": State.disconnected.rawValue]
|
|
94
|
+
case let .connected(ssid, localIp):
|
|
95
|
+
var values: [String: Any] = [
|
|
96
|
+
"state": State.connected.rawValue,
|
|
97
|
+
"ssid": ssid,
|
|
98
|
+
]
|
|
99
|
+
if let localIp = localIp {
|
|
100
|
+
values["localIp"] = localIp
|
|
101
|
+
}
|
|
102
|
+
return values
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
var storeValues: [String: Any] {
|
|
107
|
+
switch self {
|
|
108
|
+
case .disconnected:
|
|
109
|
+
[
|
|
110
|
+
"wifiConnected": false,
|
|
111
|
+
"wifiSsid": "",
|
|
112
|
+
"wifiLocalIp": "",
|
|
113
|
+
]
|
|
114
|
+
case let .connected(ssid, localIp):
|
|
115
|
+
[
|
|
116
|
+
"wifiConnected": true,
|
|
117
|
+
"wifiSsid": ssid,
|
|
118
|
+
"wifiLocalIp": localIp ?? "",
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public var description: String {
|
|
124
|
+
switch self {
|
|
125
|
+
case .disconnected:
|
|
126
|
+
"WifiStatus(disconnected)"
|
|
127
|
+
case let .connected(ssid, localIp):
|
|
128
|
+
"WifiStatus(connected: \(ssid), localIp: \(localIp ?? "unknown"))"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public struct WifiStatusEvent: CustomStringConvertible {
|
|
134
|
+
public let status: WifiStatus
|
|
135
|
+
|
|
136
|
+
public init(status: WifiStatus) {
|
|
137
|
+
self.status = status
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
init(connected: Bool, ssid: String?, localIp: String?) {
|
|
141
|
+
self.status = WifiStatus.fromStoreFields(connected: connected, ssid: ssid, localIp: localIp) ?? .disconnected
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
init(values: [String: Any]) {
|
|
145
|
+
self.status = WifiStatus(values: values) ?? .disconnected
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public var values: [String: Any] {
|
|
149
|
+
status.values.merging(["type": "wifi_status_change"]) { _, new in new }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public var description: String {
|
|
153
|
+
"WifiStatusEvent(\(status))"
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
public enum HotspotStatus: CustomStringConvertible, Equatable {
|
|
158
|
+
public enum State: String {
|
|
159
|
+
case disabled
|
|
160
|
+
case enabled
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
case disabled
|
|
164
|
+
case enabled(ssid: String, password: String, localIp: String)
|
|
165
|
+
|
|
166
|
+
public init?(enabled: Bool, ssid: String?, password: String?, localIp: String?) {
|
|
167
|
+
if enabled {
|
|
168
|
+
guard
|
|
169
|
+
let ssid = ssid?.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
170
|
+
!ssid.isEmpty,
|
|
171
|
+
let password = password?.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
172
|
+
!password.isEmpty,
|
|
173
|
+
let localIp = localIp?.trimmingCharacters(in: .whitespacesAndNewlines),
|
|
174
|
+
!localIp.isEmpty
|
|
175
|
+
else {
|
|
176
|
+
return nil
|
|
177
|
+
}
|
|
178
|
+
self = .enabled(ssid: ssid, password: password, localIp: localIp)
|
|
179
|
+
} else {
|
|
180
|
+
self = .disabled
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
public init?(values: [String: Any]) {
|
|
185
|
+
if let nested = values["hotspot"] as? [String: Any] {
|
|
186
|
+
self.init(values: nested)
|
|
187
|
+
return
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
guard let state = stringValue(values, "state")?.lowercased() else {
|
|
191
|
+
return nil
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
switch state {
|
|
195
|
+
case State.enabled.rawValue:
|
|
196
|
+
self.init(
|
|
197
|
+
enabled: true,
|
|
198
|
+
ssid: nonEmptyStringValue(values, "ssid"),
|
|
199
|
+
password: nonEmptyStringValue(values, "password"),
|
|
200
|
+
localIp: nonEmptyStringValue(values, "localIp")
|
|
201
|
+
)
|
|
202
|
+
case State.disabled.rawValue:
|
|
203
|
+
self = .disabled
|
|
204
|
+
default:
|
|
205
|
+
return nil
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static func fromStoreValues(_ values: [String: Any]) -> HotspotStatus? {
|
|
210
|
+
guard let enabled = boolValue(values, "hotspotEnabled") else {
|
|
211
|
+
return nil
|
|
212
|
+
}
|
|
213
|
+
return fromStoreFields(
|
|
214
|
+
enabled: enabled,
|
|
215
|
+
ssid: nonEmptyStringValue(values, "hotspotSsid"),
|
|
216
|
+
password: nonEmptyStringValue(values, "hotspotPassword"),
|
|
217
|
+
localIp: nonEmptyStringValue(values, "hotspotGatewayIp")
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
static func fromStoreFields(enabled: Bool, ssid: String?, password: String?, localIp: String?) -> HotspotStatus? {
|
|
222
|
+
HotspotStatus(enabled: enabled, ssid: ssid, password: password, localIp: localIp)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
var storeValues: [String: Any] {
|
|
226
|
+
switch self {
|
|
227
|
+
case .disabled:
|
|
228
|
+
[
|
|
229
|
+
"hotspotEnabled": false,
|
|
230
|
+
"hotspotSsid": "",
|
|
231
|
+
"hotspotPassword": "",
|
|
232
|
+
"hotspotGatewayIp": "",
|
|
233
|
+
]
|
|
234
|
+
case let .enabled(ssid, password, localIp):
|
|
235
|
+
[
|
|
236
|
+
"hotspotEnabled": true,
|
|
237
|
+
"hotspotSsid": ssid,
|
|
238
|
+
"hotspotPassword": password,
|
|
239
|
+
"hotspotGatewayIp": localIp,
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
public var values: [String: Any] {
|
|
245
|
+
switch self {
|
|
246
|
+
case .disabled:
|
|
247
|
+
["state": State.disabled.rawValue]
|
|
248
|
+
case let .enabled(ssid, password, localIp):
|
|
249
|
+
[
|
|
250
|
+
"state": State.enabled.rawValue,
|
|
251
|
+
"ssid": ssid,
|
|
252
|
+
"password": password,
|
|
253
|
+
"localIp": localIp,
|
|
254
|
+
]
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
public var state: State {
|
|
259
|
+
switch self {
|
|
260
|
+
case .disabled:
|
|
261
|
+
.disabled
|
|
262
|
+
case .enabled:
|
|
263
|
+
.enabled
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
public var isEnabled: Bool {
|
|
268
|
+
if case .enabled = self {
|
|
269
|
+
return true
|
|
270
|
+
}
|
|
271
|
+
return false
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
public var description: String {
|
|
275
|
+
switch self {
|
|
276
|
+
case .disabled:
|
|
277
|
+
"HotspotStatus(disabled)"
|
|
278
|
+
case let .enabled(ssid, _, localIp):
|
|
279
|
+
"HotspotStatus(enabled: \(ssid), localIp: \(localIp))"
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
public struct HotspotStatusEvent: CustomStringConvertible {
|
|
285
|
+
public let status: HotspotStatus
|
|
286
|
+
|
|
287
|
+
public init(status: HotspotStatus) {
|
|
288
|
+
self.status = status
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
init(enabled: Bool, ssid: String?, password: String?, localIp: String?) {
|
|
292
|
+
self.status = HotspotStatus.fromStoreFields(enabled: enabled, ssid: ssid, password: password, localIp: localIp) ?? .disabled
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
init(values: [String: Any]) {
|
|
296
|
+
self.status = HotspotStatus(values: values) ?? .disabled
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
public var values: [String: Any] {
|
|
300
|
+
status.values.merging(["type": "hotspot_status_change"]) { _, new in new }
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
public var description: String {
|
|
304
|
+
"HotspotStatusEvent(\(status))"
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
public struct HotspotErrorEvent: CustomStringConvertible {
|
|
309
|
+
public let values: [String: Any]
|
|
310
|
+
|
|
311
|
+
public init(values: [String: Any]) {
|
|
312
|
+
self.values = values
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
public var message: String? {
|
|
316
|
+
stringValue(values, "errorMessage")
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
public var timestamp: Int? {
|
|
320
|
+
intValue(values["timestamp"])
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
public var description: String {
|
|
324
|
+
"HotspotErrorEvent(message: \(message ?? "unknown"))"
|
|
325
|
+
}
|
|
326
|
+
}
|