custom-components / zaptec

zaptec charger custom component for home assistant
MIT License
63 stars 17 forks source link

Data from Zaptec Sense #108

Closed retifrav closed 3 weeks ago

retifrav commented 1 month ago

I might have missed something, but looks like data from Zaptec Sense isn't fetched at the moment, so this is a feature request then :)

Zaptec Sense is a module that is connected to the HAN port (a diagnostic port in a form-factor of RJ45) on the household electricity meter. Its main purpose is to read the current household power consumption and control the car charger so it wouldn't exceed a specified total power bracket.

I am mostly interested in fetching power consumption metrics, such as current household power consumption.

In Zaptec API this data is available from https://api.zaptec.com/api/installation/{id}/energySensorData, which doesn't seem to be documented (the energySensorData part). For example, a query like this (extracted from my browser console):

$ curl 'https://api.zaptec.com/api/installation/MY_INSTALLATION_ID_HERE/energySensorData?from=2024-07-26T10:59:31.000Z&to=2024-07-28T10:59:33.797Z&resolution=day1' \
    -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:129.0) Gecko/20100101 Firefox/129.0' \
    -H 'Accept: application/json, text/plain, */*' \
    -H 'Accept-Language: en,ru;q=0.5' \
    -H 'Accept-Encoding: gzip, deflate, br, zstd' \
    -H 'Authorization: Bearer MY_TOKEN_HERE' \
    -H 'Origin: https://portal.zaptec.com' \
    -H 'DNT: 1' \
    -H 'Connection: keep-alive' \
    -H 'Referer: https://portal.zaptec.com/' \
    -H 'Sec-Fetch-Dest: empty' \
    -H 'Sec-Fetch-Mode: cors' \
    -H 'Sec-Fetch-Site: same-site' \
    -H 'Pragma: no-cache' \
    -H 'Cache-Control: no-cache' \
    -H 'TE: trailers'

returns a JSON response like this (truncated, otherwise it's too long):

{
    "ChargeEnergy": [
        {
            "IntervalStart": "2024-07-26T10:00:00Z",
            "Interval": "01:00:00",
            "Value": 0.0
        },
        {
            "...": "..."
        },
        {
            "IntervalStart": "2024-07-28T10:00:00Z",
            "Interval": "01:00:00",
            "Value": 0.0
        }
    ],
    "TotalEnergy": [
        {
            "IntervalStart": "2024-07-26T10:00:00Z",
            "Interval": "01:00:00",
            "Value": 0.09923166927407186
        },
        {
            "...": "..."
        },
        {
            "IntervalStart": "2024-07-28T10:00:00Z",
            "Interval": "01:00:00",
            "Value": 0.6650176952700221
        }
    ],
    "Readings": [
        {
            "Timestamp": "2024-07-26T11:04:47.3559407+00:00",
            "Power": 1.2816600417071582
        },
        {
            "...": "..."
        },
        {
            "Timestamp": "2024-07-28T10:50:27.1515954+00:00",
            "Power": 0.5286000338733202
        }
    ],
    "PowerLimit": 17.25,
    "DynamicPowerLimit": 10.0,
    "LastReading":
    {
        "UniqueId": "SOME_ID",
        "ObservedAt": "2024-07-28T10:50:00+00:00",
        "CurrentPhase1": 0.600000023841858,
        "CurrentPhase2": 0.4000000059604645,
        "CurrentPhase3": 1.2000000476837158,
        "ChargeCurrentPhase1": 0.0,
        "ChargeCurrentPhase2": 0.0,
        "ChargeCurrentPhase3": 0.0,
        "AvailableCurrentPhase1": 6.0,
        "AvailableCurrentPhase2": 6.0,
        "AvailableCurrentPhase3": 6.0,
        "AvailableCurrentChanged": false,
        "CurrentNeutral": 0.0,
        "VoltagePhase1": 240.40000915527344,
        "VoltagePhase2": 240.60000610351562,
        "VoltagePhase3": 240.10000610351562,
        "StatusCode": "0000",
        "StatusMessage": "SOME_STATUS_MESSAGE_HERE_NOT_SURE_HOW_SENSITIVE_IT_IS",
        "Ripple": 0,
        "PartitionKey": "SOME_ID_1",
        "RowKey": "SOME_KEY",
        "Timestamp": "2024-07-28T10:50:27.1515954+00:00"
    },
    "Interval":
    {
        "From": "2024-07-26T10:59:31Z",
        "To": "2024-07-28T10:59:33.797Z",
        "Duration": "2.00:00:02.7970000"
    }
}

So it's the TotalEnergy and Readings metrics that I would be interested in, probably just the latest values. The reason why it returns series is because it has the following visualization in the user portal:

zaptec-sense-data

You can see that the latest TotalEnergy value 0.6650176952700221 became 0.67 on the blue chart. And the orange line is the Readings values. Of course, Home Assistant will have its own visualization, so there is no need to query for such a long series, this is just an illustration how the data is used by Zaptec Portal.

I can for sure help you with providing more data and/or testing beta versions with my Zaptec Sense (as you probably don't have one?). Perhaps I could even help you with the actual implementation too, as I am more or less familiar with Python, although I would first need some time/pointers to look around the repository.

sveinse commented 1 month ago

Thank you for the proposal.

The primary purpose of the Zaptec integration is to provide an interface to the Zaptec EVC. Zaptec sense is an AMS-HAN energy measurement, and I for my part does not have any plans on adding it to the current integration. Contributions through pull requests are welcome.

However, I'm a little uncertain if it should be included. Doing AMS-HAN data is somewhat different ballgame than EV charging and it would increase the scope for the integration. There exists other AMS-HAN implementation such as https://github.com/toreamun/amshan-homeassistant. It maybe worth checking if they have plans for integrating the Zaptec Sense device.

The HAN port delivers data every 2-10 seconds and once every hour. This is much more frequent that the current poll-rate of the Zaptec integration. Do you know if there are ways to subscribe to energy events instead of polling? It also worries me a little bit that the API is not documented. Does this imply that the API is not meant to be used by 3rd-party and can change at any moment?

retifrav commented 1 month ago

These are good points, and I agree that such a feature would be something outside of the current scope.

I'll try to reach out to Zaptec support to check whether this API is at all meant to be used by 3rd-party, and if so, then does it have different quota/rates or what's the recommendation there. Also, being a device connected to the local network, hopefully it also exposes some local API, so it doesn't have to go through Zaptec servers. And yes, would be great if it also published data via MQTT or something.

retifrav commented 3 weeks ago

Got a reply from Zaptec support (took them long enough to answer):

We do not have any documented and supported way of extracting metering values. Rate limits are not currently enforced for this endpoint, but will at some point. The ones that we do have documented in Swagger (https://api.zaptec.com/help/index.html) is the ones that should be used externally as of now

In other words:

So I have a ~1500 NOK device that occupies the HAN-port and does not let me use the data it collects from my electricity meter :) I guess I better get a proper (Zigbee-enabled) HAN-meter and use it in parallel with Zaptec Sense via RJ45 splitter.

This feature request can probably be closed then. It was out of scope in the first place, and even if it was implemented at some point, those potential polling rate limits would likely make it not very useful.