diff --git a/build/synctastic.js b/build/synctastic.js
index c87c019b5254a461a181fbda18c4ab739a549b11..d1174d9d024fdbf7e384f94bdd4879c56ac4aa8c 100644
--- a/build/synctastic.js
+++ b/build/synctastic.js
@@ -19997,12 +19997,61 @@
         }
       }]);
     }();
-    var Echo = /* @__PURE__ */ function(_Module) {
+    var Help = /* @__PURE__ */ function(_Module) {
+      function Help2(config, device, modules) {
+        var _this4;
+        _classCallCheck(this, Help2);
+        _this4 = _callSuper(this, Help2, [config, device]);
+        _this4.modules = modules;
+        return _this4;
+      }
+      _inherits(Help2, _Module);
+      return _createClass(Help2, [{
+        key: "handlePacket",
+        value: function handlePacket(packet, replyTo) {
+          var _a;
+          if (packet.payloadVariant["case"] !== "decoded")
+            return false;
+          var dec = new TextDecoder();
+          var msg = dec.decode(packet.payloadVariant.value.payload);
+          var cmd = msg.split(" ");
+          if (cmd[0] !== ".h" && cmd[0] !== ".help")
+            return false;
+          var hopLimit = (_a = this.config.hopLimit) != null ? _a : void 0;
+          var text = "".concat(js.global.system.name, " available commands:\r\n");
+          var _iterator28 = _createForOfIteratorHelper(this.modules), _step28;
+          try {
+            for (_iterator28.s(); !(_step28 = _iterator28.n()).done; ) {
+              var module = _step28.value;
+              text += "\r\n".concat(module.getHelp(true));
+            }
+          } catch (err) {
+            _iterator28.e(err);
+          } finally {
+            _iterator28.f();
+          }
+          this.device.sendText({
+            text: text,
+            to: replyTo,
+            channel: packet.channel,
+            replyId: packet.id,
+            hopLimit: hopLimit
+          });
+          return true;
+        }
+      }, {
+        key: "getHelp",
+        value: function getHelp(_short) {
+          return ".h, .help - This help message";
+        }
+      }]);
+    }(Module);
+    var Echo = /* @__PURE__ */ function(_Module2) {
       function Echo2(config, device) {
         _classCallCheck(this, Echo2);
         return _callSuper(this, Echo2, [config, device]);
       }
-      _inherits(Echo2, _Module);
+      _inherits(Echo2, _Module2);
       return _createClass(Echo2, [{
         key: "handlePacket",
         value: function handlePacket(packet, replyTo) {
@@ -20024,6 +20073,14 @@
           });
           return true;
         }
+      }, {
+        key: "getHelp",
+        value: function getHelp(_short2) {
+          if (_short2) {
+            return ".echo help";
+          }
+          return "The Echo module echoes your message back to you.\r\nCommand: .echo <your message>";
+        }
       }]);
     }(Module);
     function uvEmoji(uvi) {
@@ -20037,29 +20094,29 @@
         return "\uD83D\uDD34";
       return "\uD83D\uDFE3";
     }
-    var Weather = /* @__PURE__ */ function(_Module2) {
+    var Weather = /* @__PURE__ */ function(_Module3) {
       function Weather2(config, device) {
-        var _this4;
+        var _this5;
         _classCallCheck(this, Weather2);
         var _a;
-        _this4 = _callSuper(this, Weather2, [config, device]);
+        _this5 = _callSuper(this, Weather2, [config, device]);
         var wc = config;
-        _this4.units = "metric";
+        _this5.units = "metric";
         if (typeof wc.units === "string") {
           if (wc.units === "standard" || wc.units === "metric" || wc.units === "imperial") {
-            _this4.units = wc.units;
+            _this5.units = wc.units;
           } else {
-            _this4.error("invalid 'units' setting '".concat(wc.units, "'"));
+            _this5.error("invalid 'units' setting '".concat(wc.units, "'"));
           }
         }
-        _this4.alertRebroadcast = (_a = wc.alertRebroadcast) != null ? _a : false;
+        _this5.alertRebroadcast = (_a = wc.alertRebroadcast) != null ? _a : false;
         if (typeof wc.alertInterval === "number" && wc.alertInterval > 0) {
-          js.setInterval(_this4.broadcastAlerts, wc.alertInterval, _this4);
-          _this4.device.on("ready", _this4.broadcastAlerts.bind(_this4));
+          js.setInterval(_this5.broadcastAlerts, wc.alertInterval, _this5);
+          _this5.device.on("ready", _this5.broadcastAlerts.bind(_this5));
         }
-        return _this4;
+        return _this5;
       }
-      _inherits(Weather2, _Module2);
+      _inherits(Weather2, _Module3);
       return _createClass(Weather2, [{
         key: "getCurrentWeather",
         value: function getCurrentWeather(lat, lon) {
@@ -20099,10 +20156,10 @@
           if (data.alerts === void 0)
             return;
           var ws = "";
-          var _iterator28 = _createForOfIteratorHelper(data.alerts), _step28;
+          var _iterator29 = _createForOfIteratorHelper(data.alerts), _step29;
           try {
-            for (_iterator28.s(); !(_step28 = _iterator28.n()).done; ) {
-              var alert = _step28.value;
+            for (_iterator29.s(); !(_step29 = _iterator29.n()).done; ) {
+              var alert = _step29.value;
               if (alert.end < js.global.time())
                 continue;
               ws += "Weather alert from ".concat(alert.sender_name);
@@ -20111,9 +20168,9 @@
               ws += "\r\n\r\n".concat(alert.description);
             }
           } catch (err) {
-            _iterator28.e(err);
+            _iterator29.e(err);
           } finally {
-            _iterator28.f();
+            _iterator29.f();
           }
           return ws === "" ? void 0 : ws;
         }
@@ -20168,12 +20225,20 @@
             return;
           if (!this.alertRebroadcast && !this.canBroadcastAlert(wa))
             return;
-          for (var c = 0; c < this.config.channels.length; c++) {
-            this.device.sendText({
-              text: wa,
-              channel: this.config.channels[c],
-              hopLimit: this.config.hopLimit
-            });
+          var _iterator30 = _createForOfIteratorHelper(this.config.channels), _step30;
+          try {
+            for (_iterator30.s(); !(_step30 = _iterator30.n()).done; ) {
+              var channel = _step30.value;
+              this.device.sendText({
+                text: wa,
+                channel: channel,
+                hopLimit: this.config.hopLimit
+              });
+            }
+          } catch (err) {
+            _iterator30.e(err);
+          } finally {
+            _iterator30.f();
           }
         }
       }, {
@@ -20183,7 +20248,8 @@
             return false;
           var dec = new TextDecoder();
           var msg = dec.decode(packet.payloadVariant.value.payload);
-          if (!msg.startsWith(".wx"))
+          var cmd = msg.split(" ");
+          if (cmd[0] !== ".w" && cmd[0] !== ".wx" && cmd[0] !== ".weather")
             return false;
           try {
             var nodeInfo = this.device.getNodeInfo(packet.from);
@@ -20199,7 +20265,7 @@
             var lat = nodeInfo.position.latitudeI * 1e-7;
             var lon = nodeInfo.position.longitudeI * 1e-7;
             var ws;
-            switch (msg.split(" ")[1]) {
+            switch (cmd[1]) {
               case "a":
               case "alert":
               case "alerts":
@@ -20207,6 +20273,12 @@
                 if (ws === void 0)
                   ws = "There are no weather alerts at this time.";
                 break;
+              case "h":
+              case "help":
+                ws = this.getHelp(false);
+                break;
+              case "c":
+              case "current":
               default:
                 ws = this.getCurrentWeather(lat, lon);
                 break;
@@ -20226,6 +20298,18 @@
           }
           return false;
         }
+      }, {
+        key: "getHelp",
+        value: function getHelp(_short3) {
+          if (_short3) {
+            return ".weather help";
+          }
+          var hs = "The Weather module provides current weather information and alerts.";
+          hs += "\r\nCommands:";
+          hs += "\r\nCurrent weather: .w c";
+          hs += "\r\nAlerts: .w a";
+          return hs;
+        }
       }]);
     }(Module);
     function init() {
@@ -20257,6 +20341,8 @@
             return;
           for (var _i17 = 0, _modules = modules; _i17 < _modules.length; _i17++) {
             var _module = _modules[_i17];
+            if (!_module.config.enabled)
+              continue;
             if (_module.config.device !== dev.configId)
               continue;
             if (_module.config.channels.indexOf(packet.channel) < 0)
@@ -20292,6 +20378,9 @@
           case "weather":
             modules.push(new Weather(config.modules[module], devices[config.modules[module].device]));
             break;
+          case "help":
+            modules.push(new Help(config.modules[module], devices[config.modules[module].device], modules));
+            break;
           default:
             var m = js.global.load({}, config.modules[module].path);
             modules.push(new m(config.modules[module], devices[config.modules[module].device]));
diff --git a/src/lib/module.ts b/src/lib/module.ts
index d66dfeb16d54b4fc0310951a829fdcbb5c27d398..83fbacf5b3c5e1e97c020f2fac2afacc096499c7 100644
--- a/src/lib/module.ts
+++ b/src/lib/module.ts
@@ -13,6 +13,8 @@ export default abstract class Module {
 
 	abstract handlePacket(packet: protobuf.Mesh.MeshPacket, replyTo: number): boolean; // 'true' if handled
 
+	abstract getHelp(short: boolean): string;
+
 	log(level: number, msg: string): void {
 		js.global.log(level, `${this.config.name}: ${msg}`);
 	}
diff --git a/src/modules/echo.ts b/src/modules/echo.ts
index ca3159142b6476266ddc5d12ba37503af247b672..bcc4b93cd07f5ea0f871dbdff25b40e68537955b 100644
--- a/src/modules/echo.ts
+++ b/src/modules/echo.ts
@@ -20,4 +20,11 @@ export default class Echo extends Module {
 		return true;
 	}
 
+	getHelp(short: boolean): string {
+		if (short) {
+			return '.echo help';
+		}
+		return 'Echo module: .echo <your message>';
+	}
+
 }
\ No newline at end of file
diff --git a/src/modules/weather.ts b/src/modules/weather.ts
index 4eabb6801e0cff4c531b183fe964aee3ff3d4ef9..a59a550cd2d3ee16fd36548ed16e7ff4ab783d9c 100644
--- a/src/modules/weather.ts
+++ b/src/modules/weather.ts
@@ -132,7 +132,8 @@ export default class Weather extends Module {
 		// @ts-expect-error It's ambient
 		const dec = new TextDecoder();
 		const msg = dec.decode(packet.payloadVariant.value.payload);
-		if (!msg.startsWith('.wx')) return false;
+		const cmd = msg.split(' ');
+		if (cmd[0] !== '.w' && cmd[0] !== '.wx' && cmd[0] !== '.weather') return false;
 
 		try {
 			let nodeInfo = this.device.getNodeInfo(packet.from);
@@ -149,13 +150,19 @@ export default class Weather extends Module {
 			const lon = nodeInfo.position.longitudeI * .0000001;
 
 			let ws: string | undefined;
-			switch (msg.split(' ')[1]) {
+			switch (cmd[1]) {
 				case 'a':
 				case 'alert':
 				case 'alerts':
 					ws = this.getCurrentAlerts(lat, lon);
 					if (ws === undefined) ws = 'There are no weather alerts at this time.';
 					break;
+				case 'h':
+				case 'help':
+					ws = this.getHelp(false);
+					break;
+				case 'c':
+				case 'current':
 				default:
 					ws = this.getCurrentWeather(lat, lon);
 					break;
@@ -171,4 +178,14 @@ export default class Weather extends Module {
 		return false;
 	}
 
+	getHelp(short: boolean): string {
+		if (short) {
+			return '.weather help';
+		}
+		let hs: string = 'Weather module commands:\r\n';
+		hs += '\r\nCurrent weather: .w';
+		hs += '\r\nAlerts: .w a';
+		return hs;
+	}
+
 }
\ No newline at end of file
diff --git a/src/synctastic.ts b/src/synctastic.ts
index cf45f5c93293091d3c2f56509a6b79254af10a3c..bffa7cda863ccbaa02ca699d4f8eba128ad85b8e 100644
--- a/src/synctastic.ts
+++ b/src/synctastic.ts
@@ -2,6 +2,7 @@ import { sbbsdefs } from '@swag/ts4s';
 import { Device, SerialDevice, SocketDevice, defs, protobuf } from '@sota/meshtastic';
 import { default as getConfig, IServerConfig, ISerialDeviceConfig, ISocketDeviceConfig } from './lib/config';
 import Module from './lib/module';
+import Help from './modules/help';
 import Echo from './modules/echo';
 import Weather from './modules/weather';
 
@@ -32,6 +33,7 @@ function init(): void {
 		dev.on('packet', (packet: protobuf.Mesh.MeshPacket) => {
 			if (dev === undefined) return;
 			for (const module of modules) {
+				if (!module.config.enabled) continue;
 				if (module.config.device !== dev.configId) continue;
 				if (module.config.channels.indexOf(packet.channel) < 0) continue;
 				if (packet.payloadVariant.case !== 'decoded') continue;
@@ -64,6 +66,9 @@ function init(): void {
 			case 'weather':
 				modules.push(new Weather(config.modules[module], devices[config.modules[module].device]));
 				break;
+			case 'help':
+				modules.push(new Help(config.modules[module], devices[config.modules[module].device], modules));
+				break;
 			default:
 				const m = js.global.load({}, config.modules[module].path);
 				modules.push(new m(config.modules[module], devices[config.modules[module].device]));