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.defaultFormatter": "trunk.io",
"editor.quickSuggestions": { "editor.formatOnSave": true
"strings": true
}
} }

42
package.json

@ -1,6 +1,6 @@
{ {
"name": "meshtastic-web", "name": "meshtastic-web",
"version": "1.0.0", "version": "2.0.13-0",
"type": "module", "type": "module",
"description": "Meshtastic web client", "description": "Meshtastic web client",
"license": "GPL-3.0-only", "license": "GPL-3.0-only",
@ -9,9 +9,6 @@
"build": "tsc && vite build", "build": "tsc && vite build",
"preview": "vite preview", "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/)", "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": { "repository": {
"type": "git", "type": "git",
@ -27,62 +24,63 @@
"@heroicons/react": "^2.0.13", "@heroicons/react": "^2.0.13",
"@hookform/error-message": "^2.0.1", "@hookform/error-message": "^2.0.1",
"@hookform/resolvers": "^2.9.10", "@hookform/resolvers": "^2.9.10",
"@meshtastic/meshtasticjs": "^2.0.12", "@meshtastic/meshtasticjs": "2.0.13-5",
"@primer/octicons-react": "^17.10.1", "@primer/octicons-react": "^17.10.2",
"@tailwindcss/typography": "^0.5.8", "@tailwindcss/typography": "^0.5.9",
"@turf/turf": "^6.5.0", "@turf/turf": "^6.5.0",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
"chart.js": "^4.1.2", "chart.js": "^4.2.0",
"chartjs-adapter-date-fns": "^3.0.0", "chartjs-adapter-date-fns": "^3.0.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.0", "class-validator": "^0.14.0",
"date-fns": "^2.29.3", "date-fns": "^2.29.3",
"geodesy": "^2.4.0", "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", "mapbox-gl": "npm:empty-npm-package@^1.0.0",
"maplibre-gl": "2.4.0", "maplibre-gl": "2.4.0",
"pretty-ms": "^8.0.0", "pretty-ms": "^8.0.0",
"react": "^18.2.0", "react": "^18.2.0",
"react-chartjs-2": "^5.1.0", "react-chartjs-2": "^5.2.0",
"react-dom": "^18.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-hot-toast": "^2.4.0",
"react-i18next": "^12.1.4",
"react-json-tree": "^0.18.0", "react-json-tree": "^0.18.0",
"react-map-gl": "^7.0.21", "react-map-gl": "^7.0.21",
"react-qrcode-logo": "^2.8.0", "react-qrcode-logo": "^2.8.0",
"rfc4648": "^1.5.2", "rfc4648": "^1.5.2",
"timeago-react": "^3.0.5", "timeago-react": "^3.0.5",
"zustand": "4.2.0" "zustand": "4.3.2"
}, },
"devDependencies": { "devDependencies": {
"@tailwindcss/forms": "^0.5.3", "@tailwindcss/forms": "^0.5.3",
"@types/chrome": "^0.0.206", "@types/chrome": "^0.0.209",
"@types/geodesy": "^2.2.3", "@types/geodesy": "^2.2.3",
"@types/node": "^18.11.18", "@types/node": "^18.11.18",
"@types/react": "^18.0.26", "@types/react": "^18.0.27",
"@types/react-dom": "^18.0.10", "@types/react-dom": "^18.0.10",
"@types/w3c-web-serial": "^1.0.3", "@types/w3c-web-serial": "^1.0.3",
"@types/web-bluetooth": "^0.0.16", "@types/web-bluetooth": "^0.0.16",
"@typescript-eslint/eslint-plugin": "^5.48.0", "@typescript-eslint/eslint-plugin": "^5.48.2",
"@typescript-eslint/parser": "^5.48.0", "@typescript-eslint/parser": "^5.48.2",
"@vitejs/plugin-react": "^3.0.1", "@vitejs/plugin-react": "^3.0.1",
"autoprefixer": "^10.4.13", "autoprefixer": "^10.4.13",
"eslint": "^8.31.0", "eslint": "^8.32.0",
"eslint-config-prettier": "^8.6.0", "eslint-config-prettier": "^8.6.0",
"eslint-import-resolver-typescript": "^3.5.2", "eslint-import-resolver-typescript": "^3.5.3",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-react": "^7.31.11", "eslint-plugin-react": "^7.32.1",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"gzipper": "^7.2.0", "gzipper": "^7.2.0",
"postcss": "^8.4.21", "postcss": "^8.4.21",
"prettier": "^2.8.2", "prettier": "^2.8.3",
"prettier-plugin-tailwindcss": "^0.2.1", "prettier-plugin-tailwindcss": "^0.2.1",
"rollup-plugin-visualizer": "^5.9.0", "rollup-plugin-visualizer": "^5.9.0",
"tailwindcss": "^3.2.4", "tailwindcss": "^3.2.4",
"tar": "^6.1.13", "tar": "^6.1.13",
"tslib": "^2.4.1", "tslib": "^2.4.1",
"typescript": "^4.9.4", "typescript": "^4.9.4",
"unimported": "^1.24.0",
"vite": "^4.0.4", "vite": "^4.0.4",
"vite-plugin-environment": "^1.1.3", "vite-plugin-environment": "^1.1.3",
"vite-plugin-pwa": "^0.14.1" "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 = () => { const apply = () => {
channelSet?.settings.map((ch, index) => { channelSet?.settings.map((ch, index) => {
connection?.setChannel({ connection?.setChannel(
channel: { new Protobuf.Channel({
index, index,
role: role:
index === 0 index === 0
? Protobuf.Channel_Role.PRIMARY ? Protobuf.Channel_Role.PRIMARY
: Protobuf.Channel_Role.SECONDARY, : Protobuf.Channel_Role.SECONDARY,
settings: ch settings: ch
} })
}); );
}); });
if (channelSet?.loraConfig) { if (channelSet?.loraConfig) {
connection?.setConfig({ connection?.setConfig(
config: { new Protobuf.Config({
payloadVariant: { payloadVariant: {
oneofKind: "lora", case: "lora",
lora: channelSet.loraConfig value: channelSet.loraConfig
} }
} })
}); );
} }
}; };

6
src/components/Dialog/QRDialog.tsx

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

10
src/components/Dialog/RebootDialog.tsx

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

10
src/components/Dialog/ShutdownDialog.tsx

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

8
src/components/Drawer/Metrics.tsx

@ -81,7 +81,7 @@ export const Metrics = (): JSX.Element => {
data: myNode?.deviceMetrics.map((metric) => { data: myNode?.deviceMetrics.map((metric) => {
return { return {
x: metric.timestamp, x: metric.timestamp,
y: metric.airUtilTx y: metric.metric.airUtilTx
}; };
}), }),
backgroundColor: "rgba(102, 126, 234, 0.25)", backgroundColor: "rgba(102, 126, 234, 0.25)",
@ -95,7 +95,7 @@ export const Metrics = (): JSX.Element => {
data: myNode?.deviceMetrics.map((metric) => { data: myNode?.deviceMetrics.map((metric) => {
return { return {
x: metric.timestamp, x: metric.timestamp,
y: metric.channelUtilization y: metric.metric.channelUtilization
}; };
}), }),
backgroundColor: "rgba(237, 100, 166, 0.25)", backgroundColor: "rgba(237, 100, 166, 0.25)",
@ -109,7 +109,7 @@ export const Metrics = (): JSX.Element => {
data: myNode?.deviceMetrics.map((metric) => { data: myNode?.deviceMetrics.map((metric) => {
return { return {
x: metric.timestamp, x: metric.timestamp,
y: metric.batteryLevel y: metric.metric.batteryLevel
}; };
}), }),
backgroundColor: "rgba(113, 234, 102, 0.25)", backgroundColor: "rgba(113, 234, 102, 0.25)",
@ -123,7 +123,7 @@ export const Metrics = (): JSX.Element => {
data: myNode?.deviceMetrics.map((metric) => { data: myNode?.deviceMetrics.map((metric) => {
return { return {
x: metric.timestamp, x: metric.timestamp,
y: metric.voltage y: metric.metric.voltage
}; };
}), }),
backgroundColor: "rgba(234, 166, 102, 0.25)", 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) => { data: myNode?.environmentMetrics.map((metric) => {
return { return {
x: metric.timestamp, x: metric.timestamp,
y: metric.barometricPressure y: metric.metric.barometricPressure
}; };
}), }),
backgroundColor: "rgba(102, 126, 234, 0.25)", backgroundColor: "rgba(102, 126, 234, 0.25)",
@ -101,7 +101,7 @@ export const Sensor = (): JSX.Element => {
data: myNode?.environmentMetrics.map((metric) => { data: myNode?.environmentMetrics.map((metric) => {
return { return {
x: metric.timestamp, x: metric.timestamp,
y: metric.current y: metric.metric.current
}; };
}), }),
backgroundColor: "rgba(237, 100, 166, 0.25)", backgroundColor: "rgba(237, 100, 166, 0.25)",
@ -115,7 +115,7 @@ export const Sensor = (): JSX.Element => {
data: myNode?.environmentMetrics.map((metric) => { data: myNode?.environmentMetrics.map((metric) => {
return { return {
x: metric.timestamp, x: metric.timestamp,
y: metric.gasResistance y: metric.metric.gasResistance
}; };
}), }),
backgroundColor: "rgba(113, 234, 102, 0.25)", backgroundColor: "rgba(113, 234, 102, 0.25)",
@ -129,7 +129,7 @@ export const Sensor = (): JSX.Element => {
data: myNode?.environmentMetrics.map((metric) => { data: myNode?.environmentMetrics.map((metric) => {
return { return {
x: metric.timestamp, x: metric.timestamp,
y: metric.relativeHumidity y: metric.metric.relativeHumidity
}; };
}), }),
backgroundColor: "rgba(234, 166, 102, 0.25)", backgroundColor: "rgba(234, 166, 102, 0.25)",
@ -143,7 +143,7 @@ export const Sensor = (): JSX.Element => {
data: myNode?.environmentMetrics.map((metric) => { data: myNode?.environmentMetrics.map((metric) => {
return { return {
x: metric.timestamp, x: metric.timestamp,
y: metric.temperature y: metric.metric.temperature
}; };
}), }),
backgroundColor: "rgba(38, 255, 212, 0.25)", backgroundColor: "rgba(38, 255, 212, 0.25)",
@ -157,7 +157,7 @@ export const Sensor = (): JSX.Element => {
data: myNode?.environmentMetrics.map((metric) => { data: myNode?.environmentMetrics.map((metric) => {
return { return {
x: metric.timestamp, x: metric.timestamp,
y: metric.voltage y: metric.metric.voltage
}; };
}), }),
backgroundColor: "rgba(247, 255, 15, 0.25)", 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) { if (connection) {
void toast.promise( void toast.promise(
connection connection
.setChannel({ .setChannel(
channel: { new Protobuf.Channel({
role: role:
channel?.role === Protobuf.Channel_Role.PRIMARY channel?.role === Protobuf.Channel_Role.PRIMARY
? Protobuf.Channel_Role.PRIMARY ? Protobuf.Channel_Role.PRIMARY
@ -79,18 +79,18 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
...data, ...data,
psk: toByteArray(data.psk ?? "") psk: toByteArray(data.psk ?? "")
} }
} })
}) )
.then(() => .then(() =>
addChannel({ addChannel({
config: { config: new Protobuf.Channel({
index: channel.index, index: channel.index,
role: channel.role, role: channel.role,
settings: { settings: {
...data, ...data,
psk: toByteArray(data.psk ?? "") psk: toByteArray(data.psk ?? "")
} }
}, }),
lastInterraction: new Date(), lastInterraction: new Date(),
messages: [] messages: []
}) })

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

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

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

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

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

@ -35,21 +35,23 @@ export const Display = (): JSX.Element => {
if (connection) { if (connection) {
void toast.promise( void toast.promise(
connection connection
.setConfig({ .setConfig(
config: { new Protobuf.Config({
payloadVariant: { payloadVariant: {
oneofKind: "display", case: "display",
display: data value: data
}
}
})
.then(() =>
setConfig({
payloadVariant: {
oneofKind: "display",
display: data
} }
}) })
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "display",
value: data
}
})
)
), ),
{ {
loading: "Saving...", loading: "Saving...",
@ -127,6 +129,25 @@ export const Display = (): JSX.Element => {
> >
{renderOptions(Protobuf.Config_DisplayConfig_OledType)} {renderOptions(Protobuf.Config_DisplayConfig_OledType)}
</Select> </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> </Form>
); );
}; };

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

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

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

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

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

@ -55,19 +55,19 @@ export const Position = (): JSX.Element => {
const configHasChanged = !Protobuf.Config_PositionConfig.equals( const configHasChanged = !Protobuf.Config_PositionConfig.equals(
config.position, config.position,
Protobuf.Config_PositionConfig.create(rest) new Protobuf.Config_PositionConfig(rest)
); );
if (connection) { if (connection) {
void toast.promise( void toast.promise(
connection connection
.setPosition({ .setPosition(
position: Protobuf.Position.create({ new Protobuf.Position({
altitude: fixedAlt, altitude: fixedAlt,
latitudeI: fixedLat * 1e7, latitudeI: fixedLat * 1e7,
longitudeI: fixedLng * 1e7 longitudeI: fixedLng * 1e7
}) })
}) )
.then(() => reset({ ...data })), .then(() => reset({ ...data })),
{ {
loading: "Saving...", loading: "Saving...",
@ -78,21 +78,23 @@ export const Position = (): JSX.Element => {
if (configHasChanged) { if (configHasChanged) {
void toast.promise( void toast.promise(
connection connection
.setConfig({ .setConfig(
config: { new Protobuf.Config({
payloadVariant: { payloadVariant: {
oneofKind: "position", case: "position",
position: rest value: rest
}
}
})
.then(() =>
setConfig({
payloadVariant: {
oneofKind: "position",
position: data
} }
}) })
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "position",
value: rest
}
})
)
), ),
{ {
loading: "Saving...", 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 { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js"; import { useDevice } from "@core/providers/useDevice.js";
import { classValidatorResolver } from "@hookform/resolvers/class-validator"; import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const Power = (): JSX.Element => { export const Power = (): JSX.Element => {
const { config, connection, setConfig } = useDevice(); const { config, connection, setConfig } = useDevice();
@ -33,21 +34,23 @@ export const Power = (): JSX.Element => {
if (connection) { if (connection) {
void toast.promise( void toast.promise(
connection connection
.setConfig({ .setConfig(
config: { new Protobuf.Config({
payloadVariant: { payloadVariant: {
oneofKind: "power", case: "power",
power: data value: data
}
}
})
.then(() =>
setConfig({
payloadVariant: {
oneofKind: "power",
power: data
} }
}) })
)
.then(() =>
setConfig(
new Protobuf.Config({
payloadVariant: {
case: "power",
value: data
}
})
)
), ),
{ {
loading: "Saving...", loading: "Saving...",

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

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

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

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

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

@ -17,11 +17,12 @@ export const MessageInput = ({ channel }: MessageInputProps): JSX.Element => {
const sendText = async (message: string) => { const sendText = async (message: string) => {
await connection await connection
?.sendText({ ?.sendText(
text: message, message,
wantAck: true, "broadcast",
channel: channel.config.index as Types.ChannelNumber true,
}) channel.config.index as Types.ChannelNumber
)
.then((id) => setMessageState(channel.config.index, id, "ack")) .then((id) => setMessageState(channel.config.index, id, "ack"))
.catch((e: Types.PacketError) => .catch((e: Types.PacketError) =>
setMessageState(channel.config.index, e.id, e.error) 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" /> <Input label="Coordinates" />
<Button <Button
onClick={() => { onClick={() => {
void connection?.sendWaypoint({ void connection?.sendWaypoint(
waypoint: Protobuf.Waypoint.create({ new Protobuf.Waypoint({
latitudeI: Math.floor(3.89103 * 1e7), latitudeI: Math.floor(3.89103 * 1e7),
longitudeI: Math.floor(105.87005 * 1e7), longitudeI: Math.floor(105.87005 * 1e7),
name: "TEST", name: "TEST",
description: "This is a description" description: "This is a description"
}), }),
destination: "broadcast" "broadcast"
}); );
}} }}
> >
Send Send

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

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

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

@ -41,21 +41,23 @@ export const CannedMessage = (): JSX.Element => {
if (connection) { if (connection) {
void toast.promise( void toast.promise(
connection connection
.setModuleConfig({ .setModuleConfig(
moduleConfig: { new Protobuf.ModuleConfig({
payloadVariant: { payloadVariant: {
oneofKind: "cannedMessage", case: "cannedMessage",
cannedMessage: data value: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "cannedMessage",
cannedMessage: data
} }
}) })
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "cannedMessage",
value: data
}
})
)
), ),
{ {
loading: "Saving...", 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 { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js"; import { useDevice } from "@core/providers/useDevice.js";
import { classValidatorResolver } from "@hookform/resolvers/class-validator"; import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const ExternalNotification = (): JSX.Element => { export const ExternalNotification = (): JSX.Element => {
const { moduleConfig, connection, setModuleConfig } = useDevice(); const { moduleConfig, connection, setModuleConfig } = useDevice();
@ -31,21 +32,23 @@ export const ExternalNotification = (): JSX.Element => {
if (connection) { if (connection) {
void toast.promise( void toast.promise(
connection connection
.setModuleConfig({ .setModuleConfig(
moduleConfig: { new Protobuf.ModuleConfig({
payloadVariant: { payloadVariant: {
oneofKind: "externalNotification", case: "externalNotification",
externalNotification: data value: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "externalNotification",
externalNotification: data
} }
}) })
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "externalNotification",
value: data
}
})
)
), ),
{ {
loading: "Saving...", 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 { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js"; import { useDevice } from "@core/providers/useDevice.js";
import { classValidatorResolver } from "@hookform/resolvers/class-validator"; import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const MQTT = (): JSX.Element => { export const MQTT = (): JSX.Element => {
const { moduleConfig, connection, setModuleConfig } = useDevice(); const { moduleConfig, connection, setModuleConfig } = useDevice();
@ -38,21 +39,23 @@ export const MQTT = (): JSX.Element => {
if (connection) { if (connection) {
void toast.promise( void toast.promise(
connection connection
.setModuleConfig({ .setModuleConfig(
moduleConfig: { new Protobuf.ModuleConfig({
payloadVariant: { payloadVariant: {
oneofKind: "mqtt", case: "mqtt",
mqtt: data value: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "mqtt",
mqtt: data
} }
}) })
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "mqtt",
value: data
}
})
)
), ),
{ {
loading: "Saving...", 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 { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js"; import { useDevice } from "@core/providers/useDevice.js";
import { classValidatorResolver } from "@hookform/resolvers/class-validator"; import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
export const RangeTest = (): JSX.Element => { export const RangeTest = (): JSX.Element => {
const { moduleConfig, connection, setModuleConfig } = useDevice(); const { moduleConfig, connection, setModuleConfig } = useDevice();
@ -32,21 +33,23 @@ export const RangeTest = (): JSX.Element => {
if (connection) { if (connection) {
void toast.promise( void toast.promise(
connection connection
.setModuleConfig({ .setModuleConfig(
moduleConfig: { new Protobuf.ModuleConfig({
payloadVariant: { payloadVariant: {
oneofKind: "rangeTest", case: "rangeTest",
rangeTest: data value: data
}
}
})
.then(() =>
setModuleConfig({
payloadVariant: {
oneofKind: "rangeTest",
rangeTest: data
} }
}) })
)
.then(() =>
setModuleConfig(
new Protobuf.ModuleConfig({
payloadVariant: {
case: "rangeTest",
value: data
}
})
)
), ),
{ {
loading: "Saving...", loading: "Saving...",

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

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

6
src/components/Widgets/BatteryWidget.tsx

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

2
src/core/stores/appStore.ts

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

82
src/core/stores/deviceStore.ts

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

12
src/core/subscriptions.ts

@ -17,16 +17,14 @@ export const subscribeAll = (
}); });
connection.events.onRoutingPacket.subscribe((routingPacket) => { connection.events.onRoutingPacket.subscribe((routingPacket) => {
switch (routingPacket.data.variant.oneofKind) { switch (routingPacket.data.variant.case) {
case "errorReason": case "errorReason":
if ( if (routingPacket.data.variant.value === Protobuf.Routing_Error.NONE) {
routingPacket.data.variant.errorReason === Protobuf.Routing_Error.NONE
) {
return; return;
} }
toast.error( toast.error(
`Routing error: ${ `Routing error: ${
Protobuf.Routing_Error[routingPacket.data.variant.errorReason] Protobuf.Routing_Error[routingPacket.data.variant.value]
}`, }`,
{ {
icon: "❌" icon: "❌"
@ -34,12 +32,12 @@ export const subscribeAll = (
); );
break; break;
case "routeReply": case "routeReply":
toast(`Route Reply: ${routingPacket.data.variant.routeReply}`, { toast(`Route Reply: ${routingPacket.data.variant.value}`, {
icon: "✅" icon: "✅"
}); });
break; break;
case "routeRequest": case "routeRequest":
toast(`Route Request: ${routingPacket.data.variant.routeRequest}`, { toast(`Route Request: ${routingPacket.data.variant.value}`, {
icon: "✅" icon: "✅"
}); });
break; 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"; import type { Protobuf } from "@meshtastic/meshtasticjs";
export class ChannelSettingsValidation export class ChannelSettingsValidation
implements Omit<Protobuf.ChannelSettings, "psk"> implements
Omit<Protobuf.ChannelSettings, keyof Protobuf.native.Message | "psk">
{ {
@IsBoolean() @IsBoolean()
enabled: boolean; enabled: boolean;

5
src/validation/config/bluetooth.ts

@ -2,7 +2,10 @@ import { IsBoolean, IsEnum, IsInt } from "class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs"; 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() @IsBoolean()
enabled: boolean; enabled: boolean;

4
src/validation/config/device.ts

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

5
src/validation/config/position.ts

@ -2,7 +2,10 @@ import { IsBoolean, IsInt, IsNumber } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs"; 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() @IsInt()
positionBroadcastSecs: number; 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"; 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() @IsBoolean()
isPowerSaving: boolean; 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"; import type { Protobuf } from "@meshtastic/meshtasticjs";
export class UserValidation export class UserValidation
implements Omit<Protobuf.User, "ID" | "macaddr" | "hwModel"> implements
Omit<
Protobuf.User,
keyof Protobuf.native.Message | "ID" | "macaddr" | "hwModel"
>
{ {
@IsString() @IsString()
@IsOptional() @IsOptional()

13
src/validation/moduleConfig/audio.ts

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

6
src/validation/moduleConfig/externalNotification.ts

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

5
src/validation/moduleConfig/mqtt.ts

@ -2,7 +2,10 @@ import { IsBoolean, Length } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs"; 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() @IsBoolean()
enabled: boolean; enabled: boolean;

3
src/validation/moduleConfig/rangeTest.ts

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

5
src/validation/moduleConfig/serial.ts

@ -2,7 +2,10 @@ import { IsBoolean, IsEnum, IsInt } from "class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs"; 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() @IsBoolean()
enabled: boolean; enabled: boolean;

6
src/validation/moduleConfig/storeForward.ts

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

3
src/validation/moduleConfig/telemetry.ts

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

Loading…
Cancel
Save