4 Commits
0.0.5 ... 0.0.8

4 changed files with 72 additions and 11 deletions

View File

@ -27,5 +27,5 @@ WORKDIR ${APP_DIR}
VOLUME ${CONF_DIR}
CMD "python digitaltwin1.py -f ./config/config.ini"
CMD [ "/usr/local/bin/python", "digitaltwin1.py", "-f", "./config/config.ini" ]

View File

@ -9,3 +9,4 @@ digitalInputTopicPrefix = dt1/di
analogInputEventTopicPrefix = dt1/ai/event
analogInputPeriodicTopicPrefix = dt1/ai/periodic
analogInputPublishPeriod = 10.0
disableAnalogInputEventPublishing = true

55
readme.md Normal file
View File

@ -0,0 +1,55 @@
# DigitalTwin1
## Digital twin for Beckhoff BK-9000 Modbus-TCP coupler (and compatible Wago device)
### Overview
This tool connects to a Modbus-TCP coupler, reads it process image and publishes
* the new state of a discrete input register (digital input) after a change
* the new value of an input register (analog input) after a change
* periodically publishes the current values of all input registers (analog inputs)
using MQTT messages. The topic is built from a configured prefix and the index of the particular registers.
Furthermore it subscribes to MQTT messages related to the coils for the setup and anytime a message is received, it set the particular coils accordingly.
### Configuration
Configuration is done using a configuration file
[modbus]
client = 172.16.2.157
scanrate = 0.25
[mqtt]
broker = 172.16.2.16
digitalOutputTopicPrefix = dt1/coil
digitalInputTopicPrefix = dt1/di
analogInputEventTopicPrefix = dt1/ai/event
analogInputPeriodicTopicPrefix = dt1/ai/periodic
analogInputPublishPeriod = 10.0
disableAnalogInputEventPublishing = true
### Operation details
While the input and discrete input registers are scanned with the configured scanrate, an action on a coil according to a received message is issued immediately. At the same time the all input registers are scanned.
Using a configuration option it is possible to disable the publishing of analog change event - if only periodic information (like for a thermometer or so) is required.
The MQTT messages related to change events of input or discrete input registers are marked as //retained//.
### Usage
The tool is simply started using
python digitaltwin1.py
On default it searches the configuration file at ``$PWD/config``. This can be changed using the commandline argument ``-f``.
The Python modules ``pymodbus``, ``loguru`` and ``paho-mqtt`` are required.
A docker image with the required dependencies, the tool and a prepared default configuration in a volume is provided at ``registry.hottis.de/wolutator/digitaltwin1``.

View File

@ -12,6 +12,7 @@ def mqttEventPublisherStart(config, processImage):
class MqttEventPublisher(AbstractMqttPublisher):
def __init__(self, config, processImage):
super().__init__(config, processImage)
self.disableAnalogInputEventPublishing = self.config["disableAnalogInputEventPublishing"].lower() in [ "true", "on" ]
def localLoop(self):
while True:
@ -19,7 +20,8 @@ class MqttEventPublisher(AbstractMqttPublisher):
self.processImage.wait()
discreteInputChangeset = self.processImage.getChangedDiscreteInputs()
analogInputChangeset = self.processImage.getChangedAnalogsInputs()
if not self.disableAnalogInputEventPublishing:
analogInputChangeset = self.processImage.getChangedAnalogsInputs()
for discreteInputChangeItem in discreteInputChangeset:
logger.debug("Discrete input {} changed from {} to {}"
@ -27,15 +29,18 @@ class MqttEventPublisher(AbstractMqttPublisher):
discreteInputChangeItem[1][1],
discreteInputChangeItem[1][0]))
self.client.publish("{}/{}".format(self.config["digitalInputTopicPrefix"], str(discreteInputChangeItem[0])),
str(discreteInputChangeItem[1][0]))
str(discreteInputChangeItem[1][0]),
retain=True)
for analogInputChangeItem in analogInputChangeset:
logger.debug("Analog input {} changed from {} to {}"
.format(analogInputChangeItem[0],
analogInputChangeItem[1][1],
analogInputChangeItem[1][0]))
self.client.publish("{}/{}".format(self.config["analogInputEventTopicPrefix"], str(analogInputChangeItem[0])),
str(analogInputChangeItem[1][0]))
if not self.disableAnalogInputEventPublishing:
for analogInputChangeItem in analogInputChangeset:
logger.debug("Analog input {} changed from {} to {}"
.format(analogInputChangeItem[0],
analogInputChangeItem[1][1],
analogInputChangeItem[1][0]))
self.client.publish("{}/{}".format(self.config["analogInputEventTopicPrefix"], str(analogInputChangeItem[0])),
str(analogInputChangeItem[1][0]),
retain=True)