flic 0.0.1 → 0.0.2
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 +4 -4
- data/lib/flic.rb +2 -1
- data/lib/flic/callbacks.rb +36 -0
- data/lib/flic/client.rb +52 -203
- data/lib/flic/client/connection_channel.rb +21 -0
- data/lib/flic/client/features.rb +15 -0
- data/lib/flic/client/features/connection_channel.rb +175 -0
- data/lib/flic/client/features/force_disconnect.rb +13 -0
- data/lib/flic/client/features/get_button_uuid.rb +43 -0
- data/lib/flic/client/features/get_info.rb +52 -0
- data/lib/flic/client/features/ping.rb +55 -0
- data/lib/flic/client/features/scan.rb +112 -0
- data/lib/flic/client/features/scan_wizard.rb +131 -0
- data/lib/flic/client/scan_wizard.rb +14 -0
- data/lib/flic/client/scanner.rb +12 -0
- data/lib/flic/client/server_info.rb +16 -0
- data/lib/flic/protocol.rb +1 -0
- data/lib/flic/protocol/commands/change_mode_parameters.rb +3 -2
- data/lib/flic/protocol/commands/create_connection_channel.rb +3 -2
- data/lib/flic/protocol/commands/remove_connection_channel.rb +1 -1
- data/lib/flic/{client → protocol}/connection.rb +20 -26
- data/lib/flic/protocol/events/button_click_or_hold.rb +1 -1
- data/lib/flic/protocol/events/button_single_or_double_click.rb +1 -1
- data/lib/flic/protocol/events/button_single_or_double_click_or_hold.rb +1 -1
- data/lib/flic/protocol/events/button_up_or_down.rb +1 -1
- data/lib/flic/protocol/events/connection_channel_removed.rb +2 -2
- data/lib/flic/protocol/events/connection_status_changed.rb +1 -1
- data/lib/flic/protocol/events/create_connection_channel_response.rb +1 -1
- data/lib/flic/protocol/events/get_info_response.rb +3 -2
- data/lib/flic/protocol/primitives.rb +1 -0
- data/lib/flic/protocol/primitives/disconnect_time.rb +29 -0
- data/lib/flic/simple_client.rb +116 -0
- data/lib/flic/version.rb +1 -1
- metadata +18 -6
- data/lib/flic/event_bus.rb +0 -81
- data/lib/flic/event_bus/driver.rb +0 -23
- data/lib/flic/event_bus/subscription.rb +0 -66
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'flic/client/features'
|
2
|
+
|
3
|
+
module Flic
|
4
|
+
class Client
|
5
|
+
module Features
|
6
|
+
module ForceDisconnect
|
7
|
+
def force_disconnect(button_bluetooth_address)
|
8
|
+
send_command Protocol::Commands::ForceDisconnect.new(bluetooth_address: button_bluetooth_address)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'flic/client/features'
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module Flic
|
6
|
+
class Client
|
7
|
+
module Features
|
8
|
+
module GetButtonUuid
|
9
|
+
def initialize(*)
|
10
|
+
@button_bluetooth_address_callbacks_semaphore = Mutex.new
|
11
|
+
@button_bluetooth_address_callbacks = Hash.new { [] }
|
12
|
+
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_button_uuid(button_bluetooth_address, callback = Proc.new)
|
17
|
+
command = Protocol::Commands::GetButtonUuid.new(bluetooth_address: button_bluetooth_address)
|
18
|
+
|
19
|
+
@button_bluetooth_address_callbacks_semaphore.synchronize do
|
20
|
+
@button_bluetooth_address_callbacks[command.bluetooth_address] << callback
|
21
|
+
end
|
22
|
+
|
23
|
+
send_command command
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def handle_event(event)
|
29
|
+
case event
|
30
|
+
when Protocol::Events::GetButtonUuidResponse
|
31
|
+
callback = @button_bluetooth_address_callbacks_semaphore.synchronize do
|
32
|
+
@button_bluetooth_address_callbacks[event.bluetooth_address].shift
|
33
|
+
end
|
34
|
+
|
35
|
+
callback.call event.uuid if callback
|
36
|
+
else
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'flic/client/features'
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module Flic
|
6
|
+
class Client
|
7
|
+
module Features
|
8
|
+
module GetInfo
|
9
|
+
def initialize(*)
|
10
|
+
@get_info_callbacks_semaphore = Mutex.new
|
11
|
+
@get_info_callbacks = []
|
12
|
+
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_info(callback = Proc.new)
|
17
|
+
@get_info_callbacks_semaphore.synchronize do
|
18
|
+
@get_info_callbacks << callback
|
19
|
+
end
|
20
|
+
|
21
|
+
send_command Protocol::Commands::GetInfo.new
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def handle_event(event)
|
27
|
+
case event
|
28
|
+
when Protocol::Events::GetInfoResponse
|
29
|
+
server_info = ServerInfo.new(
|
30
|
+
event.bluetooth_controller_state,
|
31
|
+
event.bluetooth_address,
|
32
|
+
event.bluetooth_address_type,
|
33
|
+
event.maximum_pending_connections,
|
34
|
+
event.maximum_concurrently_connected_buttons,
|
35
|
+
event.current_pending_connections,
|
36
|
+
event.currently_no_space_for_new_connection,
|
37
|
+
event.verified_buttons_bluetooth_addresses
|
38
|
+
)
|
39
|
+
|
40
|
+
callback = @get_info_callbacks_semaphore.synchronize do
|
41
|
+
@get_info_callbacks.shift
|
42
|
+
end
|
43
|
+
|
44
|
+
callback.call server_info if callback
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'flic/client/features'
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module Flic
|
6
|
+
class Client
|
7
|
+
module Features
|
8
|
+
module Ping
|
9
|
+
def initialize(*)
|
10
|
+
@ping_id_callback_semaphore = Mutex.new
|
11
|
+
@ping_id_callback = {}
|
12
|
+
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def ping(callback = Proc.new)
|
17
|
+
ping_id = alloc_ping_id_with_callback(callback)
|
18
|
+
|
19
|
+
send_command Protocol::Commands::Ping.new(ping_id: ping_id)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def alloc_ping_id_with_callback(callback)
|
25
|
+
@ping_id_callback_semaphore.synchronize do
|
26
|
+
ping_id = nil
|
27
|
+
|
28
|
+
loop do
|
29
|
+
ping_id = rand(2**32)
|
30
|
+
|
31
|
+
break unless @ping_id_callback.has_key?(ping_id)
|
32
|
+
end
|
33
|
+
|
34
|
+
@ping_id_callback[ping_id] = callback
|
35
|
+
|
36
|
+
ping_id
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def handle_event(event)
|
41
|
+
case event
|
42
|
+
when Protocol::Events::PingResponse
|
43
|
+
callback = @ping_id_callback_semaphore.synchronize do
|
44
|
+
@ping_id_callback.delete event.ping_id
|
45
|
+
end
|
46
|
+
|
47
|
+
callback.call if callback
|
48
|
+
else
|
49
|
+
super
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'flic/client/features'
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module Flic
|
6
|
+
class Client
|
7
|
+
module Features
|
8
|
+
module Scan
|
9
|
+
def initialize(*)
|
10
|
+
@scan_id_scanner_semaphore = Mutex.new
|
11
|
+
@scan_id_scanner = {}
|
12
|
+
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def scanners
|
17
|
+
@scan_id_scanner_semaphore.synchronize { @scan_id_scanner.values }
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_scanner(scanner)
|
21
|
+
scan_id = _add_scanner(scanner)
|
22
|
+
|
23
|
+
send_command Protocol::Commands::CreateScanner.new(scan_id: scan_id) if scan_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove_scanner(scanner)
|
27
|
+
scan_id = _remove_scanner(scanner)
|
28
|
+
|
29
|
+
send_command Protocol::Commands::RemoveScanner.new(scan_id: scan_id) if scan_id
|
30
|
+
end
|
31
|
+
|
32
|
+
def shutdown(*)
|
33
|
+
scanners.each do |scanner|
|
34
|
+
_remove_scanner(scanner)
|
35
|
+
end
|
36
|
+
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def handle_event(event)
|
43
|
+
case event
|
44
|
+
when Protocol::Events::AdvertisementPacket
|
45
|
+
scanner = find_scanner_for_scan_id(scanner)
|
46
|
+
|
47
|
+
if scanner
|
48
|
+
scanner.advertisement_received(
|
49
|
+
event.bluetooth_address,
|
50
|
+
event.name,
|
51
|
+
event.rssi,
|
52
|
+
event.is_private,
|
53
|
+
event.is_already_verified
|
54
|
+
)
|
55
|
+
end
|
56
|
+
else
|
57
|
+
super
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def _add_scanner(scanner)
|
62
|
+
scan_id = nil
|
63
|
+
|
64
|
+
@scan_id_scanner_semaphore.synchronize do
|
65
|
+
unless @scan_id_scanner.values.include?(scanner)
|
66
|
+
loop do
|
67
|
+
scan_id = rand(2**32)
|
68
|
+
|
69
|
+
break unless @scan_id_scanner.has_key?(scan_id)
|
70
|
+
end
|
71
|
+
|
72
|
+
@scan_id_scanner[scan_id] = scanner
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
scanner.added self if scan_id # we have to do this here because the server does not callback
|
77
|
+
|
78
|
+
scan_id
|
79
|
+
end
|
80
|
+
|
81
|
+
def _remove_scanner(scanner)
|
82
|
+
scan_id = nil
|
83
|
+
|
84
|
+
@scan_id_scanner_semaphore.synchronize do
|
85
|
+
@scan_id_scanner.each do |_scan_id, _scanner|
|
86
|
+
if scanner == _scanner
|
87
|
+
scan_id = _scan_id
|
88
|
+
break
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
@scan_id_scanner.delete scan_id if scan_id
|
93
|
+
end
|
94
|
+
|
95
|
+
scanner.removed self if scan_id # we have to do this here because the server does not callback
|
96
|
+
|
97
|
+
scan_id
|
98
|
+
end
|
99
|
+
|
100
|
+
def find_scanner_for_scan_id(needle)
|
101
|
+
@scan_id_scanner_semaphore.synchronize do
|
102
|
+
@scan_id_scanner.each do |scan_id, scanner|
|
103
|
+
return scanner if scan_id == needle
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'flic/client/features'
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
|
5
|
+
module Flic
|
6
|
+
class Client
|
7
|
+
module Features
|
8
|
+
module ScanWizard
|
9
|
+
def initialize(*)
|
10
|
+
@scan_wizard_id_scan_wizard_semaphore = Mutex.new
|
11
|
+
@scan_wizard_id_scan_wizard = {}
|
12
|
+
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def scan_wizards
|
17
|
+
@scan_wizard_id_scan_wizard_semaphore.synchronize { @scan_wizard_id_scan_wizard.values }
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_scan_wizard(scan_wizard)
|
21
|
+
scan_wizard_id = _add_scan_wizard(scan_wizard)
|
22
|
+
|
23
|
+
if scan_wizard_id
|
24
|
+
scan_wizard.added self
|
25
|
+
send_command Protocol::Commands::CreateScanWizard.new(scan_wizard_id: scan_wizard_id)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def remove_scan_wizard(scan_wizard)
|
30
|
+
scan_wizard_id = find_scan_wizard_id_for_scan_wizard(scan_wizard)
|
31
|
+
|
32
|
+
send_command Protocol::Commands::CancelScanWizard.new(scan_wizard_id: scan_wizard_id) if scan_wizard_id
|
33
|
+
end
|
34
|
+
|
35
|
+
def shutdown(*)
|
36
|
+
scan_wizards.each do |scan_wizard|
|
37
|
+
_remove_scan_wizard(scan_wizard)
|
38
|
+
scan_wizard.removed self, nil, nil, nil
|
39
|
+
end
|
40
|
+
|
41
|
+
super
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def handle_event(event)
|
47
|
+
case event
|
48
|
+
when Protocol::Events::ScanWizardFoundPrivateButton
|
49
|
+
scan_wizard = find_scan_wizard_for_scan_wizard_id(event.scan_wizard_id)
|
50
|
+
|
51
|
+
scan_wizard.found_private_button if scan_wizard
|
52
|
+
when Protocol::Events::ScanWizardFoundPublicButton
|
53
|
+
scan_wizard = find_scan_wizard_for_scan_wizard_id(event.scan_wizard_id)
|
54
|
+
|
55
|
+
scan_wizard.button_bluetooth_address = event.bluetooth_address
|
56
|
+
scan_wizard.button_name = event.name
|
57
|
+
scan_wizard.found_public_button event.bluetooth_address, event.name
|
58
|
+
when Protocol::Events::ScanWizardCompleted
|
59
|
+
scan_wizard = find_scan_wizard_for_scan_wizard_id(event.scan_wizard_id)
|
60
|
+
|
61
|
+
if scan_wizard
|
62
|
+
_remove_scan_wizard(scan_wizard)
|
63
|
+
|
64
|
+
scan_wizard.result = event.scan_wizard_result
|
65
|
+
scan_wizard.removed self, event.scan_wizard_result, scan_wizard.button_bluetooth_address, scan_wizard.button_name
|
66
|
+
end
|
67
|
+
else
|
68
|
+
super
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def _add_scan_wizard(scan_wizard)
|
73
|
+
scan_wizard_id = nil
|
74
|
+
|
75
|
+
@scan_wizard_id_scan_wizard_semaphore.synchronize do
|
76
|
+
unless @scan_wizard_id_scan_wizard.values.include?(scan_wizard)
|
77
|
+
loop do
|
78
|
+
scan_wizard_id = rand(2**32)
|
79
|
+
|
80
|
+
break unless @scan_wizard_id_scan_wizard.has_key?(scan_wizard_id)
|
81
|
+
end
|
82
|
+
|
83
|
+
@scan_wizard_id_scan_wizard[scan_wizard_id] = scan_wizard
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
scan_wizard_id
|
88
|
+
end
|
89
|
+
|
90
|
+
def _remove_scan_wizard(scan_wizard)
|
91
|
+
scan_wizard_id = nil
|
92
|
+
|
93
|
+
@scan_wizard_id_scan_wizard_semaphore.synchronize do
|
94
|
+
if @scan_wizard_id_scan_wizard.values.include?(scan_wizard)
|
95
|
+
@scan_wizard_id_scan_wizard.each do |_scan_wizard_id, _scan_wizard|
|
96
|
+
if scan_wizard == _scan_wizard
|
97
|
+
scan_wizard_id = _scan_wizard_id
|
98
|
+
break
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
@scan_wizard_id_scan_wizard.delete scan_wizard_id if scan_wizard_id
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
scan_wizard_id
|
107
|
+
end
|
108
|
+
|
109
|
+
def find_scan_wizard_for_scan_wizard_id(needle)
|
110
|
+
@scan_wizard_id_scan_wizard_semaphore.synchronize do
|
111
|
+
@scan_wizard_id_scan_wizard.each do |scan_wizard_id, scan_wizard|
|
112
|
+
return scan_wizard if scan_wizard_id == needle
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
|
119
|
+
def find_scan_wizard_id_for_scan_wizard(needle)
|
120
|
+
@scan_wizard_id_scan_wizard_semaphore.synchronize do
|
121
|
+
@scan_wizard_id_scan_wizard.each do |scan_wizard_id, scan_wizard|
|
122
|
+
return scan_wizard_id if scan_wizard == needle
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'flic/client'
|
2
|
+
|
3
|
+
module Flic
|
4
|
+
class Client
|
5
|
+
class ScanWizard
|
6
|
+
extend Callbacks
|
7
|
+
|
8
|
+
attr_accessor :button_bluetooth_address, :button_name, :result
|
9
|
+
|
10
|
+
define_callbacks :added, :removed,
|
11
|
+
:found_private_button, :found_public_button, :button_connected
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'flic/client'
|
2
|
+
|
3
|
+
module Flic
|
4
|
+
class Client
|
5
|
+
ServerInfo = Struct.new(
|
6
|
+
'ServerInfo',
|
7
|
+
:bluetooth_controller_state, :bluetooth_address,
|
8
|
+
:bluetooth_address_type,
|
9
|
+
:maximum_pending_connections,
|
10
|
+
:maximum_concurrently_connected_buttons,
|
11
|
+
:current_pending_connections,
|
12
|
+
:currently_no_space_for_new_connection,
|
13
|
+
:verified_buttons_bluetooth_addresses
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|