mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-27 02:01:40 +00:00
[PhotonClient] Vite and Typescript complete refactor (#884)
This commit is contained in:
349
photon-client/src/stores/settings/CameraSettingsStore.ts
Normal file
349
photon-client/src/stores/settings/CameraSettingsStore.ts
Normal file
@@ -0,0 +1,349 @@
|
||||
import { defineStore } from "pinia";
|
||||
import type {
|
||||
CalibrationBoardTypes,
|
||||
CameraCalibrationResult,
|
||||
CameraSettings,
|
||||
ConfigurableCameraSettings,
|
||||
RobotOffsetType,
|
||||
VideoFormat
|
||||
} from "@/types/SettingTypes";
|
||||
import { PlaceholderCameraSettings } from "@/types/SettingTypes";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import type { WebsocketCameraSettingsUpdate } from "@/types/WebsocketDataTypes";
|
||||
import { WebsocketPipelineType } from "@/types/WebsocketDataTypes";
|
||||
import type { ActiveConfigurablePipelineSettings, ActivePipelineSettings } from "@/types/PipelineTypes";
|
||||
import type { PipelineType } from "@/types/PipelineTypes";
|
||||
import axios from "axios";
|
||||
|
||||
interface CameraSettingsStore {
|
||||
cameras: CameraSettings[]
|
||||
}
|
||||
|
||||
export const useCameraSettingsStore = defineStore("cameraSettings", {
|
||||
state: (): CameraSettingsStore => ({
|
||||
cameras: [
|
||||
PlaceholderCameraSettings
|
||||
]
|
||||
}),
|
||||
getters: {
|
||||
// TODO update types to update this value being undefined. This would be a decently large change.
|
||||
currentCameraSettings(): CameraSettings {
|
||||
return this.cameras[useStateStore().currentCameraIndex];
|
||||
},
|
||||
currentPipelineSettings(): ActivePipelineSettings {
|
||||
return this.currentCameraSettings.pipelineSettings;
|
||||
},
|
||||
currentPipelineType(): PipelineType {
|
||||
return this.currentPipelineSettings.pipelineType;
|
||||
},
|
||||
// This method only exists due to just how lazy I am and my dislike of consolidating the pipeline type enums (which mind you, suck as is)
|
||||
currentWebsocketPipelineType(): WebsocketPipelineType {
|
||||
return this.currentPipelineType - 2;
|
||||
},
|
||||
currentVideoFormat(): VideoFormat {
|
||||
return this.currentCameraSettings.validVideoFormats[this.currentPipelineSettings.cameraVideoModeIndex];
|
||||
},
|
||||
isCurrentVideoFormatCalibrated(): boolean {
|
||||
return this.currentCameraSettings.completeCalibrations.some(v =>
|
||||
v.resolution.width === this.currentVideoFormat.resolution.width
|
||||
&& v.resolution.height === this.currentVideoFormat.resolution.height);
|
||||
},
|
||||
cameraNames(): string[] {
|
||||
return this.cameras.map(c => c.nickname);
|
||||
},
|
||||
pipelineNames(): string[] {
|
||||
return this.currentCameraSettings.pipelineNicknames;
|
||||
},
|
||||
isDriverMode(): boolean {
|
||||
return this.currentCameraSettings.currentPipelineIndex === WebsocketPipelineType.DriverMode;
|
||||
},
|
||||
isCalibrationMode(): boolean {
|
||||
return this.currentCameraSettings.currentPipelineIndex == WebsocketPipelineType.Calib3d;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
updateCameraSettingsFromWebsocket(data: WebsocketCameraSettingsUpdate[]) {
|
||||
this.cameras = data.map<CameraSettings>((d) => ({
|
||||
nickname: d.nickname,
|
||||
fov: {
|
||||
value: d.fov,
|
||||
managedByVendor: !d.isFovConfigurable
|
||||
},
|
||||
stream: {
|
||||
inputPort: d.inputStreamPort,
|
||||
outputPort: d.outputStreamPort
|
||||
},
|
||||
validVideoFormats: Object.entries(d.videoFormatList)
|
||||
.sort(([firstKey], [secondKey]) => parseInt(firstKey) - parseInt(secondKey))
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.map<VideoFormat>(([k, v], i) => ({
|
||||
resolution: {
|
||||
width: v.width,
|
||||
height: v.height
|
||||
},
|
||||
fps: v.fps,
|
||||
pixelFormat: v.pixelFormat,
|
||||
index: v.index || i,
|
||||
diagonalFOV: v.diagonalFOV,
|
||||
horizontalFOV: v.horizontalFOV,
|
||||
verticalFOV: v.verticalFOV,
|
||||
standardDeviation: v.standardDeviation,
|
||||
mean: v.mean
|
||||
})),
|
||||
completeCalibrations: d.calibrations.map<CameraCalibrationResult>(calib => ({
|
||||
resolution: {
|
||||
height: calib.height,
|
||||
width: calib.width
|
||||
},
|
||||
distCoeffs: calib.distCoeffs,
|
||||
standardDeviation: calib.standardDeviation,
|
||||
perViewErrors: calib.perViewErrors,
|
||||
intrinsics: calib.intrinsics
|
||||
})),
|
||||
pipelineNicknames: d.pipelineNicknames,
|
||||
currentPipelineIndex: d.currentPipelineIndex,
|
||||
pipelineSettings: d.currentPipelineSettings
|
||||
}));
|
||||
},
|
||||
/**
|
||||
* Update the configurable camera settings.
|
||||
*
|
||||
* @param data camera settings to save.
|
||||
* @param updateStore whether or not to update the store. This is useful if the input field already models the store reference.
|
||||
* @param cameraIndex the index of the camera.
|
||||
*/
|
||||
updateCameraSettings(data: ConfigurableCameraSettings, updateStore = true, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
// The camera settings endpoint doesn't actually require all data, instead, it needs key data such as the FOV
|
||||
const payload = {
|
||||
settings: {
|
||||
...data
|
||||
},
|
||||
index: cameraIndex
|
||||
};
|
||||
if(updateStore) {
|
||||
this.currentCameraSettings.fov.value = data.fov;
|
||||
}
|
||||
return axios.post("/settings/camera", payload);
|
||||
},
|
||||
/**
|
||||
* Create a new Pipeline for the provided camera.
|
||||
*
|
||||
* @param newPipelineName the name of the new pipeline.
|
||||
* @param pipelineType the type of the new pipeline. Cannot be {@link WebsocketPipelineType.Calib3d} or {@link WebsocketPipelineType.DriverMode}.
|
||||
* @param cameraIndex the index of the camera
|
||||
*/
|
||||
createNewPipeline(newPipelineName: string, pipelineType: Exclude<WebsocketPipelineType, WebsocketPipelineType.Calib3d | WebsocketPipelineType.DriverMode>, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const payload = {
|
||||
addNewPipeline: [newPipelineName, pipelineType],
|
||||
cameraIndex: cameraIndex
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Modify the settings of the currently selected pipeline of the provided camera.
|
||||
*
|
||||
* @param settings settings to modify. The type of the settings should match the currently selected pipeline type.
|
||||
* @param updateStore whether or not to update the store. This is useful if the input field already models the store reference.
|
||||
* @param cameraIndex the index of the camera
|
||||
*/
|
||||
changeCurrentPipelineSetting(settings: ActiveConfigurablePipelineSettings, updateStore = true, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const payload = {
|
||||
changePipelineSetting: {
|
||||
...settings,
|
||||
cameraIndex: cameraIndex
|
||||
}
|
||||
};
|
||||
if(updateStore) {
|
||||
this.changePipelineSettingsInStore(settings, cameraIndex);
|
||||
}
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
changePipelineSettingsInStore(settings: Partial<ActivePipelineSettings>, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
Object.entries(settings).forEach(([k, v]) => {
|
||||
this.cameras[cameraIndex].pipelineSettings[k] = v;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Change the nickname of the currently selected pipeline of the provided camera.
|
||||
*
|
||||
* @param newName the new nickname for the camera.
|
||||
* @param updateStore whether or not to update the store. This is useful if the input field already models the store reference.
|
||||
* @param cameraIndex the index of the camera
|
||||
*/
|
||||
changeCurrentPipelineNickname(newName: string, updateStore = true, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const payload = {
|
||||
changePipelineName: newName,
|
||||
cameraIndex: cameraIndex
|
||||
};
|
||||
if(updateStore) {
|
||||
this.cameras[cameraIndex].pipelineSettings.pipelineNickname = newName;
|
||||
}
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Modify the Pipeline type of the currently selected pipeline of the provided camera. This overwrites the current pipeline's settings when the backend resets the current pipeline settings.
|
||||
*
|
||||
* @param type the pipeline type to set. Cannot be {@link WebsocketPipelineType.Calib3d} or {@link WebsocketPipelineType.DriverMode}.
|
||||
* @param cameraIndex the index of the camera.
|
||||
*/
|
||||
changeCurrentPipelineType(type: Exclude<WebsocketPipelineType, WebsocketPipelineType.Calib3d | WebsocketPipelineType.DriverMode>, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const payload = {
|
||||
pipelineType: type,
|
||||
cameraIndex: cameraIndex
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Change the index of the pipeline of the currently selected camera.
|
||||
*
|
||||
* @param index pipeline index to set.
|
||||
* @param updateStore whether or not to update the store. This is useful if the input field already models the store reference.
|
||||
* @param cameraIndex the index of the camera.
|
||||
*/
|
||||
changeCurrentPipelineIndex(index: number, updateStore = true, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const payload = {
|
||||
currentPipeline: index,
|
||||
cameraIndex: cameraIndex
|
||||
};
|
||||
if(updateStore) {
|
||||
if(this.cameras[cameraIndex].currentPipelineIndex !== -1
|
||||
&& this.cameras[cameraIndex].currentPipelineIndex !== -2) {
|
||||
this.cameras[cameraIndex].lastPipelineIndex = this.cameras[cameraIndex].currentPipelineIndex;
|
||||
}
|
||||
this.cameras[cameraIndex].currentPipelineIndex = index;
|
||||
}
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Change the currently selected pipeline of the provided camera.
|
||||
*
|
||||
* @param cameraIndex the index of the camera's pipeline to change.
|
||||
*/
|
||||
deleteCurrentPipeline(cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const payload = {
|
||||
deleteCurrentPipeline: {},
|
||||
cameraIndex: cameraIndex
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Duplicate the pipeline at the provided index.
|
||||
*
|
||||
* @param pipelineIndex index of the pipeline to duplicate.
|
||||
* @param cameraIndex the index of the camera.
|
||||
*/
|
||||
duplicatePipeline(pipelineIndex: number, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const payload = {
|
||||
duplicatePipeline: pipelineIndex,
|
||||
cameraIndex: cameraIndex
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Change the currently set camera
|
||||
*
|
||||
* @param cameraIndex the index of the camera to set as the current camera.
|
||||
* @param updateStore whether or not to update the store. This is useful if the input field already models the store reference.
|
||||
*/
|
||||
setCurrentCameraIndex(cameraIndex: number, updateStore = true) {
|
||||
const payload = {
|
||||
currentCamera: cameraIndex
|
||||
};
|
||||
if(updateStore) {
|
||||
useStateStore().currentCameraIndex = cameraIndex;
|
||||
}
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Change the nickname of the provided camera.
|
||||
*
|
||||
* @param newName the new nickname of the camera.
|
||||
* @param updateStore whether or not to update the store. This is useful if the input field already models the store reference.
|
||||
* @param cameraIndex the index of the camera.
|
||||
* @return HTTP request promise to the backend
|
||||
*/
|
||||
changeCameraNickname(newName: string, updateStore = true, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const payload = {
|
||||
name: newName,
|
||||
cameraIndex: cameraIndex
|
||||
};
|
||||
if(updateStore) {
|
||||
this.currentCameraSettings.nickname = newName;
|
||||
}
|
||||
return axios.post("/settings/camera/setNickname", payload);
|
||||
},
|
||||
/**
|
||||
* Start the 3D calibration process for the provided camera.
|
||||
*
|
||||
* @param calibrationInitData initialization calibration data.
|
||||
* @param cameraIndex the index of the camera.
|
||||
*/
|
||||
startPnPCalibration(calibrationInitData: {
|
||||
squareSizeIn: number,
|
||||
patternWidth: number,
|
||||
patternHeight: number,
|
||||
boardType: CalibrationBoardTypes
|
||||
}, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const stateCalibData = useStateStore().calibrationData;
|
||||
const payload = {
|
||||
startPnpCalibration: {
|
||||
count: stateCalibData.imageCount,
|
||||
minCount: stateCalibData.minimumImageCount,
|
||||
hasEnough: stateCalibData.hasEnoughImages,
|
||||
videoModeIndex: stateCalibData.videoFormatIndex,
|
||||
...calibrationInitData
|
||||
},
|
||||
cameraIndex: cameraIndex
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* End the 3D calibration process for the provided camera.
|
||||
*
|
||||
* @param cameraIndex the index of the camera
|
||||
* @return HTTP request promise to the backend
|
||||
*/
|
||||
endPnPCalibration(cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
return axios.post("/calibration/end", { index: cameraIndex });
|
||||
},
|
||||
/**
|
||||
* Import calibration data that was computed using CalibDB.
|
||||
*
|
||||
* @param data Data from the uploaded CalibDB config
|
||||
* @param cameraIndex the index of the camera
|
||||
*/
|
||||
importCalibDB(data: { payload: string, filename: string }, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const payload = {
|
||||
...data,
|
||||
cameraIndex: cameraIndex
|
||||
};
|
||||
return axios.post("/calibration/importFromCalibDB", payload, { headers: { "Content-Type": "text/plain" } });
|
||||
},
|
||||
/**
|
||||
* Take a snapshot for the calibration processes
|
||||
*
|
||||
* @param takeSnapshot whether or not to take a snapshot. Defaults to true
|
||||
* @param cameraIndex the index of the camera that is currently in the calibration process
|
||||
*/
|
||||
takeCalibrationSnapshot(takeSnapshot = true, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const payload = {
|
||||
takeCalibrationSnapshot: takeSnapshot,
|
||||
cameraIndex: cameraIndex
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
},
|
||||
/**
|
||||
* Set the robot offset mode type.
|
||||
*
|
||||
* @param type Offset type to take.
|
||||
* @param cameraIndex the index of the camera.
|
||||
*/
|
||||
takeRobotOffsetPoint(type: RobotOffsetType, cameraIndex: number = useStateStore().currentCameraIndex) {
|
||||
const payload = {
|
||||
robotOffsetPoint: type,
|
||||
cameraIndex: cameraIndex
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
111
photon-client/src/stores/settings/GeneralSettingsStore.ts
Normal file
111
photon-client/src/stores/settings/GeneralSettingsStore.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { defineStore } from "pinia";
|
||||
import type {
|
||||
GeneralSettings,
|
||||
LightingSettings,
|
||||
MetricData,
|
||||
NetworkSettings
|
||||
} from "@/types/SettingTypes";
|
||||
import { NetworkConnectionType } from "@/types/SettingTypes";
|
||||
import { useStateStore } from "@/stores/StateStore";
|
||||
import axios from "axios";
|
||||
import type { WebsocketSettingsUpdate } from "@/types/WebsocketDataTypes";
|
||||
|
||||
interface GeneralSettingsStore {
|
||||
general: GeneralSettings,
|
||||
network: NetworkSettings,
|
||||
lighting: LightingSettings,
|
||||
metrics: MetricData
|
||||
}
|
||||
|
||||
export const useSettingsStore = defineStore("settings", {
|
||||
state: (): GeneralSettingsStore => ({
|
||||
general: {
|
||||
version: undefined,
|
||||
gpuAcceleration: undefined,
|
||||
hardwareModel: undefined,
|
||||
hardwarePlatform: undefined
|
||||
},
|
||||
network: {
|
||||
ntServerAddress: "",
|
||||
shouldMange: true,
|
||||
connectionType: NetworkConnectionType.DHCP,
|
||||
staticIp: "",
|
||||
hostname: "photonvision",
|
||||
runNTServer: false
|
||||
},
|
||||
lighting: {
|
||||
supported: true,
|
||||
brightness: 0
|
||||
},
|
||||
metrics: {
|
||||
cpuTemp: undefined,
|
||||
cpuUtil: undefined,
|
||||
cpuMem: undefined,
|
||||
gpuMem: undefined,
|
||||
ramUtil: undefined,
|
||||
gpuMemUtil: undefined,
|
||||
cpuThr: undefined,
|
||||
cpuUptime: undefined,
|
||||
diskUtilPct: undefined
|
||||
}
|
||||
}),
|
||||
getters: {
|
||||
gpuAccelerationEnabled(): boolean {
|
||||
return this.general.gpuAcceleration !== undefined;
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
requestMetricsUpdate() {
|
||||
return axios.post("/utils/publishMetrics");
|
||||
},
|
||||
updateMetricsFromWebsocket(data: Required<MetricData>) {
|
||||
this.metrics = {
|
||||
cpuTemp: data.cpuTemp || undefined,
|
||||
cpuUtil: data.cpuUtil || undefined,
|
||||
cpuMem: data.cpuMem || undefined,
|
||||
gpuMem: data.gpuMem || undefined,
|
||||
ramUtil: data.ramUtil || undefined,
|
||||
gpuMemUtil: data.gpuMemUtil || undefined,
|
||||
cpuThr: data.cpuThr || undefined,
|
||||
cpuUptime: data.cpuUptime || undefined,
|
||||
diskUtilPct: data.diskUtilPct || undefined
|
||||
};
|
||||
},
|
||||
updateGeneralSettingsFromWebsocket(data: WebsocketSettingsUpdate) {
|
||||
this.general = {
|
||||
version: data.general.version || undefined,
|
||||
hardwareModel: data.general.hardwareModel || undefined,
|
||||
hardwarePlatform: data.general.hardwarePlatform || undefined,
|
||||
gpuAcceleration: data.general.gpuAcceleration || undefined
|
||||
};
|
||||
this.lighting = data.lighting;
|
||||
this.network = data.networkSettings;
|
||||
},
|
||||
saveGeneralSettings() {
|
||||
const payload: Required<NetworkSettings> = {
|
||||
connectionType: this.network.connectionType,
|
||||
hostname: this.network.hostname,
|
||||
networkManagerIface: this.network.networkManagerIface || "",
|
||||
ntServerAddress: this.network.ntServerAddress,
|
||||
physicalInterface: this.network.physicalInterface || "",
|
||||
runNTServer: this.network.runNTServer,
|
||||
setDHCPcommand: this.network.setDHCPcommand || "",
|
||||
setStaticCommand: this.network.setStaticCommand || "",
|
||||
shouldMange: this.network.shouldMange,
|
||||
staticIp: this.network.staticIp
|
||||
};
|
||||
return axios.post("/settings/general", payload);
|
||||
},
|
||||
/**
|
||||
* Modify the brightness of the LEDs.
|
||||
*
|
||||
* @param brightness brightness to set [0, 100]
|
||||
*/
|
||||
changeLEDBrightness(brightness: number) {
|
||||
const payload = {
|
||||
enabledLEDPercentage: brightness
|
||||
};
|
||||
useStateStore().websocket?.send(payload, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user