ledenet_api 1.2.2 → 1.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c112b458368c3f972704f893137b3b0beb90351b
4
- data.tar.gz: 0858ba4f9ca296a3d43dd3927f236ecd9f060076
3
+ metadata.gz: f8da932bc83469d8b334561d08eabd1030db8849
4
+ data.tar.gz: 2f241cab885aa1cfc4ef122724a918d919f1b9d6
5
5
  SHA512:
6
- metadata.gz: 2ef300b491b7636e9b271b8a78386074bd7be8b7a179aa69eeb88022fde35edecf1b07da21e36251e6a86d8d7528175f3ba58e5516f7784004a7f2bcdfa0e879
7
- data.tar.gz: 7bef60358efe62a5e03a72bb826fa797a492d4bbcc4166cebd8e8efc8f482de4913c226595ae350d41e750c3fd271fadd5857a1bfbc6bb7b7bbb7ea658489046
6
+ metadata.gz: 6eed4e0f31aa24481f0991d2d868ca297cb6441626f80dbb8091b3e6f1a0e13a31a78bd2607c7fe0abbd7dab2c0f10f8c248388e059665464f4d820999dafbc3
7
+ data.tar.gz: 098e2b9799d91d21d3f07c829493937f4da485979072613afa373ff902a41f09372c4f5cf5ce997f2960779a42f55c4b52e8d3f2c9fe9eeeb6aa7d62a3b3615d
data/README.md CHANGED
@@ -39,9 +39,11 @@ $ ledenet-ufo
39
39
  -w, --warm-white [VALUE] Set warm white to VALUE
40
40
  --on Turn on the controller
41
41
  --off Turn off the controller
42
- -l, --list Prints a list of available devices and exists
42
+ -l, --list Prints a list of available devices and exits
43
43
  -s, --status Prints status as JSON
44
44
  -h, --help Prints this help message
45
+ --function-id [VALUE] Set function id to VALUE
46
+ -f, --function [VALUE] Set function to VALUE.
45
47
  ```
46
48
 
47
49
  When using it, you can specify the IP address, hardware (mac) address, or let `ledenet_api` choose an arbitrary device on the local network (this would work well if you only have one).
@@ -76,6 +78,12 @@ $ ledenet-ufo --on -r 200 -g 0 -b 255 --warm-white 0 --status
76
78
  $ ledenet-ufo --off
77
79
  ```
78
80
 
81
+ #### Set function
82
+
83
+ ```
84
+ $ ledenet-ufo --function seven_color_cross_fade --speed 10
85
+ ```
86
+
79
87
  ### Ruby API
80
88
 
81
89
  #### Device discovery
@@ -161,3 +169,27 @@ api.update_color_data(red: 100)
161
169
 
162
170
  api.update_color_data(blue: 255, warm_white: 0)
163
171
  ```
172
+
173
+ #### Functions
174
+
175
+ The UFO devices ship with 20 pre-programmed lighting functions. ledenet_api has support for these:
176
+
177
+ ```ruby
178
+ LEDENET::Functions.all_functions
179
+ #=> [:SEVEN_COLOR_CROSS_FADE, :RED_GRADUAL_CHANGE, :GREEN_GRADUAL_CHANGE, :BLUE_GRADUAL_CHANGE, :YELLOW_GRADUAL_CHANGE, :CYAN_GRADUAL_CHANGE, :PURPLE_GRADUAL_CHANGE, :WHITE_GRADUAL_CHANGE, :RED_GREEN_CROSS_FADE, :RED_BLUE_CROSS_FADE, :SEVEN_COLOR_STROBE_FLASH, :RED_STROBE_FLASH, :GREEN_STROBE_FLASH, :BLUE_STROBE_FLASH, :YELLOW_STROBE_FLASH, :CYAN_STROBE_FLASH, :PURPLE_STROBE_FLASH, :WHITE_STROBE_FLASH, :SEVEN_COLOR_JUMPING_CHANGE, :GREEN_BLUE_CROSS_FADE]
180
+ ```
181
+
182
+ ```ruby
183
+ fn = LEDENET::Functions::SEVEN_COLOR_CROSS_FADE
184
+ speed = 0 # very slow
185
+
186
+ api.update_function(fn, speed)
187
+
188
+ api.update_function(:blue_green_cross_fade, 100) # Very fast
189
+ ```
190
+
191
+ To quit the function and return to a constant color, simply update a color value:
192
+
193
+ ```ruby
194
+ api.update_color_data(warm_white: 255)
195
+ ```
data/bin/ledenet-ufo CHANGED
@@ -99,12 +99,6 @@ if options[:list] && options.count > 1
99
99
  exit 1
100
100
  end
101
101
 
102
- if options[:function].nil? != options[:speed].nil?
103
- warn "--funciton and --speed must be specified together. You provide " <<
104
- "one without also providing the other."
105
- exit 1
106
- end
107
-
108
102
  begin
109
103
  if options[:list]
110
104
  devices = LEDENET.discover_devices(expected_devices: 1000)
@@ -136,22 +130,28 @@ begin
136
130
 
137
131
  api = LEDENET::Api.new(ip)
138
132
 
139
- api.set_power(options[:on?]) unless options[:on?].nil?
140
-
141
133
  color_params = options.select do |k,_|
142
134
  %w{red green blue warm_white}.include?(k.to_s)
143
135
  end
144
- api.update_color_data(color_params) unless color_params.empty?
145
136
 
146
- if options[:function] && options[:speed]
147
- api.update_function(options[:function], options[:speed])
137
+ if !options[:on?].nil?
138
+ api.set_power(options[:on?])
148
139
  end
149
140
 
150
- if options[:print_status?]
151
- status = api.current_color_data
152
- status = status.merge(is_on: api.on?)
141
+ if color_params.any?
142
+ api.update_color_data(color_params)
143
+ end
153
144
 
154
- puts status.to_json
145
+ if options[:function]
146
+ api.update_function(options[:function])
147
+ end
148
+
149
+ if options[:speed]
150
+ api.update_function_speed(options[:speed])
151
+ end
152
+
153
+ if options[:print_status?]
154
+ puts api.status.to_json
155
155
  end
156
156
  end
157
157
  rescue Exception => e
data/lib/ledenet/api.rb CHANGED
@@ -16,6 +16,13 @@ module LEDENET
16
16
  @options = DEFAULT_OPTIONS.merge(options)
17
17
  end
18
18
 
19
+ def status
20
+ response = request_status
21
+ status = { is_on: on?(response) }
22
+ status.merge!(current_color_data(response))
23
+ status.merge!(current_function_data(response))
24
+ end
25
+
19
26
  def on
20
27
  send_packet(LEDENET::Packets::SetPowerRequest.on_request)
21
28
  end
@@ -28,8 +35,8 @@ module LEDENET
28
35
  v ? on : off
29
36
  end
30
37
 
31
- def on?
32
- status.on?
38
+ def on?(response = request_status)
39
+ response.on?
33
40
  end
34
41
 
35
42
  def update_rgb(r, g, b)
@@ -53,20 +60,47 @@ module LEDENET
53
60
  current_color_data[:warm_white]
54
61
  end
55
62
 
56
- def current_color_data
57
- status_response = status
58
- color_data = %w{red green blue warm_white}.map do |x|
59
- [x.to_sym, status_response.send(x)]
60
- end
61
- Hash[color_data]
63
+ def current_color_data(response = request_status)
64
+ select_status_keys(response, *%w{red green blue warm_white})
62
65
  end
63
66
 
64
- def update_function(fn, speed)
67
+ def update_function(fn)
65
68
  if fn.is_a?(String) or fn.is_a?(Symbol)
66
69
  fn = LEDENET::Functions.const_get(fn.upcase)
67
70
  end
71
+ update_function_data(function_id: fn)
72
+ end
68
73
 
69
- send_packet(LEDENET::Packets::SetFunctionRequest.new(function_id: fn, speed: speed))
74
+ def update_function_speed(s)
75
+ update_function_data(speed: s)
76
+ end
77
+
78
+ def update_function_data(o)
79
+ o = {}.merge(o)
80
+ current_data = current_function_data
81
+ updated_data = {
82
+ function_id: current_data[:function_id],
83
+ speed: current_data[:speed_packet_value]
84
+ }
85
+
86
+ if o[:speed]
87
+ speed = LEDENET::FunctionSpeed.from_value(o.delete(:speed))
88
+ updated_data[:speed] = speed.packet_value
89
+ end
90
+ updated_data.merge!(o)
91
+
92
+ send_packet(LEDENET::Packets::SetFunctionRequest.new(updated_data))
93
+ end
94
+
95
+ def current_function_data(response = request_status)
96
+ raw_function_data = select_status_keys(response, *%w{mode speed})
97
+ function_data = {
98
+ running_function?: raw_function_data[:mode] != LEDENET::Functions::NO_FUNCTION,
99
+ speed: FunctionSpeed.from_packet_value(raw_function_data[:speed]).value,
100
+ speed_packet_value: raw_function_data[:speed],
101
+ function_name: LEDENET::Functions.value_of(raw_function_data[:mode]),
102
+ function_id: raw_function_data[:mode]
103
+ }
70
104
  end
71
105
 
72
106
  def reconnect!
@@ -85,8 +119,17 @@ module LEDENET
85
119
  end
86
120
 
87
121
  private
88
- def status
89
- send_packet(LEDENET::Packets::StatusRequest.new)
122
+ def select_status_keys(status_response, *keys)
123
+ color_data = keys.map do |x|
124
+ [x.to_sym, status_response.send(x)]
125
+ end
126
+ Hash[color_data]
127
+ end
128
+
129
+ def request_status
130
+ s = send_packet(LEDENET::Packets::StatusRequest.new)
131
+ puts s.inspect
132
+ s
90
133
  end
91
134
 
92
135
  def create_socket
@@ -0,0 +1,36 @@
1
+ module LEDENET
2
+ class FunctionSpeed
3
+ # Speed range exposed through API
4
+ INTERFACE_SPEED_RANGE = (1..100)
5
+
6
+ # Speed value is in [0x01, 0x1F], with 0x00 being the fastest.
7
+ PACKET_SPEED_RANGE = (0x01..0x1F)
8
+
9
+ attr_reader :value
10
+
11
+ def initialize(value)
12
+ @value = value
13
+ end
14
+
15
+ def packet_value
16
+ FunctionSpeed.convert_range(value, INTERFACE_SPEED_RANGE, PACKET_SPEED_RANGE)
17
+ end
18
+
19
+ def self.from_value(value)
20
+ FunctionSpeed.new(value)
21
+ end
22
+
23
+ def self.from_packet_value(value)
24
+ v = FunctionSpeed.convert_range(value, PACKET_SPEED_RANGE, INTERFACE_SPEED_RANGE)
25
+ FunctionSpeed.new(v)
26
+ end
27
+
28
+ private
29
+ def self.convert_range(value, from, to)
30
+ scaled_speed = (value / (from.max.to_f / to.max)).round
31
+ scaled_speed = [to.min, scaled_speed].max
32
+ scaled_speed = [to.max, scaled_speed].min
33
+ to.max - scaled_speed
34
+ end
35
+ end
36
+ end
@@ -20,11 +20,16 @@ module LEDENET
20
20
  CYAN_STROBE_FLASH = 0x35,
21
21
  PURPLE_STROBE_FLASH = 0x36,
22
22
  WHITE_STROBE_FLASH = 0x37,
23
- SEVEN_COLOR_JUMPING_CHANGE = 0x38
23
+ SEVEN_COLOR_JUMPING_CHANGE = 0x38,
24
+ NO_FUNCTION = 0x61
24
25
  ]
25
26
 
26
27
  def self.all_functions
27
28
  LEDENET::Functions.constants.reject { |x| x == :VALUES }
28
29
  end
30
+
31
+ def self.value_of(i)
32
+ all_functions.select { |x| self.const_get(x) == i }.first
33
+ end
29
34
  end
30
35
  end
@@ -5,30 +5,11 @@ require 'ledenet/packets/empty_response'
5
5
 
6
6
  module LEDENET::Packets
7
7
  class SetFunctionRequest < BinData::Record
8
- VALID_SPEED_RANGE = (0..100)
9
-
10
- # Speed value is in [0x00, 0x20], with 0x00 being the fastest.
11
- PACKET_SPEED_RANGE = (0x00..0x20)
12
-
13
8
  hide :checksum
14
- mandatory_parameter :function_id
15
- mandatory_parameter :speed
16
9
 
17
10
  uint8 :packet_id, value: 0x61
18
- uint8 :function_id_val, value: ->() { function_id }
19
-
20
- uint8 :speed_val, value: ->() do
21
- if !VALID_SPEED_RANGE.include?(speed)
22
- raise "Speed should be between #{VALID_SPEED_RANGE.min} and #{VALID_SPEED_RANGE.max}"
23
- end
24
-
25
- scaled_speed = (speed / (VALID_SPEED_RANGE.max / PACKET_SPEED_RANGE.max)).round
26
- scaled_speed = [PACKET_SPEED_RANGE.min, scaled_speed].max
27
- scaled_speed = [PACKET_SPEED_RANGE.max, scaled_speed].min
28
-
29
- PACKET_SPEED_RANGE.max - scaled_speed
30
- end
31
-
11
+ uint8 :function_id
12
+ uint8 :speed
32
13
  uint8 :remote_or_local, value: 0x0F
33
14
  checksum :checksum, packet_data: ->() { snapshot }
34
15
 
@@ -21,7 +21,7 @@ module LEDENET::Packets
21
21
  uint8 :blue
22
22
  uint8 :warm_white
23
23
 
24
- uint16be :unused_payload
24
+ uint24be :unused_payload
25
25
  uint8 :checksum
26
26
 
27
27
  def on?
@@ -1,3 +1,3 @@
1
1
  module LEDENET
2
- VERSION = '1.2.2'
2
+ VERSION = '1.4.0'
3
3
  end
data/lib/ledenet_api.rb CHANGED
@@ -2,3 +2,4 @@ require 'ledenet/version'
2
2
  require 'ledenet/device_discovery'
3
3
  require 'ledenet/api'
4
4
  require 'ledenet/functions'
5
+ require 'ledenet/function_speed'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ledenet_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Mullins
@@ -98,6 +98,7 @@ files:
98
98
  - ledenet_api.gemspec
99
99
  - lib/ledenet/api.rb
100
100
  - lib/ledenet/device_discovery.rb
101
+ - lib/ledenet/function_speed.rb
101
102
  - lib/ledenet/functions.rb
102
103
  - lib/ledenet/packets/empty_response.rb
103
104
  - lib/ledenet/packets/fields/checksum.rb