diff --git a/bot/bot.lua b/bot/bot.lua index 5645541..efb842d 100644 --- a/bot/bot.lua +++ b/bot/bot.lua @@ -210,6 +210,7 @@ function create_cred() derpibooru_apikey = "", fb_access_token = "", flickr_apikey = "", + forecastio_apikey = "", ftp_site = "", ftp_username = "", ftp_password = "", diff --git a/bot/utils.lua b/bot/utils.lua index 8481bdc..ec98ab1 100644 --- a/bot/utils.lua +++ b/bot/utils.lua @@ -773,4 +773,10 @@ function is_blacklisted(msg) end end return var -end \ No newline at end of file +end + +function convert_timestamp(timestamp, format) + local converted_date = run_command('date -d @'..timestamp..' +'..format) + local converted_date = string.gsub(converted_date, '%\n', '') + return converted_date + end \ No newline at end of file diff --git a/plugins/forecast.lua b/plugins/forecast.lua index 3675d04..43cc171 100644 --- a/plugins/forecast.lua +++ b/plugins/forecast.lua @@ -1,98 +1,126 @@ -do +do + +require("./plugins/time") + +local BASE_URL = "https://api.forecast.io/forecast" +local apikey = cred_data.forecastio_apikey +local google_apikey = cred_data.google_apikey + +local function get_city_name(lat, lng) + local city = redis:hget('telegram:cache:weather:pretty_names', lat..','..lng) + if city then return city end + local url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng='..lat..','..lng..'&result_type=political&language=de&key='..google_apikey + local res, code = https.request(url) + if code ~= 200 then return 'Unbekannte Stadt' end + local data = json:decode(res).results[1] + local city = data.formatted_address + print('Setting '..lat..','..lng..' in redis hash telegram:cache:weather:pretty_names to "'..city..'"') + redis:hset('telegram:cache:weather:pretty_names', lat..','..lng, city) + return city +end -local BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily" local function get_condition_symbol(weather, n) - if weather.list[n].weather[1].main == 'Clear' then - return ' ☀' - elseif weather.list[n].weather[1].main == 'Clouds' then - return ' ☁☁' - elseif weather.list[n].weather[1].main == 'Rain' then - return ' ☔' - elseif weather.list[n].weather[1].main == 'Thunderstorm' then - return ' ☔☔☔☔' - elseif weather.list[n].weather[1].main == 'Snow' then - return ' ❄️' - elseif weather.weather[1].main == 'Fog' then - return ' 🌫' + if weather.data[n].icon == 'clear-day' then + return '☀️' + elseif weather.data[n].icon == 'clear-night' then + return '🌙' + elseif weather.data[n].icon == 'rain' then + return '☔️' + elseif weather.data[n].icon == 'snow' then + return '❄️' + elseif weather.data[n].icon == 'sleet' then + return '🌨' + elseif weather.data[n].icon == 'wind' then + return '💨' + elseif weather.data[n].icon == 'fog' then + return '🌫' + elseif weather.data[n].icon == 'cloudy' then + return '☁️☁️' + elseif weather.data[n].icon == 'partly-cloudy-day' then + return '🌤' + elseif weather.data[n].icon == 'partly-cloudy-night' then + return '🌙☁️' else return '' end end local function get_temp(weather, n) - local day = (round(weather.list[n].temp.day, 1)) - local night = (round(weather.list[n].temp.night, 1)) - local condition = weather.list[n].weather[1].description - return '☀️ '..day..'°C | 🌙 '..night..'°C | '..condition + local day = round(weather.data[n].temperatureMax, 1) + local night = round(weather.data[n].temperatureMin, 1) + local condition = weather.data[n].summary + return '☀️ '..day..'°C | 🌙 '..night..'°C | '..get_condition_symbol(weather, n)..' '..condition end -local function get_forecast(location, days) - print("Bekomme Wettervorhersage für ", location) - local location = string.gsub(location," ","+") - local url = BASE_URL - local apikey = cred_data.owm_apikey - local url = url..'?q='..location - local url = url..'&lang=de&units=metric&cnt='..days..'&APPID='..apikey +local function get_forecast(lat, lng) + print('Finde Wetter in '..lat..', '..lng) + local text = redis:get('telegram:cache:forecast:'..lat..','..lng) + if text then print('...aus dem Cache..') return text end - local b, c, h = http.request(url) - if c ~= 200 then return nil end + local url = BASE_URL..'/'..apikey..'/'..lat..','..lng..'?lang=de&units=si&exclude=currently,minutely,hourly,alerts,flags' + + local response_body = {} + local request_constructor = { + url = url, + method = "GET", + sink = ltn12.sink.table(response_body) + } + local ok, response_code, response_headers, response_status_line = https.request(request_constructor) + if not ok then return nil end + local data = json:decode(table.concat(response_body)) + local ttl = string.sub(response_headers["cache-control"], 9) - local weather = json:decode(b) - local city = weather.city.name - if weather.city.country == "" then - country = '' - else - country = ' ('..weather.city.country..')' - end - local header = 'Vorhersage für '..city..country..':\n' - local text = 'Heute: '..get_temp(weather, 1)..get_condition_symbol(weather, 1) + local weather = data.daily + local city = get_city_name(lat, lng) - if days > 1 then - text = text..'\nMorgen: '..get_temp(weather, 2)..get_condition_symbol(weather, 2) - end - if days > 2 then - text = text..'\nÜbermorgen: '..get_temp(weather, 3)..get_condition_symbol(weather, 3) - end + local header = 'Vorhersage für '..city..':\n'..weather.summary..'\n' - if days > 3 then - for day in pairs(weather.list) do - if day > 3 then - local actual_day = day-1 - text = text..'\n'..actual_day..' Tage: '..get_temp(weather, day)..get_condition_symbol(weather, day) - end + local text = 'Heute: '..get_temp(weather, 1) + local text = text..'\nMorgen: '..get_temp(weather, 2) + + for day in pairs(weather.data) do + if day > 2 then + text = text..'\n'..convert_timestamp(weather.data[day].time, '%d.%m')..': '..get_temp(weather, day) end end + cache_data('forecast', lat..','..lng, header..text, tonumber(ttl), 'key') + return header..text end local function run(msg, matches) local user_id = msg.from.id local city = get_location(user_id) - if not city then city = 'Berlin' end - if tonumber(matches[1]) then - days = matches[1]+1 - else - days = 4 - end - - if matches[2] then - days = matches[1]+1 - city = matches[2] - end - - if not tonumber(matches[1]) and matches[1] ~= '/forecast' then + if matches[1] ~= '/forecast' and matches[1] ~= '/f' then city = matches[1] + else + local set_location = get_location(user_id) + if not set_location then + city = 'Berlin, Deutschland' + else + city = set_location + end end - if days > 17 then - return 'Wettervorhersagen gehen nur von 1-16 Tagen!' + local lat = redis:hget('telegram:cache:weather:'..string.lower(city), 'lat') + local lng = redis:hget('telegram:cache:weather:'..string.lower(city), 'lng') + if not lat and not lng then + print('Koordinaten nicht eingespeichert, frage Google...') + lat,lng = get_latlong(city) + end + + if not lat and not lng then + return 'Den Ort "'..city..'" gibt es nicht!' end - local text = get_forecast(city, days) + redis:hset('telegram:cache:weather:'..string.lower(city), 'lat', lat) + redis:hset('telegram:cache:weather:'..string.lower(city), 'lng', lng) + + local text = get_forecast(lat, lng) if not text then text = 'Konnte die Wettervorhersage für diese Stadt nicht bekommen.' end @@ -102,15 +130,13 @@ end return { description = "Wettervorhersage für deinen oder einen gewählten Ort", usage = { - "/forecast: Wettervorhersage für deine Stadt (!location set [Ort])", - "/forecast [0-16]: Wettervorhersage für X Tage für deine Stadt (!location set [Ort])", - "/forecast (Stadt): Wettervorhersage für diese Stadt", - "/forecast [0-16] (Stadt): Wettervorhersage für X Tage für diese Stadt" + "/forecast: Wettervorhersage für deine Stadt (/location set [Ort])", + "/forecast (Stadt): Wettervorhersage für diese Stadt" }, patterns = { - "^/forecast$", - "^/forecast (%d+) (.*)$", - "^/forecast (%d+)", + "^/f$", + "^/f (.*)$", + "^/forecast$", "^/forecast (.*)$" }, run = run diff --git a/plugins/pluginsold/forecast.lua b/plugins/pluginsold/forecast.lua new file mode 100644 index 0000000..3675d04 --- /dev/null +++ b/plugins/pluginsold/forecast.lua @@ -0,0 +1,119 @@ +do + +local BASE_URL = "http://api.openweathermap.org/data/2.5/forecast/daily" + +local function get_condition_symbol(weather, n) + if weather.list[n].weather[1].main == 'Clear' then + return ' ☀' + elseif weather.list[n].weather[1].main == 'Clouds' then + return ' ☁☁' + elseif weather.list[n].weather[1].main == 'Rain' then + return ' ☔' + elseif weather.list[n].weather[1].main == 'Thunderstorm' then + return ' ☔☔☔☔' + elseif weather.list[n].weather[1].main == 'Snow' then + return ' ❄️' + elseif weather.weather[1].main == 'Fog' then + return ' 🌫' + else + return '' + end +end + +local function get_temp(weather, n) + local day = (round(weather.list[n].temp.day, 1)) + local night = (round(weather.list[n].temp.night, 1)) + local condition = weather.list[n].weather[1].description + return '☀️ '..day..'°C | 🌙 '..night..'°C | '..condition +end + +local function get_forecast(location, days) + print("Bekomme Wettervorhersage für ", location) + local location = string.gsub(location," ","+") + local url = BASE_URL + local apikey = cred_data.owm_apikey + local url = url..'?q='..location + local url = url..'&lang=de&units=metric&cnt='..days..'&APPID='..apikey + + local b, c, h = http.request(url) + if c ~= 200 then return nil end + + local weather = json:decode(b) + local city = weather.city.name + if weather.city.country == "" then + country = '' + else + country = ' ('..weather.city.country..')' + end + local header = 'Vorhersage für '..city..country..':\n' + + local text = 'Heute: '..get_temp(weather, 1)..get_condition_symbol(weather, 1) + + if days > 1 then + text = text..'\nMorgen: '..get_temp(weather, 2)..get_condition_symbol(weather, 2) + end + if days > 2 then + text = text..'\nÜbermorgen: '..get_temp(weather, 3)..get_condition_symbol(weather, 3) + end + + if days > 3 then + for day in pairs(weather.list) do + if day > 3 then + local actual_day = day-1 + text = text..'\n'..actual_day..' Tage: '..get_temp(weather, day)..get_condition_symbol(weather, day) + end + end + end + + return header..text +end + +local function run(msg, matches) + local user_id = msg.from.id + local city = get_location(user_id) + if not city then city = 'Berlin' end + + if tonumber(matches[1]) then + days = matches[1]+1 + else + days = 4 + end + + if matches[2] then + days = matches[1]+1 + city = matches[2] + end + + if not tonumber(matches[1]) and matches[1] ~= '/forecast' then + city = matches[1] + end + + if days > 17 then + return 'Wettervorhersagen gehen nur von 1-16 Tagen!' + end + + local text = get_forecast(city, days) + if not text then + text = 'Konnte die Wettervorhersage für diese Stadt nicht bekommen.' + end + return text +end + +return { + description = "Wettervorhersage für deinen oder einen gewählten Ort", + usage = { + "/forecast: Wettervorhersage für deine Stadt (!location set [Ort])", + "/forecast [0-16]: Wettervorhersage für X Tage für deine Stadt (!location set [Ort])", + "/forecast (Stadt): Wettervorhersage für diese Stadt", + "/forecast [0-16] (Stadt): Wettervorhersage für X Tage für diese Stadt" + }, + patterns = { + "^/forecast$", + "^/forecast (%d+) (.*)$", + "^/forecast (%d+)", + "^/forecast (.*)$" + }, + run = run +} + +end \ No newline at end of file diff --git a/plugins/pluginsold/weather.lua b/plugins/pluginsold/weather.lua new file mode 100644 index 0000000..41fbcf0 --- /dev/null +++ b/plugins/pluginsold/weather.lua @@ -0,0 +1,77 @@ +do + +local BASE_URL = "http://api.openweathermap.org/data/2.5/weather" + +local function get_weather(location) + print("Finde Wetter in ", location) + local location = string.gsub(location," ","+") + local url = BASE_URL + local apikey = cred_data.owm_apikey + local url = url..'?q='..location + local url = url..'&lang=de&units=metric&APPID='..apikey + + local b, c, h = http.request(url) + if c ~= 200 then return nil end + + local weather = json:decode(b) + local city = weather.name + if weather.sys.country == 'none' then + country = '' + else + country = ' ('..weather.sys.country..')' + end + local temperature = round(weather.main.temp, 1) + local temp = 'Wetter in '..city..country..':\n'..temperature..'°C' + local conditions = ' | '..weather.weather[1].description + if weather.weather[1].main == 'Clear' then + conditions = conditions..' ☀' + elseif weather.weather[1].main == 'Clouds' then + conditions = conditions..' ☁☁' + elseif weather.weather[1].main == 'Rain' then + conditions = conditions..' ☔' + elseif weather.weather[1].main == 'Thunderstorm' then + conditions = conditions..' ☔☔☔☔' + elseif weather.weather[1].main == 'Snow' then + conditions = conditions..' ❄️' + elseif weather.weather[1].main == 'Fog' then + conditions = conditions..' 🌫' + else + conditions = conditions..'' + end + return temp..conditions +end + +local function run(msg, matches) + local user_id = msg.from.id + + if matches[1] ~= '/wetter' then + city = matches[1] + else + local set_location = get_location(user_id) + if not set_location then + city = 'Berlin' + else + city = set_location + end + end + local text = get_weather(city) + if not text then + text = 'Konnte das Wetter von dieser Stadt nicht bekommen.' + end + return text +end + +return { + description = "Wetter für deinen oder einen gewählten Ort", + usage = { + "/wetter: Wetter für deinen Wohnort (!location set [Ort])", + "/wetter (Stadt): Wetter für diese Stadt" + }, + patterns = { + "^/wetter$", + "^/wetter (.*)$" + }, + run = run +} + +end \ No newline at end of file diff --git a/plugins/weather.lua b/plugins/weather.lua index 41fbcf0..fd61814 100644 --- a/plugins/weather.lua +++ b/plugins/weather.lua @@ -1,60 +1,113 @@ do -local BASE_URL = "http://api.openweathermap.org/data/2.5/weather" +require("./plugins/time") -local function get_weather(location) - print("Finde Wetter in ", location) - local location = string.gsub(location," ","+") - local url = BASE_URL - local apikey = cred_data.owm_apikey - local url = url..'?q='..location - local url = url..'&lang=de&units=metric&APPID='..apikey +local BASE_URL = "https://api.forecast.io/forecast" +local apikey = cred_data.forecastio_apikey +local google_apikey = cred_data.google_apikey - local b, c, h = http.request(url) - if c ~= 200 then return nil end +local function get_city_name(lat, lng) + local city = redis:hget('telegram:cache:weather:pretty_names', lat..','..lng) + if city then return city end + local url = 'https://maps.googleapis.com/maps/api/geocode/json?latlng='..lat..','..lng..'&result_type=political&language=de&key='..google_apikey + local res, code = https.request(url) + if code ~= 200 then return 'Unbekannte Stadt' end + local data = json:decode(res).results[1] + local city = data.formatted_address + print('Setting '..lat..','..lng..' in redis hash telegram:cache:weather:pretty_names to "'..city..'"') + redis:hset('telegram:cache:weather:pretty_names', lat..','..lng, city) + return city +end - local weather = json:decode(b) - local city = weather.name - if weather.sys.country == 'none' then - country = '' - else - country = ' ('..weather.sys.country..')' - end - local temperature = round(weather.main.temp, 1) - local temp = 'Wetter in '..city..country..':\n'..temperature..'°C' - local conditions = ' | '..weather.weather[1].description - if weather.weather[1].main == 'Clear' then - conditions = conditions..' ☀' - elseif weather.weather[1].main == 'Clouds' then - conditions = conditions..' ☁☁' - elseif weather.weather[1].main == 'Rain' then - conditions = conditions..' ☔' - elseif weather.weather[1].main == 'Thunderstorm' then - conditions = conditions..' ☔☔☔☔' - elseif weather.weather[1].main == 'Snow' then - conditions = conditions..' ❄️' - elseif weather.weather[1].main == 'Fog' then +local function get_weather(lat, lng) + print('Finde Wetter in '..lat..', '..lng) + local text = redis:get('telegram:cache:weather:'..lat..','..lng) + if text then print('...aus dem Cache..') return text end + + local url = BASE_URL..'/'..apikey..'/'..lat..','..lng..'?lang=de&units=si&exclude=minutely,hourly,daily,alerts,flags' + + local response_body = {} + local request_constructor = { + url = url, + method = "GET", + sink = ltn12.sink.table(response_body) + } + local ok, response_code, response_headers, response_status_line = https.request(request_constructor) + if not ok then return nil end + local data = json:decode(table.concat(response_body)) + local ttl = string.sub(response_headers["cache-control"], 9) + + + local weather = data.currently + local city = get_city_name(lat, lng) + local temperature = round(weather.temperature, 1) + local feelslike = round(weather.apparentTemperature, 1) + local temp = 'Wetter in '..city..':\n'..temperature..' °C' + local conditions = ' | '..weather.summary + if weather.icon == 'clear-day' then + conditions = conditions..' ☀️' + elseif weather.icon == 'clear-night' then + conditions = conditions..' 🌙' + elseif weather.icon == 'rain' then + conditions = conditions..' ☔️' + elseif weather.icon == 'snow' then + conditions = conditions..' ❄️' + elseif weather.icon == 'sleet' then + conditions = conditions..' 🌨' + elseif weather.icon == 'wind' then + conditions = conditions..' 💨' + elseif weather.icon == 'fog' then conditions = conditions..' 🌫' + elseif weather.icon == 'cloudy' then + conditions = conditions..' ☁️☁️' + elseif weather.icon == 'partly-cloudy-day' then + conditions = conditions..' 🌤' + elseif weather.icon == 'partly-cloudy-night' then + conditions = conditions..' 🌙☁️' else conditions = conditions..'' end - return temp..conditions + local windspeed = ' | 💨 '..round(weather.windSpeed, 1)..' m/s' + + local text = temp..conditions..windspeed + + if temperature == feelslike then + text = text..'\n(gefühlt: '..feelslike..' °C)' + end + + cache_data('weather', lat..','..lng, text, tonumber(ttl), 'key') + return text end local function run(msg, matches) local user_id = msg.from.id - if matches[1] ~= '/wetter' then + if matches[1] ~= '/wetter' and matches[1] ~= '/w' then city = matches[1] else local set_location = get_location(user_id) if not set_location then - city = 'Berlin' + city = 'Berlin, Deutschland' else city = set_location end end - local text = get_weather(city) + + local lat = redis:hget('telegram:cache:weather:'..string.lower(city), 'lat') + local lng = redis:hget('telegram:cache:weather:'..string.lower(city), 'lng') + if not lat and not lng then + print('Koordinaten nicht eingespeichert, frage Google...') + lat,lng = get_latlong(city) + end + + if not lat and not lng then + return 'Den Ort "'..city..'" gibt es nicht!' + end + + redis:hset('telegram:cache:weather:'..string.lower(city), 'lat', lat) + redis:hset('telegram:cache:weather:'..string.lower(city), 'lng', lng) + + local text = get_weather(lat, lng) if not text then text = 'Konnte das Wetter von dieser Stadt nicht bekommen.' end @@ -64,12 +117,14 @@ end return { description = "Wetter für deinen oder einen gewählten Ort", usage = { - "/wetter: Wetter für deinen Wohnort (!location set [Ort])", + "/wetter: Wetter für deinen Wohnort (/location set [Ort])", "/wetter (Stadt): Wetter für diese Stadt" }, patterns = { "^/wetter$", - "^/wetter (.*)$" + "^/wetter (.*)$", + "^/w$", + "^/w (.*)$" }, run = run }