Closed CM000n closed 3 years ago
Thanks for trying π
I am gonna rewrite how this works, as other problems have risen anyway. I will ping you here in a couple of days when i have something for you to try again.
Thank for your feedback. It looks like it would work if I left out the asyncio section
Then this one:
import aiohttp
import asyncio
from mytoyota.client import MyT
username = "MYUSER"
password = "MYPW"
locale = "de-de"
session = aiohttp.ClientSession()
client = MyT(locale=locale, session=session)
print("Performing login...")
client.perform_login(username=username, password=password)
valid, cars = await client.get_cars()
print(valid)
print(cars)
results in this:
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x0000019A06946B20>, 1992.875)]']
connector: <aiohttp.connector.TCPConnector object at 0x0000019A084C6DC0>
Performing login...
True
[{'id': 1958079, 'vin': 'MYVIN', 'isNC': False, 'alias': 'Corolla', 'owner': False, 'vehicleAddedOn': '2020-11-19T17:36:19.469Z', 'isEntitled': True, 'entitledBy': 'CUSTOMER', 'entitledOn': '2020-11-20T17:28:23.074Z', 'ownerFlag': False, 'source': 'NMSC', 'horsePower': 98, 'hybrid': True, 'fuel': 'PETROL', 'engine': 'Hybrid: 1,8-l-VVT-i: Benzinmotor 72 kW (98PS), Elektromotor, 53 kW (72PS), Systemleistung 90 kW (122 PS)', 'transmissionType': 'CVT', 'transmission': 'Stufenloses Automatikgetriebe', 'fullKatashiki': 'ZWE211L-DWXNBW', 'grade': 'Mid', 'modelName': 'Corolla', 'modelCode': 'CR', 'interiorColour': '20', 'exteriorColour': '3U5 ', 'imageUrl': 'https://dj3z27z47basa.cloudfront.net/274b5a7a-5c46-4155-a275-f5e05b056e7a', 'modelDocumentId': '12345', 'productionYear': '2020', 'licensePlate': 'MYLICENSEPLATE', 'modelDescription': 'Corolla'}]
but when I then try this:
vin = 'MYVIN'
print("Retrieving latest parking information...")
parking = await client.get_parking(vin=vin)
print(parking)
I get the invalid character in header
Message from HA again:
Retrieving latest parking information...
---------------------------------------------------------------------------
BadHttpMessage Traceback (most recent call last)
~\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\client_reqrep.py in start(self, connection)
889 try:
--> 890 message, payload = await self._protocol.read() # type: ignore
891 except http.HttpProcessingError as exc:
~\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\streams.py in read(self)
603 try:
--> 604 await self._waiter
605 except (asyncio.CancelledError, asyncio.TimeoutError):
~\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\client_proto.py in data_received(self, data)
212 try:
--> 213 messages, upgraded, tail = self._parser.feed_data(data)
214 except BaseException as exc:
~\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\_http_parser.pyx in aiohttp._http_parser.HttpParser.feed_data()
BadHttpMessage: 400, message='invalid character in header'
The above exception was the direct cause of the following exception:
ClientResponseError Traceback (most recent call last)
<ipython-input-13-c5f3650c5d37> in <module>
2
3 print("Retrieving latest parking information...")
----> 4 parking = await client.get_parking(vin=vin)
5 print(parking)
~\AppData\Local\Programs\Python\Python38\lib\site-packages\mytoyota\client.py in get_parking(self, vin)
170 endpoint = f"{BASE_URL}/users/{self._uuid}/vehicle/location"
171
--> 172 retry, parking = await self._request(endpoint, headers=headers)
173
174 if retry:
~\AppData\Local\Programs\Python\Python38\lib\site-packages\mytoyota\client.py in _request(self, endpoint, headers)
68
69 resp = None
---> 70 async with self.session.get(
71 endpoint, headers=headers, timeout=TIMEOUT
72 ) as response:
~\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\client.py in __aenter__(self)
1115
1116 async def __aenter__(self) -> _RetType:
-> 1117 self._resp = await self._coro
1118 return self._resp
1119
~\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\client.py in _request(self, method, str_or_url, params, data, json, cookies, headers, skip_auto_headers, auth, allow_redirects, max_redirects, compress, chunked, expect100, raise_for_status, read_until_eof, proxy, proxy_auth, timeout, verify_ssl, fingerprint, ssl_context, ssl, proxy_headers, trace_request_ctx, read_bufsize)
542 resp = await req.send(conn)
543 try:
--> 544 await resp.start(conn)
545 except BaseException:
546 resp.close()
~\AppData\Local\Programs\Python\Python38\lib\site-packages\aiohttp\client_reqrep.py in start(self, connection)
890 message, payload = await self._protocol.read() # type: ignore
891 except http.HttpProcessingError as exc:
--> 892 raise ClientResponseError(
893 self.request_info,
894 self.history,
ClientResponseError: 400, message='invalid character in header', url=URL('https://myt-agg.toyota-europe.com/cma/api/users/4c5c95ff-c92e-4e13-a8b4-99424edefc7d/vehicle/location')
All this information helps me a lot.
I think I know what the problem is now, it seems to be that Toyotas API does not play well with aiohttp, i will fix this later to day
@CM000n
EDIT: I take it back, have found some other things i m gonna try. SCRIPT have been updated.
Can i get you to test if my latest changes have worked.
Please create a test script in the MyT folder. And add this
import asyncio
from mytoyota.client import MyT
username = "mail"
password = "password"
locale = "da-dk"
client = MyT(locale=locale)
print("Performing login...")
client.perform_login(username=username, password=password)
async def get_information():
print("Retrieving cars...")
valid, cars = await client.get_cars()
if valid:
for car in cars:
vin = car['vin']
print(car)
print(await client.get_information_for_given_car(vin))
else:
print("Invalid data received!")
loop = asyncio.get_event_loop()
loop.run_until_complete(get_information())
loop.close()
It speeds things up a lot if you could test this as these endpoints don't return anything for me (yet), so i cannot reproduce your problem.
Also don't install it with pip install as there is no setup.py yet. Just clone it and run script.
Unfortunately, this again leads to a runtime error
Performing login...
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-1-d615b7cce775> in <module>
24
25 loop = asyncio.get_event_loop()
---> 26 loop.run_until_complete(get_information())
27 loop.close()
~\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py in run_until_complete(self, future)
590 """
591 self._check_closed()
--> 592 self._check_running()
593
594 new_task = not futures.isfuture(future)
~\AppData\Local\Programs\Python\Python38\lib\asyncio\base_events.py in _check_running(self)
550 def _check_running(self):
551 if self.is_running():
--> 552 raise RuntimeError('This event loop is already running')
553 if events._get_running_loop() is not None:
554 raise RuntimeError(
RuntimeError: This event loop is already running
It complains that the task is already running. How are you to execute this? This should be put into a file and the executed like this: python3 test.py
where test.py
is the name of the file.
I cannot replicate this error on Windows, for me it works. Both Windows CMD and wsl2.
Ou man, silly me Γo. I had created a Jupyter Notebook and have it running within this. If I create a separate .py file and call it, it works :-)
Interestingly, this leads to another problem for "get_information_for_given_car" and "_get_odometer_endpoint" in client.py
No problem! π
Awesome π I have created a dev
branch to make it easier to develop a function version. Please use that instead. And that error should be fixed in the dev
branch. This will help me a lot to decipher what Toyota returns from there API's.
Cool :-)
In the dev
Branch it suddenly complains that the username is an unexpected keyword:
Sorry, i had change something and forgot to give you the updated code to test with:
import asyncio
from mytoyota.client import MyT
username = "email"
password = "password"
locale = "da-dk"
client = MyT(username=username, password=password, locale=locale)
print("Performing login...")
# This performs login and returns token and uuid. This should be saved somewhere safe and then reused when running
# this application again. Token lives about ~24 hours.
# token, uuid = client.perform_login()
client.perform_login()
async def get_information():
print("Retrieving cars...")
# Returns information about the cars registered to your account.
cars = await client.get_cars()
# Gets vehicle data from cars in the list.
for car in cars:
vin = car['vin']
print(car)
print(await client.get_information_for_given_car(vin))
loop = asyncio.get_event_loop()
loop.run_until_complete(get_information())
loop.close()
Naaaaaice! ;-)
YESS!! π
But I can see that it is missing information from one endpoint. Where it says {'ReturnCode': '000000'}
It should return more information about your HVAC and BATTERY, but this a least confirms that i'm on the right track. Can you tell if you have setup Toyota Connected Services through there website?
I set it up through the Toyota Android MyT app at the time. https://play.google.com/store/apps/details?id=app.mytoyota.toyota.com.mytoyota&hl=de&gl=US To be honest, I think I've never been on the website π
Haha, I only use the website to sniff out the API endpoints. π
When i get my car in the next couple of weeks, I will add more functions. In the mean time i will release this and the go back to work on the HA integration.
I just updated dev
again to make it return things more neatly. Can you test this? π
Ahh, I see it. The data is now grouped by Odometer, Parking & Status.
Very nice π
But the parking and status information is a bit redundant, isn't it?
{
'odometer': [{
'type': 'mileage',
'value': 2064,
'unit': 'km'
}, {
'type': 'Fuel',
'value': 87.06
}],
'parking': {
'event': {
'lat': 'MYLAT',
'lon': 'MYLON',
'address': None,
'timestamp': '1615741819000'
},
'tripStatus': '0',
'energy': None
},
'status': {
'event': {
'lat': 'MYLAT',
'lon': 'MYLON',
'address': None,
'timestamp': '1615741819000'
},
'tripStatus': '0',
'energy': None
}
}
I think this is a good approach, not to overload the first release too much with features, but to add them gradually. Have fun with the new car (what will it be?) and thanks for your work so far.
Thanks, i had a typo, that's why it is shown twice.
I have released a PyPi package, though still an alpha but it should work. You can install it by doing pip install mytoyota
.
import asyncio
from mytoyota.client import MyT
username = "email"
password = "password"
locale = "da-dk"
client = MyT(username=username, password=password, locale=locale)
print("Performing login...")
# This performs login and returns token and uuid. This should be saved somewhere safe and then reused when running
# this application again. Token lives about ~24 hours.
# token, uuid = client.perform_login()
client.perform_login()
async def get_information():
print("Retrieving cars...")
# Returns information about the cars registered to your account.
cars = await client.get_vehicles()
# Gets vehicle data from cars in the list.
for car in cars:
vin = car['vin']
print(car)
print(await client.get_vehicle_status(vin))
loop = asyncio.get_event_loop()
loop.run_until_complete(get_information())
loop.close()
And to answer you last question. I just bought an Toyota Aygo (Micro Car) and to my surprise it comes with the ability to connect it to MyT. It also have Android Auto and Apple CarPlay π
@CM000n
Would you be willing to test somethings for me and post back the information, remember to remove private info? I have rewritten much of the underlying package here and have found a lot of new information in the API and i have added statistical endpoints. But I need some one to test it, because my car does not support everything that is possible. π
Of course! I would be more than happy to support you at least by testing a little. Is there anything in particular I should look out for?
Can you run the below script and the paste the result here. Remember to desensitize it π
You will see that you now get statistical information from day, week and month. Right now i have some problems with year, but that will also come soon.
I have also changed a lot of things in the HA integration. I will release a new one very soon. Just have to fix some small things first in it.
Remember to update mytoyota
. pip install mytoyota=0.2.1
.
import asyncio
from mytoyota.client import MyT
username = "jane@doe.com"
password = "MyPassword"
locale = "da-dk"
client = MyT(username=username, password=password, locale=locale, region="europe")
async def get_information():
print("Logging in...")
await client.login()
print("Retrieving cars...")
# Returns information about the cars registered to your account
cars = await client.get_vehicles()
print(await client.gather_all_information_json())
statistics = await client.get_driving_statistics_from_date_json(cars[0]['vin'])
print(statistics)
statistics = await client.get_driving_statistics_from_week_json(cars[0]['vin'])
print(statistics)
statistics = await client.get_driving_statistics_from_month_json(cars[0]['vin'])
print(statistics)
loop = asyncio.get_event_loop()
loop.run_until_complete(get_information())
loop.close()
Ok, I have updated via pip to version 0.2.1. But when I try to run your test script, I get the following error(s):
Make sure you are running it under python 3 and not python 2. π
And can you paste the result in code-blocks next time. It is easier for me to just copy the part i need. π
UPDATE.
I found the error, was not because of you. Publishing a new package now.
EDIT: Please use mytoyota==0.2.2
π
Seems to work now :-) This is the output I get for day, week, month so far:
[
{
"alias": "Corolla",
"vin": "MYVIN",
"details": {
"engine": "Hybrid: 1,8-l-VVT-i: Benzinmotor 72 kW (98PS), Elektromotor, 53 kW (72PS), Systemleistung 90 kW (122 PS)",
"entitledBy": "CUSTOMER",
"entitledOn": "2020-11-20T17:28:23.074Z",
"exteriorColour": "3U5 ",
"fuel": "PETROL",
"fullKatashiki": "ZWE211L-DWXNBW",
"grade": "Mid",
"horsePower": 98,
"hybrid": true,
"id": 1958079,
"imageUrl": "https://dj3z27z47basa.cloudfront.net/9e45cf3a-684e-453e-859c-22cfde3272ae",
"interiorColour": "20",
"isEntitled": true,
"isNC": false,
"licensePlate": "MYLICENSEPLATE",
"modelCode": "CR",
"modelDescription": "Corolla",
"modelDocumentId": "12345",
"modelName": "Corolla",
"owner": false,
"ownerFlag": false,
"productionYear": "2020",
"source": "NMSC",
"transmission": "Stufenloses Automatikgetriebe",
"transmissionType": "CVT",
"vehicleAddedOn": "2020-11-19T17:36:19.469Z"
},
"status": {
"battery": null,
"hvac": null,
"odometer": {
"mileage": 2381,
"mileage_unit": "km",
"Fuel": 29.02
},
"parking": {
"event": {
"lat": "MYLAT",
"lon": "MYLON",
"address": null,
"timestamp": "1616853523000"
},
"tripStatus": "0",
"energy": null,
"protectionState": null
}
},
"servicesEnabled": {
"connectedServices": true
}
}
]
{
"vin": "MYVIN",
"from": "2021-03-27",
"to": "2021-03-28",
"uuid": "4c5c95ff-c92e-4e13-a8b4-99424edefc7d",
"calendarInterval": "day",
"summary": {
"tripCount": 4,
"totalDistanceInKm": 8.245,
"totalDurationInSec": 750,
"idleDurationInSec": 32,
"highwayDistanceInKm": 0.0,
"nightTripsCount": 0,
"fuelSavedInL": 0.165,
"averageDriverScore": 52.115585,
"averageAccelerationDriverScore": 42.000727,
"averageBrakingDriverScore": 42.079442,
"averageConstantSpeedDriverScore": 84.210551,
"evDurationInSec": 86,
"evDistanceInKm": 0.811,
"hardAccelerationCount": 1,
"hardBrakingCount": 1,
"coachingAdviceMostOccurrence": 5,
"averageSpeedInKmph": 39.576063,
"fuelSavedPercentage": 19.97578692493947,
"evDurationPercentage": 11.466666666666667,
"evDistancePercentage": 9.836264402668284,
"co2Savings": 47.869011522134635,
"totalFuelConsumedInL": 8.016979987871437,
"maxSpeedInKmph": 99.0,
"highwayDistancePercentage": 0.0
},
"histogram": [
{
"bucket": {
"year": 2021,
"dayOfYear": 86
},
"data": {
"tripCount": 4,
"totalDistanceInKm": 8.245,
"totalDurationInSec": 750,
"idleDurationInSec": 32,
"highwayDistanceInKm": 0.0,
"nightTripsCount": 0,
"fuelSavedInL": 0.165,
"averageDriverScore": 52.115585,
"averageAccelerationDriverScore": 42.000727,
"averageBrakingDriverScore": 42.079442,
"averageConstantSpeedDriverScore": 84.210551,
"evDurationInSec": 86,
"evDistanceInKm": 0.811,
"hardAccelerationCount": 1,
"hardBrakingCount": 1,
"coachingAdviceMostOccurrence": 5,
"averageSpeedInKmph": 39.576063,
"evDistancePercentage": 9.836264402668284,
"evDurationPercentage": 11.466666666666667,
"totalFuelConsumedInL": 8.016979987871437,
"maxSpeedInKmph": 99.0,
"highwayDistancePercentage": 0.0
}
}
]
}
{
"vin": "MYVIN",
"from": "2021-03-22",
"to": "2021-03-28",
"uuid": "4c5c95ff-c92e-4e13-a8b4-99424edefc7d",
"calendarInterval": "week",
"summary": {
"tripCount": 14,
"totalDistanceInKm": 113.484,
"totalDurationInSec": 8067,
"idleDurationInSec": 171,
"highwayDistanceInKm": 34.851,
"nightTripsCount": 0,
"fuelSavedInL": 1.622,
"averageDriverScore": 76.92702,
"averageAccelerationDriverScore": 68.549513,
"averageBrakingDriverScore": 88.453077,
"averageConstantSpeedDriverScore": 78.9504,
"evDurationInSec": 3101,
"evDistanceInKm": 30.292,
"hardAccelerationCount": 5,
"hardBrakingCount": 9,
"coachingAdviceMostOccurrence": 5,
"averageSpeedInKmph": 50.643666,
"fuelSavedPercentage": 20.994046078177583,
"evDurationPercentage": 38.440560307425315,
"evDistancePercentage": 26.69274963871559,
"co2Savings": 34.18829086038561,
"totalFuelConsumedInL": 5.37873180360227,
"maxSpeedInKmph": 128.0,
"highwayDistancePercentage": 30.710056043142647
},
"histogram": [
{
"bucket": {
"year": 2021,
"week": 13
},
"data": {
"tripCount": 14,
"totalDistanceInKm": 113.484,
"totalDurationInSec": 8067,
"idleDurationInSec": 171,
"highwayDistanceInKm": 34.851,
"nightTripsCount": 0,
"fuelSavedInL": 1.622,
"averageDriverScore": 76.92702,
"averageAccelerationDriverScore": 68.549513,
"averageBrakingDriverScore": 88.453077,
"averageConstantSpeedDriverScore": 78.9504,
"evDurationInSec": 3101,
"evDistanceInKm": 30.292,
"hardAccelerationCount": 5,
"hardBrakingCount": 9,
"coachingAdviceMostOccurrence": 5,
"averageSpeedInKmph": 50.643666,
"evDistancePercentage": 26.69274963871559,
"evDurationPercentage": 38.440560307425315,
"totalFuelConsumedInL": 5.37873180360227,
"maxSpeedInKmph": 128.0,
"highwayDistancePercentage": 30.710056043142647
}
}
]
}
{
"vin": "MYVIN",
"from": "2021-03-01",
"to": "2021-03-28",
"uuid": "4c5c95ff-c92e-4e13-a8b4-99424edefc7d",
"calendarInterval": "month",
"summary": {
"tripCount": 81,
"totalDistanceInKm": 516.324,
"totalDurationInSec": 42076,
"idleDurationInSec": 1853,
"highwayDistanceInKm": 72.647,
"nightTripsCount": 16,
"fuelSavedInL": 9.019,
"averageDriverScore": 73.547324,
"averageAccelerationDriverScore": 67.956806,
"averageBrakingDriverScore": 80.327442,
"averageConstantSpeedDriverScore": 76.605964,
"evDurationInSec": 17462,
"evDistanceInKm": 159.045,
"hardAccelerationCount": 32,
"hardBrakingCount": 67,
"coachingAdviceMostOccurrence": 5,
"averageSpeedInKmph": 44.176407,
"fuelSavedPercentage": 22.786277236903103,
"evDurationPercentage": 42.1773489770193,
"evDistancePercentage": 31.150997777481095,
"co2Savings": 41.78277205785515,
"totalFuelConsumedInL": 5.937744517008701,
"maxSpeedInKmph": 128.0,
"highwayDistancePercentage": 14.070041291901985
},
"histogram": [
{
"bucket": {
"year": 2021,
"month": 3
},
"data": {
"tripCount": 81,
"totalDistanceInKm": 516.324,
"totalDurationInSec": 42076,
"idleDurationInSec": 1853,
"highwayDistanceInKm": 72.647,
"nightTripsCount": 16,
"fuelSavedInL": 9.019,
"averageDriverScore": 73.547324,
"averageAccelerationDriverScore": 67.956806,
"averageBrakingDriverScore": 80.327442,
"averageConstantSpeedDriverScore": 76.605964,
"evDurationInSec": 17462,
"evDistanceInKm": 159.045,
"hardAccelerationCount": 32,
"hardBrakingCount": 67,
"coachingAdviceMostOccurrence": 5,
"averageSpeedInKmph": 44.176407,
"evDistancePercentage": 31.150997777481095,
"evDurationPercentage": 42.1773489770193,
"totalFuelConsumedInL": 5.937744517008701,
"maxSpeedInKmph": 128.0,
"highwayDistancePercentage": 14.070041291901985
}
}
]
}
Nice work π
Thanks a lot. This will make it easier for me to implement unittest in the HA integration. The aim is to get it add to core at some point. π Will ping you over at ha_toyota
when a new release is ready for you to test. (Very very soon) π
That sounds promising :-) What I noticed; Do the labels come from you, or directly from the API? The designation "totalFuelConsumedInL"
is a bit misleading, because I'm pretty sure I've already consumed more than 5.9 L this month. ;-) That's probably more the average consumption per 100km, rather than total consumption
They come directly from the API. And i agree totalFuelConsumedInL
is misleading. I think you are right, it is average consumptions per 100 km.
Describe the bug Hi, when I try to run your code I get a runtimer error: OS: Windows 10 Python Version: 3.8.7 64-bit
To Reproduce
pip install git+https://github.com/DurgNomis-drol/mytoyota.git
username = "MYUSER" password = "MYPW" locale = "de-de" session = aiohttp.ClientSession()
client = MyT(locale=locale, session=session)
print("Performing login...") client.perform_login(username=username, password=password)
async def get_cars(): print("Retrieving cars...") valid, cars = client.get_cars()
loop = asyncio.get_event_loop() loop.run_until_complete(get_cars()) loop.close()