Toegang krijgen tot de OMNI API
Toegang krijgen tot de OMNI API
[Discussie over het verkrijgen van toegang tot de OMNI API afgesplitst naar een eigen topic. Stromeur.]
Dat stromer geen API vrijgeeft betekent opzich niet dat er niks mee te doen is. Met behulp van een stukje software (mitmproxy) kan je het verkeer tussen de app en stromer service afluisteren en dus de functionaliteiten die de app bevat zelf nuttig gebruiken. Als ik begin April mijn Stromer krijg heb ik in ieder geval een leuk projectje.
Dat stromer geen API vrijgeeft betekent opzich niet dat er niks mee te doen is. Met behulp van een stukje software (mitmproxy) kan je het verkeer tussen de app en stromer service afluisteren en dus de functionaliteiten die de app bevat zelf nuttig gebruiken. Als ik begin April mijn Stromer krijg heb ik in ieder geval een leuk projectje.
Bodyfloat
- Stromeur
- Admin | Forum Supporter
- Berichten: 13860
- Lid geworden op: 15 mei 2017, 20:18
- Locatie: Friesland
- Merk SP: Stromer ST2 S
- Km-stand: 7.000
Re: Nieuwe Stromer OMNI technologie 2018: OMNI Connect
Zeker! Open daar tegen die tijd gerust een topic over als je zin hebt om je ervaringen hiermee te delen.
Stromer ST2 S 2017
Re: Nieuwe Stromer OMNI technologie 2018: OMNI Connect
Vandaag eens in de api van Stromer gedoken. Via deze url loopt de verbinding https://api3.stromer-portal.ch/rapi/mobile/v2/bike/ krijg alleen de authenticatie nog niet goed buiten de app.
Waar ik al wel uit ben is dat er geen actuele gps data via de api te vinden is. De omni stuurt dus niet zo vaak een gps update naar de cloud.
ik kwam wel data tegen die niet in de app terug te vinden is zoals:
"atmospheric_pressure": 10370,
"average_energy_consumption": 109,
"power_on_cycles": 34,
Nummers van onderdelen. Naast de display, controller en motor ook een serie nr van de fork.
Al met al niet heel interessant om verder naar te kijken. De beveiliging ziet er wel goed uit dus wat dat betreft ben ik tevreden
Waar ik al wel uit ben is dat er geen actuele gps data via de api te vinden is. De omni stuurt dus niet zo vaak een gps update naar de cloud.
ik kwam wel data tegen die niet in de app terug te vinden is zoals:
"atmospheric_pressure": 10370,
"average_energy_consumption": 109,
"power_on_cycles": 34,
Nummers van onderdelen. Naast de display, controller en motor ook een serie nr van de fork.
Al met al niet heel interessant om verder naar te kijken. De beveiliging ziet er wel goed uit dus wat dat betreft ben ik tevreden

Bodyfloat
- Stromeur
- Admin | Forum Supporter
- Berichten: 13860
- Lid geworden op: 15 mei 2017, 20:18
- Locatie: Friesland
- Merk SP: Stromer ST2 S
- Km-stand: 7.000
Re: Nieuwe Stromer OMNI technologie 2018: OMNI Connect
Ik kan echt niet wat jij kunt, dus ik ben diep onder de indruk. Ik zou die URL nog niet eens gevonden hebben. Hoe kom ik bijvoorbeeld in de API van mijn eigen Stromer?
Mocht je nog meer van dit soort boeiende informatie tegen komen, shoot!
Mocht je nog meer van dit soort boeiende informatie tegen komen, shoot!
Stromer ST2 S 2017
- FreddyH
- Veteraan | Forum Supporter
- Berichten: 5234
- Lid geworden op: 24 jan 2018, 17:46
- Locatie: regio Eindhoven
- Merk SP: Bulls Green Mover E45
Re: Nieuwe Stromer OMNI technologie 2018: OMNI Connect
Kan je met een netwerk-sniffer een session id of zo achterhalen?joost schreef: ↑08 jul 2018, 22:26Vandaag eens in de api van Stromer gedoken. Via deze url loopt de verbinding https://api3.stromer-portal.ch/rapi/mobile/v2/bike/ krijg alleen de authenticatie nog niet goed buiten de app.
I intend to live forever, or die trying.
(Groucho Marx)
(Groucho Marx)
Re: Nieuwe Stromer OMNI technologie 2018: OMNI Connect
@FreddyH ik heb mitmproxy gebruikt. Mijn iPhone verbind direct met deze proxy en dan zie ik al het verkeer dat over de lijn gaat.
Op deze pagina kom je in de app https://api3.stromer-portal.ch/users/login/
Naast je credentials heb je ook nog een client_id nodig (die heb ik) alleen na de submit wordt je naar de app geredirect.
https://api3.stromer-portal.ch/users/lo ... nt_id=JEID
redirect_uri al wel aangepast naar api3.stromer-portal.ch maar dat gaat niet goed. Wellicht dat iemand de android apk eens kan uitpakken en zien wat daar gebeurd.
Op deze pagina kom je in de app https://api3.stromer-portal.ch/users/login/
Naast je credentials heb je ook nog een client_id nodig (die heb ik) alleen na de submit wordt je naar de app geredirect.
https://api3.stromer-portal.ch/users/lo ... nt_id=JEID
redirect_uri al wel aangepast naar api3.stromer-portal.ch maar dat gaat niet goed. Wellicht dat iemand de android apk eens kan uitpakken en zien wat daar gebeurd.
Bodyfloat
- FreddyH
- Veteraan | Forum Supporter
- Berichten: 5234
- Lid geworden op: 24 jan 2018, 17:46
- Locatie: regio Eindhoven
- Merk SP: Bulls Green Mover E45
Re: Toegang krijgen tot de OMNI API
Je bent alweer een stapje verder. Ik zou graag ook een keer gaan hacken, maar heb zelf geen Stromer dus dat gaat hem niet worden... Wellicht weer een keer een paar dagen een 'proefrit' maken 
Die Android APK uitpakken kun je zelf natuurlijk ook. Moet ik deze downloaden en naar je toe sturen?

Die Android APK uitpakken kun je zelf natuurlijk ook. Moet ik deze downloaden en naar je toe sturen?
I intend to live forever, or die trying.
(Groucho Marx)
(Groucho Marx)
Re: Toegang krijgen tot de OMNI API
Ik heb het inmiddels even uitgezocht met een beetje python code:
Ik weet niet of ik die client_id en client_secret zo mag posten, maar zijn zijn heel gemakkelijk uit de APK te halen (of door een MITM op de app). Ik ga dit gebruiken om een tooltje te maken dat verifieert dat de fiets goed wordt opgeladen. Ik heb heel soms dat ie na een uurtje ofzo stopt met opladen en dan kom ik bijna niet meer thuis. Straks checkt ie dat gewoon ieder kwartier: staat de fiets bij mijn werk en is de batterij niet aan het opladen ==> stuur een mailtje
Code: Selecteer alles
import requests
from IPython.display import HTML
from urllib.parse import urlencode, parse_qs, splitquery
password = 'xxx'
username = 'xxx'
client_id = 'xxxxxxx'
client_secret = 'xxxxxxxxxxxxx'
def get_code(client_id, username, password):
url = "https://api3.stromer-portal.ch/users/login/"
s = requests.session()
res = s.get(url)
HTML(res.text)
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": "/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, client_secret, code):
url = "https://api3.stromer-portal.ch//o/token/"
params = {
"grant_type": "authorization_code",
"client_id": client_id,
"client_secret": client_secret,
"code": code,
"redirect_uri": "stromerauth://auth",
}
res = requests.post(url, params=params)
return res.json()["access_token"]
def call_api(access_token, endpoint, params={}):
url = f"https://api3.stromer-portal.ch/rapi/mobile/v2/{endpoint}"
headers = {"Authorization": f"Bearer {access_token}"}
res = requests.get(url, headers=headers, params={})
return res.json()["data"][0]
Code: Selecteer alles
import json
endpoint="bike/"
bike = call_api(access_token, endpoint)
print('bike:', json.dumps(bike, indent=True))
bike = call_api(access_token, endpoint="bike/")
endpoint = f'bike/{bike["bikeid"]}/state/'
params = {'cached':'false'}
state = call_api(access_token, endpoint, params)
print('state:', json.dumps(state, indent=True))
bike: {
"bikeid": ***,
"biketype": "ST2",
"color": "silver",
"hardware": "omniinterface",
"bikemodel": "ST2",
"nickname": "***",
"size": "sport 20"
}
state: {
"battery_SOC": 40,
"suiversion": "3.4.2.1",
"bike_speed": 0.0,
"tntversion": "3.5",
"trip_time": 81401,
"light_on": 255,
"average_speed_trip": 34.9,
"trip_distance": 788.5,
"average_speed_total": 34.1,
"motor_temp": 16.0,
"average_energy_consumption": 141,
"power_on_cycles": 670,
"total_time": 318409,
"atmospheric_pressure": 0,
"battery_temp": 24.0,
"battery_health": 95,
"total_distance": 3013.6,
"assistance_level": 0,
"rcvts": 1538643543,
"theft_flag": false,
"lock_flag": true,
"total_energy_consumption": 42594
}
ST2 2016 - 983wh
Re: Toegang krijgen tot de OMNI API
Knap gedaan
Met die informatie ontstaan er best wat leuke mogelijkheden.

Met die informatie ontstaan er best wat leuke mogelijkheden.
ST3 Deep Black XL 983 Wh | Stuur 20mm rise & 20° backsweep | Thudbuster ST
Woon-werk & Stroomverbruikoverzicht
Woon-werk & Stroomverbruikoverzicht
Re: Toegang krijgen tot de OMNI API
Met dank aan @merstro heb ik een portje naar NodeJS gemaakt:
Code: Selecteer alles
const request = require("request-promise");
const qs = require("qs");
const cheerio = require("cheerio");
class Stromer {
constructor(options) {
this.client_id = options.client_id;
this.client_secret = options.client_secret;
this.username = options.username;
this.password = options.password;
this.jar = request.jar();
this.LOGIN_URL = "https://api3.stromer-portal.ch/users/login/";
this.TOKEN_URL = "https://api3.stromer-portal.ch/o/token/";
this.API_URL = "https://api3.stromer-portal.ch/rapi/mobile/v2/";
}
async getCode() {
const loginPage = await request({
url: this.LOGIN_URL,
jar: this.jar
});
const cookies = this.jar.getCookieString(this.LOGIN_URL);
const [_, csrf] = cookies.split("=");
const queryString = qs.stringify({
client_id: this.client_id,
response_type: "code",
redirect_url: "stromerauth://auth",
scope:
"bikeposition bikestatus bikeconfiguration bikelock biketheft bikedata bikepin bikeblink userprofile"
});
const $ = cheerio.load(loginPage);
const formCsrf = $("input[name=csrfmiddlewaretoken]").val();
const form = {
username: this.username,
password: this.password,
csrfmiddlewaretoken: formCsrf,
next: `/o/authorize/?${queryString}`
};
let code = "";
try {
const redirect = await request({
url: this.LOGIN_URL,
method: "post",
form,
jar: this.jar,
followRedirect: false,
headers: {
Referer: this.LOGIN_URL
}
});
} catch (e) {
try {
const authorize = await request({
url: "https://api3.stromer-portal.ch" + e.response.headers.location,
followRedirect: false,
jar: this.jar
});
} catch (e) {
const location = e.response.headers.location;
const [_, code] = location.split("=");
return code;
}
}
}
async getAccessToken(code) {
const data = {
grant_type: "authorization_code",
client_id: this.client_id,
client_secret: this.client_secret,
code,
redirect_uri: "stromerauth://auth"
};
const json = await request({
url: this.TOKEN_URL,
method: "post",
formData: data,
jar: this.jar
});
return JSON.parse(json).access_token;
}
async call(endpoint) {
if (this.accessToken) {
return await this._callApi(this.accessToken, endpoint);
} else {
const code = await this.getCode();
this.accessToken = await this.getAccessToken(code);
if (this.accessToken) {
return await this._callApi(this.accessToken, endpoint);
} else {
throw new Error("No access token could be retrieved");
}
}
}
async _callApi(access_token, endpoint) {
const response = await request({
url: `${this.API_URL}${endpoint}`,
headers: { Authorization: `Bearer ${access_token}` }
});
return JSON.parse(response).data;
}
}
Code: Selecteer alles
const test = new Stromer({
username: "xxxxx",
password: "xxxxxx",
client_id: "xxxxxxx",
client_secret: "xxxxxxx"
});
test.call("bike").then(c => console.log(c));