lightpack 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []