Compare commits

...

23 Commits

Author SHA1 Message Date
SpudGunMan
4839e9ba03 Update requirements.txt 2025-01-18 20:57:26 -08:00
SpudGunMan
bde15e311a Update README.md 2025-01-18 20:55:23 -08:00
SpudGunMan
21c83222e9 Update mesh_bot.py 2025-01-18 20:52:45 -08:00
SpudGunMan
bbcdd6656a Update README.md 2025-01-18 20:38:50 -08:00
SpudGunMan
7f61b86252 Update README.md 2025-01-18 20:10:19 -08:00
SpudGunMan
25ae27a162 Update system.py 2025-01-18 20:10:16 -08:00
SpudGunMan
a04133e82f Update README.md 2025-01-18 19:59:07 -08:00
SpudGunMan
2a9dfc90ee Update checklist.py 2025-01-18 18:09:42 -08:00
SpudGunMan
f1bf84f6f0 enhance 2025-01-18 18:08:36 -08:00
SpudGunMan
4b91ef10b4 Update README.md 2025-01-18 16:59:08 -08:00
SpudGunMan
cd4497b129 Update config.template 2025-01-18 16:28:52 -08:00
SpudGunMan
01374a8307 Update config.template 2025-01-18 16:28:40 -08:00
SpudGunMan
46c115b783 Update README.md 2025-01-18 16:27:04 -08:00
SpudGunMan
eec7230a84 fix 2025-01-18 16:24:04 -08:00
SpudGunMan
9394fd6ca9 qrzHello
says hello to new seen nodes
2025-01-18 16:22:35 -08:00
SpudGunMan
c6653da1f3 fixQRZ 2025-01-18 16:17:29 -08:00
SpudGunMan
9f47958a03 Update checklist.py 2025-01-18 16:14:00 -08:00
SpudGunMan
78e51b7be1 Update qrz.py 2025-01-18 16:06:40 -08:00
SpudGunMan
26fcf6fc02 enhance 2025-01-18 15:54:27 -08:00
SpudGunMan
c2336850fe Update checklist.py 2025-01-18 15:35:03 -08:00
SpudGunMan
54e0d17e70 Update checklist.py 2025-01-18 15:17:18 -08:00
SpudGunMan
7a6d1f7b29 Update checklist.py 2025-01-18 15:13:34 -08:00
SpudGunMan
7e26d3f0e5 Update README.md 2025-01-18 15:07:16 -08:00
8 changed files with 97 additions and 27 deletions

View File

@@ -11,13 +11,14 @@ Welcome to the Mesh Bot project! This feature-rich bot is designed to enhance yo
- **Automated Responses**: The bot detects keywords like "ping" and responds with "pong" in direct messages (DMs) or group channels.
- **Customizable Triggers**: Monitor group channels for specific keywords and set custom responses.
- **Emergency Response**: Monitor channels for keywords indicating emergencies and alert a wider audience.
- **New Node Hello**: Greet new nodes on the mesh with a hello message
### Network Tools
- **Build, Test Local Mesh**: Ping allow for message delivery testing with more realistic packets vs. telemetry
- **Test Node Hardware**: `test` will send incremental sized data into the radio buffer for overall length of message testing
### Dual Radio/Node Support
- **Simultaneous Monitoring**: Monitor two networks at the same time.
### Multi Radio/Node Support
- **Simultaneous Monitoring**: Monitor up to nine networks at the same time.
- **Flexible Messaging**: send mail and messages, between networks.
### Advanced Messaging Capabilities
@@ -26,7 +27,8 @@ Welcome to the Mesh Bot project! This feature-rich bot is designed to enhance yo
- **Store and Forward**: Replay messages with the `messages` command, and log messages locally to disk.
- **Send Mail**: Send mail to nodes using `bbspost @nodeNumber #message` or `bbspost @nodeShortName #message`.
- **BBS Linking**: Combine multiple bots to expand BBS reach.
- **E-Mail/SMS**: Send mesh-messages to E-Mail or SMS expanding visability.
- **E-Mail/SMS**: Send mesh-messages to E-Mail or SMS(Email) expanding visability.
- **New Node Hello**: Send a hello to any new node seen in text message.
### Interactive AI and Data Lookup
- **NOAA location Data**: Get localized weather(alerts), River Flow, and Tide information. Open-Meteo is used for wx only outside NOAA coverage.
@@ -53,6 +55,7 @@ Welcome to the Mesh Bot project! This feature-rich bot is designed to enhance yo
- **NOAA EAS Alerts via API**: Use an internet-connected node to message Emergency Alerts from NOAA.
- **EAS Alerts over the air**: Utilizing external tools to report EAS alerts offline over mesh.
- **UK.GOV Alerts**: Pulling data form the UK.GOV alert page
- **NINA alerts for Germany**: Emergency Alerts from xrepository.de feed
### File Monitor Alerts
- **File Monitor**: Monitor a flat/text file for changes, broadcast the contents of the message to the mesh channel.
@@ -203,8 +206,8 @@ alert_interface = 1
### EAS Alerting
To Alert on Mesh with the EAS API you can set the channels and enable, checks every 20min.
#### FEMA iPAWS/EAS and UK.gov
This uses USA: SAME, FIPS, ZIP code to locate the alerts in the feed. By default ignoring Test messages. UK.gov for England
#### FEMA iPAWS/EAS and UK.gov NINA
This uses USA: SAME, FIPS, ZIP code to locate the alerts in the feed. By default ignoring Test messages.
```ini
eAlertBroadcastEnabled = False # Goverment IPAWS/CAP Alert Broadcast
@@ -213,7 +216,11 @@ ignoreFEMAtest = True # Ignore any headline that includes the word Test
# comma separated list of codes (e.g., SAME,FIPS,ZIP) trigger local alert.
# find your SAME https://www.weather.gov/nwr/counties
mySAME = 053029,053073
# To use other country services enable only a single optional serivce
enableGBalerts = False # use UK.gov for alert source
enableDEalerts = False # Use DE Alert Broadcast Data see template for filters
```
#### NOAA EAS
@@ -308,7 +315,13 @@ rtl_fm -f 162425000 -s 22050 | multimon-ng -t raw -a EAS /dev/stdin | python eas
#### Newspaper on mesh
a newspaper could be built by external scripts. could use Ollama to compile text via news web pages and write news.txt
you can also enable the line by line (hint just search for the commented lines with a 🐝) to return a string from the [bee movie](https://courses.cs.washington.edu/courses/cse163/20wi/files/lectures/L04/bee-movie.txt) for example adding it alongside news.txt as bee.txt
### Greet new nodes QRZ module
This isnt QRZ.com this is Q code for who is calling me, this will track new nodes and say hello
```ini
[qrz]
enabled = True # QRZ Hello to new nodes
qrz_hello_string = "send CMD or DM me for more info." # will be sent to all heard nodes once
```
### Scheduler
In the config.ini enable the module
@@ -362,7 +375,7 @@ There is no direct support for MQTT in the code, however, reports from Discord a
### Radio Propagation & Weather Forcasting
| Command | Description | |
|---------|-------------|-------------------
| `ea` and `ealert` | Return FEMA iPAWS/EAS alerts in USA or UK. Headline or expanded details for USA | |
| `ea` and `ealert` | Return FEMA iPAWS/EAS alerts in USA or UK/DE Headline or expanded details for USA | |
| `hfcond` | Returns a table of HF solar conditions | |
| `rlist` | Returns a table of nearby repeaters from RepeaterBook | |
| `riverflow` | Return information from NOAA for river flow info. Example: `riverflow modules/settings.py`| |
@@ -399,6 +412,7 @@ There is no direct support for MQTT in the code, however, reports from Discord a
### CheckList
| Command | Description | |
|---------|-------------|-
| `checkin` | Check in the node to the checklist database | ✅ |
| `checkout` | Checkout the node in the checklist database | ✅ |
| `checklist` | Display the checklist database | ✅ |

View File

@@ -173,6 +173,12 @@ satList = 25544,7530
enabled = False
checklist_db = data/checklist.db
[qrz]
# QRZ Hello to new nodes with message
enabled = False
qrz_db = data/qrz.db
qrz_hello_string = "send CMD or DM me for more info."
# repeater module
[repeater]
enabled = False

View File

@@ -43,8 +43,8 @@ def auto_response(message, snr, rssi, hop, pkiStatus, message_from_id, channel_n
"bbsread": lambda: handle_bbsread(message),
"blackjack": lambda: handleBlackJack(message, message_from_id, deviceID),
"checkin": lambda: handle_checklist(message, message_from_id, deviceID),
"checkout": lambda: handle_checklist(message, message_from_id, deviceID),
"checklist": lambda: handle_checklist(message, message_from_id, deviceID),
"checkout": lambda: handle_checklist(message, message_from_id, deviceID),
"clearsms": lambda: handle_sms(message_from_id, message),
"cmd": lambda: help_message,
"cq": lambda: handle_ping(message_from_id, deviceID, message, hop, snr, rssi, isDM, channel_number),
@@ -1256,8 +1256,8 @@ def onReceive(packet, interface):
if never_seen_before(message_from_id):
# add to qrz_hello list
hello(message_from_id, get_name_from_number(message_from_id, 'short', rxNode))
# send a hello message
send_message(f"Hello {get_name_from_number(message_from_id, 'short', rxNode)}", channel_number, message_from_id, rxNode)
# send a hello message as a DM
send_message(f"Hello {get_name_from_number(message_from_id, 'short', rxNode)} {qrz_hello_string}", channel_number, message_from_id, rxNode)
time.sleep(responseDelay)
else:
# Evaluate non TEXT_MESSAGE_APP packets

View File

@@ -28,6 +28,8 @@ def checkin(name, date, time, location, notes):
c = conn.cursor()
try:
c.execute("INSERT INTO checkin (checkin_name, checkin_date, checkin_time, location, checkin_notes) VALUES (?, ?, ?, ?, ?)", (name, date, time, location, notes))
# # remove any checkouts that are older than the checkin
# c.execute("DELETE FROM checkout WHERE checkout_date < ? OR (checkout_date = ? AND checkout_time < ?)", (date, date, time))
except sqlite3.OperationalError as e:
if "no such table" in str(e):
initialize_checklist_database()
@@ -36,7 +38,7 @@ def checkin(name, date, time, location, notes):
raise
conn.commit()
conn.close()
return "Checked in: " + str(name)
return "Checked In: " + str(name)
def delete_checkin(checkin_id):
# delete a checkin
@@ -47,22 +49,47 @@ def delete_checkin(checkin_id):
conn.close()
return "Checkin deleted." + str(checkin_id)
def checkout(name, date, time, location, notes):
def checkout(name, date, time_str, location, notes):
location = ", ".join(map(str, location))
# checkout a user
conn = sqlite3.connect(checklist_db)
c = conn.cursor()
try:
c.execute("INSERT INTO checkout (checkout_name, checkout_date, checkout_time, location, checkout_notes) VALUES (?, ?, ?, ?, ?)", (name, date, time, location, notes))
# Check if the user has a checkin before checking out
c.execute("""
SELECT checkin_id FROM checkin
WHERE checkin_name = ?
AND NOT EXISTS (
SELECT 1 FROM checkout
WHERE checkout_name = checkin_name
AND (checkout_date > checkin_date OR (checkout_date = checkin_date AND checkout_time > checkin_time))
)
ORDER BY checkin_date DESC, checkin_time DESC
LIMIT 1
""", (name,))
checkin_record = c.fetchone()
if checkin_record:
c.execute("INSERT INTO checkout (checkout_name, checkout_date, checkout_time, location, checkout_notes) VALUES (?, ?, ?, ?, ?)", (name, date, time_str, location, notes))
# calculate length of time checked in
c.execute("SELECT checkin_time FROM checkin WHERE checkin_id = ?", (checkin_record[0],))
checkin_time = c.fetchone()[0]
checkin_datetime = time.strptime(date + " " + checkin_time, "%Y-%m-%d %H:%M:%S")
time_checked_in_seconds = time.time() - time.mktime(checkin_datetime)
timeCheckedIn = time.strftime("%H:%M:%S", time.gmtime(time_checked_in_seconds))
# # remove the checkin record older than the checkout
# c.execute("DELETE FROM checkin WHERE checkin_date < ? OR (checkin_date = ? AND checkin_time < ?)", (date, date, time_str))
except sqlite3.OperationalError as e:
if "no such table" in str(e):
initialize_checklist_database()
c.execute("INSERT INTO checkout (checkout_name, checkout_date, checkout_time, location, checkout_notes) VALUES (?, ?, ?, ?, ?)", (name, date, time, location, notes))
c.execute("INSERT INTO checkout (checkout_name, checkout_date, checkout_time, location, checkout_notes) VALUES (?, ?, ?, ?, ?)", (name, date, time_str, location, notes))
else:
raise
conn.commit()
conn.close()
return "Checked out: " + str(name)
if checkin_record:
return "Checked Out: " + str(name) + " duration " + timeCheckedIn
else:
return "you must check in before checking out"
def delete_checkout(checkout_id):
# delete a checkout
@@ -86,9 +113,16 @@ def list_checkin():
""")
rows = c.fetchall()
conn.close()
timeCheckedIn = ""
checkin_list = ""
for row in rows:
checkin_list += "Checkin ID: " + row[1] + " Date: " + row[2] + " Time: " + row[3] + " Notes: " + row[5] + "\n"
#calculate length of time checked in
timeCheckedIn = time.strftime("%H:%M:%S", time.gmtime(time.time() - time.mktime(time.strptime(row[2] + " " + row[3], "%Y-%m-%d %H:%M:%S"))))
checkin_list += "ID: " + row[1] + " checked-In for " + timeCheckedIn
if row[5] != "":
checkin_list += " note: " + row[5]
if row != rows[-1]:
checkin_list += "\n"
# if empty list
if checkin_list == "":
return "No data to display."

View File

@@ -18,19 +18,33 @@ def never_seen_before(nodeID):
# check if we have seen this node before and sent a hello message
conn = sqlite3.connect(qrz_db)
c = conn.cursor()
c.execute("SELECT * FROM qrz WHERE qrz_call = ?", (nodeID,))
row = c.fetchone()
conn.close()
if row is None:
return True
else:
return False
try:
c.execute("SELECT * FROM qrz WHERE qrz_call = ?", (nodeID,))
row = c.fetchone()
conn.close()
if row is None:
return True
else:
return False
except sqlite3.OperationalError as e:
if "no such table" in str(e):
initalize_qrz_database()
return True
else:
raise
def hello(nodeID, name, qth, notes):
def hello(nodeID, name):
# send a hello message
conn = sqlite3.connect(qrz_db)
c = conn.cursor()
c.execute("INSERT INTO qrz (qrz_call, qrz_name, qrz_qth, qrz_notes) VALUES (?, ?, ?, ?)", (nodeID, name, qth, notes))
try:
c.execute("INSERT INTO qrz (qrz_call, qrz_name) VALUES (?, ?)", (nodeID, name))
except sqlite3.OperationalError as e:
if "no such table" in str(e):
initalize_qrz_database()
c.execute("INSERT INTO qrz (qrz_call, qrz_name) VALUES (?, ?)", (nodeID, name))
else:
raise
conn.commit()
conn.close()
return True

View File

@@ -96,7 +96,7 @@ if 'checklist' not in config:
config.write(open(config_file, 'w'))
if 'qrz' not in config:
config['qrz'] = {'enabled': 'False', 'qrz_db': 'data/qrz.db'}
config['qrz'] = {'enabled': 'False', 'qrz_db': 'data/qrz.db', 'qrz_hello_string': 'send CMD or DM me for more info.'}
config.write(open(config_file, 'w'))
# interface1 settings
@@ -276,6 +276,7 @@ try:
# qrz hello
qrz_hello_enabled = config['qrz'].getboolean('enabled', False)
qrz_db = config['qrz'].get('qrz_db', 'data/qrz.db')
qrz_hello_string = config['qrz'].get('qrz_hello_string', 'send CMD or DM me for more info.')
# E-Mail Settings
sysopEmails = config['smtp'].get('sysopEmails', '').split(',')

View File

@@ -207,7 +207,7 @@ if radio_detection_enabled:
from modules.radio import * # from the spudgunman/meshing-around repo
# File Monitor Configuration
if file_monitor_enabled or read_news_enabled:
if file_monitor_enabled or read_news_enabled or bee_enabled:
from modules.filemon import * # from the spudgunman/meshing-around repo
if read_news_enabled:
trap_list = trap_list + trap_list_filemon # items readnews

View File

@@ -10,3 +10,4 @@ geopy
schedule
wikipedia
googlesearch-python
sqlite3