use new packages for imports & new webserial transport
This commit is contained in:
@@ -5,7 +5,9 @@
|
|||||||
"name": "meshtastic-web",
|
"name": "meshtastic-web",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bufbuild/protobuf": "^2.2.3",
|
"@bufbuild/protobuf": "^2.2.3",
|
||||||
|
"@meshtastic/core": "npm:@jsr/meshtastic__core@2.6.0-0",
|
||||||
"@meshtastic/js": "npm:@jsr/meshtastic__js@2.6.0-0",
|
"@meshtastic/js": "npm:@jsr/meshtastic__js@2.6.0-0",
|
||||||
|
"@meshtastic/transport-web-serial": "npm:@jsr/meshtastic__transport-web-serial",
|
||||||
"@noble/curves": "^1.8.1",
|
"@noble/curves": "^1.8.1",
|
||||||
"@radix-ui/react-accordion": "^1.2.3",
|
"@radix-ui/react-accordion": "^1.2.3",
|
||||||
"@radix-ui/react-checkbox": "^1.1.4",
|
"@radix-ui/react-checkbox": "^1.1.4",
|
||||||
@@ -359,6 +361,8 @@
|
|||||||
|
|
||||||
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
"@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.25", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="],
|
||||||
|
|
||||||
|
"@jsr/meshtastic__core": ["@jsr/meshtastic__core@2.6.0-0", "https://npm.jsr.io/~/11/@jsr/meshtastic__core/2.6.0-0.tgz", { "dependencies": { "@bufbuild/protobuf": "^2.2.3", "@jsr/meshtastic__protobufs": "^2.6.0", "crc": "^4.3.2", "ste-simple-events": "^3.0.11", "tslog": "^4.9.3" } }, "sha512-Ks71sRagbBipotznULpsJZ1EMcQIqCEJQx6mf628dmCNVf2YECi2zi/i/5zErp1hGPgfbDvCz9oPogvsd/7fMA=="],
|
||||||
|
|
||||||
"@jsr/meshtastic__protobufs": ["@jsr/meshtastic__protobufs@2.6.0", "https://npm.jsr.io/~/11/@jsr/meshtastic__protobufs/2.6.0.tgz", { "dependencies": { "@bufbuild/protobuf": "^2.2.3" } }, "sha512-CGlgBdzAuQCZuGPrnzP8zU+EcLlmyYeeMbqFHuJ834cYfArWXDjDh1UYaPo2rI03LTjqa3MeWpfqDlzBR8kIMg=="],
|
"@jsr/meshtastic__protobufs": ["@jsr/meshtastic__protobufs@2.6.0", "https://npm.jsr.io/~/11/@jsr/meshtastic__protobufs/2.6.0.tgz", { "dependencies": { "@bufbuild/protobuf": "^2.2.3" } }, "sha512-CGlgBdzAuQCZuGPrnzP8zU+EcLlmyYeeMbqFHuJ834cYfArWXDjDh1UYaPo2rI03LTjqa3MeWpfqDlzBR8kIMg=="],
|
||||||
|
|
||||||
"@mapbox/geojson-rewind": ["@mapbox/geojson-rewind@0.5.2", "", { "dependencies": { "get-stream": "^6.0.1", "minimist": "^1.2.6" }, "bin": { "geojson-rewind": "geojson-rewind" } }, "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA=="],
|
"@mapbox/geojson-rewind": ["@mapbox/geojson-rewind@0.5.2", "", { "dependencies": { "get-stream": "^6.0.1", "minimist": "^1.2.6" }, "bin": { "geojson-rewind": "geojson-rewind" } }, "sha512-tJaT+RbYGJYStt7wI3cq4Nl4SXxG8W7JDG5DMJu97V25RnbNg3QtQtf+KD+VLjNpWKYsRvXDNmNrBgEETr1ifA=="],
|
||||||
@@ -379,8 +383,12 @@
|
|||||||
|
|
||||||
"@maplibre/maplibre-gl-style-spec": ["@maplibre/maplibre-gl-style-spec@23.1.0", "", { "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/unitbezier": "^0.0.1", "json-stringify-pretty-compact": "^4.0.0", "minimist": "^1.2.8", "quickselect": "^3.0.0", "rw": "^1.3.3", "tinyqueue": "^3.0.0" }, "bin": { "gl-style-migrate": "dist/gl-style-migrate.mjs", "gl-style-validate": "dist/gl-style-validate.mjs", "gl-style-format": "dist/gl-style-format.mjs" } }, "sha512-R6/ihEuC5KRexmKIYkWqUv84Gm+/QwsOUgHyt1yy2XqCdGdLvlBWVWIIeTZWN4NGdwmY6xDzdSGU2R9oBLNg2w=="],
|
"@maplibre/maplibre-gl-style-spec": ["@maplibre/maplibre-gl-style-spec@23.1.0", "", { "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/unitbezier": "^0.0.1", "json-stringify-pretty-compact": "^4.0.0", "minimist": "^1.2.8", "quickselect": "^3.0.0", "rw": "^1.3.3", "tinyqueue": "^3.0.0" }, "bin": { "gl-style-migrate": "dist/gl-style-migrate.mjs", "gl-style-validate": "dist/gl-style-validate.mjs", "gl-style-format": "dist/gl-style-format.mjs" } }, "sha512-R6/ihEuC5KRexmKIYkWqUv84Gm+/QwsOUgHyt1yy2XqCdGdLvlBWVWIIeTZWN4NGdwmY6xDzdSGU2R9oBLNg2w=="],
|
||||||
|
|
||||||
|
"@meshtastic/core": ["@jsr/meshtastic__core@2.6.0-0", "https://npm.jsr.io/~/11/@jsr/meshtastic__core/2.6.0-0.tgz", { "dependencies": { "@bufbuild/protobuf": "^2.2.3", "@jsr/meshtastic__protobufs": "^2.6.0", "crc": "^4.3.2", "ste-simple-events": "^3.0.11", "tslog": "^4.9.3" } }, "sha512-Ks71sRagbBipotznULpsJZ1EMcQIqCEJQx6mf628dmCNVf2YECi2zi/i/5zErp1hGPgfbDvCz9oPogvsd/7fMA=="],
|
||||||
|
|
||||||
"@meshtastic/js": ["@jsr/meshtastic__js@2.6.0-0", "https://npm.jsr.io/~/11/@jsr/meshtastic__js/2.6.0-0.tgz", { "dependencies": { "@bufbuild/protobuf": "^2.2.3", "@jsr/meshtastic__protobufs": "^2.6.0", "crc": "^4.3.2", "ste-simple-events": "^3.0.11", "tslog": "^4.9.3" } }, "sha512-+xpZpxK6oUIVOuEs7C+LyxRr2druvc7UNNNTK9Rl8ioXj63Jz1uQXlYe2Gj0xjnRAiSQLR7QVaPef21BR/YTxA=="],
|
"@meshtastic/js": ["@jsr/meshtastic__js@2.6.0-0", "https://npm.jsr.io/~/11/@jsr/meshtastic__js/2.6.0-0.tgz", { "dependencies": { "@bufbuild/protobuf": "^2.2.3", "@jsr/meshtastic__protobufs": "^2.6.0", "crc": "^4.3.2", "ste-simple-events": "^3.0.11", "tslog": "^4.9.3" } }, "sha512-+xpZpxK6oUIVOuEs7C+LyxRr2druvc7UNNNTK9Rl8ioXj63Jz1uQXlYe2Gj0xjnRAiSQLR7QVaPef21BR/YTxA=="],
|
||||||
|
|
||||||
|
"@meshtastic/transport-web-serial": ["@jsr/meshtastic__transport-web-serial@0.2.0", "https://npm.jsr.io/~/11/@jsr/meshtastic__transport-web-serial/0.2.0.tgz", { "dependencies": { "@jsr/meshtastic__core": "^2.6.0-0" } }, "sha512-mP/nxOj0syABh3FkG5iIolWhUMiFh/qtJtvqihxLkaRoxdabUyW62mOtfhCMBEjxgVnKg4Gy7GkaXfC/eFy19Q=="],
|
||||||
|
|
||||||
"@noble/curves": ["@noble/curves@1.8.1", "", { "dependencies": { "@noble/hashes": "1.7.1" } }, "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ=="],
|
"@noble/curves": ["@noble/curves@1.8.1", "", { "dependencies": { "@noble/hashes": "1.7.1" } }, "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ=="],
|
||||||
|
|
||||||
"@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="],
|
"@noble/hashes": ["@noble/hashes@1.7.1", "", {}, "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ=="],
|
||||||
|
|||||||
@@ -38,7 +38,9 @@
|
|||||||
"homepage": "https://meshtastic.org",
|
"homepage": "https://meshtastic.org",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bufbuild/protobuf": "^2.2.3",
|
"@bufbuild/protobuf": "^2.2.3",
|
||||||
|
"@meshtastic/core": "npm:@jsr/meshtastic__core@2.6.0-0",
|
||||||
"@meshtastic/js": "npm:@jsr/meshtastic__js@2.6.0-0",
|
"@meshtastic/js": "npm:@jsr/meshtastic__js@2.6.0-0",
|
||||||
|
"@meshtastic/transport-web-serial": "npm:@jsr/meshtastic__transport-web-serial",
|
||||||
"@noble/curves": "^1.8.1",
|
"@noble/curves": "^1.8.1",
|
||||||
"@radix-ui/react-accordion": "^1.2.3",
|
"@radix-ui/react-accordion": "^1.2.3",
|
||||||
"@radix-ui/react-checkbox": "^1.1.4",
|
"@radix-ui/react-checkbox": "^1.1.4",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
} from "@components/UI/Dialog.tsx";
|
} from "@components/UI/Dialog.tsx";
|
||||||
import { Input } from "@components/UI/Input.tsx";
|
import { Input } from "@components/UI/Input.tsx";
|
||||||
import { Label } from "@components/UI/Label.tsx";
|
import { Label } from "@components/UI/Label.tsx";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { Input } from "@components/UI/Input.tsx";
|
|||||||
import { Label } from "@components/UI/Label.tsx";
|
import { Label } from "@components/UI/Label.tsx";
|
||||||
import { Switch } from "@components/UI/Switch.tsx";
|
import { Switch } from "@components/UI/Switch.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { toByteArray } from "base64-js";
|
import { toByteArray } from "base64-js";
|
||||||
import { type JSX, useEffect, useState } from "react";
|
import { type JSX, useEffect, useState } from "react";
|
||||||
|
|
||||||
@@ -73,10 +73,9 @@ export const ImportDialog = ({
|
|||||||
connection?.setChannel(
|
connection?.setChannel(
|
||||||
create(Protobuf.Channel.ChannelSchema, {
|
create(Protobuf.Channel.ChannelSchema, {
|
||||||
index,
|
index,
|
||||||
role:
|
role: index === 0
|
||||||
index === 0
|
? Protobuf.Channel.Channel_Role.PRIMARY
|
||||||
? Protobuf.Channel.Channel_Role.PRIMARY
|
: Protobuf.Channel.Channel_Role.SECONDARY,
|
||||||
: Protobuf.Channel.Channel_Role.SECONDARY,
|
|
||||||
settings: ch,
|
settings: ch,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -123,21 +122,25 @@ export const ImportDialog = ({
|
|||||||
checked={channelSet?.loraConfig?.usePreset ?? true}
|
checked={channelSet?.loraConfig?.usePreset ?? true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/* <Select
|
{
|
||||||
|
/* <Select
|
||||||
label="Modem Preset"
|
label="Modem Preset"
|
||||||
disabled
|
disabled
|
||||||
value={channelSet?.loraConfig?.modemPreset}
|
value={channelSet?.loraConfig?.modemPreset}
|
||||||
>
|
>
|
||||||
{renderOptions(Protobuf.Config_LoRaConfig_ModemPreset)}
|
{renderOptions(Protobuf.Config_LoRaConfig_ModemPreset)}
|
||||||
</Select> */}
|
</Select> */
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
{/* <Select
|
{
|
||||||
|
/* <Select
|
||||||
label="Region"
|
label="Region"
|
||||||
disabled
|
disabled
|
||||||
value={channelSet?.loraConfig?.region}
|
value={channelSet?.loraConfig?.region}
|
||||||
>
|
>
|
||||||
{renderOptions(Protobuf.Config_LoRaConfig_RegionCode)}
|
{renderOptions(Protobuf.Config_LoRaConfig_RegionCode)}
|
||||||
</Select> */}
|
</Select> */
|
||||||
|
}
|
||||||
|
|
||||||
<span className="text-md block font-medium text-text-primary">
|
<span className="text-md block font-medium text-text-primary">
|
||||||
Channels:
|
Channels:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@components/UI/Dialog";
|
} from "@components/UI/Dialog";
|
||||||
import type { Protobuf, Types } from "@meshtastic/js";
|
import type { Protobuf, Types } from "@meshtastic/core";
|
||||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
||||||
import type { JSX } from "react";
|
import type { JSX } from "react";
|
||||||
|
|
||||||
@@ -24,11 +24,9 @@ export const LocationResponseDialog = ({
|
|||||||
const { nodes } = useDevice();
|
const { nodes } = useDevice();
|
||||||
|
|
||||||
const from = nodes.get(location?.from ?? 0);
|
const from = nodes.get(location?.from ?? 0);
|
||||||
const longName =
|
const longName = from?.user?.longName ??
|
||||||
from?.user?.longName ??
|
|
||||||
(from ? `!${numberToHexUnpadded(from?.num)}` : "Unknown");
|
(from ? `!${numberToHexUnpadded(from?.num)}` : "Unknown");
|
||||||
const shortName =
|
const shortName = from?.user?.shortName ??
|
||||||
from?.user?.shortName ??
|
|
||||||
(from ? `${numberToHexUnpadded(from?.num).substring(0, 4)}` : "UNK");
|
(from ? `${numberToHexUnpadded(from?.num).substring(0, 4)}` : "UNK");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -44,7 +42,9 @@ export const LocationResponseDialog = ({
|
|||||||
Coordinates:{" "}
|
Coordinates:{" "}
|
||||||
<a
|
<a
|
||||||
className="text-blue-500 dark:text-blue-400"
|
className="text-blue-500 dark:text-blue-400"
|
||||||
href={`https://www.openstreetmap.org/?mlat=${location?.data.latitudeI / 1e7}&mlon=${location?.data.longitudeI / 1e7}&layers=N`}
|
href={`https://www.openstreetmap.org/?mlat=${
|
||||||
|
location?.data.latitudeI / 1e7
|
||||||
|
}&mlon=${location?.data.longitudeI / 1e7}&layers=N`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@components/UI/Dialog";
|
} from "@components/UI/Dialog";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
||||||
import { DeviceImage } from "../generic/DeviceImage";
|
import { DeviceImage } from "../generic/DeviceImage";
|
||||||
import { TimeAgo } from "../generic/TimeAgo";
|
import { TimeAgo } from "../generic/TimeAgo";
|
||||||
@@ -32,132 +32,159 @@ export const NodeDetailsDialog = ({
|
|||||||
const { nodeNumDetails } = useAppStore();
|
const { nodeNumDetails } = useAppStore();
|
||||||
const device: Protobuf.Mesh.NodeInfo = nodes.get(nodeNumDetails);
|
const device: Protobuf.Mesh.NodeInfo = nodes.get(nodeNumDetails);
|
||||||
|
|
||||||
return device ? (
|
return device
|
||||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
? (
|
||||||
<DialogContent>
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
<DialogHeader>
|
<DialogContent>
|
||||||
<DialogTitle>
|
<DialogHeader>
|
||||||
Node Details for {device.user?.longName ?? "UNKNOWN"} (
|
<DialogTitle>
|
||||||
{device.user?.shortName ?? "UNK"})
|
Node Details for {device.user?.longName ?? "UNKNOWN"} (
|
||||||
</DialogTitle>
|
{device.user?.shortName ?? "UNK"})
|
||||||
</DialogHeader>
|
</DialogTitle>
|
||||||
<DialogFooter>
|
</DialogHeader>
|
||||||
<div className="w-full">
|
<DialogFooter>
|
||||||
<DeviceImage
|
<div className="w-full">
|
||||||
className="w-32 h-32 mx-auto rounded-lg border-4 border-slate-200 dark:border-slate-800"
|
<DeviceImage
|
||||||
deviceType={
|
className="w-32 h-32 mx-auto rounded-lg border-4 border-slate-200 dark:border-slate-800"
|
||||||
Protobuf.Mesh.HardwareModel[device.user?.hwModel ?? 0]
|
deviceType={Protobuf.Mesh
|
||||||
}
|
.HardwareModel[device.user?.hwModel ?? 0]}
|
||||||
/>
|
/>
|
||||||
<div className="bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3">
|
<div className="bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3">
|
||||||
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50">
|
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50">
|
||||||
Details:
|
Details:
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Hardware:{" "}
|
Hardware:{" "}
|
||||||
{Protobuf.Mesh.HardwareModel[device.user?.hwModel ?? 0]}
|
{Protobuf.Mesh.HardwareModel[device.user?.hwModel ?? 0]}
|
||||||
</p>
|
</p>
|
||||||
<p>Node Number: {device.num}</p>
|
<p>Node Number: {device.num}</p>
|
||||||
<p>Node HEX: !{numberToHexUnpadded(device.num)}</p>
|
<p>Node HEX: !{numberToHexUnpadded(device.num)}</p>
|
||||||
<p>
|
<p>
|
||||||
Role:{" "}
|
Role: {Protobuf.Config.Config_DeviceConfig_Role[
|
||||||
{
|
|
||||||
Protobuf.Config.Config_DeviceConfig_Role[
|
|
||||||
device.user?.role ?? 0
|
device.user?.role ?? 0
|
||||||
]
|
]}
|
||||||
}
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Last Heard:{" "}
|
|
||||||
{device.lastHeard === 0 ? (
|
|
||||||
"Never"
|
|
||||||
) : (
|
|
||||||
<TimeAgo timestamp={device.lastHeard * 1000} />
|
|
||||||
)}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{device.position ? (
|
|
||||||
<div className="mt-5 bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3">
|
|
||||||
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50">
|
|
||||||
Position:
|
|
||||||
</p>
|
</p>
|
||||||
{device.position.latitudeI && device.position.longitudeI ? (
|
<p>
|
||||||
<p>
|
Last Heard: {device.lastHeard === 0
|
||||||
Coordinates:{" "}
|
? (
|
||||||
<a
|
"Never"
|
||||||
className="text-blue-500 dark:text-blue-400"
|
)
|
||||||
href={`https://www.openstreetmap.org/?mlat=${device.position.latitudeI / 1e7}&mlon=${device.position.longitudeI / 1e7}&layers=N`}
|
: <TimeAgo timestamp={device.lastHeard * 1000} />}
|
||||||
target="_blank"
|
</p>
|
||||||
rel="noreferrer"
|
</div>
|
||||||
|
|
||||||
|
{device.position
|
||||||
|
? (
|
||||||
|
<div className="mt-5 bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3">
|
||||||
|
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50">
|
||||||
|
Position:
|
||||||
|
</p>
|
||||||
|
{device.position.latitudeI && device.position.longitudeI
|
||||||
|
? (
|
||||||
|
<p>
|
||||||
|
Coordinates:{" "}
|
||||||
|
<a
|
||||||
|
className="text-blue-500 dark:text-blue-400"
|
||||||
|
href={`https://www.openstreetmap.org/?mlat=${
|
||||||
|
device.position.latitudeI / 1e7
|
||||||
|
}&mlon=${
|
||||||
|
device.position.longitudeI / 1e7
|
||||||
|
}&layers=N`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{device.position.latitudeI / 1e7},{" "}
|
||||||
|
{device.position.longitudeI / 1e7}
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
{device.position.altitude
|
||||||
|
? <p>Altitude: {device.position.altitude}m</p>
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{device.deviceMetrics
|
||||||
|
? (
|
||||||
|
<div className="mt-5 bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3">
|
||||||
|
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50">
|
||||||
|
Device Metrics:
|
||||||
|
</p>
|
||||||
|
{device.deviceMetrics.airUtilTx
|
||||||
|
? (
|
||||||
|
<p>
|
||||||
|
Air TX utilization:{" "}
|
||||||
|
{device.deviceMetrics.airUtilTx.toFixed(2)}%
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
{device.deviceMetrics.channelUtilization
|
||||||
|
? (
|
||||||
|
<p>
|
||||||
|
Channel utilization:{" "}
|
||||||
|
{device.deviceMetrics.channelUtilization.toFixed(2)}%
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
{device.deviceMetrics.batteryLevel
|
||||||
|
? (
|
||||||
|
<p>
|
||||||
|
Battery level:{" "}
|
||||||
|
{device.deviceMetrics.batteryLevel.toFixed(2)}%
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
{device.deviceMetrics.voltage
|
||||||
|
? (
|
||||||
|
<p>
|
||||||
|
Voltage: {device.deviceMetrics.voltage.toFixed(2)}V
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
{device.deviceMetrics.uptimeSeconds
|
||||||
|
? (
|
||||||
|
<p>
|
||||||
|
Uptime:{" "}
|
||||||
|
<Uptime
|
||||||
|
seconds={device.deviceMetrics.uptimeSeconds}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
|
||||||
|
{device
|
||||||
|
? (
|
||||||
|
<div className="mt-5 w-full max-w-[464px] bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3">
|
||||||
|
<Accordion
|
||||||
|
className="AccordionRoot"
|
||||||
|
type="single"
|
||||||
|
collapsible
|
||||||
>
|
>
|
||||||
{device.position.latitudeI / 1e7},{" "}
|
<AccordionItem className="AccordionItem" value="item-1">
|
||||||
{device.position.longitudeI / 1e7}
|
<AccordionTrigger>
|
||||||
</a>
|
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50">
|
||||||
</p>
|
All Raw Metrics:
|
||||||
) : null}
|
</p>
|
||||||
{device.position.altitude ? (
|
</AccordionTrigger>
|
||||||
<p>Altitude: {device.position.altitude}m</p>
|
<AccordionContent className="overflow-x-scroll">
|
||||||
) : null}
|
<pre className="text-xs w-full">
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{device.deviceMetrics ? (
|
|
||||||
<div className="mt-5 bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3">
|
|
||||||
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50">
|
|
||||||
Device Metrics:
|
|
||||||
</p>
|
|
||||||
{device.deviceMetrics.airUtilTx ? (
|
|
||||||
<p>
|
|
||||||
Air TX utilization:{" "}
|
|
||||||
{device.deviceMetrics.airUtilTx.toFixed(2)}%
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
{device.deviceMetrics.channelUtilization ? (
|
|
||||||
<p>
|
|
||||||
Channel utilization:{" "}
|
|
||||||
{device.deviceMetrics.channelUtilization.toFixed(2)}%
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
{device.deviceMetrics.batteryLevel ? (
|
|
||||||
<p>
|
|
||||||
Battery level:{" "}
|
|
||||||
{device.deviceMetrics.batteryLevel.toFixed(2)}%
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
{device.deviceMetrics.voltage ? (
|
|
||||||
<p>Voltage: {device.deviceMetrics.voltage.toFixed(2)}V</p>
|
|
||||||
) : null}
|
|
||||||
{device.deviceMetrics.uptimeSeconds ? (
|
|
||||||
<p>
|
|
||||||
Uptime:{" "}
|
|
||||||
<Uptime seconds={device.deviceMetrics.uptimeSeconds} />
|
|
||||||
</p>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
{device ? (
|
|
||||||
<div className="mt-5 w-full max-w-[464px] bg-slate-100 dark:bg-slate-800 p-3 rounded-lg mt-3">
|
|
||||||
<Accordion className="AccordionRoot" type="single" collapsible>
|
|
||||||
<AccordionItem className="AccordionItem" value="item-1">
|
|
||||||
<AccordionTrigger>
|
|
||||||
<p className="text-lg font-semibold text-slate-900 dark:text-slate-50">
|
|
||||||
All Raw Metrics:
|
|
||||||
</p>
|
|
||||||
</AccordionTrigger>
|
|
||||||
<AccordionContent className="overflow-x-scroll">
|
|
||||||
<pre className="text-xs w-full">
|
|
||||||
{JSON.stringify(device, null, 2)}
|
{JSON.stringify(device, null, 2)}
|
||||||
</pre>
|
</pre>
|
||||||
</AccordionContent>
|
</AccordionContent>
|
||||||
</AccordionItem>
|
</AccordionItem>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
)
|
||||||
</div>
|
: null}
|
||||||
</DialogFooter>
|
</div>
|
||||||
</DialogContent>
|
</DialogFooter>
|
||||||
</Dialog>
|
</DialogContent>
|
||||||
) : null;
|
</Dialog>
|
||||||
|
)
|
||||||
|
: null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@components/UI/Dialog";
|
} from "@components/UI/Dialog";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
||||||
import { TrashIcon } from "lucide-react";
|
import { TrashIcon } from "lucide-react";
|
||||||
import type { JSX } from "react";
|
import type { JSX } from "react";
|
||||||
@@ -31,11 +31,9 @@ export const NodeOptionsDialog = ({
|
|||||||
setChatType,
|
setChatType,
|
||||||
setActiveChat,
|
setActiveChat,
|
||||||
} = useAppStore();
|
} = useAppStore();
|
||||||
const longName =
|
const longName = node?.user?.longName ??
|
||||||
node?.user?.longName ??
|
|
||||||
(node ? `!${numberToHexUnpadded(node?.num)}` : "Unknown");
|
(node ? `!${numberToHexUnpadded(node?.num)}` : "Unknown");
|
||||||
const shortName =
|
const shortName = node?.user?.shortName ??
|
||||||
node?.user?.shortName ??
|
|
||||||
(node ? `${numberToHexUnpadded(node?.num).substring(0, 4)}` : "UNK");
|
(node ? `${numberToHexUnpadded(node?.num).substring(0, 4)}` : "UNK");
|
||||||
|
|
||||||
function handleDirectMessage() {
|
function handleDirectMessage() {
|
||||||
@@ -53,7 +51,7 @@ export const NodeOptionsDialog = ({
|
|||||||
connection?.requestPosition(node.num).then(() =>
|
connection?.requestPosition(node.num).then(() =>
|
||||||
toast({
|
toast({
|
||||||
title: "Position request sent.",
|
title: "Position request sent.",
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
onOpenChange();
|
onOpenChange();
|
||||||
}
|
}
|
||||||
@@ -66,7 +64,7 @@ export const NodeOptionsDialog = ({
|
|||||||
connection?.traceRoute(node.num).then(() =>
|
connection?.traceRoute(node.num).then(() =>
|
||||||
toast({
|
toast({
|
||||||
title: "Traceroute sent.",
|
title: "Traceroute sent.",
|
||||||
}),
|
})
|
||||||
);
|
);
|
||||||
onOpenChange();
|
onOpenChange();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
} from "@components/UI/Dialog.tsx";
|
} from "@components/UI/Dialog.tsx";
|
||||||
import { Input } from "@components/UI/Input.tsx";
|
import { Input } from "@components/UI/Input.tsx";
|
||||||
import { Label } from "@components/UI/Label.tsx";
|
import { Label } from "@components/UI/Label.tsx";
|
||||||
import { Protobuf, type Types } from "@meshtastic/js";
|
import { Protobuf, type Types } from "@meshtastic/core";
|
||||||
import { fromByteArray } from "base64-js";
|
import { fromByteArray } from "base64-js";
|
||||||
import { ClipboardIcon } from "lucide-react";
|
import { ClipboardIcon } from "lucide-react";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
@@ -77,8 +77,8 @@ export const QRDialog = ({
|
|||||||
{channel.settings?.name.length
|
{channel.settings?.name.length
|
||||||
? channel.settings.name
|
? channel.settings.name
|
||||||
: channel.role === Protobuf.Channel.Channel_Role.PRIMARY
|
: channel.role === Protobuf.Channel.Channel_Role.PRIMARY
|
||||||
? "Primary"
|
? "Primary"
|
||||||
: `Channel: ${channel.index}`}
|
: `Channel: ${channel.index}`}
|
||||||
</Label>
|
</Label>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
key={channel.index}
|
key={channel.index}
|
||||||
@@ -86,7 +86,9 @@ export const QRDialog = ({
|
|||||||
onCheckedChange={() => {
|
onCheckedChange={() => {
|
||||||
if (selectedChannels.includes(channel.index)) {
|
if (selectedChannels.includes(channel.index)) {
|
||||||
setSelectedChannels(
|
setSelectedChannels(
|
||||||
selectedChannels.filter((c) => c !== channel.index),
|
selectedChannels.filter((c) =>
|
||||||
|
c !== channel.index
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
setSelectedChannels([
|
setSelectedChannels([
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@components/UI/Dialog";
|
} from "@components/UI/Dialog";
|
||||||
import type { Protobuf, Types } from "@meshtastic/js";
|
import type { Protobuf, Types } from "@meshtastic/core";
|
||||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
||||||
import type { JSX } from "react";
|
import type { JSX } from "react";
|
||||||
import { TraceRoute } from "../PageComponents/Messages/TraceRoute";
|
import { TraceRoute } from "../PageComponents/Messages/TraceRoute";
|
||||||
@@ -28,11 +28,9 @@ export const TracerouteResponseDialog = ({
|
|||||||
const snrTowards = traceroute?.data.snrTowards ?? [];
|
const snrTowards = traceroute?.data.snrTowards ?? [];
|
||||||
const snrBack = traceroute?.data.snrBack ?? [];
|
const snrBack = traceroute?.data.snrBack ?? [];
|
||||||
const from = nodes.get(traceroute?.from ?? 0);
|
const from = nodes.get(traceroute?.from ?? 0);
|
||||||
const longName =
|
const longName = from?.user?.longName ??
|
||||||
from?.user?.longName ??
|
|
||||||
(from ? `!${numberToHexUnpadded(from?.num)}` : "Unknown");
|
(from ? `!${numberToHexUnpadded(from?.num)}` : "Unknown");
|
||||||
const shortName =
|
const shortName = from?.user?.shortName ??
|
||||||
from?.user?.shortName ??
|
|
||||||
(from ? `${numberToHexUnpadded(from?.num).substring(0, 4)}` : "UNK");
|
(from ? `${numberToHexUnpadded(from?.num).substring(0, 4)}` : "UNK");
|
||||||
const to = nodes.get(traceroute?.to ?? 0);
|
const to = nodes.get(traceroute?.to ?? 0);
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { create } from "@bufbuild/protobuf";
|
|||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useToast } from "@core/hooks/useToast.ts";
|
import { useToast } from "@core/hooks/useToast.ts";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { fromByteArray, toByteArray } from "base64-js";
|
import { fromByteArray, toByteArray } from "base64-js";
|
||||||
import cryptoRandomString from "crypto-random-string";
|
import cryptoRandomString from "crypto-random-string";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
@@ -24,8 +24,9 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
|
|||||||
channel?.settings?.psk.length ?? 16,
|
channel?.settings?.psk.length ?? 16,
|
||||||
);
|
);
|
||||||
const [validationText, setValidationText] = useState<string>();
|
const [validationText, setValidationText] = useState<string>();
|
||||||
const [preSharedDialogOpen, setPreSharedDialogOpen] =
|
const [preSharedDialogOpen, setPreSharedDialogOpen] = useState<boolean>(
|
||||||
useState<boolean>(false);
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
const onSubmit = (data: ChannelValidation) => {
|
const onSubmit = (data: ChannelValidation) => {
|
||||||
const channel = create(Protobuf.Channel.ChannelSchema, {
|
const channel = create(Protobuf.Channel.ChannelSchema, {
|
||||||
@@ -107,7 +108,7 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
|
|||||||
channel?.settings?.moduleSettings?.positionPrecision === 32,
|
channel?.settings?.moduleSettings?.positionPrecision === 32,
|
||||||
positionPrecision:
|
positionPrecision:
|
||||||
channel?.settings?.moduleSettings?.positionPrecision ===
|
channel?.settings?.moduleSettings?.positionPrecision ===
|
||||||
undefined
|
undefined
|
||||||
? 10
|
? 10
|
||||||
: channel?.settings?.moduleSettings?.positionPrecision,
|
: channel?.settings?.moduleSettings?.positionPrecision,
|
||||||
},
|
},
|
||||||
@@ -126,10 +127,9 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
|
|||||||
description:
|
description:
|
||||||
"Device telemetry is sent over PRIMARY. Only one PRIMARY allowed",
|
"Device telemetry is sent over PRIMARY. Only one PRIMARY allowed",
|
||||||
properties: {
|
properties: {
|
||||||
enumValue:
|
enumValue: channel.index === 0
|
||||||
channel.index === 0
|
? { PRIMARY: 1 }
|
||||||
? { PRIMARY: 1 }
|
: { DISABLED: 0, SECONDARY: 2 },
|
||||||
: { DISABLED: 0, SECONDARY: 2 },
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -192,32 +192,31 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
|
|||||||
description:
|
description:
|
||||||
"If not sharing precise location, position shared on channel will be accurate within this distance",
|
"If not sharing precise location, position shared on channel will be accurate within this distance",
|
||||||
properties: {
|
properties: {
|
||||||
enumValue:
|
enumValue: config.display?.units === 0
|
||||||
config.display?.units === 0
|
? {
|
||||||
? {
|
"Within 23 km": 10,
|
||||||
"Within 23 km": 10,
|
"Within 12 km": 11,
|
||||||
"Within 12 km": 11,
|
"Within 5.8 km": 12,
|
||||||
"Within 5.8 km": 12,
|
"Within 2.9 km": 13,
|
||||||
"Within 2.9 km": 13,
|
"Within 1.5 km": 14,
|
||||||
"Within 1.5 km": 14,
|
"Within 700 m": 15,
|
||||||
"Within 700 m": 15,
|
"Within 350 m": 16,
|
||||||
"Within 350 m": 16,
|
"Within 200 m": 17,
|
||||||
"Within 200 m": 17,
|
"Within 90 m": 18,
|
||||||
"Within 90 m": 18,
|
"Within 50 m": 19,
|
||||||
"Within 50 m": 19,
|
}
|
||||||
}
|
: {
|
||||||
: {
|
"Within 15 miles": 10,
|
||||||
"Within 15 miles": 10,
|
"Within 7.3 miles": 11,
|
||||||
"Within 7.3 miles": 11,
|
"Within 3.6 miles": 12,
|
||||||
"Within 3.6 miles": 12,
|
"Within 1.8 miles": 13,
|
||||||
"Within 1.8 miles": 13,
|
"Within 0.9 miles": 14,
|
||||||
"Within 0.9 miles": 14,
|
"Within 0.5 miles": 15,
|
||||||
"Within 0.5 miles": 15,
|
"Within 0.2 miles": 16,
|
||||||
"Within 0.2 miles": 16,
|
"Within 600 feet": 17,
|
||||||
"Within 600 feet": 17,
|
"Within 300 feet": 18,
|
||||||
"Within 300 feet": 18,
|
"Within 150 feet": 19,
|
||||||
"Within 150 feet": 19,
|
},
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { BluetoothValidation } from "@app/validation/config/bluetooth.tsx";
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
export const Bluetooth = () => {
|
export const Bluetooth = () => {
|
||||||
@@ -111,9 +111,8 @@ export const Bluetooth = () => {
|
|||||||
disabledBy: [
|
disabledBy: [
|
||||||
{
|
{
|
||||||
fieldName: "mode",
|
fieldName: "mode",
|
||||||
selector:
|
selector: Protobuf.Config.Config_BluetoothConfig_PairingMode
|
||||||
Protobuf.Config.Config_BluetoothConfig_PairingMode
|
.FIXED_PIN,
|
||||||
.FIXED_PIN,
|
|
||||||
invert: true,
|
invert: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { DeviceValidation } from "@app/validation/config/device.tsx";
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const Device = (): JSX.Element => {
|
export const Device = (): JSX.Element => {
|
||||||
const { config, setWorkingConfig } = useDevice();
|
const { config, setWorkingConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { DisplayValidation } from "@app/validation/config/display.tsx";
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const Display = (): JSX.Element => {
|
export const Display = (): JSX.Element => {
|
||||||
const { config, setWorkingConfig } = useDevice();
|
const { config, setWorkingConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { LoRaValidation } from "@app/validation/config/lora.tsx";
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const LoRa = (): JSX.Element => {
|
export const LoRa = (): JSX.Element => {
|
||||||
const { config, setWorkingConfig } = useDevice();
|
const { config, setWorkingConfig } = useDevice();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
convertIntToIpAddress,
|
convertIntToIpAddress,
|
||||||
convertIpAddressToInt,
|
convertIpAddressToInt,
|
||||||
} from "@core/utils/ip.ts";
|
} from "@core/utils/ip.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const Network = (): JSX.Element => {
|
export const Network = (): JSX.Element => {
|
||||||
const { config, setWorkingConfig } = useDevice();
|
const { config, setWorkingConfig } = useDevice();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { PositionValidation } from "@app/validation/config/position.tsx";
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
|
|
||||||
export const Position = () => {
|
export const Position = () => {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { PowerValidation } from "@app/validation/config/power.tsx";
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const Power = (): JSX.Element => {
|
export const Power = (): JSX.Element => {
|
||||||
const { config, setWorkingConfig } = useDevice();
|
const { config, setWorkingConfig } = useDevice();
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
import type { SecurityValidation } from "@app/validation/config/security.tsx";
|
import type { SecurityValidation } from "@app/validation/config/security.tsx";
|
||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { fromByteArray, toByteArray } from "base64-js";
|
import { fromByteArray, toByteArray } from "base64-js";
|
||||||
import { Eye, EyeOff } from "lucide-react";
|
import { Eye, EyeOff } from "lucide-react";
|
||||||
import { useReducer } from "react";
|
import { useReducer } from "react";
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { useAppStore } from "@core/stores/appStore.ts";
|
|||||||
import { useDeviceStore } from "@core/stores/deviceStore.ts";
|
import { useDeviceStore } from "@core/stores/deviceStore.ts";
|
||||||
import { subscribeAll } from "@core/subscriptions.ts";
|
import { subscribeAll } from "@core/subscriptions.ts";
|
||||||
import { randId } from "@core/utils/randId.ts";
|
import { randId } from "@core/utils/randId.ts";
|
||||||
import { SerialConnection } from "@meshtastic/js";
|
import { MeshDevice } from "@meshtastic/core";
|
||||||
|
import { TransportWebSerial } from "@meshtastic/transport-web-serial";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
|
|
||||||
export const Serial = ({ closeDialog }: TabElementProps): JSX.Element => {
|
export const Serial = ({ closeDialog }: TabElementProps): JSX.Element => {
|
||||||
@@ -31,14 +32,9 @@ export const Serial = ({ closeDialog }: TabElementProps): JSX.Element => {
|
|||||||
const id = randId();
|
const id = randId();
|
||||||
const device = addDevice(id);
|
const device = addDevice(id);
|
||||||
setSelectedDevice(id);
|
setSelectedDevice(id);
|
||||||
const connection = new SerialConnection(id);
|
const transport = await TransportWebSerial.createFromPort(port);
|
||||||
await connection
|
const connection = new MeshDevice(transport, id);
|
||||||
.connect({
|
connection.configure();
|
||||||
port,
|
|
||||||
baudRate: undefined,
|
|
||||||
concurrentLogOutput: true,
|
|
||||||
})
|
|
||||||
.catch((e: Error) => console.log(`Unable to Connect: ${e.message}`));
|
|
||||||
device.addConnection(connection);
|
device.addConnection(connection);
|
||||||
subscribeAll(device, connection);
|
subscribeAll(device, connection);
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { formatQuantity } from "@app/core/utils/string";
|
|||||||
import { Avatar } from "@components/UI/Avatar";
|
import { Avatar } from "@components/UI/Avatar";
|
||||||
import { Mono } from "@components/generic/Mono.tsx";
|
import { Mono } from "@components/generic/Mono.tsx";
|
||||||
import { TimeAgo } from "@components/generic/TimeAgo.tsx";
|
import { TimeAgo } from "@components/generic/TimeAgo.tsx";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import type { Protobuf as ProtobufType } from "@meshtastic/js";
|
import type { Protobuf as ProtobufType } from "@meshtastic/core";
|
||||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
||||||
import {
|
import {
|
||||||
BatteryChargingIcon,
|
BatteryChargingIcon,
|
||||||
@@ -37,21 +37,23 @@ export const NodeDetail = ({ node }: NodeDetailProps) => {
|
|||||||
<Avatar text={node.user?.shortName} />
|
<Avatar text={node.user?.shortName} />
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{node.user?.publicKey && node.user?.publicKey.length > 0 ? (
|
{node.user?.publicKey && node.user?.publicKey.length > 0
|
||||||
<LockIcon
|
? (
|
||||||
className="text-green-600"
|
<LockIcon
|
||||||
size={12}
|
className="text-green-600"
|
||||||
strokeWidth={3}
|
size={12}
|
||||||
aria-label="Public Key Enabled"
|
strokeWidth={3}
|
||||||
/>
|
aria-label="Public Key Enabled"
|
||||||
) : (
|
/>
|
||||||
<LockOpenIcon
|
)
|
||||||
className="text-yellow-500"
|
: (
|
||||||
size={12}
|
<LockOpenIcon
|
||||||
strokeWidth={3}
|
className="text-yellow-500"
|
||||||
aria-label="No Public Key"
|
size={12}
|
||||||
/>
|
strokeWidth={3}
|
||||||
)}
|
aria-label="No Public Key"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Star
|
<Star
|
||||||
@@ -73,15 +75,13 @@ export const NodeDetail = ({ node }: NodeDetailProps) => {
|
|||||||
node.deviceMetrics?.voltage?.toPrecision(3) ?? "Unknown"
|
node.deviceMetrics?.voltage?.toPrecision(3) ?? "Unknown"
|
||||||
} volts`}
|
} volts`}
|
||||||
>
|
>
|
||||||
{node.deviceMetrics?.batteryLevel > 100 ? (
|
{node.deviceMetrics?.batteryLevel > 100
|
||||||
<BatteryChargingIcon size={22} />
|
? <BatteryChargingIcon size={22} />
|
||||||
) : node.deviceMetrics?.batteryLevel > 80 ? (
|
: node.deviceMetrics?.batteryLevel > 80
|
||||||
<BatteryFullIcon size={22} />
|
? <BatteryFullIcon size={22} />
|
||||||
) : node.deviceMetrics?.batteryLevel > 20 ? (
|
: node.deviceMetrics?.batteryLevel > 20
|
||||||
<BatteryMediumIcon size={22} />
|
? <BatteryMediumIcon size={22} />
|
||||||
) : (
|
: <BatteryLowIcon size={22} />}
|
||||||
<BatteryLowIcon size={22} />
|
|
||||||
)}
|
|
||||||
<Subtle aria-label="Battery">
|
<Subtle aria-label="Battery">
|
||||||
{node.deviceMetrics?.batteryLevel > 100
|
{node.deviceMetrics?.batteryLevel > 100
|
||||||
? "Charging"
|
? "Charging"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
} from "@app/core/stores/deviceStore.ts";
|
} from "@app/core/stores/deviceStore.ts";
|
||||||
import { Message } from "@components/PageComponents/Messages/Message.tsx";
|
import { Message } from "@components/PageComponents/Messages/Message.tsx";
|
||||||
import { MessageInput } from "@components/PageComponents/Messages/MessageInput.tsx";
|
import { MessageInput } from "@components/PageComponents/Messages/MessageInput.tsx";
|
||||||
import type { Types } from "@meshtastic/js";
|
import type { Types } from "@meshtastic/core";
|
||||||
import { InboxIcon } from "lucide-react";
|
import { InboxIcon } from "lucide-react";
|
||||||
import { useCallback, useEffect, useRef } from "react";
|
import { useCallback, useEffect, useRef } from "react";
|
||||||
import type { JSX } from "react";
|
import type { JSX } from "react";
|
||||||
@@ -34,8 +34,7 @@ export const ChannelChat = ({
|
|||||||
const scrollToBottom = useCallback(() => {
|
const scrollToBottom = useCallback(() => {
|
||||||
const scrollContainer = scrollContainerRef.current;
|
const scrollContainer = scrollContainerRef.current;
|
||||||
if (scrollContainer) {
|
if (scrollContainer) {
|
||||||
const isNearBottom =
|
const isNearBottom = scrollContainer.scrollHeight -
|
||||||
scrollContainer.scrollHeight -
|
|
||||||
scrollContainer.scrollTop -
|
scrollContainer.scrollTop -
|
||||||
scrollContainer.clientHeight <
|
scrollContainer.clientHeight <
|
||||||
100;
|
100;
|
||||||
@@ -72,9 +71,8 @@ export const ChannelChat = ({
|
|||||||
key={message.id}
|
key={message.id}
|
||||||
message={message}
|
message={message}
|
||||||
sender={nodes.get(message.from)}
|
sender={nodes.get(message.from)}
|
||||||
lastMsgSameUser={
|
lastMsgSameUser={index > 0 &&
|
||||||
index > 0 && messages[index - 1].from === message.from
|
messages[index - 1].from === message.from}
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
} from "@app/core/stores/deviceStore.ts";
|
} from "@app/core/stores/deviceStore.ts";
|
||||||
import { cn } from "@app/core/utils/cn";
|
import { cn } from "@app/core/utils/cn";
|
||||||
import { Avatar } from "@components/UI/Avatar";
|
import { Avatar } from "@components/UI/Avatar";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { AlertCircle, CheckCircle2, CircleEllipsis } from "lucide-react";
|
import { AlertCircle, CheckCircle2, CircleEllipsis } from "lucide-react";
|
||||||
import type { LucideIcon } from "lucide-react";
|
import type { LucideIcon } from "lucide-react";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { debounce } from "@app/core/utils/debounce";
|
|||||||
import { Button } from "@components/UI/Button.tsx";
|
import { Button } from "@components/UI/Button.tsx";
|
||||||
import { Input } from "@components/UI/Input.tsx";
|
import { Input } from "@components/UI/Input.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import type { Types } from "@meshtastic/js";
|
import type { Types } from "@meshtastic/core";
|
||||||
import { SendIcon } from "lucide-react";
|
import { SendIcon } from "lucide-react";
|
||||||
import {
|
import {
|
||||||
type JSX,
|
type JSX,
|
||||||
@@ -51,7 +51,7 @@ export const MessageInput = ({
|
|||||||
myNodeNum,
|
myNodeNum,
|
||||||
id,
|
id,
|
||||||
"ack",
|
"ack",
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
.catch((e: Types.PacketError) =>
|
.catch((e: Types.PacketError) =>
|
||||||
setMessageState(
|
setMessageState(
|
||||||
@@ -61,7 +61,7 @@ export const MessageInput = ({
|
|||||||
myNodeNum,
|
myNodeNum,
|
||||||
e.id,
|
e.id,
|
||||||
e.error,
|
e.error,
|
||||||
),
|
)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[channel, connection, myNodeNum, setMessageState, to],
|
[channel, connection, myNodeNum, setMessageState, to],
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useDevice } from "@app/core/stores/deviceStore.ts";
|
import { useDevice } from "@app/core/stores/deviceStore.ts";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
||||||
import type { JSX } from "react";
|
import type { JSX } from "react";
|
||||||
|
|
||||||
@@ -38,23 +38,25 @@ export const TraceRoute = ({
|
|||||||
))}
|
))}
|
||||||
{from?.user?.longName}
|
{from?.user?.longName}
|
||||||
</span>
|
</span>
|
||||||
{routeBack ? (
|
{routeBack
|
||||||
<span className="ml-4 border-l-2 border-l-background-primary pl-2 text-text-primary">
|
? (
|
||||||
<p className="font-semibold">Route back:</p>
|
<span className="ml-4 border-l-2 border-l-background-primary pl-2 text-text-primary">
|
||||||
<p>{from?.user?.longName}</p>
|
<p className="font-semibold">Route back:</p>
|
||||||
<p>↓ {snrBack?.[0] ? snrBack[0] : "??"}dB</p>
|
<p>{from?.user?.longName}</p>
|
||||||
{routeBack.map((hop, i) => (
|
<p>↓ {snrBack?.[0] ? snrBack[0] : "??"}dB</p>
|
||||||
<span key={nodes.get(hop)?.num}>
|
{routeBack.map((hop, i) => (
|
||||||
<p>
|
<span key={nodes.get(hop)?.num}>
|
||||||
{nodes.get(hop)?.user?.longName ??
|
<p>
|
||||||
`!${numberToHexUnpadded(hop)}`}
|
{nodes.get(hop)?.user?.longName ??
|
||||||
</p>
|
`!${numberToHexUnpadded(hop)}`}
|
||||||
<p>↓ {snrBack?.[i + 1] ? snrBack[i + 1] : "??"}dB</p>
|
</p>
|
||||||
</span>
|
<p>↓ {snrBack?.[i + 1] ? snrBack[i + 1] : "??"}dB</p>
|
||||||
))}
|
</span>
|
||||||
{to?.user?.longName}
|
))}
|
||||||
</span>
|
{to?.user?.longName}
|
||||||
) : null}
|
</span>
|
||||||
|
)
|
||||||
|
: null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useDevice } from "@app/core/stores/deviceStore.ts";
|
|||||||
import type { AmbientLightingValidation } from "@app/validation/moduleConfig/ambientLighting.tsx";
|
import type { AmbientLightingValidation } from "@app/validation/moduleConfig/ambientLighting.tsx";
|
||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const AmbientLighting = (): JSX.Element => {
|
export const AmbientLighting = (): JSX.Element => {
|
||||||
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { AudioValidation } from "@app/validation/moduleConfig/audio.tsx";
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const Audio = (): JSX.Element => {
|
export const Audio = (): JSX.Element => {
|
||||||
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { CannedMessageValidation } from "@app/validation/moduleConfig/canne
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const CannedMessage = (): JSX.Element => {
|
export const CannedMessage = (): JSX.Element => {
|
||||||
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useDevice } from "@app/core/stores/deviceStore.ts";
|
|||||||
import type { DetectionSensorValidation } from "@app/validation/moduleConfig/detectionSensor.tsx";
|
import type { DetectionSensorValidation } from "@app/validation/moduleConfig/detectionSensor.tsx";
|
||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const DetectionSensor = (): JSX.Element => {
|
export const DetectionSensor = (): JSX.Element => {
|
||||||
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { ExternalNotificationValidation } from "@app/validation/moduleConfi
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const ExternalNotification = (): JSX.Element => {
|
export const ExternalNotification = (): JSX.Element => {
|
||||||
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useDevice } from "@app/core/stores/deviceStore.ts";
|
|||||||
import type { MqttValidation } from "@app/validation/moduleConfig/mqtt.tsx";
|
import type { MqttValidation } from "@app/validation/moduleConfig/mqtt.tsx";
|
||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const MQTT = (): JSX.Element => {
|
export const MQTT = (): JSX.Element => {
|
||||||
const { config, moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { config, moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useDevice } from "@app/core/stores/deviceStore.ts";
|
|||||||
import type { NeighborInfoValidation } from "@app/validation/moduleConfig/neighborInfo.tsx";
|
import type { NeighborInfoValidation } from "@app/validation/moduleConfig/neighborInfo.tsx";
|
||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const NeighborInfo = (): JSX.Element => {
|
export const NeighborInfo = (): JSX.Element => {
|
||||||
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { PaxcounterValidation } from "@app/validation/moduleConfig/paxcount
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const Paxcounter = (): JSX.Element => {
|
export const Paxcounter = (): JSX.Element => {
|
||||||
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { RangeTestValidation } from "@app/validation/moduleConfig/rangeTest
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const RangeTest = (): JSX.Element => {
|
export const RangeTest = (): JSX.Element => {
|
||||||
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { SerialValidation } from "@app/validation/moduleConfig/serial.tsx";
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const Serial = (): JSX.Element => {
|
export const Serial = (): JSX.Element => {
|
||||||
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { StoreForwardValidation } from "@app/validation/moduleConfig/storeF
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const StoreForward = (): JSX.Element => {
|
export const StoreForward = (): JSX.Element => {
|
||||||
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { TelemetryValidation } from "@app/validation/moduleConfig/telemetry
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
|
|
||||||
export const Telemetry = (): JSX.Element => {
|
export const Telemetry = (): JSX.Element => {
|
||||||
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
const { moduleConfig, setWorkingModuleConfig } = useDevice();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Types } from "@meshtastic/js";
|
import { Types } from "@meshtastic/core";
|
||||||
import { produce } from "immer";
|
import { produce } from "immer";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { create } from "@bufbuild/protobuf";
|
import { create } from "@bufbuild/protobuf";
|
||||||
import { Protobuf, Types } from "@meshtastic/js";
|
import { Protobuf, Types } from "@meshtastic/core";
|
||||||
import { produce } from "immer";
|
import { produce } from "immer";
|
||||||
import { createContext, useContext } from "react";
|
import { createContext, useContext } from "react";
|
||||||
import { create as createStore } from "zustand";
|
import { create as createStore } from "zustand";
|
||||||
@@ -299,11 +299,11 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
|
|||||||
if (!device) {
|
if (!device) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const workingModuleConfigIndex =
|
const workingModuleConfigIndex = device?.workingModuleConfig
|
||||||
device?.workingModuleConfig.findIndex(
|
.findIndex(
|
||||||
(wmc) =>
|
(wmc) =>
|
||||||
wmc.payloadVariant.case ===
|
wmc.payloadVariant.case ===
|
||||||
moduleConfig.payloadVariant.case,
|
moduleConfig.payloadVariant.case,
|
||||||
);
|
);
|
||||||
if (workingModuleConfigIndex !== -1) {
|
if (workingModuleConfigIndex !== -1) {
|
||||||
device.workingModuleConfig[workingModuleConfigIndex] =
|
device.workingModuleConfig[workingModuleConfigIndex] =
|
||||||
@@ -445,8 +445,7 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
|
|||||||
if (!device) {
|
if (!device) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const currentNode =
|
const currentNode = device.nodes.get(user.from) ??
|
||||||
device.nodes.get(user.from) ??
|
|
||||||
create(Protobuf.Mesh.NodeInfoSchema);
|
create(Protobuf.Mesh.NodeInfoSchema);
|
||||||
currentNode.user = user.data;
|
currentNode.user = user.data;
|
||||||
device.nodes.set(user.from, currentNode);
|
device.nodes.set(user.from, currentNode);
|
||||||
@@ -460,8 +459,7 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
|
|||||||
if (!device) {
|
if (!device) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const currentNode =
|
const currentNode = device.nodes.get(position.from) ??
|
||||||
device.nodes.get(position.from) ??
|
|
||||||
create(Protobuf.Mesh.NodeInfoSchema);
|
create(Protobuf.Mesh.NodeInfoSchema);
|
||||||
currentNode.position = position.data;
|
currentNode.position = position.data;
|
||||||
device.nodes.set(position.from, currentNode);
|
device.nodes.set(position.from, currentNode);
|
||||||
@@ -486,12 +484,11 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const messageGroup = device.messages[message.type];
|
const messageGroup = device.messages[message.type];
|
||||||
const messageIndex =
|
const messageIndex = message.type === "direct"
|
||||||
message.type === "direct"
|
? message.from === device.hardware.myNodeNum
|
||||||
? message.from === device.hardware.myNodeNum
|
? message.to
|
||||||
? message.to
|
: message.from
|
||||||
: message.from
|
: message.channel;
|
||||||
: message.channel;
|
|
||||||
const messages = messageGroup.get(messageIndex);
|
const messages = messageGroup.get(messageIndex);
|
||||||
|
|
||||||
if (messages) {
|
if (messages) {
|
||||||
@@ -564,12 +561,9 @@ export const useDeviceStore = createStore<DeviceState>((set, get) => ({
|
|||||||
}
|
}
|
||||||
const messageGroup = device.messages[type];
|
const messageGroup = device.messages[type];
|
||||||
|
|
||||||
const messageIndex =
|
const messageIndex = type === "direct"
|
||||||
type === "direct"
|
? from === device.hardware.myNodeNum ? to : from
|
||||||
? from === device.hardware.myNodeNum
|
: channelIndex;
|
||||||
? to
|
|
||||||
: from
|
|
||||||
: channelIndex;
|
|
||||||
const messages = messageGroup.get(messageIndex);
|
const messages = messageGroup.get(messageIndex);
|
||||||
|
|
||||||
if (!messages) {
|
if (!messages) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Device } from "@core/stores/deviceStore.ts";
|
import type { Device } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf, type Types } from "@meshtastic/js";
|
import { Protobuf, type Types } from "@meshtastic/core";
|
||||||
|
|
||||||
export const subscribeAll = (
|
export const subscribeAll = (
|
||||||
device: Device,
|
device: Device,
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import { Channel } from "@components/PageComponents/Channel.tsx";
|
|||||||
import { PageLayout } from "@components/PageLayout.tsx";
|
import { PageLayout } from "@components/PageLayout.tsx";
|
||||||
import { Sidebar } from "@components/Sidebar.tsx";
|
import { Sidebar } from "@components/Sidebar.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Types } from "@meshtastic/js";
|
import { Types } from "@meshtastic/core";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { ImportIcon, QrCodeIcon } from "lucide-react";
|
import { ImportIcon, QrCodeIcon } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
@@ -17,8 +17,8 @@ export const getChannelName = (channel: Protobuf.Channel.Channel) =>
|
|||||||
channel.settings?.name.length
|
channel.settings?.name.length
|
||||||
? channel.settings?.name
|
? channel.settings?.name
|
||||||
: channel.index === 0
|
: channel.index === 0
|
||||||
? "Primary"
|
? "Primary"
|
||||||
: `Ch ${channel.index}`;
|
: `Ch ${channel.index}`;
|
||||||
|
|
||||||
const ChannelsPage = () => {
|
const ChannelsPage = () => {
|
||||||
const { channels, setDialogOpen } = useDevice();
|
const { channels, setDialogOpen } = useDevice();
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useTheme } from "@app/core/hooks/useTheme";
|
|||||||
import { PageLayout } from "@components/PageLayout.tsx";
|
import { PageLayout } from "@components/PageLayout.tsx";
|
||||||
import { Sidebar } from "@components/Sidebar.tsx";
|
import { Sidebar } from "@components/Sidebar.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { bbox, lineString } from "@turf/turf";
|
import { bbox, lineString } from "@turf/turf";
|
||||||
import { current } from "immer";
|
import { current } from "immer";
|
||||||
import { MapPinIcon } from "lucide-react";
|
import { MapPinIcon } from "lucide-react";
|
||||||
|
|||||||
+31
-36
@@ -7,7 +7,7 @@ import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.tsx";
|
|||||||
import { SidebarButton } from "@components/UI/Sidebar/sidebarButton.tsx";
|
import { SidebarButton } from "@components/UI/Sidebar/sidebarButton.tsx";
|
||||||
import { useToast } from "@core/hooks/useToast.ts";
|
import { useToast } from "@core/hooks/useToast.ts";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf, Types } from "@meshtastic/js";
|
import { Protobuf, Types } from "@meshtastic/core";
|
||||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
||||||
import { getChannelName } from "@pages/Channels.tsx";
|
import { getChannelName } from "@pages/Channels.tsx";
|
||||||
import { HashIcon, LockIcon, LockOpenIcon, WaypointsIcon } from "lucide-react";
|
import { HashIcon, LockIcon, LockOpenIcon, WaypointsIcon } from "lucide-react";
|
||||||
@@ -39,13 +39,11 @@ export const MessagesPage = () => {
|
|||||||
{filteredChannels.map((channel) => (
|
{filteredChannels.map((channel) => (
|
||||||
<SidebarButton
|
<SidebarButton
|
||||||
key={channel.index}
|
key={channel.index}
|
||||||
label={
|
label={channel.settings?.name.length
|
||||||
channel.settings?.name.length
|
? channel.settings?.name
|
||||||
? channel.settings?.name
|
: channel.index === 0
|
||||||
: channel.index === 0
|
? "Primary"
|
||||||
? "Primary"
|
: `Ch ${channel.index}`}
|
||||||
: `Ch ${channel.index}`
|
|
||||||
}
|
|
||||||
active={activeChat === channel.index}
|
active={activeChat === channel.index}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setChatType("broadcast");
|
setChatType("broadcast");
|
||||||
@@ -69,9 +67,8 @@ export const MessagesPage = () => {
|
|||||||
{filteredNodes.map((node) => (
|
{filteredNodes.map((node) => (
|
||||||
<SidebarButton
|
<SidebarButton
|
||||||
key={node.num}
|
key={node.num}
|
||||||
label={
|
label={node.user?.longName ??
|
||||||
node.user?.longName ?? `!${numberToHexUnpadded(node.num)}`
|
`!${numberToHexUnpadded(node.num)}`}
|
||||||
}
|
|
||||||
active={activeChat === node.num}
|
active={activeChat === node.num}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setChatType("direct");
|
setChatType("direct");
|
||||||
@@ -94,32 +91,30 @@ export const MessagesPage = () => {
|
|||||||
chatType === "broadcast" && currentChannel
|
chatType === "broadcast" && currentChannel
|
||||||
? getChannelName(currentChannel)
|
? getChannelName(currentChannel)
|
||||||
: chatType === "direct" && nodes.get(activeChat)
|
: chatType === "direct" && nodes.get(activeChat)
|
||||||
? (nodes.get(activeChat)?.user?.longName ?? nodeHex)
|
? (nodes.get(activeChat)?.user?.longName ?? nodeHex)
|
||||||
: "Loading..."
|
: "Loading..."
|
||||||
}`}
|
}`}
|
||||||
actions={
|
actions={chatType === "direct"
|
||||||
chatType === "direct"
|
? [
|
||||||
? [
|
{
|
||||||
{
|
icon: nodes.get(activeChat)?.user?.publicKey.length
|
||||||
icon: nodes.get(activeChat)?.user?.publicKey.length
|
? LockIcon
|
||||||
? LockIcon
|
: LockOpenIcon,
|
||||||
: LockOpenIcon,
|
iconClasses: nodes.get(activeChat)?.user?.publicKey.length
|
||||||
iconClasses: nodes.get(activeChat)?.user?.publicKey.length
|
? "text-green-600"
|
||||||
? "text-green-600"
|
: "text-yellow-300",
|
||||||
: "text-yellow-300",
|
async onClick() {
|
||||||
async onClick() {
|
const targetNode = nodes.get(activeChat)?.num;
|
||||||
const targetNode = nodes.get(activeChat)?.num;
|
if (targetNode === undefined) return;
|
||||||
if (targetNode === undefined) return;
|
toast({
|
||||||
toast({
|
title: nodes.get(activeChat)?.user?.publicKey.length
|
||||||
title: nodes.get(activeChat)?.user?.publicKey.length
|
? "Chat is using PKI encryption."
|
||||||
? "Chat is using PKI encryption."
|
: "Chat is using PSK encryption.",
|
||||||
: "Chat is using PSK encryption.",
|
});
|
||||||
});
|
},
|
||||||
},
|
},
|
||||||
},
|
]
|
||||||
]
|
: []}
|
||||||
: []
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
{allChannels.map(
|
{allChannels.map(
|
||||||
(channel) =>
|
(channel) =>
|
||||||
|
|||||||
+17
-17
@@ -8,7 +8,7 @@ import { Mono } from "@components/generic/Mono.tsx";
|
|||||||
import { Table } from "@components/generic/Table/index.tsx";
|
import { Table } from "@components/generic/Table/index.tsx";
|
||||||
import { TimeAgo } from "@components/generic/TimeAgo.tsx";
|
import { TimeAgo } from "@components/generic/TimeAgo.tsx";
|
||||||
import { useDevice } from "@core/stores/deviceStore.ts";
|
import { useDevice } from "@core/stores/deviceStore.ts";
|
||||||
import { Protobuf, type Types } from "@meshtastic/js";
|
import { Protobuf, type Types } from "@meshtastic/core";
|
||||||
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
|
||||||
import { LockIcon, LockOpenIcon } from "lucide-react";
|
import { LockIcon, LockOpenIcon } from "lucide-react";
|
||||||
import { Fragment, type JSX, useCallback, useEffect, useState } from "react";
|
import { Fragment, type JSX, useCallback, useEffect, useState } from "react";
|
||||||
@@ -107,9 +107,11 @@ const NodesPage = (): JSX.Element => {
|
|||||||
>
|
>
|
||||||
{node.user?.shortName ??
|
{node.user?.shortName ??
|
||||||
(node.user?.macaddr
|
(node.user?.macaddr
|
||||||
? `${base16
|
? `${
|
||||||
|
base16
|
||||||
.stringify(node.user?.macaddr.subarray(4, 6) ?? [])
|
.stringify(node.user?.macaddr.subarray(4, 6) ?? [])
|
||||||
.toLowerCase()}`
|
.toLowerCase()
|
||||||
|
}`
|
||||||
: `${numberToHexUnpadded(node.num).slice(-4)}`)}
|
: `${numberToHexUnpadded(node.num).slice(-4)}`)}
|
||||||
</h1>,
|
</h1>,
|
||||||
|
|
||||||
@@ -120,9 +122,11 @@ const NodesPage = (): JSX.Element => {
|
|||||||
>
|
>
|
||||||
{node.user?.longName ??
|
{node.user?.longName ??
|
||||||
(node.user?.macaddr
|
(node.user?.macaddr
|
||||||
? `Meshtastic ${base16
|
? `Meshtastic ${
|
||||||
|
base16
|
||||||
.stringify(node.user?.macaddr.subarray(4, 6) ?? [])
|
.stringify(node.user?.macaddr.subarray(4, 6) ?? [])
|
||||||
.toLowerCase()}`
|
.toLowerCase()
|
||||||
|
}`
|
||||||
: `!${numberToHexUnpadded(node.num)}`)}
|
: `!${numberToHexUnpadded(node.num)}`)}
|
||||||
</h1>,
|
</h1>,
|
||||||
|
|
||||||
@@ -136,11 +140,9 @@ const NodesPage = (): JSX.Element => {
|
|||||||
?.join(":") ?? "UNK"}
|
?.join(":") ?? "UNK"}
|
||||||
</Mono>,
|
</Mono>,
|
||||||
<Fragment key="lastHeard">
|
<Fragment key="lastHeard">
|
||||||
{node.lastHeard === 0 ? (
|
{node.lastHeard === 0
|
||||||
<p>Never</p>
|
? <p>Never</p>
|
||||||
) : (
|
: <TimeAgo timestamp={node.lastHeard * 1000} />}
|
||||||
<TimeAgo timestamp={node.lastHeard * 1000} />
|
|
||||||
)}
|
|
||||||
</Fragment>,
|
</Fragment>,
|
||||||
<Mono key="snr">
|
<Mono key="snr">
|
||||||
{node.snr}db/
|
{node.snr}db/
|
||||||
@@ -148,19 +150,17 @@ const NodesPage = (): JSX.Element => {
|
|||||||
{(node.snr + 10) * 5}raw
|
{(node.snr + 10) * 5}raw
|
||||||
</Mono>,
|
</Mono>,
|
||||||
<Mono key="pki">
|
<Mono key="pki">
|
||||||
{node.user?.publicKey && node.user?.publicKey.length > 0 ? (
|
{node.user?.publicKey && node.user?.publicKey.length > 0
|
||||||
<LockIcon className="text-green-600" />
|
? <LockIcon className="text-green-600" />
|
||||||
) : (
|
: <LockOpenIcon className="text-yellow-300 mx-auto" />}
|
||||||
<LockOpenIcon className="text-yellow-300 mx-auto" />
|
|
||||||
)}
|
|
||||||
</Mono>,
|
</Mono>,
|
||||||
<Mono key="hops">
|
<Mono key="hops">
|
||||||
{node.lastHeard !== 0
|
{node.lastHeard !== 0
|
||||||
? node.viaMqtt === false && node.hopsAway === 0
|
? node.viaMqtt === false && node.hopsAway === 0
|
||||||
? "Direct"
|
? "Direct"
|
||||||
: `${node.hopsAway.toString()} ${
|
: `${node.hopsAway.toString()} ${
|
||||||
node.hopsAway > 1 ? "hops" : "hop"
|
node.hopsAway > 1 ? "hops" : "hop"
|
||||||
} away`
|
} away`
|
||||||
: "-"}
|
: "-"}
|
||||||
{node.viaMqtt === true ? ", via MQTT" : ""}
|
{node.viaMqtt === true ? ", via MQTT" : ""}
|
||||||
</Mono>,
|
</Mono>,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import {
|
import {
|
||||||
IsBoolean,
|
IsBoolean,
|
||||||
IsEnum,
|
IsEnum,
|
||||||
@@ -10,8 +10,7 @@ import {
|
|||||||
} from "class-validator";
|
} from "class-validator";
|
||||||
|
|
||||||
export class ChannelValidation
|
export class ChannelValidation
|
||||||
implements Omit<Protobuf.Channel.Channel, keyof Message | "settings">
|
implements Omit<Protobuf.Channel.Channel, keyof Message | "settings"> {
|
||||||
{
|
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
index: number;
|
index: number;
|
||||||
|
|
||||||
@@ -22,8 +21,7 @@ export class ChannelValidation
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Channel_SettingsValidation
|
export class Channel_SettingsValidation
|
||||||
implements Omit<Protobuf.Channel.ChannelSettings, keyof Message | "psk">
|
implements Omit<Protobuf.Channel.ChannelSettings, keyof Message | "psk"> {
|
||||||
{
|
|
||||||
@IsNumber()
|
@IsNumber()
|
||||||
channelNum: number;
|
channelNum: number;
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsEnum, IsInt } from "class-validator";
|
import { IsBoolean, IsEnum, IsInt } from "class-validator";
|
||||||
|
|
||||||
export class BluetoothValidation
|
export class BluetoothValidation implements
|
||||||
implements
|
Omit<
|
||||||
Omit<
|
Protobuf.Config.Config_BluetoothConfig,
|
||||||
Protobuf.Config.Config_BluetoothConfig,
|
keyof Message | "deviceLoggingEnabled"
|
||||||
keyof Message | "deviceLoggingEnabled"
|
> {
|
||||||
>
|
|
||||||
{
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsEnum, IsInt, IsString } from "class-validator";
|
import { IsBoolean, IsEnum, IsInt, IsString } from "class-validator";
|
||||||
|
|
||||||
export class DeviceValidation
|
export class DeviceValidation
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsEnum, IsInt } from "class-validator";
|
import { IsBoolean, IsEnum, IsInt } from "class-validator";
|
||||||
|
|
||||||
export class DisplayValidation
|
export class DisplayValidation
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { IsArray, IsBoolean, IsEnum, IsInt, Max, Min } from "class-validator";
|
import { IsArray, IsBoolean, IsEnum, IsInt, Max, Min } from "class-validator";
|
||||||
|
|
||||||
export class LoRaValidation
|
export class LoRaValidation
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import {
|
import {
|
||||||
IsBoolean,
|
IsBoolean,
|
||||||
IsEnum,
|
IsEnum,
|
||||||
|
|||||||
@@ -1,16 +1,14 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { IsArray, IsBoolean, IsEnum, IsInt } from "class-validator";
|
import { IsArray, IsBoolean, IsEnum, IsInt } from "class-validator";
|
||||||
|
|
||||||
const DeprecatedPositionValidationFields = ["gpsEnabled", "gpsAttemptTime"];
|
const DeprecatedPositionValidationFields = ["gpsEnabled", "gpsAttemptTime"];
|
||||||
|
|
||||||
export class PositionValidation
|
export class PositionValidation implements
|
||||||
implements
|
Omit<
|
||||||
Omit<
|
Protobuf.Config.Config_PositionConfig,
|
||||||
Protobuf.Config.Config_PositionConfig,
|
keyof Message | (typeof DeprecatedPositionValidationFields)[number]
|
||||||
keyof Message | (typeof DeprecatedPositionValidationFields)[number]
|
> {
|
||||||
>
|
|
||||||
{
|
|
||||||
@IsInt()
|
@IsInt()
|
||||||
positionBroadcastSecs: number;
|
positionBroadcastSecs: number;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsInt, IsNumber, Max, Min } from "class-validator";
|
import { IsBoolean, IsInt, IsNumber, Max, Min } from "class-validator";
|
||||||
|
|
||||||
export class PowerValidation
|
export class PowerValidation
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsString } from "class-validator";
|
import { IsBoolean, IsString } from "class-validator";
|
||||||
|
|
||||||
export class SecurityValidation
|
export class SecurityValidation implements
|
||||||
implements
|
Omit<
|
||||||
Omit<
|
Protobuf.Config.Config_SecurityConfig,
|
||||||
Protobuf.Config.Config_SecurityConfig,
|
keyof Message | "adminKey" | "privateKey" | "publicKey"
|
||||||
keyof Message | "adminKey" | "privateKey" | "publicKey"
|
> {
|
||||||
>
|
|
||||||
{
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
adminChannelEnabled: boolean;
|
adminChannelEnabled: boolean;
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsInt } from "class-validator";
|
import { IsBoolean, IsInt } from "class-validator";
|
||||||
|
|
||||||
export class AmbientLightingValidation
|
export class AmbientLightingValidation implements
|
||||||
implements
|
Omit<
|
||||||
Omit<
|
Protobuf.ModuleConfig.ModuleConfig_AmbientLightingConfig,
|
||||||
Protobuf.ModuleConfig.ModuleConfig_AmbientLightingConfig,
|
keyof Message
|
||||||
keyof Message
|
> {
|
||||||
>
|
|
||||||
{
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
ledState: boolean;
|
ledState: boolean;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsEnum, IsInt } from "class-validator";
|
import { IsBoolean, IsEnum, IsInt } from "class-validator";
|
||||||
|
|
||||||
export class AudioValidation
|
export class AudioValidation
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsEnum, IsInt, Length } from "class-validator";
|
import { IsBoolean, IsEnum, IsInt, Length } from "class-validator";
|
||||||
|
|
||||||
export class CannedMessageValidation
|
export class CannedMessageValidation
|
||||||
implements
|
implements
|
||||||
Omit<Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig, keyof Message>
|
Omit<
|
||||||
{
|
Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig,
|
||||||
|
keyof Message
|
||||||
|
> {
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
rotary1Enabled: boolean;
|
rotary1Enabled: boolean;
|
||||||
|
|
||||||
@@ -19,13 +21,16 @@ export class CannedMessageValidation
|
|||||||
inputbrokerPinPress: number;
|
inputbrokerPinPress: number;
|
||||||
|
|
||||||
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar)
|
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar)
|
||||||
inputbrokerEventCw: Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar;
|
inputbrokerEventCw:
|
||||||
|
Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar;
|
||||||
|
|
||||||
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar)
|
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar)
|
||||||
inputbrokerEventCcw: Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar;
|
inputbrokerEventCcw:
|
||||||
|
Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar;
|
||||||
|
|
||||||
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar)
|
@IsEnum(Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar)
|
||||||
inputbrokerEventPress: Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar;
|
inputbrokerEventPress:
|
||||||
|
Protobuf.ModuleConfig.ModuleConfig_CannedMessageConfig_InputEventChar;
|
||||||
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
updown1Enabled: boolean;
|
updown1Enabled: boolean;
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsInt, Length } from "class-validator";
|
import { IsBoolean, IsInt, Length } from "class-validator";
|
||||||
|
|
||||||
export class DetectionSensorValidation
|
export class DetectionSensorValidation implements
|
||||||
implements
|
Omit<
|
||||||
Omit<
|
Protobuf.ModuleConfig.ModuleConfig_DetectionSensorConfig,
|
||||||
Protobuf.ModuleConfig.ModuleConfig_DetectionSensorConfig,
|
keyof Message
|
||||||
keyof Message
|
> {
|
||||||
>
|
|
||||||
{
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsInt } from "class-validator";
|
import { IsBoolean, IsInt } from "class-validator";
|
||||||
|
|
||||||
export class ExternalNotificationValidation
|
export class ExternalNotificationValidation implements
|
||||||
implements
|
Omit<
|
||||||
Omit<
|
Protobuf.ModuleConfig.ModuleConfig_ExternalNotificationConfig,
|
||||||
Protobuf.ModuleConfig.ModuleConfig_ExternalNotificationConfig,
|
keyof Message
|
||||||
keyof Message
|
> {
|
||||||
>
|
|
||||||
{
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import {
|
import {
|
||||||
IsBoolean,
|
IsBoolean,
|
||||||
IsNumber,
|
IsNumber,
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsInt } from "class-validator";
|
import { IsBoolean, IsInt } from "class-validator";
|
||||||
|
|
||||||
export class NeighborInfoValidation
|
export class NeighborInfoValidation
|
||||||
implements
|
implements
|
||||||
Omit<Protobuf.ModuleConfig.ModuleConfig_NeighborInfoConfig, keyof Message>
|
Omit<Protobuf.ModuleConfig.ModuleConfig_NeighborInfoConfig, keyof Message> {
|
||||||
{
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsInt } from "class-validator";
|
import { IsBoolean, IsInt } from "class-validator";
|
||||||
|
|
||||||
export class PaxcounterValidation
|
export class PaxcounterValidation
|
||||||
implements
|
implements
|
||||||
Omit<Protobuf.ModuleConfig.ModuleConfig_PaxcounterConfig, keyof Message>
|
Omit<Protobuf.ModuleConfig.ModuleConfig_PaxcounterConfig, keyof Message> {
|
||||||
{
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsInt } from "class-validator";
|
import { IsBoolean, IsInt } from "class-validator";
|
||||||
|
|
||||||
export class RangeTestValidation
|
export class RangeTestValidation
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsEnum, IsInt } from "class-validator";
|
import { IsBoolean, IsEnum, IsInt } from "class-validator";
|
||||||
|
|
||||||
export class SerialValidation
|
export class SerialValidation
|
||||||
implements
|
implements
|
||||||
Omit<Protobuf.ModuleConfig.ModuleConfig_SerialConfig, keyof Message>
|
Omit<Protobuf.ModuleConfig.ModuleConfig_SerialConfig, keyof Message> {
|
||||||
{
|
|
||||||
@IsBoolean()
|
@IsBoolean()
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsInt } from "class-validator";
|
import { IsBoolean, IsInt } from "class-validator";
|
||||||
|
|
||||||
export class StoreForwardValidation
|
export class StoreForwardValidation
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import type { Message } from "@bufbuild/protobuf";
|
import type { Message } from "@bufbuild/protobuf";
|
||||||
import type { Protobuf } from "@meshtastic/js";
|
import type { Protobuf } from "@meshtastic/core";
|
||||||
import { IsBoolean, IsInt } from "class-validator";
|
import { IsBoolean, IsInt } from "class-validator";
|
||||||
|
|
||||||
export class TelemetryValidation
|
export class TelemetryValidation
|
||||||
implements
|
implements
|
||||||
Omit<Protobuf.ModuleConfig.ModuleConfig_TelemetryConfig, keyof Message>
|
Omit<Protobuf.ModuleConfig.ModuleConfig_TelemetryConfig, keyof Message> {
|
||||||
{
|
|
||||||
@IsInt()
|
@IsInt()
|
||||||
deviceUpdateInterval: number;
|
deviceUpdateInterval: number;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user