diff --git a/Miasma iOS/ContentViewSmartCitizen.swift b/Miasma iOS/ContentViewSmartCitizen.swift index 4c919ea..6d5ca5f 100644 --- a/Miasma iOS/ContentViewSmartCitizen.swift +++ b/Miasma iOS/ContentViewSmartCitizen.swift @@ -153,7 +153,7 @@ public struct ContentViewSmartCitizen: View { .font(.headline) HStack { - ProgressView("☁️ \(smartCitizenData.data?.sensors?[8].value ?? 0) PM2.5", value: Float16(smartCitizenData.data?.sensors?[8].value ?? 0), total: 500) + ProgressView("☁️ \(String(smartCitizenViewModel.sensors[8].value ?? 0))PM2.5", value: Float16(smartCitizenViewModel.Welcome.sensors[8].value ?? 0.0), total: 500) .progressViewStyle(aQIProgressBarStyle()) .padding(.top, 0.5) .padding(.bottom, 7.0) diff --git a/Miasma iOS/DataLoaderPurpleAir.swift b/Miasma iOS/DataLoaderPurpleAir.swift index 516c35c..8e18789 100644 --- a/Miasma iOS/DataLoaderPurpleAir.swift +++ b/Miasma iOS/DataLoaderPurpleAir.swift @@ -45,6 +45,7 @@ extension PurpleAirViewModel { receiveValue: { self.purpleAirdata = $0.purpleAirdata }) + print(purpleAirdata) } } @@ -62,7 +63,7 @@ struct PurpleAirAPIClient { .tryMap { result -> Response in let value = try JSONDecoder().decode( T.self, from: result.data) -// print(Response.self) + print(Response.self) return Response(value: value, response: result.response) } .receive(on: DispatchQueue.main) diff --git a/Miasma iOS/DataLoaderSmartCitizen.swift b/Miasma iOS/DataLoaderSmartCitizen.swift index bba0fd9..16559a9 100644 --- a/Miasma iOS/DataLoaderSmartCitizen.swift +++ b/Miasma iOS/DataLoaderSmartCitizen.swift @@ -10,18 +10,18 @@ import Foundation import Combine struct SmartCitizenResponse: Codable { - let smartCitizendata: SmartCitizenDataClass + let smartCitizendata: Welcome - enum CodingKeys: String, CodingKey { - case smartCitizendata = "data" - } +// enum CodingKeys: String, CodingKey { +// case smartCitizendata = "/" +// } } class SmartCitizenViewModel: ObservableObject { - @Published var smartCitizendata: SmartCitizenDataClass = SmartCitizenDataClass() + @Published var smartCitizendata: Welcome = Welcome() var smartCitizenCancellationToken: AnyCancellable? @@ -35,7 +35,7 @@ class SmartCitizenViewModel: ObservableObject { extension SmartCitizenViewModel { func getSmartCitizen() { - smartCitizenCancellationToken = SmartCitizenDB.request(.city) + smartCitizenCancellationToken = SmartCitizenDB.request(.station) .mapError({ (error) -> Error in print(error) return error @@ -44,7 +44,7 @@ extension SmartCitizenViewModel { receiveValue: { self.smartCitizendata = $0.smartCitizendata }) - print(ProfileEditor().SensorID) +// print(ProfileEditor().SensorID) print(smartCitizendata) } } @@ -63,12 +63,17 @@ struct SmartCitizenAPIClient { .tryMap { result -> Response in let value = try JSONDecoder().decode( T.self, from: result.data) + // print(Response.self) + print(result.response) + return Response(value: value, response: result.response) + } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() + } } @@ -78,7 +83,7 @@ enum SmartCitizenDB { } enum SmartCitizenAPIPath: String { - case city = "/" + case station = "" } extension SmartCitizenDB { @@ -87,7 +92,7 @@ extension SmartCitizenDB { guard var components = URLComponents(url: baseUrl.appendingPathComponent(path.rawValue), resolvingAgainstBaseURL: true) else { fatalError("Couldn't create URL Components")} - components.queryItems = [URLQueryItem(name: "token", value: APIKeyWAQI)] +// components.queryItems = [URLQueryItem(name: "token", value: APIKeyWAQI)] let request = URLRequest(url: components.url!) @@ -97,6 +102,7 @@ extension SmartCitizenDB { .map(\.value) .eraseToAnyPublisher() + } } // define the strucutre of the JSON that will be decoded - came from https://app.quicktype.io @@ -112,7 +118,7 @@ struct SmartCitizenDataStructure: Codable { // var lastReadingAt, addedAt, updatedAt: Date? // var macAddress: String? var owner: Owner? - var data: SmartCitizenDataClass? + var data: Welcome? // var kit: Kit? enum CodingKeys: String, CodingKey { @@ -137,7 +143,7 @@ struct SmartCitizenDataStructure: Codable { } // MARK: - DataClass -struct SmartCitizenDataClass: Codable { +struct Welcome: Codable { // var recordedAt, addedAt: Date? var location: DataLocation? var sensors: [SmartCitizenSensor]? @@ -512,25 +518,25 @@ class JSONAny: Codable { // define an instance of the data that can be filled by the data loader and read by the menu var smartCitizenData = SmartCitizenDataStructure() -public class DataLoaderSmartCitizen { - - - func loadSmartCitizenData(id:String) { - - let request = NSMutableURLRequest(url: NSURL(string: - "https://api.smartcitizen.me/v0/devices/\(id)")! as URL, - cachePolicy: .useProtocolCachePolicy, - timeoutInterval: 10.0) - - - request.httpMethod = "GET" - - let session = URLSession.shared - let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in - if (error != nil) { - print(error) - } else { - let httpResponse = response as? HTTPURLResponse +//public class DataLoaderSmartCitizen { +// +// +// func loadSmartCitizenData(id:String) { +// +// let request = NSMutableURLRequest(url: NSURL(string: +// "https://api.smartcitizen.me/v0/devices/\(id)")! as URL, +// cachePolicy: .useProtocolCachePolicy, +// timeoutInterval: 10.0) +// +// +// request.httpMethod = "GET" +// +// let session = URLSession.shared +// let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in +// if (error != nil) { +// print(error) +// } else { +// let httpResponse = response as? HTTPURLResponse // print("Received from the SmartCitizen API") // if let data = data, // let urlContent = NSString(data: data, encoding: String.Encoding.ascii.rawValue) { @@ -538,20 +544,20 @@ public class DataLoaderSmartCitizen { // } else { // print("error with printing string encoded data") // } - //Parse JSON - let decoder = JSONDecoder() - do { - let dataFromSmartCitizen = try decoder.decode(SmartCitizenDataStructure.self, from: data!) - smartCitizenData = dataFromSmartCitizen - - } - catch { - print("Error in SmartCitizen JSON parsing") - // print(purpleAirData) - } - } - }) - - dataTask.resume() - } -} +// //Parse JSON +// let decoder = JSONDecoder() +// do { +// let dataFromSmartCitizen = try decoder.decode(SmartCitizenDataStructure.self, from: data!) +// smartCitizenData = dataFromSmartCitizen +// +// } +// catch { +// print("Error in SmartCitizen JSON parsing") +// // print(purpleAirData) +// } +// } +// }) +// +// dataTask.resume() +// } +//} diff --git a/Miasma.xcodeproj/project.pbxproj b/Miasma.xcodeproj/project.pbxproj index a218967..f91cde1 100644 --- a/Miasma.xcodeproj/project.pbxproj +++ b/Miasma.xcodeproj/project.pbxproj @@ -987,7 +987,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 28; + CURRENT_PROJECT_VERSION = 29; DEVELOPMENT_TEAM = VDLCQ62KZH; ENABLE_HARDENED_RUNTIME = YES; EXCLUDED_ARCHS = ""; @@ -997,7 +997,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.12; - MARKETING_VERSION = 1.20; + MARKETING_VERSION = 1.21; PRODUCT_BUNDLE_IDENTIFIER = "Darragh-Rogan.Miasma"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; @@ -1013,7 +1013,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 28; + CURRENT_PROJECT_VERSION = 29; DEVELOPMENT_TEAM = VDLCQ62KZH; ENABLE_HARDENED_RUNTIME = YES; EXCLUDED_ARCHS = ""; @@ -1023,7 +1023,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 10.12; - MARKETING_VERSION = 1.20; + MARKETING_VERSION = 1.21; PRODUCT_BUNDLE_IDENTIFIER = "Darragh-Rogan.Miasma"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; diff --git a/Miasma.xcodeproj/xcuserdata/darragh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Miasma.xcodeproj/xcuserdata/darragh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 5423564..8d984e8 100644 --- a/Miasma.xcodeproj/xcuserdata/darragh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/Miasma.xcodeproj/xcuserdata/darragh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -64,8 +64,8 @@ endingColumnNumber = "9223372036854775807" startingLineNumber = "88" endingLineNumber = "88" - landmarkName = "unknown" - landmarkType = "0"> + landmarkName = "loadClimaCellData(lat:lon:)" + landmarkType = "7"> + landmarkName = "loadClimaCellData(lat:lon:)" + landmarkType = "7"> Miasma WidgetExtension.xcscheme_^#shared#^_ orderHint - 9 + 8 Miasma iOS.xcscheme_^#shared#^_ orderHint - 8 + 10 Miasma.xcscheme_^#shared#^_ @@ -24,7 +24,7 @@ MiasmaLauncher.xcscheme_^#shared#^_ orderHint - 10 + 9 MiasmaLauncherApplication.xcscheme_^#shared#^_ diff --git a/Miasma/AppDelegate.swift b/Miasma/AppDelegate.swift index 98f792b..8a47c2c 100644 --- a/Miasma/AppDelegate.swift +++ b/Miasma/AppDelegate.swift @@ -73,11 +73,19 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele defaults.set(50, forKey:"ClimbingAQINotificationsTrigger") defaults.set("🟢", forKey: "PreviousStateForNotification") - // this is where most returning users should end up and they need an initial state for the notifications + + // this is where users should end up and allows population of the RefreshInterval feature introduced in 1.21 + } else if (defaults.bool(forKey: "First Launch") == true && isKeyPresentInUserDefaults(key: "RefreshIntervalSeconds") == false ) { + + defaults.set("🟢", forKey: "PreviousStateForNotification") + defaults.set(1200.0, forKey: "RefreshIntervalSeconds") + + + // this is where most returning users should end up and they need an initial state for the notifications } else if defaults.bool(forKey: "First Launch") == true { - + defaults.set("🟢", forKey: "PreviousStateForNotification") - + // default config for new users } else { @@ -91,6 +99,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele defaults.set(1, forKey:"FallingAQINotificationsWanted") defaults.set(50, forKey:"FallingAQINotificationsTrigger") defaults.set("🟢", forKey: "PreviousStateForNotification") + defaults.set(1200.0, forKey: "RefreshIntervalSeconds") } // Launching automatically at startup from tutorial: https://theswiftdev.com/how-to-launch-a-macos-app-at-login/ @@ -100,7 +109,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele let isRunning = !runningApps.filter { $0.bundleIdentifier == launcherAppId }.isEmpty SMLoginItemSetEnabled(launcherAppId as CFString, self.defaults.bool(forKey: "AutorunAtStartup")) - + if isRunning { DistributedNotificationCenter.default().post(name: .killLauncher, object: Bundle.main.bundleIdentifier!) } @@ -113,7 +122,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele // menuFunctions().menuRefresh(NSMenuItem) // periodically update the menu - _ = Timer.scheduledTimer(withTimeInterval: 1200.0, repeats: true) { timer in + _ = Timer.scheduledTimer(withTimeInterval: (AppDelegate().defaults.object(forKey:"RefreshIntervalSeconds") as? Double ?? Double()), repeats: true) { timer in self.statusBarItemController = menuFunctions() } } diff --git a/Miasma/Base.lproj/Main.storyboard b/Miasma/Base.lproj/Main.storyboard index 5db449a..8f0e293 100644 --- a/Miasma/Base.lproj/Main.storyboard +++ b/Miasma/Base.lproj/Main.storyboard @@ -687,11 +687,11 @@ - + - + @@ -700,7 +700,7 @@ - + @@ -709,7 +709,7 @@ - + @@ -727,7 +727,7 @@ - + @@ -736,7 +736,7 @@ - + @@ -768,7 +768,7 @@ - + @@ -776,7 +776,7 @@ - + @@ -796,7 +796,7 @@ - + @@ -806,7 +806,7 @@ - + @@ -823,7 +823,7 @@ - + @@ -832,7 +832,7 @@ - + @@ -841,7 +841,7 @@ - + @@ -861,7 +861,7 @@ - + @@ -870,7 +870,7 @@ - + @@ -882,7 +882,7 @@ - + @@ -922,7 +922,7 @@ - + @@ -931,7 +931,7 @@ - + @@ -940,7 +940,7 @@ - + @@ -949,7 +949,7 @@ - + @@ -958,7 +958,7 @@ - + @@ -1000,7 +1000,7 @@ - + @@ -1009,11 +1009,11 @@ - + - + @@ -1022,7 +1022,7 @@ - + @@ -1123,7 +1123,7 @@ - + @@ -1132,15 +1132,15 @@ - + - + - + @@ -1160,7 +1160,7 @@ - + @@ -1169,7 +1169,7 @@ - + @@ -1178,7 +1178,7 @@ - + @@ -1187,7 +1187,7 @@ - + @@ -1196,7 +1196,7 @@ - + @@ -1205,7 +1205,7 @@ - + @@ -1213,7 +1213,7 @@ - + @@ -1255,7 +1255,7 @@ - + @@ -1264,7 +1264,7 @@ - + @@ -1273,7 +1273,7 @@ - + @@ -1293,7 +1293,7 @@ - + @@ -1302,7 +1302,7 @@ - + @@ -1314,7 +1314,7 @@ - + @@ -1326,7 +1326,7 @@ - + @@ -1375,7 +1375,7 @@ - + @@ -1383,22 +1383,22 @@ - + - + - + @@ -1408,7 +1408,7 @@ - + @@ -1419,7 +1419,7 @@ It is a 4 or 5 digit number in the URL web address after clicking the sensor you - + @@ -1429,6 +1429,17 @@ It is a 5 or 9 digit number in the URL web address after clicking the street seg + @@ -1445,6 +1456,7 @@ It is a 5 or 9 digit number in the URL web address after clicking the street seg + @@ -1469,7 +1481,7 @@ It is a 5 or 9 digit number in the URL web address after clicking the street seg - + diff --git a/Miasma/DataLoaderPurpleAir.swift b/Miasma/DataLoaderPurpleAir.swift index c54f2d8..2fe2ce7 100644 --- a/Miasma/DataLoaderPurpleAir.swift +++ b/Miasma/DataLoaderPurpleAir.swift @@ -228,7 +228,7 @@ public class DataLoaderPurpleAir { print(error) } else { let httpResponse = response as? HTTPURLResponse -// print("Received from the Purple Air API") + print("Miasma received from the Purple Air API") // if let data = data, // let urlContent = NSString(data: data, encoding: String.Encoding.ascii.rawValue) { // print(urlContent) diff --git a/Miasma/DataLoaderSmartCitizen.swift b/Miasma/DataLoaderSmartCitizen.swift index e48d64e..bfbd389 100644 --- a/Miasma/DataLoaderSmartCitizen.swift +++ b/Miasma/DataLoaderSmartCitizen.swift @@ -440,7 +440,7 @@ public class DataLoaderSmartCitizen { print(error) } else { let httpResponse = response as? HTTPURLResponse -// print("Received from the SmartCitizen API") + print("Miasma received from the SmartCitizen API") // if let data = data, // let urlContent = NSString(data: data, encoding: String.Encoding.ascii.rawValue) { // print(urlContent) diff --git a/Miasma/Menu.swift b/Miasma/Menu.swift index 68a85b8..cd6f3c9 100644 --- a/Miasma/Menu.swift +++ b/Miasma/Menu.swift @@ -232,7 +232,7 @@ class menuFunctions: NSObject { ) let menuRefresh = NSMenuItem( - title: "Refresh (automatically every 20 mins)", + title: "Refresh (automatically every \((AppDelegate().defaults.object(forKey:"RefreshIntervalSeconds") as? Double ?? Double())/60) mins)", action: #selector(menuFunctions.menuRefresh(_:)), keyEquivalent: "r" ) @@ -1571,7 +1571,7 @@ class menuFunctions: NSObject { self.smartCitizenOtherPollutants.title = "☁️: VOC \(String(smartCitizenData.data?.sensors?[0].value ?? 0))\(String(smartCitizenData.data?.sensors?[0].unit ?? "0")) / CO₂ \(String(smartCitizenData.data?.sensors?[1].value ?? 0))\(String(smartCitizenData.data?.sensors?[1].unit ?? "0"))" - self.smartCitizenTemperature.title = "🌡: \(String())℃"smartCitizenData.data?.sensors?[10].value ?? 0 + self.smartCitizenTemperature.title = "🌡: \(String(smartCitizenData.data?.sensors?[10].value ?? 0))℃" self.smartCitizenHumidity.title = "💧: \(String(smartCitizenData.data?.sensors?[9].value ?? 0))%" diff --git a/Miasma/ViewController.swift b/Miasma/ViewController.swift index af10900..b7df815 100644 --- a/Miasma/ViewController.swift +++ b/Miasma/ViewController.swift @@ -389,6 +389,21 @@ @IBOutlet weak var ClimaCellButtonOutlet: NSButton! + @IBAction func RefreshIntervalButtonAction(_ sender: Any) { + if RefreshIntervalButtonOutlet.state == NSControl.StateValue.off { + AppDelegate().defaults.set(1200.0, forKey: "RefreshIntervalSeconds") + ClimaCellButtonOutlet.isEnabled.self = true + } + if RefreshIntervalButtonOutlet.state == NSControl.StateValue.on { + AppDelegate().defaults.set(600.0, forKey: "RefreshIntervalSeconds") + AppDelegate().defaults.set(false, forKey: "ClimaCellInUse") + ClimaCellButtonOutlet.isEnabled.self = false + ClimaCellButtonOutlet.state.self = NSControl.StateValue.off + + } + } + + @IBOutlet weak var RefreshIntervalButtonOutlet: NSButton! @IBOutlet weak var autoRunAtStartup: NSButton! @@ -540,6 +555,12 @@ ClimaCellButtonOutlet.state = AppDelegate().defaults.object(forKey:"ClimaCellInUse") as? NSControl.StateValue ?? NSControl.StateValue(0) + if AppDelegate().defaults.double(forKey:"RefreshIntervalSeconds") == 600.0{ + RefreshIntervalButtonOutlet.state.self = NSControl.StateValue(rawValue: 1) + ClimaCellButtonOutlet.isEnabled.self = false + } + + if AppDelegate().defaults.integer(forKey:"PurpleAirInUse") == 1{ PurpleAirRadioOutlet.state.self = NSControl.StateValue(rawValue: 1) }