A Ruby gem providing enterprise-grade, cross-platform Bluetooth Low Energy (BLE) functionality through Ruby bindings for the SimpleBLE C++ library. Delivers production-ready BLE scanning, device connection, and GATT operations.
gem install simpleble
require 'simpleble'
# Check if Bluetooth is available
SimpleBLE.bluetooth_enabled? # => true
# Get available Bluetooth adapters
adapters = SimpleBLE.adapters
adapter = adapters.first
puts adapter.identifier # => "Default Adapter [uuid]"
# Quick scan for BLE devices (5 second timeout)
devices = SimpleBLE.scan(5000)
puts "Found #{devices.length} BLE devices!"
# Advanced scanning with adapter control
adapter.scan_for(3000) # Scan for 3 seconds
peripherals = adapter.scan_results
peripherals.each do |device|
puts "Device: #{device.identifier} (#{device.address})"
end
- macOS - CoreBluetooth framework integration
- Linux - DBus/BlueZ backend support
- Windows - WinRT Bluetooth APIs (ready for testing)
- β Adapter discovery & identifiers
- β Bluetooth enabled check
- β Device scanning (blocking scan_for + continuous start/stop)
- β Peripheral information (identifier, address, RSSI, TX power, MTU, address_type)
- β Connection lifecycle (connect, disconnect, paired?, unpair)
- β Paired peripherals access
- β GATT service & characteristic enumeration with capabilities
- β Characteristic read/write operations (request & command modes)
- β Descriptor read/write operations
- β Manufacturer data & advertisement parsing
- π§ Notifications/Indications (callback support planned)
- β Core C extension foundation & memory management for adapters/peripherals
- β Exception hierarchy & native error mapping (scan/connection/characteristic errors)
- β Cross-platform build scripts (macOS/Linux/Windows all working)
- β Comprehensive adapter & peripheral API implemented
- β GATT operations layer with service/characteristic/descriptor access
- β Ruby-friendly API with helper methods and convenience features
- π§ Expanded test coverage (integration tests gated by hardware)
- π§ Notification/indication callback support
macOS:
- Xcode command line tools:
xcode-select --install
Linux:
# Ubuntu/Debian
sudo apt-get install build-essential libdbus-1-dev cmake
# Red Hat/CentOS
sudo yum install gcc-c++ dbus-devel cmake
Windows:
- Visual Studio Build Tools
- Windows SDK
- CMake
gem install simpleble
Or add to your Gemfile:
gem 'simpleble'
# Check Bluetooth availability
SimpleBLE.bluetooth_enabled? # => true/false
# Get all adapters (convenience method)
SimpleBLE.adapters # => [Adapter, ...]
# Quick scan with first available adapter
SimpleBLE.scan(timeout_ms) # => [Peripheral, ...]
# Get all available Bluetooth adapters
adapters = SimpleBLE::Adapter.get_adapters
adapter = adapters.first
# Adapter information
adapter.identifier # => "Default Adapter [uuid]"
adapter.address # => "XX:XX:XX:XX:XX:XX" (or UUID on macOS)
# Scanning operations
adapter.scan_start # Start continuous scan
adapter.scan_stop # Stop scanning
adapter.scan_for(timeout_ms) # Scan for specific duration
adapter.scan_active? # => true/false
adapter.scan_results # => [Peripheral, ...]
adapter.paired_peripherals # => [Peripheral, ...] - Previously paired devices
devices = SimpleBLE.scan(5000)
device = devices.first
# Basic information
device.identifier # Device name or identifier
device.address # MAC address or UUID
device.rssi # Signal strength in dBm
device.tx_power # Advertised TX power in dBm
device.mtu # Maximum transmission unit
device.address_type # Address type (public/random/unspecified)
# Connection management
device.connectable? # Whether device accepts connections
device.connected? # Current connection status
device.paired? # Whether device is paired
device.connect # Establish connection
device.disconnect # Close connection
device.unpair # Remove pairing
# GATT operations (requires connection)
services = device.services # => [{"uuid" => "...", "characteristics" => [...]}]
data = device.read_characteristic(service_uuid, char_uuid)
device.write_characteristic_request(service_uuid, char_uuid, data)
device.write_characteristic_command(service_uuid, char_uuid, data)
# Descriptor operations
desc_data = device.read_descriptor(service_uuid, char_uuid, desc_uuid)
device.write_descriptor(service_uuid, char_uuid, desc_uuid, data)
# Advertisement data
mfg_data = device.manufacturer_data # => [{"manufacturer_id" => 123, "data" => "..."}]
# Helper methods
device.name # Friendly name (identifier or address)
device.to_s # "Name (address)"
device.has_data? # Check if device has valid data
device.rssi_s # "-67 dBm"
device.address_type_s # "Public" / "Random" / "Unspecified"
Launch an interactive Ruby session with SimpleBLE loaded:
ruby -rsimpleble -e "
adapters = SimpleBLE.adapters
adapter = adapters.first
puts 'Try: SimpleBLE.scan(3000)'
require 'irb'; IRB.start
"
# Clone repository with submodules
git clone --recurse-submodules https://github.com/twilightcoders/ruby-simpleble.git
cd ruby-simpleble
# Or if you already cloned without submodules:
git submodule update --init --recursive
# Install dependencies
bundle install
# Compile the C extension
rake compile
# Run tests
rake test
# Update to latest SimpleBLE upstream
git submodule update --remote vendor/simpleble
# Verify the update
git submodule status
# Run all tests
bundle exec rspec
# Run with coverage
bundle exec rspec --format documentation
# Test specific functionality
bundle exec rspec spec/simpleble_spec.rb
SimpleBLE Ruby uses a layered architecture:
Ruby Application
β
SimpleBLE Ruby Wrapper (lib/simpleble.rb)
β
C Extension Layer (ext/simpleble/)
β
SimpleBLE C++ Library (vendor/simpleble/)
β
Platform BLE APIs (CoreBluetooth/BlueZ/WinRT)
- Ruby API Layer: Clean, idiomatic Ruby interface
- C Extension: Memory-safe Ruby β C++ bridge
- C++ Wrapper: Type-safe interface to SimpleBLE library
- SimpleBLE Library: Cross-platform BLE abstraction
- Platform Backends: OS-specific BLE implementations
Area | Implemented | Notes |
---|---|---|
Adapter enumeration | β | identifier, address |
Scanning (start/stop/for) | β | Timed & continuous |
Scan results retrieval | β | Returns Peripheral objects |
Peripheral basic info | β | identifier, address, RSSI, TX power, MTU, address_type |
Connection lifecycle | β | connect, disconnect, paired?, unpair |
Paired peripherals | β | Access to previously paired devices |
Services/Characteristics | β | Full enumeration with capabilities |
Characteristic I/O | β | Read/write with request & command modes |
| Descriptor I/O | β | Read/write operations | | Manufacturer data | β | Advertisement parsing | | Windows support | β | All platforms working | | Test coverage | π§ | Expanding beyond placeholders | | Documentation accuracy | β | Reflects current API |
- Notification/indication callbacks with GC-safe storage
- Hardware-gated integration test suite expansion
- Performance optimizations and memory usage analysis
- Precompiled native gem variants (later)
Platform | Status | Backend | Notes |
---|---|---|---|
macOS | β Working | CoreBluetooth | Full support, production tested |
Linux | β Working | BlueZ/DBus | CI passing, production ready |
Windows | β Working | WinRT | CI passing, production ready |
Building the SimpleBLE core for every Ruby version slows the matrix. Two knobs:
-
SIMPLEBLE_PREBUILT_LIB
β point to a prebuilt static library (and headers) so only the Ruby bridge compiles. -
SIMPLEBLE_REUSE_OBJECTS=1
β skipmake clean
and reuse previously cached.o
files.
Create a warmup job that builds once, packages tmp_flat/*.o
(or a consolidated libsimpleble_core.a
you produce via ar
), uploads as an artifact, then matrix jobs download and set:
env:
SIMPLEBLE_PREBUILT_LIB: path/to/libsimpleble_core.a
extconf.rb
detects this and links only the Ruby layer.
Use actions/cache
keyed on OS + hash of vendor/simpleble/**
:
- uses: actions/cache@v4
with:
path: ext/simpleble/tmp_flat
key: simpleble-obj-${{ runner.os }}-${{ hashFiles('vendor/simpleble/**') }}
Then set SIMPLEBLE_REUSE_OBJECTS: 1
so the compile task skips cleaning.
Var | Purpose |
---|---|
SIMPLEBLE_PREBUILT_LIB |
Path to prebuilt SimpleBLE static lib to link instead of compiling sources |
SIMPLEBLE_REUSE_OBJECTS |
If 1 , do not run make clean ; rely on cached object files |
Regenerate caches whenever the SimpleBLE submodule changes.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Run tests:
bundle exec rspec
- Commit your changes (
git commit -am 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE.txt file for details.
- SimpleBLE Library - The excellent cross-platform BLE library this gem wraps
- OpenBluetoothToolbox - For creating and maintaining SimpleBLE