Implementácia systému
Na meranie meteorologických veličín som použil meteorologickú stanicu, ktorá je umiestnená na streche Ústavu výpočtovej techniky.Celý systém som rozdelil na dva servery:
- jeden sa stará o získavanie a uchovávanie dát z meteostanice
- druhý server som použil pre samotnú webovú stránku
Cron
Celý systém musí pracovať automaticky, bez ďalších zásahov človeka. To som musel nejako vyriešiť, a keďže na oboch serveroch je ako operačný systém použitý linux, tak som využil program Cron. Vďaka nemu dokážem spúšťať skripty alebo príkazy v presne stanovený čas. Program Cron som nakonfiguroval editáciou súboru crontab. Najjednoduchšie sa to vykoná napísaním nasledujúceho príkazu do terminálu.crontab -e
Tým som sa dostal do textového editora, kde môžem crontab nakonfigurovať. Každý záznam v konfiguračnom súbore má presne stanovenú štruktúru (pozri ďalej). Viac sa o programe Cron a jeho konfigurácií dočítate na Wikipédií.
# * * * * * príkaz na spustenie # ┬ ┬ ┬ ┬ ┬ # │ │ │ │ │ # │ │ │ │ │ # │ │ │ │ └───── deň v týždni (0 - 6) (0 je Nedeľa) # │ │ │ └────────── mesiac (1 - 12) # │ │ └─────────────── deň v mesiaci (1 - 31) # │ └──────────────────── hodina (0 - 23) # └───────────────────────── minúta (0 - 59)Prebrané z Wikipédie
DWT
DWT je jednoduchý program napísaný v jazyku C, ktorý slúži na komunikáciu s meteorologickou stanicou cez sériový port počítača. Tento program si môžete stiahnúť na adrese http://ct.id.au/weather/software.Gnuplot
Na vytvorenej webovej stránke s počasím chcem vykresľovať historické priebehy niektorých veličín. Na to využívam program Gnuplot. Tento program slúži na tvorbu najrozličnejších druhov grafov. Spúšťa sa z terminálu, čo mi práve vyhovuje, keďže ho má spúšťať Cron. Jeho hlavnou výhodou je, že výstupné grafy sa dajú jednoducho prispôsobovať.Zjednodušená bloková schéma systému |
Server pre získavanie dát z meteostanice
Hlavnou úlohou tohto servera je uchovávať a poskytovať namerané údaje. To som implementoval tak, že na servri sú cez HTTP protokol (pomocou lighttpd) prístupné textové súbory s dátami. Konkrétne som vytvoril súbory current_weather.txt a current_data.txt. Do súboru current_weather.txt zapisujem aktuálne hodnoty počasia a do súboru current_data.txt postupne pridávam nové merania, čím vzniká krátkodobý archív dát.Pre získanie dát z meteostanice som využil program DWT. Ten zavolám nasledujúcim príkazom:
dwt FRMT '+%.1{OUT_TEMP} %.0{BAROMETER} %{WIND_SPEED} %{WIND_DIRECTION} %.1{DEW_POINT} %.0{SOLAR_RAD} %{SUNRISE} %{SUNSET} %{OUT_HUMIDITY} %.2{ET_TODAY} %.2{ET_MONTH} %.2{ET_MONTH} %{FORECAST_ICON}'
Program mi vráti hodnoty aktuálneho počasia naformátované podľa spusteného príkazu. Tieto hodnoty si ukladám do textových súborov, ktoré neskôr využívam na zostavenie stránky.
Proces získavania dát z meteostanice som zautomatizoval pomocou programu Cron, ktorého konfiguračný súbor vyzerá takto:
# skript na získanie aktuálnych hodnôt počasia 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /cesta_s_súboru/cron_weather_server.sh # skript na pridanie ďalšieho riadku do archívu 0,15,30,45 * * * * /cesta_s_súboru/cron_current_data.sh
Zobrazený Cron spúšťa dva skripty:
- jeden pre získania aktuálneho stavu počasia, ktorý sa spúšťa každých 5 minút
- druhý pre zapísanie ďalšieho riadku s aktuálnymi hodnotami počasia do súboru, ktorý slúži ako archív dát - ten sa spúšťa každých 15 minút
Oba tieto skripty sú jednoduché a ich obsah je zobrazený na nasledujúcich riadkoch.
# cron_weather_server.sh # zapisanie aktualineho pocasia do suboru dwt FRMT '+%.1{OUT_TEMP} %.0{BAROMETER} %{WIND_SPEED} %{WIND_DIRECTION} %.1{DEW_POINT} %.0{SOLAR_RAD} %{SUNRISE} %{SUNSET} %{OUT_HUMIDITY} %.2{ET_TODAY} %.2{ET_MONTH} %.2{ET_MONTH} %{FORECAST_ICON}' > current_weather.txt
# cron_current_data.sh
# pridanie aktualneho datumu a času
date +'%H:%M:%S %d-%m-%Y ' | tr -d "\n\r" >> current_data.txt
# pridanie aktuálnych hodnôt počasia
dwt FRMT '+%.1{OUT_TEMP} %.0{BAROMETER} %{WIND_SPEED} %{WIND_DIRECTION} %.1{DEW_POINT} %.0{SOLAR_RAD} %{SUNRISE} %{SUNSET} %{OUT_HUMIDITY} %.2{ET_TODAY} %.2{ET_MONTH} %.2{ET_MONTH} %{FORECAST_ICON}' >> current_data.txt
Server pre webovú stránku
Tento server som použil pre generovanie a poskytovanie samotnej webovej stránky. Aj na ňom som nastavil Cron, čiže generovanie stránky je opäť automatické.# stránka s aktuálnymi hodnotami počasia 0,5,10,15,20,25,30,35,40,45,50,55 * * * * /cesta_s_súboru/cron_neuron.sh # grafy 0,15,30,45 * * * * /cesta_s_súboru/graphs.sh
Aktuálne dáta z prvého servera získavam pomocou príkazu wget.
wget -q -N http://IP_adresa_servera/cesta_k_suboru/current_data.txt
Zo stiahnutých dát následne vytváram HTML stránku pomocou jednoduchécho BASH skriptu.
#!/bin/bash # vojdeme do adresára, z ktorého bol skript spustený cd $(dirname $0) # začiatok HTML echo "<!DOCTYPE html> <html lang=\"sk\"> <head> <meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\"> <meta name=\"author\" content=\"Martin Vyšňovský (martinvysnovsky@gmail.com)\"> <title>Počasie TUKE</title> </head> <body>" > pocasie.html # získame aktuálne dáta weather_string=$(wget -O- -q http://IP_adresa_servera/cesta_k_suboru/current_weather.txt) IFS=" " read -a weather <<< "$weather_string" # teplota vzduchu echo "<span class=\"temperature\">${weather[0]}°C</span> <a href=\"#\" id=\"more_values\" title=\"Zobraziť viac hodnôt\">Viac</a>" >> pocasie.html # smer vetra case "${weather[3]}" in 'N') wind_way_string="zo severu" ;; 'NNE') wind_way_string="zo severo-severovýchodu" ;; 'NE') wind_way_string="zo severovýchodu" ;; 'ENE') wind_way_string="z východo-severovýchodu" ;; 'E') wind_way_string="z východu" ;; 'ESE') wind_way_string="z východo-juhovýchodu" ;; 'SE') wind_way_string="z juhovýchodu" ;; 'SSE') wind_way_string="z juho-juhovýchodu" ;; 'S') wind_way_string="z juhu" ;; 'SSW') wind_way_string="z juho-juhozápadu" ;; 'SW') wind_way_string="z juhozápadu" ;; 'WSW') wind_way_string="zo západo-juhozápadu" ;; 'W') wind_way_string="zo západu" ;; 'WNW') wind_way_string="zo západo-severozápadu" ;; 'NW') wind_way_string="zo severozápadu" ;; 'NNW') wind_way_string="zo severo-severozápadu" ;; *) wind_way_string="" ;; esac # ostatné hodnoty echo " <div>Tlak vzduchu: <span>${weather[1]}hPa</span></div> <div>Rýchlosť vetra: <span>${weather[2]}km/h</span></div> <div>Smer: <span>$wind_way_string</span></div> <div>Slnečné žiarenie: <span>${weather[5]}W/m2</span></div> <div>Východ slnka: <span>${weather[6]:0:1}:${weather[6]:1}</span></div> <div>Západ slnka: <span>${weather[7]:0:2}:${weather[7]:2}</span></div> <div>Vlhkosť vzduchu: <span>${weather[8]}%</span></div> <div>Dnešné zrážky: <span>${weather[9]}mm</span></div> <div>Mesačné zrážky: <span>${weather[10]}mm</span></div> </body> </html> " >> pocasie.html # vytvorený súbor skopírujeme do adresára, kde je stránka a nahradíme ním neaktuálny súbor mv ./pocasie.html cesta_do_www_adresára
Generovanie grafov
Na stránke som chcel mať zobrazené aj grafické priebehy niektorých meteorologických hodnôt. Tieto grafy som vygeneroval pomocou programu Gnuplot pomocou nasledujúceho príkazu.gnuplot temperature.gnu
Tento príkaz spustí Gnuplot a vygeneruje graf podľa požiadaviek definovaných vo vstupnom súbore (v tomto prípade v temperature.gnu).
# nastavenia # ----------------------------------------------------- time_format = '"%H:%M:%S %d-%m-%Y"' min = -15 max = 15 # ----------------------------------------------------- set macros # rozmery a formát výstupného súboru # ----------------------------------------------------- set terminal pngcairo enhanced size 3000,500 font "arial,10" set output "temperature.png" # výpočet dátumov # ----------------------------------------------------- timestamp = system("date +%s") now = system(sprintf("date +'%s' -d @%s", time_format, timestamp)) from = system(sprintf("date +'%s' -d @%d", time_format, timestamp - (6 * 24 * 60 * 60))) to = system(sprintf("date +'%s' -d @%d", time_format, timestamp + (1 * 24 * 60 * 60))) # nastavenia pre X-ovú os # ----------------------------------------------------- set xdata time set timefmt @time_format set xrange [@from:@to] set xtics 6*60*60 nomirror offset 0,2 set mxtics 6 set format x "%H:%M" unset xlabel # nastavenia pre Y-ovú os # ----------------------------------------------------- set yrange [min:max] unset ylabel set label "Teplota [°C]" at @from,max font "Times Italic,10" rotate right offset screen 0.01,screen -0.02 # ----------------------------------------------------- set border 11 lc rgb "#333333" # mriežka # ----------------------------------------------------- set style line 10 lc rgb '#dddddd' lt 1 lw 0.5 set grid ytics back ls 10 set grid xtics back ls 10 # skrytie legendy unset key # štýly pre čiary # ----------------------------------------------------- set style line 1 lt 1 lw 3 pt 3 linecolor rgb "#FF6666" set style line 2 lt 1 lw 3 pt 3 linecolor rgb "#999999" # popisky na X-ovej osi # ----------------------------------------------------- timestamp6 = timestamp - (6 * 24 * 60 * 60) timestamp5 = timestamp - (5 * 24 * 60 * 60) timestamp4 = timestamp - (4 * 24 * 60 * 60) timestamp3 = timestamp - (3 * 24 * 60 * 60) timestamp2 = timestamp - (2 * 24 * 60 * 60) timestamp1 = timestamp - (1 * 24 * 60 * 60) timestamp0 = int(timestamp) timestamp_1 = timestamp + (1 * 24 * 60 * 60) now6 = system(sprintf("date +'%s' -d @%d", time_format, timestamp6)) now5 = system(sprintf("date +'%s' -d @%d", time_format, timestamp5)) now4 = system(sprintf("date +'%s' -d @%d", time_format, timestamp4)) now3 = system(sprintf("date +'%s' -d @%d", time_format, timestamp3)) now2 = system(sprintf("date +'%s' -d @%d", time_format, timestamp2)) now1 = system(sprintf("date +'%s' -d @%d", time_format, timestamp1)) now0 = now now_1 = system(sprintf("date +'%s' -d @%d", time_format, timestamp_1)) midnight5 = "\"00:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now5))."\"" midnight4 = "\"00:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now4))."\"" midnight3 = "\"00:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now3))."\"" midnight2 = "\"00:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now2))."\"" midnight1 = "\"00:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now1))."\"" midnight0 = "\"00:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now0))."\"" midnight_1 = "\"00:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now_1))."\"" set style arrow 1 heads size screen 0.003,90 lw 1 lc rgb "#333333" set style arrow 2 nohead lw 1 lc rgb "#cccccc" set arrow from @from,min to @midnight5,min as 1 set arrow from @midnight5,min to @midnight4,min as 1 set arrow from @midnight4,min to @midnight3,min as 1 set arrow from @midnight3,min to @midnight2,min as 1 set arrow from @midnight2,min to @midnight1,min as 1 set arrow from @midnight1,min to @midnight0,min as 1 set arrow from @midnight0,min to @midnight_1,min as 1 set arrow from @midnight_1,min to @to,min as 1 set arrow from @midnight5,min to @midnight5,max as 2 set arrow from @midnight4,min to @midnight4,max as 2 set arrow from @midnight3,min to @midnight3,max as 2 set arrow from @midnight2,min to @midnight2,max as 2 set arrow from @midnight1,min to @midnight1,max as 2 set arrow from @midnight0,min to @midnight0,max as 2 set arrow from @midnight_1,min to @midnight_1,max as 2 label_y = 0.03 noon6 = "\"12:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now6))."\"" noon5 = "\"12:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now5))."\"" noon4 = "\"12:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now4))."\"" noon3 = "\"12:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now3))."\"" noon2 = "\"12:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now2))."\"" noon1 = "\"12:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now1))."\"" noon0 = "\"12:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now0))."\"" noon_1 = "\"12:00:00 ".system(sprintf("echo \"%s\" | cut -b 10-", now_1))."\"" days = "Sobota Nedeľa Pondelok Utorok Streda Štvrtok Piatok" day_of_week = int(system("date +%w") + 1) day6 = word(days, (day_of_week + 7 - 6) % 7 + 1) day5 = word(days, (day_of_week + 7 - 5) % 7 + 1) day4 = word(days, (day_of_week + 7 - 4) % 7 + 1) day3 = word(days, (day_of_week + 7 - 3) % 7 + 1) day2 = word(days, (day_of_week + 7 - 2) % 7 + 1) day1 = word(days, (day_of_week + 7 - 1) % 7 + 1) day0 = word(days, day_of_week + 1) day_1 = word(days, (day_of_week + 7 + 1) % 7 + 1) day6 = day6 . system(sprintf("date +'%s' -d @%d", ' %d.%m.', timestamp6)) day5 = day5 . system(sprintf("date +'%s' -d @%d", ' %d.%m.', timestamp5)) day4 = day4 . system(sprintf("date +'%s' -d @%d", ' %d.%m.', timestamp4)) day3 = day3 . system(sprintf("date +'%s' -d @%d", ' %d.%m.', timestamp3)) day2 = day2 . system(sprintf("date +'%s' -d @%d", ' %d.%m.', timestamp2)) day1 = day1 . system(sprintf("date +'%s' -d @%d", ' %d.%m.', timestamp1)) day0 = day0 . system(sprintf("date +'%s' -d @%d", ' %d.%m.', timestamp0)) day_1 = day_1 . system(sprintf("date +'%s' -d @%d", ' %d.%m.', timestamp_1)) hour = system(sprintf("date +'%s' -d @%d", '%H', timestamp0)) if (hour < 9) set label day6 at @noon6,screen label_y center textcolor rgb "#666666"; else if (hour < 18) set label day6 at @from,screen label_y left textcolor rgb "#666666"; else ; set label day5 at @noon5,screen label_y center textcolor rgb "#666666" set label day4 at @noon4,screen label_y center textcolor rgb "#666666" set label day3 at @noon3,screen label_y center textcolor rgb "#666666" set label day2 at @noon2,screen label_y center textcolor rgb "#666666" set label day1 at @noon1,screen label_y center textcolor rgb "#666666" set label day0 at @noon0,screen label_y center textcolor rgb "#666666" if (hour > 18) set label day_1 at @noon_1,screen label_y center textcolor rgb "#666666"; else if (hour > 6) set label day_1 at @to,screen label_y right textcolor rgb "#666666"; else ; # hlavička # ----------------------------------------------------- set tmarg 1.3 set rmarg 6 set lmarg 6 months = "január február marec apríl máj jún júl august september november december" set label system("date +'%d. ' -d @" . timestamp). word(months, int(system('date +%m -d @' . timestamp))) . system("date +' %Y' -d @" . timestamp) . system("date +' %H:%I' -d @" . timestamp) at @now,screen 0.98 center # čiara a popisok, ktoré oddeľuje predikciu od historických hodnôt # ----------------------------------------------------- # vertikálna čiara set arrow from @now,min to @now,max nohead lc rgb "#666666" lw 2 # popisok position1 = system(sprintf("date +'%s' -d @%d", time_format, timestamp + (1 * 60 * 60))) position2 = system(sprintf("date +'%s' -d @%d", time_format, timestamp + (4 * 60 * 60))) set arrow from @position1,(max-1) to @position2,(max-1) head lc rgb "#666666" lw 2 set label "Predikcia (beta)" at @position1,(max-2) font "Times Italic,14" textcolor rgb "#666666" # vygenerovanie grafu # ----------------------------------------------------- plot "./current_data.txt" using 1:3 title "Teplota" with lines ls 1 axes x1y1 smooth csplines, \ "./prediction_temperature.txt" using (system(sprintf("date +'%s' -d @%d", @time_format, timestamp + (($1-290)*919)))):2 title "Predikovaná teplota" with lines ls 2 axes x1y1 smooth csplines
Výstupný formát som nastavil na PNG, čiže Gnuplot nám vygeneruje obrázok, ktorý potom zobrazujem na webovej stránke.
Graf priebehu teploty vygenerovaný cez Gnuplot |
Predikcia počasia
Na predikciu hodnôt meteorologických veličín som využil neurónovú sieť. Tú som vytvoril v programe SNNS, kde som ju učil metódou spätného šírenia chyby. Neurónová sieť mala na vstupe 288 neurónov, ktoré reprezentovali namerané dáta za posledných 72 hodín. Výstupom z neurónovej siete bola predikcia na nasledujúcich 24 hodín. Túto predikciu som potom zakomponoval do vytvorených grafov.
Záver
Vytvorená webová stránka už funguje dlhšiu dobu a za ten čas nebolo potrebné vykonať žiaden vonkajší zásah. Výsledok môžete posúdiť sami na mojej školskej stránke - http://neuron.tuke.sk/vysnovsky/pocasie. V prípade akýchkoľvek nejasností alebo otázok neváhajte pod článkom zanechať komentár. Rád vám naň odpoviem.
Žiadne komentáre:
Zverejnenie komentára