- Portiere Weather- und Forecast-Plugins
- convert_timestamp() und round() in utilites - Bugfixes und kleinere Änderungen
This commit is contained in:
parent
5523700615
commit
b176c2099b
@ -60,7 +60,7 @@ end
|
||||
function creds_manager:add_creds(var, key)
|
||||
print('Saving credential for '..var..' to redis hash '..hash)
|
||||
redis:hset(hash, var, key)
|
||||
reload_creds()
|
||||
creds_manager:reload_creds()
|
||||
return 'Gespeichert!'
|
||||
end
|
||||
|
||||
@ -68,7 +68,7 @@ function creds_manager:del_creds(var)
|
||||
if redis:hexists(hash, var) == true then
|
||||
print('Deleting credential for '..var..' from redis hash '..hash)
|
||||
redis:hdel(hash, var)
|
||||
reload_creds()
|
||||
creds_manager:reload_creds()
|
||||
return 'Key von "'..var..'" erfolgreich gelöscht!'
|
||||
else
|
||||
return 'Du hast keine Logininformationen für diese Variable eingespeichert.'
|
||||
@ -80,7 +80,7 @@ function creds_manager:rename_creds(var, newvar)
|
||||
local key = redis:hget(hash, var)
|
||||
if redis:hsetnx(hash, newvar, key) == true then
|
||||
redis:hdel(hash, var)
|
||||
reload_creds()
|
||||
creds_manager:reload_creds()
|
||||
return '"'..var..'" erfolgreich zu "'..newvar..'" umbenannt.'
|
||||
else
|
||||
return "Variable konnte nicht umbenannt werden: Zielvariable existiert bereits."
|
||||
|
222
otouto/plugins/forecast.lua
Normal file
222
otouto/plugins/forecast.lua
Normal file
@ -0,0 +1,222 @@
|
||||
local forecast = {}
|
||||
|
||||
local HTTPS = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local JSON = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bindings = require('otouto.bindings')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
|
||||
function forecast:init(config)
|
||||
if not cred_data.forecastio_apikey then
|
||||
print('Missing config value: forecastio_apikey.')
|
||||
print('weather.lua will not be enabled.')
|
||||
return
|
||||
elseif not cred_data.google_apikey then
|
||||
print('Missing config value: google_apikey.')
|
||||
print('weather.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
forecast.triggers = {
|
||||
"^(/f)$",
|
||||
"^(/f) (.*)$",
|
||||
"^(/fh)$",
|
||||
"^(/fh) (.*)$",
|
||||
"^(/forecast)$",
|
||||
"^(/forecast) (.*)$",
|
||||
"^(/forecasth)$",
|
||||
"^(/forecasth) (.*)$"
|
||||
}
|
||||
forecast.doc = [[*
|
||||
]]..config.cmd_pat..[[f*: Wettervorhersage für deinen Wohnort _(/location set <Ort>)_
|
||||
*]]..config.cmd_pat..[[f* _<Ort>_: Wettervorhersage für diesen Ort
|
||||
*]]..config.cmd_pat..[[fh*: 24-Stunden-Wettervorhersage für deine Stadt _(/location set [Ort]_
|
||||
*]]..config.cmd_pat..[[fh* _<Ort>_: 24-Stunden-Wettervorhersage für diesen Ort
|
||||
]]
|
||||
end
|
||||
|
||||
forecast.command = 'forecast'
|
||||
|
||||
local BASE_URL = "https://api.forecast.io/forecast"
|
||||
local apikey = cred_data.forecastio_apikey
|
||||
local google_apikey = cred_data.google_apikey
|
||||
|
||||
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
|
||||
|
||||
function get_condition_symbol(weather, n)
|
||||
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
|
||||
|
||||
function get_temp(weather, n, hourly)
|
||||
if hourly then
|
||||
local temperature = string.gsub(round(weather.data[n].temperature, 1), "%.", ",")
|
||||
local condition = weather.data[n].summary
|
||||
return temperature..'°C | '..get_condition_symbol(weather, n)..' '..condition
|
||||
else
|
||||
local day = string.gsub(round(weather.data[n].temperatureMax, 1), "%.", ",")
|
||||
local night = string.gsub(round(weather.data[n].temperatureMin, 1), "%.", ",")
|
||||
local condition = weather.data[n].summary
|
||||
return '☀️ '..day..'°C | 🌙 '..night..'°C | '..get_condition_symbol(weather, n)..' '..condition
|
||||
end
|
||||
end
|
||||
|
||||
function forecast: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 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 = data.daily
|
||||
local city = get_city_name(lat, lng)
|
||||
|
||||
local header = '*Vorhersage für '..city..':*\n_'..weather.summary..'_\n'
|
||||
|
||||
local text = '*Heute:* '..get_temp(weather, 1)
|
||||
local text = text..'\n*Morgen:* '..get_temp(weather, 2)
|
||||
|
||||
for day in pairs(weather.data) do
|
||||
if day > 2 then
|
||||
text = text..'\n*'..convert_timestamp(weather.data[day].time, '%a, %d.%m')..'*: '..get_temp(weather, day)
|
||||
end
|
||||
end
|
||||
|
||||
local text = string.gsub(text, "Mon", "Mo")
|
||||
local text = string.gsub(text, "Tue", "Di")
|
||||
local text = string.gsub(text, "Wed", "Mi")
|
||||
local text = string.gsub(text, "Thu", "Do")
|
||||
local text = string.gsub(text, "Fri", "Fr")
|
||||
local text = string.gsub(text, "Sat", "Sa")
|
||||
local text = string.gsub(text, "Sun", "So")
|
||||
|
||||
cache_data('forecast', lat..','..lng, header..text, tonumber(ttl), 'key')
|
||||
|
||||
return header..text
|
||||
end
|
||||
|
||||
function forecast:get_forecast_hourly(lat, lng)
|
||||
print('Finde stündliches Wetter in '..lat..', '..lng)
|
||||
local text = redis:get('telegram:cache:forecast:'..lat..','..lng..':hourly')
|
||||
if text then print('...aus dem Cache..') return text end
|
||||
|
||||
local url = BASE_URL..'/'..apikey..'/'..lat..','..lng..'?lang=de&units=si&exclude=currently,minutely,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.hourly
|
||||
local city = get_city_name(lat, lng)
|
||||
|
||||
local header = '*24-Stunden-Vorhersage für '..city..':*\n_'..weather.summary..'_'
|
||||
local text = ""
|
||||
|
||||
for hour in pairs(weather.data) do
|
||||
if hour < 26 then
|
||||
text = text..'\n*'..convert_timestamp(weather.data[hour].time, '%H:%M Uhr')..'* | '..get_temp(weather, hour, true)
|
||||
end
|
||||
end
|
||||
|
||||
cache_data('forecast', lat..','..lng..':hourly', header..text, tonumber(ttl), 'key')
|
||||
|
||||
return header..text
|
||||
end
|
||||
|
||||
function forecast:action(msg, config, matches)
|
||||
local user_id = msg.from.id
|
||||
local city = get_location(user_id)
|
||||
|
||||
if matches[2] then
|
||||
city = matches[2]
|
||||
else
|
||||
local set_location = get_location(user_id)
|
||||
if not set_location then
|
||||
city = 'Berlin, Deutschland'
|
||||
else
|
||||
city = set_location
|
||||
end
|
||||
end
|
||||
|
||||
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...')
|
||||
coords = utilities.get_coords(city, config)
|
||||
lat = coords.lat
|
||||
lng = coords.lon
|
||||
end
|
||||
|
||||
if not lat and not lng then
|
||||
utilities.send_reply(self, msg, '*Diesen Ort gibt es nicht!*', true)
|
||||
return
|
||||
end
|
||||
|
||||
redis:hset('telegram:cache:weather:'..string.lower(city), 'lat', lat)
|
||||
redis:hset('telegram:cache:weather:'..string.lower(city), 'lng', lng)
|
||||
|
||||
if matches[1] == '/forecasth' or matches[1] == '/fh' then
|
||||
text = forecast:get_forecast_hourly(lat, lng)
|
||||
else
|
||||
text = forecast:get_forecast(lat, lng)
|
||||
end
|
||||
if not text then
|
||||
text = '*Konnte die Wettervorhersage für diese Stadt nicht bekommen.*'
|
||||
end
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
|
||||
return forecast
|
@ -1,63 +1,150 @@
|
||||
local weather = {}
|
||||
|
||||
local HTTP = require('socket.http')
|
||||
local HTTPS = require('ssl.https')
|
||||
local URL = require('socket.url')
|
||||
local JSON = require('dkjson')
|
||||
local utilities = require('otouto.utilities')
|
||||
local bindings = require('otouto.bindings')
|
||||
local redis = (loadfile "./otouto/redis.lua")()
|
||||
|
||||
function weather:init(config)
|
||||
if not config.owm_api_key then
|
||||
print('Missing config value: owm_api_key.')
|
||||
if not cred_data.forecastio_apikey then
|
||||
print('Missing config value: forecastio_apikey.')
|
||||
print('weather.lua will not be enabled.')
|
||||
return
|
||||
elseif not cred_data.google_apikey then
|
||||
print('Missing config value: google_apikey.')
|
||||
print('weather.lua will not be enabled.')
|
||||
return
|
||||
end
|
||||
|
||||
weather.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('weather', true).table
|
||||
weather.doc = [[```
|
||||
]]..config.cmd_pat..[[weather <location>
|
||||
Returns the current weather conditions for a given location.
|
||||
```]]
|
||||
weather.triggers = {
|
||||
"^/wetter$",
|
||||
"^/wetter (.*)$",
|
||||
"^/w$",
|
||||
"^/w (.*)$"
|
||||
}
|
||||
weather.doc = [[*
|
||||
]]..config.cmd_pat..[[wetter*: Wetter für deinen Wohnort _(/location set [Ort])_
|
||||
*]]..config.cmd_pat..[[wetter* _<Ort>_: Wetter für diesen Ort
|
||||
]]
|
||||
end
|
||||
|
||||
weather.command = 'weather <location>'
|
||||
weather.command = 'wetter'
|
||||
|
||||
function weather:action(msg, config)
|
||||
local BASE_URL = "https://api.forecast.io/forecast"
|
||||
local apikey = cred_data.forecastio_apikey
|
||||
local google_apikey = cred_data.google_apikey
|
||||
|
||||
local input = utilities.input(msg.text)
|
||||
if not input then
|
||||
if msg.reply_to_message and msg.reply_to_message.text then
|
||||
input = msg.reply_to_message.text
|
||||
else
|
||||
utilities.send_message(self, msg.chat.id, weather.doc, true, msg.message_id, true)
|
||||
return
|
||||
end
|
||||
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
|
||||
|
||||
function weather: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 = string.gsub(round(weather.temperature, 1), "%.", ",")
|
||||
local feelslike = string.gsub(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
|
||||
local windspeed = ' | 💨 '..string.gsub(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
|
||||
|
||||
function weather:action(msg, config, matches)
|
||||
local user_id = msg.from.id
|
||||
|
||||
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, Deutschland'
|
||||
else
|
||||
city = set_location
|
||||
end
|
||||
end
|
||||
|
||||
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...')
|
||||
coords = utilities.get_coords(city, config)
|
||||
lat = coords.lat
|
||||
lng = coords.lon
|
||||
end
|
||||
|
||||
if not lat and not lng then
|
||||
utilities.send_reply(self, msg, '*Diesen Ort gibt es nicht!*', true)
|
||||
return
|
||||
end
|
||||
|
||||
local coords = utilities.get_coords(input, config)
|
||||
if type(coords) == 'string' then
|
||||
utilities.send_reply(self, msg, coords)
|
||||
return
|
||||
end
|
||||
|
||||
local url = 'http://api.openweathermap.org/data/2.5/weather?APPID=' .. config.owm_api_key .. '&lat=' .. coords.lat .. '&lon=' .. coords.lon
|
||||
|
||||
local jstr, res = HTTP.request(url)
|
||||
if res ~= 200 then
|
||||
utilities.send_reply(self, msg, config.errors.connection)
|
||||
return
|
||||
end
|
||||
|
||||
local jdat = JSON.decode(jstr)
|
||||
if jdat.cod ~= 200 then
|
||||
utilities.send_reply(self, msg, 'Error: City not found.')
|
||||
return
|
||||
end
|
||||
|
||||
local celsius = string.format('%.2f', jdat.main.temp - 273.15)
|
||||
local fahrenheit = string.format('%.2f', celsius * (9/5) + 32)
|
||||
local output = '`' .. celsius .. '°C | ' .. fahrenheit .. '°F, ' .. jdat.weather[1].description .. '.`'
|
||||
|
||||
utilities.send_reply(self, msg, output, true)
|
||||
|
||||
redis:hset('telegram:cache:weather:'..string.lower(city), 'lat', lat)
|
||||
redis:hset('telegram:cache:weather:'..string.lower(city), 'lng', lng)
|
||||
|
||||
local text = weather:get_weather(lat, lng)
|
||||
if not text then
|
||||
text = 'Konnte das Wetter von dieser Stadt nicht bekommen.'
|
||||
end
|
||||
utilities.send_reply(self, msg, text, true)
|
||||
end
|
||||
|
||||
return weather
|
||||
|
@ -8,10 +8,10 @@ local utilities = require('otouto.utilities')
|
||||
wikipedia.command = 'wiki <Begriff>'
|
||||
|
||||
function wikipedia:init(config)
|
||||
wikipedia.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('wikipedia', true):t('wiki', true):t('w', true).table
|
||||
wikipedia.triggers = utilities.triggers(self.info.username, config.cmd_pat):t('wikipedia', true):t('wiki', true).table
|
||||
wikipedia.doc = [[*
|
||||
]]..config.cmd_pat..[[wiki* _<Begriff>_: Gibt Wikipedia-Artikel aus
|
||||
Aliase: ]]..config.cmd_pat..[[w, ]]..config.cmd_pat..[[wikipedia]]
|
||||
Alias: ]]..config.cmd_pat..[[wikipedia]]
|
||||
end
|
||||
|
||||
local get_title = function(search)
|
||||
|
@ -240,6 +240,12 @@ function run_command(str)
|
||||
return result
|
||||
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
|
||||
|
||||
function string.starts(String, Start)
|
||||
return Start == string.sub(String,1,string.len(Start))
|
||||
end
|
||||
@ -659,6 +665,14 @@ function tablelength(T)
|
||||
return count
|
||||
end
|
||||
|
||||
function round(num, idp)
|
||||
if idp and idp>0 then
|
||||
local mult = 10^idp
|
||||
return math.floor(num * mult + 0.5) / mult
|
||||
end
|
||||
return math.floor(num + 0.5)
|
||||
end
|
||||
|
||||
function comma_value(amount)
|
||||
local formatted = amount
|
||||
while true do
|
||||
|
Reference in New Issue
Block a user