SMA: remove remote control (BC) (#23906)

This commit is contained in:
andig 2025-10-03 16:51:12 +02:00 • committed by GitHub
parent 16f4681429
commit 148aa76b67
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 35 additions and 254 deletions

View file

@ -92,7 +92,6 @@ export default {
case "singlePhase":
case "enabled":
case "configured":
case "allowControl":
return value
? this.$t("config.deviceValue.yes")
: this.$t("config.deviceValue.no");

View file

@ -10,19 +10,6 @@
@changed="$emit('changed')"
>
<template #default="{ values }">
<FormRow id="shmControl" :label="$t('config.shm.labelControl')" optional>
<div class="d-flex">
<input
id="shmControl"
v-model="values.allowControl"
class="form-check-input"
type="checkbox"
/>
<label class="form-check-label ms-2" for="shmControl">
{{ $t("config.shm.labelAllowControl") }}
</label>
</div>
</FormRow>
<PropertyCollapsible>
<template #advanced>
<p>{{ $t("config.shm.descriptionIds") }}</p>

View file

@ -38,7 +38,6 @@ export interface HemsConfig {
}
export interface ShmConfig {
allowControl: boolean;
vendorId: string;
deviceId: string;
}

View file

@ -638,8 +638,7 @@ export default defineComponent({
return this.vehicles.map((v) => ({ key: v.name, name: v.config?.title || v.name }));
},
shmTags() {
const { allowControl } = store.state?.shm || {};
return { allowControl: { value: allowControl || false } };
return { configured: { value: true } };
},
hemsTags() {
const { type } = store.state?.hems || {};

View file

@ -152,14 +152,13 @@ type Loadpoint struct {
planActive bool // charge plan exists and has a currently active slot
// cached state
status api.ChargeStatus // Charger status
remoteDemand loadpoint.RemoteDemand // External status demand
chargePower float64 // Charging power
chargeCurrents []float64 // Phase currents
connectedTime time.Time // Time when vehicle was connected
pvTimer time.Time // PV enabled/disable timer
phaseTimer time.Time // 1p3p switch timer
wakeUpTimer *Timer // Vehicle wake-up timeout
status api.ChargeStatus // Charger status
chargePower float64 // Charging power
chargeCurrents []float64 // Phase currents
connectedTime time.Time // Time when vehicle was connected
pvTimer time.Time // PV enabled/disable timer
phaseTimer time.Time // 1p3p switch timer
wakeUpTimer *Timer // Vehicle wake-up timeout
// charge progress
vehicleSoc float64 // Vehicle or charger soc
@ -1045,14 +1044,6 @@ func (lp *Loadpoint) disableUnlessClimater() error {
return lp.setLimit(current)
}
// remoteControlled returns true if remote control status is active
func (lp *Loadpoint) remoteControlled(demand loadpoint.RemoteDemand) bool {
lp.Lock()
defer lp.Unlock()
return lp.remoteDemand == demand
}
// statusEvents converts the observed charger status change into a logical sequence of events
func statusEvents(prevStatus, status api.ChargeStatus) []string {
res := make([]string, 0, 2)
@ -1914,9 +1905,6 @@ func (lp *Loadpoint) Update(sitePower, batteryBoostPower float64, consumption, f
return
}
// track if remote disabled is actually active
remoteDisabled := loadpoint.RemoteEnable
mode := lp.GetMode()
lp.publish(keys.Mode, mode)
@ -1933,10 +1921,6 @@ func (lp *Loadpoint) Update(sitePower, batteryBoostPower float64, consumption, f
case lp.scalePhasesRequired():
err = lp.scalePhases(lp.phasesConfigured)
case lp.remoteControlled(loadpoint.RemoteHardDisable):
remoteDisabled = loadpoint.RemoteHardDisable
fallthrough
case mode == api.ModeOff:
var current float64
if welcomeCharge {
@ -2000,12 +1984,6 @@ func (lp *Loadpoint) Update(sitePower, batteryBoostPower float64, consumption, f
lp.resetPVTimer()
}
// Sunny Home Manager
if lp.remoteControlled(loadpoint.RemoteSoftDisable) {
remoteDisabled = loadpoint.RemoteSoftDisable
targetCurrent = 0
}
err = lp.setLimit(targetCurrent)
}
@ -2022,9 +2000,10 @@ func (lp *Loadpoint) Update(sitePower, batteryBoostPower float64, consumption, f
}
// effective disabled status
if remoteDisabled != loadpoint.RemoteEnable {
lp.publish(keys.RemoteDisabled, remoteDisabled)
}
// TODO use for §14a
// if remoteDisabled != loadpoint.RemoteEnable {
// lp.publish(keys.RemoteDisabled, remoteDisabled)
// }
// log any error
if err != nil {

View file

@ -162,9 +162,6 @@ type API interface {
// SetBatteryBoost sets the battery boost
SetBatteryBoost(enable bool) error
// RemoteControl sets remote status demand
RemoteControl(string, RemoteDemand)
//
// smart grid charging
//

View file

@ -700,18 +700,6 @@ func (mr *MockAPIMockRecorder) PublishEffectiveValues() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishEffectiveValues", reflect.TypeOf((*MockAPI)(nil).PublishEffectiveValues))
}
// RemoteControl mocks base method.
func (m *MockAPI) RemoteControl(arg0 string, arg1 RemoteDemand) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RemoteControl", arg0, arg1)
}
// RemoteControl indicates an expected call of RemoteControl.
func (mr *MockAPIMockRecorder) RemoteControl(arg0, arg1 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoteControl", reflect.TypeOf((*MockAPI)(nil).RemoteControl), arg0, arg1)
}
// SetBatteryBoost mocks base method.
func (m *MockAPI) SetBatteryBoost(enable bool) error {
m.ctrl.T.Helper()

View file

@ -1,25 +0,0 @@
package loadpoint
import "strings"
// RemoteDemand defines external status demand
type RemoteDemand string
// remote status demand definition
const (
RemoteEnable RemoteDemand = ""
RemoteHardDisable RemoteDemand = "hard"
RemoteSoftDisable RemoteDemand = "soft"
)
// RemoteDemandString converts string to RemoteDemand
func RemoteDemandString(demand string) (RemoteDemand, error) {
switch strings.ToLower(demand) {
case string(RemoteHardDisable):
return RemoteHardDisable, nil
case string(RemoteSoftDisable):
return RemoteSoftDisable, nil
default:
return RemoteEnable, nil
}
}

View file

@ -578,24 +578,6 @@ func (lp *Loadpoint) SetBatteryBoost(enable bool) error {
return nil
}
// RemoteControl sets remote status demand
func (lp *Loadpoint) RemoteControl(source string, demand loadpoint.RemoteDemand) {
lp.Lock()
defer lp.Unlock()
lp.log.DEBUG.Println("remote demand:", demand)
// apply immediately
if lp.remoteDemand != demand {
lp.remoteDemand = demand
lp.publish(keys.RemoteDisabled, demand)
lp.publish(keys.RemoteDisabledSource, source)
lp.requestUpdate()
}
}
// HasChargeMeter determines if a physical charge meter is attached
func (lp *Loadpoint) HasChargeMeter() bool {
_, isWrapped := lp.chargeMeter.(*wrapper.ChargeMeter)

View file

@ -37,20 +37,19 @@ var serverName = "EVCC SEMP Server " + util.Version
// SEMP is the SMA SEMP server
type SEMP struct {
log *util.Logger
controllable bool
vid string
did []byte
uid string
hostURI string
port int
site site.API
log *util.Logger
vid string
did []byte
uid string
hostURI string
port int
site site.API
}
type Config struct {
AllowControl bool `json:"allowControl"`
VendorId string `json:"vendorId"`
DeviceId string `json:"deviceId"`
AllowControl_ bool `json:"allowControl,omitempty"` // deprecated
VendorId string `json:"vendorId"`
DeviceId string `json:"deviceId"`
}
// NewFromConfig creates a new SEMP instance from configuration and starts it
@ -83,12 +82,11 @@ func NewFromConfig(cfg Config, site site.API, addr string, router *mux.Router) e
}
s := &SEMP{
log: util.NewLogger("semp"),
site: site,
uid: uid.String(),
vid: vendorId,
did: did,
controllable: cfg.AllowControl,
log: util.NewLogger("semp"),
site: site,
uid: uid.String(),
vid: vendorId,
did: did,
}
// find external port
@ -368,19 +366,15 @@ func (s *SEMP) deviceStatus(id int, lp loadpoint.API) DeviceStatus {
chargePower := lp.GetChargePower()
status := lp.GetStatus()
mode := lp.GetMode()
isPV := mode == api.ModeMinPV || mode == api.ModePV
deviceStatus := StatusOff
if status == api.StatusC {
deviceStatus = StatusOn
}
connected := status == api.StatusB || status == api.StatusC
res := DeviceStatus{
DeviceID: s.deviceID(id),
EMSignalsAccepted: s.controllable && isPV && connected,
EMSignalsAccepted: false,
PowerInfo: PowerInfo{
AveragePower: int(chargePower),
AveragingInterval: 60,
@ -461,41 +455,12 @@ func (s *SEMP) allPlanningRequest() (res []PlanningRequest) {
func (s *SEMP) deviceControlHandler(w http.ResponseWriter, r *http.Request) {
var msg EM2Device
err := xml.NewDecoder(r.Body).Decode(&msg)
s.log.TRACE.Printf("recv: %+v", msg)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
if err := xml.NewDecoder(r.Body).Decode(&msg); err == nil {
s.log.TRACE.Printf("recv: %+v", msg)
} else {
s.log.ERROR.Printf("recv: %+v", msg)
}
for _, dev := range msg.DeviceControl {
did := dev.DeviceID
for id, lp := range s.site.Loadpoints() {
if did != s.deviceID(id) {
continue
}
if mode := lp.GetMode(); mode != api.ModeMinPV && mode != api.ModePV {
w.WriteHeader(http.StatusBadRequest)
return
}
// ignore requests if not controllable
if !s.controllable {
w.WriteHeader(http.StatusBadRequest)
return
}
demand := loadpoint.RemoteSoftDisable
if dev.On {
demand = loadpoint.RemoteEnable
}
lp.RemoteControl(sempController, demand)
}
}
w.WriteHeader(http.StatusOK)
// ignore control requests
w.WriteHeader(http.StatusBadRequest)
}

View file

@ -77,7 +77,6 @@
"title": "Поведение на управление"
},
"deviceValue": {
"allowControl": "Разреши контрол",
"amount": "Количество",
"broker": "Брокер",
"bucket": "Кофа",

View file

@ -77,7 +77,6 @@
"title": "Chování systému"
},
"deviceValue": {
"allowControl": "Povolit ovládání",
"amount": "Množství",
"broker": "Broker",
"bucket": "Úložiště (bucket)",
@ -440,8 +439,6 @@
"descriptionIds": "V Sunny Portálu každé zařízení potřebuje unikátní identifikátor. EVCC generuje tento identifikátor v závisosti na vašem HW. Pokud zmigrujete EVCC na jiný HW mohou se tyto identifikátory změnit. Pokud chcete uchovat statistiky můžete zde přepsat generované identifikátory. Otevřete SEMP URL (/semp) abyste zkontrolovali současné identifikátory.",
"descriptionSempUrl": "SEMP URL",
"descriptionVendorId": "8 znaků HEX string. Obecné předpony všech entit. Ve výchozím stavu EVCC použije vlastní interní ID.",
"labelAllowControl": "Povolit dodatečné limity výkonu doporučené SHM.",
"labelControl": "Povolit ovládání",
"labelDeviceId": "ID zařízení",
"labelVendorId": "ID výrobce",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "kontrol adfærd"
},
"deviceValue": {
"allowControl": "Tillad kontrol",
"amount": "Mængde",
"broker": "Broker",
"bucket": "Bucket",
@ -447,8 +446,6 @@
"descriptionIds": "I Sunny Portal skal hver forbrugsenhed have en unik identifikator. evcc genererer en unik identifikator baseret på din hardware. Hvis du flytter evcc til en anden hardware, kan disse identifikatorer ændre sig. Hvis du vil bevare historikken, kan du tilsidesætte de genererede identifikatorer her. Åbn SEMP-URL’en (/semp) for at tjekke dine nuværende identifikatorer.",
"descriptionSempUrl": "SEMP URL",
"descriptionVendorId": "8-tegns HEX-streng. Generelt præfiks for alle enheder. Som standard vil evcc bruge sit eget interne leverandør-ID.",
"labelAllowControl": "Accepter yderligere anbefalinger om effektgrænser fra SHM.",
"labelControl": "Tillad kontrol",
"labelDeviceId": "Enheds ID",
"labelVendorId": "Leverandør-ID",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "Regelverhalten"
},
"deviceValue": {
"allowControl": "Steuerung erlauben",
"amount": "Anzahl",
"broker": "Broker",
"bucket": "Bucket",
@ -447,8 +446,6 @@
"descriptionIds": "Im Sunny Portal benötigt jeder Verbraucher (Ladepunkt, ..) eine eindeutige Kennung. evcc generiert basierend auf deiner Hardware eine eindeutige Kennung. Wenn du evcc auf andere Hardware migrierst, kann sich diese Kennung ändern. Um die Historie zu erhalten, kannst du die generierten Kennungen hier überschreiben. Öffne die SEMP-URL (/semp), um deine aktuellen Kennungen zu überprüfen.",
"descriptionSempUrl": "SEMP-URL",
"descriptionVendorId": "8-stelliger HEX-String. Allgemeines Präfix aller Entitäten. Standardmäßig verwendet evcc seine eigene interne Hersteller-ID.",
"labelAllowControl": "Zusätzlich Leistungsbegrenzungsempfehlungen vom SHM akzeptieren.",
"labelControl": "Steuerung erlauben",
"labelDeviceId": "Geräte-ID",
"labelVendorId": "Hersteller-ID",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "Control behavior"
},
"deviceValue": {
"allowControl": "Allow control",
"amount": "Amount",
"broker": "Broker",
"bucket": "Bucket",
@ -447,8 +446,6 @@
"descriptionIds": "In Sunny Portal every consumer device needs a unique identifier. evcc generates a unique identifier based on your hardware. If you migrate evcc to another hardware these identifiers might change. If you want to maintain history you can override the generated identifiers here. Open the SEMP URL (/semp) to check your current identifiers.",
"descriptionSempUrl": "SEMP URL",
"descriptionVendorId": "8 characters HEX string. General prefix of all entities. By default evcc will use its own internal vendor ID.",
"labelAllowControl": "Accept additional power limit recommendations from SHM.",
"labelControl": "Allow control",
"labelDeviceId": "Device ID",
"labelVendorId": "Vendor ID",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "Määrittele toimintaa"
},
"deviceValue": {
"allowControl": "Salli säätäminen",
"amount": "Määrä",
"broker": "Välittäjä (Broker)",
"bucket": "Bucket",
@ -443,8 +442,6 @@
"descriptionIds": "Sunny Portal -järjestelmässä jokainen käyttölaite vaatii yksilöllisen tunnisteen. Evcc luo yksilöllisen tunnisteen laitteistosi perusteella. Jos siirrät evcc:n asennuksen toiseen laitteistoon nämä tunnisteet voivat muuttua. Jos haluat pitää vanhat tunnisteet, voit automaattiset luodut tunnisteet tässä. Avaa SEMP URL (/semp) tarkistaaksesi nykyiset tunnisteesi.",
"descriptionSempUrl": "SEMP URL",
"descriptionVendorId": "8-merkkinen HEX-merkkijono. Yleinen etuliite kaikille laitteille. Oletuksena evcc käyttää sisäistä valmistajatunnistettaan.",
"labelAllowControl": "Hyväksy lisätehorajasuositukset SHM:lta.",
"labelControl": "Salli hallinta",
"labelDeviceId": "Laite-ID",
"labelVendorId": "Valmistaja-ID",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "Comportement du contrôle"
},
"deviceValue": {
"allowControl": "Permettre contrôle",
"amount": "Montant",
"broker": "Courtier",
"bucket": "Bucket",
@ -443,8 +442,6 @@
"descriptionIds": "Dans Sunny Portal, chaque appareil consommateur doit disposer d'un identifiant unique. evcc génère un identifiant unique basé sur votre matériel. Si vous migrez evcc vers un autre matériel, ces identifiants peuvent changer. Si vous souhaitez conserver l'historique, vous pouvez remplacer les identifiants générés ici. Ouvrez l'URL SEMP (/semp) pour vérifier vos identifiants actuels.",
"descriptionSempUrl": "URL SEMP",
"descriptionVendorId": "Chaîne HEX à 8 caractères. Préfixe général de toutes les entités. Par défaut, evcc utilisera son propre identifiant fournisseur interne.",
"labelAllowControl": "Accepter les recommandations supplémentaires de SHM concernant les limites de puissance.",
"labelControl": "Autoriser le contrôle",
"labelDeviceId": "Identifiant de l'appareil",
"labelVendorId": "Identifiant du fournisseur",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "Ponašanje upravljanja"
},
"deviceValue": {
"allowControl": "Dozvoli kontrolu",
"amount": "Iznos",
"broker": "Posrednik",
"bucket": "Kanta",
@ -443,8 +442,6 @@
"descriptionIds": "U Sunny Portalu svaki potrošački uređaj mora imati jedinstveni identifikator. evcc generira jedinstveni identifikator na temelju vašeg hardvera. Ako evcc premjestite na drugi hardver, ti se identifikatori mogu promijeniti. Ako želite zadržati povijest, ovdje možete nadjačati generirane identifikatore. Otvorite SEMP URL (/semp) kako biste provjerili svoje trenutačne identifikatore.",
"descriptionSempUrl": "SEMP URL",
"descriptionVendorId": "HEX izraz od 8 znakova. Prefiks za sve objekte. Uobičajeno je da evcc koristi svoj interni ID.",
"labelAllowControl": "Prihvati dodatna ograničenja snage prema savjetima SHM-a.",
"labelControl": "Dozvoli kontrolu",
"labelDeviceId": "ID uređaja",
"labelVendorId": "ID proizvođača",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "Kontrollverhalen"
},
"deviceValue": {
"allowControl": "Steierung erlaben",
"amount": "Unzahl",
"broker": "Broker",
"bucket": "Eemer",
@ -447,8 +446,6 @@
"descriptionIds": "Am Sunny Portal brauch all Ladung (Luedpunkt, etc.) eng eenzegaarteg Identifikatioun. evcc generéiert eng eenzegaarteg Identifikatioun, déi op Ärer Hardware baséiert. Wann Dir evcc op aner Hardware migréiert, kann dësen Identifikator sech änneren. Fir den Historique ze späicheren, kënnt Dir déi generéiert Identifikatoren hei iwwerschreiwen. Maacht d'SEMP URL op (/semp) fir Är aktuell Identifikatoren ze kontrolléieren.",
"descriptionSempUrl": "SEMP-URL",
"descriptionVendorId": "8-stellegen HEX-String. Allgemenge Präfix fir all Entiéiten. Standardméisseg verwennt evcc seng eegen intern Hiersteller-ID.",
"labelAllowControl": "Zousätzlech Recommandatioune fir d'Leeschtungslimit vun SHM z'akzeptéieren.",
"labelControl": "Steierung erlaben",
"labelDeviceId": "Geräter-ID",
"labelVendorId": "Hiersteller-ID",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "Valdymo elgesys"
},
"deviceValue": {
"allowControl": "Leisti valdymą",
"amount": "Kiekis",
"broker": "Broker sistema",
"bucket": "Bucket",
@ -200,7 +199,6 @@
"description": "Įrašo įkrovimo ir kitus duomenis į InfluxDB. Duomenims vizualizuoti naudokite \"Grafana\" ar panašius įrankius.",
"descriptionToken": "Patikrinkite InfluxDB dokumentaciją, kad sužinotumėte, kaip ją sukurti. https://docs.influxdata.com/influxdb/v2/admin/",
"labelBucket": "Bucket",
"labelCheckInsecure": "Leisti savarankiškai pasirašytus sertifikatus",
"labelDatabase": "Duomenų bazė",
"labelInsecure": "Sertifikato patvirtinimas",
"labelOrg": "Organizacija",
@ -372,7 +370,6 @@
"protocolValueTcp": "TCP"
},
"modbusproxy": {
"description": "Leisti keliems klientams pasiekti vieną „Modbus“ įrenginį.",
"title": "Modbus Proxy"
},
"mqtt": {
@ -382,7 +379,6 @@
"descriptionTopic": "Palikite tuščią, kad išjungtumėte publikavimą.",
"labelBroker": "Broker",
"labelCaCert": "Serverio sertifikatas (CA)",
"labelCheckInsecure": "Leisti savarankiškai pasirašytus sertifikatus",
"labelClientCert": "Kliento sertifikatas",
"labelClientId": "Kliento ID",
"labelClientKey": "Kliento raktas",
@ -447,8 +443,6 @@
"descriptionIds": "Sunny Portal sistemoje kiekvienam vartotojo įrenginiui reikalingas unikalus identifikatorius. evcc generuoja unikalų identifikatorių pagal jūsų aparatinę įrangą. Jei migruosite evcc į kitą aparatinę įrangą, šie identifikatoriai gali pasikeisti. Jei norite išsaugoti istoriją, čia galite pakeisti sugeneruotus identifikatorius. Atidarykite SEMP URL (/semp), kad patikrintumėte dabartinius identifikatorius.",
"descriptionSempUrl": "SEMP URL",
"descriptionVendorId": "8 simbolių HEX eilutė. Bendras visų objektų prefiksas. Pagal numatytuosius nustatymus evcc naudos savo vidinį tiekėjo ID.",
"labelAllowControl": "Priimti papildomas SHM galios ribojimo rekomendacijas.",
"labelControl": "Leisti valdyti",
"labelDeviceId": "Įrenginio ID",
"labelVendorId": "Gamintojo ID",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "Regelgedrag"
},
"deviceValue": {
"allowControl": "Besturing toestaan",
"amount": "Aantal",
"broker": "Agent",
"bucket": "Bucket",
@ -444,8 +443,6 @@
"descriptionIds": "In Sunny Portal heeft elk consumentenapparaat een unieke identificatiecode nodig. evcc genereert een unieke identificatiecode op basis van uw hardware. Als u evcc naar andere hardware migreert, kunnen deze identificatiecodes veranderen. Als u de geschiedenis wilt behouden, kunt u de gegenereerde identificatiecodes hier overschrijven. Open de SEMP-URL (/semp) om uw huidige identificatiecodes te controleren.",
"descriptionSempUrl": "SEMP URL",
"descriptionVendorId": "8 karakters HEX string. Algemene prefix van alle onderdelen. Standaard zal evcc zijn eigen vendor ID gebruiken.",
"labelAllowControl": "Sta additionele aanbevelingen stroombegrenzing toe van SHM.",
"labelControl": "Besturing toestaan",
"labelDeviceId": "Device ID",
"labelVendorId": "Vendor ID",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "Comportamento de controlo"
},
"deviceValue": {
"allowControl": "Permitir controlo",
"amount": "Quantidade",
"broker": "Broker",
"bucket": "Bucket",
@ -440,8 +439,6 @@
"descriptionIds": "No Sunny Portal cada dispositivo necessita duma identidade única. O evcc gera uma identidade única com base no seu hardware. Se migrar o evcc para outro hardware estas identidades podem mudar. Se quiser manter o histórico pode substituir as identidades geradas aqui. Abra o SEMP URL(/semp) para ver as identidade atuais.",
"descriptionSempUrl": "SEMP URL",
"descriptionVendorId": "string 8 caratecteres HEX. Prefixo geral de todas as entidades. O evcc usa o seu próprio vendor ID interno Por defeito.",
"labelAllowControl": "Aceitar recomendações adicionais de limite de potência do SHM.",
"labelControl": "Permitir controlo",
"labelDeviceId": "Device ID",
"labelVendorId": "Vendor ID",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "Nadzor vedenja"
},
"deviceValue": {
"allowControl": "Dovoli nadzor",
"amount": "Znesek",
"broker": "Broker",
"bucket": "Vedro",

View file

@ -77,7 +77,6 @@
"title": "Kontrollera beteende"
},
"deviceValue": {
"allowControl": "Tillåt styrning",
"amount": "Belopp",
"broker": "Broker",
"bucket": "Bucket",
@ -447,8 +446,6 @@
"descriptionIds": "I Sunny Portal behöver varje konsumentenhet en unik identifierare. evcc genererar en unik identifierare baserat på din hårdvara. Om du migrerar evcc till en annan hårdvara kan dessa identifierare ändras. Om du vill behålla historiken kan du åsidosätta de genererade identifierarna här. Öppna SEMP-URL:en (/semp) för att kontrollera dina aktuella identifierare.",
"descriptionSempUrl": "SEMP URL",
"descriptionVendorId": "Hexsträng med 8 tecken. Generellt prefix för alla entiteter. Evcc använder sitt egna tillverkar-ID som standard.",
"labelAllowControl": "Tillåt rekommendationer från SHM för effektgränser.",
"labelControl": "Tillåt styrning",
"labelDeviceId": "Device ID",
"labelVendorId": "Tillverkar-ID",
"title": "SMA Sunny Home Manager"

View file

@ -77,7 +77,6 @@
"title": "Контрольна поведінка"
},
"deviceValue": {
"allowControl": "Дозволити керування",
"amount": "Сума",
"broker": "Брокер",
"bucket": "Відро",
@ -447,8 +446,6 @@
"descriptionIds": "У Sunny Portal кожне споживче обладнання потребує унікального ідентифікатора. evcc генерує унікальний ідентифікатор на основі вашого обладнання. Якщо ви перенесете evcc на інше обладнання, ці ідентифікатори можуть змінитися. Якщо ви хочете зберегти історію, ви можете замінити згенеровані ідентифікатори тут. Відкрийте URL-адресу SEMP (/semp), щоб перевірити ваші поточні ідентифікатори.",
"descriptionSempUrl": "SEMP URL",
"descriptionVendorId": "8-символьний шістнадцятковий рядок. Загальний префікс усіх об'єктів. За замовчуванням evcc використовуватиме власний внутрішній ідентифікатор постачальника.",
"labelAllowControl": "Прийміть додаткові рекомендації щодо обмеження потужності від SHM.",
"labelControl": "Дозволити керування",
"labelDeviceId": "Ідентифікатор пристрою",
"labelVendorId": "Ідентифікатор постачальника",
"title": "SMA Сонячний домашній менеджер"

View file

@ -201,7 +201,6 @@ func (s *HTTPd) RegisterSiteHandlers(site site.API, valueChan chan<- util.Param)
"vehicle": {"POST", "/vehicle/{name:[a-zA-Z0-9_.:-]+}", vehicleSelectHandler(site, lp)},
"vehicle2": {"DELETE", "/vehicle", vehicleRemoveHandler(lp)},
"vehicleDetect": {"PATCH", "/vehicle", vehicleDetectHandler(lp)},
"remotedemand": {"POST", "/remotedemand/{demand:[a-z]+}/{source:[0-9a-zA-Z_-]+}", remoteDemandHandler(lp)},
"enableThreshold": {"POST", "/enable/threshold/{value:-?[0-9.]+}", floatHandler(pass(lp.SetEnableThreshold), lp.GetEnableThreshold)},
"enableDelay": {"POST", "/enable/delay/{value:[0-9]+}", durationHandler(pass(lp.SetEnableDelay), lp.GetEnableDelay)},
"disableThreshold": {"POST", "/disable/threshold/{value:-?[0-9.]+}", floatHandler(pass(lp.SetDisableThreshold), lp.GetDisableThreshold)},

View file

@ -32,32 +32,6 @@ type PlanPreviewResponse struct {
Power float64 `json:"power"`
}
// remoteDemandHandler updates minimum soc
func remoteDemandHandler(lp loadpoint.API) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
source := vars["source"]
demand, err := loadpoint.RemoteDemandString(vars["demand"])
if err != nil {
jsonError(w, http.StatusBadRequest, err)
return
}
lp.RemoteControl(source, demand)
res := struct {
Demand loadpoint.RemoteDemand `json:"demand"`
Source string `json:"source"`
}{
Source: source,
Demand: demand,
}
jsonWrite(w, res)
}
}
// planHandler returns the current plan
func planHandler(lp loadpoint.API) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {

View file

@ -21,18 +21,12 @@ test.describe("SHM", () => {
await enableExperimental(page, false);
const shmCard = page.getByTestId("shm");
await expect(shmCard).toContainText(["Allow control", "no"].join(""));
// configure SHM with allow control and IDs
// configure SHM with IDs
await shmCard.getByRole("button", { name: "edit" }).click();
const modal = page.getByTestId("shm-modal");
await expectModalVisible(modal);
const allowControl = modal.getByRole("checkbox", { name: "Allow control" });
await expect(allowControl).not.toBeChecked();
await allowControl.check();
await expect(allowControl).toBeChecked();
await modal.getByRole("button", { name: "Show advanced settings" }).click();
// test vendor ID validation
@ -52,16 +46,13 @@ test.describe("SHM", () => {
await modal.getByRole("button", { name: "Save" }).click();
await expectModalHidden(modal);
await expect(shmCard).toContainText(["Allow control", "yes"].join(""));
// verify persistence after restart
await restart(CONFIG);
await page.goto("/#/config");
await expect(shmCard).toContainText(["Allow control", "yes"].join(""));
await shmCard.getByRole("button", { name: "edit" }).click();
await expectModalVisible(modal);
await expect(allowControl).toBeChecked();
await expect(vendor).toHaveValue(VALID_VENDOR_ID);
await expect(device).toHaveValue(VALID_DEVICE_ID);
@ -75,14 +66,5 @@ test.describe("SHM", () => {
`<DeviceId>F-${VALID_VENDOR_ID}-${VALID_DEVICE_ID.toLowerCase()}-00</DeviceId>`
);
await sempPage.close();
// uncheck allow control
await allowControl.uncheck();
await expect(allowControl).not.toBeChecked();
await modal.getByRole("button", { name: "Save" }).click();
await expectModalHidden(modal);
// verify it shows as disabled
await expect(shmCard).toContainText(["Allow control", "no"].join(""));
});
});