admin管理员组文章数量:1312806
I have a raspberry pi pico W, which is connected to a hall switch so it can monitor revolutions of a wheel. I am trying to broadcast this information over BLE, so I can pick it up with a Garmin watch. I am transmitting the data using CSC, and have set all the required flags I think.
In nRF connect, it shows up perfectly, all the information is there, it is connectable and it shows the time difference between wheel rotations. It also works fine in Zwift. But when connecting to garmin, it shows up, but when pairing, the connection fails. This is the bluetooth part of my code, written in mircopython:
_ADV_TYPE_FLAGS = const(0x01)
_ADV_TYPE_NAME = const(0x09)
_ADV_TYPE_UUID16_COMPLETE = const(0x3)
_ADV_TYPE_UUID32_COMPLETE = const(0x5)
_ADV_TYPE_UUID128_COMPLETE = const(0x7)
_ADV_TYPE_UUID16_MORE = const(0x2)
_ADV_TYPE_UUID32_MORE = const(0x4)
_ADV_TYPE_UUID128_MORE = const(0x6)
_ADV_TYPE_APPEARANCE = const(0x19)
# Generate a payload to be passed to gap_advertise(adv_data=...).
def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
payload = bytearray()
def _append(adv_type, value):
nonlocal payload
payload += struct.pack("BB", len(value) + 1, adv_type) + value
_append(
_ADV_TYPE_FLAGS,
struct.pack("B", (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04)),
)
if name:
_append(_ADV_TYPE_NAME, name)
if services:
for uuid in services:
b = bytes(uuid)
if len(b) == 2:
_append(_ADV_TYPE_UUID16_COMPLETE, b)
elif len(b) == 4:
_append(_ADV_TYPE_UUID32_COMPLETE, b)
elif len(b) == 16:
_append(_ADV_TYPE_UUID128_COMPLETE, b)
# See .bluetooth.characteristic.gap.appearance.xml
if appearance:
_append(_ADV_TYPE_APPEARANCE, struct.pack("<h", appearance))
return payload
_IRQ_CENTRAL_CONNECT = const(1)
_IRQ_CENTRAL_DISCONNECT = const(2)
_IRQ_GATTS_INDICATE_DONE = const(20)
_FLAG_READ = const(0x0002)
_FLAG_NOTIFY = const(0x0010)
_FLAG_INDICATE = const(0x0020)
# .bluetooth.service.environmental_sensing
_ENV_SENSE_UUID = bluetooth.UUID(0x1816)
# Custom UUID for speed characteristic
_SPEED_CHAR = (
bluetooth.UUID(0x2A5B), # Correct UUID for Cycling Speed
_FLAG_READ | _FLAG_NOTIFY | _FLAG_INDICATE,
)
# Add the Location characteristic UUID (Cycling Speed and Cadence Service)
_CSC_SENSOR_LOCATION_UUID = bluetooth.UUID(0x2A5D) # Sensor Location characteristic UUID
_SENSOR_LOCATION_CHAR = (
_CSC_SENSOR_LOCATION_UUID,
_FLAG_READ,
)
# Add the CSC Feature characteristic UUID (Cycling Speed and Cadence Service)
_CSC_FEATURE_UUID = bluetooth.UUID(0x2A5C) # CSC Feature characteristic UUID
_CSC_FEATURE_CHAR = (
_CSC_FEATURE_UUID,
_FLAG_READ,
)
# Update the service to include the CSC Feature characteristic
_ENV_SENSE_SERVICE = (
_ENV_SENSE_UUID,
(_SPEED_CHAR, _SENSOR_LOCATION_CHAR, _CSC_FEATURE_CHAR),
)
class BLESpeed:
def __init__(self, ble, name=""):
self._ble = ble
self._ble.active(True)
self._ble.irq(self._irq)
((self._handle, self._location_handle, self._csc_feature_handle),) = self._ble.gatts_register_services((_ENV_SENSE_SERVICE,))
self._connections = set()
if len(name) == 0:
name = 'Pico Speed'
print('Sensor name %s' % name)
self._payload = advertising_payload(
name=name, services=[_ENV_SENSE_UUID],
appearance=1157
)
self._advertise()
# Set the initial sensor location to "front wheel"
self.set_sensor_location()
self.set_csc_feature()
def _irq(self, event, data):
if event == _IRQ_CENTRAL_CONNECT:
conn_handle, _, _ = data
self._connections.add(conn_handle)
elif event == _IRQ_CENTRAL_DISCONNECT:
conn_handle, _, _ = data
self._connections.remove(conn_handle)
self._advertise()
elif event == _IRQ_GATTS_INDICATE_DONE:
conn_handle, value_handle, status = data
def set_sensor_location(self, notify=False, indicate=False):
"""Set the location of the sensor (e.g., 'front_wheel', 'rear_wheel', etc.)"""
location_value = SENSOR_LOCATIONS.get("front_wheel", SENSOR_LOCATIONS["other"]) # Default to 'other' if not found
self._ble.gatts_write(self._location_handle, bytes([location_value])) # Write the location value
# Notify or indicate the change to connected devices
if notify or indicate:
for conn_handle in self._connections:
if notify:
self._ble.gatts_notify(conn_handle, self._location_handle)
if indicate:
self._ble.gatts_indicate(conn_handle, self._location_handle)
def set_csc_feature(self, wheel_rev_data=True, crank_rev_data=False, multi_sensor_loc=False, notify=False, indicate=False):
"""Set the CSC feature bitfield"""
# Construct the 16-bit feature bitfield
csc_feature = 0
if wheel_rev_data:
csc_feature |= (1 << 0) # Wheel Revolution Data Supported
if crank_rev_data:
csc_feature |= (1 << 1) # Crank Revolution Data Supported
if multi_sensor_loc:
csc_feature |= (1 << 2) # Multiple Sensor Locations Supported
# Pack the 16-bit field into bytes
csc_feature_bytes = bytes([csc_feature & 0xFF, (csc_feature >> 8) & 0xFF])
# Write the data to the CSC feature characteristic handle
self._ble.gatts_write(self._csc_feature_handle, csc_feature_bytes)
# Notify or indicate the change to connected devices
if notify or indicate:
for conn_handle in self._connections:
if notify:
self._ble.gatts_notify(conn_handle, self._csc_feature_handle)
if indicate:
self._ble.gatts_indicate(conn_handle, self._csc_feature_handle)
def update_speed(self, wheel_revolution, last_wheel_event_time_sec, notify=False, indicate=False):
flags = 0x01 # Wheel revolution data present (bit 0 = 1, others = 0)
# Convert last wheel event time to the 1/1024 resolution and pack into uint16
last_wheel_event_time_1024ths = int(last_wheel_event_time_sec * 1024)
# Pack the data in little-endian format
data = bytes([
flags, # Flags (1 byte)
wheel_revolution & 0xFF, (wheel_revolution >> 8) & 0xFF, (wheel_revolution >> 16) & 0xFF, (wheel_revolution >> 24) & 0xFF, # Cumulative Wheel Revolutions (4 bytes)
last_wheel_event_time_1024ths & 0xFF, (last_wheel_event_time_1024ths >> 8) & 0xFF # Last Wheel Event Time (2 bytes)
])
print(data.hex()) # Output the packed data in hex format
# Write the data to the speed characteristic handle
self._ble.gatts_write(self._handle, data)
if notify or indicate:
for conn_handle in self._connections:
if notify:
self._ble.gatts_notify(conn_handle, self._handle)
if indicate:
self._ble.gatts_indicate(conn_handle, self._handle)
def _advertise(self, interval_us=100000):
self._ble.gap_advertise(interval_us, adv_data=self._payload)
Does anyone have any idea what is wrong? Or any possible reasons the connection could be failing. Reportedly, this similar code works fine with Garmin, but I can't spot the difference:
.ino
Edit: I've tried changing to a public MAC address, and that did not work. Checking my advertisement hex, it is: 0201060b095069636f2053706565640303161803198504 Which seems correct?
本文标签: bluetoothGarmin watch won39t connect to pico W BLE sensorStack Overflow
版权声明:本文标题:bluetooth - Garmin watch won't connect to pico W BLE sensor - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741873640a2402339.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论