Tutorial On How To Start a Vehicle Engine With Google Assistant Help!
The future is getting closer. About 10 years ago I could not think that I would start a car with the help of a voice command!
In recent years, I have watched with interest the rapid development of voice assistants. After the release of Google Home Mini, I decided that it was time for me to try, as the price became more or less adequate for the “toy”. The first project is the integration of the voice assistant with the GSM module Starline for autorun, coordinate control, voltage and other parameters given by the car alarm system.
You do not need to have Google Home, as described in the Google Assistant section of your phone. I have installed the GSM / GPS module Starline M31 but should work with all GSM alarms from StarLine.
General scheme of the application for Google Assistant
- Google Home / Google Assistant is responsible for converting voice to text and vice versa + interaction with standard Google services. When you call our application, Action in Google’s terminology, requests are passed to dialog flow (API.AI in the diagram).
- DialogFlow – is responsible for defining the dialogue scheme, processing the text of natural language queries, highlighting entities, generating responses and interacting with the outside world by calling WebHook as needed.
- WebHook – WEB-service for interaction with the outside world. The input is a branch of the dialog (Intent) + parameters extracted from the query (Entities). The output is the answer to the user.
1. DialogFlow.com
First of all, we need to create an agent on dialog flow (former API.AI).
We register using Google account to which we will be linked Google Home.
Select the language that more appropriate to you, in our case we choose English.
Next, we need to create intentions. The intention in the terminology of dialog flow is one of the branches of the dialogue responsible for the definition. In our case, this will be GetBattery, GetTemperature, StartEngine, StopEngine. Also, there is By default Intent, triggered at the very beginning, usually this is a greeting and a short story about what you can do with this application.
In each Intent, we need to specify examples of voice commands (the user says), preferably for 5-10 different options.
In all Intents, except for default, we need to send requests to your script (WebHook), so we put Execution – Use webhook.
2. WebHook to interact with the Starline server
We need a script that receives the Intent of the request from dialog flow and pulls the Starline commands. The quickest thing I did was to implement this in Python + Flask.
To run on the server I used gunicorn
gunicorn -b :3333 flask.starline:app
- + nginx as the reverse proxy.
- Please note, HTTPS is required!
Starline.py
from flask import Flask, request from flask_restful import reqparse, Resource, Api, abort import requests import logging DEVICE_ID = 1234567 # Use HTTPS sniffer to find your DEVICE_ID in https://starline-online.ru/ traffic LOGIN = 'YOUR_STARLINE_EMAIL' PASS = 'YOUR_STARLINE_PASSWORD' logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s') header = { 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest'} def start_engine(): with requests.Session() as session: t = session.get('https://starline-online.ru/', headers=header) login = session.post('https://starline-online.ru/user/login', { 'LoginForm[login]': LOGIN, 'LoginForm[pass]': PASS, 'LoginForm[rememberMe]': 'off'}, headers=header) logging.debug(login.content) r0 = session.get('https://starline-online.ru/device', headers=header) logging.debug(r0.content) r = session.post('https://starline-online.ru/device/{0}/executeCommand'.format(DEVICE_ID), { 'value': '1', 'action': 'ign', 'password': ''}, headers=header, timeout=1) logging.debug(r.status_code) logging.debug(r.content) logout = session.post('https://starline-online.ru/user/logout', { '': ''}, ) return ('Engine started!') def stop_engine(): with requests.Session() as session: t = session.get('https://starline-online.ru/', headers=header) login = session.post('https://starline-online.ru/user/login', { 'LoginForm[login]': LOGIN, 'LoginForm[pass]': PASS, 'LoginForm[rememberMe]': 'off'}, headers=header) logging.debug(login.content) r0 = session.get('https://starline-online.ru/device', headers=header) logging.debug(r0.content) r = session.post('https://starline-online.ru/device/{0}/executeCommand'.format(DEVICE_ID), { 'value': '0', 'action': 'ign', 'password': ''}, headers=header) logging.debug(r.status_code) logging.debug(r.content) logout = session.post('https://starline-online.ru/user/logout', { '': ''}, ) return ('Engine stopped!') def get_params(): with requests.Session() as session: t = session.get('https://starline-online.ru/', headers=header) login = session.post('https://starline-online.ru/user/login', { 'LoginForm[login]': LOGIN, 'LoginForm[pass]': PASS, 'LoginForm[rememberMe]': 'off'}, headers=header) logging.debug(login.content) r0 = session.get('https://starline-online.ru/device', headers=header) logging.debug(r0.content) res_dict = r0.json()['answer']['devices'][0] logout = session.post('https://starline-online.ru/user/logout', { '': ''}, ) return {'battery': res_dict['battery'], 'temperature': res_dict['ctemp']} def get_battery_text(): return ("Battery voltage {0} volts.".format(get_params()['battery'])) def get_temperature_text(): return ("Temperature: {0} degrees.".format(get_params()['temperature'])) app = Flask(__name__) app.config['BUNDLE_ERRORS'] = True api = Api(app) class ProccessGoogleRequest(Resource): def get(self): return {"status": "OK"} def post(self): req = request.get_json() logging.debug(request.get_json()) response = '' if req['result']['metadata']['intentName'] == 'GetBattery': response = get_battery_text() if req['result']['metadata']['intentName'] == 'GetTemperature': response = get_temperature_text() if req['result']['metadata']['intentName'] == 'StartEngine': response = start_engine() if req['result']['metadata']['intentName'] == 'StopEngine': response = stop_engine() if response == '': abort(400, message='Intent not detected') return {"speech": response, "displayText": response} api.add_resource(ProccessGoogleRequest, '/starline/') if __name__ == '__main__': app.run(debug=False)
3. We test in the simulator and on real equipment
For testing in DialogFlow go to Integrations -> Google Assistant -> INTEGRATION SETTINGS -> Test and get into the simulator Actions on Google
And here what it looks like in practice.
The only downside here is that in this version, it answers “Engine started” before the real start of the engine as it does not have time to wait for a response from Starline.
Ideas:
- Requesting a location from Google Assistant, scoring the distance to the machine (Starline knows how to give coordinates). While it is unclear how for WebHook in Python to request the location of Google Home.
- Simplify the integration of Google <-> Starline, then there will be no need for password hardcode. Without participation from Starline, as I understand, this is not possible.
Known Issues:
- Google Assistant does not wait to receive a response from the Starline server about the status of the engine start
- While testing you can use only the default application name (Invocation) – Hey Google, talk to my test app.