lightpack 0.0.1

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.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2014 Douwe Maan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,124 @@
1
+ # lightpack
2
+
3
+ A Ruby library for communicating with your [Lightpack](http://lightpack.tv).
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ gem install lightpack
9
+ ```
10
+
11
+ Or in your Gemfile:
12
+
13
+ ```ruby
14
+ gem "lightpack"
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```ruby
20
+ require "lightpack"
21
+
22
+ # You can open a connection to the Lightpack that will live for the duration of the block using `.open`:
23
+ Lightpack.open do |lightpack|
24
+ # Use `lightpack` as described below.
25
+ end
26
+
27
+ # If you want a little more control over opening and closing the connection, just use `.new`:
28
+ lightpack = Lightpack.new("127.0.0.1", 3636, "api_key")
29
+ # "127.0.0.1" and 3636 are the default host and port and can be omitted as in the `.open` example.
30
+ # The third parameter is the optional api key, which you need to set
31
+ # if you've set up your Lightpack to require authentication.
32
+
33
+ # You can then explicitly open a connection to the lightpack.
34
+ # You're responsible for closing it using `#disconnect` when you're done.
35
+ lightpack.connect
36
+
37
+ # If you need to authenticate but haven't done so yet with `.open` or `.new`,
38
+ # you can do so manually after connecting.
39
+ lightpack.authenticate("api_key")
40
+
41
+ # The Lightpack object exposes a lot of interesting information:
42
+ lightpack.status # :on, :off, :device_error or :unknown
43
+ lightpack.on? # true or false
44
+ lightpack.api_status # :idle or :busy
45
+
46
+ lightpack.profiles # ["Lightpack", "Other profile"]
47
+ lightpack.profile # "Lightpack"
48
+
49
+ lightpack.led_count # 10
50
+ lightpack.led_areas # [{:x=>1920, :y=>1224, :width=>640, :height=>216}, {:x=>2176, :y=>720, ...}, ...]
51
+ lightpack.colors # [[170, 170, 173], [190, 190, 192], ...] # Red, Green, Blue
52
+
53
+ lightpack.fps # 20.04
54
+ lightpack.screen_size # [0, 0, 2560, 1440]
55
+ lightpack.mode # :ambilight or :moodlamp
56
+
57
+ # Of course, you can also _do_ certain things with your Lightpack.
58
+ # All of these return true when successful and raise an error otherwise.
59
+ lightpack.turn_on
60
+ lightpack.turn_off
61
+
62
+ lightpack.profile = "Other profile"
63
+ lightpack.mode = :moodlamp
64
+
65
+ lightpack.gamma = 2.5 # 0.1..10
66
+ lightpack.brightness = 93 # 0..100
67
+ lightpack.smooth = 128 # 0..255
68
+
69
+ lightpack.set_color(0, 255, 0, 0) # index of LED, Red, Green, Blue
70
+ lightpack.set_all_colors(0, 255, 0)
71
+ lightpack.set_led_areas(0, { x: 1920, y: 1224, width: 640, height: 216 })
72
+ lightpack.add_profile("New profile")
73
+ lightpack.delete_profile("Other profile")
74
+
75
+ # Note that all of the action methods above require a lock on the Lightpack.
76
+ # This lock is acquired automatically if you haven't done so manually,
77
+ # but if you want to do a number of actions sequentially, acquiring a lock once
78
+ # would be more efficient than acquiring and releasing one for every action.
79
+
80
+ # You can acquire a lock for the duration of a block like this:
81
+ lightpack.with_lock do
82
+ lightpack.set_color(0, 255, 0, 0)
83
+ lightpack.set_color(1, 0, 255, 0)
84
+ lightpack.set_color(2, 0, 0, 255)
85
+ end
86
+
87
+ # Alternatively, you can use `#lock` in combination with `#unlock`.
88
+ lightpack.lock
89
+ lightpack.gamma = 2.5
90
+ lightpack.brightness = 93
91
+ lightpack.smooth = 128
92
+ lightpack.unlock
93
+
94
+ # If you want to, you can check whether a lock is active:
95
+ lightpack.locked?
96
+
97
+ # When you're done, you can just let the program exit or disconnect explicitly.
98
+ lightpack.disconnect
99
+ ```
100
+
101
+ ## Examples
102
+ Check out the [`examples/`](examples) folder for some basic examples.
103
+
104
+ ## License
105
+ Copyright (c) 2014 Douwe Maan
106
+
107
+ Permission is hereby granted, free of charge, to any person obtaining
108
+ a copy of this software and associated documentation files (the
109
+ "Software"), to deal in the Software without restriction, including
110
+ without limitation the rights to use, copy, modify, merge, publish,
111
+ distribute, sublicense, and/or sell copies of the Software, and to
112
+ permit persons to whom the Software is furnished to do so, subject to
113
+ the following conditions:
114
+
115
+ The above copyright notice and this permission notice shall be
116
+ included in all copies or substantial portions of the Software.
117
+
118
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
119
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
120
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
121
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
122
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
123
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
124
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+ require "rspec/core/rake_task"
2
+
3
+ spec = Gem::Specification.load("lightpack.gemspec")
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task default: :spec
8
+
9
+ desc "Build the .gem file"
10
+ task :build do
11
+ system "gem build #{spec.name}.gemspec"
12
+ end
13
+
14
+ desc "Push the .gem file to rubygems.org"
15
+ task release: :build do
16
+ system "gem push #{spec.name}-#{spec.version}.gem"
17
+ end
@@ -0,0 +1,245 @@
1
+ require "socket"
2
+
3
+ class Lightpack
4
+ module Errors
5
+ class NotConnected < StandardError; end
6
+ class AuthenticationFailed < StandardError; end
7
+
8
+ class AuthenticationRequired < StandardError; end
9
+ class UnknownCommand < StandardError; end
10
+ class NotLocked < StandardError; end
11
+ class Busy < StandardError; end
12
+ class Error < StandardError; end
13
+
14
+ MESSAGES = {
15
+ "authorization required" => AuthenticationRequired,
16
+ "unknown command" => UnknownCommand,
17
+ "not locked" => NotLocked,
18
+ "busy" => Busy,
19
+ "error" => Error
20
+ }.freeze
21
+ end
22
+
23
+ def self.open(*args)
24
+ pack = new(*args)
25
+
26
+ begin
27
+ pack.connect
28
+ yield pack
29
+ ensure
30
+ pack.disconnect
31
+ end
32
+ end
33
+
34
+ attr_reader :host, :port
35
+ attr_accessor :api_key
36
+
37
+ def initialize(host = "127.0.0.1", port = 3636, api_key = nil)
38
+ @host = host
39
+ @port = port
40
+ @api_key = api_key
41
+ end
42
+
43
+ def connected?
44
+ @connected
45
+ end
46
+
47
+ def connect
48
+ return false if connected?
49
+
50
+ @socket = TCPSocket.new(@host, @port)
51
+ @connected = true
52
+
53
+ @socket.gets # Read welcome message
54
+
55
+ unless authenticate
56
+ disconnect
57
+ raise Errors::AuthenticationFailed
58
+ end
59
+
60
+ true
61
+ rescue
62
+ false
63
+ end
64
+
65
+ def disconnect
66
+ return false unless connected?
67
+
68
+ unlock
69
+
70
+ @connected = false
71
+
72
+ @socket.close if @socket && !@socket.closed?
73
+ @socket = nil
74
+
75
+ true
76
+ end
77
+
78
+ def authenticate(api_key = @api_key)
79
+ return true unless api_key
80
+
81
+ command("apikey:#{api_key}") == true
82
+ end
83
+
84
+ def locked?
85
+ @locked
86
+ end
87
+
88
+ def lock
89
+ return true if locked?
90
+
91
+ result = command("lock")
92
+ @locked = result == :success
93
+ end
94
+
95
+ def unlock
96
+ return false unless locked?
97
+
98
+ result = command("unlock")
99
+ @locked = false
100
+
101
+ result == :success
102
+ end
103
+
104
+ def with_lock(&block)
105
+ already_locked = locked?
106
+
107
+ lock unless already_locked
108
+
109
+ yield self
110
+ ensure
111
+ unlock unless already_locked
112
+ end
113
+
114
+ # Getters
115
+ def status
116
+ command("getstatus").gsub(" ", "_").to_sym
117
+ end
118
+
119
+ def on?
120
+ status == :on
121
+ end
122
+
123
+ def api_status
124
+ command("getstatusapi").gsub(" ", "_").to_sym
125
+ end
126
+
127
+ def profiles
128
+ command("getprofiles").split(";")
129
+ end
130
+
131
+ def profile
132
+ command("getprofile")
133
+ end
134
+
135
+ def led_count
136
+ command("getcountleds").to_i
137
+ end
138
+
139
+ def led_areas
140
+ command("getleds").split(";").map do |info|
141
+ keys = [:x, :y, :width, :height]
142
+ dimensions = info.split("-", 2)[1].split(",").map(&:to_i)
143
+
144
+ Hash[keys.zip(dimensions)]
145
+ end
146
+ end
147
+
148
+ def colors
149
+ command("getcolors").split(";").map do |info|
150
+ info.split("-", 2)[1].split(",").map(&:to_i)
151
+ end
152
+ end
153
+
154
+ def fps
155
+ command("getfps").to_f
156
+ end
157
+
158
+ def screen_size
159
+ command("getscreensize").split(",").map(&:to_i)
160
+ end
161
+
162
+ def mode
163
+ command("getmode").to_sym
164
+ end
165
+
166
+ # Setters
167
+ def turn_on
168
+ with_lock do
169
+ command("setstatus:on")
170
+ end
171
+ end
172
+
173
+ def turn_off
174
+ with_lock do
175
+ command("setstatus:off")
176
+ end
177
+ end
178
+
179
+ [:mode, :gamma, :brightness, :smooth, :profile].each do |key|
180
+ define_method(:"#{key}=") do |value|
181
+ with_lock do
182
+ command("set#{key}:#{value}") && value
183
+ end
184
+ end
185
+ end
186
+
187
+ def set_color(n, r, g, b)
188
+ with_lock do
189
+ command("setcolor:#{n + 1}-#{[r, g, b].join(",")};")
190
+ end
191
+ end
192
+
193
+ def set_all_colors(r, g, b)
194
+ with_lock do
195
+ colors = [r, g, b].join(",")
196
+
197
+ cmd = "setcolor:"
198
+ led_count.times do |i|
199
+ cmd << "#{i}-#{colors};"
200
+ end
201
+ command cmd
202
+ end
203
+ end
204
+
205
+ def set_led_areas(n, dimensions)
206
+ with_lock do
207
+ dimensions = [:x, :y, :width, :height].map { |key| dimensions[key] }.join(",")
208
+ command("setleds:#{n + 1}-#{dimensions};")
209
+ end
210
+ end
211
+
212
+ def add_profile(name)
213
+ with_lock do
214
+ command("newprofile:#{name}")
215
+ end
216
+ end
217
+
218
+ def delete_profile(name)
219
+ with_lock do
220
+ command("deleteprofile:#{name}")
221
+ end
222
+ end
223
+
224
+ private
225
+ def command(action, type = nil)
226
+ raise Errors::NotConnected unless connected?
227
+
228
+ @socket.puts action
229
+ result = @socket.recv(8192).chomp
230
+
231
+ if error = Errors::MESSAGES[result]
232
+ raise error
233
+ end
234
+
235
+ if result == "ok"
236
+ true
237
+ elsif result =~ /:/
238
+ result.split(":", 2)[1]
239
+ else
240
+ result.gsub(" ", "_").to_sym
241
+ end
242
+ end
243
+ end
244
+
245
+ require "lightpack/version"
@@ -0,0 +1,3 @@
1
+ class Lightpack
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lightpack
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Douwe Maan
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-04-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &70272477253440 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70272477253440
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &70272477250700 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70272477250700
36
+ description: A Ruby library for communicating with your Lightpack.
37
+ email: douwe@selenight.nl
38
+ executables: []
39
+ extensions: []
40
+ extra_rdoc_files: []
41
+ files:
42
+ - lib/lightpack/version.rb
43
+ - lib/lightpack.rb
44
+ - LICENSE
45
+ - README.md
46
+ - Rakefile
47
+ - Gemfile
48
+ homepage: https://github.com/DouweM/lightpack
49
+ licenses:
50
+ - MIT
51
+ post_install_message:
52
+ rdoc_options: []
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ segments:
62
+ - 0
63
+ hash: 4336892820563749072
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ segments:
71
+ - 0
72
+ hash: 4336892820563749072
73
+ requirements: []
74
+ rubyforge_project:
75
+ rubygems_version: 1.8.6
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Lightpack communication library
79
+ test_files: []