Browse Source

Compat with latest JS lib

pull/82/head
Sacha Weatherstone 3 years ago
parent
commit
d538ba5a9d
No known key found for this signature in database GPG Key ID: 7AB2D7E206124B31
  1. 6
      .vscode/settings.json
  2. 42
      package.json
  3. 986
      pnpm-lock.yaml
  4. BIN
      public/apple-touch-icon.png
  5. 20
      src/components/Dialog/ImportDialog.tsx
  6. 6
      src/components/Dialog/QRDialog.tsx
  7. 10
      src/components/Dialog/RebootDialog.tsx
  8. 10
      src/components/Dialog/ShutdownDialog.tsx
  9. 8
      src/components/Drawer/Metrics.tsx
  10. 12
      src/components/Drawer/Sensor.tsx
  11. 12
      src/components/PageComponents/Channel.tsx
  12. 26
      src/components/PageComponents/Config/Bluetooth.tsx
  13. 26
      src/components/PageComponents/Config/Device.tsx
  14. 45
      src/components/PageComponents/Config/Display.tsx
  15. 26
      src/components/PageComponents/Config/LoRa.tsx
  16. 26
      src/components/PageComponents/Config/Network.tsx
  17. 34
      src/components/PageComponents/Config/Position.tsx
  18. 27
      src/components/PageComponents/Config/Power.tsx
  19. 9
      src/components/PageComponents/Config/User.tsx
  20. 55
      src/components/PageComponents/Map/MapControlls.tsx
  21. 11
      src/components/PageComponents/Messages/MessageInput.tsx
  22. 8
      src/components/PageComponents/Messages/NewLocationMessage.tsx
  23. 34
      src/components/PageComponents/ModuleConfig/Audio.tsx
  24. 26
      src/components/PageComponents/ModuleConfig/CannedMessage.tsx
  25. 27
      src/components/PageComponents/ModuleConfig/ExternalNotification.tsx
  26. 27
      src/components/PageComponents/ModuleConfig/MQTT.tsx
  27. 27
      src/components/PageComponents/ModuleConfig/RangeTest.tsx
  28. 26
      src/components/PageComponents/ModuleConfig/Serial.tsx
  29. 27
      src/components/PageComponents/ModuleConfig/StoreForward.tsx
  30. 27
      src/components/PageComponents/ModuleConfig/Telemetry.tsx
  31. 6
      src/components/Widgets/BatteryWidget.tsx
  32. 2
      src/core/stores/appStore.ts
  33. 82
      src/core/stores/deviceStore.ts
  34. 12
      src/core/subscriptions.ts
  35. 3
      src/validation/channelSettings.ts
  36. 5
      src/validation/config/bluetooth.ts
  37. 4
      src/validation/config/device.ts
  38. 4
      src/validation/config/display.ts
  39. 4
      src/validation/config/lora.ts
  40. 15
      src/validation/config/network.ts
  41. 5
      src/validation/config/position.ts
  42. 4
      src/validation/config/power.ts
  43. 6
      src/validation/config/user.ts
  44. 13
      src/validation/moduleConfig/audio.ts
  45. 6
      src/validation/moduleConfig/cannedMessage.ts
  46. 6
      src/validation/moduleConfig/externalNotification.ts
  47. 5
      src/validation/moduleConfig/mqtt.ts
  48. 3
      src/validation/moduleConfig/rangeTest.ts
  49. 5
      src/validation/moduleConfig/serial.ts
  50. 6
      src/validation/moduleConfig/storeForward.ts
  51. 3
      src/validation/moduleConfig/telemetry.ts

6
.vscode/settings.json

@ -1,6 +1,4 @@
{
"css.validate": false,
"editor.quickSuggestions": {
"strings": true
}
"editor.defaultFormatter": "trunk.io",
"editor.formatOnSave": true
}

42
package.json

@ -1,6 +1,6 @@
{
"name": "meshtastic-web",
"version": "1.0.0",
"version": "2.0.13-0",
"type": "module",
"description": "Meshtastic web client",
"license": "GPL-3.0-only",
@ -9,9 +9,6 @@
"build": "tsc && vite build",
"preview": "vite preview",
"package": "gzipper c -i html,js,css,png,ico,svg,webmanifest,txt dist dist/output && tar -cvf dist/build.tar -C ./dist/output/ $(ls ./dist/output/)",
"format:check": "prettier --check . && eslint",
"format:fix": "prettier --write . && eslint --fix",
"check:unimported": "unimported"
},
"repository": {
"type": "git",
@ -27,62 +24,63 @@
"@heroicons/react": "^2.0.13",
"@hookform/error-message": "^2.0.1",
"@hookform/resolvers": "^2.9.10",
"@meshtastic/meshtasticjs": "^2.0.12",
"@primer/octicons-react": "^17.10.1",
"@tailwindcss/typography": "^0.5.8",
"@meshtastic/meshtasticjs": "2.0.13-5",
"@primer/octicons-react": "^17.10.2",
"@tailwindcss/typography": "^0.5.9",
"@turf/turf": "^6.5.0",
"base64-js": "^1.5.1",
"chart.js": "^4.1.2",
"chart.js": "^4.2.0",
"chartjs-adapter-date-fns": "^3.0.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"date-fns": "^2.29.3",
"geodesy": "^2.4.0",
"immer": "^9.0.17",
"i18next": "^22.4.9",
"immer": "^9.0.18",
"mapbox-gl": "npm:empty-npm-package@^1.0.0",
"maplibre-gl": "2.4.0",
"pretty-ms": "^8.0.0",
"react": "^18.2.0",
"react-chartjs-2": "^5.1.0",
"react-chartjs-2": "^5.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.41.5",
"react-hook-form": "^7.42.1",
"react-hot-toast": "^2.4.0",
"react-i18next": "^12.1.4",
"react-json-tree": "^0.18.0",
"react-map-gl": "^7.0.21",
"react-qrcode-logo": "^2.8.0",
"rfc4648": "^1.5.2",
"timeago-react": "^3.0.5",
"zustand": "4.2.0"
"zustand": "4.3.2"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.3",
"@types/chrome": "^0.0.206",
"@types/chrome": "^0.0.209",
"@types/geodesy": "^2.2.3",
"@types/node": "^18.11.18",
"@types/react": "^18.0.26",
"@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10",
"@types/w3c-web-serial": "^1.0.3",
"@types/web-bluetooth": "^0.0.16",
"@typescript-eslint/eslint-plugin": "^5.48.0",
"@typescript-eslint/parser": "^5.48.0",
"@typescript-eslint/eslint-plugin": "^5.48.2",
"@typescript-eslint/parser": "^5.48.2",
"@vitejs/plugin-react": "^3.0.1",
"autoprefixer": "^10.4.13",
"eslint": "^8.31.0",
"eslint": "^8.32.0",
"eslint-config-prettier": "^8.6.0",
"eslint-import-resolver-typescript": "^3.5.2",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-react": "^7.31.11",
"eslint-import-resolver-typescript": "^3.5.3",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-react": "^7.32.1",
"eslint-plugin-react-hooks": "^4.6.0",
"gzipper": "^7.2.0",
"postcss": "^8.4.21",
"prettier": "^2.8.2",
"prettier": "^2.8.3",
"prettier-plugin-tailwindcss": "^0.2.1",
"rollup-plugin-visualizer": "^5.9.0",
"tailwindcss": "^3.2.4",
"tar": "^6.1.13",
"tslib": "^2.4.1",
"typescript": "^4.9.4",
"unimported": "^1.24.0",
"vite": "^4.0.4",
"vite-plugin-environment": "^1.1.3",
"vite-plugin-pwa": "^0.14.1"

986
pnpm-lock.yaml

File diff suppressed because it is too large

BIN
public/apple-touch-icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

20
src/components/Dialog/ImportDialog.tsx

@ -49,27 +49,27 @@ export const ImportDialog = ({
const apply = () => {
channelSet?.settings.map((ch, index) => {
connection?.setChannel({
channel: {
connection?.setChannel(
new Protobuf.Channel({
index,
role:
index === 0
? Protobuf.Channel_Role.PRIMARY
: Protobuf.Channel_Role.SECONDARY,
settings: ch
}
});
})
);
});
if (channelSet?.loraConfig) {
connection?.setConfig({
config: {
connection?.setConfig(
new Protobuf.Config({
payloadVariant: {
oneofKind: "lora",
lora: channelSet.loraConfig
case: "lora",
value: channelSet.loraConfig
}
}
});
})
);
}
};

6
src/components/Dialog/QRDialog.tsx

@ -32,13 +32,13 @@ export const QRDialog = ({
.filter((channel) => selectedChannels.includes(channel.index))
.map((channel) => channel.settings)
.filter((ch): ch is Protobuf.ChannelSettings => !!ch);
const encoded = Protobuf.ChannelSet.toBinary(
Protobuf.ChannelSet.create({
const encoded = new Protobuf.ChannelSet(
new Protobuf.ChannelSet({
loraConfig,
settings: channelsToEncode
})
);
const base64 = fromByteArray(encoded)
const base64 = fromByteArray(encoded.toBinary())
.replace(/=/g, "")
.replace(/\+/g, "-")
.replace(/\//g, "_");

10
src/components/Dialog/RebootDialog.tsx

@ -37,9 +37,7 @@ export const RebootDialog = ({
icon: <ClockIcon className="w-4" />,
action() {
connection
?.reboot({
time: time * 60
})
?.reboot(time * 60)
.then(() => setRebootDialogOpen(false));
}
}}
@ -48,11 +46,7 @@ export const RebootDialog = ({
className="w-24"
iconBefore={<ArrowPathIcon className="w-4" />}
onClick={() => {
connection
?.reboot({
time: 0
})
.then(() => setRebootDialogOpen(false));
connection?.reboot(2).then(() => setRebootDialogOpen(false));
}}
>
Now

10
src/components/Dialog/ShutdownDialog.tsx

@ -37,9 +37,7 @@ export const ShutdownDialog = ({
icon: <ClockIcon className="w-4" />,
action() {
connection
?.shutdown({
time: time * 60
})
?.shutdown(time * 60)
.then(() => setShutdownDialogOpen(false));
}
}}
@ -48,11 +46,7 @@ export const ShutdownDialog = ({
className="w-24"
iconBefore={<PowerIcon className="w-4" />}
onClick={() => {
connection
?.shutdown({
time: 0
})
.then(() => setShutdownDialogOpen(false));
connection?.shutdown(2).then(() => setShutdownDialogOpen(false));
}}
>
Now

8
src/components/Drawer/Metrics.tsx

@ -81,7 +81,7 @@ export const Metrics = (): JSX.Element => {
data: myNode?.deviceMetrics.map((metric) => {
return {
x: metric.timestamp,
y: metric.airUtilTx
y: metric.metric.airUtilTx
};
}),
backgroundColor: "rgba(102, 126, 234, 0.25)",
@ -95,7 +95,7 @@ export const Metrics = (): JSX.Element => {
data: myNode?.deviceMetrics.map((metric) => {
return {
x: metric.timestamp,
y: metric.channelUtilization
y: metric.metric.channelUtilization
};
}),
backgroundColor: "rgba(237, 100, 166, 0.25)",
@ -109,7 +109,7 @@ export const Metrics = (): JSX.Element => {
data: myNode?.deviceMetrics.map((metric) => {
return {
x: metric.timestamp,
y: metric.batteryLevel
y: metric.metric.batteryLevel
};
}),
backgroundColor: "rgba(113, 234, 102, 0.25)",
@ -123,7 +123,7 @@ export const Metrics = (): JSX.Element => {
data: myNode?.deviceMetrics.map((metric) => {
return {
x: metric.timestamp,
y: metric.voltage
y: metric.metric.voltage
};
}),
backgroundColor: "rgba(234, 166, 102, 0.25)",

12
src/components/Drawer/Sensor.tsx

@ -87,7 +87,7 @@ export const Sensor = (): JSX.Element => {
data: myNode?.environmentMetrics.map((metric) => {
return {
x: metric.timestamp,
y: metric.barometricPressure
y: metric.metric.barometricPressure
};
}),
backgroundColor: "rgba(102, 126, 234, 0.25)",
@ -101,7 +101,7 @@ export const Sensor = (): JSX.Element => {
data: myNode?.environmentMetrics.map((metric) => {
return {
x: metric.timestamp,
y: metric.current
y: metric.metric.current
};
}),
backgroundColor: "rgba(237, 100, 166, 0.25)",
@ -115,7 +115,7 @@ export const Sensor = (): JSX.Element => {
data: myNode?.environmentMetrics.map((metric) => {
return {
x: metric.timestamp,
y: metric.gasResistance
y: metric.metric.gasResistance
};
}),
backgroundColor: "rgba(113, 234, 102, 0.25)",
@ -129,7 +129,7 @@ export const Sensor = (): JSX.Element => {
data: myNode?.environmentMetrics.map((metric) => {
return {
x: metric.timestamp,
y: metric.relativeHumidity
y: metric.metric.relativeHumidity
};
}),
backgroundColor: "rgba(234, 166, 102, 0.25)",
@ -143,7 +143,7 @@ export const Sensor = (): JSX.Element => {
data: myNode?.environmentMetrics.map((metric) => {
return {
x: metric.timestamp,
y: metric.temperature
y: metric.metric.temperature
};
}),
backgroundColor: "rgba(38, 255, 212, 0.25)",
@ -157,7 +157,7 @@ export const Sensor = (): JSX.Element => {
data: myNode?.environmentMetrics.map((metric) => {
return {
x: metric.timestamp,
y: metric.voltage
y: metric.metric.voltage
};
}),
backgroundColor: "rgba(247, 255, 15, 0.25)",

12
src/components/PageComponents/Channel.tsx

@ -66,8 +66,8 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setChannel({
channel: {
.setChannel(
new Protobuf.Channel({
role:
channel?.role === Protobuf.Channel_Role.PRIMARY
? Protobuf.Channel_Role.PRIMARY
@ -79,18 +79,18 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
...data,
psk: toByteArray(data.psk ?? "")
}
}
})
})
)
.then(() =>
addChannel({
config: {
config: new Protobuf.Channel({
index: channel.index,
role: channel.role,
settings: {
...data,
psk: toByteArray(data.psk ?? "")
}
},
}),
lastInterraction: new Date(),
messages: []
})

26
src/components/PageComponents/Config/Bluetooth.tsx

@ -36,21 +36,23 @@ export const Bluetooth = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setConfig({
config: {
.setConfig(
new Protobuf.Config({
payloadVariant: {
oneofKind: "bluetooth",
bluetooth: data
}
}
})
.then(() =>
setConfig({
payloadVariant: {
oneofKind: "bluetooth",
bluetooth: data
case: "bluetooth",
value: data
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "bluetooth",
value: data
}
})
)
),
{
loading: "Saving...",

26
src/components/PageComponents/Config/Device.tsx

@ -35,21 +35,23 @@ export const Device = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setConfig({
config: {
.setConfig(
new Protobuf.Config({
payloadVariant: {
oneofKind: "device",
device: data
}
}
})
.then(() =>
setConfig({
payloadVariant: {
oneofKind: "device",
device: data
case: "device",
value: data
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "device",
value: data
}
})
)
),
{
loading: "Saving...",

45
src/components/PageComponents/Config/Display.tsx

@ -35,21 +35,23 @@ export const Display = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setConfig({
config: {
.setConfig(
new Protobuf.Config({
payloadVariant: {
oneofKind: "display",
display: data
}
}
})
.then(() =>
setConfig({
payloadVariant: {
oneofKind: "display",
display: data
case: "display",
value: data
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "display",
value: data
}
})
)
),
{
loading: "Saving...",
@ -127,6 +129,25 @@ export const Display = (): JSX.Element => {
>
{renderOptions(Protobuf.Config_DisplayConfig_OledType)}
</Select>
<Select
label="Display Mode"
description="Screen layout variant"
{...register("displaymode", { valueAsNumber: true })}
>
{renderOptions(Protobuf.Config_DisplayConfig_DisplayMode)}
</Select>
<Controller
name="headingBold"
control={control}
render={({ field: { value, ...rest } }) => (
<Toggle
label="Bold Heading"
description="Bolden the heading text"
checked={value}
{...rest}
/>
)}
/>
</Form>
);
};

26
src/components/PageComponents/Config/LoRa.tsx

@ -43,21 +43,23 @@ export const LoRa = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setConfig({
config: {
.setConfig(
new Protobuf.Config({
payloadVariant: {
oneofKind: "lora",
lora: data
}
}
})
.then(() =>
setConfig({
payloadVariant: {
oneofKind: "lora",
lora: data
case: "lora",
value: data
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "lora",
value: data
}
})
)
),
{
loading: "Saving...",

26
src/components/PageComponents/Config/Network.tsx

@ -56,21 +56,23 @@ export const Network = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setConfig({
config: {
.setConfig(
new Protobuf.Config({
payloadVariant: {
oneofKind: "network",
network: Protobuf.Config_NetworkConfig.create(data)
}
}
})
.then(() =>
setConfig({
payloadVariant: {
oneofKind: "network",
network: data
case: "network",
value: new Protobuf.Config_NetworkConfig(data)
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "network",
value: data
}
})
)
),
{
loading: "Saving...",

34
src/components/PageComponents/Config/Position.tsx

@ -55,19 +55,19 @@ export const Position = (): JSX.Element => {
const configHasChanged = !Protobuf.Config_PositionConfig.equals(
config.position,
Protobuf.Config_PositionConfig.create(rest)
new Protobuf.Config_PositionConfig(rest)
);
if (connection) {
void toast.promise(
connection
.setPosition({
position: Protobuf.Position.create({
.setPosition(
new Protobuf.Position({
altitude: fixedAlt,
latitudeI: fixedLat * 1e7,
longitudeI: fixedLng * 1e7
})
})
)
.then(() => reset({ ...data })),
{
loading: "Saving...",
@ -78,21 +78,23 @@ export const Position = (): JSX.Element => {
if (configHasChanged) {
void toast.promise(
connection
.setConfig({
config: {
.setConfig(
new Protobuf.Config({
payloadVariant: {
oneofKind: "position",
position: rest
}
}
})
.then(() =>
setConfig({
payloadVariant: {
oneofKind: "position",
position: data
case: "position",
value: rest
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "position",
value: rest
}
})
)
),
{
loading: "Saving...",

27
src/components/PageComponents/Config/Power.tsx

@ -11,6 +11,7 @@ import { PowerValidation } from "@app/validation/config/power.js";
import { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js";
import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const Power = (): JSX.Element => {
const { config, connection, setConfig } = useDevice();
@ -33,21 +34,23 @@ export const Power = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setConfig({
config: {
.setConfig(
new Protobuf.Config({
payloadVariant: {
oneofKind: "power",
power: data
}
}
})
.then(() =>
setConfig({
payloadVariant: {
oneofKind: "power",
power: data
case: "power",
value: data
}
})
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "power",
value: data
}
})
)
),
{
loading: "Saving...",

9
src/components/PageComponents/Config/User.tsx

@ -44,9 +44,12 @@ export const User = (): JSX.Element => {
if (connection && myNode?.data.user) {
void toast.promise(
connection
.setOwner({
owner: { ...myNode.data.user, ...data }
})
.setOwner(
new Protobuf.User({
...myNode.data.user,
...data
})
)
.then(() => reset({ ...data })),
{
loading: "Saving...",

55
src/components/PageComponents/Map/MapControlls.tsx

@ -1,13 +1,14 @@
import { useEffect } from "react";
import { useMap } from "react-map-gl";
import { lineString, bbox } from "@turf/turf";
import { useDevice } from "@app/core/providers/useDevice.js";
import {
MagnifyingGlassMinusIcon,
MagnifyingGlassPlusIcon,
ShareIcon
} from "@heroicons/react/24/outline";
import { useDevice } from "@app/core/providers/useDevice.js";
import { useEffect } from "react";
import { bbox, lineString } from "@turf/turf";
export const MapControlls = (): JSX.Element => {
const { current: map } = useMap();
@ -15,36 +16,23 @@ export const MapControlls = (): JSX.Element => {
const getBBox = () => {
const nodesWithPosition = nodes.filter((n) => n.data.position?.latitudeI);
if (nodesWithPosition.length > 1) {
const line = lineString(
nodesWithPosition.map((n) => [
(n.data.position?.latitudeI ?? 0) / 1e7,
(n.data.position?.longitudeI ?? 0) / 1e7
])
);
const bounds = bbox(line);
const center = map?.cameraForBounds(
[
[bounds[1], bounds[0]],
[bounds[3], bounds[2]]
],
{
padding: {
top: 10,
bottom: 10,
left: 10,
right: 10
}
}
);
if (center) {
map?.easeTo(center);
}
} else if (nodesWithPosition.length === 1) {
if (!nodesWithPosition.length) return;
const line = lineString(
nodesWithPosition.map((n) => [
(n.data.position?.latitudeI ?? 0) / 1e7,
(n.data.position?.longitudeI ?? 0) / 1e7
])
);
const bounds = bbox(line);
const center = map?.cameraForBounds(
[
[bounds[1], bounds[0]],
[bounds[3], bounds[2]]
],
{ padding: { top: 10, bottom: 10, left: 10, right: 10 } }
);
if (center) map?.easeTo(center);
else if (nodesWithPosition.length === 1)
map?.easeTo({
zoom: 12,
center: [
@ -52,7 +40,6 @@ export const MapControlls = (): JSX.Element => {
(nodesWithPosition[0].data.position?.latitudeI ?? 0) / 1e7
]
});
}
};
useEffect(() => {

11
src/components/PageComponents/Messages/MessageInput.tsx

@ -17,11 +17,12 @@ export const MessageInput = ({ channel }: MessageInputProps): JSX.Element => {
const sendText = async (message: string) => {
await connection
?.sendText({
text: message,
wantAck: true,
channel: channel.config.index as Types.ChannelNumber
})
?.sendText(
message,
"broadcast",
true,
channel.config.index as Types.ChannelNumber
)
.then((id) => setMessageState(channel.config.index, id, "ack"))
.catch((e: Types.PacketError) =>
setMessageState(channel.config.index, e.id, e.error)

8
src/components/PageComponents/Messages/NewLocationMessage.tsx

@ -31,15 +31,15 @@ export const NewLocationMessage = (): JSX.Element => {
<Input label="Coordinates" />
<Button
onClick={() => {
void connection?.sendWaypoint({
waypoint: Protobuf.Waypoint.create({
void connection?.sendWaypoint(
new Protobuf.Waypoint({
latitudeI: Math.floor(3.89103 * 1e7),
longitudeI: Math.floor(105.87005 * 1e7),
name: "TEST",
description: "This is a description"
}),
destination: "broadcast"
});
"broadcast"
);
}}
>
Send

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

@ -35,21 +35,23 @@ export const Audio = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setModuleConfig({
moduleConfig: {
.setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
oneofKind: "audio",
audio: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "audio",
audio: data
case: "audio",
value: data
}
})
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "audio",
value: data
}
})
)
),
{
loading: "Saving...",
@ -97,25 +99,25 @@ export const Audio = (): JSX.Element => {
label="i2SWs"
description="Enter a description."
type="number"
{...register("i2SWs", { valueAsNumber: true })}
{...register("i2sWs", { valueAsNumber: true })}
/>
<Input
label="i2SSd"
description="Enter a description."
type="number"
{...register("i2SSd", { valueAsNumber: true })}
{...register("i2sSd", { valueAsNumber: true })}
/>
<Input
label="i2SDin"
description="Enter a description."
type="number"
{...register("i2SDin", { valueAsNumber: true })}
{...register("i2sDin", { valueAsNumber: true })}
/>
<Input
label="i2SSck"
description="Enter a description."
type="number"
{...register("i2SSck", { valueAsNumber: true })}
{...register("i2sSck", { valueAsNumber: true })}
/>
</Form>
);

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

@ -41,21 +41,23 @@ export const CannedMessage = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setModuleConfig({
moduleConfig: {
.setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
oneofKind: "cannedMessage",
cannedMessage: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "cannedMessage",
cannedMessage: data
case: "cannedMessage",
value: data
}
})
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "cannedMessage",
value: data
}
})
)
),
{
loading: "Saving...",

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

@ -10,6 +10,7 @@ import { ExternalNotificationValidation } from "@app/validation/moduleConfig/ext
import { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js";
import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const ExternalNotification = (): JSX.Element => {
const { moduleConfig, connection, setModuleConfig } = useDevice();
@ -31,21 +32,23 @@ export const ExternalNotification = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setModuleConfig({
moduleConfig: {
.setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
oneofKind: "externalNotification",
externalNotification: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "externalNotification",
externalNotification: data
case: "externalNotification",
value: data
}
})
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "externalNotification",
value: data
}
})
)
),
{
loading: "Saving...",

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

@ -10,6 +10,7 @@ import { MQTTValidation } from "@app/validation/moduleConfig/mqtt.js";
import { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js";
import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const MQTT = (): JSX.Element => {
const { moduleConfig, connection, setModuleConfig } = useDevice();
@ -38,21 +39,23 @@ export const MQTT = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setModuleConfig({
moduleConfig: {
.setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
oneofKind: "mqtt",
mqtt: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "mqtt",
mqtt: data
case: "mqtt",
value: data
}
})
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "mqtt",
value: data
}
})
)
),
{
loading: "Saving...",

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

@ -10,6 +10,7 @@ import { RangeTestValidation } from "@app/validation/moduleConfig/rangeTest.js";
import { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js";
import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const RangeTest = (): JSX.Element => {
const { moduleConfig, connection, setModuleConfig } = useDevice();
@ -32,21 +33,23 @@ export const RangeTest = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setModuleConfig({
moduleConfig: {
.setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
oneofKind: "rangeTest",
rangeTest: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "rangeTest",
rangeTest: data
case: "rangeTest",
value: data
}
})
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "rangeTest",
value: data
}
})
)
),
{
loading: "Saving...",

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

@ -35,21 +35,23 @@ export const Serial = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setModuleConfig({
moduleConfig: {
.setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
oneofKind: "serial",
serial: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "serial",
serial: data
case: "serial",
value: data
}
})
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "serial",
value: data
}
})
)
),
{
loading: "Saving...",

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

@ -10,6 +10,7 @@ import { StoreForwardValidation } from "@app/validation/moduleConfig/storeForwar
import { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js";
import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const StoreForward = (): JSX.Element => {
const { moduleConfig, connection, setModuleConfig } = useDevice();
@ -32,21 +33,23 @@ export const StoreForward = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setModuleConfig({
moduleConfig: {
.setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
oneofKind: "storeForward",
storeForward: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "storeForward",
storeForward: data
case: "storeForward",
value: data
}
})
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "storeForward",
value: data
}
})
)
),
{
loading: "Saving...",

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

@ -10,6 +10,7 @@ import { TelemetryValidation } from "@app/validation/moduleConfig/telemetry.js";
import { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js";
import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const Telemetry = (): JSX.Element => {
const { moduleConfig, connection, setModuleConfig } = useDevice();
@ -32,21 +33,23 @@ export const Telemetry = (): JSX.Element => {
if (connection) {
void toast.promise(
connection
.setModuleConfig({
moduleConfig: {
.setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
oneofKind: "telemetry",
telemetry: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "telemetry",
telemetry: data
case: "telemetry",
value: data
}
})
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "telemetry",
value: data
}
})
)
),
{
loading: "Saving...",

6
src/components/Widgets/BatteryWidget.tsx

@ -30,12 +30,12 @@ export const BatteryWidget = ({
let previousStat: number | undefined = undefined;
let previousTime = new Date();
for (const stat of [...stats].reverse()) {
if (stat.batteryLevel) {
if (stat.metric.batteryLevel) {
if (!currentStat) {
currentStat = stat.batteryLevel;
currentStat = stat.metric.batteryLevel;
currentTime = stat.timestamp;
} else {
previousStat = stat.batteryLevel;
previousStat = stat.metric.batteryLevel;
previousTime = stat.timestamp;
break;
}

2
src/core/stores/appStore.ts

@ -1,5 +1,5 @@
import { produce } from "immer";
import create from "zustand";
import { create } from "zustand";
export interface RasterSource {
enabled: boolean;

82
src/core/stores/deviceStore.ts

@ -1,7 +1,7 @@
import { createContext } from "react";
import { produce } from "immer";
import create from "zustand";
import { create } from "zustand";
import { Protobuf, Types } from "@meshtastic/meshtasticjs";
@ -34,8 +34,14 @@ export interface Channel {
}
export interface Node {
deviceMetrics: (Protobuf.DeviceMetrics & { timestamp: Date })[];
environmentMetrics: (Protobuf.EnvironmentMetrics & { timestamp: Date })[];
deviceMetrics: {
metric: Protobuf.DeviceMetrics;
timestamp: Date;
}[];
environmentMetrics: {
metric: Protobuf.EnvironmentMetrics;
timestamp: Date;
}[];
metadata?: Protobuf.DeviceMetadata;
data: Protobuf.NodeInfo;
}
@ -125,9 +131,9 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
ready: false,
status: Types.DeviceStatusEnum.DEVICE_DISCONNECTED,
channels: [],
config: Protobuf.LocalConfig.create(),
moduleConfig: Protobuf.LocalModuleConfig.create(),
hardware: Protobuf.MyNodeInfo.create(),
config: new Protobuf.LocalConfig(),
moduleConfig: new Protobuf.LocalModuleConfig(),
hardware: new Protobuf.MyNodeInfo(),
nodes: [],
connection: undefined,
activePage: "messages",
@ -135,7 +141,7 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
activePeer: 0,
waypoints: [],
regionUnset: false,
currentMetrics: Protobuf.DeviceMetrics.create(),
currentMetrics: new Protobuf.DeviceMetrics(),
importDialogOpen: false,
QRDialogOpen: false,
shutdownDialogOpen: false,
@ -169,30 +175,30 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
const device = draft.devices.get(id);
if (device) {
switch (config.payloadVariant.oneofKind) {
switch (config.payloadVariant.case) {
case "device":
device.config.device = config.payloadVariant.device;
device.config.device = config.payloadVariant.value;
break;
case "position":
device.config.position = config.payloadVariant.position;
device.config.position = config.payloadVariant.value;
break;
case "power":
device.config.power = config.payloadVariant.power;
device.config.power = config.payloadVariant.value;
break;
case "network":
device.config.network = config.payloadVariant.network;
device.config.network = config.payloadVariant.value;
break;
case "display":
device.config.display = config.payloadVariant.display;
device.config.display = config.payloadVariant.value;
break;
case "lora":
device.config.lora = config.payloadVariant.lora;
device.config.lora = config.payloadVariant.value;
device.regionUnset =
config.payloadVariant.lora.region ===
config.payloadVariant.value.region ===
Protobuf.Config_LoRaConfig_RegionCode.UNSET;
break;
case "bluetooth":
device.config.bluetooth = config.payloadVariant.bluetooth;
device.config.bluetooth = config.payloadVariant.value;
break;
}
}
@ -205,35 +211,35 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
const device = draft.devices.get(id);
if (device) {
switch (config.payloadVariant.oneofKind) {
switch (config.payloadVariant.case) {
case "mqtt":
device.moduleConfig.mqtt = config.payloadVariant.mqtt;
device.moduleConfig.mqtt = config.payloadVariant.value;
break;
case "serial":
device.moduleConfig.serial = config.payloadVariant.serial;
device.moduleConfig.serial = config.payloadVariant.value;
break;
case "externalNotification":
device.moduleConfig.externalNotification =
config.payloadVariant.externalNotification;
config.payloadVariant.value;
break;
case "storeForward":
device.moduleConfig.storeForward =
config.payloadVariant.storeForward;
config.payloadVariant.value;
break;
case "rangeTest":
device.moduleConfig.rangeTest =
config.payloadVariant.rangeTest;
config.payloadVariant.value;
break;
case "telemetry":
device.moduleConfig.telemetry =
config.payloadVariant.telemetry;
config.payloadVariant.value;
break;
case "cannedMessage":
device.moduleConfig.cannedMessage =
config.payloadVariant.cannedMessage;
config.payloadVariant.value;
break;
case "audio":
device.moduleConfig.audio = config.payloadVariant.audio;
device.moduleConfig.audio = config.payloadVariant.value;
}
}
})
@ -257,36 +263,34 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
(n) => n.data.num === metrics.from
);
if (node) {
switch (metrics.data.variant.oneofKind) {
switch (metrics.data.variant.case) {
case "deviceMetrics":
if (device) {
if (metrics.data.variant.deviceMetrics.batteryLevel) {
if (metrics.data.variant.value.batteryLevel) {
device.currentMetrics.batteryLevel =
metrics.data.variant.deviceMetrics.batteryLevel;
metrics.data.variant.value.batteryLevel;
}
if (metrics.data.variant.deviceMetrics.voltage) {
if (metrics.data.variant.value.voltage) {
device.currentMetrics.voltage =
metrics.data.variant.deviceMetrics.voltage;
metrics.data.variant.value.voltage;
}
if (metrics.data.variant.deviceMetrics.airUtilTx) {
if (metrics.data.variant.value.airUtilTx) {
device.currentMetrics.airUtilTx =
metrics.data.variant.deviceMetrics.airUtilTx;
metrics.data.variant.value.airUtilTx;
}
if (
metrics.data.variant.deviceMetrics.channelUtilization
) {
if (metrics.data.variant.value.channelUtilization) {
device.currentMetrics.channelUtilization =
metrics.data.variant.deviceMetrics.channelUtilization;
metrics.data.variant.value.channelUtilization;
}
}
node.deviceMetrics.push({
...metrics.data.variant.deviceMetrics,
metric: metrics.data.variant.value,
timestamp: metrics.rxTime
});
break;
case "environmentMetrics":
node.environmentMetrics.push({
...metrics.data.variant.environmentMetrics,
metric: metrics.data.variant.value,
timestamp: metrics.rxTime
});
break;
@ -532,7 +536,7 @@ export const useDeviceStore = create<DeviceState>((set, get) => ({
const node = device.nodes.find((n) => n.data.num === data.from);
if (!node) {
device.nodes.push({
data: Protobuf.NodeInfo.create({
data: new Protobuf.NodeInfo({
num: data.from,
lastHeard: data.time,
snr: data.snr

12
src/core/subscriptions.ts

@ -17,16 +17,14 @@ export const subscribeAll = (
});
connection.events.onRoutingPacket.subscribe((routingPacket) => {
switch (routingPacket.data.variant.oneofKind) {
switch (routingPacket.data.variant.case) {
case "errorReason":
if (
routingPacket.data.variant.errorReason === Protobuf.Routing_Error.NONE
) {
if (routingPacket.data.variant.value === Protobuf.Routing_Error.NONE) {
return;
}
toast.error(
`Routing error: ${
Protobuf.Routing_Error[routingPacket.data.variant.errorReason]
Protobuf.Routing_Error[routingPacket.data.variant.value]
}`,
{
icon: "❌"
@ -34,12 +32,12 @@ export const subscribeAll = (
);
break;
case "routeReply":
toast(`Route Reply: ${routingPacket.data.variant.routeReply}`, {
toast(`Route Reply: ${routingPacket.data.variant.value}`, {
icon: "✅"
});
break;
case "routeRequest":
toast(`Route Request: ${routingPacket.data.variant.routeRequest}`, {
toast(`Route Request: ${routingPacket.data.variant.value}`, {
icon: "✅"
});
break;

3
src/validation/channelSettings.ts

@ -3,7 +3,8 @@ import { IsBoolean, IsInt, IsNumber, IsString, Length } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs";
export class ChannelSettingsValidation
implements Omit<Protobuf.ChannelSettings, "psk">
implements
Omit<Protobuf.ChannelSettings, keyof Protobuf.native.Message | "psk">
{
@IsBoolean()
enabled: boolean;

5
src/validation/config/bluetooth.ts

@ -2,7 +2,10 @@ import { IsBoolean, IsEnum, IsInt } from "class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export class BluetoothValidation implements Protobuf.Config_BluetoothConfig {
export class BluetoothValidation
implements
Omit<Protobuf.Config_BluetoothConfig, keyof Protobuf.native.Message>
{
@IsBoolean()
enabled: boolean;

4
src/validation/config/device.ts

@ -2,7 +2,9 @@ import { IsBoolean, IsEnum, IsInt } from "class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export class DeviceValidation implements Protobuf.Config_DeviceConfig {
export class DeviceValidation
implements Omit<Protobuf.Config_DeviceConfig, keyof Protobuf.native.Message>
{
@IsEnum(Protobuf.Config_DeviceConfig_Role)
role: Protobuf.Config_DeviceConfig_Role;

4
src/validation/config/display.ts

@ -2,7 +2,9 @@ import { IsBoolean, IsEnum, IsInt } from "class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export class DisplayValidation implements Protobuf.Config_DisplayConfig {
export class DisplayValidation
implements Omit<Protobuf.Config_DisplayConfig, keyof Protobuf.native.Message>
{
@IsInt()
screenOnSecs: number;

4
src/validation/config/lora.ts

@ -2,7 +2,9 @@ import { IsArray, IsBoolean, IsEnum, IsInt, Max, Min } from "class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export class LoRaValidation implements Protobuf.Config_LoRaConfig {
export class LoRaValidation
implements Omit<Protobuf.Config_LoRaConfig, keyof Protobuf.native.Message>
{
@IsBoolean()
usePreset: boolean;

15
src/validation/config/network.ts

@ -2,7 +2,13 @@ import { IsBoolean, IsEnum, IsIP, IsOptional, Length } from "class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export class NetworkValidation implements Protobuf.Config_NetworkConfig {
export class NetworkValidation
implements
Omit<
Protobuf.Config_NetworkConfig,
keyof Protobuf.native.Message | "ipv4Config"
>
{
@IsBoolean()
wifiEnabled: boolean;
@ -21,14 +27,17 @@ export class NetworkValidation implements Protobuf.Config_NetworkConfig {
ethEnabled: boolean;
@IsEnum(Protobuf.Config_NetworkConfig_AddressMode)
// @IsOptional()
addressMode: Protobuf.Config_NetworkConfig_AddressMode;
ipv4Config: NetworkValidation_IpV4Config;
}
export class NetworkValidation_IpV4Config
implements Protobuf.Config_NetworkConfig_IpV4Config
implements
Omit<
Protobuf.Config_NetworkConfig_IpV4Config,
keyof Protobuf.native.Message
>
{
@IsIP()
@IsOptional()

5
src/validation/config/position.ts

@ -2,7 +2,10 @@ import { IsBoolean, IsInt, IsNumber } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs";
export class PositionValidation implements Protobuf.Config_PositionConfig {
export class PositionValidation
implements
Omit<Protobuf.Config_PositionConfig, keyof Protobuf.native.Message>
{
@IsInt()
positionBroadcastSecs: number;

4
src/validation/config/power.ts

@ -2,7 +2,9 @@ import { IsBoolean, IsInt, Max, Min } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs";
export class PowerValidation implements Protobuf.Config_PowerConfig {
export class PowerValidation
implements Omit<Protobuf.Config_PowerConfig, keyof Protobuf.native.Message>
{
@IsBoolean()
isPowerSaving: boolean;

6
src/validation/config/user.ts

@ -3,7 +3,11 @@ import { IsBoolean, IsOptional, IsString, Length } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs";
export class UserValidation
implements Omit<Protobuf.User, "ID" | "macaddr" | "hwModel">
implements
Omit<
Protobuf.User,
keyof Protobuf.native.Message | "ID" | "macaddr" | "hwModel"
>
{
@IsString()
@IsOptional()

13
src/validation/moduleConfig/audio.ts

@ -2,7 +2,10 @@ import { IsBoolean, IsEnum, IsInt } from "class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export class AudioValidation implements Protobuf.ModuleConfig_AudioConfig {
export class AudioValidation
implements
Omit<Protobuf.ModuleConfig_AudioConfig, keyof Protobuf.native.Message>
{
@IsBoolean()
codec2Enabled: boolean;
@ -13,14 +16,14 @@ export class AudioValidation implements Protobuf.ModuleConfig_AudioConfig {
bitrate: Protobuf.ModuleConfig_AudioConfig_Audio_Baud;
@IsInt()
i2SWs: number;
i2sWs: number;
@IsInt()
i2SSd: number;
i2sSd: number;
@IsInt()
i2SDin: number;
i2sDin: number;
@IsInt()
i2SSck: number;
i2sSck: number;
}

6
src/validation/moduleConfig/cannedMessage.ts

@ -3,7 +3,11 @@ import { IsBoolean, IsEnum, IsInt, Length } from "class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export class CannedMessageValidation
implements Protobuf.ModuleConfig_CannedMessageConfig
implements
Omit<
Protobuf.ModuleConfig_CannedMessageConfig,
keyof Protobuf.native.Message
>
{
@IsBoolean()
rotary1Enabled: boolean;

6
src/validation/moduleConfig/externalNotification.ts

@ -3,7 +3,11 @@ import { IsBoolean, IsInt } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs";
export class ExternalNotificationValidation
implements Protobuf.ModuleConfig_ExternalNotificationConfig
implements
Omit<
Protobuf.ModuleConfig_ExternalNotificationConfig,
keyof Protobuf.native.Message
>
{
@IsBoolean()
enabled: boolean;

5
src/validation/moduleConfig/mqtt.ts

@ -2,7 +2,10 @@ import { IsBoolean, Length } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs";
export class MQTTValidation implements Protobuf.ModuleConfig_MQTTConfig {
export class MQTTValidation
implements
Omit<Protobuf.ModuleConfig_MQTTConfig, keyof Protobuf.native.Message>
{
@IsBoolean()
enabled: boolean;

3
src/validation/moduleConfig/rangeTest.ts

@ -3,7 +3,8 @@ import { IsBoolean, IsInt } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs";
export class RangeTestValidation
implements Protobuf.ModuleConfig_RangeTestConfig
implements
Omit<Protobuf.ModuleConfig_RangeTestConfig, keyof Protobuf.native.Message>
{
@IsBoolean()
enabled: boolean;

5
src/validation/moduleConfig/serial.ts

@ -2,7 +2,10 @@ import { IsBoolean, IsEnum, IsInt } from "class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export class SerialValidation implements Protobuf.ModuleConfig_SerialConfig {
export class SerialValidation
implements
Omit<Protobuf.ModuleConfig_SerialConfig, keyof Protobuf.native.Message>
{
@IsBoolean()
enabled: boolean;

6
src/validation/moduleConfig/storeForward.ts

@ -3,7 +3,11 @@ import { IsBoolean, IsInt } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs";
export class StoreForwardValidation
implements Protobuf.ModuleConfig_StoreForwardConfig
implements
Omit<
Protobuf.ModuleConfig_StoreForwardConfig,
keyof Protobuf.native.Message
>
{
@IsBoolean()
enabled: boolean;

3
src/validation/moduleConfig/telemetry.ts

@ -3,7 +3,8 @@ import { IsBoolean, IsInt } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs";
export class TelemetryValidation
implements Protobuf.ModuleConfig_TelemetryConfig
implements
Omit<Protobuf.ModuleConfig_TelemetryConfig, keyof Protobuf.native.Message>
{
@IsInt()
deviceUpdateInterval: number;

Loading…
Cancel
Save