feat(ui): add SNR, RSSI, hops info for messages (#963)
* feat(ui): add SNR, RSSI, hops, MQTT info for messages * review fixes * zeros for new fields * Move label under the message --------- Co-authored-by: Pmmlabs <meshtastic@pmmlabs.ru>
This commit is contained in:
co-authored by
Pmmlabs
parent
6a7be99a6a
commit
020e9d6b63
@@ -931,6 +931,10 @@ export class MeshDevice {
|
|||||||
from: meshPacket.from,
|
from: meshPacket.from,
|
||||||
to: meshPacket.to,
|
to: meshPacket.to,
|
||||||
channel: meshPacket.channel,
|
channel: meshPacket.channel,
|
||||||
|
hops: Math.min(meshPacket.hopStart - meshPacket.hopLimit, 0),
|
||||||
|
rxRssi: meshPacket.rxRssi,
|
||||||
|
rxSnr: meshPacket.rxSnr,
|
||||||
|
viaMqtt: meshPacket.viaMqtt,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.log.trace(
|
this.log.trace(
|
||||||
|
|||||||
@@ -60,6 +60,10 @@ export interface PacketMetadata<T> {
|
|||||||
from: number;
|
from: number;
|
||||||
to: number;
|
to: number;
|
||||||
channel: ChannelNumber;
|
channel: ChannelNumber;
|
||||||
|
hops: number;
|
||||||
|
rxRssi: number;
|
||||||
|
rxSnr: number;
|
||||||
|
viaMqtt: boolean;
|
||||||
data: T;
|
data: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ export const decodePacket = (device: MeshDevice) =>
|
|||||||
type: "direct",
|
type: "direct",
|
||||||
channel: Types.ChannelNumber.Primary,
|
channel: Types.ChannelNumber.Primary,
|
||||||
data: decodedMessage.payloadVariant.value.position,
|
data: decodedMessage.payloadVariant.value.position,
|
||||||
|
hops: 0,
|
||||||
|
rxRssi: 0,
|
||||||
|
rxSnr: 0,
|
||||||
|
viaMqtt: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,6 +103,10 @@ export const decodePacket = (device: MeshDevice) =>
|
|||||||
type: "direct",
|
type: "direct",
|
||||||
channel: Types.ChannelNumber.Primary,
|
channel: Types.ChannelNumber.Primary,
|
||||||
data: decodedMessage.payloadVariant.value.user,
|
data: decodedMessage.payloadVariant.value.user,
|
||||||
|
hops: 0,
|
||||||
|
rxRssi: 0,
|
||||||
|
rxSnr: 0,
|
||||||
|
viaMqtt: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -238,6 +246,10 @@ export const decodePacket = (device: MeshDevice) =>
|
|||||||
type: "direct",
|
type: "direct",
|
||||||
channel: Types.ChannelNumber.Primary,
|
channel: Types.ChannelNumber.Primary,
|
||||||
data: decodedMessage.payloadVariant.value,
|
data: decodedMessage.payloadVariant.value,
|
||||||
|
hops: 0,
|
||||||
|
rxRssi: 0,
|
||||||
|
rxSnr: 0,
|
||||||
|
viaMqtt: false,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,7 +134,10 @@ fix: correct caching issue in storage service
|
|||||||
## 💡 Tips for Contributors
|
## 💡 Tips for Contributors
|
||||||
- Keep PRs **small, focused, and atomic**.
|
- Keep PRs **small, focused, and atomic**.
|
||||||
- Discuss larger changes with the team on [Discord](https://discord.gg/meshtastic) before starting work.
|
- Discuss larger changes with the team on [Discord](https://discord.gg/meshtastic) before starting work.
|
||||||
- If unsure, open a draft PR for early feedback.
|
- If unsure, open a draft PR for early feedback.
|
||||||
|
- Maintain cross-platform visual consistency: when implementing new UI components, it's important to maintain a consistent
|
||||||
|
look and layout across platforms. Before introducing a new visual pattern, please reference the existing interfaces in other
|
||||||
|
client apps to ensure alignment.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -216,6 +216,21 @@ export const MessageItem = ({ message }: MessageItemProps) => {
|
|||||||
<span className="font-medium text-sm text-slate-900 dark:text-slate-100 truncate mr-1">
|
<span className="font-medium text-sm text-slate-900 dark:text-slate-100 truncate mr-1">
|
||||||
{displayName}
|
{displayName}
|
||||||
</span>
|
</span>
|
||||||
|
{message.viaMqtt && (
|
||||||
|
<TooltipProvider delayDuration={300}>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<span className="text-lg text-slate-800 dark:text-slate-200 -mt-6 h-1">
|
||||||
|
☁️
|
||||||
|
</span>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent className="bg-slate-800 dark:bg-slate-600 text-white px-4 py-1 rounded text-xs">
|
||||||
|
MQTT
|
||||||
|
<TooltipArrow className="fill-slate-800 dark:fill-slate-600" />
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
</TooltipProvider>
|
||||||
|
)}
|
||||||
{messageDate && (
|
{messageDate && (
|
||||||
<time
|
<time
|
||||||
dateTime={messageDate.toISOString()}
|
dateTime={messageDate.toISOString()}
|
||||||
@@ -245,6 +260,16 @@ export const MessageItem = ({ message }: MessageItemProps) => {
|
|||||||
{message.message}
|
{message.message}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{(message.hops && (
|
||||||
|
<div className="text-xs text-slate-500 dark:text-slate-200 whitespace-pre-wrap break-words">
|
||||||
|
{t("hops.text", { value: message.hops })}
|
||||||
|
</div>
|
||||||
|
)) ||
|
||||||
|
(message.rxSnr && message.rxRssi && (
|
||||||
|
<div className="text-xs text-slate-500 dark:text-slate-200 whitespace-pre-wrap break-words">
|
||||||
|
SNR: {message.rxSnr}, RSSI: {message.rxRssi}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Actions Menu Placeholder */}
|
{/* Actions Menu Placeholder */}
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ class PacketToMessageDTO {
|
|||||||
state: MessageState;
|
state: MessageState;
|
||||||
message: string;
|
message: string;
|
||||||
type: MessageType;
|
type: MessageType;
|
||||||
|
hops: number;
|
||||||
|
rxRssi: number;
|
||||||
|
rxSnr: number;
|
||||||
|
viaMqtt: boolean;
|
||||||
|
|
||||||
constructor(data: Types.PacketMetadata<string>, nodeNum: number) {
|
constructor(data: Types.PacketMetadata<string>, nodeNum: number) {
|
||||||
this.channel = data.channel;
|
this.channel = data.channel;
|
||||||
@@ -36,6 +40,10 @@ class PacketToMessageDTO {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.date = dateTimestamp;
|
this.date = dateTimestamp;
|
||||||
|
this.hops = data.hops;
|
||||||
|
this.rxRssi = data.rxRssi;
|
||||||
|
this.rxSnr = data.rxSnr;
|
||||||
|
this.viaMqtt = data.viaMqtt;
|
||||||
}
|
}
|
||||||
|
|
||||||
toMessage(): Message {
|
toMessage(): Message {
|
||||||
@@ -48,6 +56,10 @@ class PacketToMessageDTO {
|
|||||||
state: this.state,
|
state: this.state,
|
||||||
message: this.message,
|
message: this.message,
|
||||||
type: this.type,
|
type: this.type,
|
||||||
|
hops: this.hops,
|
||||||
|
rxRssi: this.rxRssi,
|
||||||
|
rxSnr: this.rxSnr,
|
||||||
|
viaMqtt: this.viaMqtt,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ const directMessageToOther1: Message = {
|
|||||||
messageId: 101,
|
messageId: 101,
|
||||||
state: MessageState.Waiting,
|
state: MessageState.Waiting,
|
||||||
message: "Hello other 1 from me",
|
message: "Hello other 1 from me",
|
||||||
|
rxSnr: 1,
|
||||||
|
rxRssi: 2,
|
||||||
|
viaMqtt: false,
|
||||||
|
hops: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
const directMessageFromOther1: Message = {
|
const directMessageFromOther1: Message = {
|
||||||
@@ -64,6 +68,10 @@ const directMessageFromOther1: Message = {
|
|||||||
messageId: 102,
|
messageId: 102,
|
||||||
state: MessageState.Waiting,
|
state: MessageState.Waiting,
|
||||||
message: "Hello me from other 1",
|
message: "Hello me from other 1",
|
||||||
|
rxSnr: 1,
|
||||||
|
rxRssi: 2,
|
||||||
|
viaMqtt: false,
|
||||||
|
hops: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
const directMessageToOther2: Message = {
|
const directMessageToOther2: Message = {
|
||||||
@@ -75,6 +83,10 @@ const directMessageToOther2: Message = {
|
|||||||
messageId: 103,
|
messageId: 103,
|
||||||
state: MessageState.Waiting,
|
state: MessageState.Waiting,
|
||||||
message: "Hello other 2 from me",
|
message: "Hello other 2 from me",
|
||||||
|
rxSnr: 1,
|
||||||
|
rxRssi: 2,
|
||||||
|
viaMqtt: false,
|
||||||
|
hops: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
const broadcastMessage1: Message = {
|
const broadcastMessage1: Message = {
|
||||||
@@ -86,6 +98,10 @@ const broadcastMessage1: Message = {
|
|||||||
messageId: 201,
|
messageId: 201,
|
||||||
state: MessageState.Waiting,
|
state: MessageState.Waiting,
|
||||||
message: "Broadcast message 1",
|
message: "Broadcast message 1",
|
||||||
|
rxSnr: 1,
|
||||||
|
rxRssi: 2,
|
||||||
|
viaMqtt: false,
|
||||||
|
hops: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
const broadcastMessage2: Message = {
|
const broadcastMessage2: Message = {
|
||||||
@@ -97,6 +113,10 @@ const broadcastMessage2: Message = {
|
|||||||
messageId: 202,
|
messageId: 202,
|
||||||
state: MessageState.Waiting,
|
state: MessageState.Waiting,
|
||||||
message: "Broadcast message 2",
|
message: "Broadcast message 2",
|
||||||
|
rxSnr: 1,
|
||||||
|
rxRssi: 2,
|
||||||
|
viaMqtt: false,
|
||||||
|
hops: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
describe("MessageStore persistence & rehydrate", () => {
|
describe("MessageStore persistence & rehydrate", () => {
|
||||||
@@ -764,6 +784,10 @@ describe("MessageStore persistence & rehydrate", () => {
|
|||||||
messageId: i,
|
messageId: i,
|
||||||
state: MessageState.Waiting,
|
state: MessageState.Waiting,
|
||||||
message: `m${i}`,
|
message: `m${i}`,
|
||||||
|
rxSnr: 1,
|
||||||
|
rxRssi: 2,
|
||||||
|
viaMqtt: false,
|
||||||
|
hops: 3,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ interface MessageBase {
|
|||||||
messageId: number;
|
messageId: number;
|
||||||
state: MessageState;
|
state: MessageState;
|
||||||
message: string;
|
message: string;
|
||||||
|
rxSnr: number;
|
||||||
|
rxRssi: number;
|
||||||
|
viaMqtt: boolean;
|
||||||
|
hops: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GenericMessage<T extends MessageType> extends MessageBase {
|
interface GenericMessage<T extends MessageType> extends MessageBase {
|
||||||
|
|||||||
Reference in New Issue
Block a user