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