A simple Python script that sends OpenWeatherMap forecasts to a FreeMobile phone
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
4.4KB

  1. #!/usr/bin/python3
  2. """
  3. A simple script that sends the daily weather to a FreeMobile phone
  4. """
  5. import datetime
  6. import json
  7. import locale
  8. import logging
  9. import os
  10. import pyowm
  11. import requests
  12. import sys
  13. class WeatherToFreemobile():
  14. def __init__(self, config_file):
  15. logging.info('Load configuration from {}'.format(config_file))
  16. with open(config_file) as configuration:
  17. self.config = json.load(configuration)
  18. logging.info('Setting locale')
  19. try:
  20. locale.setlocale(locale.LC_TIME, self.config['locale'])
  21. except locale.Error:
  22. logging.warning(
  23. 'Error setting locale {}'.format(self.config['locale'])
  24. )
  25. logging.info('Opening OpenWeatherMap API')
  26. apikey = self.config['openweathermap_apikey']
  27. apilanguage = self.config['openweathermap_language']
  28. self.owm = pyowm.OWM(apikey, language=apilanguage)
  29. def send_sms_to_freemobile(self, message):
  30. """
  31. Sends a SMS using the FreeMobile API
  32. https://mobile.free.fr/moncompte/index.php?page=options
  33. """
  34. data = {
  35. 'user': self.config['freemobile_user'],
  36. 'pass': self.config['freemobile_apikey'],
  37. 'msg': bytes(message, 'utf-8').decode('iso-8859-1')
  38. }
  39. logging.debug(data)
  40. logging.info('Contacting FreeMobile API')
  41. r = requests.post('https://smsapi.free-mobile.fr/sendmsg', json=data)
  42. if r.status_code == 200:
  43. logging.info('SMS sent')
  44. else:
  45. logging.warning('SMS *not* sent. Status code %s', r.status_code)
  46. def get_weather(self):
  47. """
  48. Gets the weather forecast from OpenWeatherMap
  49. """
  50. city = self.config['openweathermap_city']
  51. number_of_days = self.config['number_of_days']
  52. fc = self.owm.daily_forecast(city, limit=number_of_days+1)
  53. f = fc.get_forecast()
  54. return_message = []
  55. for weather in f:
  56. weather_date = weather.get_reference_time('date')
  57. date_diff = weather_date.date() - datetime.date.today()
  58. # Workaround API returning yesterday's weather"
  59. # https://openweathermap.desk.com/customer/en/portal/questions/
  60. # 17649060-between-hours-of-12-midnight-and-7am-gmt-we-are-receiving
  61. # -the-wrong-data-for-most-locations
  62. if(
  63. date_diff < datetime.timedelta(0)
  64. or
  65. date_diff >= datetime.timedelta(number_of_days)
  66. ):
  67. logging.info('Skipped {} (cf. API Bug)'.format(weather_date))
  68. else:
  69. temp = weather.get_temperature(unit='celsius')
  70. rain = weather.get_rain().get('all', 0)
  71. return_message.append(
  72. '{}: {} (min {}ºC, max {}ºC, rain:{}mm)'.format(
  73. weather_date.strftime('%A %d').title(),
  74. weather.get_detailed_status(),
  75. round(float(temp['min'])),
  76. round(float(temp['max'])),
  77. rain
  78. )
  79. )
  80. if(rain and date_diff == datetime.timedelta(0)):
  81. return_message.append(self.get_rain())
  82. logging.info("Got the following weather: {}".format(return_message))
  83. return "\n".join(return_message)
  84. def get_rain(self):
  85. """
  86. Gets the rain forecast from OpenWeatherMap
  87. """
  88. city = self.config['openweathermap_city']
  89. fc = self.owm.three_hours_forecast(city)
  90. f = fc.get_forecast()
  91. return_message = []
  92. for weather in f:
  93. weather_date = weather.get_reference_time('date')
  94. if(weather_date.date() != datetime.date.today()):
  95. break
  96. return_message.append(" - {:2d}h : {}mm".format(
  97. weather_date.hour,
  98. round(float(weather.get_rain().get('3h', 0)), 1)
  99. ))
  100. return "\n".join(return_message)
  101. if __name__ == "__main__":
  102. logging.basicConfig(
  103. level=logging.WARNING,
  104. format=' %(asctime)s - %(levelname)s - %(message)s'
  105. )
  106. if len(sys.argv) > 1:
  107. wtf = WeatherToFreemobile(sys.argv[1])
  108. else:
  109. config_file = os.path.join(
  110. os.path.dirname(os.path.realpath(sys.argv[0])),
  111. 'config.json'
  112. )
  113. wtf = WeatherToFreemobile(config_file)
  114. wtf.send_sms_to_freemobile(wtf.get_weather())