diff --git a/README.md b/README.md index a2255e0..0e4ee9e 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ Welcome to the Mesh Bot project! This feature-rich bot is designed to enhance yo ### Data Reporting - **HTML Generator**: Visualize bot traffic and data flows with a built-in HTML generator for [data reporting](logs/README.md). +- **RSS and news feeds**: Get data in mesh from many sources! ### Robust Message Handling - **Message Chunking**: Automatically chunk messages over 160 characters to ensure higher delivery success across hops. @@ -149,6 +150,7 @@ git clone https://github.com/spudgunman/meshing-around | `askai` and `ask:` | Ask Ollama LLM AI for a response. Example: `askai what temp do I cook chicken` | ✅ | | `messages` | Replays the last messages heard on device, like Store and Forward, returns the PublicChannel and Current | ✅ | | `readnews` | returns the contents of a file (data/news.txt, by default) can also `news mesh` via the chunker on air | ✅ | +| `readrss` | returns a set RSS feed on air | | | `satpass` | returns the pass info from API for defined NORAD ID in config or Example: `satpass 25544,33591`| | | `wiki:` | Searches Wikipedia (or local Kiwix server) and returns the first few sentences of the first result if a match. Example: `wiki: lora radio` | | `howfar` | returns the distance you have traveled since your last HowFar. `howfar reset` to start over | ✅ | @@ -576,7 +578,7 @@ I used ideas and snippets from other responder bots and want to call them out! - **mikecarper**: ideas, and testing. hamtest - **c.merphy360**: high altitude alerts - **Iris**: testing and finding 🐞 -- **Cisien, bitflip, Woof, propstg, snydermesh, trs2982, Josh, mesb1, and Hailo1999**: For testing and feature ideas on Discord and GitHub. +- **Cisien, bitflip, Woof, propstg, snydermesh, trs2982, FJRPilot, Josh, mesb1, and Hailo1999**: For testing and feature ideas on Discord and GitHub. - **Meshtastic Discord Community**: For tossing out ideas and testing code. ### Tools diff --git a/config.template b/config.template index 73f0245..ef684f9 100644 --- a/config.template +++ b/config.template @@ -55,6 +55,12 @@ DadJokesEmoji = False # enable or disable the Solar module spaceWeather = True +# enable or disable the RSS module, and truncate the story +rssEnable = True +rssFeedURL = http://www.hackaday.com/rss.xml +rssMaxItems = 3 +rssTruncate = 100 + # enable or disable the wikipedia search module wikipedia = True # Use local Kiwix server instead of online Wikipedia diff --git a/mesh_bot.py b/mesh_bot.py index 5fdc5cb..d2e6ec3 100755 --- a/mesh_bot.py +++ b/mesh_bot.py @@ -77,6 +77,7 @@ def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_n "q:": lambda: quizHandler(message, message_from_id, deviceID), "quiz": lambda: quizHandler(message, message_from_id, deviceID), "readnews": lambda: handleNews(message_from_id, deviceID, message, isDM), + "readrss": lambda: get_rss_feed() if rssEnable else "RSS feed module is disabled", "riverflow": lambda: handle_riverFlow(message, message_from_id, deviceID), "rlist": lambda: handle_repeaterQuery(message_from_id, deviceID, channel_number), "satpass": lambda: handle_satpass(message_from_id, deviceID, channel_number, message), @@ -1701,6 +1702,8 @@ async def start_rx(): logger.debug("System: Games Enabled!") if wikipedia_enabled: logger.debug("System: Wikipedia search Enabled") + if rssEnabled: + logger.debug(f"System: RSS Feed Reader Enabled for {rssFeedURL}") if motd_enabled: logger.debug(f"System: MOTD Enabled using {MOTD}") if sentry_enabled: diff --git a/modules/rss.py b/modules/rss.py new file mode 100644 index 0000000..7d01927 --- /dev/null +++ b/modules/rss.py @@ -0,0 +1,33 @@ +# rss feed module for meshing-around 2025 +from modules.log import * +import urllib.request +import xml.etree.ElementTree as ET + +RSS_FEED_URL = rssFeedURL +RSS_RETURN_COUNT = rssMaxItems +RSS_TRIM_LENGTH = rssTruncate + +def get_rss_feed(): + try: + with urllib.request.urlopen(RSS_FEED_URL) as response: + xml_data = response.read() + root = ET.fromstring(xml_data) + items = root.findall('.//item')[:RSS_RETURN_COUNT] + if not items: + return "No RSS feed entries found." + formatted_entries = [] + for item in items: + title = item.findtext('title', default='No title') + link = item.findtext('link', default='No link') + description = item.findtext('description', default='No description') + pub_date = item.findtext('pubDate', default='No date') + + # strip all HTML tags and markup + description = ''.join(ET.fromstring(f"