Xee integration

Hi victor from Spain. Thank you for you wonderful article in Medium. I´m not be able to finish it.

I get the token
{
“access_token”: “XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”,
“expires_in”: 86400,
“refresh_token”: “XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”,
“scope”: “vehicles.locations.read vehicles.read vehicles.signals.read”,
“token_type”: “Bearer”
}

When in postman I call get with https://api.xee.com/v4/users/me/vehicles and put the bearer token

No received any data []
What´s is wrong? Thank you

It’s your vehicle linked with your account? Try with the Xee application before to check if it’s correct

Yes. It´s linked. I can check the kms, the fuekl, the trips, the gps position…

The refresh_token and the access_token need to be updated every day. A simple curl script is not enough. Does anyone solve this issue?

My two cents:

You can update the token in home assistant without curl in cron.

yaml

sensor:

  • platform: command_line
    command: !secret refresh_xee_command
    name: refresh_xee
    scan_interval: 43200
    value_template: >-
    {% if value_json.access_token is defined -%}
    Token Xee Update
    {%- else -%}
    Token Xee NO Update
    {%- endif -%}

secret

refresh_xee_command: “curl -X POST https://api.xee.com/v4/oauth/token -H ‘Authorization: Basic {{acces_token}}’ -H ‘Content-Type: application/x-www-form-urlencoded’ -H ‘cache-control: no-cache’ -d ‘grant_type=refresh_token&refresh_token={{refresh_token}}&scope=vehicles.locations.read vehicles.read vehicles.signals.read’”

lovelace card

entities:

  • entity: sensor.refresh_xee
    icon: ‘mdi:cookie’
    name: Estado token XEE
    show_header_toggle: false
    type: entities

Many thanks Victor for the guide, now I have my two cars in home assistant.

What about to update the access_token @ElGranLoky ? The refresh_token can be the same in the Xee server response, but the access_token is new everytime the token is refresh.

Up to now my solution is to run the refresh command (and also updating the secrets.yaml with the new access_token) everyday and restart Home Assistant. But this workaround is ugly.

Yes i know, but you can use your username and password to avoid the access_token. Example:

refresh_xee_command: "curl -s -m 10 -X POST https://api.xee.com/v4/oauth/token -H 'Authorization:Basic {{HereYourAccessToken}}' -H 'Content-Type: application/x-www-form-urlencoded' -H 'cache-control: no-cache' -d 'grant_type=password&username={{[email protected]}}&password={{here-your-password-example}}&scope=vehicles.locations.read vehicles.read vehicles.signals.read'"

Sorry for the delay :slightly_smiling_face:

thanks!! I’m using it like this, but how do you modify it so you don’t have to restart home assistant every day

I used to be xee plugin maintainer for domogik and use this like that for the moment.

It use the python api3 sdk from quentin
You need to install it before of course :slight_smile:
Create or have a Xee dev accounts.
And then i use a simple cron that run on another container and publish through mqtt:

from xee import Xee
import xee.entities as xee_entities
import sys
import os
import pickle
import pytz
import json
import paho.mqtt.client as paho

broker="YOUR BROKER IP OR DNS NAME"
port=1883
def on_publish(client,userdata,result):             #create function for callback
    print("data published \n")
    pass
client1= paho.Client("xee2mqtt")                           #create client object
client1.on_publish = on_publish                          #assign function to callback
client1.connect(broker,port)                                 #establish connection


xee = Xee(client_id="YOUR_CLIENT_ID_FROM_XEE_DEV_ACCOUNT", 
        client_secret="YOUR_CLIENT_SECRET_FROM_XEE_DEV_ACCOUNT", 
        redirect_uri="http://localhost")


login_url = xee.get_authentication_url()+"&redirect_uri=http://localhost"
xee_config_file = os.path.join(os.path.dirname(__file__), 'xee.json')

try:
    with open(xee_config_file, 'rb') as xee_token_file:
        print ("Opening File")
        token = pickle.load(xee_token_file)
    print ("Getting user")
    user ,error = xee.get_user(token.access_token)
    print (error)
    if error is not None :
        print ("Error getting user, try refreshing with token_refresh from file")
        print (error)
        token,error = xee.get_token_from_refresh_token(token.refresh_token)
        if error != None :
            print (error)
            sys.exit("refreshing token failed from refresh_token")

except:
    print ("Error with file saved or no file saved")
    print("Go to %s allow the app and copy your oauth_verifier" %login_url)
    authorization_code = input('Please enter your authorization_code: ')
    token,error = xee.get_token_from_code(authorization_code)
    if error is not None :
        print ("Error getting token from code")
        print (error)
        print ("Exiting")
        sys.exit("refresh Error")

with open(xee_config_file, 'wb') as xee_token_file:
    pickle.dump(token, xee_token_file)

cars, err = xee.get_cars(token.access_token)
for car in cars:
    try:
        client1.publish("/XEE/" + str(car.id) + "/carname/", str(car.name))
    except:
        print ("error publishing this value")
        print (car)
    Status  ,error = xee.get_status(car.id,token.access_token)
    if error is None:
        for statu in Status:
            if statu is not None:
                for signals in statu:
                    try:
                        client1.publish("/XEE/" + str(car.id) + "/" + str(signals.name)  + "", str(signals.value))
                        print (signals)
                    except:
                        print ("error publishing this value")
                        print (signals)
        locations ,error = xee.get_locations(car.id,token.access_token,limit=1)
        for location in locations:
            try:
                lat=location.latitude
                lon=location.longitude
                client1.publish("/XEE/" + str(car.id) + "/location/", json.dumps({"longitude": lon,"latitude": lat}))
                print (location)
            except:
                print ("error publishing this value")
                print (location)

  1. Create a Xee2mqtt.py with this code
  2. Launch once by hand and it will bring you to xee user account to allow access.
    Then redirect you to a localhost page containing your authorization code.
    Type it in the answer waiting from the cli.
    It will create a json file containing the access token and the refresh token.
    So you never have to look it up again, it will try refresh it automatically (works 99% of the time).
  3. Create a cron that fire this script at the frequencies you wanted.

Benefits it list all the users cars and available signals alone :revolving_hearts:

I hope to have time to make an hacs for this but i have more to do for know, like looking at plcbus again and need to learn how HASS is working.

If anyone has more notion on how to make hacs integration do not hesitate :slight_smile: here are all the base to do it in pure python.

im trying but the api v3 dont work in the first execution… im tryng generate the code with the api v4 but is invalid…
help please!!
[email protected]:/home# python3 Xee2mqtt.py

Error with file saved or no file saved

Go to https://cloud.xee.com/v3/auth/auth?client_id=xxxx&redirect_uri=http://localhost all

ow the app and copy your oauth_verifier

Please enter your authorization_code: ZUFOYm9wWFN2VElBU1Byd0lQTzU0Y0I5cUU5RVAzRmU

Error getting token from code

{“message”:“Invalid authentication”}

Exiting

refresh Error

That seems to be a very bad news…

Maybe the V4 api code do not work with the old V3 api.

I’ll MP you to make some test if your ok

After fast test it seems indeed that new dev account could only access the xee api V4.

So if someone else needs i still have my old V3 api key that i could share, MP me if needed.

oh, I had been looking forward to implementing it.

The script xee.py I use to get the Xee v4 location and vehicle data in json format is:

#!/usr/bin/env python3

import requests
import json
import yaml
from pathlib import Path
from os.path import join

url_status = "https://api.xee.com/v4/vehicles/{vehicle_id}/status"
TOKEN_YAML = join(str(Path.home()), ".homeassistant/secrets.yaml")

# Read parameters needed from file
with open(TOKEN_YAML, 'r') as stream:
    try:
        token_file_data = yaml.load(stream)
    except yaml.YAMLError as exc:
        print('YAML error: ', exc)
        raise
    except Exception as e:
        print("Error reading secrets.yaml file: ", e)
        raise

headers = {
        'Authorization': token_file_data['xee_bearer_token'],
        'Cache-Control': "no-cache",
    }

resource = url_status.format(vehicle_id=token_file_data['xee_vehicle_id'])
response = requests.request("GET", resource, headers=headers)
if response.status_code == requests.codes.ok:
    json_response = json.loads(response.text)
    print(json.dumps(json_response))
else:
    response.raise_for_status()

Then, the sensor is HA is configured like this:

  - platform: command_line
    name: car_status
    json_attributes: 
      - signals
      - location
      - updatedAt
    command: 'python3 ~/.homeassistant/scripts/xee.py'
    value_template: 'OK'

And then following the guide from @vlaraort.

but this no autoupdate token no?

Ok seems Xee have close or not make rework the V3 api server…

I have not the same value between the web apps my.xee and my xee2mqtt api v3 scripts.

Really need to switch to V4 but with an autoreload token like the Xee2mqtt plugin do.

Confirmes android apps switch to V4 api and no more data update to V3 anymore :frowning:

Found interesting things…
the Xee V4 Api looks like nearly the sames as withings with Oauth2.

Meanings we certainly could get a good start for python Xee V4 api from the https://pypi.org/project/withings-api/

In theory just to change url path and data needed.

that’s interesting …

Hi all,

i’ve update the python xee sdk lib.
I also update my Xee2mqtt code so no more token problems.
When it expires it grab a new one automatically from refresh one’s.

All the explaination are in the Readme

Do not hesitate to ask, open ticket, PR etc.

Next step will be a complete hacs and hass compoents after that. (But it will take again a long time.)

Note also it makes a lot of print for the moment to debug…

1 Like