Signal vehicle detection and send message on guest vehicle (#4139)
This commit is contained in:
parent
14693d2267
commit
8f665ec4b9
10 changed files with 120 additions and 57 deletions
|
|
@ -149,9 +149,6 @@ export default {
|
|||
</script>
|
||||
|
||||
<style scoped>
|
||||
.car-icon {
|
||||
width: 1.75rem;
|
||||
}
|
||||
.details > div {
|
||||
flex-grow: 1;
|
||||
flex-basis: 0;
|
||||
|
|
|
|||
|
|
@ -1,33 +1,42 @@
|
|||
<template>
|
||||
<div class="d-flex justify-content-between mb-3 align-items-center">
|
||||
<VehicleOptions
|
||||
v-if="showOptions"
|
||||
class="options"
|
||||
:vehicles="otherVehicles"
|
||||
:is-unknown="isUnknown"
|
||||
@change-vehicle="changeVehicle"
|
||||
@remove-vehicle="removeVehicle"
|
||||
>
|
||||
<h4 class="d-flex align-items-center m-0 flex-grow-1 overflow-hidden">
|
||||
<shopicon-regular-car3
|
||||
v-if="carIcon"
|
||||
class="me-2 flex-shrink-0 car-icon"
|
||||
></shopicon-regular-car3>
|
||||
<shopicon-regular-cablecharge
|
||||
v-else
|
||||
class="me-2 flex-shrink-0 car-icon"
|
||||
></shopicon-regular-cablecharge>
|
||||
<h4 class="d-flex align-items-center m-0 flex-grow-1 overflow-hidden">
|
||||
<shopicon-regular-refresh
|
||||
v-if="icon === 'refresh'"
|
||||
ref="refresh"
|
||||
data-bs-toggle="tooltip"
|
||||
:title="$t('main.vehicle.detectionActive')"
|
||||
class="me-2 flex-shrink-0 spin"
|
||||
></shopicon-regular-refresh>
|
||||
<shopicon-regular-car3
|
||||
v-else-if="icon === 'car'"
|
||||
class="me-2 flex-shrink-0"
|
||||
></shopicon-regular-car3>
|
||||
<shopicon-regular-cablecharge
|
||||
v-else
|
||||
class="me-2 flex-shrink-0"
|
||||
></shopicon-regular-cablecharge>
|
||||
<VehicleOptions
|
||||
v-if="showOptions"
|
||||
class="options"
|
||||
:vehicles="otherVehicles"
|
||||
:is-unknown="isUnknown"
|
||||
@change-vehicle="changeVehicle"
|
||||
@remove-vehicle="removeVehicle"
|
||||
>
|
||||
<span class="flex-grow-1 text-truncate vehicle-name">
|
||||
{{ name }}
|
||||
</span>
|
||||
</h4>
|
||||
</VehicleOptions>
|
||||
</VehicleOptions>
|
||||
</h4>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import "@h2d2/shopicons/es/regular/car3";
|
||||
import "@h2d2/shopicons/es/regular/refresh";
|
||||
import "@h2d2/shopicons/es/regular/cablecharge";
|
||||
import { Tooltip } from "bootstrap";
|
||||
|
||||
import VehicleOptions from "./VehicleOptions.vue";
|
||||
|
||||
|
|
@ -37,14 +46,21 @@ export default {
|
|||
props: {
|
||||
vehiclePresent: Boolean,
|
||||
vehicleTitle: String,
|
||||
vehicleDetectionActive: Boolean,
|
||||
parked: Boolean,
|
||||
connected: Boolean,
|
||||
vehicles: { type: Array, default: () => [] },
|
||||
},
|
||||
emits: ["change-vehicle", "remove-vehicle"],
|
||||
computed: {
|
||||
carIcon() {
|
||||
return this.connected || this.parked;
|
||||
icon() {
|
||||
if (this.vehicleDetectionActive) {
|
||||
return "refresh";
|
||||
}
|
||||
if (this.connected || this.parked) {
|
||||
return "car";
|
||||
}
|
||||
return null;
|
||||
},
|
||||
name() {
|
||||
if (this.vehiclePresent || this.parked) {
|
||||
|
|
@ -70,6 +86,14 @@ export default {
|
|||
return !this.isUnknown || this.vehicles.length;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
icon: function () {
|
||||
this.tooltip();
|
||||
},
|
||||
},
|
||||
mounted: function () {
|
||||
this.tooltip();
|
||||
},
|
||||
methods: {
|
||||
changeVehicle(index) {
|
||||
this.$emit("change-vehicle", index);
|
||||
|
|
@ -77,6 +101,13 @@ export default {
|
|||
removeVehicle() {
|
||||
this.$emit("remove-vehicle");
|
||||
},
|
||||
tooltip() {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.refresh) {
|
||||
new Tooltip(this.$refs.refresh);
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -89,4 +120,19 @@ export default {
|
|||
text-decoration: underline;
|
||||
text-decoration-color: var(--evcc-gray);
|
||||
}
|
||||
.spin {
|
||||
animation: rotation 1s infinite cubic-bezier(0.37, 0, 0.63, 1);
|
||||
}
|
||||
.spin >>> svg {
|
||||
/* workaround to fix the not perfectly centered shopicon. Remove once its fixed in @h2d2/shopicons */
|
||||
transform: translateY(-0.7px);
|
||||
}
|
||||
@keyframes rotation {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -120,6 +120,7 @@ export default {
|
|||
none: "Kein Fahrzeug",
|
||||
unknown: "Gastfahrzeug",
|
||||
changeVehicle: "Fahrzeug ändern",
|
||||
detectionActive: "Fahrzeugerkennung läuft ...",
|
||||
},
|
||||
vehicleSoC: {
|
||||
disconnected: "getrennt",
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ export default {
|
|||
none: "No vehicle",
|
||||
unknown: "Guest vehicle",
|
||||
changeVehicle: "Change Vehicle",
|
||||
detectionActive: "Detecting vehicle ...",
|
||||
},
|
||||
vehicleSoC: {
|
||||
disconnected: "disconnected",
|
||||
|
|
|
|||
|
|
@ -4,4 +4,6 @@ const (
|
|||
phasesConfigured = "phasesConfigured" // configured phases (1/3, 0 for 1p3p chargers)
|
||||
phasesEnabled = "phasesEnabled" // enabled phases (1/3)
|
||||
phasesActive = "phasesActive" // active phases as used by vehicle (1/2/3)
|
||||
|
||||
vehicleDetectionActive = "vehicleDetectionActive" // vehicle detection is active (bool)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -29,13 +29,14 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
evChargeStart = "start" // update chargeTimer
|
||||
evChargeStop = "stop" // update chargeTimer
|
||||
evChargeCurrent = "current" // update fakeChargeMeter
|
||||
evChargePower = "power" // update chargeRater
|
||||
evVehicleConnect = "connect" // vehicle connected
|
||||
evVehicleDisconnect = "disconnect" // vehicle disconnected
|
||||
evVehicleSoC = "soc" // vehicle soc progress
|
||||
evChargeStart = "start" // update chargeTimer
|
||||
evChargeStop = "stop" // update chargeTimer
|
||||
evChargeCurrent = "current" // update fakeChargeMeter
|
||||
evChargePower = "power" // update chargeRater
|
||||
evVehicleConnect = "connect" // vehicle connected
|
||||
evVehicleDisconnect = "disconnect" // vehicle disconnected
|
||||
evVehicleSoC = "soc" // vehicle soc progress
|
||||
evVehicleUnidentified = "guest" // vehicle unidentified
|
||||
|
||||
pvTimer = "pv"
|
||||
pvEnable = "enable"
|
||||
|
|
@ -418,8 +419,9 @@ func (lp *LoadPoint) evVehicleDisconnectHandler() {
|
|||
|
||||
lp.pushEvent(evVehicleDisconnect)
|
||||
|
||||
// remove charger vehicle id
|
||||
// remove charger vehicle id and stop potential detection
|
||||
lp.setVehicleIdentifier("")
|
||||
lp.stopVehicleDetection()
|
||||
|
||||
// remove active vehicle if not default
|
||||
if lp.vehicle != lp.defaultVehicle {
|
||||
|
|
@ -526,6 +528,7 @@ func (lp *LoadPoint) Prepare(uiChan chan<- util.Param, pushChan chan<- push.Even
|
|||
lp.Unlock()
|
||||
|
||||
// set default or start detection
|
||||
lp.publish(vehicleDetectionActive, false)
|
||||
lp.vehicleDefaultOrDetect()
|
||||
|
||||
// read initial charger state to prevent immediately disabling charger
|
||||
|
|
@ -738,6 +741,8 @@ func (lp *LoadPoint) identifyVehicle() {
|
|||
lp.setVehicleIdentifier(id)
|
||||
|
||||
if id != "" {
|
||||
lp.stopVehicleDetection()
|
||||
|
||||
lp.log.DEBUG.Println("charger vehicle id:", id)
|
||||
|
||||
if vehicle := lp.selectVehicleByID(id); vehicle != nil {
|
||||
|
|
@ -855,11 +860,16 @@ func (lp *LoadPoint) unpublishVehicle() {
|
|||
|
||||
// vehicleUnidentified checks if there are associated vehicles and starts discovery period
|
||||
func (lp *LoadPoint) vehicleUnidentified() bool {
|
||||
res := len(lp.coordinatedVehicles()) > 0 && lp.vehicle == nil &&
|
||||
lp.clock.Since(lp.vehicleDetect) < vehicleDetectDuration
|
||||
res := len(lp.coordinatedVehicles()) > 0 && lp.vehicle == nil
|
||||
|
||||
// request vehicle api refresh while waiting to identify
|
||||
if res {
|
||||
if lp.clock.Since(lp.vehicleDetect) > vehicleDetectDuration {
|
||||
lp.stopVehicleDetection()
|
||||
lp.pushEvent(evVehicleUnidentified)
|
||||
return false
|
||||
}
|
||||
|
||||
select {
|
||||
case <-lp.vehicleDetectTicker.C:
|
||||
lp.log.DEBUG.Println("vehicle api refresh")
|
||||
|
|
@ -889,6 +899,7 @@ func (lp *LoadPoint) vehicleDefaultOrDetect() {
|
|||
// reset connection timer and starts api refresh timer
|
||||
lp.vehicleDetect = lp.clock.Now()
|
||||
lp.vehicleDetectTicker = lp.clock.Ticker(vehicleDetectInterval)
|
||||
lp.publish(vehicleDetectionActive, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -898,6 +909,7 @@ func (lp *LoadPoint) stopVehicleDetection() {
|
|||
if lp.vehicleDetectTicker != nil {
|
||||
lp.vehicleDetectTicker.Stop()
|
||||
}
|
||||
lp.publish(vehicleDetectionActive, false)
|
||||
}
|
||||
|
||||
// identifyVehicleByStatus validates if the active vehicle is still connected to the loadpoint
|
||||
|
|
@ -909,6 +921,7 @@ func (lp *LoadPoint) identifyVehicleByStatus() {
|
|||
_, ok := lp.charger.(api.Identifier)
|
||||
|
||||
if vehicle := lp.coordinator.IdentifyVehicleByStatus(!ok); vehicle != nil {
|
||||
lp.stopVehicleDetection()
|
||||
lp.setActiveVehicle(vehicle)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
dist/index.html
vendored
4
dist/index.html
vendored
|
|
@ -20,8 +20,8 @@
|
|||
<meta name="theme-color" content="#020318" />
|
||||
|
||||
<title>evcc</title>
|
||||
<script type="module" crossorigin src="./assets/index.f014e26a.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index.c0100ffd.css">
|
||||
<script type="module" crossorigin src="./assets/index.9738d453.js"></script>
|
||||
<link rel="stylesheet" href="./assets/index.fb2bc24b.css">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -177,6 +177,9 @@ messaging:
|
|||
soc: # vehicle soc update event
|
||||
title: SoC updated
|
||||
msg: Battery charged to ${vehicleSoC:%.0f}%
|
||||
guest: # vehicle could not be identified
|
||||
title: Unknown vehicle
|
||||
msg: Unknown vehicle, guest connected?
|
||||
services:
|
||||
# - type: pushover
|
||||
# app: # app id
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue