rble 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +169 -0
- data/LICENSE.txt +21 -0
- data/README.md +514 -0
- data/exe/rble +14 -0
- data/ext/macos_ble/Package.swift +20 -0
- data/ext/macos_ble/Sources/RBLEHelper/BLEManager.swift +783 -0
- data/ext/macos_ble/Sources/RBLEHelper/Protocol.swift +173 -0
- data/ext/macos_ble/Sources/RBLEHelper/main.swift +645 -0
- data/ext/macos_ble/extconf.rb +73 -0
- data/lib/rble/backend/base.rb +181 -0
- data/lib/rble/backend/bluez.rb +1279 -0
- data/lib/rble/backend/corebluetooth.rb +653 -0
- data/lib/rble/backend.rb +193 -0
- data/lib/rble/bluez/adapter.rb +169 -0
- data/lib/rble/bluez/async_call.rb +85 -0
- data/lib/rble/bluez/async_connection_operations.rb +492 -0
- data/lib/rble/bluez/async_gatt_operations.rb +249 -0
- data/lib/rble/bluez/async_introspection.rb +151 -0
- data/lib/rble/bluez/dbus_connection.rb +64 -0
- data/lib/rble/bluez/dbus_session.rb +344 -0
- data/lib/rble/bluez/device.rb +86 -0
- data/lib/rble/bluez/event_loop.rb +153 -0
- data/lib/rble/bluez/gatt_operation_queue.rb +129 -0
- data/lib/rble/bluez/pairing_agent.rb +132 -0
- data/lib/rble/bluez/pairing_session.rb +212 -0
- data/lib/rble/bluez/retry_policy.rb +55 -0
- data/lib/rble/bluez.rb +33 -0
- data/lib/rble/characteristic.rb +237 -0
- data/lib/rble/cli/adapter.rb +88 -0
- data/lib/rble/cli/characteristic_helpers.rb +154 -0
- data/lib/rble/cli/doctor.rb +309 -0
- data/lib/rble/cli/formatters/json.rb +122 -0
- data/lib/rble/cli/formatters/text.rb +157 -0
- data/lib/rble/cli/hex_dump.rb +48 -0
- data/lib/rble/cli/monitor.rb +129 -0
- data/lib/rble/cli/pair.rb +103 -0
- data/lib/rble/cli/paired.rb +22 -0
- data/lib/rble/cli/read.rb +55 -0
- data/lib/rble/cli/scan.rb +88 -0
- data/lib/rble/cli/show.rb +109 -0
- data/lib/rble/cli/status.rb +25 -0
- data/lib/rble/cli/unpair.rb +39 -0
- data/lib/rble/cli/value_parser.rb +211 -0
- data/lib/rble/cli/write.rb +196 -0
- data/lib/rble/cli.rb +152 -0
- data/lib/rble/company_ids.rb +90 -0
- data/lib/rble/connection.rb +539 -0
- data/lib/rble/device.rb +54 -0
- data/lib/rble/errors.rb +317 -0
- data/lib/rble/gatt/uuid_database.rb +395 -0
- data/lib/rble/scanner.rb +219 -0
- data/lib/rble/service.rb +41 -0
- data/lib/rble/tasks/check.rake +154 -0
- data/lib/rble/tasks/integration.rake +242 -0
- data/lib/rble/tasks.rb +8 -0
- data/lib/rble/version.rb +5 -0
- data/lib/rble.rb +62 -0
- metadata +120 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :rble do
|
|
4
|
+
desc 'Check system BLE readiness'
|
|
5
|
+
task :check do
|
|
6
|
+
require_relative '../../rble'
|
|
7
|
+
|
|
8
|
+
checker = RBLE::SystemChecker.new
|
|
9
|
+
checker.run
|
|
10
|
+
exit(checker.success? ? 0 : 1)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module RBLE
|
|
15
|
+
# System BLE readiness checker
|
|
16
|
+
#
|
|
17
|
+
# Validates that the system is properly configured for BLE operations.
|
|
18
|
+
# Performs platform-specific checks and provides actionable fix suggestions.
|
|
19
|
+
#
|
|
20
|
+
# @api private
|
|
21
|
+
class SystemChecker
|
|
22
|
+
def initialize
|
|
23
|
+
@checks_run = 0
|
|
24
|
+
@failures = []
|
|
25
|
+
@suggestions = {}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Run all platform-specific checks
|
|
29
|
+
def run
|
|
30
|
+
puts "RBLE System Check"
|
|
31
|
+
puts "=" * 40
|
|
32
|
+
puts
|
|
33
|
+
|
|
34
|
+
case RUBY_PLATFORM
|
|
35
|
+
when /linux/
|
|
36
|
+
run_linux_checks
|
|
37
|
+
when /darwin/
|
|
38
|
+
run_macos_checks
|
|
39
|
+
else
|
|
40
|
+
puts "[FAIL] Unsupported platform: #{RUBY_PLATFORM}"
|
|
41
|
+
@failures << "Unsupported platform"
|
|
42
|
+
return
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
print_summary
|
|
46
|
+
print_suggestions unless @failures.empty?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Check if all checks passed
|
|
50
|
+
# @return [Boolean]
|
|
51
|
+
def success?
|
|
52
|
+
@failures.empty?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
# Run a single check with standardized output
|
|
58
|
+
#
|
|
59
|
+
# @param name [String] Check name
|
|
60
|
+
# @param suggestion [String, nil] Fix suggestion if check fails
|
|
61
|
+
# @yield Block that returns truthy/falsy result
|
|
62
|
+
def check(name, suggestion: nil)
|
|
63
|
+
@checks_run += 1
|
|
64
|
+
result = yield
|
|
65
|
+
if result
|
|
66
|
+
puts "[OK] #{name}"
|
|
67
|
+
true
|
|
68
|
+
else
|
|
69
|
+
puts "[FAIL] #{name}"
|
|
70
|
+
@failures << name
|
|
71
|
+
@suggestions[name] = suggestion if suggestion
|
|
72
|
+
false
|
|
73
|
+
end
|
|
74
|
+
rescue StandardError => e
|
|
75
|
+
puts "[FAIL] #{name}: #{e.message}"
|
|
76
|
+
@failures << name
|
|
77
|
+
@suggestions[name] = suggestion if suggestion
|
|
78
|
+
false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Linux-specific BLE readiness checks
|
|
82
|
+
def run_linux_checks
|
|
83
|
+
puts "Platform: Linux"
|
|
84
|
+
puts
|
|
85
|
+
|
|
86
|
+
check("BlueZ D-Bus service",
|
|
87
|
+
suggestion: "Install BlueZ: sudo apt install bluez") do
|
|
88
|
+
system("busctl list 2>/dev/null | grep -q org.bluez")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
check("bluetoothd running",
|
|
92
|
+
suggestion: "Start Bluetooth: sudo systemctl start bluetooth") do
|
|
93
|
+
system("systemctl is-active --quiet bluetooth 2>/dev/null") ||
|
|
94
|
+
system("pgrep -x bluetoothd >/dev/null 2>&1")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
check("Bluetooth adapter found",
|
|
98
|
+
suggestion: "No adapter found. Connect USB adapter or enable built-in.") do
|
|
99
|
+
RBLE.adapters.any?
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
check("Bluetooth adapter powered",
|
|
103
|
+
suggestion: "Enable adapter: bluetoothctl power on") do
|
|
104
|
+
RBLE.adapters.any? { |a| a[:powered] }
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# macOS-specific BLE readiness checks
|
|
109
|
+
def run_macos_checks
|
|
110
|
+
puts "Platform: macOS"
|
|
111
|
+
puts
|
|
112
|
+
|
|
113
|
+
# Determine helper path relative to gem root
|
|
114
|
+
helper_path = File.expand_path('../../../ext/macos_ble/.build/release/RBLEHelper', __dir__)
|
|
115
|
+
|
|
116
|
+
helper_exists = check("Helper binary exists",
|
|
117
|
+
suggestion: "Build helper: rake build:macos") do
|
|
118
|
+
File.exist?(helper_path)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
helper_executable = check("Helper binary executable",
|
|
122
|
+
suggestion: "Fix permissions: chmod +x #{helper_path}") do
|
|
123
|
+
File.executable?(helper_path)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Only try RBLE operations if helper exists and is executable
|
|
127
|
+
# This avoids triggering CoreBluetooth permission prompts unnecessarily
|
|
128
|
+
if helper_exists && helper_executable
|
|
129
|
+
check("Bluetooth powered",
|
|
130
|
+
suggestion: "Enable Bluetooth in System Settings > Bluetooth") do
|
|
131
|
+
RBLE.adapters.any? { |a| a[:powered] }
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Print summary of check results
|
|
137
|
+
def print_summary
|
|
138
|
+
puts
|
|
139
|
+
passed = @checks_run - @failures.length
|
|
140
|
+
puts "#{passed}/#{@checks_run} checks passed"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Print grouped fix suggestions for failures
|
|
144
|
+
def print_suggestions
|
|
145
|
+
puts
|
|
146
|
+
puts "Suggestions:"
|
|
147
|
+
@failures.each do |name|
|
|
148
|
+
if (suggestion = @suggestions[name])
|
|
149
|
+
puts " - #{name}: #{suggestion}"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :test do
|
|
4
|
+
desc 'Run integration test with real BLE hardware'
|
|
5
|
+
task :integration do
|
|
6
|
+
require_relative '../../rble'
|
|
7
|
+
|
|
8
|
+
test = RBLE::IntegrationTest.new
|
|
9
|
+
test.run
|
|
10
|
+
exit(test.success? ? 0 : 1)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module RBLE
|
|
15
|
+
# Dynamic integration test for BLE hardware
|
|
16
|
+
#
|
|
17
|
+
# Scans for devices, then tries each device until finding one with
|
|
18
|
+
# a readable characteristic. Prioritizes devices advertising Device
|
|
19
|
+
# Information Service (0x180A) for reliability.
|
|
20
|
+
#
|
|
21
|
+
# @api private
|
|
22
|
+
class IntegrationTest
|
|
23
|
+
DEVICE_INFO_SERVICE = '180a'
|
|
24
|
+
MANUFACTURER_NAME = '2a29'
|
|
25
|
+
MODEL_NUMBER = '2a24'
|
|
26
|
+
SCAN_TIMEOUT = 5
|
|
27
|
+
CONNECTION_TIMEOUT = 10
|
|
28
|
+
|
|
29
|
+
def initialize
|
|
30
|
+
@success = false
|
|
31
|
+
@connection = nil
|
|
32
|
+
@results = []
|
|
33
|
+
@devices = []
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Run the integration test
|
|
37
|
+
def run
|
|
38
|
+
scan_for_devices
|
|
39
|
+
return if @devices.empty?
|
|
40
|
+
|
|
41
|
+
try_devices_until_success
|
|
42
|
+
rescue StandardError => e
|
|
43
|
+
puts "Error: #{e.message}"
|
|
44
|
+
@results << "Error: #{e.class} - #{e.message}"
|
|
45
|
+
ensure
|
|
46
|
+
cleanup
|
|
47
|
+
print_summary
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Check if test passed
|
|
51
|
+
# @return [Boolean]
|
|
52
|
+
def success?
|
|
53
|
+
@success
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def scan_for_devices
|
|
59
|
+
puts "Scanning for BLE devices (#{SCAN_TIMEOUT}s timeout)..."
|
|
60
|
+
|
|
61
|
+
scanner = Scanner.new(timeout: SCAN_TIMEOUT)
|
|
62
|
+
scanner.start do |device|
|
|
63
|
+
# Deduplicate by address
|
|
64
|
+
unless @devices.any? { |d| d.address == device.address }
|
|
65
|
+
@devices << device
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
if @devices.empty?
|
|
70
|
+
puts
|
|
71
|
+
puts "No BLE devices found."
|
|
72
|
+
puts "Suggestions:"
|
|
73
|
+
puts " - Ensure BLE devices are nearby and advertising"
|
|
74
|
+
puts " - Check that Bluetooth adapter is enabled (rake rble:check)"
|
|
75
|
+
puts " - Try increasing scan time or moving closer to devices"
|
|
76
|
+
@results << "No devices found"
|
|
77
|
+
return
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
puts "Found #{@devices.length} device(s)"
|
|
81
|
+
@results << "Scanned and found #{@devices.length} device(s)"
|
|
82
|
+
|
|
83
|
+
# Sort: prefer devices with Device Information Service
|
|
84
|
+
@devices.sort_by! do |d|
|
|
85
|
+
has_device_info = d.service_uuids.any? { |uuid| uuid.downcase.include?(DEVICE_INFO_SERVICE) }
|
|
86
|
+
has_device_info ? 0 : 1
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def try_devices_until_success
|
|
91
|
+
@devices.each_with_index do |device, index|
|
|
92
|
+
device_name = device.name || 'unnamed'
|
|
93
|
+
puts
|
|
94
|
+
puts "Trying device #{index + 1}/#{@devices.length}: #{device_name} (#{device.address})"
|
|
95
|
+
|
|
96
|
+
result = try_device(device)
|
|
97
|
+
if result == :success
|
|
98
|
+
@success = true
|
|
99
|
+
return
|
|
100
|
+
end
|
|
101
|
+
# Continue to next device on :no_readable or :connection_failed
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
puts
|
|
105
|
+
puts "Tried all #{@devices.length} device(s), none had readable characteristics"
|
|
106
|
+
@results << "No device with readable characteristics found"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Try a single device: connect, discover, read
|
|
110
|
+
# Returns :success, :no_readable, or :connection_failed
|
|
111
|
+
def try_device(device)
|
|
112
|
+
# Connect
|
|
113
|
+
puts " Connecting..."
|
|
114
|
+
begin
|
|
115
|
+
@connection = RBLE.connect(device.address, timeout: CONNECTION_TIMEOUT)
|
|
116
|
+
puts " Connected!"
|
|
117
|
+
rescue ConnectionTimeoutError
|
|
118
|
+
puts " Connection timed out, skipping..."
|
|
119
|
+
return :connection_failed
|
|
120
|
+
rescue ConnectionError => e
|
|
121
|
+
puts " Connection failed: #{e.message}, skipping..."
|
|
122
|
+
return :connection_failed
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Discover services
|
|
126
|
+
puts " Discovering services..."
|
|
127
|
+
services = @connection.discover_services
|
|
128
|
+
char_count = services.sum { |s| s.characteristics.length }
|
|
129
|
+
puts " Found #{services.length} services, #{char_count} characteristics"
|
|
130
|
+
|
|
131
|
+
# Find and read a characteristic
|
|
132
|
+
char = find_readable_characteristic(services)
|
|
133
|
+
unless char
|
|
134
|
+
puts " No readable characteristics, trying next device..."
|
|
135
|
+
disconnect_quietly
|
|
136
|
+
return :no_readable
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Read the characteristic
|
|
140
|
+
puts " Reading #{char_name(char)} (#{char.short_uuid})..."
|
|
141
|
+
value = char.read
|
|
142
|
+
display = format_value(value)
|
|
143
|
+
puts " Value: #{display.inspect}"
|
|
144
|
+
|
|
145
|
+
# Record success
|
|
146
|
+
device_name = device.name || 'unnamed'
|
|
147
|
+
@results << "Connected to #{device_name}"
|
|
148
|
+
@results << "Discovered #{services.length} services"
|
|
149
|
+
truncated = display.length > 50 ? "#{display[0..47]}..." : display
|
|
150
|
+
@results << "Read characteristic #{char.short_uuid}: #{truncated}"
|
|
151
|
+
|
|
152
|
+
:success
|
|
153
|
+
rescue StandardError => e
|
|
154
|
+
puts " Error: #{e.message}, trying next device..."
|
|
155
|
+
disconnect_quietly
|
|
156
|
+
:connection_failed
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def find_readable_characteristic(services)
|
|
160
|
+
# First try Device Information Service
|
|
161
|
+
device_info = services.find { |s| s.short_uuid == DEVICE_INFO_SERVICE }
|
|
162
|
+
|
|
163
|
+
if device_info
|
|
164
|
+
# Prefer Manufacturer Name, then Model Number
|
|
165
|
+
[MANUFACTURER_NAME, MODEL_NUMBER].each do |uuid|
|
|
166
|
+
char = device_info.characteristics.find { |c| c.short_uuid == uuid && c.readable? }
|
|
167
|
+
return char if char
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Try any readable char in Device Info service
|
|
171
|
+
char = device_info.characteristics.find(&:readable?)
|
|
172
|
+
return char if char
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Fallback: any readable characteristic from any service
|
|
176
|
+
services.each do |service|
|
|
177
|
+
char = service.characteristics.find(&:readable?)
|
|
178
|
+
return char if char
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
nil
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def format_value(value)
|
|
185
|
+
if value.bytes.all? { |b| (b >= 32 && b < 127) || b == 0 }
|
|
186
|
+
# Remove null terminators and clean up
|
|
187
|
+
value.force_encoding('UTF-8').gsub("\x00", '')
|
|
188
|
+
else
|
|
189
|
+
# Display as hex for binary data
|
|
190
|
+
value.bytes.map { |b| format('%02x', b) }.join(' ')
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def char_name(char)
|
|
195
|
+
case char.short_uuid
|
|
196
|
+
when MANUFACTURER_NAME then 'Manufacturer Name'
|
|
197
|
+
when MODEL_NUMBER then 'Model Number'
|
|
198
|
+
when '2a25' then 'Serial Number'
|
|
199
|
+
when '2a27' then 'Hardware Revision'
|
|
200
|
+
when '2a26' then 'Firmware Revision'
|
|
201
|
+
when '2a28' then 'Software Revision'
|
|
202
|
+
else 'Characteristic'
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def disconnect_quietly
|
|
207
|
+
return unless @connection
|
|
208
|
+
|
|
209
|
+
@connection.disconnect if @connection.connected?
|
|
210
|
+
rescue StandardError
|
|
211
|
+
# Ignore disconnect errors
|
|
212
|
+
ensure
|
|
213
|
+
@connection = nil
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def cleanup
|
|
217
|
+
return unless @connection
|
|
218
|
+
|
|
219
|
+
begin
|
|
220
|
+
if @connection.connected?
|
|
221
|
+
puts
|
|
222
|
+
puts "Disconnecting..."
|
|
223
|
+
@connection.disconnect
|
|
224
|
+
puts "Disconnected"
|
|
225
|
+
end
|
|
226
|
+
rescue StandardError => e
|
|
227
|
+
puts "Disconnect warning: #{e.message}"
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def print_summary
|
|
232
|
+
puts
|
|
233
|
+
puts '=' * 40
|
|
234
|
+
if @success
|
|
235
|
+
puts 'Integration test PASSED'
|
|
236
|
+
else
|
|
237
|
+
puts 'Integration test FAILED'
|
|
238
|
+
end
|
|
239
|
+
@results.each { |r| puts " - #{r}" }
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
end
|
data/lib/rble/tasks.rb
ADDED
data/lib/rble/version.rb
ADDED
data/lib/rble.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'rble/version'
|
|
4
|
+
require_relative 'rble/errors'
|
|
5
|
+
require_relative 'rble/device'
|
|
6
|
+
require_relative 'rble/service'
|
|
7
|
+
require_relative 'rble/characteristic'
|
|
8
|
+
require_relative 'rble/backend'
|
|
9
|
+
require_relative 'rble/scanner'
|
|
10
|
+
require_relative 'rble/connection'
|
|
11
|
+
|
|
12
|
+
module RBLE
|
|
13
|
+
class << self
|
|
14
|
+
# Logger for debug output
|
|
15
|
+
# Set to a Logger instance with debug level to see notification flow
|
|
16
|
+
# @example
|
|
17
|
+
# RBLE.logger = Logger.new(STDOUT)
|
|
18
|
+
# RBLE.logger.level = Logger::DEBUG
|
|
19
|
+
attr_accessor :logger
|
|
20
|
+
|
|
21
|
+
# Enable trace-level output for connection timing and D-Bus call flow
|
|
22
|
+
# @example
|
|
23
|
+
# RBLE.trace = true
|
|
24
|
+
attr_accessor :trace
|
|
25
|
+
|
|
26
|
+
# Global warning flag. Defaults to true.
|
|
27
|
+
# Set to false to suppress feature-level warnings from RBLE.
|
|
28
|
+
# @example
|
|
29
|
+
# RBLE.warnings = false
|
|
30
|
+
attr_writer :warnings
|
|
31
|
+
|
|
32
|
+
def warnings
|
|
33
|
+
@warnings.nil? ? true : @warnings
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Output a warning with [RBLE] prefix, respecting RBLE.warnings flag.
|
|
37
|
+
# @param message [String] Warning message
|
|
38
|
+
def rble_warn(message)
|
|
39
|
+
return unless warnings
|
|
40
|
+
|
|
41
|
+
warn "[RBLE] #{message}"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Backend selection API - delegates to RBLE::Backend
|
|
46
|
+
|
|
47
|
+
def self.backend
|
|
48
|
+
Backend.backend
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.backend=(value)
|
|
52
|
+
Backend.backend = value
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.available_backends
|
|
56
|
+
Backend.available_backends
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.backend_info
|
|
60
|
+
Backend.backend_info
|
|
61
|
+
end
|
|
62
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rble
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.7.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jonas Tehler
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: thor
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '1.3'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '1.3'
|
|
26
|
+
description: Reliable BLE communication for Ruby - scanning, connections, GATT operations
|
|
27
|
+
on Linux (BlueZ/D-Bus) and macOS (CoreBluetooth). Includes standalone rble CLI tool.
|
|
28
|
+
email:
|
|
29
|
+
- jonas@tehler.se
|
|
30
|
+
executables:
|
|
31
|
+
- rble
|
|
32
|
+
extensions:
|
|
33
|
+
- ext/macos_ble/extconf.rb
|
|
34
|
+
extra_rdoc_files: []
|
|
35
|
+
files:
|
|
36
|
+
- CHANGELOG.md
|
|
37
|
+
- LICENSE.txt
|
|
38
|
+
- README.md
|
|
39
|
+
- exe/rble
|
|
40
|
+
- ext/macos_ble/Package.swift
|
|
41
|
+
- ext/macos_ble/Sources/RBLEHelper/BLEManager.swift
|
|
42
|
+
- ext/macos_ble/Sources/RBLEHelper/Protocol.swift
|
|
43
|
+
- ext/macos_ble/Sources/RBLEHelper/main.swift
|
|
44
|
+
- ext/macos_ble/extconf.rb
|
|
45
|
+
- lib/rble.rb
|
|
46
|
+
- lib/rble/backend.rb
|
|
47
|
+
- lib/rble/backend/base.rb
|
|
48
|
+
- lib/rble/backend/bluez.rb
|
|
49
|
+
- lib/rble/backend/corebluetooth.rb
|
|
50
|
+
- lib/rble/bluez.rb
|
|
51
|
+
- lib/rble/bluez/adapter.rb
|
|
52
|
+
- lib/rble/bluez/async_call.rb
|
|
53
|
+
- lib/rble/bluez/async_connection_operations.rb
|
|
54
|
+
- lib/rble/bluez/async_gatt_operations.rb
|
|
55
|
+
- lib/rble/bluez/async_introspection.rb
|
|
56
|
+
- lib/rble/bluez/dbus_connection.rb
|
|
57
|
+
- lib/rble/bluez/dbus_session.rb
|
|
58
|
+
- lib/rble/bluez/device.rb
|
|
59
|
+
- lib/rble/bluez/event_loop.rb
|
|
60
|
+
- lib/rble/bluez/gatt_operation_queue.rb
|
|
61
|
+
- lib/rble/bluez/pairing_agent.rb
|
|
62
|
+
- lib/rble/bluez/pairing_session.rb
|
|
63
|
+
- lib/rble/bluez/retry_policy.rb
|
|
64
|
+
- lib/rble/characteristic.rb
|
|
65
|
+
- lib/rble/cli.rb
|
|
66
|
+
- lib/rble/cli/adapter.rb
|
|
67
|
+
- lib/rble/cli/characteristic_helpers.rb
|
|
68
|
+
- lib/rble/cli/doctor.rb
|
|
69
|
+
- lib/rble/cli/formatters/json.rb
|
|
70
|
+
- lib/rble/cli/formatters/text.rb
|
|
71
|
+
- lib/rble/cli/hex_dump.rb
|
|
72
|
+
- lib/rble/cli/monitor.rb
|
|
73
|
+
- lib/rble/cli/pair.rb
|
|
74
|
+
- lib/rble/cli/paired.rb
|
|
75
|
+
- lib/rble/cli/read.rb
|
|
76
|
+
- lib/rble/cli/scan.rb
|
|
77
|
+
- lib/rble/cli/show.rb
|
|
78
|
+
- lib/rble/cli/status.rb
|
|
79
|
+
- lib/rble/cli/unpair.rb
|
|
80
|
+
- lib/rble/cli/value_parser.rb
|
|
81
|
+
- lib/rble/cli/write.rb
|
|
82
|
+
- lib/rble/company_ids.rb
|
|
83
|
+
- lib/rble/connection.rb
|
|
84
|
+
- lib/rble/device.rb
|
|
85
|
+
- lib/rble/errors.rb
|
|
86
|
+
- lib/rble/gatt/uuid_database.rb
|
|
87
|
+
- lib/rble/scanner.rb
|
|
88
|
+
- lib/rble/service.rb
|
|
89
|
+
- lib/rble/tasks.rb
|
|
90
|
+
- lib/rble/tasks/check.rake
|
|
91
|
+
- lib/rble/tasks/integration.rake
|
|
92
|
+
- lib/rble/version.rb
|
|
93
|
+
homepage: https://github.com/jegt/rble
|
|
94
|
+
licenses:
|
|
95
|
+
- MIT
|
|
96
|
+
metadata:
|
|
97
|
+
homepage_uri: https://github.com/jegt/rble
|
|
98
|
+
source_code_uri: https://github.com/jegt/rble/tree/main
|
|
99
|
+
changelog_uri: https://github.com/jegt/rble/blob/main/CHANGELOG.md
|
|
100
|
+
documentation_uri: https://github.com/jegt/rble/blob/main/README.md
|
|
101
|
+
bug_tracker_uri: https://github.com/jegt/rble/issues
|
|
102
|
+
rubygems_mfa_required: 'true'
|
|
103
|
+
rdoc_options: []
|
|
104
|
+
require_paths:
|
|
105
|
+
- lib
|
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '3.2'
|
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
112
|
+
requirements:
|
|
113
|
+
- - ">="
|
|
114
|
+
- !ruby/object:Gem::Version
|
|
115
|
+
version: '0'
|
|
116
|
+
requirements: []
|
|
117
|
+
rubygems_version: 4.0.7
|
|
118
|
+
specification_version: 4
|
|
119
|
+
summary: BLE communication library for Ruby with CoreBluetooth and BlueZ backends
|
|
120
|
+
test_files: []
|