From bd2b8943d179ef883ff67dbad0dced19269e4b50 Mon Sep 17 00:00:00 2001 From: Javier Aranda Date: Sat, 6 Jan 2024 13:04:24 +0100 Subject: [PATCH] WIP --- .rubocop.yml | 2 + Gemfile | 3 +- Gemfile.lock | 16 +- Procfile | 2 +- app/aggregations/application_aggregation.rb | 28 +++ .../daily_grid_energy_export_aggregation.rb | 31 +++ app/lib/esios/export.rb | 4 - app/lib/esios/import.rb | 4 - app/lib/esios/indicator.rb | 25 +-- .../grid_energy_import.rb | 0 .../grid_power_export.rb | 0 .../grid_power_import.rb | 0 .../solar_energy.rb | 0 .../solar_power.rb | 0 app/lib/solaris/daily_archives/base.rb | 34 --- .../daily_archives/energy_price_export.rb | 25 --- .../daily_archives/grid_energy_export.rb | 35 --- app/lib/solaris/pvpcs/daily/export_price.rb | 27 +++ .../daily/import_price.rb} | 0 .../archive_daily_energy_price_export.rb | 3 - .../archive_daily_energy_price_import.rb | 3 - app/models/cost.rb | 18 ++ app/models/country.rb | 11 + app/models/country_holiday.rb | 6 + app/models/daily_energy_export_price.rb | 2 + app/models/daily_energy_import_price.rb | 2 + app/models/energy_period.rb | 14 ++ app/models/energy_price.rb | 14 +- app/models/energy_prices/pvpc.rb | 11 + app/models/inverter.rb | 7 +- app/models/rate.rb | 5 + app/models/rates/by_period.rb | 4 + app/models/rates/fixed.rb | 4 + app/models/rates/pvpc.rb | 4 + app/models/setting.rb | 26 --- app/models/tax.rb | 15 ++ app/models/zone.rb | 14 ++ config/application.rb | 2 +- config/clockwork.rb | 20 -- config/initializers/core_extensions.rb | 1 + config/initializers/inflections.rb | 1 + config/scheduler.rb | 18 ++ .../20230805145711_create_energy_price.rb | 10 - db/migrate/20230805174919_create_archive.rb | 13 +- ...183244_create_archive_daily_solar_power.rb | 4 +- ...72241_create_archive_daily_solar_energy.rb | 6 +- ..._create_archive_daily_grid_power_export.rb | 6 +- ..._create_archive_daily_grid_power_import.rb | 6 +- ...create_archive_daily_grid_energy_import.rb | 6 +- ...create_archive_daily_grid_energy_export.rb | 6 +- ...reate_archive_daily_energy_price_import.rb | 13 -- ...reate_archive_daily_energy_price_export.rb | 13 -- db/migrate/20231031072840_create_settings.rb | 18 -- db/migrate/20231224202745_create_zones.rb | 12 + .../20231224203015_create_energy_prices.rb | 12 + ...03523_create_daily_energy_import_prices.rb | 15 ++ ...03754_create_daily_energy_export_prices.rb | 15 ++ .../20231226105540_create_energy_periods.rb | 18 ++ ....rb => 20231227151918_create_inverters.rb} | 6 +- db/migrate/20231229001020_create_costs.rb | 18 ++ db/migrate/20231229003253_create_taxes.rb | 13 ++ db/migrate/20231229145024_create_rates.rb | 14 ++ db/migrate/20231229150159_create_countries.rb | 13 ++ .../20231229153145_create_country_holidays.rb | 11 + ...31229200236_create_zones_energy_periods.rb | 9 + db/schema.rb | 212 +++++++++++++----- db/seeds.rb | 18 -- lib/core_extensions/time.rb | 9 + test/fixtures/archives.yml | 1 - test/fixtures/costs.yml | 25 +++ test/fixtures/countries.yml | 7 + test/fixtures/country_holidays.yml | 40 ++++ test/fixtures/energy_periods.yml | 114 ++++++++++ test/fixtures/energy_price.yml | 119 ---------- test/fixtures/energy_prices.yml | 167 ++++++++++++++ test/fixtures/inverters.yml | 32 ++- test/fixtures/protocols.yml | 19 +- test/fixtures/rates.yml | 49 ++++ test/fixtures/settings.yml | 4 - test/fixtures/taxes.yml | 17 ++ test/fixtures/zones.yml | 49 ++++ test/fixtures/zones_energy_periods.yml | 15 ++ test/models/cost_test.rb | 7 + test/models/country_test.rb | 10 + test/models/energy_period_test.rb | 7 + test/models/holiday_test.rb | 7 + test/models/inverter_test.rb | 11 +- test/models/protocol_test.rb | 4 +- test/models/rate_test.rb | 7 + test/models/setting_test.rb | 93 -------- test/models/tax_test.rb | 7 + test/models/zone_test.rb | 7 + test/test_helper.rb | 2 - 93 files changed, 1175 insertions(+), 582 deletions(-) create mode 100644 app/aggregations/application_aggregation.rb create mode 100644 app/aggregations/daily_grid_energy_export_aggregation.rb rename app/lib/solaris/{daily_archives => archives}/grid_energy_import.rb (100%) rename app/lib/solaris/{daily_archives => archives}/grid_power_export.rb (100%) rename app/lib/solaris/{daily_archives => archives}/grid_power_import.rb (100%) rename app/lib/solaris/{daily_archives => archives}/solar_energy.rb (100%) rename app/lib/solaris/{daily_archives => archives}/solar_power.rb (100%) delete mode 100644 app/lib/solaris/daily_archives/base.rb delete mode 100644 app/lib/solaris/daily_archives/energy_price_export.rb delete mode 100644 app/lib/solaris/daily_archives/grid_energy_export.rb create mode 100644 app/lib/solaris/pvpcs/daily/export_price.rb rename app/lib/solaris/{daily_archives/energy_price_import.rb => pvpcs/daily/import_price.rb} (100%) delete mode 100644 app/models/archive_daily_energy_price_export.rb delete mode 100644 app/models/archive_daily_energy_price_import.rb create mode 100644 app/models/cost.rb create mode 100644 app/models/country.rb create mode 100644 app/models/country_holiday.rb create mode 100644 app/models/daily_energy_export_price.rb create mode 100644 app/models/daily_energy_import_price.rb create mode 100644 app/models/energy_period.rb create mode 100644 app/models/energy_prices/pvpc.rb create mode 100644 app/models/rate.rb create mode 100644 app/models/rates/by_period.rb create mode 100644 app/models/rates/fixed.rb create mode 100644 app/models/rates/pvpc.rb delete mode 100644 app/models/setting.rb create mode 100644 app/models/tax.rb create mode 100644 app/models/zone.rb delete mode 100644 config/clockwork.rb create mode 100644 config/scheduler.rb delete mode 100644 db/migrate/20230805145711_create_energy_price.rb delete mode 100644 db/migrate/20230808184043_create_archive_daily_energy_price_import.rb delete mode 100644 db/migrate/20230808185034_create_archive_daily_energy_price_export.rb delete mode 100644 db/migrate/20231031072840_create_settings.rb create mode 100644 db/migrate/20231224202745_create_zones.rb create mode 100644 db/migrate/20231224203015_create_energy_prices.rb create mode 100644 db/migrate/20231224203523_create_daily_energy_import_prices.rb create mode 100644 db/migrate/20231224203754_create_daily_energy_export_prices.rb create mode 100644 db/migrate/20231226105540_create_energy_periods.rb rename db/migrate/{20231220151918_create_inverters.rb => 20231227151918_create_inverters.rb} (69%) create mode 100644 db/migrate/20231229001020_create_costs.rb create mode 100644 db/migrate/20231229003253_create_taxes.rb create mode 100644 db/migrate/20231229145024_create_rates.rb create mode 100644 db/migrate/20231229150159_create_countries.rb create mode 100644 db/migrate/20231229153145_create_country_holidays.rb create mode 100644 db/migrate/20231229200236_create_zones_energy_periods.rb create mode 100644 lib/core_extensions/time.rb create mode 100644 test/fixtures/costs.yml create mode 100644 test/fixtures/countries.yml create mode 100644 test/fixtures/country_holidays.yml create mode 100644 test/fixtures/energy_periods.yml delete mode 100644 test/fixtures/energy_price.yml create mode 100644 test/fixtures/energy_prices.yml create mode 100644 test/fixtures/rates.yml delete mode 100644 test/fixtures/settings.yml create mode 100644 test/fixtures/taxes.yml create mode 100644 test/fixtures/zones.yml create mode 100644 test/fixtures/zones_energy_periods.yml create mode 100644 test/models/cost_test.rb create mode 100644 test/models/country_test.rb create mode 100644 test/models/energy_period_test.rb create mode 100644 test/models/holiday_test.rb create mode 100644 test/models/rate_test.rb delete mode 100644 test/models/setting_test.rb create mode 100644 test/models/tax_test.rb create mode 100644 test/models/zone_test.rb diff --git a/.rubocop.yml b/.rubocop.yml index 7d06261..5f27091 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -41,6 +41,8 @@ Minitest/MultipleAssertions: Performance/StringIdentifierArgument: Enabled: false +Rails/CreateTableWithTimestamps: + Enabled: false Rails/HttpStatus: EnforcedStyle: numeric diff --git a/Gemfile b/Gemfile index 4c14d9c..990addd 100644 --- a/Gemfile +++ b/Gemfile @@ -21,10 +21,11 @@ gem "turbo-rails" ## LIBRARIES gem "bootsnap", require: false -gem "clockwork" gem "foreman" +gem "groupdate" gem "http" gem "rmodbus" +gem "rufus-scheduler" gem "solid_queue" gem "sqids" diff --git a/Gemfile.lock b/Gemfile.lock index 09d9880..8fc19b9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -97,9 +97,6 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - clockwork (3.0.2) - activesupport - tzinfo concurrent-ruby (1.2.2) connection_pool (2.4.1) crass (1.0.6) @@ -116,13 +113,20 @@ GEM drb (2.2.0) ruby2_keywords erubi (1.12.0) + et-orbi (1.2.7) + tzinfo ffi (1.16.3) ffi-compiler (1.0.1) ffi (>= 1.0.0) rake foreman (0.87.2) + fugit (1.8.0) + et-orbi (~> 1, >= 1.2.7) + raabro (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) + groupdate (6.4.0) + activesupport (>= 6.1) http (5.1.1) addressable (~> 2.8) http-cookie (~> 1.0) @@ -190,6 +194,7 @@ GEM public_suffix (5.0.3) puma (6.4.0) nio4r (~> 2.0) + raabro (1.4.0) racc (1.7.3) rack (3.0.8) rack-session (2.0.0) @@ -267,6 +272,8 @@ GEM ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) rubyzip (2.3.2) + rufus-scheduler (3.8.2) + fugit (~> 1.1, >= 1.1.6) selenium-webdriver (4.16.0) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) @@ -322,10 +329,10 @@ DEPENDENCIES better_errors bootsnap capybara - clockwork debug dotenv-rails foreman + groupdate http importmap-rails propshaft @@ -337,6 +344,7 @@ DEPENDENCIES rubocop-minitest rubocop-performance rubocop-rails + rufus-scheduler selenium-webdriver solid_queue sqids diff --git a/Procfile b/Procfile index c7ca4a7..2d93768 100644 --- a/Procfile +++ b/Procfile @@ -1,3 +1,3 @@ web: bin/puma -C config/puma.rb job: bin/rails solid_queue:start -clock: bin/clockwork config/clockwork.rb +scheduler: ruby config/scheduler.rb diff --git a/app/aggregations/application_aggregation.rb b/app/aggregations/application_aggregation.rb new file mode 100644 index 0000000..d74f19d --- /dev/null +++ b/app/aggregations/application_aggregation.rb @@ -0,0 +1,28 @@ +class ApplicationAggregation + def initialize(date, archives) + @date = date + @archives = archives + end + + def run + instance = model.find_or_initialize_by(date: @date) + instance.assign_attributes(aggregations) + instance.save! + end + + private + + def aggregations_columns + %i[max maxtime min mintime sum avg] + end + + def aggregations + aggregations_columns.each_with_object({}) do |column, hash| + hash[column] = send(column) if respond_to?(column) + end + end + + def model + "ArchiveDaily#{self.class.name.demodulize}".constantize + end +end diff --git a/app/aggregations/daily_grid_energy_export_aggregation.rb b/app/aggregations/daily_grid_energy_export_aggregation.rb new file mode 100644 index 0000000..eaaed11 --- /dev/null +++ b/app/aggregations/daily_grid_energy_export_aggregation.rb @@ -0,0 +1,31 @@ +class DailyGridEnergyExportAggregation < Base + def max + sum_by_hour.values.max.round(2) + end + + def maxtime + date.to_time.change(hour: sum_by_hour.max_by { |a| a[1] }.first) + end + + def sum + (archives_array.last.grid_energy_export - archives_array.first.grid_energy_export).round(2) + end + + private + + def archives_array + @archives_array ||= archives.to_a + end + + def group_by_hour + @group_by_hour ||= archives_array.group_by do |archive| + archive.created_at.hour + end + end + + def sum_by_hour + @sum_by_hour ||= group_by_hour.transform_values do |archives| + archives.last.grid_energy_export - archives.first.grid_energy_export + end + end +end diff --git a/app/lib/esios/export.rb b/app/lib/esios/export.rb index 5c75ccd..e8c3e4e 100644 --- a/app/lib/esios/export.rb +++ b/app/lib/esios/export.rb @@ -3,9 +3,5 @@ class Export < Indicator def url "https://api.esios.ree.es/indicators/1739" end - - def geo_id - ENV.fetch("ESIOS_COUNTRY_GEO_ID", 3).to_i - end end end diff --git a/app/lib/esios/import.rb b/app/lib/esios/import.rb index b40aa13..42e57a4 100644 --- a/app/lib/esios/import.rb +++ b/app/lib/esios/import.rb @@ -3,9 +3,5 @@ class Import < Indicator def url "https://api.esios.ree.es/indicators/1001" end - - def geo_id - ENV.fetch("ESIOS_ZONE_GEO_ID", 8741).to_i - end end end diff --git a/app/lib/esios/indicator.rb b/app/lib/esios/indicator.rb index 6490992..9faedda 100644 --- a/app/lib/esios/indicator.rb +++ b/app/lib/esios/indicator.rb @@ -2,18 +2,14 @@ module ESIOS class Indicator include MissingSingleton - def for_today - perform_request - end - - def for_date(date) + def for_date(date, geo_id = nil) if date.is_a?(Range) - perform_request( - "start_date" => date.first.beginning_of_day.iso8601, - "end_date" => date.last.end_of_day.iso8601 + new( + "start_date" => date.first.beginning_of_day.iso8601, "end_date" => date.last.end_of_day.iso8601, + "geo_ids[]" => geo_id ) else - perform_request("datetime" => date.iso8601) + perform_request("datetime" => date.iso8601, "geo_ids[]" => geo_id) end end @@ -23,15 +19,11 @@ def base_request HTTP .headers("Accept" => "application/json; application/vnd.esios-api-v2+json") .headers("Content-Type" => "application/json") - .headers("x-api-key" => ENV.fetch("ESIOS_API_KEY")) - end - - def base_params - { "geo_ids[]" => geo_id } + .headers("x-api-key" => ENV.fetch("SOLARIS_ENERGY_PRICE_ESIOS_API_KEY")) end def perform_request(params = {}) - parse_response(base_request.get(url, params: base_params.merge(params))) + parse_response(base_request.get(url, params: params.compact)) end def parse_response(response) @@ -40,7 +32,8 @@ def parse_response(response) (response.dig("indicator", "values") || []).map do |value| { datetime: DateTime.parse(value["datetime"]), - value: (value["value"] / 1000.0).round(4) + value: (value["value"] / 1000.0).round(4), + geo_id: value["geo_id"] } end end diff --git a/app/lib/solaris/daily_archives/grid_energy_import.rb b/app/lib/solaris/archives/grid_energy_import.rb similarity index 100% rename from app/lib/solaris/daily_archives/grid_energy_import.rb rename to app/lib/solaris/archives/grid_energy_import.rb diff --git a/app/lib/solaris/daily_archives/grid_power_export.rb b/app/lib/solaris/archives/grid_power_export.rb similarity index 100% rename from app/lib/solaris/daily_archives/grid_power_export.rb rename to app/lib/solaris/archives/grid_power_export.rb diff --git a/app/lib/solaris/daily_archives/grid_power_import.rb b/app/lib/solaris/archives/grid_power_import.rb similarity index 100% rename from app/lib/solaris/daily_archives/grid_power_import.rb rename to app/lib/solaris/archives/grid_power_import.rb diff --git a/app/lib/solaris/daily_archives/solar_energy.rb b/app/lib/solaris/archives/solar_energy.rb similarity index 100% rename from app/lib/solaris/daily_archives/solar_energy.rb rename to app/lib/solaris/archives/solar_energy.rb diff --git a/app/lib/solaris/daily_archives/solar_power.rb b/app/lib/solaris/archives/solar_power.rb similarity index 100% rename from app/lib/solaris/daily_archives/solar_power.rb rename to app/lib/solaris/archives/solar_power.rb diff --git a/app/lib/solaris/daily_archives/base.rb b/app/lib/solaris/daily_archives/base.rb deleted file mode 100644 index 59356f2..0000000 --- a/app/lib/solaris/daily_archives/base.rb +++ /dev/null @@ -1,34 +0,0 @@ -module Solaris - module DailyArchives - class Base - attr_reader :date, :archives - - def initialize(date, archives) - @date = date - @archives = archives - end - - def run - instance = model.find_or_initialize_by(date: @date) - instance.assign_attributes(aggregations) - instance.save! - end - - private - - def aggregations_columns - %i[max maxtime min mintime sum avg] - end - - def aggregations - aggregations_columns.each_with_object({}) do |column, hash| - hash[column] = send(column) if respond_to?(column) - end - end - - def model - "ArchiveDaily#{self.class.name.demodulize}".constantize - end - end - end -end diff --git a/app/lib/solaris/daily_archives/energy_price_export.rb b/app/lib/solaris/daily_archives/energy_price_export.rb deleted file mode 100644 index 1aab39e..0000000 --- a/app/lib/solaris/daily_archives/energy_price_export.rb +++ /dev/null @@ -1,25 +0,0 @@ -module Solaris - module DailyArchives - class EnergyPriceExport < Base - def max - ::EnergyPrice.by_date(date).maximum(:export) - end - - def maxtime - ::EnergyPrice.by_date(date).where(export: max).first.datetime - end - - def min - ::EnergyPrice.by_date(date).minimum(:export) - end - - def mintime - ::EnergyPrice.by_date(date).where(export: min).first.datetime - end - - def avg - ::EnergyPrice.by_date(date).average(:export).round(4) - end - end - end -end diff --git a/app/lib/solaris/daily_archives/grid_energy_export.rb b/app/lib/solaris/daily_archives/grid_energy_export.rb deleted file mode 100644 index 345fca2..0000000 --- a/app/lib/solaris/daily_archives/grid_energy_export.rb +++ /dev/null @@ -1,35 +0,0 @@ -module Solaris - module DailyArchives - class GridEnergyExport < Base - def max - sum_by_hour.values.max.round(2) - end - - def maxtime - date.to_time.change(hour: sum_by_hour.max_by { |a| a[1] }.first) - end - - def sum - (archives_array.last.grid_energy_export - archives_array.first.grid_energy_export).round(2) - end - - private - - def archives_array - @archives_array ||= archives.to_a - end - - def group_by_hour - @group_by_hour ||= archives_array.group_by do |archive| - archive.created_at.hour - end - end - - def sum_by_hour - @sum_by_hour ||= group_by_hour.transform_values do |archives| - archives.last.grid_energy_export - archives.first.grid_energy_export - end - end - end - end -end diff --git a/app/lib/solaris/pvpcs/daily/export_price.rb b/app/lib/solaris/pvpcs/daily/export_price.rb new file mode 100644 index 0000000..45a6104 --- /dev/null +++ b/app/lib/solaris/pvpcs/daily/export_price.rb @@ -0,0 +1,27 @@ +module Solaris + module PVPCs + module Daily + class ExportPrice < Base + def max + ::EnergyPrice.by_date(date).maximum(:export) + end + + def maxtime + ::EnergyPrice.by_date(date).where(export: max).first.datetime + end + + def min + ::EnergyPrice.by_date(date).minimum(:export) + end + + def mintime + ::EnergyPrice.by_date(date).where(export: min).first.datetime + end + + def avg + ::EnergyPrice.by_date(date).average(:export).round(4) + end + end + end + end +end diff --git a/app/lib/solaris/daily_archives/energy_price_import.rb b/app/lib/solaris/pvpcs/daily/import_price.rb similarity index 100% rename from app/lib/solaris/daily_archives/energy_price_import.rb rename to app/lib/solaris/pvpcs/daily/import_price.rb diff --git a/app/models/archive_daily_energy_price_export.rb b/app/models/archive_daily_energy_price_export.rb deleted file mode 100644 index 448acfd..0000000 --- a/app/models/archive_daily_energy_price_export.rb +++ /dev/null @@ -1,3 +0,0 @@ -class ArchiveDailyEnergyPriceExport < ApplicationRecord - self.table_name = "archive_daily_energy_price_export" -end diff --git a/app/models/archive_daily_energy_price_import.rb b/app/models/archive_daily_energy_price_import.rb deleted file mode 100644 index 8cd4b82..0000000 --- a/app/models/archive_daily_energy_price_import.rb +++ /dev/null @@ -1,3 +0,0 @@ -class ArchiveDailyEnergyPriceImport < ApplicationRecord - self.table_name = "archive_daily_energy_price_import" -end diff --git a/app/models/cost.rb b/app/models/cost.rb new file mode 100644 index 0000000..a60396d --- /dev/null +++ b/app/models/cost.rb @@ -0,0 +1,18 @@ +class Cost < ApplicationRecord + belongs_to :country + + validates :start_at, presence: true + validates :transport_toll_p1, presence: true + validates :distribution_toll_p1, presence: true + validates :charges_p1, presence: true + validates :transport_toll_p2, presence: true + validates :distribution_toll_p2, presence: true + validates :charges_p2, presence: true + validates :transport_toll_p3, presence: true + validates :distribution_toll_p3, presence: true + validates :charges_p3, presence: true + + def self.for_time(time) + where('start_at <= ?', time).order(start_at: :desc).first + end +end diff --git a/app/models/country.rb b/app/models/country.rb new file mode 100644 index 0000000..bac469f --- /dev/null +++ b/app/models/country.rb @@ -0,0 +1,11 @@ +class Country < ApplicationRecord + has_many :costs, dependent: :destroy + has_many :zones, dependent: :destroy + has_many :holidays, class_name: 'CountryHoliday', dependent: :destroy + + validates :code, presence: true, uniqueness: true + validates :name, presence: true + validates :p1_name, presence: true + validates :p2_name, presence: true + validates :p3_name, presence: true +end diff --git a/app/models/country_holiday.rb b/app/models/country_holiday.rb new file mode 100644 index 0000000..d2ee928 --- /dev/null +++ b/app/models/country_holiday.rb @@ -0,0 +1,6 @@ +class CountryHoliday < ApplicationRecord + belongs_to :country + + validates :name, presence: true + validates :date, presence: true, uniqueness: { scope: :country_id } +end diff --git a/app/models/daily_energy_export_price.rb b/app/models/daily_energy_export_price.rb new file mode 100644 index 0000000..18cf601 --- /dev/null +++ b/app/models/daily_energy_export_price.rb @@ -0,0 +1,2 @@ +class DailyEnergyExportPrice < ApplicationRecord +end diff --git a/app/models/daily_energy_import_price.rb b/app/models/daily_energy_import_price.rb new file mode 100644 index 0000000..3c84da0 --- /dev/null +++ b/app/models/daily_energy_import_price.rb @@ -0,0 +1,2 @@ +class DailyEnergyImportPrice < ApplicationRecord +end diff --git a/app/models/energy_period.rb b/app/models/energy_period.rb new file mode 100644 index 0000000..30263e5 --- /dev/null +++ b/app/models/energy_period.rb @@ -0,0 +1,14 @@ +class EnergyPeriod < ApplicationRecord + has_and_belongs_to_many :zones, join_table: :zones_energy_periods + + enum :name, %i[p1 p2 p3].to_enum_hash + + validates :start_hour, presence: true + validates :end_hour, presence: true + validates :name, presence: true + + # TODO, this is not working with new format + def self.kind_for(time, zone) + where(zone: zone, day_type: time.day_type).where('start_hour <= ? AND end_hour >= ?', time.hour, time.hour).sole.name + end +end diff --git a/app/models/energy_price.rb b/app/models/energy_price.rb index e9781fc..67ff977 100644 --- a/app/models/energy_price.rb +++ b/app/models/energy_price.rb @@ -1,5 +1,15 @@ class EnergyPrice < ApplicationRecord - self.table_name = "energy_price" + self.store_full_sti_class = false - scope :by_date, ->(date) { where(datetime: date.all_day).order(datetime: :asc) } + belongs_to :zone + + scope :by_date, ->(date) { where(time: date.all_day).order(time: :asc) } + + validates :datetime, uniqueness: { scope: %i[type zone_id] } + validates :import, presence: true, numericality: true + validates :export, presence: true, numericality: true + + def self.load(date, zone) + create!({ import: import(date, zone) || [], export: export(date, zone) || [] }) + end end diff --git a/app/models/energy_prices/pvpc.rb b/app/models/energy_prices/pvpc.rb new file mode 100644 index 0000000..7e30067 --- /dev/null +++ b/app/models/energy_prices/pvpc.rb @@ -0,0 +1,11 @@ +module EnergyPrices + class PVPC < EnergyPrice + def self.import(date, zone) + ::ESIOS::Import.for_date(date, zone) + end + + def self.export(date, zone) + ::ESIOS::Export.for_date(date, zone) + end + end +end diff --git a/app/models/inverter.rb b/app/models/inverter.rb index 8d84750..7c0bc94 100644 --- a/app/models/inverter.rb +++ b/app/models/inverter.rb @@ -1,8 +1,13 @@ class Inverter < ApplicationRecord include Sqideable + enum :installation_type, %i[domestic other].to_enum_hash + belongs_to :protocol + belongs_to :zone + + has_many :rates, dependent: :destroy validates :name, presence: true - validates :timezone, presence: true + validates :installation_type, presence: true end diff --git a/app/models/rate.rb b/app/models/rate.rb new file mode 100644 index 0000000..e5d51c6 --- /dev/null +++ b/app/models/rate.rb @@ -0,0 +1,5 @@ +class Rate < ApplicationRecord + belongs_to :inverter + + validates :start_at, presence: true, uniqueness: { scope: :inverter_id } +end diff --git a/app/models/rates/by_period.rb b/app/models/rates/by_period.rb new file mode 100644 index 0000000..8de14ff --- /dev/null +++ b/app/models/rates/by_period.rb @@ -0,0 +1,4 @@ +module Rates + class ByPeriod < Rate + end +end diff --git a/app/models/rates/fixed.rb b/app/models/rates/fixed.rb new file mode 100644 index 0000000..9ce8ee2 --- /dev/null +++ b/app/models/rates/fixed.rb @@ -0,0 +1,4 @@ +module Rates + class Fixed < Rate + end +end diff --git a/app/models/rates/pvpc.rb b/app/models/rates/pvpc.rb new file mode 100644 index 0000000..1e08a3d --- /dev/null +++ b/app/models/rates/pvpc.rb @@ -0,0 +1,4 @@ +module Rates + class PVPC < Rate + end +end diff --git a/app/models/setting.rb b/app/models/setting.rb deleted file mode 100644 index a8690ea..0000000 --- a/app/models/setting.rb +++ /dev/null @@ -1,26 +0,0 @@ -class Setting < ApplicationRecord - thread_mattr_accessor :_instance, instance_accessor: false - - enum :energy_price, %i[esios].to_enum_hash - enum :inverter, %i[huawei].to_enum_hash - - validates :timezone, presence: true - validates :loop_interval, presence: true, numericality: { only_integer: true, greater_than: 0 } - validates :archive_interval, presence: true, numericality: { only_integer: true, greater_than: 0 } - - with_options presence: true, if: :esios? do - validates :energy_price_at - validates :esios_api_key - validates :esios_zone - validates :esios_country - end - - with_options presence: true, if: :huawei? do - validates :huawei_ip - validates :huawei_port, numericality: { only_integer: true, greater_than: 0 } - end - - def self.instance - self._instance ||= lock.first_or_create! - end -end diff --git a/app/models/tax.rb b/app/models/tax.rb new file mode 100644 index 0000000..129336b --- /dev/null +++ b/app/models/tax.rb @@ -0,0 +1,15 @@ +class Tax < ApplicationRecord + enum :kind, %i[value_add other].to_enum_hash, prefix: true + enum :installation_type, %i[domestic other].to_enum_hash, prefix: true + + belongs_to :zone + + validates :installation_type, presence: true + validates :start_at, presence: true + validates :name, presence: true + validates :percentage, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 } + + def self.for_time_and_zone(time, zone) + where(zone: zone).where('start_at <= ?', time).order(start_at: :desc).first # TODO, puede haber varios impuestos + end +end diff --git a/app/models/zone.rb b/app/models/zone.rb new file mode 100644 index 0000000..5df516b --- /dev/null +++ b/app/models/zone.rb @@ -0,0 +1,14 @@ +class Zone < ApplicationRecord + belongs_to :country + + has_many :energy_periods, dependent: :destroy + has_many :pvpc, dependent: :destroy + + has_and_belongs_to_many :energy_periods, join_table: :zones_energy_periods + + validates :name, presence: true, uniqueness: true + validates :timezone, presence: true + validates :configuration, presence: true + + scope :with_pvpc, -> { where("configuration LIKE ?", "%pvpc\":true%") } +end diff --git a/config/application.rb b/config/application.rb index 31894c8..a86bfdb 100644 --- a/config/application.rb +++ b/config/application.rb @@ -30,6 +30,6 @@ class Application < Rails::Application # # config.time_zone = "Central Time (US & Canada)" # config.eager_load_paths << Rails.root.join("extras") - config.time_zone = ENV.fetch("SOLARIS_TIMEZONE", "Europe/Madrid").to_s + config.time_zone = "UTC" end end diff --git a/config/clockwork.rb b/config/clockwork.rb deleted file mode 100644 index d2b5138..0000000 --- a/config/clockwork.rb +++ /dev/null @@ -1,20 +0,0 @@ -require_relative "environment" - -module Clockwork - configure do |config| - config[:tz] = ENV.fetch("SOLARIS_TIMEZONE", "Europe/Madrid").to_s - end - - every(ENV.fetch("SOLARIS_LOOP_INTERVAL", 30).to_i.seconds, "solaris.loop", thread: true) do - Solaris::Loop.run - end - - every(1.day, "solaris.energy_price", at: ENV.fetch("SOLARIS_ENERGY_PRICE_AT", "21:00").to_s, thread: true) do - price_for = ENV.fetch("SOLARIS_ENERGY_PRICE_FOR", "tomorrow").to_s - Solaris::EnergyPrice.store(price_for == "tomorrow" ? Date.tomorrow : Date.current) - end - - every(1.day, "solaris.archive.daily", at: "00:01", thread: true) do - Solaris::DailyArchive.run - end -end diff --git a/config/initializers/core_extensions.rb b/config/initializers/core_extensions.rb index affcee7..1b760ea 100644 --- a/config/initializers/core_extensions.rb +++ b/config/initializers/core_extensions.rb @@ -1 +1,2 @@ require "core_extensions/array" +require "core_extensions/time" diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index b1a54fc..5f3981f 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -12,4 +12,5 @@ ActiveSupport::Inflector.inflections(:en) do |inflect| inflect.acronym "ESIOS" + inflect.acronym "PVPC" end diff --git a/config/scheduler.rb b/config/scheduler.rb new file mode 100644 index 0000000..9f8d804 --- /dev/null +++ b/config/scheduler.rb @@ -0,0 +1,18 @@ +require_relative "environment" + +scheduler = Rufus::Scheduler.new +loop_interval = ENV.fetch("SOLARIS_LOOP_INTERVAL", 30).to_i + +scheduler.every loop_interval, name: "solaris.loop", first_at: Time.current.beginning_of_minute + 1.minute do + Solaris::Loop.run +end + +scheduler.cron "0 21 * * * Europe/Madrid", name: "solaris.energy_prices.esios_pvpc" do + Solaris::EnergyPrice.store(Date.tomorrow) +end + +scheduler.cron "1 0 * * * #{tz}", name: "solaris.archive.daily" do + Solaris::DailyArchive.run +end + +scheduler.join diff --git a/db/migrate/20230805145711_create_energy_price.rb b/db/migrate/20230805145711_create_energy_price.rb deleted file mode 100644 index 430db9f..0000000 --- a/db/migrate/20230805145711_create_energy_price.rb +++ /dev/null @@ -1,10 +0,0 @@ -class CreateEnergyPrice < ActiveRecord::Migration[7.1] - def change - # rubocop:disable Rails/CreateTableWithTimestamps - create_table :energy_price, id: :datetime, primary_key: :datetime do |t| - t.float :import - t.float :export - end - # rubocop:enable Rails/CreateTableWithTimestamps - end -end diff --git a/db/migrate/20230805174919_create_archive.rb b/db/migrate/20230805174919_create_archive.rb index 0e1ae60..7f3e428 100644 --- a/db/migrate/20230805174919_create_archive.rb +++ b/db/migrate/20230805174919_create_archive.rb @@ -1,14 +1,11 @@ class CreateArchive < ActiveRecord::Migration[7.1] def change - # rubocop:disable Rails/CreateTableWithTimestamps create_table :archive, id: :datetime, primary_key: :created_at do |t| - t.float :solar_power, null: false - t.float :solar_energy, null: false - t.float :temperature, null: false - t.float :grid_power, null: false - t.float :grid_energy_export, null: false - t.float :grid_energy_import, null: false + t.integer :solar_power, null: false + t.decimal :solar_energy, precision: 4, scale: 2, null: false + t.integer :grid_power, null: false + t.decimal :grid_energy_export, precision: 8, scale: 2, null: false + t.decimal :grid_energy_import, precision: 8, scale: 2, null: false end - # rubocop:enable Rails/CreateTableWithTimestamps end end diff --git a/db/migrate/20230806183244_create_archive_daily_solar_power.rb b/db/migrate/20230806183244_create_archive_daily_solar_power.rb index ee2c29b..ba8e443 100644 --- a/db/migrate/20230806183244_create_archive_daily_solar_power.rb +++ b/db/migrate/20230806183244_create_archive_daily_solar_power.rb @@ -1,10 +1,8 @@ class CreateArchiveDailySolarPower < ActiveRecord::Migration[7.1] def change - # rubocop:disable Rails/CreateTableWithTimestamps create_table :archive_daily_solar_power, id: :date, primary_key: :date do |t| - t.float :max, null: false + t.integer :max, null: false t.datetime :maxtime, null: false end - # rubocop:enable Rails/CreateTableWithTimestamps end end diff --git a/db/migrate/20230807072241_create_archive_daily_solar_energy.rb b/db/migrate/20230807072241_create_archive_daily_solar_energy.rb index c9517c8..f171f43 100644 --- a/db/migrate/20230807072241_create_archive_daily_solar_energy.rb +++ b/db/migrate/20230807072241_create_archive_daily_solar_energy.rb @@ -1,11 +1,9 @@ class CreateArchiveDailySolarEnergy < ActiveRecord::Migration[7.1] def change - # rubocop:disable Rails/CreateTableWithTimestamps create_table :archive_daily_solar_energy, id: :date, primary_key: :date do |t| - t.float :max, null: false + t.decimal :max, precision: 4, scale: 2, null: false t.datetime :maxtime, null: false - t.float :sum, null: false + t.decimal :sum, precision: 8, scale: 2, null: false end - # rubocop:enable Rails/CreateTableWithTimestamps end end diff --git a/db/migrate/20230807181438_create_archive_daily_grid_power_export.rb b/db/migrate/20230807181438_create_archive_daily_grid_power_export.rb index 020d73d..c852741 100644 --- a/db/migrate/20230807181438_create_archive_daily_grid_power_export.rb +++ b/db/migrate/20230807181438_create_archive_daily_grid_power_export.rb @@ -1,10 +1,8 @@ class CreateArchiveDailyGridPowerExport < ActiveRecord::Migration[7.1] def change - # rubocop:disable Rails/CreateTableWithTimestamps create_table :archive_daily_grid_power_export, id: :date, primary_key: :date do |t| - t.float :max, null: false - t.datetime :maxtime + t.integer :max, null: false + t.datetime :maxtime, null: false end - # rubocop:enable Rails/CreateTableWithTimestamps end end diff --git a/db/migrate/20230807181440_create_archive_daily_grid_power_import.rb b/db/migrate/20230807181440_create_archive_daily_grid_power_import.rb index 2585a72..b85907f 100644 --- a/db/migrate/20230807181440_create_archive_daily_grid_power_import.rb +++ b/db/migrate/20230807181440_create_archive_daily_grid_power_import.rb @@ -1,10 +1,8 @@ class CreateArchiveDailyGridPowerImport < ActiveRecord::Migration[7.1] def change - # rubocop:disable Rails/CreateTableWithTimestamps create_table :archive_daily_grid_power_import, id: :date, primary_key: :date do |t| - t.float :max, null: false - t.datetime :maxtime + t.integer :max, null: false + t.datetime :maxtime, null: false end - # rubocop:enable Rails/CreateTableWithTimestamps end end diff --git a/db/migrate/20230807181444_create_archive_daily_grid_energy_import.rb b/db/migrate/20230807181444_create_archive_daily_grid_energy_import.rb index c8d1d57..14b2b47 100644 --- a/db/migrate/20230807181444_create_archive_daily_grid_energy_import.rb +++ b/db/migrate/20230807181444_create_archive_daily_grid_energy_import.rb @@ -1,11 +1,9 @@ class CreateArchiveDailyGridEnergyImport < ActiveRecord::Migration[7.1] def change - # rubocop:disable Rails/CreateTableWithTimestamps create_table :archive_daily_grid_energy_import, id: :date, primary_key: :date do |t| - t.float :max, null: false + t.decimal :max, precision: 8, scale: 2, null: false t.datetime :maxtime, null: false - t.float :sum, null: false + t.decimal :sum, precision: 8, scale: 2, null: false end - # rubocop:enable Rails/CreateTableWithTimestamps end end diff --git a/db/migrate/20230807182537_create_archive_daily_grid_energy_export.rb b/db/migrate/20230807182537_create_archive_daily_grid_energy_export.rb index 507d74c..b98d771 100644 --- a/db/migrate/20230807182537_create_archive_daily_grid_energy_export.rb +++ b/db/migrate/20230807182537_create_archive_daily_grid_energy_export.rb @@ -1,11 +1,9 @@ class CreateArchiveDailyGridEnergyExport < ActiveRecord::Migration[7.1] def change - # rubocop:disable Rails/CreateTableWithTimestamps create_table :archive_daily_grid_energy_export, id: :date, primary_key: :date do |t| - t.float :max, null: false + t.decimal :max, precision: 8, scale: 2, null: false t.datetime :maxtime, null: false - t.float :sum, null: false + t.decimal :sum, precision: 8, scale: 2, null: false end - # rubocop:enable Rails/CreateTableWithTimestamps end end diff --git a/db/migrate/20230808184043_create_archive_daily_energy_price_import.rb b/db/migrate/20230808184043_create_archive_daily_energy_price_import.rb deleted file mode 100644 index 20d459a..0000000 --- a/db/migrate/20230808184043_create_archive_daily_energy_price_import.rb +++ /dev/null @@ -1,13 +0,0 @@ -class CreateArchiveDailyEnergyPriceImport < ActiveRecord::Migration[7.1] - def change - # rubocop:disable Rails/CreateTableWithTimestamps - create_table :archive_daily_energy_price_import, id: :date, primary_key: :date do |t| - t.float :max, null: false - t.datetime :maxtime, null: false - t.float :min, null: false - t.datetime :mintime, null: false - t.float :avg, null: false - end - # rubocop:enable Rails/CreateTableWithTimestamps - end -end diff --git a/db/migrate/20230808185034_create_archive_daily_energy_price_export.rb b/db/migrate/20230808185034_create_archive_daily_energy_price_export.rb deleted file mode 100644 index f1bc270..0000000 --- a/db/migrate/20230808185034_create_archive_daily_energy_price_export.rb +++ /dev/null @@ -1,13 +0,0 @@ -class CreateArchiveDailyEnergyPriceExport < ActiveRecord::Migration[7.1] - def change - # rubocop:disable Rails/CreateTableWithTimestamps - create_table :archive_daily_energy_price_export, id: :date, primary_key: :date do |t| - t.float :max, null: false - t.datetime :maxtime, null: false - t.float :min, null: false - t.datetime :mintime, null: false - t.float :avg, null: false - end - # rubocop:enable Rails/CreateTableWithTimestamps - end -end diff --git a/db/migrate/20231031072840_create_settings.rb b/db/migrate/20231031072840_create_settings.rb deleted file mode 100644 index 32c194a..0000000 --- a/db/migrate/20231031072840_create_settings.rb +++ /dev/null @@ -1,18 +0,0 @@ -class CreateSettings < ActiveRecord::Migration[7.1] - def change - create_table :settings do |t| - t.timestamps null: false - t.string :timezone, default: "Europe/Madrid" - t.integer :loop_interval, default: 30 - t.integer :archive_interval, default: 60 - t.string :energy_price - t.string :energy_price_at - t.string :esios_api_key - t.string :esios_zone - t.string :esios_country - t.string :inverter - t.string :huawei_ip - t.integer :huawei_port - end - end -end diff --git a/db/migrate/20231224202745_create_zones.rb b/db/migrate/20231224202745_create_zones.rb new file mode 100644 index 0000000..17599bc --- /dev/null +++ b/db/migrate/20231224202745_create_zones.rb @@ -0,0 +1,12 @@ +class CreateZones < ActiveRecord::Migration[7.1] + def change + create_table :zones do |t| + t.timestamps null: false + t.string :name, null: false + t.references :country, null: false, foreign_key: true + t.string :timezone, null: false + t.json :configuration, null: false, default: {} + t.index :name, unique: true + end + end +end diff --git a/db/migrate/20231224203015_create_energy_prices.rb b/db/migrate/20231224203015_create_energy_prices.rb new file mode 100644 index 0000000..9895214 --- /dev/null +++ b/db/migrate/20231224203015_create_energy_prices.rb @@ -0,0 +1,12 @@ +class CreateEnergyPrices < ActiveRecord::Migration[7.1] + def change + create_table :energy_prices, id: false do |t| + t.string :type, null: false + t.references :zone, null: false, foreign_key: true + t.datetime :datetime, null: false + t.decimal :import, precision: 8, scale: 6, null: false + t.decimal :export, precision: 8, scale: 6, null: false + t.index %i[type zone_id datetime], unique: true + end + end +end diff --git a/db/migrate/20231224203523_create_daily_energy_import_prices.rb b/db/migrate/20231224203523_create_daily_energy_import_prices.rb new file mode 100644 index 0000000..b85a85d --- /dev/null +++ b/db/migrate/20231224203523_create_daily_energy_import_prices.rb @@ -0,0 +1,15 @@ +class CreateDailyEnergyImportPrices < ActiveRecord::Migration[7.1] + def change + create_table :daily_energy_import_prices, id: false do |t| + t.string :type, null: false + t.references :zone, null: false, foreign_key: true + t.date :date, null: false + t.decimal :max, precision: 8, scale: 6, null: false + t.datetime :maxtime, null: false + t.decimal :min, precision: 8, scale: 6, null: false + t.datetime :mintime, null: false + t.decimal :avg, precision: 8, scale: 6, null: false + t.index %i[type zone_id date], unique: true + end + end +end diff --git a/db/migrate/20231224203754_create_daily_energy_export_prices.rb b/db/migrate/20231224203754_create_daily_energy_export_prices.rb new file mode 100644 index 0000000..78627f6 --- /dev/null +++ b/db/migrate/20231224203754_create_daily_energy_export_prices.rb @@ -0,0 +1,15 @@ +class CreateDailyEnergyExportPrices < ActiveRecord::Migration[7.1] + def change + create_table :daily_energy_export_prices, id: false do |t| + t.string :type, null: false + t.references :zone, null: false, foreign_key: true + t.date :date, null: false + t.decimal :max, precision: 8, scale: 6, null: false + t.datetime :maxtime, null: false + t.decimal :min, precision: 8, scale: 6, null: false + t.datetime :mintime, null: false + t.decimal :avg, precision: 8, scale: 6, null: false + t.index %i[type zone_id date], unique: true + end + end +end diff --git a/db/migrate/20231226105540_create_energy_periods.rb b/db/migrate/20231226105540_create_energy_periods.rb new file mode 100644 index 0000000..efe9fb2 --- /dev/null +++ b/db/migrate/20231226105540_create_energy_periods.rb @@ -0,0 +1,18 @@ +class CreateEnergyPeriods < ActiveRecord::Migration[7.1] + def change + create_table :energy_periods do |t| + t.timestamps null: false + t.boolean :monday, null: false, default: false + t.boolean :tuesday, null: false, default: false + t.boolean :wednesday, null: false, default: false + t.boolean :thursday, null: false, default: false + t.boolean :friday, null: false, default: false + t.boolean :saturday, null: false, default: false + t.boolean :sunday, null: false, default: false + t.boolean :holiday, null: false, default: false + t.integer :start_hour, null: false + t.integer :end_hour, null: false + t.string :name, null: false + end + end +end diff --git a/db/migrate/20231220151918_create_inverters.rb b/db/migrate/20231227151918_create_inverters.rb similarity index 69% rename from db/migrate/20231220151918_create_inverters.rb rename to db/migrate/20231227151918_create_inverters.rb index ec8f8c2..a8687d2 100644 --- a/db/migrate/20231220151918_create_inverters.rb +++ b/db/migrate/20231227151918_create_inverters.rb @@ -3,14 +3,14 @@ def change create_table :inverters do |t| t.timestamps null: false t.string :name, null: false + t.string :installation_type, null: false + t.references :zone, null: false, foreign_key: true t.references :protocol, null: false, foreign_key: true - t.string :timezone, null: false - t.integer :loop_interval, null: false, default: 60 - t.integer :archive_interval, null: false, default: 300 t.string :brand t.string :model t.string :serial_number t.string :firmware_version + t.datetime :viewed_at end end end diff --git a/db/migrate/20231229001020_create_costs.rb b/db/migrate/20231229001020_create_costs.rb new file mode 100644 index 0000000..587adad --- /dev/null +++ b/db/migrate/20231229001020_create_costs.rb @@ -0,0 +1,18 @@ +class CreateCosts < ActiveRecord::Migration[7.1] + def change + create_table :costs do |t| + t.timestamps null: false + t.references :country, null: false, foreign_key: true + t.datetime :start_at, null: false + t.decimal :transport_toll_p1, precision: 8, scale: 6, null: false + t.decimal :distribution_toll_p1, precision: 8, scale: 6, null: false + t.decimal :charges_p1, precision: 8, scale: 6, null: false + t.decimal :transport_toll_p2, precision: 8, scale: 6, null: false + t.decimal :distribution_toll_p2, precision: 8, scale: 6, null: false + t.decimal :charges_p2, precision: 8, scale: 6, null: false + t.decimal :transport_toll_p3, precision: 8, scale: 6, null: false + t.decimal :distribution_toll_p3, precision: 8, scale: 6, null: false + t.decimal :charges_p3, precision: 8, scale: 6, null: false + end + end +end diff --git a/db/migrate/20231229003253_create_taxes.rb b/db/migrate/20231229003253_create_taxes.rb new file mode 100644 index 0000000..1174336 --- /dev/null +++ b/db/migrate/20231229003253_create_taxes.rb @@ -0,0 +1,13 @@ +class CreateTaxes < ActiveRecord::Migration[7.1] + def change + create_table :taxes do |t| + t.timestamps null: false + t.references :zone, null: false, foreign_key: true + t.string :kind, null: false + t.string :installation_type, null: false + t.datetime :start_at, null: false + t.string :name, null: false + t.decimal :percentage, precision: 12, scale: 10, null: false + end + end +end diff --git a/db/migrate/20231229145024_create_rates.rb b/db/migrate/20231229145024_create_rates.rb new file mode 100644 index 0000000..9316f0e --- /dev/null +++ b/db/migrate/20231229145024_create_rates.rb @@ -0,0 +1,14 @@ +class CreateRates < ActiveRecord::Migration[7.1] + def change + create_table :rates do |t| + t.timestamps null: false + t.references :inverter, null: false, foreign_key: true + t.string :type, null: false + t.datetime :start_at, null: false + t.decimal :p1, precision: 8, scale: 6 + t.decimal :p2, precision: 8, scale: 6 + t.decimal :p3, precision: 8, scale: 6 + t.index %i[inverter_id start_at], unique: true + end + end +end diff --git a/db/migrate/20231229150159_create_countries.rb b/db/migrate/20231229150159_create_countries.rb new file mode 100644 index 0000000..1944be0 --- /dev/null +++ b/db/migrate/20231229150159_create_countries.rb @@ -0,0 +1,13 @@ +class CreateCountries < ActiveRecord::Migration[7.1] + def change + create_table :countries do |t| + t.timestamps null: false + t.string :code, null: false + t.string :name, null: false + t.string :p1_name, null: false + t.string :p2_name, null: false + t.string :p3_name, null: false + t.index :code, unique: true + end + end +end diff --git a/db/migrate/20231229153145_create_country_holidays.rb b/db/migrate/20231229153145_create_country_holidays.rb new file mode 100644 index 0000000..88f2ea1 --- /dev/null +++ b/db/migrate/20231229153145_create_country_holidays.rb @@ -0,0 +1,11 @@ +class CreateCountryHolidays < ActiveRecord::Migration[7.1] + def change + create_table :country_holidays do |t| + t.timestamps null: false + t.references :country, null: false, foreign_key: true + t.string :name, null: false + t.date :date, null: false + t.index %i[country_id date], unique: true + end + end +end diff --git a/db/migrate/20231229200236_create_zones_energy_periods.rb b/db/migrate/20231229200236_create_zones_energy_periods.rb new file mode 100644 index 0000000..591031b --- /dev/null +++ b/db/migrate/20231229200236_create_zones_energy_periods.rb @@ -0,0 +1,9 @@ +class CreateZonesEnergyPeriods < ActiveRecord::Migration[7.1] + def change + create_table :zones_energy_periods, id: false do |t| + t.references :zone, null: false, foreign_key: true + t.references :energy_period, null: false, foreign_key: true + t.index %i[energy_period_id zone_id], unique: true + end + end +end diff --git a/db/schema.rb b/db/schema.rb index a36150c..f71020f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,83 +10,152 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2023_12_24_131910) do +ActiveRecord::Schema[7.1].define(version: 2023_12_29_200236) do create_table "archive", primary_key: "created_at", id: :datetime, force: :cascade do |t| - t.float "solar_power", null: false - t.float "solar_energy", null: false - t.float "temperature", null: false - t.float "grid_power", null: false - t.float "grid_energy_export", null: false - t.float "grid_energy_import", null: false - end - - create_table "archive_daily_energy_price_export", primary_key: "date", id: :date, force: :cascade do |t| - t.float "max", null: false - t.datetime "maxtime", null: false - t.float "min", null: false - t.datetime "mintime", null: false - t.float "avg", null: false - end - - create_table "archive_daily_energy_price_import", primary_key: "date", id: :date, force: :cascade do |t| - t.float "max", null: false - t.datetime "maxtime", null: false - t.float "min", null: false - t.datetime "mintime", null: false - t.float "avg", null: false + t.integer "solar_power", null: false + t.decimal "solar_energy", precision: 4, scale: 2, null: false + t.integer "grid_power", null: false + t.decimal "grid_energy_export", precision: 8, scale: 2, null: false + t.decimal "grid_energy_import", precision: 8, scale: 2, null: false end create_table "archive_daily_grid_energy_export", primary_key: "date", id: :date, force: :cascade do |t| - t.float "max", null: false + t.decimal "max", precision: 8, scale: 2, null: false t.datetime "maxtime", null: false - t.float "sum", null: false + t.decimal "sum", precision: 8, scale: 2, null: false end create_table "archive_daily_grid_energy_import", primary_key: "date", id: :date, force: :cascade do |t| - t.float "max", null: false + t.decimal "max", precision: 8, scale: 2, null: false t.datetime "maxtime", null: false - t.float "sum", null: false + t.decimal "sum", precision: 8, scale: 2, null: false end create_table "archive_daily_grid_power_export", primary_key: "date", id: :date, force: :cascade do |t| - t.float "max", null: false - t.datetime "maxtime" + t.integer "max", null: false + t.datetime "maxtime", null: false end create_table "archive_daily_grid_power_import", primary_key: "date", id: :date, force: :cascade do |t| - t.float "max", null: false - t.datetime "maxtime" + t.integer "max", null: false + t.datetime "maxtime", null: false end create_table "archive_daily_solar_energy", primary_key: "date", id: :date, force: :cascade do |t| - t.float "max", null: false + t.decimal "max", precision: 4, scale: 2, null: false t.datetime "maxtime", null: false - t.float "sum", null: false + t.decimal "sum", precision: 8, scale: 2, null: false end create_table "archive_daily_solar_power", primary_key: "date", id: :date, force: :cascade do |t| - t.float "max", null: false + t.integer "max", null: false + t.datetime "maxtime", null: false + end + + create_table "costs", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "country_id", null: false + t.datetime "start_at", null: false + t.decimal "transport_toll_p1", precision: 8, scale: 6, null: false + t.decimal "distribution_toll_p1", precision: 8, scale: 6, null: false + t.decimal "charges_p1", precision: 8, scale: 6, null: false + t.decimal "transport_toll_p2", precision: 8, scale: 6, null: false + t.decimal "distribution_toll_p2", precision: 8, scale: 6, null: false + t.decimal "charges_p2", precision: 8, scale: 6, null: false + t.decimal "transport_toll_p3", precision: 8, scale: 6, null: false + t.decimal "distribution_toll_p3", precision: 8, scale: 6, null: false + t.decimal "charges_p3", precision: 8, scale: 6, null: false + t.index ["country_id"], name: "index_costs_on_country_id" + end + + create_table "countries", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "code", null: false + t.string "name", null: false + t.string "p1_name", null: false + t.string "p2_name", null: false + t.string "p3_name", null: false + t.index ["code"], name: "index_countries_on_code", unique: true + end + + create_table "country_holidays", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "country_id", null: false + t.string "name", null: false + t.date "date", null: false + t.index ["country_id", "date"], name: "index_country_holidays_on_country_id_and_date", unique: true + t.index ["country_id"], name: "index_country_holidays_on_country_id" + end + + create_table "daily_energy_export_prices", id: false, force: :cascade do |t| + t.string "type", null: false + t.integer "zone_id", null: false + t.date "date", null: false + t.decimal "max", precision: 8, scale: 6, null: false t.datetime "maxtime", null: false + t.decimal "min", precision: 8, scale: 6, null: false + t.datetime "mintime", null: false + t.decimal "avg", precision: 8, scale: 6, null: false + t.index ["type", "zone_id", "date"], name: "index_daily_energy_export_prices_on_type_and_zone_id_and_date", unique: true + t.index ["zone_id"], name: "index_daily_energy_export_prices_on_zone_id" end - create_table "energy_price", primary_key: "datetime", id: :datetime, force: :cascade do |t| - t.float "import" - t.float "export" + create_table "daily_energy_import_prices", id: false, force: :cascade do |t| + t.string "type", null: false + t.integer "zone_id", null: false + t.date "date", null: false + t.decimal "max", precision: 8, scale: 6, null: false + t.datetime "maxtime", null: false + t.decimal "min", precision: 8, scale: 6, null: false + t.datetime "mintime", null: false + t.decimal "avg", precision: 8, scale: 6, null: false + t.index ["type", "zone_id", "date"], name: "index_daily_energy_import_prices_on_type_and_zone_id_and_date", unique: true + t.index ["zone_id"], name: "index_daily_energy_import_prices_on_zone_id" + end + + create_table "energy_periods", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "monday", default: false, null: false + t.boolean "tuesday", default: false, null: false + t.boolean "wednesday", default: false, null: false + t.boolean "thursday", default: false, null: false + t.boolean "friday", default: false, null: false + t.boolean "saturday", default: false, null: false + t.boolean "sunday", default: false, null: false + t.boolean "holiday", default: false, null: false + t.integer "start_hour", null: false + t.integer "end_hour", null: false + t.string "name", null: false + end + + create_table "energy_prices", id: false, force: :cascade do |t| + t.string "type", null: false + t.integer "zone_id", null: false + t.datetime "datetime", null: false + t.decimal "import", precision: 8, scale: 6, null: false + t.decimal "export", precision: 8, scale: 6, null: false + t.index ["type", "zone_id", "datetime"], name: "index_energy_prices_on_type_and_zone_id_and_datetime", unique: true + t.index ["zone_id"], name: "index_energy_prices_on_zone_id" end create_table "inverters", force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "name", null: false + t.string "installation_type", null: false + t.integer "zone_id", null: false t.integer "protocol_id", null: false - t.string "timezone", null: false - t.integer "loop_interval", default: 60, null: false - t.integer "archive_interval", default: 300, null: false t.string "brand" t.string "model" t.string "serial_number" t.string "firmware_version" + t.datetime "viewed_at" t.index ["protocol_id"], name: "index_inverters_on_protocol_id" + t.index ["zone_id"], name: "index_inverters_on_zone_id" end create_table "protocols", force: :cascade do |t| @@ -105,20 +174,17 @@ t.index ["name"], name: "index_protocols_on_name", unique: true end - create_table "settings", force: :cascade do |t| + create_table "rates", force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.string "timezone", default: "Europe/Madrid" - t.integer "loop_interval", default: 30 - t.integer "archive_interval", default: 60 - t.string "energy_price" - t.string "energy_price_at" - t.string "esios_api_key" - t.string "esios_zone" - t.string "esios_country" - t.string "inverter" - t.string "huawei_ip" - t.integer "huawei_port" + t.integer "inverter_id", null: false + t.string "type", null: false + t.datetime "start_at", null: false + t.decimal "p1", precision: 8, scale: 6 + t.decimal "p2", precision: 8, scale: 6 + t.decimal "p3", precision: 8, scale: 6 + t.index ["inverter_id", "start_at"], name: "index_rates_on_inverter_id_and_start_at", unique: true + t.index ["inverter_id"], name: "index_rates_on_inverter_id" end create_table "solid_queue_blocked_executions", force: :cascade do |t| @@ -214,10 +280,52 @@ t.index ["key"], name: "index_solid_queue_semaphores_on_key", unique: true end + create_table "taxes", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "zone_id", null: false + t.string "kind", null: false + t.string "installation_type", null: false + t.datetime "start_at", null: false + t.string "name", null: false + t.decimal "percentage", precision: 12, scale: 10, null: false + t.index ["zone_id"], name: "index_taxes_on_zone_id" + end + + create_table "zones", force: :cascade do |t| + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "name", null: false + t.integer "country_id", null: false + t.string "timezone", null: false + t.json "configuration", default: {}, null: false + t.index ["country_id"], name: "index_zones_on_country_id" + t.index ["name"], name: "index_zones_on_name", unique: true + end + + create_table "zones_energy_periods", id: false, force: :cascade do |t| + t.integer "zone_id", null: false + t.integer "energy_period_id", null: false + t.index ["energy_period_id", "zone_id"], name: "index_zones_energy_periods_on_energy_period_id_and_zone_id", unique: true + t.index ["energy_period_id"], name: "index_zones_energy_periods_on_energy_period_id" + t.index ["zone_id"], name: "index_zones_energy_periods_on_zone_id" + end + + add_foreign_key "costs", "countries" + add_foreign_key "country_holidays", "countries" + add_foreign_key "daily_energy_export_prices", "zones" + add_foreign_key "daily_energy_import_prices", "zones" + add_foreign_key "energy_prices", "zones" add_foreign_key "inverters", "protocols" + add_foreign_key "inverters", "zones" + add_foreign_key "rates", "inverters" add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade + add_foreign_key "taxes", "zones" + add_foreign_key "zones", "countries" + add_foreign_key "zones_energy_periods", "energy_periods" + add_foreign_key "zones_energy_periods", "zones" end diff --git a/db/seeds.rb b/db/seeds.rb index 2b13072..8a9f21f 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,21 +1,3 @@ # This file should ensure the existence of records required to run the application in every environment (production, # development, test). The code here should be idempotent so that it can be executed at any point in every environment. # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). - -# create default settings -Setting.instance - -# huawei modbus protocol -Protocol - .create_with( - gateways: %w[modbus_mqtt], - solar_power: { address: 32_080, quantity: 2, type: :int32be, scale: 1 }, - solar_energy: { address: 32_114, quantity: 2, type: :uint32be, scale: 100 }, - grid_power: { address: 37_113, quantity: 2, type: :int32be, scale: 1 }, - grid_energy_export: { address: 37_119, quantity: 2, type: :int32be, scale: 100 }, - grid_energy_import: { address: 37_121, quantity: 2, type: :int32be, scale: 100 }, - model: { address: 30_000, quantity: 15, type: :string }, - serial_number: { address: 30_015, quantity: 10, type: :string }, - firmware_version: { address: 30_025, quantity: 10, type: :string } - ) - .find_or_create_by(name: "Huawei Modbus") diff --git a/lib/core_extensions/time.rb b/lib/core_extensions/time.rb new file mode 100644 index 0000000..85cea89 --- /dev/null +++ b/lib/core_extensions/time.rb @@ -0,0 +1,9 @@ +class Time + def holiday? + Holiday.where(date: self.to_date).any? + end + + def day_type + saturday? || sunday? || holiday? ? :weekend_holiday : :working_day + end +end diff --git a/test/fixtures/archives.yml b/test/fixtures/archives.yml index 2d1cfca..26e14f4 100644 --- a/test/fixtures/archives.yml +++ b/test/fixtures/archives.yml @@ -2,7 +2,6 @@ one: created_at: 2023-03-19T00:00:00+01:00 solar_power: 0.0 solar_energy: 0.0 - temperature: 0.0 grid_power: 0.0 grid_energy_export: 0.0 grid_energy_import: 0.0 diff --git a/test/fixtures/costs.yml b/test/fixtures/costs.yml new file mode 100644 index 0000000..3788ded --- /dev/null +++ b/test/fixtures/costs.yml @@ -0,0 +1,25 @@ +cost_1: + country_id: 1 + start_at: <%= Time.zone.parse("2023-01-01 00:00:00") %> + transport_toll_p1: 0.004506 + distribution_toll_p1: 0.024592 + charges_p1: 0.043893 + transport_toll_p2: 0.00305 + distribution_toll_p2: 0.016744 + charges_p2: 0.008779 + transport_toll_p3: 0.000128 + distribution_toll_p3: 0.000852 + charges_p3: 0.002195 + +cost_2: + country_id: 1 + start_at: <%= Time.zone.parse("2024-01-01 00:00:00") %> + transport_toll_p1: 0.004528 + distribution_toll_p1: 0.028553 + charges_p1: 0.0 + transport_toll_p2: 0.002589 + distribution_toll_p2: 0.016595 + charges_p2: 0.0 + transport_toll_p3: 0.000075 + distribution_toll_p3: 0.000482 + charges_p3: 0.0 diff --git a/test/fixtures/countries.yml b/test/fixtures/countries.yml new file mode 100644 index 0000000..615bbf2 --- /dev/null +++ b/test/fixtures/countries.yml @@ -0,0 +1,7 @@ +spain: + id: 1 + code: "ES" + name: "España" + p1_name: "Punta" + p2_name: "Llano" + p3_name: "Valle" diff --git a/test/fixtures/country_holidays.yml b/test/fixtures/country_holidays.yml new file mode 100644 index 0000000..0f85e98 --- /dev/null +++ b/test/fixtures/country_holidays.yml @@ -0,0 +1,40 @@ +country_holiday_1: + id: 1 + country_id: 1 + name: "Epifanía del Señor" + date: <%= Date.new(2023, 1, 6) %> +country_holiday_2: + id: 2 + country_id: 1 + name: "Día del Trabajo" + date: <%= Date.new(2023, 5, 1) %> +country_holiday_3: + id: 3 + country_id: 1 + name: "Asunción de la Virgen" + date: <%= Date.new(2023, 8, 15) %> +country_holiday_4: + id: 4 + country_id: 1 + name: "Fiesta Nacional de España" + date: <%= Date.new(2023, 10, 12) %> +country_holiday_5: + id: 5 + country_id: 1 + name: "Todos los Santos" + date: <%= Date.new(2023, 11, 1) %> +country_holiday_6: + id: 6 + country_id: 1 + name: "Día de la Constitución" + date: <%= Date.new(2023, 12, 6) %> +country_holiday_7: + id: 7 + country_id: 1 + name: "La Inmaculada Concepción" + date: <%= Date.new(2023, 12, 8) %> +country_holiday_8: + id: 8 + country_id: 1 + name: "Navidad" + date: <%= Date.new(2023, 12, 25) %> diff --git a/test/fixtures/energy_periods.yml b/test/fixtures/energy_periods.yml new file mode 100644 index 0000000..ed6f9c1 --- /dev/null +++ b/test/fixtures/energy_periods.yml @@ -0,0 +1,114 @@ +_fixture: + ignore: + - working_day + - weekend_holiday + +working_day: &working_day + monday: true + tuesday: true + wednesday: true + thursday: true + friday: true + +weekend_holiday: &weekend_holiday + saturday: true + sunday: true + holiday: true + +energy_period_pcb_1: + <<: *working_day + id: 1 + start_hour: 0 + end_hour: 7 + name: "p3" + +energy_period_pcb_2: + <<: *working_day + id: 2 + start_hour: 8 + end_hour: 9 + name: "p2" + +energy_period_pcb_3: + <<: *working_day + id: 3 + start_hour: 10 + end_hour: 13 + name: "p1" + +energy_period_pcb_4: + <<: *working_day + id: 4 + start_hour: 14 + end_hour: 17 + name: "p2" + +energy_period_pcb_5: + <<: *working_day + id: 5 + start_hour: 18 + end_hour: 21 + name: "p1" + +energy_period_pcb_6: + <<: *working_day + id: 6 + start_hour: 22 + end_hour: 23 + name: "p2" + +energy_period_pcb_7: + <<: *weekend_holiday + id: 7 + start_hour: 0 + end_hour: 23 + name: "p3" + +energy_period_cm_1: + <<: *working_day + id: 8 + start_hour: 0 + end_hour: 7 + name: "p3" + +energy_period_cm_2: + <<: *working_day + id: 9 + start_hour: 8 + end_hour: 10 + name: "p2" + +energy_period_cm_3: + <<: *working_day + id: 10 + start_hour: 11 + end_hour: 14 + name: "p1" + +energy_period_cm_4: + <<: *working_day + id: 11 + start_hour: 15 + end_hour: 18 + name: "p2" + +energy_period_cm_5: + <<: *working_day + id: 12 + start_hour: 19 + end_hour: 22 + name: "p1" + +energy_period_cm_6: + <<: *working_day + id: 13 + start_hour: 23 + end_hour: 23 + name: "p2" + +energy_period_cm_7: + <<: *weekend_holiday + id: 14 + start_hour: 0 + end_hour: 23 + name: "p3" diff --git a/test/fixtures/energy_price.yml b/test/fixtures/energy_price.yml deleted file mode 100644 index a75fa1d..0000000 --- a/test/fixtures/energy_price.yml +++ /dev/null @@ -1,119 +0,0 @@ -energy_price0: - datetime: 2023-03-19T00:00:00+01:00 - import: 0.1563 - export: 0.1087 - -energy_price1: - datetime: 2023-03-19T01:00:00+01:00 - import: 0.1542 - export: 0.1047 - -energy_price2: - datetime: 2023-03-19T02:00:00+01:00 - import: 0.1498 - export: 0.0984 - -energy_price3: - datetime: 2023-03-19T03:00:00+01:00 - import: 0.1513 - export: 0.0981 - -energy_price4: - datetime: 2023-03-19T04:00:00+01:00 - import: 0.1507 - export: 0.0975 - -energy_price5: - datetime: 2023-03-19T05:00:00+01:00 - import: 0.1554 - export: 0.1021 - -energy_price6: - datetime: 2023-03-19T06:00:00+01:00 - import: 0.1503 - export: 0.0988 - -energy_price7: - datetime: 2023-03-19T07:00:00+01:00 - import: 0.1508 - export: 0.1012 - -energy_price8: - datetime: 2023-03-19T08:00:00+01:00 - import: 0.1464 - export: 0.0982 - -energy_price9: - datetime: 2023-03-19T09:00:00+01:00 - import: 0.1136 - export: 0.0689 - -energy_price10: - datetime: 2023-03-19T10:00:00+01:00 - import: 0.104 - export: 0.064 - -energy_price11: - datetime: 2023-03-19T11:00:00+01:00 - import: 0.1022 - export: 0.064 - -energy_price12: - datetime: 2023-03-19T12:00:00+01:00 - import: 0.1042 - export: 0.0652 - -energy_price13: - datetime: 2023-03-19T13:00:00+01:00 - import: 0.1076 - export: 0.0686 - -energy_price14: - datetime: 2023-03-19T14:00:00+01:00 - import: 0.1082 - export: 0.0686 - -energy_price15: - datetime: 2023-03-19T15:00:00+01:00 - import: 0.0864 - export: 0.049 - -energy_price16: - datetime: 2023-03-19T16:00:00+01:00 - import: 0.0988 - export: 0.057 - -energy_price17: - datetime: 2023-03-19T17:00:00+01:00 - import: 0.1117 - export: 0.0681 - -energy_price18: - datetime: 2023-03-19T18:00:00+01:00 - import: 0.1491 - export: 0.1028 - -energy_price19: - datetime: 2023-03-19T19:00:00+01:00 - import: 0.2012 - export: 0.1517 - -energy_price20: - datetime: 2023-03-19T20:00:00+01:00 - import: 0.1912 - export: 0.1437 - -energy_price21: - datetime: 2023-03-19T21:00:00+01:00 - import: 0.181 - export: 0.1343 - -energy_price22: - datetime: 2023-03-19T22:00:00+01:00 - import: 0.1792 - export: 0.1319 - -energy_price23: - datetime: 2023-03-19T23:00:00+01:00 - import: 0.1775 - export: 0.129 diff --git a/test/fixtures/energy_prices.yml b/test/fixtures/energy_prices.yml new file mode 100644 index 0000000..57e3f98 --- /dev/null +++ b/test/fixtures/energy_prices.yml @@ -0,0 +1,167 @@ +energy_price0: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T00:00:00+01:00") %> + import: 0.1563 + export: 0.1087 + +energy_price1: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T01:00:00+01:00") %> + import: 0.1542 + export: 0.1047 + +energy_price2: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T02:00:00+01:00") %> + import: 0.1498 + export: 0.0984 + +energy_price3: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T03:00:00+01:00") %> + import: 0.1513 + export: 0.0981 + +energy_price4: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T04:00:00+01:00") %> + import: 0.1507 + export: 0.0975 + +energy_price5: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T05:00:00+01:00") %> + import: 0.1554 + export: 0.1021 + +energy_price6: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T06:00:00+01:00") %> + import: 0.1503 + export: 0.0988 + +energy_price7: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T07:00:00+01:00") %> + import: 0.1508 + export: 0.1012 + +energy_price8: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T08:00:00+01:00") %> + import: 0.1464 + export: 0.0982 + +energy_price9: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T09:00:00+01:00") %> + import: 0.1136 + export: 0.0689 + +energy_price10: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T10:00:00+01:00") %> + import: 0.104 + export: 0.064 + +energy_price11: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T11:00:00+01:00") %> + import: 0.1022 + export: 0.064 + +energy_price12: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T12:00:00+01:00") %> + import: 0.1042 + export: 0.0652 + +energy_price13: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T13:00:00+01:00") %> + import: 0.1076 + export: 0.0686 + +energy_price14: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T14:00:00+01:00") %> + import: 0.1082 + export: 0.0686 + +energy_price15: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T15:00:00+01:00") %> + import: 0.0864 + export: 0.049 + +energy_price16: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T16:00:00+01:00") %> + import: 0.0988 + export: 0.057 + +energy_price17: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T17:00:00+01:00") %> + import: 0.1117 + export: 0.0681 + +energy_price18: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T18:00:00+01:00") %> + import: 0.1491 + export: 0.1028 + +energy_price19: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T19:00:00+01:00") %> + import: 0.2012 + export: 0.1517 + +energy_price20: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T20:00:00+01:00") %> + import: 0.1912 + export: 0.1437 + +energy_price21: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T21:00:00+01:00") %> + import: 0.181 + export: 0.1343 + +energy_price22: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T22:00:00+01:00") %> + import: 0.1792 + export: 0.1319 + +energy_price23: + type: "PVPC" + zone_id: 1 + datetime: <%= Time.zone.parse("2023-03-19T23:00:00+01:00") %> + import: 0.1775 + export: 0.129 diff --git a/test/fixtures/inverters.yml b/test/fixtures/inverters.yml index 3bd53c1..0bcf887 100644 --- a/test/fixtures/inverters.yml +++ b/test/fixtures/inverters.yml @@ -1,8 +1,30 @@ -house: - name: "Casa" - protocol: huawei_modbus - timezone: "Europe/Madrid" +DEFAULTS: &DEFAULTS + installation_type: "domestic" + protocol_id: 1 brand: "Huawei" model: "SUN2000-3.68KTL-L1" - serial_number: "HV0000000000" firmware_version: "V200R001C00SPC130" + +house_1: + <<: *DEFAULTS + name: "Casa 1" + zone_id: 1 + serial_number: "HV0000000001" + +house_2: + <<: *DEFAULTS + name: "Casa 2" + zone_id: 1 + serial_number: "HV0000000002" + +house_3: + <<: *DEFAULTS + name: "Casa 3" + zone_id: 1 + serial_number: "HV0000000003" + +house_4: + <<: *DEFAULTS + name: "Casa 4" + zone_id: 2 + serial_number: "HV0000000004" diff --git a/test/fixtures/protocols.yml b/test/fixtures/protocols.yml index 09c4ecf..641a7a8 100644 --- a/test/fixtures/protocols.yml +++ b/test/fixtures/protocols.yml @@ -1,41 +1,42 @@ huawei_modbus: + id: 1 name: "Huawei Modbus" gateways: - - modbus_mqtt + - "modbus_mqtt" solar_power: address: 32_080 quantity: 2 - type: :int32be + type: "int32be" scale: 1 solar_energy: address: 32_114 quantity: 2 - type: :uint32be + type: "uint32be" scale: 100 grid_power: address: 37_113 quantity: 2 - type: :int32be + type: "int32be" scale: 1 grid_energy_export: address: 37_119 quantity: 2 - type: :int32be + type: "int32be" scale: 100 grid_energy_import: address: 37_121 quantity: 2 - type: :int32be + type: "int32be" scale: 100 model: address: 30_000 quantity: 15 - type: :string + type: "string" serial_number: address: 30_015 quantity: 10 - type: :string + type: "string" firmware_version: address: 30_025 quantity: 10 - type: :string + type: "string" diff --git a/test/fixtures/rates.yml b/test/fixtures/rates.yml new file mode 100644 index 0000000..8e2e249 --- /dev/null +++ b/test/fixtures/rates.yml @@ -0,0 +1,49 @@ +house_1: + inverter: house_1 + type: "Rates::Fixed" + start_at: <%= Time.zone.parse("2023-01-01 00:00:00") %> + p1: 0.122400 + p2: 0.122400 + p3: 0.122400 + +house_2_1: + inverter: house_2 + type: "Rates::ByPeriod" + start_at: <%= Time.zone.parse("2023-01-01 00:00:00") %> + p1: 0.342000 + p2: 0.281000 + p3: 0.234000 +house_2_2: + inverter: house_2 + type: "Rates::ByPeriod" + start_at: <%= Time.zone.parse("2023-05-01 00:00:00") %> + p1: 0.295000 + p2: 0.237000 + p3: 0.199000 +house_2_3: + inverter: house_2 + type: "Rates::ByPeriod" + start_at: <%= Time.zone.parse("2024-01-01 00:00:00") %> + p1: 0.247000 + p2: 0.189000 + p3: 0.154000 + +house_3: + inverter: house_3 + type: "Rates::PVPC" + start_at: <%= Time.zone.parse("2023-01-01 00:00:00") %> + +house_4_1: + inverter: house_4 + type: "Rates::Fixed" + start_at: <%= Time.zone.parse("2023-01-01 00:00:00") %> + p1: 0.122400 + p2: 0.122400 + p3: 0.122400 +house_4_2: + inverter: house_4 + type: "Rates::ByPeriod" + start_at: <%= Time.zone.parse("2023-06-01 00:00:00") %> + p1: 0.295000 + p2: 0.237000 + p3: 0.199000 diff --git a/test/fixtures/settings.yml b/test/fixtures/settings.yml deleted file mode 100644 index deef533..0000000 --- a/test/fixtures/settings.yml +++ /dev/null @@ -1,4 +0,0 @@ -default: - timezone: "Europe/Madrid" - loop_interval: 30 - archive_interval: 60 diff --git a/test/fixtures/taxes.yml b/test/fixtures/taxes.yml new file mode 100644 index 0000000..0318a05 --- /dev/null +++ b/test/fixtures/taxes.yml @@ -0,0 +1,17 @@ +ie_peninsula: + id: 1 + zone_id: 1 + kind: "other" + installation_type: "domestic" + start_at: <%= Time.new(2023, 1, 1) %> + name: "Impuesto Electricidad" + percentage: 0.005 + +iva_peninsula: + id: 2 + zone_id: 1 + kind: "value_add" + installation_type: "domestic" + start_at: <%= Time.new(2023, 1, 1) %> + name: "IVA" + percentage: 0.05 diff --git a/test/fixtures/zones.yml b/test/fixtures/zones.yml new file mode 100644 index 0000000..9f7f12a --- /dev/null +++ b/test/fixtures/zones.yml @@ -0,0 +1,49 @@ + peninsula: + id: 1 + name: "Península" + country_id: 1 + timezone: "Europe/Madrid" + configuration: + pvpc: true + esios_import_id: 8741 + esios_export_id: 3 + + canarias: + id: 2 + name: "Canarias" + country_id: 1 + timezone: "Atlantic/Canary" + configuration: + pvpc: true + esios_import_id: 8742 + esios_export_id: 3 + + baleares: + id: 3 + name: "Baleares" + country_id: 1 + timezone: "Europe/Madrid" + configuration: + pvpc: true + esios_import_id: 8743 + esios_export_id: 3 + + ceuta: + id: 4 + name: "Ceuta" + country_id: 1 + timezone: "Europe/Madrid" + configuration: + pvpc: true + esios_import_id: 8744 + esios_export_id: 3 + + melilla: + id: 5 + name: "Melilla" + country_id: 1 + timezone: "Europe/Madrid" + configuration: + pvpc: false + esios_import_id: 8745 + esios_export_id: 3 diff --git a/test/fixtures/zones_energy_periods.yml b/test/fixtures/zones_energy_periods.yml new file mode 100644 index 0000000..2b56335 --- /dev/null +++ b/test/fixtures/zones_energy_periods.yml @@ -0,0 +1,15 @@ +<% (1..3).each do |zone_id| %> + <% (1..7).each do |energy_period| %> +zone_<%= zone_id %>_ep_<%= energy_period %>: + zone_id: <%= zone_id %> + energy_period_id: <%= energy_period %> + <% end %> +<% end %> + +<% (4..5).each do |zone_id| %> + <% (8..14).each do |energy_period| %> +zone_<%= zone_id %>_ep_<%= energy_period %>: + zone_id: <%= zone_id %> + energy_period_id: <%= energy_period %> + <% end %> +<% end %> diff --git a/test/models/cost_test.rb b/test/models/cost_test.rb new file mode 100644 index 0000000..88f0533 --- /dev/null +++ b/test/models/cost_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class CostTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/country_test.rb b/test/models/country_test.rb new file mode 100644 index 0000000..ee4329b --- /dev/null +++ b/test/models/country_test.rb @@ -0,0 +1,10 @@ +require "test_helper" + +class CountryTest < ActiveSupport::TestCase + test "create without code" do + country = Country.new(name: "Test") + + assert_not country.save + assert protocol.errors.added?(:code, :blank) + end +end diff --git a/test/models/energy_period_test.rb b/test/models/energy_period_test.rb new file mode 100644 index 0000000..6a145c0 --- /dev/null +++ b/test/models/energy_period_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class EnergyPeriodTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/holiday_test.rb b/test/models/holiday_test.rb new file mode 100644 index 0000000..629df39 --- /dev/null +++ b/test/models/holiday_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class HolidayTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/inverter_test.rb b/test/models/inverter_test.rb index 3c15890..bc31575 100644 --- a/test/models/inverter_test.rb +++ b/test/models/inverter_test.rb @@ -15,15 +15,8 @@ class InverterTest < ActiveSupport::TestCase assert inverter.errors.added?(:protocol, :blank) end - test "save inverter without timezone" do - inverter = Inverter.new - - assert_not inverter.save - assert inverter.errors.added?(:timezone, :blank) - end - - test "save inverter with name, protocol and timezone" do - inverter = Inverter.new(name: "Inverter 1", protocol: protocols(:huawei_modbus), timezone: "Europe/Madrid") + test "save inverter with name, zone and protocol" do + inverter = Inverter.new(name: "Inverter 1", zone: Zone.find_by(name: "Península"), protocol: Protocol.first) assert inverter.save end diff --git a/test/models/protocol_test.rb b/test/models/protocol_test.rb index 870b8ed..cd1cf48 100644 --- a/test/models/protocol_test.rb +++ b/test/models/protocol_test.rb @@ -72,10 +72,10 @@ class ProtocolTest < ActiveSupport::TestCase end test "save protocol with duplicated name" do - protocol = Protocol.new(name: protocols(:huawei_modbus).name) + protocol = Protocol.new(name: Protocol.first.name) assert_not protocol.save - assert protocol.errors.added?(:name, :taken, value: protocols(:huawei_modbus).name) + assert protocol.errors.added?(:name, :taken, value: Protocol.first.name) end test "save protocol with all attributes" do diff --git a/test/models/rate_test.rb b/test/models/rate_test.rb new file mode 100644 index 0000000..0e99eb8 --- /dev/null +++ b/test/models/rate_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class RateTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/setting_test.rb b/test/models/setting_test.rb deleted file mode 100644 index 77edfb0..0000000 --- a/test/models/setting_test.rb +++ /dev/null @@ -1,93 +0,0 @@ -require "test_helper" - -class SettingTest < ActiveSupport::TestCase - test "should return default timezone" do - assert_equal "Europe/Madrid", Setting.new.timezone - end - - test "should return default loop interval" do - assert_equal 30, Setting.new.loop_interval - end - - test "should validate numericality of loop_interval" do - setting = Setting.new(loop_interval: "foo") - - assert_not setting.save - assert setting.errors.added?(:loop_interval, :not_a_number, value: "foo") - end - - test "should validate numericality of loop_interval greater than 0" do - setting = Setting.new(loop_interval: 0) - - assert_not setting.save - assert setting.errors.added?(:loop_interval, :greater_than, count: 0, value: 0) - end - - test "should return default archive interval" do - assert_equal 60, Setting.new.archive_interval - end - - test "should validate numericality of archive_interval" do - setting = Setting.new(archive_interval: "foo") - - assert_not setting.save - assert setting.errors.added?(:archive_interval, :not_a_number, value: "foo") - end - - test "should validate numericality of archive_interval greater than 0" do - setting = Setting.new(archive_interval: 0) - - assert_not setting.save - assert setting.errors.added?(:archive_interval, :greater_than, count: 0, value: 0) - end - - test "should validate presence of energy_price_at" do - setting = Setting.new(energy_price: "esios") - - assert_not setting.save - assert setting.errors.added?(:energy_price_at, :blank) - end - - test "should validate presence of esios_api_key" do - setting = Setting.new(energy_price: "esios") - - assert_not setting.save - assert setting.errors.added?(:esios_api_key, :blank) - end - - test "should validate presence of esios_zone" do - setting = Setting.new(energy_price: "esios") - - assert_not setting.save - assert setting.errors.added?(:esios_zone, :blank) - end - - test "should validate presence of esios_country" do - setting = Setting.new(energy_price: "esios") - - assert_not setting.save - assert setting.errors.added?(:esios_country, :blank) - end - - test "should validate presence of huawei_ip" do - setting = Setting.new(inverter: "huawei") - - assert_not setting.save - assert setting.errors.added?(:huawei_ip, :blank) - end - - test "should validate presence of huawei_port" do - setting = Setting.new(inverter: "huawei") - - assert_not setting.save - assert setting.errors.added?(:huawei_port, :blank) - end - - test "should return instance" do - assert_equal Setting.first_or_create, Setting.instance - end - - test "should return same instance" do - assert_equal Setting.instance, Setting.instance - end -end diff --git a/test/models/tax_test.rb b/test/models/tax_test.rb new file mode 100644 index 0000000..54b7a23 --- /dev/null +++ b/test/models/tax_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class TaxTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/zone_test.rb b/test/models/zone_test.rb new file mode 100644 index 0000000..1f2bae1 --- /dev/null +++ b/test/models/zone_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ZoneTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index 332896f..c309a45 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -10,7 +10,5 @@ class TestCase # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. fixtures :all - - # Add more helper methods to be used by all tests here... end end