Ugh, blijkbaar toch niet helemaal ... client_id heb ik gevonden. In de APK 3.1.4 vind ik oaut_* waaronder oaut_client_id. Maar helaas geen oauth_client_secret, zelfs in die file niets met secret. Ik heb ook 3.0.2 en 3.0.1 en een paar 2.9.x versies geprobeerd maar nothing doin'
Ik gebruikt jadx-gui en bij een global search begint die eerst te decompilen.
De mitm-proxy methode heb ik geprobeerd maar daarvoor zou ik mijn telefoon moeten rooten. Ook zoals eerder gezegd krijg ik de app niet meteen aan de praat op mijn macbook om dan een mitm-proxy op te zetten.
Toegang krijgen tot de OMNI API
-
- Pro
- Berichten: 64
- Lid geworden op: 30 nov 2020, 23:32
- Merk SP: Stromer ST3 2019
Je kunt de client_secret nog steeds vinden als je APK 2.9.11 gebruikt, zoek op 'https://api3.stromer-portal.ch/'. Maar ik heb net het script voor HA ook geüpdate op basis van onderstaande, dus misschien kun je die testen, zie helemaal onderaan in deze post.buco schreef: ↑10 feb 2022, 07:09 Ugh, blijkbaar toch niet helemaal ... client_id heb ik gevonden. In de APK 3.1.4 vind ik oaut_* waaronder oaut_client_id. Maar helaas geen oauth_client_secret, zelfs in die file niets met secret. Ik heb ook 3.0.2 en 3.0.1 en een paar 2.9.x versies geprobeerd maar nothing doin'
Ik gebruikt jadx-gui en bij een global search begint die eerst te decompilen.
De mitm-proxy methode heb ik geprobeerd maar daarvoor zou ik mijn telefoon moeten rooten. Ook zoals eerder gezegd krijg ik de app niet meteen aan de praat op mijn macbook om dan een mitm-proxy op te zetten.
Dank je wel voor de info, ik heb het verwerkt in het python script en het werkt perfect! Hierbij voor de geïnteresseerden, je hebt dus enkel je 'client_id' meer nodig:Arjannv schreef: ↑25 nov 2021, 15:43 OK, hebbes
Met de MITM proxy heb ik de volgende URLs achterhaald:
In de get_code functie wordt het:In de get_code functie moet de POST array "data->next" ook iets aangepast worden naar:Code: Selecteer alles
https://stromer-portal.ch/mobile/v4/login/
In de get_access_token functie:Code: Selecteer alles
"next": "/mobile/v4/o/authorize/?" + qs
In de get_access_token functie moet de "params" array ook iets anders:Code: Selecteer alles
https://stromer-portal.ch/mobile/v4/o/token/
In de call_api functie:Code: Selecteer alles
params = { "grant_type": "authorization_code", "client_id": client_id, "code": code, "redirect_uri": "stromer://auth", }
De "client_id" is trouwens ook veranderd (beginnend met 4P). De andere, "client_secret" wordt nergens meer gebruikt.Code: Selecteer alles
"https://api3.stromer-portal.ch/rapi/mobile/v4.1/%s" % endpoint
Ik heb 'm trouwens nog niet geprobeerd, omdat alles bij mij nog werkt.
Code: Selecteer alles
#!/usr/bin/env python3
import requests
from urllib.parse import urlencode, parse_qs, splitquery
from datetime import datetime
import json
password = "VUL IN"
username = "VUL IN"
client_id = "HAAL UIT DECOMPILED APK"
def get_code(client_id, username, password):
url = "https://stromer-portal.ch/mobile/v4/login/"
s = requests.session()
res = s.get(url)
s.cookies
qs = urlencode(
{
"client_id": client_id,
"response_type": "code",
"redirect_url": "stromerauth://auth",
"scope": "bikeposition bikestatus bikeconfiguration bikelock biketheft bikedata bikepin bikeblink userprofile",
}
)
data = {
"password": password,
"username": username,
"csrfmiddlewaretoken": s.cookies.get("csrftoken"),
"next": "/mobile/v4/o/authorize/?" + qs
}
res = s.post(url, data=data, headers=dict(Referer=url), allow_redirects=False)
res = s.send(res.next, allow_redirects=False)
_, qs = splitquery(res.headers["Location"])
code = parse_qs(qs)["code"][0]
return code
def get_access_token(client_id, code):
url = "https://stromer-portal.ch/mobile/v4/o/token/"
params = {
"grant_type": "authorization_code",
"client_id": client_id,
"code": code,
"redirect_uri": "stromer://auth",
}
res = requests.post(url, params=params)
return res.json()["access_token"]
def call_api(access_token, endpoint, params={}):
url = "https://api3.stromer-portal.ch/rapi/mobile/v4.1/%s" % endpoint
headers = {"Authorization": "Bearer %s" % access_token}
res = requests.get(url, headers=headers, params={})
data = res.json()["data"]
if isinstance(data, list):
return data[0]
else:
return data
def call_bike(access_token, bike, endpoint, cached = "true"):
endpoint = 'bike/%s/%s' % (bike["bikeid"], endpoint)
params = {'cached':'%s' % cached}
state = call_api(access_token, endpoint, params)
return state;
code = get_code(client_id, username, password)
access_token = get_access_token(client_id, code)
bike = call_api(access_token, "bike")
print('bike:', json.dumps(bike, indent=True))
state = call_bike(access_token, bike, 'state/')
print('state:', json.dumps(state, indent=True))
position = call_bike(access_token, bike, 'position/')
print('position:', json.dumps(position, indent=True))
Code: Selecteer alles
#!/usr/bin/env python3
import requests
from urllib.parse import urlencode, parse_qs, splitquery
from datetime import datetime
import json
import time
import appdaemon.plugins.hass.hassapi as hass
#
# Stromer app
#
password = "VUL IN "
username = "VUL IN"
client_id = "HAAL UIT DECOMPILED APK"
class stromer(hass.Hass):
def initialize(self):
starttime=time.time()
while True:
try:
def get_code(client_id, username, password):
MAX_RETRIES = 20 #!Added https://stackoverflow.com/questions/33895739/python-requests-module-error-cant-load-any-url-remote-end-closed-connection
session = requests.Session()
adapter = requests.adapters.HTTPAdapter(max_retries=MAX_RETRIES)
session.mount('https://', adapter)
session.mount('http://', adapter)
url = "https://stromer-portal.ch/mobile/v4/login/"
s = requests.session()
res = s.get(url)
s.cookies
qs = urlencode({
"client_id":
client_id,
"response_type":
"code",
"redirect_url":
"stromerauth://auth",
"scope":
"bikeposition bikestatus bikeconfiguration bikelock biketheft bikedata bikepin bikeblink userprofile",
})
data = {
"password": password,
"username": username,
"csrfmiddlewaretoken": s.cookies.get("csrftoken"),
"next": "/mobile/v4/o/authorize/?" + qs
}
res = s.post(url, data=data, headers=dict(Referer=url), allow_redirects=False)
res = s.send(res.next, allow_redirects=False)
_, qs = splitquery(res.headers["Location"])
code = parse_qs(qs)["code"][0]
return code
def get_access_token(client_id, code):
url = "https://stromer-portal.ch/mobile/v4/o/token/"
params = {
"grant_type": "authorization_code",
"client_id": client_id,
"code": code,
"redirect_uri": "stromer://auth",
}
res = requests.post(url, params=params)
return res.json()["access_token"]
def call_api(access_token, endpoint, params={}):
url = "https://api3.stromer-portal.ch/rapi/mobile/v4.1/%s" % endpoint
headers = {"Authorization": "Bearer %s" % access_token}
res = requests.get(url, headers=headers, params={})
data = res.json()["data"]
if isinstance(data, list):
return data[0]
else:
return data
def call_bike(access_token, bike, endpoint, cached="false"):
endpoint = 'bike/%s/%s' % (bike["bikeid"], endpoint)
params = {'cached': '%s' % cached}
state = call_api(access_token, endpoint, params)
return state
code = get_code(client_id, username, password)
access_token = get_access_token(client_id, code)
bike = call_api(access_token, "bike")
state = call_bike(access_token, bike, 'state/')
position = call_bike(access_token, bike, 'position/')
self.set_state("sensor.stromer_current_speed", state = state['bike_speed'])
self.set_state("sensor.stromer_trip_distance", state = state['trip_distance'])
self.set_state("sensor.stromer_avg_speed_trip", state = state['average_speed_trip'])
self.set_state("sensor.stromer_triptime", state = state['trip_time'])
self.set_state("sensor.stromer_battery_chargelevel", state = state['battery_SOC'])
self.set_state("sensor.stromer_lockstate", state = state['lock_flag'])
self.set_state("sensor.stromer_geocoded_location", state = '', attributes = {"altitude": position['altitude'], "latitude": position['latitude'], "longitude": position['longitude'], "icon": 'mdi:map'})
self.set_state("sensor.stromer_batterytemp", state = state['battery_temp'])
self.set_state("sensor.stromer_motortemp", state = state['motor_temp'])
self.set_state("sensor.stromer_battery_healthstate", state = state['battery_health'])
self.set_state("sensor.stromer_battery_poweron_cycles", state = state['power_on_cycles'])
self.set_state("sensor.stromer_totaldistance", state = state['total_distance'])
self.set_state("sensor.stromer_totaltime", state = state['total_time'])
self.set_state("sensor.stromer_avg_energy", state = state['average_energy_consumption'])
self.set_state("sensor.stromer_softwareversion", state = state['suiversion'])
self.set_state("sensor.stromer_lastupdated", state = state['rcvts'])
self.log("Omni data bijgewerkt")
time.sleep(60)
except Exception:
self.log("ERROR")
time.sleep(300)
continue
Excuses allen, al tijden niet op het forum geweest maar wel aan de slag geweest met Stromer en Home Assistant (ik was mijn losse scripts en zooi zat):
Mocht je avontuurlijk zijn, je API keys al hebben achterhaald en daarmee relatief makkelijk je Stromer in Home Assistant willen hebben: via HACS kun je nu https://github.com/CoMPaTech/stromer gemakkelijk toevoegen als custom_component
Mocht je avontuurlijk zijn, je API keys al hebben achterhaald en daarmee relatief makkelijk je Stromer in Home Assistant willen hebben: via HACS kun je nu https://github.com/CoMPaTech/stromer gemakkelijk toevoegen als custom_component
ST2-Wit, standaard, SP-houder, Ortlieb Office, Cratoni Commuter Geen extra toeters, wel een extra bel!
Commute: ~35km midden NL - ruwweg Vianen <-> Geldermalsen - FM: Die uit de Betuwe
Commute: ~35km midden NL - ruwweg Vianen <-> Geldermalsen - FM: Die uit de Betuwe
Ik heb op basis van jullie feedback diverse zaken aangepast, inclusief de v4 approach (kindly borrowed from @SirJohnDoe's post above) waarbij je het client secret niet meer nodig hebt + voorbeelden hoe je sneller dan de default gezette 10 minuten updates op kunt halen. Zie https://github.com/compatech/stromer voor meer informatie
ST2-Wit, standaard, SP-houder, Ortlieb Office, Cratoni Commuter Geen extra toeters, wel een extra bel!
Commute: ~35km midden NL - ruwweg Vianen <-> Geldermalsen - FM: Die uit de Betuwe
Commute: ~35km midden NL - ruwweg Vianen <-> Geldermalsen - FM: Die uit de Betuwe
-
- Rookie
- Berichten: 4
- Lid geworden op: 01 mei 2022, 12:28
- Locatie: Tilburg
- Merk SP: Stromer ST3
- Km-stand: 5000
Heeft iemand een overzicht van de endpoints die door de API worden ondersteund? In het begin van deze thread worden er meerdere genoemd die niet (meer) ondersteund worden. Naast bike, state, en position lijken er geen anderen te worden ondersteund.
-
- Rookie
- Berichten: 4
- Lid geworden op: 01 mei 2022, 12:28
- Locatie: Tilburg
- Merk SP: Stromer ST3
- Km-stand: 5000
Voor degenen die het interessant vinden heb ik een volledige python package geschreven welke op PyPi beschikbaar is.
Zie https://pypi.org/project/stromer-api/1.0/
Zie https://pypi.org/project/stromer-api/1.0/
Hoi mede Stromers,
ik lees al even dit topic mee omdat ik ook heel graag mijn Home Assistant wil uitbreiden met de data van mn ST1x.. Ik ben alleen geen hardcore techneut en loop dus al even vast bij het achterhalen van de clientID op mn macbook (in combi met de app op mn iPhone).
Ik heb MITM geinstalleerd en zie op zich wel data voorbij komen, maar ik weet niet zo goed waar ik moet kijken...:-)
Is er iemand die me een klein duwtje in de goeie richting zou willen geven??
Thanks in advance!
ik lees al even dit topic mee omdat ik ook heel graag mijn Home Assistant wil uitbreiden met de data van mn ST1x.. Ik ben alleen geen hardcore techneut en loop dus al even vast bij het achterhalen van de clientID op mn macbook (in combi met de app op mn iPhone).
Ik heb MITM geinstalleerd en zie op zich wel data voorbij komen, maar ik weet niet zo goed waar ik moet kijken...:-)
Is er iemand die me een klein duwtje in de goeie richting zou willen geven??
Thanks in advance!
FWIW; ben een flinke tijd aan het puzzelen geweest, vooral om veel info aan de oude kant was. Het is me uiteindelijk gelukt.
De weg via mitmproxy (of andere sniffers) werkt niet meer, omdat de app z'n client_id en secret niet meer via de requests lijkt door te geven.
Anyway, samengevat:
Doel was om m'n nieuwe ST3 (Yay!) in Home-Assistant te krijgen met de erg mooie integratie van gebruiker @s-EVE. (Thanks!)
Stappen:
- Via FX-File Explorer de APK geexporteerd en op m'n PC gezet.
- Met APKToolGUI alle bestanden uitgepakt.
- Notepad++ gebruikt (Search->Find in Files) om de oauth_client_id te vinden, deze staat bij mij in res\values\strings.xml.
Met de username, password en deze client_id lukt het me dan om de HA-Integratie aan de praat te krijgen.
De weg via mitmproxy (of andere sniffers) werkt niet meer, omdat de app z'n client_id en secret niet meer via de requests lijkt door te geven.
Anyway, samengevat:
Doel was om m'n nieuwe ST3 (Yay!) in Home-Assistant te krijgen met de erg mooie integratie van gebruiker @s-EVE. (Thanks!)
Stappen:
- Via FX-File Explorer de APK geexporteerd en op m'n PC gezet.
- Met APKToolGUI alle bestanden uitgepakt.
- Notepad++ gebruikt (Search->Find in Files) om de oauth_client_id te vinden, deze staat bij mij in res\values\strings.xml.
Met de username, password en deze client_id lukt het me dan om de HA-Integratie aan de praat te krijgen.