From a479a2c037264b32d034aa8bec6ba32f435f0540 Mon Sep 17 00:00:00 2001 From: Markham Date: Sun, 8 Nov 2015 21:26:38 +0100 Subject: [PATCH] initial commit luaweatherapp v1.2 (Tischi) --- luawetterapp.cfg | 4 + luawetterapp.lua | 369 ++++++++++++++++++++++++++++++++++++++++++++++ luawettericon.png | Bin 0 -> 4453 bytes 3 files changed, 373 insertions(+) create mode 100644 luawetterapp.cfg create mode 100644 luawetterapp.lua create mode 100644 luawettericon.png diff --git a/luawetterapp.cfg b/luawetterapp.cfg new file mode 100644 index 0000000..43777fd --- /dev/null +++ b/luawetterapp.cfg @@ -0,0 +1,4 @@ +name=Lua Wetter App +desc=Aktuelles Wetter + 3 Tage Vorschau +type=4 +hinticon=luawettericon \ No newline at end of file diff --git a/luawetterapp.lua b/luawetterapp.lua new file mode 100644 index 0000000..a271694 --- /dev/null +++ b/luawetterapp.lua @@ -0,0 +1,369 @@ +-- Lua Wetter App +-- (c) Tischi www.coolstream.to +-- Lizenz: GPL 2 +-- Version: 1.2 +-- Stand: 14.11.2014 + + +--Eigenen Pfad ermitteln +function script_path() + local str = debug.getinfo(2, "S").source:sub(2) + return str:match("(.*/)") +end + +--Variablen +pfad=script_path() .. "LuaWetterApp/" +txtpfad="/tmp/Lua_Wetter/" +daten=txtpfad .. "luawetter.txt" +datentxt=txtpfad .. "wetterdaten.txt" +confPfad="/var/tuxbox/config/" +confFile= confPfad .. "luawetterapp.conf" +appicon="luawettericon.png" +stadt_name={} +stadt_name["name"]="Koeln" +stadt_name["land"]="de" +wochentag=os.date("%w") +wochentag2="0" +wochentag3="0" +wochentag4="0" +config = configfile.new() +conf={} +conf["name"]="Koeln" +conf["farbe"]="COL.MENUCONTENT" +conf["txtfarbe"]="COL.MENUCONTENT_TEXT" +hintfarbe=COL.MENUCONTENT +textfarbe=COL.MENUCONTENT_TEXT +local posix = require "posix" +local json = require "json" +local n = neutrino() +tagname={} +tagname["0"]="Sonntag" +tagname["1"]="Montag" +tagname["2"]="Dienstag" +tagname["3"]="Mittwoch" +tagname["4"]="Donnerstag" +tagname["5"]="Freitag" +tagname["6"]="Samstag" +iconurl="http://icons.iconarchive.com/icons/oxygen-icons.org/oxygen/128/" + +--Ordner anlegen +os.execute("mkdir -p " .. txtpfad) +os.execute("cp -f " .. script_path() .. "/" .. appicon .. " /share/tuxbox/neutrino/icons") + +--Infofenster +function printinfo(t) + local dx = (SCREEN.END_X - SCREEN.OFF_X) / 2 + local dy = 155 + local x = ((SCREEN.END_X - SCREEN.OFF_X) - dx) / 2 + local y = ((SCREEN.END_Y - SCREEN.OFF_Y) - dy) / 2 + + local wh = cwindow.new{x=x, y=y, dx=dx, dy=dy, title="Info", icon="info", has_shadow=true, show_footer=false} + ctext.new{parent=wh, x=30, y=5, dx=dx-60, dy=110, text=t, font_text=FONT['MENU'], mode="ALIGN_CENTER"} + wh:paint() + + local i = 0 + repeat + i = i + 1 + msg1, data1 = n:GetInput(500) + until msg1 == RC['home'] or msg1 == RC['setup'] or msg1 == RC['ok'] or i == 12; -- 6 seconds + + wh:hide{no_restore=true} +end + +--zuordnung Wochentage +function wochentage() +if wochentag == "0" then + wochentag2="1" + wochentag3="2" + wochentag4="3" +end +if wochentag == "1" then + wochentag2="2" + wochentag3="3" + wochentag4="4" +end +if wochentag == "2" then + wochentag2="3" + wochentag3="4" + wochentag4="5" +end +if wochentag == "3" then + wochentag2="4" + wochentag3="5" + wochentag4="6" +end +if wochentag == "4" then + wochentag2="5" + wochentag3="6" + wochentag4="0" +end +if wochentag == "5" then + wochentag2="6" + wochentag3="0" + wochentag4="1" +end +if wochentag == "6" then + wochentag2="0" + wochentag3="1" + wochentag4="2" +end +end + +--Wetterdaten holen und auslesen +function get_weather() + wochentage() + local hb = hintbox.new{ title="Info", text="Daten werden geladen", icon="info", has_shadow=true, show_footer=false} + hb:paint() + os.execute("wget -O " .. daten .. " -U Mozilla 'http://api.openweathermap.org/data/2.5/forecast/daily?q=" .. conf["name"] .. "&units=metric&cnt=4&lang=de'" ) + fp = io.open(daten, "r") + if fp == nil then + error("Kann nicht geladen werden: " .. daten) + else + s = fp:read("*a") + fp:close() + end + + local j_table = json:decode(s) + + stadt = j_table.city.name + if stadt == nil then + printinfo("Nicht gefunden!") + hb:hide() + addMenue() + end + + zahl = 1 + repeat + j_table.list[zahl].speed=math.floor(j_table.list[zahl].speed + 0.5) + j_table.list[zahl].temp.eve=math.floor(j_table.list[zahl].temp.eve + 0.5) + j_table.list[zahl].temp.day=math.floor(j_table.list[zahl].temp.day + 0.5) + j_table.list[zahl].temp.min=math.floor(j_table.list[zahl].temp.min + 0.5) + j_table.list[zahl].temp.max=math.floor(j_table.list[zahl].temp.max + 0.5) + j_table.list[zahl].temp.night=math.floor(j_table.list[zahl].temp.night + 0.5) + zahl = zahl + 1 + until zahl == 5 + + local daten=io.open(datentxt, "w") + if daten == nil then + error("Kann nicht geladen werden: " .. datentxt) + else + daten:write(tagname[wochentag] .. "\n" .. j_table.list[1].weather[1].icon .. "\n" .. j_table.list[1].weather[1].description .. "\n" .. "Tag: " .. j_table.list[1].temp.day .. "°C" .. " " .. "Abends: " .. j_table.list[1].temp.eve .. "°C" .. " " .. "Nachts: " .. j_table.list[1].temp.night .. "°C" .. "\n" .. "minimal: " .. j_table.list[1].temp.min .. "°C" .. " " .. "maximal: " .. j_table.list[1].temp.max .. "°C" .. "\n" .. "Windgeschwindigkeit: " .. j_table.list[1].speed .. " kmh" .. "\n" .. "Luftfeuchtigkeit: " .. j_table.list[1].humidity .. "%" .. "\n" .. tagname[wochentag2] .. "\n" .. j_table.list[2].weather[1].icon .. "\n" .. j_table.list[2].weather[1].description .. "\n" .. "minimal: " .. j_table.list[2].temp.min .. "°C" .. " " .. "maximal: " .. j_table.list[2].temp.max .. "°C" .. "\n" .. tagname[wochentag3] .. "\n" .. j_table.list[3].weather[1].icon .. "\n" .. j_table.list[3].weather[1].description .. "\n" .. "minimal: " .. j_table.list[3].temp.min .. "°C" .. " " .. "maximal: " .. j_table.list[3].temp.max .. "°C" .. "\n" .. tagname[wochentag4] .. "\n" .. j_table.list[4].weather[1].icon .. "\n" .. j_table.list[4].weather[1].description .. "\n" .. "minimal: " .. j_table.list[4].temp.min .. "°C" .. " " .. "maximal: " .. j_table.list[4].temp.max .. "°C" .. "\n" .. stadt) + daten:close() + end + + lines={} + for line in io.lines(datentxt) do + lines[#lines + 1]=line + end + hb:hide() + return lines +end + +--config laden +function loadConfig() + config:loadConfig(confFile) + + conf["farbe"] = config:getString("farbe", "COL.MENUCONTENT") + conf["name"] = config:getString("name", "Koeln") + conf["txtfarbe"] = config:getString("txtfarbe", "COL.MENUCONTENT_TEXT") +end + +--Funktion zum speichern der Config +function saveConfig() + if configChanged == 1 then + local h = hintbox.new{caption="Info", text="Einstellungen werden gespeichert...", icon="info", has_shadow=true, show_footer=false}; + h:paint(); + + config:setString("farbe", conf["farbe"]) + config:setString("name", conf["name"]) + config:setString("txtfarbe", conf["txtfarbe"]) + + config:saveConfig(confFile) + + configChanged = 0 + posix.sleep(1) + h:hide(); + end +end + +--Farbvariablen zuordnen +function farbAuswahl() + if conf["farbe"] == "weiss" then + hintfarbe=COL.WHITE + elseif conf["farbe"] == "schwarz" then + hintfarbe=COL.BLACK + elseif conf["farbe"] == "grau" then + hintfarbe=COL.DARK_GRAY + elseif conf["farbe"] == "rot" then + hintfarbe=COL.RED + elseif conf["farbe"] == "grün" then + hintfarbe=COL.GREEN + elseif conf["farbe"] == "blau" then + hintfarbe=COL.BLUE + elseif conf["farbe"] == "gelb" then + hintfarbe=COL.YELLOW + else + hintfarbe=COL.MENUCONTENT + end + + if conf["txtfarbe"] == "weiss" then + textfarbe=COL.WHITE + elseif conf["txtfarbe"] == "schwarz" then + textfarbe=COL.BLACK + elseif conf["txtfarbe"] == "grau" then + textfarbe=COL.DARK_GRAY + elseif conf["txtfarbe"] == "rot" then + textfarbe=COL.RED + elseif conf["txtfarbe"] == "grün" then + textfarbe=COL.GREEN + elseif conf["txtfarbe"] == "blau" then + textfarbe=COL.BLUE + elseif conf["txtfarbe"] == "gelb" then + textfarbe=COL.YELLOW + else + textfarbe=COL.MENUCONTENT_TEXT + end + +end + +--Wetterdaten anzeigen im Fenster +function anzeigepaint() + count = 1 + while count <= 16 do + anz[count]:paint() + count = count + 1 + end +end + +--Wetterdaten verbergen +function anzeigehide() + count = 1 + while count <= 16 do + anz[count]:hide{no_restore=true} + count = count + 1 + end +end + +--Variablen conf[] setzen +function set_string(k, v) + conf[k]=v + configChanged = 1 +end + +--löscht den tmp Ordner +function beenden() +os.execute("rm -rf " .. txtpfad) +end + +--Bilder und Text auf den TV malen +function wetterfenster() +wochentage() +anz={} +local dx = (SCREEN.END_X - SCREEN.OFF_X) / 2 +local dy = (SCREEN.END_Y - SCREEN.OFF_Y) / 2 +local x = SCREEN.OFF_X +local y = SCREEN.OFF_Y +local xx = SCREEN.END_X +local yy = SCREEN.END_Y + +anz[16]=ctext.new{parent=w, x=dx-200, y=y+30, dx=450, dy=30, text=lines[20], color_body=hintfarbe, color_text=textfarbe, font_text=FONT['MENU_TITLE'], mode="ALIGN_CENTER" } +anz[3]=ctext.new{parent=w, x=dx-200, y=y+188, dx=450, dy=175, text=lines[4] .. "\n" .. lines[5] .. "\n" .. lines[6] .. "\n" .. lines[7], color_body=hintfarbe, color_text=textfarbe, font_text=FONT['MENU'], mode="ALIGN_CENTER" } +anz[2]=ctext.new{parent=w, x=dx-73, y=y+60, dx=323, dy=128, text="Heute: " .. lines[1] .. "\n" .. lines[3], color_body=hintfarbe, color_text=textfarbe, font_text=FONT['MENU'], mode="ALIGN_CENTER" } +anz[1]=cpicture.new{parent=w, x=dx-200, y=y+60 , dx=128, dy=128, image=pfad .. lines[2] .. ".png", transparency=2, color_background=hintfarbe, mode="ALIGN_RIGHT"} + +anz[4]=cpicture.new{parent=w, x=dx-562, y=yy-248 , dx=128, dy=128, image=pfad .. lines[9] .. ".png", transparency=2, color_background=hintfarbe, mode="ALIGN_RIGHT"} +anz[5]=ctext.new{parent=w, x=dx-434, y=yy-248, dx=250, dy=128, text=lines[8] .. "\n" .. lines[10], color_body=hintfarbe, color_text=textfarbe, font_text=FONT['MENU'], mode="ALIGN_CENTER" } +anz[10]=ctext.new{parent=w, x=dx-562, y=yy-120, dx=378, dy=50, text=lines[11], color_body=hintfarbe, color_text=textfarbe, font_text=FONT['MENU'], mode="ALIGN_CENTER" } + +anz[6]=cpicture.new{parent=w, x=dx-164, y=yy-248 , dx=128, dy=128, image=pfad .. lines[13] .. ".png", transparency=2, color_background=hintfarbe, mode="ALIGN_RIGHT"} +anz[7]=ctext.new{parent=w, x=dx-36, y=yy-248, dx=250, dy=128, text=lines[12] .. "\n" .. lines[14], color_body=hintfarbe, color_text=textfarbe, font_text=FONT['MENU'], mode="ALIGN_CENTER" } +anz[11]=ctext.new{parent=w, x=dx-164, y=yy-120, dx=378, dy=50, text=lines[15], color_body=hintfarbe, color_text=textfarbe, font_text=FONT['MENU'], mode="ALIGN_CENTER" } + +anz[8]=cpicture.new{parent=w, x=dx+234, y=yy-248 , dx=128, dy=128, image=pfad .. lines[17] .. ".png", transparency=2, color_background=hintfarbe, mode="ALIGN_RIGHT"} +anz[9]=ctext.new{parent=w, x=dx+362, y=yy-248, dx=250, dy=128, text=lines[16] .. "\n" .. lines[18], color_body=hintfarbe, color_text=textfarbe, font_text=FONT['MENU'], mode="ALIGN_CENTER" } +anz[12]=ctext.new{parent=w, x=dx+234, y=yy-120, dx=378, dy=50, text=lines[19], color_body=hintfarbe, color_text=textfarbe, font_text=FONT['MENU'], mode="ALIGN_CENTER" } + +anz[13]=ctext.new{parent=w, x=x+100, y=yy-50, dx=400, dy=20, text="www.openweathermap.org", color_body=0xFF, color_text=COL['WHITE'], font_text=FONT['MENU'], mode="ALIGN_CENTER" } +anz[14]=cpicture.new{parent=w, x=xx-310, y=yy-45 , dx=20, dy=10, image="menu", transparency=2, color_background=0xFF, mode="ALIGN_RIGHT"} +anz[15]=ctext.new{parent=w, x=xx-280, y=yy-50, dx=200, dy=20, text="Stadt-PLZ", color_body=0xFF, color_text=COL['WHITE'], font_text=FONT['MENU'], mode="ALIGN_LEFT" } + +anzeigepaint() + +repeat + msg, data = n:GetInput(500) + if (msg == RC['setup']) then + anzeigehide() + addMenue() + end +until msg == RC['home'] + anzeigehide() + beenden() +end + +--Prüfen ob Pluginverezechnis existiert +function FolderExists() + local fileHandle, strError = io.open(pfad .. "01d.png", "r") + if fileHandle ~= nil then + io.close(fileHandle) + return true + else + logos() + end +end + +--Anlegen der Verzeichnise und Logos +function logos() + local hb = hintbox.new{ title="Info", text="Verzeichnis " .. pfad .. " nicht vorhanden!" .. "\n" .. "Verzeichnisse werden erstellt und Icons geladen!" .. "\n" .. "Bitte warten....", has_shadow=true, show_footer=false} + hb:paint() + os.execute("mkdir -p " .. pfad) + os.execute("wget -q -O - " .. iconurl .. "Status-weather-clear-icon.png > " .. pfad .. "01d.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-clear-night-icon.png > " .. pfad .. "01n.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-few-clouds-icon.png > " .. pfad .. "02d.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-few-clouds-night-icon.png > " .. pfad .. "02n.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-clouds-icon.png > " .. pfad .. "03d.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-clouds-night-icon.png > " .. pfad .. "03n.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-many-clouds-icon.png > " .. pfad .. "04d.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-many-clouds-icon.png > " .. pfad .. "04n.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-showers-scattered-day-icon.png > " .. pfad .. "09d.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-showers-scattered-night-icon.png > " .. pfad .. "09n.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-showers-scattered-icon.png > " .. pfad .. "10d.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-showers-scattered-icon.png > " .. pfad .. "10n.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-storm-icon.png > " .. pfad .. "11d.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-storm-icon.png > " .. pfad .. "11n.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-snow-icon.png > " .. pfad .. "13d.png") + os.execute("wget -q -O - " .. iconurl .. "Status-weather-snow-icon.png > " .. pfad .. "13d.png") + + hb:hide() +end + +function handle_key(a) + if (confChanged == 0) then return MENU_RETURN.EXIT end + local res = messagebox.exec{title="Änderungen verwerfen?", text="Sollen die Änderungen verworfen werden?", buttons={ "yes", "no" }, has_shadow=true } + if (res == "yes") then return MENU_RETURN.EXIT end + return MENU_RETURN.EXIT_REPAINT +end + +--Menü anzeigen +function addMenue() + local m = menu.new{name="Wetter - Suche", has_shadow=true} + m:addKey{directkey = RC["home"], id = "home", action = "handle_key"} + m:addItem{type = "back"} + m:addItem{type="separatorline"} + m:addItem{type="stringinput", action="set_string", id="name", value=conf["name"], sms=1, name="PLZ oder Name", directkey=RC["1"]} + m:addItem{type="separatorline"} + m:addItem{type="chooser", action="set_string", options={"Theme-Farbe", "weiss", "schwarz", "grau", "rot", "grün", "blau", "gelb"}, id="farbe", value=conf["farbe"], name="Hintergrundfarbe", directkey=RC["2"]} + m:addItem{type="chooser", action="set_string", options={"Theme-Farbe", "weiss", "schwarz", "grau", "rot", "grün", "blau", "gelb"}, id="txtfarbe", value=conf["txtfarbe"], name="Textfarbe", directkey=RC["3"]} + m:addItem{type="separatorline"} + m:addItem{type="forwarder", name="Speichern", action="saveConfig", icon="rot", directkey=RC["red"]} + m:exec() + loadConfig() + get_weather() + farbAuswahl() + wetterfenster() +end + +FolderExists() +loadConfig() +farbAuswahl() +get_weather() +wetterfenster() \ No newline at end of file diff --git a/luawettericon.png b/luawettericon.png new file mode 100644 index 0000000000000000000000000000000000000000..f7522190f758d48ec7af515407016c1b2ce0d715 GIT binary patch literal 4453 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