1.3.x updates
This commit is contained in:
+21
-21
@@ -22,22 +22,22 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emeraldpay/hashicon-react": "^0.5.2",
|
"@emeraldpay/hashicon-react": "^0.5.2",
|
||||||
"@meshtastic/eslint-config": "^1.0.8",
|
"@meshtastic/eslint-config": "^1.0.8",
|
||||||
"@meshtastic/meshtasticjs": "^0.6.55",
|
"@meshtastic/meshtasticjs": "^0.6.63",
|
||||||
"@reduxjs/toolkit": "^1.8.1",
|
"@reduxjs/toolkit": "^1.8.1",
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
"framer-motion": "^6.2.10",
|
"framer-motion": "^6.3.3",
|
||||||
"mapbox-gl": "^2.8.0",
|
"mapbox-gl": "^2.8.2",
|
||||||
"prettier": "^2.6.2",
|
"prettier": "^2.6.2",
|
||||||
"react": "^18.0.0",
|
"react": "^18.1.0",
|
||||||
"react-dom": "^18.0.0",
|
"react-dom": "^18.1.0",
|
||||||
"react-error-boundary": "^3.1.4",
|
"react-error-boundary": "^3.1.4",
|
||||||
"react-flow-renderer": "^10.1.0",
|
"react-flow-renderer": "^10.2.1",
|
||||||
"react-hook-form": "^7.29.0",
|
"react-hook-form": "^7.30.0",
|
||||||
"react-icons": "^4.3.1",
|
"react-icons": "^4.3.1",
|
||||||
"react-json-pretty": "^2.2.0",
|
"react-json-pretty": "^2.2.0",
|
||||||
"react-multi-select-component": "^4.2.4",
|
"react-multi-select-component": "^4.2.5",
|
||||||
"react-redux": "^7.2.8",
|
"react-redux": "^8.0.1",
|
||||||
"react-use-clipboard": "^1.0.8",
|
"react-use-clipboard": "^1.0.8",
|
||||||
"rfc4648": "^1.5.1",
|
"rfc4648": "^1.5.1",
|
||||||
"swr": "^1.3.0",
|
"swr": "^1.3.0",
|
||||||
@@ -47,25 +47,25 @@
|
|||||||
"vite-plugin-environment": "^1.1.1"
|
"vite-plugin-environment": "^1.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@hookform/devtools": "^4.1.0",
|
"@types/chrome": "^0.0.184",
|
||||||
"@types/chrome": "^0.0.181",
|
"@types/mapbox-gl": "^2.7.1",
|
||||||
"@types/mapbox-gl": "^2.6.4",
|
"@types/node": "^17.0.31",
|
||||||
"@types/react": "^18.0.3",
|
"@types/react": "^18.0.9",
|
||||||
"@types/react-dom": "^18.0.0",
|
"@types/react-dom": "^18.0.3",
|
||||||
"@types/w3c-web-serial": "^1.0.2",
|
"@types/w3c-web-serial": "^1.0.2",
|
||||||
"@types/web-bluetooth": "^0.0.14",
|
"@types/web-bluetooth": "^0.0.14",
|
||||||
"@vitejs/plugin-react": "^1.3.0",
|
"@vitejs/plugin-react": "^1.3.2",
|
||||||
"autoprefixer": "^10.4.4",
|
"autoprefixer": "^10.4.7",
|
||||||
"gzipper": "^7.1.0",
|
"gzipper": "^7.1.0",
|
||||||
"postcss": "^8.4.12",
|
"postcss": "^8.4.13",
|
||||||
"rollup-plugin-visualizer": "^5.6.0",
|
"rollup-plugin-visualizer": "^5.6.0",
|
||||||
"tailwindcss": "^3.0.24",
|
"tailwindcss": "^3.0.24",
|
||||||
"tar": "^6.1.11",
|
"tar": "^6.1.11",
|
||||||
"typescript": "^4.6.3",
|
"typescript": "^4.6.4",
|
||||||
"unimported": "^1.19.1",
|
"unimported": "^1.20.0",
|
||||||
"vite": "^2.9.1",
|
"vite": "^2.9.8",
|
||||||
"vite-plugin-cdn-import": "^0.3.5",
|
"vite-plugin-cdn-import": "^0.3.5",
|
||||||
"vite-plugin-pwa": "^0.11.13",
|
"vite-plugin-pwa": "^0.12.0",
|
||||||
"workbox-window": "^6.5.3"
|
"workbox-window": "^6.5.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+895
-1045
File diff suppressed because it is too large
Load Diff
@@ -1,110 +0,0 @@
|
|||||||
import type React from 'react';
|
|
||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
|
|
||||||
import { Checkbox } from '@components/generic/form/Checkbox';
|
|
||||||
import { Form } from '@components/generic/form/Form';
|
|
||||||
import { Input } from '@components/generic/form/Input';
|
|
||||||
import { Select } from '@components/generic/form/Select';
|
|
||||||
import { connection } from '@core/connection';
|
|
||||||
import { useAppSelector } from '@hooks/useAppSelector';
|
|
||||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
|
||||||
|
|
||||||
export const Channels = (): JSX.Element => {
|
|
||||||
const channels = useAppSelector((state) => state.meshtastic.radio.channels);
|
|
||||||
const adminChannel =
|
|
||||||
channels.find(
|
|
||||||
(channel) => channel.role === Protobuf.Channel_Role.PRIMARY,
|
|
||||||
) ?? channels[0];
|
|
||||||
const [usePreset, setUsePreset] = useState(true);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [selectedChannel, setSelectedChannel] = useState<
|
|
||||||
Protobuf.Channel | undefined
|
|
||||||
>();
|
|
||||||
|
|
||||||
const { register, handleSubmit, reset, formState } = useForm<
|
|
||||||
DeepOmit<Protobuf.Channel, 'psk'>
|
|
||||||
>({
|
|
||||||
defaultValues: {
|
|
||||||
...adminChannel,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const onSubmit = handleSubmit(async (data) => {
|
|
||||||
setLoading(true);
|
|
||||||
|
|
||||||
const channelData = Protobuf.Channel.create({
|
|
||||||
...data,
|
|
||||||
settings: {
|
|
||||||
...data.settings,
|
|
||||||
psk: adminChannel.settings?.psk,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
await connection.setChannel(channelData, (): Promise<void> => {
|
|
||||||
reset({ ...data });
|
|
||||||
setLoading(false);
|
|
||||||
return Promise.resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{adminChannel && (
|
|
||||||
<>
|
|
||||||
<Checkbox
|
|
||||||
checked={usePreset}
|
|
||||||
label="Use Presets"
|
|
||||||
onChange={(e): void => setUsePreset(e.target.checked)}
|
|
||||||
/>
|
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
|
||||||
{usePreset ? (
|
|
||||||
<Select
|
|
||||||
label="Preset"
|
|
||||||
optionsEnum={Protobuf.ChannelSettings_ModemConfig}
|
|
||||||
{...register('settings.modemConfig', {
|
|
||||||
valueAsNumber: true,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<Input
|
|
||||||
label="Bandwidth"
|
|
||||||
type="number"
|
|
||||||
suffix="MHz"
|
|
||||||
{...register('settings.bandwidth', {
|
|
||||||
valueAsNumber: true,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
label="Spread Factor"
|
|
||||||
type="number"
|
|
||||||
suffix="CPS"
|
|
||||||
min={7}
|
|
||||||
max={12}
|
|
||||||
{...register('settings.spreadFactor', {
|
|
||||||
valueAsNumber: true,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<Input
|
|
||||||
label="Coding Rate"
|
|
||||||
type="number"
|
|
||||||
{...register('settings.codingRate', {
|
|
||||||
valueAsNumber: true,
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<Input
|
|
||||||
label="Transmit Power"
|
|
||||||
type="number"
|
|
||||||
suffix="dBm"
|
|
||||||
{...register('settings.txPower', { valueAsNumber: true })}
|
|
||||||
/>
|
|
||||||
</Form>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -11,26 +11,34 @@ import { useAppSelector } from '@hooks/useAppSelector';
|
|||||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
export const Device = (): JSX.Element => {
|
export const Device = (): JSX.Element => {
|
||||||
const preferences = useAppSelector(
|
const deviceConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.config.device,
|
||||||
);
|
);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { register, handleSubmit, formState, reset } =
|
const { register, handleSubmit, formState, reset } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.Config_DeviceConfig>({
|
||||||
defaultValues: preferences,
|
defaultValues: deviceConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(deviceConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, deviceConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit((data) => {
|
const onSubmit = handleSubmit((data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
void connection.setPreferences(data, async () => {
|
void connection.setConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'device',
|
||||||
|
device: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
@@ -39,10 +47,14 @@ export const Device = (): JSX.Element => {
|
|||||||
{...register('serialDisabled')}
|
{...register('serialDisabled')}
|
||||||
/>
|
/>
|
||||||
<Checkbox label="Factory Reset Device" {...register('factoryReset')} />
|
<Checkbox label="Factory Reset Device" {...register('factoryReset')} />
|
||||||
<Checkbox label="Debug Log Enabled" {...register('debugLogEnabled')} />
|
<Checkbox label="Enabled Debug Log" {...register('debugLogEnabled')} />
|
||||||
|
<Checkbox
|
||||||
|
label="Disable Serial COnsole"
|
||||||
|
{...register('serialDisabled')}
|
||||||
|
/>
|
||||||
<Select
|
<Select
|
||||||
label="Role"
|
label="Role"
|
||||||
optionsEnum={Protobuf.Role}
|
optionsEnum={Protobuf.Config_DeviceConfig_Role}
|
||||||
{...register('role', { valueAsNumber: true })}
|
{...register('role', { valueAsNumber: true })}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -11,26 +11,34 @@ import { useAppSelector } from '@hooks/useAppSelector';
|
|||||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
export const Display = (): JSX.Element => {
|
export const Display = (): JSX.Element => {
|
||||||
const preferences = useAppSelector(
|
const displayConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.config.display,
|
||||||
);
|
);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { register, handleSubmit, formState, reset } =
|
const { register, handleSubmit, formState, reset } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.Config_DisplayConfig>({
|
||||||
defaultValues: preferences,
|
defaultValues: displayConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(displayConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, displayConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit((data) => {
|
const onSubmit = handleSubmit((data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
void connection.setPreferences(data, async () => {
|
void connection.setConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'display',
|
||||||
|
display: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
@@ -48,7 +56,7 @@ export const Display = (): JSX.Element => {
|
|||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
label="GPS Display Units"
|
label="GPS Display Units"
|
||||||
optionsEnum={Protobuf.GpsCoordinateFormat}
|
optionsEnum={Protobuf.Config_DisplayConfig_GpsCoordinateFormat}
|
||||||
{...register('gpsFormat', { valueAsNumber: true })}
|
{...register('gpsFormat', { valueAsNumber: true })}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -22,10 +22,9 @@ import {
|
|||||||
import { CollapsibleSection } from '@components/generic/Sidebar/CollapsibleSection';
|
import { CollapsibleSection } from '@components/generic/Sidebar/CollapsibleSection';
|
||||||
import { ExternalSection } from '@components/generic/Sidebar/ExternalSection';
|
import { ExternalSection } from '@components/generic/Sidebar/ExternalSection';
|
||||||
import { SidebarOverlay } from '@components/generic/Sidebar/SidebarOverlay';
|
import { SidebarOverlay } from '@components/generic/Sidebar/SidebarOverlay';
|
||||||
import { Channels } from '@components/layout/Sidebar/Settings/Channels';
|
|
||||||
import { ChannelsGroup } from '@components/layout/Sidebar/Settings/channels/ChannelsGroup';
|
import { ChannelsGroup } from '@components/layout/Sidebar/Settings/channels/ChannelsGroup';
|
||||||
import { Display } from '@components/layout/Sidebar/Settings/Display';
|
import { Display } from '@components/layout/Sidebar/Settings/Display';
|
||||||
import { GPS } from '@components/layout/Sidebar/Settings/GPS';
|
import { Position } from '@app/components/layout/Sidebar/Settings/Position';
|
||||||
import { Interface } from '@components/layout/Sidebar/Settings/Interface';
|
import { Interface } from '@components/layout/Sidebar/Settings/Interface';
|
||||||
import { LoRa } from '@components/layout/Sidebar/Settings/LoRa';
|
import { LoRa } from '@components/layout/Sidebar/Settings/LoRa';
|
||||||
import { CannedMessage } from '@components/layout/Sidebar/Settings/modules/CannedMessage';
|
import { CannedMessage } from '@components/layout/Sidebar/Settings/modules/CannedMessage';
|
||||||
@@ -48,14 +47,9 @@ export interface SettingsProps {
|
|||||||
export const Settings = ({ open, setOpen }: SettingsProps): JSX.Element => {
|
export const Settings = ({ open, setOpen }: SettingsProps): JSX.Element => {
|
||||||
const [modulesOpen, setModulesOpen] = useState(false);
|
const [modulesOpen, setModulesOpen] = useState(false);
|
||||||
const [channelsOpen, setChannelsOpen] = useState(false);
|
const [channelsOpen, setChannelsOpen] = useState(false);
|
||||||
const {
|
const moduleConfig = useAppSelector(
|
||||||
rangeTestModuleEnabled,
|
(state) => state.meshtastic.radio.moduleConfig,
|
||||||
extNotificationModuleEnabled,
|
);
|
||||||
serialModuleEnabled,
|
|
||||||
storeForwardModuleEnabled,
|
|
||||||
mqttDisabled,
|
|
||||||
cannedMessageModuleEnabled,
|
|
||||||
} = useAppSelector((state) => state.meshtastic.radio.preferences);
|
|
||||||
|
|
||||||
const hasGps = true;
|
const hasGps = true;
|
||||||
const hasWifi = true;
|
const hasWifi = true;
|
||||||
@@ -76,8 +70,8 @@ export const Settings = ({ open, setOpen }: SettingsProps): JSX.Element => {
|
|||||||
<CollapsibleSection icon={<FiSmartphone />} title="Device">
|
<CollapsibleSection icon={<FiSmartphone />} title="Device">
|
||||||
<WiFi />
|
<WiFi />
|
||||||
</CollapsibleSection>
|
</CollapsibleSection>
|
||||||
<CollapsibleSection icon={<FiMapPin />} title="GPS">
|
<CollapsibleSection icon={<FiMapPin />} title="Position">
|
||||||
<GPS />
|
<Position />
|
||||||
</CollapsibleSection>
|
</CollapsibleSection>
|
||||||
<CollapsibleSection icon={<FiPower />} title="Power">
|
<CollapsibleSection icon={<FiPower />} title="Power">
|
||||||
<Power />
|
<Power />
|
||||||
@@ -91,9 +85,6 @@ export const Settings = ({ open, setOpen }: SettingsProps): JSX.Element => {
|
|||||||
<CollapsibleSection icon={<FiRss />} title="LoRa">
|
<CollapsibleSection icon={<FiRss />} title="LoRa">
|
||||||
<LoRa />
|
<LoRa />
|
||||||
</CollapsibleSection>
|
</CollapsibleSection>
|
||||||
<CollapsibleSection icon={<FiLayers />} title="Primary Channel">
|
|
||||||
<Channels />
|
|
||||||
</CollapsibleSection>
|
|
||||||
<ExternalSection
|
<ExternalSection
|
||||||
onClick={(): void => {
|
onClick={(): void => {
|
||||||
setChannelsOpen(true);
|
setChannelsOpen(true);
|
||||||
@@ -125,35 +116,35 @@ export const Settings = ({ open, setOpen }: SettingsProps): JSX.Element => {
|
|||||||
<CollapsibleSection
|
<CollapsibleSection
|
||||||
icon={<FiWifi />}
|
icon={<FiWifi />}
|
||||||
title="MQTT"
|
title="MQTT"
|
||||||
status={!mqttDisabled}
|
status={!moduleConfig.mqtt.disabled}
|
||||||
>
|
>
|
||||||
<MQTT />
|
<MQTT />
|
||||||
</CollapsibleSection>
|
</CollapsibleSection>
|
||||||
<CollapsibleSection
|
<CollapsibleSection
|
||||||
icon={<FiAlignLeft />}
|
icon={<FiAlignLeft />}
|
||||||
title="Serial"
|
title="Serial"
|
||||||
status={serialModuleEnabled}
|
status={moduleConfig.serial.enabled}
|
||||||
>
|
>
|
||||||
<SerialSettingsPanel />
|
<SerialSettingsPanel />
|
||||||
</CollapsibleSection>
|
</CollapsibleSection>
|
||||||
<CollapsibleSection
|
<CollapsibleSection
|
||||||
icon={<FiBell />}
|
icon={<FiBell />}
|
||||||
title="External Notifications"
|
title="External Notifications"
|
||||||
status={extNotificationModuleEnabled}
|
status={moduleConfig.extNotification.enabled}
|
||||||
>
|
>
|
||||||
<ExternalNotificationsSettingsPlanel />
|
<ExternalNotificationsSettingsPlanel />
|
||||||
</CollapsibleSection>
|
</CollapsibleSection>
|
||||||
<CollapsibleSection
|
<CollapsibleSection
|
||||||
icon={<FiFastForward />}
|
icon={<FiFastForward />}
|
||||||
title="Store & Forward"
|
title="Store & Forward"
|
||||||
status={storeForwardModuleEnabled}
|
status={moduleConfig.storeForward.enabled}
|
||||||
>
|
>
|
||||||
<StoreForwardSettingsPanel />
|
<StoreForwardSettingsPanel />
|
||||||
</CollapsibleSection>
|
</CollapsibleSection>
|
||||||
<CollapsibleSection
|
<CollapsibleSection
|
||||||
icon={<FiRss />}
|
icon={<FiRss />}
|
||||||
title="Range Test"
|
title="Range Test"
|
||||||
status={rangeTestModuleEnabled}
|
status={moduleConfig.rangeTest.enabled}
|
||||||
>
|
>
|
||||||
<RangeTestSettingsPanel />
|
<RangeTestSettingsPanel />
|
||||||
</CollapsibleSection>
|
</CollapsibleSection>
|
||||||
@@ -167,7 +158,7 @@ export const Settings = ({ open, setOpen }: SettingsProps): JSX.Element => {
|
|||||||
<CollapsibleSection
|
<CollapsibleSection
|
||||||
icon={<FiMessageSquare />}
|
icon={<FiMessageSquare />}
|
||||||
title="Canned Message"
|
title="Canned Message"
|
||||||
status={cannedMessageModuleEnabled}
|
status={moduleConfig.cannedMessage.enabled}
|
||||||
>
|
>
|
||||||
<CannedMessage />
|
<CannedMessage />
|
||||||
</CollapsibleSection>
|
</CollapsibleSection>
|
||||||
|
|||||||
@@ -12,41 +12,118 @@ import { useAppSelector } from '@hooks/useAppSelector';
|
|||||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
export const LoRa = (): JSX.Element => {
|
export const LoRa = (): JSX.Element => {
|
||||||
const preferences = useAppSelector(
|
const myNodeNum = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.hardware.myNodeNum,
|
||||||
|
);
|
||||||
|
const loraConfig = useAppSelector(
|
||||||
|
(state) => state.meshtastic.radio.config.lora,
|
||||||
);
|
);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [usePreset, setUsePreset] = useState(true);
|
||||||
|
// const { register, handleSubmit, formState, reset } =
|
||||||
|
// useForm<Protobuf.RadioConfig_UserPreferences>({
|
||||||
|
// defaultValues: preferences,
|
||||||
|
// });
|
||||||
const { register, handleSubmit, formState, reset } =
|
const { register, handleSubmit, formState, reset } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.Config_LoRaConfig>({
|
||||||
defaultValues: preferences,
|
defaultValues: loraConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(loraConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, loraConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit((data) => {
|
const onSubmit = handleSubmit((data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
void connection.setPreferences(data, async () => {
|
|
||||||
reset({ ...data });
|
const packet = Protobuf.AdminMessage.create({
|
||||||
setLoading(false);
|
variant: {
|
||||||
await Promise.resolve();
|
oneofKind: 'setConfig',
|
||||||
|
setConfig: {
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'lora',
|
||||||
|
lora: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
void connection.sendPacket(
|
||||||
|
Protobuf.AdminMessage.toBinary(packet),
|
||||||
|
Protobuf.PortNum.ADMIN_APP,
|
||||||
|
myNodeNum,
|
||||||
|
true,
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
async (num) => {
|
||||||
|
return await Promise.resolve();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// void connection.setPreferences(data, async () => {
|
||||||
|
// reset({ ...data });
|
||||||
|
// setLoading(false);
|
||||||
|
// await Promise.resolve();
|
||||||
|
// });
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<Checkbox
|
||||||
|
checked={usePreset}
|
||||||
|
label="Use Presets"
|
||||||
|
onChange={(e): void => setUsePreset(e.target.checked)}
|
||||||
|
/>
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
|
{usePreset ? (
|
||||||
|
<Select
|
||||||
|
label="Preset"
|
||||||
|
optionsEnum={Protobuf.Config_LoRaConfig_ModemPreset}
|
||||||
|
{...register('modemPreset', {
|
||||||
|
valueAsNumber: true,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Input
|
||||||
|
label="Bandwidth"
|
||||||
|
type="number"
|
||||||
|
suffix="MHz"
|
||||||
|
{...register('bandwidth', {
|
||||||
|
valueAsNumber: true,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
label="Spread Factor"
|
||||||
|
type="number"
|
||||||
|
suffix="CPS"
|
||||||
|
min={7}
|
||||||
|
max={12}
|
||||||
|
{...register('spreadFactor', {
|
||||||
|
valueAsNumber: true,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
label="Coding Rate"
|
||||||
|
type="number"
|
||||||
|
{...register('codingRate', {
|
||||||
|
valueAsNumber: true,
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<Input
|
||||||
|
label="Transmit Power"
|
||||||
|
type="number"
|
||||||
|
suffix="dBm"
|
||||||
|
{...register('txPower', { valueAsNumber: true })}
|
||||||
|
/>
|
||||||
<Input
|
<Input
|
||||||
label="Hop Count"
|
label="Hop Count"
|
||||||
type="number"
|
type="number"
|
||||||
suffix="Hops"
|
suffix="Hops"
|
||||||
{...register('hopLimit', { valueAsNumber: true })}
|
{...register('hopLimit', { valueAsNumber: true })}
|
||||||
/>
|
/>
|
||||||
<Checkbox label="Transmit Disabled" {...register('isLoraTxDisabled')} />
|
<Checkbox label="Transmit Disabled" {...register('txDisabled')} />
|
||||||
<Select
|
|
||||||
label="Operating Role"
|
|
||||||
optionsEnum={Protobuf.Role}
|
|
||||||
{...register('role')}
|
|
||||||
/>
|
|
||||||
<Input
|
<Input
|
||||||
label="Frequency Offset"
|
label="Frequency Offset"
|
||||||
type="number"
|
type="number"
|
||||||
@@ -55,9 +132,10 @@ export const LoRa = (): JSX.Element => {
|
|||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
label="Region"
|
label="Region"
|
||||||
optionsEnum={Protobuf.RegionCode}
|
optionsEnum={Protobuf.Config_LoRaConfig_RegionCode}
|
||||||
{...register('region', { valueAsNumber: true })}
|
{...register('region', { valueAsNumber: true })}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+39
-24
@@ -13,35 +13,44 @@ import { bitwiseDecode, bitwiseEncode } from '@core/utils/bitwise';
|
|||||||
import { useAppSelector } from '@hooks/useAppSelector';
|
import { useAppSelector } from '@hooks/useAppSelector';
|
||||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
export const GPS = (): JSX.Element => {
|
export const Position = (): JSX.Element => {
|
||||||
const preferences = useAppSelector(
|
const positionConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.config.position,
|
||||||
);
|
);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { register, handleSubmit, formState, reset, control } =
|
const { register, handleSubmit, formState, reset, control } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.Config_PositionConfig>({
|
||||||
defaultValues: {
|
defaultValues: positionConfig,
|
||||||
...preferences,
|
// defaultValues: {
|
||||||
positionBroadcastSecs:
|
// ...preferences,
|
||||||
preferences.positionBroadcastSecs === 0
|
// positionBroadcastSecs:
|
||||||
? preferences.role === Protobuf.Role.Router
|
// preferences.positionBroadcastSecs === 0
|
||||||
? 43200
|
// ? preferences.role === Protobuf.Role.Router
|
||||||
: 900
|
// ? 43200
|
||||||
: preferences.positionBroadcastSecs,
|
// : 900
|
||||||
},
|
// : preferences.positionBroadcastSecs,
|
||||||
|
// },
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(positionConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, positionConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit((data) => {
|
const onSubmit = handleSubmit((data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
void connection.setPreferences(data, async () => {
|
void connection.setConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'position',
|
||||||
|
position: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -90,12 +99,15 @@ export const GPS = (): JSX.Element => {
|
|||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
{label && <Label label={label} error={error?.message} />}
|
{label && <Label label={label} error={error?.message} />}
|
||||||
<MultiSelect
|
<MultiSelect
|
||||||
options={Object.entries(Protobuf.PositionFlags)
|
options={Object.entries(
|
||||||
|
Protobuf.Config_PositionConfig_PositionFlags,
|
||||||
|
)
|
||||||
.filter((value) => typeof value[1] !== 'number')
|
.filter((value) => typeof value[1] !== 'number')
|
||||||
.filter(
|
.filter(
|
||||||
(value) =>
|
(value) =>
|
||||||
parseInt(value[0]) !==
|
parseInt(value[0]) !==
|
||||||
Protobuf.PositionFlags.POS_UNDEFINED,
|
Protobuf.Config_PositionConfig_PositionFlags
|
||||||
|
.POS_UNDEFINED,
|
||||||
)
|
)
|
||||||
.map((value) => {
|
.map((value) => {
|
||||||
return {
|
return {
|
||||||
@@ -103,14 +115,17 @@ export const GPS = (): JSX.Element => {
|
|||||||
label: value[1].toString().replace('POS_', ''),
|
label: value[1].toString().replace('POS_', ''),
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
value={bitwiseDecode(value, Protobuf.PositionFlags).map(
|
value={bitwiseDecode(
|
||||||
(flag) => {
|
value,
|
||||||
|
Protobuf.Config_PositionConfig_PositionFlags,
|
||||||
|
).map((flag) => {
|
||||||
return {
|
return {
|
||||||
value: flag,
|
value: flag,
|
||||||
label: Protobuf.PositionFlags[flag].replace('POS_', ''),
|
label: Protobuf.Config_PositionConfig_PositionFlags[
|
||||||
|
flag
|
||||||
|
].replace('POS_', ''),
|
||||||
};
|
};
|
||||||
},
|
})}
|
||||||
)}
|
|
||||||
onChange={(e: { value: number; label: string }[]): void =>
|
onChange={(e: { value: number; label: string }[]): void =>
|
||||||
onChange(bitwiseEncode(e.map((v) => v.value)))
|
onChange(bitwiseEncode(e.map((v) => v.value)))
|
||||||
}
|
}
|
||||||
@@ -12,45 +12,59 @@ import { useAppSelector } from '@hooks/useAppSelector';
|
|||||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
export const Power = (): JSX.Element => {
|
export const Power = (): JSX.Element => {
|
||||||
const preferences = useAppSelector(
|
const powerConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.config.power,
|
||||||
|
);
|
||||||
|
const deviceConfig = useAppSelector(
|
||||||
|
(state) => state.meshtastic.radio.config.device,
|
||||||
);
|
);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { register, handleSubmit, formState, reset } =
|
const { register, handleSubmit, formState, reset } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.Config_PowerConfig>({
|
||||||
defaultValues: {
|
defaultValues: powerConfig,
|
||||||
...preferences,
|
// defaultValues: {
|
||||||
isLowPower:
|
// ...preferences,
|
||||||
preferences.role === Protobuf.Role.Router
|
// isLowPower:
|
||||||
? true
|
// preferences.role === Protobuf.Role.Router
|
||||||
: preferences.isLowPower,
|
// ? true
|
||||||
},
|
// : preferences.isLowPower,
|
||||||
|
// },
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(powerConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, powerConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit((data) => {
|
const onSubmit = handleSubmit((data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
void connection.setPreferences(data, async () => {
|
void connection.setConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'power',
|
||||||
|
power: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
<Select
|
<Select
|
||||||
label="Charge current"
|
label="Charge current"
|
||||||
optionsEnum={Protobuf.ChargeCurrent}
|
optionsEnum={Protobuf.Config_PowerConfig_ChargeCurrent}
|
||||||
{...register('chargeCurrent', { valueAsNumber: true })}
|
{...register('chargeCurrent', { valueAsNumber: true })}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Powered by low power source (solar)"
|
label="Powered by low power source (solar)"
|
||||||
disabled={preferences.role === Protobuf.Role.Router}
|
disabled={
|
||||||
|
deviceConfig.role === Protobuf.Config_DeviceConfig_Role.Router
|
||||||
|
}
|
||||||
validationMessage={
|
validationMessage={
|
||||||
preferences.role === Protobuf.Role.Router
|
deviceConfig.role === Protobuf.Config_DeviceConfig_Role.Router
|
||||||
? 'Enabled by default in router mode'
|
? 'Enabled by default in router mode'
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
@@ -81,12 +95,6 @@ export const Power = (): JSX.Element => {
|
|||||||
type="number"
|
type="number"
|
||||||
{...register('phoneTimeoutSecs', { valueAsNumber: true })}
|
{...register('phoneTimeoutSecs', { valueAsNumber: true })}
|
||||||
/>
|
/>
|
||||||
<Input
|
|
||||||
label="Phone SDS Timeout"
|
|
||||||
suffix="Seconds"
|
|
||||||
type="number"
|
|
||||||
{...register('phoneSdsTimeoutSec', { valueAsNumber: true })}
|
|
||||||
/>
|
|
||||||
<Input
|
<Input
|
||||||
label="Mesh SDS Timeout"
|
label="Mesh SDS Timeout"
|
||||||
suffix="Seconds"
|
suffix="Seconds"
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ export const User = (): JSX.Element => {
|
|||||||
longName: string;
|
longName: string;
|
||||||
shortName: string;
|
shortName: string;
|
||||||
isLicensed: boolean;
|
isLicensed: boolean;
|
||||||
team: Protobuf.Team;
|
|
||||||
antAzimuth: number;
|
antAzimuth: number;
|
||||||
antGainDbi: number;
|
antGainDbi: number;
|
||||||
txPowerDbm: number;
|
txPowerDbm: number;
|
||||||
@@ -33,7 +32,6 @@ export const User = (): JSX.Element => {
|
|||||||
longName: node?.data.user?.longName,
|
longName: node?.data.user?.longName,
|
||||||
shortName: node?.data.user?.shortName,
|
shortName: node?.data.user?.shortName,
|
||||||
isLicensed: node?.data.user?.isLicensed,
|
isLicensed: node?.data.user?.isLicensed,
|
||||||
team: node?.data.user?.team,
|
|
||||||
antAzimuth: node?.data.user?.antAzimuth,
|
antAzimuth: node?.data.user?.antAzimuth,
|
||||||
antGainDbi: node?.data.user?.antGainDbi,
|
antGainDbi: node?.data.user?.antGainDbi,
|
||||||
txPowerDbm: node?.data.user?.txPowerDbm,
|
txPowerDbm: node?.data.user?.txPowerDbm,
|
||||||
@@ -45,7 +43,6 @@ export const User = (): JSX.Element => {
|
|||||||
longName: node?.data.user?.longName,
|
longName: node?.data.user?.longName,
|
||||||
shortName: node?.data.user?.shortName,
|
shortName: node?.data.user?.shortName,
|
||||||
isLicensed: node?.data.user?.isLicensed,
|
isLicensed: node?.data.user?.isLicensed,
|
||||||
team: node?.data.user?.team,
|
|
||||||
});
|
});
|
||||||
}, [reset, node]);
|
}, [reset, node]);
|
||||||
|
|
||||||
@@ -86,11 +83,6 @@ export const User = (): JSX.Element => {
|
|||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
<Checkbox label="Licenced Operator?" {...register('isLicensed')} />
|
<Checkbox label="Licenced Operator?" {...register('isLicensed')} />
|
||||||
<Select
|
|
||||||
label="Team (DEPRECATED)"
|
|
||||||
optionsEnum={Protobuf.Team}
|
|
||||||
{...register('team', { valueAsNumber: true })}
|
|
||||||
/>
|
|
||||||
<Input
|
<Input
|
||||||
label="Transmit Power"
|
label="Transmit Power"
|
||||||
suffix="dBm"
|
suffix="dBm"
|
||||||
|
|||||||
@@ -11,47 +11,51 @@ import { useAppSelector } from '@hooks/useAppSelector';
|
|||||||
import type { Protobuf } from '@meshtastic/meshtasticjs';
|
import type { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
export const WiFi = (): JSX.Element => {
|
export const WiFi = (): JSX.Element => {
|
||||||
const preferences = useAppSelector(
|
const wifiConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.config.wifi,
|
||||||
);
|
);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { register, handleSubmit, formState, reset, control } =
|
const { register, handleSubmit, formState, reset, control } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.Config_WiFiConfig>({
|
||||||
defaultValues: preferences,
|
defaultValues: wifiConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
const WifiApMode = useWatch({
|
const WifiApMode = useWatch({
|
||||||
control,
|
control,
|
||||||
name: 'wifiApMode',
|
name: 'apMode',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(wifiConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, wifiConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit((data) => {
|
const onSubmit = handleSubmit((data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
void connection.setPreferences(data, async () => {
|
void connection.setConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'wifi',
|
||||||
|
wifi: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
<Checkbox label="Enable WiFi AP" {...register('wifiApMode')} />
|
<Checkbox label="Enable WiFi AP" {...register('apMode')} />
|
||||||
<Input
|
<Input label="WiFi SSID" disabled={WifiApMode} {...register('ssid')} />
|
||||||
label="WiFi SSID"
|
|
||||||
disabled={WifiApMode}
|
|
||||||
{...register('wifiSsid')}
|
|
||||||
/>
|
|
||||||
<Input
|
<Input
|
||||||
type="password"
|
type="password"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
label="WiFi PSK"
|
label="WiFi PSK"
|
||||||
disabled={WifiApMode}
|
disabled={WifiApMode}
|
||||||
{...register('wifiPassword')}
|
{...register('psk')}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ import { useAppSelector } from '@hooks/useAppSelector';
|
|||||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
export const CannedMessage = (): JSX.Element => {
|
export const CannedMessage = (): JSX.Element => {
|
||||||
const preferences = useAppSelector(
|
const cannedMessageConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.moduleConfig.cannedMessage,
|
||||||
);
|
);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { register, handleSubmit, formState, reset, control } =
|
const { register, handleSubmit, formState, reset, control } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.ModuleConfig_CannedMessageConfig>({
|
||||||
defaultValues: preferences,
|
defaultValues: cannedMessageConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
const moduleEnabled = useWatch({
|
const moduleEnabled = useWatch({
|
||||||
@@ -28,23 +28,28 @@ export const CannedMessage = (): JSX.Element => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(cannedMessageConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, cannedMessageConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit((data) => {
|
const onSubmit = handleSubmit((data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
void connection.setPreferences(data, async () => {
|
void connection.setModuleConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'cannedMessage',
|
||||||
|
cannedMessage: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
<Checkbox
|
<Checkbox label="Module Enabled" {...register('enabled')} />
|
||||||
label="Module Enabled"
|
|
||||||
{...register('cannedMessageModuleEnabled')}
|
|
||||||
/>
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Rotary Encoder #1 Enabled"
|
label="Rotary Encoder #1 Enabled"
|
||||||
{...register('rotary1Enabled')}
|
{...register('rotary1Enabled')}
|
||||||
@@ -70,31 +75,28 @@ export const CannedMessage = (): JSX.Element => {
|
|||||||
<Select
|
<Select
|
||||||
label="Clockwise event"
|
label="Clockwise event"
|
||||||
disabled={moduleEnabled}
|
disabled={moduleEnabled}
|
||||||
optionsEnum={Protobuf.InputEventChar}
|
optionsEnum={Protobuf.ModuleConfig_CannedMessageConfig_InputEventChar}
|
||||||
{...register('inputbrokerEventCw', { valueAsNumber: true })}
|
{...register('inputbrokerEventCw', { valueAsNumber: true })}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
label="Counter Clockwise event"
|
label="Counter Clockwise event"
|
||||||
disabled={moduleEnabled}
|
disabled={moduleEnabled}
|
||||||
optionsEnum={Protobuf.InputEventChar}
|
optionsEnum={Protobuf.ModuleConfig_CannedMessageConfig_InputEventChar}
|
||||||
{...register('inputbrokerEventCcw', { valueAsNumber: true })}
|
{...register('inputbrokerEventCcw', { valueAsNumber: true })}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
label="Press event"
|
label="Press event"
|
||||||
disabled={moduleEnabled}
|
disabled={moduleEnabled}
|
||||||
optionsEnum={Protobuf.InputEventChar}
|
optionsEnum={Protobuf.ModuleConfig_CannedMessageConfig_InputEventChar}
|
||||||
{...register('inputbrokerEventPress', { valueAsNumber: true })}
|
{...register('inputbrokerEventPress', { valueAsNumber: true })}
|
||||||
/>
|
/>
|
||||||
<Checkbox label="Up Down enabled" {...register('updown1Enabled')} />
|
<Checkbox label="Up Down enabled" {...register('updown1Enabled')} />
|
||||||
<Input
|
<Input
|
||||||
label="Allow Input Source"
|
label="Allow Input Source"
|
||||||
disabled={moduleEnabled}
|
disabled={moduleEnabled}
|
||||||
{...register('cannedMessageModuleAllowInputSource')}
|
{...register('allowInputSource')}
|
||||||
/>
|
|
||||||
<Checkbox
|
|
||||||
label="Send Bell"
|
|
||||||
{...register('cannedMessageModuleSendBell')}
|
|
||||||
/>
|
/>
|
||||||
|
<Checkbox label="Send Bell" {...register('sendBell')} />
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,46 +13,51 @@ import type { Protobuf } from '@meshtastic/meshtasticjs';
|
|||||||
export const ExternalNotificationsSettingsPlanel = (): JSX.Element => {
|
export const ExternalNotificationsSettingsPlanel = (): JSX.Element => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const preferences = useAppSelector(
|
const extNotificationConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.moduleConfig.extNotification,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { register, handleSubmit, formState, reset, control } =
|
const { register, handleSubmit, formState, reset, control } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.ModuleConfig_ExternalNotificationConfig>({
|
||||||
defaultValues: preferences,
|
defaultValues: extNotificationConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(extNotificationConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, extNotificationConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit(async (data) => {
|
const onSubmit = handleSubmit(async (data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await connection.setPreferences(data, async (): Promise<void> => {
|
await connection.setModuleConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'externalNotification',
|
||||||
|
externalNotification: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (): Promise<void> => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const moduleEnabled = useWatch({
|
const moduleEnabled = useWatch({
|
||||||
control,
|
control,
|
||||||
name: 'extNotificationModuleEnabled',
|
name: 'enabled',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
<Checkbox
|
<Checkbox label="Module Enabled" {...register('enabled')} />
|
||||||
label="Module Enabled"
|
|
||||||
{...register('extNotificationModuleEnabled')}
|
|
||||||
/>
|
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
label="Output MS"
|
label="Output MS"
|
||||||
suffix="ms"
|
suffix="ms"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('extNotificationModuleOutputMs', {
|
{...register('outputMs', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@@ -60,24 +65,24 @@ export const ExternalNotificationsSettingsPlanel = (): JSX.Element => {
|
|||||||
type="number"
|
type="number"
|
||||||
label="Output"
|
label="Output"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('extNotificationModuleOutput', {
|
{...register('output', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Active"
|
label="Active"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('extNotificationModuleActive')}
|
{...register('active')}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Message"
|
label="Message"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('extNotificationModuleAlertMessage')}
|
{...register('alertMessage')}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Bell"
|
label="Bell"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('extNotificationModuleAlertBell')}
|
{...register('alertBell')}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,57 +11,65 @@ import { useAppSelector } from '@hooks/useAppSelector';
|
|||||||
import type { Protobuf } from '@meshtastic/meshtasticjs';
|
import type { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
export const MQTT = (): JSX.Element => {
|
export const MQTT = (): JSX.Element => {
|
||||||
const preferences = useAppSelector(
|
const mqttConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.moduleConfig.mqtt,
|
||||||
);
|
);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { register, handleSubmit, formState, reset, control } =
|
const { register, handleSubmit, formState, reset, control } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.ModuleConfig_MQTTConfig>({
|
||||||
defaultValues: preferences,
|
defaultValues: mqttConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
const moduleEnabled = useWatch({
|
const moduleEnabled = useWatch({
|
||||||
control,
|
control,
|
||||||
name: 'mqttDisabled',
|
name: 'disabled',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(mqttConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, mqttConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit((data) => {
|
const onSubmit = handleSubmit((data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
void connection.setPreferences(data, async () => {
|
void connection.setModuleConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'mqtt',
|
||||||
|
mqtt: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
<Checkbox label="Module Disabled" {...register('mqttDisabled')} />
|
<Checkbox label="Module Disabled" {...register('disabled')} />
|
||||||
<Input
|
<Input
|
||||||
label="MQTT Server Address"
|
label="MQTT Server Address"
|
||||||
disabled={moduleEnabled}
|
disabled={moduleEnabled}
|
||||||
{...register('mqttServer')}
|
{...register('address')}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
label="MQTT Username"
|
label="MQTT Username"
|
||||||
disabled={moduleEnabled}
|
disabled={moduleEnabled}
|
||||||
{...register('mqttUsername')}
|
{...register('username')}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
label="MQTT Password"
|
label="MQTT Password"
|
||||||
type="password"
|
type="password"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
disabled={moduleEnabled}
|
disabled={moduleEnabled}
|
||||||
{...register('mqttPassword')}
|
{...register('password')}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Encryption Enabled"
|
label="Encryption Enabled"
|
||||||
disabled={moduleEnabled}
|
disabled={moduleEnabled}
|
||||||
{...register('mqttEncryptionEnabled')}
|
{...register('encryptionEnabled')}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,53 +13,58 @@ import type { Protobuf } from '@meshtastic/meshtasticjs';
|
|||||||
export const RangeTestSettingsPanel = (): JSX.Element => {
|
export const RangeTestSettingsPanel = (): JSX.Element => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const preferences = useAppSelector(
|
const rangeTestConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.moduleConfig.rangeTest,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { register, handleSubmit, formState, reset, control } =
|
const { register, handleSubmit, formState, reset, control } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.ModuleConfig_RangeTestConfig>({
|
||||||
defaultValues: preferences,
|
defaultValues: rangeTestConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(rangeTestConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, rangeTestConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit(async (data) => {
|
const onSubmit = handleSubmit(async (data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await connection.setPreferences(data, async (): Promise<void> => {
|
await connection.setModuleConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'rangeTest',
|
||||||
|
rangeTest: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (): Promise<void> => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const moduleEnabled = useWatch({
|
const moduleEnabled = useWatch({
|
||||||
control,
|
control,
|
||||||
name: 'rangeTestModuleEnabled',
|
name: 'enabled',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
<Checkbox
|
<Checkbox label="Module Enabled" {...register('enabled')} />
|
||||||
label="Module Enabled"
|
|
||||||
{...register('rangeTestModuleEnabled')}
|
|
||||||
/>
|
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
label="Message Interval"
|
label="Message Interval"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
suffix="Seconds"
|
suffix="Seconds"
|
||||||
{...register('rangeTestModuleSender', {
|
{...register('sender', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Save CSV to storage"
|
label="Save CSV to storage"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('rangeTestModuleSave')}
|
{...register('save')}
|
||||||
/>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,48 +13,52 @@ import type { Protobuf } from '@meshtastic/meshtasticjs';
|
|||||||
export const SerialSettingsPanel = (): JSX.Element => {
|
export const SerialSettingsPanel = (): JSX.Element => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const preferences = useAppSelector(
|
const serialConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.moduleConfig.serial,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { register, handleSubmit, formState, reset, control } =
|
const { register, handleSubmit, formState, reset, control } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.ModuleConfig_SerialConfig>({
|
||||||
defaultValues: preferences,
|
defaultValues: serialConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(serialConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, serialConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit(async (data) => {
|
const onSubmit = handleSubmit(async (data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await connection.setPreferences(data, async (): Promise<void> => {
|
await connection.setModuleConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'serial',
|
||||||
|
serial: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (): Promise<void> => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const moduleEnabled = useWatch({
|
const moduleEnabled = useWatch({
|
||||||
control,
|
control,
|
||||||
name: 'serialModuleEnabled',
|
name: 'enabled',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
<Checkbox label="Module Enabled" {...register('serialModuleEnabled')} />
|
<Checkbox label="Module Enabled" {...register('enabled')} />
|
||||||
<Checkbox
|
<Checkbox label="Echo" disabled={!moduleEnabled} {...register('echo')} />
|
||||||
label="Echo"
|
|
||||||
disabled={!moduleEnabled}
|
|
||||||
{...register('serialModuleEcho')}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
label="RX"
|
label="RX"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('serialModuleRxd', {
|
{...register('rxd', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@@ -62,7 +66,7 @@ export const SerialSettingsPanel = (): JSX.Element => {
|
|||||||
type="number"
|
type="number"
|
||||||
label="TX Pin"
|
label="TX Pin"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('serialModuleTxd', {
|
{...register('txd', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@@ -70,7 +74,7 @@ export const SerialSettingsPanel = (): JSX.Element => {
|
|||||||
type="number"
|
type="number"
|
||||||
label="Baud Rate"
|
label="Baud Rate"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('serialModuleBaud', {
|
{...register('baud', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@@ -78,7 +82,7 @@ export const SerialSettingsPanel = (): JSX.Element => {
|
|||||||
type="number"
|
type="number"
|
||||||
label="Timeout"
|
label="Timeout"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('serialModuleTimeout', {
|
{...register('timeout', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@@ -86,7 +90,7 @@ export const SerialSettingsPanel = (): JSX.Element => {
|
|||||||
type="number"
|
type="number"
|
||||||
label="Mode"
|
label="Mode"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('serialModuleMode', {
|
{...register('mode', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -13,51 +13,56 @@ import type { Protobuf } from '@meshtastic/meshtasticjs';
|
|||||||
export const StoreForwardSettingsPanel = (): JSX.Element => {
|
export const StoreForwardSettingsPanel = (): JSX.Element => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const preferences = useAppSelector(
|
const storeForwardConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.moduleConfig.storeForward,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { register, handleSubmit, formState, reset, control } =
|
const { register, handleSubmit, formState, reset, control } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.ModuleConfig_StoreForwardConfig>({
|
||||||
defaultValues: preferences,
|
defaultValues: storeForwardConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(storeForwardConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, storeForwardConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit(async (data) => {
|
const onSubmit = handleSubmit(async (data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await connection.setPreferences(data, async (): Promise<void> => {
|
await connection.setModuleConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'storeForward',
|
||||||
|
storeForward: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async (): Promise<void> => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const moduleEnabled = useWatch({
|
const moduleEnabled = useWatch({
|
||||||
control,
|
control,
|
||||||
name: 'storeForwardModuleEnabled',
|
name: 'enabled',
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
<Checkbox
|
<Checkbox label="Module Enabled" {...register('enabled')} />
|
||||||
label="Module Enabled"
|
|
||||||
{...register('storeForwardModuleEnabled')}
|
|
||||||
/>
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Heartbeat Enabled"
|
label="Heartbeat Enabled"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('storeForwardModuleHeartbeat')}
|
{...register('heartbeat')}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
label="Number of records"
|
label="Number of records"
|
||||||
suffix="Records"
|
suffix="Records"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('storeForwardModuleRecords', {
|
{...register('records', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@@ -65,7 +70,7 @@ export const StoreForwardSettingsPanel = (): JSX.Element => {
|
|||||||
type="number"
|
type="number"
|
||||||
label="History return max"
|
label="History return max"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('storeForwardModuleHistoryReturnMax', {
|
{...register('historyReturnMax', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@@ -73,7 +78,7 @@ export const StoreForwardSettingsPanel = (): JSX.Element => {
|
|||||||
type="number"
|
type="number"
|
||||||
label="History return window"
|
label="History return window"
|
||||||
disabled={!moduleEnabled}
|
disabled={!moduleEnabled}
|
||||||
{...register('storeForwardModuleHistoryReturnWindow', {
|
{...register('historyReturnWindow', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -12,41 +12,49 @@ import { useAppSelector } from '@hooks/useAppSelector';
|
|||||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
export const Telemetry = (): JSX.Element => {
|
export const Telemetry = (): JSX.Element => {
|
||||||
const preferences = useAppSelector(
|
const telemetryConfig = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.preferences,
|
(state) => state.meshtastic.radio.moduleConfig.telemetry,
|
||||||
);
|
);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { register, handleSubmit, formState, reset, control } =
|
const { register, handleSubmit, formState, reset, control } =
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
useForm<Protobuf.ModuleConfig_TelemetryConfig>({
|
||||||
defaultValues: preferences,
|
defaultValues: telemetryConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
reset(preferences);
|
reset(telemetryConfig);
|
||||||
}, [reset, preferences]);
|
}, [reset, telemetryConfig]);
|
||||||
|
|
||||||
const onSubmit = handleSubmit((data) => {
|
const onSubmit = handleSubmit((data) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
void connection.setPreferences(data, async () => {
|
void connection.setModuleConfig(
|
||||||
|
{
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'telemetry',
|
||||||
|
telemetry: data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
async () => {
|
||||||
reset({ ...data });
|
reset({ ...data });
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
<Form loading={loading} dirty={!formState.isDirty} submit={onSubmit}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Measurement Enabled"
|
label="Measurement Enabled"
|
||||||
{...register('telemetryModuleEnvironmentMeasurementEnabled')}
|
{...register('environmentMeasurementEnabled')}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Displayed on Screen"
|
label="Displayed on Screen"
|
||||||
{...register('telemetryModuleEnvironmentScreenEnabled')}
|
{...register('environmentScreenEnabled')}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
label="Read Error Count Threshold"
|
label="Read Error Count Threshold"
|
||||||
type="number"
|
type="number"
|
||||||
{...register('telemetryModuleEnvironmentReadErrorCountThreshold', {
|
{...register('environmentReadErrorCountThreshold', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@@ -54,7 +62,7 @@ export const Telemetry = (): JSX.Element => {
|
|||||||
label="Update Interval"
|
label="Update Interval"
|
||||||
suffix="Seconds"
|
suffix="Seconds"
|
||||||
type="number"
|
type="number"
|
||||||
{...register('telemetryModuleEnvironmentUpdateInterval', {
|
{...register('environmentUpdateInterval', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
@@ -62,25 +70,25 @@ export const Telemetry = (): JSX.Element => {
|
|||||||
label="Recovery Interval"
|
label="Recovery Interval"
|
||||||
suffix="Seconds"
|
suffix="Seconds"
|
||||||
type="number"
|
type="number"
|
||||||
{...register('telemetryModuleEnvironmentRecoveryInterval', {
|
{...register('environmentRecoveryInterval', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label="Display Farenheit"
|
label="Display Farenheit"
|
||||||
{...register('telemetryModuleEnvironmentDisplayFahrenheit')}
|
{...register('environmentDisplayFahrenheit')}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Select
|
||||||
label="Sensor Type"
|
label="Sensor Type"
|
||||||
optionsEnum={Protobuf.RadioConfig_UserPreferences_TelemetrySensorType}
|
optionsEnum={Protobuf.TelemetrySensorType}
|
||||||
{...register('telemetryModuleEnvironmentSensorType', {
|
{...register('environmentSensorType', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
label="Sensor Pin"
|
label="Sensor Pin"
|
||||||
type="number"
|
type="number"
|
||||||
{...register('telemetryModuleEnvironmentSensorPin', {
|
{...register('environmentSensorPin', {
|
||||||
valueAsNumber: true,
|
valueAsNumber: true,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -134,13 +134,13 @@ export const BottomNav = (): JSX.Element => {
|
|||||||
<BottomNavItem tooltip="MQTT Status">
|
<BottomNavItem tooltip="MQTT Status">
|
||||||
{primaryChannelSettings?.uplinkEnabled &&
|
{primaryChannelSettings?.uplinkEnabled &&
|
||||||
primaryChannelSettings?.downlinkEnabled &&
|
primaryChannelSettings?.downlinkEnabled &&
|
||||||
!meshtasticState.radio.preferences.mqttDisabled ? (
|
!meshtasticState.radio.moduleConfig.mqtt.disabled ? (
|
||||||
<RiArrowUpDownLine className="h-4" />
|
<RiArrowUpDownLine className="h-4" />
|
||||||
) : primaryChannelSettings?.uplinkEnabled &&
|
) : primaryChannelSettings?.uplinkEnabled &&
|
||||||
!meshtasticState.radio.preferences.mqttDisabled ? (
|
!meshtasticState.radio.moduleConfig.mqtt.disabled ? (
|
||||||
<RiArrowUpLine className="h-4" />
|
<RiArrowUpLine className="h-4" />
|
||||||
) : primaryChannelSettings?.downlinkEnabled &&
|
) : primaryChannelSettings?.downlinkEnabled &&
|
||||||
!meshtasticState.radio.preferences.mqttDisabled ? (
|
!meshtasticState.radio.moduleConfig.mqtt.disabled ? (
|
||||||
<RiArrowDownLine className="h-4" />
|
<RiArrowDownLine className="h-4" />
|
||||||
) : (
|
) : (
|
||||||
<FiX className="h-4" />
|
<FiX className="h-4" />
|
||||||
|
|||||||
+37
-24
@@ -6,13 +6,13 @@ import {
|
|||||||
addMessage,
|
addMessage,
|
||||||
addNode,
|
addNode,
|
||||||
addPosition,
|
addPosition,
|
||||||
addRoute,
|
|
||||||
addUser,
|
addUser,
|
||||||
resetState,
|
resetState,
|
||||||
|
setConfig,
|
||||||
setDeviceStatus,
|
setDeviceStatus,
|
||||||
setLastMeshInterraction,
|
setLastMeshInterraction,
|
||||||
|
setModuleConfig,
|
||||||
setMyNodeInfo,
|
setMyNodeInfo,
|
||||||
setPreferences,
|
|
||||||
setReady,
|
setReady,
|
||||||
updateLastInteraction,
|
updateLastInteraction,
|
||||||
} from '@core/slices/meshtasticSlice';
|
} from '@core/slices/meshtasticSlice';
|
||||||
@@ -90,24 +90,21 @@ const registerListeners = (): void => {
|
|||||||
store.dispatch(addLogEvent(log));
|
store.dispatch(addLogEvent(log));
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.onMeshPacket.subscribe((packet) => {
|
|
||||||
store.dispatch(
|
|
||||||
addRoute({
|
|
||||||
from: packet.from,
|
|
||||||
to:
|
|
||||||
packet.to === 0xffffffff
|
|
||||||
? store.getState().meshtastic.radio.hardware.myNodeNum
|
|
||||||
: packet.to,
|
|
||||||
hops: packet.hopLimit,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
connection.onDeviceStatus.subscribe((status) => {
|
connection.onDeviceStatus.subscribe((status) => {
|
||||||
store.dispatch(setDeviceStatus(status));
|
store.dispatch(setDeviceStatus(status));
|
||||||
|
|
||||||
if (status === Types.DeviceStatusEnum.DEVICE_CONFIGURED) {
|
if (status === Types.DeviceStatusEnum.DEVICE_CONFIGURED) {
|
||||||
store.dispatch(setReady(true));
|
store.dispatch(setReady(true));
|
||||||
|
void connection.getConfig(Protobuf.AdminMessage_ConfigType.DEVICE_CONFIG);
|
||||||
|
void connection.getConfig(Protobuf.AdminMessage_ConfigType.WIFI_CONFIG);
|
||||||
|
void connection.getConfig(
|
||||||
|
Protobuf.AdminMessage_ConfigType.POSITION_CONFIG,
|
||||||
|
);
|
||||||
|
void connection.getConfig(
|
||||||
|
Protobuf.AdminMessage_ConfigType.DISPLAY_CONFIG,
|
||||||
|
);
|
||||||
|
void connection.getConfig(Protobuf.AdminMessage_ConfigType.LORA_CONFIG);
|
||||||
|
void connection.getConfig(Protobuf.AdminMessage_ConfigType.POWER_CONFIG);
|
||||||
}
|
}
|
||||||
if (status === Types.DeviceStatusEnum.DEVICE_DISCONNECTED) {
|
if (status === Types.DeviceStatusEnum.DEVICE_DISCONNECTED) {
|
||||||
store.dispatch(setReady(false));
|
store.dispatch(setReady(false));
|
||||||
@@ -136,6 +133,8 @@ const registerListeners = (): void => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
connection.onAdminPacket.subscribe((adminPacket) => {
|
connection.onAdminPacket.subscribe((adminPacket) => {
|
||||||
|
console.log(adminPacket.data.variant.oneofKind);
|
||||||
|
|
||||||
switch (adminPacket.data.variant.oneofKind) {
|
switch (adminPacket.data.variant.oneofKind) {
|
||||||
case 'getChannelResponse':
|
case 'getChannelResponse':
|
||||||
store.dispatch(addChannel(adminPacket.data.variant.getChannelResponse));
|
store.dispatch(addChannel(adminPacket.data.variant.getChannelResponse));
|
||||||
@@ -143,15 +142,6 @@ const registerListeners = (): void => {
|
|||||||
addChat(adminPacket.data.variant.getChannelResponse.index),
|
addChat(adminPacket.data.variant.getChannelResponse.index),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'getRadioResponse':
|
|
||||||
if (adminPacket.data.variant.getRadioResponse.preferences) {
|
|
||||||
store.dispatch(
|
|
||||||
setPreferences(
|
|
||||||
adminPacket.data.variant.getRadioResponse.preferences,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'getOwnerResponse':
|
case 'getOwnerResponse':
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
addUser({
|
addUser({
|
||||||
@@ -159,6 +149,15 @@ const registerListeners = (): void => {
|
|||||||
packet: adminPacket.packet,
|
packet: adminPacket.packet,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
|
case 'getConfigResponse':
|
||||||
|
store.dispatch(setConfig(adminPacket.data.variant.getConfigResponse));
|
||||||
|
break;
|
||||||
|
case 'getModuleConfigResponse':
|
||||||
|
store.dispatch(
|
||||||
|
setModuleConfig(adminPacket.data.variant.getModuleConfigResponse),
|
||||||
|
);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -168,6 +167,20 @@ const registerListeners = (): void => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
connection.onRoutingPacket.subscribe((routingPacket) => {
|
connection.onRoutingPacket.subscribe((routingPacket) => {
|
||||||
|
console.log(routingPacket.data.variant.oneofKind);
|
||||||
|
|
||||||
|
switch (routingPacket.data.variant.oneofKind) {
|
||||||
|
case 'errorReason':
|
||||||
|
console.log(
|
||||||
|
Protobuf.Routing_Error[routingPacket.data.variant.errorReason],
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
updateLastInteraction({
|
updateLastInteraction({
|
||||||
id: routingPacket.packet.from,
|
id: routingPacket.packet.from,
|
||||||
|
|||||||
@@ -32,10 +32,30 @@ export interface Node {
|
|||||||
|
|
||||||
export interface Radio {
|
export interface Radio {
|
||||||
channels: Protobuf.Channel[];
|
channels: Protobuf.Channel[];
|
||||||
preferences: Protobuf.RadioConfig_UserPreferences;
|
config: Config;
|
||||||
|
moduleConfig: ModuleConfig;
|
||||||
hardware: Protobuf.MyNodeInfo;
|
hardware: Protobuf.MyNodeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Config {
|
||||||
|
device: Protobuf.Config_DeviceConfig;
|
||||||
|
position: Protobuf.Config_PositionConfig;
|
||||||
|
power: Protobuf.Config_PowerConfig;
|
||||||
|
wifi: Protobuf.Config_WiFiConfig;
|
||||||
|
display: Protobuf.Config_DisplayConfig;
|
||||||
|
lora: Protobuf.Config_LoRaConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ModuleConfig {
|
||||||
|
mqtt: Protobuf.ModuleConfig_MQTTConfig;
|
||||||
|
serial: Protobuf.ModuleConfig_SerialConfig;
|
||||||
|
extNotification: Protobuf.ModuleConfig_ExternalNotificationConfig;
|
||||||
|
storeForward: Protobuf.ModuleConfig_StoreForwardConfig;
|
||||||
|
rangeTest: Protobuf.ModuleConfig_RangeTestConfig;
|
||||||
|
telemetry: Protobuf.ModuleConfig_TelemetryConfig;
|
||||||
|
cannedMessage: Protobuf.ModuleConfig_CannedMessageConfig;
|
||||||
|
}
|
||||||
|
|
||||||
interface MeshtasticState {
|
interface MeshtasticState {
|
||||||
deviceStatus: Types.DeviceStatusEnum;
|
deviceStatus: Types.DeviceStatusEnum;
|
||||||
lastMeshInterraction: number;
|
lastMeshInterraction: number;
|
||||||
@@ -53,7 +73,24 @@ const initialState: MeshtasticState = {
|
|||||||
nodes: [],
|
nodes: [],
|
||||||
radio: {
|
radio: {
|
||||||
channels: [],
|
channels: [],
|
||||||
preferences: Protobuf.RadioConfig_UserPreferences.create(),
|
config: {
|
||||||
|
device: Protobuf.Config_DeviceConfig.create(),
|
||||||
|
position: Protobuf.Config_PositionConfig.create(),
|
||||||
|
power: Protobuf.Config_PowerConfig.create(),
|
||||||
|
wifi: Protobuf.Config_WiFiConfig.create(),
|
||||||
|
display: Protobuf.Config_DisplayConfig.create(),
|
||||||
|
lora: Protobuf.Config_LoRaConfig.create(),
|
||||||
|
},
|
||||||
|
moduleConfig: {
|
||||||
|
mqtt: Protobuf.ModuleConfig_MQTTConfig.create(),
|
||||||
|
serial: Protobuf.ModuleConfig_SerialConfig.create(),
|
||||||
|
extNotification:
|
||||||
|
Protobuf.ModuleConfig_ExternalNotificationConfig.create(),
|
||||||
|
storeForward: Protobuf.ModuleConfig_StoreForwardConfig.create(),
|
||||||
|
rangeTest: Protobuf.ModuleConfig_RangeTestConfig.create(),
|
||||||
|
telemetry: Protobuf.ModuleConfig_TelemetryConfig.create(),
|
||||||
|
cannedMessage: Protobuf.ModuleConfig_CannedMessageConfig.create(),
|
||||||
|
},
|
||||||
hardware: Protobuf.MyNodeInfo.create(),
|
hardware: Protobuf.MyNodeInfo.create(),
|
||||||
},
|
},
|
||||||
chats: {},
|
chats: {},
|
||||||
@@ -151,23 +188,71 @@ export const meshtasticSlice = createSlice({
|
|||||||
state.radio.channels.push(action.payload);
|
state.radio.channels.push(action.payload);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
addRoute: (state, action: PayloadAction<Route>) => {
|
setConfig: (state, action: PayloadAction<Protobuf.Config>) => {
|
||||||
// const node = state.nodes.find(
|
switch (action.payload.payloadVariant.oneofKind) {
|
||||||
// (node) => node.num === action.payload.from,
|
case 'device': {
|
||||||
// );
|
state.radio.config.device = action.payload.payloadVariant.device;
|
||||||
// const exists = node?.routes.findIndex(
|
break;
|
||||||
// (route) =>
|
}
|
||||||
// route.from === action.payload.from && route.to === action.payload.to,
|
case 'position': {
|
||||||
// );
|
state.radio.config.position = action.payload.payloadVariant.position;
|
||||||
// if (exists === -1) {
|
break;
|
||||||
// node?.routes.push(action.payload);
|
}
|
||||||
// }
|
case 'power': {
|
||||||
|
state.radio.config.power = action.payload.payloadVariant.power;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'wifi': {
|
||||||
|
state.radio.config.wifi = action.payload.payloadVariant.wifi;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'display': {
|
||||||
|
state.radio.config.display = action.payload.payloadVariant.display;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'lora': {
|
||||||
|
state.radio.config.lora = action.payload.payloadVariant.lora;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setPreferences: (
|
setModuleConfig: (state, action: PayloadAction<Protobuf.ModuleConfig>) => {
|
||||||
state,
|
switch (action.payload.payloadVariant.oneofKind) {
|
||||||
action: PayloadAction<Protobuf.RadioConfig_UserPreferences>,
|
case 'cannedMessage': {
|
||||||
) => {
|
state.radio.moduleConfig.cannedMessage =
|
||||||
state.radio.preferences = action.payload;
|
action.payload.payloadVariant.cannedMessage;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'externalNotification': {
|
||||||
|
state.radio.moduleConfig.extNotification =
|
||||||
|
action.payload.payloadVariant.externalNotification;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'mqtt': {
|
||||||
|
state.radio.moduleConfig.mqtt = action.payload.payloadVariant.mqtt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'rangeTest': {
|
||||||
|
state.radio.moduleConfig.rangeTest =
|
||||||
|
action.payload.payloadVariant.rangeTest;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'serial': {
|
||||||
|
state.radio.moduleConfig.serial =
|
||||||
|
action.payload.payloadVariant.serial;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'storeForward': {
|
||||||
|
state.radio.moduleConfig.storeForward =
|
||||||
|
action.payload.payloadVariant.storeForward;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'telemetry': {
|
||||||
|
state.radio.moduleConfig.telemetry =
|
||||||
|
action.payload.payloadVariant.telemetry;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
addMessage: (state, action: PayloadAction<MessageWithAck>) => {
|
addMessage: (state, action: PayloadAction<MessageWithAck>) => {
|
||||||
// todo: is last interraction for just channel chats or dm's to?
|
// todo: is last interraction for just channel chats or dm's to?
|
||||||
@@ -246,8 +331,8 @@ export const {
|
|||||||
addPosition,
|
addPosition,
|
||||||
addNode,
|
addNode,
|
||||||
addChannel,
|
addChannel,
|
||||||
setPreferences,
|
setConfig,
|
||||||
addRoute,
|
setModuleConfig,
|
||||||
addMessage,
|
addMessage,
|
||||||
ackMessage,
|
ackMessage,
|
||||||
updateLastInteraction,
|
updateLastInteraction,
|
||||||
|
|||||||
@@ -4,11 +4,15 @@ import { Button } from '@components/generic/button/Button';
|
|||||||
import { Card } from '@components/generic/Card';
|
import { Card } from '@components/generic/Card';
|
||||||
import { connection } from '@core/connection';
|
import { connection } from '@core/connection';
|
||||||
import { useAppSelector } from '@hooks/useAppSelector';
|
import { useAppSelector } from '@hooks/useAppSelector';
|
||||||
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
export const Debug = (): JSX.Element => {
|
export const Debug = (): JSX.Element => {
|
||||||
const hardwareInfo = useAppSelector(
|
const hardwareInfo = useAppSelector(
|
||||||
(state) => state.meshtastic.radio.hardware,
|
(state) => state.meshtastic.radio.hardware,
|
||||||
);
|
);
|
||||||
|
const myNodeNum = useAppSelector(
|
||||||
|
(state) => state.meshtastic.radio.hardware.myNodeNum,
|
||||||
|
);
|
||||||
const node = useAppSelector((state) =>
|
const node = useAppSelector((state) =>
|
||||||
state.meshtastic.nodes.find(
|
state.meshtastic.nodes.find(
|
||||||
(node) => node.data.num === hardwareInfo.myNodeNum,
|
(node) => node.data.num === hardwareInfo.myNodeNum,
|
||||||
@@ -20,26 +24,93 @@ export const Debug = (): JSX.Element => {
|
|||||||
<Card className="flex-grow">
|
<Card className="flex-grow">
|
||||||
<div className="grid grid-cols-4 gap-4">
|
<div className="grid grid-cols-4 gap-4">
|
||||||
<Button
|
<Button
|
||||||
onClick={async (): Promise<void> => {
|
onClick={(): void => {
|
||||||
await connection.configure();
|
void connection.configure();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Configure
|
Configure
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={async (): Promise<void> => {
|
onClick={(): void => {
|
||||||
await connection.getPreferences();
|
void connection.getAllChannels();
|
||||||
}}
|
|
||||||
>
|
|
||||||
Get Preferences
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={async (): Promise<void> => {
|
|
||||||
await connection.getAllChannels();
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Get All Channels
|
Get All Channels
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={(): void => {
|
||||||
|
const packet = Protobuf.AdminMessage.create({
|
||||||
|
variant: {
|
||||||
|
oneofKind: 'getConfigRequest',
|
||||||
|
getConfigRequest:
|
||||||
|
Protobuf.AdminMessage_ConfigType.LORA_CONFIG,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
void connection.sendPacket(
|
||||||
|
Protobuf.AdminMessage.toBinary(packet),
|
||||||
|
Protobuf.PortNum.ADMIN_APP,
|
||||||
|
myNodeNum,
|
||||||
|
true,
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
async (num) => {
|
||||||
|
return await Promise.resolve();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Get All Config
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
onClick={(): void => {
|
||||||
|
void connection.getConfig(
|
||||||
|
Protobuf.AdminMessage_ConfigType.DISPLAY_CONFIG,
|
||||||
|
async (id) => {
|
||||||
|
console.log(`RESPONSE - ${id}`);
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Get Display Config
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={(): void => {
|
||||||
|
void connection.getConfig(
|
||||||
|
Protobuf.AdminMessage_ConfigType.LORA_CONFIG,
|
||||||
|
async (id) => {
|
||||||
|
console.log(`RESPONSE - ${id}`);
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Get LoRa Config
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={(): void => {
|
||||||
|
void connection.setConfig(
|
||||||
|
Protobuf.Config.create({
|
||||||
|
payloadVariant: {
|
||||||
|
oneofKind: 'lora',
|
||||||
|
lora: Protobuf.Config_LoRaConfig.create({
|
||||||
|
modemPreset:
|
||||||
|
Protobuf.Config_LoRaConfig_ModemPreset.MidSlow,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
async (id) => {
|
||||||
|
console.log(`RESPONSE - ${id}`);
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Set LoRa Config
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -22,15 +22,15 @@ export const Logs = (): JSX.Element => {
|
|||||||
[Types.Emitter.sendText]: 'text-rose-500',
|
[Types.Emitter.sendText]: 'text-rose-500',
|
||||||
[Types.Emitter.sendPacket]: 'text-pink-500',
|
[Types.Emitter.sendPacket]: 'text-pink-500',
|
||||||
[Types.Emitter.sendRaw]: 'text-fuchsia-500',
|
[Types.Emitter.sendRaw]: 'text-fuchsia-500',
|
||||||
[Types.Emitter.setPreferences]: 'text-purple-500',
|
[Types.Emitter.setConfig]: 'text-purple-500',
|
||||||
[Types.Emitter.confirmSetPreferences]: 'text-violet-500',
|
[Types.Emitter.confirmSetConfig]: 'text-violet-500',
|
||||||
[Types.Emitter.setOwner]: 'text-indigo-500',
|
[Types.Emitter.setOwner]: 'text-indigo-500',
|
||||||
[Types.Emitter.setChannel]: 'text-blue-500',
|
[Types.Emitter.setChannel]: 'text-blue-500',
|
||||||
[Types.Emitter.confirmSetChannel]: 'text-sky-500',
|
[Types.Emitter.confirmSetChannel]: 'text-sky-500',
|
||||||
[Types.Emitter.deleteChannel]: 'text-cyan-500',
|
[Types.Emitter.deleteChannel]: 'text-cyan-500',
|
||||||
[Types.Emitter.getChannel]: 'text-teal-500',
|
[Types.Emitter.getChannel]: 'text-teal-500',
|
||||||
[Types.Emitter.getAllChannels]: 'text-emerald-500',
|
[Types.Emitter.getAllChannels]: 'text-emerald-500',
|
||||||
[Types.Emitter.getPreferences]: 'text-green-500',
|
[Types.Emitter.getConfig]: 'text-green-500',
|
||||||
[Types.Emitter.getOwner]: 'text-lime-500',
|
[Types.Emitter.getOwner]: 'text-lime-500',
|
||||||
[Types.Emitter.configure]: 'text-yellow-500',
|
[Types.Emitter.configure]: 'text-yellow-500',
|
||||||
[Types.Emitter.handleFromRadio]: 'text-amber-500',
|
[Types.Emitter.handleFromRadio]: 'text-amber-500',
|
||||||
|
|||||||
+1
-1
@@ -27,7 +27,7 @@
|
|||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"removeComments": true,
|
"removeComments": true,
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"types": ["vite/client", "vite-plugin-pwa/client"],
|
"types": ["vite/client", "vite-plugin-pwa/client", "node"],
|
||||||
"importsNotUsedAsValues": "error"
|
"importsNotUsedAsValues": "error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user