Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Solcast #9454

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/tariff.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ const (
TariffTypePriceStatic
TariffTypePriceDynamic
TariffTypeCo2
TariffTypeGeneration
)
12 changes: 8 additions & 4 deletions api/tarifftype_enumer.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions assets/js/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@ export const i18n = axios.create({
Accept: "application/toml",
},
});

export function allowErrors(status) {
return status >= 200 && status < 500;
}
58 changes: 48 additions & 10 deletions assets/js/components/TargetCharge.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
/>
</div>
</div>
<p class="mb-0">
<p class="my-2">
<span v-if="timeInThePast" class="d-block text-danger mb-1">
{{ $t("main.targetCharge.targetIsInThePast") }}
</span>
Expand All @@ -61,9 +61,27 @@
<span v-if="['off', 'now'].includes(mode)" class="d-block text-secondary mb-1">
{{ $t("main.targetCharge.onlyInPvMode") }}
</span>
&nbsp;
</p>
<div
v-if="$hiddenFeatures && !generationAvailable"
class="d-flex justify-content-end my-2"
>
<div class="form-check form-switch my-1">
<input
:id="`generationAdjusted${id}`"
v-model="generationAdjusted"
class="form-check-input"
type="checkbox"
role="switch"
/>
<div class="form-check-label">
<label :for="`generationAdjusted${id}`"> use solar forecast 🧪</label>
</div>
</div>
</div>

<TargetChargePlan v-if="targetChargePlanProps" v-bind="targetChargePlanProps" />

<div class="d-flex justify-content-between mt-3">
<button
type="button"
Expand Down Expand Up @@ -124,6 +142,8 @@ export default {
tariff: {},
activeTab: "time",
loading: false,
generationAvailable: false,
generationAdjusted: false,
};
},
computed: {
Expand Down Expand Up @@ -204,10 +224,14 @@ export default {
targetEnergy() {
this.updatePlan();
},
generationAdjusted() {
this.updatePlan();
},
},
mounted() {
async mounted() {
this.initInputFields();
this.updatePlan();
await this.checkGenerationAvailable();
await this.updatePlan();
},
methods: {
updatePlan: async function () {
Expand All @@ -221,15 +245,18 @@ export default {
this.loading = true;
this.plan = (
await api.get(`loadpoints/${this.id}/target/plan`, {
params: { targetTime: this.selectedTargetTime },
params: {
targetTime: this.selectedTargetTime,
adjusted: this.generationAdjusted,
},
})
).data.result;

const tariffRes = await api.get(`tariff/planner`, {
validateStatus: function (status) {
return status >= 200 && status < 500;
},
});
const tariffRes = await api.get(
`tariff/planner`,
{ params: { adjusted: this.generationAdjusted } },
{ validateStatus: api.allowErrors }
);
this.tariff = tariffRes.status === 404 ? { rates: [] } : tariffRes.data.result;
} catch (e) {
console.error(e);
Expand All @@ -238,6 +265,17 @@ export default {
}
}
},
checkGenerationAvailable() {
if (!this.$hiddenFeatures) {
return;
}
try {
const res = api.get(`tariff/generation`, { validateStatus: api.allowErrors });
this.generationAvailable = res.status === 200;
} catch (e) {
console.error(e);
}
},
defaultDate: function () {
const [hours, minutes] = (
window.localStorage[LAST_TARGET_TIME_KEY] || DEFAULT_TARGET_TIME
Expand Down
63 changes: 3 additions & 60 deletions cmd/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
"golang.org/x/sync/errgroup"
"golang.org/x/text/currency"
)

var conf = globalConfig{
Expand Down Expand Up @@ -91,7 +90,7 @@ type globalConfig struct {
Meters []config.Named
Chargers []config.Named
Vehicles []config.Named
Tariffs tariffConfig
Tariffs tariff.Config
Site map[string]interface{}
Loadpoints []map[string]interface{}
}
Expand Down Expand Up @@ -127,14 +126,6 @@ type messagingConfig struct {
Services []config.Typed
}

type tariffConfig struct {
Currency string
Grid config.Typed
FeedIn config.Typed
Co2 config.Typed
Planner config.Typed
}

type networkConfig struct {
Schema string
Host string
Expand Down Expand Up @@ -560,54 +551,6 @@ func configureMessengers(conf messagingConfig, valueChan chan util.Param, cache
return messageChan, nil
}

func configureTariffs(conf tariffConfig) (tariff.Tariffs, error) {
var grid, feedin, co2, planner api.Tariff
var currencyCode currency.Unit = currency.EUR
var err error

if conf.Currency != "" {
currencyCode = currency.MustParseISO(conf.Currency)
}

if conf.Grid.Type != "" {
grid, err = tariff.NewFromConfig(conf.Grid.Type, conf.Grid.Other)
if err != nil {
grid = nil
log.ERROR.Printf("failed configuring grid tariff: %v", err)
}
}

if conf.FeedIn.Type != "" {
feedin, err = tariff.NewFromConfig(conf.FeedIn.Type, conf.FeedIn.Other)
if err != nil {
feedin = nil
log.ERROR.Printf("failed configuring feed-in tariff: %v", err)
}
}

if conf.Co2.Type != "" {
co2, err = tariff.NewFromConfig(conf.Co2.Type, conf.Co2.Other)
if err != nil {
co2 = nil
log.ERROR.Printf("failed configuring co2 tariff: %v", err)
}
}

if conf.Planner.Type != "" {
planner, err = tariff.NewFromConfig(conf.Planner.Type, conf.Planner.Other)
if err != nil {
planner = nil
log.ERROR.Printf("failed configuring planner tariff: %v", err)
} else if planner.Type() == api.TariffTypeCo2 {
log.WARN.Printf("tariff configuration changed, use co2 instead of planner for co2 tariff")
}
}

tariffs := tariff.NewTariffs(currencyCode, grid, feedin, co2, planner)

return *tariffs, nil
}

func configureDevices(conf globalConfig) error {
if err := configureMeters(conf.Meters); err != nil {
return err
Expand All @@ -628,15 +571,15 @@ func configureSiteAndLoadpoints(conf globalConfig) (*core.Site, error) {
return nil, fmt.Errorf("failed configuring loadpoints: %w", err)
}

tariffs, err := configureTariffs(conf.Tariffs)
tariffs, err := tariff.New(conf.Tariffs)
if err != nil {
return nil, err
}

return configureSite(conf.Site, loadpoints, config.Instances(config.Vehicles().Devices()), tariffs)
}

func configureSite(conf map[string]interface{}, loadpoints []*core.Loadpoint, vehicles []api.Vehicle, tariffs tariff.Tariffs) (*core.Site, error) {
func configureSite(conf map[string]interface{}, loadpoints []*core.Loadpoint, vehicles []api.Vehicle, tariffs *tariff.Tariffs) (*core.Site, error) {
site, err := core.NewSiteFromConfig(log, conf, loadpoints, vehicles, tariffs)
if err != nil {
return nil, fmt.Errorf("failed configuring site: %w", err)
Expand Down
9 changes: 5 additions & 4 deletions cmd/tariff.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,11 @@ func runTariff(cmd *cobra.Command, args []string) {
}

for key, cc := range map[string]config.Typed{
"grid": conf.Tariffs.Grid,
"feedin": conf.Tariffs.FeedIn,
"co2": conf.Tariffs.Co2,
"planner": conf.Tariffs.Planner,
"grid": conf.Tariffs.Grid,
"feedin": conf.Tariffs.FeedIn,
"co2": conf.Tariffs.Co2,
"generation": conf.Tariffs.Generation,
"planner": conf.Tariffs.Planner,
} {
if cc.Type == "" || (name != "" && key != name) {
continue
Expand Down
2 changes: 1 addition & 1 deletion core/loadpoint/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ type API interface {
// SetTargetSoc sets the charge target soc
SetTargetSoc(int)
// GetPlan creates a charging plan
GetPlan(targetTime time.Time, maxPower float64) (time.Duration, api.Rates, error)
GetPlan(targetTime time.Time, maxPower float64, adjusted bool) (time.Duration, api.Rates, error)
// GetEnableThreshold gets the loadpoint enable threshold
GetEnableThreshold() float64
// SetEnableThreshold sets loadpoint enable threshold
Expand Down
6 changes: 3 additions & 3 deletions core/loadpoint_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func (lp *Loadpoint) planRequiredDuration(maxPower float64) time.Duration {
// Results:
// - required total charging duration
// - actual charging plan as rate table
func (lp *Loadpoint) GetPlan(targetTime time.Time, maxPower float64) (time.Duration, api.Rates, error) {
func (lp *Loadpoint) GetPlan(targetTime time.Time, maxPower float64, adjusted bool) (time.Duration, api.Rates, error) {
if lp.planner == nil || targetTime.IsZero() {
return 0, nil, nil
}
Expand All @@ -58,7 +58,7 @@ func (lp *Loadpoint) GetPlan(targetTime time.Time, maxPower float64) (time.Durat
}

requiredDuration := lp.planRequiredDuration(maxPower)
plan, err := lp.planner.Plan(requiredDuration, targetTime)
plan, err := lp.planner.Plan(requiredDuration, targetTime, adjusted)

// sort plan by time
slices.SortStableFunc(plan, planner.SortByTime)
Expand All @@ -74,7 +74,7 @@ func (lp *Loadpoint) plannerActive() (active bool) {

maxPower := lp.GetMaxPower()

requiredDuration, plan, err := lp.GetPlan(lp.GetTargetTime(), maxPower)
requiredDuration, plan, err := lp.GetPlan(lp.GetTargetTime(), maxPower, false)
if err != nil {
lp.log.ERROR.Println("planner:", err)
return false
Expand Down
2 changes: 1 addition & 1 deletion core/planner/planner.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func (t *Planner) plan(rates api.Rates, requiredDuration time.Duration, targetTi
}

// Plan creates a lowest-cost charging plan, considering edge conditions
func (t *Planner) Plan(requiredDuration time.Duration, targetTime time.Time) (api.Rates, error) {
func (t *Planner) Plan(requiredDuration time.Duration, targetTime time.Time, adjusted bool) (api.Rates, error) {
if t == nil || requiredDuration <= 0 {
return nil, nil
}
Expand Down
Loading