Remove camera index in ui (#1677)

With the new camera matching, this is SUPER BAD! Convert to using camera
uuid.

---------

Co-authored-by: Matt <matthew.morley.ca@gmail.com>
This commit is contained in:
Cameron (3539)
2025-01-03 18:50:25 -05:00
committed by GitHub
parent 6c7a174424
commit ab844a77b8
19 changed files with 271 additions and 250 deletions

View File

@@ -34,8 +34,8 @@ if (!is_demo) {
if (data.updatePipelineResult !== undefined) {
useStateStore().updateBackendResultsFromWebsocket(data.updatePipelineResult);
}
if (data.mutatePipelineSettings !== undefined && data.cameraIndex !== undefined) {
useCameraSettingsStore().changePipelineSettingsInStore(data.mutatePipelineSettings, data.cameraIndex);
if (data.mutatePipelineSettings !== undefined && data.cameraUniqueName !== undefined) {
useCameraSettingsStore().changePipelineSettingsInStore(data.mutatePipelineSettings, data.cameraUniqueName);
}
if (data.calibrationData !== undefined) {
useStateStore().updateCalibrationStateValuesFromWebsocket(data.calibrationData);

View File

@@ -20,7 +20,8 @@ const mdAndUp = computed<boolean>(() => getCurrentInstance()?.proxy.$vuetify.bre
const needsCamerasConfigured = computed<boolean>(() => {
return (
useCameraSettingsStore().cameras.length === 0 || useCameraSettingsStore().cameras[0] === PlaceholderCameraSettings
Object.values(useCameraSettingsStore().cameras).length === 0 ||
useCameraSettingsStore().cameras["PlaceHolder Name"] === PlaceholderCameraSettings
);
});
</script>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import PvSelect from "@/components/common/pv-select.vue";
import PvSelect, { type SelectItem } from "@/components/common/pv-select.vue";
import PvNumberInput from "@/components/common/pv-number-input.vue";
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import { useStateStore } from "@/stores/StateStore";
@@ -121,7 +121,7 @@ const openExportSettingsPrompt = () => {
const yesDeleteMySettingsText = ref("");
const deleteThisCamera = () => {
const payload = {
cameraUniqueName: useCameraSettingsStore().cameraUniqueNames[useStateStore().currentCameraIndex]
cameraUniqueName: useStateStore().currentCameraUniqueName
};
axios
@@ -152,6 +152,12 @@ const deleteThisCamera = () => {
});
showDeleteCamera.value = false;
};
const wrappedCameras = computed<SelectItem[]>(() =>
Object.keys(useCameraSettingsStore().cameras).map((cameraUniqueName) => ({
name: useCameraSettingsStore().cameras[cameraUniqueName].nickname,
value: cameraUniqueName
}))
);
</script>
<template>
@@ -159,9 +165,9 @@ const deleteThisCamera = () => {
<v-card-title>Camera Settings</v-card-title>
<div class="ml-5">
<pv-select
v-model="useStateStore().currentCameraIndex"
v-model="useStateStore().currentCameraUniqueName"
label="Camera"
:items="useCameraSettingsStore().cameraNames"
:items="wrappedCameras"
:select-cols="8"
/>
<pv-number-input
@@ -213,9 +219,7 @@ const deleteThisCamera = () => {
<v-dialog v-model="showDeleteCamera" dark width="1500">
<v-card dark class="dialog-container pa-6" color="primary" flat>
<v-card-title
>Delete camera "{{ useCameraSettingsStore().cameraNames[useStateStore().currentCameraIndex] }}"</v-card-title
>
<v-card-title>Delete camera "{{ useCameraSettingsStore().currentCameraName }}"</v-card-title>
<v-row class="pl-3 align-center pa-6">
<v-col cols="12" md="6">
<span class="mt-3"> This will delete ALL OF YOUR SETTINGS and restart PhotonVision. </span>

View File

@@ -2,7 +2,7 @@
import { computed } from "vue";
import TooltippedLabel from "@/components/common/pv-tooltipped-label.vue";
interface SelectItem {
export interface SelectItem {
name: string | number;
value: string | number;
disabled?: boolean;
@@ -14,7 +14,7 @@ const props = withDefaults(
tooltip?: string;
selectCols?: number;
// TODO fully update v-model usage in custom components on Vue3 update
value: number;
value: any;
disabled?: boolean;
items: string[] | number[] | SelectItem[];
}>(),
@@ -25,7 +25,7 @@ const props = withDefaults(
);
const emit = defineEmits<{
(e: "input", value: number): void;
(e: "input", value: string): void;
}>();
const localValue = computed({

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import PvSelect from "@/components/common/pv-select.vue";
import PvSelect, { type SelectItem } from "@/components/common/pv-select.vue";
import { useStateStore } from "@/stores/StateStore";
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import { WebsocketPipelineType } from "@/types/WebsocketDataTypes";
@@ -9,10 +9,10 @@ import PvInput from "@/components/common/pv-input.vue";
import { PipelineType } from "@/types/PipelineTypes";
import { useSettingsStore } from "@/stores/settings/GeneralSettingsStore";
const changeCurrentCameraIndex = (index: number) => {
useCameraSettingsStore().setCurrentCameraIndex(index, true);
const changeCurrentCameraUniqueName = (cameraUniqueName: string) => {
useCameraSettingsStore().setCurrentCameraUniqueName(cameraUniqueName, true);
switch (useCameraSettingsStore().cameras[index].pipelineSettings.pipelineType) {
switch (useCameraSettingsStore().cameras[cameraUniqueName].pipelineSettings.pipelineType) {
case PipelineType.Reflective:
pipelineType.value = WebsocketPipelineType.Reflective;
break;
@@ -86,7 +86,7 @@ const cancelCameraNameEdit = () => {
};
// Pipeline Name Edit
const pipelineNamesWrapper = computed<{ name: string; value: number }[]>(() => {
const pipelineNamesWrapper = computed<SelectItem[]>(() => {
const pipelineNames = useCameraSettingsStore().pipelineNames.map((name, index) => ({ name: name, value: index }));
if (useCameraSettingsStore().isDriverMode) {
@@ -212,7 +212,7 @@ const duplicateCurrentPipeline = () => {
// Change Props whenever the pipeline settings are changed
useCameraSettingsStore().$subscribe((mutation, state) => {
const currentCameraSettings = state.cameras[useStateStore().currentCameraIndex];
const currentCameraSettings = state.cameras[useStateStore().currentCameraUniqueName];
switch (currentCameraSettings.pipelineSettings.pipelineType) {
case PipelineType.Reflective:
@@ -232,6 +232,12 @@ useCameraSettingsStore().$subscribe((mutation, state) => {
break;
}
});
const wrappedCameras = computed<SelectItem[]>(() =>
Object.keys(useCameraSettingsStore().cameras).map((cameraUniqueName) => ({
name: useCameraSettingsStore().cameras[cameraUniqueName].nickname,
value: cameraUniqueName
}))
);
</script>
<template>
@@ -240,10 +246,10 @@ useCameraSettingsStore().$subscribe((mutation, state) => {
<v-col cols="10" class="pa-0">
<pv-select
v-if="!isCameraNameEdit"
v-model="useStateStore().currentCameraIndex"
v-model="useStateStore().currentCameraUniqueName"
label="Camera"
:items="useCameraSettingsStore().cameraNames"
@input="changeCurrentCameraIndex"
:items="wrappedCameras"
@input="changeCurrentCameraUniqueName"
/>
<pv-input
v-else

View File

@@ -2,6 +2,7 @@ import { defineStore } from "pinia";
import type { LogMessage, VsmState } from "@/types/SettingTypes";
import type { AutoReconnectingWebsocket } from "@/lib/AutoReconnectingWebsocket";
import type { MultitagResult, PipelineResult } from "@/types/PhotonTrackingTypes";
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import type {
WebsocketCalibrationData,
WebsocketLogMessage,
@@ -22,7 +23,7 @@ interface StateStore {
showLogModal: boolean;
sidebarFolded: boolean;
logMessages: LogMessage[];
currentCameraIndex: number;
currentCameraUniqueName: string;
backendResults: Record<number, PipelineResult>;
multitagResultBuffer: Record<string, MultitagResult[]>;
@@ -48,6 +49,7 @@ interface StateStore {
export const useStateStore = defineStore("state", {
state: (): StateStore => {
const cameraStore = useCameraSettingsStore();
return {
backendConnected: false,
websocket: undefined,
@@ -59,7 +61,7 @@ export const useStateStore = defineStore("state", {
sidebarFolded:
localStorage.getItem("sidebarFolded") === null ? false : localStorage.getItem("sidebarFolded") === "true",
logMessages: [],
currentCameraIndex: 0,
currentCameraUniqueName: Object.keys(cameraStore.cameras)[0],
backendResults: {
0: {
@@ -97,11 +99,12 @@ export const useStateStore = defineStore("state", {
},
getters: {
currentPipelineResults(): PipelineResult | undefined {
return this.backendResults[this.currentCameraIndex.toString()];
return this.backendResults[this.currentCameraUniqueName.toString()];
},
currentMultitagBuffer(): MultitagResult[] | undefined {
if (!this.multitagResultBuffer[this.currentCameraIndex]) this.multitagResultBuffer[this.currentCameraIndex] = [];
return this.multitagResultBuffer[this.currentCameraIndex];
if (!this.multitagResultBuffer[this.currentCameraUniqueName])
this.multitagResultBuffer[this.currentCameraUniqueName] = [];
return this.multitagResultBuffer[this.currentCameraUniqueName];
}
},
actions: {

View File

@@ -18,17 +18,18 @@ import axios from "axios";
import { resolutionsAreEqual } from "@/lib/PhotonUtils";
interface CameraSettingsStore {
cameras: UiCameraConfiguration[];
cameras: { [key: string]: UiCameraConfiguration };
}
export const useCameraSettingsStore = defineStore("cameraSettings", {
state: (): CameraSettingsStore => ({
cameras: [PlaceholderCameraSettings]
cameras: { [PlaceholderCameraSettings.uniqueName]: PlaceholderCameraSettings }
}),
getters: {
// TODO update types to update this value being undefined. This would be a decently large change.
currentCameraSettings(): UiCameraConfiguration {
return this.cameras[useStateStore().currentCameraIndex];
const currentCameraUniqueName = useStateStore().currentCameraUniqueName;
return this.cameras[currentCameraUniqueName] || PlaceholderCameraSettings;
},
currentPipelineSettings(): ActivePipelineSettings {
return this.currentCameraSettings.pipelineSettings;
@@ -49,19 +50,19 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
);
},
cameraNames(): string[] {
return this.cameras.map((c) => c.nickname);
return Object.values(this.cameras).map((c) => c.nickname);
},
cameraUniqueNames(): string[] {
return this.cameras.map((c) => c.uniqueName);
return Object.values(this.cameras).map((c) => c.uniqueName);
},
currentCameraName(): string {
return this.cameraNames[useStateStore().currentCameraIndex];
return this.cameras[useStateStore().currentCameraUniqueName].nickname;
},
pipelineNames(): string[] {
return this.currentCameraSettings.pipelineNicknames;
},
currentPipelineName(): string {
return this.pipelineNames[useStateStore().currentCameraIndex];
return this.pipelineNames[useStateStore().currentCameraUniqueName];
},
isDriverMode(): boolean {
return this.currentCameraSettings.currentPipelineIndex === WebsocketPipelineType.DriverMode;
@@ -93,72 +94,79 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
},
actions: {
updateCameraSettingsFromWebsocket(data: WebsocketCameraSettingsUpdate[]) {
const configuredCameras = data.map<UiCameraConfiguration>((d) => ({
cameraPath: d.cameraPath,
const configuredCameras = data.reduce<{ [key: string]: UiCameraConfiguration }>((acc, d) => {
acc[d.uniqueName] = {
cameraPath: d.cameraPath,
nickname: d.nickname,
uniqueName: d.uniqueName,
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,
isCSICamera: d.isCSICamera,
minExposureRaw: d.minExposureRaw,
maxExposureRaw: d.maxExposureRaw,
pipelineNicknames: d.pipelineNicknames,
currentPipelineIndex: d.currentPipelineIndex,
pipelineSettings: d.currentPipelineSettings,
cameraQuirks: d.cameraQuirks,
minWhiteBalanceTemp: d.minWhiteBalanceTemp,
maxWhiteBalanceTemp: d.maxWhiteBalanceTemp,
matchedCameraInfo: d.matchedCameraInfo,
isConnected: d.isConnected,
hasConnected: d.hasConnected
};
return acc;
}, {});
this.cameras =
Object.keys(configuredCameras).length > 0
? configuredCameras
: { [PlaceholderCameraSettings.uniqueName]: PlaceholderCameraSettings };
nickname: d.nickname,
uniqueName: d.uniqueName,
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,
isCSICamera: d.isCSICamera,
minExposureRaw: d.minExposureRaw,
maxExposureRaw: d.maxExposureRaw,
pipelineNicknames: d.pipelineNicknames,
currentPipelineIndex: d.currentPipelineIndex,
pipelineSettings: d.currentPipelineSettings,
cameraQuirks: d.cameraQuirks,
minWhiteBalanceTemp: d.minWhiteBalanceTemp,
maxWhiteBalanceTemp: d.maxWhiteBalanceTemp,
matchedCameraInfo: d.matchedCameraInfo,
isConnected: d.isConnected,
hasConnected: d.hasConnected
}));
// Clamp index to between 0 and [length - 1]
useStateStore().currentCameraIndex = Math.max(
0,
Math.min(useStateStore().currentCameraIndex, configuredCameras.length - 1)
);
this.cameras = configuredCameras.length > 0 ? configuredCameras : [PlaceholderCameraSettings];
// Ensure currentCameraUniqueName is valid
if (!this.cameras[useStateStore().currentCameraUniqueName]) {
useStateStore().currentCameraUniqueName = Object.keys(this.cameras)[0];
}
},
/**
* Update the configurable camera settings.
*
* @param data camera settings to save.
* @param cameraIndex the index of the camera.
* @param cameraUniqueNamendex the unique name of the camera.
*/
updateCameraSettings(data: CameraSettingsChangeRequest, cameraIndex: number = useStateStore().currentCameraIndex) {
updateCameraSettings(
data: CameraSettingsChangeRequest,
cameraUniqueName: String = useStateStore().currentCameraUniqueName
) {
// 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
cameraUniqueName: cameraUniqueName
};
return axios.post("/settings/camera", payload);
},
@@ -167,16 +175,16 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
*
* @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
* @param cameraUniqueNamendex the unique name of the camera.
*/
createNewPipeline(
newPipelineName: string,
pipelineType: Exclude<WebsocketPipelineType, WebsocketPipelineType.Calib3d | WebsocketPipelineType.DriverMode>,
cameraIndex: number = useStateStore().currentCameraIndex
cameraUniqueName: String = useStateStore().currentCameraUniqueName
) {
const payload = {
addNewPipeline: [newPipelineName, pipelineType],
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
useStateStore().websocket?.send(payload, true);
},
@@ -185,30 +193,30 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
*
* @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
* @param cameraUniqueNamendex the unique name of the camera.
*/
changeCurrentPipelineSetting(
settings: ActiveConfigurablePipelineSettings,
updateStore = true,
cameraIndex: number = useStateStore().currentCameraIndex
cameraUniqueName: string = useStateStore().currentCameraUniqueName
) {
const payload = {
changePipelineSetting: {
...settings,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
}
};
if (updateStore) {
this.changePipelineSettingsInStore(settings, cameraIndex);
this.changePipelineSettingsInStore(settings, cameraUniqueName);
}
useStateStore().websocket?.send(payload, true);
},
changePipelineSettingsInStore(
settings: Partial<ActivePipelineSettings>,
cameraIndex: number = useStateStore().currentCameraIndex
cameraUniqueName: string = useStateStore().currentCameraUniqueName
) {
Object.entries(settings).forEach(([k, v]) => {
this.cameras[cameraIndex].pipelineSettings[k] = v;
this.cameras[cameraUniqueName].pipelineSettings[k] = v;
});
},
/**
@@ -216,19 +224,19 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
*
* @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
* @param cameraUniqueNamendex the unique name of the camera.
*/
changeCurrentPipelineNickname(
newName: string,
updateStore = true,
cameraIndex: number = useStateStore().currentCameraIndex
cameraUniqueName: string = useStateStore().currentCameraUniqueName
) {
const payload = {
changePipelineName: newName,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
if (updateStore) {
this.cameras[cameraIndex].pipelineSettings.pipelineNickname = newName;
this.cameras[cameraUniqueName].pipelineSettings.pipelineNickname = newName;
}
useStateStore().websocket?.send(payload, true);
},
@@ -236,15 +244,15 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
* 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.
* @param cameraUniqueNamendex the unique name of the camera.
*/
changeCurrentPipelineType(
type: Exclude<WebsocketPipelineType, WebsocketPipelineType.Calib3d | WebsocketPipelineType.DriverMode>,
cameraIndex: number = useStateStore().currentCameraIndex
cameraUniqueName: string = useStateStore().currentCameraUniqueName
) {
const payload = {
pipelineType: type,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
useStateStore().websocket?.send(payload, true);
},
@@ -253,44 +261,44 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
*
* @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.
* @param cameraUniqueNamendex the unique name of the camera.
*/
changeCurrentPipelineIndex(
index: number,
updateStore = true,
cameraIndex: number = useStateStore().currentCameraIndex
cameraUniqueName: string = useStateStore().currentCameraUniqueName
) {
const payload = {
currentPipeline: index,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
if (updateStore) {
if (
this.cameras[cameraIndex].currentPipelineIndex !== -1 &&
this.cameras[cameraIndex].currentPipelineIndex !== -2
this.cameras[cameraUniqueName].currentPipelineIndex !== -1 &&
this.cameras[cameraUniqueName].currentPipelineIndex !== -2
) {
this.cameras[cameraIndex].lastPipelineIndex = this.cameras[cameraIndex].currentPipelineIndex;
this.cameras[cameraUniqueName].lastPipelineIndex = this.cameras[cameraUniqueName].currentPipelineIndex;
}
this.cameras[cameraIndex].currentPipelineIndex = index;
this.cameras[cameraUniqueName].currentPipelineIndex = index;
}
useStateStore().websocket?.send(payload, true);
},
setDriverMode(isDriverMode: boolean, cameraIndex: number = useStateStore().currentCameraIndex) {
setDriverMode(isDriverMode: boolean, cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
const payload = {
driverMode: isDriverMode,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
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.
* @param cameraUniqueNamendex the unique name of the camera.
*/
deleteCurrentPipeline(cameraIndex: number = useStateStore().currentCameraIndex) {
deleteCurrentPipeline(cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
const payload = {
deleteCurrentPipeline: {},
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
useStateStore().websocket?.send(payload, true);
},
@@ -298,27 +306,27 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
* Duplicate the pipeline at the provided index.
*
* @param pipelineIndex index of the pipeline to duplicate.
* @param cameraIndex the index of the camera.
* @param cameraUniqueNamendex the unique name of the camera.
*/
duplicatePipeline(pipelineIndex: number, cameraIndex: number = useStateStore().currentCameraIndex) {
duplicatePipeline(pipelineIndex: number, cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
const payload = {
duplicatePipeline: pipelineIndex,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
useStateStore().websocket?.send(payload, true);
},
/**
* Change the currently set camera
*
* @param cameraIndex the index of the camera to set as the current camera.
* @param cameraUniqueName the unique name of the 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) {
setCurrentCameraUniqueName(cameraUniqueName: string, updateStore = true) {
const payload = {
currentCamera: cameraIndex
cameraUniqueName: cameraUniqueName
};
if (updateStore) {
useStateStore().currentCameraIndex = cameraIndex;
useStateStore().currentCameraUniqueName = cameraUniqueName;
}
useStateStore().websocket?.send(payload, true);
},
@@ -327,17 +335,17 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
*
* @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.
* @param cameraUniqueNamendex the unique name of the camera.
* @return HTTP request promise to the backend
*/
changeCameraNickname(
newName: string,
updateStore = true,
cameraIndex: number = useStateStore().currentCameraIndex
cameraUniqueName: string = useStateStore().currentCameraUniqueName
) {
const payload = {
name: newName,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
if (updateStore) {
this.currentCameraSettings.nickname = newName;
@@ -348,7 +356,7 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
* Start the 3D calibration process for the provided camera.
*
* @param calibrationInitData initialization calibration data.
* @param cameraIndex the index of the camera.
* @param cameraUniqueNamendex the unique name of the camera.
*/
startPnPCalibration(
calibrationInitData: {
@@ -360,7 +368,7 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
useOldPattern: boolean;
tagFamily: CalibrationTagFamilies;
},
cameraIndex: number = useStateStore().currentCameraIndex
cameraUniqueName: string = useStateStore().currentCameraUniqueName
) {
const stateCalibData = useStateStore().calibrationData;
const payload = {
@@ -371,63 +379,63 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
videoModeIndex: stateCalibData.videoFormatIndex,
...calibrationInitData
},
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
useStateStore().websocket?.send(payload, true);
},
/**
* End the 3D calibration process for the provided camera.
*
* @param cameraIndex the index of the camera
* @param cameraUniqueName the unique name of the camera.
* @return HTTP request promise to the backend
*/
endPnPCalibration(cameraIndex: number = useStateStore().currentCameraIndex) {
return axios.post("/calibration/end", { index: cameraIndex });
endPnPCalibration(cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
return axios.post("/calibration/end", { cameraUniqueName: cameraUniqueName });
},
importCalibrationFromData(
data: { calibration: CameraCalibrationResult },
cameraIndex: number = useStateStore().currentCameraIndex
cameraUniqueName: string = useStateStore().currentCameraUniqueName
) {
const payload = {
...data,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
return axios.post("/calibration/importFromData", payload);
},
/**
* Take a snapshot for the calibration processes
*
* @param cameraIndex the index of the camera that is currently in the calibration process
* @param cameraUniqueName the unique name of the camera that is currently in the calibration process
*/
takeCalibrationSnapshot(cameraIndex: number = useStateStore().currentCameraIndex) {
takeCalibrationSnapshot(cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
const payload = {
takeCalibrationSnapshot: true,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
useStateStore().websocket?.send(payload, true);
},
/**
* Save a snapshot of the input frame of the camera.
*
* @param cameraIndex the index of the camera
* @param cameraUniqueName the unique name of the camera
*/
saveInputSnapshot(cameraIndex: number = useStateStore().currentCameraIndex) {
saveInputSnapshot(cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
const payload = {
saveInputSnapshot: true,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
useStateStore().websocket?.send(payload, true);
},
/**
* Save a snapshot of the output frame of the camera.
*
* @param cameraIndex the index of the camera
* @param cameraUniqueName the unique name of the camera
*/
saveOutputSnapshot(cameraIndex: number = useStateStore().currentCameraIndex) {
saveOutputSnapshot(cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
const payload = {
saveOutputSnapshot: true,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
useStateStore().websocket?.send(payload, true);
},
@@ -435,35 +443,42 @@ export const useCameraSettingsStore = defineStore("cameraSettings", {
* Set the robot offset mode type.
*
* @param type Offset type to take.
* @param cameraIndex the index of the camera.
* @param cameraUniqueName the unique name of the camera
*/
takeRobotOffsetPoint(type: RobotOffsetType, cameraIndex: number = useStateStore().currentCameraIndex) {
takeRobotOffsetPoint(type: RobotOffsetType, cameraUniqueName: string = useStateStore().currentCameraUniqueName) {
const payload = {
robotOffsetPoint: type,
cameraIndex: cameraIndex
cameraUniqueName: cameraUniqueName
};
useStateStore().websocket?.send(payload, true);
},
getCalibrationCoeffs(
resolution: Resolution,
cameraIndex: number = useStateStore().currentCameraIndex
cameraUniqueName: string = useStateStore().currentCameraUniqueName
): CameraCalibrationResult | undefined {
return this.cameras[cameraIndex].completeCalibrations.find((v) => resolutionsAreEqual(v.resolution, resolution));
return this.cameras[cameraUniqueName].completeCalibrations.find((v) =>
resolutionsAreEqual(v.resolution, resolution)
);
},
getCalImageUrl(host: string, resolution: Resolution, idx: number, cameraIdx = useStateStore().currentCameraIndex) {
getCalImageUrl(
host: string,
resolution: Resolution,
idx: number,
cameraUniqueName = useStateStore().currentCameraUniqueName
) {
const url = new URL(`http://${host}/api/utils/getCalSnapshot`);
url.searchParams.set("width", Math.round(resolution.width).toFixed(0));
url.searchParams.set("height", Math.round(resolution.height).toFixed(0));
url.searchParams.set("snapshotIdx", Math.round(idx).toFixed(0));
url.searchParams.set("cameraIdx", Math.round(cameraIdx).toFixed(0));
url.searchParams.set("cameraUniqueName", cameraUniqueName.replace(" ", "").trim().toLowerCase());
return url.href;
},
getCalJSONUrl(host: string, resolution: Resolution, cameraIdx = useStateStore().currentCameraIndex) {
getCalJSONUrl(host: string, resolution: Resolution, cameraUniqueName = useStateStore().currentCameraUniqueName) {
const url = new URL(`http://${host}/api/utils/getCalibrationJSON`);
url.searchParams.set("width", Math.round(resolution.width).toFixed(0));
url.searchParams.set("height", Math.round(resolution.height).toFixed(0));
url.searchParams.set("cameraIdx", Math.round(cameraIdx).toFixed(0));
url.searchParams.set("cameraUniqueName", cameraUniqueName.replace(" ", "").trim().toLowerCase());
return url.href;
}

View File

@@ -103,7 +103,7 @@ export interface IncomingWebsocketData {
deviceIps: string[];
};
mutatePipelineSettings?: Partial<ActivePipelineSettings>;
cameraIndex?: number; // Sent when mutating pipeline settings to check against currently active
cameraUniqueName?: string; // Sent when mutating pipeline settings to check against currently active
calibrationData?: WebsocketCalibrationData;
visionSourceManager?: VsmState;
}

View File

@@ -19,7 +19,7 @@ const host = inject<string>("backendHost");
const activateModule = (moduleUniqueName: string) => {
const url = new URL(`http://${host}/api/utils/activateMatchedCamera`);
url.searchParams.set("uniqueName", moduleUniqueName);
url.searchParams.set("cameraUniqueName", moduleUniqueName);
fetch(url.toString(), {
method: "POST"
@@ -34,8 +34,9 @@ const activateCamera = (cameraInfo: PVCameraInfo) => {
});
};
const deactivateCamera = (cameraUniqueName: string) => {
console.log("Deactivating " + cameraUniqueName);
const url = new URL(`http://${host}/api/utils/unassignCamera`);
url.searchParams.set("uniqueName", cameraUniqueName);
url.searchParams.set("cameraUniqueName", cameraUniqueName);
fetch(url.toString(), {
method: "POST"
@@ -134,7 +135,9 @@ const getMatchedDevice = (info: PVCameraInfo | undefined): PVCameraInfo => {
};
const unmatchedCameras = computed(() => {
const activeVmPaths = useCameraSettingsStore().cameras.map((it) => uniquePathForCamera(it.matchedCameraInfo));
const activeVmPaths = Object.values(useCameraSettingsStore().cameras).map((it) =>
uniquePathForCamera(it.matchedCameraInfo)
);
const disabledVmPaths = useStateStore().vsmState.disabledConfigs.map((it) =>
uniquePathForCamera(it.matchedCameraInfo)
);
@@ -145,7 +148,7 @@ const unmatchedCameras = computed(() => {
});
const activeVisionModules = computed(() =>
useCameraSettingsStore().cameras.filter(
Object.values(useCameraSettingsStore().cameras).filter(
(camera) => JSON.stringify(camera) !== JSON.stringify(PlaceholderCameraSettings)
)
);
@@ -166,13 +169,7 @@ const setCameraView = (camera: PVCameraInfo | null, showCurrent: boolean = false
<div class="pa-5">
<v-row>
<!-- Active modules -->
<v-col
v-for="(module, index) in activeVisionModules"
:key="`enabled-${module.uniqueName}`"
cols="12"
sm="6"
lg="4"
>
<v-col v-for="module in activeVisionModules" :key="`enabled-${module.uniqueName}`" cols="12" sm="6" lg="4">
<v-card dark color="primary">
<v-card-title>{{ module.nickname }}</v-card-title>
<v-card-subtitle v-if="_.isEqual(getMatchedDevice(module.matchedCameraInfo), module.matchedCameraInfo)"
@@ -211,11 +208,11 @@ const setCameraView = (camera: PVCameraInfo | null, showCurrent: boolean = false
}}
</td>
</tr>
<tr v-if="module.isConnected && useStateStore().backendResults[index]">
<tr v-if="module.isConnected && useStateStore().backendResults[module.uniqueName]">
<td>Frames Processed</td>
<td>
{{ useStateStore().backendResults[index].sequenceID }} ({{
useStateStore().backendResults[index].fps
{{ useStateStore().backendResults[module.uniqueName].sequenceID }} ({{
useStateStore().backendResults[module.uniqueName].fps
}}
FPS)
</td>

View File

@@ -42,12 +42,13 @@ const cameraViewType = computed<number[]>({
// TODO - deduplicate with needsCamerasConfigured
const warningShown = computed<boolean>(() => {
return (
useCameraSettingsStore().cameras.length === 0 || useCameraSettingsStore().cameras[0] === PlaceholderCameraSettings
Object.values(useCameraSettingsStore().cameras).length === 0 ||
useCameraSettingsStore().cameras["Placeholder Name"] === PlaceholderCameraSettings
);
});
const arducamWarningShown = computed<boolean>(() => {
return useCameraSettingsStore().cameras.some(
return Object.values(useCameraSettingsStore().cameras).some(
(c) =>
c.cameraQuirks?.quirks?.ArduCamCamera === true &&
!(

View File

@@ -23,7 +23,7 @@ import org.photonvision.common.dataflow.DataChangeDestination;
import org.photonvision.common.dataflow.DataChangeSource;
public class IncomingWebSocketEvent<T> extends DataChangeEvent<T> {
public final Integer cameraIndex;
public final String cameraUniqueName;
public final WsContext originContext;
public IncomingWebSocketEvent(DataChangeDestination destType, String propertyName, T newValue) {
@@ -34,10 +34,10 @@ public class IncomingWebSocketEvent<T> extends DataChangeEvent<T> {
DataChangeDestination destType,
String propertyName,
T newValue,
Integer cameraIndex,
String cameraUniqueName,
WsContext originContext) {
super(DataChangeSource.DCS_WEBSOCKET, destType, propertyName, newValue);
this.cameraIndex = cameraIndex;
this.cameraUniqueName = cameraUniqueName;
this.originContext = originContext;
}
@@ -50,8 +50,8 @@ public class IncomingWebSocketEvent<T> extends DataChangeEvent<T> {
@Override
public String toString() {
return "IncomingWebSocketEvent{"
+ "cameraIndex="
+ cameraIndex
+ "cameraUniqueName="
+ cameraUniqueName
+ ", sourceType="
+ sourceType
+ ", destType="

View File

@@ -22,14 +22,14 @@ import org.photonvision.common.hardware.HardwareManager;
import org.photonvision.vision.pipeline.result.CVPipelineResult;
public class StatusLEDConsumer implements CVPipelineResultConsumer {
private final int index;
private final String uniqueName;
public StatusLEDConsumer(int index) {
this.index = index;
public StatusLEDConsumer(String uniqueName) {
this.uniqueName = uniqueName;
}
@Override
public void accept(CVPipelineResult t) {
HardwareManager.getInstance().setTargetsVisibleStatus(this.index, t.hasTargets());
HardwareManager.getInstance().setTargetsVisibleStatus(this.uniqueName, t.hasTargets());
}
}

View File

@@ -31,11 +31,11 @@ import org.photonvision.vision.pipeline.result.CalibrationPipelineResult;
public class UIDataPublisher implements CVPipelineResultConsumer {
private static final Logger logger = new Logger(UIDataPublisher.class, LogGroup.VisionModule);
private final int index;
private final String uniqueName;
private long lastUIResultUpdateTime = 0;
public UIDataPublisher(int index) {
this.index = index;
public UIDataPublisher(String uniqueName) {
this.uniqueName = uniqueName;
}
@Override
@@ -74,8 +74,8 @@ public class UIDataPublisher implements CVPipelineResultConsumer {
dataMap.put("multitagResult", multitagData);
}
var uiMap = new HashMap<Integer, HashMap<String, Object>>();
uiMap.put(index, dataMap);
var uiMap = new HashMap<String, HashMap<String, Object>>();
uiMap.put(uniqueName, dataMap);
DataChangeService.getInstance()
.publishEvent(OutgoingUIEvent.wrappedOf("updatePipelineResult", uiMap));

View File

@@ -167,13 +167,13 @@ public class HardwareManager {
// API's supporting status LEDs
private Map<Integer, Boolean> pipelineTargets = new HashMap<Integer, Boolean>();
private Map<String, Boolean> pipelineTargets = new HashMap<String, Boolean>();
private boolean ntConnected = false;
private boolean systemRunning = false;
private int blinkCounter = 0;
public void setTargetsVisibleStatus(int pipelineIdx, boolean hasTargets) {
pipelineTargets.put(pipelineIdx, hasTargets);
public void setTargetsVisibleStatus(String uniqueName, boolean hasTargets) {
pipelineTargets.put(uniqueName, hasTargets);
}
public void setNTConnected(boolean isConnected) {

View File

@@ -80,7 +80,6 @@ public class VisionModule {
private final NTDataPublisher ntConsumer;
private final UIDataPublisher uiDataConsumer;
private final StatusLEDConsumer statusLEDsConsumer;
protected final int moduleIndex;
protected final QuirkyCamera cameraQuirks;
protected TrackedTarget lastPipelineResultBestTarget;
@@ -94,7 +93,7 @@ public class VisionModule {
MJPGFrameConsumer inputVideoStreamer;
MJPGFrameConsumer outputVideoStreamer;
public VisionModule(PipelineManager pipelineManager, VisionSource visionSource, int index) {
public VisionModule(PipelineManager pipelineManager, VisionSource visionSource) {
logger =
new Logger(
VisionModule.class,
@@ -133,8 +132,6 @@ public class VisionModule {
this.cameraQuirks,
getChangeSubscriber());
this.streamRunnable = new StreamRunnable(new OutputStreamPipeline());
this.moduleIndex = index;
changeSubscriberHandle = DataChangeService.getInstance().addSubscriber(changeSubscriber);
createStreams();
@@ -148,8 +145,9 @@ public class VisionModule {
this::setPipeline,
pipelineManager::getDriverMode,
this::setDriverMode);
uiDataConsumer = new UIDataPublisher(index);
statusLEDsConsumer = new StatusLEDConsumer(index);
uiDataConsumer = new UIDataPublisher(visionSource.getSettables().getConfiguration().uniqueName);
statusLEDsConsumer =
new StatusLEDConsumer(visionSource.getSettables().getConfiguration().uniqueName);
addResultConsumer(ntConsumer);
addResultConsumer(uiDataConsumer);
addResultConsumer(statusLEDsConsumer);
@@ -531,7 +529,6 @@ public class VisionModule {
HashMap<String, Object> map = new HashMap<>();
HashMap<String, Object> subMap = new HashMap<>();
subMap.put(propertyName, value);
map.put("cameraIndex", this.moduleIndex);
map.put("mutatePipelineSettings", subMap);
DataChangeService.getInstance()

View File

@@ -57,8 +57,8 @@ public class VisionModuleChangeSubscriber extends DataChangeSubscriber {
public void onDataChangeEvent(DataChangeEvent<?> event) {
if (event instanceof IncomingWebSocketEvent wsEvent) {
// Camera index -1 means a "multicast event" (i.e. the event is received by all cameras)
if (wsEvent.cameraIndex != null
&& (wsEvent.cameraIndex == parentModule.moduleIndex || wsEvent.cameraIndex == -1)) {
if (wsEvent.cameraUniqueName != null
&& wsEvent.cameraUniqueName.equals(parentModule.uniqueName())) {
logger.trace("Got PSC event - propName: " + wsEvent.propertyName);
changeListLock.lock();
try {

View File

@@ -35,24 +35,18 @@ public class VisionModuleManager {
return visionModules;
}
public VisionModule getModule(String nickname) {
public VisionModule getModule(String uniqueName) {
for (var module : visionModules) {
if (module.getStateAsCameraConfig().nickname.equals(nickname)) return module;
if (module.getStateAsCameraConfig().uniqueName.equals(uniqueName)) return module;
}
return null;
}
public VisionModule getModule(int i) {
return visionModules.get(i);
}
public synchronized VisionModule addSource(VisionSource visionSource) {
visionSource.cameraConfiguration.streamIndex = newCameraIndex();
var pipelineManager = new PipelineManager(visionSource.getCameraConfiguration());
var module =
new VisionModule(
pipelineManager, visionSource, visionSource.cameraConfiguration.streamIndex);
var module = new VisionModule(pipelineManager, visionSource);
visionModules.add(module);
return module;

View File

@@ -99,10 +99,10 @@ public class DataSocketHandler {
objectMapper.readValue(context.data(), new TypeReference<>() {});
// Special case the current camera index
Integer cameraIndex = null;
if (deserializedData.get("cameraIndex") instanceof Integer camIndexValue) {
cameraIndex = camIndexValue;
deserializedData.remove("cameraIndex");
String cameraUniqueName = "";
if (deserializedData.get("cameraUniqueName") instanceof String camUniqueNameValue) {
cameraUniqueName = camUniqueNameValue;
deserializedData.remove("cameraUniqueName");
}
for (Map.Entry<String, Object> entry : deserializedData.entrySet()) {
@@ -135,7 +135,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"isDriverMode",
data,
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvents(dmIsDriverEvent);
@@ -146,7 +146,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"cameraNickname",
(String) entryValue,
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvent(ccnEvent);
}
@@ -156,7 +156,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"pipelineName",
(String) entryValue,
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvent(cpnEvent);
}
@@ -173,7 +173,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"newPipelineInfo",
Pair.of(name, type),
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvent(newPipelineEvent);
}
@@ -184,14 +184,14 @@ public class DataSocketHandler {
case SMT_DUPLICATEPIPELINE -> {
var pipeIndex = (Integer) entryValue;
logger.info("Duplicating pipe@index" + pipeIndex + " for camera " + cameraIndex);
logger.info("Duplicating pipe@index" + pipeIndex + " for camera " + cameraUniqueName);
var newPipelineEvent =
new IncomingWebSocketEvent<>(
DataChangeDestination.DCD_ACTIVEMODULE,
"duplicatePipeline",
pipeIndex,
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvent(newPipelineEvent);
}
@@ -201,7 +201,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"deleteCurrPipeline",
0,
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvent(deleteCurrentPipelineEvent);
}
@@ -211,7 +211,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"robotOffsetPoint",
(Integer) entryValue,
cameraIndex,
cameraUniqueName,
null);
dcService.publishEvent(robotOffsetPointEvent);
}
@@ -227,7 +227,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"changePipeline",
(Integer) entryValue,
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvent(changePipelineEvent);
}
@@ -237,7 +237,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"startCalibration",
(Map) entryValue,
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvent(changePipelineEvent);
}
@@ -247,7 +247,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"saveInputSnapshot",
0,
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvent(takeInputSnapshotEvent);
}
@@ -257,7 +257,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"saveOutputSnapshot",
0,
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvent(takeOutputSnapshotEvent);
}
@@ -267,7 +267,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"takeCalSnapshot",
0,
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvent(takeCalSnapshotEvent);
}
@@ -275,9 +275,9 @@ public class DataSocketHandler {
HashMap<String, Object> data = (HashMap<String, Object>) entryValue;
if (data.size() >= 2) {
var cameraIndex2 = (int) data.get("cameraIndex");
var cameraIndex2 = (String) data.get("cameraUniqueName");
for (var dataEntry : data.entrySet()) {
if (dataEntry.getKey().equals("cameraIndex")) {
if (dataEntry.getKey().equals("cameraUniqueName")) {
continue;
}
var pipelineSettingChangeEvent =
@@ -299,7 +299,7 @@ public class DataSocketHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"changePipelineType",
(Integer) entryValue,
cameraIndex,
cameraUniqueName,
context);
dcService.publishEvent(changePipelineEvent);
}

View File

@@ -388,7 +388,7 @@ public class RequestHandler {
try {
var data = kObjectMapper.readTree(ctx.bodyInputStream());
int index = data.get("index").asInt();
String cameraUniqueName = data.get("cameraUniqueName").asText();
var settings =
JacksonUtils.deserialize(data.get("settings").toString(), UICameraSettingsRequest.class);
var fov = settings.fov;
@@ -396,7 +396,7 @@ public class RequestHandler {
logger.info("Changing camera FOV to: " + fov);
logger.info("Changing quirks to: " + settings.quirksToChange.toString());
var module = VisionSourceManager.getInstance().vmm.getModule(index);
var module = VisionSourceManager.getInstance().vmm.getModule(cameraUniqueName);
module.setFov(fov);
module.changeCameraQuirks(settings.quirksToChange);
@@ -426,8 +426,8 @@ public class RequestHandler {
var tempPath = Files.createTempFile("photonvision-journalctl", ".txt");
var tempPath2 = Files.createTempFile("photonvision-kernelogs", ".txt");
// In the command below:
// dmesg = output all kernel logs since current boot
// cat /var/log/kern.log = output all kernal logs since first boot
// dmesg = output all kernel logs since current boot
// cat /var/log/kern.log = output all kernal logs since first boot
shell.executeBashCommand(
"journalctl -u photonvision.service > "
+ tempPath.toAbsolutePath()
@@ -470,18 +470,20 @@ public class RequestHandler {
public static void onCalibrationEndRequest(Context ctx) {
logger.info("Calibrating camera! This will take a long time...");
int index;
String cameraUniqueName;
try {
index = kObjectMapper.readTree(ctx.bodyInputStream()).get("index").asInt();
cameraUniqueName =
kObjectMapper.readTree(ctx.bodyInputStream()).get("cameraUniqueName").asText();
var calData = VisionSourceManager.getInstance().vmm.getModule(index).endCalibration();
var calData =
VisionSourceManager.getInstance().vmm.getModule(cameraUniqueName).endCalibration();
if (calData == null) {
ctx.result("The calibration process failed");
ctx.status(500);
logger.error(
"The calibration process failed. Calibration data for module at index ("
+ index
"The calibration process failed. Calibration data for module at cameraUniqueName ("
+ cameraUniqueName
+ ") was null");
return;
}
@@ -492,9 +494,9 @@ public class RequestHandler {
} catch (JsonProcessingException e) {
ctx.status(400);
ctx.result(
"The 'index' field was not found in the request. Please make sure the index of the vision module is specified with the 'index' key.");
"The 'cameraUniqueName' field was not found in the request. Please make sure the cameraUniqueName of the vision module is specified with the 'cameraUniqueName' key.");
logger.error(
"The 'index' field was not found in the request. Please make sure the index of the vision module is specified with the 'index' key.",
"The 'cameraUniqueName' field was not found in the request. Please make sure the cameraUniqueName of the vision module is specified with the 'cameraUniqueName' key.",
e);
} catch (Exception e) {
ctx.status(500);
@@ -507,7 +509,7 @@ public class RequestHandler {
try {
var data = kObjectMapper.readTree(ctx.bodyInputStream());
int cameraIndex = data.get("cameraIndex").asInt();
String cameraUniqueName = data.get("cameraUniqueName").asText();
var coeffs =
kObjectMapper.convertValue(data.get("calibration"), CameraCalibrationCoefficients.class);
@@ -516,7 +518,7 @@ public class RequestHandler {
DataChangeDestination.DCD_ACTIVEMODULE,
"calibrationUploaded",
coeffs,
cameraIndex,
cameraUniqueName,
null);
DataChangeService.getInstance().publishEvent(uploadCalibrationEvent);
@@ -550,9 +552,9 @@ public class RequestHandler {
var data = kObjectMapper.readTree(ctx.bodyInputStream());
String name = data.get("name").asText();
int idx = data.get("cameraIndex").asInt();
String cameraUniqueName = data.get("cameraUniqueName").asText();
VisionSourceManager.getInstance().vmm.getModule(idx).setCameraNickname(name);
VisionSourceManager.getInstance().vmm.getModule(cameraUniqueName).setCameraNickname(name);
ctx.status(200);
ctx.result("Successfully changed the camera name to: " + name);
logger.info("Successfully changed the camera name to: " + name);
@@ -576,7 +578,7 @@ public class RequestHandler {
public static void onCalibrationSnapshotRequest(Context ctx) {
logger.info(ctx.queryString().toString());
int idx = Integer.parseInt(ctx.queryParam("cameraIdx"));
String cameraUniqueName = ctx.queryParam("cameraUniqueName");
var width = Integer.parseInt(ctx.queryParam("width"));
var height = Integer.parseInt(ctx.queryParam("height"));
var observationIdx = Integer.parseInt(ctx.queryParam("snapshotIdx"));
@@ -584,7 +586,7 @@ public class RequestHandler {
CameraCalibrationCoefficients calList =
VisionSourceManager.getInstance()
.vmm
.getModule(idx)
.getModule(cameraUniqueName)
.getStateAsCameraConfig()
.calibrations
.stream()
@@ -629,11 +631,12 @@ public class RequestHandler {
public static void onCalibrationExportRequest(Context ctx) {
logger.info(ctx.queryString().toString());
int idx = Integer.parseInt(ctx.queryParam("cameraIdx"));
String cameraUniqueName = ctx.queryParam("cameraUniqueName");
var width = Integer.parseInt(ctx.queryParam("width"));
var height = Integer.parseInt(ctx.queryParam("height"));
var cc = VisionSourceManager.getInstance().vmm.getModule(idx).getStateAsCameraConfig();
var cc =
VisionSourceManager.getInstance().vmm.getModule(cameraUniqueName).getStateAsCameraConfig();
CameraCalibrationCoefficients calList =
cc.calibrations.stream()
@@ -833,15 +836,15 @@ public class RequestHandler {
public static void onActivateMatchedCameraRequest(Context ctx) {
logger.info(ctx.queryString().toString());
String uniqueName = ctx.queryParam("uniqueName");
String cameraUniqueName = ctx.queryParam("cameraUniqueName");
if (VisionSourceManager.getInstance().reactivateDisabledCameraConfig(uniqueName)) {
if (VisionSourceManager.getInstance().reactivateDisabledCameraConfig(cameraUniqueName)) {
ctx.status(200);
} else {
ctx.status(403);
}
ctx.result("Successfully assigned camera with unique name: " + uniqueName);
ctx.result("Successfully assigned camera with unique name: " + cameraUniqueName);
}
public static void onAssignUnmatchedCameraRequest(Context ctx) {
@@ -858,7 +861,7 @@ public class RequestHandler {
if (VisionSourceManager.getInstance().assignUnmatchedCamera(camera)) {
ctx.status(200);
} else {
ctx.status(403);
ctx.status(404);
}
ctx.result("Successfully assigned camera: " + camera);
@@ -867,9 +870,9 @@ public class RequestHandler {
public static void onUnassignCameraRequest(Context ctx) {
logger.info(ctx.queryString().toString());
String uniqueName = ctx.queryParam("uniqueName");
String cameraUniqueName = ctx.queryParam("cameraUniqueName");
if (VisionSourceManager.getInstance().deactivateVisionSource(uniqueName)) {
if (VisionSourceManager.getInstance().deactivateVisionSource(cameraUniqueName)) {
ctx.status(200);
} else {
ctx.status(403);
@@ -877,6 +880,6 @@ public class RequestHandler {
ctx.status(200);
ctx.result("Successfully assigned camera with unique name: " + uniqueName);
ctx.result("Successfully assigned camera with unique name: " + cameraUniqueName);
}
}