diff --git a/owrx/controllers/settings/reporting.py b/owrx/controllers/settings/reporting.py index 17012cf2..19336bd5 100644 --- a/owrx/controllers/settings/reporting.py +++ b/owrx/controllers/settings/reporting.py @@ -3,6 +3,7 @@ from owrx.form.section import Section from owrx.form.input.converter import OptionalConverter from owrx.form.input.aprs import AprsBeaconSymbols, AprsAntennaDirections from owrx.form.input import TextInput, CheckboxInput, DropdownInput, NumberInput +from owrx.form.input.validator import AddressAndOptionalPortValidator from owrx.breadcrumb import Breadcrumb, BreadcrumbItem @@ -98,7 +99,15 @@ class ReportingController(SettingsFormController): ), TextInput( "mqtt_host", - "MQTT Host", + "MQTT Broker address", + infotext="Addresss of the MQTT broker to send decodes to (address[:port])", + validator=AddressAndOptionalPortValidator(), + ), + TextInput( + "mqtt_topic", + "MQTT topic", + infotext="MQTT topic to publish decodes to (default: openwebrx/decodes)", + converter=OptionalConverter(), ), ) ] diff --git a/owrx/form/input/validator.py b/owrx/form/input/validator.py index b5591ea1..bda4304d 100644 --- a/owrx/form/input/validator.py +++ b/owrx/form/input/validator.py @@ -54,3 +54,18 @@ class RangeListValidator(Validator): def _rangeStr(self): return "[{}]".format(", ".join(str(r) for r in self.rangeList)) + + +class AddressAndOptionalPortValidator(Validator): + def validate(self, key, value) -> None: + parts = value.split(":") + if len(parts) > 2: + raise ValidationError(key, "Value contains too many colons") + + if len(parts) > 1: + try: + port = int(parts[1]) + except ValueError: + raise ValidationError(key, "Port number must be numeric") + if not 0 <= port <= 65535: + raise ValidationError(key, "Port number out of range") diff --git a/owrx/reporting/mqtt.py b/owrx/reporting/mqtt.py index aa326fdf..c365e3c9 100644 --- a/owrx/reporting/mqtt.py +++ b/owrx/reporting/mqtt.py @@ -1,17 +1,44 @@ from paho.mqtt.client import Client from owrx.reporting.reporter import Reporter from owrx.config import Config +from owrx.property import PropertyDeleted import json +import logging + +logger = logging.getLogger(__name__) + class MqttReporter(Reporter): + DEFAULT_TOPIC = "openwebrx/decodes" + def __init__(self): pm = Config.get() self.client = Client() - self.client.connect(host=pm["mqtt_host"]) + self.topic = self.DEFAULT_TOPIC + self.subscriptions = [ + pm.wireProperty("mqtt_host", self._setHost), + pm.wireProperty("mqtt_topic", self._setTopic), + ] + + def _setHost(self, host): + logger.debug("setting host to %s", host) + self.client.disconnect() + parts = host.split(":") + host = parts[0] + port = int(parts[1]) if len(parts) > 1 else 1883 + self.client.connect(host=host, port=port) + + def _setTopic(self, topic): + if topic is PropertyDeleted: + self.topic = self.DEFAULT_TOPIC + else: + self.topic = topic def stop(self): self.client.disconnect() + while self.subscriptions: + self.subscriptions.pop().cancel() def spot(self, spot): - self.client.publish("openwebrx/spots", payload=json.dumps(spot)) + self.client.publish(self.topic, payload=json.dumps(spot))