diff --git a/OpenHABCore/Sources/OpenHABCore/Util/NetworkTracker.swift b/OpenHABCore/Sources/OpenHABCore/Util/NetworkTracker.swift index 21b7a5ab..2ada699f 100644 --- a/OpenHABCore/Sources/OpenHABCore/Util/NetworkTracker.swift +++ b/OpenHABCore/Sources/OpenHABCore/Util/NetworkTracker.swift @@ -71,6 +71,7 @@ public final class NetworkTracker: ObservableObject { public func startTracking(connectionConfigurations: [ConnectionConfiguration], username: String, password: String, alwaysSendBasicAuth: Bool) { self.connectionConfigurations = connectionConfigurations httpClient = HTTPClient(username: username, password: password, alwaysSendBasicAuth: alwaysSendBasicAuth) + setActiveConnection(nil) attemptConnection() } diff --git a/openHAB.xcodeproj/project.pbxproj b/openHAB.xcodeproj/project.pbxproj index 16151abe..6a53d6b9 100644 --- a/openHAB.xcodeproj/project.pbxproj +++ b/openHAB.xcodeproj/project.pbxproj @@ -115,7 +115,6 @@ DAA42BA821DC97E000244B2A /* NotificationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAA42BA721DC97DF00244B2A /* NotificationTableViewCell.swift */; }; DAA42BAA21DC983B00244B2A /* VideoUITableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAA42BA921DC983B00244B2A /* VideoUITableViewCell.swift */; }; DAA42BAC21DC984A00244B2A /* WebUITableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAA42BAB21DC984A00244B2A /* WebUITableViewCell.swift */; }; - DAAC30862CBBF0230041927F /* OpenHABWatchTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAAC30852CBBF0230041927F /* OpenHABWatchTracker.swift */; }; DAAC30872CBBF0420041927F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0775262346705F0086C685 /* ContentView.swift */; }; DAC65FC7236EDF3900F4501E /* SpinnerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC65FC6236EDF3900F4501E /* SpinnerViewController.swift */; }; DAC6608D236F771600F4501E /* PreferencesSwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DAC6608C236F771600F4501E /* PreferencesSwiftUIView.swift */; }; @@ -413,7 +412,6 @@ DAA42BA721DC97DF00244B2A /* NotificationTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationTableViewCell.swift; sourceTree = ""; }; DAA42BA921DC983B00244B2A /* VideoUITableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoUITableViewCell.swift; sourceTree = ""; }; DAA42BAB21DC984A00244B2A /* WebUITableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebUITableViewCell.swift; sourceTree = ""; }; - DAAC30852CBBF0230041927F /* OpenHABWatchTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenHABWatchTracker.swift; sourceTree = ""; }; DAC65FC6236EDF3900F4501E /* SpinnerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpinnerViewController.swift; sourceTree = ""; }; DAC6608B236F6F4200F4501E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; DAC6608C236F771600F4501E /* PreferencesSwiftUIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesSwiftUIView.swift; sourceTree = ""; }; @@ -582,7 +580,6 @@ isa = PBXGroup; children = ( DA0776EF234788010086C685 /* UserData.swift */, - DAAC30852CBBF0230041927F /* OpenHABWatchTracker.swift */, ); path = Domain; sourceTree = ""; @@ -1487,7 +1484,6 @@ DA50C7BD2B0A51BD0009F716 /* SliderWithSwitchSupportRow.swift in Sources */, DAF457A623DB9CE00018B495 /* SetpointRow.swift in Sources */, DAA070932B5181210060BB0E /* OpenHABImageDownloaderOperation.swift in Sources */, - DAAC30862CBBF0230041927F /* OpenHABWatchTracker.swift in Sources */, DAF4581823DC4A050018B495 /* ImageRow.swift in Sources */, 9350F17923814FAC00054BA8 /* ObservableOpenHABWidget.swift in Sources */, DA07752F2346705F0086C685 /* NotificationView.swift in Sources */, diff --git a/openHAB/OpenHABSitemapViewController.swift b/openHAB/OpenHABSitemapViewController.swift index 70e30d8a..56a45262 100644 --- a/openHAB/OpenHABSitemapViewController.swift +++ b/openHAB/OpenHABSitemapViewController.swift @@ -179,6 +179,8 @@ class OpenHABSitemapViewController: OpenHABViewController, GenericUITableViewCel case .notConnected: os_log("Tracking error", log: .viewCycle, type: .info) self.showPopupMessage(seconds: 60, title: NSLocalizedString("error", comment: ""), message: NSLocalizedString("network_not_available", comment: ""), theme: .error) + case .connected: + self.hidePopupMessages() case _: break } diff --git a/openHAB/SettingsView.swift b/openHAB/SettingsView.swift index 44b24745..4dcdf269 100644 --- a/openHAB/SettingsView.swift +++ b/openHAB/SettingsView.swift @@ -33,6 +33,7 @@ struct SettingsView: View { @State var settingsSortSitemapsBy: SortSitemapsOrder = .label @State var settingsDefaultMainUIPath = "" @State var settingsAlwaysAllowWebRTC = true + @State var settingsSitemapForWatch = "" @State private var showingCacheAlert = false @State private var showCrashReportingAlert = false @@ -40,6 +41,8 @@ struct SettingsView: View { @State private var hasBeenLoaded = false + @State private var sitemaps: [OpenHABSitemap] = [] + @Environment(\.dismiss) private var dismiss var appData: OpenHABDataObject? { @@ -154,6 +157,7 @@ struct SettingsView: View { // Setting .onAppear of view required here because onAppear of entire view is run after onChange is active // when migrating to iOS17 this settingsSendCrashReports = Preferences.sendCrashReports + loadSitemaps() hasBeenLoaded = true } .onChange(of: settingsSendCrashReports) { newValue in @@ -273,6 +277,14 @@ struct SettingsView: View { } label: { Text("Sort sitemaps by") } + + Picker(selection: $settingsSitemapForWatch) { + ForEach(sitemaps, id: \.name) { sitemap in + Text(sitemap.name).tag(sitemap as OpenHABSitemap?) + } + } label: { + Text("Sitemap For Apple Watch") + } } Section(header: Text(LocalizedStringKey("about_settings"))) { @@ -344,6 +356,7 @@ struct SettingsView: View { settingsSortSitemapsBy = SortSitemapsOrder(rawValue: Preferences.sortSitemapsby) ?? .label settingsDefaultMainUIPath = Preferences.defaultMainUIPath settingsAlwaysAllowWebRTC = Preferences.alwaysAllowWebRTC + settingsSitemapForWatch = Preferences.sitemapForWatch } func saveSettings() { @@ -361,10 +374,33 @@ struct SettingsView: View { Preferences.sortSitemapsby = settingsSortSitemapsBy.rawValue Preferences.defaultMainUIPath = settingsDefaultMainUIPath Preferences.alwaysAllowWebRTC = settingsAlwaysAllowWebRTC + Preferences.sitemapForWatch = settingsSitemapForWatch WatchMessageService.singleton.syncPreferencesToWatch() Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(settingsSendCrashReports) logger.debug("setCrashlyticsCollectionEnabled to \(settingsSendCrashReports)") } + + private func loadSitemaps() { + NetworkConnection.sitemaps(openHABRootUrl: appData?.openHABRootUrl ?? "") { response in + switch response.result { + case let .success(data): + os_log("Sitemap response", log: .viewCycle, type: .info) + + sitemaps = deriveSitemaps(data) + + if sitemaps.last?.name == "_default", sitemaps.count > 1 { + sitemaps = Array(sitemaps.dropLast()) + } + + switch SortSitemapsOrder(rawValue: Preferences.sortSitemapsby) ?? .label { + case .label: sitemaps.sort { $0.label < $1.label } + case .name: sitemaps.sort { $0.name < $1.name } + } + case let .failure(error): + os_log("%{PUBLIC}@", log: .default, type: .error, error.localizedDescription) + } + } + } } extension UIApplication { diff --git a/openHABWatch/Domain/OpenHABWatchTracker.swift b/openHABWatch/Domain/OpenHABWatchTracker.swift deleted file mode 100644 index cc15eb7e..00000000 --- a/openHABWatch/Domain/OpenHABWatchTracker.swift +++ /dev/null @@ -1,386 +0,0 @@ -// Copyright (c) 2010-2024 Contributors to the openHAB project -// -// See the NOTICE file(s) distributed with this work for additional -// information. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0 -// -// SPDX-License-Identifier: EPL-2.0 - -import Alamofire -import Foundation -import Network -import OpenHABCore -import os.log - -protocol OpenHABWatchTrackerDelegate: AnyObject { - func openHABTracked(_ openHABUrl: URL?, version: Int) - func openHABTrackingProgress(_ message: String?) - func openHABTrackingError(_ error: Error) -} - -protocol OpenHABWatchTrackerExtendedDelegate: OpenHABWatchTrackerDelegate { - func openHABTrackingNetworkChange(_ networkStatus: NWPath) -} - -class OpenHABWatchTracker: NSObject { - weak var delegate: OpenHABWatchTrackerDelegate? - - private var openHABLocalUrl = "" - private var openHABRemoteUrl = "" - private var restartTimer: Timer? - - var netBrowser: NWBrowser? - var pathMonitor = NWPathMonitor() - private let pathMonitorQueue = DispatchQueue(label: "NWPathMonitor") - @Published private(set) var pathStatus: NWPath.Status = .unsatisfied - - @objc - func restart() { - pathMonitor.cancel() - start() - } - - func start() { - openHABLocalUrl = ObservableOpenHABDataObject.shared.localUrl - openHABRemoteUrl = ObservableOpenHABDataObject.shared.remoteUrl - selectUrl() - enablePathMonitor() - } - - private func enablePathMonitor() { - pathMonitor.pathUpdateHandler = { [weak self] path in - guard let self else { return } - let newStatus = path.status - // use a timer to prevent bouncing/flapping around when switching between wifi, vpn, and wwan - restartTimer?.invalidate() - restartTimer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { _ in - if newStatus != self.pathStatus { - os_log( - "OpenHABTracker Network status changed from %{PUBLIC}@ to %{PUBLIC}@", - log: OSLog.remoteAccess, - type: .info, - String(reflecting: self.pathStatus), - path.debugDescription - ) - - self.pathStatus = newStatus - if self.isNetworkConnected() { - self.restart() - } - } - } - } - pathMonitor.start(queue: pathMonitorQueue) - } - - func selectUrl() { - // Check if any network is available - if isNetworkConnected() { - if isNetworkWiFi(), openHABLocalUrl.isEmpty { - startDiscovery() - } else { - os_log("OpenHABTracker network trying all", log: .default, type: .info) - tryAll() - } - } else { - os_log("OpenHABTracker network not available", log: .default, type: .info) - delegate?.openHABTrackingError(errorMessage("network_not_available")) - } - } - - func startDiscovery() { - os_log("OpenHABTracking starting Bonjour discovery", log: .default, type: .info) - - delegate?.openHABTrackingProgress(NSLocalizedString("discovering_oh", comment: "")) - let parameters = NWParameters() - netBrowser = NWBrowser(for: .bonjour(type: "_openhab-server-ssl._tcp.", domain: "local."), using: parameters) - netBrowser?.stateUpdateHandler = { state in - switch state { - case .ready: - os_log("OpenHABWatchTracker discovery ready", log: .default, type: .info) - case let .failed(error): - os_log("OpenHABWatchTracker discovery failed: %{PUBLIC}@", log: .default, type: .info, error.localizedDescription) -// TODO: -// self.trackedRemoteUrl() - default: - break - } - } - netBrowser?.browseResultsChangedHandler = { results, _ in - guard !results.isEmpty else { return } - guard let result = results.first else { return } - - switch result.endpoint { - case let .service(name, type, domain, interface): - os_log("OpenHABWatchTracker discovered service: name=%{PUBLIC}@ type=%{PUBLIC}@ domain=%{PUBLIC}@", log: OSLog.remoteAccess, type: .info, name, type, domain) - let params = NWParameters.tcp - let endpoint = NWEndpoint.service(name: name, type: type, domain: domain, interface: interface) - let connection = NWConnection(to: endpoint, using: params) - connection.stateUpdateHandler = { state in - switch state { - case .ready: - let path = connection.currentPath! - switch path.remoteEndpoint { - case let .hostPort(host, port): - var components = URLComponents() - components.scheme = "https" - components.port = Int(port.rawValue) - switch host { - case let .name(name, _): - components.host = name - case let .ipv4(ipv4): - components.host = self.getStringIp(addressFamily: AF_INET, fromAddressData: ipv4.rawValue) - case let .ipv6(ipv6): - components.host = self.getStringIp(addressFamily: AF_INET6, fromAddressData: ipv6.rawValue) - default: - components.host = nil - } - if components.host == nil { - os_log("OpenHABWatchTracker unable to build URL from discovered endpoint, using remote URL instead", log: OSLog.remoteAccess, type: .info) - self.tryUrl(URL(string: self.openHABRemoteUrl)) - } else { - os_log("OpenHABWatchTracker discovered: %{PUBLIC}@ ", log: OSLog.remoteAccess, type: .info, components.url?.description ?? "") - self.tryUrl(components.url) - } - return - default: - os_log("OpenHABWatchTracker unhandled endpoint type", log: OSLog.remoteAccess, type: .info) - connection.cancel() - } - case .preparing, .setup, .waiting: - break - default: - // Error establishing the connection or other unknown condition - connection.cancel() - os_log("OpenHABWatchTracker unable establish connection to discovered endpoint, using remote URL instead", log: OSLog.remoteAccess, type: .info) - self.tryUrl(URL(string: self.openHABRemoteUrl)) - } - } - self.netBrowser!.cancel() - connection.start(queue: .main) - return - default: - os_log("OpenHABWatchTracker discovered unhandled endpoint type", log: OSLog.remoteAccess, type: .info) - } - - self.netBrowser!.cancel() - - // Unable to discover local endpoint - os_log("OpenHABWatchTracker unable to discover local server, using remote URL", log: OSLog.remoteAccess, type: .info) - self.tryUrl(URL(string: self.openHABRemoteUrl)) - } - netBrowser?.start(queue: .main) - } - - func getStringIp(addressFamily: Int32, fromAddressData dataIn: Data?) -> String? { - let data = dataIn! as NSData - var sockAddr: in_addr = data.castToCPointer() - var ipAddressString: [CChar] = Array(repeating: 0, count: Int(INET6_ADDRSTRLEN)) - inet_ntop( - addressFamily, - &sockAddr, - &ipAddressString, - socklen_t(INET_ADDRSTRLEN) - ) - - return String(cString: ipAddressString) - } - - func normalizeUrl(_ url: String?) -> String? { - if let url, url.hasSuffix("/") { - return String(url.dropLast()) - } - return url - } - - func isNetworkConnected() -> Bool { - pathMonitor.currentPath.status == .satisfied - } - - func isNetworkWiFi() -> Bool { - (pathMonitor.currentPath.status == .satisfied && !pathMonitor.currentPath.isExpensive) - } - - /// Attemps to connect to the URL and get the openHAB version - /// - Parameter tryUrl: Completes with the url and version of openHAB that succeeded, or an Error object if failed - private func tryUrl(_ tryUrl: URL?) { - getServerInfoForUrl(tryUrl) { url, version, error in - if let error { - self.delegate?.openHABTrackingError(error) - } else { - ObservableOpenHABDataObject.shared.openHABVersion = version - ObservableOpenHABDataObject.shared.openHABRootUrl = url?.absoluteString ?? "" - self.delegate?.openHABTracked(url, version: version) - } - } - } - - /// Attemps to connect in parallel to the remote and local URLs if configured, the first URL to succeed wins - private func tryAll() { - var urls = [String: Double]() - if !openHABLocalUrl.isEmpty { - urls[openHABLocalUrl] = 0.0 - } - if !openHABRemoteUrl.isEmpty { - urls[openHABRemoteUrl] = openHABLocalUrl.isEmpty ? 0 : 1.5 - } - if urls.isEmpty { - delegate?.openHABTrackingProgress("error") - return - } - delegate?.openHABTrackingProgress(NSLocalizedString("connecting", comment: "")) - tryUrls(urls) { url, version, error in - if let error { - os_log("OpenHABTracker failed %{PUBLIC}@", log: .default, type: .info, error.localizedDescription) - self.delegate?.openHABTrackingError(error) - } else { - self.delegate?.openHABTracked(url, version: version) - } - } - } - - /// Tries to connect in parallel to all URL's passed in and completes when either the first requests succeedes, or all fail. - /// - Parameters: - /// - urls: Tuple of String URLS and a request Delay value - /// - completion: Completes with the url and version of openHAB that succeeded, or an Error object if all failed - private func tryUrls(_ urls: [String: Double], completion: @escaping (URL?, Int, Error?) -> Void) { - var isRequestCompletedSuccessfully = false - // request in flight - var requests = [URL: DataRequest]() - // timers that have yet to be executed - var timers = [URL: Timer]() - for (urlString, delay) in urls { - let url = URL(string: urlString)! - let restUrl = URL(string: "rest/", relativeTo: url)! - let timer = Timer.scheduledTimer(withTimeInterval: delay, repeats: false) { _ in - if NetworkConnection.shared == nil { - NetworkConnection.initialize(ignoreSSL: Preferences.ignoreSSL, interceptor: nil) - } - let request = NetworkConnection.shared.manager.request(restUrl, method: .get) - .validate() - requests[url] = request - // remove us from the outstanding timer list - timers.removeValue(forKey: url) - request.responseData { response in - // remove us from the outstanding request list - requests.removeValue(forKey: url) - os_log("OpenHABTracker response for URL %{PUBLIC}@", log: .notifications, type: .error, url.absoluteString) - switch response.result { - case let .success(data): - let version = self.getServerInfoFromData(data: data) - if version > 0, !isRequestCompletedSuccessfully { - isRequestCompletedSuccessfully = true - // cancel any timers not yet fired - timers.values.forEach { $0.invalidate() } - // cancel any requests still in flight - requests.values.forEach { $0.cancel() } - completion(url, version, nil) - } - case let .failure(error): - os_log("OpenHABTracker request failure %{PUBLIC}@", log: .notifications, type: .error, error.localizedDescription) - } - // check if we are the last attempt - if !isRequestCompletedSuccessfully, requests.isEmpty, timers.isEmpty { - os_log("OpenHABTracker last response", log: .notifications, type: .error) - completion(nil, 0, self.errorMessage("network_not_available")) - } - } - request.resume() - } - timers[url] = timer - RunLoop.main.add(timer, forMode: .common) - } - } - - /// Attempts to parse the data response from a request and determine if its an openHAB server and its server version - /// - Parameter data: request data - /// - Returns: Version of openHAB or -1 if not an openHAB server - private func getServerInfoFromData(data: Data) -> Int { - do { - let serverProperties = try data.decoded(as: OpenHABServerProperties.self) - os_log("OpenHABTracker openHAB version %@", log: .remoteAccess, type: .info, serverProperties.version) - // OH versions 2.0 through 2.4 return "1" as their version, so set the floor to 2 so we do not think this is a OH 1.x serevr - return max(2, Int(serverProperties.version) ?? 2) - } catch { - // testing for OH 1.x - let str = String(decoding: data, as: UTF8.self) - if str.hasPrefix(" Void) { - let strUrl = url?.absoluteString ?? "" - os_log("OpenHABTracker getServerInfo, trying: %{PUBLIC}@", log: .default, type: .info, strUrl) - NetworkConnection.tracker(openHABRootUrl: strUrl) { response in - os_log("OpenHABTracker getServerInfo, received data for URL: %{PUBLIC}@", log: .default, type: .info, strUrl) - switch response.result { - case let .success(data): - let version = self.getServerInfoFromData(data: data) - if version > 0 { - completion(url, version, nil) - } else { - completion(url, 0, self.errorMessage("error")) - } - case let .failure(error): - os_log("OpenHABTracker getServerInfo ERROR for %{PUBLIC}@ : %{PUBLIC}@ %d", log: .remoteAccess, type: .error, strUrl, error.localizedDescription, response.response?.statusCode ?? 0) - completion(url, 0, error) - } - } - } - - func errorMessage(_ message: String) -> NSError { - var errorDetail: [AnyHashable: Any] = [:] - errorDetail[NSLocalizedDescriptionKey] = NSLocalizedString(message, comment: "") - return NSError(domain: "openHAB", code: 101, userInfo: errorDetail as? [String: Any]) - } -} - -extension NWPath: @retroactive CustomStringConvertible { - public var description: String { - switch status { - case .unsatisfied, .requiresConnection: - return "unreachable" - case .satisfied: - var str = "reachable:" - for interface in availableInterfaces { - switch interface.type { - case .wifi: - str += " wifi" - case .cellular: - str += " cellular" - case .wiredEthernet: - str += " wiredEthernet" - case .loopback: - str += " loopback" - case .other: - str += " other" - default: - str += " (unknown)" - } - } - return str - default: - return "(unknown)" - } - } -} - -extension NSData { - func castToCPointer() -> T { - let mem = UnsafeMutablePointer.allocate(capacity: MemoryLayout.size) - getBytes(mem, length: MemoryLayout.size) - return mem.move() - } -} diff --git a/openHABWatch/Domain/UserData.swift b/openHABWatch/Domain/UserData.swift index 6ee4ee45..c1119a9b 100644 --- a/openHABWatch/Domain/UserData.swift +++ b/openHABWatch/Domain/UserData.swift @@ -39,8 +39,7 @@ final class UserData: ObservableObject { private var commandOperation: Alamofire.Request? private var currentPageOperation: Alamofire.Request? - private var tracker: OpenHABWatchTracker? - private var dataObjectCancellable: AnyCancellable? + private var cancellables = Set() private let logger = Logger(subsystem: "org.openhab.app.watch", category: "UserData") @@ -68,30 +67,50 @@ final class UserData: ObservableObject { } } - init(url: URL?, refresh: Bool = true) { - loadPage( - url: url, - longPolling: true, - refresh: refresh - ) - } - - init(url: URL?) { - tracker = OpenHABWatchTracker() - tracker?.delegate = self - } - init(sitemapName: String = "watch") { - tracker = OpenHABWatchTracker() - tracker?.delegate = self - tracker?.start() + updateNetworkTracker() + NetworkTracker.shared.$activeConnection + .receive(on: DispatchQueue.main) + .sink { [weak self] activeConnection in + if let activeConnection { + self?.logger.error("openHABTracked: \(activeConnection.configuration.url)") + + if !ObservableOpenHABDataObject.shared.haveReceivedAppContext { + AppMessageService.singleton.requestApplicationContext() + self?.errorDescription = NSLocalizedString("settings_not_received", comment: "") + self?.showAlert = true + return + } + + ObservableOpenHABDataObject.shared.openHABRootUrl = activeConnection.configuration.url + ObservableOpenHABDataObject.shared.openHABVersion = activeConnection.version + + let url = Endpoint.watchSitemap(openHABRootUrl: activeConnection.configuration.url, sitemapName: ObservableOpenHABDataObject.shared.sitemapForWatch).url + self?.loadPage(url: url, longPolling: false, refresh: true) + } + } + .store(in: &cancellables) - dataObjectCancellable = ObservableOpenHABDataObject.shared.objectRefreshed.sink { _ in + ObservableOpenHABDataObject.shared.objectRefreshed.sink { _ in // New settings updates from the phone app to start a reconnect self.logger.info("Settings update received, starting reconnect") - self.refreshUrl() + self.updateNetworkTracker() + } + .store(in: &cancellables) + } + + func updateNetworkTracker() { + if !ObservableOpenHABDataObject.shared.localUrl.isEmpty || !ObservableOpenHABDataObject.shared.remoteUrl.isEmpty { + let connection1 = ConnectionConfiguration( + url: ObservableOpenHABDataObject.shared.localUrl, + priority: 0 + ) + let connection2 = ConnectionConfiguration( + url: ObservableOpenHABDataObject.shared.remoteUrl, + priority: 1 + ) + NetworkTracker.shared.startTracking(connectionConfigurations: [connection1, connection2], username: ObservableOpenHABDataObject.shared.openHABUsername, password: ObservableOpenHABDataObject.shared.openHABPassword, alwaysSendBasicAuth: ObservableOpenHABDataObject.shared.openHABAlwaysSendCreds) } - refreshUrl() } func loadPage(url: URL?, @@ -157,37 +176,10 @@ final class UserData: ObservableObject { } func refreshUrl() { - if ObservableOpenHABDataObject.shared.haveReceivedAppContext { + if ObservableOpenHABDataObject.shared.haveReceivedAppContext, !ObservableOpenHABDataObject.shared.openHABRootUrl.isEmpty { showAlert = false - tracker?.selectUrl() + let url = Endpoint.watchSitemap(openHABRootUrl: ObservableOpenHABDataObject.shared.openHABRootUrl, sitemapName: ObservableOpenHABDataObject.shared.sitemapForWatch).url + loadPage(url: url, longPolling: false, refresh: true) } } } - -extension UserData: OpenHABWatchTrackerDelegate { - func openHABTracked(_ openHABUrl: URL?, version: Int) { - guard let urlString = openHABUrl?.absoluteString else { return } - logger.error("openHABTracked: \(urlString)") - - if !ObservableOpenHABDataObject.shared.haveReceivedAppContext { - AppMessageService.singleton.requestApplicationContext() - errorDescription = NSLocalizedString("settings_not_received", comment: "") - showAlert = true - return - } - - ObservableOpenHABDataObject.shared.openHABRootUrl = urlString - ObservableOpenHABDataObject.shared.openHABVersion = version - - let url = Endpoint.watchSitemap(openHABRootUrl: urlString, sitemapName: ObservableOpenHABDataObject.shared.sitemapForWatch).url - loadPage(url: url, longPolling: false, refresh: true) - } - - func openHABTrackingProgress(_ message: String?) { - logger.error("openHABTrackingProgress: \(message ?? "")") - } - - func openHABTrackingError(_ error: Error) { - logger.error("openHABTrackingError: \(error.localizedDescription)") - } -}