Skip to content

Commit

Permalink
Improving the WebUI
Browse files Browse the repository at this point in the history
  • Loading branch information
jlegrand62 committed Jun 13, 2024
1 parent 6997a32 commit 1d854c8
Show file tree
Hide file tree
Showing 4 changed files with 312 additions and 149 deletions.
6 changes: 1 addition & 5 deletions src/plantimager/webui/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ def parsing():
app_args.add_argument('--port', type=int, default=REST_API_PORT,
help="port used to serve the application")

hw_args = parser.add_argument_group("Hardware options")
hw_args.add_argument('--cnc_dev', type=str, default="/dev/ttyACM0")
hw_args.add_argument('--gimbal_dev', type=str, default="/dev/ttyACM1")

return parser


Expand Down Expand Up @@ -66,7 +62,7 @@ def main(url, port):
href="/scan")),
dbc.NavItem(
dbc.NavLink("PlantDB", style={'color': "#f3f3f3"},
href="/plantdb_api")),
href="/config")),
dbc.NavItem(
dbc.NavLink("Tutorial", style={'color': "#f3f3f3"},
href="https://docs.romi-project.eu/plant_imager/tutorials/reconstruct_scan/")),
Expand Down
204 changes: 204 additions & 0 deletions src/plantimager/webui/pages/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import dash
import dash_bootstrap_components as dbc
from dash import Input
from dash import Output
from dash import State
from dash import callback
from dash import dcc
from dash import html

from plantdb.rest_api_client import REST_API_PORT
from plantdb.rest_api_client import REST_API_URL
from plantdb.rest_api_client import test_db_availability
from plantimager.webui.utils import get_dataset_dict

global dataset_dict

dash.register_page(__name__, path="/config")

# -----------------------------------------------------------------------------
# Forms and callbacks to connect to the PlantDB REST API.
# -----------------------------------------------------------------------------
rest_api_card = dbc.Card(
id="rest-api-card",
children=[
dbc.CardHeader("PlantDB REST API"),
dbc.CardBody([
dbc.Row([
# - Input form to specify REST API URL:
dbc.Col([
dbc.Label("REST API URL:"),
dbc.Input(id="ip-address", type="url", value=REST_API_URL),
dbc.FormText(f"Use '{REST_API_URL}' for a local database.", color="secondary"),
], width=8, ),
# - Input form to specify REST API port:
dbc.Col([
dbc.Label("REST API port:"),
dbc.Input(id="ip-port", type="text", value=REST_API_PORT),
dbc.FormText(f"Should be '{REST_API_PORT}' by default.", color="secondary"),
], width=4, ),
]),
]),
dbc.CardFooter([
dbc.Row([
# - Test connexion to REST API button
dbc.Col([
dbc.Button("Test connexion", id="connect-button", color="primary"),
dbc.FormText(
dbc.Alert([
html.I(className="bi bi-info-circle-fill me-2"),
"Unknown server availability."
], color="info"),
id="connexion-status"),
], align="center", ),
# - Load scans from REST API button
dbc.Col([
dbc.Button("Load datasets", id="load-button", color="primary", disabled=True),
dbc.FormText(
dbc.Alert([
html.I(className="bi bi-info-circle-fill me-2"),
"Undefined list of datasets."
], color="info"),
id="load-status"),
], align="center", )
])
], style={"align-content": 'center'})

]
)

scanner_card = [
dbc.Card(
id="scanner-card",
children=[
dbc.CardHeader("Scanner configuration"),
dbc.CardBody([
dbc.Row([
# - Input form to specify CNC serial port:
dbc.Col([
dbc.Label("CNC serial port:"),
dbc.Input(id="cnc-port-input", type="text", value="/dev/ttyACM0",
placeholder='Enter a serial port...'),
dbc.FormText("Should be something like `/dev/ttyACM0`", color="secondary"),
], width=8, ),
# - Input form to specify Gimbal serial port:
dbc.Col([
dbc.Label("Gimbal serial port:"),
dbc.Input(id="gimbal-port-input", type="text", value="/dev/ttyACM1",
placeholder='Enter a serial port...'),
dbc.FormText("Should be something like `/dev/ttyACM1`", color="secondary"),
], width=8, ),
# - Input form to specify Camera URL:
dbc.Col([
dbc.Label("Camera URL:"),
dbc.Input(id="camera-url-input", type="url", value="192.168.122.1:10000",
placeholder='Enter a valid URL...'),
dbc.FormText("Should be something like `192.168.122.1:10000`", color="secondary"),
], width=8, ),
])
]),
dbc.CardFooter([dbc.Row([
dbc.Col([
dbc.Button("Export settings", id="hw-settings-button")
]),
dbc.Col([
dbc.Button("Initialize scanner", id="hw-init-button")
])
])
])
]
)
]

layout = html.Div([
dcc.Store(id='cnc-port', data=None),
dcc.Store(id='gimbal-port', data=None),
dcc.Store(id='camera-url', data=None),
dcc.Store(id='scanner-obj', data=None),
# Content of the scan page:
dbc.Button("< Back", href="/", style={'width': '200px'}),
html.Br(),
dbc.Row(
id="conf-page-content",
children=[
dbc.Col(rest_api_card, md=6),
dbc.Col(scanner_card, md=6),
]
)
])


@callback(Output('connexion-status', 'children'),
Output('load-button', 'disabled'),
Output('rest-api-host', 'data'),
Output('rest-api-port', 'data'),
Input('connect-button', 'n_clicks'),
State('ip-address', 'value'),
State('ip-port', 'value'))
def test_connect(n_clicks, host, port):
if test_db_availability(host, int(port)):
res = dbc.Alert([
html.I(className="bi bi-check-circle-fill me-2"), "Server available.",
], color="success", )
else:
res = dbc.Alert([
html.I(className="bi bi-x-octagon-fill me-2"), f"Server {host}:{port} unavailable!",
], color="danger", )
return res, not res, host, port


@callback(Output('load-status', 'children'),
Output('dataset-dict', 'data'),
Input('load-button', 'n_clicks'),
State('ip-address', 'value'),
State('ip-port', 'value'))
def update_db(n_clicks, host, port):
dataset_dict = get_dataset_dict(host, port)
if len(dataset_dict) > 0:
res = dbc.Alert([
html.I(className="bi bi-check-circle-fill me-2"), f"Loaded {len(dataset_dict)} dataset.",
], color="success", )
else:
res = dbc.Alert([
html.I(className="bi bi-x-octagon-fill me-2"), f"Could not load any dataset!",
], color="danger", )
return res, dataset_dict


@callback(Output('cnc-port', 'data'),
Output('gimbal-port', 'data'),
Output('camera-url', 'data'),
Input('hw-settings-button', 'n_clicks'),
State('cnc-port-input', 'value'),
State('gimbal-port-input', 'value'),
State('camera-url-input', 'value'),
prevent_initial_call=True)
def set_hw_config(cnc_port, gimbal_port, camera_url):
return cnc_port, gimbal_port, camera_url


@callback(Output('scanner-obj', 'data'),
Input('hw-init-button', 'n_clicks'),
State('cnc-port', 'data'),
State('gimbal-port', 'data'),
State('camera-url', 'data'),
prevent_initial_call=True)
def init_scanner(n_clicks, cnc_port, gimbal_port, camera_url):
from plantimager.scanner import Scanner
from plantimager.dummy import CNC
from plantimager.dummy import Gimbal
from plantimager.dummy import Camera
cnc = CNC()
gimbal = Gimbal()
camera = Camera()
return Scanner(cnc, gimbal, camera)
# from plantimager.grbl import CNC
# from plantimager.blgimbal import Gimbal
# from plantimager.urlcam import Camera
# cnc = CNC(cnc_port, x_lims=[0, 800], y_lims=[0, 800], z_lims=[0, 100])
# gimbal = Gimbal(gimbal_port, has_tilt=False, invert_rotation=True)
# camera = Camera(camera_url)
# return Scanner(cnc, gimbal, camera)
129 changes: 0 additions & 129 deletions src/plantimager/webui/pages/plantdb_api.py

This file was deleted.

Loading

0 comments on commit 1d854c8

Please sign in to comment.