mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-02 02:51:40 +00:00
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:
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 &&
|
||||
!(
|
||||
|
||||
@@ -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="
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user