Skip to content
Snippets Groups Projects
Commit 5c31c830 authored by echicken's avatar echicken :chicken:
Browse files

One-to-one module:device config mapping.

parent e465703e
No related branches found
No related tags found
No related merge requests found
...@@ -21,34 +21,39 @@ port = 4403 ...@@ -21,34 +21,39 @@ port = 4403
[module_echo] [module_echo]
name = Echo name = Echo
path = echo path = echo
devices = 0 device = 0
channel = 0 channel = 0
port = 1 port = 1
enabled = true enabled = true
debug = false debug = false
reply = same reply = same
hopLimit = 0
[module_weather] [module_weather]
name = Weather name = Weather
path = weather path = weather
devices = 0 device = 0
channel = 0 channel = 0
port = 1 port = 1
enabled = true enabled = true
debug = false debug = false
reply = same reply = same
hopLimit = 0
``` ```
Device section names must begin with `device_`, module section names must begin with `module_`, but the rest of the name is arbitrary. Device section names must begin with `device_`, module section names must begin with `module_`, but the rest of the name is arbitrary.
If you want to use the same module with multiple devices, you'll need to create a module configuration for each device.
In module config: In module config:
- `path` is either a magic word for one of the built-in modules, or the path to an external Synchronet JavaScript module (.js file). - `path` is either a magic word for one of the built-in modules, or the path to an external Synchronet JavaScript module (.js file).
- `devices` can be a single number or a comma-separated list of device IDs (which must match the `id` field for a `[device_*]` above) - `device` must match the `id` of one of `device_*`
- `port` is a Meshtastic [port number](https://buf.build/meshtastic/protobufs/docs/main:meshtastic#meshtastic.PortNum) for this module to listen on - `port` is a Meshtastic [port number](https://buf.build/meshtastic/protobufs/docs/main:meshtastic#meshtastic.PortNum) for this module to listen on
- `reply` is one of `same` (default), `direct`, or `broadcast` - `reply` is one of `same` (default), `direct`, or `broadcast`
- `same` means that if the module receives a direct message, it will respond in a direct message, and if it receives the command in a broadcast message, it will respond with a broadcast message - `same` means that if the module receives a direct message, it will respond in a direct message, and if it receives the command in a broadcast message, it will respond with a broadcast message
- `direct` means that regardless of how the original message was addressed, the response will be sent in a direct message - `direct` means that regardless of how the original message was addressed, the response will be sent in a direct message
- `broadcast` means that regardless of how the original message was addressed, the response will be sent in a broadcast message - `broadcast` means that regardless of how the original message was addressed, the response will be sent in a broadcast message
- `hopLimit` specifies the number of hops you want messages from this module to make on the mesh network ([see here for more info](https://meshtastic.org/docs/overview/mesh-algo/))
## Operation ## Operation
......
...@@ -3232,31 +3232,6 @@ ...@@ -3232,31 +3232,6 @@
} }
}); });
   
// node_modules/core-js/internals/array-for-each.js
var require_array_for_each = __commonJS({
"node_modules/core-js/internals/array-for-each.js": function(exports, module) {
"use strict";
var $forEach = require_array_iteration().forEach;
var arrayMethodIsStrict = require_array_method_is_strict();
var STRICT_METHOD = arrayMethodIsStrict("forEach");
module.exports = !STRICT_METHOD ? function forEach(callbackfn) {
return $forEach(this, callbackfn, arguments.length > 1 ? arguments[1] : void 0);
} : [].forEach;
}
});
// node_modules/core-js/modules/es.array.for-each.js
var require_es_array_for_each = __commonJS({
"node_modules/core-js/modules/es.array.for-each.js": function() {
"use strict";
var $ = require_export();
var forEach = require_array_for_each();
$({ target: "Array", proto: true, forced: [].forEach !== forEach }, {
forEach: forEach
});
}
});
// node_modules/core-js/modules/es.array.index-of.js // node_modules/core-js/modules/es.array.index-of.js
var require_es_array_index_of = __commonJS({ var require_es_array_index_of = __commonJS({
"node_modules/core-js/modules/es.array.index-of.js": function() { "node_modules/core-js/modules/es.array.index-of.js": function() {
...@@ -5428,7 +5403,7 @@ ...@@ -5428,7 +5403,7 @@
"use strict"; "use strict";
var $ = require_export(); var $ = require_export();
$({ target: "Number", stat: true }, { $({ target: "Number", stat: true }, {
isNaN: function isNaN2(number) { isNaN: function isNaN(number) {
return number !== number; return number !== number;
} }
}); });
...@@ -9281,33 +9256,6 @@ ...@@ -9281,33 +9256,6 @@
} }
}); });
   
// node_modules/core-js/modules/web.dom-collections.for-each.js
var require_web_dom_collections_for_each = __commonJS({
"node_modules/core-js/modules/web.dom-collections.for-each.js": function() {
"use strict";
var global2 = require_global();
var DOMIterables = require_dom_iterables();
var DOMTokenListPrototype = require_dom_token_list_prototype();
var forEach = require_array_for_each();
var createNonEnumerableProperty = require_create_non_enumerable_property();
var handlePrototype = function(CollectionPrototype) {
if (CollectionPrototype && CollectionPrototype.forEach !== forEach)
try {
createNonEnumerableProperty(CollectionPrototype, "forEach", forEach);
} catch (error) {
CollectionPrototype.forEach = forEach;
}
};
for (COLLECTION_NAME in DOMIterables) {
if (DOMIterables[COLLECTION_NAME]) {
handlePrototype(global2[COLLECTION_NAME] && global2[COLLECTION_NAME].prototype);
}
}
var COLLECTION_NAME;
handlePrototype(DOMTokenListPrototype);
}
});
// node_modules/core-js/modules/web.dom-collections.iterator.js // node_modules/core-js/modules/web.dom-collections.iterator.js
var require_web_dom_collections_iterator = __commonJS({ var require_web_dom_collections_iterator = __commonJS({
"node_modules/core-js/modules/web.dom-collections.iterator.js": function() { "node_modules/core-js/modules/web.dom-collections.iterator.js": function() {
...@@ -9407,7 +9355,6 @@ ...@@ -9407,7 +9355,6 @@
require_es_array_filter(); require_es_array_filter();
require_es_array_find(); require_es_array_find();
require_es_array_find_index(); require_es_array_find_index();
require_es_array_for_each();
require_es_array_index_of(); require_es_array_index_of();
require_es_array_is_array(); require_es_array_is_array();
require_es_array_iterator(); require_es_array_iterator();
...@@ -9506,7 +9453,6 @@ ...@@ -9506,7 +9453,6 @@
require_esnext_typed_array_to_reversed(); require_esnext_typed_array_to_reversed();
require_esnext_typed_array_to_sorted(); require_esnext_typed_array_to_sorted();
require_esnext_typed_array_with(); require_esnext_typed_array_with();
require_web_dom_collections_for_each();
require_web_dom_collections_iterator(); require_web_dom_collections_iterator();
require_web_self(); require_web_self();
function _callSuper(t, o, e) { function _callSuper(t, o, e) {
...@@ -19976,23 +19922,12 @@ ...@@ -19976,23 +19922,12 @@
} else if (typeof config.reply !== "string" || config.reply !== "same" && config.reply !== "direct" && config.reply !== "broadcast") { } else if (typeof config.reply !== "string" || config.reply !== "same" && config.reply !== "direct" && config.reply !== "broadcast") {
throw new Error("Invalid 'reply' setting for module ".concat(config.name)); throw new Error("Invalid 'reply' setting for module ".concat(config.name));
} }
var devices = []; if (typeof config.device !== "number")
if (typeof config.devices !== "number") { throw new Error("Invalid device ".concat(config.device, " for module ").concat(config.name));
if (typeof config.devices !== "string")
throw new Error("Invalid device list ".concat(config.devices, " for module ").concat(config.name));
config.devices.split(",").forEach(function(e) {
var n = parseInt(e, 10);
if (isNaN(n))
throw new Error("Invalid device id ".concat(e, " for module ").concat(config.name));
devices.push(n);
});
} else {
devices.push(config.devices);
}
var ret = __spreadProps(__spreadValues({}, config), { var ret = __spreadProps(__spreadValues({}, config), {
name: config.name, name: config.name,
path: config.path, path: config.path,
devices: devices, device: config.device,
channel: config.channel, channel: config.channel,
port: config.port, port: config.port,
enabled: config.enabled, enabled: config.enabled,
...@@ -20041,10 +19976,10 @@ ...@@ -20041,10 +19976,10 @@
}; };
} }
var Module = /* @__PURE__ */ function() { var Module = /* @__PURE__ */ function() {
function Module2(config, devices) { function Module2(config, device) {
_classCallCheck(this, Module2); _classCallCheck(this, Module2);
this.config = config; this.config = config;
this.devices = devices; this.device = device;
} }
return _createClass(Module2, [{ return _createClass(Module2, [{
key: "log", key: "log",
...@@ -20059,14 +19994,14 @@ ...@@ -20059,14 +19994,14 @@
}]); }]);
}(); }();
var Echo = /* @__PURE__ */ function(_Module) { var Echo = /* @__PURE__ */ function(_Module) {
function Echo2(config, devices) { function Echo2(config, device) {
_classCallCheck(this, Echo2); _classCallCheck(this, Echo2);
return _callSuper(this, Echo2, [config, devices]); return _callSuper(this, Echo2, [config, device]);
} }
_inherits(Echo2, _Module); _inherits(Echo2, _Module);
return _createClass(Echo2, [{ return _createClass(Echo2, [{
key: "handlePacket", key: "handlePacket",
value: function handlePacket(packet, device, replyTo) { value: function handlePacket(packet, replyTo) {
var _a; var _a;
if (packet.payloadVariant["case"] !== "decoded") if (packet.payloadVariant["case"] !== "decoded")
return false; return false;
...@@ -20076,7 +20011,7 @@ ...@@ -20076,7 +20011,7 @@
return false; return false;
var echo = "You sent: ".concat(msg.replace(/^.echo\s/, "")); var echo = "You sent: ".concat(msg.replace(/^.echo\s/, ""));
var hopLimit = (_a = this.config.hopLimit) != null ? _a : void 0; var hopLimit = (_a = this.config.hopLimit) != null ? _a : void 0;
device.sendText({ this.device.sendText({
text: echo, text: echo,
to: replyTo, to: replyTo,
channel: packet.channel, channel: packet.channel,
...@@ -20099,11 +20034,11 @@ ...@@ -20099,11 +20034,11 @@
return "\uD83D\uDFE3"; return "\uD83D\uDFE3";
} }
var Weather = /* @__PURE__ */ function(_Module2) { var Weather = /* @__PURE__ */ function(_Module2) {
function Weather2(config, devices) { function Weather2(config, device) {
var _this4; var _this4;
_classCallCheck(this, Weather2); _classCallCheck(this, Weather2);
var _a; var _a;
_this4 = _callSuper(this, Weather2, [config, devices]); _this4 = _callSuper(this, Weather2, [config, device]);
var wc = config; var wc = config;
_this4.units = "metric"; _this4.units = "metric";
if (typeof wc.units === "string") { if (typeof wc.units === "string") {
...@@ -20115,21 +20050,8 @@ ...@@ -20115,21 +20050,8 @@
} }
_this4.alertRebroadcast = (_a = wc.alertRebroadcast) != null ? _a : false; _this4.alertRebroadcast = (_a = wc.alertRebroadcast) != null ? _a : false;
if (typeof wc.alertInterval === "number" && wc.alertInterval > 0) { if (typeof wc.alertInterval === "number" && wc.alertInterval > 0) {
var alertBroadcastInterval2 = function alertBroadcastInterval22() { js.setInterval(_this4.broadcastAlerts, wc.alertInterval, _this4);
for (var d2 = 0; d2 < this.devices.length; d2++) { _this4.device.on("ready", _this4.broadcastAlerts.bind(_this4));
this.broadcastAlerts(this.devices[d2], this.config.channel, this.config.hopLimit);
}
};
var alertBroadcastInterval = alertBroadcastInterval2;
js.setInterval(alertBroadcastInterval2, wc.alertInterval, _this4);
var _loop3 = function _loop32(d2) {
_this4.devices[d2].on("ready", function() {
_this4.broadcastAlerts(_this4.devices[d2], _this4.config.channel, _this4.config.hopLimit);
});
};
for (var d = 0; d < _this4.devices.length; d++) {
_loop3(d);
}
} }
return _this4; return _this4;
} }
...@@ -20193,10 +20115,10 @@ ...@@ -20193,10 +20115,10 @@
} }
}, { }, {
key: "canBroadcastAlert", key: "canBroadcastAlert",
value: function canBroadcastAlert(wa, devId) { value: function canBroadcastAlert(wa) {
var ret = true; var ret = true;
var wah = js.global.md5_calc(wa); var wah = js.global.md5_calc(wa);
var wal = "".concat(Date.now(), ",").concat(devId, ",").concat(wah); var wal = "".concat(Date.now(), ",").concat(this.device.configId, ",").concat(wah);
var fn = "".concat(js.global.system.temp_dir, "synctastic-weather-alerts.txt"); var fn = "".concat(js.global.system.temp_dir, "synctastic-weather-alerts.txt");
var f = new js.global.File(fn); var f = new js.global.File(fn);
if (!f.exists) { if (!f.exists) {
...@@ -20209,7 +20131,7 @@ ...@@ -20209,7 +20131,7 @@
throw new Error("Failed to open ".concat(fn, " for reading")); throw new Error("Failed to open ".concat(fn, " for reading"));
while (!f.eof) { while (!f.eof) {
var l = f.readln().split(","); var l = f.readln().split(",");
if (parseInt(l[1], 10) !== devId) if (parseInt(l[1], 10) !== this.device.configId)
continue; continue;
if (l[2] !== wah) if (l[2] !== wah)
continue; continue;
...@@ -20228,8 +20150,8 @@ ...@@ -20228,8 +20150,8 @@
} }
}, { }, {
key: "broadcastAlerts", key: "broadcastAlerts",
value: function broadcastAlerts(device, channel, hopLimit) { value: function broadcastAlerts() {
var nodeInfo = device.getNodeInfo(device.myNodeInfo.myNodeNum); var nodeInfo = this.device.getNodeInfo(this.device.myNodeInfo.myNodeNum);
if ((nodeInfo == null ? void 0 : nodeInfo.position) === void 0) if ((nodeInfo == null ? void 0 : nodeInfo.position) === void 0)
return; return;
var lat = nodeInfo.position.latitudeI * 1e-7; var lat = nodeInfo.position.latitudeI * 1e-7;
...@@ -20237,17 +20159,17 @@ ...@@ -20237,17 +20159,17 @@
var wa = this.getCurrentAlerts(lat, lon); var wa = this.getCurrentAlerts(lat, lon);
if (wa === void 0) if (wa === void 0)
return; return;
if (!this.alertRebroadcast && !this.canBroadcastAlert(wa, device.configId)) if (!this.alertRebroadcast && !this.canBroadcastAlert(wa))
return; return;
device.sendText({ this.device.sendText({
text: wa, text: wa,
channel: channel, channel: this.config.channel,
hopLimit: hopLimit hopLimit: this.config.hopLimit
}); });
} }
}, { }, {
key: "handlePacket", key: "handlePacket",
value: function handlePacket(packet, device, replyTo) { value: function handlePacket(packet, replyTo) {
if (packet.payloadVariant["case"] !== "decoded") if (packet.payloadVariant["case"] !== "decoded")
return false; return false;
var dec = new TextDecoder(); var dec = new TextDecoder();
...@@ -20255,12 +20177,12 @@ ...@@ -20255,12 +20177,12 @@
if (!msg.startsWith(".wx")) if (!msg.startsWith(".wx"))
return false; return false;
try { try {
var nodeInfo = device.getNodeInfo(packet.from); var nodeInfo = this.device.getNodeInfo(packet.from);
if ((nodeInfo == null ? void 0 : nodeInfo.position) === void 0) { if ((nodeInfo == null ? void 0 : nodeInfo.position) === void 0) {
if (this.config.debug) { if (this.config.debug) {
this.log(sbbsdefs.LOG_DEBUG, "failed to find position for ".concat(packet.from, " in node DB. Falling back on self position")); this.log(sbbsdefs.LOG_DEBUG, "failed to find position for ".concat(packet.from, " in node DB. Falling back on self position"));
} }
nodeInfo = device.getNodeInfo(device.myNodeInfo.myNodeNum); nodeInfo = this.device.getNodeInfo(this.device.myNodeInfo.myNodeNum);
} }
if ((nodeInfo == null ? void 0 : nodeInfo.position) === void 0) { if ((nodeInfo == null ? void 0 : nodeInfo.position) === void 0) {
throw new Error("failed to find self position, cannot send lat/lon to weather API"); throw new Error("failed to find self position, cannot send lat/lon to weather API");
...@@ -20282,7 +20204,7 @@ ...@@ -20282,7 +20204,7 @@
} }
if (ws === void 0) if (ws === void 0)
return false; return false;
device.sendText({ this.device.sendText({
text: ws, text: ws,
to: replyTo, to: replyTo,
channel: packet.channel, channel: packet.channel,
...@@ -20301,7 +20223,7 @@ ...@@ -20301,7 +20223,7 @@
var config = getConfig(); var config = getConfig();
var devices = {}; var devices = {};
var modules = []; var modules = [];
var _loop4 = function _loop42() { var _loop3 = function _loop32() {
var dev = void 0; var dev = void 0;
if (config.devices[device].type === "serial") { if (config.devices[device].type === "serial") {
var cfg = config.devices[device]; var cfg = config.devices[device];
...@@ -20328,7 +20250,7 @@ ...@@ -20328,7 +20250,7 @@
var _module = _modules[_i17]; var _module = _modules[_i17];
if (_module.config.channel !== packet.channel) if (_module.config.channel !== packet.channel)
continue; continue;
if (_module.config.devices.indexOf(dev.configId) < 0) if (_module.config.device !== dev.configId)
continue; continue;
if (packet.to !== defs_exports.BROADCAST && packet.to !== dev.myNodeInfo.myNodeNum) if (packet.to !== defs_exports.BROADCAST && packet.to !== dev.myNodeInfo.myNodeNum)
continue; continue;
...@@ -20340,32 +20262,30 @@ ...@@ -20340,32 +20262,30 @@
if (_module.config.reply === "broadcast" || _module.config.reply === "same" && packet.to === defs_exports.BROADCAST) { if (_module.config.reply === "broadcast" || _module.config.reply === "same" && packet.to === defs_exports.BROADCAST) {
to = defs_exports.BROADCAST; to = defs_exports.BROADCAST;
} }
_module.handlePacket(packet, dev, to); _module.handlePacket(packet, to);
} }
}); });
dev.connect(); dev.connect();
devices[config.devices[device].id] = dev; devices[config.devices[device].id] = dev;
}; };
for (var device in config.devices) { for (var device in config.devices) {
if (_loop4()) if (_loop3())
continue; continue;
} }
for (var module in config.modules) { for (var module in config.modules) {
var devs = []; if (devices[config.modules[module].device] === void 0) {
for (var devId in config.modules[module].devices) { throw new Error("Invalid device specified for ".concat(config.modules[module].name));
if (devices[devId] !== void 0)
devs.push(devices[devId]);
} }
switch (config.modules[module].path) { switch (config.modules[module].path) {
case "echo": case "echo":
modules.push(new Echo(config.modules[module], devs)); modules.push(new Echo(config.modules[module], devices[config.modules[module].device]));
break; break;
case "weather": case "weather":
modules.push(new Weather(config.modules[module], devs)); modules.push(new Weather(config.modules[module], devices[config.modules[module].device]));
break; break;
default: default:
var m = js.global.load({}, config.modules[module].path); var m = js.global.load({}, config.modules[module].path);
modules.push(new m(config.modules[module])); modules.push(new m(config.modules[module], devices[config.modules[module].device]));
break; break;
} }
} }
......
...@@ -26,7 +26,7 @@ type ReplyType = 'same' | 'direct' | 'broadcast'; ...@@ -26,7 +26,7 @@ type ReplyType = 'same' | 'direct' | 'broadcast';
export interface IModuleConfig { export interface IModuleConfig {
name: string, name: string,
path: string, path: string,
devices: number[], device: number,
channel: number, channel: number,
port: number, port: number,
enabled: boolean, enabled: boolean,
...@@ -105,24 +105,13 @@ function parseModuleConfig(config: IniSection): IModuleConfig { ...@@ -105,24 +105,13 @@ function parseModuleConfig(config: IniSection): IModuleConfig {
} else if (typeof config.reply !== 'string' || (config.reply !== 'same' && config.reply !== 'direct' && config.reply !== 'broadcast')) { } else if (typeof config.reply !== 'string' || (config.reply !== 'same' && config.reply !== 'direct' && config.reply !== 'broadcast')) {
throw new Error(`Invalid 'reply' setting for module ${config.name}`); throw new Error(`Invalid 'reply' setting for module ${config.name}`);
} }
if (typeof config.device !== 'number') throw new Error(`Invalid device ${config.device} for module ${config.name}`);
const devices = [];
if (typeof config.devices !== 'number') {
if (typeof config.devices !== 'string') throw new Error(`Invalid device list ${config.devices} for module ${config.name}`);
config.devices.split(',').forEach(e => {
const n = parseInt(e, 10);
if (isNaN(n)) throw new Error(`Invalid device id ${e} for module ${config.name}`);
devices.push(n);
});
} else {
devices.push(config.devices);
}
const ret: IModuleConfig = { const ret: IModuleConfig = {
...config, ...config,
name: config.name, name: config.name,
path: config.path, path: config.path,
devices, device: config.device,
channel: config.channel, channel: config.channel,
port: config.port, port: config.port,
enabled: config.enabled, enabled: config.enabled,
......
...@@ -4,14 +4,14 @@ import { IModuleConfig } from './config'; ...@@ -4,14 +4,14 @@ import { IModuleConfig } from './config';
export default abstract class Module { export default abstract class Module {
config: IModuleConfig; config: IModuleConfig;
devices: Device[]; device: Device;
constructor(config: IModuleConfig, devices: Device[]) { constructor(config: IModuleConfig, device: Device) {
this.config = config; this.config = config;
this.devices = devices; this.device = device;
} }
abstract handlePacket(packet: protobuf.Mesh.MeshPacket, device: Device, replyTo: number): boolean; // 'true' if handled abstract handlePacket(packet: protobuf.Mesh.MeshPacket, replyTo: number): boolean; // 'true' if handled
log(level: number, msg: string): void { log(level: number, msg: string): void {
js.global.log(level, `${this.config.name}: ${msg}`); js.global.log(level, `${this.config.name}: ${msg}`);
......
...@@ -4,11 +4,11 @@ import { IModuleConfig } from '../lib/config'; ...@@ -4,11 +4,11 @@ import { IModuleConfig } from '../lib/config';
export default class Echo extends Module { export default class Echo extends Module {
constructor(config: IModuleConfig, devices: Device[]) { constructor(config: IModuleConfig, device: Device) {
super(config, devices); super(config, device);
} }
handlePacket(packet: protobuf.Mesh.MeshPacket, device: Device, replyTo: number): boolean { handlePacket(packet: protobuf.Mesh.MeshPacket, replyTo: number): boolean {
if (packet.payloadVariant.case !== 'decoded') return false; if (packet.payloadVariant.case !== 'decoded') return false;
// @ts-expect-error It's ambient // @ts-expect-error It's ambient
const dec = new TextDecoder(); const dec = new TextDecoder();
...@@ -16,7 +16,7 @@ export default class Echo extends Module { ...@@ -16,7 +16,7 @@ export default class Echo extends Module {
if (!msg.startsWith('.echo ')) return false; if (!msg.startsWith('.echo ')) return false;
const echo = `You sent: ${msg.replace(/^.echo\s/, '')}`; const echo = `You sent: ${msg.replace(/^.echo\s/, '')}`;
const hopLimit = this.config.hopLimit ?? undefined; const hopLimit = this.config.hopLimit ?? undefined;
device.sendText({ text: echo, to: replyTo, channel: packet.channel, replyId: packet.id, hopLimit }); this.device.sendText({ text: echo, to: replyTo, channel: packet.channel, replyId: packet.id, hopLimit });
return true; return true;
} }
......
...@@ -24,8 +24,8 @@ export default class Weather extends Module { ...@@ -24,8 +24,8 @@ export default class Weather extends Module {
private units: unit; private units: unit;
private alertRebroadcast: boolean; private alertRebroadcast: boolean;
constructor(config: IModuleConfig, devices: Device[]) { constructor(config: IModuleConfig, device: Device) {
super(config, devices); super(config, device);
const wc: IWeatherModuleConfig = config as IWeatherModuleConfig; const wc: IWeatherModuleConfig = config as IWeatherModuleConfig;
this.units = 'metric'; this.units = 'metric';
...@@ -40,17 +40,8 @@ export default class Weather extends Module { ...@@ -40,17 +40,8 @@ export default class Weather extends Module {
this.alertRebroadcast = wc.alertRebroadcast ?? false; this.alertRebroadcast = wc.alertRebroadcast ?? false;
if (typeof wc.alertInterval === 'number' && wc.alertInterval > 0) { if (typeof wc.alertInterval === 'number' && wc.alertInterval > 0) {
function alertBroadcastInterval(this: Weather): void { js.setInterval(this.broadcastAlerts, wc.alertInterval, this);
for (let d = 0; d < this.devices.length; d++) { this.device.on('ready', this.broadcastAlerts.bind(this));
this.broadcastAlerts(this.devices[d], this.config.channel, this.config.hopLimit);
}
}
js.setInterval(alertBroadcastInterval, wc.alertInterval, this);
for (let d = 0; d < this.devices.length; d++) {
this.devices[d].on('ready', () => {
this.broadcastAlerts(this.devices[d], this.config.channel, this.config.hopLimit);
});
}
} }
} }
...@@ -92,10 +83,10 @@ export default class Weather extends Module { ...@@ -92,10 +83,10 @@ export default class Weather extends Module {
return ws === '' ? undefined : ws; return ws === '' ? undefined : ws;
} }
private canBroadcastAlert(wa: string, devId: number): boolean { private canBroadcastAlert(wa: string): boolean {
let ret = true; let ret = true;
const wah = js.global.md5_calc(wa); const wah = js.global.md5_calc(wa);
const wal = `${Date.now()},${devId},${wah}`; const wal = `${Date.now()},${this.device.configId},${wah}`;
const fn = `${js.global.system.temp_dir}synctastic-weather-alerts.txt`; const fn = `${js.global.system.temp_dir}synctastic-weather-alerts.txt`;
const f = new js.global.File(fn); const f = new js.global.File(fn);
if (!f.exists) { if (!f.exists) {
...@@ -106,7 +97,7 @@ export default class Weather extends Module { ...@@ -106,7 +97,7 @@ export default class Weather extends Module {
if (!f.open('r')) throw new Error(`Failed to open ${fn} for reading`); if (!f.open('r')) throw new Error(`Failed to open ${fn} for reading`);
while (!f.eof) { while (!f.eof) {
const l = f.readln().split(','); const l = f.readln().split(',');
if (parseInt(l[1], 10) !== devId) continue; if (parseInt(l[1], 10) !== this.device.configId) continue;
if (l[2] !== wah) continue; if (l[2] !== wah) continue;
ret = false; ret = false;
break; break;
...@@ -121,18 +112,18 @@ export default class Weather extends Module { ...@@ -121,18 +112,18 @@ export default class Weather extends Module {
return ret; return ret;
} }
private broadcastAlerts(device: Device, channel: number, hopLimit: number | undefined): void { private broadcastAlerts(): void {
const nodeInfo = device.getNodeInfo(device.myNodeInfo.myNodeNum); const nodeInfo = this.device.getNodeInfo(this.device.myNodeInfo.myNodeNum);
if (nodeInfo?.position === undefined) return; if (nodeInfo?.position === undefined) return;
const lat = nodeInfo.position.latitudeI * .0000001; const lat = nodeInfo.position.latitudeI * .0000001;
const lon = nodeInfo.position.longitudeI * .0000001; const lon = nodeInfo.position.longitudeI * .0000001;
const wa = this.getCurrentAlerts(lat, lon); const wa = this.getCurrentAlerts(lat, lon);
if (wa === undefined) return; if (wa === undefined) return;
if (!this.alertRebroadcast && !this.canBroadcastAlert(wa, device.configId)) return; if (!this.alertRebroadcast && !this.canBroadcastAlert(wa)) return;
device.sendText({ text: wa, channel: channel, hopLimit }); this.device.sendText({ text: wa, channel: this.config.channel, hopLimit: this.config.hopLimit });
} }
handlePacket(packet: protobuf.Mesh.MeshPacket, device: Device, replyTo: number): boolean { handlePacket(packet: protobuf.Mesh.MeshPacket, replyTo: number): boolean {
if (packet.payloadVariant.case !== 'decoded') return false; if (packet.payloadVariant.case !== 'decoded') return false;
// @ts-expect-error It's ambient // @ts-expect-error It's ambient
const dec = new TextDecoder(); const dec = new TextDecoder();
...@@ -140,12 +131,12 @@ export default class Weather extends Module { ...@@ -140,12 +131,12 @@ export default class Weather extends Module {
if (!msg.startsWith('.wx')) return false; if (!msg.startsWith('.wx')) return false;
try { try {
let nodeInfo = device.getNodeInfo(packet.from); let nodeInfo = this.device.getNodeInfo(packet.from);
if (nodeInfo?.position === undefined) { if (nodeInfo?.position === undefined) {
if (this.config.debug) { if (this.config.debug) {
this.log(sbbsdefs.LOG_DEBUG, `failed to find position for ${packet.from} in node DB. Falling back on self position`); this.log(sbbsdefs.LOG_DEBUG, `failed to find position for ${packet.from} in node DB. Falling back on self position`);
} }
nodeInfo = device.getNodeInfo(device.myNodeInfo.myNodeNum); nodeInfo = this.device.getNodeInfo(this.device.myNodeInfo.myNodeNum);
} }
if (nodeInfo?.position === undefined) { if (nodeInfo?.position === undefined) {
throw new Error('failed to find self position, cannot send lat/lon to weather API'); throw new Error('failed to find self position, cannot send lat/lon to weather API');
...@@ -167,7 +158,7 @@ export default class Weather extends Module { ...@@ -167,7 +158,7 @@ export default class Weather extends Module {
} }
if (ws === undefined) return false; if (ws === undefined) return false;
device.sendText({ text: ws, to: replyTo, channel: packet.channel, replyId: packet.id, hopLimit: this.config.hopLimit }); this.device.sendText({ text: ws, to: replyTo, channel: packet.channel, replyId: packet.id, hopLimit: this.config.hopLimit });
return true; return true;
} catch (err: any) { } catch (err: any) {
this.error(err as string); this.error(err as string);
......
...@@ -33,7 +33,7 @@ function init(): void { ...@@ -33,7 +33,7 @@ function init(): void {
if (dev === undefined) return; if (dev === undefined) return;
for (const module of modules) { for (const module of modules) {
if (module.config.channel !== packet.channel) continue; if (module.config.channel !== packet.channel) continue;
if (module.config.devices.indexOf(dev.configId) < 0) continue; if (module.config.device !== dev.configId) continue;
if (packet.to !== defs.BROADCAST && packet.to !== dev.myNodeInfo.myNodeNum) continue; if (packet.to !== defs.BROADCAST && packet.to !== dev.myNodeInfo.myNodeNum) continue;
if (packet.payloadVariant.case !== 'decoded') continue; if (packet.payloadVariant.case !== 'decoded') continue;
if (module.config.port !== packet.payloadVariant.value.portnum) continue; if (module.config.port !== packet.payloadVariant.value.portnum) continue;
...@@ -41,7 +41,7 @@ function init(): void { ...@@ -41,7 +41,7 @@ function init(): void {
if (module.config.reply === 'broadcast' || (module.config.reply === 'same' && packet.to === defs.BROADCAST)) { if (module.config.reply === 'broadcast' || (module.config.reply === 'same' && packet.to === defs.BROADCAST)) {
to = defs.BROADCAST; to = defs.BROADCAST;
} }
module.handlePacket(packet, dev, to); module.handlePacket(packet, to);
} }
}); });
...@@ -53,21 +53,20 @@ function init(): void { ...@@ -53,21 +53,20 @@ function init(): void {
for (const module in config.modules) { for (const module in config.modules) {
const devs: Device[] = []; if (devices[config.modules[module].device] === undefined) {
for (const devId in config.modules[module].devices) { throw new Error(`Invalid device specified for ${config.modules[module].name}`);
if (devices[devId] !== undefined) devs.push(devices[devId]);
} }
switch (config.modules[module].path) { switch (config.modules[module].path) {
case 'echo': case 'echo':
modules.push(new Echo(config.modules[module], devs)); modules.push(new Echo(config.modules[module], devices[config.modules[module].device]));
break; break;
case 'weather': case 'weather':
modules.push(new Weather(config.modules[module], devs)); modules.push(new Weather(config.modules[module], devices[config.modules[module].device]));
break; break;
default: default:
const m = js.global.load({}, config.modules[module].path); const m = js.global.load({}, config.modules[module].path);
modules.push(new m(config.modules[module])); modules.push(new m(config.modules[module], devices[config.modules[module].device]));
break; break;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment