Polidea / RxBluetoothKit

iOS & OSX Bluetooth library for RxSwift
Apache License 2.0
1.41k stars 366 forks source link

Write to characteristic does not work #239

Closed aleksanderaleksic closed 6 years ago

aleksanderaleksic commented 6 years ago

Hi! I am trying to write to a Characteristic, but it doesn't seem to work. If I write directly on the peripheral and passing the CharacteristicIdentifier it works.

CODE

This is the code i want to execute

func playBeepSound() -> Observable<Void> {
    let command = ATCoreBeepForPairing()
    let obs = self.characteristic
        .flatMap{ $0.observeValueUpdateAndSetNotification() }
        .filter{
            return command.successfullInstrumentCommand(data: $0.value)
        }
        .take(1)
        .map { (_) -> Void in
            return
        }

    self.characteristic
        .flatMap { $0.writeValue(command.rawData, type: .withResponse) }
        .subscribe()
        .disposed(by: self.bag)

    return obs
}

TEST CODE

func test_playBeepSound(){
    let expectation = XCTestExpectation(description: "Play Beep Sound")

    func beep() {
        let command = ATCoreBeepForPairing()

        self.instrument.peripheral
            .flatMap { $0.writeValue(command.rawData, for: CoreCharacteristic.asrcap, type: .withResponse) }
            .subscribe()
            .disposed(by: self.bag)
    }

    let beepSound = self.instrument.asracp.playBeepSound()

    beep sound
        .subscribe(onNext: { (_) in
            expectation.fulfill()
        }, onError: { (error) in
            XCTFail("A error accured: \(error)")
        }).disposed(by: self.bag)

    beep()

    wait(for: [expectation], timeout: 20.0)
}

In the test code, i execute the self.instrument.asracp.playBeepSound() which is the CODE on top. It does not write anything to the characteristic. When running the beep() function, the device makes a beep sound and the test succeeds. The beep() does exactly the same as the self.instrument.asracp.playBeepSound() except it writes on the peripheral.

aleksanderaleksic commented 6 years ago

If i don't run beep() the observable doesn't emit anything. And the test times out.

aleksanderaleksic commented 6 years ago

I think this is a mistake by me. Since it gets disposed immediately. Haven't figured it out yet, any suggestions?

[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:21 +0000] Manager state:  poweredOn 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:21 +0000] Manager started scanning for peripherals 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] Found instrument with serial:  2900123243 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] Connected to:  2900123243 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[SERVICE] On Subscribe 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[SERVICE] On Complete 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[SERVICE] On Subscribed 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[SERVICE] On Dispose 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[CHARS] On Subscribe 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[CHARS] On Complete 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[CHARS] On Subscribed 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[CHARS] On Dispose 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[ASRACP] On Subscribe 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[ASRACP] On Complete 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[ASRACP] On Subscribed 
[AIRTHINGS.BLE]-[VERBOSE]-[2018-04-02 12:42:22 +0000] -[ASRACP] On Dispose 
kkosovsky commented 6 years ago

Hi, @aleksanderaleksic! From what I see, you've indeed made a small mistake with calling subscribe() method as you've presented in the code snippet above. Charateristic's writeValue(:) method returns a Single. And if you check Single's subscribe(:) signature, you can see, that both of it's arguments have default values of nil.

public func subscribe(onSuccess: ((ElementType) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil) -> Disposable

Try passing closures for both onSuccess and onError arguments like this:

characteristic.writeValue(data, type: writeType).subscribe(onSuccess: { [unowned self] characteristic in
            self.writeValueSubject.onNext(Result.success(characteristic))
        }, onError: { [unowned self] error in
            self.writeValueSubject.onNext(Result.error(error))
        }).disposed(by: disposeBag)

It is a snippet from the new version of our example app, which shall be merged soon. Let me know if it solves your problem and don't hesitate to let us know, if any further problems arise.

aleksanderaleksic commented 6 years ago

@kkosovsky Thanks for your reply. Now the test actually succeeds with your suggestion, yeey! But there should be a beep sound from the device, but this never happens. So it seems that the write is not executed. I still do believe there is something wrong with my code though.

aleksanderaleksic commented 6 years ago

I made it work! The problem was that the writing happens before the characteristic was set up. So I set the characteristic subject as a ReplaySubject instead, with the buffer size of 1. private let _asracpCharSubject = ReplaySubject<ASRACP>.create(bufferSize: 1)

This plays the beep sound and the test succeeds. But is there any disadvantages doing it this way?

kkosovsky commented 6 years ago

@aleksanderaleksic I'm glad you've found my suggestion helpful :) Can you paste a bigger code snippet, so I can actually see what's going on in detail? Then it would be easier, to advise you with the best type of subject for your problem :) Cheers!

pouljohn1 commented 6 years ago

@aleksanderaleksic was the problem solved?

aleksanderaleksic commented 6 years ago

Sorry for the late reply. @kkosovsky I don't have the time go into detail on what I did, but the problem was solved for me by using the ReplaySubject.

Thanks for the help.