DM support

This commit is contained in:
Sacha Weatherstone
2023-02-19 16:55:59 +10:00
parent 2265a304fe
commit b2c3c89965
17 changed files with 532 additions and 531 deletions
+153 -187
View File
@@ -4,6 +4,7 @@ import { produce } from "immer";
import { create } from "zustand";
import { Protobuf, Types } from "@meshtastic/meshtasticjs";
import { channel } from "diagnostics_channel";
export type Page = "messages" | "map" | "config" | "channels" | "peers";
@@ -11,35 +12,8 @@ export interface MessageWithState extends Types.PacketMetadata<string> {
state: MessageState;
}
export interface WaypointIDWithState
extends Omit<Types.PacketMetadata<Protobuf.Waypoint>, "data"> {
waypointID: number;
state: MessageState;
}
export type AllMessageTypes = MessageWithState | WaypointIDWithState;
export type MessageState = "ack" | "waiting" | Protobuf.Routing_Error;
export interface Channel {
config: Protobuf.Channel;
lastInterraction: Date;
messages: AllMessageTypes[];
}
export interface Node {
deviceMetrics: {
metric: Protobuf.DeviceMetrics;
timestamp: Date;
}[];
environmentMetrics: {
metric: Protobuf.EnvironmentMetrics;
timestamp: Date;
}[];
metadata?: Protobuf.DeviceMetadata;
data: Protobuf.NodeInfo;
}
export interface processPacketParams {
from: number;
snr: number;
@@ -55,22 +29,24 @@ export type DialogVariant =
export interface Device {
id: number;
ready: boolean;
status: Types.DeviceStatusEnum;
channels: Channel[];
channels: Protobuf.Channel[];
config: Protobuf.LocalConfig;
moduleConfig: Protobuf.LocalModuleConfig;
workingConfig: Protobuf.Config[];
workingModuleConfig: Protobuf.ModuleConfig[];
hardware: Protobuf.MyNodeInfo;
nodes: Node[];
nodes: Map<number, Protobuf.NodeInfo>;
metadata: Map<number, Protobuf.DeviceMetadata>;
messages: {
direct: Map<number, MessageWithState[]>;
broadcast: Map<Types.ChannelNumber, MessageWithState[]>;
};
connection?: Types.ConnectionType;
activePage: Page;
peerInfoOpen: boolean;
activePeer: number;
waypoints: Protobuf.Waypoint[];
regionUnset: boolean;
currentMetrics: Protobuf.DeviceMetrics;
// currentMetrics: Protobuf.DeviceMetrics;
pendingSettingsChanges: boolean;
messageDraft: string;
dialog: {
@@ -81,31 +57,29 @@ export interface Device {
deviceName: boolean;
};
setReady(ready: boolean): void;
setStatus: (status: Types.DeviceStatusEnum) => void;
setConfig: (config: Protobuf.Config) => void;
setModuleConfig: (config: Protobuf.ModuleConfig) => void;
setWorkingConfig: (config: Protobuf.Config) => void;
setWorkingModuleConfig: (config: Protobuf.ModuleConfig) => void;
setHardware: (hardware: Protobuf.MyNodeInfo) => void;
setMetrics: (metrics: Types.PacketMetadata<Protobuf.Telemetry>) => void;
// setMetrics: (metrics: Types.PacketMetadata<Protobuf.Telemetry>) => void;
setActivePage: (page: Page) => void;
setPeerInfoOpen: (open: boolean) => void;
setActivePeer: (peer: number) => void;
setPendingSettingsChanges: (state: boolean) => void;
addChannel: (channel: Channel) => void;
addChannel: (channel: Protobuf.Channel) => void;
addWaypoint: (waypoint: Protobuf.Waypoint) => void;
addNodeInfo: (nodeInfo: Protobuf.NodeInfo) => void;
addUser: (user: Types.PacketMetadata<Protobuf.User>) => void;
addPosition: (position: Types.PacketMetadata<Protobuf.Position>) => void;
addConnection: (connection: Types.ConnectionType) => void;
addMessage: (message: MessageWithState) => void;
addWaypointMessage: (message: WaypointIDWithState) => void;
addDeviceMetadataMessage: (
metadata: Types.PacketMetadata<Protobuf.DeviceMetadata>
) => void;
addMetadata: (from: number, metadata: Protobuf.DeviceMetadata) => void;
setMessageState: (
channelIndex: number,
type: "direct" | "broadcast",
channelIndex: Types.ChannelNumber,
to: number,
from: number,
messageId: number,
state: MessageState
) => void;
@@ -133,7 +107,6 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
produce<DeviceState>((draft) => {
draft.devices.set(id, {
id,
ready: false,
status: Types.DeviceStatusEnum.DEVICE_DISCONNECTED,
channels: [],
config: new Protobuf.LocalConfig(),
@@ -141,14 +114,17 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
workingConfig: [],
workingModuleConfig: [],
hardware: new Protobuf.MyNodeInfo(),
nodes: [],
nodes: new Map(),
metadata: new Map(),
messages: {
direct: new Map(),
broadcast: new Map()
},
connection: undefined,
activePage: "messages",
peerInfoOpen: false,
activePeer: 0,
waypoints: [],
regionUnset: false,
currentMetrics: new Protobuf.DeviceMetrics(),
// currentMetrics: new Protobuf.DeviceMetrics(),
dialog: {
import: false,
QR: false,
@@ -159,16 +135,6 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
pendingSettingsChanges: false,
messageDraft: "",
setReady: (ready: boolean) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
device.ready = ready;
}
})
);
},
setStatus: (status: Types.DeviceStatusEnum) => {
set(
produce<DeviceState>((draft) => {
@@ -203,9 +169,6 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
break;
case "lora":
device.config.lora = config.payloadVariant.value;
device.regionUnset =
config.payloadVariant.value.region ===
Protobuf.Config_LoRaConfig_RegionCode.UNSET;
break;
case "bluetooth":
device.config.bluetooth = config.payloadVariant.value;
@@ -305,50 +268,50 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
})
);
},
setMetrics: (metrics: Types.PacketMetadata<Protobuf.Telemetry>) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
let node = device?.nodes.find(
(n) => n.data.num === metrics.from
);
if (node) {
switch (metrics.data.variant.case) {
case "deviceMetrics":
if (device) {
if (metrics.data.variant.value.batteryLevel) {
device.currentMetrics.batteryLevel =
metrics.data.variant.value.batteryLevel;
}
if (metrics.data.variant.value.voltage) {
device.currentMetrics.voltage =
metrics.data.variant.value.voltage;
}
if (metrics.data.variant.value.airUtilTx) {
device.currentMetrics.airUtilTx =
metrics.data.variant.value.airUtilTx;
}
if (metrics.data.variant.value.channelUtilization) {
device.currentMetrics.channelUtilization =
metrics.data.variant.value.channelUtilization;
}
}
node.deviceMetrics.push({
metric: metrics.data.variant.value,
timestamp: metrics.rxTime
});
break;
case "environmentMetrics":
node.environmentMetrics.push({
metric: metrics.data.variant.value,
timestamp: metrics.rxTime
});
break;
}
}
})
);
},
// setMetrics: (metrics: Types.PacketMetadata<Protobuf.Telemetry>) => {
// set(
// produce<DeviceState>((draft) => {
// const device = draft.devices.get(id);
// let node = device?.nodes.find(
// (n) => n.data.num === metrics.from
// );
// if (node) {
// switch (metrics.data.variant.case) {
// case "deviceMetrics":
// if (device) {
// if (metrics.data.variant.value.batteryLevel) {
// device.currentMetrics.batteryLevel =
// metrics.data.variant.value.batteryLevel;
// }
// if (metrics.data.variant.value.voltage) {
// device.currentMetrics.voltage =
// metrics.data.variant.value.voltage;
// }
// if (metrics.data.variant.value.airUtilTx) {
// device.currentMetrics.airUtilTx =
// metrics.data.variant.value.airUtilTx;
// }
// if (metrics.data.variant.value.channelUtilization) {
// device.currentMetrics.channelUtilization =
// metrics.data.variant.value.channelUtilization;
// }
// }
// node.deviceMetrics.push({
// metric: metrics.data.variant.value,
// timestamp: metrics.rxTime
// });
// break;
// case "environmentMetrics":
// node.environmentMetrics.push({
// metric: metrics.data.variant.value,
// timestamp: metrics.rxTime
// });
// break;
// }
// }
// })
// );
// },
setActivePage: (page) => {
set(
produce<DeviceState>((draft) => {
@@ -369,18 +332,16 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
})
);
},
addChannel: (channel: Channel) => {
addChannel: (channel: Protobuf.Channel) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
const channelIndex = device.channels.findIndex(
(c) => c.config.index === channel.config.index
(c) => c.index === channel.index
);
if (channelIndex !== -1) {
const messages = device.channels[channelIndex].messages;
device.channels[channelIndex] = channel;
device.channels[channelIndex].messages = messages;
} else {
device.channels.push(channel);
}
@@ -410,29 +371,10 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
const node = device?.nodes.find(
(node) => node.data.num === nodeInfo.num
);
if (node) {
node.data = nodeInfo;
} else {
device?.nodes.push({
data: nodeInfo,
metadata: undefined,
deviceMetrics: [],
environmentMetrics: []
});
}
})
);
},
setPeerInfoOpen: (open) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
device.peerInfoOpen = open;
if (!device) {
return;
}
device.nodes.set(nodeInfo.num, nodeInfo);
})
);
},
@@ -450,12 +392,13 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
const node = device?.nodes.find(
(node) => node.data.num === user.from
);
if (node) {
node.data.user = user.data;
if (!device) {
return;
}
const currentNode =
device.nodes.get(user.from) ?? new Protobuf.NodeInfo();
currentNode.user = user.data;
device.nodes.set(user.from, currentNode);
})
);
},
@@ -463,12 +406,13 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
const node = device?.nodes.find(
(node) => node.data.num === position.from
);
if (node) {
node.data.position = position.data;
if (!device) {
return;
}
const currentNode =
device.nodes.get(position.from) ?? new Protobuf.NodeInfo();
currentNode.position = position.data;
device.nodes.set(position.from, currentNode);
})
);
},
@@ -486,53 +430,78 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
device?.channels
.find((ch) => ch.config.index === message.channel)
?.messages.push(message);
})
);
},
addWaypointMessage: (waypointID) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
device?.channels
.find((ch) => ch.config.index === waypointID.channel)
?.messages.push(waypointID);
})
);
},
addDeviceMetadataMessage: (metadata) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
const node = device?.nodes.find(
(n) => n.data.num === metadata.from
);
if (node) {
node.metadata = metadata.data;
if (!device) {
return;
}
const messageGroup = device.messages[message.type];
const messageIndex =
message.type === "direct"
? message.from === device.hardware.myNodeNum
? message.to
: message.from
: message.channel;
const messages = messageGroup.get(messageIndex);
if (messages) {
messages.push(message);
messageGroup.set(messageIndex, messages);
} else {
messageGroup.set(messageIndex, [message]);
}
})
);
},
addMetadata: (from, metadata) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (!device) {
return;
}
device.metadata.set(from, metadata);
})
);
},
setMessageState: (
channelIndex: number,
type: "direct" | "broadcast",
channelIndex: Types.ChannelNumber,
to: number,
from: number,
messageId: number,
state: MessageState
) => {
set(
produce<DeviceState>((draft) => {
console.log("setMessageState called");
const device = draft.devices.get(id);
const channel = device?.channels.find(
(ch) => ch.config.index === channelIndex
);
const message = channel?.messages.find(
(msg) => msg.id === messageId
);
if (message) {
message.state = state;
if (!device) {
console.log("no device found for id");
return;
}
const messageGroup = device.messages[type];
const messageIndex =
type === "direct"
? from === device.hardware.myNodeNum
? to
: from
: channelIndex;
const messages = messageGroup.get(messageIndex);
if (!messages) {
console.log("no messages found for id");
return;
}
messageGroup.set(
messageIndex,
messages.map((msg) => {
if (msg.id === messageId) {
msg.state = state;
}
return msg;
})
);
})
);
},
@@ -554,25 +523,22 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
if (!device) {
return;
}
const node = device.nodes.find((n) => n.data.num === data.from);
const node = device.nodes.get(data.from);
if (!node) {
device.nodes.push({
data: new Protobuf.NodeInfo({
device.nodes.set(
data.from,
new Protobuf.NodeInfo({
num: data.from,
lastHeard: data.time,
snr: data.snr
}),
metadata: undefined,
deviceMetrics: [],
environmentMetrics: []
});
return;
})
);
} else {
node.data = {
...node.data,
device.nodes.set(data.from, {
...node,
lastHeard: data.time,
snr: data.snr
};
});
}
})
);
+3 -18
View File
@@ -11,7 +11,7 @@ export const subscribeAll = (
// onMeshHeartbeat
connection.events.onDeviceMetadataPacket.subscribe((metadataPacket) => {
device.addDeviceMetadataMessage(metadataPacket);
device.addMetadata(metadataPacket.from, metadataPacket.data);
});
connection.events.onRoutingPacket.subscribe((routingPacket) => {
@@ -34,27 +34,16 @@ export const subscribeAll = (
});
connection.events.onTelemetryPacket.subscribe((telemetryPacket) => {
device.setMetrics(telemetryPacket);
// device.setMetrics(telemetryPacket);
});
connection.events.onDeviceStatus.subscribe((status) => {
device.setStatus(status);
if (status === Types.DeviceStatusEnum.DEVICE_CONFIGURED) {
// device.setReady(true);
} else if (status === Types.DeviceStatusEnum.DEVICE_DISCONNECTED) {
device.setReady(false);
}
});
connection.events.onWaypointPacket.subscribe((waypoint) => {
const { data, ...rest } = waypoint;
device.addWaypoint(data);
device.addWaypointMessage({
waypointID: data.id,
state: rest.from !== myNodeNum ? "ack" : "waiting",
...rest
});
});
connection.events.onMyNodeInfo.subscribe((nodeInfo) => {
@@ -78,11 +67,7 @@ export const subscribeAll = (
});
connection.events.onChannelPacket.subscribe((channel) => {
device.addChannel({
config: channel,
lastInterraction: new Date(),
messages: []
});
device.addChannel(channel);
});
connection.events.onConfigPacket.subscribe((config) => {
device.setConfig(config);