Salar.BluetoothLE
1.2.0
dotnet add package Salar.BluetoothLE --version 1.2.0
NuGet\Install-Package Salar.BluetoothLE -Version 1.2.0
<PackageReference Include="Salar.BluetoothLE" Version="1.2.0" />
<PackageVersion Include="Salar.BluetoothLE" Version="1.2.0" />
<PackageReference Include="Salar.BluetoothLE" />
paket add Salar.BluetoothLE --version 1.2.0
#r "nuget: Salar.BluetoothLE, 1.2.0"
#:package Salar.BluetoothLE@1.2.0
#addin nuget:?package=Salar.BluetoothLE&version=1.2.0
#tool nuget:?package=Salar.BluetoothLE&version=1.2.0
Salar.BluetoothLE
Salar.BluetoothLE is a cross-platform Bluetooth Low Energy (BLE) library for .NET applications. It gives you a clean, task-based API for common central/client workflows such as scanning for nearby devices, connecting, discovering GATT services and characteristics, reading values, writing data, and subscribing to notifications.
Please note that more than 90% of this library created by AI agents.
The library targets modern .NET applications on:
- Android
- iOS
- Linux
- Windows
- .NET MAUI apps through the companion
Salar.BluetoothLE.Mauipackage
Features
- Cross-platform BLE adapter abstraction
- Scan for nearby BLE peripherals with filtering and duplicate control
- Connect and reconnect by device address
- Discover GATT services and characteristics
- Read characteristic values
- Write characteristic values with or without response
- Subscribe to notifications and indications
- Observe adapter, scan, and library state changes
- DI-friendly registration for MAUI applications
- MAUI permission helpers for Bluetooth access flows
Links
- NuGet: Salar.BluetoothLE
- NuGet: Salar.BluetoothLE.Maui
Sample Apps
- Sample app:
samples/BleDemo.Maui - Sample console app:
samples/BleDemo.Console
Quick guide
1. Choose the package
Use the package that matches your app:
Salar.BluetoothLEfor the core BLE APISalar.BluetoothLE.Mauifor .NET MAUI convenience APIs such as Bluetooth permission helpers
dotnet add package Salar.BluetoothLE
dotnet add package Salar.BluetoothLE.Maui
2. Choose the correct TFM for your platform
Salar.BluetoothLE ships different implementations per target framework. If your app targets plain net9.0 or net10.0, that is the generic target and it is intended for Linux/non-platform-specific usage. It will not light up the Android, iOS, or Windows implementations.
Use a platform TFM that matches your app:
| Platform | Use one of these TFMs |
|---|---|
| Linux | net9.0 or net10.0 |
| Android | net9.0-android or net10.0-android |
| iOS | net9.0-ios or net10.0-ios |
| Windows | net9.0-windows10.0.19041.0 or net10.0-windows10.0.19041.0 |
Examples:
- a console app on Linux can target
net10.0 - an Android app must target
net10.0-android - a Windows desktop app must target
net10.0-windows10.0.19041.0
If you are using .NET MAUI, your app should multi-target the platform TFMs you want to support, such as net10.0-android, net10.0-ios, and net10.0-windows10.0.19041.0.
3. Register the BLE adapter in a MAUI app
If you are using .NET MAUI, register the adapter in MauiProgram.cs:
using Salar.BluetoothLE;
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>();
builder.Services.AddBluetoothLE();
return builder.Build();
}
}
4. Configure permissions
BLE applications need platform permissions.
- In .NET MAUI, use
PermissionHelper.RequestBluetoothAccess()fromSalar.BluetoothLE.Maui. - On Android, declare Bluetooth permissions in your app project. You can use the sample at
samples/BleDemo.Maui/Platforms/Android/AndroidPermissions.csas a starting point. - On Linux, install BlueZ, make sure the
bluetoothservice is running, and make sure the app can access the system D-Bus Bluetooth service.
Linux prerequisites
The Linux implementation talks directly to the system BlueZ service over D-Bus. Before running a Linux app with Salar.BluetoothLE, make sure the host is set up correctly:
Install the Bluetooth stack packages for your distro.
Debian/Ubuntu example:
sudo apt-get update sudo apt-get install -y bluez dbusOther distros should install their equivalent BlueZ and D-Bus packages.
Make sure the Bluetooth daemon is running.
sudo systemctl enable --now bluetooth sudo systemctl status bluetoothMake sure the machine actually has a Bluetooth adapter and that Linux can see it.
bluetoothctl listIf no adapter is listed, check your hardware, kernel drivers, or USB Bluetooth dongle support first.
Make sure Bluetooth is powered on.
bluetoothctl power onRun the app in an environment that can access the system D-Bus.
- On a normal Linux host, this usually just means running as a user that can talk to the system bus.
- In containers, minimal VMs, or CI environments, BlueZ and the system D-Bus socket may be missing even if the app itself builds successfully.
If Linux setup is incomplete, the library may report unavailable access or fail to find any Bluetooth adapters.
5. Quick start: scan, connect, and write data
The example below shows a typical BLE flow:
- request access
- scan for a device
- connect to the selected peripheral
- discover a service and characteristic
- write bytes to the characteristic
using System.Text;
using Salar.BluetoothLE;
using Salar.BluetoothLE.Core.Enums;
using Salar.BluetoothLE.Core.Interfaces;
using Salar.BluetoothLE.Core.Models;
public sealed class BleWorkflow
{
private readonly IBleAdapter _adapter;
public BleWorkflow(IBleAdapter adapter)
{
_adapter = adapter;
}
public async Task SendCommandAsync(Guid serviceUuid, Guid characteristicUuid, CancellationToken cancellationToken = default)
{
var access = await _adapter.RequestAccessAsync(cancellationToken);
if (access != BlePermissionStatus.Granted)
{
throw new InvalidOperationException("Bluetooth access was not granted.");
}
ScanResult? target = null;
var scanDuration = TimeSpan.FromSeconds(10);
using var subscription = _adapter.ScanResultReceived.Subscribe(result =>
{
if (result.Name == "My BLE Device")
{
target = result;
}
});
await _adapter.StartScanAsync(new ScanConfig
{
Duration = scanDuration,
ScanMode = ScanMode.LowLatency,
AllowDuplicates = false,
}, cancellationToken);
await Task.Delay(scanDuration, cancellationToken);
await _adapter.StopScanAsync(cancellationToken);
if (target is null)
{
throw new InvalidOperationException("Target device not found.");
}
using var device = await _adapter.ConnectAsync(target.Address, new ConnectionConfig
{
ConnectionTimeout = TimeSpan.FromSeconds(15),
RequestMtu = 247,
}, cancellationToken);
var service = await device.GetServiceAsync(serviceUuid, cancellationToken);
var characteristic = await service?.GetCharacteristicAsync(characteristicUuid, cancellationToken);
if (characteristic is null)
{
throw new InvalidOperationException("Characteristic not found.");
}
if (!characteristic.CanWrite && !characteristic.CanWriteWithoutResponse)
{
throw new InvalidOperationException("Characteristic does not support writes.");
}
var payload = Encoding.UTF8.GetBytes("hello from Salar.BluetoothLE");
var writeType = characteristic.CanWrite
? WriteType.WithResponse
: WriteType.WithoutResponse;
await characteristic.WriteAsync(payload, writeType, cancellationToken);
}
}
Library reference
This section highlights the most important API surface for day-to-day use.
IBleAdapter
IBleAdapter is the main entry point for BLE operations.
Properties
AdapterState: current Bluetooth adapter state (PoweredOn,PoweredOff,Unauthorized, ...)LibraryState: current library state (Idle,Scanning,Connecting)ConnectedDevices: currently connected BLE devices
Observables
AdapterStateChangedScanResultReceivedLibraryStateChanged
Key methods
RequestAccessAsync()StartScanAsync(ScanConfig? config = null)StopScanAsync()ConnectAsync(string address, ConnectionConfig? config = null)ReconnectAsync(string address, ConnectionConfig? config = null)
Example:
using var subscription = adapter.ScanResultReceived.Subscribe(result =>
{
Console.WriteLine($"{result.Name} | {result.Address} | RSSI {result.Rssi}");
});
await adapter.StartScanAsync(new ScanConfig
{
Duration = TimeSpan.FromSeconds(5),
ServiceUuidFilters = { serviceUuid },
ScanMode = ScanMode.Balanced,
});
await Task.Delay(TimeSpan.FromSeconds(5), cancellationToken);
await adapter.StopScanAsync(cancellationToken);
ScanConfig
Use ScanConfig to control scan behavior:
Duration: how long the scan should runServiceUuidFilters: optional service UUID filtersScanMode:LowPower,Balanced,LowLatency,OpportunisticAllowDuplicates: whether repeated advertisements should be emittedAndroidLegacyScan: Android-specific legacy mode toggle
IBleDevice
IBleDevice represents a connected peripheral.
Key members
IdNameStateMtuGetServicesAsync()GetServiceAsync(Guid serviceUuid)DisconnectAsync()RequestMtuAsync(int mtu)
Example:
var services = await device.GetServicesAsync(cancellationToken);
foreach (var service in services)
{
Console.WriteLine($"Service: {service.Uuid}");
}
IBleService
IBleService lets you inspect the GATT services exposed by a connected device.
UuidGetCharacteristicsAsync()GetCharacteristicAsync(Guid characteristicUuid)
IBleCharacteristic
IBleCharacteristic represents a GATT characteristic and exposes capability flags:
CanReadCanWriteCanWriteWithoutResponseCanNotifyCanIndicate
Important operations
ReadAsync()WriteAsync(byte[] data, WriteType writeType = WriteType.WithResponse)StartNotificationsAsync(Action<byte[]> handler)StopNotificationsAsync()
Example:
var value = await characteristic.ReadAsync(cancellationToken);
await characteristic.StartNotificationsAsync(data =>
{
Console.WriteLine(BitConverter.ToString(data));
}, cancellationToken);
ConnectionConfig
Use ConnectionConfig to tune connection behavior:
AutoConnectRequestMtuConnectionTimeout
Example:
var device = await adapter.ConnectAsync(address, new ConnectionConfig
{
AutoConnect = false,
RequestMtu = 247,
ConnectionTimeout = TimeSpan.FromSeconds(15),
}, cancellationToken);
PermissionHelper (Salar.BluetoothLE.Maui)
If you are building a MAUI app and reference Salar.BluetoothLE.Maui, use:
PermissionHelper.CheckBluetoothStatus()PermissionHelper.RequestBluetoothAccess()
Example:
using Salar.BluetoothLE.Maui;
var hasAccess = await PermissionHelper.RequestBluetoothAccess();
if (!hasAccess)
{
await DisplayAlert("Bluetooth", "Bluetooth permission is required.", "OK");
}
Notes
- The library is focused on BLE central/client scenarios.
- For end-to-end examples, see the MAUI and console samples included in this repository.
- On Android and iOS, always verify your app manifest and runtime permission flow before shipping.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-android35.0 is compatible. net9.0-browser was computed. net9.0-ios was computed. net9.0-ios18.0 is compatible. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net9.0-windows10.0.19041 is compatible. net10.0 is compatible. net10.0-android was computed. net10.0-android36.0 is compatible. net10.0-browser was computed. net10.0-ios was computed. net10.0-ios26.0 is compatible. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. net10.0-windows10.0.19041 is compatible. |
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- System.Reactive (>= 6.1.0)
- Tmds.DBus (>= 0.20.0)
-
net10.0-android36.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- System.Reactive (>= 6.1.0)
-
net10.0-ios26.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- System.Reactive (>= 6.1.0)
-
net10.0-windows10.0.19041
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- System.Reactive (>= 6.1.0)
-
net9.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- System.Reactive (>= 6.1.0)
- Tmds.DBus (>= 0.20.0)
-
net9.0-android35.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- System.Reactive (>= 6.1.0)
-
net9.0-ios18.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- System.Reactive (>= 6.1.0)
-
net9.0-windows10.0.19041
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- System.Reactive (>= 6.1.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Salar.BluetoothLE:
| Package | Downloads |
|---|---|
|
Salar.BluetoothLE.Maui
MAUI companion package for Salar.BluetoothLE. Provides DI registration helpers and Bluetooth permission utilities for .NET MAUI applications on Android, iOS, and Windows. |
GitHub repositories
This package is not used by any popular GitHub repositories.