diff --git a/api/tariff.go b/api/tariff.go index c433506ba..d8b1b37a0 100644 --- a/api/tariff.go +++ b/api/tariff.go @@ -8,5 +8,6 @@ const ( _ TariffType = iota TariffTypePriceStatic TariffTypePriceDynamic + TariffTypePriceForecast TariffTypeCo2 ) diff --git a/api/tarifftype_enumer.go b/api/tarifftype_enumer.go index ac0a6e744..9a7b11cf7 100644 --- a/api/tarifftype_enumer.go +++ b/api/tarifftype_enumer.go @@ -7,11 +7,11 @@ import ( "strings" ) -const _TariffTypeName = "pricestaticpricedynamicco2" +const _TariffTypeName = "pricestaticpricedynamicpriceforecastco2" -var _TariffTypeIndex = [...]uint8{0, 11, 23, 26} +var _TariffTypeIndex = [...]uint8{0, 11, 23, 36, 39} -const _TariffTypeLowerName = "pricestaticpricedynamicco2" +const _TariffTypeLowerName = "pricestaticpricedynamicpriceforecastco2" func (i TariffType) String() string { i -= 1 @@ -27,24 +27,28 @@ func _TariffTypeNoOp() { var x [1]struct{} _ = x[TariffTypePriceStatic-(1)] _ = x[TariffTypePriceDynamic-(2)] - _ = x[TariffTypeCo2-(3)] + _ = x[TariffTypePriceForecast-(3)] + _ = x[TariffTypeCo2-(4)] } -var _TariffTypeValues = []TariffType{TariffTypePriceStatic, TariffTypePriceDynamic, TariffTypeCo2} +var _TariffTypeValues = []TariffType{TariffTypePriceStatic, TariffTypePriceDynamic, TariffTypePriceForecast, 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, + _TariffTypeName[23:36]: TariffTypePriceForecast, + _TariffTypeLowerName[23:36]: TariffTypePriceForecast, + _TariffTypeName[36:39]: TariffTypeCo2, + _TariffTypeLowerName[36:39]: TariffTypeCo2, } var _TariffTypeNames = []string{ _TariffTypeName[0:11], _TariffTypeName[11:23], - _TariffTypeName[23:26], + _TariffTypeName[23:36], + _TariffTypeName[36:39], } // TariffTypeString retrieves an enum value from the enum constants string name. diff --git a/assets/js/components/Energyflow/Energyflow.vue b/assets/js/components/Energyflow/Energyflow.vue index 30ac225cb..b7b0ffdb7 100644 --- a/assets/js/components/Energyflow/Energyflow.vue +++ b/assets/js/components/Energyflow/Energyflow.vue @@ -171,7 +171,7 @@ import GridSettingsModal from "../GridSettingsModal.vue"; import formatter from "../../mixins/formatter"; import AnimatedNumber from "../AnimatedNumber.vue"; import settings from "../../settings"; -import { CO2_TYPE, PRICE_DYNAMIC_TYPE } from "../../units"; +import { CO2_TYPE, PRICE_DYNAMIC_TYPE, PRICE_FORECAST_TYPE } from "../../units"; import collector from "../../mixins/collector"; import BatterySettingsModal from "../BatterySettingsModal.vue"; @@ -216,7 +216,7 @@ export default { }, computed: { smartCostAvailable: function () { - return [CO2_TYPE, PRICE_DYNAMIC_TYPE].includes(this.smartCostType); + return [CO2_TYPE, PRICE_DYNAMIC_TYPE, PRICE_FORECAST_TYPE].includes(this.smartCostType); }, gridImport: function () { return Math.max(0, this.gridPower); diff --git a/assets/js/components/GridSettingsModal.vue b/assets/js/components/GridSettingsModal.vue index 0b6bb3397..77e0f185a 100644 --- a/assets/js/components/GridSettingsModal.vue +++ b/assets/js/components/GridSettingsModal.vue @@ -114,6 +114,7 @@ export default { props: { smartCostLimit: Number, smartCostType: String, + tariffGrid: Number, currency: String, }, data: function () { @@ -241,6 +242,11 @@ export default { this.updateTariff(); } }, + tariffGrid() { + if (this.isModalVisible) { + this.updateTariff(); + } + }, smartCostLimit(limit) { this.selectedSmartCostLimit = limit; }, diff --git a/assets/js/units.js b/assets/js/units.js index 58ab3b8be..ca11d5605 100644 --- a/assets/js/units.js +++ b/assets/js/units.js @@ -6,6 +6,7 @@ export const UNITS = [KM, MILES]; export const CO2_TYPE = "co2"; export const PRICE_DYNAMIC_TYPE = "pricedynamic"; +export const PRICE_FORECAST_TYPE = "priceforecast"; const MILES_FACTOR = 0.6213711922; diff --git a/core/site_api.go b/core/site_api.go index f7d4ba7e6..6be6cdeb9 100644 --- a/core/site_api.go +++ b/core/site_api.go @@ -147,7 +147,7 @@ func (site *Site) GetTariff(tariff string) api.Tariff { // prio 0: manually set planner tariff return site.tariffs.Planner - case site.tariffs.Grid != nil && site.tariffs.Grid.Type() == api.TariffTypePriceDynamic: + case site.tariffs.Grid != nil && site.tariffs.Grid.Type() == api.TariffTypePriceForecast: // prio 1: dynamic grid tariff return site.tariffs.Grid diff --git a/evcc.dist.yaml b/evcc.dist.yaml index 990598d27..79b797528 100644 --- a/evcc.dist.yaml +++ b/evcc.dist.yaml @@ -194,6 +194,13 @@ tariffs: # securitytoken: # api token # charges: # optional, additional charges per kWh # tax: # optional, additional tax (0.1 for 10%) + + # type: custom # price from a plugin source; see https://docs.evcc.io/docs/reference/plugins + # price: + # source: http + # uri: https://example.org/price.json + # jq: .price.current + feedin: # rate for feeding excess (pv) energy to the grid type: fixed diff --git a/tariff/awattar.go b/tariff/awattar.go index 3949575ed..5b94f43c6 100644 --- a/tariff/awattar.go +++ b/tariff/awattar.go @@ -99,5 +99,5 @@ func (t *Awattar) Rates() (api.Rates, error) { // Type implements the api.Tariff interface func (t *Awattar) Type() api.TariffType { - return api.TariffTypePriceDynamic + return api.TariffTypePriceForecast } diff --git a/tariff/elering.go b/tariff/elering.go index 99105168a..3dd1a766f 100644 --- a/tariff/elering.go +++ b/tariff/elering.go @@ -112,5 +112,5 @@ func (t *Elering) Rates() (api.Rates, error) { // Type implements the api.Tariff interface func (t *Elering) Type() api.TariffType { - return api.TariffTypePriceDynamic + return api.TariffTypePriceForecast } diff --git a/tariff/energinet.go b/tariff/energinet.go index d3ddaaf3c..c5ec71c11 100644 --- a/tariff/energinet.go +++ b/tariff/energinet.go @@ -109,5 +109,5 @@ func (t *Energinet) Rates() (api.Rates, error) { // Type implements the api.Tariff interface func (t *Energinet) Type() api.TariffType { - return api.TariffTypePriceDynamic + return api.TariffTypePriceForecast } diff --git a/tariff/fixed.go b/tariff/fixed.go index 11f6a36aa..0c1a41b46 100644 --- a/tariff/fixed.go +++ b/tariff/fixed.go @@ -133,7 +133,7 @@ func (t *Fixed) Rates() (api.Rates, error) { // Type implements the api.Tariff interface func (t *Fixed) Type() api.TariffType { if t.dynamic { - return api.TariffTypePriceDynamic + return api.TariffTypePriceForecast } return api.TariffTypePriceStatic } diff --git a/tariff/octopus.go b/tariff/octopus.go index 14867ef10..33ff2278a 100644 --- a/tariff/octopus.go +++ b/tariff/octopus.go @@ -110,5 +110,5 @@ func (t *Octopus) Rates() (api.Rates, error) { // Type implements the api.Tariff interface func (t *Octopus) Type() api.TariffType { - return api.TariffTypePriceDynamic + return api.TariffTypePriceForecast } diff --git a/tariff/tariff.go b/tariff/tariff.go new file mode 100644 index 000000000..ba759c4db --- /dev/null +++ b/tariff/tariff.go @@ -0,0 +1,68 @@ +package tariff + +import ( + "fmt" + "time" + + "github.com/evcc-io/evcc/api" + "github.com/evcc-io/evcc/provider" + "github.com/evcc-io/evcc/util" + "github.com/jinzhu/now" +) + +type Tariff struct { + *embed + priceG func() (float64, error) +} + +var _ api.Tariff = (*Tariff)(nil) + +func init() { + registry.Add(api.Custom, NewConfigurableFromConfig) +} + +func NewConfigurableFromConfig(other map[string]interface{}) (api.Tariff, error) { + var cc struct { + embed `mapstructure:",squash"` + Price provider.Config + } + + if err := util.DecodeOther(other, &cc); err != nil { + return nil, err + } + + priceG, err := provider.NewFloatGetterFromConfig(cc.Price) + if err != nil { + return nil, fmt.Errorf("price: %w", err) + } + + t := &Tariff{ + embed: &cc.embed, + priceG: priceG, + } + + return t, nil +} + +// Rates implements the api.Tariff interface +func (t *Tariff) Rates() (api.Rates, error) { + price, err := t.priceG() + if err != nil { + return nil, err + } + + res := api.Rates{ + { + Start: now.BeginningOfHour(), + End: now.BeginningOfHour().Add(48 * time.Hour), + Price: t.totalPrice(price), + }, + } + + return res, nil +} + +// Type implements the api.Tariff interface +func (t *Tariff) Type() api.TariffType { + return api.TariffTypePriceDynamic +} diff --git a/tariff/tibber.go b/tariff/tibber.go index e54c4f3a7..b1978b0e8 100644 --- a/tariff/tibber.go +++ b/tariff/tibber.go @@ -140,5 +140,5 @@ func (t *Tibber) Rates() (api.Rates, error) { // Type implements the api.Tariff interface func (t *Tibber) Type() api.TariffType { - return api.TariffTypePriceDynamic + return api.TariffTypePriceForecast }