Alright, so we totally aced the GSoC Phase 1 evaluations! Now that we’ve got a generic Hydra Server up and running, things are getting even more exciting. We’re building a Forestry Patrol Simulation using a bunch of Hydra servers and clients. Think drones, but for saving forests!

General Idea

We’re cooking up an application that simulates a whole flock of drones. Their main gig? To keep an eye out for fires or weird hot spots in a given area using their infrared sensors. Pretty cool, right?

The simulation will have these 3 main components -

  • A bunch of flying drones (N, to be exact!)
  • A centralized Hydra server to keep tabs on everything
  • A snazzy Javascript Application for the GUI part
  • And, of course, some docking stations for charging (which might just be the central server’s spot!)

Design principles and some general ideas

Drones

We need a whole flock of N flying drones (these are professional drones, mind you, for forestry patrol!).

For a basic setup, we decided that each Drone and a Central Server (or Controller) would have a two-way communication channel. So, info and signals can zip back and forth between a single Drone and the Controller, but not directly between Drones. This keeps things tidy.

Drones will act as both Hydra Servers and Hydra Clients (we call ‘em Hybrids!). They’ll have some exposed endpoints where other Hydra Clients can send orders or ask for updates. But they also have their own Hydra Client superpowers, letting them send info and signals to the Controller by calling its Hydra API.

These drones will have endpoints like https://drone123/api/order where the Controller can send orders using POST/PUT requests. When they get new orders, drones will act on them right away, unless they need to improvise (they’re smart, after all!).

Another cool thing is that Drones can ask for info about other Drones by hitting up the Controller using GET https://controller/api/drone or GET https://controller/api/status/<drone_id>. Drones have a standard behavior set by the simulation, and they’ll stick to it unless an order overrides it. They’ll just keep moving, collecting data, heading back to the recharging station, juicing up, and taking off again.

Main Functions

As I mentioned, these Drones are pretty smart, acting as both semi-intelligent Hydra Servers and Clients. Here’s what they can do:

  • Drones can get commands from the server (could be something as simple as the central server sending orders to an endpoint like PUT https://drone123/api/order/<order_id>). These commands can include stuff like speed and direction, plus any extra attributes. When a drone gets an order, it acts on it right away, unless there’s a good reason to do something else. These orders are sequential and stack up in the Drone’s limited in-memory queue. If the “order endpoint” is used, the Drone will respond with a Hydra: Status like “204 Accepted” or “409 Conflict” – basically, telling the server if it got the message or not.
  • A Drone broadcasts its status via an HTTP response from its Hydra Server at an endpoint like GET https://drone123/api/status, so the Controller can always check in on it.
  • Drones send their sensor data stream by making requests to the server at an endpoint like POST https://controller/drone/<drone_id/data.
  • Each drone gets a unique ID and has other cool parameters like speed and battery life.
  • Drones can’t chat directly with other drones or tell them what to do. They have to go through the central server. So, if a drone wants to know about nearby drones, it just asks the server via GET https://controller/drone/<drone_id/status.
  • Drones are smart enough to decide when they need to charge. If they do, they’ll override server commands, but only after sending a log of their status to the central server. Safety first!
  • And of course, drones follow some basic rules (like, you know, not crashing into each other!).

Supported Classes and their Props for Drone ApiDocumentation

### We only need to replace the subsystem_parsed_classes by this and the new hydra server for drones API is ready.
parsed_classes = [
    {
         "@id":"https://schema.org/Order",
         "@type":"hydra:Class",
         "title":"Order",
         "description":"Handle orders from the central server.",
         "supportedOperation":[
            {
                "statusCodes": [
                    {
                        "code": 200,
                        "description": "Order successfully recieved."
                    }
                ],
                "@type": "https://schema.org/UpdateAction",
                "returns": "https://schema.org/Order",
                "label": "Recieves orders from the Central Server",
                "method": "PUT",
                "@id": "_:Order_create",
                "description": "null",
                "expects": "https://schema.org/Order"
            },
                        {
                            "statusCodes": [
                                {
                                    "code": 404,
                                    "description": "If no orders were found."
                                }
                            ],
                            "@type": "hydra:Operation",
                            "returns": "https://schema.org/Order",
                            "label": "Retrieves all orders from the central server.",
                            "method": "GET",
                            "@id": "_:Order_retrieve",
                            "description": "null",
                            "expects": "null"
                        }
         ],
         "supportedProperty":[

            {  "@type": "SupportedProperty",
               "property":"https://schema.org/geo",
               "title":"Destination",
               "hydra:description":"Coordinates of the new destination",
               "required":True,
               "readonly":False,
               "writeonly":False
            },
            {  "@type": "SupportedProperty",
               "property":"https://auto.schema.org/speed",
               "title":"Speed",
               "hydra:description":"Speed of Drone in Km/h",
               "required":True,
               "readonly":False,
               "writeonly":False
            },
         ]
      },
]

Client part

Every drone will have a Client part alongside its Hydra Server Part. The cool thing is, the client part won’t know anything about the server endpoints except for the main entrypoint to the server (this is super important for showing off Hydra’s capabilities!). The client will have to figure out the rest on its own. A Drone Client will handle a couple of things:

  • It’ll send POST requests to the central server to update the drone’s status whenever it changes or if the drone needs to override server orders.
  • It’ll also send POST requests to the central server to submit data streams from its sensors. This only happens when the drone’s status is [Progress: Analysing]. Once the data stream is successfully sent, the drone moves to its next destination. After the server gets the sensor data, it’ll send new orders to the drone (either automatically or manually by a user).

Central server

The central server is a Hydra-based API server that acts as the main data hub and control center for all the drones. It also has a client part, just like the drones, which it uses to send orders to different drones. It’s basically the brain of the operation!

Main Functions

The central server is pretty busy, handling a few key tasks:

  • It acts as a central database for all the drones, storing their logs and sensor data. Drones will send POST/PUT requests at fixed intervals or when their status changes.
  • It has an endpoint to serve all the drone logs in a human-readable format for the GUI.
  • The server sends orders to all the drones, making them coordinate and cover the entire area of interest (the server’s client side handles sending these orders).
  • It acts as a middleman if different drones need to talk to each other. For example, if a drone wants to know where all the nearby drones are, it asks the server.
  • It’s also the main docking station where drones go to recharge. Think of it as their home base!
  • retrieve_drone_list() [GET][POST][/api/drones] - Will return list of all available drones {DroneCollection}. POST can be used to add new drones. For example /drones/123 will return Drone 123’s specs and details.

  • submit_status(drone_id, status) [GET][POST] [/api/status] - Will be used by the client side of drones to update their status using POST requests. GET can be used to list all the status submissions {statusCollection}. Status objects will include the following
  • submit_data(drone_id, data) [GET][POST] [/api/datastream] - Will be used by the client side of drones to send the analyzed data stream from sensors to the server. A simple GET request will return all the submitted datastreams {datastreamCollection}. POST requests can be used to submit new data streams. Datastream will include the following ( for simplicity of the simulation the drones will only have a temperature sensor and GPS for location)
  • get_latest_logs() [GET] [/api/logs]{logsCollection} - Will be used to serve the logs of past several seconds (say 5 seconds), logs will be used by the javascript application to display the progress on Map.

  • submit_message() [GET][POST] [/api/message] - An endpoint for the monitoring/GUI application, to receive commands issued by the end-user in the shape of a string that has to be sanitized, parsed, processed into the right sequence of API calls that have then to be dispatched. GET can be used to retrieve all the submitted messages {messageCollection}.

  • **issue_order(drone_id) [GET][POST][/api/orders/] {Order}** - If the order is issued automatically by the server like continue moving, then the request will be get and the server side client will be notified. The client will then take that order to make a `POST` request to the drone. Orders can also be issued directly without NLP using `POST` requests at `/api/orders/`. Upon receiving a new order the client will pass the order to the drone.

Supported Classes and their Props for APIDocumentation

See this Gist

Client Part

The central server also has a Client part. This client part is pretty cool because it doesn’t need to know all the nitty-gritty details about each drone’s endpoints, just the main entry point to each drone (this is super important for showing off Hydra’s capabilities!). It figures out the rest on its own. The Server Client is mainly used for one thing:

  • It sends new orders to each drone using POST requests.

Javascript Monitoring Application

The Javascript Application serves the following purposes -

  • It uses logs from the central server to display the progress on a map in pseudo-realtime.
  • Can act as a control center to issue commands to different drones. - The user will write commands in NLP format, the commands will be sent to the server at /message via POST requests where further processing will be done. Once the processing is done, new orders will be available at issue_order/<drone_id> that can be sent to the drones.

Deploying The Simulation

The simulation is deployed using different Docker containers:

  • 1 container small to simulate the central server (controller)
  • 1 container small for the monitoring Javascript client
  • Multiple tiny containers to simulate the drones

These components interact with a private network and are reachable using aliases:

  • A’s HTTP interface is reachable at http://central (central alias maps to port 8000)
  • B’s application is reachable at http://localhost:8080
  • C’s HTTP interfaces are reachable at http://drone:port (e.g http://drone:8001 maps to port)

If you want a sneak to the project, here’s the Github repo.