suez_mon_eau 0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5bb0b63f4f8e9e1da600d92123d83c4cd4998674d160e94ddd2ac238542d5c3b
4
+ data.tar.gz: e449685d94f7a73e1e46a86979164c91640ca3fdfb2d23b05e5df50142eca8f2
5
+ SHA512:
6
+ metadata.gz: 7769f819f65e6e9ef84827a50d40c7c8e7c1bd601859345b3aebc220ab4154522cb88e06257b2e89e99dddc4c30d4a3d93783783bcb26d253e29ce5a34b9324b
7
+ data.tar.gz: 684487bd9e82fb073377fdcb2eaec9dee4dc2568acbc61b2b5cc3d544e05c0ec1b946a7e9fdc8e718fdb930e85ec9ee7831d1f9d2b4dcb7be4e0da887c768a25
checksums.yaml.gz.sig ADDED
Binary file
data/bin/suez_mon_eau ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby -Ilib
2
+ # frozen_string_literal: true
3
+
4
+ require 'suez_mon_eau'
5
+ require 'date'
6
+ require 'optparse'
7
+
8
+ options = {}
9
+ opt_parser=OptionParser.new do |p|
10
+ p.banner = "Usage: #{$PROGRAM_NAME} [options]"
11
+ p.on('-u', '--username USER', 'Portal username', String){|v|options[:username] = v}
12
+ p.on('-p', '--password PASS', 'Portal password', String){|v|options[:password] = v}
13
+ p.on('-P', '--provider PROVIDER', 'Water Provider (Default: Suez)', String){|v|options[:provider] = v}
14
+ p.on('-i', '--id ID', 'Counter identifier', String){|v|options[:id] = v}
15
+ p.on('-d', '--debug', 'Turn on Rest trace', String){RestClient.log=$stderr}
16
+ end
17
+ opt_parser.parse!
18
+ if %i[username password].any?{|i|options[i].nil?}
19
+ puts opt_parser
20
+ exit 1
21
+ end
22
+ suez = SuezMonEau.new(**options)
23
+ puts('Contracts:')
24
+ pp suez.contracts
25
+ puts('Recent:')
26
+ pp suez.monthly_recent
27
+ puts('This Month:')
28
+ pp suez.daily_for_month(DateTime.now)
29
+ puts('Current:')
30
+ pp suez.total_volume
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rest-client'
4
+ require 'json'
5
+
6
+ # Volumes in m³
7
+ class SuezMonEau
8
+ VERSION='0.1'
9
+ GEM_NAME='suez_mon_eau'
10
+ SRC_URL='https://github.com/laurent-martin/ruby-suez-mon-eau'
11
+ DOC_URL='https://github.com/laurent-martin/ruby-suez-mon-eau'
12
+ GEM_URL='https://github.com/laurent-martin/ruby-suez-mon-eau'
13
+ BASE_URIS = {
14
+ 'Suez' => 'https://www.toutsurmoneau.fr/mon-compte-en-ligne',
15
+ 'Eau Olivet' => 'https://www.eau-olivet.fr/mon-compte-en-ligne'
16
+ }.freeze
17
+ API_ENDPOINT_LOGIN = 'je-me-connecte'
18
+ # daily (Jours) : /Y/m/counterid : Array(JJMMYYY, daily volume, cumulative volume). Volumes: .xxx
19
+ API_ENDPOINT_DAILY = 'statJData'
20
+ # monthly (Mois) : /counterid : Array(mmm. yy, monthly volume, cumulative voume, Mmmmm YYYY)
21
+ API_ENDPOINT_MONTHLY = 'statMData'
22
+ API_ENDPOINT_CONTRAT = 'donnees-contrats'
23
+ PAGE_CONSO = 'historique-de-consommation-tr'
24
+ SESSION_ID = 'eZSESSID'
25
+ MONTHS = %w[Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre Décembre].freeze
26
+ private_constant :BASE_URIS,:API_ENDPOINT_LOGIN,:API_ENDPOINT_DAILY,:API_ENDPOINT_MONTHLY,:API_ENDPOINT_CONTRAT,:PAGE_CONSO,:SESSION_ID,:MONTHS
27
+
28
+ # @param provider optional, one of supported providers or base url
29
+ def initialize(username:, password:, id: nil, provider: 'Suez')
30
+ @base_uri = BASE_URIS[provider] || provider
31
+ raise 'Not a valid provider' if @base_uri.nil?
32
+ @username = username
33
+ @password = password
34
+ @id = id
35
+ @id=nil if @id.is_a?(String) && @id.empty?
36
+ @cookies = nil
37
+ return unless @id.nil?
38
+ update_access_cookie
39
+ conso_page=RestClient.get("#{@base_uri}/#{PAGE_CONSO}",cookies: @cookies)
40
+ # get counter id from page
41
+ raise 'Could not retrieve counter id' unless (token_match = conso_page.body.match(%r{/month/([0-9]+)}))
42
+ @id=token_match[1]
43
+ end
44
+
45
+ def update_access_cookie
46
+ initial_response = RestClient.get("#{@base_uri}/#{API_ENDPOINT_LOGIN}")
47
+ raise 'Could not get token' unless (token_match = initial_response.body.match(%r{_csrf_token" value="(.*)"/>}))
48
+ data = {
49
+ '_csrf_token' => token_match[1],
50
+ '_username' => @username,
51
+ '_password' => @password,
52
+ 'signin[username]' => @username,
53
+ 'signin[password]' => nil,
54
+ 'tsme_user_login[_username]' => @username,
55
+ 'tsme_user_login[_password]' => @password
56
+ }
57
+ # There is a redirect (302) on POST
58
+ response = RestClient.post("#{@base_uri}/#{API_ENDPOINT_LOGIN}", data,
59
+ { cookies: initial_response.cookies }) do |resp, _req, _res|
60
+ case resp.code
61
+ when 301, 302, 307
62
+ begin
63
+ resp.follow_redirection
64
+ rescue RestClient::Found
65
+ raise 'Check username and password'
66
+ end
67
+ else resp.return!
68
+ end
69
+ end
70
+ raise StandardError, 'Login error: Please check your username/password.' unless response.cookies.key?(SESSION_ID)
71
+ @cookies = { SESSION_ID => response.cookies[SESSION_ID] }
72
+ end
73
+
74
+ def call_api(method:, endpoint:)
75
+ retried = false
76
+ loop do
77
+ update_access_cookie if @cookies.nil?
78
+ resp = RestClient::Request.execute(method: method, url: "#{@base_uri}/#{endpoint}", cookies: @cookies)
79
+ return JSON.parse(resp.body) if resp.headers[:content_type].include?('application/json')
80
+ raise 'Failed refreshing cookie' if retried
81
+ retried = true
82
+ @cookies = nil
83
+ end
84
+ end
85
+
86
+ def contracts
87
+ call_api(method: :get, endpoint: API_ENDPOINT_CONTRAT)
88
+ end
89
+
90
+ # @param thedate [Date] use year and month, built with Date.new(year,month,1)
91
+ # @return Hash [day_in_month]={day:, total:}
92
+ def daily_for_month(thedate)
93
+ r = call_api(method: :get, endpoint: "#{API_ENDPOINT_DAILY}/#{thedate.year}/#{thedate.month}/#{@id}")
94
+ # since the month is known, keep only day
95
+ r.each_with_object({}) do |i, m|
96
+ m[i[0].split('-').last.to_i] = { day: i[1], total: i[2] } unless i[2].eql?(0)
97
+ end
98
+ end
99
+
100
+ # @returns [Hash]
101
+ def monthly_recent
102
+ resp = call_api(method: :get, endpoint: "#{API_ENDPOINT_MONTHLY}/#{@id}")
103
+ h = {}
104
+ result = {
105
+ history: h,
106
+ total_volume: nil,
107
+ highest_monthly_volume: resp.pop,
108
+ last_year_volume: resp.pop,
109
+ this_year_volume: resp.pop
110
+ }
111
+ # fill history by hear and month
112
+ resp.each do |i|
113
+ # skip futures
114
+ next if i[2].eql?(0)
115
+ # date is Month Year
116
+ d = i[3].split(' ')
117
+ year = d.last.to_i
118
+ month = 1 + MONTHS.find_index(d.first)
119
+ h[year] ||= {}
120
+ h[year][month] = { month: i[1], total: result[:total_volume] = i[2] }
121
+ end
122
+ result
123
+ end
124
+
125
+ def total_volume
126
+ monthly_recent[:total_volume]
127
+ end
128
+ end
data.tar.gz.sig ADDED
@@ -0,0 +1,2 @@
1
+ �ȶ7 �E��l�R1 �^O[W�ӈ��^�*����0�>� �D�͜��țB��>PҩI]τ�8�'���JK[`�X͂��ȋWT*�U�J@�<9Xk���w_s+�St{�3�v���jC:�Z������ ?�V2e]ܯ4��
2
+ _�{b7��jnC�%�cK.n9o��Z�0!��� HHuQ��P�ƍ��x�P�XUm���gJ"qxX�,87Y�=�#$�I���(��]֝��b�'�>�&d�k�x9p�C���Ūp��F��?Z����&��40���4����ut�l���e����P,�"BT����7�ͺyi&7!X�C�"����_���� E&�wtw�sh5^��d�����JX��_�e����K@W6շa�
metadata ADDED
@@ -0,0 +1,193 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: suez_mon_eau
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Laurent Martin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIEkjCCAvqgAwIBAgIBATANBgkqhkiG9w0BAQsFADBHMRkwFwYDVQQDDBBsYXVy
14
+ ZW50Lm1hcnRpbi5sMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/Is
15
+ ZAEZFgNjb20wHhcNMjIxMjMwMTAyNjM0WhcNMjMxMjMwMTAyNjM0WjBHMRkwFwYD
16
+ VQQDDBBsYXVyZW50Lm1hcnRpbi5sMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzAR
17
+ BgoJkiaJk/IsZAEZFgNjb20wggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIB
18
+ gQDZloSHnbKkBEh6fW03mhvaNkUsiyO3iPbXnE7cosW3VUIzXvDeNTMVkeDnqjA8
19
+ lW5jKb0MHaymJXjuybck0kGQNwtCPVl5m9e5lAqALVWYyI7K2XKfvl11/ai0tA5g
20
+ sZdcxJkCsBBeKrEUPAw/9pNEPwtWu+5MtYxK8gXvP5mNPQs+NZx42Wksgu+DO/tk
21
+ Ph/W9f4TWB6rrOq7xm7YzG8jYHRISV2fyW7NqpB6lB9y8444IosCz9RQ/fGcIdIg
22
+ LjnvX5rofI6IDfTbUq9fvkT3ZbrxgTzY09lG7heDrgL1L7a+U5G4FF1PNzmZxgqj
23
+ z+xU6mfaVVY1hgGK6EsDgsyM7QEcOGU5witL2yUkw3jYGm8jF3YdoSoZW+MKPfNf
24
+ v6yNTGJsJAVXlo//g+HRS6KGSfTx5M7cgRxGgud72h3PlOxgO/t8d7MTmRuo1oeU
25
+ pVmEUUsVtDSUJ3bdL5W85LCIV02VBPtw/rrg6AHFbrHRnp7FWcN1i20x+sk5ZBa4
26
+ C08CAwEAAaOBiDCBhTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU
27
+ IXrSEupwwYfE3a9f2jVz1wp4KGwwJQYDVR0RBB4wHIEabGF1cmVudC5tYXJ0aW4u
28
+ bEBnbWFpbC5jb20wJQYDVR0SBB4wHIEabGF1cmVudC5tYXJ0aW4ubEBnbWFpbC5j
29
+ b20wDQYJKoZIhvcNAQELBQADggGBAAhSXNutSwyrmpo/E/Fj3gNbMEL7uteveQ9J
30
+ jzsyp02PR6gaCkAIBWHigYTSI6+AW6vfFrCcRU7mVpGFDDTtYIZsthOU7G2mG0IY
31
+ uMXqZERShk+IjzpTDYQjvsmrQ7paQ7XYm1pS3cYzQqSwWP7unIcl0w13/JEcrQpz
32
+ w9Nk/JfICyOwnsNsGq/0SNSdrlNr1qUQQM/nmMEM6AvpKp7I4P2Ap4VJkDCu+0SK
33
+ x3mBvWB8GtmMOpto9ybr7El4xjfJpNu/kvKv2bbCQPs6Z/qfz0lYyK5JFqmhpQN7
34
+ E1Wj9oKIf+RH/1FYBdx2TaQ1ijkqpfwTa0QWRY4dU/GKGgBmMriGMIh8YAL9cmgd
35
+ HdwIbOaZ+pjC4nKKT38vsb2lNismhhaiAYq+Ekld50Rb0nbCPq7VfREn8uCJatpb
36
+ 47kCk6UoPFdRvzdrQoOHQhkBuabk02iz6c35KbcKaogX8SDehA1/bO4F4VwLz4in
37
+ YmwAMTElT6RjOw71pAJ02LbhHG02SA==
38
+ -----END CERTIFICATE-----
39
+ date: 2022-12-30 00:00:00.000000000 Z
40
+ dependencies:
41
+ - !ruby/object:Gem::Dependency
42
+ name: rest-client
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.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: '1.12'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.12'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-ast
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.4'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.4'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-performance
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.10'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.10'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-shopify
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.18'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.18'
139
+ - !ruby/object:Gem::Dependency
140
+ name: solargraph
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.44'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.44'
153
+ description: Retrieve water usage information from Suez in France
154
+ email:
155
+ - laurent.martin.l@gmail.com
156
+ executables:
157
+ - suez_mon_eau
158
+ extensions: []
159
+ extra_rdoc_files: []
160
+ files:
161
+ - bin/suez_mon_eau
162
+ - lib/suez_mon_eau.rb
163
+ homepage: https://github.com/laurent-martin/ruby-suez-mon-eau
164
+ licenses:
165
+ - Apache-2.0
166
+ metadata:
167
+ allowed_push_host: https://rubygems.org
168
+ homepage_uri: https://github.com/laurent-martin/ruby-suez-mon-eau
169
+ source_code_uri: https://github.com/laurent-martin/ruby-suez-mon-eau
170
+ changelog_uri: https://github.com/laurent-martin/ruby-suez-mon-eau
171
+ rubygems_uri: https://github.com/laurent-martin/ruby-suez-mon-eau
172
+ documentation_uri: https://github.com/laurent-martin/ruby-suez-mon-eau
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '2.4'
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ requirements:
188
+ - No specific requirement
189
+ rubygems_version: 3.3.7
190
+ signing_key:
191
+ specification_version: 4
192
+ summary: Retrieve water usage information from Suez in France
193
+ test_files: []
metadata.gz.sig ADDED
Binary file