integrated send mqtt message; optimised tui; logging added
This commit is contained in:
parent
011ee98477
commit
b3db98346f
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +1,6 @@
|
|||||||
[submodule "mqtt"]
|
[submodule "mqtt"]
|
||||||
path = mqtt
|
path = mqtt
|
||||||
url = https://git.mount-mockery.de/pylib/mqtt.git
|
url = https://git.mount-mockery.de/pylib/mqtt.git
|
||||||
|
[submodule "report"]
|
||||||
|
path = report
|
||||||
|
url = https://git.mount-mockery.de/pylib/report.git
|
||||||
|
@ -1,19 +1,24 @@
|
|||||||
import argparse
|
import argparse
|
||||||
|
import config
|
||||||
import getpass
|
import getpass
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import mqtt
|
import mqtt
|
||||||
import re
|
import re
|
||||||
|
import report
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from textual.app import App, ComposeResult
|
from textual.app import App, ComposeResult
|
||||||
from textual.containers import Vertical
|
from textual.containers import Vertical
|
||||||
from textual.widgets import Footer, Header, Input, RichLog
|
from textual.widgets import Footer, Header, Input, RichLog, Button
|
||||||
|
|
||||||
|
try:
|
||||||
|
from config import APP_NAME as ROOT_LOGGER_NAME
|
||||||
|
except ImportError:
|
||||||
|
ROOT_LOGGER_NAME = 'root'
|
||||||
|
logger = logging.getLogger(ROOT_LOGGER_NAME)
|
||||||
|
|
||||||
|
|
||||||
# TODO: Integrate sending of message (topic + payload)
|
class MqttHandler(object):
|
||||||
|
|
||||||
class MqttReceiver(object):
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
self.app = app
|
self.app = app
|
||||||
args = app.args
|
args = app.args
|
||||||
@ -22,9 +27,18 @@ class MqttReceiver(object):
|
|||||||
self.mqtt_client = mqtt.mqtt_client('mqtt_sniffer', args.hostname, args.port, username=args.username, password=password)
|
self.mqtt_client = mqtt.mqtt_client('mqtt_sniffer', args.hostname, args.port, username=args.username, password=password)
|
||||||
self.mqtt_client.add_callback("#", self.__rx__)
|
self.mqtt_client.add_callback("#", self.__rx__)
|
||||||
|
|
||||||
|
def __get_logger__(self, prefix, topic):
|
||||||
|
return logging.getLogger(ROOT_LOGGER_NAME).getChild(prefix + '.' + topic.replace('/', '.'))
|
||||||
|
|
||||||
def __rx__(self, client, userdata, message):
|
def __rx__(self, client, userdata, message):
|
||||||
|
logger = self.__get_logger__('rx', message.topic)
|
||||||
|
logger.debug("Received message: topic=%s, payload=%s type=%s", message.topic, repr(message.payload), repr(type(message.payload)))
|
||||||
self.app.call_from_thread(self.app.add_log, message)
|
self.app.call_from_thread(self.app.add_log, message)
|
||||||
|
|
||||||
|
def send(self, topic, payload):
|
||||||
|
logger = self.__get_logger__('tx', topic)
|
||||||
|
logger.debug("Sending message: topic=%s, payload=%s type=%s", topic, repr(payload), repr(type(payload)))
|
||||||
|
self.mqtt_client.send(topic, payload)
|
||||||
|
|
||||||
class MqttSniffer(App):
|
class MqttSniffer(App):
|
||||||
"""a textual application for viewing mqtt messages."""
|
"""a textual application for viewing mqtt messages."""
|
||||||
@ -38,8 +52,11 @@ class MqttSniffer(App):
|
|||||||
self.args = args
|
self.args = args
|
||||||
self.password = password
|
self.password = password
|
||||||
#
|
#
|
||||||
|
self.mqtt = None
|
||||||
self.all_logs = []
|
self.all_logs = []
|
||||||
self.topic_filter = ""
|
self.topic_filter = ""
|
||||||
|
self.send_topic = ""
|
||||||
|
self.send_payload = ""
|
||||||
self.log_display = RichLog(highlight=True, markup=True)
|
self.log_display = RichLog(highlight=True, markup=True)
|
||||||
|
|
||||||
def compose(self) -> ComposeResult:
|
def compose(self) -> ComposeResult:
|
||||||
@ -49,11 +66,14 @@ class MqttSniffer(App):
|
|||||||
yield self.log_display
|
yield self.log_display
|
||||||
with Vertical(id="bottom-bar"):
|
with Vertical(id="bottom-bar"):
|
||||||
yield Input(placeholder="topic filter...", id="topic_filter")
|
yield Input(placeholder="topic filter...", id="topic_filter")
|
||||||
|
yield Input(placeholder="topic...", id="send_topic")
|
||||||
|
yield Input(placeholder="payload...", id="send_payload")
|
||||||
|
yield Button("Send", variant="success", id="send_button")
|
||||||
yield Footer()
|
yield Footer()
|
||||||
|
|
||||||
def on_mount(self) -> None:
|
def on_mount(self) -> None:
|
||||||
"""start the mqtt receiver."""
|
"""start the mqtt receiver."""
|
||||||
MqttReceiver(self)
|
self.mqtt = MqttHandler(self)
|
||||||
|
|
||||||
def add_log(self, record) -> None:
|
def add_log(self, record) -> None:
|
||||||
"""Add new mqt messages and update the tui."""
|
"""Add new mqt messages and update the tui."""
|
||||||
@ -74,15 +94,10 @@ class MqttSniffer(App):
|
|||||||
pass # No valid regular expression
|
pass # No valid regular expression
|
||||||
|
|
||||||
if topic_match:
|
if topic_match:
|
||||||
try:
|
|
||||||
payload = json.loads(record.payload)
|
|
||||||
except:
|
|
||||||
payload = record.payload.decode('utf-8')
|
|
||||||
|
|
||||||
message = (
|
message = (
|
||||||
f"[[dim]{asctime}[/dim]] "
|
f"[[dim]{asctime}[/dim]] "
|
||||||
f"[bold]{record.topic}[/bold] - "
|
f"[bold]{record.topic}[/bold] - "
|
||||||
f"{repr(payload)}"
|
f"{repr(record.payload)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.log_display.write(message)
|
self.log_display.write(message)
|
||||||
@ -94,14 +109,29 @@ class MqttSniffer(App):
|
|||||||
self._apply_filters_to_log(record)
|
self._apply_filters_to_log(record)
|
||||||
|
|
||||||
def on_input_changed(self, message: Input.Changed) -> None:
|
def on_input_changed(self, message: Input.Changed) -> None:
|
||||||
"""Update the filter and filtered messages after the user did changes."""
|
"""Update the tui inputs and execute task, if requireed."""
|
||||||
if message.input.id == "topic_filter":
|
if message.input.id == "topic_filter":
|
||||||
self.topic_filter = message.value
|
self.topic_filter = message.value
|
||||||
|
self._update_display()
|
||||||
|
elif message.input.id == "send_topic":
|
||||||
|
self.send_topic = message.value
|
||||||
|
elif message.input.id == "send_payload":
|
||||||
|
self.send_payload = message.value
|
||||||
|
|
||||||
self._update_display()
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||||
|
"""Event handler called when a button is pressed."""
|
||||||
|
if event.button.id == "send_button":
|
||||||
|
if self.mqtt is not None:
|
||||||
|
self.mqtt.send(self.send_topic, self.send_payload)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
#
|
||||||
|
# Logging
|
||||||
|
#
|
||||||
|
if config.DEBUG:
|
||||||
|
report.appLoggingConfigure(None, None, ((config.APP_NAME, logging.DEBUG), ), target_level=logging.WARNING, fmt=report.SHORT_FMT, host='localhost', port=19996)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Parse Arguments
|
# Parse Arguments
|
||||||
#
|
#
|
||||||
|
1
report
Submodule
1
report
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 74e6f20d09cf76b3fbbdfa04c192b01708e50d5d
|
22
style.tcss
22
style.tcss
@ -2,16 +2,30 @@
|
|||||||
layout: vertical;
|
layout: vertical;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
scrollbar-gutter: stable;
|
scrollbar-gutter: stable;
|
||||||
height: 89%;
|
height: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#bottom-bar {
|
#bottom-bar {
|
||||||
layout: grid;
|
layout: grid;
|
||||||
grid-size: 1;
|
grid-size: 4;
|
||||||
height: 11%;
|
grid-columns: 3fr 2fr 2fr 1fr;
|
||||||
|
height: 4;
|
||||||
border-top: solid $primary;
|
border-top: solid $primary;
|
||||||
}
|
}
|
||||||
|
|
||||||
#module_filter {
|
#topic_filter {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#send_button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#send_topic {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#send_payload {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user