https://github.com/research-virtualfortknox/msb-client-websocket-python
The python client library to connect to the websocket interface of the MSB (Manufacturing Service Bus)
https://github.com/research-virtualfortknox/msb-client-websocket-python
msb msb-client msb-client-websocket python websocket-interface
Last synced: 5 months ago
JSON representation
The python client library to connect to the websocket interface of the MSB (Manufacturing Service Bus)
- Host: GitHub
- URL: https://github.com/research-virtualfortknox/msb-client-websocket-python
- Owner: research-virtualfortknox
- License: apache-2.0
- Created: 2019-06-07T07:14:13.000Z (about 7 years ago)
- Default Branch: master
- Last Pushed: 2025-07-22T12:44:02.000Z (11 months ago)
- Last Synced: 2025-09-23T00:32:58.122Z (9 months ago)
- Topics: msb, msb-client, msb-client-websocket, python, websocket-interface
- Language: Python
- Homepage:
- Size: 2.18 MB
- Stars: 5
- Watchers: 4
- Forks: 4
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- License: LICENSE
- Code of conduct: .github/CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
# MSB websocket client library for Python

[](https://badge.fury.io/py/msb-client-websocket-python)
[](https://coveralls.io/github/research-virtualfortknox/msb-client-websocket-python?branch=feature-coveralls)
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fresearch-virtualfortknox%2Fmsb-client-websocket-python?ref=badge_shield)
**Compatibility Matrix**
Client version compatibility to MSB versions:
| | **1.5.x-RELEASE** | **1.6.x-RELEASE** |
|---|:---:|:---:|
| 1.0.x | x | x |
## Welcome
If you want to contribute, please read the [Contribution Guidelines](.github/CONTRIBUTING.md).
If you want to test this client by using its sources and a sample app, read the [App Sample](doc/app_sample.md).
If you want to know how to use this client in your own project, read below.
## What is VFK MSB
TODO: Link to general documentation about VFK MSB
You can use this client to connect a python app to VFK MSB.
## Prerequisites
* Setup [Python](https://www.python.org/downloads/) **version 3.9.x**
* last client version supporting Python 2.7 is v1.0.8
* last client version supporting Python 3.6 is v1.0.11
* last client version supporting Python 3.7 is v1.0.13
* last client version supporting Python 3.8 is v1.0.15
* MSB client installed using PyPi
* Optional: Use pipenv to run your python app in a virtual environment to avoid dependency isssues with other apps
Install MSB client from PyPi
```sh
pip install msb-client-websocket-python
```
Import to your applicaton
```python
from msb_client.ComplexDataFormat import ComplexDataFormat
from msb_client.DataType import DataType
from msb_client.Event import Event
from msb_client.Function import Function
from msb_client.MsbClient import MsbClient
```
## Create self-description
The figure below shows a minimal required `self-description model` of a smart object / application.
Every smart object / application requires (must have) a uuid and a token.
The uuid is competent for identification
and the token is used to verify the smart object / application for its owner on the MSB side.

TODO: Here you can find more information about
the `self-description structure` and `supported data formats`.
### Alternative 1 - By application.properties
Add the main description by adding an `application.poperties` file to the root of your project:
Generate the uuid e.g. by a tool like https://www.uuidgenerator.net/
```sh
msb.uuid=76499d88-34cf-4836-8cc1-7e0d9c54dacx
msb.name=YourSmartObjectName
msb.description=YourSmartObjectDesc
msb.token=5e0d9c54dacx
msb.type=SmartObject
```
When initializing your msb client instance, the `application.properties` file will be loaded.
```python
myMsbClient = MsbClient()
```
You can also set a custom path to the `application.properties` file.
```python
myMsbClient = MsbClient(applicationPropertiesCustomPath="./your/path/to/application.properties")
```
### Alternative 2 - By constructor
If you do not provide an application.properties file, use the constructor
to define the basic self description.
```python
SERVICE_TYPE = "SmartObject"
SO_UUID = str(uuid.uuid1()) # you can type in an own uuid here instead of generating it
SO_NAME = "YourSmartObjectName"
SO_DESCRIPTION = "YourSmartObjectDesc"
SO_TOKEN = SO_UUID[-6:]
myMsbClient = MsbClient(
SERVICE_TYPE,
SO_UUID,
SO_NAME,
SO_DESCRIPTION,
SO_TOKEN,
)
```
## Add Events
Add `events` to your smart object / application which can be send to MSB.
### Alternative 1: Simple event creation sample (using method params):
```python
event_id = "E1"
event_name = "EVENT " + event_id
event_description = "EVENT Description " + event_id
event_dataformat = DataType.STRING
event_priority = 1 # 0 (LOW), 1 (MEDIUM), 2 (HIGH)
isArray = False # just one value or array of it?
# add the event
myMsbClient.addEvent(
event_id,
event_name,
event_description,
event_dataformat,
event_priority,
isArray,
)
```
### Alternative 2: Complex event creation sample (using object):
```python
event_id = "E2"
event_name = "EVENT " + event_id
event_description = "EVENT Description " + event_id
event_priority = 1 # 0 (LOW), 1 (MEDIUM), 2 (HIGH)
isArray = False # just one value or array of it?
# define a complex data format to be used in an event
# init the complex data format
myDevice = ComplexDataFormat("MyDevice")
myModule = ComplexDataFormat("MyModule")
# add the properties to the complex objects
# (property_name, property_datatype, isArray)
myModule.addProperty("moduleName", DataType.STRING, False)
myDevice.addProperty("deviceName", DataType.STRING, False)
myDevice.addProperty("deviceWeight", DataType.FLOAT, False)
myDevice.addProperty("submodules", myModule, True)
# add the event (with the root of the nested complex object)
myMsbClient.addEvent(
event_id,
event_name,
event_description,
myDevice,
event_priority,
isArray,
)
```
### Alternative 3: Complex event creation sample (using json object):
```python
event_id = "E3"
event_name = "EVENT " + event_id
event_description = "EVENT Description " + event_id
event_priority = 1 # 0 (LOW), 1 (MEDIUM), 2 (HIGH)
isArray = False # just one value or array of it?
# add the event (with the MSB-ready json object)
myMsbClient.addEvent(
event_id,
event_name,
event_description,
{
"Team" : {
"type" : "object",
"properties" : {
"staff" : {
"type" : "array",
"items" : {
"$ref" : "#/definitions/Member"
}
}
}
},
"Member" : {
"type" : "object",
"properties" : {
"name" : {
"type" : "string"
},
"status" : {
"enum" : [ "present", "absent" ],
"type" : "string"
}
}
},
"dataObject" : {
"$ref" : "#/definitions/Team"
}
},
event_priority,
isArray,
)
```
See `app_sample.py` for more event creation examples.
## Add Functions
Add `functions` and their implementations your smart object / application is able to handle.
### Alternative 1: Simple function creation sample (using method params):
```python
function_id = "F1"
function_name = "FUNC " + function_id
function_description = "FUNC Description " + function_id
function_dataformat = DataType.STRING
isArray = False # handle array of values or just one value?
responseEvents = None # you can link to response events here by a list of event is e.g. ["E1"]
# define the function which will be passed to the function description
# this function implementation will be called
def printMsg(msg):
print(str(msg["dataObject"]))
# add the function
myMsbClient.addFunction(
function_id,
function_name,
function_description,
function_dataformat,
printMsg,
isArray,
responseEvents,
)
```
### Alternative 2: Complex function creation sample (using object):
```python
function_id = "F2"
function_name = "FUNC " + function_id
function_description = "FUNC Description " + function_id
isArray = False # handle array of values or just one value?
responseEvents = None # you can link to response events here by a list of event is e.g. ["E1"]
# define a complex data format to be used in an event
# init the complex data format
myCar = ComplexDataFormat("MyCar")
# add the properties to the complex objects
# (property_name, property_datatype, isArray)
myCar.addProperty("carColor", DataType.STRING, False)
myCar.addProperty("carNrOfSeats", DataType.INT32, False)
myCar.addProperty("carWeight", DataType.FLOAT, False)
# define the function which will be passed to the function description
# this function implementation will be called
def printMsg(msg):
print(str(msg["dataObject"]))
# add the function
myMsbClient.addFunction(
function_id,
function_name,
function_description,
myCar,
printMsg,
isArray,
responseEvents,
)
```
### Alternative 3: Complex function creation sample (using json object):
```python
function_id = "F3"
function_name = "FUNC " + function_id
function_description = "FUNC Description " + function_id
isArray = False # handle array of values or just one value?
responseEvents = None # you can link to response events here by a list of event is e.g. ["E1"]
# define the function which will be passed to the function description
# this function implementation will be called
def printMsg(msg):
print(str(msg["dataObject"]))
# add the function
myMsbClient.addFunction(
function_id,
function_name,
function_description,
{
"MyCar" : {
"type" : "object",
"properties" : {
"carColor" : {
"type" : "string"
},
"carNrOfSeats" : {
"format": "int32",
"type": "integer"
},
"carWeight" : {
"format": "float",
"type": "number"
},
"wheels" : {
"type" : "array",
"items" : {
"$ref" : "#/definitions/MyWheel"
}
}
}
},
"MyWheel" : {
"type" : "object",
"properties" : {
"position" : {
"enum" : [ "br", "bl", "fr", "fl" ],
"type" : "string"
}
}
},
"dataObject" : {
"$ref" : "#/definitions/MyCar"
}
},
printMsg,
isArray,
responseEvents,
)
```
See `app_sample.py` of the application template for more (and complex) examples.
## Connect and Register Client
```python
msb_url = 'ws://127.0.0.1:8085'
myMsbClient.connect(msb_url)
myMsbClient.register()
```
You will get an `IO_CONNECTED` and `IO_REGISTERED` event from MSB, if successful.
## Event publishing
For publishing an event to a websocket broker interface,
only the `eventId` and `data` are required of the already specified event (see above).
```python
event_id = "E1"
event_value = 'Hello World!'
myMsbClient.publish(
event_id,
event_value
)
```
The MSB responds with an `IO_PUBLISHED` event, if successful.
By default events are published with a low priority.
It is also possible to `set the priority` of an event.
There are three possible priorities for events like it is shown at the following table.
| `Constant` | `Value` |
|:---:|:---:|
| LOW | 0 |
| MEDIUM| 1 |
| HIGH| 2 |
```python
event_id = "E1"
event_value = 'Hello World!'
event_priority = 2
myMsbClient.publish(
event_id,
event_value,
event_priority
)
```
Another option is to publish an event as `cached event` by setting the cache parameter to true.
And you can add a `post date`.
This means that the event is not deleted if the connection is broken.
```python
event_id = "E1"
event_value = 'Hello World!'
event_priority = 2
event_isCached = True
event_postDate = datetime.datetime.utcnow().isoformat()[:-3] + "Z"
myMsbClient.publish(
event_id,
event_value,
event_priority,
event_isCached,
event_postDate
)
```
You cann also handle `correlation ids` to identify an event among flows.
```python
event_id = "E1"
event_value = 'Hello World!'
event_priority = 2
event_isCached = True
event_postDate = datetime.datetime.utcnow().isoformat()[:-3] + "Z"
event_correlationId = "72047f33-a9ae-4aa5-b7ae-c1c4a2797cac"
myMsbClient.publish(
event_id,
event_value,
event_priority,
event_isCached,
event_postDate,
event_correlationId
)
```
For values based on complex data formats it will look like this:
```python
event_id = "E2"
event_priority = 2
event_isCached = True
event_postDate = datetime.datetime.utcnow().isoformat()[:-3] + "Z"
event_correlationId = "72047f33-a9ae-4aa5-b7ae-c1c4a2797cac"
# pepare the complex ovbject based on a complex data format
# use it as event value
myModuleObj = {}
myModuleObj['moduleName'] = 'Module 1'
myDeviceObj = {}
myDeviceObj['deviceName'] = 'Device 1'
myDeviceObj['deviceWeight'] = 1.3
myDeviceObj['submodules'] = [myModuleObj]
myMsbClient.publish(
event_id,
myDeviceObj,
event_priority,
event_isCached,
event_postDate,
event_correlationId
)
```
## Function call handling
As shown above the addFunction method includes a `function pointer`
to point to the function implementation.
## Configuration parameters
Configuration parameters are a simple list of key value pairs for the smart object / application.
It is displayed and can be customized in the MSB UI to change your apps behaviour during runtime.
`Add` condifuration parameters:
```python
param_name_1 = "testParam1"
param_value_1 = True
param_datatype_1 = DataType.BOOLEAN
myMsbClient.addConfigParameter(param_name_1, param_value_1, param_datatype_1)
param_name_2 = "testParam2"
param_value_2 = "StringValue"
param_datatype_2 = DataType.STRING
myMsbClient.addConfigParameter(param_name_2, param_value_2, param_datatype_2)
param_name_3 = "testParam3"
param_value_3 = 1000
param_datatype_3 = DataType.INT32
myMsbClient.addConfigParameter(param_name_3, param_value_3, param_datatype_3)
```
`Get` configuration parameter (after changed in MSB UI) to change your app behaviour:
```python
# get by getConfigParameter using name as key
parameterValueFound_1 = myMsbClient.getConfigParameter(param_name_1)
parameterValueFound_2 = myMsbClient.getConfigParameter(param_name_2)
parameterValueFound_3 = myMsbClient.getConfigParameter(param_name_3)
```
## SSL/TLS connection configuration
To enable `SSL/TLS`, you need to specify wss:// or https:// in the URL instead of ws:// or http://.
Furthermore, it is necessary to specify a trust store in the client,
which contains the public certificate of the MSB interface, so that it is considered trustworthy.
```python
msb_url = 'wss://:'
myMsbClient.connect(msb_url)
myMsbClient.register()
```
If you use an IP instead of a public url during development,
it will be necessary to disable the hostname verification to connect via web socket secure.
```python
myMsbClient.disableHostnameVerification(True)
```
## Connection recovery
If connection to the common websocket interface is broken the client performs a reconnect.
After a reconnect the registration at the MSB will be redone automatically by the client.
You can change this interval by setting an integer value in `ms` for the reconnect interval.
```python
myMsbClient.setReconnectInterval(10000)
```
Or you can disable the automatic reconnect.
```python
myMsbClient.disableAutoReconnect(True)
```
## Event caching
If the client loses the connection, the published events are cached in a queue.
After a successfull reconnection, the queued events are published to MSB (FIFO principle).
The default size of the queue is 1000 entries. The size can be changed:
```python
myMsbClient.setEventCacheSize(1000)
```
If no event caching is needed, you can disable it.
```python
myMsbClient.disableEventCache(True)
```
## Debug mode
To debug your clients communication with MSB, you can enable the debug mode
```python
myMsbClient.enableDebug(True)
```
To enable the trace of the websocket communication use also
```python
myMsbClient.enableTrace(True)
```
It mgiht be also helpful to enable data format validation, to check if an event value is valid
```python
myMsbClient.enableDataFormatValidation(True)
```
## License
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fresearch-virtualfortknox%2Fmsb-client-websocket-python?ref=badge_large)