The software
used for controlling the UDP-connected VME rack, is a full-stack web application built with svelte for the frontend, and FastAPI for the backend. Because the software is web based, the GUI can be accessed on most devices including smartphones, and could be accessed remotely with a proper VPN setup.
Architecture
Inside the /frontend
folder, the web-based user interface is defined. By running a command in this folder, all code to operate this web-based software is compiled into several files which are placed in /backend/dbay_control/
. The backend may then load and ‘serve’ this code. If you look inside the package.json
file in frontend
, you’ll see that npm run build
has been customized to compile the code with vite build
and copy it to /backend/snspd_bias_control/
. So anytime new frontend functionality is added and it’s time to get it working with the backend, this command needs to be run.
Deprecated
Frontend Development
The frontend code may be previewed and improved without interacting with the python backend. That is, the frontend is ‘served’ by node (a javascript runtime) instead of the the python backend. The only difference is that the frontend will load a dummy ‘fallback state’ that doesn’t correspond to any state shared with the python backend.
node and npm need to be installed
cd frontend
npm install
npm run dev
Building the ‘look’ of a new module in the GUI is fastest by adding it to the fallback state located in frontend/src/fallbackState.ts
, and watching for changes while the npm run dev
development server is running.
Deprecated
Running the python server
Using npm run dev
in the /frontend
folder does not make use of the python backend at all. The ‘backend’ is needed to rout commands from the web browser to the hardware, and to be the official source of truth for the ‘state’ of the device bay system (what modules are plugged in, what voltages and channels are activated or powered, etc.)
If the frontend had been updated in some way, it will have to be recompiled by running npm run build
in the frontend folder, thereby populating /backend/snspd_bias_control/
with new html and javascript to serve.
Use anaconda or pip to install dependencies. For pip:
pip install --no-cache-dir --upgrade -r requirements.txt
cd backend
python main.py
Development Process
To create the software for a new module, code in both /frontend
and /backend
must be added. This is an iterative process that often begins with defining what structs or data packets will be sent and received from what endpoints (e.g. /dac16D/vsource/
). Here’s some steps that don’t necessarily need to happen in this order:
- Create a new ui file
{module_name}.svelte
and core logic file{module_name}_data.svelte.ts
infrontend/src/lib/modules_dbay
. The{module_name}_data.svelte.ts
may make use of the ‘addon’ classes defined infrontend/src/lib/addons
. Thefrontend/src/modules_day/index.svelte.ts
file must also be updated. Include the imports:
import { default as {module_name}_component } from './{module_name}.svelte'
import { {module_name} } from './{module_name}_data.svelte'
And add the new module/module_component to the components
and modules
objects defined below in the same file.
Module data structure.
Module state is defined with a simple hierarchy of dataclasses (python) or objects (javascript/typescript). It’s easiest to see the basic structure in backend/state.py
class IModule(BaseModel):
core: Core
vsource: IVsourceAddon | None
vsense: IVsenseAddon | None
Both IVsourceAddon
and IVsenseAddon
contain a list of channels, each of which has a number of associated properties like index
, heading_text
, and activated
.
- Create a new python file in
backend/modules/
with name{module_name}.py
. This python file may import datastructures frombackend/addons
. It must define arouter
usingAPIRouter(prefix="/{module_name}", ...)
imported fromfastapi
. This router must also be imported into themain.py
file (e.g. withfrom .modules import {module_name}
), and ‘connected’ with the rest of the application usingapp.include_router({module_name}.router)
.
NOTE: a library called pydantic2ts
is used to transform the datastructures found in the addon files like /backend/addons/vsource.py
to interface.ts
files found in frontend/src/lib/addons
(Note: I’m using a fork of the original pydantic2ts
library that supports pydantic >= 2.0). This ensures that the frontend and backend code agree on the ‘shape’ of data packets sent between them. If files like /backend/addons/vsource.py
are changed, or new datastructures are defined for get/put requests, then backend/pydantic_to_typescript.py
should be rerun and possibly updated. Because pydantic2ts
converts from python to typescript, it makes sense to (1) get your data strucutres defined first in python with pydantic classes, (2) modify backend/pydantic_to_typescript.py
to create a corresponding interface.ts
file somewhere inside frontend/
, and (3) work on the frontend code to use the datastructure from the newly modified/created interface.ts
file.
Deprecated
Docker Development Notes
Commands and notes related to building the docker container
The uploaded docker image was built on an ARM-based macbook. In order to build an image that will run on an x86-64 platform, you have to use buildx
, a feature for multi-architecture builds.
# Create a new builder instance
docker buildx create --name mybuilder
# Switch to the new builder instance
docker buildx use mybuilder
# Start up the builder instance
docker buildx inspect --bootstrap
# build the image and pull it to the local docker desktop (?)
docker buildx build --platform linux/amd64 -t sansseriff/dbay . --load
Then with the docker desktop utility, publish the image to dockerhub. This way works without signing issues. If I used the —push option for that last command, then the built container had signing issues. I would get this error when trying to pull:
Trying to pull repository docker.io/sansseriff/dbay ...
missing signature key