{"id":19285606,"url":"https://github.com/alexmoon/bluest","last_synced_at":"2025-04-12T17:39:14.889Z","repository":{"id":58170246,"uuid":"501709215","full_name":"alexmoon/bluest","owner":"alexmoon","description":"Cross-platform Rust crate for working with Bluetooth Low Energy devices. ","archived":false,"fork":false,"pushed_at":"2024-10-27T16:11:46.000Z","size":422,"stargazers_count":94,"open_issues_count":10,"forks_count":17,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-03T21:11:23.067Z","etag":null,"topics":["bluetooth","bluetooth-low-energy","cross-platform","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alexmoon.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-06-09T15:27:48.000Z","updated_at":"2025-03-31T22:25:56.000Z","dependencies_parsed_at":"2024-10-27T17:38:38.336Z","dependency_job_id":"7521790f-7dad-4ebf-ad04-ed6e250e4cfe","html_url":"https://github.com/alexmoon/bluest","commit_stats":{"total_commits":71,"total_committers":3,"mean_commits":"23.666666666666668","dds":0.05633802816901412,"last_synced_commit":"733925b40074aa537c99c17b2d4d0b851514f803"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexmoon%2Fbluest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexmoon%2Fbluest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexmoon%2Fbluest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexmoon%2Fbluest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alexmoon","download_url":"https://codeload.github.com/alexmoon/bluest/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248606866,"owners_count":21132429,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bluetooth","bluetooth-low-energy","cross-platform","rust"],"created_at":"2024-11-09T21:46:01.504Z","updated_at":"2025-04-12T17:39:14.854Z","avatar_url":"https://github.com/alexmoon.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![crates.io][crates-badge]][crates-url] [![docs.rs][docs-badge]][docs-url]\n[![Build Status][actions-badge]][actions-url]\n\n[crates-badge]: https://img.shields.io/crates/v/bluest\n[crates-url]: https://crates.io/crates/bluest\n[docs-badge]: https://docs.rs/bluest/badge.svg\n[docs-url]: https://docs.rs/bluest\n[actions-badge]: https://github.com/alexmoon/bluest/workflows/CI/badge.svg\n[actions-url]: https://github.com/alexmoon/bluest/actions?query=workflow%3ACI+branch%3Amain\n\n# Bluest — Cross-platform Bluetooth LE crate for Rust\n\n\u003c!-- cargo-rdme start --\u003e\n\nBluest is a cross-platform [Bluetooth Low Energy] (BLE) library for [Rust]. It\ncurrently supports Windows (version 10 and later), MacOS/iOS, and Linux. Android\nsupport is planned.\n\nThe goal of Bluest is to create a _thin_ abstraction on top of the\nplatform-specific Bluetooth APIs in order to provide safe, cross-platform access\nto Bluetooth LE devices. The crate currently supports the GAP Central and GATT\nClient roles. Peripheral and Server roles are not supported.\n\n[Rust]: https://www.rust-lang.org/\n[Bluetooth Low Energy]: https://www.bluetooth.com/specifications/specs/\n\n## Usage\n\n```rust\nlet adapter = Adapter::default().await.ok_or(\"Bluetooth adapter not found\")?;\nadapter.wait_available().await?;\n\nprintln!(\"starting scan\");\nlet mut scan = adapter.scan(\u0026[]).await?;\nprintln!(\"scan started\");\nwhile let Some(discovered_device) = scan.next().await {\n   println!(\n       \"{}{}: {:?}\",\n       discovered_device.device.name().as_deref().unwrap_or(\"(unknown)\"),\n       discovered_device\n           .rssi\n           .map(|x| format!(\" ({}dBm)\", x))\n           .unwrap_or_default(),\n       discovered_device.adv_data.services\n   );\n}\n```\n\n## Overview\n\nThe primary functions provided by Bluest are:\n\n- Device discovery:\n  - [Scanning][Adapter::scan] for devices and receiving advertisements\n  - Finding [connected devices][Adapter::connected_devices]\n  - [Opening][Adapter::open_device] previously found devices\n  - [Connecting][Adapter::connect_device] to discovered devices\n  - [Pairing][Device::pair] with devices\n- Accessing remote GATT services:\n  - Discovering device [services][Device::discover_services]\n  - Discovering service [characteristics][Service::discover_characteristics]\n  - Discovering characteristic\n    [descriptors][Characteristic::discover_descriptors]\n  - [Read][Characteristic::read], [write][Characteristic::write] (including\n    [write without response][Characteristic::write_without_response]), and\n    [notify/indicate][Characteristic::notify] operations on remote\n    characteristics\n  - [Read][Descriptor::read] and [write][Descriptor::write] operations on\n    characteristic descriptors\n\n## Asynchronous runtimes\n\nOn non-linux platforms, Bluest should work with any asynchronous runtime. On\nlinux the underlying `bluer` crate requires the Tokio runtime and Bluest makes\nuse of Tokio's `block_in_place` API (which requires Tokio's multi-threaded\nruntime) to make a few methods synchronous. Linux-only asynchronous versions of\nthose methods are also provided, which should be preferred in platform-specific\ncode.\n\n## Platform specifics\n\nBecause Bluest aims to provide a thin abstraction over the platform-specific\nAPIs, the available APIs represent the lowest common denominator of APIs among\nthe supported platforms. For example, CoreBluetooth never exposes the Bluetooth\naddress of devices to applications, therefore there is no method on `Device` for\nretrieving an address or even any Bluetooth address struct in the crate.\n\nMost Bluest APIs should behave consistently across all supported platforms.\nThose APIs with significant differences in behavior are summarized in the table\nbelow.\n\n| Method                                                           | MacOS/iOS | Windows | Linux |\n| ---------------------------------------------------------------- | :-------: | :-----: | :---: |\n| [`Adapter::connect_device`][Adapter::connect_device]             |    ✅     |   ✨    |  ✅   |\n| [`Adapter::disconnect_device`][Adapter::disconnect_device]       |    ✅     |   ✨    |  ✅   |\n| [`Device::name`][Device::name]                                   |    ✅     |   ✅    |  ⌛️   |\n| [`Device::is_paired`][Device::is_paired]                         |    ❌     |   ✅    |  ✅   |\n| [`Device::pair`][Device::pair]                                   |    ✨     |   ✅    |  ✅   |\n| [`Device::pair_with_agent`][Device::pair_with_agent]             |    ✨     |   ✅    |  ✅   |\n| [`Device::unpair`][Device::unpair]                               |    ❌     |   ✅    |  ✅   |\n| [`Device::rssi`][Device::rssi]                                   |    ✅     |   ❌    |  ❌   |\n| [`Service::uuid`][Service::uuid]                                 |    ✅     |   ✅    |  ⌛️   |\n| [`Service::is_primary`][Service::is_primary]                     |    ✅     |   ❌    |  ✅   |\n| [`Characteristic::uuid`][Characteristic::uuid]                   |    ✅     |   ✅    |  ⌛️   |\n| [`Characteristic::max_write_len`][Characteristic::max_write_len] |    ✅     |   ✅    |  ⌛️   |\n| [`Descriptor::uuid`][Descriptor::uuid]                           |    ✅     |   ✅    |  ⌛️   |\n\n✅ = supported\\\n✨ = managed automatically by the OS, this method is a no-op\\\n⌛️ = the underlying API is async so this method uses Tokio's `block_in_place`\nAPI internally\\\n❌ = returns a [`NotSupported`][error::ErrorKind::NotSupported] error\n\nAlso, the errors returned by APIs in a given situation may not be consistent\nfrom platform to platform. For example, Linux's bluez API does not return the\nunderlying Bluetooth protocol error in a useful way, whereas the other platforms\ndo. Where it is possible to return a meaningful error, Bluest will attempt to do\nso. In other cases, Bluest may return an error with a [`kind`][Error::kind] of\n[`Other`][error::ErrorKind::Other] and you would need to look at the\nplatform-specific [`source`][std::error::Error::source] of the error for more\ninformation.\n\n## Feature flags\n\nThe `serde` feature is available to enable serializing/deserializing device\nidentifiers.\n\n## Examples\n\nExamples demonstrating basic usage are available in the [examples folder].\n\n[examples folder]: https://github.com/alexmoon/bluest/tree/master/bluest/examples\n\n\u003c!-- cargo-rdme end --\u003e\n\nRefer to the [API documentation] for more details.\n\n[API documentation]: https://docs.rs/bluest\n[Adapter::scan]: https://docs.rs/bluest/latest/bluest/struct.Adapter.html#method.scan\n[Adapter::connected_devices]: https://docs.rs/bluest/latest/bluest/struct.Adapter.html#method.connected_devices\n[Adapter::open_device]: https://docs.rs/bluest/latest/bluest/struct.Adapter.html#method.open_device\n[Adapter::connect_device]: https://docs.rs/bluest/latest/bluest/struct.Adapter.html#method.connect_device\n[Adapter::disconnect_device]: https://docs.rs/bluest/latest/bluest/struct.Adapter.html#method.disconnect_device\n[Device::name]: https://docs.rs/bluest/latest/bluest/struct.Device.html#method.name\n[Device::is_connected]: https://docs.rs/bluest/latest/bluest/struct.Device.html#method.is_connected\n[Device::is_paired]: https://docs.rs/bluest/latest/bluest/struct.Device.html#method.is_paired\n[Device::pair]: https://docs.rs/bluest/latest/bluest/struct.Device.html#method.pair\n[Device::pair_with_agent]: https://docs.rs/bluest/latest/bluest/struct.Device.html#method.pair_with_agent\n[Device::unpair]: https://docs.rs/bluest/latest/bluest/struct.Device.html#method.unpair\n[Device::discover_services]: https://docs.rs/bluest/latest/bluest/struct.Device.html#method.discover_services\n[Device::rssi]: https://docs.rs/bluest/latest/bluest/struct.Device.html#method.rssi\n[Service::uuid]: https://docs.rs/bluest/latest/bluest/struct.Service.html#method.uuid\n[Service::is_primary]: https://docs.rs/bluest/latest/bluest/struct.Service.html#method.is_primary\n[Service::discover_characteristics]: https://docs.rs/bluest/latest/bluest/struct.Service.html#method.discover_characteristics\n[Characteristic::uuid]: https://docs.rs/bluest/latest/bluest/struct.Characteristic.html#method.uuid\n[Characteristic::properties]: https://docs.rs/bluest/latest/bluest/struct.Characteristic.html#method.properties\n[Characteristic::discover_descriptors]: https://docs.rs/bluest/latest/bluest/struct.Characteristic.html#method.discover_descriptors\n[Characteristic::read]: https://docs.rs/bluest/latest/bluest/struct.Characteristic.html#method.read\n[Characteristic::write]: https://docs.rs/bluest/latest/bluest/struct.Characteristic.html#method.write\n[Characteristic::write_without_response]: https://docs.rs/bluest/latest/bluest/struct.Characteristic.html#method.write_without_response\n[Characteristic::max_write_len]: https://docs.rs/bluest/latest/bluest/struct.Characteristic.html#method.max_write_len\n[Characteristic::notify]: https://docs.rs/bluest/latest/bluest/struct.Characteristic.html#method.notify\n[Descriptor::uuid]: https://docs.rs/bluest/latest/bluest/struct.Descriptor.html#method.uuid\n[Descriptor::read]: https://docs.rs/bluest/latest/bluest/struct.Descriptor.html#method.read\n[Descriptor::write]: https://docs.rs/bluest/latest/bluest/struct.Descriptor.html#method.write\n[Error::kind]: https://docs.rs/bluest/latest/bluest/error/struct.Error.html#method.kind\n[error::ErrorKind::NotSupported]: https://docs.rs/bluest/latest/bluest/error/enum.ErrorKind.html#variant.NotSupported\n[error::ErrorKind::Other]: https://docs.rs/bluest/latest/bluest/error/enum.ErrorKind.html#variant.Other\n[std::error::Error::source]: https://doc.rust-lang.org/stable/std/error/trait.Error.html#method.source\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexmoon%2Fbluest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexmoon%2Fbluest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexmoon%2Fbluest/lists"}