From 7c3ca53f0274df479f5253e4f77eb8d40516f768 Mon Sep 17 00:00:00 2001 From: andig Date: Wed, 31 May 2023 09:19:36 +0200 Subject: [PATCH] Add dedicated co2 tariff (#8089) --------- Co-authored-by: Michael Geers --- api/api.go | 18 +--- api/rates.go | 15 ++++ api/tariff.go | 12 +++ api/tarifftype_enumer.go | 83 +++++++++++++++++++ assets/js/components/ChargingPlan.story.vue | 18 +++- assets/js/components/ChargingPlan.vue | 3 +- .../Energyflow/Energyflow.story.vue | 4 +- .../js/components/Energyflow/Energyflow.vue | 10 ++- assets/js/components/GridSettingsModal.vue | 15 ++-- assets/js/components/Loadpoint.vue | 2 +- assets/js/components/Loadpoints.vue | 4 +- assets/js/components/Site.vue | 5 +- assets/js/components/TargetCharge.vue | 14 ++-- assets/js/components/TargetChargePlan.vue | 11 ++- assets/js/components/TariffChart.vue | 4 +- assets/js/components/Vehicle.vue | 3 +- assets/js/components/VehicleStatus.test.js | 2 +- assets/js/components/VehicleStatus.vue | 6 +- assets/js/units.js | 3 +- cmd/config.go | 1 + cmd/setup.go | 14 +++- cmd/tariff.go | 6 +- core/loadpoint/api.go | 2 - core/loadpoint/mock.go | 14 ---- core/loadpoint_plan.go | 4 - core/planner/planner.go | 7 -- core/site.go | 7 +- core/site_api.go | 40 ++++++--- evcc.dist.yaml | 4 +- mock/mock_api.go | 28 ++----- server/http_handler.go | 1 - tariff/awattar.go | 22 ++--- tariff/electricitymaps.go | 11 +-- tariff/elering.go | 17 ++-- tariff/fixed.go | 20 ++--- tariff/gruenstromindex.go | 11 +-- tariff/octopus.go | 6 +- tariff/tariffs.go | 18 ++-- tariff/tibber.go | 17 +--- 39 files changed, 267 insertions(+), 215 deletions(-) create mode 100644 api/tariff.go create mode 100644 api/tarifftype_enumer.go diff --git a/api/api.go b/api/api.go index e03e57621..bf0d11438 100644 --- a/api/api.go +++ b/api/api.go @@ -201,26 +201,10 @@ type Resurrector interface { WakeUp() error } -// Rate is a grid tariff rate -type Rate struct { - Start time.Time `json:"start"` - End time.Time `json:"end"` - Price float64 `json:"price"` -} - -// IsEmpty returns is the rate is the zero value -func (r Rate) IsEmpty() bool { - return r.Start.IsZero() && r.End.IsZero() && r.Price == 0 -} - -// Rates is a slice of (future) tariff rates -type Rates []Rate - // Tariff is a tariff capable of retrieving tariff rates type Tariff interface { - Unit() string Rates() (Rates, error) - IsDynamic() bool + Type() TariffType } // AuthProvider is the ability to provide OAuth authentication through the ui diff --git a/api/rates.go b/api/rates.go index 104948a70..2a942a03b 100644 --- a/api/rates.go +++ b/api/rates.go @@ -5,6 +5,21 @@ import ( "time" ) +// Rate is a grid tariff rate +type Rate struct { + Start time.Time `json:"start"` + End time.Time `json:"end"` + Price float64 `json:"price"` +} + +// IsEmpty returns is the rate is the zero value +func (r Rate) IsEmpty() bool { + return r.Start.IsZero() && r.End.IsZero() && r.Price == 0 +} + +// Rates is a slice of (future) tariff rates +type Rates []Rate + // Current returns the rates current rate or error func (r Rates) Current(now time.Time) (Rate, error) { for _, rr := range r { diff --git a/api/tariff.go b/api/tariff.go new file mode 100644 index 000000000..c433506ba --- /dev/null +++ b/api/tariff.go @@ -0,0 +1,12 @@ +package api + +//go:generate enumer -type TariffType -trimprefix TariffType -transform=lower + +type TariffType int + +const ( + _ TariffType = iota + TariffTypePriceStatic + TariffTypePriceDynamic + TariffTypeCo2 +) diff --git a/api/tarifftype_enumer.go b/api/tarifftype_enumer.go new file mode 100644 index 000000000..ac0a6e744 --- /dev/null +++ b/api/tarifftype_enumer.go @@ -0,0 +1,83 @@ +// Code generated by "enumer -type TariffType -trimprefix TariffType -transform=lower"; DO NOT EDIT. + +package api + +import ( + "fmt" + "strings" +) + +const _TariffTypeName = "pricestaticpricedynamicco2" + +var _TariffTypeIndex = [...]uint8{0, 11, 23, 26} + +const _TariffTypeLowerName = "pricestaticpricedynamicco2" + +func (i TariffType) String() string { + i -= 1 + if i < 0 || i >= TariffType(len(_TariffTypeIndex)-1) { + return fmt.Sprintf("TariffType(%d)", i+1) + } + return _TariffTypeName[_TariffTypeIndex[i]:_TariffTypeIndex[i+1]] +} + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the stringer command to generate them again. +func _TariffTypeNoOp() { + var x [1]struct{} + _ = x[TariffTypePriceStatic-(1)] + _ = x[TariffTypePriceDynamic-(2)] + _ = x[TariffTypeCo2-(3)] +} + +var _TariffTypeValues = []TariffType{TariffTypePriceStatic, TariffTypePriceDynamic, TariffTypeCo2} + +var _TariffTypeNameToValueMap = map[string]TariffType{ + _TariffTypeName[0:11]: TariffTypePriceStatic, + _TariffTypeLowerName[0:11]: TariffTypePriceStatic, + _TariffTypeName[11:23]: TariffTypePriceDynamic, + _TariffTypeLowerName[11:23]: TariffTypePriceDynamic, + _TariffTypeName[23:26]: TariffTypeCo2, + _TariffTypeLowerName[23:26]: TariffTypeCo2, +} + +var _TariffTypeNames = []string{ + _TariffTypeName[0:11], + _TariffTypeName[11:23], + _TariffTypeName[23:26], +} + +// TariffTypeString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func TariffTypeString(s string) (TariffType, error) { + if val, ok := _TariffTypeNameToValueMap[s]; ok { + return val, nil + } + + if val, ok := _TariffTypeNameToValueMap[strings.ToLower(s)]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to TariffType values", s) +} + +// TariffTypeValues returns all values of the enum +func TariffTypeValues() []TariffType { + return _TariffTypeValues +} + +// TariffTypeStrings returns a slice of all String values of the enum +func TariffTypeStrings() []string { + strs := make([]string, len(_TariffTypeNames)) + copy(strs, _TariffTypeNames) + return strs +} + +// IsATariffType returns "true" if the value is listed in the enum definition. "false" otherwise +func (i TariffType) IsATariffType() bool { + for _, v := range _TariffTypeValues { + if i == v { + return true + } + } + return false +} diff --git a/assets/js/components/ChargingPlan.story.vue b/assets/js/components/ChargingPlan.story.vue index b0589c0a2..5510b4566 100644 --- a/assets/js/components/ChargingPlan.story.vue +++ b/assets/js/components/ChargingPlan.story.vue @@ -16,13 +16,25 @@ const hoursFromNow = function (hours) { - + - + - + diff --git a/assets/js/components/ChargingPlan.vue b/assets/js/components/ChargingPlan.vue index 48494152b..59b799220 100644 --- a/assets/js/components/ChargingPlan.vue +++ b/assets/js/components/ChargingPlan.vue @@ -111,7 +111,8 @@ export default { vehicleSoc: Number, vehicleName: String, smartCostLimit: Number, - smartCostUnit: String, + smartCostType: String, + currency: String, }, emits: ["target-time-updated", "target-time-removed", "minsoc-updated"], data: function () { diff --git a/assets/js/components/Energyflow/Energyflow.story.vue b/assets/js/components/Energyflow/Energyflow.story.vue index 9bffe116c..d6dc9487a 100644 --- a/assets/js/components/Energyflow/Energyflow.story.vue +++ b/assets/js/components/Energyflow/Energyflow.story.vue @@ -16,7 +16,7 @@ import Energyflow from "./Energyflow.vue"; :tariffGrid="0.25" :tariffFeedIn="0.08" :tariffEffectivePrice="0.08" - smartCostUnit="EUR" + smartCostType="price" smartCostAvailable currency="EUR" siteTitle="Home" @@ -147,7 +147,7 @@ import Energyflow from "./Energyflow.vue"; :tariffEffectivePrice="0.08" :tariffCo2="723" :tariffEffectiveCo2="0" - smartCostUnit="gCO2eq" + smartCostType="co2" smartCostAvailable currency="EUR" siteTitle="Home" diff --git a/assets/js/components/Energyflow/Energyflow.vue b/assets/js/components/Energyflow/Energyflow.vue index 3cd510afb..c0f2b67d4 100644 --- a/assets/js/components/Energyflow/Energyflow.vue +++ b/assets/js/components/Energyflow/Energyflow.vue @@ -164,7 +164,7 @@ import GridSettingsModal from "../GridSettingsModal.vue"; import formatter from "../../mixins/formatter"; import AnimatedNumber from "../AnimatedNumber.vue"; import settings from "../../settings"; -import { CO2_UNIT } from "../../units"; +import { CO2_TYPE, PRICE_DYNAMIC_TYPE } from "../../units"; import collector from "../../mixins/collector"; import BatterySettingsModal from "../BatterySettingsModal.vue"; @@ -197,9 +197,8 @@ export default { tariffEffectivePrice: { type: Number }, tariffCo2: { type: Number }, tariffEffectiveCo2: { type: Number }, - smartCostAvailable: { type: Boolean }, smartCostLimit: { type: Number }, - smartCostUnit: { type: String }, + smartCostType: { type: String }, currency: { type: String }, prioritySoc: { type: Number }, bufferSoc: { type: Number }, @@ -209,6 +208,9 @@ export default { return { detailsOpen: false, detailsCompleteHeight: null, gridSettingsModal: null }; }, computed: { + smartCostAvailable: function () { + return [CO2_TYPE, PRICE_DYNAMIC_TYPE].includes(this.smartCostType); + }, gridImport: function () { return Math.max(0, this.gridPower); }, @@ -257,7 +259,7 @@ export default { return this.collectProps(BatterySettingsModal); }, co2Available() { - return this.smartCostUnit === CO2_UNIT; + return this.smartCostType === CO2_TYPE; }, }, mounted() { diff --git a/assets/js/components/GridSettingsModal.vue b/assets/js/components/GridSettingsModal.vue index d4173bdf8..3303f9378 100644 --- a/assets/js/components/GridSettingsModal.vue +++ b/assets/js/components/GridSettingsModal.vue @@ -104,7 +104,7 @@