tp_link 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.
- 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: []
|