diff --git a/photon-client/src/App.vue b/photon-client/src/App.vue index 480023f20..eb463ccaa 100644 --- a/photon-client/src/App.vue +++ b/photon-client/src/App.vue @@ -198,6 +198,7 @@ import Logs from "./views/LogsView" }; this.$options.sockets.onopen = () => { this.$store.state.backendConnected = true; + this.$store.state.connectedCallbacks.forEach(it => it()) }; let closed = () => { diff --git a/photon-client/src/components/common/cv-image.vue b/photon-client/src/components/common/cv-image.vue index 0cadb0b84..4a5d82421 100644 --- a/photon-client/src/components/common/cv-image.vue +++ b/photon-client/src/components/common/cv-image.vue @@ -14,6 +14,11 @@ name: "CvImage", // eslint-disable-next-line vue/require-prop-types props: ['address', 'scale', 'maxHeight', 'maxHeightMd', 'maxHeightXl', 'colorPicking', 'id', 'disconnected'], + data() { + return { + seed: 1.0, + } + }, computed: { styleObject: { get() { @@ -41,9 +46,17 @@ }, src: { get() { - return this.disconnected ? require("../../assets/noStream.jpg") : this.address; + return this.disconnected ? require("../../assets/noStream.jpg") : this.address + "?" + this.seed // This prevents caching }, }, }, + mounted() { + this.reload(); // Force reload image on creation + }, + methods: { + reload() { + this.seed = new Date().getTime(); + } + }, } \ No newline at end of file diff --git a/photon-client/src/components/pipeline/CameraAndPipelineSelect.vue b/photon-client/src/components/pipeline/CameraAndPipelineSelect.vue index 12a64c671..865cad801 100644 --- a/photon-client/src/components/pipeline/CameraAndPipelineSelect.vue +++ b/photon-client/src/components/pipeline/CameraAndPipelineSelect.vue @@ -34,7 +34,7 @@ :hover="true" text="edit" tooltip="Edit camera name" - @click="toCameraNameChange" + @click="changeCameraName" />
{ + this.$emit('camera-name-changed') + }) + .catch(e => { + console.log("HTTP error while changing camera name " + e); + this.$emit('camera-name-changed') + }) this.discardCameraNameChange(); } }, diff --git a/photon-client/src/store/index.js b/photon-client/src/store/index.js index 6b17b8e30..8c338f608 100644 --- a/photon-client/src/store/index.js +++ b/photon-client/src/store/index.js @@ -15,6 +15,7 @@ export default new Vuex.Store({ }, state: { backendConnected: false, + connectedCallbacks: [], colorPicking: false, logsOverlay: false, compactMode: localStorage.getItem("compactMode") === undefined ? undefined : localStorage.getItem("compactMode") === "true", // Compact mode is initially unset on purpose diff --git a/photon-client/src/views/PipelineView.vue b/photon-client/src/views/PipelineView.vue index e11e1390d..a168665b8 100644 --- a/photon-client/src/views/PipelineView.vue +++ b/photon-client/src/views/PipelineView.vue @@ -45,8 +45,9 @@ style="height: 100%;" >
- - + + + + - Because the current resolution {{ this.$store.getters.videoFormatList[this.$store.getters.currentPipelineSettings.cameraVideoModeIndex].width }} - x {{ this.$store.getters.videoFormatList[this.$store.getters.currentPipelineSettings.cameraVideoModeIndex].height }} + Because the current resolution {{ + this.$store.getters.videoFormatList[this.$store.getters.currentPipelineSettings.cameraVideoModeIndex].width + }} + x {{ + this.$store.getters.videoFormatList[this.$store.getters.currentPipelineSettings.cameraVideoModeIndex].height + }} is not yet calibrated, 3D mode cannot be enabled. Please \ No newline at end of file diff --git a/photon-server/src/main/java/org/photonvision/server/RequestHandler.java b/photon-server/src/main/java/org/photonvision/server/RequestHandler.java index 69e9c58ba..251cdc76e 100644 --- a/photon-server/src/main/java/org/photonvision/server/RequestHandler.java +++ b/photon-server/src/main/java/org/photonvision/server/RequestHandler.java @@ -160,6 +160,20 @@ public class RequestHandler { } } + public static void setCameraNickname(Context ctx) { + try { + var data = kObjectMapper.readValue(ctx.body(), HashMap.class); + String name = String.valueOf(data.get("name")); + int idx = Integer.parseInt(String.valueOf(data.get("cameraIndex"))); + VisionModuleManager.getInstance().getModule(idx).setCameraNickname(name); + ctx.status(200); + return; + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + ctx.status(500); + } + public static void uploadPnpModel(Context ctx) { UITargetData data; try { diff --git a/photon-server/src/main/java/org/photonvision/server/Server.java b/photon-server/src/main/java/org/photonvision/server/Server.java index 23b91961a..0a7c31f51 100644 --- a/photon-server/src/main/java/org/photonvision/server/Server.java +++ b/photon-server/src/main/java/org/photonvision/server/Server.java @@ -81,6 +81,7 @@ public class Server { app.post("api/restartProgram", RequestHandler::restartProgram); app.post("api/vision/pnpModel", RequestHandler::uploadPnpModel); app.post("api/sendMetrics", RequestHandler::sendMetrics); + app.post("api/setCameraNickname", RequestHandler::setCameraNickname); app.start(port); } diff --git a/photon-server/src/main/java/org/photonvision/vision/frame/consumer/MJPGFrameConsumer.java b/photon-server/src/main/java/org/photonvision/vision/frame/consumer/MJPGFrameConsumer.java index 66597f980..ee34ee718 100644 --- a/photon-server/src/main/java/org/photonvision/vision/frame/consumer/MJPGFrameConsumer.java +++ b/photon-server/src/main/java/org/photonvision/vision/frame/consumer/MJPGFrameConsumer.java @@ -34,12 +34,12 @@ import org.photonvision.vision.frame.FrameDivisor; public class MJPGFrameConsumer { - private final CvSource cvSource; - private final MjpegServer mjpegServer; + private CvSource cvSource; + private MjpegServer mjpegServer; private FrameDivisor divisor = FrameDivisor.NONE; @SuppressWarnings("FieldCanBeLocal") - private final VideoListener listener; + private VideoListener listener; private final NetworkTable table; @@ -163,4 +163,14 @@ public class MJPGFrameConsumer { return "Unknown"; } } + + public void close() { + table.getEntry("connected").setBoolean(false); + mjpegServer.close(); + cvSource.close(); + listener.close(); + mjpegServer = null; + cvSource = null; + listener = null; + } } diff --git a/photon-server/src/main/java/org/photonvision/vision/processes/VisionModule.java b/photon-server/src/main/java/org/photonvision/vision/processes/VisionModule.java index d2e447de8..aef04e03f 100644 --- a/photon-server/src/main/java/org/photonvision/vision/processes/VisionModule.java +++ b/photon-server/src/main/java/org/photonvision/vision/processes/VisionModule.java @@ -135,6 +135,11 @@ public class VisionModule { saveAndBroadcastAll(); } + private void destroyStreams() { + dashboardInputStreamer.close(); + dashboardOutputStreamer.close(); + } + private void createStreams() { var camStreamIdx = visionSource.getSettables().getConfiguration().streamIndex; // If idx = 0, we want (1181, 1182) @@ -143,11 +148,10 @@ public class VisionModule { dashboardOutputStreamer = new MJPGFrameConsumer( - visionSource.getSettables().getConfiguration().uniqueName + "-output", - outputStreamPort); + visionSource.getSettables().getConfiguration().nickname + "-output", outputStreamPort); dashboardInputStreamer = new MJPGFrameConsumer( - visionSource.getSettables().getConfiguration().uniqueName + "-input", inputStreamPort); + visionSource.getSettables().getConfiguration().nickname + "-input", inputStreamPort); } void setDriverMode(boolean isDriverMode) { @@ -280,17 +284,22 @@ public class VisionModule { OutgoingUIEvent.wrappedOf("mutatePipeline", propertyName, value, originContext)); } - void setCameraNickname(String newName) { + public void setCameraNickname(String newName) { visionSource.getSettables().getConfiguration().nickname = newName; ntConsumer.updateCameraNickname(newName); // rename streams fpsLimitedResultConsumers.clear(); + // Teardown and recreate streams + destroyStreams(); createStreams(); fpsLimitedResultConsumers.add(result -> dashboardInputStreamer.accept(result.inputFrame)); fpsLimitedResultConsumers.add(result -> dashboardOutputStreamer.accept(result.outputFrame)); + + // Push new data to the UI + saveAndBroadcastAll(); } public PhotonConfiguration.UICameraConfiguration toUICameraConfig() { diff --git a/photon-server/src/main/java/org/photonvision/vision/processes/VisionModuleChangeSubscriber.java b/photon-server/src/main/java/org/photonvision/vision/processes/VisionModuleChangeSubscriber.java index 864361b07..59842ac53 100644 --- a/photon-server/src/main/java/org/photonvision/vision/processes/VisionModuleChangeSubscriber.java +++ b/photon-server/src/main/java/org/photonvision/vision/processes/VisionModuleChangeSubscriber.java @@ -62,12 +62,11 @@ public class VisionModuleChangeSubscriber extends DataChangeSubscriber { // special case for non-PipelineSetting changes switch (propName) { - case "cameraNickname": // rename camera - var newNickname = (String) newPropValue; - logger.info("Changing nickname to " + newNickname); - parentModule.setCameraNickname(newNickname); - parentModule.saveAndBroadcastAll(); - return; + // case "cameraNickname": // rename camera + // var newNickname = (String) newPropValue; + // logger.info("Changing nickname to " + newNickname); + // parentModule.setCameraNickname(newNickname); + // return; case "pipelineName": // rename current pipeline logger.info("Changing nick to " + newPropValue); parentModule.pipelineManager.getCurrentPipelineSettings().pipelineNickname =