Skip to content

Commit

Permalink
Merge branch 'master' into local/patched
Browse files Browse the repository at this point in the history
* master: (58 commits)
  Add Huawei EMMA (evcc-io#17338)
  Config UI: device value formatting (evcc-io#17258)
  chore: upgrade npm dependencies (evcc-io#17344)
  chore: fix template
  Easee: fix PhaseGetter returning used, not configured, phases  (evcc-io#17326)
  chore: refactor
  MacOS: add gobuildid
  Script: simplify setters
  Tariffs: formula, charges, tax > advanced fields (evcc-io#17301)
  Push: add custom messenger (BC) (evcc-io#17211)
  Script: add missing string setter (evcc-io#17314)
  Sofar: fix docs (evcc-io#17324)
  Polestar: skip test
  Polestar: fix authentication (evcc-io#17276)
  chore: fix line breaks
  chore: fix quotes
  Add Tessie (evcc-io#17274)
  PUN: update api endpoint (evcc-io#17270)
  Revert "EM24: add pv usage & fix energy (evcc-io#17173)"
  Enphase: fix soc
  ...
  • Loading branch information
mabunixda committed Nov 21, 2024
2 parents c4e8c16 + 0dad8b8 commit cbdecb6
Show file tree
Hide file tree
Showing 114 changed files with 2,569 additions and 1,288 deletions.
4 changes: 4 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ builds:
goarch: arm
- goos: windows
goarch: arm64
overrides:
- goos: darwin
ldflags:
- "-B gobuildid"

env:
- CGO_ENABLED=0
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ build::
CGO_ENABLED=0 go build -v $(BUILD_TAGS) $(BUILD_ARGS)

snapshot::
goreleaser --snapshot --skip-publish --clean
goreleaser --snapshot --skip publish --clean

release::
goreleaser --clean
Expand Down
4 changes: 2 additions & 2 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ type CurrentGetter interface {
GetMaxCurrent() (float64, error)
}

// BatteryController optionally allows to control home battery (dis)charging behaviour
// BatteryController optionally allows to control home battery (dis)charging behavior
type BatteryController interface {
SetBatteryMode(BatteryMode) error
}
Expand Down Expand Up @@ -120,7 +120,7 @@ type Authorizer interface {
Authorize(key string) error
}

// PhaseDescriber returns the number of availablephases
// PhaseDescriber returns the number of available phases
type PhaseDescriber interface {
Phases() int
}
Expand Down
8 changes: 6 additions & 2 deletions api/rates.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package api

import (
"errors"
"fmt"
"slices"
"time"
)
Expand Down Expand Up @@ -36,5 +36,9 @@ func (r Rates) Current(now time.Time) (Rate, error) {
}
}

return Rate{}, errors.New("no matching rate")
if len(r) == 0 {
return Rate{}, fmt.Errorf("no matching rate for: %s", now.Local().Format(time.RFC3339))
}
return Rate{}, fmt.Errorf("no matching rate for: %s, %d rates (%s to %s)",
now.Local().Format(time.RFC3339), len(r), r[0].Start.Local().Format(time.RFC3339), r[len(r)-1].End.Local().Format(time.RFC3339))
}
2 changes: 1 addition & 1 deletion assets/js/colors.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const colors = reactive({
price: "#FF912FFF",
co2: "#00916EFF",
background: null,
selfPalette: ["#0fde41ff", "#0ba631ff", "#076f20ff", "#054e18ff", "#043611ff", "#02230bff"],
selfPalette: ["#0FDE41FF", "#FFBD2FFF", "#FD6158FF", "#03C1EFFF", "#0F662DFF", "#FF922EFF"],
palette: [
"#03C1EFFF",
"#FD6158FF",
Expand Down
17 changes: 12 additions & 5 deletions assets/js/components/Config/DeviceTags.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
{{ $t(`config.deviceValue.${entry.name}`) }}
</div>
<div
class="value overflow-hidden text-truncate"
class="value overflow-hidden"
:class="{
'value--error': !!entry.error,
'value--warning': entry.warning,
'value--muted': entry.muted || entry.value === false,
'text-truncate': allowTruncate(entry.name),
'flex-shrink-0': !allowTruncate(entry.name),
}"
>
{{ fmtDeviceValue(entry) }}
Expand All @@ -23,7 +25,9 @@
</div>
</template>
<script>
import formatter from "../../mixins/formatter";
import formatter, { POWER_UNIT } from "../../mixins/formatter";
const NO_TRUNCATE = ["phasePowers", "phaseVoltages", "phaseCurrents"];
export default {
name: "DeviceTags",
Expand Down Expand Up @@ -62,11 +66,11 @@ export default {
case "range":
return `${this.fmtNumber(value, 0)} km`;
case "phaseCurrents":
return value.map((v) => this.fmtNumber(v, 0)).join(" ") + " A";
return value.map((v) => this.fmtNumber(v, 1)).join(" · ") + " A";
case "phaseVoltages":
return value.map((v) => this.fmtNumber(v, 0)).join(" ") + " V";
return value.map((v) => this.fmtNumber(v, 0)).join(" · ") + " V";
case "phasePowers":
return value.map((v) => this.fmtW(v)).join(", ");
return value.map((v) => this.fmtW(v, POWER_UNIT.KW, false)).join(" · ") + " kW";
case "chargeStatus":
return this.$t(`config.deviceValue.chargeStatus${value}`);
case "gridPrice":
Expand All @@ -86,6 +90,9 @@ export default {
}
return value;
},
allowTruncate(name) {
return !NO_TRUNCATE.includes(name);
},
},
};
</script>
Expand Down
4 changes: 2 additions & 2 deletions assets/js/components/Config/PropertyCollapsible.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
type="button"
@click="toggle"
>
<span v-if="open">Hide advanced settings</span>
<span v-else>Show advanced settings</span>
<span v-if="open">{{ $t("config.general.hideAdvancedSettings") }}</span>
<span v-else>{{ $t("config.general.showAdvancedSettings") }}</span>
<DropdownIcon class="icon" :class="{ iconUp: open }" />
</button>

Expand Down
15 changes: 15 additions & 0 deletions assets/js/components/Config/PropertyField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,14 @@
import "@h2d2/shopicons/es/regular/minus";
import VehicleIcon from "../VehicleIcon";
import SelectGroup from "../SelectGroup.vue";
import formatter from "../../mixins/formatter";
const NS_PER_SECOND = 1000000000;
export default {
name: "PropertyField",
components: { VehicleIcon, SelectGroup },
mixins: [formatter],
props: {
id: String,
property: String,
Expand Down Expand Up @@ -149,6 +153,9 @@ export default {
if (this.property === "capacity") {
return "kWh";
}
if (this.type === "Duration") {
return this.fmtSecondUnit(this.value);
}
return null;
},
icons() {
Expand Down Expand Up @@ -203,6 +210,10 @@ export default {
return Array.isArray(this.modelValue) ? this.modelValue.join("\n") : "";
}
if (this.type === "Duration" && typeof this.modelValue === "number") {
return this.modelValue / NS_PER_SECOND;
}
return this.modelValue;
},
set(value) {
Expand All @@ -216,6 +227,10 @@ export default {
newValue = value ? value.split("\n") : [];
}
if (this.type === "Duration" && typeof newValue === "number") {
newValue = newValue * NS_PER_SECOND;
}
this.$emit("update:modelValue", newValue);
},
},
Expand Down
9 changes: 9 additions & 0 deletions assets/js/mixins/formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,15 @@ export default {
day: "numeric",
}).format(date);
},
fmtSecondUnit: function (seconds) {
return new Intl.NumberFormat(this.$i18n?.locale, {
style: "unit",
unit: "second",
unitDisplay: "long",
})
.formatToParts(seconds)
.find((part) => part.type === "unit").value;
},
fmtMoney: function (amout = 0, currency = "EUR", decimals = true, withSymbol = false) {
const currencyDisplay = withSymbol ? "narrowSymbol" : "code";
const result = new Intl.NumberFormat(this.$i18n?.locale, {
Expand Down
27 changes: 23 additions & 4 deletions charger/easee.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type Easee struct {
lastEnergyPollMux sync.Mutex
maxChargerCurrent float64
dynamicChargerCurrent float64
dynamicCircuitCurrent [3]float64
current float64
chargerEnabled bool
smartCharging bool
Expand All @@ -61,7 +62,6 @@ type Easee struct {
pilotMode string
reasonForNoCurrent int
phaseMode int
outputPhase int
sessionStartEnergy *float64
currentPower, sessionEnergy, totalEnergy,
currentL1, currentL2, currentL3 float64
Expand Down Expand Up @@ -313,8 +313,12 @@ func (c *Easee) ProductUpdate(i json.RawMessage) {
c.currentL3 = value.(float64)
case easee.PHASE_MODE:
c.phaseMode = value.(int)
case easee.OUTPUT_PHASE:
c.outputPhase = value.(int) / 10 // API gives 0,10,30 for 0,1,3p
case easee.DYNAMIC_CIRCUIT_CURRENT_P1:
c.dynamicCircuitCurrent[0] = value.(float64)
case easee.DYNAMIC_CIRCUIT_CURRENT_P2:
c.dynamicCircuitCurrent[1] = value.(float64)
case easee.DYNAMIC_CIRCUIT_CURRENT_P3:
c.dynamicCircuitCurrent[2] = value.(float64)
case easee.MAX_CHARGER_CURRENT:
c.maxChargerCurrent = value.(float64)
case easee.DYNAMIC_CHARGER_CURRENT:
Expand Down Expand Up @@ -814,7 +818,22 @@ var _ api.PhaseGetter = (*Easee)(nil)
func (c *Easee) GetPhases() (int, error) {
c.mux.RLock()
defer c.mux.RUnlock()
return c.outputPhase, nil
var phases int
if c.circuit != 0 {
// circuit level controlled charger
for _, dcc := range c.dynamicCircuitCurrent {
if dcc > 0 {
phases++
}
}
} else {
// charger level
phases = c.phaseMode
if phases == 2 { // map automatic to 3p
phases = 3
}
}
return phases, nil
}

var _ api.Identifier = (*Easee)(nil)
Expand Down
4 changes: 2 additions & 2 deletions charger/eebus.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ func (c *EEBus) writeCurrentLimitData(evEntity spineapi.EntityRemoteInterface, c
}

// if VAS VW is available, limits are completely covered by it
// this way evcc can fully control the charging behaviour
// this way evcc can fully control the charging behavior
if c.writeLoadControlLimitsVASVW(evEntity, limits) {
c.mux.Lock()
defer c.mux.Unlock()
Expand Down Expand Up @@ -410,7 +410,7 @@ func (c *EEBus) hasActiveVASVW(evEntity spineapi.EntityRemoteInterface) bool {
return false
}

// provides support for the special VW VAS ISO15118-2 charging behaviour if supported
// provides support for the special VW VAS ISO15118-2 charging behavior if supported
// will return false if it isn't supported or successful
//
// this functionality allows to fully control charging without the EV actually having a
Expand Down
7 changes: 4 additions & 3 deletions charger/homewizard.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ func NewHomeWizardFromConfig(other map[string]interface{}) (api.Charger, error)
cc := struct {
embed `mapstructure:",squash"`
URI string
Usage string
StandbyPower float64
Cache time.Duration
}{
Expand All @@ -37,12 +38,12 @@ func NewHomeWizardFromConfig(other map[string]interface{}) (api.Charger, error)
return nil, err
}

return NewHomeWizard(cc.embed, cc.URI, cc.StandbyPower, cc.Cache)
return NewHomeWizard(cc.embed, cc.URI, cc.Usage, cc.StandbyPower, cc.Cache)
}

// NewHomeWizard creates HomeWizard charger
func NewHomeWizard(embed embed, uri string, standbypower float64, cache time.Duration) (*HomeWizard, error) {
conn, err := homewizard.NewConnection(uri, cache)
func NewHomeWizard(embed embed, uri string, usage string, standbypower float64, cache time.Duration) (*HomeWizard, error) {
conn, err := homewizard.NewConnection(uri, usage, cache)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion charger/mennekes-compact.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const (
mennekesRegChargedEnergyTotal = 0x1000 // float32

mennekesAllowed = 1
mennekesHeartbeatInterval = 8 * time.Second
mennekesHeartbeatInterval = 5 * time.Second
mennekesHeartbeatToken = 0x55AA // 21930
)

Expand Down
31 changes: 23 additions & 8 deletions charger/ocpp/cs_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,33 @@ package ocpp

import (
"fmt"
"strings"
)

func (cs *CS) print(s string) {
// var ok bool
// if s, ok = strings.CutPrefix(s, "sent JSON message to"); ok {
// s = "send" + s
// } else if s, ok = strings.CutPrefix(s, "received JSON message from"); ok {
// s = "recv" + s
// }
// if ok {
cs.log.TRACE.Println(s)
// for _, p := range []string{
// "completed request",
// "dispatched request",
// "enqueued CALL",
// "handling incoming",
// "sent CALL",
// "started timeout",
// "timeout canceled",
// } {
// if strings.HasPrefix(s, p) {
// return
// }
// }

var ok bool
if s, ok = strings.CutPrefix(s, "sent JSON message to"); ok {
s = "send" + s
} else if s, ok = strings.CutPrefix(s, "received JSON message from"); ok {
s = "recv" + s
}
if ok {
cs.log.TRACE.Println(s)
}
}

func (cs *CS) Debug(args ...interface{}) {
Expand Down
3 changes: 3 additions & 0 deletions cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const (
flagIgnoreDatabase = "ignore-db"
flagIgnoreDatabaseDescription = "Run command ignoring service database"

flagDisableAuth = "disable-auth"
flagDisableAuthDescription = "Disable authentication (dangerous)"

flagBatteryMode = "battery-mode"
flagBatteryModeDescription = "Set battery mode (normal, hold, charge)"
flagBatteryModeWait = "battery-mode-wait"
Expand Down
11 changes: 10 additions & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/evcc-io/evcc/server"
"github.com/evcc-io/evcc/server/updater"
"github.com/evcc-io/evcc/util"
"github.com/evcc-io/evcc/util/auth"
"github.com/evcc-io/evcc/util/config"
"github.com/evcc-io/evcc/util/pipe"
"github.com/evcc-io/evcc/util/sponsor"
Expand Down Expand Up @@ -75,6 +76,8 @@ func init() {

rootCmd.Flags().Bool("profile", false, "Expose pprof profiles")
bind(rootCmd, "profile")

rootCmd.Flags().Bool(flagDisableAuth, false, flagDisableAuthDescription)
}

// initConfig reads in config file and ENV variables if set
Expand Down Expand Up @@ -270,7 +273,13 @@ func runRoot(cmd *cobra.Command, args []string) {
// allow web access for vehicles
configureAuth(conf.Network, config.Instances(config.Vehicles().Devices()), httpd.Router(), valueChan)

httpd.RegisterSystemHandler(valueChan, cache, func() {
auth := auth.New()
if ok, _ := cmd.Flags().GetBool(flagDisableAuth); ok {
log.WARN.Println("❗❗❗ Authentication is disabled. This is dangerous. Your data and credentials are not protected.")
auth.Disable()
}

httpd.RegisterSystemHandler(valueChan, cache, auth, func() {
log.INFO.Println("evcc was stopped by user. OS should restart the service. Or restart manually.")
once.Do(func() { close(stopC) }) // signal loop to end
})
Expand Down
2 changes: 1 addition & 1 deletion core/loadpoint_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func (lp *Loadpoint) plannerActive() (active bool) {
// don't stop an already running slot if goal was not met
lp.log.DEBUG.Println("plan: continuing until end of slot")
return true
case requiredDuration < smallGapDuration:
case requiredDuration < smallSlotDuration:
lp.log.DEBUG.Printf("plan: continuing for remaining %v", requiredDuration.Round(time.Second))
return true
case lp.clock.Until(planStart) < smallGapDuration:
Expand Down
2 changes: 1 addition & 1 deletion core/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ func (site *Site) DumpConfig() {
// verify vehicle detection
if vehicles := site.Vehicles().Instances(); len(vehicles) > 1 {
for _, v := range vehicles {
if _, ok := v.(api.ChargeState); !ok {
if _, ok := v.(api.ChargeState); !ok && len(v.Identifiers()) == 0 {
site.log.WARN.Printf("vehicle '%s' does not support automatic detection", v.Title())
}
}
Expand Down
Loading

0 comments on commit cbdecb6

Please sign in to comment.