Skip to content
This repository has been archived by the owner on May 24, 2023. It is now read-only.

Commit

Permalink
Merge mho-feature/test integration into develop (#3)
Browse files Browse the repository at this point in the history
TaskSupervisor is now middleware-independant for receiving tasks. 
This includes:
* Abstraction via broker_connector and broker_interface
* Add docker-compose yaml file for the OCB
* Integration of an  Interface for Orion
* Create entities folder for orion entities
* Cleanup folders wherever needed
* Unit and integration tests for the interface
* Create api folder for entities used in the TS
  • Loading branch information
maxhoerstr committed Apr 26, 2021
1 parent 44ef3d9 commit 4cda3ef
Show file tree
Hide file tree
Showing 72 changed files with 2,619 additions and 1,029 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Unit-Tests

# Run this workflow every time a new commit pushed to your repository
on: push

jobs:
unit-tests:
# Set the type of machine to run on
runs-on: ubuntu-latest

env:
PORT: 1026
steps:
# Checks out a copy of your repository on the ubuntu-latest machine
- uses: actions/checkout@v2

- uses: actions/setup-python@v2
with:
python-version: '3.8'

- name: Setup Testing
run: |
sudo apt -qq update
sudo apt -qq install -y graphviz
sudo ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime
pip3 install -r "requirements.txt"
export PYTHONIOENCODING=utf-8
- name: Test
run: |
cd test/integration_test
docker-compose down; docker-compose up --exit-code-from integration-test integration-test
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@



| :books: [Documentation](https://tte-project1.readthedocs.io/en/latest/) |
| :books: [Documentation](https://tasksupervisor.readthedocs.io/en/latest/) |
| --------------------------------------------- |

## Contents
Expand Down Expand Up @@ -83,4 +83,4 @@ python __main__.py
Comming soon

## License
[APACHE2](LICENSE) ©
[APACHE2](LICENSE) ©
Binary file added docs/img/broker_interface.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
146 changes: 146 additions & 0 deletions docs/programmers/integrate-your-broker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Integrate your broker

We provide an abstract interface so you can integrate your Broker into the *TaskSupervisor*. You can get started by checking out an existing implementation of an interface or by following the documentation on this page. Before you start creating your own interface make sure to check if there is not already one provived by us.

Currently implementations for the following brokers are available:

* Orion Context Broker

There are entites/objects that the *TaskSupervisor* needs from outside and some which he creates. If your broker wants to send a specific entity to the *TaskSupervisor* or notifiy about a topic the interface have to convert it into a representation that the *TaskSupervisor* can use. The interface also needs to convert these objects back into a broker specific format. For more information about how the needed entities have to look, check out the [interfaces](interfaces.md) page. The functionality is illustrated in the following image:

![broker_interface](../img/broker_interface.png)

Figure 1: Example with Two Brokers - Both have an own plugin.

You have to implement a set of methods in order for the *TaskSupervisor* to work properly. In the following we explain what each method should do.

**Note**: You have to take care of incoming messages yourself. For example if you use the Orion Context Broker you need to setup a webserver yourself and handle the incoming messages with an endpoint. To provide the *TaskSupervisor* with the objects you have to call the [retreive](#retreive) method of the *BrokerConnector* class.


## BrokerInterface

### Constructor

Every interface instance has a unique id and a name. Make sure to call the init method of the subclass when you implement your interface.

```python
def __init__(self, broker_connector, broker_name=""):
self.broker_id = uuid.uuid4()
self.broker_connector = broker_connector
self.broker_name = broker_name
```

### start_interface
The interface will be started from here. You could use it for example to start Threads for a Webserver. Make sure that everything is working after this method is getting called.

```python
def start_interface(self):
```

### subscribe
Subscribes to the given topic. If your broker generates a subscription id return it after success otherwise generate one. The *TaskSupervisor* will use
this id at some point to delete subscriptions so make sure that the id is valid.

```python
def subscribe(self, topic, opt_data=None, generic=False):
```

**Parameters**:

* **topic**: Will always be an api entity object. Could be converted into a broker specific format.
* **opt_data**: Optional data depending on the given topic. Check the documentation for more info.
* **generic**: Boolean, True when subscription should be generic and False if not

**Return value**:

**subscription_id**: An id which is related to the subscription

### create
Creates a new entry for the entity at the broker. Here you should convert the given entity in a specific format that your broker accepts.

```python
def create(self, entity):
```

**Parameters**:

* **entity**: An api entity object used in the TaskSupervisor.

### update
Updates the given entity at the broker. Here you should convert the given entity in a specific format that your broker accepts.

```python
def update(self, entity):
```

**Parameters**:

* **entity**: An api entity object used in the TaskSupervisor.

### delete

Handles deletion of entities and subscriptions. This method should be able to delete the entity or subscription the given id is refering to. In case of an subscription the id is the subscription id mentioned in [Subscribe](#subscribe). We distinguish entites from subscriptions so there is a boolean specifing if the id either refers to an entity or a subscription.

```python
def delete(self, id, delete_entity=True):
```

**Parameters**:

* **id**: Either an entity id or an subscription id depending on delete_entity
* **delete_entity**: Boolean, True if the id is from an entity and False if it is a subscription id


### shutdown

Gets called by the BrokerConnector when the TaskSupervisor is terminated. You can delete remaining entities and subscriptions here.

```python
def shutdown(self):
```

## BrokerConnector

### register_interface

Register the given interface in the *BrokerConnector*. It is important to register your Interface, otherwise the *TaskSupervisor* wont work.
```python
def register_interface(self,interface):
```

**Parameters**:

* **interface**: The interface which should be registered

### retreive

The given data will be passed in the *TaskSupersivor*. This method can be used inside an interface implementation when data from the Broker is received, therefore every Interface instance has a *BrokerConnector* object.

```python
def retreive(self, data, interface):
```

**Parameters**:

* **data**: Data the BrokerConnector should retreive, has to be an [API object](interfaces.md)
* **interface**: The interface which calls the retreive method



## Integrate your Interface implementation

If you are done implementing your Interface you can integrate it. We want the *TaskSupervisor* to be able to use multiple Brokers at once, so we provide a register_interface method by the *BrokerConnector* where you can register your interface. Currently you have to create and register your interface instance yourself in the main file.

Here is an excerpt of the main method as an example for the *OrionInterface* registration:

```python
....

# create and register interface instances here
orion_interface = OrionInterface(broker_connector, "Orion Context Broker Instance_1")
broker_connector.register_interface(orion_interface)

orion_interface.start_interface()

....
```
63 changes: 49 additions & 14 deletions docs/programmers/interfaces.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,74 @@
# Interfaces

In order to work as designed, the TaskSupervisor requires a Materialflow, which is specified on the TaskLanguage (Link)[]. This entity is explained below.
In order to work as designed, the TaskSupervisor requires a Materialflow, which is specified in the [TaskLanguage](https://lotlan.readthedocs.io/en/latest/index.html). Besides there are other entities that give important information. All entities which are used by the *TaskSupervisor* are explained below.

## Consuming

### Materialflow

* id : uuid
* type : Materialflow
* specification : The materialflow needs to be described in format of [LotLan](https://lotlan.readthedocs.io/). The payload needs to be URL encoded - more information can be found [@w3schools.com](https://www.w3schools.com/tags/ref_urlencode.ASP)
* ownerId : Text (Reference to the static UUID of the instance for the HMI)
* active: Boolean (Indidicates, if the Materialflow shall be processed by the TaskSupervisor OR not. Important: ONCE the HMI shutsdown, the HMI *needs* to set the materialflow to disable. The User needs to enable it manually after an restart of the system. This is required that the system is not doing something unexpected after boot).

### SensorAgent
Represents a physical sensor

* id: uuid
* measurement_type: String
* modified_time: String in ISO8601 format
* reading: List of SensorData
* san_id: String
* sensor_id: String
* sensor_manufacturer: String
* sensor_type: String (ON-OFF sensor, ..)
* units: String (unit of measurement)
* broker_ref_id: uuid of the broker interface the corresponding materialflow is from

### SensorData

* readings: List of readings (for example True or False by an ON_OFF sensor)

## Producing

### TaskSupervisorInfo
Gets created at the start of the Supervisor and provides information about the total number of started materialflows

* id: uuid
* used_materialflows: List of started materialflows
* number_of_materialflows: int, length of used_materialflows
* message: String

### MaterialflowSpecificationState
This entity provides information about the Materialflow and the processed TaskLanguage.

* id : uuid
* type : MaterialflowSpecificationState
* message : String
* refId: String (reference to the Materialflow Entity)
* ref_id: String (reference to the Materialflow Entity)
* state: number (0 == ok, -1 == error, >0 == ok with some additional information (tbd))
* broker_ref_id: uuid of the broker interface the corresponding materialflow is from

### MaterialflowUpdate
Gets created when a Materialflow starts to run

* id: uuid
* task_manager_name:
* transport_order_list:
* ref_owner_id:
* time: String in utc format
* broker_ref_id: uuid of the broker interface the corresponding materialflow is from

### TransportOrderUpdate
Once, a Transportion by an AGV starts, the TaskPlanner will create a TransportOrderUpdate.

* id : uuid of the running instance
* type : TransportOrderUpdate
* pickupFrom : string (name of the pickup location)
* deliverTo : string (name of the delivery location)
* name : string (name of this task)
* refMaterialflowUpdateId : id (where has been this transportation defined)
* refOwnerId : id (who has this materialflow/transportation defined)
* taskInfo : int (Idle = 0, WaitForStartTrigger = 1, MovingToPickupDestination = 2, WaitForLoading = 3, MovingToDeliveryDestination = 4, WaitForUnloading = 5)
* updateTime : string (last update of this entity)
* startTime : string (when it has been started)
* robotId : string of the robot
* pickup_from : String (name of the pickup location)
* deliver_to : String (name of the delivery location)
* name : String (name of this task)
* ref_materialflow_update_id : id (where has been this transportation defined)
* ref_owner_id : id (who has this materialflow/transportation defined)
* task_info : int (Idle = 0, WaitForStartTrigger = 1, MovingToPickupDestination = 2, WaitForLoading = 3, MovingToDeliveryDestination = 4, WaitForUnloading = 5)
* update_time : String (last update of this entity)
* start_time : String (when it has been started)
* robot_id : String of the robot
* broker_ref_id: uuid of the broker interface the corresponding materialflow is from
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ nav:
- Configuration: install/configuration.md
- Logs: install/logs.md
- Programmers Manual:
- Integrate your Broker: programmers/integrate-your-broker.md
- Connecting to Middlewares: programmers/connecting-to-middlewares.md
- Interfaces: programmers/interfaces.md
- Materialflow: programmers/materialflow.md
Expand Down
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ networkx
matplotlib
fiwareobjectconverter==0.1.1
lotlan-scheduler
sqlalchemy
sqlalchemy
unittest-xml-reporting
xmlrunner

0 comments on commit 4cda3ef

Please sign in to comment.