häiriöhavaintojärjestelmän integraatio
TRANSCRIPT
Antti Heinonen
Häiriöhavaintojärjestelmän Integraatio
Liikenteenhallintajärjestelmään
Tietotekniikan pro gradu -tutkielma
13. maaliskuuta 2019
Jyväskylän yliopisto
Informaatioteknologian tiedekunta
Tekijä: Antti Heinonen
Yhteystiedot: Antti Heinonen
Ohjaaja: Ville Isomöttönen
Työn nimi: Häiriöhavaintojärjestelmän Integraatio Liikenteenhallintajärjestelmään
Title in English: Integration of Disturbance Detection System Into Traffic Control Systems
Työ: Pro gradu -tutkielma
Suuntautumisvaihtoehto: Ohjelmistotekniikka
Sivumäärä: 87+0
Tiivistelmä: Tämä pro gradu keskittyy eritason komponenttien välisen kommunikaation
suunnittelemiseen ja toteutukseen. Tutkielma esittelee pääasialliset olevassaolemat toteutuk-
set Suomen liikennejärjestelmissä, niiden yhteisen arkkitehtuurin pääpiirteet sekä käsittelee
uuden laitetyypin integraatiota olemassaoleviin järjestelmiin.
Tutkielman lopputuloksena on uusi rajapinta liikenneviraston ohjelmistoihin, jonka avulla
pystytään välittämään ja vastaanottamaan viestejä koneoppimista hyödyntävälle kamerapoh-
jaiselle häiriöhavaintojärjestelmälle.
Avainsanat: gradu3, pro gradu -tutkielmat, Software Architecture, Software Design, C#,
WinCC OA, PLC
Abstract: This graduate thesis is focused on integration of components from different levels
of complexity and transmission of messages between these different systems. Thesis presents
the main architecture and existing solutions in Finnish traffic systems and focuses on creation
of a new integration layer of software and plc in order to effectively communicate between
REST-application and traffic cameras that detect disturbances using machine learning.
Keywords: gradu3, pro gradu -tutkielmat, Software Architecture, Software Design, C#,
WinCC OA, PLC
i
Esipuhe
Tämä Pro gradu tutkielma on toteutettu työsuhteen aikana YSP Oy -yrityksellä.
YSP Oy toimii konsulttina sekä liikenneteknisten järjestelmien toteuttajana Suomen Liiken-
nevirastolle. Pääasiallisena tuotteena toimii kokonaisratkaisujen tarjoaminen Liikenneviras-
tolle alkaen yksittäisten laitteiden tilaamisesta, asentamisesta ja logiikkaohjelmoinnista, jat-
kuen valvomo-ohjelmiston kautta REST-rajapintaan asti, johon Liikenneviraston Tieliiken-
teen ohjauksen integroitu käyttöliittymä (T-LOIK) ottaa yhteyden.
Jyväskylä, 13. maaliskuuta 2019
Antti Heinonen
ii
Termiluettelo
HTTP (lyhenne sanoista Hypertext Transfer Protocol) on protokolla,
jota selaimet ja palvelimet käyttävät viestiensä välitykseen.
TCP (lyhenne sanoista Transmission Control Protocol) on matalan
tason tietoliikenneprotokolla, jonka avulla tietokoneet viestivät
toisilleen.
REST (lyhenne sanoista Representational State Transfer) on HTTP-
protokollaan perustuva arkkitehtuurimalli ohjelmointirajapin-
tojen toteuttamiseen.
XML (engl. Extensible Markup Language) on XML-tyyppisten mer-
kintäkielien standardi, johon muunmuassa verkkosivujen HTML
kuuluu.
JSON (lyhenne sanoista JavaScript Object Notation) on avoimen stan-
dardin mukainen tiedostomuoto tiedonvälitykseen.
.NET Framework on Microsoftin kehittämä ohjelmistokomponenttikirjasto.
C# on Microsoftin kehittämä olio-ohjelmointikieli, joka pohjautuu
.Net-kirjastoon.
ASP.NET on avoimen lähdekoodin ohjelmistokehys modernien web-sovellusten
rakentamiseen.
AKKA.Net on työkalupaketti ajonaikaisten tapahtumapohjaisten ohjelmis-
tojen kehitykseen, joka pohjautuu .Net -kirjastoon.
NUnit on avoimen lähdekoodin kirjasto .NET-sovelluksien yksikkö-
testaamiseen.
SCADA (engl. Supervisory Control and Data Acquisition) on tietoko-
neohjelma, joka tarjoaa pohja-arkkitehtuurin erilaisiin automaa-
tiojärjestelmiin ja niiden hallintaan.
WinCC OA (engl. WinCC Open Architecture) on Siemensin kehittämä SCADA-
ohjelmistotuote.
PLC (engl. Programmable logic controller) on riisuttu tietokone, jo-
ta käytetään tosiaikasten automaatioprosessien ohjaamisessa.
iii
T-LOIK (lyhenne sanoista Tieliikenteen ohjauksen integroitu käyttöliit-
tymä) on järjestelmä, jonka tarkoituksena on vastaanottaa da-
taa ja hallita eri osia Suomen liikenteenhallintajärjestelmistä.
T-LOIK-Ohjaussovitin on järjestelmä, jonka tarkoituksena on toimia viestinvälittäjä-
nä SCADA-ohjelmiston ja/tai PLC-laitteiden sekä T-LOIK:n
välillä.
DriverManager on C# :lla toteutettu ajurialusta, joka pohjautuu microftin MEF-
applikaatioihin (Managed Extensible Framework).
iv
KuviotKuvio 1. Järjestelmän yleisarkkitehtuuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3Kuvio 2. Esimerkki LD:n syntaksista, lähde “Ladder Logic Examples” 2018-10-16. . . . . . . 7Kuvio 3. Modbus TCP esimerkki, lähde: “How do you program and parameterize
Modbus/TCP communication between S7-1500 CPUs and S7-1200 CPUs?” (2018-10-16). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
Kuvio 4. T-LOIK-ohjaussovittimen tietovuo-kaavio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22Kuvio 5. DriverManager WinCC OA:n projektimanagerin aliprosessina . . . . . . . . . . . . . . . . . . . 25Kuvio 6. XaidDriverin arkkitehtuuri. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37Kuvio 7. XaidDriverin sisäinen rakenne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
TaulukotTaulukko 1. Modbus TCP:n rakenne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
v
Sisältö1 JOHDANTO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2 ARKKITEHTUURIN YLEISKUVA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
3 PLC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63.1 Structured Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83.2 Modbus Protokolla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113.3 PLC käyttötapauksia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4 SCADA. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144.1 WinCC Open Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154.2 Datan vastaanottaminen ja välitys WinCC OA:ssa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
5 REST-ARKKITEHTUURI & T-LOIK-OHJAUSSOVITIN . . . . . . . . . . . . . . . . . . . . . . . . . . . 175.1 REST-arkkitehtuuri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185.2 T-LOIK-Ohjaussovitin ja Akka.NET. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
6 MANAGED EXTENSIBILITY FRAMEWORK & DRIVERMANAGER . . . . . . . . . . 24
7 X-AID HÄIRIÖNHAVAINTOJÄRJESTELMÄ JA TESTIVETOINEN KEHITYS . 287.1 Kuvaus X-AID häiriönhavaintojärjestelmästä . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297.2 X-AID-simulaattori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307.3 Testivetoinen kehitys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
8 XAIDDRIVER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328.1 Oliosuunnittelu ja XaidDriver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368.2 XaidDriverin kehityksessä sovelletut suunnittelumallit . . . . . . . . . . . . . . . . . . . . . . . . . 458.3 Datan representaatiot WinCC OA:ssa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 548.4 XaidDriverin datan käsittely WinCC OA:ssa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
9 X-AID INTEGRAATION TESTAAMINEN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649.1 XaidDriverin yksikkötestaus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 659.2 Integraatiotestaus XaidDriverin ja WinCC OA:n välillä . . . . . . . . . . . . . . . . . . . . . . . . 669.3 Kenttätestien huomioita ja tuloksia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
10 YHTEENVETO JA JATKOTOIMENPITEET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
LÄHTEET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
vi
1 Johdanto
Liikennevirasto aloitti vuonna 2013 hankkeen, jonka tarkoituksena oli yhtenäistää useita
erilaisia Suomessa olevia liikenteenohjausjärjestelmiä (“Uusi tieliikenteen ohjausjärjestel-
mä (T-LOIK) nopeuttaa tiedonkulkua tienkäyttäjille ja helpottaa liikennepäivystäjien työtä”
2016-03-04). Tämän seurauksena syntyi yksi yhteistävä järjestelmä: T-LOIK (Tieliikenteen
ohjauksen integroitu käyttöliittymä). Koska Suomessa on melko paljon liikenteenohjaus-
järjestelmiä, on kaikkien pääasiallisten järjestelmien yhdistäminen T-LOIK-järjestelmään
usean vuoden prosessi.
Tämän pro gradun keskipisteenä on Etelä-Suomeen suunnitteilla oleva tunnelijärjestelmä.
Tunnelin läpi kulkee moottoritie ja tunnelin alue sisältää lukuisia erilaisia PLC-laitteita (Pro-
grammable Logic Controller), joita ohjataan SCADA-järjestelmien (Supervisory Control and
Data Acquisition) ja T-LOIK:n kautta. Tätä yleisarkkitehtuuria havainnoillistava kuvio 1 esi-
tellään tarkemmin seuraavassa kappaleessa. Tämän tunnelin SCADA-järjestelmä on toteutet-
tu Siemensin WinCC OA -järjestelmän pohjalta.
Tunnelin teknisesti kiinnostavimpia kohteita ohjelmistokehityksen näkökulmasta on tunne-
liin tuleva häiriöhavaintojärjestelmä (HHJ, X-AID). Tämä järjestelmä prosessoi videoku-
vaa koneoppimista hyödyntäen, tunnistaen liikennehäiriöitä ja välittää niistä tietoa SCADA-
järjestelmälle ja takaisin. Näiden viestien sisältönä on esimerkiksi pysähtynyt ajoneuvo, hi-
das ajoneuvo ja väärään suuntaan ajava ajoneuvo. Häiriötilanteita varten tunnelin ohjaus-
järjestelmään on rakennettu erilaisia reaktioita liikennekäyttäjän varoittamiseen ja kaistojen
sulkemiseen. Käytännössä erilaiset hälytykset laukaisevat sekvenssejä PLC-laitteissa, jotka
sitten reagoivat tilanteesta riippuen korrektilla tavalla, kuten sulkemalla jonkin kaistan ja oh-
jaamalla liikenteen toiseen suuntaan.
Tämän pro gradun lopputuloksena on X-AID-palvelimen TCP-yhteyden (Transmission Cont-
rol Protocol) sisäistä protokollaa tulkkaava ajuri, joka kommunikoi X-AID kameroiden ko-
neoppimis-palvelimen kanssa ja välittää hälytyksiä WinCC OA -pohjaiseen tunnelijärjestel-
mään.
Tulkki toteutetaan ajuriksi C#-ohjelmointikielellä DriverManager-ohjelmistoon, mistä syys-
1
tä tämän ajurin nimeksi tuli XaidDriver. DriverManager on C#-ohjelmointikielellä toteutettu
geneerinen ajurialusta, joka käyttää WinCC OA:n C# rajapintaa. Tämän ajurialustan tarkoi-
tuksena on helpottaa WinCC OA:n sisäisen CTRL-skriptikielen jatkamista C#-ohjelmointi-
kielellä, sillä C# taipuu helpommin kompleksisempiin operaatioihin kuin CTRL. Ajurialusta
nopeuttaa ja yksinkertaistaa ulkoisten rajapintojen toteutusta WinCC OA-järjestelmään.
Tämän pro gradun aikana havainnoillistetaan miten olemassaolevia järjestelmiä integroidaan
toimivaksi kokonaisuudeksi sekä osoitetaan kuinka useita eri kokonaisuuksia yksittäinen mo-
derni automaatiojärjestelmä sisältää. Tarkoituksena on kaventaa kuilua ohjelmistotekniikan
ja automaatiosuunnittelun välillä sekä tarjota tietoa tavoista integroida automaatiojärjestelmä
korkean tason ohjelmointikielten ohjelmiin. Tutkielma esittää erilaisia kehitystapoja ja suun-
nittelumalleja luotettavan ohjelmiston kehitykseen ja havainnoillistaa käytännön esimerkeil-
le kuinka näitä malleja voi hyödyntää.
Tutkielmassa käydään läpi ensin olemassaoleva arkkitehtuuri ja avataan miten tutkielman
eri luvut liittyvät olemassaolevaan arkkitehtuuriin. Tarkoituksena on vastata seuraaviin ky-
symyksiin: mikä on PLC, mitä tarkoittaa SCADA-järjestelmä ja kuinka se kommunikoi kor-
keamman tason ohjelmointikielten ohjelmien kanssa, miten nämä järjestelmät kommunikoi-
vat keskenään ja miten näistä osista muodostuu valvomo-ohjelmisto (luvut 2 - 4). Ohessa
avataan miten tällainen tunnelivalvomojärjestelmä yhdistetään TLOIK-järjestelmään (luku
5). Tämän jälkeen siirrytään käsittelemään XaidDriverin kehitystä: minkälaisten teknolo-
gioiden päälle tämä ajuri on rakennettu (luku 6), millaisia ohjelmistokehityksen menetelmiä
voidaan soveltaa kehityksen yhteydessä, kuinka järjestelmän toimivuutta testataan, millaisia
suunnittelumalleja toteutuksessa hyödynnetään, millaista ohjelmistoarkkitehtuuria HHJ:n in-
tegraatiossa käytetään ja lopulta miten tämä järjestelmä testataan laadullisesti (luvut 7 - 9).
Lopuksi arvioidaan protokollatulkin toimivuutta, mitä puutteita löytyi alustavan testaamisen
ohessa, mitä mahdollisia jatkotoimenpiteitä järjestelmän kokonaistestaamisessa voi ilmetä ja
miten niihin voi reagoida kyseisen järjestelmän loppuun hiomiseksi sekä pohditaan yleisesti
pro gradun onnistumista (luku 10).
2
2 Arkkitehtuurin yleiskuva
Häiriöhavaintojärjestelmän integroimisen näkökulmasta on olennaista esitellä kehitykses-
sä hyödynnettävät teknologiat: olennaisimmat ovat T-LOIK, T-LOIK-ohjaussovitin, WinCC
OA-järjestelmä, PLC logiikka, DriverManager ja X-AID-palvelin.
Kuvio 1. Järjestelmän yleisarkkitehtuuri
Kuvio 1 havainnollistaa komponenttien rooleja ja niiden välisiä tiedonvälitystapoja. Jokai-
sella komponentilla tässä kuvassa on oma roolinsa. Kamerat välittävät videokuvaa koneoppi-
mispalvelimelle ja koneoppimispalvelin tunnistaa liikennehäiriöitä kuvavirrasta. XaidDriver,
joka on toteutettu ajuriksi DriverManagerin sisälle, tulkkaa näitä viestejä. DriverManager re-
kisteröityy WinCC OA:n aliprosessiksi. WinCC OA on SCADA-järjestelmä, eli se kommu-
nikoi PLC-laitteiston kanssa ja tarjoaa graafisen käyttöliittymän liikenteen hallitsemiseksi
sekä valvomiseksi tunnelissa.
3
PLC-laitteisto ohjaa alimman tason laitteistoa, eli esimerkiksi liikennepuomeja tai liiken-
nevaloja. T-LOIK-ohjaussovitin kommunikoi SCADA-järjestelmän kanssa sekä toteuttaa T-
LOIK-järjestelmän rajapinnan. T-LOIK ohjaa useita eri SCADA-järjestelmiä ja PLC-laitteistoja,
toimien keskistettynä graafisena käyttöliittymänä liikennekeskuksen päivystäjälle.
XaidDriverin toteutus on siis suunnittelututkimuksen näkökulmasta Hevnerin ja Chatterjeen
(2010) määrittelemä "wicked problem", eli kansankielisesti häijy ongelma. Tämänkaltaiset
ongelmat Hevner ja Chatterjee määrittelevät seuraavilla tavoilla:
1 . Epätasaiset vaatimukset ja rajoitteet
2 . Kompleksiset interaktiot ongelman eri osakomponenttien välillä
3 . Luontainen joustavuus, joka vaikuttaa sekä suunnitteluprosessin että tuotoksien
muutoksiin.
4 . Kriittinen riippuvuus ihmisten kognitiivisiin kykyihin luoda tehokkaita ratkaisuja
5 . Kriittinen riippuvuus ihmisten sosiaalisiin kykyihin, johtuen tiimityön tarpeesta
Lienee selvää, että tämän kokoisessa integraatioprojektissa jokainen näistä osioista täyt-
tyy: pelkästään YSP Oy:lla on useita eri ihmisiä toteuttamassa ratkaisuja ongelman eri osa-
alueisiin: ihmisiä suunnittelemassa IP-verkot sekä laitteiston välistä kommunikaatiota, ihmi-
siä tuottamassa logiikkakoodia ja asentamassa PLC-laitteistoa, CTRL-skriptikieltä ja valvo-
moa koodaavia ihmisiä, korkean tason ohjelmointikielten ratkaisuja tuottavia ihmisiä sekä
projektipääliköitä. Kun tähän lisää yhteistyövaatimukset muiden yritysten sekä asiakkaan
kanssa, on häijy ongelma syntynyt. Tässä suunnittelututkimuksessa pyritäänkin katsomaan
tämän ongelman ratkaisua kokonaisuuden kannalta ja selittämään, kuinka tämänkaltaisen
ongelman voi ratkaista.
Pro Gradun ymmärtämisen helpottamiseksi aloitetaan kokonaisuuden osien läpikäynti ma-
talimmalta tasolta siirtyen koko ajan korkeammalle abstraktiotasolle. Tämä tarkoittaa, että
ensin käsitellään PLC-laitteiston osuutta kokonaisuudessa, mistä siirrytään korkeammalle
abstraktiotasolle SCADA-järjestelmiin. SCADA-järjestelmien läpikäymisen jälkeen keski-
tytään REST-arkkitehtuuriin ja TLOIK-ohjaussovittimeen, sillä näiden kautta integroidaan
tämä SCADA-järjestelmä T-LOIK:n järjestelmään. Komponenttien käsittelyn lopuksi käy-
4
dään läpi Microsoftin MEF-applikaatiot ja DriverManager, sillä näiden pohjalta toteutetaan
XaidDriver. Lopulta siirrytään paneutumaan itse XaidDriverin suunnitteluun, toteutukseen
ja testaukseen.
5
3 PLC
PLC (engl. Programmable Logic Controller) on pieni ohjelmoitava tietokone. Ohjelmoita-
vat logiikat ovat alunperin kehittyneet korvaamaan traditionaaliset releet (Erickson 1996).
PLC:n kehitti General Motorsin automaattivaihteisto-osasto vuonna 1968 (Erickson 1996),
Nykyään PLC-laitteisto toimii sekä CERN-tutkimuslaitoksessa (Fernandez Adiego, Prieto
Barreiro ja Blanco Vinuela 2011) että liikennevaloissa. Näitä pieniä tietokoneita löytää kaik-
kialta, sillä ne ovat yleiskäyttöisiä, nopeita ja niihin voi ohjelmoida oman logiikkansa. Kuten
Erickson (1996) toteaa: "Ohjelmoitavat logiikat ovat automatisaation eturintamalla."
Vuosien aikana PLC:n käyttötapaukset ja erilaiset tarpeenmukaiset muunnokset ovat muut-
taneet maailmaa. PLC-ohjelmoinnin perustana käytetään logiikkalohkoja. Ohjelmoitavat lo-
giikkalohkot kehittivät David W. Page ja LuVerne R. Peterson vuonna 1985 (Page ja Peterson
1985).
Logiikkalohkojen tarkoituksena on toteuttaa boolean logiiikkaa ja ne toimivat logiikkaohjel-
moinnin ohjelmointiparadigman mukaisesti. Alunperin PLC-ohjelmoinnin tärkein osa olivat
LD:t (Ladder Diagram). Näiden diagrammien oli tarkoitus havainnoillistaa ohjelman raken-
netta sähkökaaviota muistuttavalla tavalla.
Kuviossa 2 esitetty esimerkki on varsin yksinkertainen, mutta oikean elämän sovelluksissa
vastaavia toiminnallisuuksia voi olla tuhansia. Myös ohjelmointi on työlästä: käytännössä
LD:a käyttäessä ohjelmoija joutuu kehitysympäristössään valitsemaan jonkin komponentin,
siirtämään sen haluamaansa paikkaan, valitsemaan toisen komponentin ja piirtämään näiden
välille kytkennän.
6
Kuvio 2. Esimerkki LD:n syntaksista, lähde “Ladder Logic Examples” 2018-10-16.
Jo tämän esimerkin perusteella voinee ymmärtää, että vastaavanlaiset ohjelmat paisuivat no-
peasti hyvin pitkiksi ja vaikealukuisiksi, mikä puolestaan teki PLC-ohjelmoinnista työläs-
tä. Ratkaisuna on kehittynyt useita eri kieliä, joita sovelletaan useimmiten tarpeen mukaan:
kieli on usein valmistajakohtainen. Esimerkiksi Schneider Electricsin laitteisto - jota YSP
pääasiassa käyttää - tukee Structured Text:iä.
Tässä pro gradussa keskitytään lähennä ST:iin, joka on määritelty PLCOpen IEC 61131-3
standardissa (Tiegelkamp ja John 1995). Nykyään tätä standardia seuraavia kieliä on viisi:
aiemmin mainittu LD ja ST, FBD (Function Block Diagram), IL (Instruction List, nykyään
deprekoitunut) sekä SFC (Sequential Function Chart). Näistä kielistä erityistä huomiota tässä
tutkielmassa saa ST, sillä tämän projektin PLC-laitteisto toimii sillä.
7
3.1 Structured Text
ST on tekstipohjainen verrattuna LD:n graafisuuteen. Sen ulkonäkö muistuttaa korkeamman
tason ohjelmointikieliä ja sen syntaksi on varsin helppolukuista. Tarkemmalla tarkastelulla
kuitenkin huomaa näiden ohjelmointikielten suuren eron, mistä syystä seuraavassa esimer-
kissä havainnoillistetaan liikennevalon keltaisen valon käyttäytymistä (YSP Oy, 2019).
(∗ Yellow f l a s h ∗ )
i f s e q S t e p =1 or s e q S t e p =6 or s e q S t e p =8 or s e q S t e p =10 then
d e v i c e O u t . c o n t r o l R e d L i g h t : = 0 ;
d e v i c e O u t . c o n t r o l G r e e n L i g h t : = 0 ;
i f s e q S t e p =1 then
yel lowFlashCTU (CU:= yellowFlashTON2 . Q, PV: = 0 ,R: = 0 ) ;
e n d _ i f ;
i f s c a d a S t a t u s . a l e r t C o m m u n i c a t i o n E r r o r =0 then
s c a d a S t a t u s . y e l l o w L i g h t F l a s h : = 1 ;
e l s e
s c a d a S t a t u s . y e l l o w L i g h t F l a s h : = 0 ;
e n d _ i f ;
ELSE
s c a d a S t a t u s . y e l l o w L i g h t F l a s h : = 0 ;
e n d _ i f ;
(∗ Yellow f l a s h t i m e r s ∗ )
yel lowFlashTON1 ( IN : = ( s c a d a S t a t u s . y e l l o w L i g h t F l a s h =1) and
n o t ( yel lowFlashTON2 .Q) , PT :=T#500ms ,Q =>
d e v i c e O u t . c o n t r o l Y e l l o w L i g h t ) ;
yellowFlashTON2 ( IN : = ( s c a d a S t a t u s . y e l l o w L i g h t F l a s h =1) and
yel lowFlashTON1 . Q, PT :=T#500ms ) ;
8
(∗ Yellow s o l i d ∗ )
i f s e q S t e p =2 then
d e v i c e O u t . c o n t r o l R e d L i g h t : = 0 ;
d e v i c e O u t . c o n t r o l Y e l l o w L i g h t : = 1 ;
d e v i c e O u t . c o n t r o l G r e e n L i g h t : = 0 ;
e n d _ i f ;
(∗ Red and y e l l ow ∗ )
i f s e q S t e p =4 then
d e v i c e O u t . c o n t r o l R e d L i g h t : = 1 ;
d e v i c e O u t . c o n t r o l Y e l l o w L i g h t : = 1 ;
d e v i c e O u t . c o n t r o l G r e e n L i g h t : = 0 ;
e n d _ i f ;
Jokaista eri valon väriä edustaa jokin numeerinen arvo, joka asetetaan status-arvoksi rekiste-
riin. Lienee myös syytä huomauttaa, että automaatiomaailmassa tilavaihtumien toteutuksessa
on aina sekä kontrolliarvo että statusarvo. Tämä johtuu siitä, että mahdollisten yhteysongel-
mien tai muiden käyttämiseen vaikuttavien tekijöiden yhteydessä näin pystyy vertaamaan
viimeksi annettua kontrolliarvoa ja varsinaista statusarvoa, varmistuen näin ohjauksen on-
nistumisesta. Kuten SCADA-luvussakin tullaan huomauttamaan, automaatiojärjestelmissä
luotettavuus on aina ensimmäinen prioriteetti.
Kieli sisältää mm. switch-case-lauseita, silmukoita, if-then-else -lauseita ja primitiivisiä funk-
tioita (sqrt(), sin()). Myös perustietotyypit ovat mukana: bitit, kokonaisluvut, reaaliluvut,
ajankesto, päivämäärä, ajankohta, päivämäärä ja ajankohta sekä tekstinpätkä. Myös muut-
tujat voivat olla paikallisia tai globaaleja, eli samankaltaisuuksia olio-ohjelmointiin löytyy.
PLC-ohjelmat toimivat ikuisessa silmukassa, jossa toteutetaan erilaisia sekvenssejä.
9
ST:n operaattorit sekä lausekkeet voi karkeasti jakaa neljään eri luokkaan (“Structured Text
Tutorial to Expand Your PLC Programming Skills” 2018-09-20):
1 . A r i t m e e t t i s e t o p e r a a t i o t
2 . R e l a a t i o n a a l i s e t o p e r a a t i o t
3 . L o o g i s e t o p e r a a t i o t
4 . B i t t i o p e r a a t i o t
Aritmeettiset operaatiot sisältävät summalaskut, negaatiot ja vähennyslaskut, moninkerrat,
eksponentit, jakamisen sekä modulon. Relaationaaliset operaatiot puolestaan sisältävät yh-
täkuin, pienempi kuin, pienempi tai yhtä iso kuin, suurempi kuin, suurempi tai yhtä iso
kuin ja ei samankokoiset vertailut. Loogiset operaatiot ja bittioperaatiot puolestaan sisäl-
tävät AND:in, OR:in, XOR:in ja NOT:in. Erona näiden käytössä bittioperaatioissa verrattu-
na loogisiin operaatioihin on, että samat toiminnot suoritetaan bittitasolla, eli boolean logii-
kan totuustaulujen mukaisesti (“Structured Text Tutorial to Expand Your PLC Programming
Skills” 2018-09-20).
ST:n suurin hyöty on koodin kierrätettävyys (“Structured Text Tutorial to Expand Your PLC
Programming Skills” 2018-09-20). LD:n graafisuuden sijasta tekstipohjainen ohjelmointi-
kieli on suuri etu, sillä samaa koodia pystyy tällä tavalla helposti uudellenkäyttämään. Tii-
vistettynä ST on siis tekstipohjainen vastaus LD:n graafiselle lähtökohdalle, minkä tuomat
edut ovat merkittäviä verrattuna graafiseen kieleen. PLC-laitteiden tarvitsee kuitenkin usein
kommunikoida toisten laitteiden kanssa. Tätä varten on kehitelty erilaisia tiedonsiirtoproto-
kollia, joista yksi on Modbus.
10
3.2 Modbus Protokolla
Yksinkertaisissa laitteissa ja käyttötapauksissa, esimerkiksi yksinkertaisessa palohälyttimes-
sä, riittää, että kolvaa kuparilangan kiinni virtapiiriin, jotta saa signaalin milloin kyseinen
laite hälyttää. Kompleksisemmissa tapauksissa sovelletaan jotakin tiedonvälitys-protokollaa.
Yksi käytettävistä protokollista on Modbus. Modbus on myös tämän tutkielman kannalta
olennainen, sillä projektin laitteisto käyttää Modbus-protokollaa.
Modbus on Modiconin (nykyään Schneider Electric) vuonna 1979 julkaisema sarjaliikenne-
protokolla. Nykyään se toimii teollisuuden de facto -standardina, eli suurin osa maailman
automaatiojärjestelmistä toimii Modbus-protokollalla (Phan 2012). Suuri osa nykyajan au-
tomaatioista itseasiassa käyttää jonkinlaista muunnelmaa virallisesta Modbus-protokollasta.
Yksittäinen laite käyttää Modbus-protokollaa, jonka avulla se saa ohjeistuksensa logiikkaoh-
jelmalta. Tämän jälkeen laite välittää viestinsä samalla protokollalla eteenpäin.
Jokainen modbus-yhteys koostuu ohjaaja-ohjattava (master-slave) -tyyppisestä kommuni-
kaatiosta. Tämä tarkoittaa että master-laite lähettää viestejä, joita slave-laite kuuntelee ja to-
teuttaa annetut käskyt. Modbus on sarjaliikenne protokolla, joka toimii parikaapelilla. Moni-
mutkaisemmissa tapauksissa laitteeseen liitetään Ethernet-portti tai sarjakytkentä, mitkä kon-
figuroidaan kommunikoimaan Modbus-protokollan kanssa, jolloin kyseiseen laitteeseen on
mahdollista päästä käsiksi TCP/IP-protokollilla (Modbus 2004). Tällöin puhutaan Modbus-
protokollan variaatiosta: Modbus TCP/IP - tai Modbus TCP -protokollasta. Muunneltu Mod-
bus TCP siis vie Modbus protokollan TCP:n sovelluskerrokseen. Lukuisista Modbus-variaatioista
huolimatta tässä tutkielmassa keskitytään lähinnä aiemmin mainittuun TCP/IP -variaatioon
Modbus-protokollasta, sillä se on tämän projektin laitetoiminnan ymmärtämisen kannalta
olennaisin variaatio kyseisestä protokollasta. Viestien välitys tapahtuu kirjoittamalla laittei-
den rekistereihin erilaisia arvoja, joita lukemalla tämä laitteisto saa käskynsä.
11
Kuvio 3. Modbus TCP esimerkki, lähde: “How do you program and parameterize Mod-
bus/TCP communication between S7-1500 CPUs and S7-1200 CPUs?” (2018-10-16).
Modbus TCP/IP -protokolla toimii hyvin samankaltaisella tavalla kuin perinteinen asiakas-
palvelin -arkkitehtuuri, jota enemmistö internetistä käyttää. Modbus-protokollan käyttämä
portti on 502. Modbus-viestin kehys koostuu sovelluksen data yksiköstä (ADU, Applica-
tion Data Unit), joka kapseloi sisällensä protokolla data yksikön (PDU, Protocol Data Unit).
ADU koostuu osoitteesta, PDU:sta ja virheentarkistuksesta. PDU puolestaan kostuu funk-
tion koodista ja datasta (Modbus 2004). Vaihtoehtoja protokollan viestintämuotoon on usei-
ta, mutta Ethernet-verkoissa käytetään Modbus TCP kehystä, jonka Modbus 2004 määritte-
lee seuraavan taulukon mukaisesti. Tässä taulukossa asiakas muodostaa kaikki nämä neljä
kohtaa. Palvelin puolestaan kopioi tunnisteet ja käyttää niitä, muodostaen oman vastausvies-
tinsä pituuskentän. Tämän kehyksen bittijärjestys on MSB (Most significant bit, merkittävin
bitti ensimmäisenä).
Nimi Pituus Kuvaus
Transaktion tunniste 2 tavua Synkronisaatio palvelimen ja asiakkaan välillä
Protokolla tunniste 2 tavua 0 = Modbus protokolla
Viestin pituus 2 tavua Viestin pituus kahdessa tavussa
Yksikön tunniste 1 tavu Slave-laitteen tunniste (255 jos ei käytössä)
Taulukko 1. Modbus TCP:n rakenne
12
3.3 PLC käyttötapauksia
Koska PLC:n sisäisen logiikan pystyy itse ohjelmoimaan, ovat sen käyttötapaukset erit-
täin vaihtelevia, mutta usein koordinaatiota vaativissa tehtävissä PLC-laitteisto yhdistetään
SCADA-ohjelmistoon (Fernandez Adiego, Prieto Barreiro ja Blanco Vinuela 2011). Useim-
mat automaatiojärjestelmät toimivat jonkinlaisella yhdistelmällä SCADA:a (Goldenberg ja
Wool 2013) sekä PLC:tä (Erickson 1996). PLC:n levinneisyys on sellainen asia, mitä harva
ihminen tulee edes ajatelleeksi. Näitä pieniä tietokoneita käytetään kaikkialla missä tarvitaan
automaatiota: tehtaissa, ydinvoimaloissa, metrojärjestelmissä ja niin edelleen.
Tämän projektin liikenteenhallinta sekä LVIS-laitteisto toimivat PLC:llä. Tämä tarkoittaa
esimerkiksi useita liikennevaloja, liikennepuomeja, kameroita, ilmanpuhaltimia, varoitus-
merkkejä, tieopasteita sekä kaikkea muuta mitä tämänkaltaiseen suureen tunnelijärjestel-
mään kuuluu. Kokonaisuuden hallitsemiseen tarvitaan SCADA:a (Supervisory Control and
Data Acquisition), eli tuttavallisemmin valvomo-ohjelmistoa.
13
4 SCADA
SCADA (engl. Supervisory Control And Data Acquisition) on tietokoneohjelmisto- tai arkki-
tehtuurityyppi, jolla yleisesti tarkoitetaan valvomo-ohjelmistoa. Kuten Boyer (2009) toteaa:
"SCADA teknologia on kehittynyt viimeisen 30 vuoden aikana suurien prosessien monito-
riontiin ja kontrolloimiseen."
Useimmiten SCADA:a käytetään PLC-laitteiston monitorointiin ja käskyttämiseen (Daneels
ja Salter 1999). Ajatus SCADA-ohjelmiston takana on saada hallitusti kerättyä tietoa useasta
lähteestä ja pystyä reagoimaan erilaisissa tilanteissa valvomon käyttöliittymän kautta, kuten
tulipalon syttyessä tai sähkövian ilmentyessä. SCADA-järjestelmät on usein myös mahdol-
lista kahdentaa: sama sovellus voi omata URI:n sekä aktiivisesta että passiivisesta palveli-
mesta, jolloin esimerkiksi yhteysvian sattuessa passiivisesta palvelimesta tulee sovelluksen
aktiivinen palvelin ja toisinpäin. SCADA-järjestelmän on tarkoitus olla ennen kaikkea luo-
tettava.
Usein nykyaikaiset valvomojärjestelmät kommunikoivat myös muiden järjestelmien kans-
sa, joko internetin tai kirjoittamansa tietokannan kautta. Tämä tosin on tuonut esiin huo-
mioita ja puutteita SCADA-järjestelmien tietoturvasta (Choi ym. 2010; Igure, Laughter ja
Williams 2006; Ten, Liu ja Manimaran 2008). Esimerkiksi Suomessa on neljä tieliikenne-
keskusta (Tampere, Helsinki, Turku, Oulu), joissa päivystetään tieliikennettä. Näiden kes-
kuksien valvomoissa on useita SCADA-ohjelmistoja joilla ohjataan liikenneympäristöä, ku-
ten tämän projektin tapauksessa. T-LOIK-hankkeen myötä liikennevirasto pyrkii yhtenäistä-
mään liikennekeskuksen päivystäjän työn yhden käyttöliittymän taakse, joka välittää viestit
eri SCADA ohjelmistoille. YSP Oy:n käyttämänä SCADA-ohjelmisto on WinCC Open Arc-
hitecture.
14
4.1 WinCC Open Architecture
WinCC OA on Siemens kehittämä SCADA-järjestelmä, jonka tarkoituksena on visualisoi-
da ja operoida erilaisia prosesseja, tuotantovirtoja, laitteita ja tehtaita kaikilla eri liiketoi-
minnan osa-alueilla. Ohjelmiston hajautettu rakenne mahdollistaa jopa 2048 ohjausjärjes-
telmän liittämisen toisiinsa saumattomasti (“The SCADA system without limits” 2018-08-
15). Lienee syytä mainita, että tässä puhutaan 2048:sta erillisestä järjestelmästä, eikä pel-
kästään yksittäisistä laitteista. Jokainen näistä järjestelmistä voi omata lukuisia eri yhteyksiä
eri PLC-laitteille. WinCC OA:n vahvuuksiin kuuluu sen tarjoama tehokkuus sekä skaalau-
tuvuus (Spangenberg, Cerff ja Kaiser 2011). WinCC OA:ta pystyy kustomisoimaan usealla
eri tavalla sekä se on alustariippumaton, eli siitä on myös saatavilla valmis jakelu Windows-,
Linux-, iOS- ja Android -käyttöjärjestelmille (“SIMATIC WinCC Open Architecture - Ba-
sic system” 2018-08-15). WinCC OA:n päälle on myös mahdollista suunnitella graafinen
käyttöliittymä.
Pähkinänkuoressa WinCC OA:n tarkoitus on siis kerätä ja välittää dataa useaan eri lähtee-
seen. Sen muokattavuuden yhdistäminen PLC-laitteistoon tarjoaakin erittäin paljon erilaisia
käyttötapauksia, mistä syystä WinCC OA:n käyttötarkoitukset sisältävät useanlaisia erilaisia
järjestelmiä. Näihin sisältyy esimerkiksi Norjan tieliikennekeskuksen liikenteenhallintajär-
jestelmä, ohjaus- ja virheenraportointi järjestelmä Sveitsin rautateille, Ranskan Besançonin
kaupungin katuvalaistuksen hallintajärjestelmä ja CERN-tutkimuskeskuksen hiukkasfysii-
kan laboratorion hallintajärjestelmä (“SIMANTIC WinCC Open Architecture - HMI Softwa-
re - Siemens” 2019-03-07).
WinCC OA:n ohjelmointikielenä toimii CTRL (control script language). CTRL:n syntaksi
perustuu ANSI-C:n standardiin (“Control script language” 2018-08-15), eli se on C:n va-
riantti, mikä tekee syntaksin opettelusta varsin triviaalia kokeneemmalle ohjelmoijalle. Ny-
kyään WinCC OA tarjoaa myös rajapinnan C#-ohjelmointikielelle, minkä kautta voi lukea
ja kirjoittaa prosessiarvoja, hälytyksiä ja historiadataa. WinCC OA tarjoaa myös rajapinnan
erilaisille tietokannoille kuten Access, Oracle ja Microsoft SQL (“Control script language”
2018-08-15). Tämä mahdollistaa esimerkiksi erillisen web-sovelluksen luomisen, mikä tark-
kailee WinCC OA:n käyttämän tietokannan dataa (Varela ym. 2018; Qiu ja Gooi 2000).
15
WinCC OA:lla on myös mahdollista luoda paneelitiedostoilla ja CTRL-skripteillä erilaisia
komponentteja sekä yhdistellä näitä graafisen käyttöjärjestelmän luomiseksi. Tämän ohjel-
miston suurin vahvuus on sen huomionarvoinen hajautettu arkkitehtuuri: järjestelmän eri
osat on luotu yksittäisiksi erilaisiksi komponenteiksi, joita WinCC OA:n prosessimanageri
tarkkailee ja käskyttää. Tällä periaatteella myös DriverManager rekisteröidään WinCC OA:n
prosessimanagerin prosessiksi. WinCC OA on siis ennen kaikkea hajautettu järjestelmä, jo-
ka rakentuu useista erilaisista komponenteista. Kun tähän käyttöliittymään yhdistää datan
vastaanottamisen ja välittämisen, on valvomo-ohjelmisto valmis.
4.2 Datan vastaanottaminen ja välitys WinCC OA:ssa
Datan kulkemisketju tapahtuu datapointeilla. WinCC OA:ssa asetetaan jokin tietty tunnis-
te datapointille. Tämä datapoint-rakenne voidaan myös konfiguroida kuuntelemaan Modbus
TCP-yhteyttä jostakin tietystä osoitteesta. Tämä ei tietenkään ole pakollista, eli datapoint-
teja voi myös käyttää väliaikaisena arvon säilytyspaikkana, johon C# API:n avulla voidaan
syöttää jotain dataa, jota myöhemmin sitten käsitellään WinCC OA:n sisäisissä operaatiois-
sa, kuten luvussa 8.4 esitetään. Jos datapoint sidotaan johonkin Modbus TCP -osoitteeseen,
osoitetta koskevaa liikennettä pystyy käsittelemään WinCC OA:ssa ja C#-rajapinnassa viit-
taamalla sen datapointtiin. Juuri tällä tavalla yksittäiset liikenteenhallinta laitteistot liitetään
valvomojärjestelmään, joka sitten antaa niille käskyjä kuten valon vaihtaminen tai liikenne-
puomin nostaminen.
Koska WinCC OA:n prosessiarvoja on mahdollista käsitellä eri ohjelmointikielillä ja se tarjo-
aa C#-rajapinnan, C# on erittäin looginen valinta kun WinCC OA:n tuottamaa dataa ruvetaan
tulkitsemaan ja välittämään muille sovelluksille.
16
5 REST-arkkitehtuuri & T-LOIK-Ohjaussovitin
REST (Representational State Transfer) on moderni arkkitehtuurimalli web-kehitykseen. Al-
lapiilevät ominaisuudet ovat hyvin ohjelmistokohtaisia, mutta REST-arkkitehtuurin ohjelmat
käyttävät aina HTTP-protokollan ominaisuuksia toteuttaakseen erilaisia operaatioita.
T-LOIK-Ohjaussovitin on REST-sovellus, jonka tarkoituksena on välittää T-LOIK:n viestejä
PLC-laitteistolle ja SCADA-järjestelmille. Se toimii liitoksena liikennejärjestelmiin, joita T-
LOIK ohjaa ja valvoo. Myös T-LOIK on REST-sovellus, joten kyseisen arkkitehtuurimallin
ymmärtäminen on olennaista kokonaiskuvan hahmoittamisen kannalta. Tässä luvussa pyri-
tään avaamaan REST-arkkitehtuuria sekä sen roolia moderneissa Suomen liikennejärjestel-
missä.
17
5.1 REST-arkkitehtuuri
REST-arkkitehtuurin tarkoituksena on jakaa web-sovelluksen eri toiminnallisuudet selkeästi
eroteltaviin kokonaisuuksiin. Arkkitehtuuri tarjoaa HTTP-protokollan yli erilaisia operaa-
tioita, jotka ovat mahdollisimman itsenäisiä, eivätkä omaa riippuvuuksia toisiin sovelluksen
operaatioihin. Kun sovellus toteuttaa REST-arkkitehtuurin, kutsutaan sovellusta RESTful-
sovellukseksi. Kuten Feng, Shen ja Fan (2009) toteavat: "REST-arkkitehtuuri ei ainoastaan
pysty hyödyntämään kaikkia HTTP-protokollan tarjoamia ominaisuuksia, vaan omaa myös
yksinkertaisuuden tarjoaman edun."
Kuusi suunnitelmallista periaatetta ohjaavat RESTful-kehitystä (Erl ym. 2012):
1 . Asiakas-palvelin -arkkitehtuuri
2 . Tilattomuus
3 . Välimuistiin tallentamisen mahdollisuus
4 . Kerroksittainen järjestelmätoteutus
5 . Koodin välitystä tarvittaessa ("Code on demand")
6 . Yhtenäinen rajapinta
Ensimmäinen periaate on hyvin yleinen web-sovelluksien kannalta: jokin järjestelmä toimii
palvelimena ja jokin asiakkaana, joka käyttää tämän palvelimen tarjoamia palveluja. Toinen
on puolestaan yleisimpiä REST-kehityksen periaatteita: REST-arkkitehtuurin mukaan teh-
dyn sovelluksen täytyy olla tilaton, eli jokainen operaatio on atominen eikä omaa jonkin
toisen operaation suorittamista esivaatimuksena. Kuten Rodriguez (2008) toteavat: "Tässä
yhteydessä tilattomuus parantaa web-palvelun suorituskykyä ja yksinkertaistaa palvelinpuo-
len komponenttien suunnittelua ja toteutusta, sillä tilan puuttuminen poistaa tarpeen synkro-
nisoida sessioiden dataa ulkoisten sovellusten kanssa."
Kolmas puolestaan on lähinnä sovelluksen suoritusnopeuden kannalta olennainen tekijä: vä-
limuistissa olennaisen tiedon säilyttäminen nopeuttaa ohjelman käyttöä ja vähentää latenssia
(Erenkrantz 2009). Välimuisti voi tässä tapauksessa olla palvelimen tai web-selaimen väli-
muisti.
18
Neljännen periaatteen mukaan REST-arkkitehtuuria seuraavassa sovelluksessa tarkoittaa kom-
ponenttien jakamista järkeviin kokonaisuuksiin, joissa matalamman tason resurssit tarjoavat
toiminallisuuksiaan ylemmille tasoille. Tällä toteutuksella järjestelmän komponentit eivät
tiedä mitään muista komponenteista, ainoastaan niistä joiden kanssa ne itse suoranaisesti
kommunikoivat (Chou ja Li 2016). Kyseessä on siis kapselointia vastaava periaate.
Viides kohta - eli koodin välitys tarvittaessa - on vapaaehtoinen, mutta toteutuu esimerkiksi
kun REST-sovellus tarjoaa web-selaimella Javascript-tiedostoja, joilla manipuloidaan web-
sivun sisältöä ja välitetään viestejä palvelimelle (Masse 2011).
Kuudes kohta on olennainen REST-sovelluksen kehitykseen ja jakautuu erinäisiin alakoh-
tiin, joiden tarkoituksena on tarkemmin määritellä kyseinen yhteinen rajapinta. Nämä koh-
dat ovat: pyydettyjen resurssien identifiointi palvelupyynnöissä, kuten tietyn URI:n kutsu-
minen tietyllä HTTP:n metodilla, resurssien manipulaatio representaatioiden kautta, atomi-
set viestit, eli jokainen viesti omaa kaiken operaatioon vaadittavan tiedon sekä HATEOAS
(Hypermedia as the engine of application state), eli hypermedia applikaation tilan mootto-
rina (Thijssen 2012). Palvelinpuoli vain suorittaa näitä atomisia operaatioita, ja sovelluksen
"tila"päätellään siitä mitä operaatiota kutsutaan.
T-LOIK-ohjaussovittimen tapauksessa kaikki kohdat paitsi viides toteutuvat - kyseinen so-
vellus ei omaa front endiä tai varsinaista käyttöliittymää, pelkästään RESTful operaatioita.
Esimerkiksi yksittäisen liikennevalon tilan hakemiseksi suoritetaan HTTP:n GET-operaatio
tiettyyn URL-osoitteeseen, kuten esimerkiksi https://www.server.org/liikennevalo/id/status.
Jos taas laitteen tilaa halutaan muokata, suoritetaan erilainen HTTP-operaatio, kuten POST
tai PUT eri URL-osoitteeseen. Jokainen aloituspiste ohjelmakoodin suoritukselle on sidottu
johonkin HTTP-metodiin (GET, POST, PUT, DELETE) sekä osoitteeseen. REST-arkkitehtuuri
seuraa CRUD-mallia (Create, Read, Update, Delete). Tämä malli asettaa raamit joiden mu-
kaisesti kyseinen sovellus toimii.
19
5.2 T-LOIK-Ohjaussovitin ja Akka.NET
Akka.NET on .NET versio Javan Akka-ohjelmistokirjastosta. Akka.NET perustuu Aktori-
suunnittelumalliin, jonka kehitti Carl Hewitt vuonna 1973 (Hewitt, Bishop ja Steiger 1973).
Akka.NET:in kehittäjien mukaan tämän kirjaston päämääränä on tarjota seuraavanlaisia toi-
mintoja (“What is Akka.NET?” 2018-08-15):
1 . Monisäikeistä käytöstä ilman matalan tason konstruktioita, kuten lukkoja ja atomisuutta
2 . Läpinäkyvää etäkommunikaatiota eri järjestelmien ja komponenttien välillä
3 . Klusteroitua ja skaalautuvaa arkkitehtuuria
Aktori-suunnittelumallissa pyritään tarjoamaan abstraktiota, joissa komponenteista tai jär-
jestelmistä tehdään omia aktoreitaan, jotka kommunikoivat keskenään asynkronisilla vies-
teillä metodikutsujen sijasta. Aktorit ylläpitävät ja hoitavat omaa tilaansa sekä reagoivat aina
vastaanottaessaan muutosviestin. Tämä reaktio voi olla esimerkiksi lapsi-aktorin luominen,
itsensä pysäyttäminen, lapsensa pysäyttäminen tai viestin välitys toisille aktoreille (“What is
Akka.NET?” 2018-08-15).
T-LOIK-Ohjaussovitin on adapteri-sovellus, joka välittää viestejä T-LOIK:n ja SCADA:n tai
PLC-laitteiden välillä. Sovelluksen tarkoituksena on integroida useita eri SCADA-järjestelmiä
ja PLC-laitteistoja T-LOIK:n käyttöliittymään, eli tulkita T-LOIK:n laittamien REST-kutsujen
sisällä kulkevasta XML:stä varsinainen komento ja muuttaa se joko SCADA:n tai PLC-
laitteen ymmärtämään muotoon.
T-LOIK-Ohjaussovittimen tapauksessa jokaista yksittäistä laitetta - kuten kamera, liikenne-
valo, tiedotusopaste, puomi ja niin edelleen - edustaa yksittäinen aktori, joka toteuttaa ky-
seisen laitteen vaatiman protokollan. Näitä protokolla-luokkia on tietenkin vain yksi, mutta
ohjelmiston ollessa ajossa jokaisesta laitteesta luodaan oma erillinen aktori-instanssinsa. Tä-
mä aktori on käytännössä C#-luokka, joka Akka.NET:iä hyödyntäen kuuntelee ja välittää
viestejä laitteen ja T-LOIK:n välillä. Yksittäiset laitteet määritellään rekursiivisessa XML-
tiedostossa. Esimerkiksi yksittäisen liikennevalon asetus voisi näyttää XML-muodossa tältä:
20
< a s e t u s n imi =" l i i k e n n e v a l o 1 " kuvaus =" l i i k e n n e v a l o n 1 a s e t u k s e t ">
< a s e t u k s e t >
< a s e t u s n imi =" i d " kuvaus =" l i i k e n n e v a l o n Id " a rvo =" 1 " / >
< a s e t u s n imi =" o s o i t e " kuvaus =" v a l o n ip−o s o i t e "
a rvo =" 1 2 7 . 0 . 0 . 1 " / >
< a s e t u s n imi =" p r o t o k o l l a " kuvaus ="AKKA. NET a k t o r i l u o k k a "
a rvo =" v a l o P r o t o k o l l a " / >
</ a s e t u k s e t >
</ a s e t u s >
Tämä aktori parsii T-LOIK:n REST-kutsulla lähettämän XML-tiedoston sisällöstä oleellisen
ohjauksen, muuttaa sen PLC-laitteen tai SCADA:n hyväksymään muotoon, suorittaa ohjauk-
sen, vastaanottaa kuittausviestin laitteelta ja parsii kuittausviestistä oleellisen tiedon ja kon-
vertoi sen takaisin T-LOIK:n hyväksymään XML-muotoon. Akka.NET siis toimii työkaluna,
jonka avulla PLC-laitteita saadaan käsiteltyä C#:n kaltaisen korkean tason ohjelmointikielen
vaatimalla abstraktiotasolla.
Esimerkiksi liikennevalojen suoraohjauksessa - eli ilman SCADA-järjestelmää - ohjaussovit-
timen liikennevalojen protokolla-aktori lukee tiedon kyseistä aktoria vastaavan laitteen IP-
osoitteesta ja eri funktiokäskyjen sijainnit PLC-laitteen muistirekisterissä sekä omaa tarvit-
tavat metodit tämän XML-käskyn konvertoimiseen muotoon, jonka PLC ymmärtää. Sinän-
sä ohjausmetodi on samanlainen myös WinCC OA-järjestelmien kanssa: erona on lähinnä
se, että muistiavaruuden osoitteiden ja hexalukujen sijasta käskyjä välitetään datapointteihin
WinCC OA:n tukemassa muodossa. T-LOIK-ohjaussovittimen toimintaa kuvaa kuviossa 4
oleva tietovuokaavio:
21
T-LOIK:in ohjatessa liikennevaloa T-LOIK laittaa verkon yli ohjaussovittimelle REST-kutsun,
joka sisältää XML-datana esitetyn ohjauskäskyn. Ohjaussovitin lukee tämän käskyn, etsii sa-
maa laitetyyppiä ja saman tunnisteen omaavan protokolla-aktorin ja lukee protokolla-aktorin
luokan tiedoista sen IP-osoitteen sekä muut relevantit tiedot, minkä jälkeen ohjaussovitin
suorittaa funktion, joka muokkaa tästä XML-käskyn datasta aktori-luokan määrittelemän ta-
vutaulukon tai SCADA:n tapauksessa jonkin muun tietotyypin, jonka ohjaussovitin välittää
PLC-laitteelle tai SCADA-järjestelmään. Samalla logiikalla välitetään tietoja PLC-laitteista
ja SCADA-järjestelmistä T-LOIK:iin, nämä operaatiot vain suoritetaan päinvastaisessa jär-
jestyksessä.
T-LOIK-Ohjaussovitin toteuttaa usean eri suunnittelumallin ominaisuuksia:
1 . AKKA.NET-kirjaston tarjoaminen aktoreiden avulla kyseinen applikaatio toteuttaa
Aktori-suunnittelumallin (Actor Model).
2 . T-LOIK sekä T-LOIK-Ohjaussovitin voivat kummatkin toimia sekä palvelimena että
asiakkaana, kommunikoiden keskenään REST-kutsuilla ja XML-tiedostoilla, joten se
toteuttaa myös kahdensuuntaisen palvelin-asiakas-suunnittelumallin.
3 . Viestinvälittäjä-suunnittelumalli (Broker pattern) toteutuu, sillä T-LOIK:illa voi olla
monta instanssia eri palvelimilla, mitkä kommunikoivat saman ohjaussovittimen kautta
PLC-laitteistolle ja SCADA-järjestelmille.
4 . Modbus TCP:n toteuttamisen seurauksesta myös master-slave -arkkitehtuuria
hyödynnetään paljon.
5 . SCADA-järjestelmien tavoin ohjaussovitin on mahdollista kahdentaa kahden eri
palvelimen toimintaan, jotka tarvittaessa vaihtavat aktiivisen ja passiivisen palvelimen
välillä. (Hot Standby)
Tämän ohjelmiston avulla SCADA-järjestelmä ja sen aliprosessiksi rekisteröity XaidDriver
yhdistyvät T-LOIK:n järjestelmään.
23
6 Managed Extensibility Framework & DriverManager
MEF (Managed extensibility framework) on .NET 4.0 versiossa ensijulkaisunsa kokenut
Microsoftin ohjelmistokirjasto (“Managed Extensibility Framework (MEF)” 2018-09-24).
MEF:in päätarkoitus on helpottaa ohjelmiston laajentamista, sillä se sallii laajennusten koo-
din helpon kapseloinnin erillisiksi komponenteiksi, joita uudelleenkäytetään eri sovelluksien
välillä ilman kovakoodattujen riippuvuuksien muodostamista (“Managed Extensibility Fra-
mework (MEF)” 2018-09-24). DriverManager on C#-ohjelmointikiellä rakennettu ajurialus-
ta WinCC OA -ohjelmille, joka on toteutettu .NET-kirjaston MEF-kirjastolla.
MEF-komponentit rekisteröidään isäntä-sovellukseen pelkällä konfiguraatio-tiedostolla, jon-
ka jälkeen sovellus pystyy käyttämään näitä komponentteja. MEF tarjoaa tavan löytää uudet
komponentit implisiittisesti: MEF-komponentti ilmaisee konfiguraatio-tiedostossa sekä riip-
puvuutensa että tarjoamansa ominaisuudet. Kun yksittäinen MEF-komponentti (kutsutaan
nimellä part) liitetään ohjelmistoon, MEF-kehyksen koostaja-moottori (MEF composition
engine) liittää sen tarjoamat toiminnallisuudet muihin MEF-komponetteihin (“Managed Ex-
tensibility Framework (MEF)” 2018-09-24).
Tässä käyttötapauksessa DriverManager on MEF-applikaatio, joka kuuntelee WinCC OA:n
Datapointtien muutoksia ja toteuttaa niiden perusteella jotain operaatioita. DriverManagerin
sekä ajurien mahdolliset riippuvuudet sijoitetaan WinCC OA:n kansiorakenteen sisälle, jol-
loin Win CC OA:n projektimanageri löytää DriverManagerin .exe-tiedoston. Tämän jälkeen
DriverManager rekisteröidään SCADA-järjestelmän projektimanageriin. Rekisteröinnin jäl-
keen projektimanageri hoitaa DriverManagerin käynnistämisen, sulkemisen, uudelleenkäyn-
nistämisen ja yleisen monitoroinnin. DriverManagerin konfiguraatiotiedostoon määritetään
ajurien kansiosijainti. XaidDriverin koodin kääntämisestä syntynyt .dll-tiedosto sijoitetaan
tietokoneella tähän määriteltyyn kansioon, jonka jälkeen DriverManager löytää ja käynnis-
tää tämän ajurin.
24
Kuvio 5. DriverManager WinCC OA:n projektimanagerin aliprosessina
Kuviossa näkyy esimerkkikonfiguraatio WinCC OA:n projektinhallinta konsolista, jossa lis-
tataan ohjelmaan ladatut erilliset komponentit, joita projektimanageri monitoroi. Viimeisenä
prosessina näkyy WCCOADriverManager. DriverManager toimii MEF-sovelluksen liitos-
kohtana WinCC OA-ohjelmistolle: konfiguraatiot toteutetaan JSON-muodossa. Esimerkik-
si XaidDriverin konfiguraatio, joka sijoitetaan WinCC OA-järjestelmän tietorakenteeseen,
näyttää simulaatiotilanteessa seuraavalta:
25
{
" i n p u t " : {
" x a i d " : {
" managerNumber " : 1 ,
" a c t i v e " : 1 ,
" connect ionName " : " xa id −1" ,
" a d d r e s s " : " h t t p : / / l o c a l h o s t : 1 1 1 8 0 / x a i d / " ,
" r ed un da nc yAd dr e s s " : " h t t p : / / l o c a l h o s t : 1 1 1 8 1 / x a i d / " ,
" oldNewComparison " : true ,
" p o r t " : " 9991 " ,
" r e d u n d a n c y P o r t " : " 9992 " ,
" i p " : " 1 2 7 . 0 . 0 . 1 " ,
" r e d u n d a n c y I p " : " 1 2 7 . 0 . 0 . 1 " ,
" c r e a t e X a i d D a t a p o i n t s " : f a l s e
}
}
}
DriverManager kyselee ja lukee nämä tiedot SCADA-järjestelmän tietorakenteesta. Käyn-
nistyessään se kyselee jokaisen datapointin yleiset konfiguraatiot ja etsii ennaltamääritel-
lystä paikasta tämänkaltaisia konfiguraatiotietoja. Output- ja input-kenttien sisällä olevan
olion nimi määrittelee etsittävän ajurin. Esimerkiksi XaidInputDriver-luokassa on luokan
nimeksi määritelty "xaid", joten DriverManager osaa yhdistää tämän konfiguraatiotiedos-
ton ja löytyneen ajurin .dll-tiedoston. Tämä mahdollistaa ohjelman vaatimien peruspara-
metrien välityksen: tämän JSON-tekstin lukeminen string-muuttujasta tarjoaa XaidDrive-
rille HTTP-rajapinnan osoitteen sekä TCP-yhteyden IP-osoitteen ja portin. Näillä tiedoilla
MEF-applikaatio käynnistää ajurin ja aloittaa välittämään dataa SCADA-järjestelmän ja X-
AID-järjestelmän välillä.
Osasta datapointeista halutaan myös ajonaikaisesti lukea dataa JSON-muodossa. Tällaisten
datapointtien sisään sijoitetaan aiemman kaltainen output-JSON, joka näyttää seuraavalta:
26
{
" o u t p u t " : {
" x a i d " : {
" managerNumber " : 1 ,
" a c t i v e " : 1 ,
" t y p e " : " camera " ,
" i d " : 9010 ,
" s e r v e r I d " : 1 ,
" connect ionName " : " XaidCam−HKA10" ,
" c o n n e c t i o n S t r i n g " : " h t t p : / / l o c a l h o s t : 1 1 1 8 0 / x a i d / s i m u l a t o r / "
}
}
}
Tämä JSON kertoo DriverManagerille, että tämän datapointin arvojen muutosta halutaan
kuunnella. Output-avaimen alla oleva xaid-avain puolestaan kertoo ajurin nimen. Tämä sallii
tämän datapointin kenttien arvojen lähettämisen XaidOutputDriver-luokan funktiolle Out-
putChangedAsync, joka sitten tulkitsee arvoja ja suorittaa parametrisoituja toimintoja.
27
7 X-AID häiriönhavaintojärjestelmä ja testivetoinen
kehitys
X-AID häiriönhavaintojärjetelmä on keinoälyä ja koneoppimista hyödyntävä liikenteen mo-
nitorointijärjestelmä. X-AID on AVID (Automatic Video Incident Detection) järjestelmä, eli
koneoppimista hyödyntävä X-AID-palvelin analysoi jatkuvalla syötöllä sille saapuvaa video-
kuvaa liikenteestä. Tämän projektin tapauksessa X-AID-järjestelmä valvoo tunnelin liiken-
nettä mahdollisissa ongelmakohdissa ja välittää viestejä valvomoon. Hälytyksien lauetessa
PLC-laitteisto laukaisee erilaisia liikenteenohjaus-sekvenssejä. Nämä sekvenssit esimerkiksi
sulkevat kaistoja, vaihtavat liikennevaloja punaisiksi, sulkevat liikennepuomeja ja vaihtavat
tieopasteiden tekstejä. Tämän tarkoituksena on lisätä liikenteen turvallisuutta ja sujuvuutta,
vähentäen vaaratilanteita.
X-AID häiriönhavaintojärjestelmän kanssa kommunikoidaan pääasiallisesti TCP-yhteydellä.
Järjestelmä omaa myös yksinkertaisen HTTP-rajapinnan, jonka kautta pystyy esimerkiksi
lataamaan johonkin tiettyyn hälytykseen sidotun videotiedoston. X-AID-palvelimen lähettä-
mästä tavutaulukosta tulkitaan varsinainen viestisisältö käsittelemällä tavutaulukkoa X-AID-
protokollan määritelmien mukaisesti. Tavutaulukko sisältää erilaisia muuttujatyyppejä, ku-
ten char, UInt32, UInt16 ja niin edelleen, joita parsitaan protokollan määritelmien mukaises-
ti. Varsinainen X-AID protokollan tekninen toteutus ja viestisisältö on määritelty järjestel-
män toimittajan tarjoamassa dokumentissa 2017-098-T004-V1r5 - External TCP Interface -
Technical Specification.pdf.
Onnistunut integraatio valvomojärjestelmiin ja tieliikenteen ohjausjärjestelmiin vaatii TCP-
datan reaaliaikaista lukemista, protokollan tulkkaamista ja viestien välittämistä SCADA:n
kautta PLC:lle ja takaisin. Jotta viestien välitys SCADA:n ja PLC:n suuntaan toimisi mahdol-
lisimman esteettömästi, toteutettiin kyseinen tulkkiohjelma TCP-kuuntelijana DriverMana-
gerin ajuriksi. Ajuri muodostaa myös aiemmin mainittuja HTTP-rajapinnan URL-osoitteita,
jotka välitetään SCADA:n kautta T-LOIK:iin. Tätä kautta T-LOIK ja SCADA pystyvät la-
taamaan hälytystapahtumista videotiedoston sekä kuvan HTTP:n kautta, ilman tarvetta TCP-
virran tulkkaamiselle.
28
7.1 Kuvaus X-AID häiriönhavaintojärjestelmästä
Järjestelmän toimittajan mukaan (“Traffic Video Analysis / Automatic Video Incident De-
tection - XAIDTM” 2018-09-27) osa-alueet joilla X-AID:ia voi hyödyntää ovat:
1 . Liikennevideoiden analysointi
2 . AVID-monitorointi tie-, tunneli- ja siltaosuuksilla
3 . Liikennerikkomusten ja epäsäännöllisyyksien havainnointi
4 . Liikenteen sujuvuuden monitorointi
Käytännössä X-AID vastaanottaa jatkuvaa videokuvaa tarkkailemastaan alueesta ja hälyt-
tää TCP:n kautta ajuria, jos epäsäännöllisyyksiä ilmenee. X-AID-järjestelmään ohjelmoidut
hälytykset ovat (“Traffic Video Analysis / Automatic Video Incident Detection - XAIDTM”
2018-09-27):
1 . Väärään suuntaan ajava ajoneuvo
2 . Pysähtynyt ajoneuvo
3 . Liikenneruuhka
4 . Hidas ajoneuvo
5 . Kävelijä
6 . Alentenut havainnointitaso (sumua, savua jne.)
7 . Esteitä tiellä
8 . Ajoradan ulkopuolella ajaminen
9 . Rekka-auto/Hidas ajoneuvo ohituskaistalla
1 0 . Keltaisen linjan ylitykset
1 1 . Ansalanka tiellä
Tästä listauksesta olennaisia tämän pro gradun kannalta ovat kohdat 1, 2 ja 4, sillä nämä
hälytykset ovat ainoat tässä projektissa huomioon otettavat hälytykset. Juuri hälytykset 1,2
ja 4 toimivat laukaisimina PLC-laitteiston suorittamille liikenteehallinta-sekvensseille.
29
7.2 X-AID-simulaattori
X-AID-järjestelmän (Automatic Video Incident Detection (AVID)) protokollatulkin kehitys-
tä varten järjestelmän toimittanut yritys tarjosi YSP Oy:lle käyttöön X-AID-simulaattorin.
Tämä simulaattori on toimitettu komentorivillä ajettavana .exe-tiedostona, joka pystyttää pai-
kallisen palvelimen ja ajaa simulaattoria.
X-AID-simulaattori tarjoaa sekä TCP-rajapinnan, jonka kautta pääasiallinen kommunikaa-
tio tapahtuu, sekä HTTP-rajapinnan, jolla pystyy aktivoimaan ja deaktivoimaan simuloituja
hälytyksiä. Tämä mahdollistaa TCP-yhteyden ottamisen ja hälytyksien simuloinnin HTTP:n
yli, jolloin TCP-yhteyden kautta saapuu informaatiota kyseisestä hälytyksestä.
Tarkemmat protokolla-määritelmät on myös tarjottu .pdf-tiedostoina. Näissä dokumenteissa
määritellään tavutaulukkojen sisältö, protokollan rakenne ja sopivat C#-ohjelmointikielen
tietotyypit sekä HTTP-kutsut joilla saa laukaistuja simuloituja hälytyksiä. Jokaisella viestillä
on 16 tavun otsikko, jonka jälkeen seuraa varsinainen tietosisältö, jota tulkitaan järjestelmän
toimittajan tarjoaman TCP-rajapinnan dokumentaation mukaisesti.
X-AID-simulaattori toimii varsinaisen kehitystyön selkärankana, sillä ottamalla TCP-yhteyden
simulaattoriin ja laukaisemalla hälytyksiä HTTP-kutsuilla pystyy palvelimelta vastaanotta-
maan simuloituja hälytyksiä, jotka vastaavat oikean elämän tilanteiden laukaisemia hälytyk-
siä. Näiden simuloitujen tilanteiden käsittely tapahtuu siis aivan samalla tavalla kuin oikeas-
sakin tilanteessa, mikä mahdollistaa itse protokollatulkin kehityksen.
Protokollamääritelmä tarjoaa myös selkeää osviittaa luokkasuunnitteluun, sillä on vähem-
män työlästä käyttää luokkasuunnittelun pohjana jo valmiiksi tässä dokumentissa määritel-
tyjä luokkarakenteita. Joka tapauksessa kyseisen simulaattorin tarjoama etu on huomattava
verrattuna esimerkiksi tilanteeseen, jossa olisi tarjolla vain .pdf-tiedosto protokollamääritel-
mistä. Tällöin järkevintä olisi kehittää simulaattori varsinaisen protokollatulkin kehityksen
ohessa. Lähtökohdat huomioon ottaen viisain tapa kehittää kyseinen ajuri on siis testivetoi-
nen kehitys (Test Driven Development).
30
7.3 Testivetoinen kehitys
Testivetoinen kehitys (Test Driven Development, TDD) on tapa suunnitella ohjelmistoja.
Aluksi vaatimuksista eritellään selkeät käyttötapaukset, joiden perusteella rakennetaan yksikkö-
ja integraatiotestit. Tämän jälkeen testejä vasten kehitetään itse ohjelmistoa, eli testit kirjoi-
tetaan ennen varsinaista ohjelman sisältöä. Testivetoisen kehityksen prosessin pystyy jaotte-
lemaan viiteen osaan (Beck 2003):
1 . Luo testi
2 . Aja testit ja katso epäonnistuuko kyseinen uusi testi
3 . Kirjoita koodi
4 . Aja testit
5 . Refaktoroi koodi
Tämän kehitystavan päämääränä on tuottaa helposti luettavaa ja siistiä koodia (Beck 2003).
Tarkoituksena on siis luoda epäonnistuvia testejä, luoda koodia joka toteuttaa testin läpäi-
semiseen vaadittavat operaatiot ja testien läpäisemisen jälkeen suorittaa tarvittavaa refakto-
rointia.
Testivetoisen kehityksen etuja ja haittoja on tarkasteltu useassa eri tutkimuksessa: esimer-
kiksi George ja Williams 2004 suorittivat kokeen, jonka tuloksista huomattiin, että testi-
vetoista kehitystä toteuttaneiden ohjelmoijien koodi oli parempilaatuisempaa, sillä heidän
koodinsa läpäisi 18% enemmän black-box testeistä kontrolliryhmään verrattuna. Tosin hait-
tana huomattiin, että testivetoista kehitystä toteuttavilla ohjelmoijilla kesti keskimäärin noin
16% enemmän aikaa. Myös IBM:n suorittamassa kokeessa (Maximilien ja Williams 2003)
huomattiin, että testivetoisen kehityksen avulla defektien määrä laski noin 50%. Automaa-
tiojärjestelmissä luotettavuus on luonnollisesti hyvin tärkeää, joten testivetoisen kehityksen
vahvuudet kannattaa hyödyntää tämän järjestelmäintegraation toteutuksessa.
31
8 XaidDriver
XaidDriver on X-AID-palvelimen rajapinta SCADA-järjestelmään. XaidDriver sijaitsee Dri-
verManagerin ajurina, joka toimii myös X-AID-järjestelmän välittämän TCP-protokollan
tulkkina sekä tämän suunnittelututkimuksen varsinaisena kohteena.
Hevner ja Chatterjee (2010) määrittelevät suunnittelututkimukselle kahdeksan eri kohtaa,
joihin tutkimuksen pitäisi pystyä vastaamaan:
1 . Mikä on tutkimuskysymys? Mitkä ovat vaatimukset?
2 . Mikä on suunnittelututkimuksen artifakti? Miten artefaktin toiminnot ilmenevät?
3 . Mitä suunnitteluprosesseja tai heurestiikkoja käytetään artefaktin rakennuksessa?
4 . Miten artefakti on sidonnainen todellisuuteen? Mitkä teoriat tukevat artefaktin
suunnittelua ja suunnitteluprosessia?
5 . Mitä evaluaatioita suoritetaan suunnittelusyklien aikana?
6 . Kuinka artefakti liitetään sovellusten ympäristöön ja kuinka sitä kenttätestataan?
7 . Mitä uutta tietoutta tämän artefaktin suunnittelusta syntyy?
8 . Onko suunnittelukysymykseen vastattu?
Tässä tapauksessa tutkimuskysymys on kuinka tämänkaltainen häiriöhavaintojärjestelmä in-
tegroidaan liikenteenhallintajärjestelmään. Tähän kysymykseen sisällöllisesti vastaa koko
tutkielma. Vaatimukset myös määritellään erikseen myöhemmin luvussa 8. Suunnittelututki-
muksen artefakti puolestaan on X-AID-järjestelmän valvomo-ohjelmiston ajuri, eli XaidDri-
ver. Suunnittelussa käytettyjä suunnittelumalleja ja heurestiikkoja käydään läpi luvussa 8.2
sekä luvussa 8.1. Evaluaatioina puolestaan toimivat yksikkötestit, integraatiotestit sekä kent-
tätestit, joita käydään läpi luvussa 9. Ajurin integraatiota olemassaolevaan ympäristöön puo-
lestaan avataan luvussa 8.3. Tutkimuskysymykseen vastaaminen ja uuden tiedon syntymistä
puolestaan pohditaan luvussa 10.
Aiemmin mainitun mukaisesti XaidDriver toteutettiin DriverManagerin ajuriksi, jotta kom-
munikointi WinCC OA:n suuntaan on helpompaa. Tämän lisäksi kehityksessä hyödynne-
tään ProtoLib-ohjelmistokirjastoa, joka on yleinen protokollakirjasto. Tämän protokollakir-
32
jaston tarkoitus on yksinkertaistaa TCP- tai UDP-yhteyksien luomista, sillä se on geneeri-
nen protokollatulkki-ohjelmistokirjasto. ProtoLib tarjoaa muutaman pakollisen toteutettavan
rajapinnan: IEncoder, IDecoder ja IMessageHandler. Näihin rajapintoihin kirjoitetaan sovel-
luskohtaiset koodit, mutta muuten itse kirjaston alustaminen on varsin yksinkertaista, kuten
luvun 8 koodista havaitsee.
ProtoLib-protokollakirjasto perustuu DotNetty-kirjastoon, joka on käännös Javan Netty-kirjas-
tosta. Hyödyntämällä näitä olemassaolevia kirjastoja ja komponentteja itse kehitystyössä
säästetään paljon aikaa. Muun muuassa SCADA-järjestelmän datanvälityksen kahdennuksen
ja TCP-protokollatulkin perustoimintojen toteutuksen pystyy näin hyvin pitkälti ohittamaan.
Suurin osa työstä menee siis protokollakohtaisten enkoodereiden ja dekoodereiden rakenta-
miseen, datan mallintamiseen C#-luokiksi ja useiden eri komponenttien integraatioon.
Ajuri on TCP-asiakas. Se pyörii DriverManagerin päällä ikuisessa silmukassa ja ottaa ti-
lattomasti DotNettyä hyödyntävän ProtoLibin avulla vastaan X-AID-palvelimen lähettämiä
viestejä ja parsii niistä C#-representaatiot sekä välittää vastaanottamaansa tietoa SCADA:n
kautta PLC:lle ja takaisin PLC:ltä SCADA:n kautta palvelimelle. Pääasialliset toiminnalliset
vaatimukset ovat seuraavat:
1 . Ajuri tulkkaa ja muodostaa X-AID protokollan määritelmän mukaisia viestejä
2 . Ajuri lähettää ja vastaanottaa dataa X-AID-järjestelmän ja SCADA-järjestelmän välillä
3 . Ajuri koostaa X-AID -järjestelmän lähettämän datan perusteella luokkarakenteet ja
välittää sen tiedot SCADA:an.
4 . Ajuri ylläpitää omissa malli-luokissaan järjestelmän tämän hetkistä tilaa.
5 . Järjestelmä koittaa uudelleenyhdistää X-AID -järjestelmään yhteysvian sattuessa.
6 . Järjestelmä osaa uudelleenkäynnistyä tietokoneen kaatuessa.
7 . Järjestelmä osaa tunnistaa kumpi palvelimista on tällä hetkellä aktiivinen ja kumpi
passiivinen
8 . Järjestelmä on luotettava, sillä se tulee pyörimään kellon ympäri SCADA:n
aliprosessina.
9 . Järjestelmä osaa alustaa itsensä asennuksen ja käynnistyksen tapahtuessa
1 0 . Järjestelmä kykenee asettamaan erilaisia suodattimia, joilla disabloidaan esimerkiksi
33
yksittäisten kameroiden aiheuttamat hälytykset
1 1 . Järjestelmä kykenee vaihtamaan aktiivisen ja passiivisen X-AID palvelimen välillä
mahdollisen yhteysvian sattuessa
Kuudennen kohdan hoitaa aiemmin mainittu WinCC OA:n prosessimanageri Pmon, jon-
ka aliprosessiksi DriverManager rekisteröityy. Seitsemäs kohta puolestaan on jo toteutet-
tu DriverManager-ohjelmistossa, jonka ajuriksi XaidDriver rekisteröityy. Toinen kohta vaa-
timuksista on toteutettu ProtoLib-kirjaston avulla, joka alustetaan DriverManagerin Input-
rajapinnan toteuttavassa XaidInputDriver-luokassa. ProtoLib-kirjaston alustuksen toteuttava
funktio näyttää seuraavanlaiselta:
/ / / <summary>
/ / / I n i t i a l i z e s t h e p r o t o l i b i n s t a n c e
/ / / </ summary>
/ / / <param name=" p o r t " > </ param >
/ / / <param name=" i p " > </ param >
p u b l i c P r o t o L i b C l i e n t I n i t i a l i z e P r o t o l i b ( s t r i n g p o r t , s t r i n g i p )
{
Logger . I n f o ( " I n i t i a l i z i n g p r o t o l i b " ) ;
S o c k e t C h a n n e l C o n f i g _ s o c k e t C h a n n e l = new
S o c k e t C h a n n e l C o n f i g . S o c k e t C h a n n e l C o n f i g B u i l d e r ( )
. Se tKeepAl ive ( t rue )
. B u i l d ( ) ;
_ c l i e n t C o n f i g = new C l i e n t C o n f i g B u i l d e r ( )
. S e t C h a n n e l C o n f i g ( _ s o c k e t C h a n n e l )
. S e t S e r v e r I p A d d r e s s ( IPAddres s . P a r s e ( i p ) )
. S e t S e r v e r P o r t ( i n t . P a r s e ( p o r t ) )
. B u i l d ( ) ;
_ f r ameDecoderConf ig = new
34
L e n g t h F i e l d B a s e d F r a m e D e c o d e r C o n f i g B u i l d e r ( )
. S e t B y t e O r d e r ( By teOrder . L i t t l e E n d i a n )
. S e t L e n g t h F i e l d O f f s e t ( 4 )
. S e t L e n g t h F i e l d L e n g t h ( 4 )
. S e t L e n g t h A d j u s t m e n t (−8)
. SetMaxFrameLength ( I n t 3 2 . MaxValue )
. S e t F a i l F a s t ( t rue )
. B u i l d ( ) ;
_ d e c o d e r B u i l d e r = new
R e s p o n s e D e c o d e r S e r v i c e . R e s p o n s e D e c o d e r B u i l d e r ( )
. S e t O b s e r v e r ( t h i s ) ;
_ e n c o d e r B u i l d e r = new
R e q u e s t E n c o d e r S e r v i c e . R e q u e s t E n c o d e r B u i l d e r ( ) ;
_messageHand le r = new MessageHandler ( new TimeSpan ( 0 , 0 , 60) ,
new TimeSpan ( 0 , 0 , 60) ) ;
_ c l i e n t B u i l d e r = new C l i e n t B u i l d e r ( )
. S e t C l i e n t C o n f i g ( _ c l i e n t C o n f i g )
. Se tFrameDecoderConf ig ( _ f rameDecoderConf ig )
. S e t D e c o d e r B u i l d e r ( _ d e c o d e r B u i l d e r )
. S e t E n c o d e r B u i l d e r ( _ e n c o d e r B u i l d e r )
. Se t InboundMessageHand le r ( _messageHand le r ) ;
re turn _ c l i e n t B u i l d e r . B u i l d ( ) ;
}
Loput listauksessa esille tulleet kohdat on toteutettu ajuriin, jonka rakenne ja sovelletut suun-
nittelumallit sekä vaatimusten täyttyminen käydään läpi tarkemmin seuraavissa luvuissa.
35
8.1 Oliosuunnittelu ja XaidDriver
Koska kyseessä on integraatioprojekti ja kyseisessä projektissa on tarjottu avuksi järjestel-
män tarjoajan kehittämä simulaattori sekä kyseisen simulaattorin dokumentaatio, on hel-
pointa aloittaa oliosuunnittelu sekä testien suunnittelu seuraamalla kyseisen dokumentaation
datarakenteita.
Palvelimelta vastaanotetuista viesteistä mallinnettiin C#-luokkia ja luokkien sisältöjen pe-
rusteella niistä muodostettiin hierarkia. Hierarkian perusteella nämä luokat voi luokitella
kolmeen eri pääkategoriaan:
1. Koko järjestelmän laajuista informaatiota tai asetuksia. Näiden kantaluokkana toimii Xaid-
SystemParameters.
2. Analysaattori-palvelimet ja niihin liittyvät luokat. Kantaluokkana toimii Server.
3. Yksittäiset kamerat. Jokaisella kameralla on tila, asetukset, isäntäpalvelin, kaistakohtaisia
tilastoja ja erilaisia hälytyksiä. Kantaluokkana toimii Camera.
Toiminnallisuuksien perusteella eritelty arkkitehtuurikuvaus tiedonkulusta ja ohjelmiston
tehtävistä on seuraavanlainen:
36
Tässä kuvataan SCADA:n aliprosessina toimivan DriverManagerin suhde XaidDriveriin se-
kä XaidDriverin suhde sen hyödyntämään ProtoLib-kirjastoon. WinCC OA:n C#-Manager
on C#-rajapinta WinCC OA:lle, jota DriverManager käyttää. XaidDriver hoitaa arvojen päi-
vittämisen DriverManagerin kautta, mutta ohjelman alustuessa ensi kertaa se käyttää itsel-
leen injektoitua referenssiä C#-Manageriin ja luo sen avulla ajurin vaatimat datarakenteet
WinCC OA -järjestelmään. DatapointModifer-luokka siis toteuttaa luvun 8 vaatimusten koh-
dan numero 9.
XaidInputDriver ja XaidOutputDriver toteuttavat DriverManagerin määrittelemät rajapinta-
vaatimukset ja rekisteröityvät DriverManageriin. Molemmat näistä omaavat funktiot, jotka
käynnistyvät kun WinCC OA:n datapoint arvot muuttuvat. Lienee silti tärkeää huomata, että
DriverManager tarkkailee vain datapoint-rakenteita joissa on erikseen määritelty konfiguraa-
tioissa DriverManagerin vaatima asetus JSON-tiedosto, kuten kappaleessa 6 esitettiin. Kum-
matkin näistä luokista omaavat XaidSingleton-luokan avulla referenssin samaan staattiseen
ajuriin. Tämän ajurin pääasiallinen luokka on XaidDriver.
XaidDriver on ajurin kantaluokka. Tämä luokka omaa ajantasalla olevat tiedot X-AID-järjestel-
män tämänhetkisestä tilasta. Kommunikaation X-AID-järjestelmään XaidDriver toteuttaa
hyödyntämällä ProtoLib-ohjelmistokirjastoa, toteuttamalla sen vaatimat rajapinnat: IClient-
MessageHandler, IDecoder ja IEncoder. IClientMessageHandlerin rajapinnan toteuttaa Mes-
sageHandler-luokka, joka omaa viestien lukemisen ja lähettämisen lisäksi muun muassa toi-
minnallisuudet viestijonojen luomiseen sekä virheenkäsittelyyn. XaidDecoder ja XaidEnco-
der puolestaan toteuttavat rajapinnat IDecoder ja IEncoder. Koska XaidDriver säilyttää tul-
kattavien olioiden tilan ja rakenteen, se toteuttaa luvun 8 vaatimusten kohdan numero 4.
XaidDriver omaa myös ajastimen, jonka perusteella lähetetään protokollamäärityksen mu-
kaista ping-viestiä viiden sekunnin välein. Tämä johtuu siitä, että X-AID-järjestelmä sulkee
yhteyden mikäli asiakas ei lähetä yhteyden ylläpitoviestiä 10 sekunnin välein. Tämä funktio
näyttää seuraavanlaiselta:
/ / / <summary>
/ / / Sends p ing message t o X−AID s e r v e r .
38
/ / / </ summary>
p u b l i c a sync vo id SendPingMessage ( )
{
i f ( ! _hostName . Equ a l s ( Envi ronment . MachineName ) )
{
i f ( _ c l i e n t . A c t i v e ) a w a i t _ c l i e n t . CloseAsync ( ) ;
i f ( _ r e d u C l i e n t != n u l l && _ r e d u C l i e n t . A c t i v e ) a w a i t
_ r e d u C l i e n t . CloseAsync ( ) ;
re turn ;
}
i f ( _ c l i e n t . A c t i v e )
{
t r y
{
a w a i t SendReques t ( Command . KeepAlive ,
( u long ) 123456178910 , MessageId , 24) ;
}
c a t c h
{
Logger . E r r o r ( $ " E x c e p t i o n o c c u r r e d w h i l e s e n d i n g a
r e q u e s t t o X−AID s e r v e r . " ) ;
a w a i t CheckForRedundancy ( ) ;
}
}
e l s e
{
t r y
{
a w a i t Connect ( ) ;
}
c a t c h
{
39
Logger . E r r o r ( $ " Couldn ’ t r e c o n n e c t t o Xaid−S e r v e r ! " ) ;
a w a i t CheckForRedundancy ( ) ;
}
}
}
Tämä funktio siis yrittää myös uudelleenyhdistää ajurin X-AID-palvelimelle, mikäli yhteys
on katkennut. Funktion alussa myös tarkistetaan, että tämä instanssi ajurista on aktiivisella
SCADA-palvelimella sijaitseva instanssi. Mikäli näin ei ole, suljetaan yhteys eikä yhteyt-
tä enää oteta, ellei aktiivisen palvelimen nimi vaihdu kyseisen tietokoneen nimeksi. Tämän
avulla siis toteutetaan luvun 8 vaatimusten kohta numero 5 ja varmistetaan kohdan numero 7
toteutuminen. Samalla mahdollisten yhteysongelmien sattuessa tämä funktio koittaa vaihtaa
aktiivisesta palvelimesta passiiviseen palvelimeen ja takaisin yhteyden luomiseksi, kunnes
jompi kumpi näistä palvelimista vastaa. Tällä tavalla saadaan myös toteutettua luvun 8 vaa-
timusten kohta numero 11. Ajuri toteuttaa vaihdoksen aktiivisen ja passiivisen palvelimen
väliä funktion CheckRedundancy avulla, mikä näyttää tältä:
/// <summary>
/// If the client can’t be reached in the ping message
(default: 5 seconds),
/// the driver will attempt to switch to using
the alternative client.
/// </summary>
private async Task CheckForRedundancy()
{
if ( _reduClient != null)
{
Logger.Warn("Attempting redundancy switch!");
ProtoLibClient switchClient = null;
await _client.CloseAsync();
switchClient = _client;
_client = _reduClient;
40
_reduClient = switchClient;
string url = _baseUrl;
_baseUrl = _reduBaseUrl;
_reduBaseUrl = url;
try
{
await _client.ConnectAsync();
await DefaultDataPointQueries();
SubscribeToEvents();
}
catch
{
Logger.Error("Couldn’t connect to redundant server!
Attempting again in 5 seconds.");
}
}
}
Tällä funktiolla siis vaihdetaan aktiivista ja passiivista palvelinta virhetilanteessa. Tämän li-
säksi tarkkaillaan SCADA:n aktiivisen ja passiivisen palvelimen tilatietoja välittävää datapoint-
arvoa, jonka perusteella päätellään ottaako tämä kyseinen instanssi ajurista yhteyttä X-AID
-palvelimeen. Tämä funktio puolestaan näyttää tältä:
/ / / <summary>
/ / / S u b s c r i b e s t o redundancy d a t a p o i n t in SCADA and d i s c o n n e c t s o r
c o n n e c t s upon h o s t name change
/ / / </ summary>
p r i v a t e async Task Subscr ibeToRedundancy ( )
{
OaVar i an t s u b s c r i p t i o n V a l u e = n u l l ;
O a D pV a l u eS u b s c r i p t i o n V a l u e S u b s c r i p t i o n = n u l l ;
V a l u e S u b s c r i p t i o n =
41
_oaManager . P r o c e s s V a l u e s . C r e a t e D p V a l u e S u b s c r i p t i o n ( ) ;
V a l u e S u b s c r i p t i o n . AddDp ( " r e d u I n f o . ac t iveHos tName " ) ;
V a l u e S u b s c r i p t i o n . S ing leVa lueChanged += ( vcsende r , vce ) =>
{
s u b s c r i p t i o n V a l u e = vce . Value . DpValue ;
_hostName = s u b s c r i p t i o n V a l u e . T o S t r i n g ( ) ;
Task . Run ( async ( ) => {
i f ( _hostName . Eq ua l s ( Envi ronment . MachineName ) ) a w a i t
Connect ( ) ;
e l s e i f ( _ c l i e n t . A c t i v e ) a w a i t _ c l i e n t . CloseAsync ( ) ;
} ) . Wait ( ) ;
} ;
a w a i t V a l u e S u b s c r i p t i o n . S t a r t A s y n c ( ) ;
}
Tämä funktio yhdessä DriverManagerin sisäänrakennetun datapoint-käsittelyn avulla toteut-
taa aiemmin vaatimuksissa mainitun SCADA-järjestelmän kahdennuksen käsittelyn.
Tärkeää on huomata myös XaidEncoder ja XaidDecoder-luokat, jotka toteuttavat ProtoLib-
ohjelmistokirjaston rajapinnat. Nämä luokat tekevät varsinaisen työn viestien kääntämisessä:
XaidDecoder tulkitsee tavuja ja muuttaa niistä C#-olioita, XaidEncoder puolestaan kääntää
C#-olion sisällön tavuiksi. Tämä tarkoittaa, että nämä ovat varsinaisen protokollatoteutuk-
sen omaavat luokat. XaidEncoder ja XaidDecoder luokat toteuttavat luvussa 8 määriteltyjen
vaatimusten kohdan numero yksi.
Esimerkiksi kameran tilan tulkitsemista varten XaidDecoder omaa tämänkaltaisen funktion:
/ / / <summary>
/ / / C r e a t e s a s i n g l e camera s t a t e from t h e b y t e a r r a y .
/ / / </ summary>
/ / / <param name=" s e r v e r C o n f i g u r a t i o n s "> S e r v e r r e s p o n s e
v a l u e s < / param >
/ / / <param name=" s t a r t I n d e x "> Index t o s t a r t i n t e r p r e t i n g
42
from </ param >
/ / / <param name=" cameras "> L i s t o f Camera o b j e c t s f o r s t o r i n g t h e
r e c e i v e d d a t a . < / param >
/ / / < r e t u r n s >The c u r r e n t i n d e x in a r r a y . < / r e t u r n s >
p u b l i c i n t C r e a t e S i n g l e C a m e r a S t a t e ( b y t e [ ] s e r v e r C o n f i g u r a t i o n s ,
i n t s t a r t I n d e x , L i s t <Camera > cameras )
{
CameraS ta t e c a m e r a S t a t e = new CameraS t a t e ( Va lueObse rve r )
{
CameraId =
B i t C o n v e r t e r . ToUInt32 ( S p l i t B y t e A r r a y ( s e r v e r C o n f i g u r a t i o n s ,
s t a r t I n d e x , 4 ) , 0 ) ,
S e r v e r I d =
B i t C o n v e r t e r . ToUInt32 ( S p l i t B y t e A r r a y ( s e r v e r C o n f i g u r a t i o n s ,
s t a r t I n d e x += 4 , 4 ) , 0 ) ,
V i d e o S i g n a l = ( V i d e o S i g n a l )
B i t C o n v e r t e r . ToUInt16 ( S p l i t B y t e A r r a y ( s e r v e r C o n f i g u r a t i o n s ,
s t a r t I n d e x += 4 , 2 ) , 0 ) ,
V i d e o Q u a l i t y = s e r v e r C o n f i g u r a t i o n s [ s t a r t I n d e x += 2 ] ,
P r o c e s s i n g E r r o r = ( P r o c e s s i n g E r r o r )
s e r v e r C o n f i g u r a t i o n s [++ s t a r t I n d e x ] ,
Act iveAlarmCount =
B i t C o n v e r t e r . ToUInt16 ( S p l i t B y t e A r r a y ( s e r v e r C o n f i g u r a t i o n s ,
++ s t a r t I n d e x , 2 ) , 0 ) ,
A l a r m S t a t e L i s t = new L i s t < Ala rmSta t e > ( )
} ;
i n t a l a r m S t a t e L i s t L e n g t h =
B i t C o n v e r t e r . To In t32 ( S p l i t B y t e A r r a y ( s e r v e r C o n f i g u r a t i o n s ,
s t a r t I n d e x += 2 , 4 ) , 0 ) ;
s t a r t I n d e x += 4 ;
f o r ( i n t i = 0 ; i < a l a r m S t a t e L i s t L e n g t h ; i ++)
{
43
s t a r t I n d e x = C r e a t e A l a r m S t a t e ( s e r v e r C o n f i g u r a t i o n s ,
s t a r t I n d e x , c a m e r a S t a t e ) ;
}
i n t camIndex = cameras . F i n d I n d e x ( cam =>
cam . CameraId . Eq ua l s ( c a m e r a S t a t e . CameraId ) ) ;
i f ( camIndex . Eq ua l s (−1) ) cameras . Add ( new Camera ( Va lueObse rve r )
{ CameraS t a t e = c a m e r a S t a t e , CameraId =
c a m e r a S t a t e . CameraId } ) ;
e l s e cameras [ camIndex ] . CameraS ta t e = c a m e r a S t a t e ;
re turn s t a r t I n d e x ;
}
Tässä tapauksessa tällä funktiolla on kolme parametria: varsinaisen datan sisältävä tavutau-
lukko, numeerinen arvo joka ilmaisee mistä indeksistä tulkitseminen aloitetaan sekä lista
Camera-olioista joihin tulkittu data säilötään. Tavutaulukon arvojen tulkinta seuraa X-AID-
protokollan määritelmää. Tässä tapauksessa se esimerkiksi tarkoittaa, että jokainen kameran
tilan sisältävä tavutaulukko alkaa uint-tietotyypillä, joka sisältää kameran tunnisteen, eli se
on taulukon lukemisen aloittaessa neljä ensimmäistä solua taulukossa. Tämän jälkeen tulee
palvelimen tunniste ja niin edelleen.
XaidDecoder ja XaidEncoder toimivat käytännössä samalla periaatteella mutta päinvastoin
toisiinsa nähden: XaidDecoder vastaanottaa tavutaulukkoja ja täyttää sille parametrisoitu-
ja luokkarakenteita, kun XaidEncoder vastaanottaa näitä olioita ja muodostaa niiden ar-
voista protokollamääritelmän mukaisia tavutaulukkoja. Esitellyssä funktiossa myös huoma-
taan ensi luvussa käsiteltävän riippuvuuksien injektoinnin suunnnittelumallin soveltaminen
XaidDriverin kehityksessä, sillä jokaiselle CameraState-luokan oliolle injektoidaan Value-
Observer-olio konstruktorin yhteydessä.
44
8.2 XaidDriverin kehityksessä sovelletut suunnittelumallit
Kehitystyössä sovellettiin useita olio-ohjelmoinnin suunnittelumalleja. Tällä tavalla pyrit-
tiin toteuttamaan SOLID-periaatetta (SRP, OCP, LSP, ISP, DIP) (Martin 2002). SOLID-
periaatteen lisäksi koodin tuottamisessa on sovellettu DRY-periaatetta (Don’t repeat your-
self, älä toista itseäsi), eli itseään toistavan koodin kirjoittamisen sijasta muodostetaan ope-
raatioita suorittavia parametrisoituja geneerisiä funktioita ja silmukoita. SOLID-periaate tar-
kemmin eriteltynä on seuraavalainen:
1 . S i n g l e R e s p o n s i b i l i t y P r i n c i p l e (SDP) , e l i yhden v a s t u u n
p e r i a a t e
2 . Open / Closed p r i n c i p l e (OCP) , e l i a v o i n / s u l j e t t u −p e r i a a t e
3 . L i skov S u b s t i t i o n p r i n c i p l e ( LSP ) , e l i L i s k o v i n
k o r v a u s p e r i a a t e
4 . I n t e r f a c e S e g r e g a t i o n P r i n c i p l e ( ISP ) , e l i r a j a p i n t o j e n
e r o t t e l u −p e r i a a t e
5 . Dependency I n v e r s i o n P r i n c i p l e ( DIP ) , e l i r i i p p u v u u k s i e n
i n j e k t o i n n i n s u u n n i t t e l u m a l l i
Yhden vastuun periaate määrittää, että jokaisella rajapinnalla, luokalla tai oliolla pitää olla
vain yksin selkeä vastuualue. Tämän periaatteen on alunperin kehittänyt Robert C. Martin
hänen kirjassaan Principles, Patterns, and Practices of Agile Software Development (“Single
Responsibility Principle” 2018-12-10; Martin 2002). Luokkasuunnittelussa tämä otetaan huo-
mioon jakamalla eri toiminnallisuudet selkeästi eri luokkiin rajapintojen taakse. Martinin
mukaan on ongelma, jos kehittäjä pystyy keksimään useamman kuin yhden syyn muokata
jotakin luokkaa. Tällöin useimmiten on kyse luokasta, jonka pitäisi olla kaksi erillistä luok-
kaa. Tämän takia XaidDriverin eri toiminnot on jaettu erillisiin luokkiin kontekstin perus-
teella ja jokaista niistä käsitellään vain rajapintojen kautta. Tämän periaatteen seuraamisen
huomaa XaidDriverin rajapintojen määrässä ja niiden selkeissä toiminnallisissa osa-alueissa:
esimerkiksi JSON-olioiden luomiselle on oma luokka nimeltä JsonBuilder, jonka tehtävänä
on vain ja ainoastaan luoda asiaankuuluvia JSON-olioita.
45
Avoin/suljettu -periaate tarkoittaa, että ohjelmiston entiteettien pitäisi olla avoimia laajen-
nukselle, mutta suljettuja muutoksille (“Open-Closed Principle” 2018-12-10; Martin 1996).
Tämän periaatteen toteuttaminen voi vaikuttaa hiukan työläältä, mutta kansantajuisesti voisi
sanoa että kovakoodauksen välttäminen on tärkein osa tätä suunnittelumallia. Avoin/suljet-
tu -periaate siis tarkoittaa että suunnitellaan moduuleja, jotka eivät koskaan muutu (Martin
1996). Jokaisen metodin ja aliohjelman pitäisi toteuttaa toiminnallisuutensa niin geneerisesti
ja parametrisoituina, että kyseisiä funktioita ei enää alkuperäisen kirjoituksen jälkeen muo-
kata. Voidaan toki kirjoittaa uusia funktioita, jotka kutsuvat näitä aiempia funktioita, mutta
valmiit funktiot ja moduulit pysyvät samanlaisina. Tämän toteutumisen havaitsee esimerkik-
si X-AID viestejä lähettävässä luokassa. Jokainen tämän luokan dataa lähettävistä funktiois-
ta käyttää SendRequest-funktiota, antaen tälle funktiolle parametrina viestisisällön, viestin
tunnisteen, viestin pituuden ja viestin tyypin. Tämä geneerisesti toteutettu funktio näyttää
seuraavalta:
/ / / <summary>
/ / / Sends t h e r e q u e s t t o X−AID s e r v e r .
/ / / </ summary>
p r i v a t e async Task < o b j e c t > SendReques t ( Command commandType , o b j e c t
c o n t e n t , u s h o r t messageId , u i n t messageLength )
{
Xa idReques t r e q u e s t = new XaidReques t . X a i d R e q u e s t B u i l d e r ( )
. SetCommandType ( commandType )
. S e t R e q u e s t C o n t e n t ( c o n t e n t )
. Se tMessage Id ( messageId )
. Se tMessageLeng th ( messageLength )
. B u i l d ( ) ;
re turn a w a i t _ c l i e n t . SendReques tAsync ( r e q u e s t ) ;
}
Myös Liskovin korvausperiaate ottaa kantaa luokkasuunnitteluun. Tämän periaatteen mu-
kaan aliluokan olion pitäisi aina olla käsiteltävissä myös perimänsä luokan oliona (Leppä-
nen M. 2009), eli samat perusoperaatiot pystyy toteuttamaan jokaisella oliolla joka perii
46
ylemmän luokan, vaikka oliokohtaiset lisäominaisuudet voivatkin vaihdella. Helpoimpia ta-
poja huomata, että tämä periaate ei toteudu, on löytää koodista erilaisia "häntiä", eli esimer-
kiksi rajapinnan toteuttava aliluokka sisältää rajapintamääritelmän omaiset funktiot, mutta
näissä funktioissa ei tehdä mitään tai pahimmassa tapauksessa heitetään NotImplemente-
dExceptionia (“Liskov Substition Principle” 2018-12-10). Nämä hännät voivat myöhemmin
aiheuttaa laajaa vahinkoa ja ongelmia, varsinkin jatkuvassa käytössä olevassa ohjelmistos-
sa. Tämän suunnittelumallin toteutumisen huomaa esimerkiksi QueryableAlarms-luokasta.
Jokainen AlarmsState-olio omaa myös AlarmState-luokan perivän QueryableAlarm-luokan
attribuutissa LatestAlarm, joka omaa kaikki AlarmState-luokan ominaisuudet sekä URL-
osoitteet kuvan ja videotiedoston lataamiseen. Myös häntiä on vältelty XaidDriverin imple-
mentaatiossa: jokaisessa ohjelman funktiossa suoritetaan jotakin operaatioita. Turhia funk-
tioita ei siis kokonaisuuden kannalta ole olemassa.
Rajapintojen erottelu -periaate toteaa, että asiakkaiden ei pitäisi olla riippuvaisia metodeista,
joita ne eivät käytä (“Interface Segregation Principle” 2018-12-10; Martin 2002). Sovellus-
kehittäjien pitäisi suosia ohuita ja keskittyneitä yhtä toiminnallisuutta toteuttavia rajapinto-
ja, eikä laajoja useita ominaisuuksia omaavia rajapintoja. Esimerkiksi moniperintä on yksi
tavoista toteuttaa tätä periaatetta: jos jokin osa sovelluksesta tarvitsee useampia toiminnal-
lisuuksia rajapinnasta, mutta muut osat sovelluksesta tarvitsevat vain osaa tämän saman ra-
japinnan toiminnallisuuksista, on järkevämpää tehdä kaksi erillistä rajapintaa ja toteuttaa ne
molemmat moniperinnän avulla useampaa toimintoa vaativassa luokassa. Tämän periaatteen
toteutumisen huomaa esimerkiksi ajurin rajapintojen määrässä: erillisiä rajapintoja ohjelmis-
tossa on yhdeksän kappaletta, joista jokainen toteuttaa vain ja ainoastaan yhtä sovelluksen
operaatioiden osa-aluetta, kuten aiemmin mainittu JsonBuilder-luokka.
Riippuvuuksien inversio -suunnittelumalli määrittelee erillisten moduulien välisen kommu-
nikaation raamit. Korkean tason moduulien ei pitäisi omata riippuvuuksia alemman tason
moduuleihin, kummankin näistä pitäisi olla riippuvaisia abstraktioista. Näiden abstraktioi-
den ei pitäisi olla riippuvaisia yksityiskohdista, vaan yksityiskohtien pitäisi olla riippuvai-
sia abstraktioista (“Dependency Inversion Principle” 2018-12-10; “Dependency Inversion
vs Dependency Injection vs Inversion of Control vs Programming to Interfaces” 2018-12-
10). Useimmiten tämän suunnittelumallin toteuttaminen aloitetaan luomalla uusia rajapin-
47
toja, jotka tarjoavat mahdollisuuden luoda ylimääräisiä abstraktiotasoja toiminnallisuutta
kutsuvan luokan ja operaation toteuttavan luokan välille. Tämän suunnittelumallin toteutu-
misen huomaa esimerkiksi XaidDriverin Driver-Service-Interface-Resource toiminnallisesta
rakenteesta. Tätä voi havainnoillistaa esimerkiksi DatapointModifier-luokan avulla. Data-
pointModifer on resurssi, jota kutsutaan IDatapointModifer rajapinnan kautta, mitä kutsu-
taan DatapointCreatorService-luokan kautta. Kun SCADA:n datapointteja alustetaan ja luo-
daan, ajuri kutsuu DatapointCreatorService-luokan funktiota, joka palauttaa IDatapointMo-
difier rajapinnan funktion, jonka DatapointModifer toteuttaa. Tällä kolmen abstraktiotason
erottelutavalla minkä tahansa osa tästä ketjusta pystyy korvaamaan jollain toisella luokalla,
mutta toiminnallisuus pysyy samanlaisena. Seuraavassa esimerkissä esitellään datapointtien
luomisen toteuttava funktioketju XaidDriverin koodilla, tosin tästä koodista on karsittu pois
asian havainnoillistamisen kannalta irrelevantteja funktioita.
p u b l i c c l a s s D a t a p o i n t C r e a t o r S e r v i c e
{
p u b l i c I D a t a P o i n t M o d i f i e r D a t a P o i n t C r e a t o r { g e t ; s e t ; }
i n t e r n a l a sync Task C r e a t e X a i d D a t a p o i n t T y p e s ( OaManager
oaManager )
{
a w a i t D a t a P o i n t C r e a t o r . C r e a t e X a i d D a t a p o i n t T y p e s ( oaManager ) ;
}
}
p u b l i c i n t e r f a c e I D a t a P o i n t M o d i f i e r
{
Task C r e a t e X a i d D a t a p o i n t T y p e s ( OaManager oaManager ) ;
}
p u b l i c c l a s s D a t a p o i n t M o d i f i e r R e s o u r c e : I D a t a P o i n t M o d i f i e r
{
p u b l i c a sync Task C r e a t e X a i d D a t a p o i n t T y p e s ( OaManager oaManager )
{
48
Logger . I n f o ( " Xaid D a t a p o i n t c r e a t i o n i n i t i a l i z e d . " ) ;
a w a i t C r e a t e S e r v e r D a t a P o i n t T y p e ( oaManager ) ;
a w a i t Crea t eCameraDa taPo in tType ( oaManager ) ;
a w a i t C r e a t e X a i d S y s t e m D a t a P o i n t T y p e ( oaManager ) ;
}
}
Aiemmin mainittujen mallien lisäksi ohjelmiston kehityksessä sovellettiin riippuvuuksien
injektoinnin suunnittelumallia (Dependency Injection), eli riippuvuudet injektoidaan luok-
kaan sen alustuksen tapahtuessa. Tämän suunnittelumallin seuraamisen on huomattu hel-
pottavan ohjelmiston ylläpitoa (Razina ja Janzen 2007). XaidDriverissa tätä mallia sovelle-
taan paljon: XaidInputDriver toteuttaa räätälöidyn IXaidObserver-rajapinnan, joka sisältää
ModelValueChanged-funktion. Alustuessaan XaidInputDriver alustaa varsinaisen ajurin si-
sältävän XaidDriver-luokan ja injektoi siihen referenssin itseensä IXaidObserverin muodos-
sa. Tämän jälkeen XaidDriver jatkaa tämän referenssin injektiota syvemmälle ohjelmiston
kerroksissa. Lopulta alimmilla tasoilla olevat malli-luokat toteuttavat IXaidObservable raja-
pinnan. Tätä aihetta sivuttiinkin jo luvussa 8.1.
Riippuvuuksien injektoinnin avulla on toteutettu muuten ongelmia aiheuttava arvojen päi-
vitys spontaanista palvelin-tapahtumasta: useimmissa tapauksissa viestin lähetys ja proses-
sointi vaatisi viestin lähettämistä ja kutsun muodostamista sekä operaation seurauksena vas-
taanotetun XaidResponse-luokan tulkintaa. Riippuvuuden injektoinnin avulla XaidDecoder
omaa referenssin XaidInputDriveriin IXaidObserverin rajapinnan muodossa ja näin spontaa-
nin palvelinviestin tulkinnan yhteydessä voidaan laukaista IXaidObserver-rajapinnan Model-
ValueChanged-funktio ja antaa kyseiselle funktiolle parametrina muuttunut malli-luokka ja
sen tyyppi. Tämän jälkeen XaidInputDriver tulkitsee vastaanotetun olion sisällön ja tyypin,
kutsuen näiden tietojen perusteella XaidDriverin malleja päivittävää funktiota sekä asettaa
arvon valvomo-ohjelmistoon. Lienee syytä mainita, että switch-case ei toimi C#:n GetType()-
funktion kanssa, mistä syystä tämä rajoite on kierretty antamalla oikea tyyppi parametrina
ja switch-case-lauseessa tulkitaan tyypin nimeä. XaidInputDriverin sisältämä ModelValue-
Changed-funktio näyttää seuraavanlaiselta:
49
/ / / <summary>
/ / / F u n c t i o n t h a t t r i g g e r s when A l a r m S t a t e / CameraS ta t e / S e r v e r S t a t e
type of message i s r e c e i v e d
/ / / by t h e d e c o d e r .
/ / / </ summary>
p u b l i c a sync vo id ModelValueChanged ( I X a i d O b s e r v a b l e observedModel ,
Type type )
{
i f ( I n i t i a l C o n n e c t i o n D o n e )
{
Camera foundCam = n u l l ;
s w i t c h ( type . Name )
{
case " A l a r m S t a t e " :
A l a r m S t a t e a l a rm = ( A l a r m S t a t e ) observedModel ;
i f ( a l a rm . A l a r m s S t a t e . Eq ua l s ( A l a r m s S t a t e . A c t i v e ) )
{
D r i v e r . MapQueryableAlarm ( a la rm ) ;
D r i v e r . B e g i n R e c o r d i n g I n f o Q u e r y ( a l a rm ) ;
}
foundCam = D r i v e r . F indAndRep laceAla rmSta t e ( a l a rm ) ;
a w a i t Upda teCameraDa tapo in t ( foundCam ) ;
break ;
case " QueryableAlarm " :
foundCam = D r i v e r . Cameras . F ind ( cam =>
cam . CameraId . Eq ua l s ( ( ( QueryableAlarm ) observedModel ) . CameraId ) ) ;
i f ( foundCam != n u l l ) a w a i t
Upda teCameraDa tapo in t ( foundCam ) ;
break ;
case " CameraS t a t e " :
foundCam =
D r i v e r . F indAndRep laceCameraS ta t e ( ( CameraS ta t e ) observedModel ) ;
50
a w a i t Upda teCameraDa tapo in t ( foundCam ) ;
break ;
case " S e r v e r S t a t e " :
S e r v e r f o u n d S e r v e r =
D r i v e r . F i n d A n d R e p l a c e S e r v e r S t a t e ( ( S e r v e r S t a t e ) observedModel ) ;
a w a i t U p d a t e S e r v e r D a t a p o i n t ( f o u n d S e r v e r ) ;
break ;
case " X a i d P a r a m e t e r s " :
D r i v e r . S y s t e m P a r a m e t e r s . X a i d P a r a m e t e r s =
( X a i d P a r a m e t e r s ) observedModel ;
break ;
case " X a i d S y s t e m P a r a m e t e r s " :
a w a i t
U p d a t e S y s t e m D a t a p o i n t ( ( X a i d S y s t e m P a r a m e t e r s ) observedModel ) ;
break ;
}
}
}
Tarkempi XaidDriverin sisäinen rakenne on eritelty seuraavassa kuvassa - tämä kuva ei tosin
sisällä koko ohjelman kaikkia luokkia - vaan pyrkii mallintamaan pelkästään ajurin sisäisen
rakenteen olennaisimmat funktionaaliset luokat sekä datan säilytystä varten kehitetyt luokat.
51
Vasemmalla olevat funktionaaliset luokat koostuvat usean abstraktiotason takana sijaitsevista
resursseista, jotka tarjotaan ajurille rajapintojen kautta, joita käyttävät palvelut. Näin varsi-
naisen ajurin tarvitsee vain kutsua palveluluokkaa, joka omaa rajapinnan resurssiluokkaan,
jossa suoritetaan varsinaiset toiminnallisuudet. Service-luokan ja rajapinnan olemassaoloa
on kuvattu tässä kuvassa mustalla pallolla.
Kuvasta on myös rajattu pois osa luokista, joihin XaidDriverilla ei ole eksplisiittisiä viit-
tauksia. Näihin sisältyy esimerkiksi XaidDriverin käyttämät XaidEncoder ja XaidDecoder,
joiden kutsuminen tapahtuu ajurin yhteydessä alustetun ProtoLib-kirjaston toimesta. Ajuria
ohjaavat XaidInputDriver ja XaidOutputDriver, jotka toteuttavat DriverManagerin ajurialus-
tan input- ja output-rajapinnat. XaidInputDriver sisältyy kuvassa DriverManagerin kokonai-
suuteen, joka omaa referenssin XaidDriveriin. Nämä input- ja output-luokat omaavat yhtei-
sen XaidSingleton-luokan joka sisältää itse XaidDriverin. Tällä tavalla estetään useamman
instanssin syntyminen ja varmistetaan, että kummassa tahansa input- ja output-luokissa aju-
riin viitatessa kyse on samasta oliosta. Järkeviksi todettujen suunnittelumallien seuraaminen
yhdistettynä testivetoiseen kehitykseen vähentää virheiden määrää ja parantaa tuotetun oh-
jelmiston laatua.
53
8.3 Datan representaatiot WinCC OA:ssa
Useimmat XaidDriverin luokkaolioista sisältävät useamman TCP-kyselyn palauttamaa da-
taa, joka on sitten koostettu kantaluokkiin. Näitä kyselyitä ovat esimerkiksi palvelimen ja
kameroiden statukset, palvelimen ja kameroiden asetukset, hälytykset ynnä muuta sellais-
ta. Pääasialliset kantaluokat ovat Server ja Camera. Näitä edustaa SCADA:ssa datatyypit
IF_XaidCam ja IF_XaidServer. Jokaisella näiden tyyppien datapointeista on kaksi olen-
naista kenttää: controlValue- ja statusValue-kentät. StatusValue sisältää X-AID-palvelimelta
vastaanotetun kyseisen olion tilan. ControlValue-kenttää käytetään datan välittämiseen X-
AID-palvelimelle. Esimerkiksi jos kameran controlValue-kenttään ajetaan JSON-teksti, joka
käskee disabloimaan tämän kameran, poimii XaidDriver DriverManagerin kautta tämän tie-
don ja disabloi kameran, päivittäen tämän jälkeen statusValue-kenttään attribuutin disabled
arvoksi true. Tämän lisäksi WinCC OA sisältää myös kaksi muuta X-AID datapointtia:
IF_XaidSystem ja INT_XaidSetup.
INT_XaidSetup sisältää alustuksen yhteydessä tarvittavat arvot ja muut vastaavat asetukset.
Näihin sisältyy esimerkiksi CreateXaidDatapoint-arvo, jota XaidDriver kysyy alustuessaan.
INT_XaidSetup-datapointtiin sijoitetaan aiemmin luvussa 6 esitelty XaidDriverin konfiguraatio-
JSON. Mikäli arvo on tosi, poistetaan kaikki IF_XaidCam, IF_XaidServer ja IF_XaidSystem
datapointit sekä niiden datapointtien tyyppi-määritelmät. Tämän poiston jälkeen luodaan uu-
det mallit näille arvoille ja täytetään ne TCP-kyselyiden vastauksien palauttamilla arvoilla.
Suoritustehojen säästämiseksi alkuperäisen alustuksen jälkeen spontaaneiden tapahtumien
seurauksesta muuttuneiden luokkien tunnisteet kerätään talteen ja WinCC OA:n datan päivi-
tys tapahtuu sekunnin välein.
IF_XaidSystem puolestaan sisältää koko järjestelmän laajuista dataa: asetuksia videoiden ja
kuvien käsittelyyn, asetuksia hälytysten käsittelyyn yms. Tämän datapointin arvoja ei varsi-
naisesti välitetä PLC:lle, mutta se omaa useita datankäsittelyyn liittyviä asetuksia. Esimerk-
kirakenne XaidSystem-1 datapointin statusarvon sisällöstä on kehityksen yhteydessä simu-
laattorilta vastaanotetun datan mukainen:
{
"XaidParameters": {
54
"EmergencyLight": 90,
"SpeedThreshold": 60,
"DetectionTimeInSeconds": 90,
"MinimumVehicles": 100,
"AverageSpeed": 90,
"StatisticsInterval": 150
},
"ProcessingFilters": [],
"AlarmSettings": [
{
"AlarmType": 2,
"ObjectType": 0,
"ObjectId": 0,
"RecordingEnabled": -1,
"ContinuousRecording": -1,
"PreAlarmRecordTime": -1,
"PostAlarmRecordTime": -1
},
{
"AlarmType": 1,
"ObjectType": 0,
"ObjectId": 0,
"RecordingEnabled": -1,
"ContinuousRecording": -1,
"PreAlarmRecordTime": -1,
"PostAlarmRecordTime": -1
},
{
"AlarmType": 3,
"ObjectType": 0,
"ObjectId": 0,
55
"RecordingEnabled": -1,
"ContinuousRecording": -1,
"PreAlarmRecordTime": -1,
"PostAlarmRecordTime": -1
}
],
}
Tämä sisältää yleiset järjestelmäparametrit, prosessointifiltterit, hälytyksien tyyppikohtai-
set asetukset ja tilastodataa jokaiselta kaistalta. Datapointtien statusarvot sisältävät JSON-
muodossa kantaluokkiensa tämänhetkiset arvot. Varsinainen datan välitys tapahtuu Driver-
Managerin kautta ja data koostetaan JSON-muotoon ylikuormittamalla ToString()-metodi
dataa sisältävissä luokissa. Tämän avulla parsitaan arvoista räätälöityjä JSON-muotoisia tek-
sipätkiä, jotka sitten välitetään näihin datapointteihin. Esimerkiksi analysaattoripalvelimia
XaidDriverissa edustavan Server-luokan ylikuormitettu ToString()-metodi näyttää tältä:
p u b l i c o v e r r i d e s t r i n g T o S t r i n g ( )
{
i f ( S e r v e r C o n f i g != n u l l && _ s e r v e r S t a t e != n u l l )
{
re turn F o r m J s o n S t r i n g ( ) ;
}
e l s e re turn " " ;
}
p r i v a t e s t r i n g F o r m J s o n S t r i n g ( )
{
re turn J O b j e c t . FromObject ( new
{
S e r v e r I d ,
S e r v e r C o n f i g . Name ,
56
S e r v e r C o n f i g . CpuPower ,
S e r v e r C o n f i g . Address ,
_ s e r v e r S t a t e . S e r v e r S t a t u s ,
_ s e r v e r S t a t e . Usage ,
_ s e r v e r S t a t e . C a m e r a I d L i s t
} ) . T o S t r i n g ( F o r m a t t i n g . None ) ;
}
SCADA:a päivittäessä arvot haetaan etsimällä päivitettävä objekti tunnisteen perusteella,
minkä jälkeen luodaan päivitettävän datapointin nimi ja annetaan sille päivitettävän objektin
ToString()-funktion tulos. Tällä tavalla toteutetaan luvun 8 vaatimusten kohta numero 3.
Yksittäisen analysaattoripalvelimen sisältämä data WinCC OA:ssa näyttää tältä:
{
"ServerId": 1,
"Name": "X-AID-01",
"CpuPower": 1300,
"Address": "192.168.1.2:12345",
"ServerStatus": 1,
"Usage": 900,
"CameraIdList": [
9065,
9063,
9057,
9028,
9022,
9014,
9017,
9010,
9050
]
}
57
Esimerkiksi tämä palvelimen tunniste on 1, nimi on X-AID-01, prosessorin maksimiteho
on 1300, sen IP-osoite on 192.168.1.2 ja portti 12345, palvelin on toiminnassa koska sta-
tus on 1 ja varsinainen CPU:n käyttö on 900/1300. Lisäksi se sisältää sen hoitamien kame-
roiden tunnisteet listassa. Näiden kameroiden oma datapoint on taas tyyppiä IF_XaidCam.
IF_XaidCam datapointin päivitys tapahtuu aivan samalla tavalla kuin palvelimien ja yksit-
täisen kameran sisältämä data SCADA:ssa näyttää seuraavanlaiselta:
{
"CameraId": 9010,
"LaneId": 0,
"ServerId": 1,
"Name": "HKA10",
"StreamId": 600010,
"CpuUsage": 100,
"ProcessingError": 0,
"VideoQuality": 0,
"VideoSignal": 0,
"AlarmStateList": [{}]
"LaneStatistics": [],
"ActiveAlarmCount": []
}
Tämä sisältää kameran, kaistan,tilastoja eri kaistoilta, videostreamin ja palvelimen tunnis-
teen. Se sisältää myös tietoa videokuvan laadusta ja signaalista. Koska kehitystyön yhtey-
dessä simulaattori ei pysty palauttamaan liikennetilastoja näiden kohdalla on tyhjä JSON-
taulukko. Jokainen tämän kameran yksittäinen hälytys AlarmsStateList-oliossa puolestaan
näyttää tältä:
{
"CameraId": 9010,
"LaneId": 1,
"LogicalAreaId": 1,
"StateTime": "2018-12-25T11:37:45.0848301+02:00",
58
"AlarmTime": "2018-12-26T12:15:23.1925127+02:00",
"AlarmType": 1,
"ProcessingState": 1,
"AlarmsState": 0,
"RecordingList": null,
"LatestAlarm": {
"QueryUrl": "http://localhost:11180/xaid/api/video/getalarmrec?
camera=9010&alarmtime=131902929081636595&alarmtype=1&lane=1&
logicalarea=1",
"QuerySnapshotUrl": "http://localhost:11180/xaid/api/video/
snapshot?camera=9010&time=131902929081636595&type=1",
"VideoReady": true,
"CameraId": 9010,
"LaneId": 1,
"LogicalAreaId": 1,
"StateTime": "2018-12-25T11:37:45.0848301+02:00",
"AlarmTime": "2018-12-26T12:15:08.1636595+02:00",
"AlarmType": 1,
"ProcessingState": 1,
"AlarmsState": 1,
"RecordingList": null,
"LatestAlarm": null
}
Järjestelmä omaa yksittäisen hälytystila-olion jokaista mahdollista hälytystä kohden. Jos ka-
mera esimerkiksi tarkkailee kolmea kaistaa ja kolmea loogista aluetta sekä omaa kolmenlai-
sia hälytystyyppejä, on tämän kameran AlarmsState listassa
33 = 27 (8.1)
solua, eli 27 erilaista hälytysoliota. Tässä siis eritellään hälytyksen kameran tunniste, kaistan
ja loogisen alueen tunniste sekä hälytyksen tyyppi. Näitä hälytyksiä on varsin monta, sillä
jokainen looginen alue ja kaista omaavat oman versionsa jokaisesta mahdollisesta hälytys-
59
tyypistä. Hälytyksen tyyppiä edustaa koodissa seuravaanlainen enumeraatio:
p u b l i c enum AlarmType { S t o p p e d V e h i c l e = 1 , SlowVehic le , Wrongway }
JSON-teksti kertoo milloin hälytyksen alustus on tapahtunut (statetime) ja milloin hälytys on
viimeksi vaihtunut aktiivisesta inaktiiviseen tai toisinpäin. Itse hälytys sisältää myös oman
AlarmState-luokkansa perivän QueryableAlarm-olion nimeltään LatestAlarm. Tämä olio si-
sältää tiedot viime kerrasta, kun tämä hälytys oli aktiivinen sekä HTTP-osoitteet kuvankaap-
pauksen ja videotiedoston lataamiseen. AlarmsState kertoo onko hälytys aktiivinen vai inak-
tiivinen. Esimerkiksi tässä yhteydessä kanta-hälytys on inaktiivinen eli 0, kun taas viimeisin
aktiivinen versio tästä hälytyksestä omaa arvon 1. VideoReady-attribuutti puolestaan kertoo,
voiko videon ladata hälytykseen liittyvien URL-osoitteiden kautta. Hälytysoliota luodessa
arvo alustetaan epätodeksi ja muodostetaan relevantit URL-osoitteet hälytyksen sisältämästä
datasta. Kun tilanne päättyy ja hälytys muuttuu inaktiiviseksi, päivitetään VideoReady-arvo
todeksi. Tällä tavalla ilmaistaan, että kyseiseen hälytykseen liittyvän videotiedoston pystyy
nyt lataamaan.
Datalle luodaan CTRL-skripti WinCC OA-järjestelmään, joka reagoi joka kerta kun jonkin
näiden datapointtien arvo muuttuu. Tämä skripti parsii arvojen sisältämästä JSON-tekstistä
relevantit tiedot ja sijoittaa ne PLC-järjestelmän arvoja edustaviin vastaaviin WinCC OA:n
datapointteihin, joista arvo välitetään PLC-logiikalle, joka laukaisee tarpeen mukaisia se-
kvenssejä.
60
8.4 XaidDriverin datan käsittely WinCC OA:ssa
Kuten aiemmin luvussa 1 todettiin, C# taipuu kompleksisempiin operaatioihin helpommin
kuin CTRL-skriptikieli. Juuri tästä syystä ajuri on toteutettu WinCC OA -järjestelmään re-
kisteröitynä C#-laajennuksena, joka välittää näitä arvoja WinCC OA:n datapoint-rakenteiden
sisälle. On kuitenkin selvää, että pelkällä tällä datalla ei tehdä mitään. Sitä pitää tulkita ja vä-
littää eteenpäin.
WinCC OA -järjestelmään on jo erikseen määritelty IF_Xaid-alkuisten datapointtien lisäk-
si PLC-sekvensseille erilliset datapoint-rakenteet, joihin näiden JSON-tietojen sisältö pitää
sijoittaa. Tätä varten käytetään WinCC OA:n aiemmin mainittua prosessimanageria. Tälle
prosessimanagerille annetaan DriverManagerin ja muiden tehtävien lisäksi tehtäväksi käyn-
nistää X-AID arvoja sijoittava yksinkertainen CTRL-skripti, joka hoitaa arvojen sijoituksen.
Pähkinänkuoressa tämä skripti jää kuuntelemaan muutoksia IF_XaidCam, IF_XaidServer
ja IF_XaidSystem datapoint-tyyppien datapointteihin, parsii kyseisen datapointin arvosta
JSON-tekstin sisällön ja rakentaa sen tietosisällön perusteella datapoint-osoitteen, johon ky-
seinen arvo sijoitetaan. Ohessa karsittu esimerkki kyseenomaisesta skriptistä: tämä funktio
hoitaa kameran arvojen sijoitusta.
main() {
dyn_string cameras = dpNames("XaidCam-HKA*.statusValue");
for (int i=1; i <= dynlen(cameras); i++) {
dpConnect("mapXaidCamera", true, cameras[i]);
}
}
void mapXaidCamera(string dp1, string valueMappings)
{
dyn_string keys;
dyn_mixed values;
mapping singleCam = jsonDecode(valueMappings);
string val = dpNames(singleCam["Name"]);
strchange(val, 0, 8, "IO_");
61
val = val + ".control";
mapping valMap = mapCameraValues(singleCam, val);
for (int camLength = 0; camLength<mappinglen(valMap); camLength++) {
dynAppend(keys, mappingGetKey(valMap, camLength + 1));
dynAppend(values, mappingGetValue(valMap, camLength + 1));
}
dpSet(keys, values);
}
Tässä esimerkissä on jätetty pois räätälöidyn mapCameraValues-funktion sisältö, jossa vain
luodaan oikeanlainen mapping-tyypin olio (vrt. C# Dictionary), joka sisältää listan datapoint-
tien sijainnista sekä niihin sijoitettavat arvot.
Toteutus hoituu pääosin CTRL-kielen funktiolla dpConnect, joka ottaa parametrina arvon
muuttuessa kutsuttavan funktion, tiedon pyöritetäänkö skripti jo alustuksen aikana kertaal-
leen läpi sekä listan tarkkailtavista datapoint-rakenteista. Tässä yhteydessä datapointtien ni-
met kysellään dpNames-funktion avulla, joka hakee kaikki kyselyyn täsmäävät datapoint-
rakenteet. Tämän jälkeen käydään vain silmukassa läpi jokainen datapoint-rakenne ja raken-
netaan sen sisällöstä mapping-olio jsonDecode()-funktion avulla. Lopuksi luodun mapping-
olion arvojen perusteella luodaan lista osoitteista sekä lista arvoista, jotka annetaan CTRL-
skriptikielen sisäiselle dpSet-funktiolle, joka sijoittaa parametrisoidut arvot vastaaviin para-
metrisoituihin datapointteihin.
Muut WinCC OA:n skriptit ja asetukset tarkkailevat näitä sijoituspaikkoja ja samalla tavalla
niiden arvojen muuttuessa nämä arvot välitetään eteenpäin PLC-logiikalle sekä T-LOIK-
Ohjaussovittimelle. WinCC OA:n SCADA-järjestelmä toimii tällä tavalla näiden usean eri
komponentin risteämiskohtana, jossa välitetään ajurin X-AID-järjestelmältä vastaanottamat
tiedot eteenpäin.
Myös erilaisten hälytystyyppien ja yksittäisten kameran hälytysten käsittelyn disablointi on
62
mahdollista. Tämä on toteutettu aiemmin mainitun ajurin XaidOutputDriver-luokan kaut-
ta, joka näkyy kuviossa 6. Käytännössä SCADA:ssa sijaitseva yksittäisen kameran tai ko-
ko järjestelmän laajuista dataa käsittelevään datapointtiin ajetaan controlValue-muuttujaan
jokin parametri JSON-muodossa, jonka DriverManager välittää XaidDriverille. Tämän jäl-
keen XaidDriver parsii tästä tiedosta esimerkiksi tietyn kameran tunnisteen ja disabloi kaikki
kyseiseltä kameralta tulevat hälytykset. Tämä toteutetaan lähettämällä X-AID palvelimelle
binääriprotokollan määrittelyn mukainen suodatinviesti, joka kertoo ettei ajuri halua vastaa-
nottaa tämän kameran tunnisteen lähettämiä hälytystietoja. Näihin suodattimiin on mahdol-
lista parametrisoida useita eri kaistoja, hälytystyyppejä, loogisia alueita ja kameroita. Tällä
tavalla on toteutettu luvun 8 vaatimuslistan kohta numero 10, sillä näiden funktioiden avulla
voidaan helposti SCADA:n kautta disabloida toisen tunneliputken kaikki ennaltamääritellyt
hälytykset: esimerkiksi eräs suodatin estää ilmoituksien saapumisen kaikista kyseisen tunne-
lin kaistalla 2 tapahtuvista hidas ajoneuvo -hälytyksistä.
63
9 X-AID integraation testaaminen
Koska kyseinen ajuri on toteutettu testivetoisella kehityksellä, on testien määrä varsin suu-
ri. Testien rakentaminen aloitettiin luomalla jokaiselle X-AID protokollatotetuksen viestille
testit. Näiden testien sisältö oli pääasiassa testata XaidDriverin kykyä tulkata ja muodostaa
protokollatoteutuksen mukaisia viestejä ja täyttää XaidDriverin sisältämiä luokkarakentei-
ta vastaanotetulla datalla. Luvussa käydään läpi toteutuksen olennaisimmat integraatiotestit,
joissa testataan mm. että WinCC OA-järjestelmä vastaanottaa XaidDriverilta tietoa ja päivit-
tää datapointtien arvoja hälytyksen lauetessa.
X-AID-järjestelmään liittyen on myös konfiguroitu useita Jenkins-operaatioita. Jenkins on
automaattinen jatkuva-integraatio-ohjelmisto, jolle saa määriteltyä erilaisista tapahtumista
laukeavia skripti-putkia. X-AID-integraatioon liittyviä Jenkins-operaatioita on monta: yk-
si PLC-koodille, joka kääntää ja arkistoi uusimmat versiot koodista ja PLC-simulaattorilla
ajettavasta logiikkaohjelmasta, toinen WinCC OA:lle, joka ajaa integraatiotestejä WinCC
OA:n ja PLC:n välillä, kolmas T-LOIK-Ohjaussovittimelle, joka käynnistää testiympäristös-
sä PLC-simulaattorin sekä WinCC OA:n ja liittää nämä kiinni toisiinsa sekä ajaa T-LOIK- ja
WinCC OA:n välisiä integraatiotestejä. Viimeisenä on vielä erillinen XaidDriver-operaatio,
joka käynnistää WinCC OA:n ja X-AID simulaattorin sekä ajaa sitä vasten XaidDriverin ja
WinCC OA:n väliset testit sekä XaidDriverin yksikkötestit. Osa näistä operaatioista ajetaan
ajastetusti esimerkiksi kaksi kertaa viikossa, kun osa taas ajetaan aina kun Jenkins huomaa
operaatioon konfiguroidun kansiopolun saaneen uutta sisältöä versionhallinnassa.
Tämä määrä erilaisia operaatioita saattaa vaikuttaa hieman ylilyönniltä, mutta kuten aiemmin
todettiin, automaatiojärjestelmissä luotettavuus on erittäin tärkeää. Näiden erilaisten auto-
matisoitujen operaatioiden avulla ohjelmaa testataan säännöllisesti jokaisella tasolla: PLC:n
ja SCADA:n välinen dataketju testataan WinCC OA:n Jenkins operaatioissa, XaidDriverin
ja WinCC OA:n väli testataan XaidDriver-operaatiossa ja T-LOIK:n ja WinCC OA:n vä-
liset operaatiot T-LOIK-Ohjaussovittimen operaatiossa. Tämä minimoi mahdolliset virheet
ja ikävät yllätykset itse käyttöönotto-vaiheessa ja kenttätesteissä. Seuraavissa luvuissa kä-
sitellään pääasialliset XaidDriverin kannalta olennaiset testit ja SCADA:n sekä XaidDrive-
rin väliset integraatiotestit. XaidDriveria varten kehitettiin myös integraatiotestejä T-LOIK-
64
ohjaussovittimen ja WinCC OA:n välille, mutta näiden käsittely ohitetaan tämän pro gradun
yhteydessä.
9.1 XaidDriverin yksikkötestaus
Yksikkötestien muodostaminen aloitettiin identifioimalla protokollamääritelmän mukaiset
luokat ja luomalla testit dekooderille sekä enkooderille. Tämän jälkeen näitä testejä vasten
kehitettiin XaidEncoder ja XaidDecoder -luokat. Testien kehityksessä hyödynnettiin NUnit-
ohjelmistokehystä, joka on suunniteltu C#-koodin kattavaan ja helppoon testaamiseen. Esi-
merkiksi tältä näyttää kameroiden tiloja kyselevä testi:
p u b l i c a sync Task Shou ldGe tCameraS ta t e ( L i s t < u i n t > c a m e r a I d s = n u l l )
{
XaidResponse r e s u l t = n u l l ;
i f ( c a m e r a I d s != n u l l ) r e s u l t = ( XaidResponse ) a w a i t
_ x a i d D r i v e r . Ge tCameraS ta t e ( camera Ids , 1 ) ;
e l s e r e s u l t = ( XaidResponse ) a w a i t
_ x a i d D r i v e r . Ge tCameraS ta t e ( new L i s t < u i n t > ( ) , 1 ) ;
A s s e r t . NotNul l ( _ x a i d D r i v e r . _ c l i e n t ) ;
A s s e r t . NotNul l ( r e s u l t ) ;
A s s e r t . NotNul l ( r e s u l t . Q u e r y R e s u l t ) ;
A s s e r t . I s I n s t a n c e O f ( t y p e o f ( L i s t <Camera >) , r e s u l t . Q u e r y R e s u l t ) ;
A s s e r t . I s N o t N u l l ( ( ( L i s t <Camera >) r e s u l t . Q u e r y R e s u l t ) [ 0 ] . CameraS t a t e ) ;
A s s e r t . IsNotEmpty ( _ x a i d D r i v e r . Cameras ) ;
A s s e r t . I s N o t N u l l ( _ x a i d D r i v e r . Cameras [ 0 ] . CameraS t a t e ) ;
}
Samankaltaiset testit on kirjoitettu jokaiselle kuudestatoista mahdollisesta TCP-kyselystä.
Joillain näistä on vielä useampia testejä, joissa haetaan esimerkiksi vain yksi kameran ti-
la, eikä kaikkia kameroiden tiloja. Ohessa myös varmistetaan että näiden kyselyiden arvot
tallennetaan XaidDriver-luokan attribuutteihin. Tämä testiluokka sisältää myös testit, joissa
simuloidaan X-AID-palvelimen kaatumista, yksittäisen analysaattoripalvelimen kaatumista
65
ja muita virhetilanteita.
Nämä testit testaavat lähinnä kuviossa 6 esiteltyjen luokkien välisten operaatioiden toimimis-
ta toivotulla tavalla. Kehityksen yhteydessä näiden testien läpäisy varmistettiin ennen koodin
lähettämistä versionhallintaan. Tämän jälkeen Jenkins-ohjelmisto ajoi automaattisesti nämä
testit vielä kertaalleen läpi ja julkaisi NUnit-testiraportin. Kattavien testien suunnittelun an-
siosta koodin refaktorointi myöhemmissä kehityksen vaiheissa oli melko vaivatonta, sillä
muutoksien jälkeen testien ajaminen auttoi huomaamaan mahdollisia epäkohtia ja helponsi
laadunhallintaa.
9.2 Integraatiotestaus XaidDriverin ja WinCC OA:n välillä
Jotta pystyttiin varmistamaan että XaidDriverin vastaanottama data kulkee WinCC OA:n as-
ti, testeihin injektoitiin WinCC OA:n C#-API, eli kuvassa 6 esitetty Oa C#-Manager. Tämän
avulla testeissä pystyi hakemaan WinCC OA:han välitettyä dataa antamalla datapointin ni-
men ja toivotun datan polun. Käytännössä tällainen operaatio näyttää seuraavanlaiselta:
s t r i n g j s o n =
oaManager . P r o c e s s V a l u e s . GetDpValue ( "HKA10 . s t a t u s V a l u e " ) . DpValue ;
C#-Manager omaa myös samanlaiset funktiot arvojen asettamiseen - mutta kuten aiemmin
mainittiin - näitä toimintoja ei kutsuta XaidDriverin sisällä alkuperäisten datarakenteiden
luomisen lisäksi, sillä itse DriverManager omaa funktiot arvojen sijoittamiseen WinCC OA-
järjestelmään ja nämä funktiot omaavat erilaisia varmistuksia, kuten järjestelmän kahden-
nuksen hallitsemisen. Integraatiotestien yhteydessä tämän API:n suora käyttö tosin helpottaa
datan kulun varmistamista.
Käytännössä jokainen WinCC OA:n ja XaidDriverin integraatiotesti on erilainen variaatio
samasta ajatuksesta:
1 . Käynnistetään WinCC OA -projekti ja DriverManager sekä alustetaan XaidDriver.
2 . Odotetaan, että XaidDriver on muodostanut yhteyden WinCC OA-järjestelmään ja
66
luonut tarvitsemansa datapointit.
3 . Haetaan jonkin datapointin arvo string-muuttujaan.
4 . Käynnistetään jokin spontaani palvelintapahtuma X-AID simulaattorissa suorittamalla
HTTP-rajapinnan yli simuloitu hälytystapahtuma.
5 . Odotetaan muutama sekuntti ja haetaan nykyinen saman datapointin arvo
string-muuttujaan.
6 . Verrataan näitä tekstiarvoja ja todetaan, että simuloidun hälytyksen arvo on päivittynyt
eteenpäin.
7 . Deaktivoidaan hälytys ja varmistetaan että arvo vastaa oletettua.
Tämän tarkemmaksi havainnoillistamiseksi esimerkkinä kameran HKA10 hälytyksiä testaa-
va yksinkertainen testi:
[ Tes t , R e t r y ( 2 ) ]
p u b l i c a sync Task Ala rmCoun tAndAla rmSta t eUpda teMul t ip l e ( )
{
a w a i t _ x a i d I n p u t D r i v e r . D r i v e r . D e f a u l t D a t a P o i n t Q u e r i e s ( ) ;
_ x a i d I n p u t D r i v e r . I n i t i a l C o n n e c t i o n D o n e = t rue ;
LogResponse ( a w a i t S i m A c t i v a t o r . GetAsync ( L o c a l H t t p +
_ i n c i d e n t D e a c t i v a t i o n S i m U r l s [ 0 ] ) ) ;
a w a i t S i m A c t i v a t o r . GetAsync ( L o c a l H t t p +
_ i n c i d e n t D e a c t i v a t i o n S i m U r l s [ 1 ] ) ;
a w a i t S i m A c t i v a t o r . GetAsync ( L o c a l H t t p +
_ i n c i d e n t D e a c t i v a t i o n S i m U r l s [ 2 ] ) ;
a w a i t Task . Delay ( 5 0 0 0 ) ;
OaManager oaManager = _ x a i d I n p u t D r i v e r . OaManager ;
s t r i n g o r i g i n a l J s o n = oaManager . P r o c e s s V a l u e s
. GetDpValue ( " XaidCam−HKA10 . s t a t u s V a l u e " ) . DpValue ;
a w a i t S i m A c t i v a t o r . GetAsync ( L o c a l H t t p +
_ i n c i d e n t A c t i v a t i o n S i m U r l s [ 0 ] ) ;
67
a w a i t S i m A c t i v a t o r . GetAsync ( L o c a l H t t p +
_ i n c i d e n t A c t i v a t i o n S i m U r l s [ 1 ] ) ;
a w a i t S i m A c t i v a t o r . GetAsync ( L o c a l H t t p +
_ i n c i d e n t A c t i v a t i o n S i m U r l s [ 2 ] ) ;
a w a i t Task . Delay ( 5 0 0 0 ) ;
s t r i n g r e c e n t J s o n = oaManager . P r o c e s s V a l u e s
. GetDpValue ( " XaidCam−HKA10 . s t a t u s V a l u e " ) . DpValue ;
A s s e r t . I s F a l s e ( o r i g i n a l J s o n . E qu a l s ( r e c e n t J s o n ) ) ;
J O b j e c t o r i g i n a l = J O b j e c t . P a r s e ( o r i g i n a l J s o n ) ;
J O b j e c t s e c o n d a r y = J O b j e c t . P a r s e ( r e c e n t J s o n ) ;
A s s e r t . AreNotEqual ( o r i g i n a l [ " Act iveAlarmCount " ] ,
s e c o n d a r y [ " Act iveAlarmCount " ] ) ;
a w a i t S i m A c t i v a t o r . GetAsync ( L o c a l H t t p +
_ i n c i d e n t D e a c t i v a t i o n S i m U r l s [ 0 ] ) ;
a w a i t S i m A c t i v a t o r . GetAsync ( L o c a l H t t p +
_ i n c i d e n t D e a c t i v a t i o n S i m U r l s [ 1 ] ) ;
a w a i t S i m A c t i v a t o r . GetAsync ( L o c a l H t t p +
_ i n c i d e n t D e a c t i v a t i o n S i m U r l s [ 2 ] ) ;
a w a i t Task . Delay ( 5 0 0 0 ) ;
r e c e n t J s o n = oaManager . P r o c e s s V a l u e s
. GetDpValue ( " XaidCam−HKA10 . s t a t u s V a l u e " ) . DpValue ;
o r i g i n a l = J O b j e c t . P a r s e ( o r i g i n a l J s o n ) ;
s e c o n d a r y = J O b j e c t . P a r s e ( r e c e n t J s o n ) ;
A s s e r t . AreEqual ( o r i g i n a l [ " Act iveAlarmCount " ] ,
s e c o n d a r y [ " Act iveAlarmCount " ] ) ;
}
Testi siis toimii juuri aiemman listan tavalla. Se hakee dataa, simuloi hälytyksiä ja noutaa
WinCC OA:sta JSON-muotoisia tekstipätkiä, parsii niistä C#:n NewtonSoft JSON-kirjaston
JObject-olion ja vertailee vastaanotettuja arvoja. Näitä testejä on tietenkin useampia ja useam-
68
malle kameralle, palvelin- ja tilastodatalle ja niin edelleen, mutta kaikki niistä seuraavat sa-
maa periaatetta.
Järjestelmien kahdennuksen testaaminen puolestaan toteutettiin kahdella identtisellä WinCC
OA-instanssilla. Toinen näistä instansseista sijaitsi virtuaalikoneella, toinen varsinaisella työ-
asemalla. Tämän lisäksi simulaattoreja oli kaksi, kummatkin konfiguroituna eri portteihin.
Tällä tavalla pystyi simuloimaan sekä SCADA:n aktiivisen ja passiivisen palvelimen vaih-
tumista, sekä X-AID-palvelimen kahdennusta. Tämä tapahtui vaihtamalla SCADA:n ak-
tiivista osapuolta summittaisesti ja aiheuttamalla keinotekoisia yhteysongelmia näiden eri
simulaattori-instanssien välillä. Jos ajatellaan, että X-AID-simulaattori 1 ja 2 ovat nimellä
X1 ja X2, kun taas SCADA-instanssit nimellä S1 ja S2, näiden testien esimerkkikulku on
seuraavanlainen:
1 . Alustetaan S1, S2, X1 ja X3.
2 . Asetetaan S1 ja X1 aktiivisiksi osapuoliksi ja varmistetaan kommunikaation toiminen
sekä simuloidaan erilaisia tilanteita.
3 . Kaadetaan X1 ja varmistetaan, että S1 osaa automaattisesti yhdistyä X2:seen sekä
simuloidaan erilaisia tilanteita..
4 . Asetetaan S1 passiviseksi ja S2 aktiiviseksi, varmistaen että S2 osaa initialisoida
yhteyden X2:seen sekä simuloidaan erilaisia tilanteita.
5 . Toistetaan kohtia 1-4 erilaisilla variaatioilla, kunnes kahdennuksen toimivuus todetaan
riittäväksi.
X-AID-palvelimet ovat järjestelmän toimittajan mukaan jatkuvasti synkronisoituja ja omaa-
vat yhteisen tietokannan, joten näiden yhteinen synkronisuus ei kuulunut tämän suunnittelu-
tutkimuksen piiriin.
Ohjelmaa testattiin mahdollisia muistivuotoja vastaan jättämällä WinCC OA:n projekti pyö-
rimään testiympäristöön viikonlopun yli XaidDriverin ollessa päällä, samalla kun ikuisessa
silmukassa pyörivällä powershell-skriptillä simuloitiin erilaisia hälytyksiä ja virhetilanteita.
Simulaatioon luotiin satunnaisuutta soveltamalla varsin paljon powershellin Get-Random()-
funktiota. Käytännössä skriptin ansiosta oli satunnaista minkä tyyppinen virhetilanne tai hä-
69
lytysmassa tapahtui, kuinka kauan tilanteet kestivät ja kuinka kauan kesti ennen kuin seuraa-
va kierros tästä silmukasta alkoi. Viikonlopun jälkeen tarkistettiin muistin kulutus ja verrat-
tiin sitä alkutilanteeseen.
Muistivuotojen tarkkailu oli erittäin tärkeää, sillä C# omaa automaattisen roskienkeruun ja
muistinvapautuksen, mutta tähän ei voi täysin luottaa. Ottaen huomioon, että kyseinen so-
vellus tulee olemaan päällä vuorokauden ympäri, voivat nämä muistivuodot aiheuttaa suuria
ongelmia liikenteenhallintajärjestelmissä. Tietenkään tämä ei ole täydellinen tapa löytää näi-
tä mahdollisia muistivuotoja, mutta se antaa suuntaa mahdollisista ongelmista. Testaamisella
pyrittiin varmistamaan, että luvun 8 vaatimusten kohta numero 9 täyttyy.
Testi suoritettiin kahdesti, kahtena eri viikonloppuna. Ensimmäisenä viikonloppuna havait-
tiin taustalle elämään jäänyt Timer-luokan olio, joka aiheutti noin 30 megatavun muistivuo-
don 24 tuntia kohden. Koodiin lisättiin yksi rivi ja muistivuoto poistui. Toisella testikerralla
puolestaan havaittiin, että järkevien suunnittelumallien ja huolellisen testaamisen seurauk-
sena ei löytynyt muistivuotoja tai ennaltaodottamattomia ongelmia. Aiemmalla testikerralla
löytynyt lievä muistivuoto jäi siis ainoaksi laatuaan.
9.3 Kenttätestien huomioita ja tuloksia
Alustavat kenttätestit X-AID integraatiolle alkoivat heti varsin positiivisella tavalla, sillä
ajurin asennus toimi juuri kuten pitikin: muutamaa nappia painamalla XaidDriver asentui
osaksi SCADA-järjestelmää, käynnistyi ilman ongelmia ja otti yhteyden oikeaan X-AID-
järjestelmään. Tämän jälkeen ajuri automaattisesti loi tarvittavat datapointit SCADA-järjestelmään
ja täytti ne palvelimelta vastaanotetun datan JSON-representaatioilla. Sen jälkeen ajuri ru-
pesi toimimaan juuri kuten se oli suunniteltu: ajuri alkoi välittämään hälytyksiä ja muita
X-AID järjestelmältä vastaanotettuja spontaaneista tapahtumista tulkittuja tietoja SCADA-
järjestelmän datapointteihin.
Täysin ongelmitta ohjelma ei kuitenkaan lähtenyt toimimaan. X-AID-järjestelmän toimitta-
ja oli luokitellut aiemmin mainitut loogiset alueet palo-aluiden perusteella (1-7), kun taas
YSP:n tuottamat sekvenssit luokittelivat loogiset alueet kamerakohtaisesti väliltä 1-3. Nämä
alueet oli laskettu kameran etäisyydestä johonkin paloalueeseen, eli PLC-laitteiston näkö-
70
kulmasta jollakin kameralla, joka esimerkiksi tarkkaili paloalueita 3, 4 ja 5, nämä alueet oli
luokiteltu alueiksi 1, 2 ja 3. Tämä vaati muutoksia SCADA:ssa sijaitsevaan CTRL-skriptiin,
joka välitti tietoa PLC-laitteistolle. Käytännössä kameran tunnisteen perusteella piti tulkita,
oliko palvelimelta vastaanotettu arvo looginen alue 1, 2 vai 3. Tämä onneksi oli melko yksin-
kertaista korjata, sillä piti vain tehdä yksi uusi funktio, joka kameran tunnisteen perusteella
konvertoi esimerkiksi vastaanotetun alueen 7 alueeksi 1 PLC-laitteistolle.
Kaikki ongelmat eivät kuitenkaan ratkenneet pelkästään tällä korjauksella: oikean järjestel-
män lähettämän datan määrä oli paljon simulaatioita suurempaa. Tämä nosti esiin selkeän
ongelman XaidDriverin vastaanottamien datojen käsittelyssä: DatapointModifer-luokassa oli
selvä suunnitteluvirhe. C#:n LINQ-operaatioita oli sovellettu varsin paljon datan asettami-
sessa. Ongelmana oli lähinnä C#:n .ForEach-lambda ja .FindIndex-lambda, sillä koko sovel-
lus oli suunniteltu asynkrooniseksi. Kyseiset funktiot aiheuttivat poikkeuksia, sillä jos tämän-
kaltaisen listan solujen läpikäymisen yhteydessä listaan lisättiin tai sieltä poistettiin materi-
aalia, meni ohjelma siitä sekaisin. XaidDriver omasi päälläollessaan keskimäärin noin 40 eri
säiettä, joista jokainen suoritti asynkronisesti omia operaatioitaan. Samoja listoja muokattiin
useassa eri säikeessä samanaikaisesti.
Ongelman olisi voinut ratkaista lukoilla, mutta nopeamman datan välityksen vuoksi ongelma
korjattiin seuraavalla tavalla: jokaisessa aliohjelmassa vain kopioitiin alkuperäinen paramet-
risoitu lista toiseen listaan, jossa suoritettiin nämä operaatiot ja operaatioiden tulokset asetet-
tiin varsinaisiin olioihin. Koska ohjelma päivitti muuttuneita arvoja SCADA-järjestelmään
sekunnin välein, joka tapauksessa seuraavan sekunnin syklin aikana aiemman datan käsit-
telyn aikana tapahtuneet ja poisjääneet muutokset päätyivät miltei reaaliajassa valvomo-
ohjelmiston datarakenteisiin.
Näiden ongelmien korjaamisen jälkeen ajuri rupesi toimimaan juuri toivotulla tavalla: sil-
lä hetkellä yhteydessä ja toiminnassa olevat kamerat, jotka havaitsivat hälytyksiä, alkoivat
välittämään dataa aivan oikealla tavalla ja laukaisemaan sekvenssejä sekä ilmaisemaan käyt-
töliittymän kautta, että näin oli tapahtunut.
71
10 Yhteenveto ja jatkotoimenpiteet
Tässä pro gradussa esiteltiin YSP Oy:n Liikeennevirastolle tuottamien liikenteenhallintajär-
jestelmien arkkitehtuurinen rakenne ja esiteltiin tapa integroida erillinen järjestelmä osaksi
tätä kokonaisuutta. Lopputuotoksena syntyi valvomo-ohjelmistoon ajuri, jonka avulla ohjel-
misto pystyy ottamaan vastaan dataa tältä erilliseltä järjestelmältä. Samalla eriteltiin erilaisia
järkeviä suunnittelumalleja joita soveltamalla varmistettiin, että koodin laatu pysyi hyvänä
sekä esiteltiin pääpiirteissään erilaisia tapoja testata kyseisen ajurin toimivuutta.
Pro gradussa käsiteltiin XaidDriver-nimisen protokollatulkin kehitystä ja avattiin sen toi-
mintaan liittyviä erillisiä komponentteja. Näitä komponentteja ovat PLC, SCADA ja REST-
sovellukset. PLC kappaleessa esiteltiin ohjelmoitavien logiikoiden toiminta, niitä ohjaava
kieli (Structured Text) ja niiden liittäminen SCADA-ohjelmistoon. SCADA-luvussa käsitel-
tiin SCADA-ohjelmiston rakenne, taustalla oleva ajatus ja XaidDriverin kanssa sovelletta-
vaa SCADA-ohjelmistoa, eli Siemensin WinCC OA:ta. WinCC OA:n käsittelyn yhteydes-
sä avattiin mahdollisia tapoja liittää korkean tason ohjelmointikielten tarjoamia komplek-
sisempia operaatiota WinCC OA:n CTRL-skriptikieleen. Tämän jälkeen käsiteltiin REST-
arkkitehtuuria sekä T-LOIK-Ohjaussovitinta, jonka avulla SCADA-järjestelmä liitetään laa-
jempaan suomenlaajuiseen T-LOIK sovellukseen.
Lopuksi käsiteltiin pro gradun tuloksena syntyneen XaidDriverin rakenne, sen kehityksessä
sovelletut suunnittelumallit sekä sen testaaminen. Käsiteltyjä suunnittelumalleja olivat muun
muassa SOLID-periaate sekä riippuvuuksien injektio. Tämän pro gradun yhteydessä tarjot-
tiin uutta tietoa Suomen liikennejärjestelmien toiminnasta: tästä aiheesta ei juurikaan ole tie-
dettä saatavilla, sillä tällaisia ratkaisuja tarjoavia yrityksiä on Suomessa vain muutama, jois-
ta mikään ei ole juurikaan julkaissut tieteellisiä artikkeleja. Tutkielma tarjoaa näkökulmaa
automaatiosuunnittelun maailmaan ohjelmistosuunnittelijan näkökulmasta.
Suunnitteluprosessi seurasi Hevnerin ja Chatterjeen (2010) määrittelemiä suunnittelututki-
muksen syklejä: relevanssisykliä, suunnittelusykliä sekä täsmällisyyssykliä. Relevanssisyklis-
sä kartoitettiin olemassaolevat kirjastot, teknologiat, vaatimukset ja ympäristö, mitä ohjel-
miston kehityksessä sovellettiin sekä suunniteltiin toteutusta ja ohjelmiston rakennetta. Suun-
72
nittelusyklinä toimi ajurin kehitys ja eri komponenttien yhteensovittaminen. Täsmällisyys-
syklinä puolestaan toimi ohjelman jatkuva testaaminen sekä lopputulokset. Näitä syklejä
toistettiin useita kertoja ja tuloksia hiottiin ajan kuluessa, kunnes ajuri saavutti toivotun toi-
mivuustason ja täytti sille asetetut kohdassa 8 määritellyt vaatimukset.
Toteutettu ajuri on nopeampi kuin perinteinen REST-palvelu. Data kulkee binääriprotokol-
lan kautta, minkä seurauksena yksittäinen viesti on erittäin pieni, pienimmillään vain 16 ta-
vua. Tätä kun vertaa REST-palveluun, jossa viestejä välitetään XML- tai JSON-muodossa,
on datan koko pienempi ja operaatiot ovat nopeampia. Syntynyt ajuri on myös reaaliaikai-
nen: hälytyksen lauetessa viimeistään sekuntti hälytystilanteen alkamisen jälkeen tieto hä-
lytystilanteesta ja kuva tilanteen alkamisesta on toimitettu SCADA-järjestelmään. Tilanteen
päättyessä tai parametrisoidun aikavälin päättyessä myös videotiedosto on saatavilla. Eli jos
vaikkapa laukeaa väärään suuntaan ajavan ajoneuvon hälytys, joka kestää 30 sekunttia, on
valvomossa viimeistään 35 sekunnin päästä tilanteen alkamisesta ladattavissa videotiedosto
kyseisestä hälytystilanteesta. Tämäntasoinen reaaliaikaisuus mahdollistaa nopean reagoinnin
vaaratilanteissa ja parantaa liikenteen turvallisuutta tunnelissa.
Simulaattoria vasten ajurilla kesti 59 millisekunttia hakea 38 eri kameran 27 eri mahdol-
lista hälytystä ja muodostaa niistä C#-representaatiot. Käytännössä näiden 59 millisekun-
nin aikana täytettiin ja sijoitettiin tietorakenteisiin 1026 luokkaa, joista jokaiselle täytet-
tiin 8 eri kenttää. Tämän tasoinen reaaliaikaisuus olisi huomattavasti vaikeampaa toteuttaa
REST-sovelluksella, sillä XML:n ja JSON:in käsittelyssä ja tulkinnassa kestää pidempään
kuin yksinkertaisen tavutaulukon lukemisessa, kuten myös itse viestin kulussa, sillä TCP on
huomattavasti matalamman tason protokolla kuin HTTP. Tutkielman ohessa myös sivuuttiin
ProtoLib-kirjastoa, jonka avulla tämänkaltaisten protokollatulkkien toteutus on helpompaa.
Tulosten perusteella voi kysyä, miksi tämänkaltaiset räätälöidyt binääriprotokollat eivät ole
vielä nykyistä yleisemmässä käytössä internetin välityksellä kommunikoivissa järjestelmis-
sä. Selvästi ne ovat suoritusteholtaan parempia ja nopeampia. Kyse varmaan lieneekin sii-
tä, että yksinkertaisen REST-sovelluksen kehittäminen on huomattavasti helpompaa, kuin
tämänkaltaisen binääriprotokollan. Tästä syystä sovellukset, jotka eivät tarvitse reaaliaikai-
suutta samalla tasolla kuin esimerkiksi liikenteenhallintajärjestelmä, voivat hyvin toimia hi-
taammalla ja raskaammalla HTTP:n yli kommunikoivilla REST-rajapinnoilla. Tämän pro-
73
tokollan toteutus onnistui silti varsin helposti, sillä protokollakäsittelyjä varten kehitetty
ProtoLib-ohjelmistokirjasto tarjosi suurta apua tähän prosessiin.
Tutkielman esittämä tapa tulkita binääriprotokollaa TCP-virrasta on myös yleistettävissä.
Periaatteessa jokainen internetin kautta kommunikoiva peli käyttää samantapaista toteutus-
ta, sillä esimerkiksi kameran ja hälytysten tietojen sijasta samankaltaisen protokollan sisällä
voi kulkea vaikkapa hahmon tunniste ja kordinaatit, joihin hahmo on liikkumassa. Tämä tar-
koittaa, että tutkielmassa esitettyjä suunnittelumalleja ja testivetoista kehitystä voi ja kannat-
taa soveltaa myös pelisuunnittelussa, mikäli peli kommunikoi verkon yli jonkin palvelimen
kanssa.
Testivetoisen kehityksen edut nousivat esille työn tuloksessa: huolellisen integraatiotestaa-
misen, automaatiotestaamisen ja yksikkötestaamisen tuloksena XaidDriverin asentaminen
tuotantopalvelimelle tapahtui kivuttomasti: samantien asennuksen jälkeen ohjelma otti yh-
teyden oikeaan X-AID-palvelimeen ja täytti WinCC OA:n datapointit palvelimelta haetuista
arvoista muodostetuilla JSON-olioilla ja alkoi välittämään hälytyksiä. Vaikka ajurin toimin-
nassa ilmenikin pieniä ongelmia, joita käsiteltiin aiemmassa kappaleessa, toimi ajuri pää-
piirteissään aivan suunnittelulla tavalla. Tämä vain vahvistaa luvussa 7.3 mainittujen IBM:n
sekä Georgen ja Williamsin tutkimuksissa havaittuja huomioita: testivetoisella kehityksellä
toteutetun koodin laatu ja luotettavuus on parempaa.
Sovelluksen toimintaa testataan myös kenttätesteissä. Näiden testien aikana SCADA-järjestel-
mää testataan paikan päällä. Tälle on varattu aikaa noin puoli vuotta, sillä kyseessä on varsin
monimutkainen järjestelmä. Tähän puoleen vuoteen tosin kuuluvat kaikki muutkin järjes-
telmään kuuluvat toiminnallisuudet, eikä pelkästään tutkielmassa käsitelty X-AID. Toden-
näköisesti tämän kattavan testauksen yhteydessä tulee varmasti esille joitain puutteita tai
ongelmia. Joka tapauksessa varsin laajalla testaamisella kehityksen yhteydessä näiden mah-
dollisten ongelmien määrä on pyritty minimoimaan.
Tämänkaltainen integraatioprojekti luonnollisesti vaatii laajamittaista testausta myös oikean
elämän tilanteissa ja todellisessa maailmassa. Ilman kenttätestausta olisi milten mahdotonta
kehittää näin suuria järjestelmiä. Tutkielma tarjoaa myös näkökulmaa siihen, kuinka laajo-
jen kokonaisuuksien kanssa ohjemistoalalla joutuu työskentelemään. Ero akateemisen maa-
74
ilman hallittuihin ja kompakteihin järjestelmiin on melkoinen ja mittakaava huomattavasti
suurempi.
Järjestelmää ei ole parin päivän mittaisen muistivuototestin lisäksi testattu jatkuvalla syö-
töllä, joten paikan päällä sen ollessa päällä vuorokauden ympäri useamman viikon putkeen
saattaa ilmetä joitain korjausta vaativia ongelmia. Onneksi juuri tämänkaltaisten syiden takia
järjestelmien testaamiseen on varattu aikaa. Kun kenttätesteissä ilmenneet puutteet ja virheet
on korjattu, siirrytään järjestelmän ylläpitoon.
75
Lähteet
Beck, Kent. 2003. Test-driven development: by example. Addison-Wesley Professional.
Boyer, Stuart A. 2009. SCADA: supervisory control and data acquisition. International Socie-
ty of Automation.
Choi, Donghyun, Sungjin Lee, Dongho Won ja Seungjoo Kim. 2010. “Efficient secure group
communications for SCADA”. IEEE Transactions on Power Delivery 25 (2): 714–722.
Chou, Wu, ja Li Li. 2016. Method and system for managing and using sessions as RESTful
web services. US Patent 9,509,776, marraskuu.
“Control script language”. 2018-08-15. Viitattu 6. elokuuta 2018. http://www.etm.
at/index%5C_e.asp?id=2%5C&sb1=67%5C&sb2=118.
Daneels, Axel, ja Wayne Salter. 1999. “What is SCADA?”
“Dependency Inversion Principle”. 2018-12-10. Viitattu 10. joulukuuta 2018. https://
deviq.com/dependency-inversion-principle/.
“Dependency Inversion vs Dependency Injection vs Inversion of Control vs Programming to
Interfaces”. 2018-12-10. Viitattu 10. joulukuuta 2018. https://www.equinox.co.
nz/blog/dependency-inversion-dependency-injection-inversion-
control-programming-interfaces/.
Erenkrantz, Justin Ryan. 2009. Computational REST: a new model for decentralized, internet-
scale applications. Citeseer.
Erickson, Kelvin T. 1996. “Programmable logic controllers”. IEEE potentials 15 (1): 14–17.
Erl, Thomas, Benjamin Carlyle, Cesare Pautasso ja Raj Balasubramanian. 2012. Soa with
rest: Principles, patterns &constraints for building enterprise solutions with rest. Prentice
Hall Press.
Feng, Xinyang, Jianjing Shen ja Ying Fan. 2009. “REST: An alternative to RPC for Web
services architecture”. Teoksessa Future Information Networks, 2009. ICFIN 2009. First
International Conference on, 7–10. IEEE.
76
Fernandez Adiego, B, I Prieto Barreiro ja E Blanco Vinuela. 2011. “UNICOS CPC6: automa-
ted code generation for process control applications”. Teoksessa Conf. Proc. Nide 111010,
WEPKS033. CERN-ATS-Note-2011-109 TECH.
George, Boby, ja Laurie Williams. 2004. “A structured experiment of test-driven develop-
ment”. Information and software Technology 46 (5): 337–342.
Goldenberg, Niv, ja Avishai Wool. 2013. “Accurate modeling of Modbus/TCP for intrusion
detection in SCADA systems”. International Journal of Critical Infrastructure Protection 6
(2): 63–75.
Hewitt, Carl, Peter Bishop ja Richard Steiger. 1973. “Session 8 formalisms for artificial intel-
ligence a universal modular actor formalism for artificial intelligence”. Teoksessa Advance
Papers of the Conference, 3:235. Stanford Research Institute.
Hevner, Alan, ja Samir Chatterjee. 2010. “Design science research in information systems”.
Teoksessa Design research in information systems, 9–22. Springer.
“How do you program and parameterize Modbus/TCP communication between S7-1500
CPUs and S7-1200 CPUs?” 2018-10-16. Viitattu 16. lokakuuta 2018. https://suppo
rt.industry.siemens.com/cs/document/102020340/how-do-you-
program-and-parameterize-modbus-tcp-communication-between-
s7-1500-cpus-and-s7-1200-cpus-?dti=0%5C&lc=en-WW.
Igure, Vinay M, Sean A Laughter ja Ronald D Williams. 2006. “Security issues in SCADA
networks”. Computers & Security 25 (7): 498–506.
“Interface Segregation Principle”. 2018-12-10. Viitattu 10. joulukuuta 2018. https://
deviq.com/interface-segregation-principle/.
“Ladder Logic Examples”. 2018-10-16. Viitattu 16. lokakuuta 2018. https://www.
plcacademy.com/ladder-logic-examples/.
Leppänen M., Nurminen M., Käkölä T. 2009. ITKA111 Oliosuuntautunut analyysi ja suun-
nittelu.
“Liskov Substition Principle”. 2018-12-10. Viitattu 10. joulukuuta 2018. https://devi
q.com/liskov-substitution-principle/.
77
“Managed Extensibility Framework (MEF)”. 2018-09-24. Viitattu 24. syyskuuta 2018. htt
ps://docs.microsoft.com/en-us/dotnet/framework/mef/.
Martin, Robert C. 1996. “The open-closed principle”. More C++ gems 19 (96): 9.
. 2002. Agile software development: principles, patterns, and practices. Prentice Hall.
Masse, Mark. 2011. REST API Design Rulebook: Designing Consistent RESTful Web Service
Interfaces. "O’Reilly Media, Inc.".
Maximilien, E Michael, ja Laurie Williams. 2003. “Assessing test-driven development at
IBM”. Teoksessa Software Engineering, 2003. Proceedings. 25th International Conference
on, 564–569. IEEE.
Modbus, IDA. 2004. “Modbus messaging on TCP/IP implementation guide”. v1. 0a, June 4.
“Open-Closed Principle”. 2018-12-10. Viitattu 10. joulukuuta 2018. https://deviq.
com/open-closed-principle/.
Page, David W, ja LuVerne R Peterson. 1985. Re-programmable PLA. US Patent 4,508,977,
huhtikuu.
Phan, Raphael C-W. 2012. “Authenticated modbus protocol for critical infrastructure protec-
tion”. Ieee transactions on power delivery 27 (3): 1687–1689.
Qiu, Bin, ja Hoay Beng Gooi. 2000. “Web-based SCADA display systems (WSDS) for
access via Internet”. IEEE transactions on power systems 15 (2): 681–686.
Razina, Ekaterina, ja David S Janzen. 2007. “Effects of dependency injection on maintai-
nability”. Teoksessa Proceedings of the 11th IASTED International Conference on Software
Engineering and Applications: Cambridge, MA, 7.
Rodriguez, Alex. 2008. “Restful web services: The basics”. IBM developerWorks 33.
“SIMANTIC WinCC Open Architecture - HMI Software - Siemens”. 2019-03-07. Viitattu
7. maaliskuuta 2019. https://w3.siemens.com/mcms/human- machine-
interface/en/visualization-software/simatic-wincc-open-arch
itecture/Pages/Default.aspx?vpl=References#i=1,language=en,
produkt=key_9180609/.
78
“SIMATIC WinCC Open Architecture - Basic system”. 2018-08-15. Viitattu 6. elokuuta
2018. https://w3.siemens.com/mcms/human- machine- interface/
en/visualization-software/simatic-wincc-open-architecture/
wincc-oa-basic-sw/Pages/default.aspx.
“Single Responsibility Principle”. 2018-12-10. Viitattu 10. joulukuuta 2018. https://
deviq.com/single-responsibility-principle/.
Spangenberg, Thomas, Karlheinz Cerff ja W Mexner V Kaiser. 2011. “„Tango Integration
of a SIMATIC WinCC Open Architecture SCADA System at ANKA “”. Teoksessa Procee-
dings of the 13th International Conference on Accelerator and Large Experimental Physics
Control Systems, 749–752.
“Structured Text Tutorial to Expand Your PLC Programming Skills”. 2018-09-20. Viitattu
20. syyskuuta 2018. https://www.plcacademy.com/structured- text-
tutorial//wincc-oa-basic-sw/Pages/default.aspx.
Ten, Chee-Wooi, Chen-Ching Liu ja Govindarasu Manimaran. 2008. “Vulnerability assess-
ment of cybersecurity for SCADA systems”. IEEE Transactions on Power Systems 23 (4):
1836–1846.
“The SCADA system without limits”. 2018-08-15. Viitattu 6. elokuuta 2018. https://
w3.siemens.com/mcms/human-machine-interface/en/visualization-
software/simatic-wincc-open-architecture/pages/default.aspx.
Thijssen, J. 2012. “Asynchronous operations-The RESTful cookbook”. The RESTful cook-
book.
Tiegelkamp, Michael, ja Karl-Heinz John. 1995. IEC 61131-3: Programming industrial au-
tomation systems. Springer.
“Traffic Video Analysis / Automatic Video Incident Detection - XAIDTM”. 2018-09-27. Vii-
tattu 27. syyskuuta 2018. https://www.telegra-europe.com/solutions/
solution - 54 - automatic - video - incident - detection - avid - and -
traffic-analysis-system/#61.
79
“Uusi tieliikenteen ohjausjärjestelmä (T-LOIK) nopeuttaa tiedonkulkua tienkäyttäjille ja hel-
pottaa liikennepäivystäjien työtä”. 2016-03-04. Viitattu 15. elokuuta 2018. https://www.
liikennevirasto . fi/ - /uusi - tieliikenteen - ohjausjarjestelma -
t-loik-nopeuttaa-tiedonkulkua-tienkayttajille-ja-helpottaa-
liikennepaivystajien-tyota.
Varela, Fernando, Montserrat Gonzalez Corral, Stanislaw Podgorski, Eleni Mandilara ja Uwe
Epting. 2018. “JACoW: MARS: Easing maintenance and interventions for CERN controls”.
“What is Akka.NET?” 2018-08-15. Viitattu 13. syyskuuta 2018. https://getakka.
net/articles/intro/what-is-akka.html.
80