Liikennevirasto tarjoaa mittavan määrän erilaista liikenteeseen ja säähän liittyvää avointa dataa Digitrafficin kautta. Tuosta olisi houkuttelevaa rakentaa kaikennäköisiä analyyseja, mutta nyt tarkoitukseni oli nimenomaan testata Power BI:n Real-time/Streaming-data ominaisuuksia.
Alun perin toiveenani oli tehdä live-seuranta jonkun mittauspisteen liikennenopeuksista. Tähän olikin tarjolla kuvauksen mukaan minuutin välein päivittyvää dataa pääkaupunkiseudulla sijaitsevilta linkki-asemilta. Tutkinnan jälkeen paljastui, että eihän nuo tiedot tuolla päivity. Osa oli kuukausia vanhoja.
Vaihtoehdoksi oli tarjolla TMS (Traffic Measurement System) mittaamat 5 minuutin ja 60 minuutin keskiarvot nopeuksista, mutta nuo eivät oikein palvelleet reaaliaikaisen raportoinnin demonstroinnin tarvetta. Niinpä sitten vaihdoin kohteen Liikenneviraston sääasemien tarjoamaan dataan, joka kuvauksen sekä ennen kaikkea testien perusteella päivittyy noin minuutin välein.
Alla esimerkki https://tie.digitraffic.fi/api/v1/data/documentation/swagger-ui.html#/ sivulta löytyvästä json-viestistä, jonka api:n kautta voi hakea:
Päätin rakentaa Python-ohjelman, jolla pystyin kutsumaan REST API rajapintaa, lukemaan ja käsittelemään viestin sekä lähettämään eteenpäin Power BI:lle.
Luin vielä erikseen TMS-asemien metatiedot Power BI:hin, jonka avulla sain laitettua sääasemat kartalle sekä rakennettua tiekohtaisen valintahierarkian. Esimerkiksi Seututie 101:n eli suomeksi Kehä I:n mittausasemat näkyvät ohessa:
Olisi ollut ihan mukava yhdistää liikennedataa säädataan, mutta kuten alla olevasta kartasta huomaatte, niin esim. Kehä I sääasemat ovat eri asia kuin TMS-asemat.
Valitsin seurattavaksi mittariksi tuulensuunnan, koska se oletuksen mukaan vaihtuu verrattain useasti, jolloin dashboardille saisi vähän eloa.
Seuraavaksi loin Power BI:hin Streaming-dataset tyyppisen sisäänluettavan tietojoukon. Kerroin minkä nimisiä ja muotoisia tietoja olin ajatellut puskea sisään, jonka jälkeen Power BI osasi kertoa minkälaisen json-viestin se odottaa saavansa:
Testien perusteella Power BI on aika tarkka tuosta muodosta eli jouduin aika paljon tappelemaan tuon Timestamp-tiedon kanssa. En aluksi myöskään laittanut noita hakasulkuja, joiden puuttuminen aiheutti kovasti ongelmia. Laitoin historia-tiedon tallennuksen myös päälle. Sen avulla pystyy rakentamaan myös tavallisia raportteja rikkaammilla visualisointivaihtoehdoilla pohjautuen samaan dataan. Muuten visualisointi rajoittuu pelkästään dashboardin real-time data-tileihin.
Tallennuksen jälkeen kävin hakemassa data setin tiedoista tuon Push URL:in, jonne pystyin puskemaan dataani. Tässä on tapahtunut suurta edistystä, koska aiemmin minun olisi pitänyt erikseen vielä rekisteröidä sovellukseni Azuressa, suorittaa erillinen autentikointi sekä mahdollisesti luoda Azure Stream Analytics jobi puskemaan dataa.
Tämän jälkeen loin vielä dashboardin, johon lisäsin kaksi real-time tilea – toinen on kortti, joka kertoo vain viimeisimmän arvon ja toinen on aika pohjainen viivadiagrammi, joka kuvaa myöskin muutoksia.
Nyt oli sitten kaikki valmista ja ei muuta kuin ajamaan koodia. Ja kyllähän sitä käppyrää alkoi itsestään dashboardille piirtymään! Mutta ei todellakaan ensimmäisellä yrityksellä.
Valitettavasti dashboardia ei voi Power BI:ssä julkisesti jakaa, joten sitä ei voi myöskään itse testata vaikka tuon Python-ohjelman jakaisinkin. Julkaisin nyt kuitenkin kartta-raportin (klikkaa vasemmalla olevaa tekstiä), jossa näkyy nuo Liikenneviraston eri mittauspisteet, jos se jota kuta kiinnostaa.
Lopussa vielä Python-koodi, jolla tein kutsun Digitrafficin palveluun, muokkasin vastauksen haluamaani muotoon sekä lähetin Power BI:lle. Nuo print-komennot sinällään turhia, mutta halusin nähdä minkälaista tietoa tuolla liikkuu. Alla yksi esimerkki lähetystä viestistä:
Lopputuloksena voi todeta, että aika näppärä tuo Streaming Data -rajapinta, mutta on syytä huomata, ettei dataa voi suoraan yhdistellä muuhun saatavilla olevaan dataan. Sitä varten data pitää tallentaa erikseen toisaalle. Hälytyksiä en testannut, mutta dokumentaation mukaan tuonne voisi rakentaa sellaisiakin, jos vaikka real-time datan raja-arvo joko ylittyy tai alittuu.
Python-koodi:
# -*- coding: utf-8 -*-
”””
Created on Thu Nov 02 21:03:27 2017
@author: Tero Kruth
”””
from urllib2 import Request, urlopen, URLError
import json
import requests
import pandas as pd
import time
import itertools
from datetime import datetime
import dateutil.parser
def response(address):
resp = requests.get(address)
if resp.status_code != 200:
# This means something went wrong.
raise ApiError(’GET /tasks/ {}’.format(resp.status_code))
WS = resp.json()[”weatherStations”]
ID = WS[0][”id”]
SV = WS[0][”sensorValues”]
DFSV = pd.DataFrame(SV)
WindDir = DFSV.loc[DFSV[’id’] == 18, ’sensorValue’].values[0]
SensorName = DFSV.loc[DFSV[’id’] == 18, ’name’].values[0]
TimeNow = datetime.strftime(datetime.now(), ”%Y-%m-%dT%H:%M:%S.%f”)[:-3]
DateTime = resp.json()[”dataUpdatedTime”]
json_out = ([{’ID’: ID, ’Timestamp’: TimeNow+’Z’, ’WindDir’: WindDir, ’SensorName’: SensorName}])
PB_url = ’https://api.powerbi.com/beta/9fcd5d80-219a-4082-a1fa-d825e77372ca/datasets/454562cc-79d0-43b9-9758-d22706421d77/rows?key=uUvG9pb9MsYTwQJj3MJyoSd65nKmu6CZQaV095Ns%2BvknvaJhp%2FFPZ1QJ2gPaqduevyU0zlYXpVFgrbRUJk5TM’
r = requests.post(PB_url, data=json.dumps(json_out))
print ID
print TimeNow
print DateTime
print WindDir
print SensorName
print json_out
print r
asema = raw_input(u”Anna aseman numero: ”)
for _ in itertools.repeat(None, 5):
response(’https://tie.digitraffic.fi/api/v1/data/weather-data/’ + asema)
time.sleep(60)