basilfx / homeassistant-biketrax

Custom component for the PowUnity BikeTrax integration for Home Assistant.
MIT License
5 stars 2 forks source link

Unable to parse API response #117

Closed oriold closed 7 months ago

oriold commented 7 months ago

I can't add the integration right now as I can't log in. I get the following error:


Logger: custom_components.biketrax.config_flow
Source: custom_components/biketrax/config_flow.py:77
Integration: PowUnity BikeTrax (documentation, issues)
First occurred: 12:44:31 (1 occurrences)
Last logged: 12:44:31

Unexpected exception
Traceback (most recent call last):
  File "/usr/local/lib/python3.12/site-packages/aiobiketrax/api.py", line 49, in wrapper
    return await func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/aiobiketrax/api.py", line 220, in get_devices
    return [models.device_from_dict(device) for device in response]
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 871, in device_from_dict
    return Device.from_dict(s)
           ^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 625, in from_dict
    attributes = DeviceAttributes.from_dict(obj.get("attributes"))
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 553, in from_dict
    passport = from_union([Passport.from_dict, from_none], obj.get("passport"))
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 30, in from_union
    assert False
AssertionError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/config/custom_components/biketrax/config_flow.py", line 77, in async_step_user
    info = await validate_input(self.hass, user_input)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/config/custom_components/biketrax/config_flow.py", line 41, in validate_input
    await account.update_devices()
  File "/usr/local/lib/python3.12/site-packages/aiobiketrax/client.py", line 61, in update_devices
    device.id: device for device in await self.traccar_api.get_devices()
                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.12/site-packages/aiobiketrax/api.py", line 51, in wrapper
    raise ApiError("Unable to parse API response.") from e
aiobiketrax.exceptions.ApiError: Unable to parse API response.

The step to reproduce remove integration and then add it again. It fails on login.

basilfx commented 7 months ago

Please enable debug logging (see HASS documentation) and provide the API responses. Be sure to hide any sensitive information.

oriold commented 7 months ago
2024-02-15 13:54:28.455 DEBUG (MainThread) [custom_components.biketrax.config_flow] Exception while validating input for 'REDACTED'.
Traceback (most recent call last):
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/api.py", line 49, in wrapper
return await func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/api.py", line 220, in get_devices
return [models.device_from_dict(device) for device in response]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 871, in device_from_dict
return Device.from_dict(s)
^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 625, in from_dict
attributes = DeviceAttributes.from_dict(obj.get("attributes"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 553, in from_dict
passport = from_union([Passport.from_dict, from_none], obj.get("passport"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 30, in from_union
assert False
AssertionError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/config/custom_components/biketrax/config_flow.py", line 41, in validate_input
await account.update_devices()
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/client.py", line 61, in update_devices
device.id: device for device in await self.traccar_api.get_devices()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/api.py", line 51, in wrapper
raise ApiError("Unable to parse API response.") from e
aiobiketrax.exceptions.ApiError: Unable to parse API response.
2024-02-15 13:54:28.457 ERROR (MainThread) [custom_components.biketrax.config_flow] Unexpected exception
Traceback (most recent call last):
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/api.py", line 49, in wrapper
return await func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/api.py", line 220, in get_devices
return [models.device_from_dict(device) for device in response]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 871, in device_from_dict
return Device.from_dict(s)
^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 625, in from_dict
attributes = DeviceAttributes.from_dict(obj.get("attributes"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 553, in from_dict
passport = from_union([Passport.from_dict, from_none], obj.get("passport"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/models.py", line 30, in from_union
assert False
AssertionError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/config/custom_components/biketrax/config_flow.py", line 77, in async_step_user
info = await validate_input(self.hass, user_input)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/config/custom_components/biketrax/config_flow.py", line 41, in validate_input
await account.update_devices()
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/client.py", line 61, in update_devices
device.id: device for device in await self.traccar_api.get_devices()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/site-packages/aiobiketrax/api.py", line 51, in wrapper
raise ApiError("Unable to parse API response.") from e
aiobiketrax.exceptions.ApiError: Unable to parse API response.
basilfx commented 7 months ago

The integration is still working for me.

Can you try the following? In the PowUnity BikeTrax app, go to your bicycle's passport, and change/add at least one value. Then try it again.

oriold commented 7 months ago

Didn't work. I have installed aiobiketrax and used the CLI, I can get a bit of better error:

`DEBUG:aiobiketrax.client:Updating devices. DEBUG:aiobiketrax.api:Commencing login for 'REDACTED'. DEBUG:aiobiketrax.api:Retrieved JWT token. DEBUG:aiobiketrax.api:GET request to 'https://traccar.powunity.com/api/devices' returned HTTP status code 200. DEBUG:aiobiketrax.api.responses:[{'id': 000000, 'attributes': {'passport': {'bikePictures': [['http://res.cloudinary.com/powunity/image/upload/v1707918836/production/passport/REDACTED.jpg']], 'specialFeatures': '', 'receiptPictures': [], 'manufacturer': 'REDACTED', 'model': 'REDACTED', 'modelYear': '2023-02-15T12:01:00-00:00', 'colour': 'green', 'bikeType': 'freight', 'engine': 'bosch', 'shiftingSystemManufacturer': 'REDACTED', 'shiftingSystemModel': 'REDACTED', 'shiftingSystemGears': '8', 'purchaseDate': '2024-02-02T12:07:00-00:00', 'price': '0', 'frameNumber': '000', 'used': False}, 'onboardingFinished': True, 'trialEnd': '2025-02-13T13:53:58.359Z', 'firmware': 'LK_CAR_TQ2020/10/14 11:12', 'guardType': 'movement', 'gpsDisabled': False, 'subscription': {'id': 'REDACTED', 'plan_id': 'biketrax-service-plan-12m', 'plan_quantity': 1, 'plan_unit_price': 3950, 'billing_period': 1, 'billing_period_unit': 'year', 'trial_end': 1739454838, 'customer_id': 'REDACTED', 'plan_amount': 3950, 'plan_free_quantity': 0, 'status': 'in_trial', 'trial_start': 1707998400, 'next_billing_at': 1739454838, 'created_at': 1707998400, 'started_at': 1707998400, 'created_from_ip': '1.1.1.1', 'updated_at': 1707998400, 'has_scheduled_changes': False, 'channel': 'web', 'resource_version': 1707998400118, 'deleted': False, 'object': 'subscription', 'currency_code': 'EUR', 'due_invoices_count': 0, 'cf_device_id': 000, 'has_scheduled_advance_invoices': False}}, 'groupId': 0, 'name': 'REDACTED', 'uniqueId': '0001', 'status': 'offline', 'lastUpdate': '2024-02-20T04:01:47.221+00:00', 'positionId': 00, 'geofenceIds': [], 'phone': None, 'model': None, 'contact': None, 'category': None, 'disabled': False}, {'id': 0000, 'attributes': {'passport': {'specialFeatures': '', 'bikePictures': ['http://res.cloudinary.com/powunity/image/upload/v1707999248/production/passport/REDACTED.jpg', 'http://res.cloudinary.com/powunity/image/upload/v1707999275/production/passport/REDACTED.jpg'], 'receiptPictures': ['http://res.cloudinary.com/powunity/image/upload/v1707999649/production/passport/REDACTED.png', 'http://res.cloudinary.com/powunity/image/upload/v1707999650/production/passport/REDACTED.png'], 'manufacturer': 'REDACTED', 'model': 'REDACTED', 'modelYear': '2021-02-15T12:15:00-00:00', 'colour': 'grey', 'bikeType': 'freight', 'engine': 'bosch', 'shiftingSystemManufacturer': 'REDACTED', 'shiftingSystemModel': 'REDACTED', 'purchaseDate': '2023-08-28T12:17:00+01:00', 'price': '0', 'used': True, 'frameNumber': 'REDACTED'}, 'onboardingFinished': True, 'trialEnd': '2024-08-30T09:29:14.000Z', 'guardType': 'movement', 'firmware': 'LK_CAR_TQ2020/10/14 11:12', 'gpsDisabled': False, 'subscription': {'id': 'REDACTED', 'plan_id': 'biketrax-service-plan-12m', 'plan_quantity': 1, 'plan_unit_price': 3950, 'billing_period': 1, 'billing_period_unit': 'year', 'trial_end': 1725010154, 'customer_id': 'REDACTED', 'plan_amount': 3950, 'plan_free_quantity': 0, 'status': 'in_trial', 'trial_start': 1707999145, 'next_billing_at': 1725010154, 'created_at': 1693387754, 'started_at': 1693387754, 'created_from_ip': '1.1.1.1', 'updated_at': 1707999145, 'has_scheduled_changes': False, 'payment_source_id': 'REDACTED', 'cancel_schedule_created_at': 1707906398, 'channel': 'web', 'resource_version': 1707999145623, 'deleted': False, 'object': 'subscription', 'currency_code': 'EUR', 'due_invoices_count': 0, 'cf_device_id': 0000, 'has_scheduled_advance_invoices': False, 'meta_data': {'paidUntil': '2024-08-30T09:29:14.000Z'}}, 'guarded': True, 'alarm': False, 'lastAlarm': 1708113282092}, 'groupId': 0, 'name': 'REDACTED', 'uniqueId': '000', 'status': 'offline', 'lastUpdate': '2024-02-20T19:25:49.362+00:00', 'positionId': 0, 'geofenceIds': [], 'phone': None, 'model': None, 'contact': None, 'category': None, 'disabled': False}] Traceback (most recent call last): File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/api.py", line 49, in wrapper return await func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/api.py", line 220, in get_devices return [models.device_from_dict(device) for device in response] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/api.py", line 220, in return [models.device_from_dict(device) for device in response] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/models.py", line 871, in device_from_dict return Device.from_dict(s) ^^^^^^^^^^^^^^^^^^^ File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/models.py", line 625, in from_dict attributes = DeviceAttributes.from_dict(obj.get("attributes")) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/models.py", line 553, in from_dict passport = from_union([Passport.from_dict, from_none], obj.get("passport")) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/models.py", line 30, in from_union assert False AssertionError

The above exception was the direct cause of the following exception:

Traceback (most recent call last): File "/home/oriol/venv/biketrax/bin/biketrax", line 8, in sys.exit(run()) ^^^^^ File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/cli.py", line 178, in run sys.exit(asyncio.run(main(sys.argv))) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/asyncio/runners.py", line 190, in run return runner.run(main) ^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/asyncio/runners.py", line 118, in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete return future.result() ^^^^^^^^^^^^^^^ File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/cli.py", line 167, in main await command_devices(arguments) File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/cli.py", line 55, in command_devices await account.update_devices() File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/client.py", line 61, in update_devices device.id: device for device in await self.traccar_api.get_devices() ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/home/oriol/venv/biketrax/lib/python3.11/site-packages/aiobiketrax/api.py", line 51, in wrapper raise ApiError("Unable to parse API response.") from e aiobiketrax.exceptions.ApiError: Unable to parse API response. (`

oriold commented 7 months ago

Going to close this. Found the problem in the JSON. So apparently there is extra brackets on the first image of the bike. I think this may have been an error when creating the image capturing directly from the app. So it would be a bug in the Powunity app.

Removing the images has fixed the issue in the CLI and I expect now the integration to work.