diff --git a/config.ini.example b/config.ini.example index a1a029d..b4a2a76 100644 --- a/config.ini.example +++ b/config.ini.example @@ -219,16 +219,44 @@ long_jokes = false # channels = general,#bot,#jokes [Keywords] -# Keyword-response pairs (keyword = response format) -# Available fields: {sender}, {connection_info}, {snr}, {timestamp}, {path}, {path_distance}, {firstlast_distance} -# {sender}: Name/ID of message sender -# {connection_info}: "Direct connection (0 hops)" or "Routed through X hops" -# {snr}: Signal-to-noise ratio in dB -# {timestamp}: Message timestamp in HH:MM:SS format -# {path}: Message routing path (e.g., "01,5f (2 hops)") -# {rssi}: Received Signal Strength Indicator in dBm -# {path_distance}: Total distance between all hops in path with locations (e.g., "123.4km (3 segs, 1 no-loc)") -# {firstlast_distance}: Distance between first and last repeater in path (e.g., "45.6km" or empty if locations missing) +# Available placeholders (message-based): +# {sender} - Name/ID of message sender +# {connection_info} - Path info, SNR, and RSSI combined (e.g., "01,5f (2 hops) | SNR: 15 dB | RSSI: -120 dBm") +# {snr} - Signal-to-noise ratio in dB +# {rssi} - Received signal strength indicator in dBm +# {timestamp} - Message timestamp in HH:MM:SS format +# {path} - Message routing path (e.g., "01,5f (2 hops)") +# {path_distance} - Total distance between all hops in path with locations (e.g., "123.4km (3 segs, 1 no-loc)") +# {firstlast_distance} - Distance between first and last repeater in path (e.g., "45.6km" or empty if locations missing) +# {elapsed} - Message elapsed time +# +# Available placeholders (mesh network info - same as Scheduled_Messages): +# Total counts (ever heard): +# {total_contacts} - Total number of contacts ever heard +# {total_repeaters} - Total number of repeater devices ever heard +# {total_companions} - Total number of companion devices ever heard +# {total_roomservers} - Total number of roomserver devices ever heard +# {total_sensors} - Total number of sensor devices ever heard +# +# Recent activity: +# {recent_activity_24h} - Number of unique users active in last 24 hours +# +# Active in last 30 days (last_heard): +# {total_contacts_30d} - Total contacts active (last_heard) in last 30 days +# {total_repeaters_30d} - Total repeaters active (last_heard) in last 30 days +# {total_companions_30d} - Total companions active (last_heard) in last 30 days +# {total_roomservers_30d} - Total roomservers active (last_heard) in last 30 days +# {total_sensors_30d} - Total sensors active (last_heard) in last 30 days +# +# New devices (first heard in last 7 days): +# {new_companions_7d} - New companion devices first heard in last 7 days +# {new_repeaters_7d} - New repeater devices first heard in last 7 days +# {new_roomservers_7d} - New roomserver devices first heard in last 7 days +# {new_sensors_7d} - New sensor devices first heard in last 7 days +# +# Legacy placeholders (for backward compatibility): +# {repeaters} - Same as {total_repeaters} +# {companions} - Same as {total_companions} test = "ack @[{sender}]{phrase_part} | {connection_info} | Received at: {timestamp}" ping = "Pong!" pong = "Ping!" diff --git a/modules/commands/advert_command.py b/modules/commands/advert_command.py index 3b34940..68d58e4 100644 --- a/modules/commands/advert_command.py +++ b/modules/commands/advert_command.py @@ -33,6 +33,7 @@ class AdvertCommand(BaseCommand): bot: The bot instance. """ super().__init__(bot) + self.advert_enabled = self.get_config_value('Advert_Command', 'enabled', fallback=True, value_type='bool') def get_help_text(self) -> str: """Get help text for the advert command. @@ -54,6 +55,10 @@ class AdvertCommand(BaseCommand): Returns: bool: True if the command can be executed, False otherwise. """ + # Check if advert command is enabled + if not self.advert_enabled: + return False + # Use the base class cooldown check if not super().can_execute(message): return False diff --git a/modules/commands/aqi_command.py b/modules/commands/aqi_command.py index 246eff7..922bbdd 100644 --- a/modules/commands/aqi_command.py +++ b/modules/commands/aqi_command.py @@ -37,6 +37,7 @@ class AqiCommand(BaseCommand): def __init__(self, bot): super().__init__(bot) + self.aqi_enabled = self.get_config_value('Aqi_Command', 'enabled', fallback=True, value_type='bool') self.url_timeout = 10 # seconds # Get default state from config for city disambiguation @@ -88,6 +89,19 @@ class AqiCommand(BaseCommand): def get_help_text(self) -> str: return f"Usage: aqi - Get AQI for city/neighborhood in {self.default_state}, international cities, coordinates, or pollutant help" + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.aqi_enabled: + return False + return super().can_execute(message) + def get_pollutant_help(self) -> str: """Get help text explaining pollutant types within 130 characters. diff --git a/modules/commands/catfact_command.py b/modules/commands/catfact_command.py index 89538e0..2ebeb7f 100644 --- a/modules/commands/catfact_command.py +++ b/modules/commands/catfact_command.py @@ -31,6 +31,7 @@ class CatfactCommand(BaseCommand): bot: The bot instance. """ super().__init__(bot) + self.catfact_enabled = self.get_config_value('Catfact_Command', 'enabled', fallback=True, value_type='bool') # Collection of cat facts - fallback if translations not available self.cat_facts_fallback = [ @@ -124,6 +125,19 @@ class CatfactCommand(BaseCommand): # Return empty string so it doesn't appear in help return "" + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.catfact_enabled: + return False + return super().can_execute(message) + async def execute(self, message: MeshMessage) -> bool: """Execute the cat fact command. diff --git a/modules/commands/channels_command.py b/modules/commands/channels_command.py index fd9a70a..1b69386 100644 --- a/modules/commands/channels_command.py +++ b/modules/commands/channels_command.py @@ -24,6 +24,28 @@ class ChannelsCommand(BaseCommand): description = "Lists hashtag channels with sub-categories. Use 'channels' for general, 'channels list' for all categories, 'channels ' for specific categories, 'channels #channel' for specific channel info." category = "basic" + def __init__(self, bot): + """Initialize the channels command. + + Args: + bot: The bot instance. + """ + super().__init__(bot) + self.channels_enabled = self.get_config_value('Channels_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.channels_enabled: + return False + return super().can_execute(message) + def get_help_text(self) -> str: return self.translate('commands.channels.help') diff --git a/modules/commands/cmd_command.py b/modules/commands/cmd_command.py index 72affea..15dfecd 100644 --- a/modules/commands/cmd_command.py +++ b/modules/commands/cmd_command.py @@ -18,6 +18,28 @@ class CmdCommand(BaseCommand): description = "Lists available commands in compact format" category = "basic" + def __init__(self, bot): + """Initialize the cmd command. + + Args: + bot: The bot instance. + """ + super().__init__(bot) + self.cmd_enabled = self.get_config_value('Cmd_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.cmd_enabled: + return False + return super().can_execute(message) + def get_help_text(self) -> str: """Get help text for the cmd command. diff --git a/modules/commands/dice_command.py b/modules/commands/dice_command.py index 105c455..666a661 100644 --- a/modules/commands/dice_command.py +++ b/modules/commands/dice_command.py @@ -29,6 +29,28 @@ class DiceCommand(BaseCommand): 'd20': 20 } + def __init__(self, bot): + """Initialize the dice command. + + Args: + bot: The bot instance. + """ + super().__init__(bot) + self.dice_enabled = self.get_config_value('Dice_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.dice_enabled: + return False + return super().can_execute(message) + def get_help_text(self) -> str: """Get help text for the dice command. diff --git a/modules/commands/hello_command.py b/modules/commands/hello_command.py index 4a4a0d4..e3ce22c 100644 --- a/modules/commands/hello_command.py +++ b/modules/commands/hello_command.py @@ -27,6 +27,9 @@ class HelloCommand(BaseCommand): """ super().__init__(bot) + # Load configuration + self.hello_enabled = self.get_config_value('Hello_Command', 'enabled', fallback=True, value_type='bool') + # Fallback arrays if translations not available self._init_fallback_arrays() @@ -353,6 +356,22 @@ class HelloCommand(BaseCommand): return bool(re.match(defined_emoji_pattern, cleaned_text)) + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + # Check if hello command is enabled + if not self.hello_enabled: + return False + + # Call parent can_execute() which includes channel checking, cooldown, etc. + return super().can_execute(message) + def get_emoji_response(self, text: str, bot_name: str) -> str: """Get appropriate response for emoji-only message""" import random diff --git a/modules/commands/help_command.py b/modules/commands/help_command.py index 5b9b6ff..db2a30f 100644 --- a/modules/commands/help_command.py +++ b/modules/commands/help_command.py @@ -25,6 +25,28 @@ class HelpCommand(BaseCommand): description = "Shows commands. Use 'help ' for details." category = "basic" + def __init__(self, bot): + """Initialize the help command. + + Args: + bot: The bot instance. + """ + super().__init__(bot) + self.help_enabled = self.get_config_value('Help_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.help_enabled: + return False + return super().can_execute(message) + def get_help_text(self) -> str: """Get help text for the help command. diff --git a/modules/commands/hfcond_command.py b/modules/commands/hfcond_command.py index 9c2b942..94d1afc 100644 --- a/modules/commands/hfcond_command.py +++ b/modules/commands/hfcond_command.py @@ -29,6 +29,20 @@ class HfcondCommand(BaseCommand): bot: The MeshCoreBot instance. """ super().__init__(bot) + self.hfcond_enabled = self.get_config_value('Hfcond_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.hfcond_enabled: + return False + return super().can_execute(message) async def execute(self, message: MeshMessage) -> bool: """Execute the hfcond command. diff --git a/modules/commands/magic8_command.py b/modules/commands/magic8_command.py index 0b9fbac..97a884f 100644 --- a/modules/commands/magic8_command.py +++ b/modules/commands/magic8_command.py @@ -27,6 +27,28 @@ class Magic8Command(BaseCommand): description = "Emulates the classic Magic 8-ball toy'" category = "games" + def __init__(self, bot): + """Initialize the magic8 command. + + Args: + bot: The bot instance. + """ + super().__init__(bot) + self.magic8_enabled = self.get_config_value('Magic8_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.magic8_enabled: + return False + return super().can_execute(message) + def get_help_text(self) -> str: """Get help text for the magic8 command. diff --git a/modules/commands/moon_command.py b/modules/commands/moon_command.py index fcce79f..6498c47 100644 --- a/modules/commands/moon_command.py +++ b/modules/commands/moon_command.py @@ -24,6 +24,20 @@ class MoonCommand(BaseCommand): bot: The bot instance. """ super().__init__(bot) + self.moon_enabled = self.get_config_value('Moon_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.moon_enabled: + return False + return super().can_execute(message) async def execute(self, message: MeshMessage) -> bool: """Execute the moon command. diff --git a/modules/commands/multitest_command.py b/modules/commands/multitest_command.py index c47f5bf..543e829 100644 --- a/modules/commands/multitest_command.py +++ b/modules/commands/multitest_command.py @@ -23,6 +23,7 @@ class MultitestCommand(BaseCommand): def __init__(self, bot): super().__init__(bot) + self.multitest_enabled = self.get_config_value('Multitest_Command', 'enabled', fallback=True, value_type='bool') self.listening = False self.collected_paths: Set[str] = set() self.listening_start_time = 0 @@ -31,6 +32,19 @@ class MultitestCommand(BaseCommand): self.triggering_timestamp: float = 0.0 # Timestamp of the triggering message self._load_config() + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.multitest_enabled: + return False + return super().can_execute(message) + def _load_config(self): """Load configuration for multitest command""" response_format = self.get_config_value('Multitest_Command', 'response_format', fallback='') diff --git a/modules/commands/path_command.py b/modules/commands/path_command.py index cf11161..5765a4f 100644 --- a/modules/commands/path_command.py +++ b/modules/commands/path_command.py @@ -26,6 +26,7 @@ class PathCommand(BaseCommand): def __init__(self, bot): super().__init__(bot) + self.path_enabled = self.get_config_value('Path_Command', 'enabled', fallback=True, value_type='bool') # Get bot location from config for geographic proximity calculations # Check if geographic guessing is enabled (bot has location configured) self.geographic_guessing_enabled = False @@ -85,6 +86,19 @@ class PathCommand(BaseCommand): except Exception as e: self.logger.warning(f"Error reading bot location from config: {e} - geographic proximity guessing disabled") + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.path_enabled: + return False + return super().can_execute(message) + def matches_keyword(self, message: MeshMessage) -> bool: """Check if message starts with 'path' keyword or 'p' shortcut (if enabled)""" content = message.content.strip() diff --git a/modules/commands/ping_command.py b/modules/commands/ping_command.py index bd6626a..7b0e11f 100644 --- a/modules/commands/ping_command.py +++ b/modules/commands/ping_command.py @@ -22,6 +22,28 @@ class PingCommand(BaseCommand): description = "Responds to 'ping' with 'Pong!'" category = "basic" + def __init__(self, bot): + """Initialize the ping command. + + Args: + bot: The bot instance. + """ + super().__init__(bot) + self.ping_enabled = self.get_config_value('Ping_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.ping_enabled: + return False + return super().can_execute(message) + def get_help_text(self) -> str: """Get help text for the ping command. diff --git a/modules/commands/prefix_command.py b/modules/commands/prefix_command.py index 0d62116..907dc12 100644 --- a/modules/commands/prefix_command.py +++ b/modules/commands/prefix_command.py @@ -34,6 +34,7 @@ class PrefixCommand(BaseCommand): bot: The bot instance. """ super().__init__(bot) + self.prefix_enabled = self.get_config_value('Prefix_Command', 'enabled', fallback=True, value_type='bool') # Get API URL from config, no fallback to regional API self.api_url = self.bot.config.get('External_Data', 'repeater_prefix_api_url', fallback="") @@ -67,6 +68,19 @@ class PrefixCommand(BaseCommand): self.max_prefix_range > 0 ) + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.prefix_enabled: + return False + return super().can_execute(message) + def get_help_text(self) -> str: """Get help text for the prefix command. diff --git a/modules/commands/repeater_command.py b/modules/commands/repeater_command.py index 75e5895..51b8bcc 100644 --- a/modules/commands/repeater_command.py +++ b/modules/commands/repeater_command.py @@ -32,6 +32,20 @@ class RepeaterCommand(BaseCommand): def __init__(self, bot): super().__init__(bot) + self.repeater_enabled = self.get_config_value('Repeater_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.repeater_enabled: + return False + return super().can_execute(message) def _truncate_for_lora(self, message: str, max_size: int = None) -> str: """Truncate message to fit within LoRa size limits. diff --git a/modules/commands/roll_command.py b/modules/commands/roll_command.py index 08adb7e..7c98f74 100644 --- a/modules/commands/roll_command.py +++ b/modules/commands/roll_command.py @@ -24,6 +24,28 @@ class RollCommand(BaseCommand): description = "Roll a random number between 1 and X (default 100). Use 'roll' for 1-100, 'roll 50' for 1-50, etc." category = "games" + def __init__(self, bot): + """Initialize the roll command. + + Args: + bot: The bot instance. + """ + super().__init__(bot) + self.roll_enabled = self.get_config_value('Roll_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.roll_enabled: + return False + return super().can_execute(message) + def get_help_text(self) -> str: """Get help text for the roll command. diff --git a/modules/commands/satpass_command.py b/modules/commands/satpass_command.py index 5ea3086..1a4c202 100644 --- a/modules/commands/satpass_command.py +++ b/modules/commands/satpass_command.py @@ -35,6 +35,20 @@ class SatpassCommand(BaseCommand): bot: The bot instance. """ super().__init__(bot) + self.satpass_enabled = self.get_config_value('Satpass_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.satpass_enabled: + return False + return super().can_execute(message) async def execute(self, message: MeshMessage) -> bool: """Execute the satpass command. diff --git a/modules/commands/solar_command.py b/modules/commands/solar_command.py index 01a7092..598db75 100644 --- a/modules/commands/solar_command.py +++ b/modules/commands/solar_command.py @@ -29,6 +29,20 @@ class SolarCommand(BaseCommand): bot: The MeshCoreBot instance. """ super().__init__(bot) + self.solar_enabled = self.get_config_value('Solar_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.solar_enabled: + return False + return super().can_execute(message) async def execute(self, message: MeshMessage) -> bool: """Execute the solar command. diff --git a/modules/commands/solarforecast_command.py b/modules/commands/solarforecast_command.py index aa83ca7..dae12ef 100644 --- a/modules/commands/solarforecast_command.py +++ b/modules/commands/solarforecast_command.py @@ -41,6 +41,7 @@ class SolarforecastCommand(BaseCommand): def __init__(self, bot): super().__init__(bot) + self.solarforecast_enabled = self.get_config_value('Solarforecast_Command', 'enabled', fallback=True, value_type='bool') self.url_timeout = 15 # seconds # Forecast cache: {cache_key: {'data': dict, 'timestamp': float}} @@ -55,6 +56,19 @@ class SolarforecastCommand(BaseCommand): # Get database manager for geocoding cache self.db_manager = bot.db_manager + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.solarforecast_enabled: + return False + return super().can_execute(message) + def get_help_text(self) -> str: return self.translate('commands.solarforecast.usage') diff --git a/modules/commands/sun_command.py b/modules/commands/sun_command.py index 1760049..07ffbd4 100644 --- a/modules/commands/sun_command.py +++ b/modules/commands/sun_command.py @@ -28,6 +28,20 @@ class SunCommand(BaseCommand): bot: The MeshCoreBot instance. """ super().__init__(bot) + self.sun_enabled = self.get_config_value('Sun_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.sun_enabled: + return False + return super().can_execute(message) async def execute(self, message: MeshMessage) -> bool: """Execute the sun command. diff --git a/modules/commands/test_command.py b/modules/commands/test_command.py index 041b3de..5ca7f1c 100644 --- a/modules/commands/test_command.py +++ b/modules/commands/test_command.py @@ -28,6 +28,7 @@ class TestCommand(BaseCommand): def __init__(self, bot): super().__init__(bot) + self.test_enabled = self.get_config_value('Test_Command', 'enabled', fallback=True, value_type='bool') # Get bot location from config for geographic proximity calculations self.geographic_guessing_enabled = False self.bot_latitude = None @@ -56,6 +57,19 @@ class TestCommand(BaseCommand): except Exception as e: self.logger.warning(f"Error reading bot location from config: {e}") + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.test_enabled: + return False + return super().can_execute(message) + def get_help_text(self) -> str: """Get help text for the command. diff --git a/modules/commands/webviewer_command.py b/modules/commands/webviewer_command.py index 290ca3e..57ab995 100644 --- a/modules/commands/webviewer_command.py +++ b/modules/commands/webviewer_command.py @@ -26,6 +26,20 @@ class WebViewerCommand(BaseCommand): bot: The bot instance. """ super().__init__(bot) + self.webviewer_enabled = self.get_config_value('WebViewer_Command', 'enabled', fallback=True, value_type='bool') + + def can_execute(self, message: MeshMessage) -> bool: + """Check if this command can be executed with the given message. + + Args: + message: The message triggering the command. + + Returns: + bool: True if command is enabled and checks pass, False otherwise. + """ + if not self.webviewer_enabled: + return False + return super().can_execute(message) def get_help_text(self) -> str: """Get help text for the webviewer command. diff --git a/modules/commands/wx_command.py b/modules/commands/wx_command.py index eb7dae0..f06c27d 100644 --- a/modules/commands/wx_command.py +++ b/modules/commands/wx_command.py @@ -44,6 +44,7 @@ class WxCommand(BaseCommand): def __init__(self, bot): super().__init__(bot) + self.wx_enabled = self.get_config_value('Wx_Command', 'enabled', fallback=True, value_type='bool') # Check weather provider setting - delegate to international command if using Open-Meteo weather_provider = bot.config.get('Weather', 'weather_provider', fallback='noaa').lower() @@ -129,6 +130,10 @@ class WxCommand(BaseCommand): def can_execute(self, message: MeshMessage) -> bool: """Override to delegate or use base class cooldown""" + # Check if wx command is enabled + if not self.wx_enabled: + return False + if self.delegate_command: return self.delegate_command.can_execute(message)