Use TomTom-evSearch API for integrating status of public chargepoints

Problem Statement
I am struggling to find a time slot for a public chargepoint
I’m trying to hit reload on a charging-App manually multiple times
But the public chargepoint is a busy one and offers only two loadoints, which are more or less constantly occupied
Because there’s only a limited time slot, when one loadpoint is available as it’s very cheap by far
Which makes me feel frustated and hit the reload button every other minute! :wink:

Solution
Find a public available (best case free) API, which offers the status of a specific loadpoint and/or loadpoints of a chargepoint. Then add items for those states, so I can build rules around it.

Step1: Get TomTom account
As of now (Nov '24), there’s a Freemium plan of the TomTom API, which allows for 2,500 free on-tile request daily. Which is all you need. After successful registration copy your API Key.

Step2: Find out, the TomTom ID of your specific chargepoint
After successfully registered, you’ll need to login to your account on developer.tomtom.com and use the “Nearby search” with coordinates near the chargepoint on this page:

You’ll get an JSON as response, which you can walk through (again v2 of that endpoint in Nov '24): object►results►0►id (assuming your desired chargepoint is the first result in that JSON). That ID looks something like this: 12345678-123-1234-1234-12345678912 (alphanumerical). Copy that ID

Step2: Add http-thing for TomTom
With -again v2 Nov '24- you can add five new channels for each of the possible status: available, occupied, outOfService, reserved, unknown:

UID: http:url:HTTPYourChargePoint
label: HTTP Your Chargepoint
thingTypeUID: http:url
configuration:
  authMode: BASIC
  ignoreSSLErrors: false
  baseURL: https://api.tomtom.com/search/2/chargingAvailability.json
  delay: 0
  stateMethod: GET
  refresh: 60
  commandMethod: GET
  contentType: text/plain
  timeout: 3000
  bufferSize: 2048
channels:
  - id: last-failure
    channelTypeUID: http:request-date-time
    label: Last Failure
    configuration: {}
  - id: last-success
    channelTypeUID: http:request-date-time
    label: Last Success
    configuration: {}
  - id: responseJSON
    channelTypeUID: http:string
    label: JSON four your chargepoint
    description: JSON for status of your chargepoint
    configuration:
      stateExtension: ?chargingAvailability={INSERT_ID_OF_CHARGEPOINT}&key={INSERT_YOUR_API-KEY}
  - id: availableLoadpoints
    channelTypeUID: http:number
    label: available loadpoints
    description: amount of available loadpoints
    configuration:
      stateExtension: ?chargingAvailability={INSERT_ID_OF_CHARGEPOINT}&key={INSERT_YOUR_API-KEY}
      stateTransformation: JSONPATH:$.connectors[0].availability.current.available
  - id: occupiedLoadpoints
    channelTypeUID: http:number
    label: occupied loadpoints
    description: amount of occupied loadpoints
    configuration:
      stateExtension: ?chargingAvailability={INSERT_ID_OF_CHARGEPOINT}&key={INSERT_YOUR_API-KEY}
      stateTransformation: JSONPATH:$.connectors[0].availability.current.occupied
  - id: offlineLoadpoints
    channelTypeUID: http:number
    label: offline loadpoints
    description: amount of offline loadpoints
    configuration:
      stateExtension: ?chargingAvailability={INSERT_ID_OF_CHARGEPOINT}&key={INSERT_YOUR_API-KEY}
      stateTransformation: JSONPATH:$.connectors[0].availability.current.outOfService
  - id: reservedLoadpoints
    channelTypeUID: http:number
    label: reserved loadpoints
    description: amount of reserved loadpoints
    configuration:
      stateExtension: ?chargingAvailability={INSERT_ID_OF_CHARGEPOINT}&key={INSERT_YOUR_API-KEY}
      stateTransformation: JSONPATH:$.connectors[0].availability.current.reserved
  - id: unknownLoadpoints
    channelTypeUID: http:number
    label: unknown loadpoints
    description: amount of unknown loadpoints
    configuration:
      stateExtension: ?chargingAvailability={INSERT_ID_OF_CHARGEPOINT}&key={INSERT_YOUR_API-KEY}
      stateTransformation: JSONPATH:$.connectors[0].availability.current.unknown

Step3: Add the items
Add the items and link them to the channels as you like. for me, best is to “Add Equipment from Thing”
Now you should have at least five items:

  • LoadpointsAvailable
  • LoadpointsOccupied
  • LoadpointsOffline
  • LoadpointsReserved
  • LoadpointsUnknown

As I only need to “observe” in a certain amount of time, I addes a “LoadpointsObservation” item. It’s a simple switch-item in the same Group/Model as the above ones. Description later on. In the Metadata I used “Expire” to set the item to “OFF” after 12h (which should be enough as observation time)

value: 12h0m0s,OFF
config: {}

What happens now, is that http-binding calls the API in the configured intervall (60secs in Step2 refresh)

Step4: a rule for it.
It’s a simple rule and fires, if the “Available”-item changes. It then will compare the previous state with the current one and add a log-entry and send a notification.

configuration: {}
triggers:
  - id: "2"
    configuration:
      itemName: LoadpointsAvailable
    type: core.ItemStateChangeTrigger
conditions:
  - inputs: {}
    id: "1"
    configuration:
      itemName: LoadpointsObservation
      state: ON
      operator: =
    type: core.ItemStateCondition
actions:
  - inputs: {}
    id: "3"
    configuration:
      type: application/javascript
      script: >
        // checks, when a loadpoint of your chargepoint is available or is occupied again

        var prevAvailable =
        items.getItem("LoadpointsAvailable").persistence.previousState(true,
        "jdbc").numericState;
        var curAvailable = items.getItem("LoadpointsAvailable").numericState;

        var text = curVerfuegbar + " loadpoints available on YOUR CHARGEPOINT! was "
        + prevVerfuegbar;
        var icon = "";
        var tag = "";

        if (prevVerfuegbar == 0 && curVerfuegbar > 0) {
          // at least one is available now
          text += " Drive now!";
          icon = "flowpipe";
          tag = "info";
        } else if (prevVerfuegbar > 0 && curVerfuegbar == 0) {
          // previously available turned to occupied
          text += " Stay or return home!"
          icon = "error";
          tag = "urgent";
        }


        if (icon != "") {
          console.info("INFO Loadpoint: " + text);
          actions.NotificationAction.sendNotification("YOUR@EMAIL.COM", text, icon, tag);  
        }
    type: script.ScriptAction

Step5: whatever you want
of course that’s not the only thing you could do with that information. I’m thinking on adding some flavour to it with calculating the “occupied since” or “available since” timeframe. So you could also use that information (based on persistence and “lastChanged”-argument) to further drive my inner nerd. You could display that on a page or widget, you could add some logic to it like “average standing time is xx hours” and use it to “predict” free timeslots…

3 Likes