IoT kategória bejegyzései

BKK Futár Microsoft Bandre – service és webtile (3. rész)

A Microsoft Band programozási lehetőségeinek és a BKK Futár API-jának a megismerése után el kellett döntenem, hogyan is szeretnék menetrendi adatokat megjeleníteni a Banden. Végül a webtile mellett döntöttem, leginkább azért, mert az SDK-s megoldás egy folyamatosan futó mobil alkalmazást igényelt volna.

A webtile korlátja, hogy sajnos nem tudjuk befolyásolni, mikor frissüljön, ezért nem álmodozhatunk olyan megoldásról, ami relatív időpontokat használ. Le kell tehát mondanunk a “3 perc múlva indul” stílusú, azonnal érthető megjelenítésről, helyette abszolút időpontokat használhatunk, azaz például “indulás 11:23-kor”. Ez nem annyira szép, de nem óriási probléma, hiszen a Band elsődleges képernyője (Me Tile) mindig a pontos időt mutatja, egy ilyen bonyolult kivonást pedig rá merek bízni a felhasználóra.

A nagyobb probléma, hogy ezzel megszűnik a “következő indulás” fogalma, hiszen a frissítési időközön belül akár több indulás is lehet, és előfordulhat, hogy egy vagy több már múltbeli lesz, mikor a felhasználó rápillant a csempére. Erre nem tudtam jobb megoldást kitalálni, mint hogy több indulási időpontot jelenítek meg, amiből majd a felhasználó némi humán komparálással kiválasztja, hogy melyik a legközelebbi. Egyébként is terveztem, hogy célszerű lenne több időpontot megmutatni, hiszen előfordulhat, hogy a nem a következő buszt, hanem csak a következő utánit szeretném elérni, mert túl messze van a megálló. A sajnálatos szépséghiba, hogy a listában jó eséllyel lesz múltbeli időpont is.

Az adatforrás

A leendő webtile-t természetesen el kell látni adatokkal, azaz szükséges hozzá egy GET-en elérhető szerviz. Bár ahogy az előző részben láttuk, létezik BKK Futár API, az sajnos nem tudja az adatokat pont olyan formában szolgáltatni, amire nekünk szükségünk van. Az eltérések:

  • A Futár API az indulási időpontokat epochtól eltelt másodpercben adja meg, azaz egy bazi nagy, igen barátságtalan számként. Ezt sajnos a webtile nem tudja emberileg fogyasztható formátumra konvertálni.
  • Az API-ban van predictedArrivalTime, arrivalTime és departureTime mező is, és változó, hogy mikor melyik van kitöltve, vagy melyiket érdemes használni. Dokumentáció híján csak tippelni tudok, melyik mit jelent, de a tapasztalat az, hogy a predicted csak a már közeledő járműveknél van kitöltve (tipikusan a következő vagy esetleg a következő kettő), és ez a legpontosabb. A sima arrivalTime szinte mindig ki van töltve, kivéve végállomásoknál, ahol csak a departureTime jelenik meg.
  • Az API hívás sikerességét nem (vagy nem csak?) a HTTP status code, hanem a HTTP válaszban lévő több mező értéke együttesen írja le, amit webtile esetén nem tudunk vizsgálni.
  • A Futár API-tól a következő indulások objektum tömbként kérhetők le, azonban egyik lehetséges webtile layout sem tudja azokat praktikusan megjeleníteni. Sokkal jobb lenne egy vesszővel elválasztott string, például “10:45, 10:56, 11:07”, de ilyen adat átalakításra a webtile nem képes.

Ezen problémák miatt végül úgy döntöttem, hogy készítek egy saját webszervizt, ami adatokkal fogja táplálni Bandit. Tekintve, hogy viszonylag primitív logikáról van szó, ellenben van benne JSON matatás rendesen, és mostanában elsősorban JavaScriptben dolgozom, egy Node.js-es szolgáltatást készítettem. Webszerver frameworkként Hapi-t, a Futár API hívásához pedig a request-promise NPM package-et választottam, mert ezeket már ismertem korábban.

Mivel a webtile nem paraméterezhető, nem láttam értelmét olyan szolgáltatást készítésének, amit bárki, bármilyen járat indulásainak lekérésére használhat. Ez nagyban egyszerűsítette a dolgomat, mert így a KoviBuszból kikeresett megálló azonosítókat én bizony simán beledrótoztam a forráskódba. Az én szervizem, az én megállóim. Persze a forráskódot kitettem Githubra, hogy bárki barkácsolhasson magának hasonlót, vagy még jobbat:

github-logo

 https://github.com/balassy/band-futar-tile

Íme néhány érdekesebb pont a kódból:

  • A webszerviz kódja az src mappában található, a webtile által hívott végpont pedig azon belül a next-ride mappában.
  • Azon belül a service.js hívja a Futár API-t a paraméterként kapott megálló azonosítóval.
  • A service.js-t a controller.js hívja, átadva neki a keresett megállók azonosítóit.
  • A gulpfile.js az urbanjs-tools nevű NPM package-t használja statikus kódelemzésre, ami nagyon kényelmessé teszi az ESLint és az ES6 használatát.
  • A forráskódot Visual Studio Code-dal írtam, erre utalnak a .vscode, typings mappák és a tsd.json fájl. (Igen, a typings mappát nem kellene betenni a repoba, de így sokkal kényelmesebb volt.)
  • A projektet pillanatok alatt sikerült bekötnöm Travisbe és AppVeyorba, ezek beállításai találhatók a .travis.yml és az appveyor.yml fájlokban. Ezek az ingyenes online build környezetek segítettek a forráskód folyamatos karbantartásában, mindkettőt csak ajánlani tudom.

Hosting környezetnek természetesen Azure-t választottam, mert piszkosul egyszerű egy Githubon tárolt web alkalmazás continuous deploymentjét összelőni. Most amint felküldök egy kód módosítást a Githubra, lefut a build Travisben és települ is ki automatikusan az Azure-os webszerverre. Ez az automatizmus még egy ilyen egyszerű alkalmazás esetén is óriási segítség fejlesztés közben.

A webtile

A webtile elkészítéséhez az első részben is említett varázslót használtam. Úgy döntöttem, hogy ez egyes járatok adatait külön page-en fogom megjeleníteni (Multiple page tile), azon belül egy a Scrolling text wrap (MSBand_ScrollingText) elrendezés bizonyult legpraktikusabbnak az ismeretlen hosszúságú szöveg megjelenítésére. Ezt így mutatja a varázsló (az 59-es villamos következő indulásai a Vas Gereben utcai megállóból):

band-webtile-wizard-preview-1

Jelenleg a szerviz az engem leginkább érdeklő három járat adatait adja vissza, ezek mind külön page-et kaptak, utánuk pedig egy negyedik oldalra az utolsó frissítés időpontját tettem. Ez hibakereséshez lehet jó, a szerviz a válasz JSON egyik property-jében visszaadja, hogy mikor kérte le utoljára az adatokat a Futár API-tól, így könnyű volt megjeleníteni:

band-webtile-wizard-preview-2

A varázsló által generált webtile-t nem közvetlenül telepítettem Bandira, hanem letöltöttem, kicsomagoltam (mert valójában egy ZIP fájl), és módosítottam rajta (a végeredmény megtalálható a a webtile/manifest.json fájlban):

  • Kijavítottam azokat az apró hibákat, amiket a webes varázslóban egyszerűen nem sikerült.
  • Beállítottam a refreshIntervalMinutes tulajdonság értékét 15-re, ami negyedórás frissítési időközt jelent, ennél sűrűbben nem is lehet.
  • Beállítottam a version és a versionString tulajdonságokat, és minden újabb kísérletnél inkrementáltam őket, hogy biztosan észrevegye a Microsoft Health alkalmazás, hogy újabb verziót akarok telepíteni.
  • Beállítottam a name, description, author, organization és contactEmail tulajdonságok értékeit, hogy azok kulturáltan jelenjenek meg telepítéskor.

Jelenleg a webszerviz HTTP 500 status code-dal tér vissza, ha valami nem sikerül szerver oldalon, de erősen gondolkodom rajta, hogy hibakeresési célzattal minden ilyen esetben HTTP 200 OK-val térjek vissza, és a hiba leírását adjam vissza a válaszban, hogy azt könnyen meg lehessen jeleníteni a Banden.

A végeredmény

Örömmel tölt el, hogy az elkészült megoldás működik, a Futár API-tól kapott adatok megjelennek, és a megoldás nem bonyolult.

band-futar-tile

band-futar-page

band-futar-update-page

A Futár igazi értéke abban van, hogy nem csak egy sima menetrend, hanem (elméletileg legalábbis) valós idejű adatokat tartalmaz, azaz az aktuális forgalmi helyzetet tükrözi. Sajnos a webtile legjobb esetben is negyedórás frissítési időköze ezt a remek lehetőséget tökéletesen megöli, ami már kevésbé örvendetes, hiszen így az esetek nagy részében “csak” a menetrendi adatokat látom, ami Tokióban minden bizonnyal tökéletesen működne, Budapesten még nem 100%-os. Mivel engem leggyakrabban egy villamosmegálló és egy buszvégállomás indulási időpontjai érdekelnek, számomra egészen jól használható a végeredmény.

Te milyen adatokat látnál szívesen az órádon?

 

Technorati-címkék: ,

BKK Futár Microsoft Bandre – a BKK Futár API (2. rész)

Ahogy az előző részben említettem, azt tűztem ki célul, hogy a BKK Futártól kapott aktuális tömegközlekedési információkat okosórán, konkrétan Microsoft Banden jelenítem meg. A Band programozási lehetőségeinek áttekintése után ebben a részben először nézzük meg azt, hogy a BKK Futár adatait hogyan érhetjük el.

A BKK Futár API

A Budapesti Közlekedése Központ honlapján igen haladó módon létezik egy Fejlesztőknek szóló oldal, ahol gyorsan kiderült, hogy nem rám gondoltak. A BKK megközelítése az, hogy a menetrendi információkat bizonyos időközönként publikálják az oldalukon egy kb. 28 MB-os ZIP fájlban. Értem én, hogy a ZIP-ben GTFS, azaz General Transit Feed Specification formátumban vannak az adatok, ami igen elterjedt, hiszen a G csak udvariasságból General és nem Google, meg hogy így könnyű feltölteni a Mapsre és hogy sűrűn frissítik, ez tényleg szép, csak nekem éppen most pont nem jó.

A következő utam a BKK Futár oldalára vezetett, ahol minden bevezető nélkül egy interaktív térképet találhatunk, ami már sokkal érdekesebb, hiszen ez teljesen friss adatokkal dolgozik. Irány a fejlesztőknek szóló leírás: F12. Nem is kellett sokáig keresgélni a Firebugban, hogy ráleljek erre a kérésre (kattints a teljes méretű képért):

ms-band-4-futar-api

Ebből az egyetlen kérésből több dolog is kiderült:

  • Létezik API, sőt már az URL-jét is tudom. Kellene dokumentáció, amiből kiderül, hogy milyen végpontok vannak.
  • Az API verziózottnak tűnik, ami általában jó hír. Kellene dokumentáció, amiből kiderül, hogy milyen verziók léteznek.
  • Az API hívásához lehet, hogy kell API kulcs. Kellene dokumentáció, amiből kiderül, honnan lesz API kulcsom.
  • Lehet, hogy van throttling, legalábbis a data.limitExceeded mező erre utal. Kellene dokumentáció, amiből kiderül, hogy mennyi az annyi.
  • Státusz információ van bőven: a HTTP státusz kódon kívül a válaszban is van egy status, egy code, és egy text mező, sőt (és ez a fenti képen nem látszik) a szerver még egy X-BKK-Status fejlécet is visszaküld “OK” értékkel. Kellene egy dokumentáció, amiből kiderül, hogy melyik kell nekem.

Ez elég volt ahhoz, hogy elinduljak, de minden jel arra utalt, hogy nagy hasznát venném bármiféle további dokumentációnak.

Neki is álltam óriási lelkesedéssel, keresgéltem a BKK oldalán, a Bingben, de sajnos az összes Google-fu tudásom is kevésnek bizonyult, nem találtam hivatalos leírást. (Aki ismer ilyet, kérem küldje el nekem, köszönöm.)

Találtam viszont több nem hivatalos forrást is:

  • Létezik egy Index Fórum “A BKV GTFS adatbázisa” címmel, ahonnan számomra az derült ki, hogy a nép szenved a GTFS-től és egy barátságosabb API-t szeretne.
  • Az Apiary oldalán találtam egy dokumentációt BKK FUTÁR Utazástervező API címmel. Sajnos nem tűnik hivatalosnak, használhatónak viszont annál inkább.
  • Nádai Gábor (alias Mefi) nevén találtam egy Github repót KoviBusz néven, ami egy adott busz következő indulási idejét mutatja az API-t felhasználva. A kód Node.js-ben készült, és egy barátságos fájlban JSON formátumban tartalmazza a megállókat.

Járatinformációk

Az Apiary dokumentáció és a Firebug böngészése közben világossá vált, hogy nekem az Arrivals and Departures for Stop (nem is olyan nehéz egy API-t jól elnevezni, igaz?) API-ra van szükségem, amit így kell meghívni:

GET http://futar.bkk.hu/bkk-utvonaltervezo-api/ws/otp/api/where/arrivals-and-departures-for-stop.json?stopId&onlyDepartures&minutesBefore&minutesAfter

Ahol:

  • A stopId a megálló azonosítója, például BKK_F00945.
  • Az onlyDepartures paramétert true-ra állítva megadhatjuk, hogy csak az indulások érdekelnek.
  • A doksi szerint a minutesBefore-ral lekérdezhetjük a korábban elment járatokat, ami Marty McFly számára kétségkívül egy hasznos funkció, nálam 0 lesz, az biztos.
  • A minutesAfter-rel pedig azt állíthatjuk be, hogy hány percre előre szeretnénk lekérni az érkező és induló járatokat.

Következő lépésként megálló azonosítóra volt szükségem. Ehhez legjobb forrásnak a Mefi KoviBusz oldala bizonyult, ami térképen kirajzolja az összes megállót, csak rá kell bökni valamelyikre, és Firebugban máris látszódik az azonosítója. A József Nádor tér például F00979.

GET-es API-ról lévén szó, ezt könnyen ki is próbálhatjuk, csak tegyük a megálló azonosítója elé a BKK_ előtagot, és írjuk be a címet a böngésző címsorába:

http://futar.bkk.hu/bkk-utvonaltervezo-api/ws/otp/api/where/arrivals-and-departures-for-stop.json?stopId=BKK_F00979

Íme a szervertől kapott válasz, ahogy azt a Chrome mutatja:

ms-band-5-futar-api-response

Kiemeltem néhány érdekességet:

  • A dátumok és időpontok igen barátságtalanok: nem csak hogy epochtól számított számként jönnek, de hol másodpercben, hol milliszekundumban vannak kifejezve. És akkor az időzónákról még nem is beszéltünk.
  • A következő indulásoknál megjelenik a predictedArrivalTime tulajdonság, sőt létezik predictedDepartureTime is. Végállomásoknál indulási oldalon egyik sincs, csak departureTime.
  • Ebben a megállóban két járat is megáll, a 16-os és a 105-ös. Mi a stop azonosítóját tudjuk, ahhoz tartoznak stopTime-ok, ahhoz trip-ek és végül ahhoz route-ok.

Erős nézés módszerével meglett tehát az API, amiből kinyerhetőek az adatok, már csak össze kell kötnünk a Banddel.

 

(Folytatás következik…)

 

Technorati-címkék: ,

BKK Futár Microsoft Bandre (1. rész)

ms-band-1Nem rég szerencsés tulajdonosa lettem egy Microsoft Bandnek, és természetesen legjobban arra voltam kíváncsi, hogyan készíthetek rá saját alkalmazást. Első célul azt tűztem ki, hogy a BKK Futártól származó információkat fogom rajta megjeleníteni, hiszen milyen jó lenne, hogy amikor kilépek a lakásból csak ránézek az órámra, és rögtön látom, hogy mikor jön a következő buszom. Bandiban van GPS, a telefonon keresztül kilát az internetre, így első körben ez a feladat megvalósíthatónak látszott.

Korlátlan lehetőségek fejlesztőknek

A Microsoft Band “For Developers” oldalára ellátogatva gyorsan fel tudjuk mérni, hogy fejlesztőként háromféle irányból támadhatjuk meg ezt az eszközt.

A Band SDK-t felhasználva készíthetünk egy Windows, Android vagy iOS alkalmazást, ami képes kommunikálni a Band-del. Van szép PDF dokumentáció sok példakóddal, sőt még design guidelines-t is kapunk. A telefonon futó alkalmazás eléri a szenzorokat, új csempéket, azon belül pedig oldalakat és UI vezérlőket tud megjeleníteni.

Készítethetünk Web Tile-t, amihez még különösebb fejlesztői tudás sem kell. Egy böngészőben futó varázsló segítségével kiválaszthatjuk, hogy milyen URL-ről érkező adatokat milyen formában szeretnénk megjeleníteni. A web tile JSON vagy RSS adatokat tud letölteni és megmutatni, sőt még arra is képes, hogy ha a letöltött adatok megfelelnek az általunk megadott feltételnek, akkor a Band megjelenít egy értesítést. Ezek a lehetséges elrendezések:

ms-band-2-tile-layouts

Az elkészült Web Tile-t a készítő feltöltheti egy galériába, ahonnan bárki két kattintással letöltheti azt a telefonjára, majd onnan a Bandjére.

A harmadik lehetőség a Microsoft Health Cloud API használata, ahol egy szép REST API-n keresztül kérhetünk le adatokat a felhasználóról és edzéseiről. Az API kevés végpontot tartalmaz, de ezek sok adatot tudnak visszaadni:

ms-band-3-swagger

A korlátlan lehetőségei korlátai

Első körben tehát el kell döntenünk, hogy hogyan akarjuk megközelíteni a problémát: SDK-val, Web Tile-lal vagy felhős API-val.

SDK

Az első lehetőség az SDK, ami a dokumentáció alapján nagyon izgalmasnak tűnik, de fontos megérteni, hogy

nem a Bandre írjuk az alkalmazást.

Készítünk egy telefonos vagy Windowsos alkalmazást, ami használja a Bandet, de nem a Banden fut. Nincs új projekt típus a Visual Studioban, sőt még azt sem mondhatjuk el, hogy a Banden is Windows 10 futna, mert nem (még). Az alkalmazásunk szempontjából a Band leginkább egy érintőkijelzőre hasonlít, amiben vannak egyéb szenzorok is.

Ez sajnos rögtön magával hozza azt a korlátozást is, hogy a telefonos alkalmazás tudja elérni a Bandet, nem pedig a karperec a telefonos alkalmazást. Tehát készíthetünk egy olyan mobil appot, ami elkéri a Bandtől a pulzusszámunkat vagy a napi kalória fogyasztásunkat, de azt nem lehet megoldani (még), hogy az óránkon kezdeményezzünk bármit, mert a telefonos alkalmazás nélkül a Banden sem történik semmi. Azaz a telefonos alkalmazásnak mindig futnia kell, ami például Windows Phone-on egyelőre csak elég korlátozottan oldható meg (ebben a Windows 10 és a DeviceUseTrigger tud segíteni). Kivétel ez alól a Cortana, mert a Bandről indított hangvezérléssel lehet alkalmazást aktiválni a telefonon, de nálunk ugye nincs Cortana.

A második erős korlátozás a UI. Nem elég, hogy kicsi a képernyő, a felhasználható vezérlők  listája is elég rövid:

  • Egyszerű vezérlők:
    • TextBlock
    • WrappedTextBlock
    • Icon
    • Barcode
    • TextButton
    • FilledButton
  • Konténer vezérlők:
    • FlowPanel
    • ScrollFlowPanel
    • FilledPanel

A jó hír, hogy van gomb, de ne feledjük, hogy csak akkor ér valamit, ha a hozzá tartozó eseménykezelőt tartalmazó telefonos alkalmazás fut éppen.

A rossz hír, hogy gyakorlatilag nincsenek input vezérlők, se szövegdoboz, se lista, semmi. Pedig a Banden még mini billentyűzet is van, hiszen SMS-ekre tudunk onnan válaszolni, ez azonban jelenleg nem érhető el más alkalmazások számára. Arról se álmodjunk, hogy akkor majd mi megoldjuk egyszerű vezérlőkből, ugyanis azokból maximum 10 lehet egy oldalon (page-en).

Ezek után az, hogy a vezérlőkre a számukkal kell hivatkozni, és a gomb eseménykezelőt nem is a gombhoz, hanem az egész csempéhez (lényegében az alkalmazáshoz) kapcsoljuk, és a kódban kell megvizsgálni, hogy melyik gombra nyomott a felhasználó, már nem is tűnik komoly korlátozásnak.

A szenzorok között vannak olyanok (nem mind, de például a szívritmus), amit a felhasználó tudta nélkül nem lehet kiolvasni. Ez a gyakorlatban azt jelenti, hogy az alkalmazásnak először egy GetCurrentUserConsent() függvényt kell hívnia, ami feldob egy engedélykérő ablakot, ahol a felhasználó eldöntheti, hogy az app olvashatja-e azt a szenzort vagy nem. Ez rögtön meghatározza, hogy olyan alkalmazást kell írnunk, amihez tartozik felhasználói felület, azaz háttérben futó windows service-ek és headless IoT alkalmazások kizárva. Nem barkácsolhatunk olyan ventillátort, ami Bluetooth-on keresztül közvetlenül a Bandről olvassa a szívverésemet, és ha magas szívritmust érzékel, bekapcsol, mert a kijelző nélküli ventillátor nem tud engedélyt kérni a HeartRate szenzor olvasásához. Mindenképpen szükségünk van a telefonra az engedélyezés miatt.

Web Tile

A Web Tile egyszerűen elkészíthető és praktikus megoldás például hírportálok információinak megjelenítésére: csak rákötöm a meglévő RSS feedre és már készen is van. Érdemes azonban átgondolni, hogy valóban a meglévő JSON-os végpont vagy RSS feed a legoptimálisabb-e a Band számára, mert a kijelző mérete korlátos, és a web tile nem képes a letöltött adatokon semmilyen formázást elvégezni. A varázslóban csak azt tudjuk megmondani, hogy a szervertől kapott JSON válasz egyes property-jei melyik TextBlockokban jelenjenek meg. Ha a szöveg túl hosszú, nem fog kiférni (kivéve a görgethető elrendezés esetén), hanem egyszerűen levágódik. A legbonyolultabb művelet a sztring összefűzés (több property megjelenítése egy TextBlockban), de arról ne is álmodjunk, hogy számot fogunk dátummá konvertálni, vagy kiszámoljuk az eltelt időt két időpont között.

Ahogy a fenti képen is látszik, a varázsló felkínálja, hogy válasszunk a 6 előre definiált oldalrendezés közül. Más lehetőségünk nincs, ezek valamelyikén (vagy több oldalon) kell elrendeznünk a megjeleníteni kívánt információkat. A hatból 3 elrendezés képes képet megjeleníteni, ezek azonban csak kis méretű, átlátszó hátterű, fehér ikonok lehetnek, amik már a tile telepítésekor rendelkezésre állnak. Arra például nincs lehetőségünk, hogy fotót vagy szerverről letöltött képet jelenítsünk meg (például árfolyamok alakulása on-demand rajzolva). Jó hír viszont, hogy a csomagba tehetünk több ikont, és meghatározhatjuk, hogy feltételtől függően melyik jelenjen meg (például különböző időjárás ikonok).

Érdemes egyébként elolvasni a web tile specifikációt, mert a varázsló csak a fontosabb paramétereket állítja be, nem kérdez rá mindenre. Az egyik ilyen kimaradó paraméter a refreshIntervalMinutes, amivel azt állíthatjuk be, hogy milyen gyakran frissüljön a csempe. Ennek az értéke alapértelmezés szerint 30 perc, de akár 15 percre is állíthatjuk (sűrűbbre nem). Ehhez nevezzük át a varázsló által generált .webtile fájlt .zip-re, csomagoljuk ki, majd módosítsuk a benne található manifest.json fájlt.

Sajnos a gyakorlatban azt tapasztaltam (és a StackOverflow szerint nem vagyok ezzel egyedül), hogy az adatok néha a megadottnál jóval ritkábban frissülnek, nálam volt olyan, hogy 3 óra is eltelt két frissítés között. A sikeres frissítéshez a HTTP válasznak 200 OK-val kell visszatérnie, és a szokásos kliens oldali gyorsítótárazási módszerek itt is bezavarhatnak.

A web tile által hívott URL fix és csak GET lehet, tehát ne is álmodozzunk például arról, hogy majd így küldjük fel az UV szenzor által mért értékeket.

 

Ezek alapján szerintetek hogy lenne a legpraktikusabb megvalósítani a BKK Futárt Microsoft Bandre?

 

(Folytatás következik…)

 

Technorati-címkék: ,