growatt 0.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.
- checksums.yaml +7 -0
- data/.env.template +4 -0
- data/.gitignore +47 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +6 -0
- data/README.md +83 -0
- data/Rakefile +19 -0
- data/growatt.gemspec +36 -0
- data/lib/growatt/api.rb +35 -0
- data/lib/growatt/authorization.rb +36 -0
- data/lib/growatt/client.rb +138 -0
- data/lib/growatt/connection.rb +28 -0
- data/lib/growatt/const.rb +19 -0
- data/lib/growatt/error.rb +12 -0
- data/lib/growatt/pagination.rb +26 -0
- data/lib/growatt/version.rb +5 -0
- data/lib/growatt.rb +27 -0
- data/test/auth_test.rb +20 -0
- data/test/client_test.rb +44 -0
- data/test/test_helper.rb +23 -0
- metadata +136 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d8f7a2c9e157fa1d945fdb7f29b9196ebe9104ebb84bcd348382e6b63c462aef
|
4
|
+
data.tar.gz: c748548639e53602a547b20ae2ba87edd70b8e9ce56b8a14db92f077c43b1643
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b732fd4efb07fd62e4e9a3a080b32da09bc45aff31804ee9b39f7dc74194e24eea975c58bcbc49e9ed7619533126cca6ecfe21a51cf4297caaaedf97d71e8dfa
|
7
|
+
data.tar.gz: 625b1e596b341b080e41d90d70aed14c42e1178171f8544f89a7f7fdacb4dfd10f8e18664c47507f1c98aa1cf720fae31eb7728f049a707c9ba06468a582f87a
|
data/.env.template
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
/data/
|
13
|
+
*.log
|
14
|
+
*.txt
|
15
|
+
*.json
|
16
|
+
*.yml
|
17
|
+
.DS_Store
|
18
|
+
__pycache__
|
19
|
+
*.py
|
20
|
+
|
21
|
+
# Used by dotenv library to load environment variables.
|
22
|
+
.env
|
23
|
+
|
24
|
+
|
25
|
+
## Documentation cache and generated files:
|
26
|
+
/.yardoc/
|
27
|
+
/_yardoc/
|
28
|
+
/doc/
|
29
|
+
/rdoc/
|
30
|
+
|
31
|
+
## Environment normalization:
|
32
|
+
/.bundle/
|
33
|
+
/vendor/bundle
|
34
|
+
/lib/bundler/man/
|
35
|
+
|
36
|
+
# for a library or gem, you might want to ignore these files since the code is
|
37
|
+
# intended to run in multiple environments; otherwise, check them in:
|
38
|
+
# Gemfile.lock
|
39
|
+
# .ruby-version
|
40
|
+
# .ruby-gemset
|
41
|
+
|
42
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
43
|
+
.rvmrc
|
44
|
+
|
45
|
+
# Used by RuboCop. Remote config files pulled in from inherit_from directive.
|
46
|
+
# .rubocop-https?--*
|
47
|
+
Gemfile.lock
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# Growatt API
|
2
|
+
[](https://rubygems.org/gems/growatt)
|
3
|
+
|
4
|
+
This is a wrapper for the Growatt rest API. Main objective is to turn inverter on/off. This has been testen with MOD-9000TL-X.
|
5
|
+
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'growatt'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install growatt
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
Before you start making the requests to API provide the endpoint and api key using the configuration wrapping.
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
require 'growatt'
|
29
|
+
require 'logger'
|
30
|
+
|
31
|
+
# use do block
|
32
|
+
Growatt.configure do |config|
|
33
|
+
config.username = ENV['GROWATT_USERNAME']
|
34
|
+
config.password = ENV['GROWATT_PASSWORD']
|
35
|
+
config.logger = Logger.new(TEST_LOGGER)
|
36
|
+
end
|
37
|
+
|
38
|
+
# or configure with options hash
|
39
|
+
client = Growatt.client
|
40
|
+
client.login
|
41
|
+
|
42
|
+
```
|
43
|
+
|
44
|
+
## Resources
|
45
|
+
### Authentication
|
46
|
+
```ruby
|
47
|
+
# setup
|
48
|
+
#
|
49
|
+
begin
|
50
|
+
client = Growatt.client
|
51
|
+
client.login
|
52
|
+
# turn invertor off
|
53
|
+
client.turn_inverter('<serial_no>', false)
|
54
|
+
rescue Growatt::AuthenticationError => e
|
55
|
+
puts "Error logging in growatt api"
|
56
|
+
puts e
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
## Publishing
|
63
|
+
|
64
|
+
1. Update version in [version.rb](lib/growatt/version.rb).
|
65
|
+
2. Add release to [CHANGELOG.md](CHANGELOG.md)
|
66
|
+
3. Commit.
|
67
|
+
4. Test build.
|
68
|
+
```
|
69
|
+
> rake build
|
70
|
+
|
71
|
+
```
|
72
|
+
5. Release
|
73
|
+
```
|
74
|
+
> rake release
|
75
|
+
|
76
|
+
## Contributing
|
77
|
+
|
78
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/jancotanis/growatt.
|
79
|
+
|
80
|
+
## License
|
81
|
+
|
82
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
83
|
+
"# growatt"
|
data/Rakefile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
require 'dotenv'
|
5
|
+
require 'rake/testtask'
|
6
|
+
|
7
|
+
Dotenv.load
|
8
|
+
|
9
|
+
#system './bin/cc-test-reporter before-build'
|
10
|
+
Rake::TestTask.new(:test) do |t|
|
11
|
+
t.libs << 'test'
|
12
|
+
t.libs << 'lib'
|
13
|
+
t.test_files = FileList['test/**/*_test.rb']
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'rubocop/rake_task'
|
17
|
+
RuboCop::RakeTask.new
|
18
|
+
task default: %i[test rubocop]
|
19
|
+
#system './bin/cc-test-reporter after-build'
|
data/growatt.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/growatt/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'growatt'
|
7
|
+
s.version = Growatt::VERSION
|
8
|
+
s.authors = ['Janco Tanis']
|
9
|
+
s.email = 'gems@jancology.com'
|
10
|
+
s.license = 'MIT'
|
11
|
+
|
12
|
+
s.summary = 'A Ruby wrapper for the Growatt APIs (readonly)'
|
13
|
+
s.homepage = 'https://rubygems.org/gems/growatt'
|
14
|
+
|
15
|
+
s.required_ruby_version = Gem::Requirement.new('>= 2.4.0')
|
16
|
+
|
17
|
+
s.metadata['homepage_uri'] = s.homepage
|
18
|
+
s.metadata['source_code_uri'] = 'https://github.com/jancotanis/growatt'
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
s.files = Dir.chdir(File.expand_path(__dir__)) do
|
23
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
24
|
+
end
|
25
|
+
s.bindir = 'exe'
|
26
|
+
s.executables = s.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
27
|
+
s.require_paths = ['lib']
|
28
|
+
|
29
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
30
|
+
s.platform = Gem::Platform::RUBY
|
31
|
+
s.add_runtime_dependency 'wrapi', ">= 0.3.0"
|
32
|
+
s.add_development_dependency 'dotenv'
|
33
|
+
s.add_development_dependency 'minitest'
|
34
|
+
s.add_development_dependency 'simplecov'
|
35
|
+
s.add_development_dependency 'rubocop'
|
36
|
+
end
|
data/lib/growatt/api.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require "wrapi"
|
2
|
+
require File.expand_path('authorization', __dir__)
|
3
|
+
require File.expand_path('connection', __dir__)
|
4
|
+
|
5
|
+
module Growatt
|
6
|
+
# @private
|
7
|
+
class API
|
8
|
+
|
9
|
+
# @private
|
10
|
+
attr_accessor *WrAPI::Configuration::VALID_OPTIONS_KEYS
|
11
|
+
|
12
|
+
# Creates a new API and copies settings from singleton
|
13
|
+
def initialize(options = {})
|
14
|
+
options = Growatt.options.merge(options)
|
15
|
+
WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
|
16
|
+
send("#{key}=", options[key])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def config
|
21
|
+
conf = {}
|
22
|
+
WrAPI::Configuration::VALID_OPTIONS_KEYS.each do |key|
|
23
|
+
conf[key] = send key
|
24
|
+
end
|
25
|
+
conf
|
26
|
+
end
|
27
|
+
|
28
|
+
include WrAPI::Connection
|
29
|
+
include Connection
|
30
|
+
include WrAPI::Request
|
31
|
+
include WrAPI::Authentication
|
32
|
+
include Authentication
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require File.expand_path('error', __dir__)
|
3
|
+
|
4
|
+
module Growatt
|
5
|
+
# Deals with authentication flow and stores it within global configuration
|
6
|
+
module Authentication
|
7
|
+
|
8
|
+
# Authorize to the Growatt portal
|
9
|
+
def login()
|
10
|
+
raise ConfigurationError, "Username/password not set" unless username || password
|
11
|
+
_password = hash_password(self.password) #unless is_password_hashed
|
12
|
+
|
13
|
+
_format = self.format
|
14
|
+
self.format = 'x-www-form-urlencoded'
|
15
|
+
response = post('newTwoLoginAPI.do', {'userName': self.username, 'password': _password})
|
16
|
+
self.format = _format
|
17
|
+
data = response.body['back']
|
18
|
+
if data && data['success']
|
19
|
+
@login_data = data
|
20
|
+
data
|
21
|
+
else
|
22
|
+
raise AuthenticationError.new(data['error'])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
private
|
26
|
+
def hash_password(password)
|
27
|
+
password_md5 = Digest::MD5.hexdigest(password.encode('utf-8'))
|
28
|
+
(0...password_md5.length).step(2) do |i|
|
29
|
+
if password_md5[i] == '0'
|
30
|
+
password_md5[i] = 'c'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
password_md5
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require File.expand_path('api', __dir__)
|
2
|
+
require File.expand_path('const', __dir__)
|
3
|
+
require File.expand_path('error', __dir__)
|
4
|
+
|
5
|
+
module Growatt
|
6
|
+
# Wrapper for the Growatt REST API
|
7
|
+
#
|
8
|
+
# @see no API documentation, reverse engineered
|
9
|
+
class Client < API
|
10
|
+
|
11
|
+
def initialize(options = {})
|
12
|
+
super(options)
|
13
|
+
end
|
14
|
+
|
15
|
+
# access data returned from login
|
16
|
+
def login_info
|
17
|
+
@login_data
|
18
|
+
end
|
19
|
+
def plant_list(user_id=nil)
|
20
|
+
user_id = login_info['user']['id'] unless user_id
|
21
|
+
_plant_list({'userId':user_id})
|
22
|
+
end
|
23
|
+
def plant_detail(plant_id,type=Timespan::DAY,date=Time.now)
|
24
|
+
_plant_detail( {
|
25
|
+
'plantId': plant_id,
|
26
|
+
'type': type,
|
27
|
+
'date': timespan_date(type,date)
|
28
|
+
})
|
29
|
+
end
|
30
|
+
def plant_info(plant_id)
|
31
|
+
_plant_info({
|
32
|
+
'op': 'getAllDeviceList',
|
33
|
+
'plantId': plant_id,
|
34
|
+
'pageNum': 1,
|
35
|
+
'pageSize': 1
|
36
|
+
})
|
37
|
+
end
|
38
|
+
def device_list(plant_id)
|
39
|
+
plant_info(plant_id).deviceList
|
40
|
+
end
|
41
|
+
|
42
|
+
def inverter_list(plant_id)
|
43
|
+
devices = device_list(plant_id)
|
44
|
+
devices.select { |device| 'inverter'.eql? device.deviceType }
|
45
|
+
end
|
46
|
+
|
47
|
+
# get data for invertor control
|
48
|
+
def inverter_control_data(inverter_id)
|
49
|
+
r = _inverter_api({
|
50
|
+
'op': 'getMaxSetData',
|
51
|
+
'serialNum': inverter_id
|
52
|
+
})
|
53
|
+
puts ">>>> #{r.to_json}"
|
54
|
+
r.obj.maxSetBean
|
55
|
+
end
|
56
|
+
|
57
|
+
def update_inverter_setting(serial_number,command,setting_type,parameters)
|
58
|
+
command_parameters = {
|
59
|
+
'op': command,
|
60
|
+
'serialNum': serial_number,
|
61
|
+
'type': setting_type
|
62
|
+
}
|
63
|
+
# repeated values to hash { param1: value1 }
|
64
|
+
|
65
|
+
parameters = parameters.map.with_index { |value, index| ["param#{index + 1}", value] }.to_h if parameters.is_a? Array
|
66
|
+
self.format = 'x-www-form-urlencoded'
|
67
|
+
data = JSON.parse(post('newTcpsetAPI.do',command_parameters.merge(parameters)).body)
|
68
|
+
self.format = :json
|
69
|
+
data['success']
|
70
|
+
end
|
71
|
+
|
72
|
+
# turn invertor on of off
|
73
|
+
def turn_inverter(serial_number,on=true)
|
74
|
+
onoff = (on ? Inverter::ON : Inverter::OFF )
|
75
|
+
update_inverter_setting(serial_number,'maxSetApi',nil,{'paramId':'max_cmd_on_off','param1':onoff})
|
76
|
+
end
|
77
|
+
|
78
|
+
# check if invertor is turned on
|
79
|
+
def inverter_on?(serial_number)
|
80
|
+
status = inverter_control_data(serial_number)
|
81
|
+
Inverter::ON.eql? status.max_cmd_on_off
|
82
|
+
end
|
83
|
+
|
84
|
+
# utility function to get date accordign timespan month/day
|
85
|
+
def timespan_date(timespan=Timespan::DAY,date=Time.now)
|
86
|
+
if Timespan::MONTH.eql? timespan
|
87
|
+
date.strftime("%Y-%m")
|
88
|
+
else
|
89
|
+
date.strftime("%Y-%m-%d")
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# functions below are copied from python example code but not sure if these work with MOD9000 inverters
|
95
|
+
#
|
96
|
+
def inverter_data(inverter_id,type=Timespan::DAY,date=Time.now)
|
97
|
+
_inverter_api({
|
98
|
+
'op': 'getInverterData',
|
99
|
+
'inverterId': inverter_id,
|
100
|
+
'type': type,
|
101
|
+
'date': timespan_date(type,date)
|
102
|
+
})
|
103
|
+
end
|
104
|
+
def inverter_detail(inverter_id)
|
105
|
+
_inverter_api({
|
106
|
+
'op': 'getInverterDetailData',
|
107
|
+
'inverterId': inverter_id
|
108
|
+
})
|
109
|
+
end
|
110
|
+
def inverter_detail_two(inverter_id)
|
111
|
+
_inverter_api({
|
112
|
+
'op': 'getInverterDetailData_two',
|
113
|
+
'inverterId': inverter_id
|
114
|
+
})
|
115
|
+
end
|
116
|
+
def update_mix_inverter_setting(serial_number, setting_type, parameters)
|
117
|
+
update_inverter_setting(serial_number,'mixSetApiNew',setting_type,parameters)
|
118
|
+
end
|
119
|
+
def update_ac_inverter_setting(serial_number, setting_type, parameters)
|
120
|
+
update_inverter_setting(serial_number,'spaSetApi',setting_type,parameters)
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
private
|
125
|
+
def self.api_endpoint(method,path)
|
126
|
+
# all records
|
127
|
+
self.send(:define_method, method) do |params = {}|
|
128
|
+
# return data result
|
129
|
+
get(path,params)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
api_endpoint :_plant_list, 'PlantListAPI.do'
|
133
|
+
api_endpoint :_plant_detail, 'PlantDetailAPI.do'
|
134
|
+
api_endpoint :_inverter_api, 'newInverterAPI.do'
|
135
|
+
api_endpoint :_plant_info, 'newTwoPlantAPI.do'
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday/follow_redirects'
|
3
|
+
require 'faraday-cookie_jar'
|
4
|
+
|
5
|
+
module Growatt
|
6
|
+
# Create connection and use cookies for authentication tokens
|
7
|
+
module Connection
|
8
|
+
def connection
|
9
|
+
raise ConfigurationError, "Option for endpoint is not defined" unless endpoint
|
10
|
+
|
11
|
+
options = setup_options
|
12
|
+
@connection ||= Faraday::Connection.new(options) do |connection|
|
13
|
+
# connection.use Faraday::FollowRedirects::Middleware, limit: 10
|
14
|
+
connection.use :cookie_jar
|
15
|
+
|
16
|
+
connection.use Faraday::Response::RaiseError
|
17
|
+
connection.adapter Faraday.default_adapter
|
18
|
+
setup_authorization(connection)
|
19
|
+
setup_headers(connection)
|
20
|
+
connection.response :json, content_type: /\bjson$/
|
21
|
+
connection.use Faraday::Request::UrlEncoded
|
22
|
+
|
23
|
+
setup_logger_filtering(connection, logger) if logger
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Growatt
|
2
|
+
|
3
|
+
# Generic error to be able to rescue all Hudu errors
|
4
|
+
class GrowattError < StandardError; end
|
5
|
+
|
6
|
+
# Configuration returns error
|
7
|
+
class ConfigurationError < GrowattError; end
|
8
|
+
|
9
|
+
# Issue authenticting
|
10
|
+
class AuthenticationError < GrowattError; end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Growatt
|
5
|
+
|
6
|
+
# Defines HTTP request methods
|
7
|
+
module RequestPagination
|
8
|
+
|
9
|
+
class DataPager < WrAPI::RequestPagination::DefaultPager
|
10
|
+
|
11
|
+
def self.data(body)
|
12
|
+
# data is at 'back'
|
13
|
+
if body.is_a? Hash
|
14
|
+
if body['back']
|
15
|
+
body['back']
|
16
|
+
else
|
17
|
+
body
|
18
|
+
end
|
19
|
+
else
|
20
|
+
# in some cases wrong contenttype is returned instead of app/json
|
21
|
+
JSON.parse(body)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/growatt.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "wrapi"
|
2
|
+
require File.expand_path('growatt/client', __dir__)
|
3
|
+
require File.expand_path('growatt/version', __dir__)
|
4
|
+
require File.expand_path('growatt/pagination', __dir__)
|
5
|
+
|
6
|
+
module Growatt
|
7
|
+
extend WrAPI::Configuration
|
8
|
+
extend WrAPI::RespondTo
|
9
|
+
|
10
|
+
DEFAULT_UA = "Ruby Growatt API client #{Growatt::VERSION}".freeze
|
11
|
+
# https://openapi.growatt.com/ is an option but does not work with my account
|
12
|
+
DEFAULT_ENDPOINT = 'https://server.growatt.com/'.freeze
|
13
|
+
DEFAULT_PAGINATION = RequestPagination::DataPager
|
14
|
+
#
|
15
|
+
# @return [Growatt::Client]
|
16
|
+
def self.client(options = {})
|
17
|
+
Growatt::Client.new({ user_agent: DEFAULT_UA, endpoint: DEFAULT_ENDPOINT, pagination_class: DEFAULT_PAGINATION }.merge(options))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.reset
|
21
|
+
super
|
22
|
+
self.endpoint = nil
|
23
|
+
self.user_agent = DEFAULT_UA
|
24
|
+
self.endpoint = DEFAULT_ENDPOINT
|
25
|
+
self.pagination_class = DEFAULT_PAGINATION
|
26
|
+
end
|
27
|
+
end
|
data/test/auth_test.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'dotenv'
|
2
|
+
require 'logger'
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
|
6
|
+
describe 'authentication' do
|
7
|
+
|
8
|
+
it '#1 use wrong username/password' do
|
9
|
+
assert_raises Growatt::AuthenticationError do
|
10
|
+
client = Growatt.client( { username: "xxx"+Growatt.username, password: Growatt.password } )
|
11
|
+
client.login
|
12
|
+
flunk( 'AuthenticationError expected' )
|
13
|
+
end
|
14
|
+
end
|
15
|
+
it '#2 use correct username/password' do
|
16
|
+
client = Growatt.client( { username: Growatt.username, password:Growatt.password } )
|
17
|
+
client.login
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/test/client_test.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'dotenv'
|
2
|
+
require 'logger'
|
3
|
+
require 'test_helper'
|
4
|
+
|
5
|
+
def p m, o
|
6
|
+
# puts "#{m}: #{o.inspect}"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe 'client' do
|
10
|
+
before do
|
11
|
+
@client = Growatt.client
|
12
|
+
@client.login
|
13
|
+
end
|
14
|
+
|
15
|
+
it '#1 GET info' do
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
it "#2 plant/device list" do
|
20
|
+
plants = @client.plant_list
|
21
|
+
|
22
|
+
p "\n* plants", plants
|
23
|
+
plant_id = plants.data.first.plantId
|
24
|
+
assert plant_id, "plant_id should not be nil"
|
25
|
+
|
26
|
+
detail = @client.plant_detail(plant_id)
|
27
|
+
p "\n* plant detail", detail
|
28
|
+
assert value(detail.plantData.plantId).must_equal(plant_id), 'correct plantId/structure'
|
29
|
+
|
30
|
+
plant_info = @client.plant_info(plant_id)
|
31
|
+
p "\n* plant info:", plant_info
|
32
|
+
|
33
|
+
devices = @client.device_list(plant_id)
|
34
|
+
p "\n* devices:", plant_info.deviceList
|
35
|
+
inverter = devices.first
|
36
|
+
# turn device on
|
37
|
+
result = @client.turn_inverter(inverter.deviceSn,true)
|
38
|
+
p "\n* turnon result:", result
|
39
|
+
is_on = @client.inverter_on?(inverter.deviceSn)
|
40
|
+
|
41
|
+
assert result, "inverter on should be success"
|
42
|
+
assert is_on, "Inverter should be on"
|
43
|
+
end
|
44
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'simplecov'
|
3
|
+
SimpleCov.start
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
6
|
+
require 'minitest/autorun'
|
7
|
+
require 'minitest/spec'
|
8
|
+
|
9
|
+
require 'dotenv'
|
10
|
+
require 'growatt'
|
11
|
+
|
12
|
+
Dotenv.load
|
13
|
+
|
14
|
+
TEST_LOGGER = 'test.log'
|
15
|
+
|
16
|
+
File.delete(TEST_LOGGER) if File.exist?(TEST_LOGGER)
|
17
|
+
|
18
|
+
Growatt.reset
|
19
|
+
Growatt.configure do |config|
|
20
|
+
config.username = ENV['GROWATT_USERNAME']
|
21
|
+
config.password = ENV['GROWATT_PASSWORD']
|
22
|
+
config.logger = Logger.new(TEST_LOGGER)
|
23
|
+
end
|
metadata
ADDED
@@ -0,0 +1,136 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: growatt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Janco Tanis
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-05-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: wrapi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.3.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.3.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dotenv
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description:
|
84
|
+
email: gems@jancology.com
|
85
|
+
executables: []
|
86
|
+
extensions: []
|
87
|
+
extra_rdoc_files: []
|
88
|
+
files:
|
89
|
+
- ".env.template"
|
90
|
+
- ".gitignore"
|
91
|
+
- CHANGELOG.md
|
92
|
+
- Gemfile
|
93
|
+
- README.md
|
94
|
+
- Rakefile
|
95
|
+
- growatt.gemspec
|
96
|
+
- lib/growatt.rb
|
97
|
+
- lib/growatt/api.rb
|
98
|
+
- lib/growatt/authorization.rb
|
99
|
+
- lib/growatt/client.rb
|
100
|
+
- lib/growatt/connection.rb
|
101
|
+
- lib/growatt/const.rb
|
102
|
+
- lib/growatt/error.rb
|
103
|
+
- lib/growatt/pagination.rb
|
104
|
+
- lib/growatt/version.rb
|
105
|
+
- test/auth_test.rb
|
106
|
+
- test/client_test.rb
|
107
|
+
- test/test_helper.rb
|
108
|
+
homepage: https://rubygems.org/gems/growatt
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata:
|
112
|
+
homepage_uri: https://rubygems.org/gems/growatt
|
113
|
+
source_code_uri: https://github.com/jancotanis/growatt
|
114
|
+
post_install_message:
|
115
|
+
rdoc_options: []
|
116
|
+
require_paths:
|
117
|
+
- lib
|
118
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: 2.4.0
|
123
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
requirements: []
|
129
|
+
rubygems_version: 3.0.3.1
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: A Ruby wrapper for the Growatt APIs (readonly)
|
133
|
+
test_files:
|
134
|
+
- test/auth_test.rb
|
135
|
+
- test/client_test.rb
|
136
|
+
- test/test_helper.rb
|