tp_link 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/tp_link.rb +19 -0
- data/lib/tp_link/api.rb +109 -0
- data/lib/tp_link/config.rb +71 -0
- data/lib/tp_link/device.rb +101 -0
- data/lib/tp_link/errors.rb +19 -0
- data/lib/tp_link/light.rb +45 -0
- data/lib/tp_link/plug.rb +31 -0
- data/lib/tp_link/rgb_light.rb +39 -0
- data/lib/tp_link/smart_home.rb +85 -0
- metadata +93 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1ecbd0295f05df003c78bbcc8cf1299dc1a7af18
|
4
|
+
data.tar.gz: f34c62675f5fdd65b9607f06408d0c5a66f1c90a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9aa8132ae642b60c8bd28623acb3dbd3c5ab1e76d0c712fba47e5026b34cb838eaae53b49cbd58b916c18a9014cb113c2a53cccd8ded999630db4d17e8b08afd
|
7
|
+
data.tar.gz: 6b13493b9a882282f9fe0c9ec7015bd5204007813b1c3397289b0aa46f4a5805ab3d11d93fb710919ebe57ef3cb878bb9e097c9e8d06a098f6b9b066849e9643
|
data/lib/tp_link.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
require 'faraday'
|
5
|
+
require 'net/https'
|
6
|
+
require 'json'
|
7
|
+
require 'faraday_middleware'
|
8
|
+
require 'yaml'
|
9
|
+
require 'json'
|
10
|
+
require 'securerandom'
|
11
|
+
|
12
|
+
require 'tp_link/errors.rb'
|
13
|
+
require 'tp_link/config.rb'
|
14
|
+
require 'tp_link/device.rb'
|
15
|
+
require 'tp_link/light.rb'
|
16
|
+
require 'tp_link/rgb_light.rb'
|
17
|
+
require 'tp_link/plug.rb'
|
18
|
+
require 'tp_link/api.rb'
|
19
|
+
require 'tp_link/smart_home.rb'
|
data/lib/tp_link/api.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# TPLink Module
|
4
|
+
module TPLink
|
5
|
+
# Talk to TPLink's API. This class is use internally. You should not need to call it.
|
6
|
+
# @!visibility private
|
7
|
+
class API
|
8
|
+
# @!visibility private
|
9
|
+
DEFAULT_PARAMS = {
|
10
|
+
'appName' => 'Kasa_Android',
|
11
|
+
'termID' => proc { @config.terminal_uuid },
|
12
|
+
'appVer' => '1.4.4.607',
|
13
|
+
'ospf' => 'Android+6.0.1',
|
14
|
+
'netType' => 'wifi',
|
15
|
+
'locale' => 'es_ES'
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
# @!visibility private
|
19
|
+
DEFAULT_HEADERS = {
|
20
|
+
'Connection' => 'Keep-Alive',
|
21
|
+
'User-Agent' => 'Dalvik/2.1.0 (Linux; U; Android 6.0.1; ' \
|
22
|
+
'A0001 Build/M4B30X)',
|
23
|
+
'Content-Type' => 'applicatoin/json;charset=utf-8',
|
24
|
+
'Accept' => 'application/json, text/plain, */*'
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
# # @!visibility private
|
28
|
+
# TOKEN_API = Faraday.new('https://wap.tplinkcloud.com') do |c|
|
29
|
+
# c.request :json
|
30
|
+
# c.response :json, content_type: /\bjson$/i
|
31
|
+
# c.adapter Faraday.default_adapter
|
32
|
+
# c.params.merge!(DEFAULT_PARAMS)
|
33
|
+
# c.headers.merge!(DEFAULT_HEADERS)
|
34
|
+
# end
|
35
|
+
|
36
|
+
# @!visibility private
|
37
|
+
TPLINK_API = Faraday.new('https://wap.tplinkcloud.com') do |c|
|
38
|
+
c.request :json
|
39
|
+
c.response :json, content_type: /\bjson$/i
|
40
|
+
c.adapter Faraday.default_adapter
|
41
|
+
c.params.merge!(DEFAULT_PARAMS)
|
42
|
+
c.headers.merge!(DEFAULT_HEADERS)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @!visibility private
|
46
|
+
def initialize(opts = nil)
|
47
|
+
options = opts || "#{ENV['HOME']}/.tp_link"
|
48
|
+
@config = Config.new(options)
|
49
|
+
@token = nil
|
50
|
+
@device_list = []
|
51
|
+
end
|
52
|
+
|
53
|
+
def token(regen = false)
|
54
|
+
return @token if @token && regen == false
|
55
|
+
response = TPLINK_API.post do |req|
|
56
|
+
req.body = { method: 'login', url: 'https://wap.tplinkcloud.com',
|
57
|
+
params: @config.to_hash }.to_json
|
58
|
+
end
|
59
|
+
@token = parse_response(response)['token']
|
60
|
+
end
|
61
|
+
|
62
|
+
def device_list
|
63
|
+
@device_list if @device_list
|
64
|
+
response = TPLINK_API.post do |req|
|
65
|
+
req.params['token'] = token
|
66
|
+
req.body = { method: 'getDeviceList' }.to_json
|
67
|
+
end
|
68
|
+
@device_list = parse_response(response)['deviceList']
|
69
|
+
end
|
70
|
+
|
71
|
+
def send_data(device, data)
|
72
|
+
conn = data_connection(device)
|
73
|
+
res = conn.post do |req|
|
74
|
+
req.body = { method: 'passthrough',
|
75
|
+
params: { deviceId: device.id,
|
76
|
+
requestData: data.to_json } }.to_json
|
77
|
+
end
|
78
|
+
parse_response(res)
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def data_connection(device)
|
84
|
+
Faraday.new(device.url) do |c|
|
85
|
+
c.request :json
|
86
|
+
c.response :json, content_type: /\bjson$/i
|
87
|
+
c.adapter Faraday.default_adapter
|
88
|
+
c.params['token'] = token
|
89
|
+
c.headers.merge!(DEFAULT_HEADERS)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def parse_response(res)
|
94
|
+
raise TPLink::TPLinkCloudError, 'Generic TPLinkCloud Error' unless res.success?
|
95
|
+
response = JSON.parse(res.body)
|
96
|
+
raise TPLink::DeviceOffline if response['error_code'].to_i == -20_571
|
97
|
+
raise TPLink::TPLinkCloudError, 'TPLinkCloud API Error' \
|
98
|
+
unless response['error_code'].to_i.zero?
|
99
|
+
raise TPLink::TPLinkCloudError, 'No respone data' \
|
100
|
+
unless res.body['result']
|
101
|
+
if response['result'].key?('responseData') && \
|
102
|
+
response['result']['responseData'].class == String
|
103
|
+
response['result']['responseData'] = \
|
104
|
+
JSON.parse(response['result']['responseData'])
|
105
|
+
end
|
106
|
+
response['result']
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TPLink
|
4
|
+
# This class handles the configuration.
|
5
|
+
# It is used internally and should not need to be called.
|
6
|
+
# @!visibility private
|
7
|
+
class Config
|
8
|
+
def initialize(config = "#{ENV['HOME']}/.tp_link")
|
9
|
+
@config_file = nil
|
10
|
+
@config = get_config(config)
|
11
|
+
raise 'User name not spcified in configuration.' \
|
12
|
+
unless @config.key?('user')
|
13
|
+
raise 'Password not specified in configuration.' \
|
14
|
+
unless @config.key?('password')
|
15
|
+
generate_uuid unless @config.key? 'uuid'
|
16
|
+
end
|
17
|
+
|
18
|
+
def generate_uuid
|
19
|
+
if @config_file && @config['uuid'].nil?
|
20
|
+
@config['uuid'] ||= SecureRandom.uuid
|
21
|
+
File.open(@config_file, 'w') do |f|
|
22
|
+
f.write @config.to_yaml
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@config['uuid']
|
26
|
+
end
|
27
|
+
|
28
|
+
def app_type
|
29
|
+
'Kasa_Android'
|
30
|
+
end
|
31
|
+
|
32
|
+
def terminal_uuid
|
33
|
+
@config['uuid']
|
34
|
+
end
|
35
|
+
|
36
|
+
def cloud_user_name
|
37
|
+
@config['user']
|
38
|
+
end
|
39
|
+
|
40
|
+
def cloud_password
|
41
|
+
@config['password']
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_hash
|
45
|
+
{
|
46
|
+
appType: app_type,
|
47
|
+
cloudUserName: cloud_user_name,
|
48
|
+
cloudPassword: cloud_password,
|
49
|
+
terminalUUID: terminal_uuid
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_json(_o)
|
54
|
+
to_hash.to_json
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def get_config(config)
|
60
|
+
if config.is_a? String
|
61
|
+
raise "Config file missing: #{config}" \
|
62
|
+
unless File.exist?(config)
|
63
|
+
@config_file = config
|
64
|
+
return YAML.load_file(config) || {}
|
65
|
+
elsif !config.is_a?(Hash)
|
66
|
+
raise "Invalid config type #{config.class}"
|
67
|
+
end
|
68
|
+
config
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TPLink
|
4
|
+
# Generic class for all TPLink devices0
|
5
|
+
class Device
|
6
|
+
# Returns satus of device.
|
7
|
+
# @return [Boolean<1>] if device is on.
|
8
|
+
# @return [Boolean<0>] if device is off.
|
9
|
+
attr_reader :status
|
10
|
+
|
11
|
+
# Returns alais of device.
|
12
|
+
# @return [String] Device alias (name in kasa app).
|
13
|
+
attr_reader :alias
|
14
|
+
|
15
|
+
# Returns name of device.
|
16
|
+
# @return [String] Name of device (e.g. TP Link Smart Plug).
|
17
|
+
attr_reader :name
|
18
|
+
|
19
|
+
# @!visibility private
|
20
|
+
attr_reader :type, :url, :model, :mac, :role
|
21
|
+
# @!visibility private
|
22
|
+
attr_reader :same_region, :hw_id, :fw_id, :id, :hw_version, :fw_version
|
23
|
+
|
24
|
+
# @!visibility private
|
25
|
+
# This should only be called internally
|
26
|
+
def initialize(parent, dev)
|
27
|
+
@parent = parent
|
28
|
+
@alias = dev['alias']
|
29
|
+
@name = dev['deviceName']
|
30
|
+
@status = dev['status']
|
31
|
+
@type = dev['deviceType']
|
32
|
+
@url = dev['appServerUrl']
|
33
|
+
@model = dev['deviceModel']
|
34
|
+
@mac = dev['deviceMac']
|
35
|
+
@role = dev['role']
|
36
|
+
@same_region = dev['isSameRegion']
|
37
|
+
@hw_id = dev['hwId']
|
38
|
+
@fw_id = dev['fwId']
|
39
|
+
@id = dev['deviceId']
|
40
|
+
@hw_version = dev['deviceHwVersion']
|
41
|
+
@fw_version = dev['fwVer']
|
42
|
+
end
|
43
|
+
|
44
|
+
# Get Wifi signal strength in dB
|
45
|
+
# @returns [Integer]
|
46
|
+
def rssi
|
47
|
+
reload
|
48
|
+
@rssi
|
49
|
+
end
|
50
|
+
|
51
|
+
# Reload data / device state
|
52
|
+
def reload
|
53
|
+
res = @parent.send_data(self,
|
54
|
+
"system":
|
55
|
+
{ "get_sysinfo": nil },
|
56
|
+
"emeter": { "get_realtime": nil })
|
57
|
+
@rssi = res['responseData']['system']['get_sysinfo']['rssi']
|
58
|
+
case self.class.to_s
|
59
|
+
when 'TPLink::Light'
|
60
|
+
reload_light(res)
|
61
|
+
when 'TPLink::Plug'
|
62
|
+
reload_plug(res)
|
63
|
+
end
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
# Turn device on
|
68
|
+
def on; end
|
69
|
+
|
70
|
+
# Turn device off
|
71
|
+
def off; end
|
72
|
+
|
73
|
+
# @return [True] if device is on.
|
74
|
+
# @return [False] if device is off.
|
75
|
+
def on?
|
76
|
+
reload
|
77
|
+
@status == 1
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [True] if device is off.
|
81
|
+
# @return [False] if device is on.
|
82
|
+
def off?
|
83
|
+
!on?
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def reload_plug(res)
|
89
|
+
@status = res['responseData']['system']['get_sysinfo']['relay_state']
|
90
|
+
end
|
91
|
+
|
92
|
+
def reload_light(res)
|
93
|
+
@status = res['responseData']['system']['get_sysinfo']['light_state']['on_off']
|
94
|
+
end
|
95
|
+
|
96
|
+
def reload_rgb(res)
|
97
|
+
# TODO: Add variables for Hue, and Saturation
|
98
|
+
@status = res['responseData']['system']['get_sysinfo']['light_state']['on_off']
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Provides errors raised by the gem.
|
4
|
+
|
5
|
+
module TPLink
|
6
|
+
# Handle Errrors related to TPLink's Cloud
|
7
|
+
class DeviceOffline < StandardError
|
8
|
+
def initialize
|
9
|
+
super('Device Offline')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
class TPLinkCloudError < StandardError
|
13
|
+
attr_reader :action
|
14
|
+
def initialize(message, action = nil)
|
15
|
+
super(message)
|
16
|
+
@action = action
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TPLink
|
4
|
+
# Control TPLink Dimmable lights
|
5
|
+
# @example
|
6
|
+
# light.on # turn on light
|
7
|
+
# light.off # turn off light
|
8
|
+
#
|
9
|
+
# # turn on light and set brightness to 50%
|
10
|
+
# light.on
|
11
|
+
# light.on(50)
|
12
|
+
class Light < TPLink::Device
|
13
|
+
# Turn light on
|
14
|
+
# @param b [Integer<1-100>] Set light intensity between 1 and 100
|
15
|
+
def on(b = 100)
|
16
|
+
transition_light_state(1, b)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Turn light off
|
20
|
+
def off
|
21
|
+
transition_light_state(0, 100)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Toggle device (turn off if on, on if off)
|
25
|
+
def toggle
|
26
|
+
if on?
|
27
|
+
off
|
28
|
+
else
|
29
|
+
on
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def transition_light_state(o, b)
|
36
|
+
@parent.send_data(self,
|
37
|
+
"smartlife.iot.smartbulb.lightingservice": {
|
38
|
+
"transition_light_state": {
|
39
|
+
"on_off": o,
|
40
|
+
"brightness": b
|
41
|
+
}
|
42
|
+
})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/tp_link/plug.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TPLink
|
4
|
+
# Control TPLink Smart Plugs
|
5
|
+
class Plug < TPLink::Device
|
6
|
+
# Turn device on
|
7
|
+
def on
|
8
|
+
relay_state(1)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Turn device off
|
12
|
+
def off
|
13
|
+
relay_state(0)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Toggle device (turn off if on, on if off)
|
17
|
+
def toggle
|
18
|
+
if on?
|
19
|
+
off
|
20
|
+
else
|
21
|
+
on
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def relay_state(s)
|
28
|
+
@parent.send_data(self, "system": { "set_relay_state": { "state": s } })
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TPLink
|
4
|
+
# Control TP-Link LS130 / RGB lights
|
5
|
+
class RGBLight < TPLink::Device
|
6
|
+
# Turn Light on
|
7
|
+
def on(b = 100, h = 100, s = 100)
|
8
|
+
transition_light_state(1, b, h, s)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Turn light off
|
12
|
+
def off
|
13
|
+
transition_light_state(0, 100, 100, 100)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Toggle device (turn off if on, on if off)
|
17
|
+
def toggle
|
18
|
+
if on?
|
19
|
+
off
|
20
|
+
else
|
21
|
+
on
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def transition_light_state(o, b, h, s)
|
28
|
+
@parent.send_data(self,
|
29
|
+
"smartlife.iot.smartbulb.lightingservice": {
|
30
|
+
"transition_light_state": {
|
31
|
+
"on_off": o,
|
32
|
+
"brightness": b,
|
33
|
+
"hue": h,
|
34
|
+
"saturation": s
|
35
|
+
}
|
36
|
+
})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TPLink
|
4
|
+
# Main class for TPLink. This is likely the only class you will initialize.
|
5
|
+
# @example
|
6
|
+
# sh = TPLink::SmartHome.new
|
7
|
+
#
|
8
|
+
# # Get array of TPLink Devices (currently only dimmable lights work).
|
9
|
+
# sh.devices
|
10
|
+
#
|
11
|
+
# # Find a device by name:
|
12
|
+
# light = sh.find("kitchen")
|
13
|
+
#
|
14
|
+
# # Turn light on
|
15
|
+
# light.on
|
16
|
+
#
|
17
|
+
# # Turn light off
|
18
|
+
# light.off
|
19
|
+
#
|
20
|
+
# # Dim light to 50%
|
21
|
+
# light.on(50)
|
22
|
+
class SmartHome
|
23
|
+
# @!visibility private
|
24
|
+
attr_reader :api
|
25
|
+
# @param [Hash,String] config options for TPLink
|
26
|
+
# @option config [String] :user Your Kasa user name
|
27
|
+
# @option config [String] :password Your Kasa password
|
28
|
+
# @option config [String] :uuid Your "device" (program) uuid.
|
29
|
+
# @example
|
30
|
+
# smarthome = TPLink::SmartHome.new(user: kasa@example.com, password: password: 1234)
|
31
|
+
# kitchen_light = smarthome.find("kitchen")
|
32
|
+
# kitchen_light.on
|
33
|
+
# kitchen_light.off
|
34
|
+
def initialize(config = {})
|
35
|
+
@api = TPLink::API.new(config)
|
36
|
+
reload
|
37
|
+
end
|
38
|
+
|
39
|
+
# Find a device by it's alias. Search is case insensitive.
|
40
|
+
# @param [String] a device alias.
|
41
|
+
# @return [TPLink::Light] If device is a dimmable light.
|
42
|
+
# @return [TPLink::RGBLight] if device is an RGB light.
|
43
|
+
# @return [TPLink::Plug] if device is a smart plug.
|
44
|
+
# @return [nil] if no device is found.
|
45
|
+
# @example Find your kitchen light
|
46
|
+
# smarthome.find("kitchen")
|
47
|
+
def find(a)
|
48
|
+
devices.find { |d| d.alias.match(/^#{a}$/i) }
|
49
|
+
end
|
50
|
+
|
51
|
+
# Find a device by it's alias.
|
52
|
+
# @return [Array<TPLink::Light,TPLink::RGBLight,TPLlink::Plug>] an array of devices.
|
53
|
+
# @example Turn everything off
|
54
|
+
# smarthome.devices.each { |device| device.off }
|
55
|
+
def devices
|
56
|
+
@devices ||= @raw_devices.map { |d| dev_to_class(d) }.compact
|
57
|
+
end
|
58
|
+
|
59
|
+
def send_data(device, data)
|
60
|
+
@api.send_data(device, data)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Reload devices from TPLink api.
|
64
|
+
def reload
|
65
|
+
@raw_devices = @api.device_list
|
66
|
+
@devices = nil
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
# TODO: Test LB130, LB120, LB110, and BR30 devices.
|
72
|
+
def dev_to_class(device)
|
73
|
+
case device['deviceType']
|
74
|
+
when 'IOT.SMARTBULB'
|
75
|
+
return TPLink::Light.new(self, device) \
|
76
|
+
if device['deviceModel'].match(/^(LB100|LB110|BR30)/)
|
77
|
+
return TPLink::RGBLight.new(self, device) \
|
78
|
+
if device['deviceModel'].match(/^(LB130|LB120)/)
|
79
|
+
when 'IOT.SMARTPLUGSWITCH'
|
80
|
+
return TPLink::Plug.new(self, device)
|
81
|
+
end
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tp_link
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Paterni
|
8
|
+
- Ian MOrgan
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2018-03-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: faraday
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0.13'
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.13.1
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - "~>"
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0.13'
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.13.1
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: faraday_middleware
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.12'
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.12.2
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - "~>"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0.12'
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.12.2
|
54
|
+
description: Control various TPLink smart home devices.
|
55
|
+
email: tp_link@ruby-code.com
|
56
|
+
executables: []
|
57
|
+
extensions: []
|
58
|
+
extra_rdoc_files: []
|
59
|
+
files:
|
60
|
+
- "./lib/tp_link.rb"
|
61
|
+
- "./lib/tp_link/api.rb"
|
62
|
+
- "./lib/tp_link/config.rb"
|
63
|
+
- "./lib/tp_link/device.rb"
|
64
|
+
- "./lib/tp_link/errors.rb"
|
65
|
+
- "./lib/tp_link/light.rb"
|
66
|
+
- "./lib/tp_link/plug.rb"
|
67
|
+
- "./lib/tp_link/rgb_light.rb"
|
68
|
+
- "./lib/tp_link/smart_home.rb"
|
69
|
+
homepage: https://ruby-code.com/james/tp_link
|
70
|
+
licenses:
|
71
|
+
- MIT
|
72
|
+
metadata: {}
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options: []
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
requirements: []
|
88
|
+
rubyforge_project:
|
89
|
+
rubygems_version: 2.6.14
|
90
|
+
signing_key:
|
91
|
+
specification_version: 4
|
92
|
+
summary: TPLink smarthome library
|
93
|
+
test_files: []
|