neotrellis 0.1.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.
@@ -0,0 +1,113 @@
1
+ # Neotrellis
2
+
3
+ Neotrellis is a ruby driver for Adafruit's NeoTrellis keypad. This device uses an I2C bus to control both the keypad and the RGB led array.
4
+
5
+ [Neotrelliis](datasheets/neotrellis.jpg)
6
+
7
+ See https://www.adafruit.com/product/3954 for more details on this device.
8
+
9
+ This ruby gem is mainly compose of two classes :
10
+ - Neotrellis::Neopixels to control the leds behind each keys.
11
+ - Neotrellis::Keypad to execute code when a key is pressed or released on the keypad
12
+
13
+ The Keypad class provide two modes to react to key events: using pooling with a loop or using interruption handler. The pooling mode require only the I2C communication to be set up. For the interruption mode to work, the pin INT on the keypad need to be connected to a GPIO input supporting hardware interruption on your computer. A common use case are the pins 15 or 16 of the Raspberry Pi GPIO header. See Raspberry Pi documentation for more details.
14
+
15
+ The support of hardware interruption is done by the [YaGPIO](https://github.com/nagius/ya_gpio) gem based on Sysfs interface. It has been designed for Raspberry Pi but should work with any GPIO systems supported by the Sysfs kernel driver.
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'neotrellis'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ $ bundle
28
+
29
+ Or install it yourself as:
30
+
31
+ $ gem install neotrellis
32
+
33
+ ## Usage
34
+
35
+ We will suppose here that you are using a Rasberry Pi B+ to control the Neotrellis device. Adapt the I2C device name and pin numbers for other boards.
36
+
37
+ First, connect the pins SDA and SLC of the keypad to GPIO pins 3 and 5. The device will appear on the second I2C bus of the Raspberry Pi `/dev/i2c-1`. Te I2C port need to be enabled in the linux kenel to operate. Refer to Raspberry Pi documentation to do so.
38
+
39
+ If you want to use the interruption mode also connect the INT pin to the GPIO pin 15 (GPIO22).
40
+
41
+ ### Example 1: Print a message when key #3 is pressed using polling
42
+
43
+ ```ruby
44
+ seesaw = Neotrellis::Seesaw.new(device: "/dev/i2c-1", addr: 0x2E)
45
+ keypad = Neotrellis::Keypad.new(seesaw)
46
+ keypad.set_event(2, event: Neotrellis::Keypad::KEY_PRESSED) { |event|
47
+ puts "Key #{event.key} pressed"
48
+ }
49
+ loop do
50
+ sleep(1)
51
+ puts "Processing pending events"
52
+ keypad.sync
53
+ end
54
+ ```
55
+
56
+ ### Example 2: Print a message when key #3 is released using interruption
57
+
58
+ ```ruby
59
+ seesaw = Neotrellis::Seesaw.new(device: "/dev/i2c-1", addr: 0x2E)
60
+ keypad = Neotrellis::Keypad.new(seesaw)
61
+ keypad.set_event(2, event: Neotrellis::Keypad::KEY_RELEASED) { |event|
62
+ puts "Key #{event.key}"
63
+ puts event.edge == Neotrellis::Keypad::KEY_PRESSED ? "pressed" : "released"
64
+ }
65
+ keypad.enable_interrupt(22)
66
+ keypad.wait_for_event
67
+ ```
68
+
69
+ ### Example 3: Turn on led #2 in red for 2 seconds
70
+
71
+ ```ruby
72
+ seesaw = Neotrellis::Seesaw.new(device: "/dev/i2c-1", addr: 0x2E)
73
+ pixels = Neotrellis::Neopixel.new(seesaw)
74
+ pixels.set(1, Neotrellis::Neopixel::RED)
75
+ sleep 2
76
+ pixels.set(1, Neotrellis::Neopixel::OFF)
77
+ ```
78
+
79
+ ### Example 4: Turn on the pressed key with a random color
80
+
81
+ ```ruby
82
+ seesaw = Neotrellis::Seesaw.new(device: "/dev/i2c-1", addr: 0x2E)
83
+ keypad = Neotrellis::Keypad.new(seesaw, interrupt_pin: 22)
84
+ pixels = Neotrellis::Neopixel.new(seesaw)
85
+
86
+ Neotrellis::Neopixel::DEFAULT_PIXEL_NUMBER.times do |key|
87
+ keypad.set_event(key) do |event|
88
+ if event.edge == Neotrellis::Keypad::KEY_PRESSED
89
+ pixels.set(event.key, Neotrellis::Neopixel::Color.new(rand(255), rand(255), rand(255)))
90
+ else
91
+ pixels.set(event.key, Neotrellis::Neopixel::OFF)
92
+ end
93
+ end
94
+ end
95
+ keypad.wait_for_event
96
+ ```
97
+
98
+ ### API documentation
99
+
100
+ The API documentation is available in the Yard format. To generate it under the `doc` directory, run :
101
+
102
+ ```
103
+ bundle exec rake yard
104
+ ```
105
+
106
+ ## Contributing
107
+
108
+ Bug reports and pull requests are welcome on GitHub at https://github.com/nagius/neotrellis.
109
+
110
+ ## License
111
+
112
+ Copyleft 2019 - Nicolas AGIUS - GNU GPLv3
113
+
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require 'yard'
4
+
5
+ YARD::Rake::YardocTask.new do |t|
6
+ t.files = ['lib/neotrellis/*.rb']
7
+ t.stats_options = ['--list-undoc']
8
+ end
9
+
10
+ RSpec::Core::RakeTask.new(:spec)
11
+
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "neotrellis"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
Binary file
@@ -0,0 +1,3 @@
1
+ require 'neotrellis/seesaw'
2
+ require 'neotrellis/neopixel'
3
+ require 'neotrellis/keypad'
@@ -0,0 +1,230 @@
1
+ # Neotrellis - Driver for Adafruit's NeoTrellis keypad
2
+ # Copyleft 2019 - Nicolas AGIUS <nicolas.agius@lps-it.fr>
3
+
4
+ ###########################################################################
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+ ###########################################################################
20
+
21
+ require 'ya_gpio'
22
+
23
+ module Neotrellis
24
+ # Driver for the Neotrellis 4x4 keypad.
25
+ #
26
+ # @example Print a message when key #3 is pressed
27
+ # seesaw = Neotrellis::Seesaw.new(device: "/dev/i2c-1", addr: 0x2E)
28
+ # keypad = Neotrellis::Keypad.new(seesaw)
29
+ # keypad.set_event(2, event: Neotrellis::Keypad::KEY_PRESSED) { |event|
30
+ # puts "Key #{event.key} pressed"
31
+ # }
32
+ # loop do
33
+ # sleep(1)
34
+ # puts "Processing pending events"
35
+ # keypad.sync
36
+ # end
37
+ #
38
+ # @example Print a message when key #3 is released using interruption on GPIO pin 22
39
+ # seesaw = Neotrellis::Seesaw.new(device: "/dev/i2c-1", addr: 0x2E)
40
+ # keypad = Neotrellis::Keypad.new(seesaw)
41
+ # keypad.set_event(2, event: Neotrellis::Keypad::KEY_RELEASED) { |event|
42
+ # puts "Key #{event.key}"
43
+ # puts event.edge == Neotrellis::Keypad::KEY_PRESSED ? "pressed" : "released"
44
+ # }
45
+ # keypad.enable_interrupt(22)
46
+ # keypad.wait_for_event
47
+ #
48
+ # @example Stop waiting for events when key #4 is pressed
49
+ # seesaw = Neotrellis::Seesaw.new(device: "/dev/i2c-1", addr: 0x2E)
50
+ # keypad = Neotrellis::Keypad.new(seesaw, interrupt_pin: 22)
51
+ # keypad.set_event(3, event: Neotrellis::Keypad::KEY_PRESSED) {
52
+ # keypad.resume
53
+ # }
54
+ # keypad.wait_for_event
55
+ # puts "loop ended"
56
+ class Keypad
57
+
58
+ private
59
+ # Internal SeeSaw registers
60
+ KEYPAD_BASE = 0x10
61
+
62
+ KEYPAD_STATUS = 0x00
63
+ KEYPAD_EVENT = 0x01
64
+ KEYPAD_INTENSET = 0x02
65
+ KEYPAD_INTENCLR = 0x03
66
+ KEYPAD_COUNT = 0x04
67
+ KEYPAD_FIFO = 0x10
68
+
69
+ public
70
+
71
+ KEY_HIGH = 0 # Key is pressed
72
+ KEY_LOW = 1 # Key is released
73
+ KEY_RELEASED = 2 # Key is falling edge
74
+ KEY_PRESSED = 3 # Key is rising edge
75
+ KEY_BOTH = 4 # Key is rising edge or falling edge
76
+
77
+ # Initialize the keypad driven by a Seesaw chip.
78
+ #
79
+ # @param seesaw [Neotrellis::SeeSaw] Seesaw driver
80
+ # @param interrupt_pin [Integer] GPIO pin used by the interruption handler. If false, the interruption mode will be disabled.
81
+ # @param debug [Boolean] Enable debug ouput on stdout
82
+ def initialize(seesaw, interrupt_pin: false, debug: false)
83
+ @seesaw = seesaw
84
+ @debug = debug
85
+ @callbacks = {}
86
+
87
+ enable_interrupt(interrupt_pin) if interrupt_pin
88
+ end
89
+
90
+ # Get the number of events (key pressed or released) waiting to be processed in the Seesaw buffer.
91
+ #
92
+ # @return [Integer] Number of events
93
+ def count_events
94
+ @seesaw.read_byte(KEYPAD_BASE, KEYPAD_COUNT)
95
+ end
96
+
97
+ # Register a callback to execute when a key's event is processed.
98
+ #
99
+ # @param key [Integer] ID of the key. Must be between 0 and 15 (for the 4x4 keypad)
100
+ # @param event [Neotrellis::Keypad::KEY_PRESSED|Neotrellis::Keypad::KEY_RELEASED|Neotrellis::Keypad::KEY_BOTH] Type of event to react to.
101
+ # @param enabled [Boolean] If false, the callback will be disabled.
102
+ # @param block [Block] Code to execute when the event is trigerred. A Neotrellis::Keypad::KeyEvent will be passed as argument to the block.
103
+ def set_event(key, event: KEY_BOTH, enabled: true, &block)
104
+ if event == KEY_BOTH
105
+ set_event(key, event: KEY_PRESSED, enabled: enabled, &block)
106
+ set_event(key, event: KEY_RELEASED, enabled: enabled, &block)
107
+ else
108
+ raise "event must be one of KEY_PRESSED, KEY_RELEASED" unless [KEY_PRESSED, KEY_RELEASED].include? event
109
+ raise "enabled must be a boolean" unless [true, false].include? enabled
110
+
111
+ # Convert data to SeeSaw's binary registers
112
+ key_b = (key/4)*8 + (key%4)
113
+ edge_b = (1 << (event+1)) | ( enabled ? 1 : 0 )
114
+
115
+ @seesaw.write(KEYPAD_BASE, KEYPAD_EVENT, key_b, edge_b)
116
+ @callbacks[KeyEvent.new(key, event)] = block
117
+ end
118
+ end
119
+
120
+ # Trigger the callback for each event waiting to be processed.
121
+ # This method will be automatically called when the interruption mode is enabled.
122
+ def sync
123
+ count = count_events()
124
+ if count >0
125
+ read_events(count).each do |event|
126
+ trigger_event(event)
127
+ end
128
+ end
129
+ end
130
+
131
+ # Enable the interruption mode.
132
+ # In this mode, the `sync()` method will be automatically called when an interruption is triggered by the Seesaw device.
133
+ # The INT ligne of the keypad need to be connected to this GPIO pin.
134
+ #
135
+ # @param pin [Integer] GPIO pin to configure for interruption on. Pin number is in the BCM numbering, as reported by Sysfs.
136
+ def enable_interrupt(pin)
137
+ raise "pin must be an integer" unless pin.is_a? Integer
138
+
139
+ @interrupt_enabled=true
140
+ @seesaw.write(KEYPAD_BASE, KEYPAD_INTENSET, 0x01)
141
+
142
+ @gpio = YaGPIO.new(pin, YaGPIO::INPUT)
143
+ @gpio.set_interrupt(YaGPIO::EDGE_FALLING) do
144
+ puts "DEBUG Interrupt received." if @debug
145
+ sync
146
+ end
147
+ end
148
+
149
+ # Tell if the interruption mode is enabled.
150
+ #
151
+ # @return [Boolean] True if interruption mode is enabled.
152
+ def interrupt?
153
+ @interrupt_enabled
154
+ end
155
+
156
+ # Disable interruption mode and release the GPIO pin.
157
+ def disable_interrupt
158
+ @interrupt_enabled=false
159
+ @seesaw.write(KEYPAD_BASE, KEYPAD_INTENCLR, 0x01)
160
+ @gpio.close
161
+ end
162
+
163
+ # Wait for an interruption and process all pending event.
164
+ # The interruption mode must be enabled for this method to work.
165
+ # This is a blocking method. Use `resume()` inside a callback to stop waiting.
166
+ def wait_for_event
167
+ raise "Interrupt is not enabled. Setup enable_interrupt() first" unless interrupt?
168
+ YaGPIO::wait([@gpio])
169
+ end
170
+
171
+ # Stop waiting for an event in the interruption mode.
172
+ # This need to be run from a callback triggered by `wait_for_event()`.
173
+ def resume
174
+ YaGPIO::resume
175
+ end
176
+
177
+ # Represent an event attached to a key
178
+ class KeyEvent
179
+ attr_reader :key # Key ID
180
+ attr_reader :edge # Event type
181
+
182
+ # Create a new event.
183
+ #
184
+ # @param key [Integer] Key ID related to the event
185
+ # @param edge [Neotrellis::Keypad::KEY_PRESSED|Neotrellis::Keypad::KEY_RELEASED] Type of event
186
+ def initialize(key, edge)
187
+ @key = key
188
+ @edge = edge
189
+ end
190
+
191
+ def to_s
192
+ "Event-#{key}-#{edge}"
193
+ end
194
+
195
+ def ==(other)
196
+ @key == other.key && @edge == other.edge
197
+ end
198
+
199
+ alias eql? ==
200
+
201
+ def hash
202
+ @key.hash ^ @edge.hash # XOR
203
+ end
204
+ end
205
+
206
+ private
207
+
208
+ def read_events(count)
209
+ @seesaw.read_bytes(count, KEYPAD_BASE, KEYPAD_FIFO).map do |raw|
210
+ # Convert raw event into key number
211
+ val = (raw >> 2) & 0x3F
212
+ key = (val/8)*4 + (val%8)
213
+ edge = raw & 0x3
214
+
215
+ KeyEvent.new(key, edge)
216
+ end
217
+ end
218
+
219
+ def trigger_event(event)
220
+ callback = @callbacks[event]
221
+ if callback.nil?
222
+ puts "WARNING: No callback defined for #{event}"
223
+ else
224
+ callback.call(event)
225
+ end
226
+ end
227
+ end
228
+ end
229
+
230
+ # vim: ts=4:sw=4:ai
@@ -0,0 +1,198 @@
1
+ # Neotrellis - Driver for Adafruit's NeoTrellis keypad
2
+ # Copyleft 2019 - Nicolas AGIUS <nicolas.agius@lps-it.fr>
3
+
4
+ ###########################################################################
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+ ###########################################################################
20
+
21
+
22
+ # Neotrellis is a ruby driver for Adafruit's NeoTrellis keypad
23
+ module Neotrellis
24
+
25
+ # Neopixel is the driver of the RGB led array on the Neotrellis device.
26
+ #
27
+ # @example Turn on led #2 in red for 2 seconds with debug output
28
+ # seesaw = Neotrellis::Seesaw.new(device: "/dev/i2c-1", addr: 0x2E, debug: true)
29
+ # pixels = Neotrellis::Neopixel.new(seesaw)
30
+ # pixels.set(1, Neotrellis::Neopixel::RED)
31
+ # sleep 2
32
+ # pixels.set(1, Neotrellis::Neopixel::OFF)
33
+ #
34
+ # @example Turn on all leds with color #b5f115 for 2 seconds
35
+ # seesaw = Neotrellis::Seesaw.new(device: "/dev/i2c-1", addr: 0x2E)
36
+ # pixels = Neotrellis::Neopixel.new(seesaw)
37
+ # pixels.fill(Neotrellis::Neopixel::Color.new(181, 241, 21))
38
+ # sleep 2
39
+ # pixels.off
40
+ #
41
+ # @example Display white columns
42
+ # seesaw = Neotrellis::Seesaw.new(device: "/dev/i2c-1", addr: 0x2E)
43
+ # pixels = Neotrellis::Neopixel.new(seesaw, autoshow: false)
44
+ # Neotrellis::Neopixel::DEFAULT_PIXEL_NUMBER.times { |i|
45
+ # pixels.set(i, Neotrellis::Neopixel::WHITE) unless i%2 == 0
46
+ # }
47
+ # pixels.show
48
+ class Neopixel
49
+ attr_reader :brightness # Get the brightness of the leds.
50
+ attr_accessor :autoshow # Enable autoshow feature. Automatically call `show()` after each update.
51
+
52
+ DEFAULT_PIXEL_NUMBER = 16 # Default number of leds on the neotrellis 4x4 keypad
53
+
54
+ private
55
+
56
+ NEOPIXEL_BASE = 0x0E
57
+
58
+ NEOPIXEL_STATUS = 0x00
59
+ NEOPIXEL_PIN = 0x01
60
+ NEOPIXEL_SPEED = 0x02
61
+ NEOPIXEL_BUF_LENGTH = 0x03
62
+ NEOPIXEL_BUF = 0x04
63
+ NEOPIXEL_SHOW = 0x05
64
+
65
+ public
66
+
67
+ # Initialize a neopixel array driven by a seesaw chip.
68
+ #
69
+ # @param seesaw [Neotrellis::SeeSaw] Seesaw driver
70
+ # @param size [Integer] Number of leds on the array
71
+ # @param autoshow [Boolean] Automatically call `show()` after each update
72
+ # @param brightness [Float] Brightness of the leds. Must be between 0.0 and 1.0
73
+ def initialize(seesaw, size: DEFAULT_PIXEL_NUMBER, autoshow: true, brightness: 1.0)
74
+ @seesaw = seesaw
75
+ @pin = 3 # NeoPixel bus is on SeeSaw's pin 3
76
+ @n = size # Number of NeoPixels on the bus
77
+ @bpp = 3 # 3 bytes per pixel
78
+ @autoshow = autoshow # Automaticaly display data in buffer
79
+ @brightness = [[brightness, 0.0].max, 1.0].min
80
+
81
+ # Size of RGB buffer, 2 bytes for Unsigned Int Big Endian
82
+ buf_length = [@n*@bpp].pack('S>').unpack('C*')
83
+
84
+ @seesaw.write(NEOPIXEL_BASE, NEOPIXEL_PIN, @pin)
85
+ @seesaw.write(NEOPIXEL_BASE, NEOPIXEL_BUF_LENGTH, *buf_length)
86
+ end
87
+
88
+ # Set the brightness of the leds
89
+ #
90
+ # @param brightness [Float] Brightness of the leds. Must be between 0.0 and 1.0
91
+ #
92
+ # @return [Float] New brightness value
93
+ def brightness=(brightness)
94
+ @brightness = [[brightness, 0.0].max, 1.0].min
95
+ end
96
+
97
+ # Set the color of one pixel.
98
+ # If `autoshow` is false nothing will be displayed until you call the `show()` method.
99
+ #
100
+ # @param pixel [Integer] ID of the pixel in the array. Must be between 0 and `size`-1
101
+ # @param color [Neotrellis::Neopixel::Color] Color to display by the pixel
102
+ def set(pixel, color)
103
+ raise "pixel out of range" unless pixel.between?(0, @n-1)
104
+
105
+ @seesaw.write(NEOPIXEL_BASE, NEOPIXEL_BUF, *([pixel*@bpp].pack('S>').unpack('C*')), *color.to_b(brightness))
106
+ show if @autoshow
107
+ end
108
+
109
+ # Render the data already written in the Seesaw buffer.
110
+ # If `autoshow` is true, this method is called automatically by `set()` and `fill()`
111
+ def show
112
+ @seesaw.write(NEOPIXEL_BASE, NEOPIXEL_SHOW)
113
+ end
114
+
115
+ # Set the same color for all pixels of the array.
116
+ # If `autoshow` is false nothing will be displayed until you call the `show()` method.
117
+ #
118
+ # @param color [Neotrellis::Neopixel::Color] Color to display by the pixels
119
+ def fill(color)
120
+ # Disable auto show while filling the buffer
121
+ current_autoshow = @autoshow
122
+ @autoshow=false
123
+
124
+ @n.times do |pixel|
125
+ set(pixel, color)
126
+ end
127
+
128
+ @autoshow = current_autoshow
129
+ show if @autoshow
130
+ end
131
+
132
+ # Set a different random color for every pixels of the array.
133
+ # If `autoshow` is false nothing will be displayed until you call the `show()` method.
134
+ def fill_random()
135
+ # Disable auto show while filling the buffer
136
+ current_autoshow = @autoshow
137
+ @autoshow=false
138
+
139
+ @n.times do |pixel|
140
+ set(pixel, Color.new(rand(255), rand(255), rand(255)))
141
+ end
142
+
143
+ @autoshow = current_autoshow
144
+ show if @autoshow
145
+ end
146
+
147
+ # Swtich off all pixels of the array.
148
+ # If `autoshow` is false nothing will be displayed until you call the `show()` method.
149
+ def off()
150
+ fill(OFF)
151
+ end
152
+
153
+ # Define a color to be set on a pixel
154
+ class Color
155
+ attr_reader :r, :g, :b # R G B components
156
+
157
+ # Create a new color.
158
+ # R G B values must be between 0 and 255
159
+ #
160
+ # @param r [Integer] Red component
161
+ # @param g [Integer] Green component
162
+ # @param b [Integer] Blue component
163
+ def initialize(r, g, b)
164
+ @r = within_range(r)
165
+ @g = within_range(g)
166
+ @b = within_range(b)
167
+ end
168
+
169
+ # Apply a brightness to the color.
170
+ #
171
+ # @param brightness [Float] Brightness of the color. Must be between 0.0 and 1.0
172
+ #
173
+ # @return [Array] Color values as integer in the order GRB
174
+ def to_b(brightness = 1.0)
175
+ # Order is GRB
176
+ [(@g*brightness).to_i, (@r*brightness).to_i, (@b*brightness).to_i]
177
+ end
178
+
179
+ private
180
+
181
+ def within_range(byte)
182
+ [[byte, 0].max, 255].min
183
+ end
184
+ end
185
+
186
+ # Default common colors
187
+ OFF = Color.new(0, 0, 0)
188
+ RED = Color.new(255, 0, 0)
189
+ YELLOW = Color.new(255, 150, 0)
190
+ GREEN = Color.new(0, 255, 0)
191
+ CYAN = Color.new(0, 255, 255)
192
+ BLUE = Color.new(0, 0, 255)
193
+ PURPLE = Color.new(180, 0, 255)
194
+ WHITE = Color.new(255, 255, 255)
195
+ end
196
+ end
197
+
198
+ # vim: ts=4:sw=4:ai