Skip to content

Commit

Permalink
Merge branch 'master' into feature/stiebel-isg
Browse files Browse the repository at this point in the history
  • Loading branch information
andig committed Dec 14, 2024
2 parents 4f3b676 + 6b1dd99 commit 11ee97f
Show file tree
Hide file tree
Showing 255 changed files with 5,916 additions and 2,421 deletions.
11 changes: 9 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {
"moby": true,
"installDockerBuildx": true,
"installDockerComposeSwitch": true,
"version": "latest",
"dockerDashComposeVersion": "v2"
},
"ghcr.io/devcontainers/features/node:1": {
"nodeGypDependencies": true,
"installYarnUsingApt": true,
"version": "latest",
"version": "lts",
"pnpmVersion": "latest",
"nvmVersion": "latest"
},
"ghcr.io/devcontainers/features/go:1": {
"version": "latest"
}
},
"postCreateCommand": "make install-ui && make install",
Expand All @@ -26,5 +30,8 @@
"octref.vetur"
]
}
},
"remoteEnv": {
"GOTOOLCHAIN": "auto"
}
}
}
9 changes: 9 additions & 0 deletions .goreleaser-nightly.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ builds:
goarch: arm
- goos: windows
goarch: arm64
overrides:
- goos: darwin
goarch: arm64
ldflags:
- -X github.com/evcc-io/evcc/server.Version={{ .Tag }} -X github.com/evcc-io/evcc/server.Commit={{ .ShortCommit }} -X github.com/evcc-io/evcc/vehicle/tesla.TESLA_CLIENT_ID={{ .Env.TESLA_CLIENT_ID }} -s -w -B gobuildid
- goos: darwin
goarch: amd64
ldflags:
- -X github.com/evcc-io/evcc/server.Version={{ .Tag }} -X github.com/evcc-io/evcc/server.Commit={{ .ShortCommit }} -X github.com/evcc-io/evcc/vehicle/tesla.TESLA_CLIENT_ID={{ .Env.TESLA_CLIENT_ID }} -s -w -B gobuildid

archives:
- builds:
Expand Down
7 changes: 6 additions & 1 deletion .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,13 @@ builds:
goarch: arm64
overrides:
- goos: darwin
goarch: arm64
ldflags:
- -X github.com/evcc-io/evcc/server.Version={{ .Version }} -X github.com/evcc-io/evcc/vehicle/tesla.TESLA_CLIENT_ID={{ .Env.TESLA_CLIENT_ID }} -s -w -B gobuildid
- goos: darwin
goarch: amd64
ldflags:
- "-B gobuildid"
- -X github.com/evcc-io/evcc/server.Version={{ .Version }} -X github.com/evcc-io/evcc/vehicle/tesla.TESLA_CLIENT_ID={{ .Env.TESLA_CLIENT_ID }} -s -w -B gobuildid

env:
- CGO_ENABLED=0
Expand Down
1 change: 1 addition & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export default {
printWidth: 100,
trailingComma: "es5",
plugins: ["prettier-plugin-sh"],
};
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

evcc is an extensible EV Charge Controller and home energy management system. Featured in [PV magazine](https://www.pv-magazine.de/2021/01/15/selbst-ist-der-groeoenlandhof-wallbox-ladesteuerung-selbst-gebaut/).

![Screenshot](docs/screenshot.png)
![Screenshot](docs/screenshot.webp)

## Features

Expand Down Expand Up @@ -55,4 +55,4 @@ Maintaining evcc consumes time and effort. With the vast amount of different dev

While evcc is open source, we would also like to encourage vendors to provide open source hardware devices, public documentation and support open source projects like ours that provide additional value to otherwise closed hardware. Where this is not the case, evcc requires "sponsor token" to finance ongoing development and support of evcc.

The personal sponsor token requires a [Github Sponsorship](https://github.com/sponsors/evcc-io) and can be requested at [sponsor.evcc.io](https://sponsor.evcc.io/).
Learn more about our [sponsorship model](https://docs.evcc.io/docs/sponsorship).
9 changes: 9 additions & 0 deletions api/plans.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package api

type RepeatingPlanStruct struct {
Weekdays []int `json:"weekdays"` // 0-6 (Sunday-Saturday)
Time string `json:"time"` // HH:MM
Tz string `json:"tz"` // timezone in IANA format
Soc int `json:"soc"`
Active bool `json:"active"`
}
4 changes: 4 additions & 0 deletions assets/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -632,3 +632,7 @@ html.app .modal-dialog {
.alert-danger code {
color: var(--evcc-darkest-green);
}

input::-webkit-date-and-time-value {
text-align: left;
}
49 changes: 35 additions & 14 deletions assets/js/components/ChargingPlan.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
data-testid="charging-plan"
>
<div class="value m-0 d-block align-items-baseline justify-content-center">
<button class="value-button p-0" :class="buttonColor" @click="openModal">
<button
class="value-button p-0"
:class="buttonColor"
data-testid="charging-plan-button"
@click="openModal"
>
<strong v-if="enabled">
<span class="targetTimeLabel"> {{ targetTimeLabel }}</span>
<div
Expand All @@ -33,6 +38,7 @@
tabindex="-1"
role="dialog"
aria-hidden="true"
data-testid="charging-plan-modal"
>
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
Expand Down Expand Up @@ -74,11 +80,12 @@
</li>
</ul>
<div v-if="isModalVisible">
<ChargingPlanSettings
<ChargingPlansSettings
v-if="departureTabActive"
v-bind="chargingPlanSettingsProps"
@plan-updated="updatePlan"
@plan-removed="removePlan"
v-bind="chargingPlansSettingsProps"
@static-plan-updated="updateStaticPlan"
@static-plan-removed="removeStaticPlan"
@repeating-plans-updated="updateRepeatingPlans"
/>
<ChargingPlanArrival
v-if="arrivalTabActive"
Expand All @@ -98,7 +105,7 @@
<script>
import Modal from "bootstrap/js/dist/modal";
import LabelAndValue from "./LabelAndValue.vue";
import ChargingPlanSettings from "./ChargingPlanSettings.vue";
import ChargingPlansSettings from "./ChargingPlansSettings.vue";
import ChargingPlanArrival from "./ChargingPlanArrival.vue";
import formatter from "../mixins/formatter";
Expand All @@ -110,7 +117,7 @@ const ONE_MINUTE = 60 * 1000;
export default {
name: "ChargingPlan",
components: { LabelAndValue, ChargingPlanSettings, ChargingPlanArrival },
components: { LabelAndValue, ChargingPlansSettings, ChargingPlanArrival },
mixins: [formatter, collector],
props: {
currency: String,
Expand Down Expand Up @@ -162,12 +169,18 @@ export default {
limitSoc: function () {
return this.vehicle?.limitSoc;
},
plans: function () {
staticPlan: function () {
if (this.socBasedPlanning) {
return this.vehicle?.plans || [];
return this.vehicle?.plan;
}
if (this.planEnergy && this.planTime) {
return [{ energy: this.planEnergy, time: this.planTime }];
return { energy: this.planEnergy, time: this.planTime };
}
return null;
},
repeatingPlans: function () {
if (this.vehicle?.repeatingPlans.length > 0) {
return [...this.vehicle.repeatingPlans];
}
return [];
},
Expand All @@ -183,8 +196,8 @@ export default {
arrivalTabActive: function () {
return this.activeTab === "arrival";
},
chargingPlanSettingsProps: function () {
return this.collectProps(ChargingPlanSettings);
chargingPlansSettingsProps: function () {
return this.collectProps(ChargingPlansSettings);
},
chargingPlanArrival: function () {
return this.collectProps(ChargingPlanArrival);
Expand All @@ -211,6 +224,11 @@ export default {
effectivePlanTime() {
this.updateTargetTimeLabel();
},
"$i18n.locale": {
handler() {
this.updateTargetTimeLabel();
},
},
},
mounted() {
this.modal = Modal.getOrCreateInstance(this.$refs.modal);
Expand Down Expand Up @@ -263,21 +281,24 @@ export default {
showArrivalTab: function () {
this.activeTab = "arrival";
},
updatePlan: function ({ soc, time, energy }) {
updateStaticPlan: function ({ soc, time, energy }) {
const timeISO = time.toISOString();
if (this.socBasedPlanning) {
api.post(`${this.apiVehicle}plan/soc/${soc}/${timeISO}`);
} else {
api.post(`${this.apiLoadpoint}plan/energy/${energy}/${timeISO}`);
}
},
removePlan: function () {
removeStaticPlan: function () {
if (this.socBasedPlanning) {
api.delete(`${this.apiVehicle}plan/soc`);
} else {
api.delete(`${this.apiLoadpoint}plan/energy`);
}
},
updateRepeatingPlans: function (plans) {
api.post(`${this.apiVehicle}plan/repeating`, { plans });
},
setMinSoc: function (soc) {
api.post(`${this.apiVehicle}minsoc/${soc}`);
},
Expand Down
4 changes: 2 additions & 2 deletions assets/js/components/ChargingPlanPreview.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ describe("basics", () => {
result = wrapper.vm.slots;
});

test("should return 42 slots", () => {
expect(result.length).eq(42);
test("should return 39 slots", () => {
expect(result.length).eq(39);
});

test("slots should be an hour apart", () => {
Expand Down
37 changes: 34 additions & 3 deletions assets/js/components/ChargingPlanPreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@
</div>
</div>
</div>
<TariffChart :slots="slots" @slot-hovered="slotHovered" />
<TariffChart
:slots="slots"
:target-text="targetText"
:target-offset="targetHourOffset"
@slot-hovered="slotHovered"
/>
</div>
</template>

Expand Down Expand Up @@ -114,12 +119,28 @@ export default {
}
return null;
},
targetHourOffset() {
if (!this.targetTime) {
return null;
}
const start = new Date(this.startTime);
start.setMinutes(0);
start.setSeconds(0);
start.setMilliseconds(0);
return (this.targetTime.getTime() - start.getTime()) / (60 * 60 * 1000);
},
targetText() {
if (!this.targetTime) {
return null;
}
return this.fmtWeekdayTime(this.targetTime);
},
slots() {
const result = [];
const rates = this.convertDates(this.rates);
const plan = this.convertDates(this.plan);
const oneHour = 60 * 60 * 1000;
for (let i = 0; i < 42; i++) {
for (let i = 0; i < 39; i++) {
const start = new Date(this.startTime.getTime() + oneHour * i);
const startHour = start.getHours();
start.setMinutes(0);
Expand All @@ -132,13 +153,23 @@ export default {
const toLate = this.targetTime && this.targetTime <= start;
// TODO: handle multiple matching time slots
const price = this.findSlotInRange(start, end, rates)?.price;
const isTarget = start <= this.targetTime && end > this.targetTime;
const charging = this.findSlotInRange(start, end, plan) != null;
const warning =
charging &&
this.targetTime &&
end > this.targetTime &&
this.targetTime < this.endTime;
result.push({ day, price, startHour, endHour, charging, toLate, warning });
result.push({
day,
price,
startHour,
endHour,
charging,
toLate,
warning,
isTarget,
});
}
return result;
},
Expand Down
Loading

0 comments on commit 11ee97f

Please sign in to comment.