Printer Technical Guide
This document describes how to use the software components of the Bergstein DIGI Gen3 Printer.
DIGI HMI
The main interface of the printer is the DIGI HMI app. This app manages and directs printer process commands for the printer. Like reading a Job file, addressing print hardware and providing data to the Controller/PLC.
The app runs in Windows under the standard location: "C:/DigiHMI" (app folder). Application data, like machine variables and recipes, are stored separately at the standard location: "C:\ProgramData\Bergstein Digital BV\Bergstein DIGI Manager" (data folder). Application settings are loaded through an 'appsettings' file at standard location: "C:/DigiHMI/appsettings.json".
Under all circumstances should the HMI app be running for the printer to function. The DIGI HMI app must have read and write access to both app & data folders.
Requirements
The operating system must be Windows 11 or higher. The system specification shall be: Recommended:
- 8 Core CPU (or more) at 2.5GHZ (or higher)
- 16 GB RAM (or more)
- 256 GB SSD storage (or more)
- At least one USB 3.0 (or higher)
Also the following software packages must be installed:
- Latest C++ Redistributables: see https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170#latest-supported-redistributable-version .
- Latest Advantech ADAM USB-to-UART driver: https://www.advantech.com/en/support/details/driver?id=1-13U9QTV .
Settings
Various app settings are encapsulated in the 'appsettings.json' file.
If you want to change it, its advised to have knowledge about .JSON files (e.g. see https://en.wikipedia.org/wiki/JSON).
Before changing its recommended to make a copy of this file so it can be restored when something goes wrong.
What follows is a breakdown of the most common options in this settings file;
| Key | Default | Comment |
|---|---|---|
| JobHandlerOptions__NumberOfSides | 0 | If the printer has a jig capable of printer multiple sides, else value is 0 |
| JobHandlerOptions__NumberOfActuatorPositionsPerSide | 0 | If the printer has a jig with at least one actuator, else value is 0 |
| FeatureFlags__PrinterControllerApiEnabled | true | If true, exposes the HTTP API |
| FeatureFlags__DeveloperMode | false | If true, exposes the HTTP API developer page at '/swagger' |
| FeatureFlags__DetailedLogging | true | If true, logs debug level messages |
| FeatureFlags__HTTPS | true | If true, enforces HTTPS on the API (e.g. HTTP2 with TLS1.3) |
| FeatureFlags__SimulatedController | false | If true, mocks the API with a simulated controller behavior |
| FeatureFlags__SimulatedControllerRandomBehavior | false | If true, and the SimulatedController is true, the bahavior is randomized (random stops, errors and messages) |
| FeatureFlags__SimulatedControllerControllerMode | false | Deprecated |
| FeatureFlags__SimulatedControllerWorkerMode | false | Deprecated |
| FeatureFlags__AllowRemoteStart | false | If true, allows the 'Start' API command to take effect; start JobQueue processing |
| FeatureFlags__AllowRemoteStop | false | If true, allows the 'Stop' API command to take effect; stop JobQueue processing |
| FeatureFlags__WorkerModeEnabled | false | Deprecated |
| ServerOptions__AllowedOrigins | ["*"] | A list of origin URL strings. Sets the HTTP allow-origin whitelist. A "*" indicates a wild card and allows all API client origins |
| ServerOptions__HttpsRedirectionPort | 6001 | The HTTPS port which non-HTTPS traffic is redirected to if 'ServerOptions__RedirectToHttps' is set to 'true' |
| ServerOptions__MaximumNumberOfGrpcStreamingClients | 5 | The maximum number of unique(concurrent) client connection that can start a gRPC server stream subscription. |
| Kestrel__Endpoints__Https1__Url | "https://*:6001" | The address/URL of the HTTPS endpoint. |
| Kestrel__Certificates__Default__Path | "C:\Temp\ssl\certificate.pfx" | The path to the '.pfx' file of the X509 certificate to use for the HTTP API |
| Kestrel__Certificates__Default__Password | "" | The password of the X509 certificate |
API
External integration can be achieved by using its HTTP API, which comes in two forms; gRPC & JSON REST. The API is exposed as HTTPS on port 6001 using TLS1.3 . A self signed X509 certificates is used when the printer is delivered. For optimal security its advised to provide your own certificate instead of the supplied self-signed-certificate.
The capabilities of the API are described in comments in the IDL (Interface-Definition-Language) of the API. For gRPC this is the corresponding protobuf file: https://developer.bergstein.com/api/printer-gen3/v1.4.0/grpc/bergstein.digi.printer.proto . For JSON REST this is the corresponding OpenAPI file: https://developer.bergstein.com/api/printer-gen3/v1.4.0/rest/bergstein.digi.printer.json .
The gRPC API is our native interface, the JSON REST API is transcoded from that API and lacks the capability to transcode server streams. So please consult the following table in your decision of API to use;
| Endpoint | Comment | gRPC | REST |
|---|---|---|---|
| PrinterControllerService.Start | Starts the printer | ✅ | ✅ |
| PrinterControllerService.Stop | ✅ | ✅ | |
| PrinterControllerService.SendPrintJob | Sends a DJOB print file to the printer | ✅ | ✅ |
| PrintControllerService.GetPrintJobStatus | Gets the state of the current active job | ✅ | ✅ |
| PrinterControllerService.GetPrinterState | Gets the state of the printer | ✅ | ✅ |
| PrinterControllerService.GetNotifications | Gets all the notifications of the printer | ✅ | ✅ |
| PrinterControllerService.OnJobStatusUpdated | Subscribe on server stream to be notified when a Job changes state | ✅ | ❌ |
| PrinterControllerService.OnNotification | Subscribe on server stream to be notified when a new notification is made | ✅ | ❌ |
| PrinterControllerService.OnPrinterStatusUpdated | Subscribes on server stream to be notified when the printer changes state | ✅ | ❌ |
| PrinterControllerService.OnRequestJob | Subscribes on server stream to be notified when the printer request new job | ✅ | ❌ |
| RecipeService.CreateRecipe | Creates a new recipe in the printer | ✅ | ✅ |
| RecipeService.GetRecipe | Get a specified recipe stored in the printer | ✅ | ✅ |
| RecipeService.ListRecipe | List all stored recipes in the printer | ✅ | ✅ |
| RecipeService.UpdateRecipe | Updates a specified recipe in the printer | ✅ | ✅ |
| RecipeService.DeleteRecipe | Deletes a specific recipe in the printer | ✅ | ✅ |
| VariableService.GetVariable | Gets a variable, which is a Key-Value pair part of the Recipe, from the printer | ✅ | ✅ |
| VariableService.ListVariable | Gets a variable, which is a Key-Value pair part of the Recipe, from the printer | ✅ | ✅ |
Use cases
Using the API means sending an specific HTTP commands by messaging an endpoint and receiving a corresponding reply.
If you wish to issue these HTTP commands from the network, you should enable inbound TCP traffic for that API port (e.g. 6001) on the host device and along the network.
Example 1 - Getting Printer State
For example we want to get the current state of the printer using REST:
JSON REST - HTTP GET on 'https://
Then you will get a reply like:
{
"status": "PrinterStatus_Started"
}
Example 2 - Getting all error notifications
For example we want to get all the error notifications in the printer using REST:
JSON REST - HTTP GET on 'https://
Then you will get a reply like:
{
"notifications": [
{
"id": "8233849b-c813-404e-bfe7-b8ab0aafe03b",
"type": "NotificationType_Error",
"startTime": "2026-09-04T06:44:34.530949400Z",
"componentName": "Shift shuttle",
"content": "Shift shuttle not in position"
},
{
"id": "03561b5f-df76-4ac1-8ab3-dbea031a0d61",
"type": "NotificationType_Warning",
"startTime": "2026-09-04T06:44:35.315939800Z",
"componentName": "Shuttle B",
"content": "General motion warning of shuttle"
},
{
"id": "01174e4f-f039-4002-843d-48ca6b101e96",
"type": "NotificationType_Warning",
"startTime": "2026-09-04T07:43:09.012756300Z",
"componentName": "Job Queue",
"content": "Unable to print layer 'Spot4' no available hardware found"
},
{
"id": "3c6f5024-abe7-4d03-9fa9-780447426db2",
"type": "NotificationType_Warning",
"startTime": "2026-09-04T08:21:03.757707700Z",
"componentName": "Lift",
"content": "Not In Print Position"
},
{
"id": "1165a0b9-b92f-4c8c-a55a-4bba2b4b65ac",
"type": "NotificationType_Info",
"startTime": "2026-09-04T08:22:03.107905700Z",
"componentName": "Printer PLC interface",
"content": "Drip tray attached"
},
{
"id": "ee917c74-de79-48b9-900e-29bbc23a7800",
"type": "NotificationType_Info",
"startTime": "2026-09-04T08:22:03.115199400Z",
"componentName": "Printer PLC interface",
"content": "Drip tray 1 attached"
},
{
"id": "70e76063-9e14-49bc-a742-53be3448db87",
"type": "NotificationType_Info",
"startTime": "2026-09-04T08:22:03.140225200Z",
"componentName": "Printer PLC interface",
"content": "Auto fire running"
},
{
"id": "6186e91a-6297-4a46-b2a9-5ff71f732414",
"type": "NotificationType_Error",
"startTime": "2026-09-07T12:00:16.347070500Z",
"componentName": "Printer PLC interface",
"content": "No active print job"
}
]
}
Next you can select the messages which have the "type" of value "NotificationType_Error".
Example 3 - Get the current Job state
For example we want to get the current Job state from the printer:
REST - HTTP GET on 'https://
Then you will get a reply like:
{
"jobId": "00000861-0000-0000-0000-000000000000",
"jobName": "Job7x15_360L5",
"status": "JobStatus_Printing"
}
If you fetch this state when the current job is just about done you might get:
{
"jobId": "00000861-0000-0000-0000-000000000000",
"jobName": "Job7x15_360L5",
"status": "JobStatus_Finished"
}
Example 4 - Streaming Job state
For example we want to get immediate notice of the current Job changing state from the printer:
gRPC - HTTP printer.PrinterControllerService.OnJobStatusUpdated
You will get a streamed reply like at '14:00:00':
{
"jobId": "00000861-0000-0000-0000-000000000000",
"jobName": "Job7x15_360L5",
"status": "JobStatus_Idle"
}
Then a few moment later the printer is started and you could receive this at '14:00:30':
{
"jobId": "00000861-0000-0000-0000-000000000000",
"jobName": "Job7x15_360L5",
"status": "JobStatus_Active"
}
Next a the printer has loaded and initialized everything and starts printing at '14:00:35':
{
"jobId": "00000861-0000-0000-0000-000000000000",
"jobName": "Job7x15_360L5",
"status": "JobStatus_Printing"
}
Finally a the following response could be returned when the printer finishes the job at '14:01:00':
{
"jobId": "00000861-0000-0000-0000-000000000000",
"jobName": "Job7x15_360L5",
"status": "JobStatus_Finished"
}