diff --git a/LICENSE b/LICENSE index f8ccd89..cef5acd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 MichielVanwelsenaere +Copyright (c) 2024 Michiel Vanwelsenaere Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 94cb8b0..4305f5d 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,11 @@ To translate the byte array received by the modbus device to their actual value In addition to the above a buscontroller function block ([FB_RS485_BUSCONTROLLER](./docs/FunctionBlocks/FB_RS485_BUSCONTROLLER.md)) is used to control access to the RS485 bus between multiple RS485 device function blocks. +### DALI +Control DALI drivers using the WAGO DALI modules (753-647). + +- [FB_OUTPUT_DIMMER_DALI_MQTT](./docs/FunctionBlocks/FB_OUTPUT_DIMMER_DALI_MQTT.md) + # Additional functionality - [MQTT related settings](./docs/AdditionalFunctionality/MQTT_General.md) diff --git a/docs/FunctionBlocks/FB_INPUT_BINARYSENSOR_MQTT.md b/docs/FunctionBlocks/FB_INPUT_BINARYSENSOR_MQTT.md index f09c82e..fdb3926 100644 --- a/docs/FunctionBlocks/FB_INPUT_BINARYSENSOR_MQTT.md +++ b/docs/FunctionBlocks/FB_INPUT_BINARYSENSOR_MQTT.md @@ -21,11 +21,12 @@ METHOD(S) - InitMQTT: enables MQTT events on the FB, an overview of the parameters: - `MQTTPublishPrefix`: datatype *POINTER TO STRING*, pointer to the MQTT publish prefix that should be used for publishing any messages/events for this FB. Suffix is automatically set to FB name. - `pMqttPublishQueue`: datatype *POINTER TO FB_MqttPublishQueue*, pointer to the MQTT queue to publish messages. + - `pMqttCallbackCollector`: datatype _POINTER TO MQTT.CallbackCollector, pointer to the MQTT callback collector to receive subscribe messages. - ConfigureFunctionBlock: configures the behaviour of output `Q` using the parameters below: - `T_TurnOffDelay`: duration of the turn off delay added on output `Q` to prevent rapid ON/OFF behaviour on the output caused by a fast switching sensor on the digital input. Defaults to 0 seconds, can be extremely usefull when connecting a motion sensor the the PLC. -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | diff --git a/docs/FunctionBlocks/FB_INPUT_PUSHBUTTON_DIMMER_MQTT.md b/docs/FunctionBlocks/FB_INPUT_PUSHBUTTON_DIMMER_MQTT.md index caecc46..20f91d1 100644 --- a/docs/FunctionBlocks/FB_INPUT_PUSHBUTTON_DIMMER_MQTT.md +++ b/docs/FunctionBlocks/FB_INPUT_PUSHBUTTON_DIMMER_MQTT.md @@ -29,6 +29,7 @@ METHOD(S) - `OutputDimmer`: datatype *BOOL*, specify whether the DIM values (0-255) should be outputted as MQTT events. - `Qos_Dimm`: datatype *SD_MQTT.QoS*, MQTT QoS of the DIM MQTT events. - `Delta_Dimm`: datatype *INT*, resolution of the MQTT DIM events. For example: specifying value *5* will configure the FB to only emit an MQTT event when the DIM output differs *5* or more than its previous value. Note that the last value of output DIM (when input `PB` becomes low again) is always published. Even if the resolution delta hasn't been reached yet. This way the last DIM value published through MQTT is always synchronized with the DIM output of the FB. + - `pMqttCallbackCollector`: datatype _POINTER TO MQTT.CallbackCollector, pointer to the MQTT callback collector to receive subscribe messages. - ConfigureFunctionBlock: configures the dimmer with your prefered configurations, an overview of the parameters and their default values: - `T_Debounce`: debounce time for input PB, defaults to 10ms. @@ -46,7 +47,7 @@ METHOD(S) ### **Function Block Behaviour** This MQTT function block is a wrapper of the `DIMM_I` function block in the OSCAT building library enhanced with additional functionality in order to be able to emit MQTT events for single, double, long and dimmer events. To fully understand it's logic it's advised to give the documentation present in [the OSCAT building library docs](../_img/oscat_building100_en.pdf) a good read (page 52). -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | diff --git a/docs/FunctionBlocks/FB_INPUT_PUSHBUTTON_MQTT.md b/docs/FunctionBlocks/FB_INPUT_PUSHBUTTON_MQTT.md index 9de92f7..7000dd8 100644 --- a/docs/FunctionBlocks/FB_INPUT_PUSHBUTTON_MQTT.md +++ b/docs/FunctionBlocks/FB_INPUT_PUSHBUTTON_MQTT.md @@ -21,10 +21,11 @@ METHOD(S) - InitMQTT: enables MQTT events on the FB, an overview of the parameters: - `MQTTPublishPrefix`: datatype *POINTER TO STRING*, pointer to the MQTT publish prefix that should be used for publishing any messages/events for this FB. Suffix is automatically set to FB name. - `pMqttPublishQueue`: datatype *POINTER TO FB_MqttPublishQueue*, pointer to the MQTT queue to publish messages. + - `pMqttCallbackCollector`: datatype _POINTER TO MQTT.CallbackCollector, pointer to the MQTT callback collector to receive subscribe messages. - ConfigureFunctionBlock: configures the time parameter specifing the decoding time for long key press. Defaults to 400ms. -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | diff --git a/docs/FunctionBlocks/FB_MQTT_LOG.md b/docs/FunctionBlocks/FB_MQTT_LOG.md index 72036dd..9a947d4 100644 --- a/docs/FunctionBlocks/FB_MQTT_LOG.md +++ b/docs/FunctionBlocks/FB_MQTT_LOG.md @@ -14,6 +14,7 @@ METHOD(S) - `pMqttPublishQueue`: datatype _POINTER TO FB_MqttPublishQueue_, pointer to the MQTT queue to publish messages. - `MqttQos`: datatype _SD_MQTT.QoS_, configures the MQTT Qos for the function block published messages. - `MqttRetain`: datatype _BOOL_, configures the MQTT retain flag for the function block published messages. + - `pMqttCallbackCollector`: datatype _POINTER TO MQTT.CallbackCollector, pointer to the MQTT callback collector to receive subscribe messages. - send: allows logging to MQTT. The output string is formatted as follows: `instance | payload` - `instance` String for your own choice. - `payload`: datatype _STRING_, the payload to be sent to MQTT. String(128) diff --git a/docs/FunctionBlocks/FB_OUTPUT_BINARY_MQTT.md b/docs/FunctionBlocks/FB_OUTPUT_BINARY_MQTT.md index 095b813..d5ce1cd 100644 --- a/docs/FunctionBlocks/FB_OUTPUT_BINARY_MQTT.md +++ b/docs/FunctionBlocks/FB_OUTPUT_BINARY_MQTT.md @@ -25,7 +25,7 @@ METHOD(S) - PublishReceived: callback method called by the callbackcollector when a message is received on the subscribed topic by the callbackcollector. -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | @@ -34,7 +34,7 @@ Requires method call `InitMQTT` to enable MQTT capabilities. MQTT publish topic is a concatination of the publish prefix and the function block name. -### **MQTT Subscription Behaviour** +### **MQTT subscribe behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Commands are executed by the FB if the topic `MQTTSubscribeTopic` matches the MQTT topic and the payload exists in the table below. diff --git a/docs/FunctionBlocks/FB_OUTPUT_BISTABLE_MQTT.md b/docs/FunctionBlocks/FB_OUTPUT_BISTABLE_MQTT.md index 20d99ac..7d21137 100644 --- a/docs/FunctionBlocks/FB_OUTPUT_BISTABLE_MQTT.md +++ b/docs/FunctionBlocks/FB_OUTPUT_BISTABLE_MQTT.md @@ -35,7 +35,7 @@ METHOD(S) - ConfigureFunctionBlock: configures the behaviour of output `OUT` using the parameters below: - `T_Hold`: duration of the pulse generated on output `OUT` to switch the bistable relais. -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | @@ -44,7 +44,7 @@ Requires method call `InitMQTT` to enable MQTT capabilities. MQTT publish topic is a concatination of the publish prefix and the function block name. -### **MQTT Subscription Behaviour** +### **MQTT subscribe behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Commands are executed by the FB if the topic `MQTTSubscribeTopic` matches the MQTT topic and the payload exists in the table below. diff --git a/docs/FunctionBlocks/FB_OUTPUT_COVER_MQTT.md b/docs/FunctionBlocks/FB_OUTPUT_COVER_MQTT.md index c9f3364..8920009 100644 --- a/docs/FunctionBlocks/FB_OUTPUT_COVER_MQTT.md +++ b/docs/FunctionBlocks/FB_OUTPUT_COVER_MQTT.md @@ -34,6 +34,7 @@ METHOD(S) - InitMQTT: enables MQTT events on the FB, an overview of the parameters: - `MQTTPublishPrefix`: datatype _POINTER TO STRING_, pointer to the MQTT publish prefix that should be used for publishing any messages/events for this FB. The suffix is automatically set to FB name. - `pMqttPublishQueue`: datatype _POINTER TO FB_MqttPublishQueue_, pointer to the MQTT queue to publish messages. + - `pMqttCallbackCollector`: datatype _POINTER TO MQTT.CallbackCollector, pointer to the MQTT callback collector to receive subscribe messages. - ConfigureFunctionBlock: configures the behaviour of the cover using the parameters below: - `T_LOCKOUT`: delay between change of direction. @@ -41,7 +42,7 @@ METHOD(S) - PublishReceived: callback method called by the callbackcollector when a message is received on the subscribed topic by the callbackcollector. -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. @@ -51,7 +52,7 @@ Requires method call `InitMQTT` to enable MQTT capabilities. MQTT publish topic is a concatination of the publish prefix and the function block name. -### **MQTT Subscription Behaviour** +### **MQTT subscribe behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Commands are executed by the FB if the topic `MQTTSubscribeTopic` matches the MQTT topic and the payload exists in the table below. diff --git a/docs/FunctionBlocks/FB_OUTPUT_DIMMER_DALI_MQTT.md b/docs/FunctionBlocks/FB_OUTPUT_DIMMER_DALI_MQTT.md new file mode 100644 index 0000000..2934305 --- /dev/null +++ b/docs/FunctionBlocks/FB_OUTPUT_DIMMER_DALI_MQTT.md @@ -0,0 +1,166 @@ +## FB_OUTPUT_DIMMER_DALI_MQTT +![MQTT Discovery](https://img.shields.io/badge/MQTT%20Discovery-brightgreen) + +### **General** + +Can be controlled using pulses from [FB_INPUT_PUSHBUTTON_MQTT](./FB_INPUT_PUSHBUTTON_MQTT.md), maintains output state through powercycles. Sets the driver fade time and fade rate setting. Allows dimming via a long persistent push on a pushbutton. Performs periodic writes to the DALI address to avoid state issues. + +DALI configuration via the Wago DALI tool and creation of the `typBallast` is explained pretty well in [this video](https://www.youtube.com/watch?v=FaoOY2-VFVk). + +### **Block diagram** + + + +INPUT(S) + +- BALLAST: input to configure the `typBallast` that should be linked to this function block. +- TOGGLE: input to connect to one or multiple `SINGLE` from one or multiple [FB_INPUT_PUSHBUTTON_MQTT](./FB_INPUT_PUSHBUTTON_MQTT.md). +- P_LONG: input to connect to one or multiple `P_LONG` from one or multiple [FB_INPUT_PUSHBUTTON_MQTT](./FB_INPUT_PUSHBUTTON_MQTT.md). +- PRIO_HIGH: when high the output `Q` is set to high with a maximum brightness, has priority over the other inputs. +- PRIO_LOW: when high the output `Q` is set to low, has priority over the other inputs. + + +OUTPUT(S) + +- STATUS_LED: high when light intensity > 0, off otherwise. + +METHOD(S) + +- InitMQTT: enables MQTT events on the FB, an overview of the parameters: + - `MQTTPublishPrefix`: datatype _POINTER TO STRING_, pointer to the MQTT publish prefix that should be used for publishing any messages/events for this FB. Suffix is automatically set to FB name. + - `MQTTSubscribePrefix`: datatype _POINTER TO STRING_, pointer to the MQTT subscribe prefix that should be used for publishing any messages/events to this FB. Suffix is automatically set to FB name. + - `pMqttPublishQueue`: datatype _POINTER TO FB_MqttPublishQueue_, pointer to the MQTT queue to publish messages. + - `pMqttPublishQueue`: datatype _POINTER TO FB_MqttPublishQueue_, pointer to the MQTT queue to publish messages. + - `pMqttCallbackCollector`: datatype _POINTER TO MQTT.CallbackCollector, pointer to the MQTT callback collector to receive subscribe messages. + +- ConfigureFunctionBlock: configures the dimmer with your preferred configurations, an overview of the parameters and their default values. + - `FadeTime`: _BYTE_ value setting the fade time. + - `FadeRate`: _BYTE_ value setting the fade rate. +- PublishReceived: callback method called by the callbackcollector when a message is received on the subscribed topic by the callbackcollector. + +### Fade Time and Fade Rate + +Can be configured using `ConfigureFunctionBlock` method call. + +| Value | Fade time [s] | Fade rate [fades/s] | +| :--------| :--------------| :-------------------| +| 0 | Extended fade | not applicable +| 1 | 0.707 | 357.796 +| 2 | 1.0 | 253.0 +| 3 | 1.414 | 178.898 +| 4 | 2.0 | 126.5 +| 5 | 2.828 | 89.449 +| 6 | 4.0 | 63.25 +| 7 | 5.657 | 44.725 +| 8 | 8.0 | 31.625 +| 9 | 11.314 | 22.362 +| 10 | 16.0 | 15.813 +| 11 | 22.627 | 11.181 +| 12 | 32.0 | 7.906 +| 13 | 45.255 | 5.591 +| 14 | 64.0 | 3.953 +| 15 | 90.51 | 2.795 + +Note: table has been extracted from WagoAppDALI library documentation. + +### **MQTT publish behavior** + +Requires method call `InitMQTT` to enable MQTT capabilities. + +| Event | Description | MQTT payload | QoS | Retain flag | Published on startup | +| :---------------------- | :----------------------------------------- | :----------- | :----------------------------------- | :---------- | :------------------- | +| **Light intensity value changes** | Light intensity value changes | `0-100` | 2 | `TRUE` | yes | +| **light intensity values changes to 0 or 100** | Light intensity value changes to minimum or maximum value, published on `BRIGHTNESS` subtopic. | `ON/OFF` | 2` | `TRUE` | yes, if light intensity value > 0 | + +(\*): MQTT publish topic is a concatenation of the publish prefix variable, the function block name and the name of the output. + +### **MQTT subscribe behavior** + +Requires method call `InitMQTT` to enable MQTT capabilities. +Commands are executed by the FB if the topic `MQTTSubscribeTopic` matches the MQTT topic and the payload exists in the table below. + +| Command | Description | expected payload | Additional notes | +| :-------------------------- | :--------------------------------------------------- | :--------------- | :--------------------------------------------------------------- | +| **Turn on** | Turns the dimmer on to maximum brightness | `ON` | Command executed when `PRIO_HIGH` and `PRIO_LOW` inputs are low. | +| **Turn off** | Turns the dimmer off | `OFF` | Command executed when `PRIO_HIGH` and `PRIO_LOW` inputs are low. | +| **Set brightness value** | Request to set specific brightness value. value expected on `BRIGHTNESS` subtopic. | `0-100` | Command executed when `PRIO_HIGH` and `PRIO_LOW` inputs are low. | + +MQTT subscription topic is a concatenation of the subscribe prefix variable and the function block name. +Note that the function block also accepts float values for setting the dimmer output value, the float value will get rounded to the nearest integer value. + +### **Code example** //TODO + +- DALI global variable initiation: +``` +VAR_GLOBAL + M1_Light1: typBallast:=(bAddress:=0,xIsGroup:=FALSE,bPortDALI:=1); +END_VAR +``` + +- variables initiation: +``` +MqttPubDimmerPrefix :STRING(100) := 'Devices/PLC/House/Out/Dimmers/'; +MqttSubDimmerPrefix :STRING(100) := 'Devices/PLC/House/In/Dimmers/'; +M1_DALIMASTER :FbDaliMaster; +FB_DALI_1_ADR0 :FB_OUTPUT_DIMMER_DALI_MQTT; +``` + +- Init MQTT method call (called once during startup): +``` +FB_DALI_1_ADR0.InitMqtt(MQTTPublishPrefix:= ADR(MqttVariables.MqttPubDimmerPrefix), + MQTTSubscribePrefix:= ADR(MqttVariables.MqttSubDimmerPrefix), + pMqttPublishQueue := ADR(MqttVariables.fbMqttPublishQueue), + pMqttCallbackCollector := ADR(MqttVariables.collector_FB_DIMMER_MQTT) +); +``` + +The MQTT publish topic in this code example will be `Devices/PLC/House/Out/Dimmers/FB_DALI_1_ADR0` (MQTTPubSwitchPrefix variable + function block name). The subscription topic will be `Devices/PLC/House/In/Dimmers/FB_DALI_1_ADR0` (MQTTSubSwitchPrefix variable + function block name). + + +- checking for events to switch the DALI output (cyclic): +``` +// Run the master before anything else +M1_DALIMASTER( + bPortDALI:=1, + I_Port:=IoConfig_Globals.DALI_MULTI_MASTER_MODULE); + +// Run individual DALI FB +FB_DALI_1_ADR0( + BALLAST := DALIVariables.M1_Light1, + TOGGLE := FB_DI_PB_002.SINGLE, + P_LONG := FB_DI_PB_002.P_LONG, + STATUS_LED => DO_002); +``` + +The above illustrates an integration with [FB_INPUT_PUSHBUTTON_MQTT](./FB_INPUT_PUSHBUTTON_MQTT.md). + + +- MQTT discovery: +``` +FB_DALI_1_ADR0.InitMqttDiscovery( + name := '001. Office strip cold', (* The name show in Home Assistant frond-end*) + Device := ADR(PLC_Device), (* The device show in Home Assistant *) +); +``` + +### **Home Assistant YAML** +If [MQTT discovery](../AdditionalFunctionality/MQTT_Discovery.md) is not working for you, you can use the YAML code below in your [MQTT lights](https://www.home-assistant.io/components/light.mqtt/) config: + +```YAML +mqtt: + light: + - name: "Kitchen" + state_topic: "Devices/PLC/House/Out/Dimmers/FB_DALI_1_ADR0" + command_topic: "Devices/PLC/House/In/Dimmers/FB_DALI_1_ADR0" + brightness_command_topic: "Devices/PLC/House/In/Dimmers/FB_DALI_1_ADR0/BRIGHTNESS" + brightness_state_topic: "Devices/PLC/House/Out/Dimmers/FB_DALI_1_ADR0/BRIGHTNESS" + on_command_type: "brightness" + payload_on: "ON" + payload_off: "OFF" + optimistic: false + brightness_scale: 100 + qos: 2 + availability: "Devices/PLC/House/availability" + payload_not_available: "offline" + payload_available: "online" +``` diff --git a/docs/FunctionBlocks/FB_OUTPUT_DIMMER_MQTT.md b/docs/FunctionBlocks/FB_OUTPUT_DIMMER_MQTT.md index b2d8181..da8341b 100644 --- a/docs/FunctionBlocks/FB_OUTPUT_DIMMER_MQTT.md +++ b/docs/FunctionBlocks/FB_OUTPUT_DIMMER_MQTT.md @@ -36,6 +36,7 @@ METHOD(S) - `OutputDimmer`: datatype _BOOL_, specify whether the DIM values (0-255) should be outputted as MQTT events. - `Qos_Dimm`: datatype _SD_MQTT.QoS_, MQTT QoS of the DIM MQTT events. - `Delta_Dimm`: datatype _INT_, resolution of the MQTT OUT events. For example: specifying value _5_ will configure the FB to only emit an MQTT event when the OUT output differs _5_ or more than its previous value. Note that the last value of output OUT (when input `P_LONG` becomes low again) is always published. Even if the resolution delta hasn't been reached yet. This way the last OUT value published through MQTT is always synchronized with the OUT output of the FB. + - `pMqttCallbackCollector`: datatype _POINTER TO MQTT.CallbackCollector, pointer to the MQTT callback collector to receive subscribe messages. - ConfigureFunctionBlock: configures the dimmer with your prefered configurations, an overview of the parameters and their default values. - `T_Debounce`: debounce time for input PB, defaults to 10ms. @@ -72,7 +73,7 @@ The following table shows the operating status of the dimmer: This MQTT function block is a wrapper of the `DIMM_I` function block in the OSCAT building library enhanced with additional functionality in order to be able to emit MQTT events. To fully understand it's logic it's advised to give the documentation present in [the OSCAT building library docs](../_img/oscat_building100_en.pdf) a good read (page 52). -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. @@ -83,7 +84,7 @@ Requires method call `InitMQTT` to enable MQTT capabilities. (\*): MQTT publish topic is a concatenation of the publish prefix variable, the function block name and the name of the output. -### **MQTT Subscription Behaviour** +### **MQTT subscribe behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Commands are executed by the FB if the topic `MQTTSubscribeTopic` matches the MQTT topic and the payload exists in the table below. diff --git a/docs/FunctionBlocks/FB_RS485_DUCO_DUCOBOX_MQTT.md b/docs/FunctionBlocks/FB_RS485_DUCO_DUCOBOX_MQTT.md index 3a9f777..31b605e 100644 --- a/docs/FunctionBlocks/FB_RS485_DUCO_DUCOBOX_MQTT.md +++ b/docs/FunctionBlocks/FB_RS485_DUCO_DUCOBOX_MQTT.md @@ -21,12 +21,13 @@ METHOD(S) - InitMQTT: enables MQTT events on the FB, an overview of the parameters: - `MQTTPublishPrefix`: datatype *POINTER TO STRING*, pointer to the MQTT publish prefix that should be used for publishing any messages/events for this FB. Suffix is automatically set to FB name. - `pMqttPublishQueue`: datatype *POINTER TO FB_MqttPublishQueue*, pointer to the MQTT queue to publish messages. + - `pMqttCallbackCollector`: datatype _POINTER TO MQTT.CallbackCollector, pointer to the MQTT callback collector to receive subscribe messages. - InitRS485: configures the Modbus RTU device address and the execution/polling interval for the multiple modbus read commands. - RequestBusTime: method implemented by each RS485 device function block. More information in the [RS485Device interface docs](../RS485/RS485Device_Interface.md). - GetRtuQuery: method implemented by each RS485 device function block. More information in the [RS485Device interface docs](../RS485/RS485Device_Interface.md). - ProcessDataArray: method implemented by each RS485 device function block. More information in the [RS485Device interface docs](../RS485/RS485Device_Interface.md). -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | @@ -39,7 +40,7 @@ MQTT publish topic is a concatination of the publish prefix and the function blo Depending on the type of the node the published register value represents a certain parameter value. -### **MQTT Subscription Behaviour** +### **MQTT subscribe behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Commands are executed by the FB if the topic `MQTTSubscribeTopic` matches the MQTT topic and the payload exists in the table below. diff --git a/docs/FunctionBlocks/FB_RS485_EASTRON_SDM220_MQTT.md b/docs/FunctionBlocks/FB_RS485_EASTRON_SDM220_MQTT.md index 099cd19..9d99da2 100644 --- a/docs/FunctionBlocks/FB_RS485_EASTRON_SDM220_MQTT.md +++ b/docs/FunctionBlocks/FB_RS485_EASTRON_SDM220_MQTT.md @@ -45,13 +45,14 @@ Outputs sharing the same modbus read commando are read from the device at a sing METHOD(S) - InitMQTT: enables MQTT events on the FB, an overview of the parameters: - `MQTTPublishPrefix`: datatype *POINTER TO STRING*, pointer to the MQTT publish prefix that should be used for publishing any messages/events for this FB. Suffix is automatically set to FB name. - - `pMqttPublishQueue`: datatype *POINTER TO FB_MqttPublishQueue*, pointer to the MQTT queue to publish messages. + - `pMqttPublishQueue`: datatype *POINTER TO FB_MqttPublishQueue*, pointer to the MQTT queue to publish messages. + - `pMqttCallbackCollector`: datatype _POINTER TO MQTT.CallbackCollector, pointer to the MQTT callback collector to receive subscribe messages. - InitRS485: configures the Modbus RTU device address and the execution/polling interval for the multiple modbus read commands. - RequestBusTime: method implemented by each RS485 device function block. More information in the [RS485Device interface docs](../RS485/RS485Device_Interface.md). - GetRtuQuery: method implemented by each RS485 device function block. More information in the [RS485Device interface docs](../RS485/RS485Device_Interface.md). - ProcessDataArray: method implemented by each RS485 device function block. More information in the [RS485Device interface docs](../RS485/RS485Device_Interface.md). -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | diff --git a/docs/FunctionBlocks/FB_RS485_EASTRON_SDM_POWER_MQTT.md b/docs/FunctionBlocks/FB_RS485_EASTRON_SDM_POWER_MQTT.md index 4e24aa4..f5a37b2 100644 --- a/docs/FunctionBlocks/FB_RS485_EASTRON_SDM_POWER_MQTT.md +++ b/docs/FunctionBlocks/FB_RS485_EASTRON_SDM_POWER_MQTT.md @@ -27,13 +27,14 @@ OUTPUT(S): METHOD(S) - InitMQTT: enables MQTT events on the FB, an overview of the parameters: - `MQTTPublishPrefix`: datatype *POINTER TO STRING*, pointer to the MQTT publish prefix that should be used for publishing any messages/events for this FB. Suffix is automatically set to FB name. - - `pMqttPublishQueue`: datatype *POINTER TO FB_MqttPublishQueue*, pointer to the MQTT queue to publish messages. + - `pMqttPublishQueue`: datatype *POINTER TO FB_MqttPublishQueue*, pointer to the MQTT queue to publish messages. + - `pMqttCallbackCollector`: datatype _POINTER TO MQTT.CallbackCollector, pointer to the MQTT callback collector to receive subscribe messages. - InitRS485: configures the Modbus RTU device address and the execution/polling interval for the modbus read command. - RequestBusTime: method implemented by each RS485 device function block. More information in the [RS485Device interface docs](../RS485/RS485Device_Interface.md). - GetRtuQuery: method implemented by each RS485 device function block. More information in the [RS485Device interface docs](../RS485/RS485Device_Interface.md). - ProcessDataArray: method implemented by each RS485 device function block. More information in the [RS485Device interface docs](../RS485/RS485Device_Interface.md). -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | diff --git a/docs/FunctionBlocks/FB_RS485_ESERA_OWD_MQTT.md b/docs/FunctionBlocks/FB_RS485_ESERA_OWD_MQTT.md index ed0a8b8..9177770 100644 --- a/docs/FunctionBlocks/FB_RS485_ESERA_OWD_MQTT.md +++ b/docs/FunctionBlocks/FB_RS485_ESERA_OWD_MQTT.md @@ -23,7 +23,7 @@ Nevertheless, adding a new device is a simple task, feel free to reach out. -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | diff --git a/docs/FunctionBlocks/FB_VIRTUAL_BOOL_MQTT.md b/docs/FunctionBlocks/FB_VIRTUAL_BOOL_MQTT.md index d507e13..97323cc 100644 --- a/docs/FunctionBlocks/FB_VIRTUAL_BOOL_MQTT.md +++ b/docs/FunctionBlocks/FB_VIRTUAL_BOOL_MQTT.md @@ -39,7 +39,7 @@ METHOD(S) - SetValue: method to set the function block virtual value, only works if the function block is in output mode. -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable if the function block is configured in output mode, outputting the value on input `IN` or set using the SetValue method through MQTT. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | @@ -48,7 +48,7 @@ Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable if MQTT publish topic is a concatination of the publish prefix and the function block name. -### **MQTT Subscription Behaviour** +### **MQTT subscribe behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable is the function block is configured in input mode which will allow the input of a value to the PLC through MQTT which will be exposed on the function block `OUT` output. Commands are executed by the FB if the topic `MQTTSubscribeTopic` matches the MQTT topic and the payload exists in the table below. diff --git a/docs/FunctionBlocks/FB_VIRTUAL_INT_MQTT.md b/docs/FunctionBlocks/FB_VIRTUAL_INT_MQTT.md index 5af0672..d100f80 100644 --- a/docs/FunctionBlocks/FB_VIRTUAL_INT_MQTT.md +++ b/docs/FunctionBlocks/FB_VIRTUAL_INT_MQTT.md @@ -39,7 +39,7 @@ METHOD(S) - SetValue: method to set the function block virtual value, only works if the function block is in output mode. -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable if the function block is configured in output mode, outputting the value on input `IN` or set using the SetValue method through MQTT. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | @@ -48,7 +48,7 @@ Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable if MQTT publish topic is a concatination of the publish prefix and the function block name. -### **MQTT Subscription Behaviour** +### **MQTT subscribe behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable is the function block is configured in input mode which will allow the input of a value to the PLC through MQTT which will be exposed on the function block `OUT` output. Commands are executed by the FB if the topic `MQTTSubscribeTopic` matches the MQTT topic and the payload exists in the table below. diff --git a/docs/FunctionBlocks/FB_VIRTUAL_REAL_MQTT.md b/docs/FunctionBlocks/FB_VIRTUAL_REAL_MQTT.md index ab1b997..074796c 100644 --- a/docs/FunctionBlocks/FB_VIRTUAL_REAL_MQTT.md +++ b/docs/FunctionBlocks/FB_VIRTUAL_REAL_MQTT.md @@ -39,7 +39,7 @@ METHOD(S) - SetValue: method to set the function block virtual value, only works if the function block is in output mode. -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable if the function block is configured in output mode, outputting the value on input `IN` or set using the SetValue method through MQTT. | Event | Description | MQTT payload | QoS | Retain flag | Published on startup | @@ -48,7 +48,7 @@ Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable if MQTT publish topic is a concatination of the publish prefix and the function block name. -### **MQTT Subscription Behaviour** +### **MQTT subscribe behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable is the function block is configured in input mode which will allow the input of a value to the PLC through MQTT which will be exposed on the function block `OUT` output. Commands are executed by the FB if the topic `MQTTSubscribeTopic` matches the MQTT topic and the payload exists in the table below. diff --git a/docs/FunctionBlocks/FB_VIRTUAL_STRING_MQTT.md b/docs/FunctionBlocks/FB_VIRTUAL_STRING_MQTT.md index 61e704a..ad91d08 100644 --- a/docs/FunctionBlocks/FB_VIRTUAL_STRING_MQTT.md +++ b/docs/FunctionBlocks/FB_VIRTUAL_STRING_MQTT.md @@ -44,7 +44,7 @@ METHOD(S) - SetValue: method to set the function block virtual value, only works if the function block is in output mode. -### **MQTT Event Behaviour** +### **MQTT publish behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable if the function block is configured in output mode, outputting the value on input `IN` or set using the SetValue method through MQTT. @@ -54,7 +54,7 @@ Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable if MQTT publish topic is a concatination of the publish prefix and the function block name. -### **MQTT Subscription Behaviour** +### **MQTT subscribe behavior** Requires method call `InitMQTT` to enable MQTT capabilities. Only applicable is the function block is configured in input mode which will allow the input of a value to the PLC through MQTT which will be exposed on the function block `OUT` output. Commands are executed by the FB if the topic `MQTTSubscribeTopic` matches the MQTT topic and the payload exists in the table below. diff --git a/docs/_drawio/FB_OUTPUT_DIMMER_DALI_MQTT.drawio b/docs/_drawio/FB_OUTPUT_DIMMER_DALI_MQTT.drawio new file mode 100644 index 0000000..da01163 --- /dev/null +++ b/docs/_drawio/FB_OUTPUT_DIMMER_DALI_MQTT.drawio @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/_img/FB_OUTPUT_DIMMER_DALI_MQTT.svg b/docs/_img/FB_OUTPUT_DIMMER_DALI_MQTT.svg new file mode 100644 index 0000000..a419ac6 --- /dev/null +++ b/docs/_img/FB_OUTPUT_DIMMER_DALI_MQTT.svg @@ -0,0 +1 @@ +
FB_OUTPUT_DIMMER_DALI_MQTT
FB_OUTPUT_DIMMER_DALI_MQTT
SINGLE
SINGLE
STATUS_LED
STATUS_LED
P_LONG
P_LONG
PRIO_LOW
PRIO_LOW
PRIO_HIGH
PRIO_HIGH
BALLAST
BALLAST
Text is not SVG - cannot display
\ No newline at end of file diff --git a/src/Exports/CodesysV3.export b/src/Exports/CodesysV3.export index da2151c..c2073dc 100644 --- a/src/Exports/CodesysV3.export +++ b/src/Exports/CodesysV3.export @@ -1,7 +1,7 @@ - AAEAAAD/////AQAAAAAAAAAMAgAAADxDb3JlLCBWZXJzaW9uPTMuNS4xNy4yLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAACNfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuUHJvZmlsZQMAAAAeX3BsdWdJbkd1aWRUb1ZlcnNpb25Db25zdHJhaW50Fl9wbHVnSW5HdWlkVG9FeHRlbnNpb24aX3BsdWdJbkd1aWRUb0V4dGVuc2lvbkxpc3QEBAQ9XzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb1ZlcnNpb25Db25zdHJhaW50RGljdGlvbmFyeQIAAAAwXzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb0Jvb2xEaWN0aW9uYXJ5AgAAAEBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvUHJvZmlsZUV4dGVuc2lvbkxpc3REaWN0aW9uYXJ5AgAAAAIAAAAJAwAAAAkEAAAACQUAAAAFAwAAAD1fM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvVmVyc2lvbkNvbnN0cmFpbnREaWN0aW9uYXJ5AQAAABhEaWN0aW9uYXJ5QmFzZStoYXNodGFibGUDHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUCAAAACQYAAAAFBAAAADBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvQm9vbERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJBwAAAAUFAAAAQF8zUy5Db0RlU3lzLkNvcmUuQ29tcG9uZW50cy5HdWlkVG9Qcm9maWxlRXh0ZW5zaW9uTGlzdERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJCAAAAAQGAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUHAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhh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AAAAAAAAAWsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFsAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABbQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAW4BAABhAQAAAwAAAAUAAAAOAAAACgAAAAFvAQAAYQEAAAMAAAAFAAAADgAAAB4AAAABcAEAAGEBAAADAAAABQAAAA4AAAAKAAAAAXEBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFyAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXQBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF1AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABdgEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF4AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABeQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXoBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAF7AQAAYQEAAAMAAAAFAAAADgAAAAoAAAABfAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAX0BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF+AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABfwEAAGEBAAADAAAABQAAAA4AAAAeAAAAAYABAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGBAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABggEAAGEBAAADAAAABQAAAA4AAAAKAAAAAYMBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGEAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABhQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYYBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGHAQAAYQEAAAMAAAAFAAAADgAAABQAAAABiAEAAGEBAAADAAAABQAAAA4AAAAUAAAAAYkBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGKAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYwBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGNAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABjgEAAGEBAAADAAAABQAAAA4A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AAAAAAAAAdcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHYAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB2QEAAGEBAAADAAAABQAAAA4AAAAAAAAAAdoBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAHbAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB3AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAd0BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHeAQAAYQEAAAMAAAAFAAAADgAAAB4AAAAB3wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAeABAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHhAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB4gEAAGEBAAADAAAABQAAAA4AAAAAAAAAAeMBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHkAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB5QEAAGEBAAADAAAABQAAAA4AAAAeAAAAAeYBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHnAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB6AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAekBAABhAQAAAwAAAAUAAAAOAAAACgAAAAHqAQAAYQEAAAMAAAAFAAAADgAAABQAAAAB6wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAewBAABhAQAAAwAAAAUAAAAOAAAAFAAAAAHtAQAAYQEAAAMAAAAFAAAADgAAABQAAAAB7gEAAGEBAAADAAAABQAAAA4AAAAAAAAAAe8BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHwAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB8QEAAGEBAAADAAAABQAAAA4AAAAUAAAAAfIBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHzAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB9AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAfUBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAH2AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB9wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAfgBAABhAQAAAwAAAAUAAAAOAAAACgAAAAH5AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB+gEAAGEBAAADAAAABQAAAA4AAAAKAAAAAfsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAH8AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB/QEAAGEBAAADAAAABQAAAA4AAAAAAAAAAf4BAABhAQAAAwAAAAUAAAAOAAAAHgAAAAH/AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABAAIAAGEBAAADAAAABQAAAA4AAAAAAAAAAQECAABhAQAAAwAAAAUAAAAOAAAAAAAAAAECAgAAYQEAAAMAAAAFAAAADgAAAAAAAAABAwIAAGEBAAADAAAABQAAAA4AAAAeAAAAAQQCAABhAQAAAwAAAAUAAAAOAAAAFAAAAAEFAgAAYQEAAAMAAAAFAAAADgAAAAAAAAAL + AAEAAAD/////AQAAAAAAAAAMAgAAADxDb3JlLCBWZXJzaW9uPTMuNS4xNy4yLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAACNfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuUHJvZmlsZQMAAAAeX3BsdWdJbkd1aWRUb1ZlcnNpb25Db25zdHJhaW50Fl9wbHVnSW5HdWlkVG9FeHRlbnNpb24aX3BsdWdJbkd1aWRUb0V4dGVuc2lvbkxpc3QEBAQ9XzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb1ZlcnNpb25Db25zdHJhaW50RGljdGlvbmFyeQIAAAAwXzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb0Jvb2xEaWN0aW9uYXJ5AgAAAEBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvUHJvZmlsZUV4dGVuc2lvbkxpc3REaWN0aW9uYXJ5AgAAAAIAAAAJAwAAAAkEAAAACQUAAAAFAwAAAD1fM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvVmVyc2lvbkNvbnN0cmFpbnREaWN0aW9uYXJ5AQAAABhEaWN0aW9uYXJ5QmFzZStoYXNodGFibGUDHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUCAAAACQYAAAAFBAAAADBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvQm9vbERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJBwAAAAUFAAAAQF8zUy5Db0RlU3lzLkNvcmUuQ29tcG9uZW50cy5HdWlkVG9Qcm9maWxlRXh0ZW5zaW9uTGlzdERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJCAAAAAQGAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUHAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhh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AAAeAAAAAWsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFsAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABbQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAW4BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFvAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAXEBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFyAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXQBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF1AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABdgEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF4AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABeQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXoBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAF7AQAAYQEAAAMAAAAFAAAADgAAAAoAAAABfAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAX0BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF+AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABfwEAAGEBAAADAAAABQAAAA4AAAAeAAAAAYABAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGBAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABggEAAGEBAAADAAAABQAAAA4AAAAKAAAAAYMBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGEAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABhQEAAGEBAAADAAAABQAAAA4AAAAKAAAAAYYBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGHAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiAEAAGEBAAADAAAABQAAAA4AAAAUAAAAAYkBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGKAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYwBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGNAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABjgEAAGEBAAADAAAABQAAAA4A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 True @@ -3625,6 +3625,540 @@ -1 + + True + + 363f82ae-0e61-485f-89ce-768985a60108 + 00000000-0000-0000-0000-000000000000 + FB_OUTPUT_DIMMER_DALI_MQTT + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + + + + + + 6f9dac99-8de1-4efc-8465-68ac443b7d08 + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc + + 638645790957738140 + + + None + + + + + 3 + + DaliSendFadeTime( + + + 4 + + typBallast := BALLAST, + + + 5 + + bFadeTime := 2); // 1 sec + + + 6 + + + + + 7 + + DaliSendFadeRate( + + + 8 + + typBallast := BALLAST, + + + 9 + + bFadeRate := 2); // 1 sec + + + 10 + + + + + 11 + + DaliSendDimValue( + + + 12 + + typBallast := BALLAST, + + + 13 + + rDimValue := DimValue); + + + 14 + + + + + 15 + + DaliSyncSignalGenerator( + + + 16 + + ENABLE := TRUE, + + + 17 + + TIMEHIGH := T#1S, + + + 18 + + TIMELOW := T#1M, + + + 19 + + OUT => DaliSendDimValue.xUpdate); + + + 20 + + + + + 21 + + Toggle_RTrigger(CLK:=TOGGLE); + + + 22 + + + + + 23 + + // Regular push + + + 24 + + IF(Toggle_RTrigger.Q AND DimValue = 0) THEN + + + 25 + + SetDimValue(100); + + + 26 + + ELSIF(Toggle_RTrigger.Q AND DimValue > 0) THEN + + + 27 + + SetDimValue(0); + + + 28 + + END_IF + + + 29 + + + + + 30 + + // Long push + + + 31 + + IF P_LONG THEN + + + 32 + + SetDimValue(DimValue + DimDirection); + + + 33 + + END_IF + + + 34 + + + + + 35 + + IF MqttSendBrightnessUpdate OR Startup AND InitMqttDone THEN + + + 36 + + pMqttPublishQueue^.AddMessage( + + + 37 + + Payload := REAL_TO_STRING(DimValue), + + + 38 + + Topic := CONCAT(THIS^.MQTTPublishTopic, '/BRIGHTNESS'), + + + 39 + + Qos := MQTT.QoS.ExactlyOnce, + + + 40 + + MqttRetain := TRUE + + + 41 + + ); + + + 42 + + MqttSendBrightnessUpdate := FALSE; + + + 43 + + END_IF + + + 44 + + + + + 45 + + IF MqttSendOnUpdate OR (Startup AND DimValue > 0) AND InitMqttDone THEN + + + 46 + + pMqttPublishQueue^.AddMessage( + + + 47 + + Payload := 'ON', + + + 48 + + Topic := THIS^.MQTTPublishTopic, + + + 49 + + Qos := MQTT.QoS.ExactlyOnce, + + + 50 + + MqttRetain := TRUE + + + 51 + + ); + + + 52 + + MqttSendOnUpdate := FALSE; + + + 53 + + END_IF + + + 54 + + + + + 55 + + IF MqttSendOffUpdate OR (Startup AND DimValue = 0) AND InitMqttDone THEN + + + 56 + + pMqttPublishQueue^.AddMessage( + + + 57 + + Payload := 'OFF', + + + 58 + + Topic := THIS^.MQTTPublishTopic, + + + 59 + + Qos := MQTT.QoS.ExactlyOnce, + + + 60 + + MqttRetain := TRUE + + + 61 + + ); + + + 62 + + MqttSendOffUpdate := FALSE; + + + 63 + + END_IF + + + 64 + + + + + 65 + + Startup:=FALSE; + + + 2 + + STATUS_LED := REAL_TO_BOOL(DimValue); + + + + + + + + + 66 + + {attribute 'reflection' := ''} + + + 67 + + FUNCTION_BLOCK FB_OUTPUT_DIMMER_DALI_MQTT EXTENDS FB_MQTT_BASE IMPLEMENTS MQTT.MQTT_SUBSCRIBE_CALLBACK + + + 68 + + VAR_INPUT + + + 69 + + BALLAST: typBallast; + + + 70 + + TOGGLE: BOOL; + + + 71 + + P_LONG: BOOL; + + + 72 + + PRIO_HIGH: BOOL := FALSE; + + + 73 + + PRIO_LOW: BOOL := FALSE; + + + 74 + + END_VAR + + + 75 + + VAR_OUTPUT + + + 76 + + STATUS_LED: BOOL; + + + 77 + + END_VAR + + + 78 + + VAR + + + 79 + + /// Refelection: object's full instance name + + + 80 + + {attribute 'noinit'} + + + 81 + + {attribute 'instance-path' := ''} + + + 82 + + InstancePath: STRING; + + + 83 + + Startup: BOOL := TRUE; + + + 84 + + DaliSendDimValue: FbDaliSendDimValue; + + + 85 + + DaliSendFadeTime: FbDaliSendFadeTime; + + + 86 + + DaliSendFadeRate: FbDaliSendFadeRate; + + + 87 + + MqttSendBrightnessUpdate: BOOL; + + + 88 + + MqttSendOnUpdate: BOOL; + + + 89 + + MqttSendOffUpdate: BOOL; + + + 90 + + Toggle_RTrigger: Standard.R_TRIG; + + + 91 + + DaliSyncSignalGenerator: Util.BLINK; + + + 92 + + DimDirection: INT := 1; + + + 93 + + END_VAR + + + 94 + + VAR PERSISTENT + + + 95 + + DimValue: REAL; + + + 96 + + END_VAR + + + 1 + + + + + + + 96 + Standard + + False + + 00000000-0000-0000-0000-000000000000 + + -1 + True @@ -14345,7 +14879,872 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115483685217844 + 638115483685217844 + + + + + + + 3 + + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + + + 4 + + + + + 5 + + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + + + 6 + + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + + + 7 + + ELSE + + + 8 + + id := overruleId; // 'MY_PH_GND_HALL_01' + + + 9 + + END_IF + + + 10 + + + + + 11 + + Device^.CreateCoverEntity( + + + 12 + + Name := name, + + + 13 + + Id := id, + + + 14 + + Meta := meta, + + + 15 + + CommandTopic := THIS^.MQTTSubscribeTopic, + + + 16 + + PayloadOpen := 'OPEN', + + + 17 + + PayloadClose := 'CLOSE', + + + 18 + + PayloadStop := 'STOP', + + + 19 + + StateTopic := THIS^.MQTTPublishTopic, + + + 20 + + StateOpen := 'OPEN', + + + 21 + + StateClosed := 'CLOSED', + + + 22 + + DeviceClass := DeviceClass + + + 23 + + ); + + + 24 + + + + + 25 + + initMqttDiscoveryDone := TRUE; + + + 2 + + END_IF + + + + + + + + + 26 + + METHOD InitMqttDiscovery + + + 27 + + VAR_INPUT + + + 28 + + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + + + 29 + + Name: STRING(255); + + + 30 + + overruleId: STRING(255) := ''; + + + 31 + + meta: STRING(255) := ''; + + + 32 + + DeviceClass: STRING(50) := 'shutter'; + + + 33 + + END_VAR + + + 34 + + VAR + + + 35 + + id: STRING(255); + + + 36 + + END_VAR + + + 1 + + + + + + + + a78cae3d-77db-4556-bb78-ee45b5903249 + + FB_OUTPUT_COVER_MQTT + + -1 + + + False + + cb2a9447-21b5-4579-addb-f9df7cecaa34 + a78cae3d-77db-4556-bb78-ee45b5903249 + PublishReceived + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + + + + + + f8a58466-d7f6-439f-bbb8-d4600e41d099 + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc + + 638115483684517851 + + + + + + + 3 + + //first check if Mqtt is initialized, otherwise do nothing + + + 4 + + IF NOT(InitMqttDone) THEN + + + 5 + + //mark the interface call from the collector as done + + + 6 + + PublishReceived := TRUE; + + + 7 + + //check if the packet is for this FB + + + 8 + + ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN + + + 9 + + //mark the interface call from the collector as done + + + 10 + + PublishReceived := TRUE; + + + 11 + + //now process the data + + + 12 + + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('STOP')) THEN + + + 13 + + THIS^.MqttRequestStop:=TRUE; + + + 14 + + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('OPEN')) THEN + + + 15 + + THIS^.MqttRequestOpen:=TRUE; + + + 16 + + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('CLOSE')) THEN + + + 17 + + THIS^.MqttRequestClose:=TRUE; + + + 18 + + END_IF + + + 19 + + + + + 2 + + END_IF + + + + + + + + + 20 + + METHOD PublishReceived : BOOL + + + 21 + + VAR_INPUT + + + 22 + + ///Collection of recived Data + + + 23 + + Data: MQTT.CALLBACK_DATA; + + + 24 + + END_VAR + + + 1 + + + + + + + + a78cae3d-77db-4556-bb78-ee45b5903249 + + FB_OUTPUT_COVER_MQTT + + -1 + + + False + + 6b17af45-4df7-4c05-97a9-2efc96ffe06a + 363f82ae-0e61-485f-89ce-768985a60108 + ConfigureFunctionBlock + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + + + + + + f8a58466-d7f6-439f-bbb8-d4600e41d099 + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc + + 638645790961782298 + + + + + + + 3 + + DaliSendFadeTime.bFadeTime := FadeTime; + + + 2 + + DaliSendFadeRate.bFadeRate := FadeRate; + + + + + + + + + 4 + + METHOD ConfigureFunctionBlock : BOOL + + + 5 + + VAR_INPUT + + + 6 + + FadeTime: BYTE; + + + 7 + + FadeRate: BYTE; + + + 8 + + END_VAR + + + 1 + + + + + + + + 363f82ae-0e61-485f-89ce-768985a60108 + + FB_OUTPUT_DIMMER_DALI_MQTT + + -1 + + + False + + 48380491-1d39-4dd6-afc4-455b9d70b408 + 363f82ae-0e61-485f-89ce-768985a60108 + InitMqtt + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + + + + + + f8a58466-d7f6-439f-bbb8-d4600e41d099 + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc + + 638645790959457923 + + + + + + + 3 + + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important + + + 4 + + + + + 5 + + (*pass trough*) + + + 6 + + THIS^.pMqttPublishQueue := pMqttPublishQueue; + + + 7 + + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + + + 8 + + THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; + + + 9 + + THIS^.pMqttPublishQueue:=pMqttPublishQueue; + + + 10 + + + + + 11 + + SUPER^.InitBaseMqtt(); + + + 12 + + pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + + + 13 + + + + + 2 + + + + + + + + + + + 14 + + METHOD InitMqtt + + + 15 + + VAR_INPUT + + + 16 + + MQTTPublishPrefix: POINTER TO STRING; + + + 17 + + MQTTSubscribePrefix: POINTER TO STRING; + + + 18 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 19 + + pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + + + 20 + + END_VAR + + + 1 + + + + + + + + 363f82ae-0e61-485f-89ce-768985a60108 + + FB_OUTPUT_DIMMER_DALI_MQTT + + -1 + + + False + + 948d1121-8995-4e30-9f66-4cbb37a4f011 + 363f82ae-0e61-485f-89ce-768985a60108 + InitMqttDiscovery + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + + + + + + f8a58466-d7f6-439f-bbb8-d4600e41d099 + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc + + 638645790958623935 + + + + + + + 3 + + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + + + 4 + + + + + 5 + + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + + + 6 + + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + + + 7 + + ELSE + + + 8 + + id := overruleId; // 'MY_PH_GND_HALL_01' + + + 9 + + END_IF + + + 10 + + + + + 11 + + Device^.CreateLightDimmerEntity( + + + 12 + + Name := name, + + + 13 + + Id := Id, + + + 14 + + Meta := meta, + + + 15 + + CommandTopic := THIS^.MQTTSubscribeTopic, + + + 16 + + PayloadOn := 'ON', + + + 17 + + PayloadOff := 'OFF', + + + 18 + + StateTopic := THIS^.MQTTPublishTopic, + + + 19 + + BrightnessCommandTopic := CONCAT(THIS^.MQTTSubscribeTopic, '/BRIGHTNESS'), + + + 20 + + BrightnessStateTopic := CONCAT(THIS^.MQTTPublishTopic, '/BRIGHTNESS'), + + + 21 + + BrightnessScale := 100, + + + 22 + + OnCommandType := 'brightness'); + + + 23 + + + + + 24 + + initMqttDiscoveryDone := TRUE; + + + 2 + + END_IF + + + + + + + + + 25 + + METHOD InitMqttDiscovery + + + 26 + + VAR_INPUT + + + 27 + + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + + + 28 + + Name: STRING(255); + + + 29 + + overruleId: STRING(255) := ''; + + + 30 + + meta: STRING(255) := ''; + + + 31 + + END_VAR + + + 32 + + VAR + + + 33 + + id: STRING(255); + + + 34 + + END_VAR + + + 1 + + + + + + + + 363f82ae-0e61-485f-89ce-768985a60108 + + FB_OUTPUT_DIMMER_DALI_MQTT + + -1 + + + False + + 6617d080-b077-42c8-90b9-5c529483eece + 363f82ae-0e61-485f-89ce-768985a60108 + PublishReceived + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + + + + + + f8a58466-d7f6-439f-bbb8-d4600e41d099 + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc + + 638645790960223358 @@ -14354,122 +15753,87 @@ 3 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + //first check if Mqtt is initialized, otherwise do nothing 4 - + IF NOT(InitMqttDone) THEN 5 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + //mark the interface call from the collector as done 6 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + PublishReceived := TRUE; 7 - ELSE + 8 - id := overruleId; // 'MY_PH_GND_HALL_01' + ELSIF MQTTSubscribeTopic = Data.TopicOut^ THEN 9 - END_IF + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('ON')) THEN 10 - + SetDimValue(100); 11 - Device^.CreateCoverEntity( + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('OFF')) THEN 12 - Name := name, + SetDimValue(0); 13 - Id := id, + END_IF 14 - Meta := meta, + 15 - CommandTopic := THIS^.MQTTSubscribeTopic, + ELSIF CONCAT(MQTTSubscribeTopic, '/BRIGHTNESS') = Data.TopicOut^ THEN 16 - PayloadOpen := 'OPEN', + IF OSCAT_BASIC.IS_CC(str:= Data.PayloadString^,cmp:='0123456789.') AND THIS^.PRIO_HIGH = FALSE THEN 17 - PayloadClose := 'CLOSE', + SetDimValue(STRING_TO_REAL(Data.PayloadString^)); 18 - PayloadStop := 'STOP', - - - 19 - - StateTopic := THIS^.MQTTPublishTopic, - - - 20 - - StateOpen := 'OPEN', - - - 21 - - StateClosed := 'CLOSED', - - - 22 - - DeviceClass := DeviceClass - - - 23 - - ); - - - 24 - - - - - 25 - - initMqttDiscoveryDone := TRUE; + END_IF 2 - END_IF + END_IF @@ -14478,57 +15842,27 @@ - 26 + 19 - METHOD InitMqttDiscovery + METHOD PublishReceived : BOOL - 27 + 20 VAR_INPUT - 28 - - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - - - 29 - - Name: STRING(255); - - - 30 - - overruleId: STRING(255) := ''; - - - 31 - - meta: STRING(255) := ''; - - - 32 - - DeviceClass: STRING(50) := 'shutter'; - - - 33 - - END_VAR - - - 34 + 21 - VAR + ///Collection of recived Data - 35 + 22 - id: STRING(255); + Data: MQTT.CALLBACK_DATA; - 36 + 23 END_VAR @@ -14541,18 +15875,18 @@ - a78cae3d-77db-4556-bb78-ee45b5903249 + 363f82ae-0e61-485f-89ce-768985a60108 - FB_OUTPUT_COVER_MQTT + FB_OUTPUT_DIMMER_DALI_MQTT -1 False - cb2a9447-21b5-4579-addb-f9df7cecaa34 - a78cae3d-77db-4556-bb78-ee45b5903249 - PublishReceived + 472024f5-1424-4e74-88fa-82501ee22b71 + 363f82ae-0e61-485f-89ce-768985a60108 + SetDimValue @@ -14576,7 +15910,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115483684517851 + 638645790961044179 @@ -14585,92 +15919,87 @@ 3 - //first check if Mqtt is initialized, otherwise do nothing + THIS^.MqttSendBrightnessUpdate := TRUE; 4 - IF NOT(InitMqttDone) THEN + 5 - //mark the interface call from the collector as done + IF THIS^.DimValue = 0 AND Value > 0 THEN 6 - PublishReceived := TRUE; + THIS^.MqttSendOnUpdate := TRUE; 7 - //check if the packet is for this FB + END_IF 8 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN + 9 - //mark the interface call from the collector as done + IF THIS^.DimValue > 0 AND Value = 0 THEN 10 - PublishReceived := TRUE; + THIS^.MqttSendOffUpdate := TRUE; 11 - //now process the data + END_IF 12 - IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('STOP')) THEN + 13 - THIS^.MqttRequestStop:=TRUE; + IF Value = 0 THEN 14 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('OPEN')) THEN + DimDirection := 1; 15 - THIS^.MqttRequestOpen:=TRUE; + ELSIF Value = 100 THEN 16 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('CLOSE')) THEN + DimDirection := -1; 17 - THIS^.MqttRequestClose:=TRUE; + END_IF 18 - END_IF - - - 19 - 2 - END_IF + THIS^.DimValue := Value; @@ -14679,27 +16008,22 @@ - 20 + 19 - METHOD PublishReceived : BOOL + METHOD PRIVATE SetDimValue - 21 + 20 VAR_INPUT - 22 - - ///Collection of recived Data - - - 23 + 21 - Data: MQTT.CALLBACK_DATA; + Value: REAL; - 24 + 22 END_VAR @@ -14712,9 +16036,9 @@ - a78cae3d-77db-4556-bb78-ee45b5903249 + 363f82ae-0e61-485f-89ce-768985a60108 - FB_OUTPUT_COVER_MQTT + FB_OUTPUT_DIMMER_DALI_MQTT -1 @@ -28136,7 +29460,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638271218545506870 + 638645794352779442 @@ -28230,7 +29554,7 @@ 20 - MqttDiscMsgLightDim.on_cmd_type.CharString := 'last'; + MqttDiscMsgLightDim.on_cmd_type.CharString := OnCommandType; 21 @@ -28553,6 +29877,11 @@ BrightnessScale: INT; + + 94 + + OnCommandType: STRING := 'last'; + 83 @@ -33539,7 +34868,7 @@ - AAEAAAD/////AQAAAAAAAAAMAgAAADxDb3JlLCBWZXJzaW9uPTMuNS4xNy4yLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAACNfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuUHJvZmlsZQMAAAAeX3BsdWdJbkd1aWRUb1ZlcnNpb25Db25zdHJhaW50Fl9wbHVnSW5HdWlkVG9FeHRlbnNpb24aX3BsdWdJbkd1aWRUb0V4dGVuc2lvbkxpc3QEBAQ9XzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb1ZlcnNpb25Db25zdHJhaW50RGljdGlvbmFyeQIAAAAwXzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb0Jvb2xEaWN0aW9uYXJ5AgAAAEBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvUHJvZmlsZUV4dGVuc2lvbkxpc3REaWN0aW9uYXJ5AgAAAAIAAAAJAwAAAAkEAAAACQUAAAAFAwAAAD1fM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvVmVyc2lvbkNvbnN0cmFpbnREaWN0aW9uYXJ5AQAAABhEaWN0aW9uYXJ5QmFzZStoYXNodGFibGUDHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUCAAAACQYAAAAFBAAAADBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvQm9vbERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJBwAAAAUFAAAAQF8zUy5Db0RlU3lzLkNvcmUuQ29tcG9uZW50cy5HdWlkVG9Qcm9maWxlRXh0ZW5zaW9uTGlzdERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJCAAAAAQGAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUHAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhhc2hTaXplBEtleXMGVmFsdWVzAAADAwAFBQsIHFN5c3RlbS5Db2xsZWN0aW9ucy5JQ29tcGFyZXIkU3lzdGVtLkNvbGxlY3Rpb25zLklIYXNoQ29kZVByb3ZpZGVyCOxROD+vAAAACgqvAQAACQkAAAAJCgAAAAEHAAAABgAAAOxROD8AAAAACgoDAAAACQsAAAAJDAAAAAEIAAAABgAAAOxROD8AAAAACgoDAAAACQ0AAAAJDgAAABAJAAAAqQAAAAkPAAAACRAAAAAJEQAAAAkSAAAACRMAAAAJFAAAAAkVAAAACRYAAAAJFwAAAAkYAAAACRkAAAAJGgAAAAkbAAAACRwAAAAJHQAAAAkeAAAACR8AAAAJIAAAAAkhAAAACSIAAAAJIwAAAAkkAAAACSUAAAAJJgAAAAknAAAACSgAAAAJKQAAAAkqAAAACSsAAAAJLAAAAAktAAAACS4AAAAJLwAAAAkwAAAACTEAAAAJMgAAAAkzAAAACTQAAAAJNQAAAAk2AAAACTcAAAAJOAAAAAk5AAAACToAAAAJOwAAAAk8AAAACT0AAAAJPgAAAAk/AAAACUAAAAAJQQAAAAlCAAAACUMAAAAJRAAAAAlFAAAACUYAAAAJRwAAAAlIAAAACUkAAAAJSgAAAAlLAAAACUwAAAAJTQAAAAlOAAAACU8AAAAJUAAAAAlRAAAACVIAAAAJUwAAAAlUAAAACVUAAAAJVgAAAAlXAAAACVgAAAAJWQAAAAlaAAAACVsAAAAJXAAAAAldAAAACV4AAAAJXwAAAAlgAAAACWEAAAAJYgAAAAljAAAACWQAAAAJZQAAAAlmAAAACWcAAAAJaAAAAAlpAAAACWoAAAAJawAAAAlsAAAACW0AAAAJbgAAAAlvAAAACXAAAAAJcQAAAAlyAAAACXMAAAAJdAAAAAl1AAAACXYAAAAJdwAAAAl4AAAACXkAAAAJegAAAAl7AAAACXwAAAAJfQAAAAl+AAAACX8AAAAJgAAAAAmBAAAACYIAAAAJgwAAAAmEAAAACYUAAAAJhgAAAAmHAAAACYgAAAAJiQAAAAmKAAAACYsAAAAJjAAAAAmNAAAACY4AAAAJjwAAAAmQAAAACZEAAAAJkgAAAAmTAAAACZQAAAAJlQAAAAmWAAAACZcAAAAJmAAAAAmZAAAACZoAAAAJmwAAAAmcAAAACZ0AAAAJngAAAAmfAAAACaAAAAAJoQAAAAmiAAAACaMAAAAJpAAAAAmlAAAACaYAAAAJpwAAAAmoAAAACakAAAAJqgAAAAmrAAAACawAAAAJrQAAAAmuAAAACa8AAAAJsAAAAAmxAAAACbIAAAAJswAAAAm0AAAACbUAAAAJtgAAAAm3AAAAEAoAAACpAAAACbgAAAAJuQAAAAm6AAAACbsAAAAJvAAAAAm9AAAACb4AAAAJvwAAAAnAAAAACcEAAAAJwgAAAAnDAAAACcQAAAAJxQAAAAnGAAAACccAAAAJyAAAAAnJAAAACcoAAAAJywAAAAnMAAAACc0AAAAJzgAAAAnPAAAACdAAAAAJ0QAAAAnSAAAACdMAAAAJ1AAAAAnVAAAACdYAAAAJ1wAAAAnYAAAACdkAAAAJ2gAAAAnbAAAACdwAAAAJ3QAAAAneAAAACd8AAAAJ4AAAAAnhAAAACeIAAAAJ4wAAAAnkAAAACeUAAAAJ5gAAAAnnAAAACegAAAAJ6QAAAAnqAAAACesAAAAJ7AAAAAntAAAACe4AAAAJ7wAAAAnwAAAACfEAAAAJ8gAAAAnzAAAACfQAAAAJ9QAAAAn2AAAACfcAAAAJ+AAAAAn5AAAACfoAAAAJ+wAAAAn8AAAACf0AAAAJ/gAAAAn/AAAACQABAAAJAQEAAAkCAQAACQMBAAAJBAEAAAkFAQAACQYBAAAJBwEAAAkIAQAACQkBAAAJCgEAAAkLAQAACQwBAAAJDQEAAAkOAQAACQ8BAAAJEAEAAAkRAQAACRIBAAAJEwEAAAkUAQAACRUBAAAJFgEAAAkXAQAACRgBAAAJGQEAAAkaAQAACRsBAAAJHAEAAAkdAQAACR4BAAAJHwEAAAkgAQAACSEBAAAJIgEAAAkjAQAACSQBAAAJJQEAAAkmAQAACScBAAAJKAEAAAkpAQAACSoBAAAJKwEAAAksAQAACS0BAAAJLgEAAAkvAQAACTABAAAJMQEAAAkyAQAACTMBAAAJNAEAAAk1AQAACTYBAAAJNwEAAAk4AQAACTkBAAAJOgEAAAk7AQAACTwBAAAJPQEAAAk+AQAACT8BAAAJQAEAAAlBAQAACUIBAAAJQwEAAAlEAQAACUUBAAAJRgEAAAlHAQAACUgBAAAJSQEAAAlKAQAACUsBAAAJTAEAAAlNAQAACU4BAAAJTwEAAAlQAQAACVEBAAAJUgEAAAlTAQAACVQBAAAJVQEAAAlWAQAACVcBAAAJWAEAAAlZAQAACVoBAAAJWwEAAAlcAQAACV0BAAAJXgEAAAlfAQAACWABAAAQCwAAAAAAAAAQDAAAAAAAAAAQDQAAAAAAAAAQDgAAAAAAAAAEDwAAAAtTeXN0ZW0uR3VpZAsAAAACX2ECX2ICX2MCX2QCX2UCX2YCX2cCX2gCX2kCX2oCX2sAAAAAAAAAAAAAAAgHBwICAgICAgICWuyUr5L9jkGnkbl7WKcqBwEQAAAADwAAAD1psfDKWPNOp5/Ty5I/8DABEQAAAA8AAACOf63gy/QeTLv/e5cv4YVRARIAAAAPAAAAsuhsAY3BeE+uzG87z32KpQETAAAADwAAANT/u7IHoVhKo9ucePUT2ckBFAAAAA8AAACcPmiggjN4SqHa4uRWoTe1ARUAAAAPAAAADy9C/3eQTUWDrPCJWESddQEWAAAADwAAAK8IIX9tHcZGgQZ70RkLuWoBFwAAAA8AAAA6RwhsyWNSSZKm/waSiX3pARgAAAAPAAAAIocbrfVDoEq123XzL2CrjgEZAAAADwAAAA6Q6K9T8M5Og6qTKoSwBLABGgAAAA8AAAAUS/MppeClT4c3yLrvIBtqARsAAAAPAAAA4NfVXbOXrku+4kyJG3IcWwEcAAAADwAAAIL1Lul3Wq9DhfweaUn2nbMBHQAAAA8AAABttTuumFsGR4y2W/6qAK3gAR4AAAAPAAAAV616bZoWQkm841ow0gV67AEfAAAADwAAAMOKXsYsbMZJt3K7MbKx8qABIAAAAA8AAACpthSKCltARIgLqtHwqmR4ASEAAAAPAAAAi0Uzj1S350q4BX6EHCN4GgEiAAAADwAAAJa/jUSyh8NBkjz7AenFTQ4BIwAAAA8AAAA1dbXBt/CfQZt2RqT4MLdwASQAAAAPAAAA3klNVQXbV0O0cRyexRzcBAElAAAADwAAAIekenoooPpDiUj197NgfFQBJgAAAA8AAAA4Syrfz1bbT5svH0YRQx3RAScAAAAPAAAA/DTl/gWtfUWBjQFM0lnEDwEoAAAADwAAADb852pHYQVMocunmbUYFXUBKQAAAA8AAABnX2sztfIRTJPf2KJb67KoASoAAAAPAAAAC9Bk1ogeLEi/Gzn1BdwS1AErAAAADwAAAC9FgCZDxAhCiJMGtsWtxVsBLAAAAA8AAABLpYtWOEbRSq8c3ZIJqTn9AS0AAAAPAAAACrlIF8QoH0ew8pRG0GCgWQEuAAAADwAAAKOwCgOmutRFvFAYHasWy/QBLwAAAA8AAADLi3QQofnxT6U0Ruc8z+mEATAAAAAPAAAABpBxVoHa3UWO28DbmRePOAExAAAADwAAAER+gHokGvFJl5kVTdJTrI4BMgAAAA8AAAB0iY4QaicMT5hlKA5SmZCDATMAAAAPAAAAo1JqLw/wWE2HSVF0IzNStAE0AAAADwAAAGW6+fU402dErsSMlSnUI8cBNQAAAA8AAADia46/qEOhRYokU3duLTzUATYAAAAPAAAAiCXtBxUBw0ev+uthkm2bTgE3AAAADwAAAEby9w94OwxKncGUEF3dVjsBOAAAAA8AAADUz89AuvukT4tLbeye2XQEATkAAAAPAAAAXbYFj+HFuEqZ0t8OnqQ/VQE6AAAADwAAAA3dhquQKjBOkOmiz/cGwkUBOwAAAA8AAAA12rfh23vUQYK1TlOMGxyCATwAAAAPAAAAJv4GG9FT9ES1eEc3PrPrGwE9AAAADwAAAJ1WexDDyeBOomv1tbcsqHgBPgAAAA8AAAD35pM0V1xmQqiwQ4YsCTMvAT8AAAAPAAAAvtEkxxB3NEiUanYRierPoQFAAAAADwAAAK8HyKwQpERGttE7gAIkvMkBQQAAAA8AAAA2WqxlnAkAR7UB5W8T4LTTAUIAAAAPAAAAUuM5ruHgMU65VIZVI42xkAFDAAAADwAAALO+mcvUQTZGo9x0XKbAi8wBRAAAAA8AAACeQ6s3I4QoSJ+WG1mEnCSbAUUAAAAPAAAA+yn3tHxGOE2M63Cf0mK03gFGAAAADwAAALKdlzAFomdAgLHJmxw9+/MBRwAAAA8AAADHKN1CFqKpQZfltooozqLrAUgAAAAPAAAAphhrU53ckka5Y+4Z9XPZhAFJAAAADwAAACF7aswic/dHmBQh3Ujhg78BSgAAAA8AAACTgqLPdMynQL393STB+vXZAUsAAAAPAAAAcDu5rJZLmkOqBkvnfcveGwFMAAAADwAAAEsGvfSSUj1FhjLD9cRIzqcBTQAAAA8AAAB6wpHSlKcMSpWA1NOvpNc9AU4AAAAPAAAA4DKwy8N1uUu83rbJ/x1t1gFPAAAADwAAAO68/Zepr39ChT4Pr+zbR4sBUAAAAA8AAAAWJWWBZ0mKT5/1NuMVDGItAVEAAAAPAAAAVMVpV63m/kGq/KpyKxyOEwFSAAAADwAAAKouPwpkKY1Kjfn2gAVLyeABUwAAAA8AAABPtY3L6AB6SopNt4y+6mFDAVQAAAAPAAAAzYK+B4A2y0upV16ZVwhD1wFVAAAADwAAAHgvp9ETSKFIhtCRM0hl8E8BVgAAAA8AAAAVpI63eXRLSr0PDU99EM+tAVcAAAAPAAAAA/C4iEJ4z0OWNXnbVuYU3wFYAAAADwAAAFP1X6cen5hCuNfNqgPtBmUBWQAAAA8AAAC+4CENW7YFSYI39dY+yuJvAVoAAAAPAAAAyh++p8DxIE6dN8VV72G9FgFbAAAADwAAABy9z59SsdhLi8KXc7tWYIQBXAAAAA8AAADAoiU6eVw7SIycDH5aegddAV0AAAAPAAAAfE8YVixxykmyPMuF816MVAFeAAAADwAAAJpFH7lMw0NBs/JFMeUdjBABXwAAAA8AAAD1f5rNwT72RaWwpTMavi0dAWAAAAAPAAAAQYhAeX9P9E6RP2PmTZKePAFhAAAADwAAAExpdN3kG4JEiKoXzmLLqsoBYgAAAA8AAACjpJ8Ruo2VRZhtqruocAUkAWMAAAAPAAAAYzc8lUqsSEumyi4iw6CpkgFkAAAADwAAALoZ1vU3kjVFno9uXOYfJZsBZQAAAA8AAABFszCuy6qkQ4/eQhTMV2IRAWYAAAAPAAAAg2g8QT/0IEijsjZjBzdSUgFnAAAADwAAAMUlN9azvPlLstDzjU1SQIUBaAAAAA8AAAC+mlRNL0NaT5pjyZnggYSxAWkAAAAPAAAAo09Ao59Vs0+e1jbSoZX8NgFqAAAADwAAABUMm8Qc7ZtNhDL+u4C79ssBawAAAA8AAACwi6thbesIQL3mG8U4fhZUAWwAAAAPAAAAoFEPntrRzEKrcAlDWNuqgQFtAAAADwAAAFC3KKKVna9DtqeCjv/09zgBbgAAAA8AAAB7L5+zDG4CSasUsrhaAWDbAW8AAAAPAAAAZx5e0/tp30mE1k1bRkU63wFwAAAADwAAAC4hwMO9FR1Hl/MtAUH4/tcBcQAAAA8AAAAgHK+6OAZ8RJgvZ/+lvkqzAXIAAAAPAAAAe8qIXKAGZUy8jqJXjBfoOQFzAAAADwAAAEZUza8USedPu3ib/+tw/RcBdAAAAA8AAADcfOTjvW4vR5CQgEEQTxXGAXUAAAAPAAAAaus4puPnsU+ElsA0OUP/wgF2AAAADwAAAPgMiVwFHCVDkLg8w+heVMoBdwAAAA8AAAA1K5+nHDksQbgDodLk1XE6AXgAAAAPAAAABYPSXidBQEC/DoT/OEPdUAF5AAAADwAAANgeze+3jpJNhR1F/hpFW3kBegAAAA8AAAC71vsw0RN8QJhe3wndcxlBAXsAAAAPAAAAJ6Huy6UqYkGF2+JicgMO6QF8AAAADwAAAAQZ2/aAUj1KqrQRSRvcceoBfQAAAA8AAACO+ltOSNUSQLYuc5+/tLnnAX4AAAAPAAAALn9A1HmTG0yIhLunpegYXwF/AAAADwAAAMFQzGO/qqhMllSzgiwjESYBgAAAAA8AAABEGUwaVA6XRI6/Ck1PnWPnAYEAAAAPAAAA0vnXkMkniUeCUGwYJitKDgGCAAAADwAAAKvptFwYfVJMrcdC/pz1IioBgwAAAA8AAACJNjR+X5qqRr9WWQPE7+xZAYQAAAAPAAAAXB3plvtgMUaT9I9n4CQ9xgGFAAAADwAAAAQo9GZPa1dEm8Pc5wnC+3IBhgAAAA8AAAC847bFrBV4SouLO+1kGzmNAYcAAAAPAAAAg9HcBjUnR02mEnK2BwKXFAGIAAAADwAAAHXZ+y8yIDdHhO+tzzd/mboBiQAAAA8AAAA5YYcG15EGTJHMonuFZhnFAYoAAAAPAAAAsgclsDFSVEehRniVfZn2BAGLAAAADwAAAIexF11nIxNIia+jCJBIezsBjAAAAA8AAAAlXcnAWX0eQ6n0LK65YfgSAY0AAAAPAAAAxZknScbnGEOnnMdPy6tUGQGOAAAADwAAACGsBcEZtVNHmYK1Qby2nJEBjwAAAA8AAACZWnpefKgmQYSuaOKkRbbfAZAAAAAPAAAAFGm8pYtW7EqI/VOpVRanmwGRAAAADwAAAAV0te0UJFpNuf6SWK1OrgoBkgAAAA8AAACiHYAijBBjRLbnQQy16GlXAZMAAAAPAAAAcbZsXT+h7kWDr2N5EhM3BAGUAAAADwAAAH/er5Pi+gRJgTrD0lLQJpkBlQAAAA8AAAC70DTQQnV5QYSXhTBSvNtbAZYAAAAPAAAAbVp4Kkb10UeRB2vKoPIyzwGXAAAADwAAAMEytgrggs5DsBQjDmmNFYABmAAAAA8AAACJ0jLZCk92T7DnbQP3p+d2AZkAAAAPAAAAhnno7TSNr0uGUyqNMScIiQGaAAAADwAAALuQojDJAc9Dj9GMERd7dOEBmwAAAA8AAABK27wBhcqHR6OJgYVlPbcGAZwAAAAPAAAAQjjTJvMkEUylT3I4iW7pmwGdAAAADwAAAK46HQA2OpVCsa+b+PrqUR0BngAAAA8AAACoc9CJAYJiQb9Mf1/Vfq6sAZ8AAAAPAAAAGNZ+cBMH5kmm1rvSh/64jgGgAAAADwAAAK0B30FSWKlFpHI8nbpfwz0BoQAAAA8AAABBeTP/Djd2QbPRxk0iTrFmAaIAAAAPAAAARRDVcWZjVUGh9fChpLYjCgGjAAAADwAAAKgNStjQgCJGgeclsPA2C0IBpAAAAA8AAAC7D836EKvIT5BXjwIrDwo+AaUAAAAPAAAA7jDOa6rIFEmbGbABmZlfJQGmAAAADwAAAHMunt8V9jdMtQ1nmtKjpDMBpwAAAA8AAABytpA8zmWYSbTRn1yjrPQeAagAAAAPAAAAxzG+vdcLmkqkF/UTPo/NaQGpAAAADwAAAFyu2SmamfdKlpNk1kSyMkoBqgAAAA8AAADxHohC9COUQ4GGNhfbEDKsAasAAAAPAAAAUi1b1RwP2k6hCewZolRJeAGsAAAADwAAAMvwyrEYzBBHtKO1Tt/EjlIBrQAAAA8AAAAYfJPc8OlNQ4W3G49JnjeKAa4AAAAPAAAAF9KBIGm50UCxuzIRswJDlQGvAAAADwAAAOCHP5IfzMlOp1kLvqFayHsBsAAAAA8AAACvONpViueuRpFbdoZlf2+sAbEAAAAPAAAAfhLjfrtm5UaHNDB2fB4plgGyAAAADwAAADXs1mOsNsZCt83kZa7STFEBswAAAA8AAADW/+ijjOTtRZhEgdlfcd8GAbQAAAAPAAAA9fXBsFpuJEmSt5W44JU7KQG1AAAADwAAAApa4BIm8WBKmHb6PANuaEEBtgAAAA8AAAApNPcGI6c8T5tJG4zlKgSGAbcAAAAPAAAAxiH7prHvh0mmvPLcF1LCVAW4AAAAMl8zUy5Db0RlU3lzLkNvcmUuQ29tcG9uZW50cy5FeGFjdFZlcnNpb25Db25zdHJhaW50AQAAAAhfdmVyc2lvbgMOU3lzdGVtLlZlcnNpb24CAAAACWEBAAABuQAAALgAAAAJYgEAAAG6AAAAuAAAAAljAQAAAbsAAAC4AAAACWQBAAABvAAAALgAAAAJZQEAAAG9AAAAuAAAAAlmAQAAAb4AAAC4AAAACWcBAAABvwAAALgAAAAJaAEAAAHAAAAAuAAAAAlpAQAABcEAAAAzXzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLk5ld2VzdFZlcnNpb25Db25zdHJhaW50AAAAAAIAAAABwgAAALgAAAAJagEAAAHDAAAAuAAAAAlrAQAAAcQAAADBAAAAAcUAAAC4AAAACWwBAAABxgAAALgAAAAJbQEAAAHHAAAAuAAAAAluAQAAAcgAAAC4AAAACW8BAAAByQAAALgAAAAJcAEAAAHKAAAAuAAAAAlxAQAAAcsAAAC4AAAACXIBAAABzAAAALgAAAAJcwEAAAHNAAAAuAAAAAl0AQAAAc4AAAC4AAAACXUBAAABzwAAAMEAAAAB0AAAALgAAAAJdgEAAAHRAAAAuAAAAAl3AQAAAdIAAAC4AAAACXgBAAAB0wAAALgAAAAJeQEAAAHUAAAAuAAAAAl6AQAAAdUAAAC4AAAACXsBAAAB1gAAALgAAAAJfAEAAAHXAAAAuAAAAAl9AQAAAdgAAAC4AAAACX4BAAAB2QAAALgAAAAJfwEAAAHaAAAAuAAAAAmAAQAAAdsAAAC4AAAACYEBAAAB3AAAALgAAAAJggEAAAHdAAAAuAAAAAmDAQAAAd4AAAC4AAAACYQBAAAB3wAAALgAAAAJhQEAAAHgAAAAuAAAAAmGAQAAAeEAAAC4AAAACYcBAAAB4gAAALgAAAAJiAEAAAHjAAAAuAAAAAmJAQAAAeQAAAC4AAAACYoBAAAB5QAAALgAAAAJiwEAAAHmAAAAuAAAAAmMAQAAAecAAAC4AAAACY0BAAAB6AAAALgAAAAJjgEAAAHpAAAAuAAAAAmPAQAAAeoAAAC4AAAACZABAAAB6wAAALgAAAAJkQEAAAHsAAAAuAAAAAmSAQAAAe0AAAC4AAAACZMBAAAB7gAAALgAAAAJlAEAAAHvAAAAuAAAAAmVAQAAAfAAAAC4AAAACZYBAAAB8QAAALgAAAAJlwEAAAHyAAAAuAAAAAmYAQAAAfMAAAC4AAAACZkBAAAB9AAAALgAAAAJmgEAAAH1AAAAuAAAAAmbAQAAAfYAAAC4AAAACZwBAAAB9wAAALgAAAAJnQEAAAH4AAAAuAAAAAmeAQAAAfkAAAC4AAAACZ8BAAAB+gAAALgAAAAJoAEAAAH7AAAAuAAAAAmhAQAAAfwAAAC4AAAACaIBAAAB/QAAALgAAAAJowEAAAH+AAAAuAAAAAmkAQAAAf8AAAC4AAAACaUBAAABAAEAALgAAAAJpgEAAAEBAQAAuAAAAAmnAQAAAQIBAAC4AAAACagBAAABAwEAALgAAAAJqQEAAAEEAQAAuAAAAAmqAQAAAQUBAAC4AAAACasBAAABBgEAALgAAAAJrAEAAAEHAQAAuAAAAAmtAQAAAQgBAAC4AAAACa4BAAABCQEAALgAAAAJrwEAAAEKAQAAuAAAAAmwAQAAAQsBAAC4AAAACbEBAAABDAEAALgAAAAJsgEAAAENAQAAuAAAAAmzAQAAAQ4BAAC4AAAACbQBAAABDwEAALgAAAAJtQEAAAEQAQAAuAAAAAm2AQAAAREBAAC4AAAACbcBAAABEgEAALgAAAAJuAEAAAETAQAAuAAAAAm5AQAAARQBAAC4AAAACboBAAABFQEAALgAAAAJuwEAAAEWAQAAuAAAAAm8AQAAARcBAAC4AAAACb0BAAABGAEAALgAAAAJvgEAAAEZAQAAuAAAAAm/AQAAARoBAAC4AAAACcABAAABGwEAALgAAAAJwQEAAAEcAQAAuAAAAAnCAQAAAR0BAAC4AAAACcMBAAABHgEAALgAAAAJxAEAAAEfAQAAuAAAAAnFAQAAASABAAC4AAAACcYBAAABIQEAALgAAAAJxwEAAAEiAQAAuAAAAAnIAQAAASMBAAC4AAAACckBAAABJAEAALgAAAAJygEAAAElAQAAuAAAAAnLAQAAASYBAAC4AAAACcwBAAABJwEAALgAAAAJzQEAAAEoAQAAuAAAAAnOAQAAASkBAAC4AAAACc8BAAABKgEAALgAAAAJ0AEAAAErAQAAuAAAAAnRAQAAASwBAAC4AAAACdIBAAABLQEAALgAAAAJ0wEAAAEuAQAAuAAAAAnUAQAAAS8BAAC4AAAACdUBAAABMAEAALgAAAAJ1gEAAAExAQAAuAAAAAnXAQAAATIBAAC4AAAACdgBAAABMwEAALgAAAAJ2QEAAAE0AQAAuAAAAAnaAQAAATUBAAC4AAAACdsBAAABNgEAALgAAAAJ3AEAAAE3AQAAuAAAAAndAQAAATgBAAC4AAAACd4BAAABOQEAALgAAAAJ3wEAAAE6AQAAuAAAAAngAQAAATsBAAC4AAAACeEBAAABPAEAALgAAAAJ4gEAAAE9AQAAuAAAAAnjAQAAAT4BAAC4AAAACeQBAAABPwEAALgAAAAJ5QEAAAFAAQAAuAAAAAnmAQAAAUEBAAC4AAAACecBAAABQgEAALgAAAAJ6AEAAAFDAQAAuAAAAAnpAQAAAUQBAAC4AAAACeoBAAABRQEAALgAAAAJ6wEAAAFGAQAAuAAAAAnsAQAAAUcBAAC4AAAACe0BAAABSAEAALgAAAAJ7gEAAAFJAQAAuAAAAAnvAQAAAUoBAAC4AAAACfABAAABSwEAALgAAAAJ8QEAAAFMAQAAuAAAAAnyAQAAAU0BAAC4AAAACfMBAAABTgEAALgAAAAJ9AEAAAFPAQAAuAAAAAn1AQAAAVABAAC4AAAACfYBAAABUQEAALgAAAAJ9wEAAAFSAQAAwQAAAAFTAQAAuAAAAAn4AQAAAVQBAAC4AAAACfkBAAABVQEAALgAAAAJ+gEAAAFWAQAAuAAAAAn7AQAAAVcBAAC4AAAACfwBAAABWAEAALgAAAAJ/QEAAAFZAQAAuAAAAAn+AQAAAVoBAAC4AAAACf8BAAABWwEAALgAAAAJAAIAAAFcAQAAuAAAAAkBAgAAAV0BAAC4AAAACQICAAABXgEAALgAAAAJAwIAAAFfAQAAuAAAAAkEAgAAAWABAAC4AAAACQUCAAAEYQEAAA5TeXN0ZW0uVmVyc2lvbgQAAAAGX01ham9yBl9NaW5vcgZfQnVpbGQJX1JldmlzaW9uAAAAAAgICAgDAAAABQAAAA4AAAAAAAAAAWIBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAFjAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABZAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAWUBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFmAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABZwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAWgBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAFpAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABagEAAGEBAAADAAAABQAAAA4AAAAAAAAAAWsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFsAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABbQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAW4BAABhAQAAAwAAAAUAAAAOAAAACgAAAAFvAQAAYQEAAAMAAAAFAAAADgAAAB4AAAABcAEAAGEBAAADAAAABQAAAA4AAAAKAAAAAXEBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFyAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXQBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF1AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABdgEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF4AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABeQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXoBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAF7AQAAYQEAAAMAAAAFAAAADgAAAAoAAAABfAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAX0BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF+AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABfwEAAGEBAAADAAAABQAAAA4AAAAeAAAAAYABAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGBAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABggEAAGEBAAADAAAABQAAAA4AAAAKAAAAAYMBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGEAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABhQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYYBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGHAQAAYQEAAAMAAAAFAAAADgAAABQAAAABiAEAAGEBAAADAAAABQAAAA4AAAAUAAAAAYkBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGKAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYwBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGNAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABjgEAAGEBAAADAAAABQAAAA4AAAAKAAAAAY8BAABhAQAAAwAAAAUAAAAOAAAAFAAAAAGQAQAAYQEAAAMAAAAFAAAADgAAAB4AAAABkQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAZIBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGTAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABlAEAAGEBAAADAAAABQAAAA4AAAAAAAAAAZUBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGWAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABlwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAZgBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGZAQAAYQEAAAMAAAAFAAAADgAAAB4AAAABmgEAAGEBAAADAAAABQAAAA4AAAAeAAAAAZsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGcAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABnQEAAGEBAAADAAAABQAAAA4AAAAKAAAAAZ4BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGfAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABoAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAaEBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGiAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABowEAAGEBAAADAAAABQAAAA4AAAAAAAAAAaQBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAGlAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABpgEAAGEBAAADAAAABQAAAA4AAAAAAAAAAacBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGoAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABqQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAaoBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGrAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABrAEAAGEBAAADAAAABQAAAA4AAAAUAAAAAa0BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGuAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABrwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAbABAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGxAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABsgEAAGEBAAADAAAABQAAAA4AAAAAAAAAAbMBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAG0AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABtQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAbYBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAG3AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABuAEAAGEBAAADAAAABQAAAA4AAAAAAAAAAbkBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAG6AQAAYQEAAAMAAAAFAAAADgAAAAoAAAABuwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAbwBAABhAQAAAwAAAAUAAAAOAAAACgAAAAG9AQAAYQEAAAMAAAAFAAAADgAAABQAAAABvgEAAGEBAAADAAAABQAAAA4AAAAKAAAAAb8BAABhAQAAAwAAAAUAAAAOAAAACgAAAAHAAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABwQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAcIBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAHDAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABxAEAAGEBAAADAAAABQAAAA4AAAAAAAAAAcUBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHGAQAAYQEAAAMAAAAFAAAADgAAAB4AAAABxwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAcgBAABhAQAAAwAAAAUAAAAOAAAACgAAAAHJAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABygEAAGEBAAADAAAABQAAAA4AAAAeAAAAAcsBAABhAQAAAwAAAAUAAAAOAAAACgAAAAHMAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABzQEAAGEBAAADAAAABQAAAA4AAAAKAAAAAc4BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHPAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB0AEAAGEBAAADAAAABQAAAA4AAAAKAAAAAdEBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHSAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB0wEAAGEBAAADAAAABQAAAA4AAAAAAAAAAdQBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHVAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB1gEAAGEBAAADAAAABQAAAA4AAAAAAAAAAdcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHYAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB2QEAAGEBAAADAAAABQAAAA4AAAAAAAAAAdoBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAHbAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB3AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAd0BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHeAQAAYQEAAAMAAAAFAAAADgAAAB4AAAAB3wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAeABAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHhAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB4gEAAGEBAAADAAAABQAAAA4AAAAAAAAAAeMBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHkAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB5QEAAGEBAAADAAAABQAAAA4AAAAeAAAAAeYBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHnAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB6AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAekBAABhAQAAAwAAAAUAAAAOAAAACgAAAAHqAQAAYQEAAAMAAAAFAAAADgAAABQAAAAB6wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAewBAABhAQAAAwAAAAUAAAAOAAAAFAAAAAHtAQAAYQEAAAMAAAAFAAAADgAAABQAAAAB7gEAAGEBAAADAAAABQAAAA4AAAAAAAAAAe8BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHwAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB8QEAAGEBAAADAAAABQAAAA4AAAAUAAAAAfIBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHzAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB9AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAfUBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAH2AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB9wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAfgBAABhAQAAAwAAAAUAAAAOAAAACgAAAAH5AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB+gEAAGEBAAADAAAABQAAAA4AAAAKAAAAAfsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAH8AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB/QEAAGEBAAADAAAABQAAAA4AAAAAAAAAAf4BAABhAQAAAwAAAAUAAAAOAAAAHgAAAAH/AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABAAIAAGEBAAADAAAABQAAAA4AAAAAAAAAAQECAABhAQAAAwAAAAUAAAAOAAAAAAAAAAECAgAAYQEAAAMAAAAFAAAADgAAAAAAAAABAwIAAGEBAAADAAAABQAAAA4AAAAeAAAAAQQCAABhAQAAAwAAAAUAAAAOAAAAFAAAAAEFAgAAYQEAAAMAAAAFAAAADgAAAAAAAAAL + AAEAAAD/////AQAAAAAAAAAMAgAAADxDb3JlLCBWZXJzaW9uPTMuNS4xNy4yLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAACNfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuUHJvZmlsZQMAAAAeX3BsdWdJbkd1aWRUb1ZlcnNpb25Db25zdHJhaW50Fl9wbHVnSW5HdWlkVG9FeHRlbnNpb24aX3BsdWdJbkd1aWRUb0V4dGVuc2lvbkxpc3QEBAQ9XzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb1ZlcnNpb25Db25zdHJhaW50RGljdGlvbmFyeQIAAAAwXzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb0Jvb2xEaWN0aW9uYXJ5AgAAAEBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvUHJvZmlsZUV4dGVuc2lvbkxpc3REaWN0aW9uYXJ5AgAAAAIAAAAJAwAAAAkEAAAACQUAAAAFAwAAAD1fM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvVmVyc2lvbkNvbnN0cmFpbnREaWN0aW9uYXJ5AQAAABhEaWN0aW9uYXJ5QmFzZStoYXNodGFibGUDHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUCAAAACQYAAAAFBAAAADBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvQm9vbERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJBwAAAAUFAAAAQF8zUy5Db0RlU3lzLkNvcmUuQ29tcG9uZW50cy5HdWlkVG9Qcm9maWxlRXh0ZW5zaW9uTGlzdERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJCAAAAAQGAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUHAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhh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AAAeAAAAAWsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFsAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABbQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAW4BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFvAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAXEBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFyAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXQBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF1AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABdgEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF4AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABeQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXoBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAF7AQAAYQEAAAMAAAAFAAAADgAAAAoAAAABfAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAX0BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF+AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABfwEAAGEBAAADAAAABQAAAA4AAAAeAAAAAYABAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGBAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABggEAAGEBAAADAAAABQAAAA4AAAAKAAAAAYMBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGEAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABhQEAAGEBAAADAAAABQAAAA4AAAAKAAAAAYYBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGHAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiAEAAGEBAAADAAAABQAAAA4AAAAUAAAAAYkBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGKAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYwBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGNAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABjgEAAGEBAAADAAAABQAAAA4A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 True @@ -33627,6 +34956,58 @@ -1 + + False + + 5232f53d-845f-4696-ac63-167ae46c5456 + dc8b4b06-db0a-415d-9c9a-bbaa6953bc53 + DALIVariables + + ffbfa93a-b94d-45fc-a329-229860183b1d + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + + 638645795238512552 + + + + + + + 2 + + {attribute 'qualified_only'} + + + 3 + + VAR_GLOBAL + + + 4 + + M1_Light1: typBallast:=(bAddress:=0,xIsGroup:=FALSE,bPortDALI:=1); + + + 1 + + END_VAR + + + + + + False + False + + dc8b4b06-db0a-415d-9c9a-bbaa6953bc53 + + PLC + PLC Logic + HomeAutomation + + -1 + False @@ -34062,7 +35443,7 @@ adb5cb65-8e1d-4a00-b70a-375ea27582f3 - 638115486612493699 + 638645805475306997 @@ -34690,6 +36071,86 @@ False False + + WagoAppDALI, * (WAGO) + False + + + MAX_RX_BUFFER + + + 7881299347898372 + + 300 + AnyInt + False + AnyInt + + + + MAX_MODULES + + + 7318349394477062 + + 25 + AnyInt + False + AnyInt + + + + WagoAppDALI + b303f5ce-75ff-4668-a777-7da8debb449c + 2648186880 + WagoAppDALI + False + False + False + False + False + + + WagoSysModule_753_647, * (WAGO) + False + + + DEBUG_MODE + + + 5910974510923778 + + 0 + Bool + False + Bool + + + + WagoSysModule_753_647 + b303f5ce-75ff-4668-a777-7da8debb449c + 3459978198 + WagoSysModule_753_647 + True + False + False + False + False + + + WagoSysKbusServices, * (WAGO) + False + + WagoSysKbusServices + b303f5ce-75ff-4668-a777-7da8debb449c + 633550780 + WagoSysKbusServices + True + False + False + False + False + @@ -35212,6 +36673,166 @@ WagoSysTypedefs_Debugging, 1.0.3.0 (WAGO) + + + WagoAppDALI + + + WagoAppDALI, 1.3.0.39 (WAGO) + + + + + System_VisuElems + + + VisuElems, 4.1.0.0 (System) + + + + + System_VisuElemMeter + + + VisuElemMeter, 4.1.0.0 (System) + + + + + System_VisuElemsSpecialControls + + + VisuElemsSpecialControls, 4.1.0.0 (System) + + + + + System_VisuElemsWinControls + + + VisuElemsWinControls, 4.1.0.0 (System) + + + + + System_VisuElemTextEditor + + + VisuElemTextEditor, 4.1.0.0 (System) + + + + + System_VisuElemTrace + + + VisuElemTrace, 4.1.0.0 (System) + + + + + System_VisuNativeControl + + + VisuNativeControl, 4.1.0.0 (System) + + + + + System_VisuElemsAlarm + + + VisuElemsAlarm, 4.1.0.0 (System) + + + + + System_VisuElemCamDisplayer + + + VisuElemCamDisplayer, 4.1.0.0 (System) + + + + + System_VisuElem3DPath + + + VisuElem3DPath, 4.1.0.0 (System) + + + + + System_VisuElemsDateTime + + + VisuElemsDateTime, 4.1.0.0 (System) + + + + + WagoTypesModule_753_647 + + + WagoTypesModule_753_647, 1.1.1.0 (WAGO) + + + + + WagoTypesModuleBase + + + WagoTypesModuleBase, 1.9.10.1 (WAGO) + + + + + WagoTypesBusServices + + + WagoTypesBusServices, 1.8.4.1 (WAGO) + + + + + WagoVisuIcons + + + WagoVisuIcons, 1.1.0.5 (WAGO) + + + + + System_VisuElemXYChart + + + VisuElemXYChart, 4.1.0.0 (System) + + + + + WagoSysModule_753_647 + + + WagoSysModule_753_647, 1.1.1.0 (WAGO) + + + + + WagoSysModuleBase + + + WagoSysModuleBase, 1.9.13.1 (WAGO) + + + + + WagoSysKbusServices + + + WagoSysKbusServices, 1.8.7.4 (WAGO) + + dc8b4b06-db0a-415d-9c9a-bbaa6953bc53 @@ -36300,7 +37921,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 74f81948-1328-492c-b6c1-a9ea72048b28 - 638133838537199548 + 638645804101561972 None @@ -36554,6 +38175,59 @@ + + + + 38391c6d-6d4a-42f8-8ee7-9f45e5adafa8 + + DALI + + + 325 + 324 + + + 7d894980-aeea-405c-a0f6-e2b26429c58f + + + + + 326 + 324 + + + 01580b27-6378-448b-8ecb-0e4b795b58d6 + + FALSE + FALSE + + 327 + 324 + + + bc882c11-1e91-4dd8-a6b8-2075724ed18b + + 79a4fdd5-c859-4de4-aa8d-c03372c880c2 + + 0 + 0 + + 328 + 324 + + + e174fc0d-80b0-4a9e-a530-ca239c249a50 + + N + + + 329 + 324 + + + 324 + 40 + @@ -37502,6 +39176,31 @@ FB_VIRTUAL_REAL_001 :FB_VIRTUAL_REAL_MQTT; + + 319 + + + + + 322 + + (* DALI FUNCTION BLOCKS *) + + + 323 + + M1_DALIMASTER :FbDaliMaster; + + + 321 + + FB_DALI_1_ADR0 :FB_OUTPUT_DIMMER_DALI_MQTT; + + + 320 + + + 1 @@ -37510,7 +39209,7 @@ - 318 + 329 Standard False @@ -40692,6 +42391,93 @@ -1 + + False + + 353dab8b-6c60-41cc-8756-e1855fbbd18e + 98c8b3af-823f-460e-96b4-4a3a11616ef1 + DALI + + 8ac092e5-3128-4e26-9e7e-11016c6684f2 + + 3b83b776-fb25-43b8-99f2-3c507c9143fc + + 638645804541323706 + + + + + + + 2 + + // Run the master before anything else + + + 3 + + M1_DALIMASTER( + + + 4 + + bPortDALI:=1, + + + 5 + + I_Port:=IoConfig_Globals.DALI_MULTI_MASTER_MODULE); + + + 6 + + + + + 7 + + // Run individual DALI FB + + + 8 + + FB_DALI_1_ADR0( + + + 9 + + BALLAST := DALIVariables.M1_Light1, + + + 10 + + TOGGLE := FB_DI_PB_002.SINGLE, + + + 11 + + P_LONG := FB_DI_PB_002.P_LONG, + + + 1 + + STATUS_LED => DO_002); + + + + + 11 + + 98c8b3af-823f-460e-96b4-4a3a11616ef1 + + PLC + PLC Logic + HomeAutomation + PRG's + PLC_PRG_MAIN + + -1 + False @@ -40703,7 +42489,7 @@ 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638133838359628321 + 638645803401043150 @@ -41439,6 +43225,51 @@ + + 761 + + + + + 762 + + (* DALI *) + + + 770 + + FB_DALI_1_ADR0.InitMqtt(MQTTPublishPrefix:= ADR(MqttVariables.MqttPubDimmerPrefix), + + + 771 + + MQTTSubscribePrefix:= ADR(MqttVariables.MqttSubDimmerPrefix), + + + 772 + + pMqttPublishQueue := ADR(MqttVariables.fbMqttPublishQueue), + + + 775 + + pMqttCallbackCollector := ADR(MqttVariables.collector_FB_DIMMER_MQTT) + + + 765 + + ); + + + 769 + + + + + 763 + + FB_DALI_1_ADR0.InitMqttDiscovery(ADR(MqttVariables.PLC_Device), 'Keuken'); + 723 @@ -41467,7 +43298,7 @@ - 760 + 775 98c8b3af-823f-460e-96b4-4a3a11616ef1 diff --git a/src/Exports/PLCopen.xml b/src/Exports/PLCopen.xml index 4916a0c..4b5c1dd 100644 --- a/src/Exports/PLCopen.xml +++ b/src/Exports/PLCopen.xml @@ -1,7 +1,7 @@  - - + + @@ -1139,7 +1139,42 @@ - + + + + + + + + + + + + + + + + + + + + + + + + pMqttPublishQueue^.AddMessage( + Payload:= CONCAT(CONCAT(instance,' | '),str), + Topic := CONCAT(MqttDiagnosticTopic, '/Log'), + Qos := 1, + MqttRetain := TRUE +); + + + + + + + @@ -1160,7 +1195,7 @@ - + @@ -1168,29 +1203,35 @@ entity specific - + - - - - + - - config or diagnostic - - + - + + + + + + + + + + + + + + + + - - - @@ -1199,7 +1240,7 @@ - + @@ -1224,43 +1265,47 @@ MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); // Entity related: Basis -MqttDiscMsgSensorWCat.name.CharString := name; // friendly name -MqttDiscMsgSensorWCat.obj_id.CharString := Id; -MqttDiscMsgSensorWCat.uniq_id.CharString := Id; +MqttDiscMsgSwitch.name.CharString := name; // friendly name +MqttDiscMsgSwitch.obj_id.CharString := Id; +MqttDiscMsgSwitch.uniq_id.CharString := Id; // Entity related: Specific -//MqttDiscoverySensorMessage.ic.CharString := Icon; -MqttDiscMsgSensorWCat.stat_t.CharString := StateTopic; -MqttDiscMsgSensorWCat.exp_aft.Integer := ExpiryAfter; -MqttDiscMsgSensorWCat.ent_cat.CharString := EntityCategory; +MqttDiscMsgSwitch.cmd_t.CharString := CommandTopic; +MqttDiscMsgSwitch.pl_on.CharString := PayloadOn; +MqttDiscMsgSwitch.pl_off.CharString := PayloadOff; +MqttDiscMsgSwitch.stat_t.CharString := StateTopic; +MqttDiscMsgSwitch.stat_on.CharString := StateOnPayload; +MqttDiscMsgSwitch.stat_off.CharString := StateOffPayload; +MqttDiscMsgSwitch.opt.Boolean := FALSE; +MqttDiscMsgSwitch.dev_cla.CharString := DeviceClass; // Availabilty related -MqttDiscMsgSensorWCat.avty[1].topic.CharString := THIS^.availabilityTopic1; -MqttDiscMsgSensorWCat.avty[2].topic.CharString := THIS^.availabilityTopic2; -MqttDiscMsgSensorWCat.avty_mode.CharString := 'all'; -MqttDiscMsgSensorWCat.pl_avail.CharString := THIS^.availabilityOnline; -MqttDiscMsgSensorWCat.pl_not_avail.CharString := THIS^.availabilityOffline; -MqttDiscMsgSensorWCat.qos.Integer := 2; +MqttDiscMsgSwitch.avty[1].topic.CharString := THIS^.availabilityTopic1; +MqttDiscMsgSwitch.avty[2].topic.CharString := THIS^.availabilityTopic2; +MqttDiscMsgSwitch.avty_mode.CharString := 'all'; +MqttDiscMsgSwitch.pl_avail.CharString := THIS^.availabilityOnline; +MqttDiscMsgSwitch.pl_not_avail.CharString := THIS^.availabilityOffline; +MqttDiscMsgSwitch.qos.Integer := 2; // Device related -MqttDiscMsgSensorWCat.dev.cu.CharString := THIS^.cu; -MqttDiscMsgSensorWCat.dev.name.CharString := THIS^.name; -MqttDiscMsgSensorWCat.dev.hw.CharString := THIS^.hw; -MqttDiscMsgSensorWCat.dev.ids.CharString := THIS^.ids; -MqttDiscMsgSensorWCat.dev.sw.CharString := THIS^.sw; -MqttDiscMsgSensorWCat.dev.mdl.CharString := THIS^.mdl; -MqttDiscMsgSensorWCat.dev.mf.CharString := THIS^.mf; +MqttDiscMsgSwitch.dev.cu.CharString := THIS^.cu; +MqttDiscMsgSwitch.dev.name.CharString := THIS^.name; +MqttDiscMsgSwitch.dev.hw.CharString := THIS^.hw; +MqttDiscMsgSwitch.dev.ids.CharString := THIS^.ids; +MqttDiscMsgSwitch.dev.sw.CharString := THIS^.sw; +MqttDiscMsgSwitch.dev.mdl.CharString := THIS^.mdl; +MqttDiscMsgSwitch.dev.mf.CharString := THIS^.mf; // Extra meta-data IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - MqttDiscMsgSensorWCat.meta.CharString := meta; + MqttDiscMsgSwitch.meta.CharString := meta; END_IF ComposeJSON( JSONString:= ADR(MqttJSON), JSONStringSize:= SIZEOF(MqttJSON), - JSONVars:= ADR(MqttDiscMsgSensorWCat), - NumberOfVars:= SIZEOF(MqttDiscMsgSensorWCat) / SIZEOF(JSONVAR), + JSONVars:= ADR(MqttDiscMsgSwitch), + NumberOfVars:= SIZEOF(MqttDiscMsgSwitch) / SIZEOF(JSONVAR), MaxLevel := 1, ); ComposeJSON.Execute := TRUE; @@ -1275,15 +1320,6 @@ ELSIF NOT (MqttJSON = '') THEN Qos := MQTT.QoS.ExactlyOnce, MqttRetain := TRUE, ); - IF NOT (StateValue = '') THEN - pMqttPublishQueue^.AddMessage( - Payload:= StateValue, - Topic := StateTopic, - Qos := MQTT.QoS.ExactlyOnce, - MqttRetain := TRUE, - ); - END_IF - SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -1293,7 +1329,7 @@ END_IF - + @@ -1314,7 +1350,7 @@ END_IF - + @@ -1332,19 +1368,61 @@ END_IF - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + - config or diagnostic + dmx specific + + + + + + + + + + + + + + + + @@ -1352,7 +1430,7 @@ END_IF - + @@ -1371,58 +1449,59 @@ END_IF - - - - - - - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); - // Entity related: Basis -MqttDiscMsgBinSensWCat.name.CharString := name; // friendly name -MqttDiscMsgBinSensWCat.obj_id.CharString := Id; -MqttDiscMsgBinSensWCat.uniq_id.CharString := Id; +MqttDiscMsgLightDim.name.CharString := name; // friendly name +MqttDiscMsgLightDim.obj_id.CharString := Id; +MqttDiscMsgLightDim.uniq_id.CharString := Id; // Entity related: Specific -MqttDiscMsgBinSensWCat.stat_t.CharString := StateTopic; -MqttDiscMsgBinSensWCat.pl_on.CharString := PayloadOn; -MqttDiscMsgBinSensWCat.pl_off.CharString := PayloadOff; -MqttDiscMsgBinSensWCat.dev_cla.CharString := DeviceClass; -MqttDiscMsgBinSensWCat.ent_cat.CharString := EntityCategory; +MqttDiscMsgLightDim.cmd_t.CharString := CommandTopic; +MqttDiscMsgLightDim.pl_on.CharString := PayloadOn; +MqttDiscMsgLightDim.pl_off.CharString := PayloadOff; +MqttDiscMsgLightDim.stat_t.CharString := StateTopic; +MqttDiscMsgLightDim.opt.Boolean := FALSE; + +MqttDiscMsgLightDim.bri_cmd_t.CharString := BrightnessCommandTopic; +MqttDiscMsgLightDim.bri_stat_t.CharString := BrightnessStateTopic; +MqttDiscMsgLightDim.bri_scl.Integer := BrightnessScale; +MqttDiscMsgLightDim.on_cmd_type.CharString := OnCommandType; + +MqttDiscMsgLightDim.dmxChannel.Integer := DmxChannel; +MqttDiscMsgLightDim.dmxWidth.Integer := DmxWidth; +MqttDiscMsgLightDim.dmxUniverse.Integer := DmxUniverse; // Availabilty related -MqttDiscMsgBinSensWCat.avty[1].topic.CharString := THIS^.availabilityTopic1; -MqttDiscMsgBinSensWCat.avty[2].topic.CharString := THIS^.availabilityTopic2; -MqttDiscMsgBinSensWCat.avty_mode.CharString := 'all'; -MqttDiscMsgBinSensWCat.pl_avail.CharString := THIS^.availabilityOnline; -MqttDiscMsgBinSensWCat.pl_not_avail.CharString := THIS^.availabilityOffline; -MqttDiscMsgBinSensWCat.qos.Integer := 2; +MqttDiscMsgLightDim.avty[1].topic.CharString := THIS^.availabilityTopic1; +MqttDiscMsgLightDim.avty[2].topic.CharString := THIS^.availabilityTopic2; +MqttDiscMsgLightDim.avty_mode.CharString := 'all'; +MqttDiscMsgLightDim.pl_avail.CharString := THIS^.availabilityOnline; +MqttDiscMsgLightDim.pl_not_avail.CharString := THIS^.availabilityOffline; +MqttDiscMsgLightDim.qos.Integer := 2; // Device related -MqttDiscMsgBinSensWCat.dev.cu.CharString := THIS^.cu; -MqttDiscMsgBinSensWCat.dev.name.CharString := THIS^.name; -MqttDiscMsgBinSensWCat.dev.hw.CharString := THIS^.hw; -MqttDiscMsgBinSensWCat.dev.ids.CharString := THIS^.ids; -MqttDiscMsgBinSensWCat.dev.sw.CharString := THIS^.sw; -MqttDiscMsgBinSensWCat.dev.mdl.CharString := THIS^.mdl; -MqttDiscMsgBinSensWCat.dev.mf.CharString := THIS^.mf; +MqttDiscMsgLightDim.dev.cu.CharString := THIS^.cu; +MqttDiscMsgLightDim.dev.name.CharString := THIS^.name; +MqttDiscMsgLightDim.dev.hw.CharString := THIS^.hw; +MqttDiscMsgLightDim.dev.ids.CharString := THIS^.ids; +MqttDiscMsgLightDim.dev.sw.CharString := THIS^.sw; +MqttDiscMsgLightDim.dev.mdl.CharString := THIS^.mdl; +MqttDiscMsgLightDim.dev.mf.CharString := THIS^.mf; // Extra meta-data IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - MqttDiscMsgBinSensWCat.meta.CharString := meta; + MqttDiscMsgLightDim.meta.CharString := meta; END_IF ComposeJSON( JSONString:= ADR(MqttJSON), JSONStringSize:= SIZEOF(MqttJSON), - JSONVars:= ADR(MqttDiscMsgBinSensWCat), - NumberOfVars:= SIZEOF(MqttDiscMsgBinSensWCat) / SIZEOF(JSONVAR), + JSONVars:= ADR(MqttDiscMsgLightDim), + NumberOfVars:= SIZEOF(MqttDiscMsgLightDim) / SIZEOF(JSONVAR), MaxLevel := 1, ); ComposeJSON.Execute := TRUE; @@ -1446,7 +1525,7 @@ END_IF - + @@ -1475,20 +1554,13 @@ END_IF entity specific - + - - - - - - - - - - - + + + + @@ -1497,7 +1569,7 @@ END_IF - + @@ -1516,57 +1588,48 @@ END_IF - - - - - - - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); - // Entity related: Basis -MqttDiscMsgBinSens.name.CharString := name; // friendly name -MqttDiscMsgBinSens.obj_id.CharString := Id; -MqttDiscMsgBinSens.uniq_id.CharString := Id; +MqttDiscMsgSensor.name.CharString := name; // friendly name +MqttDiscMsgSensor.obj_id.CharString := Id; +MqttDiscMsgSensor.uniq_id.CharString := Id; // Entity related: Specific -MqttDiscMsgBinSens.stat_t.CharString := StateTopic; -MqttDiscMsgBinSens.pl_on.CharString := PayloadOn; -MqttDiscMsgBinSens.pl_off.CharString := PayloadOff; -MqttDiscMsgBinSens.dev_cla.CharString := DeviceClass; +//MqttDiscoverySensorMessage.ic.CharString := Icon; +MqttDiscMsgSensor.stat_t.CharString := StateTopic; +MqttDiscMsgSensor.exp_aft.Integer := ExpiryAfter; // Availabilty related -MqttDiscMsgBinSens.avty[1].topic.CharString := THIS^.availabilityTopic1; -MqttDiscMsgBinSens.avty[2].topic.CharString := THIS^.availabilityTopic2; -MqttDiscMsgBinSens.avty_mode.CharString := 'all'; -MqttDiscMsgBinSens.pl_avail.CharString := THIS^.availabilityOnline; -MqttDiscMsgBinSens.pl_not_avail.CharString := THIS^.availabilityOffline; -MqttDiscMsgBinSens.qos.Integer := 2; +MqttDiscMsgSensor.avty[1].topic.CharString := THIS^.availabilityTopic1; +MqttDiscMsgSensor.avty[2].topic.CharString := THIS^.availabilityTopic2; +MqttDiscMsgSensor.avty_mode.CharString := 'all'; +MqttDiscMsgSensor.pl_avail.CharString := THIS^.availabilityOnline; +MqttDiscMsgSensor.pl_not_avail.CharString := THIS^.availabilityOffline; +MqttDiscMsgSensor.qos.Integer := 2; // Device related -MqttDiscMsgBinSens.dev.cu.CharString := THIS^.cu; -MqttDiscMsgBinSens.dev.name.CharString := THIS^.name; -MqttDiscMsgBinSens.dev.hw.CharString := THIS^.hw; -MqttDiscMsgBinSens.dev.ids.CharString := THIS^.ids; -MqttDiscMsgBinSens.dev.sw.CharString := THIS^.sw; -MqttDiscMsgBinSens.dev.mdl.CharString := THIS^.mdl; -MqttDiscMsgBinSens.dev.mf.CharString := THIS^.mf; +MqttDiscMsgSensor.dev.cu.CharString := THIS^.cu; +MqttDiscMsgSensor.dev.name.CharString := THIS^.name; +MqttDiscMsgSensor.dev.hw.CharString := THIS^.hw; +MqttDiscMsgSensor.dev.ids.CharString := THIS^.ids; +MqttDiscMsgSensor.dev.sw.CharString := THIS^.sw; +MqttDiscMsgSensor.dev.mdl.CharString := THIS^.mdl; +MqttDiscMsgSensor.dev.mf.CharString := THIS^.mf; // Extra meta-data IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - MqttDiscMsgBinSens.meta.CharString := meta; + MqttDiscMsgSensor.meta.CharString := meta; END_IF ComposeJSON( JSONString:= ADR(MqttJSON), JSONStringSize:= SIZEOF(MqttJSON), - JSONVars:= ADR(MqttDiscMsgBinSens), - NumberOfVars:= SIZEOF(MqttDiscMsgBinSens) / SIZEOF(JSONVAR), + JSONVars:= ADR(MqttDiscMsgSensor), + NumberOfVars:= SIZEOF(MqttDiscMsgSensor) / SIZEOF(JSONVAR), MaxLevel := 1, ); ComposeJSON.Execute := TRUE; @@ -1590,7 +1653,7 @@ END_IF - + @@ -1619,17 +1682,12 @@ END_IF entity specific - - - - - - + - + @@ -1639,17 +1697,12 @@ END_IF - - - - - - + - + @@ -1661,7 +1714,7 @@ END_IF - + @@ -1686,48 +1739,47 @@ END_IF MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); // Entity related: Basis -MqttDiscMsgCover.name.CharString := name; // friendly name -MqttDiscMsgCover.obj_id.CharString := Id; -MqttDiscMsgCover.uniq_id.CharString := Id; +MqttDiscMsgSiren.name.CharString := name; // friendly name +MqttDiscMsgSiren.obj_id.CharString := Id; +MqttDiscMsgSiren.uniq_id.CharString := Id; // Entity related: Specific -MqttDiscMsgCover.cmd_t.CharString := CommandTopic; -MqttDiscMsgCover.pl_open.CharString := PayloadOpen; -MqttDiscMsgCover.pl_cls.CharString := PayloadClose; -MqttDiscMsgCover.pl_stop.CharString := PayloadStop; -MqttDiscMsgCover.stat_t.CharString := StateTopic; -MqttDiscMsgCover.stat_open.CharString := StateOpen; -MqttDiscMsgCover.stat_clsd.CharString := StateClosed; -MqttDiscMsgCover.opt.Boolean := FALSE; -MqttDiscMsgCover.dev_cla.CharString := Deviceclass; +MqttDiscMsgSiren.cmd_t.CharString := CommandTopic; +MqttDiscMsgSiren.pl_on.CharString := PayloadOn; +MqttDiscMsgSiren.pl_off.CharString := PayloadOff; +MqttDiscMsgSiren.stat_t.CharString := StateTopic; +MqttDiscMsgSiren.stat_on.CharString := StateOnPayload; +MqttDiscMsgSiren.stat_off.CharString := StateOffPayload; +MqttDiscMsgSiren.opt.Boolean := FALSE; // Availabilty related -MqttDiscMsgCover.avty[1].topic.CharString := THIS^.availabilityTopic1; -MqttDiscMsgCover.avty[2].topic.CharString := THIS^.availabilityTopic2; -MqttDiscMsgCover.avty_mode.CharString := 'all'; -MqttDiscMsgCover.pl_avail.CharString := THIS^.availabilityOnline; -MqttDiscMsgCover.pl_not_avail.CharString := THIS^.availabilityOffline; -MqttDiscMsgCover.qos.Integer := 2; +MqttDiscMsgSiren.avty[1].topic.CharString := THIS^.availabilityTopic1; +MqttDiscMsgSiren.avty[2].topic.CharString := THIS^.availabilityTopic2; +MqttDiscMsgSiren.avty_mode.CharString := 'all'; +MqttDiscMsgSiren.pl_avail.CharString := THIS^.availabilityOnline; +MqttDiscMsgSiren.pl_not_avail.CharString := THIS^.availabilityOffline; +MqttDiscMsgSiren.qos.Integer := 2; + // Device related -MqttDiscMsgCover.dev.cu.CharString := THIS^.cu; -MqttDiscMsgCover.dev.name.CharString := THIS^.name; -MqttDiscMsgCover.dev.hw.CharString := THIS^.hw; -MqttDiscMsgCover.dev.ids.CharString := THIS^.ids; -MqttDiscMsgCover.dev.sw.CharString := THIS^.sw; -MqttDiscMsgCover.dev.mdl.CharString := THIS^.mdl; -MqttDiscMsgCover.dev.mf.CharString := THIS^.mf; +MqttDiscMsgSiren.dev.cu.CharString := THIS^.cu; +MqttDiscMsgSiren.dev.name.CharString := THIS^.name; +MqttDiscMsgSiren.dev.hw.CharString := THIS^.hw; +MqttDiscMsgSiren.dev.ids.CharString := THIS^.ids; +MqttDiscMsgSiren.dev.sw.CharString := THIS^.sw; +MqttDiscMsgSiren.dev.mdl.CharString := THIS^.mdl; +MqttDiscMsgSiren.dev.mf.CharString := THIS^.mf; // Extra meta-data IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - MqttDiscMsgCover.meta.CharString := meta; + MqttDiscMsgSiren.meta.CharString := meta; END_IF ComposeJSON( JSONString:= ADR(MqttJSON), JSONStringSize:= SIZEOF(MqttJSON), - JSONVars:= ADR(MqttDiscMsgCover), - NumberOfVars:= SIZEOF(MqttDiscMsgCover) / SIZEOF(JSONVAR), + JSONVars:= ADR(MqttDiscMsgSiren), + NumberOfVars:= SIZEOF(MqttDiscMsgSiren) / SIZEOF(JSONVAR), MaxLevel := 1, ); ComposeJSON.Execute := TRUE; @@ -1751,161 +1803,148 @@ END_IF - + + + default + - - - - - - + - + - + + + entity specific + - + - + - + - - - - + - - - - + - + + + - + - + - - - - - - - - - - - + - + - + - + - + - - - - - + - + - THIS^.availabilityTopic1 := availabilityTopic; + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); -IF CommonTypesAndFunctions.StrEquals(str1:= ADR(availabilityTopic2), str2:= ADR('')) THEN - THIS^.availabilityTopic2 := availabilityTopic; -ELSE - THIS^.availabilityTopic2 := availabilityTopic2; -END_IF +// Entity related: Basis +MqttDiscMsgLock.name.CharString := name; // friendly name +MqttDiscMsgLock.obj_id.CharString := Id; +MqttDiscMsgLock.uniq_id.CharString := Id; -THIS^.availabilityOnline := availabilityOnline; -THIS^.availabilityOffline := availabilityOffline; -THIS^.pMqttPublishQueue := pMqttPublishQueue; -THIS^.MqttDiscoveryPrefix := MqttDiscoveryPrefix; -THIS^.MqttDiagnosticTopic := MqttDiagnosticTopic; +// Entity related: Specific +MqttDiscMsgLock.cmd_t.CharString := CommandTopic; +MqttDiscMsgLock.pl_lock.CharString := PayloadLock; +MqttDiscMsgLock.pl_unlk.CharString := PayloadUnlock; +MqttDiscMsgLock.stat_t.CharString := StateTopic; +MqttDiscMsgLock.stat_locked.CharString := StateLocked; +MqttDiscMsgLock.stat_unlocked.CharString := StateUnlocked; +MqttDiscMsgLock.opt.Boolean := FALSE; -THIS^.name := Name; -THIS^.cu:= ConfigurationUrl; -THIS^.ids:= Identifiers; -THIS^.mf:= Manufacturer; -THIS^.mdl:= Model; -THIS^.hw:= HardwareVersion; -THIS^.sw:= SoftwareVersion; -THIS^.ip := IpAddress; -THIS^.mac := MacAddress; +// Availabilty related +MqttDiscMsgLock.avty[1].topic.CharString := THIS^.availabilityTopic1; +MqttDiscMsgLock.avty[2].topic.CharString := THIS^.availabilityTopic2; +MqttDiscMsgLock.avty_mode.CharString := 'all'; +MqttDiscMsgLock.pl_avail.CharString := THIS^.availabilityOnline; +MqttDiscMsgLock.pl_not_avail.CharString := THIS^.availabilityOffline; +MqttDiscMsgLock.qos.Integer := 2; -//Create a diagnostics availability binary sensor -CreateBinarySensorEntityWithCategory( - Name := 'Availability', - Id := CONCAT(THIS^.Name,'_diag_availability'), - Meta := '', - StateTopic := availabilityTopic, - PayloadOn := availabilityOnline, - PayloadOff := availabilityOffline, - DeviceClass := 'CONNECTIVITY', - EntityCategory := 'diagnostic'); - -//Logger -CreateSensorEntityWithCategory( - Name := 'Log', - Id := CONCAT(THIS^.Name,'_diag_log'), - Meta := '', - StateTopic := CONCAT(MqttDiagnosticTopic, '/Log'), - EntityCategory := 'diagnostic'); +// Device related +MqttDiscMsgLock.dev.cu.CharString := THIS^.cu; +MqttDiscMsgLock.dev.name.CharString := THIS^.name; +MqttDiscMsgLock.dev.hw.CharString := THIS^.hw; +MqttDiscMsgLock.dev.ids.CharString := THIS^.ids; +MqttDiscMsgLock.dev.sw.CharString := THIS^.sw; +MqttDiscMsgLock.dev.mdl.CharString := THIS^.mdl; +MqttDiscMsgLock.dev.mf.CharString := THIS^.mf; -// MAC address -IF NOT(MacAddress = '') THEN - CreateSensorEntityWithCategory( - Name := 'MAC', - Id := CONCAT(THIS^.Name,'_diag_mac'), - Meta := '', - StateTopic := CONCAT(MqttDiagnosticTopic, '/MAC'), - StateValue := MacAddress, - EntityCategory := 'diagnostic'); +// Extra meta-data +IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN + MqttDiscMsgLock.meta.CharString := meta; END_IF +ComposeJSON( + JSONString:= ADR(MqttJSON), + JSONStringSize:= SIZEOF(MqttJSON), + JSONVars:= ADR(MqttDiscMsgLock), + NumberOfVars:= SIZEOF(MqttDiscMsgLock) / SIZEOF(JSONVAR), + MaxLevel := 1, +); +ComposeJSON.Execute := TRUE; +ComposeJSON(); +IF MqttJSON = '' THEN + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); +ELSIF NOT (MqttJSON = '') THEN + pMqttPublishQueue^.AddMessage( + Payload:= MqttJSON, + Topic := MqttTopic, + Qos := MQTT.QoS.ExactlyOnce, + MqttRetain := TRUE, + ); + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); +END_IF @@ -2050,148 +2089,161 @@ END_IF - + - - default - - + - + - + - - entity specific - - + - + - + - + + + + + + + + + + + + - + - - - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + THIS^.availabilityTopic1 := availabilityTopic; -// Entity related: Basis -MqttDiscMsgLock.name.CharString := name; // friendly name -MqttDiscMsgLock.obj_id.CharString := Id; -MqttDiscMsgLock.uniq_id.CharString := Id; +IF CommonTypesAndFunctions.StrEquals(str1:= ADR(availabilityTopic2), str2:= ADR('')) THEN + THIS^.availabilityTopic2 := availabilityTopic; +ELSE + THIS^.availabilityTopic2 := availabilityTopic2; +END_IF -// Entity related: Specific -MqttDiscMsgLock.cmd_t.CharString := CommandTopic; -MqttDiscMsgLock.pl_lock.CharString := PayloadLock; -MqttDiscMsgLock.pl_unlk.CharString := PayloadUnlock; -MqttDiscMsgLock.stat_t.CharString := StateTopic; -MqttDiscMsgLock.stat_locked.CharString := StateLocked; -MqttDiscMsgLock.stat_unlocked.CharString := StateUnlocked; -MqttDiscMsgLock.opt.Boolean := FALSE; +THIS^.availabilityOnline := availabilityOnline; +THIS^.availabilityOffline := availabilityOffline; +THIS^.pMqttPublishQueue := pMqttPublishQueue; +THIS^.MqttDiscoveryPrefix := MqttDiscoveryPrefix; +THIS^.MqttDiagnosticTopic := MqttDiagnosticTopic; -// Availabilty related -MqttDiscMsgLock.avty[1].topic.CharString := THIS^.availabilityTopic1; -MqttDiscMsgLock.avty[2].topic.CharString := THIS^.availabilityTopic2; -MqttDiscMsgLock.avty_mode.CharString := 'all'; -MqttDiscMsgLock.pl_avail.CharString := THIS^.availabilityOnline; -MqttDiscMsgLock.pl_not_avail.CharString := THIS^.availabilityOffline; -MqttDiscMsgLock.qos.Integer := 2; +THIS^.name := Name; +THIS^.cu:= ConfigurationUrl; +THIS^.ids:= Identifiers; +THIS^.mf:= Manufacturer; +THIS^.mdl:= Model; +THIS^.hw:= HardwareVersion; +THIS^.sw:= SoftwareVersion; +THIS^.ip := IpAddress; +THIS^.mac := MacAddress; -// Device related -MqttDiscMsgLock.dev.cu.CharString := THIS^.cu; -MqttDiscMsgLock.dev.name.CharString := THIS^.name; -MqttDiscMsgLock.dev.hw.CharString := THIS^.hw; -MqttDiscMsgLock.dev.ids.CharString := THIS^.ids; -MqttDiscMsgLock.dev.sw.CharString := THIS^.sw; -MqttDiscMsgLock.dev.mdl.CharString := THIS^.mdl; -MqttDiscMsgLock.dev.mf.CharString := THIS^.mf; +//Create a diagnostics availability binary sensor +CreateBinarySensorEntityWithCategory( + Name := 'Availability', + Id := CONCAT(THIS^.Name,'_diag_availability'), + Meta := '', + StateTopic := availabilityTopic, + PayloadOn := availabilityOnline, + PayloadOff := availabilityOffline, + DeviceClass := 'CONNECTIVITY', + EntityCategory := 'diagnostic'); -// Extra meta-data -IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - MqttDiscMsgLock.meta.CharString := meta; +//Logger +CreateSensorEntityWithCategory( + Name := 'Log', + Id := CONCAT(THIS^.Name,'_diag_log'), + Meta := '', + StateTopic := CONCAT(MqttDiagnosticTopic, '/Log'), + EntityCategory := 'diagnostic'); + +// MAC address +IF NOT(MacAddress = '') THEN + CreateSensorEntityWithCategory( + Name := 'MAC', + Id := CONCAT(THIS^.Name,'_diag_mac'), + Meta := '', + StateTopic := CONCAT(MqttDiagnosticTopic, '/MAC'), + StateValue := MacAddress, + EntityCategory := 'diagnostic'); END_IF -ComposeJSON( - JSONString:= ADR(MqttJSON), - JSONStringSize:= SIZEOF(MqttJSON), - JSONVars:= ADR(MqttDiscMsgLock), - NumberOfVars:= SIZEOF(MqttDiscMsgLock) / SIZEOF(JSONVAR), - MaxLevel := 1, -); -ComposeJSON.Execute := TRUE; -ComposeJSON(); -IF MqttJSON = '' THEN - SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); -ELSIF NOT (MqttJSON = '') THEN - pMqttPublishQueue^.AddMessage( - Payload:= MqttJSON, - Topic := MqttTopic, - Qos := MQTT.QoS.ExactlyOnce, - MqttRetain := TRUE, - ); - SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); -END_IF @@ -2199,7 +2251,7 @@ END_IF - + @@ -2228,12 +2280,17 @@ END_IF entity specific - + - + + + + + + @@ -2243,12 +2300,17 @@ END_IF - + - + + + + + + @@ -2260,7 +2322,7 @@ END_IF - + @@ -2285,47 +2347,48 @@ END_IF MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); // Entity related: Basis -MqttDiscMsgSiren.name.CharString := name; // friendly name -MqttDiscMsgSiren.obj_id.CharString := Id; -MqttDiscMsgSiren.uniq_id.CharString := Id; +MqttDiscMsgCover.name.CharString := name; // friendly name +MqttDiscMsgCover.obj_id.CharString := Id; +MqttDiscMsgCover.uniq_id.CharString := Id; // Entity related: Specific -MqttDiscMsgSiren.cmd_t.CharString := CommandTopic; -MqttDiscMsgSiren.pl_on.CharString := PayloadOn; -MqttDiscMsgSiren.pl_off.CharString := PayloadOff; -MqttDiscMsgSiren.stat_t.CharString := StateTopic; -MqttDiscMsgSiren.stat_on.CharString := StateOnPayload; -MqttDiscMsgSiren.stat_off.CharString := StateOffPayload; -MqttDiscMsgSiren.opt.Boolean := FALSE; +MqttDiscMsgCover.cmd_t.CharString := CommandTopic; +MqttDiscMsgCover.pl_open.CharString := PayloadOpen; +MqttDiscMsgCover.pl_cls.CharString := PayloadClose; +MqttDiscMsgCover.pl_stop.CharString := PayloadStop; +MqttDiscMsgCover.stat_t.CharString := StateTopic; +MqttDiscMsgCover.stat_open.CharString := StateOpen; +MqttDiscMsgCover.stat_clsd.CharString := StateClosed; +MqttDiscMsgCover.opt.Boolean := FALSE; +MqttDiscMsgCover.dev_cla.CharString := Deviceclass; // Availabilty related -MqttDiscMsgSiren.avty[1].topic.CharString := THIS^.availabilityTopic1; -MqttDiscMsgSiren.avty[2].topic.CharString := THIS^.availabilityTopic2; -MqttDiscMsgSiren.avty_mode.CharString := 'all'; -MqttDiscMsgSiren.pl_avail.CharString := THIS^.availabilityOnline; -MqttDiscMsgSiren.pl_not_avail.CharString := THIS^.availabilityOffline; -MqttDiscMsgSiren.qos.Integer := 2; - +MqttDiscMsgCover.avty[1].topic.CharString := THIS^.availabilityTopic1; +MqttDiscMsgCover.avty[2].topic.CharString := THIS^.availabilityTopic2; +MqttDiscMsgCover.avty_mode.CharString := 'all'; +MqttDiscMsgCover.pl_avail.CharString := THIS^.availabilityOnline; +MqttDiscMsgCover.pl_not_avail.CharString := THIS^.availabilityOffline; +MqttDiscMsgCover.qos.Integer := 2; // Device related -MqttDiscMsgSiren.dev.cu.CharString := THIS^.cu; -MqttDiscMsgSiren.dev.name.CharString := THIS^.name; -MqttDiscMsgSiren.dev.hw.CharString := THIS^.hw; -MqttDiscMsgSiren.dev.ids.CharString := THIS^.ids; -MqttDiscMsgSiren.dev.sw.CharString := THIS^.sw; -MqttDiscMsgSiren.dev.mdl.CharString := THIS^.mdl; -MqttDiscMsgSiren.dev.mf.CharString := THIS^.mf; +MqttDiscMsgCover.dev.cu.CharString := THIS^.cu; +MqttDiscMsgCover.dev.name.CharString := THIS^.name; +MqttDiscMsgCover.dev.hw.CharString := THIS^.hw; +MqttDiscMsgCover.dev.ids.CharString := THIS^.ids; +MqttDiscMsgCover.dev.sw.CharString := THIS^.sw; +MqttDiscMsgCover.dev.mdl.CharString := THIS^.mdl; +MqttDiscMsgCover.dev.mf.CharString := THIS^.mf; // Extra meta-data IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - MqttDiscMsgSiren.meta.CharString := meta; + MqttDiscMsgCover.meta.CharString := meta; END_IF ComposeJSON( JSONString:= ADR(MqttJSON), JSONStringSize:= SIZEOF(MqttJSON), - JSONVars:= ADR(MqttDiscMsgSiren), - NumberOfVars:= SIZEOF(MqttDiscMsgSiren) / SIZEOF(JSONVAR), + JSONVars:= ADR(MqttDiscMsgCover), + NumberOfVars:= SIZEOF(MqttDiscMsgCover) / SIZEOF(JSONVAR), MaxLevel := 1, ); ComposeJSON.Execute := TRUE; @@ -2349,7 +2412,7 @@ END_IF - + @@ -2378,13 +2441,20 @@ END_IF entity specific - + - + + + + + + + + + + + - - - @@ -2393,7 +2463,7 @@ END_IF - + @@ -2412,48 +2482,57 @@ END_IF + + + + + + + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + // Entity related: Basis -MqttDiscMsgSensor.name.CharString := name; // friendly name -MqttDiscMsgSensor.obj_id.CharString := Id; -MqttDiscMsgSensor.uniq_id.CharString := Id; +MqttDiscMsgBinSens.name.CharString := name; // friendly name +MqttDiscMsgBinSens.obj_id.CharString := Id; +MqttDiscMsgBinSens.uniq_id.CharString := Id; // Entity related: Specific -//MqttDiscoverySensorMessage.ic.CharString := Icon; -MqttDiscMsgSensor.stat_t.CharString := StateTopic; -MqttDiscMsgSensor.exp_aft.Integer := ExpiryAfter; +MqttDiscMsgBinSens.stat_t.CharString := StateTopic; +MqttDiscMsgBinSens.pl_on.CharString := PayloadOn; +MqttDiscMsgBinSens.pl_off.CharString := PayloadOff; +MqttDiscMsgBinSens.dev_cla.CharString := DeviceClass; // Availabilty related -MqttDiscMsgSensor.avty[1].topic.CharString := THIS^.availabilityTopic1; -MqttDiscMsgSensor.avty[2].topic.CharString := THIS^.availabilityTopic2; -MqttDiscMsgSensor.avty_mode.CharString := 'all'; -MqttDiscMsgSensor.pl_avail.CharString := THIS^.availabilityOnline; -MqttDiscMsgSensor.pl_not_avail.CharString := THIS^.availabilityOffline; -MqttDiscMsgSensor.qos.Integer := 2; +MqttDiscMsgBinSens.avty[1].topic.CharString := THIS^.availabilityTopic1; +MqttDiscMsgBinSens.avty[2].topic.CharString := THIS^.availabilityTopic2; +MqttDiscMsgBinSens.avty_mode.CharString := 'all'; +MqttDiscMsgBinSens.pl_avail.CharString := THIS^.availabilityOnline; +MqttDiscMsgBinSens.pl_not_avail.CharString := THIS^.availabilityOffline; +MqttDiscMsgBinSens.qos.Integer := 2; // Device related -MqttDiscMsgSensor.dev.cu.CharString := THIS^.cu; -MqttDiscMsgSensor.dev.name.CharString := THIS^.name; -MqttDiscMsgSensor.dev.hw.CharString := THIS^.hw; -MqttDiscMsgSensor.dev.ids.CharString := THIS^.ids; -MqttDiscMsgSensor.dev.sw.CharString := THIS^.sw; -MqttDiscMsgSensor.dev.mdl.CharString := THIS^.mdl; -MqttDiscMsgSensor.dev.mf.CharString := THIS^.mf; +MqttDiscMsgBinSens.dev.cu.CharString := THIS^.cu; +MqttDiscMsgBinSens.dev.name.CharString := THIS^.name; +MqttDiscMsgBinSens.dev.hw.CharString := THIS^.hw; +MqttDiscMsgBinSens.dev.ids.CharString := THIS^.ids; +MqttDiscMsgBinSens.dev.sw.CharString := THIS^.sw; +MqttDiscMsgBinSens.dev.mdl.CharString := THIS^.mdl; +MqttDiscMsgBinSens.dev.mf.CharString := THIS^.mf; // Extra meta-data IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - MqttDiscMsgSensor.meta.CharString := meta; + MqttDiscMsgBinSens.meta.CharString := meta; END_IF ComposeJSON( JSONString:= ADR(MqttJSON), JSONStringSize:= SIZEOF(MqttJSON), - JSONVars:= ADR(MqttDiscMsgSensor), - NumberOfVars:= SIZEOF(MqttDiscMsgSensor) / SIZEOF(JSONVAR), + JSONVars:= ADR(MqttDiscMsgBinSens), + NumberOfVars:= SIZEOF(MqttDiscMsgBinSens) / SIZEOF(JSONVAR), MaxLevel := 1, ); ComposeJSON.Execute := TRUE; @@ -2477,7 +2556,7 @@ END_IF - + @@ -2498,7 +2577,7 @@ END_IF - + @@ -2516,53 +2595,19 @@ END_IF - - - - - - + - + - - - - - - - - - - - - - - dmx specific + config or diagnostic - - - - - - - - - - - - - - - - @@ -2570,7 +2615,7 @@ END_IF - + @@ -2589,59 +2634,58 @@ END_IF + + + + + + + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + // Entity related: Basis -MqttDiscMsgLightDim.name.CharString := name; // friendly name -MqttDiscMsgLightDim.obj_id.CharString := Id; -MqttDiscMsgLightDim.uniq_id.CharString := Id; +MqttDiscMsgBinSensWCat.name.CharString := name; // friendly name +MqttDiscMsgBinSensWCat.obj_id.CharString := Id; +MqttDiscMsgBinSensWCat.uniq_id.CharString := Id; // Entity related: Specific -MqttDiscMsgLightDim.cmd_t.CharString := CommandTopic; -MqttDiscMsgLightDim.pl_on.CharString := PayloadOn; -MqttDiscMsgLightDim.pl_off.CharString := PayloadOff; -MqttDiscMsgLightDim.stat_t.CharString := StateTopic; -MqttDiscMsgLightDim.opt.Boolean := FALSE; - -MqttDiscMsgLightDim.bri_cmd_t.CharString := BrightnessCommandTopic; -MqttDiscMsgLightDim.bri_stat_t.CharString := BrightnessStateTopic; -MqttDiscMsgLightDim.bri_scl.Integer := BrightnessScale; -MqttDiscMsgLightDim.on_cmd_type.CharString := 'last'; - -MqttDiscMsgLightDim.dmxChannel.Integer := DmxChannel; -MqttDiscMsgLightDim.dmxWidth.Integer := DmxWidth; -MqttDiscMsgLightDim.dmxUniverse.Integer := DmxUniverse; +MqttDiscMsgBinSensWCat.stat_t.CharString := StateTopic; +MqttDiscMsgBinSensWCat.pl_on.CharString := PayloadOn; +MqttDiscMsgBinSensWCat.pl_off.CharString := PayloadOff; +MqttDiscMsgBinSensWCat.dev_cla.CharString := DeviceClass; +MqttDiscMsgBinSensWCat.ent_cat.CharString := EntityCategory; // Availabilty related -MqttDiscMsgLightDim.avty[1].topic.CharString := THIS^.availabilityTopic1; -MqttDiscMsgLightDim.avty[2].topic.CharString := THIS^.availabilityTopic2; -MqttDiscMsgLightDim.avty_mode.CharString := 'all'; -MqttDiscMsgLightDim.pl_avail.CharString := THIS^.availabilityOnline; -MqttDiscMsgLightDim.pl_not_avail.CharString := THIS^.availabilityOffline; -MqttDiscMsgLightDim.qos.Integer := 2; +MqttDiscMsgBinSensWCat.avty[1].topic.CharString := THIS^.availabilityTopic1; +MqttDiscMsgBinSensWCat.avty[2].topic.CharString := THIS^.availabilityTopic2; +MqttDiscMsgBinSensWCat.avty_mode.CharString := 'all'; +MqttDiscMsgBinSensWCat.pl_avail.CharString := THIS^.availabilityOnline; +MqttDiscMsgBinSensWCat.pl_not_avail.CharString := THIS^.availabilityOffline; +MqttDiscMsgBinSensWCat.qos.Integer := 2; // Device related -MqttDiscMsgLightDim.dev.cu.CharString := THIS^.cu; -MqttDiscMsgLightDim.dev.name.CharString := THIS^.name; -MqttDiscMsgLightDim.dev.hw.CharString := THIS^.hw; -MqttDiscMsgLightDim.dev.ids.CharString := THIS^.ids; -MqttDiscMsgLightDim.dev.sw.CharString := THIS^.sw; -MqttDiscMsgLightDim.dev.mdl.CharString := THIS^.mdl; -MqttDiscMsgLightDim.dev.mf.CharString := THIS^.mf; +MqttDiscMsgBinSensWCat.dev.cu.CharString := THIS^.cu; +MqttDiscMsgBinSensWCat.dev.name.CharString := THIS^.name; +MqttDiscMsgBinSensWCat.dev.hw.CharString := THIS^.hw; +MqttDiscMsgBinSensWCat.dev.ids.CharString := THIS^.ids; +MqttDiscMsgBinSensWCat.dev.sw.CharString := THIS^.sw; +MqttDiscMsgBinSensWCat.dev.mdl.CharString := THIS^.mdl; +MqttDiscMsgBinSensWCat.dev.mf.CharString := THIS^.mf; // Extra meta-data IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - MqttDiscMsgLightDim.meta.CharString := meta; + MqttDiscMsgBinSensWCat.meta.CharString := meta; END_IF ComposeJSON( JSONString:= ADR(MqttJSON), JSONStringSize:= SIZEOF(MqttJSON), - JSONVars:= ADR(MqttDiscMsgLightDim), - NumberOfVars:= SIZEOF(MqttDiscMsgLightDim) / SIZEOF(JSONVAR), + JSONVars:= ADR(MqttDiscMsgBinSensWCat), + NumberOfVars:= SIZEOF(MqttDiscMsgBinSensWCat) / SIZEOF(JSONVAR), MaxLevel := 1, ); ComposeJSON.Execute := TRUE; @@ -2665,7 +2709,7 @@ END_IF - + @@ -2686,7 +2730,7 @@ END_IF - + @@ -2694,44 +2738,38 @@ END_IF entity specific - + + + + - + + + config or diagnostic + - + - + + + + - - - - - - - - - - - - - - - - - - + + + - + @@ -2756,47 +2794,43 @@ END_IF MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); // Entity related: Basis -MqttDiscMsgSwitch.name.CharString := name; // friendly name -MqttDiscMsgSwitch.obj_id.CharString := Id; -MqttDiscMsgSwitch.uniq_id.CharString := Id; +MqttDiscMsgSensorWCat.name.CharString := name; // friendly name +MqttDiscMsgSensorWCat.obj_id.CharString := Id; +MqttDiscMsgSensorWCat.uniq_id.CharString := Id; // Entity related: Specific -MqttDiscMsgSwitch.cmd_t.CharString := CommandTopic; -MqttDiscMsgSwitch.pl_on.CharString := PayloadOn; -MqttDiscMsgSwitch.pl_off.CharString := PayloadOff; -MqttDiscMsgSwitch.stat_t.CharString := StateTopic; -MqttDiscMsgSwitch.stat_on.CharString := StateOnPayload; -MqttDiscMsgSwitch.stat_off.CharString := StateOffPayload; -MqttDiscMsgSwitch.opt.Boolean := FALSE; -MqttDiscMsgSwitch.dev_cla.CharString := DeviceClass; +//MqttDiscoverySensorMessage.ic.CharString := Icon; +MqttDiscMsgSensorWCat.stat_t.CharString := StateTopic; +MqttDiscMsgSensorWCat.exp_aft.Integer := ExpiryAfter; +MqttDiscMsgSensorWCat.ent_cat.CharString := EntityCategory; // Availabilty related -MqttDiscMsgSwitch.avty[1].topic.CharString := THIS^.availabilityTopic1; -MqttDiscMsgSwitch.avty[2].topic.CharString := THIS^.availabilityTopic2; -MqttDiscMsgSwitch.avty_mode.CharString := 'all'; -MqttDiscMsgSwitch.pl_avail.CharString := THIS^.availabilityOnline; -MqttDiscMsgSwitch.pl_not_avail.CharString := THIS^.availabilityOffline; -MqttDiscMsgSwitch.qos.Integer := 2; +MqttDiscMsgSensorWCat.avty[1].topic.CharString := THIS^.availabilityTopic1; +MqttDiscMsgSensorWCat.avty[2].topic.CharString := THIS^.availabilityTopic2; +MqttDiscMsgSensorWCat.avty_mode.CharString := 'all'; +MqttDiscMsgSensorWCat.pl_avail.CharString := THIS^.availabilityOnline; +MqttDiscMsgSensorWCat.pl_not_avail.CharString := THIS^.availabilityOffline; +MqttDiscMsgSensorWCat.qos.Integer := 2; // Device related -MqttDiscMsgSwitch.dev.cu.CharString := THIS^.cu; -MqttDiscMsgSwitch.dev.name.CharString := THIS^.name; -MqttDiscMsgSwitch.dev.hw.CharString := THIS^.hw; -MqttDiscMsgSwitch.dev.ids.CharString := THIS^.ids; -MqttDiscMsgSwitch.dev.sw.CharString := THIS^.sw; -MqttDiscMsgSwitch.dev.mdl.CharString := THIS^.mdl; -MqttDiscMsgSwitch.dev.mf.CharString := THIS^.mf; +MqttDiscMsgSensorWCat.dev.cu.CharString := THIS^.cu; +MqttDiscMsgSensorWCat.dev.name.CharString := THIS^.name; +MqttDiscMsgSensorWCat.dev.hw.CharString := THIS^.hw; +MqttDiscMsgSensorWCat.dev.ids.CharString := THIS^.ids; +MqttDiscMsgSensorWCat.dev.sw.CharString := THIS^.sw; +MqttDiscMsgSensorWCat.dev.mdl.CharString := THIS^.mdl; +MqttDiscMsgSensorWCat.dev.mf.CharString := THIS^.mf; // Extra meta-data IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - MqttDiscMsgSwitch.meta.CharString := meta; + MqttDiscMsgSensorWCat.meta.CharString := meta; END_IF ComposeJSON( JSONString:= ADR(MqttJSON), JSONStringSize:= SIZEOF(MqttJSON), - JSONVars:= ADR(MqttDiscMsgSwitch), - NumberOfVars:= SIZEOF(MqttDiscMsgSwitch) / SIZEOF(JSONVAR), + JSONVars:= ADR(MqttDiscMsgSensorWCat), + NumberOfVars:= SIZEOF(MqttDiscMsgSensorWCat) / SIZEOF(JSONVAR), MaxLevel := 1, ); ComposeJSON.Execute := TRUE; @@ -2811,6 +2845,15 @@ ELSIF NOT (MqttJSON = '') THEN Qos := MQTT.QoS.ExactlyOnce, MqttRetain := TRUE, ); + IF NOT (StateValue = '') THEN + pMqttPublishQueue^.AddMessage( + Payload:= StateValue, + Topic := StateTopic, + Qos := MQTT.QoS.ExactlyOnce, + MqttRetain := TRUE, + ); + END_IF + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -2819,41 +2862,6 @@ END_IF - - - - - - - - - - - - - - - - - - - - - - - - - pMqttPublishQueue^.AddMessage( - Payload:= CONCAT(CONCAT(instance,' | '),str), - Topic := CONCAT(MqttDiagnosticTopic, '/Log'), - Qos := 1, - MqttRetain := TRUE -); - - - - - @@ -6254,77 +6262,528 @@ ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= D THIS^.MqttRequestClose:=TRUE; END_IF -END_IF +END_IF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important + +(*pass trough*) +THIS^.pMqttPublishQueue := pMqttPublishQueue; +THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; +THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; +THIS^.pMqttPublishQueue:=pMqttPublishQueue; + +SUPER^.InitBaseMqtt(); +pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Refelection: object's full instance name + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FB_MQTT_BASE + MQTT.MQTT_SUBSCRIBE_CALLBACK + + + + + + + + + + + + DaliSendFadeTime( + typBallast := BALLAST, + bFadeTime := 2); // 1 sec + +DaliSendFadeRate( + typBallast := BALLAST, + bFadeRate := 2); // 1 sec + +DaliSendDimValue( + typBallast := BALLAST, + rDimValue := DimValue); + +DaliSyncSignalGenerator( + ENABLE := TRUE, + TIMEHIGH := T#1S, + TIMELOW := T#1M, + OUT => DaliSendDimValue.xUpdate); + +Toggle_RTrigger(CLK:=TOGGLE); + +// Regular push +IF(Toggle_RTrigger.Q AND DimValue = 0) THEN + SetDimValue(100); +ELSIF(Toggle_RTrigger.Q AND DimValue > 0) THEN + SetDimValue(0); +END_IF + +// Long push +IF P_LONG THEN + SetDimValue(DimValue + DimDirection); +END_IF + +IF MqttSendBrightnessUpdate OR Startup AND InitMqttDone THEN + pMqttPublishQueue^.AddMessage( + Payload := REAL_TO_STRING(DimValue), + Topic := CONCAT(THIS^.MQTTPublishTopic, '/BRIGHTNESS'), + Qos := MQTT.QoS.ExactlyOnce, + MqttRetain := TRUE + ); + MqttSendBrightnessUpdate := FALSE; +END_IF + +IF MqttSendOnUpdate OR (Startup AND DimValue > 0) AND InitMqttDone THEN + pMqttPublishQueue^.AddMessage( + Payload := 'ON', + Topic := THIS^.MQTTPublishTopic, + Qos := MQTT.QoS.ExactlyOnce, + MqttRetain := TRUE + ); + MqttSendOnUpdate := FALSE; +END_IF + +IF MqttSendOffUpdate OR (Startup AND DimValue = 0) AND InitMqttDone THEN + pMqttPublishQueue^.AddMessage( + Payload := 'OFF', + Topic := THIS^.MQTTPublishTopic, + Qos := MQTT.QoS.ExactlyOnce, + MqttRetain := TRUE + ); + MqttSendOffUpdate := FALSE; +END_IF + +Startup:=FALSE; +STATUS_LED := REAL_TO_BOOL(DimValue); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + ELSE + id := overruleId; // 'MY_PH_GND_HALL_01' + END_IF + + Device^.CreateLightDimmerEntity( + Name := name, + Id := Id, + Meta := meta, + CommandTopic := THIS^.MQTTSubscribeTopic, + PayloadOn := 'ON', + PayloadOff := 'OFF', + StateTopic := THIS^.MQTTPublishTopic, + BrightnessCommandTopic := CONCAT(THIS^.MQTTSubscribeTopic, '/BRIGHTNESS'), + BrightnessStateTopic := CONCAT(THIS^.MQTTPublishTopic, '/BRIGHTNESS'), + BrightnessScale := 100, + OnCommandType := 'brightness'); + + initMqttDiscoveryDone := TRUE; +END_IF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important + +(*pass trough*) +THIS^.pMqttPublishQueue := pMqttPublishQueue; +THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; +THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; +THIS^.pMqttPublishQueue:=pMqttPublishQueue; + +SUPER^.InitBaseMqtt(); +pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + + + + + + + + + + + + + + + + + + + + Collection of recived Data + + + + + + + //first check if Mqtt is initialized, otherwise do nothing +IF NOT(InitMqttDone) THEN + //mark the interface call from the collector as done + PublishReceived := TRUE; + +ELSIF MQTTSubscribeTopic = Data.TopicOut^ THEN + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('ON')) THEN + SetDimValue(100); + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('OFF')) THEN + SetDimValue(0); + END_IF + +ELSIF CONCAT(MQTTSubscribeTopic, '/BRIGHTNESS') = Data.TopicOut^ THEN + IF OSCAT_BASIC.IS_CC(str:= Data.PayloadString^,cmp:='0123456789.') AND THIS^.PRIO_HIGH = FALSE THEN + SetDimValue(STRING_TO_REAL(Data.PayloadString^)); + END_IF +END_IF + + + + + + + + + + + + + + + + + + + + + + + + THIS^.MqttSendBrightnessUpdate := TRUE; + +IF THIS^.DimValue = 0 AND Value > 0 THEN + THIS^.MqttSendOnUpdate := TRUE; +END_IF + +IF THIS^.DimValue > 0 AND Value = 0 THEN + THIS^.MqttSendOffUpdate := TRUE; +END_IF + +IF Value = 0 THEN + DimDirection := 1; +ELSIF Value = 100 THEN + DimDirection := -1; +END_IF + +THIS^.DimValue := Value; - + + + + - - - - - - - - - - - - - - - - - - - + - - - - - + - + - - - - - + - - - - - - - - - - - - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important - -(*pass trough*) -THIS^.pMqttPublishQueue := pMqttPublishQueue; -THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; -THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; -THIS^.pMqttPublishQueue:=pMqttPublishQueue; - -SUPER^.InitBaseMqtt(); -pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + DaliSendFadeTime.bFadeTime := FadeTime; +DaliSendFadeRate.bFadeRate := FadeRate; @@ -7209,210 +7668,72 @@ ELSIF CONCAT(MQTTSubscribeTopic,'/OUT') = Data.TopicOut^ THEN THIS^.SoftDimToValue:=TRUE; END_IF - -// Legacy! backwards compatiably with /+ topics instead of /# -ELSIF CommonTypesAndFunctions.StrEqualsAtStart(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN - //mark the interface call from the collector as done - PublishReceived := TRUE; - //now process the data - IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('TRUE')) THEN - MqttHighRequest := TRUE; - ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN - MqttLowRequest := TRUE; - ELSIF OSCAT_BASIC.IS_CC(str:= Data.PayloadString^,cmp:='0123456789.') AND THIS^.PRIO_HIGH = FALSE THEN - THIS^.OUT_Target:=STRING_TO_BYTE(Data.PayloadString^); - THIS^.SoftDimToValue:=TRUE; - END_IF -END_IF - - - - - - - - - - - - - - - - - - - - - - - - - FB_BASE_MQTT_DISCOVERY_DEVICE - - - - - - - - - - - - (* allow the pulse generator to generate a pulse, used for refreshing IP address *) -MqttRefreshIP(); - -(* Refresh the IP address on every pulse *) -IF NOT(xInit) AND MqttRefreshIP.Q THEN - pMqttPublishQueue^.AddMessage( - Payload:= GetIpAddress(), - Topic := MqttDiagnosticTopicIP, - Qos := MQTT.QoS.ExactlyOnce, - MqttRetain := TRUE, - ); -END_IF - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - xFirstAdapter := TRUE; -rResult := 0; -WHILE rResult = 0 DO - IF xFirstAdapter THEN - hAdapter := SysSockGetFirstAdapterInfo(ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); - ELSE - hAdapter := SysSockGetNextAdapterInfo(hAdapter, ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); - END_IF - IF rResult = 0 THEN - GetMac := Standard.CONCAT(SM0.Byte_To_HexString(AdapterInfo.abyMac[0]),'-'); - GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[1])); - GetMac := Standard.CONCAT(GetMac,'-'); - GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[2])); - GetMac := Standard.CONCAT(GetMac,'-'); - GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[3])); - GetMac := Standard.CONCAT(GetMac,'-'); - GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[4])); - GetMac := Standard.CONCAT(GetMac,'-'); - GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[5])); - END_IF - xFirstAdapter := FALSE; -END_WHILE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - xFirstAdapter := TRUE; -rResult := 0; -WHILE rResult = 0 DO - IF xFirstAdapter THEN - hAdapter := SysSockGetFirstAdapterInfo(ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); - ELSE - hAdapter := SysSockGetNextAdapterInfo(hAdapter, ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); - END_IF - IF rResult = 0 THEN - GetIpAddress := Standard.CONCAT(BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b1),'.'); - GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b2)); - GetIpAddress := Standard.CONCAT(GetIpAddress,'.'); - GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b3)); - GetIpAddress := Standard.CONCAT(GetIpAddress,'.'); - GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b4)); + +// Legacy! backwards compatiably with /+ topics instead of /# +ELSIF CommonTypesAndFunctions.StrEqualsAtStart(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN + //mark the interface call from the collector as done + PublishReceived := TRUE; + //now process the data + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('TRUE')) THEN + MqttHighRequest := TRUE; + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN + MqttLowRequest := TRUE; + ELSIF OSCAT_BASIC.IS_CC(str:= Data.PayloadString^,cmp:='0123456789.') AND THIS^.PRIO_HIGH = FALSE THEN + THIS^.OUT_Target:=STRING_TO_BYTE(Data.PayloadString^); + THIS^.SoftDimToValue:=TRUE; END_IF - xFirstAdapter := FALSE; -END_WHILE +END_IF + + + + + + + + + + + + + + + + + + + + FB_BASE_MQTT_DISCOVERY_DEVICE + + + + + + + + + + + + (* allow the pulse generator to generate a pulse, used for refreshing IP address *) +MqttRefreshIP(); + +(* Refresh the IP address on every pulse *) +IF NOT(xInit) AND MqttRefreshIP.Q THEN + pMqttPublishQueue^.AddMessage( + Payload:= GetIpAddress(), + Topic := MqttDiagnosticTopicIP, + Qos := MQTT.QoS.ExactlyOnce, + MqttRetain := TRUE, + ); +END_IF + + + @@ -7683,6 +8004,144 @@ END_IF + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + xFirstAdapter := TRUE; +rResult := 0; +WHILE rResult = 0 DO + IF xFirstAdapter THEN + hAdapter := SysSockGetFirstAdapterInfo(ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); + ELSE + hAdapter := SysSockGetNextAdapterInfo(hAdapter, ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); + END_IF + IF rResult = 0 THEN + GetIpAddress := Standard.CONCAT(BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b1),'.'); + GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b2)); + GetIpAddress := Standard.CONCAT(GetIpAddress,'.'); + GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b3)); + GetIpAddress := Standard.CONCAT(GetIpAddress,'.'); + GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b4)); + END_IF + xFirstAdapter := FALSE; +END_WHILE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + xFirstAdapter := TRUE; +rResult := 0; +WHILE rResult = 0 DO + IF xFirstAdapter THEN + hAdapter := SysSockGetFirstAdapterInfo(ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); + ELSE + hAdapter := SysSockGetNextAdapterInfo(hAdapter, ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); + END_IF + IF rResult = 0 THEN + GetMac := Standard.CONCAT(SM0.Byte_To_HexString(AdapterInfo.abyMac[0]),'-'); + GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[1])); + GetMac := Standard.CONCAT(GetMac,'-'); + GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[2])); + GetMac := Standard.CONCAT(GetMac,'-'); + GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[3])); + GetMac := Standard.CONCAT(GetMac,'-'); + GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[4])); + GetMac := Standard.CONCAT(GetMac,'-'); + GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[5])); + END_IF + xFirstAdapter := FALSE; +END_WHILE + + + + + @@ -12692,6 +13151,33 @@ SwapWordsToReal := pt_REAL^; + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -12767,6 +13253,19 @@ SwapWordsToReal := pt_REAL^; + + + + + + DALI FUNCTION BLOCKS + + + + + + + @@ -12952,6 +13451,15 @@ FB_VIRTUAL_REAL_001.ConfigureFunctionBlockAsVirtualInput(DefaultValue:=0.1,SetDe (* FB_VIRTUAL_REAL_001.ConfigureFunctionBlockAsVirtualOutput(PublishAtStartup:=TRUE); *) +(* DALI *) +FB_DALI_1_ADR0.InitMqtt(MQTTPublishPrefix:= ADR(MqttVariables.MqttPubDimmerPrefix), + MQTTSubscribePrefix:= ADR(MqttVariables.MqttSubDimmerPrefix), + pMqttPublishQueue := ADR(MqttVariables.fbMqttPublishQueue), + pMqttCallbackCollector := ADR(MqttVariables.collector_FB_DIMMER_MQTT) +); + +FB_DALI_1_ADR0.InitMqttDiscovery(ADR(MqttVariables.PLC_Device), 'Keuken'); + MqttVariables.PLC_Device.SendLogMessage('Init finished', 'MAIN_INIT'); @@ -12984,6 +13492,24 @@ FB_VIRTUAL_REAL_001(); + + + + // Run the master before anything else +M1_DALIMASTER( + bPortDALI:=1, + I_Port:=IoConfig_Globals.DALI_MULTI_MASTER_MODULE); + +// Run individual DALI FB +FB_DALI_1_ADR0( + BALLAST := DALIVariables.M1_Light1, + TOGGLE := FB_DI_PB_002.SINGLE, + P_LONG := FB_DI_PB_002.P_LONG, + STATUS_LED => DO_002); + + + + @@ -13071,12 +13597,27 @@ FB_VIRTUAL_REAL_001(); - + + + + + + + + DALI + FALSE + 0 + N + + + + + @@ -13091,7 +13632,7 @@ FB_VIRTUAL_REAL_001(); - + @@ -13106,7 +13647,7 @@ FB_VIRTUAL_REAL_001(); - + @@ -13121,7 +13662,7 @@ FB_VIRTUAL_REAL_001(); - + @@ -13137,19 +13678,19 @@ FB_VIRTUAL_REAL_001(); - + TRUE - + - + @@ -13164,10 +13705,10 @@ FB_VIRTUAL_REAL_001(); - + - + @@ -14445,6 +14986,18 @@ END_IF + + + + + + + + + + + + diff --git a/src/HomeAutomation.ecp b/src/HomeAutomation.ecp index cd41426..115eb66 100644 Binary files a/src/HomeAutomation.ecp and b/src/HomeAutomation.ecp differ