Class: BLE::Device
Overview
Defined Under Namespace
Classes: NotConnected
Instance Attribute Summary collapse
-
#requires_connection ⇒ Object
Returns the value of attribute requires_connection.
Instance Method Summary collapse
-
#[](service, characteristic, raw: false, async: false) ⇒ Object
(also: #read)
Get value for a service/characteristic.
-
#[]=(service, characteristic, val, raw: false, async: false) ⇒ void
(also: #write)
Set value for a service/characteristic.
-
#address ⇒ String
The Bluetooth device address of the remote device.
-
#alias ⇒ String
The name alias for the remote device.
-
#alias=(val) ⇒ void
Setting an empty string or nil as alias will convert it back to the remote device name.
- #async_read(service, characteristic, raw: false) ⇒ Object
- #async_write(service, characteristic, val, raw: false) ⇒ Object
-
#blocked=(val) ⇒ void
If set to true any incoming connections from the device will be immediately rejected.
-
#cancel_pairing ⇒ Boolean
This method can be used to cancel a pairing operation initiated by the Pair method.
-
#characteristics(service) ⇒ Array<String>?
List of available characteristics UUID for a service.
-
#connect(profile = :all) ⇒ Boolean
This connect to the specified profile UUID or to any (:all) profiles the remote device supports that can be connected to and have been flagged as auto-connectable on our side.
-
#disconnect(profile = :all) ⇒ Boolean
This method gracefully disconnects :all connected profiles and then terminates low-level ACL connection.
-
#has_service?(service) ⇒ Boolean
Check if service is available on the device.
-
#initialize(adapter, dev, auto_refresh: true) ⇒ Device
constructor
A new instance of Device.
-
#is_blocked? ⇒ Boolean
Is the device blocked?.
-
#is_connected? ⇒ Boolean
Indicates if the remote device is currently connected.
-
#is_paired? ⇒ Boolean
Indicates if the remote device is paired.
-
#is_trusted? ⇒ Boolean
Is the device trusted?.
-
#name ⇒ String
The Bluetooth remote name.
-
#pair ⇒ Boolean
This method will connect to the remote device, initiate pairing and then retrieve all SDP records (or GATT primary services).
-
#refresh ⇒ Boolean
Refresh list of services and characteristics.
-
#refresh! ⇒ self
Refresh list of services and characteristics.
-
#remove ⇒ Boolean
This removes the remote device object.
-
#rssi ⇒ Integer
Received Signal Strength Indicator of the remote device (inquiry or advertising).
-
#services ⇒ Array<String>
List of available services as UUID.
- #subscribe(service, characteristic, raw: false, &block) ⇒ Object
-
#trusted=(val) ⇒ void
Indicates if the remote is seen as trusted.
-
#tx_power ⇒ Integer
Advertised transmitted power level (inquiry or advertising).
Methods included from Notifications
#on_notification, #start_notify!
Constructor Details
#initialize(adapter, dev, auto_refresh: true) ⇒ Device
Returns a new instance of Device.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/ble/device.rb', line 21 def initialize(adapter, dev, auto_refresh: true) @adapter, @dev = adapter, dev @auto_refresh = auto_refresh @services = {} @n_adapter = adapter @p_adapter = "/org/bluez/#{@n_adapter}" @o_adapter = BLUEZ.object(@p_adapter) @o_adapter.introspect @n_dev = 'dev_' + dev.tr(':', '_') @p_dev = "/org/bluez/#{@n_adapter}/#{@n_dev}" @o_dev = BLUEZ.object(@p_dev) @o_dev.introspect self.refresh if @auto_refresh @o_dev[I_PROPERTIES] .on_signal('PropertiesChanged') do |intf, props| case intf when I_DEVICE case props['Connected'] when true self.refresh if @auto_refresh end end end end |
Instance Attribute Details
#requires_connection ⇒ Object
Returns the value of attribute requires_connection.
15 16 17 |
# File 'lib/ble/device.rb', line 15 def requires_connection @requires_connection end |
Instance Method Details
#[](service, characteristic, raw: false, async: false) ⇒ Object Also known as: read
Get value for a service/characteristic.
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 |
# File 'lib/ble/device.rb', line 401 def [](service, characteristic, raw: false, async: false) _require_connection! uuid = _uuid_characteristic(characteristic) chars = _characteristics(service) raise Service::NotFound, service if chars.nil? char = chars[uuid] raise Characteristic::NotFound, characteristic if char.nil? if char.flag?('read') async ? char.async_read(raw: raw) : char.read(raw: raw) elsif char.flag?('encrypt-read') || char.flag?('encrypt-authenticated-read') raise NotYetImplemented else raise AccessUnavailable end end |
#[]=(service, characteristic, val, raw: false, async: false) ⇒ void Also known as: write
This method returns an undefined value.
Set value for a service/characteristic
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 |
# File 'lib/ble/device.rb', line 434 def []=(service, characteristic, val, raw: false, async: false) _require_connection! uuid = _uuid_characteristic(characteristic) chars = _characteristics(service) raise Service::NotFound, service if chars.nil? char = chars[uuid] raise Characteristic::NotFound, characteristic if char.nil? if char.flag?('write') || char.flag?('write-without-response') async ? char.async_write(val, raw: raw) : char.write(val, raw: raw) elsif char.flag?('encrypt-write') || char.flag?('encrypt-authenticated-write') raise NotYetImplemented else raise AccessUnavailable end end |
#address ⇒ String
The Bluetooth device address of the remote device.
253 254 255 |
# File 'lib/ble/device.rb', line 253 def address @o_dev[I_DEVICE]['Address'] end |
#alias ⇒ String
The name alias for the remote device. The alias can be used to have a different friendly name for the remote device. In case no alias is set, it will return the remote device name.
270 271 272 |
# File 'lib/ble/device.rb', line 270 def alias @o_dev[I_DEVICE]['Alias'] end |
#alias=(val) ⇒ void
This method returns an undefined value.
Setting an empty string or nil as alias will convert it back to the remote device name.
277 278 279 |
# File 'lib/ble/device.rb', line 277 def alias=(val) @o_dev[I_DEVICE]['Alias'] = val.nil? ? "" : val.to_str end |
#async_read(service, characteristic, raw: false) ⇒ Object
419 420 421 |
# File 'lib/ble/device.rb', line 419 def async_read service, characteristic, raw: false read service, characteristic, raw: raw, async: true end |
#async_write(service, characteristic, val, raw: false) ⇒ Object
453 454 455 |
# File 'lib/ble/device.rb', line 453 def async_write(service, characteristic, val, raw: false) write service, characteristic, val, raw: raw, async: true end |
#blocked=(val) ⇒ void
This method returns an undefined value.
If set to true any incoming connections from the device will be immediately rejected. Any device drivers will also be removed and no new ones will be probed as long as the device is blocked
310 311 312 313 314 315 |
# File 'lib/ble/device.rb', line 310 def blocked=(val) if ! [ true, false ].include?(val) raise ArgumentError, "value must be a boolean" end @o_dev[I_DEVICE]['Blocked'] = val end |
#cancel_pairing ⇒ Boolean
This method can be used to cancel a pairing operation initiated by the Pair method.
101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/ble/device.rb', line 101 def cancel_pairing block_given? ? @o_dev[I_DEVICE].CancelPairing(&Proc.new) : @o_dev[I_DEVICE].CancelPairing() true rescue DBus::Error => e case e.name when E_DOES_NOT_EXIST then true when E_FAILED then false else raise ScriptError end end |
#characteristics(service) ⇒ Array<String>?
The list is retrieve once when object is connected if auto_refresh is enable, otherwise you need to call #refresh.
List of available characteristics UUID for a service.
244 245 246 247 248 249 |
# File 'lib/ble/device.rb', line 244 def characteristics(service) _require_connection! if chars = _characteristics(service) chars.keys end end |
#connect(profile = :all) ⇒ Boolean
This connect to the specified profile UUID or to any (:all) profiles the remote device supports that can be connected to and have been flagged as auto-connectable on our side. If only subset of profiles is already connected it will try to connect currently disconnected ones. If at least one profile was connected successfully this method will indicate success.
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/ble/device.rb', line 121 def connect(profile=:all) case profile when UUID::REGEX block_given? ? @o_dev[I_DEVICE].ConnectProfile(profile, &Proc.new) : @o_dev[I_DEVICE].ConnectProfile(profile) when :all block_given? ? @o_dev[I_DEVICE].Connect(&Proc.new) : @o_dev[I_DEVICE].Connect() else raise ArgumentError, "profile uuid or :all expected" end true rescue DBus::Error => e case e.name when E_NOT_READY when E_FAILED when E_IN_PROGRESS false when E_ALREADY_CONNECTED true when E_UNKNOWN_OBJECT raise StalledObject else raise ScriptError end end |
#disconnect(profile = :all) ⇒ Boolean
This method gracefully disconnects :all connected profiles and then terminates low-level ACL connection. ACL connection will be terminated even if some profiles were not disconnected properly e.g. due to misbehaving device. This method can be also used to cancel a preceding #connect call before a reply to it has been received. If a profile UUID is specified, only this profile is disconnected, and as their is no connection tracking for a profile, so as long as the profile is registered this will always succeed
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/ble/device.rb', line 156 def disconnect(profile=:all) case profile when UUID::REGEX block_given? ? @o_dev[I_DEVICE].DisconnectProfile(profile, &Proc.new) : @o_dev[I_DEVICE].DisconnectProfile(profile) when :all block_given? ? @o_dev[I_DEVICE].Disconnect(&Proc.new) : @o_dev[I_DEVICE].Disconnect() else raise ArgumentError, "profile uuid or :all expected" end true rescue DBus::Error => e case e.name when E_FAILED when E_IN_PROGRESS false when E_INVALID_ARGUMENTS raise ArgumentError, "unsupported profile (#{profile})" when E_NOT_SUPPORTED raise NotSupported when E_NOT_CONNECTED true when E_UNKNOWN_OBJECT raise StalledObject else raise ScriptError end end |
#has_service?(service) ⇒ Boolean
Check if service is available on the device
230 231 232 |
# File 'lib/ble/device.rb', line 230 def has_service?(service) @service.key?(_uuid_service(service)) end |
#is_blocked? ⇒ Boolean
Is the device blocked?
300 301 302 |
# File 'lib/ble/device.rb', line 300 def is_blocked? @o_dev[I_DEVICE]['Blocked'] end |
#is_connected? ⇒ Boolean
Indicates if the remote device is currently connected.
196 197 198 199 200 201 202 203 204 |
# File 'lib/ble/device.rb', line 196 def is_connected? !@requires_connection || @o_dev[I_DEVICE]['Connected'] rescue DBus::Error => e case e.name when E_UNKNOWN_OBJECT raise StalledObject else raise ScriptError end end |
#is_paired? ⇒ Boolean
Indicates if the remote device is paired
185 186 187 188 189 190 191 192 193 |
# File 'lib/ble/device.rb', line 185 def is_paired? @o_dev[I_DEVICE]['Paired'] rescue DBus::Error => e case e.name when E_UNKNOWN_OBJECT raise StalledObject else raise ScriptError end end |
#is_trusted? ⇒ Boolean
Is the device trusted?
283 284 285 |
# File 'lib/ble/device.rb', line 283 def is_trusted? @o_dev[I_DEVICE]['Trusted'] end |
#name ⇒ String
The Bluetooth remote name. It is better to always use the #alias when displaying the devices name.
261 262 263 |
# File 'lib/ble/device.rb', line 261 def name # optional @o_dev[I_DEVICE]['Name'] end |
#pair ⇒ Boolean
This method will connect to the remote device, initiate pairing and then retrieve all SDP records (or GATT primary services). If the application has registered its own agent, then that specific agent will be used. Otherwise it will use the default agent. Only for applications like a pairing wizard it would make sense to have its own agent. In almost all other cases the default agent will handle this just fine. In case there is no application agent and also no default agent present, this method will fail.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/ble/device.rb', line 80 def pair block_given? ? @o_dev[I_DEVICE].Pair(&Proc.new) : @o_dev[I_DEVICE].Pair() true rescue DBus::Error => e case e.name when E_INVALID_ARGUMENTS then false when E_FAILED then false when E_ALREADY_EXISTS then true when E_AUTH_CANCELED then raise NotAuthorized when E_AUTH_FAILED then raise NotAuthorized when E_AUTH_REJECTED then raise NotAuthorized when E_AUTH_TIMEOUT then raise NotAuthorized when E_AUTH_ATTEMPT_FAILED then raise NotAuthorized else raise ScriptError end end |
#refresh ⇒ Boolean
Refresh list of services and characteristics
343 344 345 346 347 348 |
# File 'lib/ble/device.rb', line 343 def refresh refresh! true rescue NotConnected, StalledObject false end |
#refresh! ⇒ self
Refresh list of services and characteristics
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 |
# File 'lib/ble/device.rb', line 353 def refresh! _require_connection! max_wait ||= 1.5 # Use ||= due to the retry @services = Hash[@o_dev.subnodes.map {|p_srv| p_srv = [@o_dev.path, p_srv].join '/' o_srv = BLUEZ.object(p_srv) o_srv.introspect srv = o_srv.GetAll(I_GATT_SERVICE).first char = Hash[o_srv.subnodes.map {|char| p_char = [o_srv.path, char].join '/' o_char = BLUEZ.object(p_char) o_char.introspect uuid = o_char[I_GATT_CHARACTERISTIC]['UUID' ].downcase flags = o_char[I_GATT_CHARACTERISTIC]['Flags'] [ uuid, Characteristic.new({ :uuid => uuid, :flags => flags, :obj => o_char }) ] }] uuid = srv['UUID'].downcase [ uuid, { :uuid => uuid, :primary => srv['Primary'], :characteristics => char } ] }] self rescue DBus::Error => e case e.name when E_UNKNOWN_OBJECT raise StalledObject when E_INVALID_ARGS # That's probably because all the bluez information # haven't been collected yet on dbus for GattServices if max_wait > 0 sleep(0.25) ; max_wait -= 0.25 ; retry end raise NotReady else raise ScriptError end end |
#remove ⇒ Boolean
This removes the remote device object. It will remove also the pairing information.
53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/ble/device.rb', line 53 def remove block_given? ? @o_adapter[I_ADAPTER].RemoveDevice(@p_dev, &Proc.new) : @o_adapter[I_ADAPTER].RemoveDevice(@p_dev) true rescue DBus::Error => e case e.name when E_FAILED then false when E_DOES_NOT_EXIST then raise StalledObject when E_UNKNOWN_OBJECT then raise StalledObject else raise ScriptError end end |
#rssi ⇒ Integer
Received Signal Strength Indicator of the remote device (inquiry or advertising).
320 321 322 323 324 325 326 327 |
# File 'lib/ble/device.rb', line 320 def rssi # optional @o_dev[I_DEVICE]['RSSI'] rescue DBus::Error => e case e.name when E_INVALID_ARGS then raise NotSupported else raise ScriptError end end |
#services ⇒ Array<String>
The list is retrieve once when object is connected if auto_refresh is enable, otherwise you need to call #refresh.
This is the list of UUIDs for which we have an entry in the underlying api (bluez-dbus), which can be less that the list of advertised UUIDs.
List of available services as UUID.
223 224 225 226 |
# File 'lib/ble/device.rb', line 223 def services _require_connection! @services.keys end |
#subscribe(service, characteristic, raw: false, &block) ⇒ Object
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 |
# File 'lib/ble/device.rb', line 457 def subscribe(service, characteristic, raw: false, &block) _require_connection! uuid = _uuid_characteristic(characteristic) chars = _characteristics(service) raise Service::NotFound, service if chars.nil? char = chars[uuid] raise Characteristic::NotFound, characteristic if char.nil? if char.flag? 'notify' char.notify! char.on_change(raw: raw, &block) else raise OperationNotSupportedError.new("No notifications available for characteristic #{characteristic}") end end |
#trusted=(val) ⇒ void
This method returns an undefined value.
Indicates if the remote is seen as trusted. This setting can be changed by the application.
291 292 293 294 295 296 |
# File 'lib/ble/device.rb', line 291 def trusted=(val) if ! [ true, false ].include?(val) raise ArgumentError, "value must be a boolean" end @o_dev[I_DEVICE]['Trusted'] = val end |
#tx_power ⇒ Integer
Advertised transmitted power level (inquiry or advertising).
331 332 333 334 335 336 337 338 |
# File 'lib/ble/device.rb', line 331 def tx_power # optional @o_dev[I_DEVICE]['TxPower'] rescue DBus::Error => e case e.name when E_INVALID_ARGS then raise NotSupported else raise ScriptError end end |