Browse Source

Start adding module config

pull/110/head
Malte Grimm 3 years ago
parent
commit
0f01ee1cff
  1. 3
      src/components/Dashboard.tsx
  2. 47
      src/components/PageComponents/ModuleConfig/Audio.tsx
  3. 47
      src/components/PageComponents/ModuleConfig/CannedMessage.tsx
  4. 47
      src/components/PageComponents/ModuleConfig/ExternalNotification.tsx
  5. 47
      src/components/PageComponents/ModuleConfig/MQTT.tsx
  6. 47
      src/components/PageComponents/ModuleConfig/RangeTest.tsx
  7. 47
      src/components/PageComponents/ModuleConfig/Serial.tsx
  8. 48
      src/components/PageComponents/ModuleConfig/StoreForward.tsx
  9. 47
      src/components/PageComponents/ModuleConfig/Telemetry.tsx
  10. 16
      src/core/stores/appStore.ts
  11. 1
      src/core/stores/deviceStore.ts
  12. 52
      src/pages/Config/ConfigTabs.tsx
  13. 5
      src/pages/Config/ModuleConfig.tsx

3
src/components/Dashboard.tsx

@ -13,6 +13,7 @@ import { Subtle } from '@components/UI/Typography/Subtle.js';
import { ConfigList } from './PageComponents/Flasher/ConfigList';
import { DeviceList } from './PageComponents/Flasher/DeviceList';
import { ConfigTabs } from '@app/pages/Config/ConfigTabs';
export const Dashboard = () => {
let { configPresetRoot, configPresetSelected, overallFlashingState } = useAppStore();
@ -33,7 +34,7 @@ export const Dashboard = () => {
<div className="flex w-full h-full gap-3 overflow-auto">
<DeviceList rootConfig={configPresetRoot} totalConfigCount={totalConfigCount}/>
<ConfigList rootConfig={configPresetRoot} setTotalConfigCountDiff={(diff) => setTotalConfigCount(totalConfigCount + diff)}/>
<div className="flex h-full overflow-auto w-full relative"><DeviceConfig key={configPresetSelected?.name}/></div>
<div className="flex h-full overflow-auto w-full relative"><ConfigTabs key={configPresetSelected?.name}/></div>
</div>
</div>
);

47
src/components/PageComponents/ModuleConfig/Audio.tsx

@ -1,26 +1,43 @@
import type { AudioValidation } from "@app/validation/moduleConfig/audio.js";
import { useDevice } from "@core/stores/deviceStore.js";
import { useConfig, useDevice } from "@core/stores/deviceStore.js";
import { Protobuf } from "@meshtastic/meshtasticjs";
import { DynamicForm } from "@components/Form/DynamicForm.js";
import { DynamicForm, EnableSwitchData } from "@components/Form/DynamicForm.js";
import type { ConfigPreset } from "@app/core/stores/appStore";
export const Audio = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: AudioValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "audio",
value: data
}
})
);
};
const config = useConfig();
const enableSwitch: EnableSwitchData | undefined = config.overrideValues ? {
getEnabled(name) {
return config.overrideValues![name] ?? false;
},
setEnabled(name, value) {
config.overrideValues![name] = value;
},
} : undefined;
const isPresetConfig = !("id" in config);
const setConfig: (data: AudioValidation) => void =
isPresetConfig ? (data) => {
config.moduleConfig.audio = new Protobuf.ModuleConfig_AudioConfig(data);
(config as ConfigPreset).saveConfigTree();
}
: (data) => {
useDevice().setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "audio",
value: data
}
})
);
}
const onSubmit = setConfig;
return (
<DynamicForm<AudioValidation>
onSubmit={onSubmit}
defaultValues={moduleConfig.audio}
defaultValues={config.moduleConfig.audio}
enableSwitch={enableSwitch}
fieldGroups={[
{
label: "Audio Settings",

47
src/components/PageComponents/ModuleConfig/CannedMessage.tsx

@ -1,26 +1,43 @@
import type { CannedMessageValidation } from "@app/validation/moduleConfig/cannedMessage.js";
import { useDevice } from "@core/stores/deviceStore.js";
import { useConfig, useDevice } from "@core/stores/deviceStore.js";
import { Protobuf } from "@meshtastic/meshtasticjs";
import { DynamicForm } from "@components/Form/DynamicForm.js";
import { DynamicForm, EnableSwitchData } from "@components/Form/DynamicForm.js";
import type { ConfigPreset } from "@app/core/stores/appStore";
export const CannedMessage = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: CannedMessageValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "cannedMessage",
value: data
}
})
);
};
const config = useConfig();
const enableSwitch: EnableSwitchData | undefined = config.overrideValues ? {
getEnabled(name) {
return config.overrideValues![name] ?? false;
},
setEnabled(name, value) {
config.overrideValues![name] = value;
},
} : undefined;
const isPresetConfig = !("id" in config);
const setConfig: (data: CannedMessageValidation) => void =
isPresetConfig ? (data) => {
config.moduleConfig.cannedMessage = new Protobuf.ModuleConfig_CannedMessageConfig(data);
(config as ConfigPreset).saveConfigTree();
}
: (data) => {
useDevice().setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "cannedMessage",
value: data
}
})
);
}
const onSubmit = setConfig;
return (
<DynamicForm<CannedMessageValidation>
onSubmit={onSubmit}
defaultValues={moduleConfig.mqtt}
defaultValues={config.moduleConfig.mqtt}
enableSwitch={enableSwitch}
fieldGroups={[
{
label: "Canned Message Settings",

47
src/components/PageComponents/ModuleConfig/ExternalNotification.tsx

@ -1,26 +1,43 @@
import type { ExternalNotificationValidation } from "@app/validation/moduleConfig/externalNotification.js";
import { useDevice } from "@core/stores/deviceStore.js";
import { useConfig, useDevice } from "@core/stores/deviceStore.js";
import { Protobuf } from "@meshtastic/meshtasticjs";
import { DynamicForm } from "@components/Form/DynamicForm.js";
import { DynamicForm, EnableSwitchData } from "@components/Form/DynamicForm.js";
import type { ConfigPreset } from "@app/core/stores/appStore";
export const ExternalNotification = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: ExternalNotificationValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "externalNotification",
value: data
}
})
);
};
const config = useConfig();
const enableSwitch: EnableSwitchData | undefined = config.overrideValues ? {
getEnabled(name) {
return config.overrideValues![name] ?? false;
},
setEnabled(name, value) {
config.overrideValues![name] = value;
},
} : undefined;
const isPresetConfig = !("id" in config);
const setConfig: (data: ExternalNotificationValidation) => void =
isPresetConfig ? (data) => {
config.moduleConfig.externalNotification = new Protobuf.ModuleConfig_ExternalNotificationConfig(data);
(config as ConfigPreset).saveConfigTree();
}
: (data) => {
useDevice().setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "externalNotification",
value: data
}
})
);
}
const onSubmit = setConfig;
return (
<DynamicForm<ExternalNotificationValidation>
onSubmit={onSubmit}
defaultValues={moduleConfig.externalNotification}
defaultValues={config.moduleConfig.externalNotification}
enableSwitch={enableSwitch}
fieldGroups={[
{
label: "External Notification Settings",

47
src/components/PageComponents/ModuleConfig/MQTT.tsx

@ -1,26 +1,43 @@
import type { MQTTValidation } from "@app/validation/moduleConfig/mqtt.js";
import { Protobuf } from "@meshtastic/meshtasticjs";
import { DynamicForm } from "@components/Form/DynamicForm.js";
import { useDevice } from "@app/core/stores/deviceStore.js";
import { DynamicForm, EnableSwitchData } from "@components/Form/DynamicForm.js";
import { useConfig, useDevice } from "@app/core/stores/deviceStore.js";
import type { ConfigPreset } from "@app/core/stores/appStore";
export const MQTT = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: MQTTValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "mqtt",
value: data
}
})
);
};
const config = useConfig();
const enableSwitch: EnableSwitchData | undefined = config.overrideValues ? {
getEnabled(name) {
return config.overrideValues![name] ?? false;
},
setEnabled(name, value) {
config.overrideValues![name] = value;
},
} : undefined;
const isPresetConfig = !("id" in config);
const setConfig: (data: MQTTValidation) => void =
isPresetConfig ? (data) => {
config.moduleConfig.mqtt = new Protobuf.ModuleConfig_MQTTConfig(data);
(config as ConfigPreset).saveConfigTree();
}
: (data) => {
useDevice().setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "mqtt",
value: data
}
})
);
}
const onSubmit = setConfig;
return (
<DynamicForm<MQTTValidation>
onSubmit={onSubmit}
defaultValues={moduleConfig.mqtt}
defaultValues={config.moduleConfig.mqtt}
enableSwitch={enableSwitch}
fieldGroups={[
{
label: "MQTT Settings",

47
src/components/PageComponents/ModuleConfig/RangeTest.tsx

@ -1,26 +1,43 @@
import type { RangeTestValidation } from "@app/validation/moduleConfig/rangeTest.js";
import { useDevice } from "@core/stores/deviceStore.js";
import { useConfig, useDevice } from "@core/stores/deviceStore.js";
import { Protobuf } from "@meshtastic/meshtasticjs";
import { DynamicForm } from "@components/Form/DynamicForm.js";
import { DynamicForm, EnableSwitchData } from "@components/Form/DynamicForm.js";
import type { ConfigPreset } from "@app/core/stores/appStore";
export const RangeTest = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: RangeTestValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "rangeTest",
value: data
}
})
);
};
const config = useConfig();
const enableSwitch: EnableSwitchData | undefined = config.overrideValues ? {
getEnabled(name) {
return config.overrideValues![name] ?? false;
},
setEnabled(name, value) {
config.overrideValues![name] = value;
},
} : undefined;
const isPresetConfig = !("id" in config);
const setConfig: (data: RangeTestValidation) => void =
isPresetConfig ? (data) => {
config.moduleConfig.rangeTest = new Protobuf.ModuleConfig_RangeTestConfig(data);
(config as ConfigPreset).saveConfigTree();
}
: (data) => {
useDevice().setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "rangeTest",
value: data
}
})
);
}
const onSubmit = setConfig;
return (
<DynamicForm<RangeTestValidation>
onSubmit={onSubmit}
defaultValues={moduleConfig.mqtt}
defaultValues={config.moduleConfig.rangeTest}
enableSwitch={enableSwitch}
fieldGroups={[
{
label: "Range Test Settings",

47
src/components/PageComponents/ModuleConfig/Serial.tsx

@ -1,26 +1,43 @@
import type { SerialValidation } from "@app/validation/moduleConfig/serial.js";
import { useDevice } from "@core/stores/deviceStore.js";
import { useConfig, useDevice } from "@core/stores/deviceStore.js";
import { Protobuf } from "@meshtastic/meshtasticjs";
import { DynamicForm } from "@components/Form/DynamicForm.js";
import { DynamicForm, EnableSwitchData } from "@components/Form/DynamicForm.js";
import type { ConfigPreset } from "@app/core/stores/appStore";
export const Serial = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: SerialValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "serial",
value: data
}
})
);
};
const config = useConfig();
const enableSwitch: EnableSwitchData | undefined = config.overrideValues ? {
getEnabled(name) {
return config.overrideValues![name] ?? false;
},
setEnabled(name, value) {
config.overrideValues![name] = value;
},
} : undefined;
const isPresetConfig = !("id" in config);
const setConfig: (data: SerialValidation) => void =
isPresetConfig ? (data) => {
config.moduleConfig.serial = new Protobuf.ModuleConfig_SerialConfig(data);
(config as ConfigPreset).saveConfigTree();
}
: (data) => {
useDevice().setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "serial",
value: data
}
})
);
}
const onSubmit = setConfig;
return (
<DynamicForm<SerialValidation>
onSubmit={onSubmit}
defaultValues={moduleConfig.serial}
defaultValues={config.moduleConfig.serial}
enableSwitch={enableSwitch}
fieldGroups={[
{
label: "Serial Settings",

48
src/components/PageComponents/ModuleConfig/StoreForward.tsx

@ -1,26 +1,42 @@
import type { StoreForwardValidation } from "@app/validation/moduleConfig/storeForward.js";
import { useDevice } from "@core/stores/deviceStore.js";
import { useConfig, useDevice } from "@core/stores/deviceStore.js";
import { Protobuf } from "@meshtastic/meshtasticjs";
import { DynamicForm } from "@components/Form/DynamicForm.js";
import { DynamicForm, EnableSwitchData } from "@components/Form/DynamicForm.js";
import type { ConfigPreset } from "@app/core/stores/appStore";
export const StoreForward = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: StoreForwardValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "storeForward",
value: data
}
})
);
};
const config = useConfig();
const enableSwitch: EnableSwitchData | undefined = config.overrideValues ? {
getEnabled(name) {
return config.overrideValues![name] ?? false;
},
setEnabled(name, value) {
config.overrideValues![name] = value;
},
} : undefined;
const isPresetConfig = !("id" in config);
const setConfig: (data: StoreForwardValidation) => void =
isPresetConfig ? (data) => {
config.moduleConfig.storeForward = new Protobuf.ModuleConfig_StoreForwardConfig(data);
(config as ConfigPreset).saveConfigTree();
}
: (data) => {
useDevice().setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "storeForward",
value: data
}
})
);
}
const onSubmit = setConfig;
return (
<DynamicForm<StoreForwardValidation>
onSubmit={onSubmit}
defaultValues={moduleConfig.mqtt}
defaultValues={config.moduleConfig.storeForward}
enableSwitch={enableSwitch}
fieldGroups={[
{
label: "Store & Forward Settings",

47
src/components/PageComponents/ModuleConfig/Telemetry.tsx

@ -1,26 +1,43 @@
import type { TelemetryValidation } from "@app/validation/moduleConfig/telemetry.js";
import { useDevice } from "@core/stores/deviceStore.js";
import { useConfig, useDevice } from "@core/stores/deviceStore.js";
import { Protobuf } from "@meshtastic/meshtasticjs";
import { DynamicForm } from "@components/Form/DynamicForm.js";
import { DynamicForm, EnableSwitchData } from "@components/Form/DynamicForm.js";
import type { ConfigPreset } from "@app/core/stores/appStore";
export const Telemetry = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: TelemetryValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "telemetry",
value: data
}
})
);
};
const config = useConfig();
const enableSwitch: EnableSwitchData | undefined = config.overrideValues ? {
getEnabled(name) {
return config.overrideValues![name] ?? false;
},
setEnabled(name, value) {
config.overrideValues![name] = value;
},
} : undefined;
const isPresetConfig = !("id" in config);
const setConfig: (data: TelemetryValidation) => void =
isPresetConfig ? (data) => {
config.moduleConfig.telemetry = new Protobuf.ModuleConfig_TelemetryConfig(data);
(config as ConfigPreset).saveConfigTree();
}
: (data) => {
useDevice().setWorkingModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "telemetry",
value: data
}
})
);
}
const onSubmit = setConfig;
return (
<DynamicForm<TelemetryValidation>
onSubmit={onSubmit}
defaultValues={moduleConfig.telemetry}
defaultValues={config.moduleConfig.telemetry}
enableSwitch={enableSwitch}
fieldGroups={[
{
label: "Telemetry Settings",

16
src/core/stores/appStore.ts

@ -5,6 +5,7 @@ import { Protobuf } from '@meshtastic/meshtasticjs';
import type { OverallFlashingState } from '../flashing/Flasher';
import type { FirmwareVersion } from '@app/components/PageComponents/Flasher/FlashSettings';
import type { LocalModuleConfig } from '@meshtastic/meshtasticjs/dist/protobufs';
export interface RasterSource {
enabled: boolean;
@ -28,7 +29,7 @@ export class ConfigPreset {
public count: number = 0;
public overrideValues: {[fieldName: string]: boolean};
public constructor(public name: string, public parent?: ConfigPreset, public config = ConfigPreset.createDefaultConfig()) {
public constructor(public name: string, public parent?: ConfigPreset, public config = ConfigPreset.createDefaultConfig(), public moduleConfig = ConfigPreset.createDefaultModuleConfig()) {
if(parent) {
// Root config should not be overridable
this.overrideValues = {};
@ -177,6 +178,19 @@ export class ConfigPreset {
});
}
private static createDefaultModuleConfig(): Protobuf.LocalModuleConfig {
return new Protobuf.LocalModuleConfig({
mqtt: new Protobuf.ModuleConfig_MQTTConfig({ }),
serial: new Protobuf.ModuleConfig_SerialConfig({ }),
externalNotification: new Protobuf.ModuleConfig_ExternalNotificationConfig({ }),
storeForward: new Protobuf.ModuleConfig_StoreForwardConfig({ }),
rangeTest: new Protobuf.ModuleConfig_RangeTestConfig({ }),
telemetry: new Protobuf.ModuleConfig_TelemetryConfig({ }),
cannedMessage: new Protobuf.ModuleConfig_CannedMessageConfig({ }),
audio: new Protobuf.ModuleConfig_AudioConfig({ })
});
}
}
function loadFirmwareListFromStorage(): FirmwareVersion[] {

1
src/core/stores/deviceStore.ts

@ -604,6 +604,7 @@ export const useDevice = (): Device => {
interface ConfigProvider {
config: Protobuf.LocalConfig;
moduleConfig: Protobuf.LocalModuleConfig;
overrideValues?: {[fieldName: string]: boolean};
}

52
src/pages/Config/ConfigTabs.tsx

@ -0,0 +1,52 @@
import { Fragment, useContext } from "react";
import { Network } from "@components/PageComponents/Config/Network.js";
import { Bluetooth } from "@components/PageComponents/Config/Bluetooth.js";
import { Device } from "@components/PageComponents/Config/Device.js";
import { Display } from "@components/PageComponents/Config/Display.js";
import { LoRa } from "@components/PageComponents/Config/LoRa.js";
import { Position } from "@components/PageComponents/Config/Position.js";
import { Power } from "@components/PageComponents/Config/Power.js";
import { DeviceContext, useDevice } from "@core/stores/deviceStore.js";
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger
} from "@components/UI/Tabs.js";
import { DeviceConfig } from "./DeviceConfig";
import { ModuleConfig } from "./ModuleConfig";
export const ConfigTabs = (): JSX.Element => {
const tabs = [
{
label: "Device",
element: DeviceConfig,
count: 0
},
{
label: "Module",
element: ModuleConfig
}
];
return (
<Tabs defaultValue="Device">
<TabsList>
{tabs.map((tab) => (
<TabsTrigger
key={tab.label}
value={tab.label}
>
{tab.label}
</TabsTrigger>
))}
</TabsList>
{tabs.map((tab) => (
<TabsContent key={tab.label} value={tab.label} className="border-0 p-0">
<tab.element />
</TabsContent>
))}
</Tabs>
);
};

5
src/pages/Config/ModuleConfig.tsx

@ -7,7 +7,6 @@ import { RangeTest } from "@components/PageComponents/ModuleConfig/RangeTest.js"
import { Serial } from "@components/PageComponents/ModuleConfig/Serial.js";
import { StoreForward } from "@components/PageComponents/ModuleConfig/StoreForward.js";
import { Telemetry } from "@components/PageComponents/ModuleConfig/Telemetry.js";
import { useDevice } from "@app/core/stores/deviceStore.js";
import {
Tabs,
TabsContent,
@ -15,9 +14,7 @@ import {
TabsTrigger
} from "@components/UI/Tabs.js";
export const ModuleConfig = (): JSX.Element => {
const { workingModuleConfig, connection } = useDevice();
export const ModuleConfig = (): JSX.Element => {
const tabs = [
{
label: "MQTT",

Loading…
Cancel
Save