Use Tronity API to extract car data into sensors using Node-Red

UPDATE

Tronity have released a custom integration in HAC’s

This works without issue. Please use instead

I have been unable to use the Stellantis API to extract information from my Vauxlhall Corsa-E. The third party PSA Car Controller addin seems to be missing data, and for me has been unreliable. I stumbled on the third party Tronity app. This is a paid service but provides a wealth of information and an API I can use. The phone app is also much better than the PSA one

I have created a Node-Red flow to extract the data from the Tronity api. This is based on the the following Tronity - get SOC for your BEV from their API (flow) - Node-RED

The flow will create the following sensors. It will require the Node-RED Companion Integration

Lastupdate
GPS Tracker
Odometer
Charge Status
Range
Millege
Cable

The flow has some documentation built in . You will need a Tronity account linked to your car and login to the API.

This code will extend your free trial to 4 weeks and give me a month free.

Updated with better instructions v3 and scubbed code

Updated 22/10/2022 as Tronity have changed the api

Added Charge Power and Charge remaining time entities

Updated 18/11/2022 Changed last update state to mins rather than hours fix Bugs Tidy code ( copy shamelessly !) thanks @ pmuk

[{"id":"c19de7dca674fbd1","type":"tab","label":"Tronity","disabled":false,"info":""},{"id":"2c1cd936024c090d","type":"http request","z":"c19de7dca674fbd1","name":"Get data","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":400,"y":340,"wires":[["3897d42d56402287","1f8a3b2be030ad33","6e9694a727dbfa3e","1644367a5f5e9edc","02425b84808d8ccb","e6b440297bc2cc6e","7ba6d8b089095cf4","3237bc1ea39a6d6c","d8cb2e9516708391","822ed5b88887df70"]]},{"id":"45dbece70049d1d0","type":"http request","z":"c19de7dca674fbd1","name":"Post Auth","method":"POST","ret":"obj","paytoqs":"query","url":"https://api.tronity.tech/authentication","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":280,"y":220,"wires":[["96b9a28cae2d0186"]]},{"id":"fa68aef5ff9cef58","type":"inject","z":"c19de7dca674fbd1","name":"15 minutes","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"900","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":90,"y":160,"wires":[["a3f5d9024fe73b88"]]},{"id":"769bc94a09907e76","type":"comment","z":"c19de7dca674fbd1","name":"Get car info ","info":"","x":90,"y":280,"wires":[]},{"id":"e3197fcf1ed9b18c","type":"comment","z":"c19de7dca674fbd1","name":"Get new token every 15 minutes ","info":"","x":200,"y":60,"wires":[]},{"id":"96b9a28cae2d0186","type":"change","z":"c19de7dca674fbd1","name":"Store Token","rules":[{"t":"set","p":"tronitybearer","pt":"flow","to":"payload.access_token","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":220,"wires":[[]]},{"id":"41112a71d20a7d04","type":"function","z":"c19de7dca674fbd1","name":"Build  API","func":"let token = flow.get('tronitybearer')\nlet car = flow.get('car')\nlet measure = flow.get('measurement')\nmsg.headers = {\n    'Authorization': 'Bearer ' + token,\n    'Unit-System': measure,\n}\nmsg.url = \"https://api.tronity.tech/tronity/vehicles/\" + car + \"/last_record\"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":260,"y":340,"wires":[["2c1cd936024c090d"]]},{"id":"2eed05c0b7a1c63e","type":"inject","z":"c19de7dca674fbd1","name":"3 minutes","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"180","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":340,"wires":[["41112a71d20a7d04"]]},{"id":"1c88e0ca45cf9de3","type":"comment","z":"c19de7dca674fbd1","name":"Info (click me)","info":"1) Login here: https://app.platform.tronity.io/\n(same credentials as in the app)\n\n2) Open the existing app. Needed are 4 things:\n- ID \n- Password (regenerate a new one to show it)\n- Number of your car\n- Measurement imperial or metric\n\n3) Enter ID,password,car number, imperial or metric into setup Tronity params \n\n4) change the Home Assistant names of all the blue sensors to match your car details , change unit of measure mi/km \n5) GPS data function names the device tracker \"corsae\" change to match your car details  \n","x":90,"y":40,"wires":[]},{"id":"3897d42d56402287","type":"function","z":"c19de7dca674fbd1","name":"GPS data","func":"msg.payload = {\n    data: {dev_id: \"corsa\",gps: [msg.payload.latitude,msg.payload.longitude],gps_accuracy: \"100\"}}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":620,"y":860,"wires":[["0ea5d1851edb62a2"]]},{"id":"0ea5d1851edb62a2","type":"api-call-service","z":"c19de7dca674fbd1","name":"Create  tracker","server":"","version":5,"debugenabled":false,"domain":"device_tracker","service":"see","areaId":[],"deviceId":[],"entityId":[],"data":"","dataType":"json","mergeContext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":800,"y":860,"wires":[[]]},{"id":"3200da140b1c5468","type":"function","z":"c19de7dca674fbd1","name":"Login Payload","func":"let client  = flow.get('client')\nlet password = flow.get('password')\n\nmsg.payload  = {'client_id': client,\n                'client_secret': password,\n                \"grant_type\":\"app\"\n}\n    \n\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":160,"wires":[["45dbece70049d1d0"]]},{"id":"a3f5d9024fe73b88","type":"change","z":"c19de7dca674fbd1","name":"Tronity params ","rules":[{"t":"set","p":"client","pt":"flow","to":"","tot":"str"},{"t":"set","p":"password","pt":"flow","to":"","tot":"str"},{"t":"set","p":"car","pt":"flow","to":"","tot":"str"},{"t":"set","p":"measurement","pt":"flow","to":"","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":260,"y":160,"wires":[["3200da140b1c5468"]]},{"id":"1f8a3b2be030ad33","type":"ha-sensor","z":"c19de7dca674fbd1","name":"All data","entityConfig":"176d488f557e35c4","version":0,"state":"payload.odometer","stateType":"msg","attributes":[{"property":"range","value":"payload.range","valueType":"msg"},{"property":"SOC","value":"payload.level","valueType":"msg"},{"property":"Charge Status","value":"payload.charging","valueType":"msg"},{"property":"Plugged In","value":"payload.plugged","valueType":"msg"},{"property":"Latitude","value":"payload.latitude","valueType":"msg"},{"property":"longitude","value":"payload.longitude","valueType":"msg"},{"property":"Last update","value":"payload.lastUpdate","valueType":"msg"}],"inputOverride":"allow","outputProperties":[],"x":620,"y":340,"wires":[[]]},{"id":"6e9694a727dbfa3e","type":"ha-sensor","z":"c19de7dca674fbd1","name":"Range","entityConfig":"05758513e60898cb","version":0,"state":"payload.range","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":610,"y":400,"wires":[[]]},{"id":"1644367a5f5e9edc","type":"ha-sensor","z":"c19de7dca674fbd1","name":"Mileage","entityConfig":"1c63d4adcc9c4770","version":0,"state":"payload.odometer","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":620,"y":580,"wires":[[]]},{"id":"02425b84808d8ccb","type":"ha-sensor","z":"c19de7dca674fbd1","name":"Charge Status ","entityConfig":"0e98215a55ad0ce0","version":0,"state":"payload.charging","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":640,"y":640,"wires":[[]]},{"id":"e6b440297bc2cc6e","type":"ha-sensor","z":"c19de7dca674fbd1","name":"SOC","entityConfig":"2c9fb2aa82cf4aef","version":0,"state":"payload.level","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":610,"y":460,"wires":[[]]},{"id":"7ba6d8b089095cf4","type":"ha-binary-sensor","z":"c19de7dca674fbd1","name":"Cable","entityConfig":"08ee2ea801be48bd","version":0,"state":"payload.plugged","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":610,"y":520,"wires":[[]]},{"id":"3237bc1ea39a6d6c","type":"ha-sensor","z":"c19de7dca674fbd1","name":"Charge Power","entityConfig":"5b61acc67627921e","version":0,"state":"payload.chargerPower","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":640,"y":700,"wires":[[]]},{"id":"d8cb2e9516708391","type":"ha-sensor","z":"c19de7dca674fbd1","name":"Charge Remaining Time","entityConfig":"8002120e974c1696","version":0,"state":"payload.chargeRemainingTime","stateType":"msg","attributes":[],"inputOverride":"allow","outputProperties":[],"x":670,"y":780,"wires":[[]]},{"id":"822ed5b88887df70","type":"function","z":"c19de7dca674fbd1","name":"mins","func":"msg.nomn  = Math.round(Math.abs((Date.now() - msg.payload.lastUpdate) / 1000 / 60 ));\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":610,"y":920,"wires":[["441ddc047af385fd"]]},{"id":"f00e5f7a25c39ca4","type":"ha-sensor","z":"c19de7dca674fbd1","name":"lastupdate","entityConfig":"8ae07a618641546e","version":0,"state":"msg.nomn","stateType":"msg","attributes":[{"property":"time","value":"time","valueType":"msg"},{"property":"lastupdate","value":"payload.lastUpdate","valueType":"msg"},{"property":"date","value":"date","valueType":"msg"}],"inputOverride":"allow","outputProperties":[],"x":1010,"y":920,"wires":[[]]},{"id":"441ddc047af385fd","type":"moment","z":"c19de7dca674fbd1","name":"Date","topic":"","input":"payload.lastUpdate","inputType":"msg","inTz":"Europe/London","adjAmount":0,"adjType":"days","adjDir":"add","format":"DD/MM/YY","locale":"C","output":"date","outputType":"msg","outTz":"Europe/London","x":750,"y":920,"wires":[["dfe9a7afc8bb4b6e"]]},{"id":"dfe9a7afc8bb4b6e","type":"moment","z":"c19de7dca674fbd1","name":"Time","topic":"","input":"payload.lastUpdate","inputType":"msg","inTz":"Europe/London","adjAmount":0,"adjType":"days","adjDir":"add","format":"hh:mm:ss","locale":"C","output":"time","outputType":"msg","outTz":"Europe/London","x":870,"y":920,"wires":[["f00e5f7a25c39ca4"]]},{"id":"176d488f557e35c4","type":"ha-entity-config","server":"c7744623.68df68","deviceConfig":"","name":"sensor config for All data","version":6,"entityType":"sensor","haConfig":[{"property":"name","value":"corsa_tronity"},{"property":"device_class","value":""},{"property":"icon","value":"si:vauxhall"},{"property":"unit_of_measurement","value":"mi"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"resend":true},{"id":"05758513e60898cb","type":"ha-entity-config","server":"c7744623.68df68","deviceConfig":"","name":"sensor config for Range","version":6,"entityType":"sensor","haConfig":[{"property":"name","value":"corsae-range"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:gauge"},{"property":"unit_of_measurement","value":"mi"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"resend":true},{"id":"1c63d4adcc9c4770","type":"ha-entity-config","server":"c7744623.68df68","deviceConfig":"","name":"sensor config for Mileage","version":6,"entityType":"sensor","haConfig":[{"property":"name","value":"corsae-mileage"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:counter"},{"property":"unit_of_measurement","value":"mi"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"resend":true},{"id":"0e98215a55ad0ce0","type":"ha-entity-config","server":"c7744623.68df68","deviceConfig":"","name":"sensor config for Charge Status ","version":6,"entityType":"sensor","haConfig":[{"property":"name","value":"corsae-charge"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:cable-data"},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"resend":true},{"id":"2c9fb2aa82cf4aef","type":"ha-entity-config","server":"c7744623.68df68","deviceConfig":"","name":"sensor config for SOC","version":6,"entityType":"sensor","haConfig":[{"property":"name","value":"corsae-soc"},{"property":"device_class","value":"battery"},{"property":"icon","value":"mdi:battery"},{"property":"unit_of_measurement","value":"%"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"resend":true},{"id":"08ee2ea801be48bd","type":"ha-entity-config","server":"c7744623.68df68","deviceConfig":"","name":"binary sensor config for Cable","version":6,"entityType":"binary_sensor","haConfig":[{"property":"name","value":"corsae-cable"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:cable-data"},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"resend":true},{"id":"5b61acc67627921e","type":"ha-entity-config","server":"c7744623.68df68","deviceConfig":"","name":"sensor config for Charge Power","version":6,"entityType":"sensor","haConfig":[{"property":"name","value":"corsae-charge_power"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:cable-data"},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"resend":true},{"id":"8002120e974c1696","type":"ha-entity-config","server":"c7744623.68df68","deviceConfig":"","name":"sensor config for Charge Remaining Time","version":6,"entityType":"sensor","haConfig":[{"property":"name","value":"corsae-charge_remain_time"},{"property":"device_class","value":""},{"property":"icon","value":""},{"property":"unit_of_measurement","value":"time"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"resend":true},{"id":"8ae07a618641546e","type":"ha-entity-config","server":"c7744623.68df68","deviceConfig":"","name":"sensor config for Last Update","version":"6","entityType":"sensor","haConfig":[{"property":"name","value":"corsae-lastupdate"},{"property":"icon","value":"mdi:clock-outline"},{"property":"entity_category","value":""},{"property":"device_class","value":""},{"property":"unit_of_measurement","value":"mins"},{"property":"state_class","value":""}],"resend":true,"debugEnabled":false}]
4 Likes

Hello
installes everything but got the following errors every 3 minutes :

 Feb 20:01:08 - [error] [ha-entity:All] State must be defined.
5 Feb 20:01:08 - [error] [ha-entity:Charge Status ] State must be defined.
5 Feb 20:01:08 - [error] [ha-entity:Range] State must be defined.
5 Feb 20:01:08 - [error] [ha-entity:Mileage] State must be defined.
5 Feb 20:01:08 - [error] [ha-entity:SOC] State must be defined.
5 Feb 20:01:08 - [error] [ha-entity:Cable] State must be defined.
5 Feb 20:01:08 - [error] [api-call-service:Create  tracker] Call-service error. invalid latitude for dictionary value @ data['gps']

have you installed the Node-RED Companion Integration

This add the entities into home assistant

Yes now it works but only with every 3 minutes of you call every 1 minute tronity produces same errors …

Place a debug after the bulk request and see what is being returned by the api call.

ok just added the green debug button at the botom but where can i read the log ?

https://www.google.com/search?q=home+assistant+node+red+beginners&rlz=1CAPOUW_enGB973&oq=home+assistant+node+red+beginners&aqs=chrome..69i57j33i22i29i30.17969j0j7&sourceid=chrome&ie=UTF-8

Any guide for adding this as new to node red

Lots of guides on the internet for installing node red

Just copy my flow and import into node red

https://nodered.org/docs/user-guide/editor/workspace/import-export

The flow has some instructions for use

thanks is the get data part of the flow supposed to have no http?

To use you need to setup a Tronity developers account (see first post) . You then use the details
from this account and fill put the parameters in the flow. This will extract the data into Home assistant entities. The HTTP’s call are contain with the function nodes

I got it all working last night fine, but then woke up this morning to all sesnors down and looked in node red log after restarting flow, last update and device tracker report back with.

3 Aug 08:30:49 - [error] [ha-entity:308 All data] State must be defined.
3 Aug 08:30:49 - [error] [ha-entity:308 Charge Status ] State must be defined.
3 Aug 08:30:49 - [error] [ha-entity:308 Range] State must be defined.
3 Aug 08:30:49 - [error] [ha-entity:308 Mileage] State must be defined.
3 Aug 08:30:49 - [error] [ha-entity:308 SOC] State must be defined.
3 Aug 08:30:49 - [error] [ha-entity:308 Cable] State must be defined.
3 Aug 08:30:49 - [error] [ha-entity:Last Update] Sensor update attempted without connection to server.
3 Aug 08:30:49 - [error] [api-call-service:Create  tracker] Call-service error. invalid latitude for dictionary value @ data['gps']

Have you installed Node-Red Companion integration . It sounds like all the entities have been deleted

i got there in the end, it was something wrong with node red installation as it kept crashing on a reboot, restored previous partial backup and re installed node red and it works fine now, thanks for your help.

1 Like

All nodes works fine, except “Create Tracker”: “Call-Service attempted without connection to server.”

What value do I give here? Car-id, Car number, VIN number, e208? Tried all of them, nothing works and give all the same error. I have NodeRed Companion installed…

Tronity Platform gives me this options on my car: read_battery,read_charges,read_idles,read_location,read_odometer,read_records,read_sleeps,read_vehicle_info,read_vin,read_charge

Do all the other entities get created ?

If so check the All Data entity attributes , does it return latitude and longitude ?

Found the problem… There where two Home Assistant servers in the drop down list… Picked the other one, now it works :wink:

I receive a : TypeError: Cannot convert undefined or null to object in the debug screen of nodered.
Any idea what this means ?

I do receive SOME info :smiley:

object
vin: null
odometer: null
range: 114
level: 52.4
charging: null
plugged: null
chargerPower: null
chargeRemainingTime: null
latitude: null
longitude: null
timestamp: 1666336139000
lastUpdate: 1666336139000

check with tronity on what data your car returns

Thanks for this. Its driving me nuts though! (I can see why you said you spent far too long on it!)

I have all my settings right, and the first function runs fine and gets the access_token back (I can see it when I add debug)

Yet the 2nd one seems to work on the first. Then occasionally on the 2nd (Range).

What am I doing wrong? Its driving me nuts I’m so close, yet so far! :confused:

Thanks

Andy