Skip to content
EN | DE

User-defined Devices

When creating a charger, heater, grid meter, battery, solar system, other consumer, vehicle, tariff or notification service, you can pick the User-defined device option from the device type list and describe your own logic based on the plugin system.

That way you can integrate devices that aren’t covered by a built-in template, e.g. read the current power from an HTTP endpoint, or write a target current via Modbus.

In the UI, every device type lists a User-defined device entry in the template selector. Picking it opens the editor for your own configuration. A device with type: custom is created by default. The type can be overridden with another value when needed (e.g. type: heatpump).

power:
source: mqtt
topic: home/current/imsys/chn2/raw

Alternatively, write the full configuration directly in evcc.yaml with name, type: custom and the attribute block underneath:

meters:
- name: imsys
type: custom
power:
source: mqtt
topic: home/current/imsys/chn2/raw

All other examples on this page use the flat attribute-block form you enter in the UI.

For the list of available plugin sources (http, mqtt, modbus, …) and helpers (calc, map, watchdog, …) see the plugins reference.

Every user-defined device is described by three kinds of fields:

  • Read attributes — plugins evcc polls to obtain a value (e.g. power, soc, status).
  • Write attributes — plugins evcc invokes to set a value or trigger an action (e.g. enable, maxcurrent, wakeup). The value to be written is available in the plugin.
  • Featuresfeatures list toggling non-default behaviour. Available flags depend on the device type.

Generic shape:

# read attributes
power:
source: http
uri: http://meter.local/power
soc:
source: mqtt
topic: battery/soc
# write attributes
enable:
source: http
uri: "http://charger/relay?turn={{if .enable}}on{{else}}off{{end}}"
maxcurrent:
source: mqtt
topic: charger/maxcurrent
payload: ${maxcurrent:%d}
# features
features:
- heating
- integrateddevice

The available attribute names and feature flags differ per device type and are listed in the sections below.

Power meters are configured in the meters section. Meters defined under meters: can be referenced from site:

  • grid: Grid meter
  • pv: PV meter
  • battery: Home battery meter
  • charge: Meter for the charging power of the wallbox
  • aux: Consumption meter for intelligent consumers
  • consumer: Meter for a regular consumer, recorded for consumption statistics
  • ext: Additional meter not used for regulation or shown in the UI, only logged and exported

power is the only required attribute. Not all meter roles support all attributes:

  • limitsoc and batterymode are used exclusively for battery meters (referenced from site.battery).
  • currents, voltages and powers are phase attributes that must be configured with exactly three plugin entries each (as a YAML array) and apply to grid meters (grid) and wallboxes (charge).

Return the correct data type from each plugin. To convert, use the reading pipelines.

AttributeTypeRequiredContextDescription
powerfloatyesallCurrent power in W
energyfloatnoallMeter reading in kWh
returnenergyfloatnoallMeter reading in reverse direction in kWh (see below)
maxpowerintnopv (hybrid)Maximum AC power in W
socintnobatteryState of charge in %
capacityfloatnobatteryCapacity in kWh
powers[float,float,float]noallPhase powers in W. For sign detection of unsigned currents.
currents[float,float,float]noallPhase currents in A. For detecting active phases.
voltages[float,float,float]noallPhase voltages in V. For connection detection (1p/3p).

What a positive power value and the two energy directions mean depends on the meter role:

Rolepower positiveenergyreturnenergy
gridGrid importImportedExported (feed-in)
pvProductionProducedConsumed (rare)
batteryDischarging (negative: charging)DischargedCharged
chargeChargingChargedDischarged (V2X)
aux, ext, consumerConsumptionConsumedProduced (rare)

energy and returnenergy are increasing meter readings in kWh, ideally lifetime totals like the import and export registers of a grid meter. The differences between readings are calculated automatically, so the plugin must return a meter reading and not consumption values per interval. A counter that resets periodically (e.g. daily) also works, as the reset is detected automatically. A reading of 0 is treated as not available.

Both attributes are optional. Without them, the energy history is derived from power over time. Real meter readings give more accurate long-term statistics.

AttributeTypeRequiredContextDescription
limitsocintnobatterySet charging target for battery in %. The charging target is calculated from the configured MinSoc, MaxSoc and the current state of charge (attribute soc).
batterymodeintnobatterySet charging mode directly (1: normal, 2: hold, 3: charge)

Read the current grid power from an HTTP endpoint.

power:
source: http
uri: http://zaehler.network.local:8080/api/data.json?from=now
jq: .data.tuples[0][1]

The default type: custom covers wallboxes with continuous current control. For other devices, specialised charger types are described under Switchsocket and Heat pumps.

AttributeTypeRequiredDescription
statusstringyesStatus (A..F)
enabledboolyesIs charging enabled?
powerfloatnoCharging power in W
energyfloatnoMeter reading in kWh
returnenergyfloatnoMeter reading in reverse direction in kWh (discharged energy, V2X)
identifystringnoCurrent RFID identifier
socintnoState of charge in %
limitsocintnoCharge limit in %
tempfloatnoCurrent temperature in °C (heating, alias for soc)
limittempintnoTemperature limit in °C (heating, alias for limitsoc)
finishtimestringnoEstimated charging finish time (RFC3339, Go duration, Unix timestamp, or remaining seconds)
phasesintnoNumber of physical phases (1..3)
powers[float,float,float]noPhase powers in W. For sign detection of unsigned currents.
currents[float,float,float]noPhase currents in A. For detecting active phases.
voltages[float,float,float]noPhase voltages in V. For connection detection (1p/3p).
AttributeTypeRequiredDescription
enableboolyesEnable / disable charging
maxcurrentintyesSet maximum charging current in A
maxcurrentmillisfloatnoSet maximum charging current in A (with decimals)
phases1p3pintnoPerform phase switching (requires tos: true)
wakeupboolnoWake up vehicle
FeatureDescription
integrateddeviceNo vehicle selection. Device runs without a connected vehicle and without charging sessions (e.g. heat pump, heating rod, permanently installed consumer).
heatingTreat device as heating: SOC and limits are displayed in °C instead of %.
continuousDevice keeps running in its own normal operation when “disabled”. The UI shows “Normal operation” instead of “Standby”. A request to increase power (e.g. on PV surplus or cheap grid power) is labelled “Boost”.
switchdeviceDevice can only be switched on/off (no continuous current control). Max current and the Min+PV mode are not shown. Min current and phases set the PV enable power.

Common feature combinations seen in built-in templates:

Electric heater:

features:
- integrateddevice
- heating

Socket:

features:
- switchdevice
- integrateddevice # optional, when the socket drives a fixed load
- heating # optional, when it controls a heating device

Heat pump:

features:
- integrateddevice
- heating
- continuous
- switchdevice # optional, when no current control is available (SG Ready)

Query the charging status of a charger via Modbus.

features:
- integrateddevice
enabled:
source: modbus
id: 4711
uri: modbus.local:502
rtu: false
register:
address: 100
type: holding
decode: uint16

Switch a Tasmota socket via an MQTT message.

enable:
source: mqtt
broker: mosquitto.local:883
topic: cmd/unu-switch/Power
payload: ON

type: switchsocket

For smart sockets and similar relay devices that can only be switched on/off without continuous current control. The charging status is derived from the current power (above standbypower means charging). Full setup details are under Smart switches.

AttributeTypeRequiredDescription
enabledboolyesRead socket state (on/off)
powerfloatyesCurrent power in W
energyfloatnoMeter reading in kWh
socfloatnoState of charge in %
enableboolyesSwitch socket on/off
standbypowerfloatnoPower threshold in W. Above it: charging; below: standby. Negative: static (no metering)

Heat pumps and similar heating devices use dedicated charger types, each with its own attributes. The full setup is described under Heat pumps, electric heaters.

type: heatpump

For inverter-controlled heat pumps that accept a continuous power setpoint over Modbus, HTTP or similar. The target heating power is written directly via setmaxpower.

AttributeTypeRequiredDescription
powerfloatnoCurrent power in W
energyfloatnoMeter reading in kWh
tempfloatnoCurrent temperature in °C
limittempintnoDevice-internal temperature limit in °C
setmaxpowerintyesSet maximum heating power in W
getmaxpowerfloatnoCurrent maximum heating power in W

Vehicle parameters can also be read via plugins.

AttributeTypeRequiredDescription
socintyesState of charge in %
limitsocintnoCharge limit in %
statusstringnoStatus (A..F)
rangeintnoRange in km
odometerintnoOdometer reading in km
climaterboolnoClimate control active?
getmaxcurrentfloatnoMaximum charging current in A
finishtimestringnoEstimated charging finish time (RFC3339, Go duration, Unix timestamp, or remaining seconds)
AttributeTypeRequiredDescription
wakeupboolnoWake up vehicle
chargeenableboolnoStart/stop charging process
maxcurrentintnoSet maximum charging current in A
AttributeTypeRequiredDescription
titlestringnoDisplay name of the vehicle
capacityfloatnoBattery capacity in kWh
iconstringnoIcon shown in the user interface
FeatureDescription
coarsecurrentVehicle accepts charging current only in whole 1 A steps. The control logic is constrained to coarse 1 A steps even when the charger could regulate more finely.
streamingVehicle pushes data instead of being polled (e.g. BMW Cardata). SOC updates outside active charging are treated as reliable.
welcomechargeVehicle expects the wallbox to be active on connect to register the link as working. Otherwise it reports an error.

Read the current range from MQTT messages.

title: Green Mazda # display name (optional)
capacity: 50 # battery capacity in kWh (optional)
features:
- coarsecurrent
range:
source: mqtt
topic: mazda2mqtt/c53/chargeInfo/drivingRangeKm

Wake a car via an HTTP ping before sending further queries.

wakeup:
source: http
uri: http://teslalogger.local:5000/command/08154711/wake_up

onIdentify sets the charge mode automatically when the vehicle is detected.

soc:
source: mqtt
topic: car/soc
onIdentify:
mode: pv

Available modes: off, now, minpv, pv.

A user-defined tariff connects evcc to a custom value source via the plugin mechanism. The tariff attribute selects what the source represents and which unit the values use.

Exactly one of price or forecast must be configured.

AttributeTypeDescription
pricefloatCurrent value. Float returned by the plugin.
forecaststringForecast as JSON string with a list of time periods and values (see schema below). Polled hourly.
AttributeTypeRequiredDescription
tariffstringnoprice (default), co2 or solar. Sets the unit of the returned values: price in configured currency per kWh, CO₂ intensity in g/kWh, solar forecast in W.
chargesfloatnoFixed additional charge per kWh added to every value. Default 0.
chargesZoneslistnoTime-based charges (e.g. grid fees) that override charges for specific periods. See time-based grid fees.
taxfloatnoPercentage tax applied to the result, e.g. 0.2 for 20%. Default 0.
formulastringnoGo expression for a custom calculation, with price, charges and tax in scope. See examples.
intervaldurationnoPolling interval for forecast. Default 1h.
cachedurationnoCache duration for price. Default 15m.
FeatureDescription
averageSmooths fine-grained price slots (e.g. 15-minute values) into hourly averages.
cacheablePersists fetched values. Used as fallback after a restart or provider outage (up to 24 hours).

Current price via HTTP:

price:
source: http
uri: https://example.com/api/price

Forecast via HTTP:

forecast:
source: http
uri: https://api.allinpower.nl/troodon/api/p/spot_market/prices/?product_type=ELK
jq: '[.timestamps, .prices] | transpose | map({ "start": (.[0] | strptime("%Y-%m-%dT%H:%M:%S.%f%z") | strftime("%Y-%m-%dT%H:%M:%SZ")), "end": (.[0] | strptime("%Y-%m-%dT%H:%M:%S.%f%z") | mktime + 3600 | strftime("%Y-%m-%dT%H:%M:%SZ")), "value": .[1] }) | tostring'

The plugin must return a JSON structure containing a list of time periods and prices. Date fields must be in the form YYYY-MM-DDTHH:MM:SSZ and the price in the correct currency unit (e.g. EUR). evcc works internally with 15-minute intervals; plugins may return hourly data, which is converted automatically.

[
{
"start": "2025-01-01T00:00:00Z",
"end": "2025-01-01T00:15:00Z",
"value": 25.0
},
{
"start": "2025-01-01T00:15:00Z",
"end": "2025-01-01T00:30:00Z",
"value": 26.5
},
{
"start": "2025-01-01T00:30:00Z",
"end": "2025-01-01T00:45:00Z",
"value": 24.8
},
{
"start": "2025-01-01T00:45:00Z",
"end": "2025-01-01T01:00:00Z",
"value": 27.2
}
]

The formula field accepts a Go expression with price, charges, tax and the slot timestamp ts in scope. The math library and time.Time methods on ts are available. The formula runs for the current price and each forecast slot.

Price cap:

charges: 0.22
tax: 0.19
formula: math.Min(0.5, (price + charges) * (1 + tax))

Caps the result at 50 ct/kWh.

No feed-in tariff on negative day-ahead prices (German PV systems commissioned after February 25, 2025):

formula: factor := 1.0; if price < 0 { factor = 0.0 }; factor * 0.07

Pays a fixed feed-in tariff of 7 ct/kWh, except when the day-ahead market price is negative.

A user-defined integration for the External Limit feature connects a control box or energy management system that isn’t covered by a built-in integration. In the UI, pick User-defined integration under Configuration → External Limit.

Unlike other device types, there is no type: custom here. Instead, one of three types describes how the limit signal is received: relay (single switch contact), fnn (FNN control box with multiple switch contacts) or eebus (EEBus protocol). Each signal is read via a plugin configuration (GPIO, MQTT, HTTP, Modbus). See also the hems configuration reference.

The connection via a single switch contact is the simplest solution. The control box activates a contact which is evaluated by your evcc instance.

AttributeTypeRequiredDescription
maxPowerint (W)yesTotal power limit applied while the signal is active.
limitpluginyesPlugin configuration for reading the switch contact. true/1 = limited, false/0 = normal.
passthroughpluginnoPasses the limitation signal through to an external system.
intervaldurationnoPolling interval for the switch contact. Default 10s.

The power limit is communicated to you by the grid operator. For multiple controllable consumption devices (SteuVE), the simultaneity factor is taken into account. You can also calculate the limit yourself using the formula: Total limit = Number of SteuVE × 4.2 kW × Simultaneity factor. Details on the calculation can be found here.

When using a Raspberry Pi, the GPIO pin can be read directly:

type: relay
maxPower: 8400 # Example for 2 SteuVE
limit:
source: gpio
function: read
pin: 17 # Read GPIO pin 17
# Return value: false = not limited, true = limited

For more details on the GPIO plugin, see the plugin documentation.

Control boxes following the FNN standard signal dimming and curtailment via separate switch contacts. Consumption dimming (W4) and feed-in curtailment (W3, S2, S1) operate independently. At least one of the signals w4 or w3 must be configured.

AttributeTypeRequiredDescription
maxDimPowerint (W)yes¹Consumption limit while the dim signal (W4) is active.
maxCurtailPowerint (W)yes²Installed solar power, base value for the curtailment steps.
w4pluginnoReads the dim signal. Limits consumption to maxDimPower.
w3pluginnoReads the curtailment signal. Limits feed-in to 0% of maxCurtailPower.
s2pluginnoReads the curtailment signal. Limits feed-in to 30% of maxCurtailPower.
s1pluginnoReads the curtailment signal. Limits feed-in to 60% of maxCurtailPower.
intervaldurationnoPolling interval for the switch contacts. Default 10s.

¹ required when w4 is configured, ² required when w3 is configured.

type: fnn
maxDimPower: 4200 # Consumption limit while dimmed (in watts)
maxCurtailPower: 10000 # Installed solar power, base for curtailment steps (in watts)
w4:
source: gpio
function: read
pin: 17 # Read GPIO pin 17
# Return value: false = normal, true = active
w3:
source: gpio
function: read
pin: 27
s2:
source: gpio
function: read
pin: 22
s1:
source: gpio
function: read
pin: 23

The digital connection via the EEBus protocol. The control box communicates directly with your evcc instance and automatically transmits the power limit. Control box and evcc need to be paired once.

AttributeTypeRequiredDescription
skistringyesSKI (Subject Key Identifier) of the control box.
contractualConsumptionNominalMaxint (W)noContractual maximum consumption power.
failsafeConsumptionActivePowerLimitint (W)noFailsafe limit for consumption power.
productionNominalMaxint (W)noInstalled generator power (Wp).
failsafeProductionActivePowerLimitint (W)noFailsafe limit for feed-in power.
failsafeDurationMinimumdurationnoMinimum failsafe duration, e.g. 2h.
passthroughpluginnoPasses the limitation signal through to an external system.
type: eebus
ski: "1234-5678-90AB-CDEF" # SKI of the control box

A user-defined notification service processes notification messages via any plugin with write access, e.g. a shell script, HTTP request, or MQTT message. In the UI, pick User-defined service under Configuration → Notifications → Services.

The message is provided to the plugin in the ${send} parameter (or as a template parameter {{.send}}).

AttributeTypeRequiredDescription
sendpluginyesPlugin invoked for each message. Must support write access.
encodingstringnoFormat of the value provided in ${send}. See below.

The possible encoding values are:

EncodingContent of ${send}
jsonJSON object { "msg": msg, "title": title }. The title field is only added if defined for the event.
csvtitle and msg as a comma-separated list
tsvLike csv, but tab-separated
titleOnly the title
(none)Only the message (msg)
messaging:
events:
connect:
title: "${vehicleTitle} connected"
msg: "${vehicleTitle} was connected (charging mode: ${mode})."
services:
- type: custom
encoding: json
send:
# plugin type
source: script
# plugin-specific configuration;
# {{.send}} contains the JSON message
cmd: /usr/local/bin/evcc_message "{{.send}}"

In this example, a shell script (cmd) is invoked with the argument {"title": "...", "msg": "..."}.