From 00d058b6ea5152ebdee0ca6218e7aadd4adf745f Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Tue, 16 Dec 2025 15:03:24 +0100 Subject: [PATCH 01/13] Attempted to introduce configurable time window for average price calculation --- .env.example | 11 +++++++ .env.test | 4 +++ app/config.rb | 25 ++++++++++++++++ app/prices_provider.rb | 31 +++++++++++++++++-- test/config_test.rb | 58 ++++++++++++++++++++++++++++++++++++ test/prices_provider_test.rb | 24 +++++++++++++++ 6 files changed, 151 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index a8eb8c1..722683f 100644 --- a/.env.example +++ b/.env.example @@ -47,3 +47,14 @@ INFLUX_MEASUREMENT_FORECAST=my-forecast # Timezone TZ=Europe/Berlin + +# Price calculation average window ============================= +# If not set, price calculation will averaged for the next 24h +# which also averages out regular differences between day/night. + +# Optional: Start of relevant time range for price calculation +CHARGER_PRICE_COMPARION_HOUR_START=6 + +# Optional: End of relevant time range for price calculation +CHARGER_PRICE_COMPARION_HOUR_END=20 +# -------------------------------------------------------------- diff --git a/.env.test b/.env.test index ea13bdc..5ef5a37 100644 --- a/.env.test +++ b/.env.test @@ -14,3 +14,7 @@ INFLUX_ORG=my-org INFLUX_BUCKET=my-bucket INFLUX_MEASUREMENT_PRICES=my-prices INFLUX_MEASUREMENT_FORECAST=my-forecast + +# Price calculation average window +CHARGER_PRICE_COMPARION_HOUR_START=6 +CHARGER_PRICE_COMPARION_HOUR_END=20 diff --git a/app/config.rb b/app/config.rb index 8b77bef..223ade3 100644 --- a/app/config.rb +++ b/app/config.rb @@ -6,6 +6,8 @@ :charger_price_max, :charger_price_time_range, :charger_forecast_threshold, + :charger_price_comparison_hour_start, + :charger_price_comparison_hour_end, :charger_dry_run, :influx_schema, :influx_host, @@ -26,6 +28,7 @@ def initialize(*options) validate_price_max!(charger_price_max) validate_price_time_range!(charger_price_time_range) validate_forecast_threshold!(charger_forecast_threshold) + validate_price_comparison_hours!(charger_price_comparison_hour_start, charger_price_comparison_hour_end) end def influx_url @@ -70,6 +73,26 @@ def validate_url!(url) throw("URL is invalid: #{url}") end + def validate_price_comparison_hours!(start_hour, end_hour) + # Valid if both are nil (feature disabled) + return if start_hour.nil? && end_hour.nil? + + # Invalid if only one is set + if start_hour.nil? || end_hour.nil? + raise ArgumentError, 'Both start and end hour must be set for price comparison' + end + + # Invalid if out of bounds (0-23) + unless (0..23).cover?(start_hour) && (0..23).cover?(end_hour) + raise ArgumentError, 'Price comparison hours must be between 0 and 23' + end + + # Invalid if start is not before end + return if start_hour < end_hour + + raise ArgumentError, 'Price comparison start hour must be before end hour' + end + def self.from_env(options = {}) new( { @@ -93,6 +116,8 @@ def self.from_env(options = {}) ENV.fetch('INFLUX_MEASUREMENT_PRICES', 'Prices'), influx_measurement_forecast: ENV.fetch('INFLUX_MEASUREMENT_FORECAST', 'Forecast'), + charger_price_comparison_hour_start: ENV['CHARGER_PRICE_COMPARISON_HOUR_START']&.to_i, + charger_price_comparison_hour_end: ENV['CHARGER_PRICE_COMPARISON_HOUR_END']&.to_i, }.merge(options), ) end diff --git a/app/prices_provider.rb b/app/prices_provider.rb index 652bf4c..e313fa1 100644 --- a/app/prices_provider.rb +++ b/app/prices_provider.rb @@ -16,9 +16,19 @@ def cheap_ahead? end def best_price_acceptable? - return false unless best_prices_average && prices_average + # We need a valid best price average + return false unless best_prices_average - best_prices_average <= prices_average * config.charger_price_max / 100 + # Determine the reference price to compare against. + # Use the comparison average (filtered) if available, otherwise the full average. + # If a range is configured but no prices exist for it (ref_price is nil), + # we return false to be safe. + # 1. Try to get the average of the configured time window (comparison_average). + # 2. If not configured (or empty), fall back to the full 24h average (prices_average). + ref_price = comparison_average || prices_average + return false unless ref_price + + best_prices_average <= ref_price * config.charger_price_max / 100 end def best_prices_now? @@ -55,6 +65,23 @@ def end_time(price_list) private + # Returns the average of the specific time window (if configured) + # Returns nil if the filtered list is empty + def comparison_average + average(comparison_prices) + end + + def comparison_prices + # Because of Config validation, we know if one is set, both are set and valid. + return prices unless config.charger_price_comparison_hour_start && config.charger_price_comparison_hour_end + + # Filter prices to only include those within the configured hour range + prices.select do |price| + hour = price.time.hour + hour.between?(config.charger_price_comparison_hour_start, config.charger_price_comparison_hour_end) + end + end + def average(cons) return if cons.empty? diff --git a/test/config_test.rb b/test/config_test.rb index 6580690..ddb0ecd 100644 --- a/test/config_test.rb +++ b/test/config_test.rb @@ -102,4 +102,62 @@ def test_from_env assert_equal 'my-prices', config.influx_measurement_prices assert_equal 'my-forecast', config.influx_measurement_forecast end + + def test_price_comparison_config_valid + config = Config.new(VALID_OPTIONS.merge( + charger_price_comparison_hour_start: 6, + charger_price_comparison_hour_end: 18, + )) + + assert_equal 6, config.charger_price_comparison_hour_start + assert_equal 18, config.charger_price_comparison_hour_end + end + + def test_price_comparison_config_missing_one + # Should fail if only start is provided + assert_raises(ArgumentError) do + Config.new(VALID_OPTIONS.merge(charger_price_comparison_hour_start: 6)) + end + + # Should fail if only end is provided + assert_raises(ArgumentError) do + Config.new(VALID_OPTIONS.merge(charger_price_comparison_hour_end: 18)) + end + end + + def test_price_comparison_config_out_of_bounds + # Start hour too low + assert_raises(ArgumentError) do + Config.new(VALID_OPTIONS.merge( + charger_price_comparison_hour_start: -1, + charger_price_comparison_hour_end: 10, + )) + end + + # End hour too high + assert_raises(ArgumentError) do + Config.new(VALID_OPTIONS.merge( + charger_price_comparison_hour_start: 10, + charger_price_comparison_hour_end: 24, + )) + end + end + + def test_price_comparison_config_invalid_order + # Start hour same as end hour + assert_raises(ArgumentError) do + Config.new(VALID_OPTIONS.merge( + charger_price_comparison_hour_start: 10, + charger_price_comparison_hour_end: 10, + )) + end + + # Start hour after end hour + assert_raises(ArgumentError) do + Config.new(VALID_OPTIONS.merge( + charger_price_comparison_hour_start: 12, + charger_price_comparison_hour_end: 10, + )) + end + end end diff --git a/test/prices_provider_test.rb b/test/prices_provider_test.rb index e4fd501..e18709e 100644 --- a/test/prices_provider_test.rb +++ b/test/prices_provider_test.rb @@ -107,6 +107,30 @@ def test_cheap_now_relaxed_twelve_o_clock end end + def test_best_price_acceptable_moderate_with_comparison_range + # In the fake_prices data: + # - Best 4h average: 0.138 + # - Global 24h average: 0.176 + # - MODERATE threshold (70%): 0.176 * 0.7 = 0.123 + # 0.138 is NOT <= 0.123, so this normally fails (refute_predicate). + + # We configure the comparison range to 17:00 - 18:00. + # - Price at 17:00-18:00: 0.199 + # - New Reference Average: 0.199 + # - New Threshold (70%): 0.199 * 0.7 = 0.1393 + # 0.138 IS <= 0.1393, so this should now PASS. + + config.stub :charger_price_max, MODERATE do + config.stub :charger_price_comparison_hour_start, 17 do + config.stub :charger_price_comparison_hour_end, 18 do + VCR.use_cassette('prices_success') do + assert_predicate prices_provider, :best_price_acceptable? + end + end + end + end + end + private def prices_provider From 783cda75be2951b9cb29c6a661e2ba3262426c07 Mon Sep 17 00:00:00 2001 From: Georg Ledermann Date: Tue, 16 Dec 2025 17:05:56 +0100 Subject: [PATCH 02/13] Relax RuboCop config and fix warnings --- .rubocop.yml | 7 +++++-- test/config_test.rb | 10 +++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index a5210ee..628a892 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -21,10 +21,13 @@ Metrics/MethodLength: Max: 40 Metrics/AbcSize: - Max: 25 + Max: 26 + +Metrics/CyclomaticComplexity: + Max: 10 Metrics/ClassLength: - Max: 110 + Max: 130 Exclude: - test/**/* diff --git a/test/config_test.rb b/test/config_test.rb index ddb0ecd..cb976bb 100644 --- a/test/config_test.rb +++ b/test/config_test.rb @@ -107,7 +107,7 @@ def test_price_comparison_config_valid config = Config.new(VALID_OPTIONS.merge( charger_price_comparison_hour_start: 6, charger_price_comparison_hour_end: 18, - )) + )) assert_equal 6, config.charger_price_comparison_hour_start assert_equal 18, config.charger_price_comparison_hour_end @@ -131,7 +131,7 @@ def test_price_comparison_config_out_of_bounds Config.new(VALID_OPTIONS.merge( charger_price_comparison_hour_start: -1, charger_price_comparison_hour_end: 10, - )) + )) end # End hour too high @@ -139,7 +139,7 @@ def test_price_comparison_config_out_of_bounds Config.new(VALID_OPTIONS.merge( charger_price_comparison_hour_start: 10, charger_price_comparison_hour_end: 24, - )) + )) end end @@ -149,7 +149,7 @@ def test_price_comparison_config_invalid_order Config.new(VALID_OPTIONS.merge( charger_price_comparison_hour_start: 10, charger_price_comparison_hour_end: 10, - )) + )) end # Start hour after end hour @@ -157,7 +157,7 @@ def test_price_comparison_config_invalid_order Config.new(VALID_OPTIONS.merge( charger_price_comparison_hour_start: 12, charger_price_comparison_hour_end: 10, - )) + )) end end end From 0de771d3e4729c9fe3c452a3f28957410a68d5e3 Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Tue, 16 Dec 2025 17:33:44 +0100 Subject: [PATCH 03/13] Fixed embarrassing typo --- .env.example | 4 ++-- .env.test | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 722683f..acd9f64 100644 --- a/.env.example +++ b/.env.example @@ -53,8 +53,8 @@ TZ=Europe/Berlin # which also averages out regular differences between day/night. # Optional: Start of relevant time range for price calculation -CHARGER_PRICE_COMPARION_HOUR_START=6 +CHARGER_PRICE_COMPARISON_HOUR_START=6 # Optional: End of relevant time range for price calculation -CHARGER_PRICE_COMPARION_HOUR_END=20 +CHARGER_PRICE_COMPARISON_HOUR_END=20 # -------------------------------------------------------------- diff --git a/.env.test b/.env.test index 5ef5a37..d20695c 100644 --- a/.env.test +++ b/.env.test @@ -16,5 +16,5 @@ INFLUX_MEASUREMENT_PRICES=my-prices INFLUX_MEASUREMENT_FORECAST=my-forecast # Price calculation average window -CHARGER_PRICE_COMPARION_HOUR_START=6 -CHARGER_PRICE_COMPARION_HOUR_END=20 +CHARGER_PRICE_COMPARISON_HOUR_START=6 +CHARGER_PRICE_COMPARISON_HOUR_END=20 From 4d33f7c397e3789a4e46d402c57e01862428e0b3 Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Tue, 16 Dec 2025 17:35:38 +0100 Subject: [PATCH 04/13] Included 'fiddle' in Gemfile (apparently moved out of standard library in Ruby 3.4) --- Gemfile | 4 ++++ Gemfile.lock | 3 +++ 2 files changed, 7 insertions(+) diff --git a/Gemfile b/Gemfile index 5a4ab14..a1b6ef7 100644 --- a/Gemfile +++ b/Gemfile @@ -1,4 +1,5 @@ source 'https://rubygems.org' +source 'https://rubygems.org' # Loads environment variables from `.env`. (https://github.com/bkeepers/dotenv) gem 'dotenv' @@ -51,4 +52,7 @@ group :development, :test do # A gem providing "time travel" and "time freezing" capabilities, making it dead simple to test time-dependent code. It provides a unified method to mock Time.now, Date.today, and DateTime.now in a single call. (https://github.com/travisjeffery/timecop) gem 'timecop' + + # Used for interacting with C libraries (moved out of the default standard library in Ruby 3.4) + gem 'fiddle' end diff --git a/Gemfile.lock b/Gemfile.lock index b350ef3..5b98cbf 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -25,6 +25,7 @@ GEM net-http-persistent (>= 4.0.4, < 5) faraday-request-timer (0.2.0) faraday (>= 0.9.0) + fiddle (1.1.6) hashdiff (1.2.1) hashie (5.0.0) influxdb-client (3.2.0) @@ -121,12 +122,14 @@ GEM PLATFORMS ruby + x64-mingw-ucrt DEPENDENCIES base64 climate_control csv dotenv + fiddle influxdb-client minitest minitest-silence From a2dc6f1b8bd6d81a106353f7e0a3f78daa1e67b8 Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Tue, 16 Dec 2025 18:37:46 +0100 Subject: [PATCH 05/13] Extended test_helper.rb for tests to work standalone e.g. in Ruby Mine (without Rakefile) --- test/test_helper.rb | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 21bd12f..9aa08ed 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,15 +1,28 @@ -require 'simplecov' -require 'simplecov_json_formatter' -SimpleCov.start do - formatter SimpleCov::Formatter::JSONFormatter -end - require 'minitest/autorun' +require 'minitest/spec' +require 'webmock/minitest' +require 'vcr' require 'timecop' -require File.expand_path './support/vcr_setup.rb', __dir__ +require 'dotenv' + +Dotenv.load('.env.test') + +# 1. Add 'app' folder to the Load Path +# This ensures that if code inside app/ uses "require 'config'", it works. +$LOAD_PATH.unshift File.expand_path('../app', __dir__) -require 'loop' -require 'config' +# 2. Load Application Files using require_relative +# We use require_relative here because it is stricter and safer than 'require'. +# It guarantees finding the file relative to this test_helper. +require_relative '../app/config' +require_relative '../app/senec_provider' +require_relative '../app/prices_provider' +require_relative '../app/forecast_provider' +require_relative '../app/battery_action' +require_relative '../app/loop' -# Silence deprecation warnings caused by the `influxdb-client` gem -Warning[:deprecated] = false +# --- VCR Config --- +VCR.configure do |config| + config.cassette_library_dir = 'test/cassettes' + config.hook_into :webmock +end \ No newline at end of file From 38a3af93fc6fa160f931eca3e466a87af2db6cb7 Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Tue, 16 Dec 2025 18:39:22 +0100 Subject: [PATCH 06/13] Rubocop: Removed line ending enforcement so LF and CRLF both work (Windows/OSX/Linux) --- .rubocop.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.rubocop.yml b/.rubocop.yml index 628a892..15140df 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -48,3 +48,6 @@ Layout/FirstArrayElementIndentation: Minitest/MultipleAssertions: Enabled: false + +Layout/EndOfLine: + Enabled: false From a3ec35eacd0260514af42744603cf4d8dc642606 Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Tue, 16 Dec 2025 18:41:33 +0100 Subject: [PATCH 07/13] Out-commented CHARGER_PRICE_COMPARISON_HOUR settings in env files --- .env.example | 4 ++-- .env.test | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/.env.example b/.env.example index acd9f64..b305ae8 100644 --- a/.env.example +++ b/.env.example @@ -53,8 +53,8 @@ TZ=Europe/Berlin # which also averages out regular differences between day/night. # Optional: Start of relevant time range for price calculation -CHARGER_PRICE_COMPARISON_HOUR_START=6 +# CHARGER_PRICE_COMPARISON_HOUR_START=6 # Optional: End of relevant time range for price calculation -CHARGER_PRICE_COMPARISON_HOUR_END=20 +# CHARGER_PRICE_COMPARISON_HOUR_END=20 # -------------------------------------------------------------- diff --git a/.env.test b/.env.test index d20695c..ea13bdc 100644 --- a/.env.test +++ b/.env.test @@ -14,7 +14,3 @@ INFLUX_ORG=my-org INFLUX_BUCKET=my-bucket INFLUX_MEASUREMENT_PRICES=my-prices INFLUX_MEASUREMENT_FORECAST=my-forecast - -# Price calculation average window -CHARGER_PRICE_COMPARISON_HOUR_START=6 -CHARGER_PRICE_COMPARISON_HOUR_END=20 From 29c4da7ce690fddfc11f97dae05fe2aa2653c428 Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Tue, 16 Dec 2025 19:06:36 +0100 Subject: [PATCH 08/13] Reset config after test with optional settings --- test/prices_provider_test.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/prices_provider_test.rb b/test/prices_provider_test.rb index e18709e..27de1e5 100644 --- a/test/prices_provider_test.rb +++ b/test/prices_provider_test.rb @@ -129,6 +129,10 @@ def test_best_price_acceptable_moderate_with_comparison_range end end end + + # This prevents local .env settings from breaking standard tests + @config.charger_price_comparison_hour_start = nil + @config.charger_price_comparison_hour_end = nil end private From 9048e4d4c2bfc9562ddf5eebdd20908fb7a11e6c Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Tue, 16 Dec 2025 19:26:45 +0100 Subject: [PATCH 09/13] Extended logs for charge/not-charge decisions --- app/prices_provider.rb | 45 ++++++++++++++++++++++++++++-------- test/prices_provider_test.rb | 32 +++++++++++++++++++------ 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/app/prices_provider.rb b/app/prices_provider.rb index e313fa1..df0d081 100644 --- a/app/prices_provider.rb +++ b/app/prices_provider.rb @@ -43,16 +43,43 @@ def prices_average average(prices) end - def to_s # rubocop:disable Metrics/AbcSize - if prices.any? - <<~RESULT - Checked prices between #{prices.first.time.strftime('%A, %H:%M')} - #{end_time(prices).strftime('%A, %H:%M')}, ⌀ #{prices_average.round(2)} - Best #{config.charger_price_time_range}-hour range: #{best_prices.first.time.strftime('%A, %H:%M')} - #{end_time(best_prices).strftime('%A, %H:%M')}, ⌀ #{best_prices_average.round(2)} - Ratio best/average: #{(best_prices_average * 100 / prices_average).round(1)} % - RESULT - else - "No prices found between #{range_start} and #{range_stop}" + def to_s + subset = comparison_prices + return 'No prices available' if subset.empty? + + ref_price = (comparison_average || prices_average).round(3) + + # Combine the summaries + range_summary(subset, ref_price) + best_slot_summary(ref_price) + end + + def range_summary(subset, ref_price) + start_time = subset.first.time.strftime('%H:%M') + end_time = subset.last.time.strftime('%H:%M') + + msg = "Checked prices #{start_time}-#{end_time}" + + if config.charger_price_comparison_hour_start + msg += " (filtered #{config.charger_price_comparison_hour_start}:00-#{config.charger_price_comparison_hour_end}:00)" end + + msg + ", Ref Ø #{ref_price}" + end + + def best_slot_summary(ref_price) + return '' unless best_prices&.any? + + best_avg = best_prices_average.round(3) + slot_start = best_prices.first.time.strftime('%H:%M') + slot_end = best_prices.last.time.strftime('%H:%M') + + # Calculate Ratio and Decision + ratio = ((best_avg / ref_price) * 100).round(1) + target_price = (ref_price * config.charger_price_max / 100).round(3) + is_cheap = best_avg <= target_price + + "\n Best slot: #{slot_start} - #{slot_end} @ #{best_avg}" \ + "\n Decision: #{ratio}% of Ref (Limit #{config.charger_price_max}% / < #{target_price}) -> #{is_cheap ? 'CHEAP' : 'EXPENSIVE'}" end def end_time(price_list) diff --git a/test/prices_provider_test.rb b/test/prices_provider_test.rb index 27de1e5..d97b9eb 100644 --- a/test/prices_provider_test.rb +++ b/test/prices_provider_test.rb @@ -33,13 +33,19 @@ def test_best_prices_average def test_to_s VCR.use_cassette('prices_success') do - # Test with actual data from cassette, regardless of current time output = prices_provider.to_s - assert_match(/Checked prices between/, output) - assert_match(/Best 4-hour range:/, output) - assert_match(%r{Ratio best/average:}, output) - assert_match(/⌀ \d+\.\d+/, output) + # Verify the structure of the new multi-line log + # Line 1: Basic info + assert_match(/Checked prices \d{2}:\d{2}-\d{2}:\d{2}/, output) + assert_match(/Ref Ø \d+\.\d+/, output) + + # Line 2: Best slot + assert_match(/Best slot: \d{2}:\d{2} - \d{2}:\d{2} @ \d+\.\d+/, output) + + # Line 3: Decision logic + assert_match(/Decision: \d+\.\d+% of Ref/, output) + assert_match(/-> (CHEAP|EXPENSIVE)/, output) end end @@ -47,8 +53,20 @@ def test_to_s_empty # Travel to a time where we don't have any prices Timecop.travel('2023-05-02 12:10:00 +0200') do VCR.use_cassette('prices_blank') do - assert_equal 'No prices found between 2023-05-02 12:00:00 +0200 and 2023-05-03 12:00:00 +0200', - prices_provider.to_s + # UPDATE: Expect the new simple message + assert_equal 'No prices available', prices_provider.to_s + end + end + end + + def test_to_s_with_filter + # Verify that the log explicitly mentions the filter when active + config.stub :charger_price_comparison_hour_start, 6 do + config.stub :charger_price_comparison_hour_end, 20 do + VCR.use_cassette('prices_success') do + output = prices_provider.to_s + assert_match(/\(filtered 6:00-20:00\)/, output) + end end end end From f8d78d739a74218f674c2eab7236a71361893fd7 Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Tue, 16 Dec 2025 19:28:42 +0100 Subject: [PATCH 10/13] Optionally using local build via docker-compose --- compose.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compose.yml b/compose.yml index f1670d9..23a4e2b 100644 --- a/compose.yml +++ b/compose.yml @@ -1,6 +1,14 @@ services: senec-charger: + + # OPTION A: Use to use latest official built image: ghcr.io/solectrus/senec-charger:latest + + # OPTION B: Use local build with local .env file + # build: . + # env_file: + # - .env + depends_on: influxdb: condition: service_healthy From 3f09227443bbb1c365186ef78c3b29098564b7c8 Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Tue, 16 Dec 2025 19:44:07 +0100 Subject: [PATCH 11/13] Tamed rubocop --- .rubocop.yml | 2 +- app/prices_provider.rb | 6 ++++-- test/prices_provider_test.rb | 1 + test/test_helper.rb | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 15140df..63d5152 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -27,7 +27,7 @@ Metrics/CyclomaticComplexity: Max: 10 Metrics/ClassLength: - Max: 130 + Max: 140 Exclude: - test/**/* diff --git a/app/prices_provider.rb b/app/prices_provider.rb index df0d081..97fbfa0 100644 --- a/app/prices_provider.rb +++ b/app/prices_provider.rb @@ -60,7 +60,8 @@ def range_summary(subset, ref_price) msg = "Checked prices #{start_time}-#{end_time}" if config.charger_price_comparison_hour_start - msg += " (filtered #{config.charger_price_comparison_hour_start}:00-#{config.charger_price_comparison_hour_end}:00)" + msg += " (filtered #{config.charger_price_comparison_hour_start}" \ + ":00-#{config.charger_price_comparison_hour_end}:00)" end msg + ", Ref Ø #{ref_price}" @@ -79,7 +80,8 @@ def best_slot_summary(ref_price) is_cheap = best_avg <= target_price "\n Best slot: #{slot_start} - #{slot_end} @ #{best_avg}" \ - "\n Decision: #{ratio}% of Ref (Limit #{config.charger_price_max}% / < #{target_price}) -> #{is_cheap ? 'CHEAP' : 'EXPENSIVE'}" + "\n Decision: #{ratio}% of Ref (Limit #{config.charger_price_max}% " \ + "/ < #{target_price}) -> #{is_cheap ? 'CHEAP' : 'EXPENSIVE'}" end def end_time(price_list) diff --git a/test/prices_provider_test.rb b/test/prices_provider_test.rb index d97b9eb..3ed915b 100644 --- a/test/prices_provider_test.rb +++ b/test/prices_provider_test.rb @@ -65,6 +65,7 @@ def test_to_s_with_filter config.stub :charger_price_comparison_hour_end, 20 do VCR.use_cassette('prices_success') do output = prices_provider.to_s + assert_match(/\(filtered 6:00-20:00\)/, output) end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 9aa08ed..3d9fe5b 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -25,4 +25,4 @@ VCR.configure do |config| config.cassette_library_dir = 'test/cassettes' config.hook_into :webmock -end \ No newline at end of file +end From 659f74a867bab2f0320f73597e061cf6790f053e Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Tue, 16 Dec 2025 19:48:22 +0100 Subject: [PATCH 12/13] Added CHARGER_PRICE_COMPARISON_HOUR_START/END to docker-compose file --- compose.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compose.yml b/compose.yml index 23a4e2b..a09f4f9 100644 --- a/compose.yml +++ b/compose.yml @@ -22,6 +22,8 @@ services: - CHARGER_PRICE_MAX - CHARGER_PRICE_TIME_RANGE - CHARGER_FORECAST_THRESHOLD + - CHARGER_PRICE_COMPARISON_HOUR_START + - CHARGER_PRICE_COMPARISON_HOUR_END - CHARGER_DRY_RUN - INFLUX_HOST=influxdb - INFLUX_TOKEN=${INFLUX_TOKEN_READ} From 52170e3de0841b9c340eeb8800c8e2d33590cfdb Mon Sep 17 00:00:00 2001 From: rupert_jung Date: Wed, 17 Dec 2025 17:02:09 +0100 Subject: [PATCH 13/13] Gemfile: Removed duplicate source --- Gemfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Gemfile b/Gemfile index a1b6ef7..9382441 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,4 @@ source 'https://rubygems.org' -source 'https://rubygems.org' # Loads environment variables from `.env`. (https://github.com/bkeepers/dotenv) gem 'dotenv'