-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
140 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,77 @@ | ||
# Operator Control of Rubin Observatory NVR Camera Infrared Illuminators | ||
|
||
```{abstract} | ||
A solution is proposed to provide web dashboard control of the infrared illuminators on the UniFi web cameras deployed throughout the observatory, without needing to provide and admin-level UniFi account for each operator. | ||
Proposed solution to provide web dashboard control of the infrared illuminators on the UniFi web cameras | ||
deployed throughout the observatory, without needing to provide and admin-level UniFi account for each | ||
operator. | ||
``` | ||
|
||
## Add content here | ||
## Introduction | ||
|
||
See the [Documenteer documentation](https://documenteer.lsst.io/technotes/index.html) for tips on how to write and configure your new technote. | ||
Operators at the observatory occasionally need to control the illuminators on the UniFi web cameras deployed | ||
throughout the observatory. This has been problematic, since such control via the stock UniFi web interface | ||
requires a UniFi account with administrator-level privileges and the system supports only a limited number of | ||
such accounts. Broad distribution of a shared admin-level account with full control over the UniFi system to | ||
the entire operator staff has been viewed as a non-starter from a security perspective. | ||
|
||
A survey of available Python libraries which might be used to control the illuminators via UniFi-provided web | ||
APIs was conducted. Unfortunately, a compelling option was not immediately apparent; the UniFi APIs | ||
themselves are rather poorly documented, and the off-the-shelf client libraries currently available are the | ||
usual assortment of abandonware, partially implemented, or outdated solutions. | ||
|
||
In the course of the survey, however, it was discovered that there is a fairly complete and up-to-date support | ||
for UniFi NVR camera systems within the [Home Assistant](https://home-assistant.io) home automation platform. | ||
Home Assistant is a popular and vigorous open-source project with hundreds-of-thousands of installations | ||
world-wide. In addition to providing an up to date, maintained, and complete interface to the UniFi camera | ||
systems, the Home Assistant platform itself provides a tailorable web control UI, configuartion support, | ||
authentication plugins, etc. all directly out of the box. Home Assistant is also distributed as a pre-built | ||
container that can be directly utilized on the observator Kubernetes clusters. It was decided to evaluate the | ||
use of Home Asisstant and its [in-built UniFi | ||
support](https://www.home-assistant.io/integrations/unifiprotect/) as a potential low-effort near-term | ||
solution. | ||
|
||
## Prototype | ||
|
||
IT provided the following for the purposes of prototyping: | ||
|
||
* Access to the kueyen dev cluster | ||
* A DNS CNAME (`test-nvr.dev.lsst.org`) for the ingres controller | ||
* A dedicated, local service account on the NVR appliance | ||
|
||
A simple Kubernetes deployment using the latest official Home Assistant release container was hand-coded and | ||
manually deployed with `kubectl`: | ||
|
||
```{figure} kubernetes.svg | ||
Prototype Kubernetes Deployment | ||
``` | ||
|
||
Home Assistant was then configured via its built-in UI. Once pointed at the NVR appliance and auth'd, all | ||
on-site UniFi cameras were automatically introspected and made available in the interface. | ||
|
||
A dedicated "kiosk mode" page which exposes illuminator controls only was built, using a kiosk plug-in | ||
available in the Home Assistant community store. This was set as the default view for a shared "operators" | ||
local Home Assistant account, and we had a fully operable system up and running: | ||
|
||
```{figure} interface.png | ||
Prototype illuminator control page | ||
``` | ||
|
||
## To Do | ||
|
||
Use of Home Assistant for this purpose in the near term seems completely feasible from a technical | ||
perspective. Should we wish to do this, the following would still need to be done to close the gap between a | ||
prototype and an operable deployment: | ||
|
||
* If desired, integrate with Keycloak authentication for finer-grained access control. This would obviate | ||
need for a shared Home Assistant "operator" account and password. This is feasible, but perhaps not an | ||
issue since the dashboard is limited to illuminators only? <br><br> | ||
|
||
* Decide which organization within the observatory would adopt and maintain the deployment. This would | ||
seemingly be either Telescope and Site, or IT. The deployment described here has no direct integration with | ||
the observatory control systems, and interacts only with IT owned/administrated systems. <br><br> | ||
|
||
|
||
* "Devops-ify" the deployment. This would mean wrapping up the existing prototype deployment | ||
yamls in either Rancher Fleet (if adopted by IT) or Phalanx (if adopted by Telescope and Site). <br><br> | ||
|
||
* Arrange for backup of the persistent volume on which the Home Assistant configuration is stored. <br><br> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
<mxfile host="Electron" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.5 Chrome/126.0.6478.183 Electron/31.3.0 Safari/537.36" version="24.7.5"> | ||
<diagram name="Page-1" id="1ndsgg4-D2hNgmVH_vr4"> | ||
<mxGraphModel dx="1036" dy="702" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" background="none" math="0" shadow="0"> | ||
<root> | ||
<mxCell id="0" /> | ||
<mxCell id="1" parent="0" /> | ||
<mxCell id="aDZf9LyQNGa_F-r6yj7t-6" value="" style="whiteSpace=wrap;html=1;fillColor=none;dashed=1;rounded=1;arcSize=9;" parent="1" vertex="1"> | ||
<mxGeometry x="100" y="130" width="480" height="360" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-1" value="" style="aspect=fixed;sketch=0;html=1;dashed=0;whitespace=wrap;verticalLabelPosition=bottom;verticalAlign=top;fillColor=#2875E2;strokeColor=#ffffff;points=[[0.005,0.63,0],[0.1,0.2,0],[0.9,0.2,0],[0.5,0,0],[0.995,0.63,0],[0.72,0.99,0],[0.5,1,0],[0.28,0.99,0]];shape=mxgraph.kubernetes.icon2;kubernetesLabel=1;prIcon=deploy" parent="1" vertex="1"> | ||
<mxGeometry x="170" y="290" width="50" height="48" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-2" value="x1" style="aspect=fixed;sketch=0;html=1;dashed=0;whitespace=wrap;verticalLabelPosition=bottom;verticalAlign=top;fillColor=#2875E2;strokeColor=#ffffff;points=[[0.005,0.63,0],[0.1,0.2,0],[0.9,0.2,0],[0.5,0,0],[0.995,0.63,0],[0.72,0.99,0],[0.5,1,0],[0.28,0.99,0]];shape=mxgraph.kubernetes.icon2;kubernetesLabel=1;prIcon=rs" parent="1" vertex="1"> | ||
<mxGeometry x="275" y="290" width="50" height="48" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-3" value="Home<br>Assistant" style="aspect=fixed;sketch=0;html=1;dashed=0;whitespace=wrap;verticalLabelPosition=middle;verticalAlign=middle;fillColor=#2875E2;strokeColor=#ffffff;points=[[0.005,0.63,0],[0.1,0.2,0],[0.9,0.2,0],[0.5,0,0],[0.995,0.63,0],[0.72,0.99,0],[0.5,1,0],[0.28,0.99,0]];shape=mxgraph.kubernetes.icon2;kubernetesLabel=1;prIcon=pod;labelPosition=right;align=center;spacingLeft=6;" parent="1" vertex="1"> | ||
<mxGeometry x="380" y="290" width="50" height="48" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-5" value="" style="aspect=fixed;sketch=0;html=1;dashed=0;whitespace=wrap;verticalLabelPosition=bottom;verticalAlign=top;fillColor=#2875E2;strokeColor=#ffffff;points=[[0.005,0.63,0],[0.1,0.2,0],[0.9,0.2,0],[0.5,0,0],[0.995,0.63,0],[0.72,0.99,0],[0.5,1,0],[0.28,0.99,0]];shape=mxgraph.kubernetes.icon2;kubernetesLabel=1;prIcon=pv" parent="1" vertex="1"> | ||
<mxGeometry x="485" y="390" width="50" height="48" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-6" value="/config" style="aspect=fixed;sketch=0;html=1;dashed=0;whitespace=wrap;verticalLabelPosition=bottom;verticalAlign=top;fillColor=#2875E2;strokeColor=#ffffff;points=[[0.005,0.63,0],[0.1,0.2,0],[0.9,0.2,0],[0.5,0,0],[0.995,0.63,0],[0.72,0.99,0],[0.5,1,0],[0.28,0.99,0]];shape=mxgraph.kubernetes.icon2;kubernetesLabel=1;prIcon=pvc;labelPosition=center;align=center;" parent="1" vertex="1"> | ||
<mxGeometry x="380" y="390" width="50" height="48" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-7" value="" style="aspect=fixed;sketch=0;html=1;dashed=0;whitespace=wrap;verticalLabelPosition=bottom;verticalAlign=top;fillColor=#2875E2;strokeColor=#ffffff;points=[[0.005,0.63,0],[0.1,0.2,0],[0.9,0.2,0],[0.5,0,0],[0.995,0.63,0],[0.72,0.99,0],[0.5,1,0],[0.28,0.99,0]];shape=mxgraph.kubernetes.icon2;kubernetesLabel=1;prIcon=svc" parent="1" vertex="1"> | ||
<mxGeometry x="275" y="190" width="50" height="48" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-8" value="test-nvr.dev.lsst.org<br>(ssl termination)" style="aspect=fixed;sketch=0;html=1;dashed=0;whitespace=wrap;verticalLabelPosition=bottom;verticalAlign=top;fillColor=#2875E2;strokeColor=#ffffff;points=[[0.005,0.63,0],[0.1,0.2,0],[0.9,0.2,0],[0.5,0,0],[0.995,0.63,0],[0.72,0.99,0],[0.5,1,0],[0.28,0.99,0]];shape=mxgraph.kubernetes.icon2;kubernetesLabel=1;prIcon=ing;labelPosition=center;align=center;" parent="1" vertex="1"> | ||
<mxGeometry x="170" y="190" width="50" height="48" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.995;exitY=0.63;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.005;entryY=0.63;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="A0QEv23gE5V9U2TAgRKM-1" target="A0QEv23gE5V9U2TAgRKM-2" edge="1"> | ||
<mxGeometry relative="1" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.995;exitY=0.63;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.005;entryY=0.63;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="A0QEv23gE5V9U2TAgRKM-2" target="A0QEv23gE5V9U2TAgRKM-3" edge="1"> | ||
<mxGeometry relative="1" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="A0QEv23gE5V9U2TAgRKM-3" target="A0QEv23gE5V9U2TAgRKM-6" edge="1"> | ||
<mxGeometry relative="1" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.995;exitY=0.63;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.005;entryY=0.63;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="A0QEv23gE5V9U2TAgRKM-6" target="A0QEv23gE5V9U2TAgRKM-5" edge="1"> | ||
<mxGeometry relative="1" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="aDZf9LyQNGa_F-r6yj7t-1" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.995;exitY=0.63;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.1;entryY=0.2;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="A0QEv23gE5V9U2TAgRKM-7" target="A0QEv23gE5V9U2TAgRKM-3" edge="1"> | ||
<mxGeometry relative="1" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="aDZf9LyQNGa_F-r6yj7t-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.995;exitY=0.63;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.005;entryY=0.63;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="A0QEv23gE5V9U2TAgRKM-8" target="A0QEv23gE5V9U2TAgRKM-7" edge="1"> | ||
<mxGeometry relative="1" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="A0QEv23gE5V9U2TAgRKM-4" value="home-assistant" style="aspect=fixed;sketch=0;html=1;dashed=0;whitespace=wrap;verticalLabelPosition=bottom;verticalAlign=top;fillColor=#2875E2;strokeColor=#ffffff;points=[[0.005,0.63,0],[0.1,0.2,0],[0.9,0.2,0],[0.5,0,0],[0.995,0.63,0],[0.72,0.99,0],[0.5,1,0],[0.28,0.99,0]];shape=mxgraph.kubernetes.icon2;kubernetesLabel=1;prIcon=ns" parent="1" vertex="1"> | ||
<mxGeometry x="140" y="100" width="50" height="48" as="geometry" /> | ||
</mxCell> | ||
<mxCell id="aDZf9LyQNGa_F-r6yj7t-8" value="to on-prem<br>NVR appliance<br>using local service account" style="html=1;outlineConnect=0;fillColor=#CCCCCC;strokeColor=#6881B3;gradientColor=none;gradientDirection=north;strokeWidth=2;shape=mxgraph.networks.comm_link_edge;html=1;rounded=0;labelBackgroundColor=none;" parent="1" edge="1"> | ||
<mxGeometry x="1" y="-38" width="100" height="100" relative="1" as="geometry"> | ||
<mxPoint x="425" y="288" as="sourcePoint" /> | ||
<mxPoint x="465" y="238" as="targetPoint" /> | ||
<mxPoint x="-5" y="-52" as="offset" /> | ||
</mxGeometry> | ||
</mxCell> | ||
</root> | ||
</mxGraphModel> | ||
</diagram> | ||
</mxfile> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters