G-Two / subarulink

A python package for interacting with Subaru STARLINK remote vehicle services.
Apache License 2.0
84 stars 14 forks source link

Question: remote start configuration #11

Closed mconlow closed 3 years ago

mconlow commented 4 years ago

I got the HA restful switch working for the locks. I'm happy to document that somehow if others would find it useful. But your HA integration seems like it is close and will accomplish the same thing and not be so hacky.

I'm moving on to remote_start and I have what I think is a basic question.

When I do subarulink remote_start it tells me ERROR - Remote start settings not found in config file. Configure settings interactively first

When I go into interactive mode, then do start it says hvac <set|start|stop> and gives me a new prompt. I can't figure out what to put in that new prompt line.

I probably just don't know this notation. Help appreciated, thank you!

G-Two commented 4 years ago

@mconlow from the interactive mode, just run start set, and you'll be guided through the remote start options and given the choice to save them to the config file. Sorry about unclear (and incorrect) notation in the interactive mode.

G-Two commented 4 years ago

@mconlow my vehicle (2019 Crosstrek) doesn't support some of the remote start options such as heated seats or rear A/C, so I'll be curious to know if they work for you.

G-Two commented 4 years ago

I pushed some minor edits to make interactive mode clearer. I'll keep this open until I know the remote start configs work with the 2020 Ascent.

mconlow commented 4 years ago

First try gives this 403 error and a push notification from the app that it failed. Will give it another shot momentarily

2020-07-22 01:05:53,985 - subarulink.connection - DEBUG - GET: https://mobileapi.prod.subarucs.com/g2v15/service/g2/remoteService/status.json
2020-07-22 01:05:54,206 - subarulink.controller - DEBUG - {'data': {'cancelled': False,
          'errorCode': 'NegativeAcknowledge:unknown',
          'remoteServiceState': 'finished',
          'remoteServiceType': 'engineStart',
          'result': None,
          'serviceRequestId': '******_1595376340325_22_@NGTP',
          'subState': None,
          'success': False,
          'updateTime': 1595376345000,
          'vin': '******'},
 'dataName': 'remoteServiceStatus',
 'errorCode': None,
 'success': True}
2020-07-22 01:05:56,212 - subarulink.connection - DEBUG - GET: https://mobileapi.prod.subarucs.com/g2v15/service/g2/remoteService/status.json
2020-07-22 01:05:56,983 - subarulink.controller - DEBUG - {'data': {'errorDescription': None,
          'errorLabel': '403-soa-unableToParseResponseBody'},
 'dataName': 'errorResponse',
 'errorCode': '403-soa-unableToParseResponseBody',
 'success': False}
Traceback (most recent call last):
  File "/usr/local/bin/subarulink", line 10, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.7/dist-packages/subarulink/app/cli.py", line 554, in main
    LOOP.run_until_complete(cli.single_command(args.command, args.vin))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.7/dist-packages/subarulink/app/cli.py", line 449, in single_command
    self._config["hvac"]["rear_ac"],
  File "/usr/local/lib/python3.7/dist-packages/subarulink/controller.py", line 238, in remote_start
    resp = await self._actuate(vin, "engineStart", data=form_data)
  File "/usr/local/lib/python3.7/dist-packages/subarulink/controller.py", line 305, in _actuate
    return await self._remote_command(vin, cmd, data=form_data)
  File "/usr/local/lib/python3.7/dist-packages/subarulink/controller.py", line 295, in _remote_command
    js_resp = await self._wait_request_status(req_id, api_gen, poll_url)
  File "/usr/local/lib/python3.7/dist-packages/subarulink/controller.py", line 348, in _wait_request_status
    if js_resp["data"]["success"]:
KeyError: 'success'
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x75bdbd30>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x75b89ce0>, 2288860.67670159)]']
connector: <aiohttp.connector.TCPConnector object at 0x75bdbcb0>
mconlow commented 4 years ago

Yeah tried a couple time and always get this. It loops through this cycle maybe 5 or 6 times before erroring.

mconlow commented 3 years ago

This one looks slightly different in that it appears to error on the execute.json request instead of after a status.json request.

2020-07-22 03:19:13,805 - subarulink.connection - DEBUG - GET: https://mobileapi.prod.subarucs.com/g2v15/validateSession.json
2020-07-22 03:19:13,986 - subarulink.connection - DEBUG - {'data': None, 'dataName': None, 'errorCode': None, 'success': True}
2020-07-22 03:19:13,988 - subarulink.connection - DEBUG - POST: https://mobileapi.prod.subarucs.com/g2v15/service/g2/engineStart/execute.json
2020-07-22 03:19:14,240 - subarulink.controller - DEBUG - {'data': {'errorDescription': None,
          'errorLabel': '403-soa-unableToParseResponseBody'},
 'dataName': 'errorResponse',
 'errorCode': '403-soa-unableToParseResponseBody',
 'success': False}
Traceback (most recent call last):
  File "/usr/local/bin/subarulink", line 10, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.7/dist-packages/subarulink/app/cli.py", line 554, in main
    LOOP.run_until_complete(cli.single_command(args.command, args.vin))
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "/usr/local/lib/python3.7/dist-packages/subarulink/app/cli.py", line 449, in single_command
    self._config["hvac"]["rear_ac"],
  File "/usr/local/lib/python3.7/dist-packages/subarulink/controller.py", line 238, in remote_start
    resp = await self._actuate(vin, "engineStart", data=form_data)
  File "/usr/local/lib/python3.7/dist-packages/subarulink/controller.py", line 305, in _actuate
    return await self._remote_command(vin, cmd, data=form_data)
  File "/usr/local/lib/python3.7/dist-packages/subarulink/controller.py", line 299, in _remote_command
    raise SubaruException("Remote command failed.  Response: %s " % js_resp)
subarulink.exceptions.SubaruException
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x75bb9dd0>
Unclosed connector
connections: ['[(<aiohttp.client_proto.ResponseHandler object at 0x75b68d18>, 2296857.933376786)]']
connector: <aiohttp.connector.TCPConnector object at 0x75bb9d50>
G-Two commented 3 years ago

@mconlow I just pushed a new commit that should ignore the 403 errors and attempt to continue. It won't necessarily make remote start work, but it should at least help us get better logging to determine the issue. Please try to test with seat heaters and rear A/C turned off, since that is a known working config on my end. Thanks for the help! I hope to get these bugs resolved before the integration makes it into Home Assistant.

I didn't push this to PyPI yet, so you'll need to clone the git repo and use pipenv to setup the environment to test it out.

mconlow commented 3 years ago

Do you mind giving me a couple pointers on setting up pipenv to test it out? Make a new virtual environment to try it?

G-Two commented 3 years ago

@mconlow sure, no problem. If you're familiar with virtual environments, this will be even easier, as it just manages the virtual environment for your local repo. You can even use your normal virtualenv workflow and pip install the requirements from Pipfile if you prefer to do it manually.

To setup with pipenv (which ensures we're using all the same python packages):

Alternatively, if you just want to run a single command and not deal with entering/exiting the virtual environment shell, you can just use pipenv run ./subaurlink.py <args>

stboch commented 3 years ago

Been working on testing this this morning... getting 500 errors on my end... 2020-07-22 12:51:40,673 - subarulink.connection - DEBUG - {'errorCode': 'error', 'errorMessage': 'org.springframework.web.client.HttpServerErrorException$InternalServerError ' '- 500 Internal Server Error', 'httpCode': 500} 2020-07-22 12:51:40,673 - subarulink - ERROR - SubaruException caught: 500

Also you can fetch the Climate Settings last used via /service/g2/remoteEngineStart/fetch.json and an equivalent save service too /service/g2/remoteEngineStart/save.json (haven't update the code to pull it seems my version of the url's tend to be different then the ones your using...

G-Two commented 3 years ago

@stboch I've observed that I also get the 500 errors if I try to enable an option that my vehicle is not equipped to handle (in my case, seat heaters and rear A/C). Are you able to make any successful remote start requests with those features not enabled? I might also be setting up the calls incorrectly, I need to cross check with the Android app again.

Thanks for reminding me about the fetch/save API calls, those will be a much better way maintain those settings.

stboch commented 3 years ago

@G-Two I have heated seats so that should have been fine. I tried rearac to both true and false same error for both. Outback does not have rear ac only front heated/cool seats

mconlow commented 3 years ago

Tried it with the new code. It appear to attempt the start a lot more times, but none of them work and eventually gives up. I still get a failed push notification from the app.

2020-07-22 14:20:11,294 - subarulink.connection - DEBUG - GET: https://mobileapi.prod.subarucs.com/g2v15/service/g2/remoteService/status.json 2020-07-22 14:20:11,418 - subarulink.controller - DEBUG - {'data': {'cancelled': False, 'errorCode': 'NegativeAcknowledge:unknown', 'remoteServiceState': 'finished', 'remoteServiceType': 'engineStart', 'result': None, 'serviceRequestId': '**_159544197054222@NGTP', 'subState': None, 'success': False, 'updateTime': 1595441976000, 'vin': '*****'}, 'dataName': 'remoteServiceStatus', 'errorCode': None, 'success': True} 2020-07-22 14:20:13,424 - subarulink.controller - ERROR - Remote service request completion message not received

stboch commented 3 years ago

Try locking the doors then rerunning the start. I have had times where the car just doesn't want to respond to a command sometimes issuing a different one kicks it in the butt.

G-Two commented 3 years ago

@mconlow you shouldn't be receiving that final error if 'remoteServiceState'=='finished'. I think you may still be running an older revision. Be sure to pip uninstall subarulink otherwise it will conflict (and override, I think) with the module in the cloned repo. This stop the loop once the 'finished' response is received. It doesn't fix the remoteStart not working, but it should at least gracefully fail faster.

I'm still not sure what is causing 'NegativeAcknowledge:unknown'. I sometimes get 'NegativeAcknowledge:inVehicleTimeout'.

G-Two commented 3 years ago

I think I misread the javascript implementation in the Android app and have the heated seat (and probably other) parameters incorrect in const.py. Looks like it should be HIGH_HEAT, MEDIUM_HEAT, LOW_HEAT, OFF

mconlow commented 3 years ago

OK - do you think that explains this behavior? Should I wait for your next commit or try to uninstall it and reclone with this code?

G-Two commented 3 years ago

I think it explains the 500 error. It still doesn't explain the NegativeAcknowledgement.

I just committed a fix for the heated seats. You don't need to reclone. Just issue git pull from your local copy of the repo and you'll be running the new code (assuming you have already done pip uninstall subarulink).

stboch commented 3 years ago

FIGURED OUT THE 500!!!!

Heated Seats OFF or var heatedSeatVol = { 'LOW_HEAT' : 1, 'MEDIUM_HEAT' : 2, 'HIGH_HEAT' : 3 }

mconlow commented 3 years ago

Looks like same error. errorCode: NegativeAcknowledge:unknown Here are my hvac settings from the config file if that is helpful.

"hvac": {"temp": "71", "mode": "AUTO", "speed": "AUTO", "left_seat": "OFF", "right_seat": "OFF",
 "rear_defrost": "false", "recirculate": "recirculation", "rear_ac": "true"}
mconlow commented 3 years ago

in the app, when I go into "Climate and Delay Settings", when I swtich to ClimateSettings --> AUTO, the remaining selections are Engine Runtime, Heated Seats (driver and passenger), defroster (rear), and rear AC (on or off). Could it not be expecting the recirculate setting and the speed setting?

stboch commented 3 years ago

@G-Two GOT IT consts.py change to: START_CONFIG_DEFAULT = "START_ENGINE_ALLOW_KEY_IN_IGNITION"

G-Two commented 3 years ago

ah...good find! The string I'm using must be for PHEV remote start only. This is an easy fix since you already added the code to check for EV vs RES!

stboch commented 3 years ago

Well ok a little more complicated than START_CONFIG_DEFAULT = "START_ENGINE_ALLOW_KEY_IN_IGNITION" VS startConfiguration = 'start_Climate_Control_only_allow_key_in_ignition'

stboch commented 3 years ago

I wondered what the difference was between climateControlGen vs engineStart Also looking at adding some things like beep and blink as services on the HA Side. Been looking at the BMW connected intergration for inspiration.

G-Two commented 3 years ago

I'm about to commit this change with the appropriate constants in const.py. Hopefully that will do the trick!

    async def remote_start(
        self, vin, temp, mode, heat_left_seat, heat_right_seat, rear_defrost, fan_speed, recirculate, rear_ac,
    ):
        """Send remote start command."""
        form_data = {
            sc.TEMP: temp,
            sc.CLIMATE: sc.CLIMATE_DEFAULT,
            sc.RUNTIME: sc.RUNTIME_DEFAULT,
            sc.MODE: mode,
            sc.HEAT_SEAT_LEFT: heat_left_seat,
            sc.HEAT_SEAT_RIGHT: heat_right_seat,
            sc.REAR_DEFROST: rear_defrost,
            sc.FAN_SPEED: fan_speed,
            sc.RECIRCULATE: recirculate,
            sc.REAR_AC: rear_ac,
        }
        if self._hasEV[vin]:
            form_data[sc.START_CONFIG] = sc.START_CONFIG_DEFAULT_EV
        elif self._hasRES[vin]:
            form_data[sc.START_CONFIG] = sc.START_CONFIG_DEFAULT_RES
        else:
            raise SubaruException("Vehicle Remote Start not supported.")

        if _validate_remote_start_params(form_data):
            success, js_resp = await self._actuate(vin, "engineStart", data=form_data)
            return success
        else:
            return None
G-Two commented 3 years ago

Fixes committed. I'm still unsure if the heated seat parameter for the API are the words or the numbers? The numbers might be for the application UI. Let me know if the heated seats don't work, and I'll change the constants to the numbers. I made a few other changes as well, see the commit for more details.

mconlow commented 3 years ago

I still get NegativeAcknowledge:unknown. I'm pretty sure I'm using the latest code because I see the other changes you made like moving to remote_start on

G-Two commented 3 years ago

@mconlow yep, you're running the latest. Could you start a new interactive session and run remote_start show and paste the response please? It should display what the Subaru API thinks your current settings are. I'll keep digging through the Android App to see if I missed anything. We may need you to try activating remote start from a web browser and monitoring the transaction to get to the ground truth. But first, let's see what remote_start show tells us.

mconlow commented 3 years ago

Here it is. I know what you're asking on the web browser so I can take a look at that shortly

2020-07-22 19:56:06,069 - subarulink.connection - DEBUG - GET: https://mobileapi.prod.subarucs.com/g2v15//service/g2/remoteEngineStart/fetch.json 2020-07-22 19:56:06,156 - subarulink.controller - DEBUG - {'success': True, 'errorCode': None, 'dataName': None, 'data': '{"climateZoneFrontTemp": "71", "climateZoneFrontAirMode": "AUTO", "climateZoneFrontAirVolume": "AUTO", "heatedSeatFrontLeft": "OFF", "heatedSeatFrontRight": "OFF", "heatedRearWindowActive": "false", "outerAirCirculation": "recirculation", "airConditionOn": "true", "climateSettings": "climateSettings", "startConfiguration": "START_ENGINE_ALLOW_KEY_IN_IGNITION"}'} 2020-07-22 19:56:06,157 - subarulink - INFO - Fetching data for ***... {'airConditionOn': 'true', 'climateSettings': 'climateSettings', 'climateZoneFrontAirMode': 'AUTO', 'climateZoneFrontAirVolume': 'AUTO', 'climateZoneFrontTemp': '71', 'heatedRearWindowActive': 'false', 'heatedSeatFrontLeft': 'OFF', 'heatedSeatFrontRight': 'OFF', 'outerAirCirculation': 'recirculation', 'startConfiguration': 'START_ENGINE_ALLOW_KEY_IN_IGNITION'}

mconlow commented 3 years ago

here is the request payload from the web app execute.json request.

now=1595462444482&pin=****&delay=0&horn=true&unlockDoorType=FRONT_LEFT_DOOR_CMD&climateZoneFrontTemp=71&climateZoneFrontAirMode=AUTO&climateZoneFrontAirVolume=AUTO&heatedSeatFrontLeft=OFF&heatedSeatFrontRight=OFF&heatedRearWindowActive=false&outerAirCirculation=recirculation&airConditionOn=true&climateSettings=climateSettings&startConfiguration=START_ENGINE_ALLOW_KEY_IN_IGNITION&runTimeMinutes=10

on the 7th status.json request it came back true

G-Two commented 3 years ago

hmm...when I refactored remote_start() in the latest revision, it looks like I forgot to keep runTimeMinutes as a parameter. I just put it back now (keeping it hardcoded to 10 minutes since that is what the Android app has).

I think the horn=true and unlockDoorType=FRONT_LEFT_DOOR_CMD only happens with the browser based requests for remote start, so I'll leave them out for now unless we start running out of ideas.

stboch commented 3 years ago

@G-Two Ok just tested the changes you made, looks good. I noticed did the startConfiguration come down as part of the enginestart settings?

mconlow commented 3 years ago

worked!! Even when you know how they work, these things always feel a little bit like magic.

Are you planning to push to PyPI soon? Or should I just pull code from the repo for now?

G-Two commented 3 years ago

@mconlow awesome! Thanks for testing and helping to get this working. I'll push to PyPI as this is a significant set of fixes. You should be able to install subarulink==0.3.3 now.

G-Two commented 3 years ago

@stboch yes, the startConfiguration comes down as part of the enginestart settings from fetch.json. Thanks for your help in resolving this issue!