Kostal Piko 4.6 API

Lately i got interested in the data capture of certain energy values around our house. One of those measurements are the values from our PV inverter. It is a Piko 4.6 from Kostal.

Through some research and trial and error i discovered that there is an API endpoint that can be queried for certain values. It is located at: http://<ip-of-your-inverter>/api/dxs.json?<list-of-data to query>.

I discovered that the following numbers correspond to the following values:

Dxs entry id Value description Unit
251658753 Total yield - de: Ertrag gesamt kWh
251658496 Operating hours - de: Betriebsstunden h
251659009 Total household consumption - de: Hausverbrauch gesamt kWh
251659265 Total self-consumption - de: Eigenverbrauch gesamt kWh
251659280 Self-consumption rate - de: Eigenverbrauchsquote %
251659281 Total degree of self-sufficiency - de: Autarkiegrad gesamt %
251658754 Yield today - de: Ertrag heute Wh
251659010 Household consumption today - de: Hausverbrauch heute Wh
251659266 Self-consumption today - de: Eigenverbrauch heute Wh
251659279 Degree of self-sufficiency - de: Autarkiegrad %
33556736 Total DC input power - de: C Eingangsleistung gesamt W
67109120 Total AC output power - de: C Ausgangsleistung gesamt W
33555202 Input DC 1 voltage - de: Eingang DC 1 Spannung V
33555201 Input DC 1 current - de: Eingang DC 1 Strom A
33555203 Input DC 1 Power - de: Eingang DC 1 Leistung W
33555458 Input DC 2 voltage - de: Eingang DC 2 Spannung V
33555457 Input DC 2 current - de: Eingang DC 2 Strom A
33555459 Input DC 2 power - de: ingang DC 2 Leistung W
67110400 Mains frequency - de: Netzfrequenz Hz
67110656 Cosine phi - de: Cosinus phi -
67110144 Regulate to - de: Abregeln auf %
67109378 Voltage Phase 1 - de: Spannung Phase 1 V
67109377 Current Phase 1 - de: Strom Phase 1 A
67109379 Power Phase 1 - de: Leistung Phase 1 W
67109634 Voltage Phase 2 - de: Spannung Phase 2 V
67109633 Current Phase 2 - de: Strom Phase 2 A
67109635 Power Phase 2 - de: Leistung Phase 2 W
67109890 Voltage Phase 3 - de: Spannung Phase 3 V
67109889 Current Phase 3 - de: Strom Phase 3 A
67109891 Power Phase 3 - de: Leistung Phase 3 W

So in order to query the total yield, the total AC and DC power as well als the DC powers of the two strings (1 and 2) and the phase powers, the query would looked like the following:

http://<ip-of-your-inverter>/api/dxs.json?dxsEntries=251658753&dxsEntries=67109120&dxsEntries=33556736&dxsEntries=33555203&dxsEntries=33555459&dxsEntries=67109379&dxsEntries=67109635&dxsEntries=67109891

Executing this with curl produces the following output:

❯ curl -v "http://192.168.0.101/api/dxs.json?dxsEntries=251658753&dxsEntries=67109120&dxsEntries=33556736&dxsEntries=33555203&dxsEntries=33555459&dxsEntries=67109379&dxsEntries=67109635&dxsEntries=67109891"
*   Trying 192.168.0.101:80...
* Connected to 192.168.0.101 (192.168.0.101) port 80
> GET /api/dxs.json?dxsEntries=251658753&dxsEntries=67109120&dxsEntries=33556736&dxsEntries=33555203&dxsEntries=33555459&dxsEntries=67109379&dxsEntries=67109635&dxsEntries=67109891 HTTP/1.1
> Host: 192.168.0.101
> User-Agent: curl/8.9.1
> Accept: */*
>
* Request completely sent off
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: text/plain
< Expires: Sun, 02 Jan 2000 11:11:11 GMT
<
* shutting down connection #0
{"dxsEntries":[{"dxsId":251658753,"value":41731.171875},{"dxsId":67109120,"value":2222.075928},{"dxsId":33556736,"value":2390.199707},{"dxsId":33555203,"value":1106.056152},{"dxsId":33555459,"value":1284.143555},{"dxsId":67109379,"value":744.989014},{"dxsId":67109635,"value":741.761047},{"dxsId":67109891,"value":735.325867}],"session":{"sessionId":0,"roleId":0},"status":{"code":0}}⏎

The returned data format is json even if it claims to be text/plain. When inspecting the output more carefully we can see that we got the measurements for all requested metrics:

{
  "dxsEntries": [
    // answers are returned in the "dxsEntries" array
    { "dxsId": 251658753, "value": 41731.171875 }, // Total yield
    { "dxsId": 67109120, "value": 2222.075928 }, // Total AC output power
    { "dxsId": 33556736, "value": 2390.199707 }, // Total DC input power
    { "dxsId": 33555203, "value": 1106.056152 }, // Input DC 1 Power
    { "dxsId": 33555459, "value": 1284.143555 }, // Input DC 2 power
    { "dxsId": 67109379, "value": 744.989014 }, // Power Phase 1
    { "dxsId": 67109635, "value": 741.761047 }, // Power Phase 2
    { "dxsId": 67109891, "value": 735.325867 } // Power Phase 3
  ],
  "session": { "sessionId": 0, "roleId": 0 },
  "status": { "code": 0 }
}

To make these values easier to use i want them to be in an Influx DB so that i can work with them. I use Telegraf to ingest this data. A possible configuration could look like this:

[[inputs.http]]
  urls = [
    "http://192.168.0.101/api/dxs.json?dxsEntries=251658753&dxsEntries=67109120&dxsEntries=33556736&dxsEntries=33555203&dxsEntries=33555459&dxsEntries=67109379&dxsEntries=67109635&dxsEntries=67109891"
  ]
  method = "GET"
  data_format = "json"
  json_query = "dxsEntries"
  name_override = "pv_generation"
  tag_keys = ["dxsId"]
  tagexclude = ["url"]

[[processors.starlark]]
  namepass = ["pv_generation"]
  source = '''
dxs_map = {
    "251658753": "total_yield",
    "67109120": "ac_output_power",
    "33556736": "dc_input_power",
    "33555203": "input_dc1_power",
    "33555459": "input_dc2_power",
    "67109379": "power_phase_1",
    "67109635": "power_phase_2",
    "67109891": "power_phase_3"
}

def apply(metric):
    dxsId = metric.tags.get("dxsId")
    if dxsId in dxs_map:
        val = metric.fields.get("value")
        val_key = dxs_map[dxsId]
        new_metric = Metric(metric.name)
        new_metric.time = metric.time
        new_metric.fields[val_key] = val
        for k,v in metric.tags.items():
            if k != "dxsId":
                new_metric.tags[k] = v
        return new_metric
    return None
'''

First it uses the http input to read the data from the http api. The output of the http plugin itself is not that descriptive so i added a processor that renames the fields from the dxs id’s to more descriptive names.