[PhotonClient] Vite and Typescript complete refactor (#884)

This commit is contained in:
Sriman Achanta
2023-08-21 01:51:35 -04:00
committed by GitHub
parent 8397b43bef
commit f623e4a1cc
119 changed files with 11821 additions and 19318 deletions

View 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);
}
}
});

View 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);
}
}
});