jungwonhyuk / obd2-iOS-OBD-Example-App

Boilerplate App for reading and translating OBD data

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

SwiftyOBD


Content

  1. Intro
  2. Checklist to run the Example App
    1. Install Cocoapods dependencies
    2. Devices and setup used in this project
    3. Get access to the Car Diagnostic API
    4. Setting client credentials
  3. SwiftyOBD Usage
    1. Define an OBDStreamManager and an OBDAPIManager
    2. Connect and Setup
    3. Ask for DTCs
  4. Sending and Parsing Data
  5. About SwiftyOBD

Intro

SwiftyOBD is a boilerplate for an iOS App written in Swift that shows you how to establish a connection between smartphone and an ELM327 OBD WIFI dongle. It reads data out from the dongle and uses the Car Diagnostic API from Hella Ventures to translate the error codes stored in the vehicle.

CocoaPods was used to manage third party libraries in this project. More info about installation and how to use at https://cocoapods.org.

How to run the Example App

a) Install Cocoapods dependencies

In order to run the example project, you will need to install the Cocoapods dependencies specifed in the Podfile. All you need to do is go into the project folder and run pod install using the terminal.

b) Devices and setup used in this project

We used the Diamex OBD2 Profi Simulator and the Veepeak WiFi OBD2 Scanner for iPhone for the test and development of this example project.

We also selected the protocol 7: ISO 15765-4 CAN (29 bit ID,500 Kbaud) on the Diamex Simulator for this simple example (just in cased we missed something). This is important, since the format of the responses coming from the dongle may differ according to the selected protocol and therefore need to be parsed differently. However, all other protocols that are supported by this dongle are also supported by this App.

You can of course also plug the OBD2 Dongle into your vehicle to test the application. But you would normaly expect not to find any error codes in your vehicle :). But in any case, the App should be able to connect to the OBD2 port and send and receive data.

Note: Before testing anything you will need to make sure that your device is properly connected to the OBD Dongle. The standard setup goes usually as following:

  1. Plug the OBD Dongle into the OBD2 port on your vehicle (or OBD2 Simulator).
  1. Turn ignition key to the ON position (or turn the OBD2 Simulator on).
  1. Enable WiFI on your device, find the WiFI SSID (e.g. WiFi_OBDII) of your dongle and connect to it.
  1. Go to the WiFI settings, select Static IP Address and enter the following information: IP 192.168.0.10, Subnet Mask 255.255.255.0, and Gateway 192.168.0.10. By doing this step you can use your mobile data. We will need this if we want to get data from the OBD API

c) Get access to the Car Diagnostic API

You will need a client ID and a client secret to be able to make API calls and get data from the Hella Ventures OBD API:

Follow the Getting Started Guide to get access to the Car Diagnostic API.

d) Setup your client credentials

Open the AppDelegate.swift file and set the apiManager's credentials in the application...didFinishLaunching...-function as follows:

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
 
        // SETUP the API Manager
        apiManager.client_id = "<<Your API client_id>>" // TODO
        apiManager.client_secret = "<<Your API client_secret>>" // TODO
        
        ...

e) Run the App

You are ready to go!

SwiftyOBD Usage

First, import the files from the SwiftyOBD folder of this repo into your project. If you want to read data out of the OBD Dongle using SwiftyOBD just follow the steps below:

1) Define an OBDStreamManager and an OBDAPIManager


Define a global instance of the OBDStreamManager and OBDAPIManager in the AppDelegate.swift right before the beginning of the AppDelegate class. The OBDStreamManager takes care of the connection, input- and outputStream between your App and the OBD WiFI dongle. And the OBDAPIManager helps to storage information related to the Car Diagnostic API. Get an instance of them by calling:

let streamManager = OBDStreamManager.sharedInstance
let apiManager = OBDAPIManager.sharedInstance

You will also need to get and setup your client credentials as explained above (Setup your client credentials) in order to use the Car Diagnostic API.

2) Connect to the WiFI and Setup the OBD Dongle


The next step is to connect to the dongle using the connect() method. You will need to provide an instance of OBDConnection as parameter or you can also leave it blank to use the default OBDConnection that has host "192.168.0.10" and port 35000 as default properties. However, you may want to check if a connection is already opened and close it before opening a new one. So just to be sure you can call the disconnect() method before.

streamManager.disconnect()
streamManager.connect() // or streamManager.connect(OBDConnection(host: "192.168.0.10", port: 35000))

Or you could use instead the startStreaming method which does both for you at once.

streamManager.startStreaming() // or streamManager.startStreaming(OBDConnection(host: "192.168.0.10", port: 35000))

The following step is to call the setupAdapter() method which is used determine which protocol is used by the Vehicle OBD2 port. You will need to call this in a separate Thread in order to run properly. An example of a basic Connect and Setup ViewController could look as following:

class ViewController: UIViewController, OBDStreamManagerDelegate {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        obdStreamManager.delegate = self
        obdStreamManager.startStreaming()
        Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.timedTunc), userInfo: nil, repeats: false)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    func timedTunc(){
        obdStreamManager.setupAdapter()
    }
    
    func setupProgress(_ progress: Double) {
        print(progress)
        
        //If progress is 100 then I know that the setup is finished and do something.
    }
}

If you implement the setupProgress() callback method from the OBDStreamManagerDelegate protocol you can have an idea of how far the setup is from finishing.

3) Ask for DTCs


Once the stream is opened and the setup is done we can use the requestDTCs() method of the stream manager to get the error codes. However, since the manager is sending data to the OBD2 Dongle in the background and the response may come with some delay you will need to implement the DTCsUpdated() callback method from the OBDStreamManagerDelegate protocol which passes the error codes back as parameter.

class ResultsTableViewController: UIViewController, OBDStreamManagerDelegate{
    
    var dtcsArray: [String] = []
    
    override func viewDidLoad() {
        streamManager.delegate = self
        super.viewDidLoad()
        
        streamManager.requestDTCs()
    }

    // MARK: OBD STREAM MANAGER PROTOCOL IMPLEMENTATION
    func DTCsUpdated(_ newDTCs: [String], dtcs: Int) {
        self.dtcsArray = newDTCs
        
        if(newDTCs.count == dtcs){
            Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.timedFunc), userInfo: nil, repeats: false)
        }
    }
    
    func timedFunc(){
        self.error = false
        if dtcsArray.count > 0 {
            for i in 0...dtcsArray.count-1 {
                makeAPIRequest(i)
            }
        }
    }
    
    func makeAPIRequest(_ errorCodeNumber: Int){
        
        let parameters = [
            "code_id":dtcsArray[errorCodeNumber],
            "vin":apiManager.vin,
            "language":apiManager.language,
            "client_secret":apiManager.client_secret,
            "client_id": apiManager.client_id
        ]
        
        Alamofire.request(apiManager.api_address, parameters: parameters).responseJSON { response in
                
            if let responseJSON = response.result.value {
                let swiftyJSONObject = JSON(responseJSON)
                let dtcObject = OBDDTC.parseFronJSON(swiftyJSONObject, withDTC: self.dtcsArray[errorCodeNumber])
                
                if let uDTCObject = dtcObject {
                    print("Translated DTC using API ")
                }
            }else{
                print("JSON is nil")
            }
        }
    }
}

Sending and Parsing Data

If you want to know more about requesting and parsing data, you might want to take a look at the speficifications of the ELM327 module (ELM327 Specs). If you take for example a look at the specifications (page 34) you can find information about how to interprete trouble codes and also other things.

Feel free to take a look at the OBDParser and OBDStreamManager classes where you can find how I implemented the parsing and data sending part and improve it if you want.

About SwiftyOBD

This example App uses dependencies based on the work of the following GitHub contributors.

  • Alamofire: Elegant HTTP Networking in Swift.
  • SwiftyJSON: The better were to deal with JSON data in Swift.
  • Eureka: Elegant iOS form builder in Swift 3.
  • XCGLogger: A debug log framework for use in Swift projects.
  • DZNEmptyDataSet: A drop-in UITableView/UICollectionView superclass category for showing empty datasets whenever the view has no content to display.
  • iOS CircleProgressView: This control will allow a user to use code instantiated or interface builder to create and render a circle progress view.

About

Boilerplate App for reading and translating OBD data

License:Other


Languages

Language:Swift 98.3%Language:Ruby 1.7%