From 074f9a7210e5a5bb25c01193ffef3c73e32f991a Mon Sep 17 00:00:00 2001 From: Sacha Weatherstone Date: Sun, 21 Nov 2021 23:45:56 +1100 Subject: [PATCH] WIP --- package.json | 1 + pnpm-lock.yaml | 17 + src/components/Channel.tsx | 44 ++- src/components/Connection.tsx | 307 +++++-------------- src/components/FormFooter.tsx | 10 +- src/components/LoraConfig.tsx | 115 ------- src/components/connection/BLE.tsx | 64 ++++ src/components/connection/HTTP.tsx | 40 +++ src/components/connection/Serial.tsx | 65 ++++ src/components/generic/Modal.tsx | 14 +- src/components/menu/buttons/DeviceStatus.tsx | 12 +- src/core/connection.ts | 40 ++- src/core/slices/appSlice.ts | 48 +++ src/pages/settings/Channels.tsx | 202 +++++++++++- todo.txt | 2 + 15 files changed, 598 insertions(+), 383 deletions(-) delete mode 100644 src/components/LoraConfig.tsx create mode 100644 src/components/connection/BLE.tsx create mode 100644 src/components/connection/HTTP.tsx create mode 100644 src/components/connection/Serial.tsx diff --git a/package.json b/package.json index 679864e3..c31233cc 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "react-i18next": "^11.14.2", "react-icons": "^4.3.1", "react-json-pretty": "^2.2.0", + "react-qr-code": "^2.0.3", "react-redux": "^7.2.6", "rfc4648": "^1.5.0", "swr": "^1.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3554e977..d76d08a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -36,6 +36,7 @@ specifiers: react-i18next: ^11.14.2 react-icons: ^4.3.1 react-json-pretty: ^2.2.0 + react-qr-code: ^2.0.3 react-redux: ^7.2.6 rfc4648: ^1.5.0 swr: ^1.0.1 @@ -63,6 +64,7 @@ dependencies: react-i18next: 11.14.2_i18next@21.5.2+react@17.0.2 react-icons: 4.3.1_react@17.0.2 react-json-pretty: 2.2.0_react-dom@17.0.2+react@17.0.2 + react-qr-code: 2.0.3_react@17.0.2 react-redux: 7.2.6_react-dom@17.0.2+react@17.0.2 rfc4648: 1.5.0 swr: 1.0.1_react@17.0.2 @@ -4063,6 +4065,10 @@ packages: engines: {node: '>=6'} dev: true + /qr.js/0.0.0: + resolution: {integrity: sha1-ys6GOG9ZoNuAUPqQ2baw6IoeNk8=} + dev: false + /queue-microtask/1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -4149,6 +4155,17 @@ packages: react-dom: 17.0.2_react@17.0.2 dev: false + /react-qr-code/2.0.3_react@17.0.2: + resolution: {integrity: sha512-6GDH0l53lksf2JgZwwcoS0D60a1OAal/GQRyNFkMBW19HjSqvtD5S20scmSQsKl+BgWM85Wd5DCcUYoHd+PZnQ==} + peerDependencies: + react: ^16.x || ^17.x + react-native-svg: '*' + dependencies: + prop-types: 15.7.2 + qr.js: 0.0.0 + react: 17.0.2 + dev: false + /react-redux/7.2.6_react-dom@17.0.2+react@17.0.2: resolution: {integrity: sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==} peerDependencies: diff --git a/src/components/Channel.tsx b/src/components/Channel.tsx index f60b3fa9..d2b0249f 100644 --- a/src/components/Channel.tsx +++ b/src/components/Channel.tsx @@ -1,16 +1,19 @@ import React from 'react'; import { useForm } from 'react-hook-form'; +import { FaQrcode } from 'react-icons/fa'; import { FiEdit3, FiSave } from 'react-icons/fi'; +import QRCode from 'react-qr-code'; +import { Card } from '@components/generic/Card'; +import { Checkbox } from '@components/generic/form/Checkbox'; +import { Input } from '@components/generic/form/Input'; +import { IconButton } from '@components/generic/IconButton'; import { Loading } from '@components/generic/Loading'; +import { Modal } from '@components/generic/Modal'; +import { connection } from '@core/connection'; import { Protobuf } from '@meshtastic/meshtasticjs'; -import { connection } from '../core/connection'; -import { Checkbox } from './generic/form/Checkbox'; -import { Input } from './generic/form/Input'; -import { IconButton } from './generic/IconButton'; - export interface ChannelProps { channel: Protobuf.Channel; hideEnabled?: boolean; @@ -22,6 +25,7 @@ export const Channel = ({ }: ChannelProps): JSX.Element => { const [edit, setEdit] = React.useState(false); const [loading, setLoading] = React.useState(false); + const [showQr, setShowQr] = React.useState(false); const { register, handleSubmit } = useForm<{ enabled: boolean; @@ -80,6 +84,16 @@ export const Channel = ({ return (
+ { + setShowQr(false); + }} + > + + + + {edit ? ( <> {loading && } @@ -139,12 +153,20 @@ export const Channel = ({ : `Channel: ${channel.index}`}
- { - setEdit(true); - }} - icon={} - /> +
+ { + setShowQr(true); + }} + icon={} + /> + { + setEdit(true); + }} + icon={} + /> +
)} diff --git a/src/components/Connection.tsx b/src/components/Connection.tsx index 0747d6eb..c6dd267b 100644 --- a/src/components/Connection.tsx +++ b/src/components/Connection.tsx @@ -1,267 +1,114 @@ import React from 'react'; -import { FiCheck } from 'react-icons/fi'; -import JSONPretty from 'react-json-pretty'; - import { useAppDispatch, useAppSelector } from '@app/hooks/redux'; +import { Serial } from '@components/connection/Serial'; import { Button } from '@components/generic/Button'; import { Card } from '@components/generic/Card'; -import { Checkbox } from '@components/generic/form/Checkbox'; -import { Input } from '@components/generic/form/Input'; import { Select } from '@components/generic/form/Select'; -import { IconButton } from '@components/generic/IconButton'; import { Modal } from '@components/generic/Modal'; import { - ble, + cleanupListeners, connection, connectionUrl, - serial, setConnection, } from '@core/connection'; -import { closeConnectionModal } from '@core/slices/appSlice'; import { - IBLEConnection, - IHTTPConnection, - ISerialConnection, - Protobuf, - SettingsManager, -} from '@meshtastic/meshtasticjs'; -import type { - BLEConnectionParameters, - HTTPConnectionParameters, - SerialConnectionParameters, -} from '@meshtastic/meshtasticjs/dist/types'; + closeConnectionModal, + connType, + setConnectionParams, + setConnType, +} from '@core/slices/appSlice'; +import { Types } from '@meshtastic/meshtasticjs'; -import { DeviceStatus } from './menu/buttons/DeviceStatus'; - -enum connType { - HTTP, - BLE, - SERIAL, -} +import { BLE } from './connection/BLE'; +import { HTTP } from './connection/HTTP'; export const Connection = (): JSX.Element => { const dispatch = useAppDispatch(); - const [selectedConnType, setSelectedConnType] = React.useState(connType.HTTP); - const [bleDevices, setBleDevices] = React.useState([]); - const [serialDevices, setSerialDevices] = React.useState([]); - const [httpIpSource, setHttpIpSource] = React.useState<'local' | 'remote'>( - 'local', - ); - const hostOverrideEnabled = useAppSelector( - (state) => state.meshtastic.hostOverrideEnabled, - ); - const hostOverride = useAppSelector((state) => state.meshtastic.hostOverride); - const connectionModalOpen = useAppSelector( - (state) => state.app.connectionModalOpen, - ); - const ready = useAppSelector((state) => state.meshtastic.ready); - const connect = async ( - connectionType: connType, - params: - | HTTPConnectionParameters - | SerialConnectionParameters - | BLEConnectionParameters, - ): Promise => { - connection.complete(); - await connection.disconnect(); - if (connectionType === connType.BLE) { - setConnection(new IBLEConnection()); - } else if (connectionType === connType.HTTP) { - setConnection(new IHTTPConnection()); - } else { - setConnection(new ISerialConnection()); - } - - // @ts-ignore tmp - await connection.connect(params); - }; - - const updateBleDeviceList = React.useCallback(async (): Promise => { - const devices = await ble.getDevices(); - setBleDevices(devices); - }, []); - - const updateSerialDeviceList = React.useCallback(async (): Promise => { - const devices = await serial.getPorts(); - setSerialDevices(devices); - }, []); + const state = useAppSelector((state) => state.meshtastic); + const appState = useAppSelector((state) => state.app); React.useEffect(() => { - if (ready) { - dispatch(closeConnectionModal()); - } - }, [ready, dispatch]); - - React.useEffect(() => { - if (selectedConnType === connType.BLE) { - void updateBleDeviceList(); - } - if (selectedConnType === connType.SERIAL) { - void updateSerialDeviceList(); - } - }, [selectedConnType, updateBleDeviceList, updateSerialDeviceList]); - - React.useEffect(() => { - const connectionMethod = localStorage.getItem('connectionMethod'); - - switch (connectionMethod) { - case 'serial': - setConnection(new ISerialConnection()); - //show connection dialogue - break; - case 'bluetooth': - setConnection(new IBLEConnection()); - //show connection dialogue - break; - default: - setConnection(new IHTTPConnection()); - void connection.connect({ + dispatch( + setConnectionParams({ + type: connType.HTTP, + params: { address: connectionUrl, tls: false, receiveBatchRequests: false, fetchInterval: 2000, - }); - break; + }, + }), + ); + void setConnection(connType.HTTP); + }, [dispatch]); + + React.useEffect(() => { + if (state.ready) { + dispatch(closeConnectionModal()); } - SettingsManager.debugMode = Protobuf.LogRecord_Level.TRACE; - }, [hostOverrideEnabled, hostOverride]); + }, [state.ready, dispatch]); return ( { dispatch(closeConnectionModal()); }} > -
- {ready ? ( -
- { - setHttpIpSource(e.target.value as 'local' | 'remote'); - }} - /> - {httpIpSource === 'local' ? ( - - ) : ( - - )} - - - )} - {selectedConnType === connType.BLE && ( -
-
- - -
-
-
Previously connected devices
- {bleDevices.map((device, index) => ( -
=> { - await connect(connType.BLE, { - device: device, - }); - }} - className="flex justify-between p-2 bg-gray-700 rounded-md" - key={index} - > -
{device.name}
- => { - await connect(connType.BLE, { - device: device, - }); - }} - icon={} - /> -
- ))} -
-
- )} - {selectedConnType === connType.SERIAL && ( -
-
- - -
-
-
Previously connected devices
- {serialDevices.map((device, index) => ( -
-
- {device.getInfo().usbProductId} - {device.getInfo().usbVendorId} -
- => { - await connect(connType.SERIAL, { - // @ts-ignore tmp - device: device, - }); - }} - icon={} - /> - -
- ))} -
-
- )} - - ) : ( -
- +
+
+
+

+ {`Connected to: ${ + state.nodes.find( + (node) => node.number === state.radio.hardware.myNodeNum, + )?.user?.longName ?? 'Unknown' + }`} +

+

{`Via: ${connType[appState.connType]}`}

- )} +
+ {state.deviceStatus === + Types.DeviceStatusEnum.DEVICE_DISCONNECTED ? ( + + ) : ( + + )} +
+
+
+ - - - - - - -
- - ); -}; diff --git a/src/components/connection/BLE.tsx b/src/components/connection/BLE.tsx new file mode 100644 index 00000000..5f3edb20 --- /dev/null +++ b/src/components/connection/BLE.tsx @@ -0,0 +1,64 @@ +import React from 'react'; + +import { FiCheck } from 'react-icons/fi'; + +import { connType } from '@app/core/slices/appSlice'; +import { Button } from '@components/generic/Button'; +import { IconButton } from '@components/generic/IconButton'; +import { ble, setConnection } from '@core/connection'; + +export const BLE = (): JSX.Element => { + const [bleDevices, setBleDevices] = React.useState([]); + + const updateBleDeviceList = React.useCallback(async (): Promise => { + const devices = await ble.getDevices(); + setBleDevices(devices); + }, []); + + React.useEffect(() => { + void updateBleDeviceList(); + }, [updateBleDeviceList]); + + return ( +
+
+ + +
+
+
Previously connected devices
+ {bleDevices.map((device, index) => ( +
=> { + await setConnection(connType.BLE, { + device: device, + }); + }} + className="flex justify-between p-2 bg-gray-700 rounded-md" + key={index} + > +
{device.name}
+ => { + await setConnection(connType.BLE, { + device: device, + }); + }} + icon={} + /> +
+ ))} +
+
+ ); +}; diff --git a/src/components/connection/HTTP.tsx b/src/components/connection/HTTP.tsx new file mode 100644 index 00000000..a5996437 --- /dev/null +++ b/src/components/connection/HTTP.tsx @@ -0,0 +1,40 @@ +import React from 'react'; + +import { Checkbox } from '@components/generic/form/Checkbox'; +import { Input } from '@components/generic/form/Input'; +import { Select } from '@components/generic/form/Select'; +import { connectionUrl } from '@core/connection'; + +export const HTTP = (): JSX.Element => { + const [httpIpSource, setHttpIpSource] = React.useState<'local' | 'remote'>( + 'local', + ); + + return ( +
+ + ) : ( + + )} + +
+ ); +}; diff --git a/src/components/connection/Serial.tsx b/src/components/connection/Serial.tsx new file mode 100644 index 00000000..58dbb6dd --- /dev/null +++ b/src/components/connection/Serial.tsx @@ -0,0 +1,65 @@ +import React from 'react'; + +import { FiCheck } from 'react-icons/fi'; +import JSONPretty from 'react-json-pretty'; + +import { Button } from '@components/generic/Button'; +import { IconButton } from '@components/generic/IconButton'; +import { serial, setConnection } from '@core/connection'; +import { connType } from '@core/slices/appSlice'; + +export const Serial = (): JSX.Element => { + const [serialDevices, setSerialDevices] = React.useState([]); + + const updateSerialDeviceList = React.useCallback(async (): Promise => { + const devices = await serial.getPorts(); + setSerialDevices(devices); + }, []); + + React.useEffect(() => { + void updateSerialDeviceList(); + }, [updateSerialDeviceList]); + + return ( +
+
+ + +
+
+
Previously connected devices
+ {serialDevices.map((device, index) => ( +
+
+ {device.getInfo().usbProductId} + {device.getInfo().usbVendorId} +
+ => { + await setConnection(connType.SERIAL, { + // @ts-ignore tmp + device: device, + }); + }} + icon={} + /> + +
+ ))} +
+
+ ); +}; diff --git a/src/components/generic/Modal.tsx b/src/components/generic/Modal.tsx index 1ee81f48..a90aef6a 100644 --- a/src/components/generic/Modal.tsx +++ b/src/components/generic/Modal.tsx @@ -3,13 +3,21 @@ import type React from 'react'; import { useAppSelector } from '@app/hooks/redux'; import { Dialog } from '@headlessui/react'; -export interface ModalProps { +type DefaultDivProps = JSX.IntrinsicElements['div']; + +export interface ModalProps extends DefaultDivProps { children: React.ReactNode; open: boolean; onClose: () => void; } -export const Modal = ({ children, open, onClose }: ModalProps): JSX.Element => { +export const Modal = ({ + children, + open, + onClose, + className, + ...props +}: ModalProps): JSX.Element => { const darkMode = useAppSelector((state) => state.app.darkMode); return ( <> @@ -27,7 +35,7 @@ export const Modal = ({ children, open, onClose }: ModalProps): JSX.Element => { > ​ -
+
{children}
diff --git a/src/components/menu/buttons/DeviceStatus.tsx b/src/components/menu/buttons/DeviceStatus.tsx index 0d9ea68c..31002021 100644 --- a/src/components/menu/buttons/DeviceStatus.tsx +++ b/src/components/menu/buttons/DeviceStatus.tsx @@ -9,7 +9,7 @@ import { Types } from '@meshtastic/meshtasticjs'; export const DeviceStatus = (): JSX.Element => { const dispatch = useAppDispatch(); - const deviceStatus = useAppSelector((state) => state.meshtastic.deviceStatus); + const state = useAppSelector((state) => state.meshtastic); const ready = useAppSelector((state) => state.meshtastic.ready); return ( @@ -27,18 +27,22 @@ export const DeviceStatus = (): JSX.Element => { [ Types.DeviceStatusEnum.DEVICE_CONNECTED, Types.DeviceStatusEnum.DEVICE_CONFIGURED, - ].includes(deviceStatus) + ].includes(state.deviceStatus) ? 'bg-green-400' : [ Types.DeviceStatusEnum.DEVICE_CONNECTING, Types.DeviceStatusEnum.DEVICE_RECONNECTING, Types.DeviceStatusEnum.DEVICE_CONFIGURING, - ].includes(deviceStatus) + ].includes(state.deviceStatus) ? 'bg-yellow-400' : 'bg-gray-400' }`} >
-
{Types.DeviceStatusEnum[deviceStatus]}
+
+ {state.nodes.find( + (node) => node.number === state.radio.hardware.myNodeNum, + )?.user?.longName ?? 'Unknown'} +
{ready ? ( diff --git a/src/core/connection.ts b/src/core/connection.ts index f1166f6f..520059c6 100644 --- a/src/core/connection.ts +++ b/src/core/connection.ts @@ -1,3 +1,4 @@ +import { connType } from '@core/slices/appSlice'; import { addChannel, addMessage, @@ -16,6 +17,7 @@ import { IHTTPConnection, ISerialConnection, Protobuf, + SettingsManager, Types, } from '@meshtastic/meshtasticjs'; @@ -34,14 +36,42 @@ export const connectionUrl = state.hostOverrideEnabled export const ble = new IBLEConnection(); export const serial = new ISerialConnection(); -export const setConnection = (conn: connectionType): void => { +export const setConnection = async (conn: connType): Promise => { + await connection.disconnect(); cleanupListeners(); - connection = conn; - + switch (conn) { + case connType.HTTP: + connection = new IHTTPConnection(); + break; + case connType.BLE: + connection = new IBLEConnection(); + break; + case connType.SERIAL: + connection = new ISerialConnection(); + break; + } registerListeners(); + const connectionParams = store.getState().app.connectionParams; + switch (conn) { + case connType.HTTP: + await connection.connect(connectionParams.HTTP); + break; + case connType.BLE: + await connection.connect( + // @ts-ignore tmp + connectionParams.BLE, + ); + break; + case connType.SERIAL: + await connection.connect( + // @ts-ignore tmp + connectionParams.SERIAL, + ); + break; + } }; -const cleanupListeners = (): void => { +export const cleanupListeners = (): void => { connection.onDeviceStatus.cancelAll(); connection.onMyNodeInfo.cancelAll(); connection.onUserPacket.cancelAll(); @@ -53,6 +83,8 @@ const cleanupListeners = (): void => { }; const registerListeners = (): void => { + SettingsManager.debugMode = Protobuf.LogRecord_Level.TRACE; + connection.onDeviceStatus.subscribe((status) => { store.dispatch(setDeviceStatus(status)); diff --git a/src/core/slices/appSlice.ts b/src/core/slices/appSlice.ts index c2a5550b..a5dc5dc5 100644 --- a/src/core/slices/appSlice.ts +++ b/src/core/slices/appSlice.ts @@ -1,13 +1,26 @@ +import type { Types } from '@meshtastic/meshtasticjs'; import type { PayloadAction } from '@reduxjs/toolkit'; import { createSlice } from '@reduxjs/toolkit'; export type currentPageName = 'messages' | 'settings'; +export enum connType { + HTTP, + BLE, + SERIAL, +} + interface AppState { mobileNavOpen: boolean; connectionModalOpen: boolean; darkMode: boolean; currentPage: currentPageName; + connType: connType; + connectionParams: { + BLE: Types.BLEConnectionParameters; + HTTP: Types.HTTPConnectionParameters; + SERIAL: Types.SerialConnectionParameters; + }; } const initialState: AppState = { @@ -15,6 +28,17 @@ const initialState: AppState = { connectionModalOpen: true, darkMode: localStorage.getItem('darkMode') === 'true' ?? false, currentPage: 'messages', + connType: connType.HTTP, + connectionParams: { + BLE: {}, + HTTP: { + address: 'http://meshtastic.local/', + tls: false, + receiveBatchRequests: false, + fetchInterval: 2000, + }, + SERIAL: {}, + }, }; export const appSlice = createSlice({ @@ -40,6 +64,28 @@ export const appSlice = createSlice({ setCurrentPage(state, action: PayloadAction) { state.currentPage = action.payload; }, + setConnType(state, action: PayloadAction) { + state.connType = action.payload; + }, + setConnectionParams( + state, + action: PayloadAction<{ + type: connType; + params: Types.ConnectionParameters; + }>, + ) { + switch (action.payload.type) { + case connType.BLE: + state.connectionParams.BLE = action.payload.params; + break; + case connType.HTTP: + state.connectionParams.HTTP = action.payload.params; + break; + case connType.SERIAL: + state.connectionParams.SERIAL = action.payload.params; + break; + } + }, }, }); @@ -50,6 +96,8 @@ export const { closeConnectionModal, setDarkModeEnabled, setCurrentPage, + setConnType, + setConnectionParams, } = appSlice.actions; export default appSlice.reducer; diff --git a/src/pages/settings/Channels.tsx b/src/pages/settings/Channels.tsx index f12760c8..3d7bd580 100644 --- a/src/pages/settings/Channels.tsx +++ b/src/pages/settings/Channels.tsx @@ -1,17 +1,23 @@ import React from 'react'; -import { FiCode, FiMenu, FiSave } from 'react-icons/fi'; +import { useForm, useWatch } from 'react-hook-form'; +import { FiCode, FiMenu } from 'react-icons/fi'; import JSONPretty from 'react-json-pretty'; import { useAppSelector } from '@app/hooks/redux'; import { Channel } from '@components/Channel'; +import { FormFooter } from '@components/FormFooter'; import { Button } from '@components/generic/Button'; import { Card } from '@components/generic/Card'; import { Cover } from '@components/generic/Cover'; +import { Checkbox } from '@components/generic/form/Checkbox'; +import { Input } from '@components/generic/form/Input'; +import { Select } from '@components/generic/form/Select'; import { IconButton } from '@components/generic/IconButton'; -import { LoraConfig } from '@components/LoraConfig'; +import { Loading } from '@components/generic/Loading'; import { PrimaryTemplate } from '@components/templates/PrimaryTemplate'; import { connection } from '@core/connection'; +import { Protobuf } from '@meshtastic/meshtasticjs'; export interface ChannelsProps { navOpen?: boolean; @@ -23,7 +29,122 @@ export const Channels = ({ setNavOpen, }: ChannelsProps): JSX.Element => { const channels = useAppSelector((state) => state.meshtastic.radio.channels); + const channel = channels[0].channel; + const [debug, setDebug] = React.useState(false); + const [loading, setLoading] = React.useState(false); + + enum PresetName { + 'Long Slow', + 'Long Alt', + 'Medium', + 'Short Fast', + } + + const { register, handleSubmit, reset, formState, control } = useForm<{ + simple: boolean; + preset?: PresetName; + enabled: boolean; + settings: { + name: string; + bandwidth?: number; + codingRate?: number; + spreadFactor?: number; + downlinkEnabled?: boolean; + uplinkEnabled?: boolean; + txPower?: number; + psk?: string; + }; + }>({ + defaultValues: { + simple: true, + preset: PresetName['Long Slow'], + enabled: + channel.role === + (Protobuf.Channel_Role.PRIMARY || Protobuf.Channel_Role.SECONDARY) + ? true + : false, + settings: { + name: channel.settings?.name, + bandwidth: channel.settings?.bandwidth, + codingRate: channel.settings?.codingRate, + spreadFactor: channel.settings?.spreadFactor, + downlinkEnabled: channel.settings?.downlinkEnabled, + uplinkEnabled: channel.settings?.uplinkEnabled, + txPower: channel.settings?.txPower, + psk: new TextDecoder().decode(channel.settings?.psk), + }, + }, + }); + + const presets = [ + { + name: PresetName['Long Slow'], + config: { + bandwidth: 125, + codingRate: 8, // 4/8 + + spreadFactor: 12, // 4096chips/symbol + }, + }, + { + name: PresetName['Long Alt'], + config: { + bandwidth: 31.25, + codingRate: 8, // 4/8 + spreadFactor: 9, // 512chips/symbol, + }, + }, + { + name: PresetName['Medium'], + config: { + bandwidth: 125, + codingRate: 5, // 4/5 + spreadFactor: 7, // 128chips/symbol, + }, + }, + { + name: PresetName['Short Fast'], + config: { + bandwidth: 500, + codingRate: 5, // 4/5 + spreadFactor: 7, // 128chips/symbol, + }, + }, + ]; + + const watchSimple = useWatch({ + control, + name: 'simple', + defaultValue: true, + }); + + const onSubmit = handleSubmit(async (data) => { + setLoading(true); + console.log(data); + const selectedPreset = data.simple + ? presets.find((preset) => preset.name === data.preset)?.config + : undefined; + + const adminChannel = Protobuf.Channel.create({ + role: data.enabled + ? Protobuf.Channel_Role.SECONDARY + : Protobuf.Channel_Role.DISABLED, + index: channel.index, + settings: { + ...data.settings, + ...selectedPreset, + psk: new TextEncoder().encode(data.settings.psk), + }, + }); + + console.log(adminChannel); + + // await connection.setChannel(adminChannel, (): Promise => { + // setLoading(false); + // return Promise.resolve(); + // }); + }); return ( } footer={ - + } >
- {channels[0] && } + {channel && ( + + {loading && } +
+ {/* TODO: get gap working */} + + // setSimpleChannelSettings(e.target.checked) + // } + /> +
+ {watchSimple ? ( + + + + + )} + + + + +
+
+ )} } />
diff --git a/todo.txt b/todo.txt index 377f28f3..1f480a85 100644 --- a/todo.txt +++ b/todo.txt @@ -9,6 +9,8 @@ form prefix should be located in the input (absolute?) form suffix should focus input reset store on new connection redux actions seem to be dispatched twice +add qr generator in channel editor +no save button for channel config (bw,sf,cr,tx etc) meshtastic.js - fix entering device-reconnecting state and not re-connecting despite packets being received \ No newline at end of file