brianmitchl / weatherbot Goto Github PK
View Code? Open in Web Editor NEW⛈ A Twitter bot for weather
License: MIT License
⛈ A Twitter bot for weather
License: MIT License
Parts of the bot could greatly benefit from OO design. WeatherBotStrings has already been implemented.
The next step is the behemoth weather_data
dict. Other bits of data such as alerts might be good to convert into a class as well.
textwrap.shorten would be a great function to auto-truncate a tweet that is too long.
This wasn't added to the standard library until python 3.4, so this will require a breaking change.
Decouple might be worth investigating in place of configparser and a custom ENV var file.
Stack trace:
2015-04-12 06:45:10,045 ERROR 'NoneType' object is not subscriptable
2015-04-12 06:45:10,045 ERROR We got an exception!
Traceback (most recent call last):
File "weatherBot.py", line 266, in run
main()
File "weatherBot.py", line 219, in main
get_weather_variables(ydata)
File "weatherBot.py", line 109, in get_weather_variables
units = ydata['query']['results']['channel']['units']
TypeError: 'NoneType' object is not subscriptable
If it snows, you don't want to see a tweet about it every half hour. Maybe make a list of recent special events with a time stamp, and check against that when another special event is triggered to see if it has happened recently. Then special events of type 'snow', for example, could wait two hours, instead of 30 minutes before tweeting about it again. This would allow another special event, such as, 'rain' to happen within that two hours.
Dark Sky was recently acquired by Apple. Signups for the API are no longer being accepted and the API will shut down at the end of 2021. My plan right now is to continue to run my bots and maintain the API as it stands today ceases to function.
If it's going to rain in the next hour, it would be good to warn followers of the impeding wetness.
The Dark Sky 'minutely' field is only available in the US and UK at the moment, so this should gracefully be skipped in other locations.
Several functions still require large dicts and other data to be passed around. It would be great if only the data needed would be passed around. This should help with #5.
They're not really unit tests if they depend on a network call.
This will math file handling more universal from system to system (Windows).
No useful error handling happens if an invalid configuration path is passed in as an argument.
I have managed to get this running as a system service. Has been running consistently for over a week and can be seen on twitter @ https://twitter.com/ComputeHole.
what is needed to get this running as a system service on Ubuntu 19.04 (should be the same for any Linux system using systemd
Step 1.)
clone the GitHub repo
git clone https://github.com/BrianMitchL/weatherBot.git
Step 2.)
edit keys.py
in your favorite text editor and fill in the required information
Step 3.)
create the following file
sudo nano /etc/systemd/system/weatherBot.service
with the following content
[Unit]
Description=weatherBot
[Service]
Type=simple
WorkingDirectory=/path/to/weatherBot/GitHub/clone
ExecStart=/usr/bin/python3 weatherBot.py weatherBot.conf
[Install]
WantedBy=multi-user.target
Step 4.)
after creating the file above run the following commands
sudo systemctl enable weatherBot.service
Your weatherBot will now run as a systemd service
and start @ boot
sudo systemctl start weatherBot.service
Your weatherBot is now running as a systemd service
" weatherBot.service
"
you can check the status by running
sudo systemctl status weatherBot.service
if changes are made the configuration of weatherBot you will have to reload the service for changes to be noticed
sudo systemctl daemon-reload
Step 5.)
????
Step 6.)
Profit.
I would have created a P/R but I wasn't sure how to go about adding the information correctly.
Also one benefit of this is it doesn't require the installation of any additional software to make use of this great project!!
forecast.io was recently changed to Dark Sky API, so the environmental variables should be changed to reflect this in the next breaking update.
If weatherBot is stopped/crashes and then restarted in the middle of a throttled special event, a tweet for the same event will be sent. Saving and loading throttles and any cache information from a file on every main loop would solve this problem.
I think the pickle
library would be a good fit as this is data that users should not interact with. Datetimes are how weatherBot keeps track of throttles. Being able to work with datetimes directly instead of using a conversation between other data types/structures would make for cleaner and more direct code.
Every so often, the bot crashes from a requests.exceptions.ConnectionError
on the weather API. This should be excepted, pause, and try the request again.
For example, I had some tweets from the middle of the Gulf of Finland and it crashed the bot because the Twitter place name is of NoneType.
Python 3.3 is at end-of-life (https://docs.python.org/devguide/index.html#branchstatus). Support should be dropped in the next major release.
Any new features from Python 3.4 should be implemented (for example, see #26).
The degree symbol is missing from daily forecasts. Every temperature should have the degree symbol.
Example tweet over 140 character limit:
The forecast for today is mostly cloudy throughout the day and breezy starting in the afternoon, continuing until evening. 18ºC/13ºC. I want to believe.
This is what I get when I run test.py any ideas? The main program runs in terminal but won't tweet?
FF...........ERROR:root:Tweet failed: [{'code': 186, 'message': 'Status is over 140 characters.'}]
WARNING:root:Tweet skipped due to error: This tweet is over 140 characters.
This tweet is over 140 characters.
This tweet is over 140 characters.
This tweet is over 140 characters.
This tweet is over 140 characters.
4519
.
Warning (from warnings module):
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 760
self._tunnel_headers = {}
ResourceWarning: unclosed <ssl.SSLSocket fd=11, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=(‘IP Address’, 58307), raddr=(‘IP Address’, 443)>
..ERROR:root:400 Client Error: Bad Request for url: https://api.darksky.net/forecast/87e6e57f74628921d8f1d26397be733f/345.5,123.45?units=us&lang=en
ERROR:root:Error when getting Forecast object
Traceback (most recent call last):
File "/Users/Tom/Documents/weatherBot-master/weatherBot.py", line 154, in get_forecast_object
return forecastio.manual(url)
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/forecastio/api.py", line 51, in manual
return get_forecast(requestURL)
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/forecastio/api.py", line 60, in get_forecast
forecastio_reponse.raise_for_status()
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/requests/models.py", line 862, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.darksky.net/forecast/87e6e57f74628921d8f1d26397be733f/345.5,123.45?units=us&lang=en
Warning (from warnings module):
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 1076
for i, one_value in enumerate(values):
ResourceWarning: unclosed <ssl.SSLSocket fd=12, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=(‘IP Address’, 58310), raddr=(‘IP Address’, 443)>
.WARNING:root:Could not find tweet with location, falling back to hardcoded location
.2016-11-29 19:18:22,394 INFO Starting weatherBot with Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 26 2016, 10:47:25)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
2016-11-29 19:18:22,505 DEBUG debug
2016-11-29 19:18:22,569 WARNING uh oh
Warning (from warnings module):
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/testfixtures/logcapture.py", line 122
logger.handlers = self.old['handlers'][name]
ResourceWarning: unclosed file <_io.TextIOWrapper name='/Users/Tom/Documents/weatherBot-master/weatherBotTest.log' mode='a' encoding='US-ASCII'>
....
Warning (from warnings module):
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/yaml/scanner.py", line 1311
return ScalarToken(''.join(chunks), True, start_mark, end_mark)
ResourceWarning: unclosed <ssl.SSLSocket fd=13, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=(‘IP Address’, 58315), raddr=('IP Address.130', 443)>
Warning (from warnings module):
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/yaml/error.py", line 7
self.name = name
ResourceWarning: unclosed <ssl.SSLSocket fd=9, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('IP Address', 58305), raddr=(‘IP Address.130', 443)>
Warning (from warnings module):
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/yaml/error.py", line 7
self.name = name
ResourceWarning: unclosed <ssl.SSLSocket fd=10, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('IP Address', 58306), raddr=('IP Address', 443)>
Warning (from warnings module):
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/yaml/error.py", line 7
self.name = name
ResourceWarning: unclosed <ssl.SSLSocket fd=11, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('IP Address', 58308), raddr=('IP Address', 443)>
Warning (from warnings module):
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/yaml/error.py", line 7
self.name = name
ResourceWarning: unclosed <ssl.SSLSocket fd=12, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('IP Address', 58314), raddr=('IP Address', 443)>
................
======================================================================
FAIL: test_set_darksky_env_vars (__main__.TestKeys)
Test that the Dark Sky environmental variable is set to value in keys.py
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/Tom/Documents/weatherBot-master/test.py", line 871, in test_set_darksky_env_vars
self.assertEqual(os.getenv('WEATHERBOT_DARKSKY_KEY'), 'xxx')
AssertionError: '87e6e57f74628921d8f1d26397be733f' != 'xxx'
- 87e6e57f74628921d8f1d26397be733f
+ xxx
======================================================================
FAIL: test_set_twitter_env_vars (__main__.TestKeys)
Test that Twitter environmental variables are set to values in keys.py
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/Tom/Documents/weatherBot-master/test.py", line 860, in test_set_twitter_env_vars
self.assertEqual(os.getenv('WEATHERBOT_CONSUMER_KEY'), 'xxx')
AssertionError: 'jtLQOSlkGIvYxnKRyl6MnkTO4' != 'xxx'
- jtLQOSlkGIvYxnKRyl6MnkTO4
+ xxx
----------------------------------------------------------------------
Ran 38 tests in 6.650s
FAILED (failures=2)
>>>
When un-configured, the log file is created at the user's home directory. I think switching this to default to the base directory of the bot makes more sense.
While talking with @ryanmr, he made a good point that moving strings to something like a YAML file might be a good thing to do. It would be a lot easier for non-developers to add strings and contribute to the bot.
I'll work on this for v2.0. Any tips on structure or other features related to this would be appreciated!
Test coverage is poor to say the least. Improving test coverage to something closer to 75% would be awesome. Adding to version 1.1 milestone.
I keep on getting this when running weatherBot.py: You need to pass in the path of the conf file. Try again.
How do I get dark sky API? it's asking for dark sky API is there any other alternative source to get API
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.