sb-ble 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bbab52be19f92ec7202ac18981e9b65ead354a2c
4
+ data.tar.gz: b695176d8a305d5ac043fa350a5e2d995d8bc699
5
+ SHA512:
6
+ metadata.gz: df55d481209aaa635386dfa2deb9f2204824bc23ac44b8adcb55e8b4331c44971f35b90bb88ed5601b215795b630ca3256796c3a69fecb5c210acba58ccdd90f
7
+ data.tar.gz: 5bb64da90ebf9a2e0ccb14f62c8f6b580f9c01dcb7ff039f28829dc1e64f1145936ee4276035138de31fcafb916ca8a143438f407a4656083f023ddddbd3410b
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.semver ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 5
4
+ :patch: 0
5
+ :special: ''
data/Gemfile ADDED
@@ -0,0 +1,21 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "ruby-dbus", "~> 0"
4
+ gem 'semver2', '~> 3'
5
+
6
+ group :development do
7
+ gem "rspec", "~> 3"
8
+ gem "yard", "~> 0"
9
+ gem "rdoc", "~> 3"
10
+ gem "bundler", "~> 1"
11
+ gem "juwelier", "~> 2"
12
+ gem "simplecov", ">= 0"
13
+ gem "pry", "~> 0"
14
+ gem "pry-byebug", "~> 3"
15
+ gem "pry-doc", "~> 0"
16
+ gem "pry-remote", "~> 0"
17
+ gem "pry-rescue", "~> 1"
18
+ gem "pry-stack_explorer", "~> 0"
19
+ gem 'redcarpet'
20
+ gem 'github-markup'
21
+ end
@@ -0,0 +1,130 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ addressable (2.4.0)
5
+ binding_of_caller (0.7.2)
6
+ debug_inspector (>= 0.0.1)
7
+ builder (3.2.3)
8
+ byebug (9.0.6)
9
+ coderay (1.1.1)
10
+ debug_inspector (0.0.3)
11
+ descendants_tracker (0.0.4)
12
+ thread_safe (~> 0.3, >= 0.3.1)
13
+ diff-lcs (1.3)
14
+ docile (1.1.5)
15
+ faraday (0.9.2)
16
+ multipart-post (>= 1.2, < 3)
17
+ git (1.3.0)
18
+ github-markup (1.6.0)
19
+ github_api (0.17.0)
20
+ addressable (~> 2.4.0)
21
+ descendants_tracker (~> 0.0.4)
22
+ faraday (~> 0.8, < 0.10)
23
+ hashie (>= 3.4)
24
+ mime-types (>= 1.16, < 3.0)
25
+ oauth2 (~> 1.0)
26
+ hashie (3.5.5)
27
+ highline (1.7.8)
28
+ interception (0.5)
29
+ json (1.8.6)
30
+ juwelier (2.4.5)
31
+ builder
32
+ bundler (>= 1.13)
33
+ git (>= 1.2.5)
34
+ github_api
35
+ highline (>= 1.6.15)
36
+ kamelcase (~> 0)
37
+ nokogiri (>= 1.5.10)
38
+ psych (~> 2.2)
39
+ rake
40
+ rdoc
41
+ semver2
42
+ jwt (1.5.6)
43
+ kamelcase (0.0.0)
44
+ semver2 (~> 3)
45
+ method_source (0.8.2)
46
+ mime-types (2.99.3)
47
+ mini_portile2 (2.1.0)
48
+ multi_json (1.12.1)
49
+ multi_xml (0.6.0)
50
+ multipart-post (2.0.0)
51
+ nokogiri (1.7.2)
52
+ mini_portile2 (~> 2.1.0)
53
+ oauth2 (1.3.1)
54
+ faraday (>= 0.8, < 0.12)
55
+ jwt (~> 1.0)
56
+ multi_json (~> 1.3)
57
+ multi_xml (~> 0.5)
58
+ rack (>= 1.2, < 3)
59
+ pry (0.10.4)
60
+ coderay (~> 1.1.0)
61
+ method_source (~> 0.8.1)
62
+ slop (~> 3.4)
63
+ pry-byebug (3.4.2)
64
+ byebug (~> 9.0)
65
+ pry (~> 0.10)
66
+ pry-doc (0.10.0)
67
+ pry (~> 0.9)
68
+ yard (~> 0.9)
69
+ pry-remote (0.1.8)
70
+ pry (~> 0.9)
71
+ slop (~> 3.0)
72
+ pry-rescue (1.4.5)
73
+ interception (>= 0.5)
74
+ pry
75
+ pry-stack_explorer (0.4.9.2)
76
+ binding_of_caller (>= 0.7)
77
+ pry (>= 0.9.11)
78
+ psych (2.2.4)
79
+ rack (2.0.3)
80
+ rake (12.0.0)
81
+ rdoc (3.12.2)
82
+ json (~> 1.4)
83
+ redcarpet (3.4.0)
84
+ rspec (3.6.0)
85
+ rspec-core (~> 3.6.0)
86
+ rspec-expectations (~> 3.6.0)
87
+ rspec-mocks (~> 3.6.0)
88
+ rspec-core (3.6.0)
89
+ rspec-support (~> 3.6.0)
90
+ rspec-expectations (3.6.0)
91
+ diff-lcs (>= 1.2.0, < 2.0)
92
+ rspec-support (~> 3.6.0)
93
+ rspec-mocks (3.6.0)
94
+ diff-lcs (>= 1.2.0, < 2.0)
95
+ rspec-support (~> 3.6.0)
96
+ rspec-support (3.6.0)
97
+ ruby-dbus (0.13.0)
98
+ semver2 (3.4.2)
99
+ simplecov (0.14.1)
100
+ docile (~> 1.1.0)
101
+ json (>= 1.8, < 3)
102
+ simplecov-html (~> 0.10.0)
103
+ simplecov-html (0.10.1)
104
+ slop (3.6.0)
105
+ thread_safe (0.3.6)
106
+ yard (0.9.9)
107
+
108
+ PLATFORMS
109
+ ruby
110
+
111
+ DEPENDENCIES
112
+ bundler (~> 1)
113
+ github-markup
114
+ juwelier (~> 2)
115
+ pry (~> 0)
116
+ pry-byebug (~> 3)
117
+ pry-doc (~> 0)
118
+ pry-remote (~> 0)
119
+ pry-rescue (~> 1)
120
+ pry-stack_explorer (~> 0)
121
+ rdoc (~> 3)
122
+ redcarpet
123
+ rspec (~> 3)
124
+ ruby-dbus (~> 0)
125
+ semver2 (~> 3)
126
+ simplecov
127
+ yard (~> 0)
128
+
129
+ BUNDLED WITH
130
+ 1.14.6
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Fred Mitchell & Sensorberg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,62 @@
1
+ * sb-ble
2
+ :PROPERTIES:
3
+ :CUSTOM_ID: ruby-ble
4
+ :END:
5
+
6
+ Bluetooth Low Energy for Ruby -- Sensorberg Version
7
+ [[https://badge.fury.io/rb/ble][[[https://badge.fury.io/rb/ble.svg]]]]
8
+
9
+ ** Prelimaries
10
+ This is a fork of a fork. More features are being added here,
11
+ such as support for advertising.
12
+
13
+ ** Requirements
14
+ :PROPERTIES:
15
+ :CUSTOM_ID: requirements
16
+ :END:
17
+
18
+ - ruby >= 2.3
19
+ - Dbus
20
+ - bluez >= 5.36 (available on debian testing)
21
+ - =bluetoothd= started with option =-E= (experimental)
22
+
23
+ ** Examples
24
+ :PROPERTIES:
25
+ :CUSTOM_ID: examples
26
+ :END:
27
+
28
+ #+BEGIN_SRC ruby
29
+ # Selecter adapter
30
+ $a = BLE::Adapter.new('hci0')
31
+ puts "Info: #{$a.iface} #{$a.address} #{$a.name}"
32
+
33
+ # Run discovery
34
+ $a.start_discovery
35
+ sleep(2)
36
+ $a.stop_discovery
37
+
38
+ # Get device and connect to it
39
+ $d = $a['F4:AD:CB:FB:B4:85']
40
+ $d.connect
41
+
42
+ # Get temperature from the environmental sensing service
43
+ $d[:environmental_sensing, :temperature]
44
+
45
+ # Dump device information
46
+ srv = :device_information
47
+ $d.characteristics(srv).each {|uuid|
48
+ info = BLE::Characteristic[uuid]
49
+ name = info.nil? ? uuid : info[:name]
50
+ value = $d[srv, uuid] rescue '/!\\ not-readable /!\\'
51
+ puts "%-30s: %s" % [ name, value ]
52
+ }
53
+ #+END_SRC
54
+
55
+ ** Contributors
56
+ :PROPERTIES:
57
+ :CUSTOM_ID: contributors
58
+ :END:
59
+
60
+ - Fred Mitchell (Sensorberg GmbH) LE Advertisement support
61
+ - Oliver Valls (tramuntanal): Bug fixes / BLE Notification support
62
+ - Stephane D'Alu
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+
6
+ begin
7
+ Bundler.setup(:default, :development)
8
+ rescue Bundler::BundlerError => e
9
+ $stderr.puts e.message
10
+ $stderr.puts "Run `bundle install` to install missing gems"
11
+ exit e.status_code
12
+ end
13
+
14
+ require 'rake'
15
+ require 'semver'
16
+
17
+ def s_version
18
+ SemVer.find.format "%M.%m.%p%s"
19
+ end
20
+
21
+ require 'juwelier'
22
+
23
+ Juwelier::Tasks.new do |gem|
24
+ gem.name = "sb-ble"
25
+ gem.homepage = "http://github.com/flajann2/ruby-ble"
26
+ gem.license = "MIT"
27
+ gem.summary = %Q{Bluetooth Low Energy for Ruby -- Sensorberg Version}
28
+ gem.description = %Q{This supports LE Advertising}
29
+ gem.email = "frederick.mitchell@sensorberg.com"
30
+ gem.authors = ["Fred Mitchell & Sensorberg"]
31
+ gem.version = s_version
32
+ # dependencies defined in Gemfile
33
+ end
34
+
35
+ Juwelier::RubygemsDotOrgTasks.new
36
+ require 'rspec/core'
37
+ require 'rspec/core/rake_task'
38
+ RSpec::Core::RakeTask.new(:spec) do |spec|
39
+ spec.pattern = FileList['spec/**/*_spec.rb']
40
+ end
41
+
42
+ desc "Code coverage detail"
43
+ task :simplecov do
44
+ ENV['COVERAGE'] = "true"
45
+ Rake::Task['spec'].execute
46
+ end
47
+
48
+ task :default => :spec
49
+
50
+ require 'yard'
51
+ YARD::Rake::YardocTask.new
File without changes
@@ -0,0 +1,112 @@
1
+ # coding: utf-8
2
+ require 'dbus'
3
+ require 'logger'
4
+
5
+ # https://github.com/mvidner/ruby-dbus/blob/master/doc/Tutorial.md
6
+ # https://kernel.googlesource.com/pub/scm/bluetooth/bluez/+/refs/heads/master/doc/
7
+
8
+
9
+ #
10
+ module BLE
11
+ private
12
+ # Interfaces
13
+ I_ADAPTER = 'org.bluez.Adapter1'
14
+ I_DEVICE = 'org.bluez.Device1'
15
+ I_AGENT_MANAGER = 'org.bluez.AgentManager1'
16
+ I_AGENT = 'org.bluez.Agent1'
17
+ I_GATT_CHARACTERISTIC = 'org.bluez.GattCharacteristic1'
18
+ I_GATT_SERVICE = 'org.bluez.GattService1'
19
+ I_PROXIMITY_REPORTER = 'org.bluez.ProximityReporter1'
20
+ I_PROPERTIES = 'org.freedesktop.DBus.Properties'
21
+ I_INTROSPECTABLE = 'org.freedesktop.DBus.Introspectable'
22
+
23
+ # Errors
24
+ E_IN_PROGRESS = 'org.bluez.Error.InProgress'
25
+ E_FAILED = 'org.bluez.Error.Failed'
26
+ E_NOT_READY = 'org.bluez.Error.NotReady'
27
+ E_ALREADY_CONNECTED = 'org.bluez.Error.AlreadyConnected'
28
+ E_NOT_CONNECTED = 'org.bluez.Error.NotConnected'
29
+ E_DOES_NOT_EXIST = 'org.bluez.Error.DoesNotExist'
30
+ E_NOT_SUPPORTED = 'org.bluez.Error.NotSupported'
31
+ E_NOT_AUTHORIZED = 'org.bluez.Error.NotAuthorized'
32
+ E_INVALID_ARGUMENTS = 'org.bluez.Error.InvalidArguments'
33
+ E_ALREADY_EXISTS = 'org.bluez.Error.AlreadyExists'
34
+ E_AUTH_CANCELED = 'org.bluez.Error.AuthenticationCanceled'
35
+ E_AUTH_FAILED = 'org.bluez.Error.AuthenticationFailed'
36
+ E_AUTH_REJECTED = 'org.bluez.Error.AuthenticationRejected'
37
+ E_AUTH_TIMEOUT = 'org.bluez.Error.AuthenticationTimeout'
38
+ E_AUTH_ATTEMPT_FAILED = 'org.bluez.Error.ConnectionAttemptFailed'
39
+ E_UNKNOWN_OBJECT = 'org.freedesktop.DBus.Error.UnknownObject'
40
+ E_INVALID_ARGS = 'org.freedesktop.DBus.Error.InvalidArgs'
41
+ E_INVALID_SIGNATURE = 'org.freedesktop.DBus.Error.InvalidSignature'
42
+
43
+ # Bus
44
+ DBUS = DBus.system_bus
45
+ BLUEZ = DBUS.service('org.bluez')
46
+
47
+ public
48
+ # Generic Error class
49
+ class Error < StandardError ; end
50
+ # Notify of unimplemented part
51
+ class NotYetImplemented < Error ; end
52
+ # Notify that the underlying API object is dead
53
+ class StalledObject < Error ; end
54
+ # Notify that execution wass not able to fulill as some requirement
55
+ # was not ready. Usually you can wait a little and restart the action.
56
+ class NotReady < Error ; end
57
+ # Notify that you don't have the necessary authorization to perfrom
58
+ # the operation
59
+ class NotAuthorized < Error ; end
60
+ # Notify that some service/characteristic/... is not found
61
+ # on this device
62
+ class NotFound < Error ; end
63
+ class AccessUnavailable < Error ; end
64
+ class NotSupported < Error ; end
65
+
66
+
67
+ # Base UUID for GATT services defined with 16bit or 32bit UUID
68
+ GATT_BASE_UUID="00000000-0000-1000-8000-00805f9b34fb"
69
+
70
+ #"DisplayOnly", "DisplayYesNo", "KeyboardOnly",
71
+ # "NoInputNoOutput" and "KeyboardDisplay" which
72
+
73
+
74
+ def self.registerAgent(agent, service, path)
75
+ raise NotYetImplemented
76
+ bus = DBus.session_bus
77
+ service = bus.request_service("org.ruby.service")
78
+
79
+ service.export(BLE::Agent.new(agent_path))
80
+
81
+ o_bluez = BLUEZ.object('/org/bluez')
82
+ o_bluez.introspect
83
+ o_bluez[I_AGENT_MANAGER].RegisterAgent(agent_path, "NoInputNoOutput")
84
+ end
85
+
86
+
87
+
88
+
89
+ # Check if Bluetooth underlying API is accessible
90
+ def self.ok?
91
+ BLUEZ.exists?
92
+ end
93
+
94
+ end
95
+
96
+ require_relative 'ble/version'
97
+ require_relative 'ble/uuid'
98
+ require_relative 'ble/adapter'
99
+ require_relative 'ble/char_desc'
100
+ require_relative 'ble/notifications'
101
+ require_relative 'ble/device'
102
+ require_relative 'ble/service'
103
+ require_relative 'ble/char_registry'
104
+ require_relative 'ble/characteristic'
105
+ require_relative 'ble/agent'
106
+
107
+ require_relative 'ble/db_sig_service'
108
+ require_relative 'ble/db_sig_characteristic'
109
+ require_relative 'ble/db_eddystone'
110
+ require_relative 'ble/db_nordic'
111
+
112
+
@@ -0,0 +1,162 @@
1
+ module BLE
2
+ # Adapter class
3
+ # Adapter.list
4
+ # a = Adapter.new('hci0')
5
+ # a.start_discover ; sleep(10) ; a.stop_discovery
6
+ # a.devices
7
+ #
8
+ class Adapter
9
+ # Return a list of available unix device name for the
10
+ # adapter installed on the system.
11
+ # @return [Array<String>] list of unix device name
12
+ def self.list
13
+ o_bluez = BLUEZ.object('/org/bluez')
14
+ o_bluez.introspect
15
+ o_bluez.subnodes.reject {|adapter| ['test'].include?(adapter) }
16
+ end
17
+
18
+ # Create a new Adapter
19
+ #
20
+ # @param iface [String] name of the Unix device
21
+ def initialize(iface)
22
+ @iface = iface.dup.freeze
23
+ @o_adapter = BLUEZ.object("/org/bluez/#{@iface}")
24
+ @o_adapter.introspect
25
+
26
+ # @o_adapter[I_PROPERTIES]
27
+ # .on_signal('PropertiesChanged') do |intf, props|
28
+ # end
29
+ # end
30
+ end
31
+
32
+ # The Bluetooth interface name
33
+ # @return [String] name of the Unix device
34
+ def iface
35
+ @iface
36
+ end
37
+
38
+ # The Bluetooth device address.
39
+ # @return [String] MAC address of the adapter
40
+ def address
41
+ @o_adapter[I_ADAPTER]['Address']
42
+ end
43
+
44
+ # The Bluetooth system name (pretty hostname).
45
+ # @return [String]
46
+ def name
47
+ @o_adapter[I_ADAPTER]['Name']
48
+ end
49
+
50
+ # The Bluetooth friendly name.
51
+ # In case no alias is set, it will return the system provided name.
52
+ # @return [String]
53
+ def alias
54
+ @o_adapter[I_ADAPTER]['Alias']
55
+ end
56
+
57
+ # Set the alias name.
58
+ #
59
+ # When resetting the alias with an empty string, the
60
+ # property will default back to system name
61
+ #
62
+ # @param val [String] new alias name.
63
+ # @return [void]
64
+ def alias=(val)
65
+ @o_adapter[I_ADAPTER]['Alias'] = val.nil? ? '' : val.to_str
66
+ nil
67
+ end
68
+
69
+ # Return the device corresponding to the given address.
70
+ # @note The device object returned has a dependency on the adapter.
71
+ #
72
+ # @param address MAC address of the device
73
+ # @return [Device] a device
74
+ def [](address)
75
+ Device.new(@iface, address)
76
+ end
77
+
78
+ # This method sets the device discovery filter for the caller.
79
+ # When this method is called with +nil+ or an empty list of UUIDs,
80
+ # filter is removed.
81
+ #
82
+ # @todo Need to sync with the adapter-api.txt
83
+ #
84
+ # @param uuids a list of uuid to filter on
85
+ # @param rssi RSSI threshold
86
+ # @param pathloss pathloss threshold
87
+ # @param transport [:auto, :bredr, :le]
88
+ # type of scan to run (default: :le)
89
+ # @return [self]
90
+ def filter(uuids, rssi: nil, pathloss: nil, transport: :le)
91
+ unless [:auto, :bredr, :le].include?(transport)
92
+ raise ArgumentError,
93
+ "transport must be one of :auto, :bredr, :le"
94
+ end
95
+ filter = { }
96
+
97
+ unless uuids.nil? || uuids.empty?
98
+ filter['UUIDs' ] = DBus.variant('as', uuids)
99
+ end
100
+ unless rssi.nil?
101
+ filter['RSSI' ] = DBus.variant('n', rssi)
102
+ end
103
+ unless pathloss.nil?
104
+ filter['Pathloss' ] = DBus.variant('q', pathloss)
105
+ end
106
+ unless transport.nil?
107
+ filter['Transport'] = DBus.variant('s', transport.to_s)
108
+ end
109
+
110
+ @o_adapter[I_ADAPTER].SetDiscoveryFilter(filter)
111
+
112
+ self
113
+ end
114
+
115
+ # Starts the device discovery session.
116
+ # This includes an inquiry procedure and remote device name resolving.
117
+ # Use {#stop_discovery} to release the sessions acquired.
118
+ # This process will start creating device in the underlying api
119
+ # as new devices are discovered.
120
+ #
121
+ # @return [Boolean]
122
+ def start_discovery
123
+ @o_adapter[I_ADAPTER].StartDiscovery
124
+ true
125
+ rescue DBus::Error => e
126
+ case e.name
127
+ when E_IN_PROGRESS then true
128
+ when E_FAILED then false
129
+ else raise ScriptError
130
+ end
131
+ end
132
+
133
+ # This method will cancel any previous {#start_discovery}
134
+ # transaction.
135
+ # @note The discovery procedure is shared
136
+ # between all discovery sessions thus calling {#stop_discovery}
137
+ # will only release a single session.
138
+ #
139
+ # @return [Boolean]
140
+ def stop_discovery
141
+ @o_adapter[I_ADAPTER].StopDiscovery
142
+ true
143
+ rescue DBus::Error => e
144
+ case e.name
145
+ when E_FAILED then false
146
+ when E_NOT_READY then false
147
+ when E_NOT_AUTHORIZED then raise NotAuthorized
148
+ else raise ScriptError
149
+ end
150
+
151
+ end
152
+
153
+ # List of devices MAC address that have been discovered.
154
+ #
155
+ # @return [Array<String>] List of devices MAC address.
156
+ def devices
157
+ @o_adapter.introspect # Force refresh
158
+ @o_adapter.subnodes.map {|dev| # Format: dev_aa_bb_cc_dd_ee_ff
159
+ dev[4..-1].tr('_', ':') }
160
+ end
161
+ end
162
+ end