flic 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +51 -49
  3. data/Rakefile +6 -1
  4. data/flic.gemspec +1 -0
  5. data/lib/flic.rb +1 -0
  6. data/lib/flic/blocker.rb +59 -0
  7. data/lib/flic/client.rb +12 -7
  8. data/lib/flic/client/scan_wizard.rb +4 -0
  9. data/lib/flic/protocol.rb +20 -6
  10. data/lib/flic/protocol/commands.rb +7 -0
  11. data/lib/flic/protocol/commands/cancel_scan_wizard.rb +1 -3
  12. data/lib/flic/protocol/commands/change_mode_parameters.rb +1 -3
  13. data/lib/flic/protocol/commands/command.rb +10 -4
  14. data/lib/flic/protocol/commands/create_connection_channel.rb +1 -3
  15. data/lib/flic/protocol/commands/create_scan_wizard.rb +1 -3
  16. data/lib/flic/protocol/commands/create_scanner.rb +1 -3
  17. data/lib/flic/protocol/commands/force_disconnect.rb +0 -2
  18. data/lib/flic/protocol/commands/get_button_uuid.rb +0 -2
  19. data/lib/flic/protocol/commands/get_info.rb +0 -1
  20. data/lib/flic/protocol/commands/ping.rb +1 -3
  21. data/lib/flic/protocol/commands/remove_connection_channel.rb +1 -3
  22. data/lib/flic/protocol/commands/remove_scanner.rb +1 -3
  23. data/lib/flic/protocol/connection.rb +22 -19
  24. data/lib/flic/protocol/events.rb +9 -2
  25. data/lib/flic/protocol/events/advertisement_packet.rb +2 -4
  26. data/lib/flic/protocol/events/bluetooth_controller_state_change.rb +0 -2
  27. data/lib/flic/protocol/events/button_click_or_hold.rb +2 -4
  28. data/lib/flic/protocol/events/button_single_or_double_click.rb +2 -4
  29. data/lib/flic/protocol/events/button_single_or_double_click_or_hold.rb +2 -4
  30. data/lib/flic/protocol/events/button_up_or_down.rb +2 -4
  31. data/lib/flic/protocol/events/connection_channel_removed.rb +1 -3
  32. data/lib/flic/protocol/events/connection_status_changed.rb +1 -3
  33. data/lib/flic/protocol/events/create_connection_channel_response.rb +1 -3
  34. data/lib/flic/protocol/events/event.rb +11 -5
  35. data/lib/flic/protocol/events/get_button_uuid_response.rb +0 -2
  36. data/lib/flic/protocol/events/get_info_response.rb +4 -6
  37. data/lib/flic/protocol/events/got_space_for_new_connection.rb +1 -3
  38. data/lib/flic/protocol/events/new_verified_button.rb +0 -2
  39. data/lib/flic/protocol/events/no_space_for_new_connection.rb +1 -3
  40. data/lib/flic/protocol/events/ping_response.rb +1 -3
  41. data/lib/flic/protocol/events/scan_wizard_button_connected.rb +1 -3
  42. data/lib/flic/protocol/events/scan_wizard_completed.rb +1 -3
  43. data/lib/flic/protocol/events/scan_wizard_found_private_button.rb +1 -3
  44. data/lib/flic/protocol/events/scan_wizard_found_public_button.rb +1 -3
  45. data/lib/flic/protocol/packet_header.rb +2 -2
  46. data/lib/flic/protocol/primitives.rb +1 -0
  47. data/lib/flic/protocol/primitives/bluetooth_address.rb +2 -1
  48. data/lib/flic/protocol/primitives/bluetooth_address_type.rb +3 -0
  49. data/lib/flic/protocol/primitives/bluetooth_controller_state.rb +7 -3
  50. data/lib/flic/protocol/primitives/boolean.rb +1 -0
  51. data/lib/flic/protocol/primitives/click_type.rb +13 -6
  52. data/lib/flic/protocol/primitives/connection_status.rb +7 -4
  53. data/lib/flic/protocol/primitives/create_connection_channel_error.rb +4 -2
  54. data/lib/flic/protocol/primitives/device_name.rb +2 -1
  55. data/lib/flic/protocol/primitives/disconnect_reason.rb +8 -4
  56. data/lib/flic/protocol/primitives/disconnect_time.rb +8 -9
  57. data/lib/flic/protocol/primitives/enum.rb +12 -1
  58. data/lib/flic/protocol/primitives/latency_mode.rb +7 -3
  59. data/lib/flic/protocol/primitives/removed_reason.rb +14 -7
  60. data/lib/flic/protocol/primitives/scan_wizard_result.rb +15 -8
  61. data/lib/flic/protocol/primitives/uuid.rb +13 -3
  62. data/lib/flic/simple_client.rb +116 -78
  63. data/lib/flic/version.rb +1 -1
  64. metadata +17 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 30e6a6023c2fe3f2a83299ce7358050ef07195c8
4
- data.tar.gz: f1ac706e5cfca806615de68e6bf147893225662e
3
+ metadata.gz: b313acdfde6b058cfba2f4d0c148b8937e6c2ab9
4
+ data.tar.gz: c5805fd3c6421a2b688e7f4b85b7594423dbe4a1
5
5
  SHA512:
6
- metadata.gz: a9bc7ad01daea014be21f5214cb15a5cd4d4a2cb0ae6a7cc69b8da408fed1153279475607d1267172f6f1a2bb6e13fe391829f596989189af3f449a3030b257b
7
- data.tar.gz: a1263c875e8c918b4cd100d65d91964dda1a3d08c3ea613468556ac1eb6dcad6d25ec3c9e8a8fb074d445249358646dd4c1a2ca8b945712ea6065048fb9e84d0
6
+ metadata.gz: 2e8dd3aa2feed080bf4d36af89dd3bf532ebf00842099d08aca5a3403974a83fcc859edae2b45760d5097db6b6308277d4f194f26bf22e5b7733586a8bb25b68
7
+ data.tar.gz: 934f32212c39ef034446a6d502ffd6a7fd611e1fd751a1dba8bceaee079fe4bb455038cf93ae305db0d04ef2a46f4550b2b51cbc8865e75c89ccbfd7a215cb04
data/README.md CHANGED
@@ -32,7 +32,7 @@ A button must be in public mode before it can be added. To put a button in publi
32
32
  Similarly, a button may be disconnected by passing `Flic::SimpleClient#disconnect_button` a button's bluetooth address.
33
33
 
34
34
  ### Listening for button events
35
- `Flic::SimpleClient#listen` accepts a latency mode (`:low`, `:normal`, or `:high`) as it's first argument and button bluetooth addresses as its other arguments. For each event that occurs to those buttons, it yields the bluetooth address of the button responsible for a given event, the type of click involved in the event (`:button_down`, `:button_up`, `:button_single_click`, `:button_double_click`, or `:button_hold`), the time in milliseconds since the event occured, and whether the event was queued. **It will block until the connection is closed or the block raises some other exception.**
35
+ `Flic::SimpleClient#listen` accepts a latency mode (`:low`, `:normal`, or `:high`) as it's first argument and button bluetooth addresses as its other arguments. For each event that occurs to those buttons, it yields the bluetooth address of the button responsible for a given event, the type of click involved in the event (`:button_down`, `:button_up`, `:button_single_click`, `:button_double_click`, or `:button_hold`), the time in seconds since the event occured, and whether the event was queued. **It will block until the connection is closed or the block raises some other exception.**
36
36
 
37
37
  ### Closing the connection to `flicd`
38
38
  To gracefully cleanup all connection channels and close the socket connection, call `Flic::SimpleClient#shutdown`. Once a `Flic::SimpleClient` has been shutdown it will close the underlying socket and cannot be used anymore.
@@ -40,6 +40,7 @@ To gracefully cleanup all connection channels and close the socket connection, c
40
40
  ### Example
41
41
  This is the script that I wrote to allow some of my Flic buttons to control Wink-enabled smart devices in home.
42
42
  ```ruby
43
+
43
44
  #!/usr/bin/env ruby
44
45
 
45
46
  require 'bundler/setup'
@@ -55,61 +56,62 @@ BEDROOM_BUTTON = 'XX:XX:XX:XX:XX:XX'
55
56
  NIGHTSTAND_BUTTON = 'XX:XX:XX:XX:XX:XX'
56
57
 
57
58
  begin
58
- puts "[*] Opening a connection to flicd..."
59
- client = Flic::SimpleClient.new
60
-
61
- puts "[*] Entering main loop"
62
- client.listen(:low, LIVING_ROOM_BUTTON, BEDROOM_BUTTON, NIGHTSTAND_BUTTON) do |button, event, latency_ms|
63
- if latency_ms > 2000
64
- puts "[*] [#{button}] Ignoring #{event} because the latency is #{latency_ms} ms"
65
- else
66
- puts "[*] [#{button}] Handling #{event}"
67
-
68
- case button
69
- when LIVING_ROOM_BUTTON
70
- case event
71
- when :button_single_click
72
- puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
73
- when :button_double_click
74
- puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
75
- when :button_hold
76
- puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
77
- end
78
-
79
- when BEDROOM_BUTTON
80
- case event
81
- when :button_single_click
82
- puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
83
- when :button_double_click
84
- puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
85
- when :button_hold
86
- puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
87
- end
88
-
89
- when NIGHTSTAND_BUTTON
90
- case event
91
- when :button_single_click
92
- puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
93
- when :button_double_click
94
- puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
95
- when :button_hold
96
- puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
97
- end
98
- end
99
- end
100
- end
59
+ puts "[*] Opening a connection to flicd..."
60
+ client = Flic::SimpleClient.new
61
+
62
+ puts "[*] Entering main loop"
63
+ client.listen(:low, LIVING_ROOM_BUTTON, BEDROOM_BUTTON, NIGHTSTAND_BUTTON) do |button, event, latency|
64
+ if latency > 10
65
+ puts "[*] [#{button}] Ignoring #{event} because the latency is #{latency} seconds"
66
+ else
67
+ puts "[*] [#{button}] Handling #{event}"
68
+
69
+ case button
70
+ when LIVING_ROOM_BUTTON
71
+ case event
72
+ when :button_single_click
73
+ puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
74
+ when :button_double_click
75
+ puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
76
+ when :button_hold
77
+ puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
78
+ end
79
+
80
+ when BEDROOM_BUTTON
81
+ case event
82
+ when :button_single_click
83
+ puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
84
+ when :button_double_click
85
+ puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
86
+ when :button_hold
87
+ puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
88
+ end
89
+
90
+ when NIGHTSTAND_BUTTON
91
+ case event
92
+ when :button_single_click
93
+ puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
94
+ when :button_double_click
95
+ puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
96
+ when :button_hold
97
+ puts HTTParty.post('https://api.wink.com/scenes/SCENE_ID/activate', headers: { Authorization: "Bearer #{WINK_ACCESS_TOKEN}" }).inspect
98
+ end
99
+ end
100
+ end
101
+ end
101
102
  rescue StandardError => error
102
- puts "[!] Whoops! #{error.inspect} occured. Wait for a second and restart everything."
103
- sleep 1
103
+ puts "[!] Whoops! #{error.inspect} occured. Wait for a second and restart everything."
104
+ sleep 1
104
105
 
105
- retry
106
+ retry
106
107
  rescue Interrupt
107
- puts "[*] Shutting down gracefully because of an interrupt"
108
+ puts "[*] Shutting down gracefully because of an interrupt"
108
109
 
109
- client.shutdown
110
+ client.shutdown
110
111
  end
111
112
 
112
113
  puts "[*] Goodbye cruel world!"
114
+
113
115
  ```
114
116
 
115
117
  ## Advanced Usage
data/Rakefile CHANGED
@@ -1,12 +1,17 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
+ require 'yard'
3
4
 
4
5
  RSpec::Core::RakeTask.new(:spec)
5
- task :default => :spec
6
6
  task :test => :spec
7
7
 
8
+ YARD::Rake::YardocTask.new(:yard)
9
+ task :doc => :yard
10
+
8
11
  task :console do
9
12
  require 'flic'
10
13
  require 'pry'
11
14
  Pry.start
12
15
  end
16
+
17
+ task :default => [:spec, :doc]
@@ -22,4 +22,5 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency 'rake', '~> 10.0'
23
23
  spec.add_development_dependency 'rspec', '~> 3.0'
24
24
  spec.add_development_dependency 'pry'
25
+ spec.add_development_dependency 'yard'
25
26
  end
@@ -1,6 +1,7 @@
1
1
  require 'flic/version'
2
2
 
3
3
  module Flic
4
+ autoload :Blocker, 'flic/blocker'
4
5
  autoload :Callbacks, 'flic/callbacks'
5
6
  autoload :Client, 'flic/client'
6
7
  autoload :Protocol, 'flic/protocol'
@@ -0,0 +1,59 @@
1
+ require 'flic'
2
+
3
+ require 'thread'
4
+
5
+ module Flic
6
+ class Blocker
7
+ attr_reader :rejection_value
8
+
9
+ def initialize
10
+ @semaphore = Mutex.new
11
+ @queues = []
12
+ @rejection_value = nil
13
+ end
14
+
15
+ def block_until_callback
16
+ queue = Queue.new
17
+
18
+ begin
19
+ @semaphore.synchronize do
20
+ if @queues.frozen?
21
+ raise *rejection_value
22
+ else
23
+ @queues << queue
24
+ end
25
+ end
26
+
27
+ yield proc { |value| queue << [:resolve, value] }
28
+
29
+ control, value = queue.pop
30
+
31
+ case control
32
+ when :resolve
33
+ value
34
+ when :reject
35
+ raise *rejection_value
36
+ end
37
+ ensure
38
+ @semaphore.synchronize do
39
+ unless @queues.frozen?
40
+ @queues.delete queue
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ def unblock_all!(*rejection_value)
47
+ @semaphore.synchronize do
48
+ unless @queues.frozen?
49
+ @rejection_value = rejection_value
50
+
51
+ @queues.each { |queue| queue << [:reject, *rejection_value] }.clear
52
+ @queues.freeze
53
+
54
+ freeze
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -6,7 +6,7 @@ require 'socket'
6
6
  module Flic
7
7
  class Client
8
8
  class Error < StandardError; end
9
- class ClientShutdownError < Error; end
9
+ class Shutdown < Error; end
10
10
 
11
11
  autoload :ConnectionChannel, 'flic/client/connection_channel'
12
12
  autoload :Features, 'flic/client/features'
@@ -41,27 +41,32 @@ module Flic
41
41
  define_callbacks :new_button_verified, :bluetooth_controller_state_changed,
42
42
  :connections_exhausted, :connection_available
43
43
 
44
-
45
44
  def initialize(host = 'localhost', port = 5551)
46
45
  @host, @port = host, port
47
46
  @handle_next_event_semaphore = Mutex.new
48
47
  @socket = TCPSocket.new(host, port)
49
48
  @connection = Protocol::Connection.new(socket)
49
+ @is_shutdown = false
50
50
  yield self if block_given?
51
51
  end
52
52
 
53
+ def shutdown?
54
+ @is_shutdown
55
+ end
56
+
53
57
  def shutdown
54
- connection.close
58
+ socket.close
59
+ @is_shutdown = true
55
60
  end
56
61
 
57
62
  def handle_next_event
58
63
  @handle_next_event_semaphore.synchronize do
59
64
  begin
60
65
  handle_event connection.recv_event
61
- rescue Protocol::Connection::ConnectionClosedError
66
+ rescue Protocol::Connection::UnderlyingSocketClosedError
62
67
  shutdown
63
68
 
64
- raise ClientShutdownError, 'The connection has been closed'
69
+ raise Shutdown, 'The connection has been closed'
65
70
  end
66
71
  end
67
72
  end
@@ -74,10 +79,10 @@ module Flic
74
79
 
75
80
  def send_command(command)
76
81
  connection.send_command(command)
77
- rescue Protocol::Connection::ConnectionClosedError
82
+ rescue Protocol::Connection::UnderlyingSocketClosedError
78
83
  shutdown
79
84
 
80
- raise ClientShutdownError, 'The connection has been closed'
85
+ raise Shutdown, 'The connection has been closed'
81
86
  end
82
87
 
83
88
  def handle_event(event)
@@ -9,6 +9,10 @@ module Flic
9
9
 
10
10
  define_callbacks :added, :removed,
11
11
  :found_private_button, :found_public_button, :button_connected
12
+
13
+ def successful?
14
+ result == :success
15
+ end
12
16
  end
13
17
  end
14
18
  end
@@ -1,7 +1,11 @@
1
1
  require 'flic'
2
2
 
3
3
  module Flic
4
+ # This module contains an implementation of the Flic binary protocol. Of particular external interest is
5
+ # `Flic::Protocol::Connection` which provides a wrapper for the binary protocol around a socket instance.
4
6
  module Protocol
7
+ extend self
8
+
5
9
  class Error < StandardError; end
6
10
 
7
11
  autoload :Commands, 'flic/protocol/commands'
@@ -10,9 +14,10 @@ module Flic
10
14
  autoload :PacketHeader, 'flic/protocol/packet_header'
11
15
  autoload :Primitives, 'flic/protocol/primitives'
12
16
 
13
- INVALID_BUTTON_UUID = '00000000-0000-0000-0000-000000000000'.freeze
14
-
15
- def self.serialize_command(command)
17
+ # Serializes an instance of a protocol command class to a binary string
18
+ # @param command [Flic::Protocol::Commands::Command]
19
+ # @return [String] binary string
20
+ def serialize_command(command)
16
21
  case command
17
22
  when Commands::Command
18
23
  command.to_binary_s
@@ -23,7 +28,10 @@ module Flic
23
28
  raise Error, "Cannot serialize command `#{command.inspect}`"
24
29
  end
25
30
 
26
- def self.parse_command(serialized_command)
31
+ # Deserializes an instance of a protocol command class from a binary string
32
+ # @param serialized_command [String] binary string
33
+ # @return [Flic::Protocol::Commands::Command]
34
+ def parse_command(serialized_command)
27
35
  command = Commands::Command.read(serialized_command)
28
36
  opcode = command.opcode
29
37
  command_class = Commands::Command.command_class_for_opcode(opcode)
@@ -37,7 +45,10 @@ module Flic
37
45
  raise Error, "Cannot parse event `#{serialized_command.inspect}`"
38
46
  end
39
47
 
40
- def self.serialize_event(event)
48
+ # Serializes an instance of a protocol event class to a binary string
49
+ # @param event [Flic::Protocol::Events::Event]
50
+ # @return [String] binary string
51
+ def serialize_event(event)
41
52
  case event
42
53
  when Commands::Event
43
54
  event.to_binary_s
@@ -48,7 +59,10 @@ module Flic
48
59
  raise Error, "Cannot serialize event `#{event.inspect}`"
49
60
  end
50
61
 
51
- def self.parse_event(serialized_event)
62
+ # Deserializes an instance of a protocol event class from a binary string
63
+ # @param serialized_event [String] binary string
64
+ # @return [Flic::Protocol::Events::Event]
65
+ def parse_event(serialized_event)
52
66
  event = Events::Event.read(serialized_event)
53
67
  opcode = event.opcode
54
68
  event_class = Events.event_class_for_opcode(opcode)
@@ -2,6 +2,7 @@ require 'flic/protocol'
2
2
 
3
3
  module Flic
4
4
  module Protocol
5
+ # A namespace module for all of the command classes
5
6
  module Commands
6
7
  autoload :CancelScanWizard, 'flic/protocol/commands/cancel_scan_wizard'
7
8
  autoload :ChangeModeParameters, 'flic/protocol/commands/change_mode_parameters'
@@ -32,10 +33,16 @@ module Flic
32
33
 
33
34
  OPCODE_COMMAND_CLASS = COMMAND_CLASS_OPCODE.invert.freeze
34
35
 
36
+ # Finds the command class for a given opcode
37
+ # @param opcode [Integer]
38
+ # @return [Class]
35
39
  def self.command_class_for_opcode(opcode)
36
40
  OPCODE_COMMAND_CLASS[opcode]
37
41
  end
38
42
 
43
+ # Finds the opcode for a given command class
44
+ # @param command_class [Class]
45
+ # @return [Integer]
39
46
  def self.opcode_for_command_class(command_class)
40
47
  COMMAND_CLASS_OPCODE[command_class]
41
48
  end
@@ -6,9 +6,7 @@ module Flic
6
6
  module Protocol
7
7
  module Commands
8
8
  class CancelScanWizard < Command
9
- endian :little
10
-
11
- uint32 :scan_wizard_id
9
+ uint32le :scan_wizard_id
12
10
  end
13
11
  end
14
12
  end
@@ -7,9 +7,7 @@ module Flic
7
7
  module Protocol
8
8
  module Commands
9
9
  class ChangeModeParameters < Command
10
- endian :little
11
-
12
- uint32 :connection_channel_id
10
+ uint32le :connection_channel_id
13
11
  latency_mode :latency_mode
14
12
  disconnect_time :auto_disconnect_time
15
13
  end
@@ -6,15 +6,21 @@ module Flic
6
6
  module Protocol
7
7
  module Commands
8
8
  class Command < BinData::Record
9
- endian :little
10
-
11
- uint8 :opcode, initial_value: -> { init_opcode }
9
+ uint8le :opcode, initial_value: :class_opcode, assert: :opcode_matcher
12
10
 
13
11
  private
14
12
 
15
- def init_opcode
13
+ def class_opcode
16
14
  Commands.opcode_for_command_class(self.class)
17
15
  end
16
+
17
+ def opcode_matcher
18
+ if class_opcode
19
+ class_opcode
20
+ else
21
+ true
22
+ end
23
+ end
18
24
  end
19
25
  end
20
26
  end
@@ -8,9 +8,7 @@ module Flic
8
8
  module Protocol
9
9
  module Commands
10
10
  class CreateConnectionChannel < Command
11
- endian :little
12
-
13
- uint32 :connection_channel_id
11
+ uint32le :connection_channel_id
14
12
  bluetooth_address :bluetooth_address
15
13
 
16
14
  latency_mode :latency_mode