From 74a8870f43547e8e1b1c2b1ec6affd7276f2fb3c Mon Sep 17 00:00:00 2001 From: Justin Beharry Date: Fri, 29 Jul 2022 14:46:27 -0400 Subject: Create submenu item to view remote climate settings --- Example Apps/Example Swift/MenuManager.swift | 33 ++++-- RemoteControlManager.swift | 155 ++++++++++++++++++++------- 2 files changed, 141 insertions(+), 47 deletions(-) diff --git a/Example Apps/Example Swift/MenuManager.swift b/Example Apps/Example Swift/MenuManager.swift index 943b9bc8b..1620efd97 100644 --- a/Example Apps/Example Swift/MenuManager.swift +++ b/Example Apps/Example Swift/MenuManager.swift @@ -213,32 +213,43 @@ private extension MenuManager { /// - Parameter manager: The SDL Manager /// - Returns: A SDLMenuCell object class func menuCellRemoteControl(with manager: SDLManager) -> SDLMenuCell { + + /// Initialize Remote Control Manager + let remoteControlManager = RemoteControlManager(sdlManager: manager) /// Lets give an example of 2 templates var submenuItems = [SDLMenuCell]() let errorMessage = "Changing the template failed" /// Climate Control Menu - let submenuTitleNonMedia = "Climate Control" - submenuItems.append(SDLMenuCell(title: submenuTitleNonMedia, secondaryText: nil, tertiaryText: nil, icon: nil, secondaryArtwork: nil, voiceCommands: nil, handler: { (triggerSource) in - manager.screenManager.changeLayout(SDLTemplateConfiguration(predefinedLayout: .nonMedia)) { err in + let submenuTitleControl = "Climate Control" + submenuItems.append(SDLMenuCell(title: submenuTitleControl, secondaryText: nil, tertiaryText: nil, icon: nil, secondaryArtwork: nil, voiceCommands: nil, handler: { (triggerSource) in + manager.screenManager.changeLayout(SDLTemplateConfiguration(predefinedLayout: .tilesOnly)) { err in if err != nil { AlertManager.sendAlert(textField1: errorMessage, sdlManager: manager) return } - RemoteControlManager(sdlManager: manager) + remoteControlManager.showClimateControl() } })) - /// Graphic with Text - let submenuTitleGraphicText = "Radio Control" - submenuItems.append(SDLMenuCell(title: submenuTitleGraphicText, secondaryText: nil, tertiaryText: nil, icon: nil, secondaryArtwork: nil, voiceCommands: nil, handler: { (triggerSource) in - manager.screenManager.changeLayout(SDLTemplateConfiguration(predefinedLayout: .graphicWithText)) { err in - if err != nil { - AlertManager.sendAlert(textField1: errorMessage, sdlManager: manager) + /// View Climate Data + let submenuTitleView = "View Climate" + submenuItems.append(SDLMenuCell(title: submenuTitleView, secondaryText: nil, tertiaryText: nil, icon: nil, secondaryArtwork: nil, voiceCommands: nil, handler: { _ in + let climateDataMessage = SDLScrollableMessage(message: remoteControlManager.getClimateData()) + manager.send(request: climateDataMessage, responseHandler: { (request, response, error) in + guard let response = response else { return } + guard response.resultCode == .success else { + if response.resultCode == .timedOut { + AlertManager.sendAlert(textField1: AlertScrollableMessageTimedOutWarningText, sdlManager: manager) + } else if response.resultCode == .aborted { + AlertManager.sendAlert(textField1: AlertScrollableMessageCancelledWarningText, sdlManager: manager) + } else { + AlertManager.sendAlert(textField1: AlertScrollableMessageGeneralWarningText, sdlManager: manager) + } return } - } + }) })) return SDLMenuCell(title: "Remote Control", secondaryText: nil, tertiaryText: nil, icon: nil, secondaryArtwork: nil, submenuLayout: .list, subCells: submenuItems) diff --git a/RemoteControlManager.swift b/RemoteControlManager.swift index 6b11ce87a..9b2d70897 100644 --- a/RemoteControlManager.swift +++ b/RemoteControlManager.swift @@ -14,8 +14,11 @@ class RemoteControlManager { private var remoteControlCapabilities: SDLRemoteControlCapabilities! private var climateModuleId: String! private var consent: [Bool]! + private var climateData: SDLClimateControlData! - + /// Creates and returns the menu items + /// + /// - Parameter sdlManager: The SDL Manager init(sdlManager: SDLManager) { self.sdlManager = sdlManager /// Retrieve remote control information and store module ids @@ -23,13 +26,11 @@ class RemoteControlManager { guard capability?.remoteControlCapability != nil else { return } self.remoteControlCapabilities = capability?.remoteControlCapability - let firstClimateModule = self.remoteControlCapabilities.climateControlCapabilities?.first let moduleId = firstClimateModule?.moduleInfo?.moduleId self.climateModuleId = moduleId - print("Climate Control Module Id ------------------------------------------------------------------------- \(self.climateModuleId ?? "Missing")") - + /// Get Consent to control module let getInteriorVehicleDataConsent = SDLGetInteriorVehicleDataConsent(moduleType: .climate, moduleIds: [self.climateModuleId]) self.sdlManager.send(request: getInteriorVehicleDataConsent, responseHandler: { (request, response, error) in @@ -41,30 +42,99 @@ class RemoteControlManager { self.consent = boolAllowed - self.showClimateControl() + // initialize climate data and setup subscription + if self.consent[0] == true { + self.initializeClimateData() + self.subscribeVehicleData() + self.subscribeClimateControlData() + } + }) } } + /// Displays Buttons for the user to control the climate + func showClimateControl() { + /// Check that the climate module id has been set and consent has been given + if climateModuleId == nil && consent[0] == false { + AlertManager.sendAlert(textField1: "The climate module id was not set or consent was not given", sdlManager: self.sdlManager) + } + + let screenManager = self.sdlManager.screenManager + screenManager.beginUpdates() + + screenManager.softButtonObjects = climateButtons + + screenManager.endUpdates { error in + if error != nil { + // Print out the error if there is one and return early + print("Issue updating UI") + return + } + } + } + + /// Retrieve a formatted string containing climate data + /// + /// - Parameter manager: The SDL Manager + /// - Returns: A SDLVoiceCommand object + func getClimateData() -> String { + let climateString = """ + AC Enable \(climateData.acEnable!.boolValue ? "On" : "Off") + AC Max Enable \(climateData.acMaxEnable!.boolValue ? "On" : "Off") + Auto Mode Enable \(climateData.autoModeEnable!.boolValue ? "On": "Off") + Circulate Air Enable \(climateData.circulateAirEnable!.boolValue ? "On" : "Off") + Climate Enable \(climateData.climateEnable!.boolValue ? "On" : " Off") + Current Temperature \(climateData.currentTemperature?.description ?? "Nil") + Defrost Zone \(climateData.defrostZone?.rawValue.rawValue ?? "Nil") + Desired Temperature \(climateData.desiredTemperature?.description ?? "Nil") + Dual Mode Enable \(climateData.dualModeEnable!.boolValue ? "On" : "Off") + Fan Speed \(climateData.fanSpeed?.description ?? "Nil") + Heated Mirrors Enable \(climateData.heatedMirrorsEnable!.boolValue ? "On" : " Off") + Heated Rears Window Enable \(climateData.heatedRearWindowEnable!.boolValue ? "On" : " Off") + Heated Steering Enable \(climateData.heatedSteeringWheelEnable!.boolValue ? "On" : " Off") + Heated Windshield Enable \(climateData.heatedWindshieldEnable!.boolValue ? "On" : " Off") + Ventilation \(climateData.ventilationMode?.rawValue.rawValue ?? "Nil") + """ + return climateString + } + + private func initializeClimateData() { + /// Check that the climate module id has been set and consent has been given + if climateModuleId == nil && consent[0] == false { + AlertManager.sendAlert(textField1: "The climate module id was not set or consent was not given", sdlManager: self.sdlManager) + } + + let getInteriorVehicleData = SDLGetInteriorVehicleData(moduleType: .climate, moduleId: self.climateModuleId) + self.sdlManager.send(request: getInteriorVehicleData) { (req, res, err) in + guard let response = res as? SDLGetInteriorVehicleDataResponse else { return } + + self.climateData = response.moduleData?.climateControlData + } + } + private func subscribeVehicleData() { sdlManager.subscribe(to: .SDLDidReceiveInteriorVehicleData) { (message) in guard let onInteriorVehicleData = message as? SDLOnInteriorVehicleData else { return } - - print("Climate Data Changing") - print(onInteriorVehicleData.moduleData.climateControlData as Any) + + // This block will now be called whenever vehicle data changes + // NOTE: If you subscribe to multiple modules, all the data will be sent here. You will have to split it out based on `onInteriorVehicleData.moduleData.moduleType` yourself. + self.climateData = onInteriorVehicleData.moduleData.climateControlData + print("Is data changing") + print(self.climateData as Any) } } - private func subscribeClimateData() { - let getInteriorVehicleData = SDLGetInteriorVehicleData(andSubscribeToModuleType: .climate, moduleId: climateModuleId) - self.sdlManager.send(request: getInteriorVehicleData) { (req, res, err) in + private func subscribeClimateControlData() { + let getInteriorVehicleData = SDLGetInteriorVehicleData(andSubscribeToModuleType: .climate, moduleId: self.climateModuleId) + sdlManager.send(request: getInteriorVehicleData) { (req, res, err) in guard let response = res as? SDLGetInteriorVehicleDataResponse else { return } - + // This can now be used to retrieve data print(response) } } - func turnOnAC() { + private func turnOnAC() { let climateDictionary: [String: Any] = [ "acEnable": true as NSNumber & SDLBool ] @@ -78,7 +148,7 @@ class RemoteControlManager { } } - func turnOffAC() { + private func turnOffAC() { let climateDictionary: [String: Any] = [ "acEnable": false as NSNumber & SDLBool ] @@ -92,22 +162,27 @@ class RemoteControlManager { } } - func showClimateControl() { - let screenManager = self.sdlManager.screenManager - screenManager.beginUpdates() - - screenManager.textField1 = "Climate Control Data" - screenManager.textField2 = "Press Buttons" - screenManager.textField3 = "Remote Control" - - self.subscribeVehicleData() - self.subscribeClimateData() - + /// Changes multiple climate variables at once + private func setClimate() { + let climateDictionary: [String: Any] = [ + "acEnable": true as NSNumber & SDLBool, + "fanSpeed": NSNumber(100), + "desiredTemperature": SDLTemperature(fahrenheitValue: 73), + "ventilationMode": SDLVentilationMode(rawValue: SDLVentilationMode.both.rawValue) + ] - screenManager.changeLayout(SDLTemplateConfiguration(predefinedLayout: .nonMedia)) { err in - // This listener will be ignored, and will use the handler set in the endUpdates call. + + let climateControlData = SDLClimateControlData(dictionary: climateDictionary) + let moduleData = SDLModuleData(climateControlData: climateControlData) + let setInteriorVehicleData = SDLSetInteriorVehicleData(moduleData: moduleData) + + self.sdlManager.send(request: setInteriorVehicleData) { (request, response, error) in + guard response?.success.boolValue == true else { return } } - + } + + /// An array of button objects to control the climate + private var climateButtons : [SDLSoftButtonObject] { let acOnButton = SDLSoftButtonObject(name: "AC On", text: "AC On", artwork: nil) { (buttonPress, buttonEvent) in guard buttonPress != nil else { return } @@ -120,6 +195,16 @@ class RemoteControlManager { self.turnOffAC() } + let acMaxToggle = SDLSoftButtonObject(name: "AC Max", text: "AC Max", artwork: nil) { (buttonPress, buttonEvent) in + guard buttonPress != nil else { return } + + let buttonPress = SDLButtonPress(buttonName: .acMax, moduleType: .climate, moduleId: self.climateModuleId, buttonPressMode: .short) + + self.sdlManager.send(request: buttonPress) { (request, response, error) in + guard response?.success.boolValue == true else { return } + } + } + let temperatureDecreaseButton = SDLSoftButtonObject(name: "Temperature Decrease", text: "Temperature -", artwork: nil) { (buttonPress, buttonEvent) in guard buttonPress != nil else { return } @@ -140,14 +225,12 @@ class RemoteControlManager { } } - screenManager.softButtonObjects = [acOnButton, acOffButton, temperatureDecreaseButton, temperatureIncreaseButton] - - screenManager.endUpdates { error in - if error != nil { - // Print out the error if there is one and return early - print("Issue updating UI") - return - } + let setClimateButton = SDLSoftButtonObject(name: "Set Climate", text: "Set Climate", artwork: nil) { (buttonPress, buttonEvent) in + guard buttonPress != nil else { return } + + self.setClimate() } + + return [acOnButton, acOffButton, acMaxToggle, temperatureDecreaseButton, temperatureIncreaseButton, setClimateButton] } } -- cgit v1.2.1