Initial 1.3.x rework

This commit is contained in:
Sacha Weatherstone
2022-07-26 08:52:23 +10:00
parent ff6019098b
commit a2280ab96e
163 changed files with 6383 additions and 14397 deletions
+418
View File
@@ -0,0 +1,418 @@
import { createContext, useContext } from "react";
import { produce } from "immer";
import create from "zustand";
import { IConnection, Protobuf, Types } from "@meshtastic/meshtasticjs";
export type Page =
| "messages"
| "map"
| "extensions"
| "config"
| "channels"
| "info";
export interface MessageWithAck {
message: Types.TextPacket;
ack: boolean;
received: Date;
}
export interface Channel {
config: Protobuf.Channel;
lastInterraction: Date;
messages: MessageWithAck[];
}
export interface Node {
deviceMetrics: Protobuf.DeviceMetrics;
environmentMetrics: Protobuf.EnvironmentMetrics;
data: Protobuf.NodeInfo;
}
export interface Device {
ready: boolean;
status: Types.DeviceStatusEnum;
channels: Channel[];
config: Protobuf.LocalConfig;
moduleConfig: Protobuf.LocalModuleConfig;
hardware: Protobuf.MyNodeInfo;
nodes: Node[];
connection?: IConnection;
activeChat: number;
activePage: Page;
setReady(ready: boolean): void;
setStatus: (status: Types.DeviceStatusEnum) => void;
addChannel: (channel: Channel) => void;
setConfig: (config: Protobuf.Config) => void;
setModuleConfig: (config: Protobuf.ModuleConfig) => void;
setHardware: (hardware: Protobuf.MyNodeInfo) => void;
setMetrics: (metrics: Types.TelemetryPacket) => void;
setActiveChat: (chatIndex: number) => void;
setActivePage: (page: Page) => void;
addNodeInfo: (nodeInfo: Types.NodeInfoPacket) => void;
addUser: (user: Types.UserPacket) => void;
addPosition: (position: Types.PositionPacket) => void;
addConnection: (connection: IConnection) => void;
addMessage: (message: MessageWithAck) => void;
ackMessage: (channelIndex: number, messageId: number) => void;
}
export interface DeviceState {
devices: Map<number, Device>;
remoteDevices: Map<number, undefined>;
addDevice: (id: number) => Device;
removeDevice: (id: number) => void;
getDevices: () => Device[];
}
export const useDeviceStore = create<DeviceState>((set, get) => ({
devices: new Map(),
remoteDevices: new Map(),
addDevice: (id: number) => {
set(
produce<DeviceState>((draft) => {
draft.devices.set(id, {
ready: false,
status: Types.DeviceStatusEnum.DEVICE_DISCONNECTED,
channels: [],
config: Protobuf.LocalConfig.create(),
moduleConfig: Protobuf.LocalModuleConfig.create(),
hardware: Protobuf.MyNodeInfo.create(),
nodes: [],
connection: undefined,
activeChat: 0,
activePage: "messages",
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) => {
const device = draft.devices.get(id);
if (device) {
device.status = status;
}
})
);
},
addChannel: (channel: 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
);
if (channelIndex !== -1) {
const messages = device.channels[channelIndex].messages;
device.channels[channelIndex] = channel;
device.channels[channelIndex].messages = messages;
} else {
device.channels.push(channel);
}
}
})
);
},
setConfig: (config: Protobuf.Config) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
switch (config.payloadVariant.oneofKind) {
case "device":
device.config.device = config.payloadVariant.device;
break;
case "position":
device.config.position = config.payloadVariant.position;
break;
case "power":
device.config.power = config.payloadVariant.power;
break;
case "wifi":
device.config.wifi = config.payloadVariant.wifi;
break;
case "display":
device.config.display = config.payloadVariant.display;
break;
case "lora":
device.config.lora = config.payloadVariant.lora;
break;
}
}
})
);
},
setModuleConfig: (config: Protobuf.ModuleConfig) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
switch (config.payloadVariant.oneofKind) {
case "mqtt":
device.moduleConfig.mqtt = config.payloadVariant.mqtt;
break;
case "serial":
device.moduleConfig.serial = config.payloadVariant.serial;
break;
case "externalNotification":
device.moduleConfig.externalNotification =
config.payloadVariant.externalNotification;
break;
case "storeForward":
device.moduleConfig.storeForward =
config.payloadVariant.storeForward;
break;
case "rangeTest":
device.moduleConfig.rangeTest =
config.payloadVariant.rangeTest;
break;
case "telemetry":
device.moduleConfig.telemetry =
config.payloadVariant.telemetry;
break;
case "cannedMessage":
device.moduleConfig.cannedMessage =
config.payloadVariant.cannedMessage;
break;
}
}
})
);
},
setHardware: (hardware: Protobuf.MyNodeInfo) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
device.hardware = hardware;
}
})
);
},
setMetrics: (metrics: Types.TelemetryPacket) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
let node = device?.nodes.find(
(n) => n.data.num === metrics.packet.from
);
if (device && !node) {
node = {
data: Protobuf.NodeInfo.create({
num: metrics.packet.from,
snr: metrics.packet.rxSnr,
lastHeard: new Date().getSeconds(),
}),
deviceMetrics: Protobuf.DeviceMetrics.create(),
environmentMetrics: Protobuf.EnvironmentMetrics.create(),
};
device.nodes.push(node);
}
if (node) {
switch (metrics.data.variant.oneofKind) {
case "deviceMetrics":
node.deviceMetrics = metrics.data.variant.deviceMetrics;
break;
case "environmentMetrics":
node.environmentMetrics =
metrics.data.variant.environmentMetrics;
break;
}
}
})
);
},
setActiveChat: (chatIndex) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
device.activeChat = chatIndex;
}
})
);
},
setActivePage: (page) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
device.activePage = page;
}
})
);
},
addNodeInfo: (nodeInfo) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
const node = device.nodes.find(
(node) => node.data.num === nodeInfo.data.num
);
if (node) {
node.data = nodeInfo.data;
// if (action.payload.packet.rxTime) {
// node.data.lastHeard = new Date(
// action.payload.packet.rxTime * 1000,
// ).getTime();
// }
} else {
device.nodes.push({
data: Protobuf.NodeInfo.create(nodeInfo.data),
deviceMetrics: Protobuf.DeviceMetrics.create(),
environmentMetrics: Protobuf.EnvironmentMetrics.create(),
});
}
}
})
);
},
addUser: (user) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
const node = device.nodes.find(
(node) => node.data.num === user.packet.from
);
if (node) {
node.data.user = user.data;
// if (action.payload.packet.rxTime) {
// node.data.lastHeard = new Date(
// action.payload.packet.rxTime * 1000,
// ).getTime();
// }
} else {
device.nodes.push({
data: Protobuf.NodeInfo.create({
num: user.packet.from,
snr: user.packet.rxSnr,
user: user.data,
}),
deviceMetrics: Protobuf.DeviceMetrics.create(),
environmentMetrics: Protobuf.EnvironmentMetrics.create(),
});
}
}
})
);
},
addPosition: (position) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
const node = device.nodes.find(
(node) => node.data.num === position.packet.from
);
if (node) {
node.data.position = position.data;
// if (action.payload.packet.rxTime) {
// node.data.lastHeard = new Date(
// action.payload.packet.rxTime * 1000,
// ).getTime();
// }
} else {
console.log("PUSH333333333333333333333");
device.nodes.push({
data: Protobuf.NodeInfo.create({
num: position.packet.from,
position: position.data,
}),
deviceMetrics: Protobuf.DeviceMetrics.create(),
environmentMetrics: Protobuf.EnvironmentMetrics.create(),
});
}
}
})
);
},
addConnection: (connection) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
device.connection = connection;
}
})
);
},
addMessage: (message) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
device.channels
.find(
(ch) => ch.config.index === message.message.packet.channel
)
?.messages.push(message);
}
})
);
},
ackMessage: (channelIndex: number, messageId: number) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
const channel = device.channels.find(
(ch) => ch.config.index === channelIndex
);
if (channel) {
const message = channel.messages.find(
(msg) => msg.message.packet.id === messageId
);
if (message) {
message.ack = true;
}
}
}
})
);
},
});
})
);
const device = get().devices.get(id);
if (!device) {
throw new Error("Device not found");
}
return device;
},
removeDevice: (id) =>
produce<DeviceState>((draft) => {
draft.devices.delete(id);
}),
getDevices: () => Array.from(get().devices.values()),
}));
export const DeviceContext = createContext<Device | undefined>(undefined);
export const useDevice = (): Device => {
const context = useContext(DeviceContext);
if (context === undefined) {
throw new Error("useDevice must be used within a ConnectionProvider");
}
return context;
};