You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I inspected the bluetooth device and found a link to your company.
The Application i am developing uses Swift to connect to the bluetooth button, name "ATG-SJL".
I can pair successfully with it, but i am struggling to capture pressed events from the device.
Is it possible to use your tech to communicate with custom Applications?
or just the native iOS Camera application?
After i pair the bluetooth button, i see the native Volume UI appear and disappear.
Is iOS intercepting the keypress events on a lower level and routing them somewhere else?
Here is my swift code, "processInputReport" is never logged to the xcode console upon button press.
import Foundation
import Capacitor
import CoreBluetooth
@objc(BluetoothButtonPlugin)
public class BluetoothButtonPlugin: CAPPlugin, CBCentralManagerDelegate, CBPeripheralDelegate {
private var centralManager: CBCentralManager!
private var connectedPeripheral: CBPeripheral?
private let deviceName = "ATG-SJL"
private let deviceUUID = "9303D0FF-69DE-0137-0F69-EA4BC58D46C0"
private var ae42Characteristic: CBCharacteristic?
private var ae41Characteristic: CBCharacteristic? // Added AE41 characteristic
private var inputBuffer: [Data] = []
private var readTimer: Timer?
override public func load() {
centralManager = CBCentralManager(delegate: self, queue: nil)
print("BluetoothButtonPlugin loaded")
}
@objc func connect(_ call: CAPPluginCall) {
print("Attempting to connect to ATG-SJL")
if centralManager.state == .poweredOn {
centralManager.scanForPeripherals(withServices: nil, options: nil)
call.resolve()
} else {
call.reject("Bluetooth is not powered on")
}
}
public func centralManagerDidUpdateState(_ central: CBCentralManager) {
print("Bluetooth state updated: \(central.state.rawValue)")
if central.state == .poweredOn {
notifyListeners("bluetoothReady", data: nil)
centralManager.scanForPeripherals(withServices: nil, options: nil)
}
}
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
print("Discovered peripheral: \(peripheral.name ?? "Unknown"), ID: \(peripheral.identifier.uuidString)")
if peripheral.name == deviceName || peripheral.identifier.uuidString == deviceUUID {
print("Found ATG-SJL device")
connectedPeripheral = peripheral
centralManager.stopScan()
centralManager.connect(peripheral, options: nil)
}
}
public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Connected to device: \(peripheral.name ?? "Unknown")")
peripheral.delegate = self
peripheral.discoverServices(nil)
notifyListeners("deviceConnected", data: ["name": peripheral.name ?? ""])
}
public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
guard let services = peripheral.services else { return }
print("Discovered \(services.count) services")
for service in services {
print("Service: \(service.uuid)")
peripheral.discoverCharacteristics(nil, for: service)
}
}
public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
guard let characteristics = service.characteristics else { return }
print("Discovered \(characteristics.count) characteristics for service: \(service.uuid)")
for characteristic in characteristics {
print("Characteristic: \(characteristic.uuid), Properties: \(characteristic.properties.rawValue)")
if characteristic.uuid.uuidString == "AE42" {
ae42Characteristic = characteristic
peripheral.setNotifyValue(true, for: characteristic)
print("Notifications enabled for AE42 characteristic")
}
if characteristic.uuid.uuidString == "AE41" {
ae41Characteristic = characteristic
peripheral.setNotifyValue(true, for: characteristic) // Enable notifications for AE41
print("Notifications enabled for AE41 characteristic")
}
}
}
public func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
print("Error changing notification state for \(characteristic.uuid): \(error.localizedDescription)")
} else {
print("Notification state updated for characteristic: \(characteristic.uuid), isNotifying: \(characteristic.isNotifying)")
}
}
public func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if let error = error {
print("Error updating value for characteristic \(characteristic.uuid): \(error.localizedDescription)")
return
}
guard let value = characteristic.value else {
print("No value received for characteristic \(characteristic.uuid)")
return
}
print("Value received for characteristic: \(characteristic.uuid), value: \(value.hexEncodedString())")
if characteristic.uuid.uuidString == "AE42" {
processInputReport(value)
}
if characteristic.uuid.uuidString == "AE41" {
print("Value received for AE41: \(value.hexEncodedString())") // Log AE41 data
}
}
private func processInputReport(_ data: Data) {
print("Processing input report: \(data.hexEncodedString())")
inputBuffer.append(data)
print("Input buffer: \(inputBuffer.map { $0.hexEncodedString() })")
// Check for button interactions like click, double click, long press
if checkForSingleClick() {
handleClick()
inputBuffer.removeAll()
} else if checkForDoubleClick() {
handleDoubleClick()
inputBuffer.removeAll()
} else if checkForLongPress() {
handleLongPress()
inputBuffer.removeAll()
}
if inputBuffer.count > 20 {
inputBuffer.removeAll()
}
}
private func checkForSingleClick() -> Bool {
let pattern: [UInt8] = [0x07, 0x06, 0x70, 0x07]
return inputBuffer.contains { data in
guard data.count >= pattern.count else { return false }
return pattern.enumerated().allSatisfy { data[$0.offset] == $0.element }
}
}
private func checkForDoubleClick() -> Bool {
let pattern1: [UInt8] = [0x07, 0x07, 0x70, 0x07]
let pattern2: [UInt8] = [0x00, 0x07, 0x70, 0x07]
return inputBuffer.contains { data in
guard data.count >= pattern1.count else { return false }
return pattern1.enumerated().allSatisfy { data[$0.offset] == $0.element }
} && inputBuffer.contains { data in
guard data.count >= pattern2.count else { return false }
return pattern2.enumerated().allSatisfy { data[$0.offset] == $0.element }
}
}
private func checkForLongPress() -> Bool {
let pressPattern: [UInt8] = [0x01, 0x00, 0x00]
let releasePattern: [UInt8] = [0x00, 0x00, 0x00]
return inputBuffer.contains { data in
guard data.count >= pressPattern.count else { return false }
return pressPattern.enumerated().allSatisfy { data[$0.offset] == $0.element }
} && inputBuffer.contains { data in
guard data.count >= releasePattern.count else { return false }
return releasePattern.enumerated().allSatisfy { data[$0.offset] == $0.element }
}
}
private func handleClick() {
print("buttonSingleClick")
notifyListeners("buttonSingleClick", data: [:])
}
private func handleDoubleClick() {
print("buttonDoubleClick")
notifyListeners("buttonDoubleClick", data: [:])
}
private func handleLongPress() {
print("buttonLongPress")
notifyListeners("buttonLongPress", data: [:])
}
@objc func disconnect(_ call: CAPPluginCall) {
if let peripheral = connectedPeripheral {
centralManager.cancelPeripheralConnection(peripheral)
readTimer?.invalidate()
call.resolve(["message": "Disconnected from ATG-SJL"])
} else {
call.reject("No device connected")
}
}
@objc func isConnected(_ call: CAPPluginCall) {
call.resolve(["connected": connectedPeripheral != nil])
}
你好!,
Greetings from New Zealand, I am hoping you can assist me.
I am developing an iOS Application that requires a remote bluetooth button.
I purchased this bluetooth button from Temu;
https://www.temu.com/goods.html?_bg_fs=1&goods_id=601099537315419
I inspected the bluetooth device and found a link to your company.
The Application i am developing uses Swift to connect to the bluetooth button, name "ATG-SJL".
I can pair successfully with it, but i am struggling to capture pressed events from the device.
Is it possible to use your tech to communicate with custom Applications?
or just the native iOS Camera application?
After i pair the bluetooth button, i see the native Volume UI appear and disappear.
Is iOS intercepting the keypress events on a lower level and routing them somewhere else?
Here is my swift code, "processInputReport" is never logged to the xcode console upon button press.
Here is my log;
Discovered peripheral: ATG-SJL, ID: 9303D0FF-69DE-0137-0F69-EA4BC58D46C0
Found ATG-SJL device
Connected to device: ATG-SJL
Discovered 3 services
Service: Device Information
Service: Battery
Service: AE40
Discovered 9 characteristics for service: Device Information
Characteristic: Manufacturer Name String, Properties: 2
Characteristic: Model Number String, Properties: 2
Characteristic: Serial Number String, Properties: 2
Characteristic: Hardware Revision String, Properties: 2
Characteristic: Firmware Revision String, Properties: 2
Characteristic: Software Revision String, Properties: 2
Characteristic: System ID, Properties: 2
Characteristic: IEEE Regulatory Certification, Properties: 2
Characteristic: PnP ID, Properties: 2
Discovered 1 characteristics for service: Battery
Characteristic: Battery Level, Properties: 18
Discovered 2 characteristics for service: AE40
Characteristic: AE41, Properties: 4
Notifications enabled for AE41 characteristic
Characteristic: AE42, Properties: 16
Notifications enabled for AE42 characteristic
Error changing notification state for AE41: The request is not supported.
Notification state updated for characteristic: AE42, isNotifying: true
Thanks in advance.
If you could supply any information,
it would be much appreciated!
The text was updated successfully, but these errors were encountered: