diff --git a/PurpleMenu.xcodeproj/project.pbxproj b/PurpleMenu.xcodeproj/project.pbxproj index f19085a..1ded75a 100644 --- a/PurpleMenu.xcodeproj/project.pbxproj +++ b/PurpleMenu.xcodeproj/project.pbxproj @@ -13,7 +13,6 @@ 3726C1D4252CEEAB00B0B216 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3726C1D3252CEEAB00B0B216 /* Preview Assets.xcassets */; }; 3726C1D7252CEEAB00B0B216 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3726C1D5252CEEAB00B0B216 /* Main.storyboard */; }; 3726C1E1252CF33000B0B216 /* Sensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3726C1E0252CF33000B0B216 /* Sensor.swift */; }; - 3726C1E4252CF44600B0B216 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3726C1E3252CF44600B0B216 /* Result.swift */; }; 3726C1E7252CF4CE00B0B216 /* PurpleAirApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3726C1E6252CF4CE00B0B216 /* PurpleAirApi.swift */; }; 3748D18D252D505200A758D6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3748D18C252D505200A758D6 /* AppDelegate.swift */; }; 3748D191252D505300A758D6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3748D190252D505300A758D6 /* Assets.xcassets */; }; @@ -48,7 +47,6 @@ 3726C1D8252CEEAB00B0B216 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 3726C1D9252CEEAB00B0B216 /* PurpleMenu.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = PurpleMenu.entitlements; sourceTree = ""; }; 3726C1E0252CF33000B0B216 /* Sensor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sensor.swift; sourceTree = ""; }; - 3726C1E3252CF44600B0B216 /* Result.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Result.swift; sourceTree = ""; }; 3726C1E6252CF4CE00B0B216 /* PurpleAirApi.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = PurpleAirApi.swift; sourceTree = ""; tabWidth = 4; wrapsLines = 0; }; 3748D18A252D505200A758D6 /* LauncherApplication.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LauncherApplication.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3748D18C252D505200A758D6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -113,7 +111,6 @@ 3726C1D9252CEEAB00B0B216 /* PurpleMenu.entitlements */, 3726C1D2252CEEAB00B0B216 /* Preview Content */, 3726C1E0252CF33000B0B216 /* Sensor.swift */, - 3726C1E3252CF44600B0B216 /* Result.swift */, 3726C1E6252CF4CE00B0B216 /* PurpleAirApi.swift */, 37A3C07E252FB74400C2D12C /* SensorViewModel.swift */, 37A3C082252FCCA700C2D12C /* UserDefaultsExtension.swift */, @@ -263,7 +260,6 @@ 3726C1CF252CEEA900B0B216 /* ContentView.swift in Sources */, 3726C1E1252CF33000B0B216 /* Sensor.swift in Sources */, 3726C1E7252CF4CE00B0B216 /* PurpleAirApi.swift in Sources */, - 3726C1E4252CF44600B0B216 /* Result.swift in Sources */, 37A3C07F252FB74400C2D12C /* SensorViewModel.swift in Sources */, 37A3C083252FCCA700C2D12C /* UserDefaultsExtension.swift in Sources */, 3726C1CD252CEEA900B0B216 /* AppDelegate.swift in Sources */, @@ -426,7 +422,7 @@ COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"PurpleMenu/Preview Content\""; - DEVELOPMENT_TEAM = BVZF7TL777; + DEVELOPMENT_TEAM = SV8J3E48E9; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = PurpleMenu/Info.plist; @@ -453,7 +449,7 @@ COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"PurpleMenu/Preview Content\""; - DEVELOPMENT_TEAM = BVZF7TL777; + DEVELOPMENT_TEAM = SV8J3E48E9; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = PurpleMenu/Info.plist; @@ -481,7 +477,7 @@ COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"LauncherApplication/Preview Content\""; - DEVELOPMENT_TEAM = BVZF7TL777; + DEVELOPMENT_TEAM = SV8J3E48E9; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = LauncherApplication/Info.plist; @@ -510,7 +506,7 @@ COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"LauncherApplication/Preview Content\""; - DEVELOPMENT_TEAM = BVZF7TL777; + DEVELOPMENT_TEAM = SV8J3E48E9; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = LauncherApplication/Info.plist; diff --git a/PurpleMenu/AppDelegate.swift b/PurpleMenu/AppDelegate.swift index 274f197..6863c8c 100644 --- a/PurpleMenu/AppDelegate.swift +++ b/PurpleMenu/AppDelegate.swift @@ -81,19 +81,17 @@ class AppDelegate: NSObject, NSApplicationDelegate { } func refreshAqi() { - PurpleAirApi(sensorId: UserDefaults.standard.sensorId, apiKey: UserDefaults.standard.apiKey).getData { (sensor) in - guard let result = sensor.results?.first, - let resultB = sensor.results?.last, - let pm25Str = result.pM2_5Value, - let pm25 = Float(pm25Str), - let pm25Cf1Str = result.pm2_5_cf_1, - let pm25Cf1 = Float(pm25Cf1Str), - let pm25Cf1StrB = resultB.pm2_5_cf_1, - let pm25Cf1B = Float(pm25Cf1StrB), - let humidityStr = result.humidity, - let humidity = Float(humidityStr) + PurpleAirApi(sensorId: UserDefaults.standard.sensorId, apiKey: UserDefaults.standard.apiKey).getData { (sensors) in + guard let sensor = sensors.sensor, + let pm25D = sensor.pm25, + let pm25Cf1D = sensor.pm25_CF1, + let humidityD = sensor.humidity else { return } + let pm25 = Float(pm25D) + let pm25Cf1 = Float(pm25Cf1D) + let humidity = Float(humidityD) + debugPrint("id = \(self.sensorViewModel.sensorId), conversion = \(UserDefaults.standard.conversion), pm25 = \(pm25), pm25Cf1 = \(pm25Cf1), RH = \(humidity)") let aqi: Int @@ -102,13 +100,13 @@ class AppDelegate: NSObject, NSApplicationDelegate { case .none: aqi = self.pmToAQI(pm25) case .epa: - aqi = self.pmToEPA(paCf1: (pm25Cf1 + pm25Cf1B) * 0.5, humidity: humidity) + aqi = self.pmToEPA(paCf1: pm25Cf1, humidity: humidity) case .aqandu: aqi = self.pmToAQandU(pm: pm25) case .lrapa: aqi = self.pmToLRAPA(paCf1: pm25Cf1) case .woodsmoke: - aqi = self.pmToWoodsmoke(pm25Cf1: (pm25Cf1 + pm25Cf1B) * 0.5) + aqi = self.pmToWoodsmoke(pm25Cf1: pm25Cf1) } DispatchQueue.main.async { diff --git a/PurpleMenu/PurpleAirApi.swift b/PurpleMenu/PurpleAirApi.swift index 35e773e..967b6f8 100644 --- a/PurpleMenu/PurpleAirApi.swift +++ b/PurpleMenu/PurpleAirApi.swift @@ -16,7 +16,7 @@ class PurpleAirApi { self.apiKey = apiKey } - func getData(completionHandler: @escaping (Sensor) -> ()) { + func getData(completionHandler: @escaping (Sensors) -> ()) { guard let url = URL(string: urlString) else { return } var request = URLRequest(url: url) @@ -29,8 +29,8 @@ class PurpleAirApi { let decoder = JSONDecoder() do { - let sensor = try decoder.decode(Sensor.self, from: data) - completionHandler(sensor) + let sensors = try decoder.decode(Sensors.self, from: data) + completionHandler(sensors) } catch { debugPrint("error decoding response") } diff --git a/PurpleMenu/Result.swift b/PurpleMenu/Result.swift deleted file mode 100644 index ed523c7..0000000 --- a/PurpleMenu/Result.swift +++ /dev/null @@ -1,139 +0,0 @@ -// -// Result.swift -// PurpleMenu -// -// Created by Andrew Ng on 10/6/20. -// - -import Foundation - -struct Result : Codable { - let iD : Int? - let label : String? - let dEVICE_LOCATIONTYPE : String? - let tHINGSPEAK_PRIMARY_ID : String? - let tHINGSPEAK_PRIMARY_ID_READ_KEY : String? - let tHINGSPEAK_SECONDARY_ID : String? - let tHINGSPEAK_SECONDARY_ID_READ_KEY : String? - let lat : Double? - let lon : Double? - let pM2_5Value : String? - let lastSeen : Int? - let type : String? - let hidden : String? - let dEVICE_BRIGHTNESS : String? - let dEVICE_HARDWAREDISCOVERED : String? - let dEVICE_FIRMWAREVERSION : String? - let version : String? - let lastUpdateCheck : Int? - let created : Int? - let uptime : String? - let rSSI : String? - let adc : String? - let p_0_3_um : String? - let p_0_5_um : String? - let p_1_0_um : String? - let p_2_5_um : String? - let p_5_0_um : String? - let p_10_0_um : String? - let pm1_0_cf_1 : String? - let pm2_5_cf_1 : String? - let pm10_0_cf_1 : String? - let pm1_0_atm : String? - let pm2_5_atm : String? - let pm10_0_atm : String? - let isOwner : Int? - let humidity : String? - let temp_f : String? - let pressure : String? - let aGE : Int? - let stats : String? - - enum CodingKeys: String, CodingKey { - case iD = "ID" - case label = "Label" - case dEVICE_LOCATIONTYPE = "DEVICE_LOCATIONTYPE" - case tHINGSPEAK_PRIMARY_ID = "THINGSPEAK_PRIMARY_ID" - case tHINGSPEAK_PRIMARY_ID_READ_KEY = "THINGSPEAK_PRIMARY_ID_READ_KEY" - case tHINGSPEAK_SECONDARY_ID = "THINGSPEAK_SECONDARY_ID" - case tHINGSPEAK_SECONDARY_ID_READ_KEY = "THINGSPEAK_SECONDARY_ID_READ_KEY" - case lat = "Lat" - case lon = "Lon" - case pM2_5Value = "PM2_5Value" - case lastSeen = "LastSeen" - case type = "Type" - case hidden = "Hidden" - case dEVICE_BRIGHTNESS = "DEVICE_BRIGHTNESS" - case dEVICE_HARDWAREDISCOVERED = "DEVICE_HARDWAREDISCOVERED" - case dEVICE_FIRMWAREVERSION = "DEVICE_FIRMWAREVERSION" - case version = "Version" - case lastUpdateCheck = "LastUpdateCheck" - case created = "Created" - case uptime = "Uptime" - case rSSI = "RSSI" - case adc = "Adc" - case p_0_3_um = "p_0_3_um" - case p_0_5_um = "p_0_5_um" - case p_1_0_um = "p_1_0_um" - case p_2_5_um = "p_2_5_um" - case p_5_0_um = "p_5_0_um" - case p_10_0_um = "p_10_0_um" - case pm1_0_cf_1 = "pm1_0_cf_1" - case pm2_5_cf_1 = "pm2_5_cf_1" - case pm10_0_cf_1 = "pm10_0_cf_1" - case pm1_0_atm = "pm1_0_atm" - case pm2_5_atm = "pm2_5_atm" - case pm10_0_atm = "pm10_0_atm" - case isOwner = "isOwner" - case humidity = "humidity" - case temp_f = "temp_f" - case pressure = "pressure" - case aGE = "AGE" - case stats = "Stats" - } - - init(from decoder: Decoder) throws { - let values = try decoder.container(keyedBy: CodingKeys.self) - iD = try values.decodeIfPresent(Int.self, forKey: .iD) - label = try values.decodeIfPresent(String.self, forKey: .label) - dEVICE_LOCATIONTYPE = try values.decodeIfPresent(String.self, forKey: .dEVICE_LOCATIONTYPE) - tHINGSPEAK_PRIMARY_ID = try values.decodeIfPresent(String.self, forKey: .tHINGSPEAK_PRIMARY_ID) - tHINGSPEAK_PRIMARY_ID_READ_KEY = try values.decodeIfPresent(String.self, forKey: .tHINGSPEAK_PRIMARY_ID_READ_KEY) - tHINGSPEAK_SECONDARY_ID = try values.decodeIfPresent(String.self, forKey: .tHINGSPEAK_SECONDARY_ID) - tHINGSPEAK_SECONDARY_ID_READ_KEY = try values.decodeIfPresent(String.self, forKey: .tHINGSPEAK_SECONDARY_ID_READ_KEY) - lat = try values.decodeIfPresent(Double.self, forKey: .lat) - lon = try values.decodeIfPresent(Double.self, forKey: .lon) - pM2_5Value = try values.decodeIfPresent(String.self, forKey: .pM2_5Value) - lastSeen = try values.decodeIfPresent(Int.self, forKey: .lastSeen) - type = try values.decodeIfPresent(String.self, forKey: .type) - hidden = try values.decodeIfPresent(String.self, forKey: .hidden) - dEVICE_BRIGHTNESS = try values.decodeIfPresent(String.self, forKey: .dEVICE_BRIGHTNESS) - dEVICE_HARDWAREDISCOVERED = try values.decodeIfPresent(String.self, forKey: .dEVICE_HARDWAREDISCOVERED) - dEVICE_FIRMWAREVERSION = try values.decodeIfPresent(String.self, forKey: .dEVICE_FIRMWAREVERSION) - version = try values.decodeIfPresent(String.self, forKey: .version) - lastUpdateCheck = try values.decodeIfPresent(Int.self, forKey: .lastUpdateCheck) - created = try values.decodeIfPresent(Int.self, forKey: .created) - uptime = try values.decodeIfPresent(String.self, forKey: .uptime) - rSSI = try values.decodeIfPresent(String.self, forKey: .rSSI) - adc = try values.decodeIfPresent(String.self, forKey: .adc) - p_0_3_um = try values.decodeIfPresent(String.self, forKey: .p_0_3_um) - p_0_5_um = try values.decodeIfPresent(String.self, forKey: .p_0_5_um) - p_1_0_um = try values.decodeIfPresent(String.self, forKey: .p_1_0_um) - p_2_5_um = try values.decodeIfPresent(String.self, forKey: .p_2_5_um) - p_5_0_um = try values.decodeIfPresent(String.self, forKey: .p_5_0_um) - p_10_0_um = try values.decodeIfPresent(String.self, forKey: .p_10_0_um) - pm1_0_cf_1 = try values.decodeIfPresent(String.self, forKey: .pm1_0_cf_1) - pm2_5_cf_1 = try values.decodeIfPresent(String.self, forKey: .pm2_5_cf_1) - pm10_0_cf_1 = try values.decodeIfPresent(String.self, forKey: .pm10_0_cf_1) - pm1_0_atm = try values.decodeIfPresent(String.self, forKey: .pm1_0_atm) - pm2_5_atm = try values.decodeIfPresent(String.self, forKey: .pm2_5_atm) - pm10_0_atm = try values.decodeIfPresent(String.self, forKey: .pm10_0_atm) - isOwner = try values.decodeIfPresent(Int.self, forKey: .isOwner) - humidity = try values.decodeIfPresent(String.self, forKey: .humidity) - temp_f = try values.decodeIfPresent(String.self, forKey: .temp_f) - pressure = try values.decodeIfPresent(String.self, forKey: .pressure) - aGE = try values.decodeIfPresent(Int.self, forKey: .aGE) - stats = try values.decodeIfPresent(String.self, forKey: .stats) - } - -} diff --git a/PurpleMenu/Sensor.swift b/PurpleMenu/Sensor.swift index 6326bd9..818e0db 100644 --- a/PurpleMenu/Sensor.swift +++ b/PurpleMenu/Sensor.swift @@ -16,24 +16,160 @@ enum Conversion: String, CaseIterable, Identifiable { } } -struct Sensor: Codable { - let mapVersion : String? - let baseVersion : String? - let mapVersionString : String? - let results : [Result]? +// MARK: - Sensors +struct Sensors: Codable { + let apiVersion: String? + let timeStamp, dataTimeStamp: Int? + let sensor: Sensor? enum CodingKeys: String, CodingKey { - case mapVersion = "mapVersion" - case baseVersion = "baseVersion" - case mapVersionString = "mapVersionString" - case results = "results" + case apiVersion = "api_version" + case timeStamp = "time_stamp" + case dataTimeStamp = "data_time_stamp" + case sensor } +} - init(from decoder: Decoder) throws { - let values = try decoder.container(keyedBy: CodingKeys.self) - mapVersion = try values.decodeIfPresent(String.self, forKey: .mapVersion) - baseVersion = try values.decodeIfPresent(String.self, forKey: .baseVersion) - mapVersionString = try values.decodeIfPresent(String.self, forKey: .mapVersionString) - results = try values.decodeIfPresent([Result].self, forKey: .results) +// MARK: - Sensor +struct Sensor: Codable { + let sensorIndex, lastModified, dateCreated, lastSeen: Int? + let sensorPrivate, isOwner: Int? + let name: String? + let icon, locationType: Int? + let model, hardware: String? + let ledBrightness: Int? + let firmwareVersion, firmwareUpgrade: String? + let rssi, uptime, paLatency, memory: Int? + let positionRating: Int? + let latitude, longitude: Double? + let altitude, channelState, channelFlags, channelFlagsManual: Int? + let channelFlagsAuto, confidence, confidenceAuto, confidenceManual: Int? + let humidity, humidityA, temperature, temperatureA: Int? + let pressure, pressureA, analogInput, pm10: Double? + let pm10_A, pm10_B, pm25, pm25_A: Double? + let pm25_B, pm25_Alt, pm25_AltA, pm25_AltB: Double? + let pm100, pm100_A, pm100_B, scatteringCoefficient: Double? + let scatteringCoefficientA, scatteringCoefficientB, deciviews, deciviewsA: Double? + let deciviewsB, visualRange, visualRangeA, visualRangeB: Double? + let the03_UmCount, the03_UmCountA, the03_UmCountB, the05_UmCount: Int? + let the05_UmCountA, the05_UmCountB, the10_UmCount, the10_UmCountA: Int? + let the10_UmCountB, the25_UmCount, the25_UmCountA, the25_UmCountB: Int? + let the50_UmCount, the50_UmCountA, the50_UmCountB, the100_UmCount: Int? + let the100_UmCountA, the100_UmCountB: Int? + let pm10_CF1, pm10_CF1_A, pm10_CF1_B, pm10_ATM: Double? + let pm10_ATMA, pm10_ATMB, pm25_ATM, pm25_ATMA: Double? + let pm25_ATMB, pm25_CF1, pm25_CF1_A, pm25_CF1_B: Double? + let pm100_ATM, pm100_ATMA, pm100_ATMB, pm100_CF1: Double? + let pm100_CF1_A, pm100_CF1_B: Double? + let primaryIDA: Int? + let primaryKeyA: String? + let primaryIDB: Int? + let primaryKeyB: String? + let secondaryIDA: Int? + let secondaryKeyA: String? + let secondaryIDB: Int? + let secondaryKeyB: String? + let stats, statsA, statsB: [String: Double]? + + enum CodingKeys: String, CodingKey { + case sensorIndex = "sensor_index" + case lastModified = "last_modified" + case dateCreated = "date_created" + case lastSeen = "last_seen" + case sensorPrivate = "private" + case isOwner = "is_owner" + case name, icon + case locationType = "location_type" + case model, hardware + case ledBrightness = "led_brightness" + case firmwareVersion = "firmware_version" + case firmwareUpgrade = "firmware_upgrade" + case rssi, uptime + case paLatency = "pa_latency" + case memory + case positionRating = "position_rating" + case latitude, longitude, altitude + case channelState = "channel_state" + case channelFlags = "channel_flags" + case channelFlagsManual = "channel_flags_manual" + case channelFlagsAuto = "channel_flags_auto" + case confidence + case confidenceAuto = "confidence_auto" + case confidenceManual = "confidence_manual" + case humidity + case humidityA = "humidity_a" + case temperature + case temperatureA = "temperature_a" + case pressure + case pressureA = "pressure_a" + case analogInput = "analog_input" + case pm10 = "pm1.0" + case pm10_A = "pm1.0_a" + case pm10_B = "pm1.0_b" + case pm25 = "pm2.5" + case pm25_A = "pm2.5_a" + case pm25_B = "pm2.5_b" + case pm25_Alt = "pm2.5_alt" + case pm25_AltA = "pm2.5_alt_a" + case pm25_AltB = "pm2.5_alt_b" + case pm100 = "pm10.0" + case pm100_A = "pm10.0_a" + case pm100_B = "pm10.0_b" + case scatteringCoefficient = "scattering_coefficient" + case scatteringCoefficientA = "scattering_coefficient_a" + case scatteringCoefficientB = "scattering_coefficient_b" + case deciviews + case deciviewsA = "deciviews_a" + case deciviewsB = "deciviews_b" + case visualRange = "visual_range" + case visualRangeA = "visual_range_a" + case visualRangeB = "visual_range_b" + case the03_UmCount = "0.3_um_count" + case the03_UmCountA = "0.3_um_count_a" + case the03_UmCountB = "0.3_um_count_b" + case the05_UmCount = "0.5_um_count" + case the05_UmCountA = "0.5_um_count_a" + case the05_UmCountB = "0.5_um_count_b" + case the10_UmCount = "1.0_um_count" + case the10_UmCountA = "1.0_um_count_a" + case the10_UmCountB = "1.0_um_count_b" + case the25_UmCount = "2.5_um_count" + case the25_UmCountA = "2.5_um_count_a" + case the25_UmCountB = "2.5_um_count_b" + case the50_UmCount = "5.0_um_count" + case the50_UmCountA = "5.0_um_count_a" + case the50_UmCountB = "5.0_um_count_b" + case the100_UmCount = "10.0_um_count" + case the100_UmCountA = "10.0_um_count_a" + case the100_UmCountB = "10.0_um_count_b" + case pm10_CF1 = "pm1.0_cf_1" + case pm10_CF1_A = "pm1.0_cf_1_a" + case pm10_CF1_B = "pm1.0_cf_1_b" + case pm10_ATM = "pm1.0_atm" + case pm10_ATMA = "pm1.0_atm_a" + case pm10_ATMB = "pm1.0_atm_b" + case pm25_ATM = "pm2.5_atm" + case pm25_ATMA = "pm2.5_atm_a" + case pm25_ATMB = "pm2.5_atm_b" + case pm25_CF1 = "pm2.5_cf_1" + case pm25_CF1_A = "pm2.5_cf_1_a" + case pm25_CF1_B = "pm2.5_cf_1_b" + case pm100_ATM = "pm10.0_atm" + case pm100_ATMA = "pm10.0_atm_a" + case pm100_ATMB = "pm10.0_atm_b" + case pm100_CF1 = "pm10.0_cf_1" + case pm100_CF1_A = "pm10.0_cf_1_a" + case pm100_CF1_B = "pm10.0_cf_1_b" + case primaryIDA = "primary_id_a" + case primaryKeyA = "primary_key_a" + case primaryIDB = "primary_id_b" + case primaryKeyB = "primary_key_b" + case secondaryIDA = "secondary_id_a" + case secondaryKeyA = "secondary_key_a" + case secondaryIDB = "secondary_id_b" + case secondaryKeyB = "secondary_key_b" + case stats + case statsA = "stats_a" + case statsB = "stats_b" } }