LLLit: Изучение и практика программирования

Данные Swift 3 не отправляются на устройство Bluetooth из приложения iPhone

Я пытаюсь отправить данные с моего iPhone на устройство Bluetooth, подключенное к Arduino. Я знаю, что устройство Bluetooth работает нормально, потому что я использовал приложение nRF connect и отправлял данные оттуда в Bluetooth, который читал Arduino.

Я думаю, что то, как организовано мое приложение, создает некоторые проблемы. В настоящее время существует три контроллера представления.

Контроллер первого представления — это экран домашней страницы, на котором мало что есть. Вы можете подключить второй и третий контроллер просмотра с домашней страницы. Второй вью-контроллер — это экран подключения по блютусу. Третий вью-контроллер — это экран действий с кнопками.

Второй контроллер представления представляет собой табличное представление с возможностью сканирования для поиска доступных устройств Bluetooth. я использую этот код:

import UIKit
import CoreBluetooth

class ViewController: UIViewController, CBCentralManagerDelegate, UITableViewDataSource, UITableViewDelegate
{

//MARK: Variables
    //central manager
    var manager: CBCentralManager?

    //peripheral manager
    var peripheral: CBPeripheral?

    //HM-10 service code
    let HMServiceCode = CBUUID(string: "0xFFE0")

    //HM-10 characteristic code
    let HMCharactersticCode = CBUUID(string: "0xFFE1")

    //array to store the peripherals
    var peripheralArray:[(peripheral: CBPeripheral, RSSI: Float)] = []

    //for timing..obvs
    var timer: Timer!

//MARK: IBOutlets
    //if cancel is pressed go back to homepage
    @IBAction func cancelButton(_ sender: Any)
    {
        performSegue(withIdentifier: "segueBackwards", sender: nil)
    }

    //this is for the tableview so that you can reference it
    @IBOutlet var tableView: UITableView!

    //allow for disabling the scanning button whilst scanning
    @IBOutlet var scanningButton: UIBarButtonItem!

    //loads the centralmanager delegate in here
    override func viewDidLoad()
    {
        manager = CBCentralManager(delegate: self, queue: nil)
        tableView.delegate = self
        tableView.dataSource = self
        super.viewDidLoad()
        if(peripheral != nil)
            {
                disconnectPeripheral()
            }
    }

    //nothing
    override func didReceiveMemoryWarning()
    {
        super.didReceiveMemoryWarning()
    }

//MARK: cancel any preexisting connection - this still needs to be done
    func disconnectPeripheral()
    {
        manager?.cancelPeripheralConnection(peripheral!)
    }

//MARK: Bluetooth central

    //required centralmanager component. Text for what power state currently is
    func centralManagerDidUpdateState(_ central: CBCentralManager)
    {
        var consoleMsg = ""
        switch (central.state)
        {
        case.poweredOff:
            consoleMsg = "BLE is Powered Off"
            scanningButton.isEnabled = false
            alert()

        case.poweredOn:
            consoleMsg = "BLE is Powered On"
            scanningButton.isEnabled = true

        case.resetting:
            consoleMsg = "BLE is resetting"

        case.unknown:
            consoleMsg = "BLE is in an unknown state"

        case.unsupported:
            consoleMsg = "This device is not supported by BLE"

        case.unauthorized:
            consoleMsg = "BLE is not authorised"
        }
        print("\(consoleMsg)")
    }

//MARK: Alert if Bluetooth is not turned on
    func alert ()
    {
        //main header
        let title = "Bluetooth Power"

        //the little debrief below the main title
        let message = "Please turn on Bluetooth to use this app"

        //text in the text box
        let text = "OK"

        //this says what the title and message is
        let alert = UIAlertController(title: title, message: message , preferredStyle: UIAlertControllerStyle.alert)

        //add button for the answer
        let okayButton = UIAlertAction(title: text, style: UIAlertActionStyle.cancel, handler: nil)
        alert.addAction(okayButton)

        //show the alert
        present(alert, animated: true, completion: nil)
        print("said ok on button to turning on bluetooth")
    }

//MARK: Connection to bluetooth
    //once scanned this will say what has been discovered - add to peripheralArray
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber)
    {
        for existing in peripheralArray
        {
            if existing.peripheral.identifier == peripheral.identifier {return}
        }
        //adding peripheral to the array
        let theRSSI = RSSI.floatValue 
        peripheralArray.append(peripheral: peripheral, RSSI: theRSSI)
        peripheralArray.sort { $0.RSSI < $1.RSSI }
        print("discovered peripheral")
        tableView.reloadData()
        print("There are \(peripheralArray.count) peripherals in the array")
    }

    //create a link/connection to the peripheral
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
    {
        peripheral.discoverServices(nil) //may need to remove this not sure it does much
        print("connected to peripheral")
    }

    //disconnect from the peripheral
    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)
    {
        print("disconnected from peripheral")
        stopScanning()
    }

    //if it failed to connect to a peripheral will tell us (although not why)
    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?)
    {
        print("failed to connect to peripheral")
        stopScanning()
    }

//MARK: scanning
    //press scan button to initiate scanning sequence
    @IBAction func scanButton(_ sender: Any)
    {
        startTimer()
    }

    //start scanning for 5 seconds
    func startTimer()
    {
        //after 5 seconds this goes to the stop scanning routine
        timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(ViewController.stopScanning), userInfo: nil, repeats: true)
        print("Start Scan")
        manager?.scanForPeripherals(withServices: [HMServiceCode], options: nil)
        scanningButton.isEnabled = false
    }
    //stop the scanning and re-enable the scan button so you can do it again
    func stopScanning()
    {
        timer?.invalidate()
        print("timer stopped")
        manager?.stopScan()
        print("Scan Stopped")
        print("array items are: \(peripheralArray)")
        print("peripheral items are: \(peripheral)")
        print("manager items are: \(manager)")

        scanningButton.isEnabled = true

    }

//MARK: Table View
    //number of sections the table will have
    func numberOfSections(in tableView: UITableView) -> Int
    {
        return 1
    }

    //number of rows each section of the table will have
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        return peripheralArray.count
    }

    //the way the data will be displayed in each row for the sections
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let BluetoothNaming = peripheralArray[indexPath.row].peripheral.name
        cell.textLabel?.text = BluetoothNaming

        return cell
    }

    //what happens when we select an item from the bluetooth list
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
    {
        //tableView.deselectRow(at: indexPath, animated: true)
        stopScanning()
        peripheral = peripheralArray[(indexPath as NSIndexPath).row].peripheral
        print ("connecting to peripheral called \(peripheral)")

        //store the name of the connected peripeheral
        let connectedPeripheral = peripheral
        manager?.connect(connectedPeripheral!, options: nil)
        performSegue(withIdentifier: "segueBackwards", sender: nil)
    }

//MARK: change label name
    override func prepare(for segue: UIStoryboardSegue, sender: Any?)
    {
        if segue.identifier == "segueBackwards"
        {
            if let indexPath = self.tableView.indexPathForSelectedRow
            {
                //storing the name of the peripheral and then saving to send to Homepage
                let peripheral = peripheralArray[indexPath.row].peripheral.name
                let vc = segue.destination as! HomepageViewController
                vc.selectedName = peripheral

                //this is to unselect the row in the table
                tableView.deselectRow(at: indexPath, animated: true)
            }
        }
    }

//MARK: end
}

В целом на второй странице я могу подключиться к устройству Bluetooth. Затем я возвращаюсь на главный экран. Отсюда я затем перехожу к третьему контроллеру представления, который должен управлять действиями для моего приложения. У меня настроено так, что вы нажимаете кнопку, а затем это позволяет отправлять данные в Bluetooth. Однако по какой-то причине я не могу отправить данные. нажатие кнопки работает, но данные не отправляются.

Вот мой код для третьего контроллера представления:

    import UIKit
    import CoreBluetooth

    class SelectionViewController: UIViewController, CBPeripheralDelegate
    {

    //MARK: Variables
        var mainPeripheral: CBPeripheral?
        let UuidSerialService = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
        let UuidTx =            "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
        let UuidRx =            "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
        let txCharacteristicUUID =  "0000ffe0-0000-1000-8000-00805f9b34fb"
        let txServiceUUID =         "0000ffe1-0000-1000-8000-00805f9b34fb"

        /// Whether to write to the HM10 with or without response.
        /// Legit HM10 modules (from JNHuaMao) require 'Write without Response',
        /// while fake modules (e.g. from Bolutek) require 'Write with Response'.
        var writeType: CBCharacteristicWriteType = .withoutResponse
        var writeCharacteristic: CBCharacteristic?

    //MARK: IBOutlets

        @IBOutlet var whiteButtonControl: UIButton!

        @IBAction func doneButton(_ sender: Any)
        {
            performSegue(withIdentifier: "segueControltoHome", sender: nil)
        }

    //MARK: preset buttons
        @IBAction func whiteButton(_ sender: Any)
        {
            let value : UInt8 = 75
            let data = Data([value])
            mainPeripheral?.writeValue(data, for: writeCharacteristic!, type: writeType)
            print("Button pressed")
        }

//MARK: Peripheral Control
    func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager)
    {
        var consoleMsg = ""
        switch (peripheral.state)
        {
        case.poweredOff:
            consoleMsg = "Peripheral is Powered Off"

        case.poweredOn:
            consoleMsg = "Peripheral is Powered On"

        case.resetting:
            consoleMsg = "Peripheral is resetting"

        case.unknown:
            consoleMsg = "Peripheral is in an unknown state"

        case.unsupported:
            consoleMsg = "This device is not supported by Peripheral"

        case.unauthorized:
            consoleMsg = "Peripheral is not authorised"
        }
        print("\(consoleMsg)")
    }

    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?)
    {
        // discover the 0xFFE1 characteristic for all services (though there should only be one)
        for service in peripheral.services!
        {
            peripheral.discoverCharacteristics([CBUUID(string: "FFE1")], for: service)
        }
    }

    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)
    {
        // check whether the characteristic we're looking for (0xFFE1) is present - just to be sure
        print("reading this part")
        for characteristic in service.characteristics!

        {
            if characteristic.uuid == CBUUID(string: "FFE1")
            {
                // subscribe to this value (so we'll get notified when there is serial data for us..)
                peripheral.setNotifyValue(true, for: characteristic)
                print ("subscribed to this value")

                // keep a reference to this characteristic so we can write to it
                writeCharacteristic = characteristic
                print("characteristic is fine")
            }
        }
    }

Я думаю часть проблемы в том, что периферийный сервис и характеристика не подключаются к центральному? Это звучит правильно? На данный момент я хочу отправить значение 75 в bluetooth, которое затем может прочитать Arduino. Я сделал что-то не так с периферийным делегатом? Что мне нужно сделать, чтобы он мог отправлять данные

Спасибо

03.02.2017

  • Используйте Singleton для управления частью Bluetooth. Тогда все ViewController будут иметь к нему доступ. 03.02.2017
  • есть ли шанс, что вы могли бы расширить это? 03.02.2017

Ответы:


1

@ Ларме прав. Создайте одноэлементный класс для управления всеми действиями Core Bluetooth. Затем создайте экземпляр этого синглтона в любом месте.

Я создал пример одноэлементного класса с основными функциями Bluetooth здесь, https://github.com/alextarrago/bletest.

03.02.2017
  • Привет, Алекс, спасибо за ссылку на gitb. Я новичок в Swift, что мне делать с синглтоном? Как бы я включил это в свою работу? 03.02.2017
  • Просто используйте класс Singleton для создания всех методов и действий, которые вы хотите выполнять на своих устройствах BLE. Затем создайте экземпляр этого одноэлементного класса для каждого класса, который вам нужен. Очевидно, вам нужно создать протокол (или аналогичный) для связи между синглтоном и другими вашими контроллерами. 03.02.2017
  • Ок круто, попробую сделать. создайте синглтон со всеми вещами на основе BLE, которые я хочу сделать. затем создайте этот экземпляр во всех контроллерах представления, правильно? Надо будет поискать протоколы, потому что я с ними не очень знаком. Любое руководство? 03.02.2017
  • Не во всех контроллерах представления, а только в тех, которые вам действительно нужны для доступа к ним. Конечно, ищите делегацию. developer.apple.com/library/content/documentation/ Свифт/ 03.02.2017
  • Ок, гениально, спасибо Алекс. Как я могу связаться с вами, если у меня возникнут проблемы? 03.02.2017
  • Вы можете размещать свои вопросы по конкретной теме здесь, в StackOverflow. Я буду отслеживать их. 03.02.2017
  • Хорошо спасибо. Я сделаю все возможное, чтобы ограничить вопросы, когда и где это возможно 03.02.2017
  • @TejkaranSamra Singleton - это шаблон проектирования, он не подходит для Objective-C, Swift или iOS, он существовал на многих языках. Вы можете сделать поиск, который объяснит это. 03.02.2017

  • 2

    UUID ваших характеристик неверен

    if characteristic.uuid == CBUUID(string: "FFE1")
    

    характеристика = FFFE0

    изменить это -> if characteristic.uuid == CBUUID(string: "FFE0")

    14.04.2017
  • Сейчас я разобрался, но дело было не в этом. 19.04.2017
  • Новые материалы

    Создание корзины покупок с помощью Redux-Toolkit
    В этой статье мы рассмотрим, как использовать Redux Toolkit для управления состоянием в приложении React, на примере корзины покупок. Когда я начал использовать инструментарий redux, моя..

    Предварительная обработка данных для машинного обучения
    Предварительная обработка данных включает в себя подготовку данных, включающую интеграцию, очистку, нормализацию и преобразование данных; и задачи по сокращению данных; такие как выбор..

    Различия между обычными функциями и стрелочными функциями с точки зрения «этого»
    Концепции Javascript Различия между обычными функциями и стрелочными функциями с точки зрения «этого» Основное различие между обычными функциями и стрелочными функциями с точки зрения this..

    Python + Flask: раскрытие возможностей веб-разработки
    Привет! Меня зовут Гейб, и я увлечен обучением других Python и машинному обучению. Сегодня я хочу погрузиться в захватывающий мир веб-разработки с помощью Python и Flask. Это тема,..

    Как хранить данные для вашего процесса обработки данных
    Узнайте, как разработать эффективную стратегию хранения данных… Данные - новое масло: Все мы знаем, что в современном мире «данные - это новая нефть». Область науки о данных также является..

    Нужно ли высшее образование, чтобы быть разработчиком программного обеспечения?
    Самый простой ответ: нет. С тех пор, как я поджег операционную систему своего ПК, установив плохо разработанное программное обеспечение со всевозможными ошибками, я знал, что это то, чему я..

    ИИ в бизнесе / Развенчаны самые распространенные мифы
    Поскольку искусственный интеллект (ИИ) становится все более распространенным в деловом мире, вокруг этой технологии возникло множество мифов и заблуждений. Некоторые из этих мифов могут..