|
|
@ -6,31 +6,13 @@ import { create as createStore } from "zustand"; |
|
|
|
|
|
|
|
|
export type Page = "messages" | "map" | "config" | "channels" | "nodes"; |
|
|
export type Page = "messages" | "map" | "config" | "channels" | "nodes"; |
|
|
|
|
|
|
|
|
export interface MessageWithState extends Types.PacketMetadata<string> { |
|
|
|
|
|
state: MessageState; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export type MessageState = "ack" | "waiting" | 'failed'; |
|
|
|
|
|
|
|
|
|
|
|
export interface ProcessPacketParams { |
|
|
export interface ProcessPacketParams { |
|
|
from: number; |
|
|
from: number; |
|
|
snr: number; |
|
|
snr: number; |
|
|
time: number; |
|
|
time: number; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
export type DialogVariant = |
|
|
export type DialogVariant = keyof Device["dialog"]; |
|
|
| "import" |
|
|
|
|
|
| "QR" |
|
|
|
|
|
| "shutdown" |
|
|
|
|
|
| "reboot" |
|
|
|
|
|
| "rebootOTA" |
|
|
|
|
|
| "deviceName" |
|
|
|
|
|
| "nodeRemoval" |
|
|
|
|
|
| "pkiBackup" |
|
|
|
|
|
| "nodeDetails" |
|
|
|
|
|
| "unsafeRoles" |
|
|
|
|
|
| "refreshKeys" |
|
|
|
|
|
| "deleteMessages"; |
|
|
|
|
|
|
|
|
|
|
|
type NodeError = { |
|
|
type NodeError = { |
|
|
node: number; |
|
|
node: number; |
|
|
@ -46,7 +28,6 @@ export interface Device { |
|
|
workingConfig: Protobuf.Config.Config[]; |
|
|
workingConfig: Protobuf.Config.Config[]; |
|
|
workingModuleConfig: Protobuf.ModuleConfig.ModuleConfig[]; |
|
|
workingModuleConfig: Protobuf.ModuleConfig.ModuleConfig[]; |
|
|
hardware: Protobuf.Mesh.MyNodeInfo; |
|
|
hardware: Protobuf.Mesh.MyNodeInfo; |
|
|
nodes: Map<number, Protobuf.Mesh.NodeInfo>; |
|
|
|
|
|
metadata: Map<number, Protobuf.Mesh.DeviceMetadata>; |
|
|
metadata: Map<number, Protobuf.Mesh.DeviceMetadata>; |
|
|
traceroutes: Map< |
|
|
traceroutes: Map< |
|
|
number, |
|
|
number, |
|
|
@ -57,10 +38,10 @@ export interface Device { |
|
|
activePage: Page; |
|
|
activePage: Page; |
|
|
activeNode: number; |
|
|
activeNode: number; |
|
|
waypoints: Protobuf.Mesh.Waypoint[]; |
|
|
waypoints: Protobuf.Mesh.Waypoint[]; |
|
|
// currentMetrics: Protobuf.DeviceMetrics;
|
|
|
|
|
|
pendingSettingsChanges: boolean; |
|
|
pendingSettingsChanges: boolean; |
|
|
messageDraft: string; |
|
|
messageDraft: string; |
|
|
unreadCounts: Map<number, number>; |
|
|
unreadCounts: Map<number, number>; |
|
|
|
|
|
nodesMap: Map<number, Protobuf.Mesh.NodeInfo>; |
|
|
dialog: { |
|
|
dialog: { |
|
|
import: boolean; |
|
|
import: boolean; |
|
|
QR: boolean; |
|
|
QR: boolean; |
|
|
@ -76,14 +57,12 @@ export interface Device { |
|
|
deleteMessages: boolean; |
|
|
deleteMessages: boolean; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setStatus: (status: Types.DeviceStatusEnum) => void; |
|
|
setStatus: (status: Types.DeviceStatusEnum) => void; |
|
|
setConfig: (config: Protobuf.Config.Config) => void; |
|
|
setConfig: (config: Protobuf.Config.Config) => void; |
|
|
setModuleConfig: (config: Protobuf.ModuleConfig.ModuleConfig) => void; |
|
|
setModuleConfig: (config: Protobuf.ModuleConfig.ModuleConfig) => void; |
|
|
setWorkingConfig: (config: Protobuf.Config.Config) => void; |
|
|
setWorkingConfig: (config: Protobuf.Config.Config) => void; |
|
|
setWorkingModuleConfig: (config: Protobuf.ModuleConfig.ModuleConfig) => void; |
|
|
setWorkingModuleConfig: (config: Protobuf.ModuleConfig.ModuleConfig) => void; |
|
|
setHardware: (hardware: Protobuf.Mesh.MyNodeInfo) => void; |
|
|
setHardware: (hardware: Protobuf.Mesh.MyNodeInfo) => void; |
|
|
// setMetrics: (metrics: Types.PacketMetadata<Protobuf.Telemetry>) => void;
|
|
|
|
|
|
setActivePage: (page: Page) => void; |
|
|
setActivePage: (page: Page) => void; |
|
|
setActiveNode: (node: number) => void; |
|
|
setActiveNode: (node: number) => void; |
|
|
setPendingSettingsChanges: (state: boolean) => void; |
|
|
setPendingSettingsChanges: (state: boolean) => void; |
|
|
@ -105,9 +84,15 @@ export interface Device { |
|
|
setNodeError: (nodeNum: number, error: string) => void; |
|
|
setNodeError: (nodeNum: number, error: string) => void; |
|
|
clearNodeError: (nodeNum: number) => void; |
|
|
clearNodeError: (nodeNum: number) => void; |
|
|
getNodeError: (nodeNum: number) => NodeError | undefined; |
|
|
getNodeError: (nodeNum: number) => NodeError | undefined; |
|
|
hasNodeError: (nodeNum: number) => boolean |
|
|
hasNodeError: (nodeNum: number) => boolean; |
|
|
incrementUnread: (nodeNum: number) => void; |
|
|
incrementUnread: (nodeNum: number) => void; |
|
|
resetUnread: (nodeNum: number) => void; |
|
|
resetUnread: (nodeNum: number) => void; |
|
|
|
|
|
getNodes: ( |
|
|
|
|
|
filter?: (node: Protobuf.Mesh.NodeInfo) => boolean, |
|
|
|
|
|
) => Protobuf.Mesh.NodeInfo[]; |
|
|
|
|
|
getNodesLength: () => number; |
|
|
|
|
|
getNode: (nodeNum: number) => Protobuf.Mesh.NodeInfo | undefined; |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
export interface DeviceState { |
|
|
export interface DeviceState { |
|
|
@ -125,6 +110,7 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
remoteDevices: new Map(), |
|
|
remoteDevices: new Map(), |
|
|
|
|
|
|
|
|
addDevice: (id: number) => { |
|
|
addDevice: (id: number) => { |
|
|
|
|
|
|
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
draft.devices.set(id, { |
|
|
draft.devices.set(id, { |
|
|
@ -136,7 +122,6 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
workingConfig: [], |
|
|
workingConfig: [], |
|
|
workingModuleConfig: [], |
|
|
workingModuleConfig: [], |
|
|
hardware: create(Protobuf.Mesh.MyNodeInfoSchema), |
|
|
hardware: create(Protobuf.Mesh.MyNodeInfoSchema), |
|
|
nodes: new Map(), |
|
|
|
|
|
metadata: new Map(), |
|
|
metadata: new Map(), |
|
|
traceroutes: new Map(), |
|
|
traceroutes: new Map(), |
|
|
connection: undefined, |
|
|
connection: undefined, |
|
|
@ -161,8 +146,9 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
messageDraft: "", |
|
|
messageDraft: "", |
|
|
nodeErrors: new Map(), |
|
|
nodeErrors: new Map(), |
|
|
unreadCounts: new Map(), |
|
|
unreadCounts: new Map(), |
|
|
|
|
|
nodesMap: new Map(), |
|
|
|
|
|
|
|
|
|
|
|
// --- Standard Setter Methods ---
|
|
|
setStatus: (status: Types.DeviceStatusEnum) => { |
|
|
setStatus: (status: Types.DeviceStatusEnum) => { |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
@ -177,40 +163,16 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
|
|
|
|
|
|
if (device) { |
|
|
if (device) { |
|
|
switch (config.payloadVariant.case) { |
|
|
switch (config.payloadVariant.case) { |
|
|
case "device": { |
|
|
case "device": { device.config.device = config.payloadVariant.value; break; } |
|
|
device.config.device = config.payloadVariant.value; |
|
|
case "position": { device.config.position = config.payloadVariant.value; break; } |
|
|
break; |
|
|
case "power": { device.config.power = config.payloadVariant.value; break; } |
|
|
} |
|
|
case "network": { device.config.network = config.payloadVariant.value; break; } |
|
|
case "position": { |
|
|
case "display": { device.config.display = config.payloadVariant.value; break; } |
|
|
device.config.position = config.payloadVariant.value; |
|
|
case "lora": { device.config.lora = config.payloadVariant.value; break; } |
|
|
break; |
|
|
case "bluetooth": { device.config.bluetooth = config.payloadVariant.value; break; } |
|
|
} |
|
|
case "security": { device.config.security = config.payloadVariant.value; } |
|
|
case "power": { |
|
|
|
|
|
device.config.power = config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "network": { |
|
|
|
|
|
device.config.network = config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "display": { |
|
|
|
|
|
device.config.display = config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "lora": { |
|
|
|
|
|
device.config.lora = config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "bluetooth": { |
|
|
|
|
|
device.config.bluetooth = config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "security": { |
|
|
|
|
|
device.config.security = config.payloadVariant.value; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}), |
|
|
}), |
|
|
@ -220,66 +182,20 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
|
|
|
|
|
|
if (device) { |
|
|
if (device) { |
|
|
switch (config.payloadVariant.case) { |
|
|
switch (config.payloadVariant.case) { |
|
|
case "mqtt": { |
|
|
case "mqtt": { device.moduleConfig.mqtt = config.payloadVariant.value; break; } |
|
|
device.moduleConfig.mqtt = config.payloadVariant.value; |
|
|
case "serial": { device.moduleConfig.serial = config.payloadVariant.value; break; } |
|
|
break; |
|
|
case "externalNotification": { device.moduleConfig.externalNotification = config.payloadVariant.value; break; } |
|
|
} |
|
|
case "storeForward": { device.moduleConfig.storeForward = config.payloadVariant.value; break; } |
|
|
case "serial": { |
|
|
case "rangeTest": { device.moduleConfig.rangeTest = config.payloadVariant.value; break; } |
|
|
device.moduleConfig.serial = config.payloadVariant.value; |
|
|
case "telemetry": { device.moduleConfig.telemetry = config.payloadVariant.value; break; } |
|
|
break; |
|
|
case "cannedMessage": { device.moduleConfig.cannedMessage = config.payloadVariant.value; break; } |
|
|
} |
|
|
case "audio": { device.moduleConfig.audio = config.payloadVariant.value; break; } |
|
|
case "externalNotification": { |
|
|
case "neighborInfo": { device.moduleConfig.neighborInfo = config.payloadVariant.value; break; } |
|
|
device.moduleConfig.externalNotification = |
|
|
case "ambientLighting": { device.moduleConfig.ambientLighting = config.payloadVariant.value; break; } |
|
|
config.payloadVariant.value; |
|
|
case "detectionSensor": { device.moduleConfig.detectionSensor = config.payloadVariant.value; break; } |
|
|
break; |
|
|
case "paxcounter": { device.moduleConfig.paxcounter = config.payloadVariant.value; break; } |
|
|
} |
|
|
|
|
|
case "storeForward": { |
|
|
|
|
|
device.moduleConfig.storeForward = |
|
|
|
|
|
config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "rangeTest": { |
|
|
|
|
|
device.moduleConfig.rangeTest = |
|
|
|
|
|
config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "telemetry": { |
|
|
|
|
|
device.moduleConfig.telemetry = |
|
|
|
|
|
config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "cannedMessage": { |
|
|
|
|
|
device.moduleConfig.cannedMessage = |
|
|
|
|
|
config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "audio": { |
|
|
|
|
|
device.moduleConfig.audio = config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "neighborInfo": { |
|
|
|
|
|
device.moduleConfig.neighborInfo = |
|
|
|
|
|
config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "ambientLighting": { |
|
|
|
|
|
device.moduleConfig.ambientLighting = |
|
|
|
|
|
config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "detectionSensor": { |
|
|
|
|
|
device.moduleConfig.detectionSensor = |
|
|
|
|
|
config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
case "paxcounter": { |
|
|
|
|
|
device.moduleConfig.paxcounter = |
|
|
|
|
|
config.payloadVariant.value; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
}), |
|
|
}), |
|
|
@ -289,40 +205,30 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (!device) { |
|
|
if (!device) return; |
|
|
return; |
|
|
const index = device.workingConfig.findIndex( |
|
|
} |
|
|
|
|
|
const workingConfigIndex = device?.workingConfig.findIndex( |
|
|
|
|
|
(wc) => wc.payloadVariant.case === config.payloadVariant.case, |
|
|
(wc) => wc.payloadVariant.case === config.payloadVariant.case, |
|
|
); |
|
|
); |
|
|
if (workingConfigIndex !== -1) { |
|
|
if (index !== -1) { |
|
|
device.workingConfig[workingConfigIndex] = config; |
|
|
device.workingConfig[index] = config; |
|
|
} else { |
|
|
} else { |
|
|
device?.workingConfig.push(config); |
|
|
device.workingConfig.push(config); |
|
|
} |
|
|
} |
|
|
}), |
|
|
}), |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
setWorkingModuleConfig: ( |
|
|
setWorkingModuleConfig: (moduleConfig: Protobuf.ModuleConfig.ModuleConfig) => { |
|
|
moduleConfig: Protobuf.ModuleConfig.ModuleConfig, |
|
|
|
|
|
) => { |
|
|
|
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (!device) { |
|
|
if (!device) return; |
|
|
return; |
|
|
const index = device.workingModuleConfig.findIndex( |
|
|
} |
|
|
(wmc) => wmc.payloadVariant.case === moduleConfig.payloadVariant.case, |
|
|
const workingModuleConfigIndex = device?.workingModuleConfig |
|
|
); |
|
|
.findIndex( |
|
|
if (index !== -1) { |
|
|
(wmc) => |
|
|
device.workingModuleConfig[index] = moduleConfig; |
|
|
wmc.payloadVariant.case === |
|
|
|
|
|
moduleConfig.payloadVariant.case, |
|
|
|
|
|
); |
|
|
|
|
|
if (workingModuleConfigIndex !== -1) { |
|
|
|
|
|
device.workingModuleConfig[workingModuleConfigIndex] = |
|
|
|
|
|
moduleConfig; |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
device?.workingModuleConfig.push(moduleConfig); |
|
|
device.workingModuleConfig.push(moduleConfig); |
|
|
} |
|
|
} |
|
|
}), |
|
|
}), |
|
|
); |
|
|
); |
|
|
@ -337,50 +243,6 @@ export const useDeviceStore = createStore<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;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// })
|
|
|
|
|
|
// );
|
|
|
|
|
|
// },
|
|
|
|
|
|
setActivePage: (page) => { |
|
|
setActivePage: (page) => { |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
@ -405,10 +267,9 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (!device) { |
|
|
if (device) { |
|
|
return; |
|
|
device.channels.set(channel.index, channel); |
|
|
} |
|
|
} |
|
|
device.channels.set(channel.index, channel); |
|
|
|
|
|
}), |
|
|
}), |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
@ -417,12 +278,9 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (device) { |
|
|
if (device) { |
|
|
const waypointIndex = device.waypoints.findIndex( |
|
|
const index = device.waypoints.findIndex((wp) => wp.id === waypoint.id); |
|
|
(wp) => wp.id === waypoint.id, |
|
|
if (index !== -1) { |
|
|
); |
|
|
device.waypoints[index] = waypoint; |
|
|
|
|
|
|
|
|
if (waypointIndex !== -1) { |
|
|
|
|
|
device.waypoints[waypointIndex] = waypoint; |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
device.waypoints.push(waypoint); |
|
|
device.waypoints.push(waypoint); |
|
|
} |
|
|
} |
|
|
@ -434,10 +292,9 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (!device) { |
|
|
|
|
|
return; |
|
|
if (!device) return; |
|
|
} |
|
|
device.nodesMap.set(nodeInfo.num, nodeInfo); |
|
|
device.nodes.set(nodeInfo.num, nodeInfo); |
|
|
|
|
|
}), |
|
|
}), |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
@ -458,11 +315,11 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
if (!device) { |
|
|
if (!device) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
const currentNode = device.nodes.get(user.from) ?? |
|
|
const currentNode = device.nodesMap.get(user.from) ?? create(Protobuf.Mesh.NodeInfoSchema); |
|
|
create(Protobuf.Mesh.NodeInfoSchema); |
|
|
|
|
|
currentNode.user = user.data; |
|
|
currentNode.user = user.data; |
|
|
device.nodes.set(user.from, currentNode); |
|
|
currentNode.num = user.from; |
|
|
}), |
|
|
device.nodesMap.set(user.from, currentNode); |
|
|
|
|
|
}) |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
addPosition: (position) => { |
|
|
addPosition: (position) => { |
|
|
@ -472,11 +329,11 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
if (!device) { |
|
|
if (!device) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
const currentNode = device.nodes.get(position.from) ?? |
|
|
const currentNode = device.nodesMap.get(position.from) ?? create(Protobuf.Mesh.NodeInfoSchema); |
|
|
create(Protobuf.Mesh.NodeInfoSchema); |
|
|
|
|
|
currentNode.position = position.data; |
|
|
currentNode.position = position.data; |
|
|
device.nodes.set(position.from, currentNode); |
|
|
currentNode.num = position.from; |
|
|
}), |
|
|
device.nodesMap.set(position.from, currentNode); |
|
|
|
|
|
}) |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
addConnection: (connection) => { |
|
|
addConnection: (connection) => { |
|
|
@ -493,10 +350,9 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (!device) { |
|
|
if (device) { |
|
|
return; |
|
|
device.metadata.set(from, metadata); |
|
|
} |
|
|
} |
|
|
device.metadata.set(from, metadata); |
|
|
|
|
|
}), |
|
|
}), |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
@ -504,17 +360,10 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (!device) { |
|
|
if (!device) return; |
|
|
return; |
|
|
const routes = device.traceroutes.get(traceroute.from) ?? []; |
|
|
} |
|
|
routes.push(traceroute); |
|
|
|
|
|
device.traceroutes.set(traceroute.from, routes); |
|
|
const nodetraceroutes = device.traceroutes.get(traceroute.from); |
|
|
|
|
|
if (nodetraceroutes) { |
|
|
|
|
|
nodetraceroutes.push(traceroute); |
|
|
|
|
|
device.traceroutes.set(traceroute.from, nodetraceroutes); |
|
|
|
|
|
} else { |
|
|
|
|
|
device.traceroutes.set(traceroute.from, [traceroute]); |
|
|
|
|
|
} |
|
|
|
|
|
}), |
|
|
}), |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
@ -523,46 +372,38 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (!device) { |
|
|
if (!device) { |
|
|
return; |
|
|
return |
|
|
} |
|
|
} |
|
|
device.nodes.delete(nodeNum); |
|
|
device.nodesMap.delete(nodeNum); |
|
|
}), |
|
|
})) |
|
|
); |
|
|
|
|
|
}, |
|
|
}, |
|
|
setDialogOpen: (dialog: DialogVariant, open: boolean) => { |
|
|
setDialogOpen: (dialog: DialogVariant, open: boolean) => { |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (!device) { |
|
|
if (device) { |
|
|
return; |
|
|
device.dialog[dialog] = open; |
|
|
} |
|
|
} |
|
|
device.dialog[dialog] = open; |
|
|
|
|
|
}), |
|
|
}), |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
getDialogOpen: (dialog: DialogVariant) => { |
|
|
getDialogOpen: (dialog: DialogVariant) => { |
|
|
const device = get().devices.get(id); |
|
|
const device = get().devices.get(id); |
|
|
if (!device) { |
|
|
if (!device) throw new Error(`Device ${id} not found`); |
|
|
throw new Error("Device not found"); |
|
|
|
|
|
} |
|
|
|
|
|
return device.dialog[dialog]; |
|
|
return device.dialog[dialog]; |
|
|
}, |
|
|
}, |
|
|
processPacket(data: ProcessPacketParams) { |
|
|
processPacket(data: ProcessPacketParams) { |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (!device) { |
|
|
if (!device) return; |
|
|
return; |
|
|
const node = device.nodesMap.get(data.from); |
|
|
} |
|
|
|
|
|
const node = device.nodes.get(data.from); |
|
|
|
|
|
if (node) { |
|
|
if (node) { |
|
|
device.nodes.set(data.from, { |
|
|
node.lastHeard = data.time; |
|
|
...node, |
|
|
node.snr = data.snr; |
|
|
lastHeard: data.time, |
|
|
device.nodesMap.set(data.from, node); |
|
|
snr: data.snr, |
|
|
|
|
|
}); |
|
|
|
|
|
} else { |
|
|
} else { |
|
|
device.nodes.set( |
|
|
device.nodesMap.set( |
|
|
data.from, |
|
|
data.from, |
|
|
create(Protobuf.Mesh.NodeInfoSchema, { |
|
|
create(Protobuf.Mesh.NodeInfoSchema, { |
|
|
num: data.from, |
|
|
num: data.from, |
|
|
@ -606,26 +447,19 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
}, |
|
|
}, |
|
|
getNodeError: (nodeNum: number) => { |
|
|
getNodeError: (nodeNum: number) => { |
|
|
const device = get().devices.get(id); |
|
|
const device = get().devices.get(id); |
|
|
if (!device) { |
|
|
if (!device) throw new Error(`Device ${id} not found`); |
|
|
throw new Error("Device not found"); |
|
|
|
|
|
} |
|
|
|
|
|
return device.nodeErrors.get(nodeNum); |
|
|
return device.nodeErrors.get(nodeNum); |
|
|
}, |
|
|
}, |
|
|
hasNodeError: (nodeNum: number) => { |
|
|
hasNodeError: (nodeNum: number) => { |
|
|
const device = get().devices.get(id); |
|
|
const device = get().devices.get(id); |
|
|
if (!device) { |
|
|
if (!device) throw new Error(`Device ${id} not found`); |
|
|
throw new Error("Device not found"); |
|
|
|
|
|
} |
|
|
|
|
|
return device.nodeErrors.has(nodeNum); |
|
|
return device.nodeErrors.has(nodeNum); |
|
|
}, |
|
|
}, |
|
|
incrementUnread: (nodeNum: number) => { |
|
|
incrementUnread: (nodeNum: number) => { |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (!device) { |
|
|
if (!device) return; |
|
|
console.warn(`incrementUnread: Device with ID ${id} not found.`); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
const currentCount = device.unreadCounts.get(nodeNum) ?? 0; |
|
|
const currentCount = device.unreadCounts.get(nodeNum) ?? 0; |
|
|
device.unreadCounts.set(nodeNum, currentCount + 1); |
|
|
device.unreadCounts.set(nodeNum, currentCount + 1); |
|
|
}) |
|
|
}) |
|
|
@ -635,29 +469,54 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({ |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
const device = draft.devices.get(id); |
|
|
const device = draft.devices.get(id); |
|
|
if (!device) { |
|
|
if (!device) return; |
|
|
console.warn(`resetUnread: Device with ID ${id} not found.`); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
device.unreadCounts.set(nodeNum, 0); |
|
|
device.unreadCounts.set(nodeNum, 0); |
|
|
|
|
|
|
|
|
if (device.unreadCounts.get(nodeNum) === 0) { |
|
|
if (device.unreadCounts.get(nodeNum) === 0) { |
|
|
device.unreadCounts.delete(nodeNum); |
|
|
device.unreadCounts.delete(nodeNum); |
|
|
} |
|
|
} |
|
|
}) |
|
|
}) |
|
|
); |
|
|
); |
|
|
}, |
|
|
}, |
|
|
|
|
|
getNodes: (filter?: (node: Protobuf.Mesh.NodeInfo) => boolean): Protobuf.Mesh.NodeInfo[] => { |
|
|
|
|
|
const device = get().devices.get(id); |
|
|
|
|
|
if (!device) { |
|
|
|
|
|
return []; |
|
|
|
|
|
} |
|
|
|
|
|
const allNodes = Array.from(device.nodesMap.values()).filter( |
|
|
|
|
|
(node) => node.num !== get().devices.get(id)?.hardware.myNodeNum); |
|
|
|
|
|
if (filter) { |
|
|
|
|
|
return allNodes.filter(filter); |
|
|
|
|
|
} |
|
|
|
|
|
return allNodes; |
|
|
|
|
|
}, |
|
|
|
|
|
getNode: (nodeNum: number): Protobuf.Mesh.NodeInfo | undefined => { |
|
|
|
|
|
const device = get().devices.get(id); |
|
|
|
|
|
if (!device) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
if (!device.nodesMap.has(nodeNum)) { |
|
|
|
|
|
return undefined; |
|
|
|
|
|
} |
|
|
|
|
|
return device.nodesMap.get(nodeNum); |
|
|
|
|
|
}, |
|
|
|
|
|
getNodesLength: () => { |
|
|
|
|
|
const device = get().devices.get(id); |
|
|
|
|
|
if (!device) { |
|
|
|
|
|
return 0; |
|
|
|
|
|
} |
|
|
|
|
|
return device.nodesMap.size |
|
|
|
|
|
}, |
|
|
}); |
|
|
}); |
|
|
}), |
|
|
}), |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
const device = get().devices.get(id); |
|
|
const device = get().devices.get(id); |
|
|
|
|
|
|
|
|
if (!device) { |
|
|
if (!device) { |
|
|
throw new Error("Device not found"); |
|
|
throw new Error(`Failed to create or retrieve device with ID ${id}`); |
|
|
} |
|
|
} |
|
|
return device; |
|
|
return device; |
|
|
}, |
|
|
}, |
|
|
|
|
|
|
|
|
removeDevice: (id) => { |
|
|
removeDevice: (id) => { |
|
|
set( |
|
|
set( |
|
|
produce<DeviceState>((draft) => { |
|
|
produce<DeviceState>((draft) => { |
|
|
|