Skip to content
Merged
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
3 changes: 2 additions & 1 deletion assets/js/components/Energyflow/Energyflow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ export default defineComponent({
props: {
gridConfigured: Boolean,
experimental: Boolean,
solarAdjusted: Boolean,
gridPower: { type: Number, default: 0 },
homePower: { type: Number, default: 0 },
pvConfigured: Boolean,
Expand Down Expand Up @@ -523,7 +524,7 @@ export default defineComponent({
return undefined;
}
const { today, scale } = this.forecast.solar || {};
const factor = this.experimental && settings.solarAdjusted && scale ? scale : 1;
const factor = this.experimental && this.solarAdjusted && scale ? scale : 1;
const energy = today?.energy || 0;
return energy * factor;
},
Expand Down
1 change: 1 addition & 0 deletions assets/js/components/Site/Site.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export default defineComponent({
ext: { type: Array as PropType<Meter[]>, default: () => [] },
consumers: { type: Array as PropType<Meter[]>, default: () => [] },
batteryDischargeControl: Boolean,
solarAdjusted: Boolean,
batteryGridChargeLimit: { type: [Number, null] as PropType<number | null>, default: null },
batteryGridChargeActive: Boolean,
batteryMode: String as PropType<BATTERY_MODE>,
Expand Down
4 changes: 0 additions & 4 deletions assets/js/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ const SAVINGS_INDICATOR = "savings_indicator";
const SESSIONS_GROUP = "sessions_group";
const SESSIONS_TYPE = "sessions_type";
const BATTERY_UNIT = "battery_unit";
const SETTINGS_SOLAR_ADJUSTED = "settings_solar_adjusted";
const SETTINGS_PRICE_ZOOM = "settings_price_zoom";
const SETTINGS_HIDE_FEEDIN = "settings_hide_feedin";
const LAST_BATTERY_SMART_COST_LIMIT = "last_battery_smart_cost_limit";
Expand Down Expand Up @@ -126,7 +125,6 @@ export interface Settings {
sessionsGroup: string;
sessionsType: string;
batteryUnit: string;
solarAdjusted: boolean;
priceZoom: boolean;
hideFeedin: boolean;
loadpoints: Record<string, LoadpointSettings>;
Expand Down Expand Up @@ -156,7 +154,6 @@ const settings: Settings = reactive({
sessionsGroup: read(SESSIONS_GROUP),
sessionsType: read(SESSIONS_TYPE),
batteryUnit: read(BATTERY_UNIT),
solarAdjusted: readBool(SETTINGS_SOLAR_ADJUSTED),
priceZoom: readBool(SETTINGS_PRICE_ZOOM),
hideFeedin: readBool(SETTINGS_HIDE_FEEDIN),
loadpoints: readJSON(LOADPOINTS),
Expand Down Expand Up @@ -185,7 +182,6 @@ watch(() => settings.savingsIndicator, save(SAVINGS_INDICATOR));
watch(() => settings.sessionsGroup, save(SESSIONS_GROUP));
watch(() => settings.sessionsType, save(SESSIONS_TYPE));
watch(() => settings.batteryUnit, save(BATTERY_UNIT));
watch(() => settings.solarAdjusted, saveBool(SETTINGS_SOLAR_ADJUSTED));
watch(() => settings.priceZoom, saveBool(SETTINGS_PRICE_ZOOM));
watch(() => settings.hideFeedin, saveBool(SETTINGS_HIDE_FEEDIN));
watch(() => settings.loadpoints, saveJSON(LOADPOINTS), { deep: true });
Expand Down
1 change: 1 addition & 0 deletions assets/js/types/evcc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export interface State {
prioritySoc?: number;
bufferStartSoc?: number;
batteryDischargeControl?: boolean;
solarAdjusted?: boolean;
batteryGridChargeLimit?: number | null;
smartCostAvailable?: boolean;
smartCostType?: SMART_COST_TYPE;
Expand Down
13 changes: 10 additions & 3 deletions assets/js/views/Forecast.vue
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ import GridDetails from "../components/Forecast/GridDetails.vue";
import Co2Chart from "../components/Forecast/Co2Chart.vue";
import Co2Details from "../components/Forecast/Co2Details.vue";
import formatter from "@/mixins/formatter";
import api from "@/api";
import settings from "@/settings";
import store from "../store";
import { adjustedSolar, ForecastType, isStaticTariff } from "@/utils/forecast";
Expand Down Expand Up @@ -234,7 +235,7 @@ export default defineComponent({
return store.state?.experimental;
},
solarAdjusted() {
return settings.solarAdjusted;
return store.state?.solarAdjusted;
},
priceZoom() {
return settings.priceZoom;
Expand Down Expand Up @@ -271,8 +272,14 @@ export default defineComponent({
},
},
methods: {
changeAdjusted() {
settings.solarAdjusted = !settings.solarAdjusted;
async changeAdjusted(e: Event) {
try {
await api.post(
`solaradjusted/${(e.target as HTMLInputElement).checked ? "true" : "false"}`
);
} catch (err) {
console.error(err);
}
},
togglePriceZoom() {
settings.priceZoom = !settings.priceZoom;
Expand Down
3 changes: 3 additions & 0 deletions core/keys/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ const (
BufferSoc = "bufferSoc"
BufferStartSoc = "bufferStartSoc"

// forecast settings
SolarAdjusted = "solarAdjusted"

// optimizer
OptimizerChargingStrategy = "optimizerChargingStrategy"
OptimizerChargingStrategies = "optimizerChargingStrategies"
Expand Down
7 changes: 7 additions & 0 deletions core/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ type Site struct {
batteryDischargeControl bool // prevent battery discharge for fast and planned charging
batteryGridChargeLimit *float64 // grid charging limit

// forecast settings
solarAdjusted bool // adjust solar forecast to real production data

// optimizer settings
optimizerChargingStrategy string // optimizer grid charging strategy

Expand Down Expand Up @@ -374,6 +377,9 @@ func (site *Site) restoreSettings() error {
return err
}
}
if v, err := settings.Bool(keys.SolarAdjusted); err == nil {
site.SetSolarAdjusted(v)
}
if v, err := settings.String(keys.OptimizerChargingStrategy); err == nil && v != "" {
if err := site.SetOptimizerChargingStrategy(v); err != nil {
site.log.WARN.Printf("optimizer charging strategy: %v", err)
Expand Down Expand Up @@ -1167,6 +1173,7 @@ func (site *Site) prepare() {
site.publish(keys.BufferStartSoc, site.bufferStartSoc)
site.publish(keys.BatteryMode, site.batteryMode)
site.publish(keys.BatteryDischargeControl, site.batteryDischargeControl)
site.publish(keys.SolarAdjusted, site.solarAdjusted)
site.publish(keys.ResidualPower, site.GetResidualPower())
site.publish(keys.SmartCostAvailable, site.isDynamicTariff(api.TariffUsagePlanner))
site.publish(keys.SmartFeedInPriorityAvailable, site.isDynamicTariff(api.TariffUsageFeedIn))
Expand Down
9 changes: 9 additions & 0 deletions core/site/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ type API interface {
// GetTariff returns the respective tariff
GetTariff(api.TariffUsage) api.Tariff

//
// forecast
//

// GetSolarAdjusted returns if the solar forecast is adjusted to real production data
GetSolarAdjusted() bool
// SetSolarAdjusted sets if the solar forecast is adjusted to real production data
SetSolarAdjusted(bool)

//
// battery control
//
Expand Down
21 changes: 21 additions & 0 deletions core/site_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,27 @@ func (site *Site) SetBatteryDischargeControl(val bool) error {
return nil
}

// GetSolarAdjusted returns if the solar forecast is adjusted to real production data
func (site *Site) GetSolarAdjusted() bool {
site.RLock()
defer site.RUnlock()
return site.solarAdjusted
}

// SetSolarAdjusted sets if the solar forecast is adjusted to real production data
func (site *Site) SetSolarAdjusted(val bool) {
site.log.DEBUG.Println("set solar adjusted:", val)

site.Lock()
defer site.Unlock()

if site.solarAdjusted != val {
site.solarAdjusted = val
settings.SetBool(keys.SolarAdjusted, val)
site.publish(keys.SolarAdjusted, val)
}
}

func (site *Site) GetBatteryGridChargeLimit() *float64 {
site.RLock()
defer site.RUnlock()
Expand Down
2 changes: 1 addition & 1 deletion core/site_optimizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ func (site *Site) optimizerUpdate(battery []types.Measurement) error {
return err
}

ft = prorate(scaleAndPrune(solarEnergy, site.solarScale(), minLen), firstSlotDuration)
ft = prorate(scaleAndPrune(solarEnergy, site.effectiveSolarScale(), minLen), firstSlotDuration)
}

req := optimizer.OptimizationInput{
Expand Down
15 changes: 11 additions & 4 deletions core/site_tariffs.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

type solarDetails struct {
Scale *float64 `json:"scale,omitempty"` // scale factor yield/forecasted today
Scale float64 `json:"scale"` // scale factor yield/forecasted today, 1 if unscaled
Today dailyDetails `json:"today,omitempty"` // tomorrow
Tomorrow dailyDetails `json:"tomorrow,omitempty"` // tomorrow
DayAfterTomorrow dailyDetails `json:"dayAfterTomorrow,omitempty"` // day after tomorrow
Expand Down Expand Up @@ -152,13 +152,20 @@ func (site *Site) solarDetails(solar api.Rates) solarDetails {
}
}

if scale := site.solarScale(); scale != 1 {
res.Scale = &scale
}
res.Scale = site.solarScale()

return res
}

// effectiveSolarScale returns the solar forecast scale if forecast adjustment
// is enabled, 1 otherwise.
func (site *Site) effectiveSolarScale() float64 {
if !site.GetSolarAdjusted() {
return 1
}
return site.solarScale()
}

// solarScale returns the ratio of produced solar energy to forecasted solar
// energy for the current day, queried from the metrics database. Used to
// adjust forecasts when PV is consistently under-/over-producing relative
Expand Down
1 change: 1 addition & 0 deletions server/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ func (s *HTTPd) RegisterSiteHandlers(site site.API) {
"batterymodedelete": {"DELETE", "/batterymode", updateBatteryMode(site)},
"prioritysoc": {"POST", "/prioritysoc/{value:[0-9.]+}", floatHandler(site.SetPrioritySoc, site.GetPrioritySoc)},
"residualpower": {"POST", "/residualpower/{value:-?[0-9.]+}", floatHandler(site.SetResidualPower, site.GetResidualPower)},
"solaradjusted": {"POST", "/solaradjusted/{value:[01truefalse]+}", boolHandler(pass(site.SetSolarAdjusted), site.GetSolarAdjusted)},
"smartcost": {"POST", "/smartcostlimit/{value:-?[0-9.]+}", updateSmartCostLimit(site, smartCostLimit)},
"smartcostdelete": {"DELETE", "/smartcostlimit", updateSmartCostLimit(site, smartCostLimit)},
"smartfeedin": {"POST", "/smartfeedinprioritylimit/{value:-?[0-9.]+}", updateSmartCostLimit(site, smartFeedInPriorityLimit)},
Expand Down
20 changes: 20 additions & 0 deletions server/mcp/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -2578,6 +2578,26 @@
]
}
},
"/solaradjusted/{enable}": {
"post": {
"description": "Adjust the solar forecast to real production data of the current day.",
"operationId": "setSolarAdjusted",
"parameters": [
{
"$ref": "#/components/parameters/enable"
}
],
"responses": {
"200": {
"$ref": "#/components/responses/BooleanResult"
}
},
"summary": "Adjust solar forecast",
"tags": [
"experimental"
]
}
},
"/state": {
"get": {
"description": "Returns the complete state of the system. This structure is used by the UI. It can be filtered by JQ to only return a subset of the data.",
Expand Down
20 changes: 20 additions & 0 deletions server/mcp/openapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,26 @@ call getEnergyHistory {
}
```

## setSolarAdjusted

Adjust the solar forecast to real production data of the current day.

**Tags:** experimental

**Arguments:**

| Name | Type | Description |
|------|------|-------------|
| enable | string | Charging mode. |

**Example call:**

```json
call setSolarAdjusted {
"enable": "true"
}
```

## getState

Returns the complete state of the system. This structure is used by the UI. It can be filtered by JQ to only return a subset of the data.
Expand Down
1 change: 1 addition & 0 deletions server/mqtt.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ func (m *MQTT) listenSiteSetters(topic string, site site.API) error {
{"batteryDischargeControl", boolSetter(site.SetBatteryDischargeControl)},
{"prioritySoc", floatSetter(site.SetPrioritySoc)},
{"residualPower", floatSetter(site.SetResidualPower)},
{"solarAdjusted", boolSetter(pass(site.SetSolarAdjusted))},
{"smartCostLimit", floatPtrSetter(pass(func(limit *float64) {
for _, lp := range site.Loadpoints() {
lp.SetSmartCostLimit(limit)
Expand Down
12 changes: 12 additions & 0 deletions server/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,18 @@ paths:
responses:
"200":
$ref: "#/components/responses/NumberResult"
/solaradjusted/{enable}:
post:
operationId: setSolarAdjusted
summary: Adjust solar forecast
description: "Adjust the solar forecast to real production data of the current day."
tags:
- experimental
parameters:
- $ref: "#/components/parameters/enable"
responses:
"200":
$ref: "#/components/responses/BooleanResult"
/smartfeedinprioritylimit:
delete:
operationId: removeGlobalSmartFeedInPriorityLimit
Expand Down
Loading