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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/lib/flic.rb +2 -1
  3. data/lib/flic/callbacks.rb +36 -0
  4. data/lib/flic/client.rb +52 -203
  5. data/lib/flic/client/connection_channel.rb +21 -0
  6. data/lib/flic/client/features.rb +15 -0
  7. data/lib/flic/client/features/connection_channel.rb +175 -0
  8. data/lib/flic/client/features/force_disconnect.rb +13 -0
  9. data/lib/flic/client/features/get_button_uuid.rb +43 -0
  10. data/lib/flic/client/features/get_info.rb +52 -0
  11. data/lib/flic/client/features/ping.rb +55 -0
  12. data/lib/flic/client/features/scan.rb +112 -0
  13. data/lib/flic/client/features/scan_wizard.rb +131 -0
  14. data/lib/flic/client/scan_wizard.rb +14 -0
  15. data/lib/flic/client/scanner.rb +12 -0
  16. data/lib/flic/client/server_info.rb +16 -0
  17. data/lib/flic/protocol.rb +1 -0
  18. data/lib/flic/protocol/commands/change_mode_parameters.rb +3 -2
  19. data/lib/flic/protocol/commands/create_connection_channel.rb +3 -2
  20. data/lib/flic/protocol/commands/remove_connection_channel.rb +1 -1
  21. data/lib/flic/{client → protocol}/connection.rb +20 -26
  22. data/lib/flic/protocol/events/button_click_or_hold.rb +1 -1
  23. data/lib/flic/protocol/events/button_single_or_double_click.rb +1 -1
  24. data/lib/flic/protocol/events/button_single_or_double_click_or_hold.rb +1 -1
  25. data/lib/flic/protocol/events/button_up_or_down.rb +1 -1
  26. data/lib/flic/protocol/events/connection_channel_removed.rb +2 -2
  27. data/lib/flic/protocol/events/connection_status_changed.rb +1 -1
  28. data/lib/flic/protocol/events/create_connection_channel_response.rb +1 -1
  29. data/lib/flic/protocol/events/get_info_response.rb +3 -2
  30. data/lib/flic/protocol/primitives.rb +1 -0
  31. data/lib/flic/protocol/primitives/disconnect_time.rb +29 -0
  32. data/lib/flic/simple_client.rb +116 -0
  33. data/lib/flic/version.rb +1 -1
  34. metadata +18 -6
  35. data/lib/flic/event_bus.rb +0 -81
  36. data/lib/flic/event_bus/driver.rb +0 -23
  37. 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,12 @@
1
+ require 'flic/client'
2
+
3
+ module Flic
4
+ class Client
5
+ class Scanner
6
+ extend Callbacks
7
+
8
+ define_callbacks :added, :removed,
9
+ :advertisement_received
10
+ end
11
+ end
12
+ 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