Class: Kasa::Protocol

Inherits:
Object
  • Object
show all
Defined in:
lib/kasa/protocol.rb

Overview

TP link protocol

Constant Summary collapse

START_KEY =
171
TIMEOUT =
2
KASA_PORT =
9999

Class Method Summary collapse

Class Method Details

.decode(line) ⇒ Object

Decrypt and decode



82
83
84
85
86
87
88
89
90
# File 'lib/kasa/protocol.rb', line 82

def self.decode(line)
  key = START_KEY

  line.unpack('C*').map do |enc_byte|
    byte = key ^ enc_byte
    key = enc_byte
    byte
  end.pack('C*')
end

.encode(plain) ⇒ Object

Encrypt and encode



71
72
73
74
75
76
77
78
79
# File 'lib/kasa/protocol.rb', line 71

def self.encode(plain)
  key = START_KEY

  enc_bytes = plain.unpack('C*').map do |byte|
    key = key ^ byte
    key
  end
  ([enc_bytes.length] + enc_bytes).pack('I>C*')
end

.get(ip, location:, value: nil, extra: {}) ⇒ Object

get result from request



14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/kasa/protocol.rb', line 14

def self.get(ip, location:, value: nil, extra: {})
  request = request_to_hash location, value
  request.merge! extra

  encoded_response = Timeout.timeout(TIMEOUT) do
    transport(ip, encode(request.to_json))
  end

  response = JSON.parse decode(encoded_response)
  response = strip_location(location, response)
  validate response

  response
end

.request_to_hash(location, value) ⇒ Object

convert location and value to a hash



45
46
47
48
49
50
51
52
53
# File 'lib/kasa/protocol.rb', line 45

def self.request_to_hash(location, value)
  request = value
  location = location.split('/').reject(&:empty?).reverse
  location.each do |e|
    request = { e => request }
  end

  request
end

.strip_location(location, response) ⇒ Object

strip away the request location from the response



35
36
37
38
39
40
41
42
# File 'lib/kasa/protocol.rb', line 35

def self.strip_location(location, response)
  location = location.split('/').reject(&:empty?)
  location.each do |j|
    response = (response[j] or response)
  end

  response
end

.transport(ip, request) ⇒ Object

Open socket and send request and response



56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/kasa/protocol.rb', line 56

def self.transport(ip, request)
  Socket.tcp(ip, KASA_PORT) do |s|
    s.write request

    result_length = s.recv(4).unpack1('I>')
    result = ''
    while result_length.positive?
      result += s.recv(1024)
      result_length -= 1024
    end
    result
  end
end

.validate(response) ⇒ Object

examine error code



30
31
32
# File 'lib/kasa/protocol.rb', line 30

def self.validate(response)
  raise response.to_json if response.is_a?(Hash) && response['err_code']&.negative?
end