Er lijkt wel een soort vloek te rusten op de beschikbaarheid van mijn vrije tijd en dit project

. Ik zal daarom proberen hier alvast even het e.e.a. uiteen te zetten. Met een beetje handigheid kunnen jullie dat vervolgens wel in het platform naar keuze hangen, de voorbeelden die ik hieronder zal geven zullen java en JSON zijn.
Communicatie
Communicatie met de server is redelijk simpel, het is een JSON RPC-achtig protocol over een SSL (TLSv1.2) verbinding op port 9010. Voor zover ik heb kunnen zien is de server niet enorm strikt met certificaten en kun je door de client simpelweg alle certificaten te laten accepteren een TLSv1.2 verbinding op laten bouwen.
Java:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| //protocol = TLSv1.2
private static SSLSocketFactory createSocketFactory(String protocol) {
try {
logger.debug("[SSLContext][" + protocol + "] getting sslcontext instance...");
SSLContext instance = SSLContext.getInstance(protocol);
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
instance.init(null, trustAllCerts, new java.security.SecureRandom());
logger.debug("[SSLContext][" + protocol + "] Initiated instance");
return instance.getSocketFactory();
} catch (KeyManagementException | NoSuchAlgorithmException e) {
logger.error("[SSLContext][" + protocol + "] failed", e);
throw new RuntimeException(e);
}
} |
Het idee is om de verbinding eenmalig op te zetten en daarna open te houden. Middels RPC kan men dan interacteren met de server en doormiddel van topic-subscribe kan men op de hoogte blijven van events in het systeem.
JSON RPC Protocol
Voor het berichtenverkeer gebruikt OneSmart transactionele JSON request-response berichten. Minimaal bestaat een request uit een JSON object met een "cmd"- en een numeriek "transaction" veld. Afhankelijk van welk CMD je uit wil voeren kan het zijn dat er meer velden nodig zijn (het "action" veld wordt bijvoorbeeld veelal gebruikt i.c.m. "cmd"). Ik zal verderop een overzicht geven van de CMD's en bijhorende velden die ik tot nu toe heb ontdekt.
Een minimale request-response ziet er dan als volgt uit:
JavaScript:
1
| { "cmd"="<command>", "transaction"=<transaction_id> } |
De server geeft hierop een response met op zijn minst de velden "transaction" en "result"
JavaScript:
1
| { "transaction"=<transaction_id>,"result"={} } |
Op basis van de (zelf verzonnen) numerieke transaction_id (ik gebruik hier een thread-safe counter voor) van de request kun je de bijhorende response correleren op het moment van ontvangst. Je zal dus "open" transacties zelf moeten monitoren. Je kan op deze manier wel meerdere requests tegelijk doen zonder de afzonderlijke antwoorden steeds af te wachten.
Keep-Alive
Om de verbinding tussen client en server open te houden verwacht de server periodiek communicatie. Als deze uitblijft zat na verloop van tijd de server de verbinding verbreken. Om dat te voorkomen kan de client periodiek een ping request versturen om de verbinding open te houden.
JavaScript:
1
| {"cmd":"ping","transaction":12} |
De response:
JavaScript:
1
| { "cmd": "ping", "result": { }, "transaction": 12 } |
Login
Doorgaans het eerste bericht wat verstuurd word naar de server is om de sessie te autenticeren. Voor zover ik nu kan beoordelen geld deze authenticatie voor de duratie van de socket verbinding en vallen alle opvolgende requests op deze socket verbinding hieronder. Uitloggen lijkt dan ook simpelweg het verbreken van de verbinding.
JavaScript:
1
| { "cmd"="authenticate", "username"="<user>", "password"="<sha1:password>", "transaction"=<transaction_id> } |
De username is gelijk aan wat je in de app hebt ingesteld en het password is een sha1 hash van het bijhorende password
Response:
JavaScript:
1
| { "cmd": "authenticate", "transaction": <transaction_id>, "result": { } } |
Events
De onesmart server kent naast de RPC structuur ook een topic-subscribe structuur waarbij je doormiddel van "inschrijven" op een bepaald topic events vanuit de server kunt ontvangen en verwerken. Denk hierbij aan verbruik van de meters, het triggeren van een scene (ook via fysieke schakelaars), inloggen op de app, etc.
Inschrijven kan door het versturen van een request met cmd "events" en action "subscribe"
JavaScript:
1
| {"cmd":"events","action":"subscribe","topics":["SITE","AUTHENTICATION","DEVICE","ROOM","METER","PRESET","PRESETGROUP","TRIGGER","ROLE","USER","SITEPRESET","UPGRADE","MESSAGE","ENERGY"],"transaction":<transaction_id>} |
Hierna ontvang je periodiek (in het geval van meters), of op het moment van optreden (scenes, triggers, etc) events berichten op de socketverbinding.
Voorbeeld:
JavaScript:
1
| { "event": "energy_consumption", "data": { "values": [ { "id": "<meter_id_1>", "value": 8 }, { "id": "<meter_id_2>", "value": 116 }, { "id": "<meter_id_3>", "value": 27 }, { "id": "<meter_id_4>", "value": 216 }, { "id": "<meter_id_5>", "value": 386 }, { "id": "<meter_id_6>", "value": 4 }, { "id": "<meter_id_7>", "value": 738 }, { "id": "<meter_id_8>", "value": -595 }, { "id": "<meter_id_9>", "value": 444 } ] } } |
De meter id's die in dit event terug komen zijn weer te vinden met het cmd: "meter" met action: "list". Dit gaat in principe op voor alle events.
Commands
Hieronder een samenvatting van de requests die ik tot nu toe heb ontdekt. De meeste (list commands) doe je eenmalig om een beeld te vormen van het systeem en om latere device of preset id's in events of triggeres te kunnen correleren.
cmd | action | extra velden | omschrijving |
---|
ping | - | - | Keep-Alive |
authenticate | - |
username | text | Gebruikersnaam uit de app | password | text:sha1 | Wachtwoord bij gebruiker uit de app |
| Autenticeren user op socket verbinding |
site | get | - | Ophalen site details |
user | get |
username | text | Gebruikersnaam uit de app |
| Ophalen gebruiker details |
room | list | - | Ophalen lijst rooms |
preset | list | - | Ophalen lijst presets |
meter | list | - | Ophalen lijst meters |
presetgroup | list | - | Ophalen lijst presetgroups |
device | list | - | Ophalen lijst devices |
preset | perform |
id | text | Preset ID | force | boolean | Force perform (?) |
| Uitvoeren preset via ID |
Ik denk dat dit een aardig inzicht geeft in het OneSmart protocol en de werking daarvan. Ik zal vast het een en ander over het hoofd gezien hebben, dus mocht er verduidelijking nodig zijn laat het maar weten!