How to use the EV-Monitor API

General

The API is available at url: /api/[endpoint]
The API accepts and returns JSON only. Every API-call should be a HTTP-POST request (If not stated otherwise)
You are free tu use the API. There is no rate-limit, but we expect you not to abuse the system. We will take countermeasures if we see a malicious user / dev.

Authentication

In order to use the API, your user need to authenticate. The user need to have an account (register here) and have to create at least 1 vehicle ( >> profile). You can make an API-Call to: /api/login
The function expects 2 variables to be set in the post-body:
username:{username} password:{password}
This represents the same user credentials the user can use on the website to login. So please keep in mind that {username} need to be the emailaddress of the user. The {password} needs to be the password in plain text. We might add other option in the future to allow apps to store the password of the user encrypted.
The function returns a json looking like the following:
{ "SUCCESS": "OK", "token": "o7axty6jzequrg5" }
or
{ "SUCCESS": "ERROR", "error": "Email / Password combination wrong!" }
You get the idea.
The returned token is needed for further requests and is for security reasons valid for 10 minutes. After that you need to generate a new token with this login api-endpoint.

get vehicles

You want to push data related to a vehicle. Therefore yopu first need to get the Vehicle_ID to use it in further requests related to a vehicle. The API endpoint to get a list of vehicles is:
/api/get_vehicles
The function expects 1 variable to be set in the post-body:
token:{token}
simple, right?
expected response:
{ "SUCCESS": "OK", "vehicles": [ { "id": "abcdefg1234", "user_id": "aabbcc112233", "make": "84a2z6xrqomuh9b", "model": "rn8ytw6qvs16iwt", "nickname": "The Rocket", "plan": "0" } ], }
What are those cryptic values?
Well, the ID is just an unique identifier, same goes for user_id and also make and model.
The user should be able to identify his vehicle based on nickname, but if you want, you can also show the user what make and model his vehicles are. So maybe thats easier for them.

get make


In order to get the real names of the make and model instead of cryptic ID's, you can call the API at
/api/get_make
The function expects 2 variabels in the post-body:
token:{token} make:{make_id}
expected result is something like this:
{ "SUCCESS": "OK", "name": "Energica" }

get model


In order to get the real names of the make and model instead of cryptic ID's, you can call the API at
/api/get_model
The function expects 2 variabels in the post-body:
token:{token} model:{model_id}
expected result is something like this:
{ "SUCCESS": "OK", "name": "SS9" }

Push Data


Finally, let's push some data. The API-Endpoint to do so is
/api/push_data
The function expects variables in the post-body:
token:{token}
user-agent:{name of your app} (optional)
data:{array}

data array

The data array consists of 1 or multiple Datasets. Lets break it down.
data[0][general][timestamp]={timestamp:int(seconds)}
data[0][general][vehicle]={vehicle_id}

With this data a push is not very useful, but it is in fact the most minimal dataset you can provide to generate a valid entry in our database. You can extend this minimalistic dataset with the following "objects".
data[0][general][speed]={speed:int}(in kmh)
data[0][general][range]={range:int}(in km)
data[0][general][state]={state:int}(0 = off, 1 = on, 10 = charging (AC), 11 = charging (DC))
data[0][general][odometer]={odometer:int}(in km)
data[0][general][watt_100km]={mean consumption:int}(in watt/100km)

The code above is related to the vehicle itself. In the following I will show you how you can add more "Objects" to the dataset.

motors

A vehicle can have multiple motors. So in addition of the data-array itself to be an array which allows you to send multiple "snapshots" in 1 request (just add another "general" array with the index 1, or 2, or x. you get the point), the motor object itself is also an array. {motorindex} can be a int between 0 and 255.
data[0][general][motor][{motorindex}][watt]:{watt:int}(realtime wattage)
data[0][general][motor][{motorindex}][rpm]:{rpm:int}(realtime rpm)
data[0][general][motor][{motorindex}][torque]:{torque:int}(realtime torque in nm)
data[0][general][motor][{motorindex}][temp]:{temp:int}(motortemperature in C°)
data[0][general][motor][{motorindex}][coolfluid_temp]:{coolfluid_temp:int}(coolfluid temperature in C°)
data[0][general][motor][{motorindex}][coolfluid_pump]:{coolfluid_pump:int}(pump status, 0 = off, 1 = on)

All motor values are Optional. If you dont want to send a specific value, just exclude them.

batteries

A vehicle can have multiple batteries. The battery object itself is also an array. {battindex} can be a int between 0 and 255.
data[0][general][batt][{battindex}][soc]:{soc:int}(soc in %)
data[0][general][batt][{battindex}][soc_wh]:{soc_wh:int}(soc in wh)
data[0][general][batt][{battindex}][v]:{v:int}(Battery Voltage in V)
data[0][general][batt][{battindex}][vmin]:{vmin:int}(lowest cellvoltage in mV)
data[0][general][batt][{battindex}][vmax]:{vax:int}(highest cellvoltage in mV)
data[0][general][batt][{battindex}][i]:{i:int}(realtime current in A (discharge / Driving)
data[0][general][batt][{battindex}][i_charge]:{i:int}(realtime current in A (charging)
data[0][general][batt][{battindex}][w]:{w:int}(realtime energy in Watt (discharge / Driving)
data[0][general][batt][{battindex}][w_charge]:{w:int}(realtime energy in Watt (charging)
data[0][general][batt][{battindex}][i_charge_max]:{i_charge_max:int}(BMS-Prediction of maximum charge current in A)
data[0][general][batt][{battindex}][i_discharge_max]:{i_discharge_max:int}(BMS-Prediction of max. discharge current in A)
data[0][general][batt][{battindex}][temp]:{temp:int}(battery temperature in C°)
data[0][general][batt][{battindex}][temp_min]:{temp_min:int}(lowest cell-temperature in C°)
data[0][general][batt][{battindex}][temp_max]:{temp_max:int}(highest cell-temperature in C°)
data[0][general][batt][{battindex}][coolfluid_temp]:{coolfluid_temp:int}(coolfluid temperature in C°)
data[0][general][batt][{battindex}][coolfluid_pump]:{coolfluid_pump:int}(pump status, 0 = off, 1 = on)
data[0][general][batt][{battindex}][soh]:{soh:int}(soc in %)

All battery values are Optional. If you dont want to send a specific value, just exclude them.

GPS

A vehicle only have 1 position at a given time. therefore the GPS-Object is not an array
data[0][general][gps][lat]:{latitude:double}
data[0][general][gps][lng]:{longitude:double}
data[0][general][gps][acc]:{accuracy:int}(in meter)
data[0][general][gps][alt]:{altitude:double} - optional

The GPS object itself is optional (same as motor and battery object), but if a GPS object is pushed, the values lat,lng and acc are mandatory. Altitude is optional as not all GPS-receivers can provide the altitude.

This is an example call to push 2 datasets with each 2 motors:
token=hgfhjgfhj2fhj2gfhj
user-agent=My cool app
data[0][general][timestamp]=1631956967
data[0][general][vehicle]=2j2jkh2jkgh2jkh
data[0][general][gps][lat]=52.4534563
data[0][general][gps][lng]=-4.56456456
data[0][general][gps][acc]=7
data[0][general][speed]=111
data[0][general][motor][0][watt]=11000
data[0][general][motor][1][watt]=1000
data[0][general][batt][0][soc]=54
data[1][general][timestamp]=1631956969
data[1][general][vehicle]=2j2jkh2jkgh2jkh
data[1][general][gps][lat]=52.5534563
data[1][general][gps][lng]=-4.66456456
data[1][general][gps][acc]=5
data[1][general][speed]=90
data[1][general][motor][0][watt]=10000
data[1][general][motor][1][watt]=3000
data[1][general][batt][0][soc]=53