sunscout 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 932d2d5473a423b5839198dde6179124b13c5090
4
+ data.tar.gz: ea0ca9ec4af624858f71f976a50b3abf6e63a7de
5
+ SHA512:
6
+ metadata.gz: 88afb8ab77d532ddc8cca0344259904d32856c33c4f836d282b831b59c6aefebc6703a08e83c1b0478a451621ccb253d013d0c1f1f1c094ba78b12a39c487823
7
+ data.tar.gz: a7f2a597d77e64702d9dc997e7602b62b0b499db5c8828ba27733d1557a1b6a17978eefd09544306c15c462d2eb88d9c6798200efd5672f5a37a258ee9603637
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.0
5
+ before_install: gem install bundler -v 1.12.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sunscout.gemspec
4
+ gemspec
@@ -0,0 +1,13 @@
1
+ Copyright 2016 Michael Senn
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,41 @@
1
+ # Sunscout
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/sunscout`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'sunscout'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install sunscout
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sunscout.
36
+
37
+
38
+ ## License
39
+
40
+ The gem is available as open source under the terms of the [Apache-2.0 License](http://opensource.org/licenses/Apache-2.0).
41
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "sunscout"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,7 @@
1
+ # coding: utf-8
2
+
3
+ require_relative 'sunscout/solar_log'
4
+
5
+ module Sunscout
6
+ # Your code goes here...
7
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+
3
+ require_relative 'solar_log/client'
4
+ require_relative 'solar_log/solar_log'
5
+
6
+ module Sunscout
7
+ # Classes to interact with SolarLog HTTP API.
8
+ #
9
+ # - {SolarLog::Client} Low-Level client which returns API data directly, remapped to human-readable keys
10
+ # - {SolarLog::SolarLog} High-level client, which offers various convenience functions.
11
+ # @example
12
+ # #!/usr/bin/env ruby
13
+ # # coding: utf-8
14
+ #
15
+ # require 'sunscout'
16
+ #
17
+ # puts 'Querying data from SolarLog API'
18
+ # solar_log = Sunscout::SolarLog::SolarLog.new('http://10.0.0.10')
19
+ #
20
+ # puts "Data from: #{ solar_log.time.iso8601 }"
21
+ # puts "AC Power: #{ solar_log.power_ac }W (DC Power: #{ solar_log.power_dc }W, #{ (solar_log.efficiency*100).round(0) }% efficiency, #{ solar_log.alternator_loss }W loss)"
22
+ #
23
+ # puts "Current usage: #{ solar_log.consumption_ac }W (#{ (solar_log.usage*100).round(0) }%)"
24
+ module SolarLog
25
+ end
26
+ end
@@ -0,0 +1,100 @@
1
+ # coding: utf-8
2
+
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'uri'
6
+
7
+ REQUEST_QUERY = 'getjp'
8
+ REQUEST_PAYLOAD = { 801 => { 170 => nil } }
9
+
10
+ module Sunscout
11
+ module SolarLog
12
+ # Low-level binding to the SolarLog HTTP API
13
+ # @example Basic usage
14
+ # require 'sunscout'
15
+ # c = Sunscout::SolarLog::Client.new('http://10.60.1.10')
16
+ # data = c.get_data()
17
+ # puts "Current power output: #{ data[:power_ac] }W"
18
+ class Client
19
+ # Initialize a new instance of the class.
20
+ # @param host [String] URI of the SolarLog web interface.
21
+ def initialize(host)
22
+ @host = host
23
+ end
24
+
25
+ # Retrieve data from the HTTP API.
26
+ # @return [Hash<Symbol, String|Integer>] Hash containing retrieved data
27
+ def get_data
28
+ uri = build_uri
29
+ req = build_request(uri)
30
+ data = send_request(req, uri)
31
+
32
+ data
33
+ end
34
+
35
+ private
36
+ # Create URI of HTTP endpoint
37
+ def build_uri
38
+ URI("#{ @host }/#{ REQUEST_QUERY }")
39
+ end
40
+
41
+ # Build HTTP POST request
42
+ # @param uri [URI] URI of HTTP endpoint
43
+ def build_request(uri)
44
+ req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
45
+ req.body = JSON.dump(REQUEST_PAYLOAD)
46
+
47
+ req
48
+ end
49
+
50
+ # Send HTTP request to URI
51
+ # @param req [Net::HTTP::Post] HTTP request
52
+ # @param uri [URI] URI of HTTP endpoint
53
+ # @return [Hash] Raw data retrieved by HTTP API
54
+ def send_request(req, uri)
55
+ res = Net::HTTP.start(uri.hostname, uri.port) do |http|
56
+ http.request(req)
57
+ end
58
+
59
+ # Todo: Exception handling:
60
+ # - catching in case of failure (DNS, timeout, ...)
61
+ # - throwing in case of API failure
62
+ case res
63
+ when Net::HTTPSuccess
64
+ data = parse_data(JSON.parse(res.body))
65
+ else
66
+ data = {}
67
+ end
68
+
69
+ data
70
+ end
71
+
72
+ # Remap raw API data to human-readable data.
73
+ # @param data [Hash] Raw API data
74
+ # @return [Hash] Human-readable data
75
+ def parse_data(data)
76
+ data = data.fetch('801').fetch('170')
77
+
78
+ out = {
79
+ time: data.fetch('100'),
80
+ power_ac: data.fetch('101'),
81
+ power_dc: data.fetch('102'),
82
+ voltage_ac: data.fetch('103'),
83
+ voltage_dc: data.fetch('104'),
84
+ yield_day: data.fetch('105'),
85
+ yield_yesterday: data.fetch('106'),
86
+ yield_month: data.fetch('107'),
87
+ yield_year: data.fetch('108'),
88
+ yield_total: data.fetch('109'),
89
+ consumption_ac: data.fetch('110'),
90
+ consumption_day: data.fetch('111'),
91
+ consumption_yesterday: data.fetch('112'),
92
+ consumption_month: data.fetch('113'),
93
+ consumption_year: data.fetch('114'),
94
+ consumption_total: data.fetch('115'),
95
+ power_total: data.fetch('116'),
96
+ }
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,172 @@
1
+ # coding: utf-8
2
+
3
+ require 'date'
4
+
5
+ module Sunscout
6
+ module SolarLog
7
+ # High-level binding to the SolarLog HTTP API
8
+ # @example Basic usage
9
+ # require 'sunscout'
10
+ # sl = Sunscout::SolarLog::SolarLog.new('http://10.60.1.10')
11
+ # puts "AC power: #{ sl.power_ac }W (DC: #{ sl.power_dc }W, Efficiency #{ (sl.efficiency*100).round(0) }%)"
12
+ # puts "Remaining power: #{ sl.power_available }W"
13
+ class SolarLog
14
+ # Timestamp of the data.
15
+ # @return [DateTime]
16
+ attr_reader :time
17
+
18
+ # AC power in W
19
+ # @return [Fixnum]
20
+ attr_reader :power_ac
21
+ # DC power in W
22
+ # @return [Fixnum]
23
+ attr_reader :power_dc
24
+ # Maximum DC power in W
25
+ # @return [Fixnum]
26
+ attr_reader :power_total
27
+
28
+ # AC voltage in V
29
+ # @return [Fixnum]
30
+ attr_reader :voltage_ac
31
+ # DC voltage in V
32
+ # @return [Fixnum]
33
+ attr_reader :voltage_dc
34
+
35
+ # Today's yield in Wh
36
+ # @return [Fixnum]
37
+ attr_reader :yield_day
38
+ # Yesterday's yield in WH
39
+ # @return [Fixnum]
40
+ attr_reader :yield_yesterday
41
+ # This month's yield in Wh
42
+ # @return [Fixnum]
43
+ attr_reader :yield_month
44
+ # This year's yield in Wh
45
+ # @return [Fixnum]
46
+ attr_reader :yield_year
47
+ # Total yield in Wh
48
+ # @return [Fixnum]
49
+ attr_reader :yield_total
50
+
51
+ # Current consumption in W
52
+ # @return [Fixnum]
53
+ attr_reader :consumption_ac
54
+ # Today's consumption in Wh
55
+ # @return [Fixnum]
56
+ attr_reader :consumption_day
57
+ # Yesterday's consumption in Wh
58
+ # @return [Fixnum]
59
+ attr_reader :consumption_yesterday
60
+ # This month's consumption in Wh
61
+ # @return [Fixnum]
62
+ attr_reader :consumption_month
63
+ # This year's consumption in Wh
64
+ # @return [Fixnum]
65
+ attr_reader :consumption_year
66
+ # Total consumption in Wh
67
+ # @return [Fixnum]
68
+ attr_reader :consumption_total
69
+
70
+ # Initialize a new instance of the class.
71
+ #
72
+ # This also immediately queries data from the SolarLog API.
73
+ #
74
+ # @param host [String] URI of the SolarLog web interface
75
+ def initialize(host)
76
+ client = Sunscout::SolarLog::Client.new(host)
77
+ data = client.get_data
78
+
79
+ @time = DateTime.strptime(data.fetch(:time), '%d.%m.%y %H:%M:%s')
80
+
81
+ @power_ac = data.fetch :power_ac
82
+ @power_dc = data.fetch :power_dc
83
+ @power_total = data.fetch :power_total
84
+
85
+ @voltage_ac = data.fetch :voltage_ac
86
+ @voltage_dc = data.fetch :voltage_dc
87
+
88
+ @yield_day = data.fetch :yield_day
89
+ @yield_yesterday = data.fetch :yield_yesterday
90
+ @yield_month = data.fetch :yield_month
91
+ @yield_year = data.fetch :yield_year
92
+ @yield_total = data.fetch :yield_total
93
+
94
+ @consumption_ac = data.fetch :consumption_ac
95
+ @consumption_day = data.fetch :consumption_day
96
+ @consumption_yesterday = data.fetch :consumption_yesterday
97
+ @consumption_month = data.fetch :consumption_month
98
+ @consumption_year = data.fetch :consumption_year
99
+ @consumption_total = data.fetch :consumption_total
100
+ end
101
+
102
+ # Efficiency of DC to AC conversion.
103
+ # @return [Float] Efficiency as percentage between 0 and 1.
104
+ #
105
+ # @example
106
+ # solar_log.power_ac #=> 94
107
+ # solar_log.power_dc #=> 100
108
+ # solar_log.efficiency #=> 0.94
109
+ def efficiency
110
+ return 0 if @power_dc == 0
111
+ power_ac.to_f / power_dc
112
+ end
113
+
114
+ # Loss of DC to AC conversion.
115
+ # @return [Fixnum] Loss of alternator in Watt.
116
+ #
117
+ # @example
118
+ # solar_log.power_ac #=> 94
119
+ # solar_log.power_dc #=> 100
120
+ # solar_log.alternator_loss #=> 6
121
+ def alternator_loss
122
+ power_dc - power_ac
123
+ end
124
+
125
+ # Usage of AC power.
126
+ # @return [Float] Usage of AC power as percentage. >1 if more power consumed than generated.
127
+ #
128
+ # @example Usage <100%
129
+ # solar_log.consumption_ac #=> 50
130
+ # solar_log.power_ac #=> 100
131
+ # solar_log.usage #=> 0.5
132
+ #
133
+ # @example Usage >100%
134
+ # solar_log.consumption_ac #=> 200
135
+ # solar_log.power_ac #=> 100
136
+ # solar_log.usage #=> 2
137
+ def usage
138
+ return 0 if @power_ac == 0
139
+ consumption_ac.to_f / power_ac
140
+ end
141
+
142
+ # Surplus AC power.
143
+ # @return [Fixnum] Surplus AC power in Watt. Negative if more power consumed than generated.
144
+ #
145
+ # @example Usage <100%
146
+ # solar_log.consumption_ac #=> 50
147
+ # solar_log.power_ac #=> 100
148
+ # solar_log.power_available #=> 50
149
+ #
150
+ # @example Usage >100%
151
+ # solar_log.consumption_ac #=> 200
152
+ # solar_log.power_ac #=> 100
153
+ # solar_log.power_available #=> -100
154
+ def power_available
155
+ power_ac - consumption_ac
156
+ end
157
+
158
+ # Capacity of peak power generation.
159
+ # @return [Float] Percentage of peak power generation.
160
+ #
161
+ # @example
162
+ # solar_log.power_dc #=> 8000
163
+ # solar_log.power_total #=> 10000
164
+ # solar_log.capacity #=> 0.8
165
+ def capacity
166
+ return 0 if power_total == 0
167
+ power_dc / power_total
168
+ end
169
+ end
170
+ end
171
+ end
172
+
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "sunscout"
7
+ spec.version = '0.1'
8
+ spec.authors = ["Michael Senn"]
9
+ spec.email = ["michael@morrolan.ch"]
10
+
11
+ spec.summary = %q{Binding to Solarlog HTTP API}
12
+ # spec.description = %q{}
13
+ # spec.homepage = ""
14
+ spec.license = "Apache-2.0"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.12"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.0"
24
+ spec.add_development_dependency "yard"
25
+ end
metadata ADDED
@@ -0,0 +1,114 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sunscout
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Michael Senn
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-08-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: yard
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
+ description:
70
+ email:
71
+ - michael@morrolan.ch
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - bin/console
84
+ - bin/setup
85
+ - lib/sunscout.rb
86
+ - lib/sunscout/solar_log.rb
87
+ - lib/sunscout/solar_log/client.rb
88
+ - lib/sunscout/solar_log/solar_log.rb
89
+ - sunscout.gemspec
90
+ homepage:
91
+ licenses:
92
+ - Apache-2.0
93
+ metadata: {}
94
+ post_install_message:
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ requirements: []
109
+ rubyforge_project:
110
+ rubygems_version: 2.5.1
111
+ signing_key:
112
+ specification_version: 4
113
+ summary: Binding to Solarlog HTTP API
114
+ test_files: []