samsung 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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8765c385dabd7c0bf6e7c5550c869a5ac45221a9
4
+ data.tar.gz: f4dc04a698a7c8c6d1b766abe686e09cbbac44f8
5
+ SHA512:
6
+ metadata.gz: 4013b1151df8e1984a0aa2feb0d9dd6531200868d470ce8ae4629aacd7a67f3496c7b507c91e74a74e64b628196ffb558a8db76a889bfe9db04023ddb49565ae
7
+ data.tar.gz: fa33e3a1160fd73cd0e9fe6fbfcfb0121ff3de6f8097bcde62c7ae663df4762d12c293ac58424f1ee9aa7621bf75638ecbd895611acec77740e51a8589997664
@@ -0,0 +1,32 @@
1
+ = samsung
2
+
3
+ Remote control for Samsung SmartTVs.
4
+
5
+ == Quick start
6
+
7
+ Install the gem:
8
+
9
+ gem install samsung
10
+
11
+ Or add it to your Gemfile:
12
+
13
+ gem "samsung"
14
+
15
+ Use it:
16
+
17
+ require 'samsung'
18
+
19
+ remote = Samsung::Remote.new(IP)
20
+
21
+ # wait for TV to respond
22
+ remote.peek_frame
23
+
24
+ remote.send_key 'KEY_VOLUP'
25
+
26
+ == To Do
27
+
28
+ * Lots of things, this is POC-level code
29
+
30
+ == License
31
+
32
+ This gem is released under the {MIT License}[http://www.opensource.org/licenses/MIT].
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'samsung'
@@ -0,0 +1,6 @@
1
+ require_relative 'samsung/network'
2
+ require_relative 'samsung/protocol'
3
+ require_relative 'samsung/remote'
4
+
5
+ module Samsung
6
+ end
@@ -0,0 +1,11 @@
1
+ module Samsung
2
+ class Network
3
+ def local_ip
4
+ Socket.ip_address_list.find {|a| a.ipv4? and !a.ipv4_loopback? and a.ipv4_private? }.ip_address
5
+ end
6
+
7
+ def local_hw_address
8
+ `ifconfig -a | grep HWaddr | cut -c39- | head -n1`.strip
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'protocol/frame'
2
+ require_relative 'protocol/header_frame'
3
+ require_relative 'protocol/auth_frame'
4
+ require_relative 'protocol/key_frame'
5
+ require_relative 'protocol/response'
6
+
7
+ module Samsung
8
+ module Protocol
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ module Samsung
2
+ module Protocol
3
+ class AuthFrame < Frame
4
+ def initialize(local_ip, app_id, name)
5
+ super()
6
+ push_int8(0x64)
7
+ push_int8(0x00)
8
+ push_string64(local_ip)
9
+ push_string64(app_id)
10
+ push_string64(name)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,88 @@
1
+ require 'base64'
2
+
3
+ module Samsung
4
+ module Protocol
5
+ class Frame
6
+ attr_accessor :data
7
+
8
+ def initialize data = ''
9
+ @data = data
10
+ end
11
+
12
+ def size
13
+ @data.size
14
+ end
15
+
16
+ def hex
17
+ data.split('').map do |c|
18
+ "0x%.2x" % c.ord
19
+ end.join(' ')
20
+ end
21
+
22
+ # String
23
+
24
+ def push_string(s)
25
+ push_int16(s.size)
26
+ self.data += s
27
+ end
28
+
29
+ def pop_string
30
+ len = pop_int16
31
+ data.slice!(0..len-1)
32
+ end
33
+
34
+ # Base64 string
35
+
36
+ def push_string64(s)
37
+ push_string(Base64.encode64(s))
38
+ end
39
+
40
+ def pop_string64
41
+ len = pop_int16
42
+ Base64.decode64(data.slice!(0..len-1))
43
+ end
44
+
45
+ # 8-bit integer
46
+
47
+ def push_int8(v)
48
+ self.data += [v].pack('C')
49
+ end
50
+
51
+ def pop_int8
52
+ data.slice!(0).unpack('C').first
53
+ end
54
+
55
+ # 16-bit integer
56
+
57
+ def push_int16(v)
58
+ self.data += [v].pack('S<')
59
+ end
60
+
61
+ def pop_int16
62
+ data.slice!(0..1).unpack('S<').first
63
+ end
64
+
65
+ # 32-bit integer
66
+
67
+ def push_int32(v)
68
+ self.data += [v].pack('L<')
69
+ end
70
+
71
+ def pop_int32
72
+ data.slice!(0..1).unpack('L<').first
73
+ end
74
+
75
+ # Frames
76
+
77
+ def push_frame(frame)
78
+ push_int16(frame.size)
79
+ self.data += frame.data
80
+ end
81
+
82
+ def pop_frame
83
+ frame_size = pop_int16
84
+ Frame.new(data.slice!(0..frame_size-1))
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,11 @@
1
+ module Samsung
2
+ module Protocol
3
+ class HeaderFrame < Frame
4
+ def initialize(app_name)
5
+ super()
6
+ push_int8(0)
7
+ push_string(app_name)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ module Samsung
2
+ module Protocol
3
+ class KeyFrame < Frame
4
+ def initialize(key)
5
+ super()
6
+ push_int8(0)
7
+ push_int8(0)
8
+ push_int8(0)
9
+ push_string64(key)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ module Samsung
2
+ module Protocol
3
+ class Response < Frame
4
+ attr_accessor :code, :app_name, :response_frame
5
+
6
+ def initialize data
7
+ @data = data
8
+ parse_response
9
+ end
10
+
11
+ def response_type
12
+ return :wait if r[0].ord == 0x0a
13
+ return :timeout if r[0].ord == 0x65
14
+ return :accepted if r[0].ord == 0x64 and r[2].ord == 0x01
15
+ return :rejected if r[0].ord == 0x64 and r[2].ord == 0x02
16
+ return :unknown
17
+ end
18
+
19
+ private
20
+
21
+ def parse_response
22
+ self.code = pop_int8
23
+ self.app_name = pop_string
24
+ self.response_frame = pop_frame
25
+ end
26
+
27
+ def r
28
+ response_frame.data
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,63 @@
1
+ require 'socket'
2
+
3
+ module Samsung
4
+ class Remote
5
+ PORT = 55000
6
+ APP_NAME = "net.kapati.samsung.remote"
7
+
8
+ attr_accessor :display_name, :ip
9
+
10
+ def initialize(ip, display_name = "Ruby")
11
+ self.ip = ip
12
+ self.display_name = display_name
13
+ connect
14
+ send_auth
15
+ end
16
+
17
+ def has_data?(wait = 0)
18
+ ready = IO.select([@socket], nil, nil, wait)
19
+ return ready != nil
20
+ end
21
+
22
+ def peek_frame(wait = 1)
23
+ return nil unless has_data?(wait)
24
+ read_frame
25
+ end
26
+
27
+ def read_frame
28
+ data = @socket.readpartial(512)
29
+ Protocol::Response.new(data)
30
+ end
31
+
32
+ def connect
33
+ @socket = TCPSocket.open ip, PORT
34
+ end
35
+
36
+ def send_frame(frame)
37
+ f = build_header
38
+ f.push_frame(frame)
39
+ @socket.write(f.data)
40
+ end
41
+
42
+ def send_key key_code
43
+ send_frame(Protocol::KeyFrame.new(key_code))
44
+ end
45
+
46
+ def send_auth
47
+ net = Network.new
48
+ send_frame(
49
+ Protocol::AuthFrame.new(
50
+ net.local_ip,
51
+ net.local_hw_address,
52
+ display_name
53
+ )
54
+ )
55
+ end
56
+
57
+ private
58
+
59
+ def build_header
60
+ Protocol::HeaderFrame.new(APP_NAME)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,26 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "samsung"
3
+ s.version = "1.0"
4
+ s.date = "2014-10-04"
5
+ s.summary = "Remote control for Samsung SmartTV."
6
+ s.description = "Control your Samsung StartTV with Ruby code"
7
+ s.authors = ["Robert Nasiadek"]
8
+ s.files = [
9
+ "init.rb",
10
+ "lib/samsung.rb",
11
+ "lib/samsung/remote.rb",
12
+ "lib/samsung/protocol.rb",
13
+ "lib/samsung/network.rb",
14
+ "lib/samsung/protocol/frame.rb",
15
+ "lib/samsung/protocol/key_frame.rb",
16
+ "lib/samsung/protocol/auth_frame.rb",
17
+ "lib/samsung/protocol/header_frame.rb",
18
+ "lib/samsung/protocol/response.rb",
19
+ "README.rdoc",
20
+ "samsung.gemspec"
21
+ ]
22
+ s.email = "robert@kapati.net"
23
+ s.homepage = "http://robzon.pl/"
24
+ s.license = "MIT"
25
+
26
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: samsung
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ platform: ruby
6
+ authors:
7
+ - Robert Nasiadek
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-04 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Control your Samsung StartTV with Ruby code
14
+ email: robert@kapati.net
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - README.rdoc
20
+ - init.rb
21
+ - lib/samsung.rb
22
+ - lib/samsung/network.rb
23
+ - lib/samsung/protocol.rb
24
+ - lib/samsung/protocol/auth_frame.rb
25
+ - lib/samsung/protocol/frame.rb
26
+ - lib/samsung/protocol/header_frame.rb
27
+ - lib/samsung/protocol/key_frame.rb
28
+ - lib/samsung/protocol/response.rb
29
+ - lib/samsung/remote.rb
30
+ - samsung.gemspec
31
+ homepage: http://robzon.pl/
32
+ licenses:
33
+ - MIT
34
+ metadata: {}
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ required_rubygems_version: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ requirements: []
50
+ rubyforge_project:
51
+ rubygems_version: 2.2.1
52
+ signing_key:
53
+ specification_version: 4
54
+ summary: Remote control for Samsung SmartTV.
55
+ test_files: []