senec 0.6.2 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 877e39b91e6ff1f4709131aaf96394db590396faad43d8648c88ab90cce1ca3a
4
- data.tar.gz: bffeb00945d5a22ab11936299ec8d716283aa5c8283250c2ec337534f10af690
3
+ metadata.gz: 3fd3ccc37bfaa1b9583583d9d845200844da9f51e4231c3c527729ac7494c790
4
+ data.tar.gz: 2cd5722e55aca66579c755d6fc9490b1f546616048f3a208b4e4fce15d68723c
5
5
  SHA512:
6
- metadata.gz: 966c843b9dfe626d753cf7ceafa1c030479a59c8bd076009e8406252147d09f11f239225b86c628a537eb87b538d5893503c6206579cf0c769d235e442035100
7
- data.tar.gz: ca2fc0dfe72ce5934bc0ebeae1b2ac453f188031dbd0a2c515f135c892bc1d971fec9d81f9b7ccde604affdd0a6d312ee9dabfa349f00bd9df2ec97039e22734
6
+ metadata.gz: e14c8db17de64087e464f587764c29ea3f3d89b92edd95b1bd1a8090d81610dac5bcd5e177620260ef29784a24dc2572fc993dfda33205b7534b7d154c863dd2
7
+ data.tar.gz: c650cbe64f69875e943330752510b525d2215399b6087fcaa46625e6aa3a07f89cf3ca6699d260ac132329b5913a267526afcbc1cbf29f12331c8490f49d8350
@@ -6,6 +6,11 @@ jobs:
6
6
  test:
7
7
  runs-on: ubuntu-latest
8
8
 
9
+ strategy:
10
+ fail-fast: false
11
+ matrix:
12
+ ruby: ['3.0', '3.1', '3.2']
13
+
9
14
  steps:
10
15
  - name: Checkout the code
11
16
  uses: actions/checkout@v3
@@ -14,7 +19,7 @@ jobs:
14
19
  uses: ruby/setup-ruby@v1
15
20
  with:
16
21
  bundler-cache: true
17
- ruby-version: '3.1'
22
+ ruby-version: ${{ matrix.ruby }}
18
23
 
19
24
  - name: Lint with RuboCop
20
25
  run: bundle exec rubocop
data/.rubocop.yml CHANGED
@@ -4,7 +4,7 @@ require:
4
4
  - rubocop-rake
5
5
 
6
6
  AllCops:
7
- TargetRubyVersion: 2.7
7
+ TargetRubyVersion: 3.0
8
8
  NewCops: enable
9
9
 
10
10
  Style/Documentation:
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2020,2022 Georg Ledermann
3
+ Copyright (c) 2020,2023 Georg Ledermann
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,3 +1,6 @@
1
+ [![Continuous integration](https://github.com/solectrus/senec/actions/workflows/push.yml/badge.svg)](https://github.com/solectrus/senec/actions/workflows/push.yml)
2
+ [![wakatime](https://wakatime.com/badge/user/697af4f5-617a-446d-ba58-407e7f3e0243/project/84ac7dc2-9288-497c-bb20-9c6123d3de66.svg)](https://wakatime.com/badge/user/697af4f5-617a-446d-ba58-407e7f3e0243/project/84ac7dc2-9288-497c-bb20-9c6123d3de66)
3
+
1
4
  # Unofficial Ruby Client for SENEC Home
2
5
 
3
6
  Access your local SENEC Solar Battery Storage System
@@ -20,7 +23,8 @@ $ gem install senec
20
23
  ```ruby
21
24
  require 'senec'
22
25
 
23
- request = Senec::Request.new host: '10.0.1.99'
26
+ senec_ip = '10.0.1.99'
27
+ request = Senec::Request.new host: senec_ip
24
28
 
25
29
  puts "PV production: #{request.inverter_power} W"
26
30
  puts "House power consumption: #{request.house_power} W"
@@ -53,10 +57,22 @@ puts "Measure time: #{Time.at request.measure_time}"
53
57
  # Wallbox charge power: [ 8680, 0, 0, 0 ] W
54
58
  #
55
59
  # Grid power: 315 W
56
- # Current state of the system: CHARGE
60
+ # Current state of the system: 14
57
61
  # Measure time: 2021-10-06 17:50:22 +0200
58
62
  ```
59
63
 
64
+ To get the state name (in German) instead of just the number:
65
+
66
+ ```ruby
67
+ state_names = Senec::State.new(host: senec_ip).names
68
+ request = Senec::Request.new host: senec_ip, state_names: state_names
69
+
70
+ puts request.current_state_name
71
+ # => "LADEN"
72
+ ```
73
+
74
+ The state names are extracted on-the-fly from the JavaScript source code returned by the SENEC web interface.
75
+
60
76
  ## Development
61
77
 
62
78
  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.
@@ -71,6 +87,8 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/solect
71
87
 
72
88
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
73
89
 
90
+ Copyright (c) 2020,2023 Georg Ledermann
91
+
74
92
  ## Code of Conduct
75
93
 
76
94
  Everyone interacting in this project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/solectrus/senec/blob/master/CODE_OF_CONDUCT.md).
@@ -1,100 +1,4 @@
1
- module Senec # rubocop:disable Metrics/ModuleLength
2
- # Taken from https://github.com/mchwalisz/pysenec
3
- STATE_NAMES = {
4
- 0 => 'INITIAL STATE',
5
- 1 => 'ERROR INVERTER COMMUNICATION',
6
- 2 => 'ERROR ELECTRICY METER',
7
- 3 => 'RIPPLE CONTROL RECEIVER',
8
- 4 => 'INITIAL CHARGE',
9
- 5 => 'MAINTENANCE CHARGE',
10
- 6 => 'MAINTENANCE READY',
11
- 7 => 'MAINTENANCE REQUIRED',
12
- 8 => 'MAN. SAFETY CHARGE',
13
- 9 => 'SAFETY CHARGE READY',
14
- 10 => 'FULL CHARGE',
15
- 11 => 'EQUALIZATION: CHARGE',
16
- 12 => 'DESULFATATION: CHARGE',
17
- 13 => 'BATTERY FULL',
18
- 14 => 'CHARGE',
19
- 15 => 'BATTERY EMPTY',
20
- 16 => 'DISCHARGE',
21
- 17 => 'PV + DISCHARGE',
22
- 18 => 'GRID + DISCHARGE',
23
- 19 => 'PASSIVE',
24
- 20 => 'OFF',
25
- 21 => 'OWN CONSUMPTION',
26
- 22 => 'RESTART',
27
- 23 => 'MAN. EQUALIZATION: CHARGE',
28
- 24 => 'MAN. DESULFATATION: CHARGE',
29
- 25 => 'SAFETY CHARGE',
30
- 26 => 'BATTERY PROTECTION MODE',
31
- 27 => 'EG ERROR',
32
- 28 => 'EG CHARGE',
33
- 29 => 'EG DISCHARGE',
34
- 30 => 'EG PASSIVE',
35
- 31 => 'EG PROHIBIT CHARGE',
36
- 32 => 'EG PROHIBIT DISCHARGE',
37
- 33 => 'EMERGANCY CHARGE',
38
- 34 => 'SOFTWARE UPDATE',
39
- 35 => 'NSP ERROR',
40
- 36 => 'NSP ERROR: GRID',
41
- 37 => 'NSP ERROR: HARDWRE',
42
- 38 => 'NO SERVER CONNECTION',
43
- 39 => 'BMS ERROR',
44
- 40 => 'MAINTENANCE: FILTER',
45
- 41 => 'SLEEPING MODE',
46
- 42 => 'WAITING EXCESS',
47
- 43 => 'CAPACITY TEST: CHARGE',
48
- 44 => 'CAPACITY TEST: DISCHARGE',
49
- 45 => 'MAN. DESULFATATION: WAIT',
50
- 46 => 'MAN. DESULFATATION: READY',
51
- 47 => 'MAN. DESULFATATION: ERROR',
52
- 48 => 'EQUALIZATION: WAIT',
53
- 49 => 'EMERGANCY CHARGE: ERROR',
54
- 50 => 'MAN. EQUALIZATION: WAIT',
55
- 51 => 'MAN. EQUALIZATION: ERROR',
56
- 52 => 'MAN: EQUALIZATION: READY',
57
- 53 => 'AUTO. DESULFATATION: WAIT',
58
- 54 => 'ABSORPTION PHASE',
59
- 55 => 'DC-SWITCH OFF',
60
- 56 => 'PEAK-SHAVING: WAIT',
61
- 57 => 'ERROR BATTERY INVERTER',
62
- 58 => 'NPU-ERROR',
63
- 59 => 'BMS OFFLINE',
64
- 60 => 'MAINTENANCE CHARGE ERROR',
65
- 61 => 'MAN. SAFETY CHARGE ERROR',
66
- 62 => 'SAFETY CHARGE ERROR',
67
- 63 => 'NO CONNECTION TO MASTER',
68
- 64 => 'LITHIUM SAFE MODE ACTIVE',
69
- 65 => 'LITHIUM SAFE MODE DONE',
70
- 66 => 'BATTERY VOLTAGE ERROR',
71
- 67 => 'BMS DC SWITCHED OFF',
72
- 68 => 'GRID INITIALIZATION',
73
- 69 => 'GRID STABILIZATION',
74
- 70 => 'REMOTE SHUTDOWN',
75
- 71 => 'OFFPEAK-CHARGE',
76
- 72 => 'ERROR HALFBRIDGE',
77
- 73 => 'BMS: ERROR OPERATING TEMPERATURE',
78
- 74 => 'FACOTRY SETTINGS NOT FOUND',
79
- 75 => 'BACKUP POWER MODE - ACTIVE',
80
- 76 => 'BACKUP POWER MODE - BATTERY EMPTY',
81
- 77 => 'BACKUP POWER MODE ERROR',
82
- 78 => 'INITIALISING',
83
- 79 => 'INSTALLATION MODE',
84
- 80 => 'GRID OFFLINE',
85
- 81 => 'BMS UPDATE NEEDED',
86
- 82 => 'BMS CONFIGURATION NEEDED',
87
- 83 => 'INSULATION TEST',
88
- 84 => 'SELFTEST',
89
- 85 => 'EXTERNAL CONTROL',
90
- 86 => 'ERROR: TEMPERATURESENSOR',
91
- 87 => 'GRID OPERATOR: CHARGE PROHIBITED',
92
- 88 => 'GRID OPERATOR: DISCHARGE PROHIBITED',
93
- 89 => 'SPARE CAPACITY',
94
- 90 => 'SELFTEST ERROR',
95
- 91 => 'EARTH FAULT'
96
- }.freeze
97
-
1
+ module Senec
98
2
  # For a full list of available vars, see http://[IP-of-your-SENEC]/vars.html
99
3
  # Comments taken from https://gist.github.com/smashnet/82ad0b9d7f0ba2e5098e6649ba08f88a
100
4
  BASIC_REQUEST = {
@@ -112,6 +16,9 @@ module Senec # rubocop:disable Metrics/ModuleLength
112
16
  GUI_INVERTER_POWER: '', # PV production (W)
113
17
  STAT_HOURS_OF_OPERATION: '' # Appliance hours of operation
114
18
  },
19
+ PV1: {
20
+ MPP_POWER: '' # List: MPP power (W)
21
+ },
115
22
  TEMPMEASURE: {
116
23
  CASE_TEMP: ''
117
24
  },
data/lib/senec/request.rb CHANGED
@@ -1,12 +1,12 @@
1
- require 'http'
2
- require 'json'
1
+ require 'httparty'
3
2
  require 'senec/value'
4
3
  require 'senec/constants'
5
4
 
6
5
  module Senec
7
6
  class Request
8
- def initialize(host:)
7
+ def initialize(host:, state_names: nil)
9
8
  @host = host
9
+ @state_names = state_names
10
10
  end
11
11
 
12
12
  def house_power
@@ -17,6 +17,10 @@ module Senec
17
17
  get('ENERGY', 'GUI_INVERTER_POWER')
18
18
  end
19
19
 
20
+ def mpp_power
21
+ get('PV1', 'MPP_POWER')
22
+ end
23
+
20
24
  def bat_power
21
25
  get('ENERGY', 'GUI_BAT_DATA_POWER')
22
26
  end
@@ -46,9 +50,13 @@ module Senec
46
50
  end
47
51
 
48
52
  def current_state
49
- state = get('STATISTIC', 'CURRENT_STATE')
53
+ get('STATISTIC', 'CURRENT_STATE')
54
+ end
55
+
56
+ def current_state_name
57
+ throw RuntimeError, 'No state names provided!' unless @state_names
50
58
 
51
- STATE_NAMES[state]
59
+ @state_names[current_state]
52
60
  end
53
61
 
54
62
  def measure_time
@@ -71,15 +79,15 @@ module Senec
71
79
 
72
80
  def response
73
81
  @response ||= begin
74
- res = HTTP.post uri, json: Senec::BASIC_REQUEST
75
- raise Senec::Error, res.status.to_s unless res.status.success?
82
+ res = HTTParty.post(url, body: JSON.generate(Senec::BASIC_REQUEST))
83
+ raise Senec::Error, res.message.to_s unless res.success?
76
84
 
77
- JSON.parse(res.body)
85
+ res.parsed_response
78
86
  end
79
87
  end
80
88
 
81
- def uri
82
- URI.parse("http://#{@host}/lala.cgi")
89
+ def url
90
+ "http://#{@host}/lala.cgi"
83
91
  end
84
92
  end
85
93
  end
@@ -0,0 +1,46 @@
1
+ require 'httparty'
2
+
3
+ module Senec
4
+ class State
5
+ def initialize(host:)
6
+ @host = host
7
+ end
8
+
9
+ attr_reader :host
10
+
11
+ # Extract state names from JavaScript file, which is formatted like this:
12
+ #
13
+ # var system_state_name = {
14
+ # 0: "FIRST STATE",
15
+ # 1: "SECOND STATE",
16
+ # ...
17
+ # };
18
+ def names
19
+ response.match(FILE_REGEX)[0].split("\n").each_with_object({}) do |line, hash|
20
+ key, value = line.match(LINE_REGEX)&.captures
21
+ next unless key && value
22
+
23
+ hash[key.to_i] = value
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ FILE_REGEX = /var system_state_name = \{(.*?)\};/m
30
+ LINE_REGEX = /(\d+)\s*:\s*"(.*)"/
31
+
32
+ def response
33
+ @response ||= begin
34
+ res = HTTParty.get url
35
+ raise Senec::Error, res.message unless res.success?
36
+
37
+ res.body
38
+ end
39
+ end
40
+
41
+ # Use the JavaScript file with German names from the SENEC web interface
42
+ def url
43
+ "http://#{host}/js/DE-de.js"
44
+ end
45
+ end
46
+ end
data/lib/senec/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Senec
2
- VERSION = '0.6.2'.freeze
2
+ VERSION = '0.7.1'.freeze
3
3
  end
data/lib/senec.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'senec/version'
2
+ require 'senec/state'
2
3
  require 'senec/request'
3
4
 
4
5
  module Senec
data/senec.gemspec CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |spec|
10
10
  spec.description = 'Access your local SENEC Solar Battery Storage System'
11
11
  spec.homepage = 'https://github.com/solectrus/senec'
12
12
  spec.license = 'MIT'
13
- spec.required_ruby_version = Gem::Requirement.new('>= 2.7.0')
14
- spec.add_runtime_dependency 'http', '~> 5'
13
+ spec.required_ruby_version = Gem::Requirement.new('>= 3.0.0')
14
+ spec.add_runtime_dependency 'httparty'
15
15
 
16
16
  spec.metadata['homepage_uri'] = spec.homepage
17
17
  spec.metadata['source_code_uri'] = 'https://github.com/solectrus/senec'
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: senec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Georg Ledermann
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-13 00:00:00.000000000 Z
11
+ date: 2023-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: http
14
+ name: httparty
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5'
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '5'
26
+ version: '0'
27
27
  description: Access your local SENEC Solar Battery Storage System
28
28
  email:
29
29
  - georg@ledermann.dev
@@ -46,6 +46,7 @@ files:
46
46
  - lib/senec.rb
47
47
  - lib/senec/constants.rb
48
48
  - lib/senec/request.rb
49
+ - lib/senec/state.rb
49
50
  - lib/senec/value.rb
50
51
  - lib/senec/version.rb
51
52
  - senec.gemspec
@@ -65,14 +66,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
65
66
  requirements:
66
67
  - - ">="
67
68
  - !ruby/object:Gem::Version
68
- version: 2.7.0
69
+ version: 3.0.0
69
70
  required_rubygems_version: !ruby/object:Gem::Requirement
70
71
  requirements:
71
72
  - - ">="
72
73
  - !ruby/object:Gem::Version
73
74
  version: '0'
74
75
  requirements: []
75
- rubygems_version: 3.3.25
76
+ rubygems_version: 3.4.7
76
77
  signing_key:
77
78
  specification_version: 4
78
79
  summary: Unofficial Ruby Client for SENEC Home