https://velog.io/@maddie/iOS-CoreBluetooth-1-%EA%B0%9C%EC%9A%94
저번엔 CoreBluetooth 이론적인 내용에 대해 다뤘다고 한다면, 오늘은 진짜 써야 되는 실무적인 내용과 알아야 할 키워드를 다뤄보려고 합니다!
RSSI (Received Signal Strength Indicator)는 블루투스 통신에서 신호의 강도를 측정하는 값입니다. 일반적으로 데시벨 밀리와트(dBm) 단위로 측정되며, 음수 값으로 표시됩니다. RSSI 값은 블루투스 장치 간의 거리와 신호 품질을 추정하는 데 유용합니다. 값이 0에 가까울수록 신호가 강하고, 값이 더 작아질수록 신호가 약합니다.
앱 개발에서 RSSI 값을 활용할 수 있는 몇 가지 방법은 다음과 같습니다:
RSSI 값을 이용하여 두 블루투스 장치 간의 거리를 추정할 수 있습니다. 이는 주로 실내 위치 추적 시스템에서 많이 사용됩니다. 다만, RSSI 값은 주변 환경(벽, 장애물 등)에 영향을 받기 때문에, 정확한 거리 측정을 위해 보정이 필요합니다.
특정 범위 내에 있는 장치를 감지하고, 그에 따라 동작을 수행할 수 있습니다. 예를 들어, 특정 범위 내에 사용자가 들어오면 자동으로 문을 여는 스마트 도어락 같은 애플리케이션에서 사용할 수 있습니다.
블루투스 연결의 신호 강도를 모니터링하여 연결 품질이 나빠질 경우 사용자에게 경고를 보내거나, 연결을 유지하기 위한 조치를 취할 수 있습니다.
앱에서 장치 간의 거리나 신호 강도에 따라 기능을 조정할 수 있습니다. 예를 들어, 무선 오디오 장치는 신호 강도가 약해지면 자동으로 볼륨을 낮추거나, 데이터 전송 속도를 조절할 수 있습니다.
MTU (Maximum Transmission Unit)는 네트워크 통신에서 한 번에 전송할 수 있는 최대 패킷 크기를 나타내는 용어입니다. MTU는 바이트 단위로 측정되며, 전송되는 데이터의 최대 크기를 결정합니다. 블루투스에서도 MTU 설정이 중요한 역할을 합니다.
기본적으로 BLE에서 초기 MTU 값은 23 바이트로 설정되어 있습니다. 이는 프로토콜 오버헤드(ATT, L2CAP 헤더 등)를 제외한 20 바이트의 데이터 페이로드를 의미합니다.
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
peripheral.delegate = self
peripheral.discoverServices(nil)
}
🍉 업데이트 내용 (샤라웃 투 머스크)
iOS에서는 MTU 크기를 직접 요청하거나 설정할 수 있는 공개 API가 없습니다. iOS는 자동으로 MTU 크기를 협상하며, 개발자가 이를 직접 제어할 수 없습니다.
iOS에서 MTU와 관련하여 할 수 있는 것은 다음과 같습니다:
let withResponseMTU = peripheral.maximumWriteValueLength(for: .withResponse)
let withoutResponseMTU = peripheral.maximumWriteValueLength(for: .withoutResponse)
print("MTU with response: \(withResponseMTU)")
print("MTU without response: \(withoutResponseMTU)")
func peripheral(_ peripheral: CBPeripheral, didUpdateMTU mtu: Int, error: Error?) {
if let error = error {
print("MTU 업데이트 실패: \(error.localizedDescription)")
} else {
print("새로운 MTU 크기: \(mtu)")
}
}
iOS에서는 시스템이 자동으로 최적의 MTU 크기를 협상하므로, 대부분의 경우 개발자가 이를 직접 관리할 필요가 없습니다.
블루투스 저에너지(BLE)에서는 데이터를 쓰는 두 가지 주요 방법이 있습니다:
MAC 주소(Media Access Control Address)는 네트워크 인터페이스 카드(NIC)에 할당된 고유 식별자입니다. 이 주소는 네트워크 장치 간의 통신을 가능하게 하며, 주로 로컬 네트워크 내에서 사용됩니다. MAC 주소는 48비트(6바이트) 길이의 식별자로, 일반적으로 16진수 형식으로 표기됩니다. 예를 들어, 00:1A:2B:3C:4D:5E
와 같은 형태입니다.
let macAddress = peripheral.identifier.uuid
// (244, 101, 114, 136, 206, 144, 223, 15, 177, 162, 117, 116, 211, 116, 53, 99)
let macAddress = peripheral.identifier.uuidString // identifier와 동일
MAC 주소는 두 부분으로 나뉩니다:
블루투스와 관련하여 iPhone의 MAC 주소는 다음과 같은 역할을 합니다:
블루투스 기능을 개발할 때는 iOS의 CoreBluetooth 프레임워크를 사용하여 블루투스 통신을 관리하게 됩니다. CoreBluetooth를 사용하면 iPhone의 블루투스 기능을 제어하고 다른 블루투스 장치와의 통신을 설정할 수 있습니다. iOS에서는 보안 및 개인 정보 보호를 고려하여 MAC 주소를 직접 공개하지 않으며, 대신 CoreBluetooth를 통해 블루투스 통신을 수행합니다.
identifier
는 iOS 기기가 주변 장치를 식별하기 위해 사용하는 고유한 값이며, 로봇의 MAC 주소와 직접적으로 관련이 없습니다.
iOS 기기의 MAC 주소는 보안 및 개인 정보 보호를 고려하여 직접적으로 접근할 수 없습니다. iOS에서는 MAC 주소를 숨기고 대신 앱이 블루투스를 통해 주변 장치와 통신할 수 있도록 CBPeripheral
객체를 제공합니다. 따라서 iOS 앱에서는 자체적으로 iOS 기기의 MAC 주소를 가져올 수 없습니다.
대신 iOS 앱은 기기의 식별자인 UUID (Universally Unique Identifier)를 사용할 수 있습니다.
ex) iOS mac 주소: 22AB382D-...-...-BF28-D55C066FD854
Bluetooth Low Energy (BLE)에서 CBCharacteristicProperties
는 특정 특성의 동작을 나타내는 속성들의 비트 마스크입니다. 여기에는 다양한 속성이 있으며, 각 속성은 특정 기능을 활성화하거나 제한합니다. 주요 속성들에 대해 설명하겠습니다:
broadcast
):read
):writeWithoutResponse
):write
):notify
):indicate
):authenticatedSignedWrites
):extendedProperties
):notifyEncryptionRequired
):indicateEncryptionRequired
):이 속성들은 비트 마스크로 조합될 수 있습니다. 예를 들어, 특성이 읽기 및 알림 속성을 모두 가질 수 있습니다. 이러한 속성을 사용하여 특성과 상호작용할 수 있는 방법을 결정합니다.
특정 특성의 속성을 확인하고, 해당 속성에 따라 동작을 정의하는 코드 예시입니다:
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
guard let characteristics = service.characteristics else {
return
}
for characteristic in characteristics {
print("Discovered Characteristic: \\(characteristic)")
if characteristic.properties.contains(.broadcast) {
print("This characteristic supports broadcast")
}
if characteristic.properties.contains(.read) {
print("This characteristic supports read")
peripheral.readValue(for: characteristic)
}
if characteristic.properties.contains(.writeWithoutResponse) {
print("This characteristic supports write without response")
}
if characteristic.properties.contains(.write) {
print("This characteristic supports write")
}
if characteristic.properties.contains(.notify) {
print("This characteristic supports notify")
peripheral.setNotifyValue(true, for: characteristic)
}
if characteristic.properties.contains(.indicate) {
print("This characteristic supports indicate")
}
if characteristic.properties.contains(.authenticatedSignedWrites) {
print("This characteristic supports authenticated signed writes")
}
if characteristic.properties.contains(.extendedProperties) {
print("This characteristic has extended properties")
}
if characteristic.properties.contains(.notifyEncryptionRequired) {
print("This characteristic requires encryption for notify")
}
if characteristic.properties.contains(.indicateEncryptionRequired) {
print("This characteristic requires encryption for indicate")
}
}
}
위의 코드는 특성의 속성을 검사하고, 각 속성에 대해 적절한 동작을 수행합니다. 예를 들어, 특성이 notify
속성을 가지고 있다면, setNotifyValue(true, for: characteristic)
을 호출하여 알림을 활성화합니다.