Skip to content

Commit f08e739

Browse files
authored
Merge pull request #15 from agessaman/dev
v0.6
2 parents aa40a1d + 99c4dd5 commit f08e739

33 files changed

+6479
-1213
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ Thumbs.db
121121
*.log
122122
config.ini
123123
*.db
124+
*.db-wal
125+
*.db-shm
124126
mctomqtt.py
125127
bot_cli.py
126128
bot_start_time.txt

README.md

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ startup_advert = flood # Send advert on startup
9999
# Format: keyword = response_template
100100
# Variables: {sender}, {connection_info}, {snr}, {timestamp}, {path}
101101
test = "Message received from {sender} | {connection_info}"
102-
help = "Bot Help: test, ping, help, hello, cmd, wx, aqi, sun, moon, solar, hfcond, satpass, dice, roll, joke, dadjoke, sports, channels, path, prefix, repeater, stats"
102+
help = "Bot Help: test, ping, help, hello, cmd, wx, aqi, sun, moon, solar, hfcond, satpass, dice, roll, joke, dadjoke, sports, channels, path, prefix, repeater, stats, alert"
103103
```
104104

105105
### Channels
@@ -117,6 +117,16 @@ n2yo_api_key = # Satellite pass data
117117
airnow_api_key = # Air quality data
118118
```
119119

120+
### Alert Command
121+
```ini
122+
[Alert_Command]
123+
alert_enabled = true # Enable/disable alert command
124+
max_incident_age_hours = 24 # Maximum age for incidents (hours)
125+
max_distance_km = 20.0 # Maximum distance for proximity queries (km)
126+
agency.city.<city_name> = <agency_ids> # City-specific agency IDs (e.g., agency.city.seattle = 17D20,17M15)
127+
agency.county.<county_name> = <agency_ids> # County-specific agency IDs (aggregates all city agencies)
128+
```
129+
120130
### Logging
121131
```ini
122132
[Logging]
@@ -139,43 +149,68 @@ python meshcore_bot.py
139149
The bot responds to these commands:
140150

141151
**Basic Commands:**
142-
- `test` - Test message response
152+
- `test` or `t` - Test message response (can include optional phrase: `test <phrase>`)
143153
- `ping` - Ping/pong response
144-
- `help` - Show available commands
145-
- `hello` - Greeting response
146-
- `cmd` - List available commands
154+
- `help` - Show available commands (use `help <command>` for command details)
155+
- `hello` - Greeting response (also responds to: hi, hey, howdy, greetings, etc.)
156+
- `cmd` - List available commands in compact format
147157

148158
**Information Commands:**
149-
- `wx <location>` - Weather information
150-
- `aqi <location>` - Air quality index
159+
- `channels` - List hashtag channels (use `channels` for general, `channels list` for all categories, `channels <category>` for specific categories, `channels #channel` for specific channel info)
160+
- `wx <zipcode>` - Weather information for US zip code (also: `weather`, `wxa`, `wxalert`)
161+
- `gwx <location>` - Global weather for any location worldwide (also: `globalweather`, `gwxa`)
162+
- `aqi <location>` - Air quality index (usage: `aqi seattle`, `aqi greenwood`, `aqi vancouver canada`, `aqi 47.6,-122.3`, or `aqi help`)
151163
- `sun` - Sunrise/sunset times
152164
- `moon` - Moon phase and times
153-
- `solar` - Solar conditions
165+
- `solar` - Solar conditions and HF band status
166+
- `solarforecast` or `sf` - Solar panel production forecast (usage: `sf <location|repeater_name|coordinates|zipcode> [panel_size] [azimuth, 0=south] [angle]`)
154167
- `hfcond` - HF band conditions
155168
- `satpass <NORAD>` - Satellite pass information (default: radio passes, all passes above horizon)
156169
- `satpass <NORAD> visual` - Visual passes only (must be visually observable)
157170
- `satpass <shortcut>` - Use shortcuts like `iss`, `hst`, `hubble`, `goes18`, `tiangong`
158171

172+
**Emergency Commands:**
173+
- `alert <city|zipcode|street city|lat,lon|county> [all]` - Get active emergency incidents (e.g., `alert seattle`, `alert 98101`, `alert seattle all`)
174+
159175
**Gaming Commands:**
160176
- `dice` - Roll dice (d6 by default, or specify like `dice d20`, `dice 2d6`)
161177
- `roll` - Roll random number (1-100 by default, or specify like `roll 50`)
162178

163179
**Entertainment Commands:**
164-
- `joke` - Get a random joke
180+
- `joke` - Get a random joke (use `joke [category]` for specific category)
165181
- `dadjoke` - Get a dad joke from icanhazdadjoke.com
182+
- `hacker` - Responds to Linux commands (`sudo`, `ps aux`, `grep`, `ls -l`, etc.) with supervillain mainframe errors
166183

167184
**Sports Commands:**
168185
- `sports` - Get scores for default teams
169186
- `sports <team>` - Get scores for specific team
170187
- `sports <league>` - Get scores for league (nfl, mlb, nba, etc.)
171188

172-
**MeshCore Network Commands:**
173-
- `channels` - List hashtag channels
174-
- `path` - Decode message routing path
175-
- `prefix <XX>` - Look up repeaters by prefix
176-
- `repeater` - Manage repeater contacts and scan for new ones (DM only)
177-
- `stats` - Show bot usage statistics
178-
- `advert` - Send network advert (DM only)
189+
**MeshCore Utility Commands:**
190+
- `path` or `decode` or `route` - Decode message routing path
191+
- `prefix <XX>` - Look up repeaters by two-character prefix (e.g., `prefix 1A`)
192+
- `prefix refresh` - Refresh prefix cache
193+
- `prefix free` or `prefix available` - Show available prefixes
194+
- `prefix <XX> all` - Include all repeaters (not just active)
195+
- `stats` - Show bot usage statistics for past 24 hours
196+
- `stats messages` - Message statistics
197+
- `stats channels` - Channel statistics
198+
- `stats paths` - Path statistics
199+
- `multitest` or `mt` - Listens for 6 seconds and collects all unique paths from incoming messages
200+
201+
**Management Commands (DM only):**
202+
- `repeater` or `repeaters` or `rp` - Manage repeater contacts (DM only, requires ACL permissions)
203+
- `repeater scan` - Scan and catalog new repeaters
204+
- `repeater list` - List repeater contacts (use `--all` to show purged ones)
205+
- `repeater purge <days>` - Purge repeaters older than specified days
206+
- `repeater purge <name>` - Purge specific repeater by name
207+
- `repeater purge all` - Purge all repeaters
208+
- `repeater restore <name>` - Restore a previously purged repeater
209+
- `repeater stats` - Show repeater management statistics
210+
- `repeater status` - Show contact list status and limits
211+
- `repeater manage` - Auto-manage contact list (use `--dry-run` to preview)
212+
- See `help repeater` for full list of subcommands
213+
- `advert` - Send network flood advert (DM only, 1hr cooldown)
179214

180215
## Message Response Templates
181216

@@ -192,7 +227,7 @@ Example:
192227
[Keywords]
193228
test = "Message received from {sender} | {connection_info}"
194229
ping = "Pong!"
195-
help = "Bot Help: test, ping, help, hello, cmd, wx, aqi, sun, moon, solar, hfcond, satpass, dice, roll, joke, dadjoke, sports, channels, path, prefix, repeater, stats"
230+
help = "Bot Help: test, ping, help, hello, cmd, wx, gwx, aqi, sun, moon, solar, solarforecast, hfcond, satpass, dice, roll, joke, dadjoke, sports, channels, path, prefix, repeater, stats, multitest, alert, webviewer"
196231
```
197232

198233
## Hardware Setup

com.meshcore.bot.plist

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>Label</key>
6+
<string>com.meshcore.bot</string>
7+
8+
<key>ProgramArguments</key>
9+
<array>
10+
<string>/usr/local/meshcore-bot/venv/bin/python</string>
11+
<string>/usr/local/meshcore-bot/meshcore_bot.py</string>
12+
</array>
13+
14+
<key>WorkingDirectory</key>
15+
<string>/usr/local/meshcore-bot</string>
16+
17+
<key>RunAtLoad</key>
18+
<true/>
19+
20+
<key>KeepAlive</key>
21+
<dict>
22+
<key>SuccessfulExit</key>
23+
<false/>
24+
</dict>
25+
26+
<key>StandardOutPath</key>
27+
<string>/usr/local/var/log/meshcore-bot/meshcore-bot.log</string>
28+
29+
<key>StandardErrorPath</key>
30+
<string>/usr/local/var/log/meshcore-bot/meshcore-bot.error.log</string>
31+
32+
<key>EnvironmentVariables</key>
33+
<dict>
34+
<key>PYTHONPATH</key>
35+
<string>/usr/local/meshcore-bot</string>
36+
<key>PYTHONUNBUFFERED</key>
37+
<string>1</string>
38+
</dict>
39+
40+
<key>ThrottleInterval</key>
41+
<integer>10</integer>
42+
43+
<key>ProcessType</key>
44+
<string>Background</string>
45+
46+
<key>Nice</key>
47+
<integer>1</integer>
48+
</dict>
49+
</plist>
50+

config.ini.example

Lines changed: 137 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,29 @@ bot_latitude = 40.7128
8585
# Example: -74.0060 for New York City, -123.00 for Victoria BC
8686
bot_longitude = -74.0060
8787

88+
# Maximum number of channels to fetch from MeshCore node
89+
# MeshCore supports up to 40 channels (default: 40)
90+
# Set to a lower value if you want to limit channel fetching for performance
91+
max_channels = 12
92+
93+
# Interval-based advertising settings
94+
# Send periodic flood adverts at specified intervals
95+
# 0: Disabled (default)
96+
# >0: Send flood advert every N hours
97+
advert_interval_hours = 0
98+
99+
# Send startup advert when bot finishes initializing
100+
# false: No startup advert (default)
101+
# zero-hop: Send local broadcast advert
102+
# flood: Send network-wide flood advert
103+
startup_advert = false
104+
105+
# Auto-manage contact list when new contacts are discovered
106+
# device: Device handles auto-addition using standard auto-discovery mode, bot manages contact list capacity (purge old contacts when near limits)
107+
# bot: Bot automatically adds new companion contacts to device, bot manages contact list capacity (purge old contacts when near limits)
108+
# false: Manual mode - no automatic actions, use !repeater commands to manage contacts (default)
109+
auto_manage_contacts = false
110+
88111
[Localization]
89112
# Language code for bot responses (en, es, es-MX, es-ES, fr, de, ja, etc.)
90113
# Default: en (English)
@@ -166,24 +189,6 @@ dadjoke_enabled = true
166189
# true: Split long jokes into multiple messages
167190
long_jokes = false
168191

169-
# Send startup advert when bot finishes initializing
170-
# false: No startup advert (default)
171-
# zero-hop: Send local broadcast advert
172-
# flood: Send network-wide flood advert
173-
startup_advert = false
174-
175-
# Auto-manage contact list when new contacts are discovered
176-
# device: Device handles auto-addition using standard auto-discovery mode, bot manages contact list capacity (purge old contacts when near limits)
177-
# bot: Bot automatically adds new companion contacts to device, bot manages contact list capacity (purge old contacts when near limits)
178-
# false: Manual mode - no automatic actions, use !repeater commands to manage contacts (default)
179-
auto_manage_contacts = false
180-
181-
# Interval-based advertising settings
182-
# Send periodic flood adverts at specified intervals
183-
# 0: Disabled (default)
184-
# >0: Send flood advert every N hours
185-
advert_interval_hours = 0
186-
187192
[Keywords]
188193
# Keyword-response pairs (keyword = response format)
189194
# Available fields: {sender}, {connection_info}, {snr}, {timestamp}, {path}, {path_distance}, {firstlast_distance}
@@ -198,7 +203,7 @@ advert_interval_hours = 0
198203
test = "ack @[{sender}]{phrase_part} | {connection_info} | Received at: {timestamp}"
199204
ping = "Pong!"
200205
pong = "Ping!"
201-
help = "Bot Help: test (or t), ping, help, hello, cmd, advert, @string, wx, aqi, sun, moon, solar, hfcond, satpass, prefix, path, sports, dice, roll, stats | Use 'help <command>' for details"
206+
help = "Bot Help: test (or t), ping, help, hello, cmd, advert, @string, wx, aqi, sun, moon, solar, hfcond, satpass, prefix, path, sports, dice, roll, stats | More: 'help <command>'"
202207
cmd = "Available commands: test (or t), ping, help, hello, cmd, advert, @string, wx, aqi, sun, moon, solar, hfcond, satpass, prefix, path, sports, dice, roll, stats"
203208

204209
[Channels]
@@ -249,6 +254,73 @@ colored_output = true
249254
# Options: DEBUG, INFO, WARNING, ERROR, CRITICAL
250255
meshcore_log_level = INFO
251256

257+
[Greeter_Command]
258+
# Enable or disable the greeter command
259+
# true: Bot will greet users on their first public channel message
260+
# false: Greeter is disabled
261+
enabled = false
262+
263+
# Channels where greetings should occur (comma-separated)
264+
# IMPORTANT: Leave commented out (or omit entirely) to use global monitor_channels (default behavior)
265+
# If uncommented with empty value (channels = ), command will be DM-only
266+
# Comma-separated list to restrict to specific channels (only greeter command works there)
267+
# Example: channels = general,welcome,newbies
268+
# If not specified, uses the channels from [Channels] monitor_channels setting
269+
# channels =
270+
271+
# Greeting message template (default for all channels)
272+
# Available fields: {sender} - the user's name/ID
273+
# For multi-part greetings, separate messages with pipe (|)
274+
# Example (single): "Welcome to the mesh, @[{sender}]!"
275+
# Example (multi-part): "Welcome to the mesh, @[{sender}]!|This is a great place to chat.|Use !help for commands."
276+
greeting_message = Welcome to the mesh, @[{sender}]!
277+
278+
# Channel-specific greeting messages (optional)
279+
# Format: channel_name:greeting_message,channel_name2:greeting_message2
280+
# If a channel has a specific greeting, it will be used instead of the default greeting_message
281+
# Example: Public:Welcome to Public channel, @[{sender}]!|general:Welcome to general, @[{sender}]!
282+
# Multi-part greetings are supported per channel using pipe (|) separator
283+
# Leave empty to use greeting_message for all channels
284+
channel_greetings =
285+
286+
# Per-channel greetings (tracking behavior)
287+
# false: Greet each user only once globally (default - user gets one greeting total)
288+
# true: Greet each user once per channel (user can be greeted on each channel separately)
289+
# Note: This controls tracking, not the greeting message itself. Use channel_greetings for different messages.
290+
per_channel_greetings = false
291+
292+
# Include mesh network information in greeting
293+
# true: Add mesh statistics to greeting (total contacts, repeaters, etc.)
294+
# false: Only send the greeting message
295+
include_mesh_info = true
296+
297+
# Mesh info format template
298+
# Available fields: {total_contacts}, {repeaters}, {companions}, {recent_activity_24h}
299+
# Example: "\n\nMesh Info: {total_contacts} contacts, {repeaters} repeaters"
300+
# Note: Mesh info is appended to the last greeting message part
301+
mesh_info_format = \n\nMesh Info: {total_contacts} contacts, {repeaters} repeaters, {recent_activity_24h} active in last 24h
302+
303+
# Rollout period in days
304+
# When greeter is first enabled on an active mesh, this sets how many days
305+
# to listen and mark all active users as already greeted before beginning
306+
# to greet new users. This prevents greeting everyone on an established mesh.
307+
# Set to 0 to disable rollout (will greet all new users immediately)
308+
# Note: Use auto_backfill to mark historical users and shorten/eliminate rollout period
309+
rollout_days = 7
310+
311+
# Auto-backfill from historical message_stats data
312+
# true: Automatically mark all users who have posted on public channels in the past
313+
# false: Only mark users during rollout period (default)
314+
# This allows shortening or eliminating the rollout period by using existing data
315+
auto_backfill = false
316+
317+
# Backfill lookback period in days
318+
# Number of days to look back when auto-backfilling (0 = all time)
319+
# Only used if auto_backfill = true
320+
# Example: 30 = only mark users who posted in last 30 days
321+
# Example: 0 = mark all users who have ever posted (all time)
322+
backfill_lookback_days = 30
323+
252324
[Custom_Syntax]
253325
# Custom syntax patterns for special message formats
254326
# Format: pattern = "response_format"
@@ -419,9 +491,12 @@ sports_enabled = true
419491
# Comma-separated list of team names (use lowercase)
420492
teams = seahawks,mariners,sounders,kraken
421493

422-
# Channels where sports command is allowed (leave empty for all channels)
423-
# Comma-separated list of channel names
424-
channels = general,#bot,#sounders,#seahawks
494+
# Channels where sports command is allowed
495+
# IMPORTANT: Leave commented out (or omit entirely) to use global monitor_channels (default behavior)
496+
# If uncommented with empty value (channels = ), command will be DM-only
497+
# Comma-separated list to restrict to specific channels (only sports command works there)
498+
# Example: channels = #sounders,#seahawks (only sports command works in these channels)
499+
# channels = general,#bot,#sounders,#seahawks
425500

426501
# Channel overrides for sports command
427502
# Format: channel_name = default_team
@@ -488,6 +563,13 @@ max_proximity_range = 200
488563
# Set to 0 to disable age filtering
489564
max_repeater_age_days = 14
490565

566+
# Star bias multiplier for path command
567+
# When a contact is starred in the web viewer, multiply its selection score by this value
568+
# Higher values = stronger preference for starred repeaters
569+
# Default: 2.5 (starred repeaters get 2.5x their normal score)
570+
# Set to 1.0 to disable star bias
571+
star_bias_multiplier = 2.5
572+
491573
# Recency vs Proximity weighting (0.0 to 1.0)
492574
# Controls how much recency (when last heard) vs proximity (distance) matters
493575
# 0.0 = 100% proximity (only distance matters)
@@ -517,6 +599,39 @@ enable_p_shortcut = false
517599
# false: Hacker command is disabled
518600
hacker_enabled = false
519601

602+
[Multitest_Command]
603+
# Response format for multitest command results
604+
# Available fields: {sender}, {path_count}, {paths}, {listening_duration}
605+
# {sender}: Name/ID of message sender
606+
# {path_count}: Number of unique paths found
607+
# {paths}: Newline-separated list of paths
608+
# {listening_duration}: Listening window duration in seconds
609+
# Leave empty to use default format
610+
# Example: "Found {path_count} unique path(s) for @[{sender}]:\n{paths}"
611+
response_format =
612+
613+
[Alert_Command]
614+
# Enable or disable the alert command
615+
# true: Alert command is available
616+
# false: Alert command is disabled
617+
alert_enabled = false
618+
619+
# PulsePoint agency IDs by county/region
620+
# Format: agency.<county_name> = comma-separated agency IDs
621+
# Get agency IDs from: https://web.pulsepoint.org/ or PulsePoint searchagencies API
622+
# You can use any naming convention that makes sense for your region
623+
# Examples: agency.county1, agency.city1, agency.region1, etc.
624+
625+
# Example: County agencies
626+
# agency.county1 =
627+
628+
# Example: City agencies (can have multiple entries for the same region)
629+
# agency.city1 =
630+
# agency.city1_alias =
631+
632+
# Example: Combined region (all counties/agencies)
633+
# agency.region_all =
634+
520635
[Web_Viewer]
521636
# Enable or disable the web data viewer
522637
# true: web viewer is available for viewing bot data

0 commit comments

Comments
 (0)