2.1. Basic Concepts and Objects in Manufacturing¶
The goal of the Internet of Things is to create a digital image of the real world and its entities. These entities act as specific material objects on one hand and abstract concepts on the other. An Internet of Things, for the field of manufacturing, generates a digital image of both the machines and tools used at the production plant, as well as the concepts that dominate the everyday production such as production orders and operations.
2.1.1. Entities from the Field of Manufacturing¶
2.1.1.1. Production Orders¶
If a certain product is to be produced at a certain point with a specified quantity. The production planning system issues the generation of a production order. The template for the production order is the routing, which contains each step (operation) required to produce the final product. The routing defines at which kind of workplace or machines the operation is to be carried out, as well as how much time and which components are required.
The scenario for the creation of a production order is as follows:
1. The company receives one or multiple customer orders to produce a certain product or wants to produce a certain quantity of it in stock.
2. A new production order with its own number is created in the ERP system which contains all the information from the routing.
3. In addition to the information in the routing, the production order also contains the specification of the quantity of the product to be produced, the so-called target quantity.
4. Finally, the delivery date is used to create a basic finish date for the production order and the result of material requirements planning is a basic start date. The latter corresponds to the point in time at which all of the components required for processing of the production order are available.
2.1.1.2. Operations¶
An operation describes a single step that is required to process a production order. Each operation produces a specific material in a specified quantity (target quantity of the operation). This involves either a material that is processed further as a component in a subsequent operation or, in the case of the last operation, by the end product of the production order.
The standard values stored in the operation include …
- The material to be manufactured.
- The target quantity is the quantity of the material to be produced. This can differ from the target quantity of the production order (for example, 4 doors that must be produced in one operation in order to finally produce an automobile).
- The quantity unit of the target quantity (for example, piece, meter, kilogram, …)
- The workplace or a group of equivalent workplaces, at which the operation is to be processed.
- The target time per unit, i.e. the time required for the production of a unit of the material to be produced.
- The target processing time is the time that is used for the entire processing time of the operation. It is the product of target quantity and target time per unit.
- The target setup time is the time scheduled for the setup of the workplace.
- The target teardown time is the time scheduled for the teardown of the workplace.
- The target move time is the time scheduled for the transfer to the next workplace.
- The target wait time is the time scheduled for e.g. cooling, drying or curing of the material to be produced.
- The components needed in order to produce the material.
- The production resources and tools (e.g. tools, equipment or documents) that are needed at the workplace in order to execute the operation.
2.1.1.2.1. Operation Phases¶
The operation phases describe the state of an operation, from the release by the ERP system to the completion and booking of the output quantities of the operation back to the ERP system.
2.1.1.3. Workplaces¶
Each operation is executed at at least one workplace. A workplace can be a simple manual workplace or a workplace with an automated production line (machine).
2.1.1.4. Workplace Groups¶
Workplaces are often lodged in ERP systems as a single workplace with a number of capacities. In Bridge API, each workplace is displayed individually and is then assigned to a specific capacity group or production line, respectively.
- Capacity groups
- are workplaces at which the same production procedure is executed and which are therefore summarized. E.g. an injection molding workplace belongs to a capacity group injection molding machines.
- Production lines
- are different workplaces that map a complete production process for a product. They use the procedures line production or mass production. Here, the different production stations are not connected by a timing (production cycle). Buffer stocks catch the time differences during processing between neighboring stations. Thus, for example, a faulty product can be removed from the production flow to be reworked, without disturbing the production process.
Each workplace can be assigned to exactly one capacity group and at most to one production line.
2.1.1.5. Staff Members¶
The staff is the production personnel, which is divided into shifts and can be assigned to the respective workplaces. Apart from his personnel data, an employee carries additional information like e.g. qualifications, posted vacation, … - that are important for the scheduling and flow of the production.
2.1.1.6. Tools¶
Production tools are needed at machine workplaces to properly complete an operation. A tool is e.g. the die casting mold of an injection molding system. The tool has a storage location, current site of operation and a lifespan. The lifespan describes how much time is left until the tool has to be replaced.
2.1.1.7. Documents¶
The documents that are required for the execution of an operation are stored in production folders. These documents usually originate from the product life cycle system. The documents can be NC programs for controlling machine tools, but also other documents such as test plans, assembly instructions or assembly sketches. If documents are changed, the IoT platform automatically creates a new version.
All documents belonging to an operation are displayed in the Shop Floor Terminal. From there, the NC programs from the production folder can also be loaded into the machine control.
2.1.1.8. Devices¶
Device refers to all devices that are connected to the IoT platform. These include in particular the programmable logic controller of the connected machines and production plants. These are permanently assigned to a specific workplace. By calling
GET/workplaces/{workplaceId}/devices
you get a list of all devices which are available at a workplace/a machine. All recorded process and sensor data can be queried for the devices.
2.1.2. The Digital Image in FORCE Bridge API¶
Bridge API maps the complete digital image of a production plant. The RESTful [1] webservice can be called directly via a web browser to interact with the resources provided in the API.
2.1.2.1. The Entry Point and the Top-Level Resources¶
A RESTful Webservice usually has only one Entry Point (API Base), from which all other outgoing resources can be retrieved from. Therefore it is important that the uniform resource indicator (URI) is correctly communicating with the REST clients, so they can find the API resources.
In this chapter the following top-level resources will be discussed in further detail:
- productionOrders/
- Production orders from the ERP system.
- operations/
- Operations of the production orders.
- workplaces/
- Workplaces (machines or manual workplaces) on which the operations are executed.
- workplaceGroups/
- Capacity groups (functionally identical machines) or production lines.
- staffMembers/
- The staff available for the execution of operations.
- tools/
- The tools available for the execution of operations.
- documents/
- Documents important to the entire production plant.
- devices/
- Devices such as the programmable logic controllers of machines.
2.1.3. Using the Application Development Kit¶
2.1.3.1. Retrieving the Entry Point¶
Java
You will need to instantiate a
BridgeAPI
class with the URL to the webservice and its credentials you want to interact with.
1 2 3 4 5 6 7 String url = "http://localhost:24080"; String user = "myUser"; String secret = "mySecret"; BridgeAPI api = new BridgeAPI(url, user, secret); /* ... */Afterwards you can retrieve the individual clients - for one of the specific top-level resource mentioned in section The Entry Point and the top-level resources - from the newly instantiated object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 IProductionOrderClient productionOrderClient = api.getProductionOrderClient(); IOperationClient operationClient = api.getOperationClient(); IWorkplaceClient workplaceClient = api.getWorkplaceClient(); IWorkplaceGroupClient workplaceGroupClient = api.getWorkplaceGroupClient(); IDeviceClient deviceClient = api.getDeviceClient(); IToolClient toolClient = api.getToolClient(); IMasterDataClient masterDataClient = api.getMasterDataClient(); IStaffMemberClient staffMemberClient = api.getStaffMemberClient(); IOperationPlanningClient planningScenarioClient = api.getPlanningScenarioClient(); IEventClient eventClient = api.getEventClient(); ICallbackClient callbackClient = api.getCallbackClient(); ICommandClient commandClient = api.getCommandClient(); ICommandClientAsync commandClientAsync = api.getCommandClientAsync(); IMachineClient machineClient = api.getMachineClient(); IMachineStateDetailClient machineStateDetailClient = api.getMachineStateDetailClient(); IStatusDefinitionClient statusDefinitionClient = api.getStatusDefinitionClient(); IMiscellaneousClient miscClient = api.getMiscellaneousClient();Note
The authorization happens automatically when a request is sent.
CURL
1 2 3 4 5 6 curl -X POST http(s)://$HOST:$PORT/ffwebservices/oauth/token \ --header "accept:application/x-www-urlencode" \ -d "client_id=$CLIENT_ID" \ -d "client_secret=$CLIENT_SECRED" \ -d "grant_type=client_credentials" \ -d "scope=read%20write"Important
Keep in mind that a valid authorization token is required for every resource access !
2.1.3.2. Retrieving Resources¶
Every resource can be retrieved as follows.
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 | final GetProductionOrdersRequest ordersRequest = new GetProductionOrdersRequest();
final Page<ProductionOrderResponse> orderResponsePage = productionOrderClient.getProductionOrders(ordersRequest);
/* Retrieve the elements of the first page */
final List<ProductionOrderResponse> orderResponses = orderResponsePage.getElements();
for (ProductionOrderResponse orderResponse : orderResponses) {
final OrderPropertiesWSModel orderProperties = orderResponse.getProperties();
final String id = orderProperties.getId();
final String description = orderProperties.getDescription();
/* ... */
}
|
CURL
curl -X POST "http(s)://$HOST:$PORT/ffwebservices/api/v2/$resource"
-H "Authorization: Bearer $TOKEN"
-H "Accept-Language: en-US"
2.1.3.3. Pagination¶
Each collection of resources may contain several thousand elements, to avoid
oversized responses, elements are split into several smaller collections.
Therefor the concept of pagination is applied. Every response is split into
several manageable pages, with maximal one hundred elements per page. The
limit
parameter can be used to set custom page sizes on the API responses
and the offset parameter to page through the data. API response return
pre-build pagination links with relations to the first
, next
,
previous
, last
and current
page and client applications are
encouraged to follow these links for pagination.
Java
With the Java ADK every collection-resource will return a Page
object,
which allows for an easy pragmatic way to browse through the pages, without
constructing the previous or next request yourself.
Note
By using the streamForward()
method, all elements can be
retrieved and processed through the Java 8 Stream API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | IOperationClient operationClient = api.getOperationClient();
/* Every response will return a Page object with the specific Operation Response */
Page<OperationResponse> operationsPage = operationClient.getOperations(new GetOperationsRequest());
/* Meta data of the current pagination */
CollectionResponse<OperationResponse> response = operationsPage.getResponse();
Pagination pagination = response.getPagination();
int limit = pagination.getLimit();
int count = pagination.getCount();
Optional<Integer> offset = pagination.getOffset();
long total = pagination.getTotal();
/* Retrieve the Elements of the current page */
List<OperationResponse> elements = operationsPage.getElements();
try {
/* Retrieve the first specific page */
SpecificPage<OperationResponse, CollectionResponse<OperationResponse>> first = operationsPage.getFirstPage();
/* Retrieve the next specific page */
SpecificPage<OperationResponse, CollectionResponse<OperationResponse>> next = operationsPage.getNextPage();
/* Retrieve the previous specific page */
SpecificPage<OperationResponse, CollectionResponse<OperationResponse>> previous = operationsPage.getPreviousPage();
/* Retrieve the last specific page */
SpecificPage<OperationResponse, CollectionResponse<OperationResponse>> last = operationsPage.getLastPage();
} catch (PageNotAvailableException ex) {
LOGGER.error(ex.getMessage());
}
/* Stream through all pages forward */
Stream<OperationResponse> operationForwardStream = operationsPage.streamForward();
/* Stream through all pages backward */
Stream<OperationResponse> operationBackwardStream = operationsPage.streamBackward();
|
CURL
..literalinclude:: /../_code/curl/
Important
Some resources update more frequently, which could lead to a circular effect, when paging though a response. To avoid this, the offset parameter is not used here, but rather additional fields are introduced.
2.1.3.3.1. Frequently Updated Resources¶
Any resource, which is updated frequently cannot be paginated with offset
parameter, as it could be that new resource entries are generated while
retrieving the next page of an previous request.
This would cause several problems as for example entries appearing twice, as
the new entries get pushed at the top of the first page.
To avoid this issue every resource which is bound to this effect, will use a different pagination mechanism. For requests the following fields dictate the pagination behavior:
paginationDirection
- The pagination direction defines how to sort the request. Either
NEXT
orPREVIOUS
from the request. Values:NEXT
(default),PREVIOUS
paginationTimestamp
- The first or last pagination timestamp of the considered period.
paginationIdentifier
- Unique identifier for pagination. Used, for example, in cases where the timestamp is not unique but is used more than once.
Every response will have the following two additional Identifiers set.
firstIdentifier
lastIdentifier
Both properties will have a unique paginationIdentifier
and
paginationTimestamp
, which is set by FORCE at the time of the request.
2.1.3.4. Embedding resources¶
Java
Sub-resources can be embedded and retrieved as follows. The following example specifically embeds the operations for the production orders.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | IProductionOrderClient productionOrderClient = api.getProductionOrderClient();
GetProductionOrdersRequest ordersRequest = new GetProductionOrdersRequest();
ordersRequest.embed(new ProductionOrderEmbed().operations(true));
Page<ProductionOrderResponse> productionOrders = productionOrderClient.getProductionOrders(ordersRequest);
List<OperationPropertiesWSModel> operations = productionOrders
.streamForward()
.flatMap(productionOrderResponse -> productionOrderResponse
.getOperations()
.stream())
.map(LinkEmbeddedWSModel::getEmbedded)
.collect(Collectors.toList());
|
curl
1 2 3 | curl -X GET "http://$HOST:$PORT/ffwebservices/api/v2/$resource?embed=$embedableResource" \
--header "accept: application/json;charset=UTF-8" \
--header "authorization: Bearer $TOKEN"
|
2.1.4. Tutorials¶
Tutorial 1
Find and list each manual labor and machine workplace.
Solution: show/hide
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | final IWorkplaceClient workplaceClient = api.getWorkplaceClient();
try {
final Page<WorkplaceResponse> workplaceResponsePage = workplaceClient.getWorkplaces(new GetWorkplacesRequest());
final Pagination pagination = workplaceResponsePage
.getResponse()
.getPagination();
final long totalWorkplaces = pagination.getTotal();
final Map<Boolean, List<WorkplaceResponse>> groups = workplaceResponsePage
.streamForward()
.collect(Collectors.partitioningBy(workplaceResponse -> workplaceResponse
.getProperties()
.isIsManualWorkplace()));
for (Map.Entry<Boolean, List<WorkplaceResponse>> entry : groups.entrySet()) {
final Boolean isManualWorkplace = entry.getKey();
final List<WorkplaceResponse> responses = entry.getValue();
final int sumWorkplaces = responses.size();
if (isManualWorkplace) {
System.out.println("Manual Workplaces: (" + sumWorkplaces + "/" + totalWorkplaces + ")");
} else {
System.out.println("Machine Workplaces: (" + sumWorkplaces + "/" + totalWorkplaces + ")");
}
responses.forEach(workplaceResponse -> {
final WorkplacePropertiesWSModel properties = workplaceResponse.getProperties();
System.out.printf("\t %5s - %s%n", properties.getNumber(), properties.getDescription());
});
System.out.println();
}
} catch (ForceAPIException e) {
LOGGER.error(e.getMessage());
}
|
Tutorial 2
Find and list all manual labor workplaces in every capacity group.
Solution: show/hide
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | final IWorkplaceGroupClient workplaceGroupClient = api.getWorkplaceGroupClient();
final IWorkplaceClient workplaceClient = api.getWorkplaceClient();
try {
final GetWorkplaceGroupsRequest workplaceGroupsRequest = new GetWorkplaceGroupsRequest();
workplaceGroupsRequest.setType(WorkplaceGroupType.CAPACITY_GROUP);
final Page<WorkplaceGroupResponse> workplaceGroupResponsePage = workplaceGroupClient.getWorkplaceGroups(workplaceGroupsRequest);
final List<String> capacityGroupIds = workplaceGroupResponsePage
.streamForward()
.map(workplaceGroups -> workplaceGroups
.getProperties()
.getId())
.collect(Collectors.toList());
if (capacityGroupIds.isEmpty()) {
System.out.println("No Capacity Groups!");
return;
}
Map<String, List<WorkplaceResponse>> capacityGroupManualWorkplaces = capacityGroupIds
.stream()
.collect(Collectors.toMap(capacityGroupId -> capacityGroupId, capacityGroupId -> {
GetWorkplacesRequest workplacesRequest = new GetWorkplacesRequest();
workplacesRequest.setWorkplaceGroupNumber(capacityGroupId);
List<WorkplaceResponse> collect = new ArrayList<>();
try {
collect.addAll(workplaceClient
.getWorkplaces(workplacesRequest)
.streamForward()
.filter(workplace -> workplace
.getProperties()
.isIsManualWorkplace())
.collect(Collectors.toList()));
} catch (ForceAPIException e) {
LOGGER.error(e.getMessage());
}
return collect;
}));
System.out.println("Manual Workplaces for");
capacityGroupManualWorkplaces.forEach((capacityGroupId, workplaceResponses) -> {
System.out.printf("\tCapacity Group [%s]\n", capacityGroupId);
workplaceResponses
.stream()
.map(WorkplaceResponse::getProperties)
.forEach(p -> System.out.printf("\t\tWorkplace %s [%s]\n", p.getNumber(), p.getId()));
});
} catch (ForceAPIException e1) {
e1.printStackTrace();
}
|
/../_code/java/src/main/java/com/forcam/apps/ManualLaborWorkplacesInCapacityGroups.java
Tutorial 3
Find all production orders of the current week for which all operations are completed.
Solution: show/hide
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | IProductionOrderClient productionOrderClient = api.getProductionOrderClient();
Interval currentWeek = Interval.getWeekInterval(1, 0);
try {
GetProductionOrdersRequest ordersRequest = new GetProductionOrdersRequest();
ordersRequest.setStartDate(currentWeek.getStartDate());
ordersRequest.setEndDate(currentWeek.getEndDate());
ordersRequest.embed(new ProductionOrderEmbed().operations(true));
Page<ProductionOrderResponse> orderResponses = productionOrderClient.getProductionOrders(ordersRequest);
List<ProductionOrderResponse> productionOrderResponses = orderResponses.getElements();
List<ProductionOrderResponse> completedProductionOrdersResponses = productionOrderResponses
.stream()
.filter(productionOrderResponse -> productionOrderResponse
.getOperations()
.stream()
.map(LinkEmbeddedWSModel::getEmbedded)
.noneMatch(operationProperties -> operationProperties.getOperationPhaseId() != OperationPhase.COMPLETED))
.collect(Collectors.toList());
printProductionOrders(completedProductionOrdersResponses);
} catch (ForceAPIException e) {
LOGGER.error(e.getMessage());
}
|
/../_code/java/src/main/java/com/forcam/apps/CompletedProductionOrders.java
Tutorial 4
Find which operating states all workplaces reside in and what percentage of workplaces reside in the operating state production.
Solution: show/hide
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | final IWorkplaceClient workplaceClient = api.getWorkplaceClient();
try {
final GetWorkplacesRequest workplacesRequest = new GetWorkplacesRequest();
final Page<WorkplaceResponse> workplaceResponsePage = workplaceClient.getWorkplaces(workplacesRequest);
final Pagination pagination = workplaceResponsePage
.getResponse()
.getPagination();
final long totalNumberOfWorkplaces = pagination.getTotal();
workplaceResponsePage
.streamBackward()
.map(WorkplaceResponse::getProperties)
.forEach(workplace -> System.out.printf("Workplace %s: %s%n",
workplace.getNumber(),
workplace
.getOperatingState()
.getDescription()));
final long numberOfWorkplacesInProduction = workplaceResponsePage
.streamForward()
.map(WorkplaceResponse::getProperties)
.filter(properties -> properties
.getOperatingState()
.getWorkplaceStateId()
.equals(WorkplaceState.PRODUCTION))
.count();
float workplacesInProduction = ((float) numberOfWorkplacesInProduction / (float) totalNumberOfWorkplaces) * 100;
System.out.printf("Workplaces in Production %.2f %%%n", workplacesInProduction);
} catch (ForceAPIException e) {
LOGGER.error(e.getMessage());
}
|
/../_code/java/src/main/java/com/forcam/apps/OperatingStatesOfWorkplaces.java
Tutorial 5
Figure out which operation phase each operation currently resides in and calculate the percentage of how many running operations are in the phase setup and in the phase processing respectively.
Solution: show/hide
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | final IOperationClient operationClient = api.getOperationClient();
try {
final GetOperationsRequest operationsRequest = new GetOperationsRequest();
final Page<OperationResponse> operationResponsePage = operationClient.getOperations(operationsRequest);
final Pagination pagination = operationResponsePage
.getResponse()
.getPagination();
final long totalNumberOfOperations = pagination.getTotal();
System.out.println("Number of Operations: " + totalNumberOfOperations);
final Map<OperationPhase, List<OperationResponse>> groups = operationResponsePage
.streamForward()
.collect(Collectors.groupingBy(e -> e
.getProperties()
.getOperationPhaseId()));
int numberOfOperationsInSetup = 0;
int numberOfOperationsInProcessing = 0;
if (groups.containsKey(OperationPhase.SETUP)) {
numberOfOperationsInSetup = groups
.get(OperationPhase.SETUP)
.size();
}
if (groups.containsKey(OperationPhase.PROCESSING)) {
numberOfOperationsInProcessing = groups
.get(OperationPhase.PROCESSING)
.size();
}
float percentageOperationsInProcessing = ((float) numberOfOperationsInProcessing / totalNumberOfOperations) * 100;
float percentageOperationsInSetup = ((float) numberOfOperationsInSetup / totalNumberOfOperations) * 100;
System.out.printf("Percentage of Operations in Phase Setup: %.2f %%%n", percentageOperationsInSetup);
System.out.printf("Percentage of Operations in Phase Processing: %.2f %%%n", percentageOperationsInProcessing);
} catch (ForceAPIException e) {
LOGGER.error(e.getMessage());
}
|
/../_code/java/src/main/java/com/forcam/apps/OperationPhasesOfOperations.java
Footnotes
[1] | RESTful are applications or web services which offer states and functionalities as a set of resources and which can also be changed via them. |