Internal rework

This commit is contained in:
Sacha Weatherstone
2021-11-21 00:28:24 +11:00
parent 1f8170130d
commit 0cea0b2165
34 changed files with 903 additions and 803 deletions
+103
View File
@@ -1,16 +1,119 @@
import {
addChannel,
addMessage,
addNode,
addPosition,
addUser,
setDeviceStatus,
setLastMeshInterraction,
setMyNodeInfo,
setPreferences,
setReady,
} from '@core/slices/meshtasticSlice';
import { store } from '@core/store';
import {
IBLEConnection,
IHTTPConnection,
ISerialConnection,
Protobuf,
Types,
} from '@meshtastic/meshtasticjs';
type connectionType = IBLEConnection | IHTTPConnection | ISerialConnection;
export let connection: connectionType = new IHTTPConnection();
const state = store.getState().meshtastic;
export const connectionUrl = state.hostOverrideEnabled
? state.hostOverride
: import.meta.env.PROD
? window.location.hostname
: (import.meta.env.VITE_PUBLIC_DEVICE_IP as string) ??
'http://meshtastic.local';
export const ble = new IBLEConnection();
export const serial = new ISerialConnection();
export const setConnection = (conn: connectionType): void => {
cleanupListeners();
connection = conn;
registerListeners();
};
const cleanupListeners = (): void => {
connection.onDeviceStatus.cancelAll();
connection.onMyNodeInfo.cancelAll();
connection.onUserPacket.cancelAll();
connection.onPositionPacket.cancelAll();
connection.onNodeInfoPacket.cancelAll();
connection.onAdminPacket.cancelAll();
connection.onMeshHeartbeat.cancelAll();
connection.onTextPacket.cancelAll();
};
const registerListeners = (): void => {
connection.onDeviceStatus.subscribe((status) => {
store.dispatch(setDeviceStatus(status));
if (status === Types.DeviceStatusEnum.DEVICE_CONFIGURED) {
store.dispatch(setReady(true));
}
if (status === Types.DeviceStatusEnum.DEVICE_DISCONNECTED) {
store.dispatch(setReady(false));
}
});
connection.onMyNodeInfo.subscribe((nodeInfo) => {
store.dispatch(setMyNodeInfo(nodeInfo));
});
connection.onUserPacket.subscribe((user) => {
store.dispatch(addUser(user));
});
connection.onPositionPacket.subscribe((position) => {
store.dispatch(addPosition(position));
});
connection.onNodeInfoPacket.subscribe(
(nodeInfoPacket): void | { payload: Protobuf.NodeInfo; type: string } => {
store.dispatch(addNode(nodeInfoPacket.data));
},
);
connection.onAdminPacket.subscribe((adminPacket) => {
switch (adminPacket.data.variant.oneofKind) {
case 'getChannelResponse':
store.dispatch(addChannel(adminPacket.data.variant.getChannelResponse));
break;
case 'getRadioResponse':
if (adminPacket.data.variant.getRadioResponse.preferences) {
store.dispatch(
setPreferences(
adminPacket.data.variant.getRadioResponse.preferences,
),
);
}
break;
}
});
connection.onMeshHeartbeat.subscribe(
(date): void | { payload: number; type: string } =>
store.dispatch(setLastMeshInterraction(date.getTime())),
);
connection.onTextPacket.subscribe((message) => {
const myNodeNum = store.getState().meshtastic.radio.hardware.myNodeNum;
store.dispatch(
addMessage({
message: message,
ack: message.packet.from !== myNodeNum,
isSender: message.packet.from === myNodeNum,
received: new Date(message.packet.rxTime),
}),
);
});
};
+10
View File
@@ -5,12 +5,14 @@ export type currentPageName = 'messages' | 'settings';
interface AppState {
mobileNavOpen: boolean;
connectionModalOpen: boolean;
darkMode: boolean;
currentPage: currentPageName;
}
const initialState: AppState = {
mobileNavOpen: false,
connectionModalOpen: true,
darkMode: localStorage.getItem('darkMode') === 'true' ?? false,
currentPage: 'messages',
};
@@ -25,6 +27,12 @@ export const appSlice = createSlice({
closeMobileNav(state) {
state.mobileNavOpen = false;
},
openConnectionModal(state) {
state.connectionModalOpen = true;
},
closeConnectionModal(state) {
state.connectionModalOpen = false;
},
setDarkModeEnabled(state, action: PayloadAction<boolean>) {
localStorage.setItem('darkMode', String(action.payload));
state.darkMode = action.payload;
@@ -38,6 +46,8 @@ export const appSlice = createSlice({
export const {
openMobileNav,
closeMobileNav,
openConnectionModal,
closeConnectionModal,
setDarkModeEnabled,
setCurrentPage,
} = appSlice.actions;
+91 -60
View File
@@ -2,7 +2,7 @@ import { Protobuf, Types } from '@meshtastic/meshtasticjs';
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { connection } from '../connection';
// import { connection } from '../connection';
export interface MessageWithAck {
message: Types.TextPacket;
@@ -16,17 +16,31 @@ enum connType {
SERIAL,
}
export interface ChannelData {
channel: Protobuf.Channel;
messages: MessageWithAck[];
}
export interface Node {
number: number;
lastHeard: Date;
snr: number[];
positions: Protobuf.Position[];
user?: Protobuf.User;
}
export interface Radio {
channels: ChannelData[];
preferences: Protobuf.RadioConfig_UserPreferences;
hardware: Protobuf.MyNodeInfo;
}
interface MeshtasticState {
deviceStatus: Types.DeviceStatusEnum;
lastMeshInterraction: number;
ready: boolean;
myNodeInfo: Protobuf.MyNodeInfo;
users: Types.UserPacket[];
positionPackets: Types.PositionPacket[];
nodes: Protobuf.NodeInfo[];
channels: Protobuf.Channel[];
preferences: Protobuf.RadioConfig_UserPreferences;
messages: MessageWithAck[];
nodes: Node[];
radio: Radio;
hostOverrideEnabled: boolean;
hostOverride: string;
connectionType: connType;
@@ -36,13 +50,12 @@ const initialState: MeshtasticState = {
deviceStatus: Types.DeviceStatusEnum.DEVICE_DISCONNECTED,
lastMeshInterraction: 0,
ready: false,
myNodeInfo: Protobuf.MyNodeInfo.create(),
users: [],
positionPackets: [],
nodes: [],
channels: [],
preferences: Protobuf.RadioConfig_UserPreferences.create(),
messages: [],
radio: {
channels: [],
preferences: Protobuf.RadioConfig_UserPreferences.create(),
hardware: Protobuf.MyNodeInfo.create(),
},
//todo implement
// connectionMethod: localStorage.getItem('connectionMethod'),
hostOverrideEnabled:
@@ -65,76 +78,94 @@ export const meshtasticSlice = createSlice({
state.ready = action.payload;
},
setMyNodeInfo: (state, action: PayloadAction<Protobuf.MyNodeInfo>) => {
state.myNodeInfo = action.payload;
state.radio.hardware = action.payload;
},
addUser: (state, action: PayloadAction<Types.UserPacket>) => {
if (
state.users.findIndex(
(user) => user.data.id === action.payload.data.id,
) !== -1
) {
state.users = state.users.map((user) => {
return user.data.id === action.payload.data.id
? action.payload
: user;
});
} else {
state.users.push(action.payload);
const node = state.nodes.find(
(node) => node.number === action.payload.packet.from,
);
if (node) {
node.user = action.payload.data;
// todo: use rx time
node.lastHeard = new Date();
}
},
addPosition: (state, action: PayloadAction<Types.PositionPacket>) => {
if (
state.positionPackets.findIndex(
(position) => position.packet.from === action.payload.packet.from,
) !== -1
) {
state.positionPackets = state.positionPackets.map((position) => {
return position.packet.from === action.payload.packet.from
? action.payload
: position;
});
} else {
state.positionPackets.push(action.payload);
const node = state.nodes.find(
(node) => node.number === action.payload.packet.from,
);
node?.positions.push(action.payload.data);
if (node) {
// todo: use rx time
node.lastHeard = new Date();
}
},
addNode: (state, action: PayloadAction<Protobuf.NodeInfo>) => {
if (
state.nodes.findIndex((node) => node.num === action.payload.num) !== -1
) {
state.nodes = state.nodes.map((node) => {
return node.num === action.payload.num ? action.payload : node;
});
const node = state.nodes.find(
(node) => node.number === action.payload.num,
);
if (node) {
console.log('node exists');
node.lastHeard = new Date(action.payload.lastHeard * 1000);
node.snr.push(action.payload.snr);
} else {
state.nodes.push(action.payload);
console.log('node does not exist');
state.nodes.push({
number: action.payload.num,
lastHeard: new Date(action.payload.lastHeard * 1000),
snr: [action.payload.snr],
positions: [],
});
}
},
addChannel: (state, action: PayloadAction<Protobuf.Channel>) => {
if (
state.channels.findIndex(
(channel) => channel.index === action.payload.index,
state.radio.channels.findIndex(
(channel) => channel.channel.index === action.payload.index,
) !== -1
) {
state.channels = state.channels.map((channel) => {
return channel.index === action.payload.index
? action.payload
state.radio.channels = state.radio.channels.map((channel) => {
return channel.channel.index === action.payload.index
? {
channel: action.payload,
messages: channel.messages,
}
: channel;
});
} else {
state.channels.push(action.payload);
state.radio.channels.push({
channel: action.payload,
messages: [],
});
}
},
setPreferences: (
state,
action: PayloadAction<Protobuf.RadioConfig_UserPreferences>,
) => {
state.preferences = action.payload;
state.radio.preferences = action.payload;
},
addMessage: (state, action: PayloadAction<MessageWithAck>) => {
state.messages.push(action.payload);
const channelIndex = state.radio.channels.findIndex(
(channel) =>
channel.channel.index === action.payload.message.packet.channel,
);
state.radio.channels[channelIndex].messages.push(action.payload);
},
ackMessage: (state, messageId: PayloadAction<number>) => {
state.messages.map((message) => {
if (message.message.packet.id === messageId.payload) {
ackMessage: (
state,
action: PayloadAction<{ channel: number; messageId: number }>,
) => {
const channelIndex = state.radio.channels.findIndex(
(channel) => channel.channel.index === action.payload.channel,
);
// todo: update last mesh/user interraction here
state.radio.channels[channelIndex].messages.map((message) => {
if (message.message.packet.id === action.payload.messageId) {
message.ack = true;
}
});
@@ -143,21 +174,21 @@ export const meshtasticSlice = createSlice({
state.hostOverrideEnabled = action.payload;
localStorage.setItem('hostOverrideEnabled', String(action.payload));
if (state.hostOverrideEnabled !== action.payload) {
connection.disconnect();
// connection.disconnect();
}
},
setHostOverride: (state, action: PayloadAction<string>) => {
state.hostOverride = action.payload;
localStorage.setItem('hostOverride', action.payload);
if (state.hostOverride !== action.payload) {
connection.disconnect();
// connection.disconnect();
}
},
setConnectionType: (state, action: PayloadAction<connType>) => {
state.connectionType = action.payload;
localStorage.setItem('connectionType', String(action.payload));
if (state.connectionType !== action.payload) {
connection.disconnect();
// connection.disconnect();
}
},
},