# Server and client implementation This chapter describes the **project-defined common robot-control interface implemented for the MG400** using the provided `src/dobot/server_fastapi/` sources. `ese774_frame` transports calls; it does not define the robot-specific control contract. ## Control paths - Local: application → `DobotCtrl` → `DobotTcp` → MG400. - Remote: application → `SyncDobotClient` / `AsyncDobotClient` / `DeviceProxy` → `ese774_frame` → server-side `DobotCtrl` → `DobotTcp` → MG400. The server configures `FastApiServer` with `device_cls=DobotCtrl`, `router_cls=None`, `api_spec=None`, and `object_name="dobot"`. This uses the framework's automatic dispatch without requiring a custom router or API specification. ## Starting the server The packaged `dobot.server_fastapi.server` module constructs its server from the `Config` class attributes. Defaults include `SERVER_IP="127.0.0.1"`, `SERVER_PORT=8000`, and `DOBOT_IP="192.168.1.6"`. ```bash python -m dobot.server_fastapi.server ``` **Important:** The module constructs its `FastApiServer` object at import time. Calling `Config.load_yaml()` in a different Python process does not configure this server process. To customize settings, load the configuration **in the same process, before creating the server**. The provided server entry point does not automatically load a YAML file. The following is a **separate launcher script** that explicitly loads YAML before constructing the server. An absolute path is used because `Config.load_yaml()` resolves relative paths against the calling source file. ```python from pathlib import Path from dobot.config import Config from dobot.dobot_ctrl import DobotCtrl from ese774_frame import FastApiServer from x_logger import XLogger Config.load_yaml(Path(__file__).resolve().parent / "config_dobot_server.yaml") logger = XLogger(log_level=Config.LOGGER_LEVEL, logger_name=Config.SERVER_LOGGER_NAME) server = FastApiServer( device_cls=DobotCtrl, router_cls=None, config=Config, api_spec=None, object_name="dobot", device_kwargs={"dobot_ip": Config.DOBOT_IP, "instance_name": Config.INSTANCE_NAME}, logger=logger, logger_name=Config.SERVER_LOGGER_NAME, lifespan_msg_prefix="DOBOT", ) server.run(host=Config.SERVER_IP, port=Config.SERVER_PORT) ``` ```yaml SERVER_IP: "127.0.0.1" SERVER_PORT: 8000 DOBOT_IP: "192.168.1.6" INSTANCE_NAME: "Ctrl" LOGGER_LEVEL: "INFO" ``` `SERVER_IP` is the HTTP server bind address; `DOBOT_IP` is the robot controller address. They are not interchangeable. Exposing a motion-capable HTTP service requires separate network and access-control measures. ## Synchronous and asynchronous clients `SyncDobotClient` extends `SyncDeviceClient`; `AsyncDobotClient` extends `AsyncDeviceClient`. Both pass `object_name="dobot"` and `api_spec=None` to their base class. ```python from dobot.server_fastapi.client_sync import SyncDobotClient client = SyncDobotClient(server_ip="127.0.0.1", server_port=8000) ``` ```python from dobot.server_fastapi.client_async import AsyncDobotClient client = AsyncDobotClient(server_ip="127.0.0.1", server_port=8000) ``` **Important:** Both constructors default `server_ip` and `server_port` to `None`. Without a `config` argument, the current implementation assembles `http://None:None`. Pass explicit connection parameters or a `Config` instance. When `config` is provided, its `SERVER_IP` and `SERVER_PORT` take precedence over the individual parameters. `server_fastapi/__init__.py` registers `DeviceProxy` under `DobotCtrl` and the alias `dobot`, with `default_async_mode=True`. This **does not mean that a robot motion has completed**: asynchronous HTTP calls and robot motion completion are separate concerns. ## Scope of verification These examples reproduce initialization patterns from the supplied Python sources. The actual MG400, deployment environment, installed `ese774_frame` version, and physical motion require separate verification. Do not use an HTTP response as the sole safety-stop mechanism.