feat: add setPlayMode SDK API with isActivated precondition

This commit is contained in:
km2023
2026-05-06 10:42:09 +08:00
parent 7aec09be2a
commit c3a726fc02
2 changed files with 72 additions and 0 deletions

View File

@@ -291,6 +291,56 @@ public final class DuooomiBleSDK: NSObject {
}) })
} }
/// 0= / 1=
///
/// `BIND_DEVICE` (0x0F) `BindingResponse`
/// `deviceInfo` `loop` expo
///
/// - Important: ** `userId` `bind`** `isActivated == true`
/// `success=0`SDK
/// - Note: `bind` / `unbind` / `setPlayMode` `0x0F` / `0x12` opId ****
public func setPlayMode(
_ mode: PlayMode,
userId: String,
completion: @escaping (Result<BindingResponse, Error>) -> Void
) {
guard ensureConnected(completion: completion) else { return }
guard isActivated else {
BleLog.w("setPlayMode called before bind (isActivated=false)", "Command")
DispatchQueue.main.async {
completion(.failure(DuooomiBleError.bindingFailed("Device not bound; call bind(userId:) first")))
}
return
}
BleLog.d("Sending setPlayMode (mode=\(mode), userId=\(userId))", "Command")
sendAndWait(commandType: .bindDevice, completion: { [weak self] result in
guard let self = self else { return }
switch result {
case .failure(let error):
completion(.failure(error))
case .success(let data):
do {
let resp = try self.decodeResponse(BindingResponse.self, from: data)
if resp.success != 1 {
BleLog.w("setPlayMode failed: device rejected", "Command")
completion(.failure(DuooomiBleError.bindingFailed("Set play mode failed")))
return
}
BleLog.i("setPlayMode success: mode=\(mode)", "Command")
// deviceInfo loop
self.getDeviceInfo { _ in
completion(.success(resp))
}
} catch {
completion(.failure(error))
}
}
}, send: {
try self.deviceInfoService.setPlayMode(userId: userId, loop: mode)
})
}
/// ///
public func unbind(userId: String, completion: @escaping (Result<UnbindResponse, Error>) -> Void) { public func unbind(userId: String, completion: @escaping (Result<UnbindResponse, Error>) -> Void) {
guard ensureConnected(completion: completion) else { return } guard ensureConnected(completion: completion) else { return }

View File

@@ -81,3 +81,25 @@ final class BindPayloadEncodingTests: XCTestCase {
XCTAssertEqual(dict["loop"] as? Int, 0) XCTAssertEqual(dict["loop"] as? Int, 0)
} }
} }
final class SetPlayModeGuardTests: XCTestCase {
private func makeSDK() -> DuooomiBleSDK {
DuooomiBleSDK(config: DuooomiBleConfig(apiKey: "test"))
}
func testSetPlayModeFailsWhenNotConnected() {
let sdk = makeSDK()
let exp = expectation(description: "completion")
sdk.setPlayMode(.loop, userId: "u1") { result in
switch result {
case .success:
XCTFail("expected failure when not connected")
case .failure(let error):
XCTAssertTrue("\(error)".lowercased().contains("connect"),
"expected notConnected-style error, got \(error)")
}
exp.fulfill()
}
wait(for: [exp], timeout: 1.0)
}
}