From 94c2606797503bf2ce5381fb81522710e7cfe708 Mon Sep 17 00:00:00 2001 From: andig Date: Fri, 10 Apr 2026 15:48:23 +0200 Subject: [PATCH] Fix docorating by promoting embedded type methods as capabilities (#28995) --- charger/abl_decorators.go | 3 + charger/alfen_decorators.go | 3 + charger/amperfied_decorators.go | 3 + charger/bender_decorators.go | 3 + charger/cfos_decorators.go | 3 + charger/charger_decorators.go | 3 + charger/daheimladen_decorators.go | 3 + charger/eebus_decorators.go | 3 + charger/em2go_decorators.go | 3 + charger/etek_decorators.go | 3 + charger/evecube_decorators.go | 3 + charger/evsedin_decorators.go | 3 + charger/evsewifi_decorators.go | 3 + charger/ghosteebus_decorators.go | 3 + charger/go-e_decorators.go | 3 + charger/hardybarth-salia_decorators.go | 3 + charger/heatpump_decorators.go | 3 + charger/homeassistant_decorators.go | 3 + charger/innogy_decorators.go | 3 + charger/keba-modbus_decorators.go | 3 + charger/keba-udp_decorators.go | 3 + charger/kse_decorators.go | 3 + charger/mennekes-compact_decorators.go | 3 + charger/nrggen2_decorators.go | 3 + charger/ocpp_decorators.go | 3 + charger/openevse_decorators.go | 3 + charger/openwb-2.0_decorators.go | 3 + charger/openwb-native_decorators_linux.go | 3 + charger/openwb-pro_decorators.go | 3 + charger/openwb_decorators.go | 3 + charger/pcelectric_decorators.go | 3 + charger/peblar_decorators.go | 3 + charger/phoenix-charx_decorators.go | 3 + charger/phoenix-em-eth_decorators.go | 3 + charger/phoenix-ev-eth_decorators.go | 3 + charger/pulsares_decorators.go | 3 + charger/semp_decorators.go | 3 + charger/sgready_decorators.go | 3 + charger/shelly_decorators.go | 3 + charger/solax_decorators.go | 3 + charger/switchsocket_decorators.go | 3 + charger/tasmota_decorators.go | 3 + charger/vaillant_decorators.go | 3 + charger/vestel_decorators.go | 3 + charger/victron_decorators.go | 3 + charger/wallbe_decorators.go | 3 + charger/warp-ws_decorators.go | 3 + charger/warp2-mqtt_decorators.go | 3 + charger/weidmüller_decorators.go | 3 + charger/zaptec_decorators.go | 3 + cmd/decorate/decorate.tpl | 3 + cmd/decorate/decorate_decorators.go | 3 + core/capable_test.go | 106 ++++++++++++++++++++++ meter/dsmr_decorators.go | 3 + meter/e3dc_decorators.go | 3 + meter/goodwe-wifi_decorators.go | 3 + meter/lgess_decorators.go | 3 + meter/meter_decorators.go | 6 ++ meter/powerwall_decorators.go | 3 + meter/rct_decorators.go | 3 + meter/shelly_decorators.go | 3 + meter/tasmota_decorators.go | 3 + meter/tq-em_decorators.go | 3 + vehicle/tronity_decorators.go | 3 + vehicle/vehicle_decorators.go | 3 + 65 files changed, 301 insertions(+) create mode 100644 core/capable_test.go diff --git a/charger/abl_decorators.go b/charger/abl_decorators.go index 98c12b083..18714b77d 100644 --- a/charger/abl_decorators.go +++ b/charger/abl_decorators.go @@ -33,6 +33,9 @@ type decorateABLeMHCapable struct { func (d *decorateABLeMHCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/alfen_decorators.go b/charger/alfen_decorators.go index ecf840de9..610538e87 100644 --- a/charger/alfen_decorators.go +++ b/charger/alfen_decorators.go @@ -33,6 +33,9 @@ type decorateAlfenCapable struct { func (d *decorateAlfenCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/amperfied_decorators.go b/charger/amperfied_decorators.go index cf1d039c5..67548cbd6 100644 --- a/charger/amperfied_decorators.go +++ b/charger/amperfied_decorators.go @@ -33,6 +33,9 @@ type decorateAmperfiedCapable struct { func (d *decorateAmperfiedCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/bender_decorators.go b/charger/bender_decorators.go index 152d92cb5..140fec094 100644 --- a/charger/bender_decorators.go +++ b/charger/bender_decorators.go @@ -61,6 +61,9 @@ type decorateBenderCCCapable struct { func (d *decorateBenderCCCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/cfos_decorators.go b/charger/cfos_decorators.go index 03574566a..f58b588fe 100644 --- a/charger/cfos_decorators.go +++ b/charger/cfos_decorators.go @@ -41,6 +41,9 @@ type decorateCfosCapable struct { func (d *decorateCfosCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/charger_decorators.go b/charger/charger_decorators.go index a25543a4d..38a738f45 100644 --- a/charger/charger_decorators.go +++ b/charger/charger_decorators.go @@ -65,6 +65,9 @@ type decorateCustomCapable struct { func (d *decorateCustomCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/daheimladen_decorators.go b/charger/daheimladen_decorators.go index 3dc12d3a5..4ab19bab3 100644 --- a/charger/daheimladen_decorators.go +++ b/charger/daheimladen_decorators.go @@ -33,6 +33,9 @@ type decorateDaheimLadenCapable struct { func (d *decorateDaheimLadenCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/eebus_decorators.go b/charger/eebus_decorators.go index f285b7d65..207f27d17 100644 --- a/charger/eebus_decorators.go +++ b/charger/eebus_decorators.go @@ -37,6 +37,9 @@ type decorateEEBusCapable struct { func (d *decorateEEBusCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/em2go_decorators.go b/charger/em2go_decorators.go index 8ae05d41b..73e0c9eea 100644 --- a/charger/em2go_decorators.go +++ b/charger/em2go_decorators.go @@ -37,6 +37,9 @@ type decorateEm2GoCapable struct { func (d *decorateEm2GoCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/etek_decorators.go b/charger/etek_decorators.go index bf970e440..dfd008e7f 100644 --- a/charger/etek_decorators.go +++ b/charger/etek_decorators.go @@ -37,6 +37,9 @@ type decorateEtekCapable struct { func (d *decorateEtekCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/evecube_decorators.go b/charger/evecube_decorators.go index da37e04c3..a80f9a02a 100644 --- a/charger/evecube_decorators.go +++ b/charger/evecube_decorators.go @@ -33,6 +33,9 @@ type decorateEVECUBECapable struct { func (d *decorateEVECUBECapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/evsedin_decorators.go b/charger/evsedin_decorators.go index de9709da9..8eacdecb2 100644 --- a/charger/evsedin_decorators.go +++ b/charger/evsedin_decorators.go @@ -29,6 +29,9 @@ type decorateEvseDINCapable struct { func (d *decorateEvseDINCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/evsewifi_decorators.go b/charger/evsewifi_decorators.go index 362b50b4e..0409faae6 100644 --- a/charger/evsewifi_decorators.go +++ b/charger/evsewifi_decorators.go @@ -49,6 +49,9 @@ type decorateEVSECapable struct { func (d *decorateEVSECapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/ghosteebus_decorators.go b/charger/ghosteebus_decorators.go index bfaa947f9..6e60a779b 100644 --- a/charger/ghosteebus_decorators.go +++ b/charger/ghosteebus_decorators.go @@ -45,6 +45,9 @@ type decorateGhostEEBusCapable struct { func (d *decorateGhostEEBusCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/go-e_decorators.go b/charger/go-e_decorators.go index 8c81e75a3..8f2c9dd4c 100644 --- a/charger/go-e_decorators.go +++ b/charger/go-e_decorators.go @@ -33,6 +33,9 @@ type decorateGoECapable struct { func (d *decorateGoECapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/hardybarth-salia_decorators.go b/charger/hardybarth-salia_decorators.go index e8c1fe4df..20188cbba 100644 --- a/charger/hardybarth-salia_decorators.go +++ b/charger/hardybarth-salia_decorators.go @@ -45,6 +45,9 @@ type decorateSaliaCapable struct { func (d *decorateSaliaCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/heatpump_decorators.go b/charger/heatpump_decorators.go index d97d5d883..68c876185 100644 --- a/charger/heatpump_decorators.go +++ b/charger/heatpump_decorators.go @@ -41,6 +41,9 @@ type decorateHeatpumpCapable struct { func (d *decorateHeatpumpCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/homeassistant_decorators.go b/charger/homeassistant_decorators.go index 2040ad1fb..4dac8fd14 100644 --- a/charger/homeassistant_decorators.go +++ b/charger/homeassistant_decorators.go @@ -49,6 +49,9 @@ type decorateHomeAssistantCapable struct { func (d *decorateHomeAssistantCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/innogy_decorators.go b/charger/innogy_decorators.go index 6bba9854d..c73120052 100644 --- a/charger/innogy_decorators.go +++ b/charger/innogy_decorators.go @@ -33,6 +33,9 @@ type decorateInnogyCapable struct { func (d *decorateInnogyCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/keba-modbus_decorators.go b/charger/keba-modbus_decorators.go index 8c25c376b..31aeda7ee 100644 --- a/charger/keba-modbus_decorators.go +++ b/charger/keba-modbus_decorators.go @@ -53,6 +53,9 @@ type decorateKebaCapable struct { func (d *decorateKebaCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/keba-udp_decorators.go b/charger/keba-udp_decorators.go index 64ac7a55a..f3ae427ab 100644 --- a/charger/keba-udp_decorators.go +++ b/charger/keba-udp_decorators.go @@ -37,6 +37,9 @@ type decorateKebaUdpCapable struct { func (d *decorateKebaUdpCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/kse_decorators.go b/charger/kse_decorators.go index 35901d756..ab78ee55e 100644 --- a/charger/kse_decorators.go +++ b/charger/kse_decorators.go @@ -37,6 +37,9 @@ type decorateKSECapable struct { func (d *decorateKSECapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/mennekes-compact_decorators.go b/charger/mennekes-compact_decorators.go index a6df54f85..3da5e4095 100644 --- a/charger/mennekes-compact_decorators.go +++ b/charger/mennekes-compact_decorators.go @@ -29,6 +29,9 @@ type decorateMennekesCompactCapable struct { func (d *decorateMennekesCompactCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/nrggen2_decorators.go b/charger/nrggen2_decorators.go index 943f70891..c09c2d9c2 100644 --- a/charger/nrggen2_decorators.go +++ b/charger/nrggen2_decorators.go @@ -29,6 +29,9 @@ type decorateNRGKickGen2Capable struct { func (d *decorateNRGKickGen2Capable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/ocpp_decorators.go b/charger/ocpp_decorators.go index 2add164f9..cb1a1939b 100644 --- a/charger/ocpp_decorators.go +++ b/charger/ocpp_decorators.go @@ -53,6 +53,9 @@ type decorateOCPPCapable struct { func (d *decorateOCPPCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/openevse_decorators.go b/charger/openevse_decorators.go index 3fcdc6359..7e76f0dea 100644 --- a/charger/openevse_decorators.go +++ b/charger/openevse_decorators.go @@ -29,6 +29,9 @@ type decorateOpenEVSECapable struct { func (d *decorateOpenEVSECapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/openwb-2.0_decorators.go b/charger/openwb-2.0_decorators.go index 5f28551ce..b990a7062 100644 --- a/charger/openwb-2.0_decorators.go +++ b/charger/openwb-2.0_decorators.go @@ -33,6 +33,9 @@ type decorateOpenWB20Capable struct { func (d *decorateOpenWB20Capable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/openwb-native_decorators_linux.go b/charger/openwb-native_decorators_linux.go index b18205488..b714e329f 100644 --- a/charger/openwb-native_decorators_linux.go +++ b/charger/openwb-native_decorators_linux.go @@ -37,6 +37,9 @@ type decorateOpenWbNativeCapable struct { func (d *decorateOpenWbNativeCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/openwb-pro_decorators.go b/charger/openwb-pro_decorators.go index e109bdef0..41b9e4c90 100644 --- a/charger/openwb-pro_decorators.go +++ b/charger/openwb-pro_decorators.go @@ -29,6 +29,9 @@ type decorateOpenWBProCapable struct { func (d *decorateOpenWBProCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/openwb_decorators.go b/charger/openwb_decorators.go index 7aa5b6f2f..a88cac499 100644 --- a/charger/openwb_decorators.go +++ b/charger/openwb_decorators.go @@ -33,6 +33,9 @@ type decorateOpenWBCapable struct { func (d *decorateOpenWBCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/pcelectric_decorators.go b/charger/pcelectric_decorators.go index adb8848ad..e51d5e2bd 100644 --- a/charger/pcelectric_decorators.go +++ b/charger/pcelectric_decorators.go @@ -37,6 +37,9 @@ type decoratePCECapable struct { func (d *decoratePCECapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/peblar_decorators.go b/charger/peblar_decorators.go index da4e64e5d..4146b7fe7 100644 --- a/charger/peblar_decorators.go +++ b/charger/peblar_decorators.go @@ -33,6 +33,9 @@ type decoratePeblarCapable struct { func (d *decoratePeblarCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/phoenix-charx_decorators.go b/charger/phoenix-charx_decorators.go index 37fec3e1e..c36619a10 100644 --- a/charger/phoenix-charx_decorators.go +++ b/charger/phoenix-charx_decorators.go @@ -41,6 +41,9 @@ type decoratePhoenixCharxCapable struct { func (d *decoratePhoenixCharxCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/phoenix-em-eth_decorators.go b/charger/phoenix-em-eth_decorators.go index 5e8af9605..780a9c36e 100644 --- a/charger/phoenix-em-eth_decorators.go +++ b/charger/phoenix-em-eth_decorators.go @@ -41,6 +41,9 @@ type decoratePhoenixEMEthCapable struct { func (d *decoratePhoenixEMEthCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/phoenix-ev-eth_decorators.go b/charger/phoenix-ev-eth_decorators.go index 886219277..dd6a6dbfb 100644 --- a/charger/phoenix-ev-eth_decorators.go +++ b/charger/phoenix-ev-eth_decorators.go @@ -49,6 +49,9 @@ type decoratePhoenixEVEthCapable struct { func (d *decoratePhoenixEVEthCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/pulsares_decorators.go b/charger/pulsares_decorators.go index 0068a86f8..fb252ee26 100644 --- a/charger/pulsares_decorators.go +++ b/charger/pulsares_decorators.go @@ -29,6 +29,9 @@ type decoratePulsaresCapable struct { func (d *decoratePulsaresCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/semp_decorators.go b/charger/semp_decorators.go index c6fc75c9e..ed11668c4 100644 --- a/charger/semp_decorators.go +++ b/charger/semp_decorators.go @@ -37,6 +37,9 @@ type decorateSEMPCapable struct { func (d *decorateSEMPCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/sgready_decorators.go b/charger/sgready_decorators.go index d981ce092..056a490a9 100644 --- a/charger/sgready_decorators.go +++ b/charger/sgready_decorators.go @@ -41,6 +41,9 @@ type decorateSgReadyCapable struct { func (d *decorateSgReadyCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/shelly_decorators.go b/charger/shelly_decorators.go index 945665799..3c80eb071 100644 --- a/charger/shelly_decorators.go +++ b/charger/shelly_decorators.go @@ -37,6 +37,9 @@ type decorateShellyCapable struct { func (d *decorateShellyCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/solax_decorators.go b/charger/solax_decorators.go index 14feae8ba..40f10cd7a 100644 --- a/charger/solax_decorators.go +++ b/charger/solax_decorators.go @@ -33,6 +33,9 @@ type decorateSolaxCapable struct { func (d *decorateSolaxCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/switchsocket_decorators.go b/charger/switchsocket_decorators.go index 349b1dfd2..0e3e9d91c 100644 --- a/charger/switchsocket_decorators.go +++ b/charger/switchsocket_decorators.go @@ -33,6 +33,9 @@ type decorateSwitchSocketCapable struct { func (d *decorateSwitchSocketCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/tasmota_decorators.go b/charger/tasmota_decorators.go index 1c02f67e1..fdde72fa8 100644 --- a/charger/tasmota_decorators.go +++ b/charger/tasmota_decorators.go @@ -33,6 +33,9 @@ type decorateTasmotaCapable struct { func (d *decorateTasmotaCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/vaillant_decorators.go b/charger/vaillant_decorators.go index b942619ac..1e84858e9 100644 --- a/charger/vaillant_decorators.go +++ b/charger/vaillant_decorators.go @@ -33,6 +33,9 @@ type decorateVaillantCapable struct { func (d *decorateVaillantCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/vestel_decorators.go b/charger/vestel_decorators.go index cf55dd7e2..b498fbe90 100644 --- a/charger/vestel_decorators.go +++ b/charger/vestel_decorators.go @@ -37,6 +37,9 @@ type decorateVestelCapable struct { func (d *decorateVestelCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/victron_decorators.go b/charger/victron_decorators.go index 3306784db..24573317a 100644 --- a/charger/victron_decorators.go +++ b/charger/victron_decorators.go @@ -33,6 +33,9 @@ type decorateVictronCapable struct { func (d *decorateVictronCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/wallbe_decorators.go b/charger/wallbe_decorators.go index 39b877394..6467878b6 100644 --- a/charger/wallbe_decorators.go +++ b/charger/wallbe_decorators.go @@ -41,6 +41,9 @@ type decorateWallbeCapable struct { func (d *decorateWallbeCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/warp-ws_decorators.go b/charger/warp-ws_decorators.go index 5f2179b55..9c3df9117 100644 --- a/charger/warp-ws_decorators.go +++ b/charger/warp-ws_decorators.go @@ -53,6 +53,9 @@ type decorateWarpWSCapable struct { func (d *decorateWarpWSCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/warp2-mqtt_decorators.go b/charger/warp2-mqtt_decorators.go index ed5871ac6..ecbd4ecb5 100644 --- a/charger/warp2-mqtt_decorators.go +++ b/charger/warp2-mqtt_decorators.go @@ -53,6 +53,9 @@ type decorateWarp2Capable struct { func (d *decorateWarp2Capable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/weidmüller_decorators.go b/charger/weidmüller_decorators.go index b35215673..489556d45 100644 --- a/charger/weidmüller_decorators.go +++ b/charger/weidmüller_decorators.go @@ -29,6 +29,9 @@ type decorateWeidmüllerCapable struct { func (d *decorateWeidmüllerCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/charger/zaptec_decorators.go b/charger/zaptec_decorators.go index 344ee1eec..eb486e4e6 100644 --- a/charger/zaptec_decorators.go +++ b/charger/zaptec_decorators.go @@ -29,6 +29,9 @@ type decorateZaptecCapable struct { func (d *decorateZaptecCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/cmd/decorate/decorate.tpl b/cmd/decorate/decorate.tpl index a4dcd362c..ca7e4660b 100644 --- a/cmd/decorate/decorate.tpl +++ b/cmd/decorate/decorate.tpl @@ -22,6 +22,9 @@ type {{.Function}}Capable struct { func (d *{{.Function}}Capable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/cmd/decorate/decorate_decorators.go b/cmd/decorate/decorate_decorators.go index 17b8c4ae1..2a3a16b4a 100644 --- a/cmd/decorate/decorate_decorators.go +++ b/cmd/decorate/decorate_decorators.go @@ -37,6 +37,9 @@ type decorateTestCapable struct { func (d *decorateTestCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/core/capable_test.go b/core/capable_test.go new file mode 100644 index 000000000..40b9b9157 --- /dev/null +++ b/core/capable_test.go @@ -0,0 +1,106 @@ +package core + +import ( + "reflect" + "testing" + + "github.com/evcc-io/evcc/api" + "github.com/stretchr/testify/assert" +) + +type charger struct { + caps map[reflect.Type]any +} + +var _ api.Capable = (*charger)(nil) + +func (c *charger) Capability(typ reflect.Type) (any, bool) { + cap, ok := c.caps[typ] + if !ok && reflect.TypeOf(c).Implements(typ) { + return c, true + } + return cap, ok +} + +var _ api.Meter = (*charger)(nil) + +func (c *charger) CurrentPower() (float64, error) { + return 0, nil +} + +var _ api.BatteryCapacity = (*charger)(nil) + +func (c *charger) Capacity() float64 { + return 0 +} + +var _ api.MeterEnergy = (*charger)(nil) + +func (c *charger) TotalEnergy() (float64, error) { + return 0, nil +} + +var _ api.Battery = (*batteryImpl)(nil) + +type batteryImpl struct { + soc func() (float64, error) +} + +func (impl *batteryImpl) Soc() (float64, error) { + return impl.soc() +} + +func TestCapsWrapping(t *testing.T) { + // type is just a shortcut for something simple that is not a meter + var c api.BatteryCapacity + + c = &charger{ + caps: make(map[reflect.Type]any), + } + + c.(*charger).caps[reflect.TypeFor[api.Battery]()] = &batteryImpl{ + soc: func() (float64, error) { + return 0, nil + }, + } + + { + _, ok := c.(api.Meter) + assert.True(t, ok) + } + { + _, ok := c.(api.MeterEnergy) + assert.True(t, ok) + } + { + _, ok := c.(api.Battery) + assert.False(t, ok) + assert.True(t, api.HasCap[api.Battery](c)) + } + + var m api.Meter + + if mt, ok := api.Cap[api.Meter](c); ok { + if c, ok := c.(api.Capable); ok { + m = &capableMeter{Meter: mt, Capable: c} + } else { + m = mt + } + } + + { + _, ok := m.(api.MeterEnergy) + assert.False(t, ok, "unexpected promoted energy") + assert.True(t, api.HasCap[api.MeterEnergy](m), "missing promoted energy cap") + + var mm any = m.(*capableMeter).Meter + _, ok = mm.(api.MeterEnergy) + assert.True(t, ok, "missing embedded energy") + assert.True(t, api.HasCap[api.MeterEnergy](mm), "missing embedded energy cap") + } + { + _, ok := m.(api.Battery) + assert.False(t, ok) + assert.True(t, api.HasCap[api.Battery](m), "missing battery cap") + } +} diff --git a/meter/dsmr_decorators.go b/meter/dsmr_decorators.go index cf10cad14..be00f203c 100644 --- a/meter/dsmr_decorators.go +++ b/meter/dsmr_decorators.go @@ -33,6 +33,9 @@ type decorateDsmrCapable struct { func (d *decorateDsmrCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/meter/e3dc_decorators.go b/meter/e3dc_decorators.go index cbd04db0c..82d479a3e 100644 --- a/meter/e3dc_decorators.go +++ b/meter/e3dc_decorators.go @@ -49,6 +49,9 @@ type decorateE3dcCapable struct { func (d *decorateE3dcCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/meter/goodwe-wifi_decorators.go b/meter/goodwe-wifi_decorators.go index 0288610fd..b0d41e2c7 100644 --- a/meter/goodwe-wifi_decorators.go +++ b/meter/goodwe-wifi_decorators.go @@ -33,6 +33,9 @@ type decorateGoodWeWifiCapable struct { func (d *decorateGoodWeWifiCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/meter/lgess_decorators.go b/meter/lgess_decorators.go index b2613af99..4c607cb6b 100644 --- a/meter/lgess_decorators.go +++ b/meter/lgess_decorators.go @@ -49,6 +49,9 @@ type decorateLgEssCapable struct { func (d *decorateLgEssCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/meter/meter_decorators.go b/meter/meter_decorators.go index f30e1a774..71e1399c7 100644 --- a/meter/meter_decorators.go +++ b/meter/meter_decorators.go @@ -45,6 +45,9 @@ type decorateMeterCapable struct { func (d *decorateMeterCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } @@ -129,6 +132,9 @@ type decorateMeterBatteryCapable struct { func (d *decorateMeterBatteryCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/meter/powerwall_decorators.go b/meter/powerwall_decorators.go index fc68c0880..12c7cefbf 100644 --- a/meter/powerwall_decorators.go +++ b/meter/powerwall_decorators.go @@ -49,6 +49,9 @@ type decoratePowerWallCapable struct { func (d *decoratePowerWallCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/meter/rct_decorators.go b/meter/rct_decorators.go index 828761eb9..44857b73c 100644 --- a/meter/rct_decorators.go +++ b/meter/rct_decorators.go @@ -57,6 +57,9 @@ type decorateRCTCapable struct { func (d *decorateRCTCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/meter/shelly_decorators.go b/meter/shelly_decorators.go index 2a7e3b3ec..cc2e48ff7 100644 --- a/meter/shelly_decorators.go +++ b/meter/shelly_decorators.go @@ -37,6 +37,9 @@ type decorateShellyCapable struct { func (d *decorateShellyCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/meter/tasmota_decorators.go b/meter/tasmota_decorators.go index dee171478..0ad3cc223 100644 --- a/meter/tasmota_decorators.go +++ b/meter/tasmota_decorators.go @@ -37,6 +37,9 @@ type decorateTasmotaCapable struct { func (d *decorateTasmotaCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/meter/tq-em_decorators.go b/meter/tq-em_decorators.go index 838a28b61..e4424c290 100644 --- a/meter/tq-em_decorators.go +++ b/meter/tq-em_decorators.go @@ -29,6 +29,9 @@ type decorateTqEmCapable struct { func (d *decorateTqEmCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/vehicle/tronity_decorators.go b/vehicle/tronity_decorators.go index 07e3da4a5..43d96e5e1 100644 --- a/vehicle/tronity_decorators.go +++ b/vehicle/tronity_decorators.go @@ -37,6 +37,9 @@ type decorateTronityCapable struct { func (d *decorateTronityCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok } diff --git a/vehicle/vehicle_decorators.go b/vehicle/vehicle_decorators.go index 3949aaecb..aff3271a9 100644 --- a/vehicle/vehicle_decorators.go +++ b/vehicle/vehicle_decorators.go @@ -74,6 +74,9 @@ type decorateVehicleCapable struct { func (d *decorateVehicleCapable) Capability(typ reflect.Type) (any, bool) { c, ok := d.caps[typ] + if !ok && reflect.TypeOf(d).Implements(typ) { + return d, true + } return c, ok }