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.
How to define a device
Section titled “How to define a device”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/rawAlternatively, 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/rawAll 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.
Attributes and features
Section titled “Attributes and features”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. - Features —
featureslist toggling non-default behaviour. Available flags depend on the device type.
Generic shape:
# read attributespower: source: http uri: http://meter.local/powersoc: source: mqtt topic: battery/soc
# write attributesenable: source: http uri: "http://charger/relay?turn={{if .enable}}on{{else}}off{{end}}"maxcurrent: source: mqtt topic: charger/maxcurrent payload: ${maxcurrent:%d}
# featuresfeatures: - heating - integrateddeviceThe 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 meterpv: PV meterbattery: Home battery metercharge: Meter for the charging power of the wallboxaux: Consumption meter for intelligent consumersext: Additional meter, e.g. for load management or data collection
power is the only required attribute.
Not all meter roles support all attributes:
limitsocandbatterymodeare used exclusively for battery meters (referenced fromsite.battery).currents,voltagesandpowersare 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.
Read attributes
Section titled “Read attributes”| Attribute | Type | Required | Context | Description |
|---|---|---|---|---|
power | float | yes | all | Current power in W |
energy | float | no | all | Meter reading in kWh |
maxpower | int | no | pv (hybrid) | Maximum AC power in W |
soc | int | no | battery | State of charge in % |
capacity | float | no | battery | Capacity in kWh |
powers | [float,float,float] | no | all | Phase powers in W. For sign detection of unsigned currents. |
currents | [float,float,float] | no | all | Phase currents in A. For detecting active phases. |
voltages | [float,float,float] | no | all | Phase voltages in V. For connection detection (1p/3p). |
Write attributes
Section titled “Write attributes”| Attribute | Type | Required | Context | Description |
|---|---|---|---|---|
limitsoc | int | no | battery | Set charging target for battery in %. The charging target is calculated from the configured MinSoc, MaxSoc and the current state of charge (attribute soc). |
batterymode | int | no | battery | Set charging mode directly (1: normal, 2: hold, 3: charge) |
Example
Section titled “Example”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]Charger
Section titled “Charger”The default type: custom covers wallboxes with continuous current control.
For other devices, specialised charger types are described under Switchsocket and Heat pumps.
Read attributes
Section titled “Read attributes”| Attribute | Type | Required | Description |
|---|---|---|---|
status | string | yes | Status (A..F) |
enabled | bool | yes | Is charging enabled? |
power | float | no | Charging power in W |
energy | float | no | Meter reading in kWh |
identify | string | no | Current RFID identifier |
soc | int | no | State of charge in % |
limitsoc | int | no | Charge limit in % |
temp | float | no | Current temperature in °C (heating, alias for soc) |
limittemp | int | no | Temperature limit in °C (heating, alias for limitsoc) |
finishtime | string | no | Estimated charging finish time (RFC3339, Go duration, Unix timestamp, or remaining seconds) |
phases | int | no | Number of physical phases (1..3) |
powers | [float,float,float] | no | Phase powers in W. For sign detection of unsigned currents. |
currents | [float,float,float] | no | Phase currents in A. For detecting active phases. |
voltages | [float,float,float] | no | Phase voltages in V. For connection detection (1p/3p). |
Write attributes
Section titled “Write attributes”| Attribute | Type | Required | Description |
|---|---|---|---|
enable | bool | yes | Enable / disable charging |
maxcurrent | int | yes | Set maximum charging current in A |
maxcurrentmillis | float | no | Set maximum charging current in A (with decimals) |
phases1p3p | int | no | Perform phase switching (requires tos: true) |
wakeup | bool | no | Wake up vehicle |
Features
Section titled “Features”| Feature | Description |
|---|---|
integrateddevice | No vehicle selection. Device runs without a connected vehicle and without charging sessions (e.g. heat pump, heating rod, permanently installed consumer). |
heating | Treat device as heating: SOC and limits are displayed in °C instead of %. |
continuous | Device 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”. |
switchdevice | Device can only be switched on/off (no continuous current control). Min/max current settings and the Min+PV mode are hidden. |
Common feature combinations seen in built-in templates:
Electric heater:
features: - integrateddevice - heatingSocket:
features: - switchdevice - integrateddevice # optional, when the socket drives a fixed load - heating # optional, when it controls a heating deviceHeat pump:
features: - integrateddevice - heating - continuous - switchdevice # optional, when no current control is available (SG Ready)Examples
Section titled “Examples”Query the charging status of a charger via Modbus.
features: - integrateddeviceenabled: source: modbus id: 4711 uri: modbus.local:502 rtu: false register: address: 100 type: holding decode: uint16Switch a Tasmota socket via an MQTT message.
enable: source: mqtt broker: mosquitto.local:883 topic: cmd/unu-switch/Power payload: ONSwitchsocket
Section titled “Switchsocket”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.
| Attribute | Type | Required | Description |
|---|---|---|---|
enabled | bool | yes | Read socket state (on/off) |
power | float | yes | Current power in W |
energy | float | no | Meter reading in kWh |
soc | float | no | State of charge in % |
enable | bool | yes | Switch socket on/off |
standbypower | float | no | Power threshold in W. Above it: charging; below: standby. Negative: static (no metering) |
Heat pumps
Section titled “Heat pumps”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.
| Attribute | Type | Required | Description |
|---|---|---|---|
power | float | no | Current power in W |
energy | float | no | Meter reading in kWh |
temp | float | no | Current temperature in °C |
limittemp | int | no | Device-internal temperature limit in °C |
setmaxpower | int | yes | Set maximum heating power in W |
getmaxpower | float | no | Current maximum heating power in W |
type: sgready
For heat pumps that expose the standard SG-Ready interface as a single mode value.
Three modes are supported: 1 reduced, 2 normal, 3 boost.
| Attribute | Type | Required | Description |
|---|---|---|---|
power | float | no | Current power in W |
energy | float | no | Meter reading in kWh |
temp | float | no | Current temperature in °C |
limittemp | int | no | Device-internal temperature limit in °C |
setmode | int | yes | Change SG-Ready mode (1: reduced, 2: normal, 3: boost) |
getmode | int | no | Current SG-Ready mode (1, 2, 3) |
setmaxpower | int | no | Set maximum heating power in W |
type: sgready-relay
For heat pumps whose SG-Ready input is wired as two dry relay contacts (boost + dim). Each contact is driven by a separate sub-charger referenced by type, not via plugins.
| Attribute | Type | Required | Description |
|---|---|---|---|
power | float | no | Current power in W |
energy | float | no | Meter reading in kWh |
temp | float | no | Current temperature in °C |
limittemp | int | no | Device-internal temperature limit in °C |
boost | charger-typed | yes | Relay for the SG-Ready boost contact |
dim | charger-typed | no | Relay for the SG-Ready dim contact |
Vehicle
Section titled “Vehicle”Vehicle parameters can also be read via plugins.
Read attributes
Section titled “Read attributes”| Attribute | Type | Required | Description |
|---|---|---|---|
soc | int | yes | State of charge in % |
limitsoc | int | no | Charge limit in % |
status | string | no | Status (A..F) |
range | int | no | Range in km |
odometer | int | no | Odometer reading in km |
climater | bool | no | Climate control active? |
getmaxcurrent | float | no | Maximum charging current in A |
finishtime | string | no | Estimated charging finish time (RFC3339, Go duration, Unix timestamp, or remaining seconds) |
Write attributes
Section titled “Write attributes”| Attribute | Type | Required | Description |
|---|---|---|---|
wakeup | bool | no | Wake up vehicle |
chargeenable | bool | no | Start/stop charging process |
maxcurrent | int | no | Set maximum charging current in A |
Configuration
Section titled “Configuration”| Attribute | Type | Required | Description |
|---|---|---|---|
title | string | no | Display name of the vehicle |
capacity | float | no | Battery capacity in kWh |
icon | string | no | Icon shown in the user interface |
Features
Section titled “Features”| Feature | Description |
|---|---|
coarsecurrent | Vehicle 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. |
streaming | Vehicle pushes data instead of being polled (e.g. BMW Cardata). SOC updates outside active charging are treated as reliable. |
welcomecharge | Vehicle expects the wallbox to be active on connect to register the link as working. Otherwise it reports an error. |
Examples
Section titled “Examples”Read the current range from MQTT messages.
title: Green Mazda # display name (optional)capacity: 50 # battery capacity in kWh (optional)features: - coarsecurrentrange: source: mqtt topic: mazda2mqtt/c53/chargeInfo/drivingRangeKmWake a car via an HTTP ping before sending further queries.
wakeup: source: http uri: http://teslalogger.local:5000/command/08154711/wake_uponIdentify sets the charge mode automatically when the vehicle is detected.
soc: source: mqtt topic: car/soconIdentify: mode: pvAvailable modes: off, now, minpv, pv.
Tariff and forecast
Section titled “Tariff and forecast”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.
Read attributes
Section titled “Read attributes”Exactly one of price or forecast must be configured.
| Attribute | Type | Description |
|---|---|---|
price | float | Current value. Float returned by the plugin. |
forecast | string | Forecast as JSON string with a list of time periods and values (see schema below). Polled hourly. |
Configuration
Section titled “Configuration”| Attribute | Type | Required | Description |
|---|---|---|---|
tariff | string | no | price (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. |
charges | float | no | Fixed additional charge per kWh added to every value. Default 0. |
tax | float | no | Percentage tax applied to the result, e.g. 0.2 for 20 %. Default 0. |
formula | string | no | Go expression for a custom calculation, with price, charges and tax in scope. See examples. |
interval | duration | no | Polling interval for forecast. Default 1h. |
cache | duration | no | Cache duration for price. Default 15m. |
Features
Section titled “Features”| Feature | Description |
|---|---|
average | Smooths fine-grained price slots (e.g. 15-minute values) into hourly averages. |
cacheable | Persists fetched values. Used as fallback after a restart or provider outage (up to 24 hours). |
Examples
Section titled “Examples”Current price via HTTP:
price: source: http uri: https://example.com/api/priceForecast 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.22tax: 0.19formula: 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.07Pays a fixed feed-in tariff of 7 ct/kWh, except when the day-ahead market price is negative.