diff --git a/src/Exports/CodesysV3.export b/src/Exports/CodesysV3.export index 5a06132..6502fb9 100644 --- a/src/Exports/CodesysV3.export +++ b/src/Exports/CodesysV3.export @@ -1,7 +1,7 @@ - AAEAAAD/////AQAAAAAAAAAMAgAAADxDb3JlLCBWZXJzaW9uPTMuNS4xNy4yLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAACNfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuUHJvZmlsZQMAAAAeX3BsdWdJbkd1aWRUb1ZlcnNpb25Db25zdHJhaW50Fl9wbHVnSW5HdWlkVG9FeHRlbnNpb24aX3BsdWdJbkd1aWRUb0V4dGVuc2lvbkxpc3QEBAQ9XzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb1ZlcnNpb25Db25zdHJhaW50RGljdGlvbmFyeQIAAAAwXzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb0Jvb2xEaWN0aW9uYXJ5AgAAAEBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvUHJvZmlsZUV4dGVuc2lvbkxpc3REaWN0aW9uYXJ5AgAAAAIAAAAJAwAAAAkEAAAACQUAAAAFAwAAAD1fM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvVmVyc2lvbkNvbnN0cmFpbnREaWN0aW9uYXJ5AQAAABhEaWN0aW9uYXJ5QmFzZStoYXNodGFibGUDHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUCAAAACQYAAAAFBAAAADBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvQm9vbERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJBwAAAAUFAAAAQF8zUy5Db0RlU3lzLkNvcmUuQ29tcG9uZW50cy5HdWlkVG9Qcm9maWxlRXh0ZW5zaW9uTGlzdERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJCAAAAAQGAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUHAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhh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AAAAAAAAAWsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFsAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABbQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAW4BAABhAQAAAwAAAAUAAAAOAAAACgAAAAFvAQAAYQEAAAMAAAAFAAAADgAAAB4AAAABcAEAAGEBAAADAAAABQAAAA4AAAAKAAAAAXEBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFyAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXQBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF1AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABdgEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF4AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABeQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXoBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAF7AQAAYQEAAAMAAAAFAAAADgAAAAoAAAABfAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAX0BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF+AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABfwEAAGEBAAADAAAABQAAAA4AAAAeAAAAAYABAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGBAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABggEAAGEBAAADAAAABQAAAA4AAAAKAAAAAYMBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGEAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABhQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYYBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGHAQAAYQEAAAMAAAAFAAAADgAAABQAAAABiAEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYkBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGKAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYwBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGNAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABjgEAAGEBAAADAAAABQAAAA4A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AAAAAAAAAdcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHYAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB2QEAAGEBAAADAAAABQAAAA4AAAAAAAAAAdoBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAHbAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB3AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAd0BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHeAQAAYQEAAAMAAAAFAAAADgAAAB4AAAAB3wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAeABAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHhAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB4gEAAGEBAAADAAAABQAAAA4AAAAAAAAAAeMBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHkAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB5QEAAGEBAAADAAAABQAAAA4AAAAeAAAAAeYBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHnAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB6AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAekBAABhAQAAAwAAAAUAAAAOAAAACgAAAAHqAQAAYQEAAAMAAAAFAAAADgAAABQAAAAB6wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAewBAABhAQAAAwAAAAUAAAAOAAAAFAAAAAHtAQAAYQEAAAMAAAAFAAAADgAAABQAAAAB7gEAAGEBAAADAAAABQAAAA4AAAAAAAAAAe8BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHwAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB8QEAAGEBAAADAAAABQAAAA4AAAAUAAAAAfIBAABhAQAAAwAAAAUAAAAOAAAAFAAAAAHzAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB9AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAfUBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAH2AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB9wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAfgBAABhAQAAAwAAAAUAAAAOAAAACgAAAAH5AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB+gEAAGEBAAADAAAABQAAAA4AAAAKAAAAAfsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAH8AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB/QEAAGEBAAADAAAABQAAAA4AAAAAAAAAAf4BAABhAQAAAwAAAAUAAAAOAAAAHgAAAAH/AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABAAIAAGEBAAADAAAABQAAAA4AAAAAAAAAAQECAABhAQAAAwAAAAUAAAAOAAAAAAAAAAECAgAAYQEAAAMAAAAFAAAADgAAAAAAAAABAwIAAGEBAAADAAAABQAAAA4AAAAeAAAAAQQCAABhAQAAAwAAAAUAAAAOAAAAFAAAAAEFAgAAYQEAAAMAAAAFAAAADgAAAAAAAAAL + AAEAAAD/////AQAAAAAAAAAMAgAAADxDb3JlLCBWZXJzaW9uPTMuNS4xNy4yLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAACNfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuUHJvZmlsZQMAAAAeX3BsdWdJbkd1aWRUb1ZlcnNpb25Db25zdHJhaW50Fl9wbHVnSW5HdWlkVG9FeHRlbnNpb24aX3BsdWdJbkd1aWRUb0V4dGVuc2lvbkxpc3QEBAQ9XzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb1ZlcnNpb25Db25zdHJhaW50RGljdGlvbmFyeQIAAAAwXzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb0Jvb2xEaWN0aW9uYXJ5AgAAAEBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvUHJvZmlsZUV4dGVuc2lvbkxpc3REaWN0aW9uYXJ5AgAAAAIAAAAJAwAAAAkEAAAACQUAAAAFAwAAAD1fM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvVmVyc2lvbkNvbnN0cmFpbnREaWN0aW9uYXJ5AQAAABhEaWN0aW9uYXJ5QmFzZStoYXNodGFibGUDHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUCAAAACQYAAAAFBAAAADBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvQm9vbERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJBwAAAAUFAAAAQF8zUy5Db0RlU3lzLkNvcmUuQ29tcG9uZW50cy5HdWlkVG9Qcm9maWxlRXh0ZW5zaW9uTGlzdERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJCAAAAAQGAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUHAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhh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AAAeAAAAAWsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFsAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABbQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAW4BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFvAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAXEBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFyAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXQBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF1AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABdgEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF4AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABeQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXoBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF7AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABfAEAAGEBAAADAAAABQAAAA4AAAAKAAAAAX0BAABhAQAAAwAAAAUAAAAOAAAAHgAAAAF+AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABfwEAAGEBAAADAAAABQAAAA4AAAAeAAAAAYABAABhAQAAAwAAAAUAAAAOAAAAHgAAAAGBAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABggEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYMBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGEAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABhQEAAGEBAAADAAAABQAAAA4AAAAKAAAAAYYBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGHAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiAEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYkBAABhAQAAAwAAAAUAAAAOAAAAFAAAAAGKAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYwBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGNAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABjgEAAGEBAAADAAAABQAAAA4A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 True @@ -543,6 +543,310 @@ -1 + + True + + 66c93670-7793-463e-93d0-a9b318db344d + 00000000-0000-0000-0000-000000000000 + FB_BASE_MQTT_DISCOVERY_DEVICE + + + + 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 + + 638133836320838396 + + + None + + + + + 2 + + + + + + + + + + + 3 + + {attribute 'reflection' := ''} + + + 4 + + FUNCTION_BLOCK FB_BASE_MQTT_DISCOVERY_DEVICE + + + 5 + + VAR + + + 6 + + name: STRING; + + + 7 + + ///configuration_url + + + 8 + + cu: STRING; + + + 9 + + ///connections + + + 10 + + cns: ARRAY[1..2] OF ARRAY[1..2] OF STRING; + + + 11 + + ///identifiers + + + 12 + + ids: STRING; + + + 13 + + ///manufacturer + + + 14 + + mf: STRING; + + + 15 + + ///model + + + 16 + + mdl: STRING; + + + 17 + + ///sw_version + + + 18 + + sw: STRING; + + + 19 + + ///hw_version + + + 20 + + hw: STRING; + + + 21 + + ip: STRING; + + + 22 + + mac: STRING; + + + 23 + + /// must identic to the name in the device tree + + + 24 + + sAppName: STRING := 'Application'; + + + 25 + + xInit: BOOL := TRUE; + + + 26 + + /// object's full instance name + + + 27 + + {attribute 'instance-path' := ''} + + + 28 + + {attribute 'noinit'} + + + 29 + + InstanceName: STRING; + + + 30 + + Startup: BOOL := TRUE; + + + 31 + + InitMqttDone: BOOL; + + + 32 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 33 + + logger: FB_MQTT_LOG; + + + 34 + + availabilityTopic1: STRING; + + + 35 + + availabilityTopic2: STRING; + + + 36 + + availabilityOnline: STRING; + + + 37 + + availabilityOffline: STRING; + + + 38 + + MqttDiscoveryPrefix: STRING; + + + 39 + + MqttDiagnosticTopic: STRING; + + + 40 + + MqttDiscMsgBinSens: MQTT_DISCOVERY_BINARY_SENSOR; + + + 41 + + MqttDiscMsgBinSensWCat: MQTT_DISCOVERY_BINARY_SENSOR_ENT_CAT; + + + 42 + + MqttDiscMsgCover: MQTT_DISCOVERY_COVER; + + + 43 + + MqttDiscMsgLightDim: MQTT_DISCOVERY_LIGHT_DIMMER; + + + 44 + + MqttDiscMsgLight: MQTT_DISCOVERY_LIGHT; + + + 45 + + MqttDiscMsgLock: MQTT_DISCOVERY_LOCK; + + + 46 + + MqttDiscMsgSensor: MQTT_DISCOVERY_SENSOR; + + + 47 + + MqttDiscMsgSensorWCat: MQTT_DISCOVERY_SENSOR_ENT_CAT; + + + 48 + + MqttDiscMsgSiren: MQTT_DISCOVERY_SIREN; + + + 49 + + MqttDiscMsgSwitch: MQTT_DISCOVERY_SWITCH; + + + 50 + + END_VAR + + + 1 + + + + + + + 50 + Standard + + False + + 00000000-0000-0000-0000-000000000000 + + -1 + True @@ -2456,7 +2760,7 @@ True - 8c517942-8e59-4e94-9803-6498eac9f87f + fb058f61-66e0-49ec-9946-da2492e34dad 00000000-0000-0000-0000-000000000000 FB_OUTPUT_BINARY_MQTT @@ -2482,7 +2786,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638129306703965019 + 638133836327708016 None @@ -2713,12 +3017,12 @@ 45 - {attribute 'instance-path' := ''} + {attribute 'noinit'} 46 - {attribute 'noinit'} + {attribute 'instance-path' := ''} 47 @@ -2820,7 +3124,7 @@ True - b5a7395b-79b0-4613-b65d-fa71daa858f4 + 7ab5f4f2-a03c-498e-b52e-ac3df962622c 00000000-0000-0000-0000-000000000000 FB_OUTPUT_BISTABLE_MQTT @@ -2846,7 +3150,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638129306707495005 + 638133836330588398 None @@ -3137,12 +3441,12 @@ 57 - {attribute 'instance-path' := ''} + {attribute 'noinit'} 58 - {attribute 'noinit'} + {attribute 'instance-path' := ''} 59 @@ -4887,9 +5191,9 @@ True - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + 20eaf0ea-fc95-467c-9beb-a3212b0f3e69 00000000-0000-0000-0000-000000000000 - FB_RS485_DUCO_DUCOBOX_MQTT + FB_PLC_MQTT_DISCOVERY_DEVICE @@ -4913,7 +5217,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389525966538 + 638133836333778386 None @@ -4923,261 +5227,62 @@ 3 - timerData(); + (* allow the pulse generator to generate a pulse, used for refreshing IP address *) 4 - + MqttRefreshIP(); 5 - FOR loopCounter := 2 TO 30 DO + 6 - Nodes[loopCounter](); - - - 2 - - END_FOR + (* Refresh the IP address on every pulse *) - - - - - - 7 - {attribute 'reflection' := ''} + IF NOT(xInit) AND MqttRefreshIP.Q THEN 8 - FUNCTION_BLOCK FB_RS485_DUCO_DUCOBOX_MQTT IMPLEMENTS RS485Device, MQTT.MQTT_SUBSCRIBE_CALLBACK + pMqttPublishQueue^.AddMessage( 9 - VAR_OUTPUT + Payload:= GetIpAddress(), 10 - ACTIVEPOWER: REAL := 0; + Topic := MqttDiagnosticTopicIP, 11 - DataAvailable: BOOL := FALSE; + Qos := MQTT.QoS.ExactlyOnce, 12 - Error: BOOL := FALSE; + MqttRetain := TRUE, 13 - END_VAR - - - 14 - - VAR - - - 15 - - /// object's full instance name - - - 16 - - {attribute 'instance-path' := ''} - - - 17 - - {attribute 'noinit' := ''} - - - 18 - - InstanceName: STRING; - - - 19 - - Startup: BOOL := TRUE; - - - 20 - - InitMqttDone: BOOL; - - - 21 - - MqttPublishTopicPrefix: POINTER TO STRING; - - - 22 - - MqttPublishTopicSuffix: STRING(50); - - - 23 - - MQTTSubscribeTopic: STRING(50); - - - 24 - - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; - - - 25 - - InitRS485Done: BOOL := FALSE; - - - 26 - - timerData: TON; - - - 27 - - isDataUpdated: BOOL := FALSE; - - - 28 - - Nodes: ARRAY[2..30] OF FB_RS485_DUCO_DUCOBOX_NODE_MQTT; - - - 29 - - NodePointer: UINT := 2; - - - 30 - - ActiveNode: INT := 0; - - - 31 - - loopCounter: INT; - - - 32 - - ReadMasterUnitQuery: RS485_RtuQuery := (FunctionCode := 4, ReadAddress := 10, ReadQuantity := 6); - - - 33 - - WriteQueryReady: BOOL := FALSE; - - - 34 - - WriteQueryBeingExecuted: BOOL := FALSE; - - - 35 - - WriteQuerySuffix: STRING; - - - 36 - - WriteQueryPayload: STRING; - - - 37 - - WriteQuery: RS485_RtuQuery := (FunctionCode := 6, WriteQuantity := 1); - - - 38 - - END_VAR - - - 1 - - - - - - - 38 - Standard - - False - - 00000000-0000-0000-0000-000000000000 - - -1 - - - True - - 6da195a7-86d2-4618-bcdb-49518274d9f3 - 00000000-0000-0000-0000-000000000000 - FB_RS485_DUCO_DUCOBOX_NODE_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 - - 638103389528677018 - - - None - - - - - 3 - - timerData(); - - - 4 - - + ); 2 - + END_IF @@ -5186,57 +5291,32 @@ - 5 - - FUNCTION_BLOCK FB_RS485_DUCO_DUCOBOX_NODE_MQTT - - - 6 - - VAR - - - 7 - - NodeNumber: UINT; - - - 8 - - InitMqttDone: BOOL; - - - 9 - - MqttPublishTopicPrefix: POINTER TO STRING; - - - 10 + 14 - MqttPublishTopicSuffix: STRING(51); + {attribute 'reflection' := ''} - 11 + 15 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + FUNCTION_BLOCK FB_PLC_MQTT_DISCOVERY_DEVICE EXTENDS FB_BASE_MQTT_DISCOVERY_DEVICE - 12 + 16 - NodeInitialized: BOOL := FALSE; + VAR - 13 + 17 - timerData: TON; + MqttDiagnosticTopicIP: STRING; - 14 + 18 - RtuQueryRead: RS485_RtuQuery := (FunctionCode := 4, ReadAddress := 20, ReadQuantity := 6); + MqttRefreshIP: OSCAT_BASIC.GEN_PULSE; - 15 + 19 END_VAR @@ -5248,7 +5328,7 @@ - 15 + 19 Standard False @@ -5260,9 +5340,382 @@ True - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 00000000-0000-0000-0000-000000000000 - FB_RS485_EASTRON_SDM_POWER_MQTT + FB_RS485_DUCO_DUCOBOX_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 + + 638103389525966538 + + + None + + + + + 3 + + timerData(); + + + 4 + + + + + 5 + + FOR loopCounter := 2 TO 30 DO + + + 6 + + Nodes[loopCounter](); + + + 2 + + END_FOR + + + + + + + + + 7 + + {attribute 'reflection' := ''} + + + 8 + + FUNCTION_BLOCK FB_RS485_DUCO_DUCOBOX_MQTT IMPLEMENTS RS485Device, MQTT.MQTT_SUBSCRIBE_CALLBACK + + + 9 + + VAR_OUTPUT + + + 10 + + ACTIVEPOWER: REAL := 0; + + + 11 + + DataAvailable: BOOL := FALSE; + + + 12 + + Error: BOOL := FALSE; + + + 13 + + END_VAR + + + 14 + + VAR + + + 15 + + /// object's full instance name + + + 16 + + {attribute 'instance-path' := ''} + + + 17 + + {attribute 'noinit' := ''} + + + 18 + + InstanceName: STRING; + + + 19 + + Startup: BOOL := TRUE; + + + 20 + + InitMqttDone: BOOL; + + + 21 + + MqttPublishTopicPrefix: POINTER TO STRING; + + + 22 + + MqttPublishTopicSuffix: STRING(50); + + + 23 + + MQTTSubscribeTopic: STRING(50); + + + 24 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 25 + + InitRS485Done: BOOL := FALSE; + + + 26 + + timerData: TON; + + + 27 + + isDataUpdated: BOOL := FALSE; + + + 28 + + Nodes: ARRAY[2..30] OF FB_RS485_DUCO_DUCOBOX_NODE_MQTT; + + + 29 + + NodePointer: UINT := 2; + + + 30 + + ActiveNode: INT := 0; + + + 31 + + loopCounter: INT; + + + 32 + + ReadMasterUnitQuery: RS485_RtuQuery := (FunctionCode := 4, ReadAddress := 10, ReadQuantity := 6); + + + 33 + + WriteQueryReady: BOOL := FALSE; + + + 34 + + WriteQueryBeingExecuted: BOOL := FALSE; + + + 35 + + WriteQuerySuffix: STRING; + + + 36 + + WriteQueryPayload: STRING; + + + 37 + + WriteQuery: RS485_RtuQuery := (FunctionCode := 6, WriteQuantity := 1); + + + 38 + + END_VAR + + + 1 + + + + + + + 38 + Standard + + False + + 00000000-0000-0000-0000-000000000000 + + -1 + + + True + + 6da195a7-86d2-4618-bcdb-49518274d9f3 + 00000000-0000-0000-0000-000000000000 + FB_RS485_DUCO_DUCOBOX_NODE_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 + + 638103389528677018 + + + None + + + + + 3 + + timerData(); + + + 4 + + + + + 2 + + + + + + + + + + + 5 + + FUNCTION_BLOCK FB_RS485_DUCO_DUCOBOX_NODE_MQTT + + + 6 + + VAR + + + 7 + + NodeNumber: UINT; + + + 8 + + InitMqttDone: BOOL; + + + 9 + + MqttPublishTopicPrefix: POINTER TO STRING; + + + 10 + + MqttPublishTopicSuffix: STRING(51); + + + 11 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 12 + + NodeInitialized: BOOL := FALSE; + + + 13 + + timerData: TON; + + + 14 + + RtuQueryRead: RS485_RtuQuery := (FunctionCode := 4, ReadAddress := 20, ReadQuantity := 6); + + + 15 + + END_VAR + + + 1 + + + + + + + 15 + Standard + + False + + 00000000-0000-0000-0000-000000000000 + + -1 + + + True + + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + 00000000-0000-0000-0000-000000000000 + FB_RS485_EASTRON_SDM_POWER_MQTT @@ -8807,496 +9260,6 @@ -1 - - False - - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - 00000000-0000-0000-0000-000000000000 - FB_BASE_MQTT_DISCOVERY_DEVICE - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - - - - - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 41e5d1be-9ffa-4b96-90ce-6d2da0ca0c54 - - - - - - - - 6f9dac99-8de1-4efc-8465-68ac443b7d08 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638119891893372992 - - - None - - - - - 2 - - - - - - - - - - - 3 - - {attribute 'reflection' := ''} - - - 4 - - FUNCTION_BLOCK FB_BASE_MQTT_DISCOVERY_DEVICE - - - 5 - - VAR - - - 6 - - name: STRING; - - - 7 - - ///configuration_url - - - 8 - - cu: STRING; - - - 9 - - ///connections - - - 10 - - cns: ARRAY[1..2] OF ARRAY[1..2] OF STRING; - - - 11 - - ///identifiers - - - 12 - - ids: STRING; - - - 13 - - ///manufacturer - - - 14 - - mf: STRING; - - - 15 - - ///model - - - 16 - - mdl: STRING; - - - 17 - - ///sw_version - - - 18 - - sw: STRING; - - - 19 - - ///hw_version - - - 20 - - hw: STRING; - - - 21 - - ip: STRING; - - - 22 - - mac: STRING; - - - 23 - - /// must identic to the name in the device tree - - - 24 - - sAppName: STRING := 'Application'; - - - 25 - - xInit: BOOL := TRUE; - - - 26 - - /// object's full instance name - - - 27 - - {attribute 'instance-path' := ''} - - - 28 - - {attribute 'noinit'} - - - 29 - - InstanceName: STRING; - - - 30 - - Startup: BOOL := TRUE; - - - 31 - - InitMqttDone: BOOL; - - - 32 - - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; - - - 33 - - availabilityTopic1: STRING; - - - 34 - - availabilityTopic2: STRING; - - - 35 - - availabilityOnline: STRING; - - - 36 - - availabilityOffline: STRING; - - - 37 - - MqttDiscoveryPrefix: STRING; - - - 38 - - MqttDiagnosticTopic: STRING; - - - 39 - - MqttDiscMsgBinSens: MQTT_DISCOVERY_BINARY_SENSOR; - - - 40 - - MqttDiscMsgBinSensWCat: MQTT_DISCOVERY_BINARY_SENSOR_ENT_CAT; - - - 41 - - MqttDiscMsgCover: MQTT_DISCOVERY_COVER; - - - 42 - - MqttDiscMsgLightDim: MQTT_DISCOVERY_LIGHT_DIMMER; - - - 43 - - MqttDiscMsgLight: MQTT_DISCOVERY_LIGHT; - - - 44 - - MqttDiscMsgLock: MQTT_DISCOVERY_LOCK; - - - 45 - - MqttDiscMsgSensor: MQTT_DISCOVERY_SENSOR; - - - 46 - - MqttDiscMsgSensorWCat: MQTT_DISCOVERY_SENSOR_ENT_CAT; - - - 47 - - MqttDiscMsgSiren: MQTT_DISCOVERY_SIREN; - - - 48 - - MqttDiscMsgSwitch: MQTT_DISCOVERY_SWITCH; - - - 49 - - END_VAR - - - 1 - - - - - - - 49 - Standard - - False - - 41e5d1be-9ffa-4b96-90ce-6d2da0ca0c54 - - MqttDiscovery - - -1 - - - False - - 4ce5d04c-d166-4f84-8f14-40dee7843ab7 - 00000000-0000-0000-0000-000000000000 - FB_PLC_MQTT_DISCOVERY_DEVICE - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - - - - - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 41e5d1be-9ffa-4b96-90ce-6d2da0ca0c54 - - - - - - - - 6f9dac99-8de1-4efc-8465-68ac443b7d08 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638119891902002981 - - - None - - - - - 3 - - (* allow the pulse generator to generate a pulse, used for refreshing IP address *) - - - 4 - - MqttRefreshIP(); - - - 5 - - - - - 6 - - (* Refresh the IP address on every pulse *) - - - 7 - - IF NOT(xInit) AND MqttRefreshIP.Q THEN - - - 8 - - pMqttPublishQueue^.AddMessage( - - - 9 - - Payload:= GetIpAddress(), - - - 10 - - Topic := MqttDiagnosticTopicIP, - - - 11 - - Qos := MQTT.QoS.ExactlyOnce, - - - 12 - - MqttRetain := TRUE, - - - 13 - - ); - - - 2 - - END_IF - - - - - - - - - 14 - - {attribute 'reflection' := ''} - - - 15 - - FUNCTION_BLOCK FB_PLC_MQTT_DISCOVERY_DEVICE EXTENDS FB_BASE_MQTT_DISCOVERY_DEVICE - - - 16 - - VAR - - - 17 - - MqttDiagnosticTopicIP: STRING; - - - 18 - - MqttRefreshIP: OSCAT_BASIC.GEN_PULSE; - - - 19 - - END_VAR - - - 1 - - - - - - - 19 - Standard - - False - - 41e5d1be-9ffa-4b96-90ce-6d2da0ca0c54 - - MqttDiscovery - - -1 - False @@ -9997,9 +9960,9 @@ False - 46900d0a-7814-422e-afc3-0dfae8ff432a - a267de92-bab5-4cb3-917a-2be8d7a0661f - ConfigureFunctionBlock + 141b0776-1c7e-477b-b97a-01ee6094be76 + 66c93670-7793-463e-93d0-a9b318db344d + CreateBinarySensorEntity @@ -10023,459 +9986,301 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115483669607851 + 638133836325347984 - - - - 2 - - THIS^.T_TurnOffDelay:=T_TurnOffDelay; - - - - - 3 - METHOD ConfigureFunctionBlock + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); 4 - VAR_INPUT + 5 - T_TurnOffDelay: TIME; + 6 - END_VAR + // Entity related: Basis - 1 + 7 - - - - - - - a267de92-bab5-4cb3-917a-2be8d7a0661f - - FB_INPUT_BINARYSENSOR_MQTT - - -1 - - - False - - ecbb5bef-d79c-4aac-976b-34395632d443 - a267de92-bab5-4cb3-917a-2be8d7a0661f - InitMqtt - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + MqttDiscMsgBinSens.name.CharString := name; // friendly name - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483668978260 - - - - - - 3 + 8 - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important + MqttDiscMsgBinSens.obj_id.CharString := Id; - 4 + 9 - + MqttDiscMsgBinSens.uniq_id.CharString := Id; - 5 + 10 - (*pass trough*) + - 6 + 11 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + // Entity related: Specific - 7 + 12 - THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + MqttDiscMsgBinSens.stat_t.CharString := StateTopic; - 8 + 13 - SUPER^.InitBaseMqtt(); + MqttDiscMsgBinSens.pl_on.CharString := PayloadOn; - 2 + 14 - + MqttDiscMsgBinSens.pl_off.CharString := PayloadOff; - - - - - - - 9 + 15 - METHOD InitMqtt + MqttDiscMsgBinSens.dev_cla.CharString := DeviceClass; - 10 + 16 - VAR_INPUT + - 11 + 17 - MQTTPublishPrefix: POINTER TO STRING; + // Availabilty related - 12 + 18 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + MqttDiscMsgBinSens.avty[1].topic.CharString := THIS^.availabilityTopic1; - 13 + 19 - END_VAR + MqttDiscMsgBinSens.avty[2].topic.CharString := THIS^.availabilityTopic2; - 1 + 20 - - - - - - - a267de92-bab5-4cb3-917a-2be8d7a0661f - - FB_INPUT_BINARYSENSOR_MQTT - - -1 - - - False - - 2070ee38-ec9d-43d5-85fb-f0980d5482b7 - a267de92-bab5-4cb3-917a-2be8d7a0661f - InitMqttDiscovery - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + MqttDiscMsgBinSens.avty_mode.CharString := 'all'; - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483669297853 - - - - - - 3 + 21 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + MqttDiscMsgBinSens.pl_avail.CharString := THIS^.availabilityOnline; - 4 + 22 - + MqttDiscMsgBinSens.pl_not_avail.CharString := THIS^.availabilityOffline; - 5 + 23 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + MqttDiscMsgBinSens.qos.Integer := 2; - 6 + 24 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + - 7 + 25 - ELSE + // Device related - 8 + 26 - id := overruleId; // 'MY_PH_GND_HALL_01' + MqttDiscMsgBinSens.dev.cu.CharString := THIS^.cu; - 9 + 27 - END_IF + MqttDiscMsgBinSens.dev.name.CharString := THIS^.name; - 10 + 28 - + MqttDiscMsgBinSens.dev.hw.CharString := THIS^.hw; - 11 + 29 - Device^.CreateBinarySensorEntity( + MqttDiscMsgBinSens.dev.ids.CharString := THIS^.ids; - 12 + 30 - Id := id, + MqttDiscMsgBinSens.dev.sw.CharString := THIS^.sw; - 13 + 31 - Name := name, + MqttDiscMsgBinSens.dev.mdl.CharString := THIS^.mdl; - 14 + 32 - Meta := meta, + MqttDiscMsgBinSens.dev.mf.CharString := THIS^.mf; - 15 + 33 - StateTopic := THIS^.MQTTPublishTopic, + - 16 + 34 - PayloadOn := 'ON', + // Extra meta-data - 17 + 35 - PayloadOff := 'OFF', + IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - 18 + 36 - DeviceClass := DeviceClass); + MqttDiscMsgBinSens.meta.CharString := meta; - 19 + 37 - + END_IF - 20 + 38 - initMqttDiscoveryDone := TRUE; + - 2 + 39 - END_IF + ComposeJSON( - - - - - - - 21 + 40 - METHOD InitMqttDiscovery + JSONString:= ADR(MqttJSON), - 22 + 41 - VAR_INPUT + JSONStringSize:= SIZEOF(MqttJSON), - 23 + 42 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + JSONVars:= ADR(MqttDiscMsgBinSens), - 24 + 43 - Name: STRING(255); + NumberOfVars:= SIZEOF(MqttDiscMsgBinSens) / SIZEOF(JSONVAR), - 25 + 44 - DeviceClass: STRING(100) := 'smoke'; + MaxLevel := 1, - 26 + 45 - overruleId: STRING(255) := ''; + ); - 27 + 46 - meta: STRING(255) := ''; + ComposeJSON.Execute := TRUE; - 28 + 47 - END_VAR + ComposeJSON(); - 29 + 48 - VAR + - 30 + 49 - id: STRING(255); + IF MqttJSON = '' THEN - 31 + 50 - END_VAR + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); - 1 + 51 - - - - - - - a267de92-bab5-4cb3-917a-2be8d7a0661f - - FB_INPUT_BINARYSENSOR_MQTT - - -1 - - - False - - 1f4b71e5-eb2a-4c4a-b6d4-a20ad170453c - 98f79313-4387-4064-a781-6319454c2036 - ConfigureFunctionBlock - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + ELSIF NOT (MqttJSON = '') THEN - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483670867852 - - - - - - 3 + 52 - THIS^.T_Debounce:=T_Debounce; + pMqttPublishQueue^.AddMessage( - 4 + 53 - THIS^.T_Reconfig:=T_Reconfig; + Payload:= MqttJSON, - 5 + 54 - THIS^.T_On_Max:=T_On_Max; + Topic := MqttTopic, - 6 + 55 - THIS^.T_Dimm_Start:=T_Dimm_Start; + Qos := MQTT.QoS.ExactlyOnce, - 7 + 56 - THIS^.T_Dimm:=T_Dimm; + MqttRetain := TRUE, - 8 + 57 - THIS^.Min_On:=Min_On; + ); - 9 + 58 - THIS^.Max_On:=Max_On; + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); - 10 + 59 - + END_IF 2 - THIS^.T_Long:=T_Long; + @@ -10484,82 +10289,97 @@ - 11 + 60 - METHOD ConfigureFunctionBlock + {attribute 'reflection' := ''} - 12 + 61 + + METHOD CreateBinarySensorEntity + + + 62 VAR_INPUT - 13 + 63 - /// Default values for dimmer, can be overwritten by method call + /// default - 14 + 64 - T_Debounce: TIME; + Name: STRING; - 15 + 65 - T_Reconfig: TIME; + Id: STRING; - 16 + 66 - T_On_Max: TIME; + Meta: STRING; - 17 + 67 - T_Dimm_Start: TIME; + /// entity specific - 18 + 68 - T_Dimm: TIME; + StateTopic: STRING; - 19 + 69 - Min_On: BYTE; + PayloadOn: STRING; - 20 + 70 - Max_On: BYTE; + PayloadOff: STRING; - 21 + 71 - Soft_Dimm: BOOL; + DeviceClass: STRING; - 22 + 72 - Dbl_Toggle: BOOL; + END_VAR - 23 + 73 - Rst_Out: BOOL; + VAR - 24 + 74 - /// Default value for click mode, can be overwritten by method call + EntityId: STRING(25) := 'binary_sensor'; - 25 + 75 - T_Long: TIME; + ComposeJSON: STRUCT_TO_JSON; - 26 + 76 + + MqttJSON: STRING(1500); + + + 77 + + MqttTopic: STRING(100); + + + 78 END_VAR @@ -10572,18 +10392,18 @@ - 98f79313-4387-4064-a781-6319454c2036 + 66c93670-7793-463e-93d0-a9b318db344d - FB_INPUT_PUSHBUTTON_DIMMER_MQTT + FB_BASE_MQTT_DISCOVERY_DEVICE -1 False - 597edaa9-daf6-4235-891a-58677c97ecc5 - 98f79313-4387-4064-a781-6319454c2036 - InitMqtt + 2ce33ecc-6621-456a-abb7-e5f46580ad2b + 66c93670-7793-463e-93d0-a9b318db344d + CreateBinarySensorEntityWithCategory @@ -10607,7 +10427,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115483670557846 + 638133836325747996 @@ -10616,12 +10436,12 @@ 3 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); 4 - THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; + 5 @@ -10631,440 +10451,282 @@ 6 - InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(THIS^.InstanceName)) + 1; + // Entity related: Basis 7 - THIS^.MqttPublishTopicSuffix := InstanceNamePt^; + MqttDiscMsgBinSensWCat.name.CharString := name; // friendly name 8 - + MqttDiscMsgBinSensWCat.obj_id.CharString := Id; 9 - THIS^.OutputDimmer:=OutputDimmer; + MqttDiscMsgBinSensWCat.uniq_id.CharString := Id; 10 - THIS^.Qos_Dimm:=Qos_Dimm; + 11 - THIS^.Delta_Dimm:=Delta_Dimm; + // Entity related: Specific 12 - - - - 2 - - InitMqttDone := TRUE; + MqttDiscMsgBinSensWCat.stat_t.CharString := StateTopic; - - - - - - 13 - METHOD InitMqtt + MqttDiscMsgBinSensWCat.pl_on.CharString := PayloadOn; 14 - VAR_INPUT + MqttDiscMsgBinSensWCat.pl_off.CharString := PayloadOff; 15 - MQTTPublishPrefix: POINTER TO STRING; + MqttDiscMsgBinSensWCat.dev_cla.CharString := DeviceClass; 16 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + MqttDiscMsgBinSensWCat.ent_cat.CharString := EntityCategory; 17 - OutputDimmer: BOOL; + 18 - Qos_Dimm: MQTT.QoS; + // Availabilty related 19 - Delta_Dimm: INT; + MqttDiscMsgBinSensWCat.avty[1].topic.CharString := THIS^.availabilityTopic1; 20 - END_VAR + MqttDiscMsgBinSensWCat.avty[2].topic.CharString := THIS^.availabilityTopic2; 21 - VAR + MqttDiscMsgBinSensWCat.avty_mode.CharString := 'all'; 22 - InstanceNamePt: POINTER TO STRING; + MqttDiscMsgBinSensWCat.pl_avail.CharString := THIS^.availabilityOnline; 23 - END_VAR + MqttDiscMsgBinSensWCat.pl_not_avail.CharString := THIS^.availabilityOffline; - 1 + 24 + + MqttDiscMsgBinSensWCat.qos.Integer := 2; + + + 25 - - - - - 98f79313-4387-4064-a781-6319454c2036 - - FB_INPUT_PUSHBUTTON_DIMMER_MQTT - - -1 - - - False - - 6ebfd5ef-9849-4eae-aae9-726c64dd33f7 - b624cd6e-bc6f-46a8-9c3d-8588be854a5d - 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 - - 638115483672408235 - - - - - - 2 + 26 - THIS^.T_Long:=T_Long; + // Device related - - - - - - - 3 + 27 - METHOD ConfigureFunctionBlock + MqttDiscMsgBinSensWCat.dev.cu.CharString := THIS^.cu; - 4 + 28 - VAR_INPUT + MqttDiscMsgBinSensWCat.dev.name.CharString := THIS^.name; - 5 + 29 - /// Default value for click mode, can be overwritten by method call + MqttDiscMsgBinSensWCat.dev.hw.CharString := THIS^.hw; - 6 + 30 - T_Long: TIME; + MqttDiscMsgBinSensWCat.dev.ids.CharString := THIS^.ids; - 7 + 31 - END_VAR + MqttDiscMsgBinSensWCat.dev.sw.CharString := THIS^.sw; - 1 + 32 - - - - - - - b624cd6e-bc6f-46a8-9c3d-8588be854a5d - - FB_INPUT_PUSHBUTTON_MQTT - - -1 - - - False - - f6303c90-5efc-4c71-9fd2-2ec6bc009dbf - b624cd6e-bc6f-46a8-9c3d-8588be854a5d - InitMqtt - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + MqttDiscMsgBinSensWCat.dev.mdl.CharString := THIS^.mdl; - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483672107845 - - - - - - 3 + 33 - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important + MqttDiscMsgBinSensWCat.dev.mf.CharString := THIS^.mf; - 4 + 34 - + - 5 + 35 - (*pass trough*) + // Extra meta-data - 6 + 36 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - 7 + 37 - THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + MqttDiscMsgBinSensWCat.meta.CharString := meta; - 8 + 38 - SUPER^.InitBaseMqtt(); + END_IF - 2 + 39 - - - - - - - - 9 - - METHOD InitMqtt - - 10 + 40 - VAR_INPUT + ComposeJSON( - 11 + 41 - MQTTPublishPrefix: POINTER TO STRING; + JSONString:= ADR(MqttJSON), - 12 + 42 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + JSONStringSize:= SIZEOF(MqttJSON), - 13 + 43 - END_VAR + JSONVars:= ADR(MqttDiscMsgBinSensWCat), - 1 + 44 - - - - - - - b624cd6e-bc6f-46a8-9c3d-8588be854a5d - - FB_INPUT_PUSHBUTTON_MQTT - - -1 - - - False - - 24bbe81f-bf22-4511-ab47-fca2890ecb47 - b624cd6e-bc6f-46a8-9c3d-8588be854a5d - InitMqttDiscovery - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + NumberOfVars:= SIZEOF(MqttDiscMsgBinSensWCat) / SIZEOF(JSONVAR), - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483671738153 - - - - - - 3 + 45 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + MaxLevel := 1, - 4 + 46 - + ); - 5 + 47 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + ComposeJSON.Execute := TRUE; - 6 + 48 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + ComposeJSON(); - 7 + 49 - ELSE + - 8 + 50 - id := overruleId; // 'MY_PH_GND_HALL_01' + IF MqttJSON = '' THEN - 9 + 51 - END_IF + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); - 10 + 52 - + ELSIF NOT (MqttJSON = '') THEN - 11 + 53 - Device^.CreateSensorEntity( + pMqttPublishQueue^.AddMessage( - 12 + 54 - Name := name, + Payload:= MqttJSON, - 13 + 55 - Id := id, + Topic := MqttTopic, - 14 + 56 - Meta := meta, + Qos := MQTT.QoS.ExactlyOnce, - 15 + 57 - StateTopic := THIS^.MQTTPublishTopic, + MqttRetain := TRUE, - 16 + 58 - ExpiryAfter := 2); + ); - 17 + 59 - + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); - 18 + 60 - initMqttDiscoveryDone := TRUE; + END_IF 2 - END_IF + @@ -11073,52 +10735,107 @@ - 19 + 61 - METHOD InitMqttDiscovery + {attribute 'reflection' := ''} - 20 + 62 + + METHOD CreateBinarySensorEntityWithCategory + + + 63 VAR_INPUT - 21 + 64 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + /// default - 22 + 65 - Name: STRING(255); + Name: STRING; - 23 + 66 - overruleId: STRING(255) := ''; + Id: STRING; - 24 + 67 - meta: STRING(255) := ''; + Meta: STRING; - 25 + 68 + + /// entity specific + + + 69 + + StateTopic: STRING; + + + 70 + + PayloadOn: STRING; + + + 71 + + PayloadOff: STRING; + + + 72 + + DeviceClass: STRING; + + + 73 + + /// config or diagnostic + + + 74 + + EntityCategory: STRING; + + + 75 END_VAR - 26 + 76 VAR - 27 + 77 - id: STRING(255); + EntityId: STRING(25) := 'binary_sensor'; - 28 + 78 + + ComposeJSON: STRUCT_TO_JSON; + + + 79 + + MqttJSON: STRING(1500); + + + 80 + + MqttTopic: STRING(100); + + + 81 END_VAR @@ -11131,18 +10848,18 @@ - b624cd6e-bc6f-46a8-9c3d-8588be854a5d + 66c93670-7793-463e-93d0-a9b318db344d - FB_INPUT_PUSHBUTTON_MQTT + FB_BASE_MQTT_DISCOVERY_DEVICE -1 False - 28d234e5-a1bf-45f1-a68e-df4591772edd - c9779880-673c-4a93-b351-acbcc8c75d81 - InitBaseMqtt + 404dfe3c-2ec6-4d90-9bb1-f282b0b2efe0 + 66c93670-7793-463e-93d0-a9b318db344d + CreateCoverEntity @@ -11166,7 +10883,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115483673477845 + 638133836324968006 @@ -11175,409 +10892,312 @@ 3 - + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); 4 - (*Define instance names*) + 5 - InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(_InstancePath)) + 1; + // Entity related: Basis 6 - + MqttDiscMsgCover.name.CharString := name; // friendly name 7 - DeviceName := LEFT(_InstancePath,find(_InstancePath, '.' )-1 ) ; + MqttDiscMsgCover.obj_id.CharString := Id; 8 - + MqttDiscMsgCover.uniq_id.CharString := Id; 9 - // Publish (Out); + 10 - IF NOT CommonTypesAndFunctions.StrEquals(ADR(MqttPublishTopicPrefix),ADR('')) THEN + // Entity related: Specific 11 - THIS^.MqttPublishTopicSuffix := InstanceNamePt^; + MqttDiscMsgCover.cmd_t.CharString := CommandTopic; 12 - THIS^.MQTTPublishTopic := CONCAT(MqttPublishTopicPrefix^, THIS^.MqttPublishTopicSuffix); + MqttDiscMsgCover.pl_open.CharString := PayloadOpen; 13 - END_IF + MqttDiscMsgCover.pl_cls.CharString := PayloadClose; 14 - + MqttDiscMsgCover.pl_stop.CharString := PayloadStop; 15 - // Subscribe (In) + MqttDiscMsgCover.stat_t.CharString := StateTopic; 16 - IF NOT CommonTypesAndFunctions.StrEquals(ADR(MqttSubscribeTopicPrefix),ADR('')) THEN + MqttDiscMsgCover.stat_open.CharString := StateOpen; 17 - THIS^.MQTTSubscribeTopicSuffix := InstanceNamePt^; + MqttDiscMsgCover.stat_clsd.CharString := StateClosed; 18 - THIS^.MQTTSubscribeTopic := CONCAT(MqttSubscribeTopicPrefix^ ,THIS^.MQTTSubscribeTopicSuffix); + MqttDiscMsgCover.opt.Boolean := FALSE; 19 - END_IF + MqttDiscMsgCover.dev_cla.CharString := Deviceclass; 20 - - 2 - - InitMqttDone := TRUE; - - - - - - - 21 - METHOD InitBaseMqtt + // Availabilty related 22 - VAR + MqttDiscMsgCover.avty[1].topic.CharString := THIS^.availabilityTopic1; 23 - MQTTPublishPrefix: POINTER TO STRING; + MqttDiscMsgCover.avty[2].topic.CharString := THIS^.availabilityTopic2; 24 - MQTTSubscribePrefix: POINTER TO STRING; + MqttDiscMsgCover.avty_mode.CharString := 'all'; 25 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + MqttDiscMsgCover.pl_avail.CharString := THIS^.availabilityOnline; 26 - END_VAR + MqttDiscMsgCover.pl_not_avail.CharString := THIS^.availabilityOffline; - 1 + 27 - - - - - - - c9779880-673c-4a93-b351-acbcc8c75d81 - - FB_MQTT_BASE - - -1 - - - False - - c535088d-119a-4b9d-9c46-f86698af42bb - a1bd57b2-7fd1-4392-bd24-7f01031c67fc - InitMqtt - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + MqttDiscMsgCover.qos.Integer := 2; - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483674897863 - - - - - - 3 + 28 - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important + - 4 + 29 - + // Device related - 5 + 30 - (*pass trough*) + MqttDiscMsgCover.dev.cu.CharString := THIS^.cu; - 6 + 31 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + MqttDiscMsgCover.dev.name.CharString := THIS^.name; - 7 + 32 - THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + MqttDiscMsgCover.dev.hw.CharString := THIS^.hw; - 8 + 33 - THIS^.pMqttPublishQueue:=pMqttPublishQueue; + MqttDiscMsgCover.dev.ids.CharString := THIS^.ids; - 9 + 34 - + MqttDiscMsgCover.dev.sw.CharString := THIS^.sw; - 10 + 35 - THIS^.MqttQos := MqttQos; + MqttDiscMsgCover.dev.mdl.CharString := THIS^.mdl; - 11 + 36 - THIS^.MqttRetain := MqttRetain; + MqttDiscMsgCover.dev.mf.CharString := THIS^.mf; - 12 + 37 - + - 2 + 38 - SUPER^.InitBaseMqtt(); + // Extra meta-data - - - - - - - 13 + 39 - METHOD InitMqtt + IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - 14 + 40 - VAR_INPUT + MqttDiscMsgCover.meta.CharString := meta; - 15 + 41 - MQTTPublishPrefix: POINTER TO STRING; + END_IF - 16 + 42 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + - 17 + 43 - MqttQos: MQTT.QoS := MQTT.QoS.ExactlyOnce; + ComposeJSON( - 18 + 44 - MqttRetain: BOOL := FALSE; + JSONString:= ADR(MqttJSON), - 19 + 45 - END_VAR + JSONStringSize:= SIZEOF(MqttJSON), - 1 + 46 - + JSONVars:= ADR(MqttDiscMsgCover), - - - - - a1bd57b2-7fd1-4392-bd24-7f01031c67fc - - FB_MQTT_LOG - - -1 - - - False - - 196c70ab-0d3c-4fa5-a394-2b9ec6f8139d - a1bd57b2-7fd1-4392-bd24-7f01031c67fc - InitMqttDiscovery - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 47 + + NumberOfVars:= SIZEOF(MqttDiscMsgCover) / SIZEOF(JSONVAR), - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483674207866 - - - - - - 3 + 48 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + MaxLevel := 1, - 4 + 49 - + ); - 5 + 50 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + ComposeJSON.Execute := TRUE; - 6 + 51 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + ComposeJSON(); - 7 + 52 - ELSE + - 8 + 53 - id := overruleId; // 'MY_PH_GND_HALL_01' + IF MqttJSON = '' THEN - 9 + 54 - END_IF + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); - 10 + 55 - + ELSIF NOT (MqttJSON = '') THEN - 11 + 56 - Device^.CreateSensorEntity( + pMqttPublishQueue^.AddMessage( - 12 + 57 - Name := name, + Payload:= MqttJSON, - 13 + 58 - Id := id, + Topic := MqttTopic, - 14 + 59 - Meta := meta, + Qos := MQTT.QoS.ExactlyOnce, - 15 + 60 - StateTopic := THIS^.MQTTPublishTopic); + MqttRetain := TRUE, - 16 + 61 - + ); - 17 + 62 - initMqttDiscoveryDone := TRUE; + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); + + + 63 + + END_IF 2 - END_IF + @@ -11586,173 +11206,112 @@ - 18 + 64 - METHOD InitMqttDiscovery + METHOD CreateCoverEntity - 19 + 65 VAR_INPUT - 20 - - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - - - 21 - - Name: STRING(255) := 'plc_log'; - - - 22 + 66 - overruleId: STRING(255) := ''; + /// default - 23 + 67 - meta: STRING(255) := ''; + Name: STRING; - 24 + 68 - END_VAR + Id: STRING; - 25 + 69 - VAR + Meta: STRING; - 26 + 70 - id: STRING(255); + /// entity specific - 27 + 71 - END_VAR + CommandTopic: STRING; - 1 + 72 - - - - - - - a1bd57b2-7fd1-4392-bd24-7f01031c67fc - - FB_MQTT_LOG - - -1 - - - False - - f30010c6-e326-46b1-a927-dd59f6b94b42 - a1bd57b2-7fd1-4392-bd24-7f01031c67fc - send - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + PayloadOpen: STRING; - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483674587846 - - - - - - 3 + 73 - IF InitMqttDone THEN + PayloadClose: STRING; - 4 + 74 - pMqttPublishQueue^.AddMessage( + PayloadStop: STRING; - 5 + 75 - Payload:= CONCAT(CONCAT(instance,' | '),str), + StateTopic: STRING; - 6 + 76 - Topic := THIS^.MQTTPublishTopic, + StateOpen: STRING; - 7 + 77 - Qos := 1, + StateClosed: STRING; - 8 + 78 - MqttRetain := TRUE + Deviceclass: STRING; - 9 + 79 - ); + END_VAR - 2 + 80 - END_IF + VAR - - - - - - - 10 + 81 - METHOD send + EntityId: STRING(25) := 'cover'; - 11 + 82 - VAR_INPUT + ComposeJSON: STRUCT_TO_JSON; - 12 + 83 - str: STRING(128); + MqttJSON: STRING(1500); - 13 + 84 - instance: STRING := ''; + MqttTopic: STRING(100); - 14 + 85 END_VAR @@ -11765,18 +11324,18 @@ - a1bd57b2-7fd1-4392-bd24-7f01031c67fc + 66c93670-7793-463e-93d0-a9b318db344d - FB_MQTT_LOG + FB_BASE_MQTT_DISCOVERY_DEVICE -1 False - adb7b24f-1464-453b-9fce-53289ad068e1 - 8c517942-8e59-4e94-9803-6498eac9f87f - InitMqtt + b122ebec-5317-400e-959b-5461bee907c3 + 66c93670-7793-463e-93d0-a9b318db344d + CreateLightDimmerEntity @@ -11800,7 +11359,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638129306704374582 + 638133836322598001 @@ -11809,7 +11368,7 @@ 3 - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); 4 @@ -11819,513 +11378,456 @@ 5 - (*pass trough*) + // Entity related: Basis 6 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + MqttDiscMsgLightDim.name.CharString := name; // friendly name 7 - THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + MqttDiscMsgLightDim.obj_id.CharString := Id; 8 - THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; + MqttDiscMsgLightDim.uniq_id.CharString := Id; 9 - THIS^.pMqttPublishQueue:=pMqttPublishQueue; + 10 - + // Entity related: Specific 11 - SUPER^.InitBaseMqtt(); + MqttDiscMsgLightDim.cmd_t.CharString := CommandTopic; 12 - pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + MqttDiscMsgLightDim.pl_on.CharString := PayloadOn; 13 - - - - 2 - - + MqttDiscMsgLightDim.pl_off.CharString := PayloadOff; - - - - - - 14 - METHOD InitMqtt + MqttDiscMsgLightDim.stat_t.CharString := StateTopic; 15 - VAR_INPUT + MqttDiscMsgLightDim.opt.Boolean := FALSE; 16 - MQTTPublishPrefix: POINTER TO STRING; + 17 - MQTTSubscribePrefix: POINTER TO STRING; + MqttDiscMsgLightDim.bri_cmd_t.CharString := BrightnessCommandTopic; 18 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + MqttDiscMsgLightDim.bri_stat_t.CharString := BrightnessStateTopic; 19 - pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + MqttDiscMsgLightDim.bri_scl.Integer := BrightnessScale; 20 - END_VAR + MqttDiscMsgLightDim.on_cmd_type.CharString := 'last'; - 1 + 21 - - - - - 8c517942-8e59-4e94-9803-6498eac9f87f - - FB_OUTPUT_BINARY_MQTT - - -1 - - - False - - fb12c903-d04a-49a3-ab14-a9a22b136355 - 8c517942-8e59-4e94-9803-6498eac9f87f - InitMqttDiscoveryAsLight - - - - 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 - - 638129306706214599 - - - - - - 3 + 22 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + MqttDiscMsgLightDim.dmxChannel.Integer := DmxChannel; - 4 + 23 - + MqttDiscMsgLightDim.dmxWidth.Integer := DmxWidth; - 5 + 24 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + MqttDiscMsgLightDim.dmxUniverse.Integer := DmxUniverse; - 6 + 25 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + - 7 + 26 - ELSE + // Availabilty related - 8 + 27 - id := overruleId; // 'MY_PH_GND_HALL_01' + MqttDiscMsgLightDim.avty[1].topic.CharString := THIS^.availabilityTopic1; - 9 + 28 - END_IF + MqttDiscMsgLightDim.avty[2].topic.CharString := THIS^.availabilityTopic2; - 10 + 29 - + MqttDiscMsgLightDim.avty_mode.CharString := 'all'; - 11 + 30 - Device^.CreateLightEntity( + MqttDiscMsgLightDim.pl_avail.CharString := THIS^.availabilityOnline; - 12 + 31 - Name := name, + MqttDiscMsgLightDim.pl_not_avail.CharString := THIS^.availabilityOffline; - 13 + 32 - Id := id, + MqttDiscMsgLightDim.qos.Integer := 2; - 14 + 33 - Meta := meta, + - 15 + 34 - CommandTopic := THIS^.MQTTSubscribeTopic, + // Device related - 16 + 35 - PayloadOn := BOOL_TO_STRING(NOT(Invert)), + MqttDiscMsgLightDim.dev.cu.CharString := THIS^.cu; - 17 + 36 - PayloadOff := BOOL_TO_STRING(Invert), + MqttDiscMsgLightDim.dev.name.CharString := THIS^.name; - 18 + 37 - StateTopic := THIS^.MQTTPublishTopic); + MqttDiscMsgLightDim.dev.hw.CharString := THIS^.hw; - 19 + 38 - + MqttDiscMsgLightDim.dev.ids.CharString := THIS^.ids; - 20 + 39 - initMqttDiscoveryDone := TRUE; + MqttDiscMsgLightDim.dev.sw.CharString := THIS^.sw; - 2 + 40 - END_IF + MqttDiscMsgLightDim.dev.mdl.CharString := THIS^.mdl; - - - - - - - 21 + 41 - METHOD InitMqttDiscoveryAsLight + MqttDiscMsgLightDim.dev.mf.CharString := THIS^.mf; - 22 + 42 - VAR_INPUT + - 23 + 43 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + // Extra meta-data - 24 + 44 - Name: STRING(255); + IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - 25 + 45 - overruleId: STRING(255) := ''; + MqttDiscMsgLightDim.meta.CharString := meta; - 26 + 46 - meta: STRING(255) := ''; + END_IF - 27 + 47 - Invert: BOOL := FALSE; + - 28 + 48 - END_VAR + ComposeJSON( - 29 + 49 - VAR + JSONString:= ADR(MqttJSON), - 30 + 50 - id: STRING(255); + JSONStringSize:= SIZEOF(MqttJSON), - 31 + 51 - END_VAR + JSONVars:= ADR(MqttDiscMsgLightDim), - 1 + 52 + + NumberOfVars:= SIZEOF(MqttDiscMsgLightDim) / SIZEOF(JSONVAR), + + + 53 + + MaxLevel := 1, + + + 54 + + ); + + + 55 + + ComposeJSON.Execute := TRUE; + + + 56 + + ComposeJSON(); + + + 57 - - - - - 8c517942-8e59-4e94-9803-6498eac9f87f - - FB_OUTPUT_BINARY_MQTT - - -1 - - - False - - c62272c1-f10b-4967-931a-95c833eb6751 - 8c517942-8e59-4e94-9803-6498eac9f87f - InitMqttDiscoveryAsLock - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 58 + + IF MqttJSON = '' THEN - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638129306706534583 - - - - - - 3 + 59 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); - 4 + 60 - + ELSIF NOT (MqttJSON = '') THEN - 5 + 61 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + pMqttPublishQueue^.AddMessage( - 6 + 62 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + Payload:= MqttJSON, - 7 + 63 - ELSE + Topic := MqttTopic, - 8 + 64 - id := overruleId; // 'MY_PH_GND_HALL_01' + Qos := MQTT.QoS.ExactlyOnce, - 9 + 65 - END_IF + MqttRetain := TRUE, - 10 + 66 - + ); - 11 + 67 - Device^.CreateLockEntity( + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); - 12 + 68 - Name := name, + END_IF - 13 + 2 - Id := id, + + + + + + + + + + 69 + + METHOD CreateLightDimmerEntity - 14 + 70 - Meta := meta, + VAR_INPUT - 15 + 71 - CommandTopic := THIS^.MQTTSubscribeTopic, + /// default - 16 + 72 - PayloadLock := BOOL_TO_STRING(NOT(Invert)), + Name: STRING; - 17 + 73 - PayloadUnlock := BOOL_TO_STRING(Invert), + Id: STRING; - 18 + 74 - StateTopic := THIS^.MQTTPublishTopic, + Meta: STRING; - 19 + 75 - StateUnlocked := BOOL_TO_STRING(Invert), + /// entity specific - 20 + 76 - StateLocked := BOOL_TO_STRING(NOT(Invert))); + CommandTopic: STRING; - 21 + 77 - + PayloadOn: STRING; - 22 + 78 - initMqttDiscoveryDone := TRUE; + PayloadOff: STRING; - 2 + 79 - END_IF + StateTopic: STRING; - - - - - - - 23 + 80 - METHOD InitMqttDiscoveryAsLock + BrightnessCommandTopic: STRING; - 24 + 81 - VAR_INPUT + BrightnessStateTopic: STRING; - 25 + 82 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + BrightnessScale: INT; - 26 + 83 - Name: STRING(255); + /// dmx specific - 27 + 84 - overruleId: STRING(255) := ''; + DmxChannel: INT := 0; - 28 + 85 - meta: STRING(255) := ''; + DmxWidth: INT := 0; - 29 + 86 - Invert: BOOL := FALSE; + DmxUniverse: INT := 0; - 30 + 87 END_VAR - 31 + 88 VAR - 32 + 89 - id: STRING(255); + EntityId: STRING(25) := 'light'; - 33 + 90 + + ComposeJSON: STRUCT_TO_JSON; + + + 91 + + MqttJSON: STRING(1500); + + + 92 + + MqttTopic: STRING(100); + + + 93 END_VAR @@ -12338,18 +11840,18 @@ - 8c517942-8e59-4e94-9803-6498eac9f87f + 66c93670-7793-463e-93d0-a9b318db344d - FB_OUTPUT_BINARY_MQTT + FB_BASE_MQTT_DISCOVERY_DEVICE -1 False - 79d4abbf-d6b4-42a8-bf56-60ac90fdc5a1 - 8c517942-8e59-4e94-9803-6498eac9f87f - InitMqttDiscoveryAsSiren + 11d622ac-ab2e-4a32-b68f-5af43c1b8efb + 66c93670-7793-463e-93d0-a9b318db344d + CreateLightEntity @@ -12373,7 +11875,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638129306706974597 + 638133836324207994 @@ -12382,338 +11884,292 @@ 3 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); 4 - + 5 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + // Entity related: Basis 6 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + MqttDiscMsgLight.name.CharString := name; // friendly name 7 - ELSE + MqttDiscMsgLight.obj_id.CharString := Id; 8 - id := overruleId; // 'MY_PH_GND_HALL_01' + MqttDiscMsgLight.uniq_id.CharString := Id; 9 - END_IF + 10 - + // Entity related: Specific 11 - Device^.CreateSirenEntity( + MqttDiscMsgLight.cmd_t.CharString := CommandTopic; 12 - Name := name, + MqttDiscMsgLight.pl_on.CharString := PayloadOn; 13 - Id := id, + MqttDiscMsgLight.pl_off.CharString := PayloadOff; 14 - Meta := meta, + MqttDiscMsgLight.stat_t.CharString := StateTopic; 15 - CommandTopic := THIS^.MQTTSubscribeTopic, + MqttDiscMsgLight.opt.Boolean := FALSE; 16 - PayloadOn := BOOL_TO_STRING(NOT(Invert)), + 17 - PayloadOff := BOOL_TO_STRING(Invert), + // Availabilty related 18 - StateTopic := THIS^.MQTTPublishTopic, + MqttDiscMsgLight.avty[1].topic.CharString := THIS^.availabilityTopic1; 19 - StateOnPayload := BOOL_TO_STRING(NOT(Invert)), + MqttDiscMsgLight.avty[2].topic.CharString := THIS^.availabilityTopic2; 20 - StateOffPayload := BOOL_TO_STRING(Invert) + MqttDiscMsgLight.avty_mode.CharString := 'all'; 21 - ); + MqttDiscMsgLight.pl_avail.CharString := THIS^.availabilityOnline; 22 - + MqttDiscMsgLight.pl_not_avail.CharString := THIS^.availabilityOffline; 23 - + MqttDiscMsgLight.qos.Integer := 2; 24 - initMqttDiscoveryDone := TRUE; - - - 2 - - END_IF + - - - - - - 25 - METHOD InitMqttDiscoveryAsSiren + // Device related 26 - VAR_INPUT + MqttDiscMsgLight.dev.cu.CharString := THIS^.cu; 27 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + MqttDiscMsgLight.dev.name.CharString := THIS^.name; 28 - Name: STRING(255); + MqttDiscMsgLight.dev.hw.CharString := THIS^.hw; 29 - overruleId: STRING(255) := ''; + MqttDiscMsgLight.dev.ids.CharString := THIS^.ids; 30 - meta: STRING(255) := ''; + MqttDiscMsgLight.dev.sw.CharString := THIS^.sw; 31 - Invert: BOOL := FALSE; + MqttDiscMsgLight.dev.mdl.CharString := THIS^.mdl; 32 - END_VAR + MqttDiscMsgLight.dev.mf.CharString := THIS^.mf; 33 - VAR + 34 - id: STRING(255); + // Extra meta-data 35 - END_VAR + IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - 1 + 36 - + MqttDiscMsgLight.meta.CharString := meta; - - - - - 8c517942-8e59-4e94-9803-6498eac9f87f - - FB_OUTPUT_BINARY_MQTT - - -1 - - - False - - fe73c6c0-dead-4ab5-be90-a5fadeae1e18 - 8c517942-8e59-4e94-9803-6498eac9f87f - InitMqttDiscoveryAsSwitch - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 37 + + END_IF - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638129306705844586 - - - - - - 3 + 38 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + - 4 + 39 - + ComposeJSON( - 5 + 40 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + JSONString:= ADR(MqttJSON), - 6 + 41 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + JSONStringSize:= SIZEOF(MqttJSON), - 7 + 42 - ELSE + JSONVars:= ADR(MqttDiscMsgLight), - 8 + 43 - id := overruleId; // 'MY_PH_GND_HALL_01' + NumberOfVars:= SIZEOF(MqttDiscMsgLight) / SIZEOF(JSONVAR), - 9 + 44 - END_IF + MaxLevel := 1, - 10 + 45 - + ); - 11 + 46 - Device^.CreateSwitchEntity( + ComposeJSON.Execute := TRUE; - 12 + 47 - Name := name, + ComposeJSON(); - 13 + 48 - Id := id, + - 14 + 49 - Meta := meta, + IF MqttJSON = '' THEN - 15 + 50 - CommandTopic := THIS^.MQTTSubscribeTopic, + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); - 16 + 51 - PayloadOn := BOOL_TO_STRING(NOT(Invert)), + ELSIF NOT (MqttJSON = '') THEN - 17 + 52 - PayloadOff := BOOL_TO_STRING(Invert), + pMqttPublishQueue^.AddMessage( - 18 + 53 - StateTopic := THIS^.MQTTPublishTopic, + Payload:= MqttJSON, - 19 + 54 - StateOnPayload := BOOL_TO_STRING(NOT(Invert)), + Topic := MqttTopic, - 20 + 55 - StateOffPayload := BOOL_TO_STRING(Invert), + Qos := MQTT.QoS.ExactlyOnce, - 21 + 56 - DeviceClass := DeviceClass); + MqttRetain := TRUE, - 22 + 57 - + ); - 23 + 58 - initMqttDiscoveryDone := TRUE; + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); + + + 59 + + END_IF 2 - END_IF + @@ -12722,86 +12178,116 @@ - 24 + 60 - METHOD InitMqttDiscoveryAsSwitch + METHOD CreateLightEntity - 25 + 61 VAR_INPUT - 26 + 62 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + /// default - 27 + 63 - Name: STRING(255); + Name: STRING; - 28 + 64 - DeviceClass: STRING(100) := 'outlet'; + Id: STRING; - 29 + 65 - overruleId: STRING(255) := ''; + Meta: STRING; - 30 + 66 - meta: STRING(255) := ''; + /// entity specific - 31 + 67 - Invert: BOOL := FALSE; + CommandTopic: STRING; - 32 + 68 - END_VAR + PayloadOn: STRING; - 33 + 69 - VAR + PayloadOff: STRING; - 34 + 70 - id: STRING(255); + StateTopic: STRING; - 35 + 71 END_VAR - 1 + 72 - + VAR - - - - - 8c517942-8e59-4e94-9803-6498eac9f87f - - FB_OUTPUT_BINARY_MQTT - - -1 - - - False - - 211d22bc-fca6-4ed8-bd6e-191bfb434f53 - 8c517942-8e59-4e94-9803-6498eac9f87f - PublishReceived + + 73 + + EntityId: STRING(25) := 'light'; + + + 74 + + ComposeJSON: STRUCT_TO_JSON; + + + 75 + + MqttJSON: STRING(1500); + + + 76 + + MqttTopic: STRING(100); + + + 77 + + END_VAR + + + 1 + + + + + + + + 66c93670-7793-463e-93d0-a9b318db344d + + FB_BASE_MQTT_DISCOVERY_DEVICE + + -1 + + + False + + e37b1fa8-cd93-481a-8836-7516a61b006f + 66c93670-7793-463e-93d0-a9b318db344d + CreateLockEntity @@ -12825,7 +12311,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638129306705535025 + 638133836323797991 @@ -12834,564 +12320,406 @@ 3 - //first check if Mqtt is initialized, otherwise do nothing + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); 4 - IF NOT(InitMqttDone) THEN + 5 - //mark the interface call from the collector as done + // Entity related: Basis 6 - PublishReceived := TRUE; + MqttDiscMsgLock.name.CharString := name; // friendly name 7 - //check if the packet is for this FB + MqttDiscMsgLock.obj_id.CharString := Id; 8 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN + MqttDiscMsgLock.uniq_id.CharString := Id; 9 - //mark the interface call from the collector as done + 10 - PublishReceived := TRUE; + // Entity related: Specific 11 - //now process the data + MqttDiscMsgLock.cmd_t.CharString := CommandTopic; 12 - IF FIND(Data.PayloadString^, 'TRUE') > 0 THEN + MqttDiscMsgLock.pl_lock.CharString := PayloadLock; 13 - MqttHighRequest := TRUE; + MqttDiscMsgLock.pl_unlk.CharString := PayloadUnlock; 14 - END_IF + MqttDiscMsgLock.stat_t.CharString := StateTopic; 15 - IF FIND(Data.PayloadString^, 'FALSE') > 0 THEN + MqttDiscMsgLock.stat_locked.CharString := StateLocked; 16 - MqttLowRequest := TRUE; + MqttDiscMsgLock.stat_unlocked.CharString := StateUnlocked; 17 - END_IF - - - 2 - - END_IF + MqttDiscMsgLock.opt.Boolean := FALSE; - - - - - - 18 - METHOD PublishReceived : BOOL + 19 - VAR_INPUT + // Availabilty related 20 - ///Collection of recived Data + MqttDiscMsgLock.avty[1].topic.CharString := THIS^.availabilityTopic1; 21 - Data: MQTT.CALLBACK_DATA; + MqttDiscMsgLock.avty[2].topic.CharString := THIS^.availabilityTopic2; 22 - END_VAR + MqttDiscMsgLock.avty_mode.CharString := 'all'; - 1 + 23 - - - - - - - 8c517942-8e59-4e94-9803-6498eac9f87f - - FB_OUTPUT_BINARY_MQTT - - -1 - - - False - - 905cdce0-95e6-4ba5-8bf7-4c9d6d7231f4 - b5a7395b-79b0-4613-b65d-fa71daa858f4 - ConfigureFunctionBlock - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + MqttDiscMsgLock.pl_avail.CharString := THIS^.availabilityOnline; - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638129306708165012 - - - - - - 2 + 24 - THIS^.T_hold:=T_hold; + MqttDiscMsgLock.pl_not_avail.CharString := THIS^.availabilityOffline; - - - - - - - 3 + 25 - METHOD ConfigureFunctionBlock + MqttDiscMsgLock.qos.Integer := 2; - 4 + 26 - VAR_INPUT + - 5 + 27 - /// Default value for click mode, can be overwritten by method call + // Device related - 6 + 28 - T_hold: TIME; + MqttDiscMsgLock.dev.cu.CharString := THIS^.cu; - 7 + 29 - END_VAR + MqttDiscMsgLock.dev.name.CharString := THIS^.name; - 1 + 30 - - - - - - - b5a7395b-79b0-4613-b65d-fa71daa858f4 - - FB_OUTPUT_BISTABLE_MQTT - - -1 - - - False - - dd109535-f5e1-46eb-9f68-e2b986de35f0 - b5a7395b-79b0-4613-b65d-fa71daa858f4 - InitMqtt - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + MqttDiscMsgLock.dev.hw.CharString := THIS^.hw; - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638129306708794585 - - - - - - 3 + 31 - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important + MqttDiscMsgLock.dev.ids.CharString := THIS^.ids; - 4 + 32 - + MqttDiscMsgLock.dev.sw.CharString := THIS^.sw; - 5 + 33 - (*pass trough*) + MqttDiscMsgLock.dev.mdl.CharString := THIS^.mdl; - 6 + 34 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + MqttDiscMsgLock.dev.mf.CharString := THIS^.mf; - 7 + 35 - THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + - 8 + 36 - THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; + // Extra meta-data - 9 + 37 - THIS^.pMqttPublishQueue:=pMqttPublishQueue; + IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - 10 + 38 - + MqttDiscMsgLock.meta.CharString := meta; - 11 + 39 - + END_IF - 12 + 40 - 13 + 41 - SUPER^.InitBaseMqtt(); + ComposeJSON( - 14 + 42 - pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + JSONString:= ADR(MqttJSON), - 15 + 43 - + JSONStringSize:= SIZEOF(MqttJSON), - 2 + 44 - + JSONVars:= ADR(MqttDiscMsgLock), - - - - - - - 16 + 45 - METHOD InitMqtt + NumberOfVars:= SIZEOF(MqttDiscMsgLock) / SIZEOF(JSONVAR), - 17 + 46 - VAR_INPUT + MaxLevel := 1, - 18 + 47 - MQTTPublishPrefix: POINTER TO STRING; + ); - 19 + 48 - MQTTSubscribePrefix: POINTER TO STRING; + ComposeJSON.Execute := TRUE; - 20 + 49 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + ComposeJSON(); - 21 + 50 - pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + - 22 + 51 - END_VAR + IF MqttJSON = '' THEN - 1 + 52 - - - - - - - b5a7395b-79b0-4613-b65d-fa71daa858f4 - - FB_OUTPUT_BISTABLE_MQTT - - -1 - - - False - - 05df25c9-f00a-425c-a70b-ca731f9caa47 - b5a7395b-79b0-4613-b65d-fa71daa858f4 - InitMqttDiscoveryAsLight - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638129306709774588 - - - - - - 3 + 53 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + ELSIF NOT (MqttJSON = '') THEN - 4 + 54 - + pMqttPublishQueue^.AddMessage( - 5 + 55 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + Payload:= MqttJSON, - 6 + 56 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + Topic := MqttTopic, - 7 + 57 - ELSE + Qos := MQTT.QoS.ExactlyOnce, - 8 + 58 - id := overruleId; // 'MY_PH_GND_HALL_01' + MqttRetain := TRUE, - 9 + 59 - END_IF + ); - 10 + 60 - + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); - 11 + 61 - Device^.CreateLightEntity( + END_IF - 12 + 2 - Name := name, + + + + + + + - 13 + 62 - Id := id, + METHOD CreateLockEntity - 14 + 63 - Meta := meta, + VAR_INPUT - 15 + 64 - CommandTopic := THIS^.MQTTSubscribeTopic, + /// default - 16 + 65 - PayloadOn := BOOL_TO_STRING(NOT(Invert)), + Name: STRING; - 17 + 66 - PayloadOff := BOOL_TO_STRING(Invert), + Id: STRING; - 18 + 67 - StateTopic := THIS^.MQTTPublishTopic); + Meta: STRING; - 19 + 68 - + /// entity specific - 20 + 69 - initMqttDiscoveryDone := TRUE; + CommandTopic: STRING; - 2 + 70 - END_IF + PayloadLock: STRING; - - - - - - - 21 + 71 - METHOD InitMqttDiscoveryAsLight + PayloadUnlock: STRING; - 22 + 72 - VAR_INPUT + StateTopic: STRING; - 23 + 73 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + StateLocked: STRING; - 24 + 74 - Name: STRING(255); + StateUnlocked: STRING; - 25 + 75 - overruleId: STRING(255) := ''; + END_VAR - 26 + 76 - meta: STRING(255) := ''; + VAR - 27 + 77 - Invert: BOOL := FALSE; + EntityId: STRING(25) := 'lock'; - 28 + 78 - END_VAR + ComposeJSON: STRUCT_TO_JSON; - 29 + 79 - VAR + MqttJSON: STRING(1500); - 30 + 80 - id: STRING(255); + MqttTopic: STRING(100); - 31 + 81 END_VAR @@ -13404,18 +12732,18 @@ - b5a7395b-79b0-4613-b65d-fa71daa858f4 + 66c93670-7793-463e-93d0-a9b318db344d - FB_OUTPUT_BISTABLE_MQTT + FB_BASE_MQTT_DISCOVERY_DEVICE -1 False - ba8b2c03-d214-4f57-a64c-ebae705e1533 - b5a7395b-79b0-4613-b65d-fa71daa858f4 - InitMqttDiscoveryAsLock + 877c7b1e-2e2a-4d73-8215-76b820272119 + 66c93670-7793-463e-93d0-a9b318db344d + CreateSensorEntity @@ -13439,7 +12767,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638129306709465031 + 638133836322997997 @@ -13448,328 +12776,282 @@ 3 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); 4 - + 5 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + // Entity related: Basis 6 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + MqttDiscMsgSensor.name.CharString := name; // friendly name 7 - ELSE + MqttDiscMsgSensor.obj_id.CharString := Id; 8 - id := overruleId; // 'MY_PH_GND_HALL_01' + MqttDiscMsgSensor.uniq_id.CharString := Id; 9 - END_IF + 10 - + // Entity related: Specific 11 - Device^.CreateLockEntity( + //MqttDiscoverySensorMessage.ic.CharString := Icon; 12 - Name := name, + MqttDiscMsgSensor.stat_t.CharString := StateTopic; 13 - Id := id, + MqttDiscMsgSensor.exp_aft.Integer := ExpiryAfter; 14 - Meta := meta, + 15 - CommandTopic := THIS^.MQTTSubscribeTopic, + // Availabilty related 16 - PayloadLock := BOOL_TO_STRING(NOT(Invert)), + MqttDiscMsgSensor.avty[1].topic.CharString := THIS^.availabilityTopic1; 17 - PayloadUnlock := BOOL_TO_STRING(Invert), + MqttDiscMsgSensor.avty[2].topic.CharString := THIS^.availabilityTopic2; 18 - StateTopic := THIS^.MQTTPublishTopic, + MqttDiscMsgSensor.avty_mode.CharString := 'all'; 19 - StateUnlocked := BOOL_TO_STRING(Invert), + MqttDiscMsgSensor.pl_avail.CharString := THIS^.availabilityOnline; 20 - StateLocked := BOOL_TO_STRING(NOT(Invert))); + MqttDiscMsgSensor.pl_not_avail.CharString := THIS^.availabilityOffline; 21 - + MqttDiscMsgSensor.qos.Integer := 2; 22 - initMqttDiscoveryDone := TRUE; - - - 2 - - END_IF + - - - - - - 23 - METHOD InitMqttDiscoveryAsLock + // Device related 24 - VAR_INPUT + MqttDiscMsgSensor.dev.cu.CharString := THIS^.cu; 25 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + MqttDiscMsgSensor.dev.name.CharString := THIS^.name; 26 - Name: STRING(255); + MqttDiscMsgSensor.dev.hw.CharString := THIS^.hw; 27 - overruleId: STRING(255) := ''; + MqttDiscMsgSensor.dev.ids.CharString := THIS^.ids; 28 - meta: STRING(255) := ''; + MqttDiscMsgSensor.dev.sw.CharString := THIS^.sw; 29 - Invert: BOOL := FALSE; + MqttDiscMsgSensor.dev.mdl.CharString := THIS^.mdl; 30 - END_VAR + MqttDiscMsgSensor.dev.mf.CharString := THIS^.mf; 31 - VAR + 32 - id: STRING(255); + // Extra meta-data 33 - END_VAR + IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - 1 + 34 - + MqttDiscMsgSensor.meta.CharString := meta; - - - - - b5a7395b-79b0-4613-b65d-fa71daa858f4 - - FB_OUTPUT_BISTABLE_MQTT - - -1 - - - False - - bf25159a-ef5a-488c-80c9-0188dbf485df - b5a7395b-79b0-4613-b65d-fa71daa858f4 - InitMqttDiscoveryAsSiren - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 35 + + END_IF - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638129306709095000 - - - - - - 3 + 36 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + - 4 + 37 - + ComposeJSON( - 5 + 38 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + JSONString:= ADR(MqttJSON), - 6 + 39 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + JSONStringSize:= SIZEOF(MqttJSON), - 7 + 40 - ELSE + JSONVars:= ADR(MqttDiscMsgSensor), - 8 + 41 - id := overruleId; // 'MY_PH_GND_HALL_01' + NumberOfVars:= SIZEOF(MqttDiscMsgSensor) / SIZEOF(JSONVAR), - 9 + 42 - END_IF + MaxLevel := 1, - 10 + 43 - + ); - 11 + 44 - Device^.CreateSirenEntity( + ComposeJSON.Execute := TRUE; - 12 + 45 - Name := name, + ComposeJSON(); - 13 + 46 - Id := id, + - 14 + 47 - Meta := meta, + IF MqttJSON = '' THEN - 15 + 48 - CommandTopic := THIS^.MQTTSubscribeTopic, + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); - 16 + 49 - PayloadOn := BOOL_TO_STRING(NOT(Invert)), + ELSIF NOT (MqttJSON = '') THEN - 17 + 50 - PayloadOff := BOOL_TO_STRING(Invert), + pMqttPublishQueue^.AddMessage( - 18 + 51 - StateTopic := THIS^.MQTTPublishTopic, + Payload:= MqttJSON, - 19 + 52 - StateOnPayload := BOOL_TO_STRING(NOT(Invert)), + Topic := MqttTopic, - 20 + 53 - StateOffPayload := BOOL_TO_STRING(Invert) + Qos := MQTT.QoS.ExactlyOnce, - 21 + 54 - ); + MqttRetain := TRUE, - 22 + 55 - + ); - 23 + 56 - initMqttDiscoveryDone := TRUE; + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); + + + 57 + + END_IF 2 - END_IF + @@ -13778,57 +13060,82 @@ - 24 + 58 - METHOD InitMqttDiscoveryAsSiren + METHOD CreateSensorEntity - 25 + 59 VAR_INPUT - 26 + 60 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + /// default - 27 + 61 - Name: STRING(255); + Name: STRING; - 28 + 62 - overruleId: STRING(255) := ''; + Id: STRING; - 29 + 63 - meta: STRING(255) := ''; + Meta: STRING; - 30 + 64 - Invert: BOOL := FALSE; + /// entity specific - 31 + 65 + + StateTopic: STRING; + + + 66 + + ExpiryAfter: INT := 0; + + + 67 END_VAR - 32 + 68 VAR - 33 + 69 - id: STRING(255); + EntityId: STRING(25) := 'sensor'; - 34 + 70 + + ComposeJSON: STRUCT_TO_JSON; + + + 71 + + MqttJSON: STRING(1500); + + + 72 + + MqttTopic: STRING(100); + + + 73 END_VAR @@ -13841,18 +13148,18 @@ - b5a7395b-79b0-4613-b65d-fa71daa858f4 + 66c93670-7793-463e-93d0-a9b318db344d - FB_OUTPUT_BISTABLE_MQTT + FB_BASE_MQTT_DISCOVERY_DEVICE -1 False - 5f30d5df-7428-45c0-8e88-6ebd604a2aaf - b5a7395b-79b0-4613-b65d-fa71daa858f4 - InitMqttDiscoveryAsSwitch + 13fdb1a5-e8f5-4476-a654-d9213b3cbe32 + 66c93670-7793-463e-93d0-a9b318db344d + CreateSensorEntityWithCategory @@ -13876,7 +13183,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638129306707805016 + 638133836326147995 @@ -13885,584 +13192,431 @@ 3 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); 4 - + 5 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + // Entity related: Basis 6 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + MqttDiscMsgSensorWCat.name.CharString := name; // friendly name 7 - ELSE + MqttDiscMsgSensorWCat.obj_id.CharString := Id; 8 - id := overruleId; // 'MY_PH_GND_HALL_01' + MqttDiscMsgSensorWCat.uniq_id.CharString := Id; 9 - END_IF + 10 - + // Entity related: Specific 11 - Device^.CreateSwitchEntity( + //MqttDiscoverySensorMessage.ic.CharString := Icon; 12 - Name := name, + MqttDiscMsgSensorWCat.stat_t.CharString := StateTopic; 13 - Id := id, + MqttDiscMsgSensorWCat.exp_aft.Integer := ExpiryAfter; 14 - Meta := meta, + MqttDiscMsgSensorWCat.ent_cat.CharString := EntityCategory; 15 - CommandTopic := THIS^.MQTTSubscribeTopic, + 16 - PayloadOn := BOOL_TO_STRING(NOT(Invert)), + // Availabilty related 17 - PayloadOff := BOOL_TO_STRING(Invert), + MqttDiscMsgSensorWCat.avty[1].topic.CharString := THIS^.availabilityTopic1; 18 - StateTopic := THIS^.MQTTPublishTopic, + MqttDiscMsgSensorWCat.avty[2].topic.CharString := THIS^.availabilityTopic2; 19 - StateOnPayload := BOOL_TO_STRING(NOT(Invert)), + MqttDiscMsgSensorWCat.avty_mode.CharString := 'all'; 20 - StateOffPayload := BOOL_TO_STRING(Invert), + MqttDiscMsgSensorWCat.pl_avail.CharString := THIS^.availabilityOnline; 21 - DeviceClass := DeviceClass); + MqttDiscMsgSensorWCat.pl_not_avail.CharString := THIS^.availabilityOffline; 22 - + MqttDiscMsgSensorWCat.qos.Integer := 2; 23 - initMqttDiscoveryDone := TRUE; - - - 2 - - END_IF + - - - - - - 24 - METHOD InitMqttDiscoveryAsSwitch + // Device related 25 - VAR_INPUT + MqttDiscMsgSensorWCat.dev.cu.CharString := THIS^.cu; 26 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + MqttDiscMsgSensorWCat.dev.name.CharString := THIS^.name; 27 - Name: STRING(255); + MqttDiscMsgSensorWCat.dev.hw.CharString := THIS^.hw; 28 - DeviceClass: STRING(100) := 'outlet'; + MqttDiscMsgSensorWCat.dev.ids.CharString := THIS^.ids; 29 - overruleId: STRING(255) := ''; + MqttDiscMsgSensorWCat.dev.sw.CharString := THIS^.sw; 30 - meta: STRING(255) := ''; + MqttDiscMsgSensorWCat.dev.mdl.CharString := THIS^.mdl; 31 - Invert: BOOL := FALSE; + MqttDiscMsgSensorWCat.dev.mf.CharString := THIS^.mf; 32 - END_VAR + 33 - VAR + // Extra meta-data 34 - id: STRING(255); + IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN 35 - END_VAR + MqttDiscMsgSensorWCat.meta.CharString := meta; - 1 + 36 - + END_IF - - - - - b5a7395b-79b0-4613-b65d-fa71daa858f4 - - FB_OUTPUT_BISTABLE_MQTT - - -1 - - - False - - 03cd0bac-d83c-4646-b20c-e50695e23fd1 - b5a7395b-79b0-4613-b65d-fa71daa858f4 - PublishReceived - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 37 + + - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638129306708454915 - - - - - - 3 + 38 - //first check if Mqtt is initialized, otherwise do nothing + ComposeJSON( - 4 + 39 - IF NOT(InitMqttDone) THEN + JSONString:= ADR(MqttJSON), - 5 + 40 - //mark the interface call from the collector as done + JSONStringSize:= SIZEOF(MqttJSON), - 6 + 41 - PublishReceived := TRUE; + JSONVars:= ADR(MqttDiscMsgSensorWCat), - 7 + 42 - //check if the packet is for this FB + NumberOfVars:= SIZEOF(MqttDiscMsgSensorWCat) / SIZEOF(JSONVAR), - 8 + 43 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN + MaxLevel := 1, - 9 + 44 - //mark the interface call from the collector as done + ); - 10 + 45 - PublishReceived := TRUE; + ComposeJSON.Execute := TRUE; - 11 + 46 - //now process the data + ComposeJSON(); - 12 + 47 - IF FIND(Data.PayloadString^, 'TRUE') > 0 THEN + - 13 + 48 - MqttHighRequest := TRUE; + IF MqttJSON = '' THEN - 14 + 49 - END_IF + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); - 15 + 50 - IF FIND(Data.PayloadString^, 'FALSE') > 0 THEN + ELSIF NOT (MqttJSON = '') THEN - 16 + 51 - MqttLowRequest := TRUE; + pMqttPublishQueue^.AddMessage( - 17 + 52 - END_IF + Payload:= MqttJSON, - 2 + 53 - END_IF + Topic := MqttTopic, - - - - - - - 18 + 54 - METHOD PublishReceived : BOOL + Qos := MQTT.QoS.ExactlyOnce, - 19 + 55 - VAR_INPUT + MqttRetain := TRUE, - 20 + 56 - ///Collection of recived Data + ); - 21 + 57 - Data: MQTT.CALLBACK_DATA; + IF NOT (StateValue = '') THEN - 22 + 58 - END_VAR + pMqttPublishQueue^.AddMessage( - 1 + 59 - + Payload:= StateValue, - - - - - b5a7395b-79b0-4613-b65d-fa71daa858f4 - - FB_OUTPUT_BISTABLE_MQTT - - -1 - - - False - - 1bf75fcd-baec-4e6b-99a5-eac88b92fc98 - a78cae3d-77db-4556-bb78-ee45b5903249 - ConfigureFunctionBlock - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 60 + + Topic := StateTopic, - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483684817847 - - - - - - 3 + 61 - THIS^.T_LOCKOUT:=T_LOCKOUT; + Qos := MQTT.QoS.ExactlyOnce, - 2 + 62 - THIS^.T_UD:=T_UD; + MqttRetain := TRUE, - - - - - - - 4 + 63 - METHOD ConfigureFunctionBlock : BOOL + ); - 5 + 64 - VAR_INPUT + END_IF - 6 + 65 - T_LOCKOUT: TIME; + - 7 + 66 - T_UD: TIME; + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); - 8 + 67 - END_VAR + END_IF - 1 + 2 - - a78cae3d-77db-4556-bb78-ee45b5903249 - - FB_OUTPUT_COVER_MQTT - - -1 - - - False - - d7ec667b-b145-4daa-9ed9-dc4af7254830 - a78cae3d-77db-4556-bb78-ee45b5903249 - 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 - - 638115483684158237 - - - + - 3 - - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important - - - 4 + 68 - + METHOD CreateSensorEntityWithCategory - 5 + 69 - (*pass trough*) + VAR_INPUT - 6 + 70 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + /// default - 7 + 71 - THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + Name: STRING; - 8 + 72 - THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; + Id: STRING; - 9 + 73 - THIS^.pMqttPublishQueue:=pMqttPublishQueue; + Meta: STRING; - 10 + 74 - + /// entity specific - 11 + 75 - SUPER^.InitBaseMqtt(); + StateTopic: STRING; - 2 + 76 - pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + StateValue: STRING := ''; - - - - - - - 12 + 77 - METHOD InitMqtt + /// config or diagnostic - 13 + 78 - VAR_INPUT + EntityCategory: STRING; - 14 + 79 - MQTTPublishPrefix: POINTER TO STRING; + ExpiryAfter: INT := 0; - 15 + 80 - MQTTSubscribePrefix: POINTER TO STRING; + END_VAR - 16 + 81 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + VAR - 17 + 82 - pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + EntityId: STRING(25) := 'sensor'; - 18 + 83 - END_VAR + ComposeJSON: STRUCT_TO_JSON; - 19 + 84 - VAR + MqttJSON: STRING(1500); - 20 + 85 - InstanceNamePt: POINTER TO STRING; + MqttTopic: STRING(100); - 21 + 86 END_VAR @@ -14475,18 +13629,18 @@ - a78cae3d-77db-4556-bb78-ee45b5903249 + 66c93670-7793-463e-93d0-a9b318db344d - FB_OUTPUT_COVER_MQTT + FB_BASE_MQTT_DISCOVERY_DEVICE -1 False - 742b01b6-131d-448e-a18f-8de8995e02d6 - a78cae3d-77db-4556-bb78-ee45b5903249 - InitMqttDiscovery + 12ed69ff-4fd7-4539-82e1-a2b44f611da7 + 66c93670-7793-463e-93d0-a9b318db344d + CreateSirenEntity @@ -14510,7 +13664,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115483685217844 + 638133836323377979 @@ -14519,324 +13673,308 @@ 3 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); 4 - + 5 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + // Entity related: Basis 6 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + MqttDiscMsgSiren.name.CharString := name; // friendly name 7 - ELSE + MqttDiscMsgSiren.obj_id.CharString := Id; 8 - id := overruleId; // 'MY_PH_GND_HALL_01' + MqttDiscMsgSiren.uniq_id.CharString := Id; 9 - END_IF + 10 - + // Entity related: Specific 11 - Device^.CreateCoverEntity( + MqttDiscMsgSiren.cmd_t.CharString := CommandTopic; 12 - Name := name, + MqttDiscMsgSiren.pl_on.CharString := PayloadOn; 13 - Id := id, + MqttDiscMsgSiren.pl_off.CharString := PayloadOff; 14 - Meta := meta, + MqttDiscMsgSiren.stat_t.CharString := StateTopic; 15 - CommandTopic := THIS^.MQTTSubscribeTopic, + MqttDiscMsgSiren.stat_on.CharString := StateOnPayload; 16 - PayloadOpen := 'OPEN', + MqttDiscMsgSiren.stat_off.CharString := StateOffPayload; 17 - PayloadClose := 'CLOSE', + MqttDiscMsgSiren.opt.Boolean := FALSE; 18 - PayloadStop := 'STOP', + 19 - StateTopic := THIS^.MQTTPublishTopic, + // Availabilty related 20 - StateOpen := 'OPEN', + MqttDiscMsgSiren.avty[1].topic.CharString := THIS^.availabilityTopic1; 21 - StateClosed := 'CLOSED', + MqttDiscMsgSiren.avty[2].topic.CharString := THIS^.availabilityTopic2; 22 - DeviceClass := DeviceClass + MqttDiscMsgSiren.avty_mode.CharString := 'all'; 23 - ); + MqttDiscMsgSiren.pl_avail.CharString := THIS^.availabilityOnline; 24 - + MqttDiscMsgSiren.pl_not_avail.CharString := THIS^.availabilityOffline; 25 - initMqttDiscoveryDone := TRUE; - - - 2 - - END_IF + MqttDiscMsgSiren.qos.Integer := 2; - - - - - - 26 - METHOD InitMqttDiscovery + 27 - VAR_INPUT + 28 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + // Device related 29 - Name: STRING(255); + MqttDiscMsgSiren.dev.cu.CharString := THIS^.cu; 30 - overruleId: STRING(255) := ''; + MqttDiscMsgSiren.dev.name.CharString := THIS^.name; 31 - meta: STRING(255) := ''; + MqttDiscMsgSiren.dev.hw.CharString := THIS^.hw; 32 - DeviceClass: STRING(50) := 'shutter'; + MqttDiscMsgSiren.dev.ids.CharString := THIS^.ids; 33 - END_VAR + MqttDiscMsgSiren.dev.sw.CharString := THIS^.sw; 34 - VAR + MqttDiscMsgSiren.dev.mdl.CharString := THIS^.mdl; 35 - id: STRING(255); + MqttDiscMsgSiren.dev.mf.CharString := THIS^.mf; 36 - END_VAR + - 1 + 37 + + // Extra meta-data + + + 38 + + IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN + + + 39 + + MqttDiscMsgSiren.meta.CharString := meta; + + + 40 + + END_IF + + + 41 - - - - - 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 - + + 42 + + ComposeJSON( - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483684517851 - - - - - - 3 + 43 - //first check if Mqtt is initialized, otherwise do nothing + JSONString:= ADR(MqttJSON), - 4 + 44 - IF NOT(InitMqttDone) THEN + JSONStringSize:= SIZEOF(MqttJSON), - 5 + 45 - //mark the interface call from the collector as done + JSONVars:= ADR(MqttDiscMsgSiren), - 6 + 46 - PublishReceived := TRUE; + NumberOfVars:= SIZEOF(MqttDiscMsgSiren) / SIZEOF(JSONVAR), - 7 + 47 - //check if the packet is for this FB + MaxLevel := 1, - 8 + 48 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN + ); - 9 + 49 - //mark the interface call from the collector as done + ComposeJSON.Execute := TRUE; - 10 + 50 - PublishReceived := TRUE; + ComposeJSON(); - 11 + 51 - //now process the data + - 12 + 52 - IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('STOP')) THEN + IF MqttJSON = '' THEN - 13 + 53 - THIS^.MqttRequestStop:=TRUE; + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); - 14 + 54 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('OPEN')) THEN + ELSIF NOT (MqttJSON = '') THEN - 15 + 55 - THIS^.MqttRequestOpen:=TRUE; + pMqttPublishQueue^.AddMessage( - 16 + 56 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('CLOSE')) THEN + Payload:= MqttJSON, - 17 + 57 - THIS^.MqttRequestClose:=TRUE; + Topic := MqttTopic, - 18 + 58 - END_IF + Qos := MQTT.QoS.ExactlyOnce, - 19 + 59 - + MqttRetain := TRUE, - 2 + 60 + + ); + + + 61 + + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); + + + 62 END_IF + + 2 + + + @@ -14844,27 +13982,102 @@ - 20 + 63 - METHOD PublishReceived : BOOL + METHOD CreateSirenEntity - 21 + 64 VAR_INPUT - 22 + 65 - ///Collection of recived Data + /// default - 23 + 66 - Data: MQTT.CALLBACK_DATA; + Name: STRING; - 24 + 67 + + Id: STRING; + + + 68 + + Meta: STRING; + + + 69 + + /// entity specific + + + 70 + + CommandTopic: STRING; + + + 71 + + PayloadOn: STRING; + + + 72 + + PayloadOff: STRING; + + + 73 + + StateTopic: STRING; + + + 74 + + StateOnPayload: STRING; + + + 75 + + StateOffPayload: STRING; + + + 76 + + END_VAR + + + 77 + + VAR + + + 78 + + EntityId: STRING(25) := 'siren'; + + + 79 + + ComposeJSON: STRUCT_TO_JSON; + + + 80 + + MqttJSON: STRING(1500); + + + 81 + + MqttTopic: STRING(100); + + + 82 END_VAR @@ -14877,18 +14090,18 @@ - a78cae3d-77db-4556-bb78-ee45b5903249 + 66c93670-7793-463e-93d0-a9b318db344d - FB_OUTPUT_COVER_MQTT + FB_BASE_MQTT_DISCOVERY_DEVICE -1 False - f8dd8d24-fdd6-4d76-9b04-0c2a3bdd2731 - f1306b9c-42ee-45fa-892a-f187063e8d39 - ConfigureFunctionBlock + 6b9b402a-1f81-4c18-b959-eb7f14dbe9f4 + 66c93670-7793-463e-93d0-a9b318db344d + CreateSwitchEntity @@ -14912,7 +14125,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115483686667844 + 638133836321257988 @@ -14921,409 +14134,302 @@ 3 - THIS^.T_Debounce:=T_Debounce; + MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); 4 - THIS^.T_Reconfig:=T_Reconfig; + 5 - THIS^.T_On_Max:=T_On_Max; + // Entity related: Basis 6 - THIS^.T_Dimm_Start:=T_Dimm_Start; + MqttDiscMsgSwitch.name.CharString := name; // friendly name 7 - THIS^.T_Dimm:=T_Dimm; + MqttDiscMsgSwitch.obj_id.CharString := Id; 8 - THIS^.Min_On:=Min_On; + MqttDiscMsgSwitch.uniq_id.CharString := Id; 9 - THIS^.Max_On:=Max_On; + 10 - THIS^.Soft_Dimm:=Soft_Dimm; + // Entity related: Specific 11 - THIS^.Rst_Out:=Rst_Out; + MqttDiscMsgSwitch.cmd_t.CharString := CommandTopic; 12 - THIS^.OUT_LinearScaleMin:=OUT_LinearScaleMin; + MqttDiscMsgSwitch.pl_on.CharString := PayloadOn; - - 2 - - THIS^.OUT_LinearScaleMax:=OUT_LinearScaleMax; - - - - - - - 13 - METHOD ConfigureFunctionBlock + MqttDiscMsgSwitch.pl_off.CharString := PayloadOff; 14 - VAR_INPUT + MqttDiscMsgSwitch.stat_t.CharString := StateTopic; 15 - /// Default values for dimmer, can be overwritten by method call + MqttDiscMsgSwitch.stat_on.CharString := StateOnPayload; 16 - T_Debounce: TIME := TIME#10ms; + MqttDiscMsgSwitch.stat_off.CharString := StateOffPayload; 17 - T_Reconfig: TIME := TIME#10s0ms; + MqttDiscMsgSwitch.opt.Boolean := FALSE; 18 - T_On_Max: TIME := TIME#0ms; + MqttDiscMsgSwitch.dev_cla.CharString := DeviceClass; 19 - T_Dimm_Start: TIME := TIME#400ms; + 20 - T_Dimm: TIME := TIME#3s0ms; + // Availabilty related 21 - Min_On: BYTE := 50; + MqttDiscMsgSwitch.avty[1].topic.CharString := THIS^.availabilityTopic1; 22 - Max_On: BYTE := 255; + MqttDiscMsgSwitch.avty[2].topic.CharString := THIS^.availabilityTopic2; 23 - Soft_Dimm: BOOL := TRUE; + MqttDiscMsgSwitch.avty_mode.CharString := 'all'; 24 - Rst_Out: BOOL := FALSE; + MqttDiscMsgSwitch.pl_avail.CharString := THIS^.availabilityOnline; 25 - OUT_LinearScaleMin: INT := 0; + MqttDiscMsgSwitch.pl_not_avail.CharString := THIS^.availabilityOffline; 26 - OUT_LinearScaleMax: INT := 32767; + MqttDiscMsgSwitch.qos.Integer := 2; 27 - END_VAR + - 1 + 28 - - - - - - - f1306b9c-42ee-45fa-892a-f187063e8d39 - - FB_OUTPUT_DIMMER_MQTT - - -1 - - - False - - 06c245c1-2220-4230-98c9-4adcfafaf41b - f1306b9c-42ee-45fa-892a-f187063e8d39 - initDMX - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + // Device related - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483687357849 - - - - - - 3 + 29 - + MqttDiscMsgSwitch.dev.cu.CharString := THIS^.cu; - 4 + 30 - IF NOT THIS^.InitDmxDone THEN + MqttDiscMsgSwitch.dev.name.CharString := THIS^.name; - 5 + 31 - THIS^.DmxChannel := DmxChannel; + MqttDiscMsgSwitch.dev.hw.CharString := THIS^.hw; - 6 + 32 - THIS^.pDmxValues := pDmxValues; + MqttDiscMsgSwitch.dev.ids.CharString := THIS^.ids; - 7 + 33 - THIS^.DmxWidth := DmxWidth; + MqttDiscMsgSwitch.dev.sw.CharString := THIS^.sw; - 8 + 34 - THIS^.InitDmxDone := TRUE; + MqttDiscMsgSwitch.dev.mdl.CharString := THIS^.mdl; - 9 + 35 - + MqttDiscMsgSwitch.dev.mf.CharString := THIS^.mf; - 10 + 36 - THIS^.InitDmxDone := TRUE; + - 2 + 37 - END_IF + // Extra meta-data - - - - - - - 11 + 38 - METHOD initDMX + IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - 12 + 39 - VAR_INPUT + MqttDiscMsgSwitch.meta.CharString := meta; - 13 + 40 - DmxChannel: INT; + END_IF - 14 + 41 - DmxWidth: INT := 1; + - 15 + 42 - DmxUniverse: INT := 1; + ComposeJSON( - 16 + 43 - pDmxValues: POINTER TO oscat_network.NETWORK_BUFFER_SHORT; + JSONString:= ADR(MqttJSON), - 17 + 44 - END_VAR + JSONStringSize:= SIZEOF(MqttJSON), - 1 + 45 - - - - - - - f1306b9c-42ee-45fa-892a-f187063e8d39 - - FB_OUTPUT_DIMMER_MQTT - - -1 - - - False - - b5055521-50eb-4976-b6d8-a46b1e71804c - f1306b9c-42ee-45fa-892a-f187063e8d39 - InitMqtt - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + JSONVars:= ADR(MqttDiscMsgSwitch), - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483687008233 - - - - - - 3 + 46 - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important + NumberOfVars:= SIZEOF(MqttDiscMsgSwitch) / SIZEOF(JSONVAR), - 4 + 47 - + MaxLevel := 1, - 5 + 48 - (*pass trough*) + ); - 6 + 49 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + ComposeJSON.Execute := TRUE; - 7 + 50 - THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + ComposeJSON(); - 8 + 51 - THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; + - 9 + 52 - THIS^.pMqttPublishQueue:=pMqttPublishQueue; + IF MqttJSON = '' THEN - 10 + 53 - + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); - 11 + 54 - // Dimmer specific + ELSIF NOT (MqttJSON = '') THEN - 12 + 55 - THIS^.OutputDimmer:=OutputDimmer; + pMqttPublishQueue^.AddMessage( - 13 + 56 - THIS^.Qos_Dimm:=Qos_Dimm; + Payload:= MqttJSON, - 14 + 57 - THIS^.Delta_Dimm:=Delta_Dimm; + Topic := MqttTopic, - 15 + 58 - + Qos := MQTT.QoS.ExactlyOnce, - 16 + 59 - + MqttRetain := TRUE, - 17 + 60 - SUPER^.InitBaseMqtt(); + ); - 18 + 61 - pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); - 19 + 62 - + END_IF 2 @@ -15337,57 +14443,107 @@ - 20 + 63 - METHOD InitMqtt + METHOD CreateSwitchEntity - 21 + 64 VAR_INPUT - 22 + 65 - MQTTPublishPrefix: POINTER TO STRING; + /// default - 23 + 66 - MQTTSubscribePrefix: POINTER TO STRING; + Name: STRING; - 24 + 67 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + Id: STRING; - 25 + 68 - pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + Meta: STRING; - 26 + 69 - /// Dimmer specific + /// entity specific - 27 + 70 - OutputDimmer: BOOL; + CommandTopic: STRING; - 28 + 71 - Qos_Dimm: MQTT.QoS; + PayloadOn: STRING; - 29 + 72 - Delta_Dimm: INT; + PayloadOff: STRING; - 30 + 73 + + StateTopic: STRING; + + + 74 + + StateOnPayload: STRING; + + + 75 + + StateOffPayload: STRING; + + + 76 + + DeviceClass: STRING; + + + 77 + + END_VAR + + + 78 + + VAR + + + 79 + + EntityId: STRING(25) := 'switch'; + + + 80 + + ComposeJSON: STRUCT_TO_JSON; + + + 81 + + MqttJSON: STRING(1500); + + + 82 + + MqttTopic: STRING(100); + + + 83 END_VAR @@ -15400,18 +14556,18 @@ - f1306b9c-42ee-45fa-892a-f187063e8d39 + 66c93670-7793-463e-93d0-a9b318db344d - FB_OUTPUT_DIMMER_MQTT + FB_BASE_MQTT_DISCOVERY_DEVICE -1 False - 3374cc16-98f5-4f93-97c9-86ddbebe87ac - f1306b9c-42ee-45fa-892a-f187063e8d39 - InitMqttDiscovery + c4bcdea4-3213-45c0-a9a2-0de6faca6117 + 66c93670-7793-463e-93d0-a9b318db344d + initBaseDevice @@ -15435,7 +14591,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115483687667845 + 638133836324578414 @@ -15444,427 +14600,381 @@ 3 - IF InitMqttDone AND NOT initMqttDiscoveryDone THEN + THIS^.availabilityTopic1 := availabilityTopic; 4 - + 5 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(availabilityTopic2), str2:= ADR('')) THEN 6 - id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' + THIS^.availabilityTopic2 := availabilityTopic; 7 - ELSE + ELSE 8 - id := overruleId; // 'MY_PH_GND_HALL_01' + THIS^.availabilityTopic2 := availabilityTopic2; 9 - END_IF + END_IF 10 - + 11 - Device^.CreateLightDimmerEntity( + THIS^.availabilityOnline := availabilityOnline; 12 - Name := name, + THIS^.availabilityOffline := availabilityOffline; 13 - Id := Id, + THIS^.pMqttPublishQueue := pMqttPublishQueue; 14 - Meta := meta, + THIS^.MqttDiscoveryPrefix := MqttDiscoveryPrefix; 15 - CommandTopic := CONCAT(THIS^.MQTTSubscribeTopic,'/Q'), + THIS^.MqttDiagnosticTopic := MqttDiagnosticTopic; 16 - PayloadOn := 'TRUE', + 17 - PayloadOff := 'FALSE', + THIS^.name := Name; 18 - StateTopic := CONCAT(THIS^.MQTTPublishTopic,'/Q'), + THIS^.cu:= ConfigurationUrl; 19 - BrightnessCommandTopic := CONCAT(THIS^.MQTTSubscribeTopic,'/OUT'), + THIS^.ids:= Identifiers; 20 - BrightnessStateTopic := CONCAT(THIS^.MQTTPublishTopic,'/OUT'), + THIS^.mf:= Manufacturer; 21 - BrightnessScale := 255, + THIS^.mdl:= Model; 22 - DmxChannel := THIS^.DmxChannel, + THIS^.hw:= HardwareVersion; 23 - DmxWidth := THIS^.DmxWidth, + THIS^.sw:= SoftwareVersion; 24 - DmxUniverse := THIS^.DmxUniverse); + THIS^.ip := IpAddress; 25 - + THIS^.mac := MacAddress; 26 - initMqttDiscoveryDone := TRUE; - - - 2 - - END_IF + - - - - - - 27 - METHOD InitMqttDiscovery + //Create a diagnostics availability binary sensor 28 - VAR_INPUT + CreateBinarySensorEntityWithCategory( 29 - Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; + Name := 'Availability', 30 - Name: STRING(255); + Id := CONCAT(THIS^.Name,'_diag_availability'), 31 - overruleId: STRING(255) := ''; + Meta := '', 32 - meta: STRING(255) := ''; + StateTopic := availabilityTopic, 33 - END_VAR + PayloadOn := availabilityOnline, 34 - VAR + PayloadOff := availabilityOffline, 35 - id: STRING(255); + DeviceClass := 'CONNECTIVITY', 36 - END_VAR + EntityCategory := 'diagnostic'); - 1 + 37 - - - - - - - f1306b9c-42ee-45fa-892a-f187063e8d39 - - FB_OUTPUT_DIMMER_MQTT - - -1 - - - False - - 503a6124-4e59-42e8-9059-2d7d5153fa01 - f1306b9c-42ee-45fa-892a-f187063e8d39 - 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 - - 638115483686338242 - - - - - - 3 + 38 - //first check if Mqtt is initialized, otherwise do nothing + //Logger - 4 + 39 - IF NOT(InitMqttDone) THEN + CreateSensorEntityWithCategory( - 5 + 40 - //mark the interface call from the collector as done + Name := 'Log', - 6 + 41 - PublishReceived := TRUE; + Id := CONCAT(THIS^.Name,'_diag_log'), - 7 + 42 - //check if the packet is for this FB + Meta := '', - 8 + 43 - ELSIF CONCAT(MQTTSubscribeTopic,'/Q') = Data.TopicOut^ THEN + StateTopic := CONCAT(MqttDiagnosticTopic, '/Log'), - 9 + 44 - IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('TRUE')) THEN + EntityCategory := 'diagnostic'); - 10 + 45 - MqttHighRequest := TRUE; + - 11 + 46 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN + // MAC address - 12 + 47 - MqttLowRequest := TRUE; + IF NOT(MacAddress = '') THEN - 13 + 48 - END_IF; + CreateSensorEntityWithCategory( - 14 + 49 - + Name := 'MAC', - 15 + 50 - ELSIF CONCAT(MQTTSubscribeTopic,'/OUT') = Data.TopicOut^ THEN + Id := CONCAT(THIS^.Name,'_diag_mac'), - 16 + 51 - IF OSCAT_BASIC.IS_CC(str:= Data.PayloadString^,cmp:='0123456789.') AND THIS^.PRIO_HIGH = FALSE THEN + Meta := '', - 17 + 52 - THIS^.OUT_Target:=STRING_TO_BYTE(Data.PayloadString^); + StateTopic := CONCAT(MqttDiagnosticTopic, '/MAC'), - 18 + 53 - THIS^.SoftDimToValue:=TRUE; + StateValue := MacAddress, - 19 + 54 - END_IF + EntityCategory := 'diagnostic'); - 20 + 55 - + END_IF - 21 + 56 - + - 22 + 57 - // Legacy! backwards compatiably with /+ topics instead of /# + - 23 + 2 - ELSIF CommonTypesAndFunctions.StrEqualsAtStart(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN + + + + + + + - 24 + 58 - //mark the interface call from the collector as done + METHOD initBaseDevice - 25 + 59 - PublishReceived := TRUE; + VAR_INPUT - 26 + 60 - //now process the data + Name: STRING; - 27 + 61 - IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('TRUE')) THEN + ConfigurationUrl: STRING; - 28 + 62 - MqttHighRequest := TRUE; + Identifiers: STRING; - 29 + 63 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN + Manufacturer: STRING; - 30 + 64 - MqttLowRequest := TRUE; + Model: STRING; - 31 + 65 - ELSIF OSCAT_BASIC.IS_CC(str:= Data.PayloadString^,cmp:='0123456789.') AND THIS^.PRIO_HIGH = FALSE THEN + SoftwareVersion: STRING; - 32 + 66 - THIS^.OUT_Target:=STRING_TO_BYTE(Data.PayloadString^); + HardwareVersion: STRING; - 33 + 67 - THIS^.SoftDimToValue:=TRUE; + IpAddress: STRING := ''; - 34 + 68 - END_IF + MacAddress: STRING := ''; - 2 + 69 - END_IF + availabilityTopic: STRING; - - - - - - - 35 + 70 - METHOD PublishReceived : BOOL + availabilityTopic2: STRING := ''; - 36 + 71 - VAR_INPUT + availabilityOnline: STRING; - 37 + 72 - ///Collection of recived Data + availabilityOffline: STRING; - 38 + 73 - Data: MQTT.CALLBACK_DATA; + MqttDiscoveryPrefix: STRING; - 39 + 74 + + MqttDiagnosticTopic: STRING; + + + 75 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 76 END_VAR @@ -15877,18 +14987,18 @@ - f1306b9c-42ee-45fa-892a-f187063e8d39 + 66c93670-7793-463e-93d0-a9b318db344d - FB_OUTPUT_DIMMER_MQTT + FB_BASE_MQTT_DISCOVERY_DEVICE -1 False - 984fa948-b007-4cb3-9e0f-2d63e7f44db7 - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - AddNode + ad8d7441-e59b-4b9f-afa4-6618466fc0c3 + 66c93670-7793-463e-93d0-a9b318db344d + SendLogMessage @@ -15912,7 +15022,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389528346545 + 638133836326488268 @@ -15921,37 +15031,32 @@ 3 - THIS^.Nodes[NodePointer].InitNode( + pMqttPublishQueue^.AddMessage( 4 - DeviceAddress := THIS^.ReadMasterUnitQuery.DeviceId, + Payload:= CONCAT(CONCAT(instance,' | '),str), 5 - NodeNumber := NodePointer -1, + Topic := CONCAT(MqttDiagnosticTopic, '/Log'), 6 - DataPollingInterval := DataPollingInterval + Qos := 1, 7 - ); - - - 8 - - + MqttRetain := TRUE 2 - NodePointer := NodePointer + 1; + ); @@ -15959,20 +15064,25 @@ + + 8 + + METHOD SendLogMessage : BOOL + 9 - METHOD AddNode : BOOL + VAR_INPUT 10 - VAR_INPUT + str: STRING(128); 11 - DataPollingInterval: TIME; + instance: STRING := ''; 12 @@ -15988,18 +15098,18 @@ - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + 66c93670-7793-463e-93d0-a9b318db344d - FB_RS485_DUCO_DUCOBOX_MQTT + FB_BASE_MQTT_DISCOVERY_DEVICE -1 False - ea4a3060-cbd7-4ff9-940d-93b4781abc91 - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - GetRtuQuery + 46900d0a-7814-422e-afc3-0dfae8ff432a + a267de92-bab5-4cb3-917a-2be8d7a0661f + ConfigureFunctionBlock @@ -16023,66 +15133,127 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389527486540 + 638115483669607851 + + + + 2 + + THIS^.T_TurnOffDelay:=T_TurnOffDelay; + + + + + 3 - IF WriteQueryReady THEN + METHOD ConfigureFunctionBlock 4 - GetRtuQuery := THIS^.WriteQuery; + VAR_INPUT 5 - WriteQueryBeingExecuted := TRUE; + T_TurnOffDelay: TIME; 6 - // master + END_VAR - 7 + 1 - ELSIF ActiveNode = 1 THEN + + + + + + + a267de92-bab5-4cb3-917a-2be8d7a0661f + + FB_INPUT_BINARYSENSOR_MQTT + + -1 + + + False + + ecbb5bef-d79c-4aac-976b-34395632d443 + a267de92-bab5-4cb3-917a-2be8d7a0661f + 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 + + 638115483668978260 + + + + + + + 3 + + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important - 8 + 4 - THIS^.timerData.IN := FALSE; + - 9 + 5 - GetRtuQuery := THIS^.ReadMasterUnitQuery; + (*pass trough*) - 10 + 6 - // other nodes + THIS^.pMqttPublishQueue := pMqttPublishQueue; - 11 + 7 - ELSIF ActiveNode > 1 THEN + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; - 12 + 8 - GetRtuQuery := THIS^.Nodes[ActiveNode].GetRtuQuery(); + SUPER^.InitBaseMqtt(); 2 - END_IF + @@ -16090,10 +15261,30 @@ + + 9 + + METHOD InitMqtt + + + 10 + + VAR_INPUT + + + 11 + + MQTTPublishPrefix: POINTER TO STRING; + + + 12 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + 13 - METHOD GetRtuQuery : RS485_RtuQuery + END_VAR 1 @@ -16104,18 +15295,18 @@ - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + a267de92-bab5-4cb3-917a-2be8d7a0661f - FB_RS485_DUCO_DUCOBOX_MQTT + FB_INPUT_BINARYSENSOR_MQTT -1 False - 372d5ec1-4c34-43e7-a93a-115a801b0a96 - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - InitMqtt + 2070ee38-ec9d-43d5-85fb-f0980d5482b7 + a267de92-bab5-4cb3-917a-2be8d7a0661f + InitMqttDiscovery @@ -16139,7 +15330,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389526927034 + 638115483669297853 @@ -16148,102 +15339,97 @@ 3 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; + 5 - + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(THIS^.InstanceName)) + 1; + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - THIS^.MqttPublishTopicSuffix := InstanceNamePt^; + ELSE 8 - THIS^.MQTTSubscribeTopic := CONCAT(MQTTSubscribePrefix^ ,THIS^.MqttPublishTopicSuffix); + id := overruleId; // 'MY_PH_GND_HALL_01' 9 - + END_IF 10 - // register the FB agains the collector so mqtt events can be received + 11 - pMqttCallbackCollector^.put(instance:= THIS^); + Device^.CreateBinarySensorEntity( 12 - + Id := id, 13 - + Name := name, 14 - FOR loopCounter := 2 TO 30 DO + Meta := meta, 15 - Nodes[loopCounter].InitMqtt( + StateTopic := THIS^.MQTTPublishTopic, 16 - MQTTPublishPrefix := MQTTPublishPrefix, + PayloadOn := 'ON', 17 - MqttPublishTopicSuffix := InstanceNamePt^, + PayloadOff := 'OFF', 18 - pMqttPublishQueue := pMqttPublishQueue + DeviceClass := DeviceClass); 19 - ); + 20 - END_FOR - - - 21 - - + initMqttDiscoveryDone := TRUE; 2 - InitMqttDone := TRUE; + END_IF @@ -16251,35 +15437,40 @@ + + 21 + + METHOD InitMqttDiscovery + 22 - METHOD InitMqtt + VAR_INPUT 23 - VAR_INPUT + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; 24 - MQTTPublishPrefix: POINTER TO STRING; + Name: STRING(255); 25 - MQTTSubscribePrefix: POINTER TO STRING; + DeviceClass: STRING(100) := 'smoke'; 26 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + overruleId: STRING(255) := ''; 27 - pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + meta: STRING(255) := ''; 28 @@ -16294,7 +15485,7 @@ 30 - InstanceNamePt: POINTER TO STRING; + id: STRING(255); 31 @@ -16310,18 +15501,18 @@ - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + a267de92-bab5-4cb3-917a-2be8d7a0661f - FB_RS485_DUCO_DUCOBOX_MQTT + FB_INPUT_BINARYSENSOR_MQTT -1 False - 723bccfa-a813-453d-a7fb-6bb45f91344e - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - InitRS485 + 1f4b71e5-eb2a-4c4a-b6d4-a20ad170453c + 98f79313-4387-4064-a781-6319454c2036 + ConfigureFunctionBlock @@ -16345,7 +15536,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389526576970 + 638115483670867852 @@ -16354,32 +15545,47 @@ 3 - THIS^.timerData.PT := DataPollingInterval; + THIS^.T_Debounce:=T_Debounce; 4 - THIS^.ReadMasterUnitQuery.DeviceId := DeviceAddress; + THIS^.T_Reconfig:=T_Reconfig; 5 - THIS^.WriteQuery.DeviceId := DeviceAddress; + THIS^.T_On_Max:=T_On_Max; 6 - THIS^.timerData.IN := TRUE; + THIS^.T_Dimm_Start:=T_Dimm_Start; 7 + THIS^.T_Dimm:=T_Dimm; + + + 8 + + THIS^.Min_On:=Min_On; + + + 9 + + THIS^.Max_On:=Max_On; + + + 10 + 2 - THIS^.InitRS485Done := TRUE; + THIS^.T_Long:=T_Long; @@ -16388,27 +15594,82 @@ - 8 + 11 - METHOD InitRS485 + METHOD ConfigureFunctionBlock - 9 + 12 VAR_INPUT - 10 + 13 - DataPollingInterval: TIME; + /// Default values for dimmer, can be overwritten by method call - 11 + 14 - DeviceAddress: BYTE; + T_Debounce: TIME; - 12 + 15 + + T_Reconfig: TIME; + + + 16 + + T_On_Max: TIME; + + + 17 + + T_Dimm_Start: TIME; + + + 18 + + T_Dimm: TIME; + + + 19 + + Min_On: BYTE; + + + 20 + + Max_On: BYTE; + + + 21 + + Soft_Dimm: BOOL; + + + 22 + + Dbl_Toggle: BOOL; + + + 23 + + Rst_Out: BOOL; + + + 24 + + /// Default value for click mode, can be overwritten by method call + + + 25 + + T_Long: TIME; + + + 26 END_VAR @@ -16421,18 +15682,18 @@ - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + 98f79313-4387-4064-a781-6319454c2036 - FB_RS485_DUCO_DUCOBOX_MQTT + FB_INPUT_PUSHBUTTON_DIMMER_MQTT -1 False - 7e3a8fa6-6437-43f2-8c12-65ca0de644c9 - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - ProcessDataArray + 597edaa9-daf6-4235-891a-58677c97ecc5 + 98f79313-4387-4064-a781-6319454c2036 + InitMqtt @@ -16456,7 +15717,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389526296862 + 638115483670557846 @@ -16465,177 +15726,289 @@ 3 - THIS^.Error := Error^; + THIS^.pMqttPublishQueue := pMqttPublishQueue; 4 - + THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; 5 - IF Error^ AND NOT WriteQueryBeingExecuted THEN + 6 - PubMqttMessage(Suffix := '/availability', Data := 'offline'); + InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(THIS^.InstanceName)) + 1; 7 - ELSE + THIS^.MqttPublishTopicSuffix := InstanceNamePt^; 8 - PubMqttMessage(Suffix := '/availability', Data := 'online'); + 9 - END_IF + THIS^.OutputDimmer:=OutputDimmer; 10 - + THIS^.Qos_Dimm:=Qos_Dimm; 11 - IF WriteQueryBeingExecuted THEN + THIS^.Delta_Dimm:=Delta_Dimm; 12 - WriteQueryReady := FALSE; + + + + 2 + + InitMqttDone := TRUE; + + + + + + 13 - WriteQueryBeingExecuted := FALSE; + METHOD InitMqtt 14 - IF NOT Error^ THEN + VAR_INPUT 15 - PubMqttMessage(Suffix := CONCAT('/', WriteQuerySuffix), Data := WriteQueryPayload); + MQTTPublishPrefix: POINTER TO STRING; 16 - END_IF + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; 17 - // data for master unit (= main node) + OutputDimmer: BOOL; 18 - ELSIF THIS^.ActiveNode = 1 THEN + Qos_Dimm: MQTT.QoS; 19 - THIS^.timerData.IN := TRUE; + Delta_Dimm: INT; 20 - THIS^.ActiveNode := 0; + END_VAR 21 - + VAR 22 - IF NOT Error^ THEN + InstanceNamePt: POINTER TO STRING; 23 - PubMqttMessage(Suffix := '/1/read/0', Data := WORD_TO_STRING(Data^[0])); + END_VAR - 24 + 1 - PubMqttMessage(Suffix := '/1/read/1', Data := WORD_TO_STRING(Data^[1])); + + + + + + + 98f79313-4387-4064-a781-6319454c2036 + + FB_INPUT_PUSHBUTTON_DIMMER_MQTT + + -1 + + + False + + 6ebfd5ef-9849-4eae-aae9-726c64dd33f7 + b624cd6e-bc6f-46a8-9c3d-8588be854a5d + 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 + + 638115483672408235 + + + + + - 25 + 2 - PubMqttMessage(Suffix := '/1/read/2', Data := WORD_TO_STRING(Data^[2])); + THIS^.T_Long:=T_Long; + + + + + + - 26 + 3 - PubMqttMessage(Suffix := '/1/read/3', Data := WORD_TO_STRING(Data^[3])); + METHOD ConfigureFunctionBlock - 27 + 4 - PubMqttMessage(Suffix := '/1/read/4', Data := WORD_TO_STRING(Data^[4])); + VAR_INPUT - 28 + 5 - PubMqttMessage(Suffix := '/1/read/5', Data := WORD_TO_STRING(Data^[5])); + /// Default value for click mode, can be overwritten by method call - 29 + 6 - END_IF + T_Long: TIME; - 30 + 7 - // data for nodes + END_VAR - 31 + 1 - ELSIF THIS^.ActiveNode > 1 THEN + + + + + + + b624cd6e-bc6f-46a8-9c3d-8588be854a5d + + FB_INPUT_PUSHBUTTON_MQTT + + -1 + + + False + + f6303c90-5efc-4c71-9fd2-2ec6bc009dbf + b624cd6e-bc6f-46a8-9c3d-8588be854a5d + 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 + + 638115483672107845 + + + + + - 32 + 3 - THIS^.Nodes[ActiveNode].ProcessDataArray( + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important - 33 + 4 - Data := Data, + - 34 + 5 - Error := Error + (*pass trough*) - 35 + 6 - ); + THIS^.pMqttPublishQueue := pMqttPublishQueue; - 36 + 7 - THIS^.ActiveNode := 0; + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + + + 8 + + SUPER^.InitBaseMqtt(); 2 - END_IF + @@ -16644,27 +16017,27 @@ - 37 + 9 - METHOD ProcessDataArray + METHOD InitMqtt - 38 + 10 VAR_INPUT - 39 + 11 - Error: POINTER TO BOOL; + MQTTPublishPrefix: POINTER TO STRING; - 40 + 12 - Data: POINTER TO ARRAY[0..124] OF WORD; + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; - 41 + 13 END_VAR @@ -16677,18 +16050,18 @@ - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + b624cd6e-bc6f-46a8-9c3d-8588be854a5d - FB_RS485_DUCO_DUCOBOX_MQTT + FB_INPUT_PUSHBUTTON_MQTT -1 False - eaa441be-86d1-44ee-a353-eaca63e8d47e - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - PublishReceived + 24bbe81f-bf22-4511-ab47-fca2890ecb47 + b624cd6e-bc6f-46a8-9c3d-8588be854a5d + InitMqttDiscovery @@ -16712,7 +16085,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389528026550 + 638115483671738153 @@ -16721,122 +16094,87 @@ 3 - //first check if Mqtt is initialized, otherwise do nothing + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - IF NOT(InitMqttDone) THEN + 5 - //mark the interface call from the collector as done + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - PublishReceived := TRUE; + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - //check if the packet is for this FB + ELSE 8 - ELSIF MQTTSubscribeTopic = LEFT(Data.TopicOut^, LEN(MQTTSubscribeTopic)) THEN + id := overruleId; // 'MY_PH_GND_HALL_01' 9 - //mark the interface call from the collector as done + END_IF 10 - PublishReceived := TRUE; + 11 - // process the data + Device^.CreateSensorEntity( 12 - SubTopic := RIGHT(Data.TopicOut^, 9); // 2/write/9 -> 10 chars + Name := name, 13 - NodeNumber := LEFT(SubTopic, 1); + Id := id, 14 - NodeRegister := RIGHT(SubTopic, 1); + Meta := meta, 15 - + StateTopic := THIS^.MQTTPublishTopic, 16 - IF FIND(SubTopic, 'write') > 0 AND + ExpiryAfter := 2); 17 - OSCAT_BASIC.IS_NUM(NodeNumber) AND + 18 - OSCAT_BASIC.IS_NUM(NodeRegister) AND - - - 19 - - OSCAT_BASIC.IS_NUM(Data.PayloadString^) THEN - - - 20 - - WriteQuery.WriteAddress := (STRING_TO_UINT(NodeNumber) * 10) + STRING_TO_UINT(NodeRegister); - - - 21 - - WriteQuery.WriteData[0] := STRING_TO_WORD(Data.PayloadString^); - - - 22 - - WriteQuerySuffix := SubTopic; - - - 23 - - WriteQueryPayload := Data.PayloadString^; - - - 24 - - WriteQueryReady := TRUE; - - - 25 - - END_IF + initMqttDiscoveryDone := TRUE; 2 - END_IF + END_IF @@ -16845,52 +16183,52 @@ - 26 + 19 - METHOD PublishReceived : BOOL + METHOD InitMqttDiscovery - 27 + 20 VAR_INPUT - 28 + 21 - ///Collection of recived Data + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - 29 + 22 - Data: MQTT.CALLBACK_DATA; + Name: STRING(255); - 30 + 23 - END_VAR + overruleId: STRING(255) := ''; - 31 + 24 - VAR + meta: STRING(255) := ''; - 32 + 25 - SubTopic: STRING; + END_VAR - 33 + 26 - NodeNumber: STRING; + VAR - 34 + 27 - NodeRegister: STRING; + id: STRING(255); - 35 + 28 END_VAR @@ -16903,18 +16241,18 @@ - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + b624cd6e-bc6f-46a8-9c3d-8588be854a5d - FB_RS485_DUCO_DUCOBOX_MQTT + FB_INPUT_PUSHBUTTON_MQTT -1 False - 04d3b380-14c7-4633-b3eb-30e8fb76c702 - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - PubMqttMessage + 28d234e5-a1bf-45f1-a68e-df4591772edd + c9779880-673c-4a93-b351-acbcc8c75d81 + InitBaseMqtt @@ -16938,7 +16276,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389527756959 + 638115483673477845 @@ -16947,43 +16285,98 @@ 3 - IF InitMqttDone THEN + 4 - pMqttPublishQueue^.AddMessage( + (*Define instance names*) 5 - Payload := Data, + InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(_InstancePath)) + 1; 6 - Topic := CONCAT(CONCAT(MqttPublishTopicPrefix^, MqttPublishTopicSuffix), Suffix ), + 7 - Qos := MQTT.QoS.ExactlyOnce, + DeviceName := LEFT(_InstancePath,find(_InstancePath, '.' )-1 ) ; 8 - MqttRetain := FALSE + 9 - ); + // Publish (Out); - 2 + 10 + + IF NOT CommonTypesAndFunctions.StrEquals(ADR(MqttPublishTopicPrefix),ADR('')) THEN + + + 11 + + THIS^.MqttPublishTopicSuffix := InstanceNamePt^; + + + 12 + + THIS^.MQTTPublishTopic := CONCAT(MqttPublishTopicPrefix^, THIS^.MqttPublishTopicSuffix); + + + 13 + + END_IF + + + 14 + + + + + 15 + + // Subscribe (In) + + + 16 + + IF NOT CommonTypesAndFunctions.StrEquals(ADR(MqttSubscribeTopicPrefix),ADR('')) THEN + + + 17 + + THIS^.MQTTSubscribeTopicSuffix := InstanceNamePt^; + + + 18 + + THIS^.MQTTSubscribeTopic := CONCAT(MqttSubscribeTopicPrefix^ ,THIS^.MQTTSubscribeTopicSuffix); + + + 19 END_IF + + 20 + + + + + 2 + + InitMqttDone := TRUE; + @@ -16991,27 +16384,32 @@ - 10 + 21 - METHOD PubMqttMessage + METHOD InitBaseMqtt - 11 + 22 - VAR_INPUT + VAR - 12 + 23 - Suffix: STRING(100); + MQTTPublishPrefix: POINTER TO STRING; - 13 + 24 - Data: STRING(100); + MQTTSubscribePrefix: POINTER TO STRING; - 14 + 25 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 26 END_VAR @@ -17024,18 +16422,18 @@ - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + c9779880-673c-4a93-b351-acbcc8c75d81 - FB_RS485_DUCO_DUCOBOX_MQTT + FB_MQTT_BASE -1 False - 284fb9e1-88e7-4941-bc27-4f35fb4e92ce - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - RequestBusTime + c535088d-119a-4b9d-9c46-f86698af42bb + a1bd57b2-7fd1-4392-bd24-7f01031c67fc + InitMqtt @@ -17059,7 +16457,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389527206545 + 638115483674897863 @@ -17068,106 +16466,101 @@ 3 - IF NOT InitRS485Done THEN + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important 4 - RequestBusTime := FALSE; + 5 - ELSIF WriteQueryReady THEN + (*pass trough*) 6 - RequestBusTime := TRUE; + THIS^.pMqttPublishQueue := pMqttPublishQueue; 7 - ELSIF timerData.Q THEN // Master node + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; 8 - RequestBusTime := TRUE; + THIS^.pMqttPublishQueue:=pMqttPublishQueue; 9 - THIS^.ActiveNode := 1; + 10 - ELSIF NodePointer > 2 THEN// other nodes, if configured + THIS^.MqttQos := MqttQos; 11 - FOR loopCounter := 2 TO 30 DO + THIS^.MqttRetain := MqttRetain; 12 - IF Nodes[loopCounter].RequestBusTime() AND RequestBusTime = FALSE THEN + + + + 2 + + SUPER^.InitBaseMqtt(); + + + + + + 13 - THIS^.ActiveNode := loopCounter; + METHOD InitMqtt 14 - RequestBusTime := TRUE; + VAR_INPUT 15 - END_IF + MQTTPublishPrefix: POINTER TO STRING; 16 - END_FOR + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; 17 - ELSE + MqttQos: MQTT.QoS := MQTT.QoS.ExactlyOnce; 18 - RequestBusTime := FALSE; + MqttRetain: BOOL := FALSE; 19 - END_IF + END_VAR - 2 - - - - - - - - - - - 20 - - METHOD RequestBusTime : BOOL - - - 1 + 1 @@ -17175,18 +16568,18 @@ - 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + a1bd57b2-7fd1-4392-bd24-7f01031c67fc - FB_RS485_DUCO_DUCOBOX_MQTT + FB_MQTT_LOG -1 False - 33a50ff3-9c75-4b75-a3db-042629418278 - 6da195a7-86d2-4618-bcdb-49518274d9f3 - GetRtuQuery + 196c70ab-0d3c-4fa5-a394-2b9ec6f8139d + a1bd57b2-7fd1-4392-bd24-7f01031c67fc + InitMqttDiscovery @@ -17210,7 +16603,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389529006952 + 638115483674207866 @@ -17219,108 +16612,82 @@ 3 - IF timerData.Q THEN + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - THIS^.timerData.IN := FALSE; + 5 - GetRtuQuery := THIS^.RtuQueryRead; + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN - 2 + 6 - END_IF + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' - - - - - - - 6 + 7 - METHOD GetRtuQuery : RS485_RtuQuery + ELSE - 1 + 8 - + id := overruleId; // 'MY_PH_GND_HALL_01' - - - - - 6da195a7-86d2-4618-bcdb-49518274d9f3 - - FB_RS485_DUCO_DUCOBOX_NODE_MQTT - - -1 - - - False - - 57422230-b02b-47fd-883e-95a351732463 - 6da195a7-86d2-4618-bcdb-49518274d9f3 - InitMqtt - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 9 + + END_IF - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638103389530166534 - - - - - - 3 + 10 - THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; + - 4 + 11 - THIS^.MqttPublishTopicSuffix := MqttPublishTopicSuffix; + Device^.CreateSensorEntity( - 5 + 12 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + Name := name, - 6 + 13 + + Id := id, + + + 14 + + Meta := meta, + + + 15 + + StateTopic := THIS^.MQTTPublishTopic); + + + 16 + + 17 + + initMqttDiscoveryDone := TRUE; + 2 - THIS^.InitMqttDone := TRUE; + END_IF @@ -17329,32 +16696,52 @@ - 7 + 18 - METHOD InitMqtt + METHOD InitMqttDiscovery - 8 + 19 VAR_INPUT - 9 + 20 - MQTTPublishPrefix: POINTER TO STRING; + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - 10 + 21 - MqttPublishTopicSuffix: STRING(255); + Name: STRING(255) := 'plc_log'; - 11 + 22 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + overruleId: STRING(255) := ''; - 12 + 23 + + meta: STRING(255) := ''; + + + 24 + + END_VAR + + + 25 + + VAR + + + 26 + + id: STRING(255); + + + 27 END_VAR @@ -17367,18 +16754,18 @@ - 6da195a7-86d2-4618-bcdb-49518274d9f3 + a1bd57b2-7fd1-4392-bd24-7f01031c67fc - FB_RS485_DUCO_DUCOBOX_NODE_MQTT + FB_MQTT_LOG -1 False - e8f2e620-c121-4dd7-ae15-57589c9c150e - 6da195a7-86d2-4618-bcdb-49518274d9f3 - InitNode + f30010c6-e326-46b1-a927-dd59f6b94b42 + a1bd57b2-7fd1-4392-bd24-7f01031c67fc + send @@ -17402,7 +16789,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389529876572 + 638115483674587846 @@ -17411,47 +16798,42 @@ 3 - THIS^.RtuQueryRead.DeviceId := DeviceAddress; + IF InitMqttDone THEN 4 - THIS^.RtuQueryRead.ReadAddress := (NodeNumber * 10) + 10; + pMqttPublishQueue^.AddMessage( 5 - + Payload:= CONCAT(CONCAT(instance,' | '),str), 6 - THIS^.timerData.PT := DataPollingInterval; + Topic := THIS^.MQTTPublishTopic, 7 - THIS^.NodeNumber := NodeNumber + 1; + Qos := 1, 8 - + MqttRetain := TRUE 9 - THIS^.timerData.IN := TRUE; - - - 10 - - + ); 2 - THIS^.NodeInitialized := TRUE; + END_IF @@ -17460,32 +16842,27 @@ - 11 + 10 - METHOD InitNode + METHOD send - 12 + 11 VAR_INPUT - 13 - - DeviceAddress: BYTE; - - - 14 + 12 - NodeNumber: UINT; + str: STRING(128); - 15 + 13 - DataPollingInterval: TIME; + instance: STRING := ''; - 16 + 14 END_VAR @@ -17498,18 +16875,18 @@ - 6da195a7-86d2-4618-bcdb-49518274d9f3 + a1bd57b2-7fd1-4392-bd24-7f01031c67fc - FB_RS485_DUCO_DUCOBOX_NODE_MQTT + FB_MQTT_LOG -1 False - 98b35e54-97b2-4227-bca4-337378a9d265 - 6da195a7-86d2-4618-bcdb-49518274d9f3 - ProcessDataArray + 6ff95b0f-793d-408b-bbd0-ac2ecea639ac + fb058f61-66e0-49ec-9946-da2492e34dad + InitMqtt @@ -17533,7 +16910,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389529316913 + 638133836328107986 @@ -17542,7 +16919,7 @@ 3 - THIS^.timerData.IN := TRUE; + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important 4 @@ -17552,42 +16929,52 @@ 5 - IF NOT Error^ THEN + (*pass trough*) 6 - PubMqttMessage(Suffix := '/read/0', Data := WORD_TO_STRING(Data^[0])); + THIS^.pMqttPublishQueue := pMqttPublishQueue; 7 - PubMqttMessage(Suffix := '/read/1', Data := WORD_TO_STRING(Data^[1])); + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; 8 - PubMqttMessage(Suffix := '/read/2', Data := WORD_TO_STRING(Data^[2])); + THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; 9 - PubMqttMessage(Suffix := '/read/3', Data := WORD_TO_STRING(Data^[3])); + THIS^.pMqttPublishQueue:=pMqttPublishQueue; 10 - PubMqttMessage(Suffix := '/read/4', Data := WORD_TO_STRING(Data^[4])); + 11 - PubMqttMessage(Suffix := '/read/5', Data := WORD_TO_STRING(Data^[5])); + SUPER^.InitBaseMqtt(); + + + 12 + + pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + + + 13 + + 2 - END_IF + @@ -17596,27 +16983,37 @@ - 12 + 14 - METHOD ProcessDataArray + METHOD InitMqtt - 13 + 15 VAR_INPUT - 14 + 16 - Error: POINTER TO BOOL; + MQTTPublishPrefix: POINTER TO STRING; - 15 + 17 - Data: POINTER TO ARRAY[0..124] OF WORD; + MQTTSubscribePrefix: POINTER TO STRING; - 16 + 18 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 19 + + pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + + + 20 END_VAR @@ -17629,18 +17026,18 @@ - 6da195a7-86d2-4618-bcdb-49518274d9f3 + fb058f61-66e0-49ec-9946-da2492e34dad - FB_RS485_DUCO_DUCOBOX_NODE_MQTT + FB_OUTPUT_BINARY_MQTT -1 False - 816a26ad-fa61-4c29-b284-8d41f2463f2e - 6da195a7-86d2-4618-bcdb-49518274d9f3 - PubMqttMessage + d3590eba-661f-46c6-9cef-4bad6377490e + fb058f61-66e0-49ec-9946-da2492e34dad + InitMqttDiscoveryAsLight @@ -17664,7 +17061,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103389530446540 + 638133836329188057 @@ -17673,169 +17070,158 @@ 3 - IF InitMqttDone THEN + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - pMqttPublishQueue^.AddMessage( + 5 - Payload := Data, + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - Topic := CONCAT(CONCAT(CONCAT(CONCAT(MqttPublishTopicPrefix^, MqttPublishTopicSuffix), '/'), UINT_TO_STRING(NodeNumber)), Suffix ), + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - Qos := MQTT.QoS.ExactlyOnce, + ELSE 8 - MqttRetain := FALSE + id := overruleId; // 'MY_PH_GND_HALL_01' 9 - ); - - - 2 - - END_IF + END_IF - - - - - - 10 - METHOD PubMqttMessage + 11 - VAR_INPUT + Device^.CreateLightEntity( 12 - Suffix: STRING(100); + Name := name, 13 - Data: STRING(100); + Id := id, 14 - END_VAR + Meta := meta, - 1 + 15 + + CommandTopic := THIS^.MQTTSubscribeTopic, + + + 16 + + PayloadOn := BOOL_TO_STRING(NOT(Invert)), + + + 17 + + PayloadOff := BOOL_TO_STRING(Invert), + + + 18 + + StateTopic := THIS^.MQTTPublishTopic); + + + 19 + + 20 + + initMqttDiscoveryDone := TRUE; + + + 2 + + END_IF + - - 6da195a7-86d2-4618-bcdb-49518274d9f3 - - FB_RS485_DUCO_DUCOBOX_NODE_MQTT - - -1 - - - False - - 6f3af5be-1a1b-4474-af9f-b3b4961b2598 - 6da195a7-86d2-4618-bcdb-49518274d9f3 - RequestBusTime - - - - 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 - - 638103389529596961 - - - + - 3 + 21 - IF NOT NodeInitialized THEN + METHOD InitMqttDiscoveryAsLight - 4 + 22 - RequestBusTime := FALSE; + VAR_INPUT - 5 + 23 - ELSIF timerData.Q THEN + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - 6 + 24 - RequestBusTime := TRUE; + Name: STRING(255); - 7 + 25 - ELSE + overruleId: STRING(255) := ''; - 8 + 26 - RequestBusTime := FALSE; + meta: STRING(255) := ''; - 2 + 27 - END_IF + Invert: BOOL := FALSE; - - - - - - - 9 + 28 - METHOD RequestBusTime : BOOL + END_VAR + + + 29 + + VAR + + + 30 + + id: STRING(255); + + + 31 + + END_VAR 1 @@ -17846,18 +17232,18 @@ - 6da195a7-86d2-4618-bcdb-49518274d9f3 + fb058f61-66e0-49ec-9946-da2492e34dad - FB_RS485_DUCO_DUCOBOX_NODE_MQTT + FB_OUTPUT_BINARY_MQTT -1 False - 333dbf37-ebcd-46b9-be3b-adc8ad3216f3 - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 - GetRtuQuery + af6b52fe-46ad-454e-90d9-b9b94da26d07 + fb058f61-66e0-49ec-9946-da2492e34dad + InitMqttDiscoveryAsLock @@ -17881,7 +17267,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326551448711 + 638133836329618390 @@ -17890,143 +17276,107 @@ 3 - IF timerData.Q THEN + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - THIS^.timerData.IN := FALSE; + 5 - IF DeviceType = RS485_EASTRON_SDM_Devices.SDM120 OR DeviceType = RS485_EASTRON_SDM_Devices.SDM220 THEN + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - GetRtuQuery := THIS^.SDM120AndSDM220RtuQuery; + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - END_IF + ELSE 8 - IF DeviceType = RS485_EASTRON_SDM_Devices.SDM630 THEN + id := overruleId; // 'MY_PH_GND_HALL_01' 9 - GetRtuQuery := THIS^.SDM630RtuQuery; + END_IF 10 - END_IF + - 2 + 11 - END_IF + Device^.CreateLockEntity( - - - - - - - 11 + 12 - METHOD GetRtuQuery : RS485_RtuQuery + Name := name, - 1 + 13 - + Id := id, - - - - - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 - - FB_RS485_EASTRON_SDM_POWER_MQTT - - -1 - - - False - - dbf3b033-3fa0-4bef-ae08-ea325660b4dc - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 - InitMqtt - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 14 + + Meta := meta, - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638103326552160124 - - - - - - 3 + 15 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + CommandTopic := THIS^.MQTTSubscribeTopic, - 4 + 16 - THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; + PayloadLock := BOOL_TO_STRING(NOT(Invert)), - 5 + 17 - + PayloadUnlock := BOOL_TO_STRING(Invert), - 6 + 18 - InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(THIS^.InstanceName)) + 1; + StateTopic := THIS^.MQTTPublishTopic, - 7 + 19 - THIS^.MqttPublishTopicSuffix := InstanceNamePt^; + StateUnlocked := BOOL_TO_STRING(Invert), - 8 + 20 + + StateLocked := BOOL_TO_STRING(NOT(Invert))); + + + 21 + + 22 + + initMqttDiscoveryDone := TRUE; + 2 - THIS^.InitMqttDone := TRUE; + END_IF @@ -18035,42 +17385,57 @@ - 9 + 23 - METHOD InitMqtt + METHOD InitMqttDiscoveryAsLock - 10 + 24 VAR_INPUT - 11 + 25 - MQTTPublishPrefix: POINTER TO STRING; + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - 12 + 26 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + Name: STRING(255); - 13 + 27 + + overruleId: STRING(255) := ''; + + + 28 + + meta: STRING(255) := ''; + + + 29 + + Invert: BOOL := FALSE; + + + 30 END_VAR - 14 + 31 VAR - 15 + 32 - InstanceNamePt: POINTER TO STRING; + id: STRING(255); - 16 + 33 END_VAR @@ -18083,18 +17448,18 @@ - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + fb058f61-66e0-49ec-9946-da2492e34dad - FB_RS485_EASTRON_SDM_POWER_MQTT + FB_OUTPUT_BINARY_MQTT -1 False - 1dfb6296-ec83-451a-8f4a-b952d2f4c484 - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 - InitRS485 + 1990d527-e4fb-478d-b331-c8a6ba51e997 + fb058f61-66e0-49ec-9946-da2492e34dad + InitMqttDiscoveryAsSiren @@ -18118,7 +17483,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326552503645 + 638133836329948382 @@ -18127,37 +17492,117 @@ 3 - THIS^.timerData.PT := DataPollingInterval; + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - THIS^.SDM120AndSDM220RtuQuery.DeviceId := DeviceAddress; + 5 - THIS^.SDM630RtuQuery.DeviceId := DeviceAddress; + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - THIS^.timerData.IN := TRUE; + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - THIS^.DeviceType := DeviceType; + ELSE 8 + id := overruleId; // 'MY_PH_GND_HALL_01' + + + 9 + + END_IF + + + 10 + + + + + 11 + + Device^.CreateSirenEntity( + + + 12 + + Name := name, + + + 13 + + Id := id, + + + 14 + + Meta := meta, + + + 15 + + CommandTopic := THIS^.MQTTSubscribeTopic, + + + 16 + + PayloadOn := BOOL_TO_STRING(NOT(Invert)), + + + 17 + + PayloadOff := BOOL_TO_STRING(Invert), + + + 18 + + StateTopic := THIS^.MQTTPublishTopic, + + + 19 + + StateOnPayload := BOOL_TO_STRING(NOT(Invert)), + + + 20 + + StateOffPayload := BOOL_TO_STRING(Invert) + + + 21 + + ); + + + 22 + + + + + 23 + + + 24 + + initMqttDiscoveryDone := TRUE; + 2 - THIS^.InitRS485Done := TRUE; + END_IF @@ -18166,32 +17611,57 @@ - 9 + 25 - METHOD InitRS485 + METHOD InitMqttDiscoveryAsSiren - 10 + 26 VAR_INPUT - 11 + 27 - DataPollingInterval: TIME; + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - 12 + 28 - DeviceAddress: BYTE; + Name: STRING(255); - 13 + 29 - DeviceType: RS485_EASTRON_SDM_Devices; + overruleId: STRING(255) := ''; - 14 + 30 + + meta: STRING(255) := ''; + + + 31 + + Invert: BOOL := FALSE; + + + 32 + + END_VAR + + + 33 + + VAR + + + 34 + + id: STRING(255); + + + 35 END_VAR @@ -18204,18 +17674,18 @@ - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + fb058f61-66e0-49ec-9946-da2492e34dad - FB_RS485_EASTRON_SDM_POWER_MQTT + FB_OUTPUT_BINARY_MQTT -1 False - 1a4d1912-d02c-4e04-92e8-871ffaac1da6 - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 - ProcessDataArray + 913d0ffa-3c04-4e38-9103-5b4ab79620bb + fb058f61-66e0-49ec-9946-da2492e34dad + InitMqttDiscoveryAsSwitch @@ -18239,7 +17709,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326552872370 + 638133836328798327 @@ -18248,97 +17718,112 @@ 3 - THIS^.Error := Error^; + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - THIS^.timerData.IN := TRUE; + 5 - + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - IF Error^ THEN + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - PubMqttMessage(Suffix := '/availability', Data := 'offline'); + ELSE 8 - ELSE + id := overruleId; // 'MY_PH_GND_HALL_01' 9 - PubMqttMessage(Suffix := '/availability', Data := 'online'); + END_IF 10 - END_IF + 11 - + Device^.CreateSwitchEntity( 12 - IF NOT Error^ THEN + Name := name, 13 - THIS^.ACTIVEPOWER := SwapWordsToReal(Data^[0], Data^[1]); + Id := id, 14 - THIS^.isDataUpdated := TRUE; + Meta := meta, 15 - END_IF + CommandTopic := THIS^.MQTTSubscribeTopic, 16 - + PayloadOn := BOOL_TO_STRING(NOT(Invert)), 17 - ActiveDevice := FALSE; + PayloadOff := BOOL_TO_STRING(Invert), 18 - + StateTopic := THIS^.MQTTPublishTopic, 19 - + StateOnPayload := BOOL_TO_STRING(NOT(Invert)), 20 - + StateOffPayload := BOOL_TO_STRING(Invert), + + + 21 + + DeviceClass := DeviceClass); + + + 22 + + + + + 23 + + initMqttDiscoveryDone := TRUE; 2 - + END_IF @@ -18347,27 +17832,62 @@ - 21 + 24 - METHOD ProcessDataArray + METHOD InitMqttDiscoveryAsSwitch - 22 + 25 VAR_INPUT - 23 + 26 - Error: POINTER TO BOOL; + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - 24 + 27 - Data: POINTER TO ARRAY[0..124] OF WORD; + Name: STRING(255); - 25 + 28 + + DeviceClass: STRING(100) := 'outlet'; + + + 29 + + overruleId: STRING(255) := ''; + + + 30 + + meta: STRING(255) := ''; + + + 31 + + Invert: BOOL := FALSE; + + + 32 + + END_VAR + + + 33 + + VAR + + + 34 + + id: STRING(255); + + + 35 END_VAR @@ -18380,18 +17900,18 @@ - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + fb058f61-66e0-49ec-9946-da2492e34dad - FB_RS485_EASTRON_SDM_POWER_MQTT + FB_OUTPUT_BINARY_MQTT -1 False - 236983d6-b20a-4991-811a-245d9ab2ffdb - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 - PubMqttMessage + 81f7626c-c2a1-41aa-a542-77b9cb4433b4 + fb058f61-66e0-49ec-9946-da2492e34dad + PublishReceived @@ -18415,7 +17935,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326551139504 + 638133836328427980 @@ -18424,42 +17944,102 @@ 3 - IF InitMqttDone THEN + //first check if Mqtt is initialized, otherwise do nothing 4 - pMqttPublishQueue^.AddMessage( + IF NOT(InitMqttDone) THEN 5 - Payload := Data, + //mark the interface call from the collector as done 6 - Topic := CONCAT(CONCAT(MqttPublishTopicPrefix^, MqttPublishTopicSuffix), Suffix ), + PublishReceived := TRUE; 7 - Qos := MQTT.QoS.ExactlyOnce, + //check if the packet is for this FB 8 - MqttRetain := FALSE + 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('TRUE')) THEN + + + 13 + + MqttHighRequest := TRUE; + + + 14 + + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN + + + 15 + + MqttLowRequest := TRUE; + + + 16 + + // Siren sends out a JSON + + + 17 + + ELSIF FIND(Data.PayloadString^, 'TRUE') > 0 THEN + + + 18 + + MqttHighRequest := TRUE; + + + 19 + + ELSIF FIND(Data.PayloadString^, 'FALSE') > 0 THEN + + + 20 + + MqttLowRequest := TRUE; + + + 21 + + END_IF 2 - END_IF + END_IF @@ -18468,27 +18048,27 @@ - 10 + 22 - METHOD PubMqttMessage + METHOD PublishReceived : BOOL - 11 + 23 VAR_INPUT - 12 + 24 - Suffix: STRING(100); + ///Collection of recived Data - 13 + 25 - Data: STRING(100); + Data: MQTT.CALLBACK_DATA; - 14 + 26 END_VAR @@ -18501,18 +18081,18 @@ - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + fb058f61-66e0-49ec-9946-da2492e34dad - FB_RS485_EASTRON_SDM_POWER_MQTT + FB_OUTPUT_BINARY_MQTT -1 False - bb158147-189d-4cd6-829c-e3f886d74bf4 - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 - RequestBusTime + 55e7a1f0-16ac-4a55-a71b-474a70737fff + 7ab5f4f2-a03c-498e-b52e-ac3df962622c + ConfigureFunctionBlock @@ -18536,57 +18116,47 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326551850643 + 638133836331317982 + + + + 2 + + THIS^.T_hold:=T_hold; + + + + + 3 - IF NOT InitRS485Done THEN + METHOD ConfigureFunctionBlock 4 - RequestBusTime := FALSE; + VAR_INPUT 5 - ELSIF timerData.Q THEN + /// Default value for click mode, can be overwritten by method call 6 - RequestBusTime := TRUE; + T_hold: TIME; 7 - ELSE - - - 8 - - RequestBusTime := FALSE; - - - 2 - - END_IF - - - - - - - - - 9 - - METHOD RequestBusTime : BOOL + END_VAR 1 @@ -18597,18 +18167,18 @@ - b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + 7ab5f4f2-a03c-498e-b52e-ac3df962622c - FB_RS485_EASTRON_SDM_POWER_MQTT + FB_OUTPUT_BISTABLE_MQTT -1 False - c2816008-578a-495d-aa59-42fedf1bc654 - 98167287-8297-40e7-8354-c4ecab8b3787 - GetRtuQuery + 46d9c133-c77a-4e46-be08-dee91433ee62 + 7ab5f4f2-a03c-498e-b52e-ac3df962622c + InitMqtt @@ -18632,7 +18202,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326556987689 + 638133836332047995 @@ -18641,67 +18211,72 @@ 3 - IF timerData1.Q THEN + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important 4 - THIS^.timerData1.IN := FALSE; + 5 - THIS^.ActiveRtuQuery := 1; + (*pass trough*) 6 - GetRtuQuery := THIS^.Data1RtuQuery; + THIS^.pMqttPublishQueue := pMqttPublishQueue; 7 - ELSIF timerData2.Q THEN + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; 8 - THIS^.timerData2.IN := FALSE; + THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; 9 - THIS^.ActiveRtuQuery := 2; + THIS^.pMqttPublishQueue:=pMqttPublishQueue; 10 - GetRtuQuery := THIS^.Data2RtuQuery; + 11 - ELSIF timerData3.Q THEN + 12 - THIS^.timerData3.IN := FALSE; + 13 - THIS^.ActiveRtuQuery := 3; + SUPER^.InitBaseMqtt(); 14 - GetRtuQuery := THIS^.Data3RtuQuery; + pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + + + 15 + + 2 - END_IF + @@ -18710,9 +18285,39 @@ - 15 + 16 - METHOD GetRtuQuery : RS485_RtuQuery + METHOD InitMqtt + + + 17 + + VAR_INPUT + + + 18 + + MQTTPublishPrefix: POINTER TO STRING; + + + 19 + + MQTTSubscribePrefix: POINTER TO STRING; + + + 20 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 21 + + pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + + + 22 + + END_VAR 1 @@ -18723,18 +18328,18 @@ - 98167287-8297-40e7-8354-c4ecab8b3787 + 7ab5f4f2-a03c-498e-b52e-ac3df962622c - FB_RS485_EASTRON_SDM220_MQTT + FB_OUTPUT_BISTABLE_MQTT -1 False - 58603822-6916-4088-ad30-98dcf6b9779b - 98167287-8297-40e7-8354-c4ecab8b3787 - InitMqtt + 8ef29c27-bcb9-4c6c-8309-d23ab3c28c7b + 7ab5f4f2-a03c-498e-b52e-ac3df962622c + InitMqttDiscoveryAsLight @@ -18758,7 +18363,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326557711312 + 638133836333237979 @@ -18767,37 +18372,97 @@ 3 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; + 5 - + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(THIS^.InstanceName)) + 1; + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - THIS^.MqttPublishTopicSuffix := InstanceNamePt^; + ELSE 8 + id := overruleId; // 'MY_PH_GND_HALL_01' + + + 9 + + END_IF + + + 10 + + + + + 11 + + Device^.CreateLightEntity( + + + 12 + + Name := name, + + + 13 + + Id := id, + + + 14 + + Meta := meta, + + + 15 + + CommandTopic := THIS^.MQTTSubscribeTopic, + + + 16 + + PayloadOn := BOOL_TO_STRING(NOT(Invert)), + + + 17 + + PayloadOff := BOOL_TO_STRING(Invert), + + + 18 + + StateTopic := THIS^.MQTTPublishTopic); + + + 19 + + + 20 + + initMqttDiscoveryDone := TRUE; + 2 - THIS^.InitMqttDone := TRUE; + END_IF @@ -18806,42 +18471,57 @@ - 9 + 21 - METHOD InitMqtt + METHOD InitMqttDiscoveryAsLight - 10 + 22 VAR_INPUT - 11 + 23 - MQTTPublishPrefix: POINTER TO STRING; + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - 12 + 24 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + Name: STRING(255); - 13 + 25 + + overruleId: STRING(255) := ''; + + + 26 + + meta: STRING(255) := ''; + + + 27 + + Invert: BOOL := FALSE; + + + 28 END_VAR - 14 + 29 VAR - 15 + 30 - InstanceNamePt: POINTER TO STRING; + id: STRING(255); - 16 + 31 END_VAR @@ -18854,18 +18534,18 @@ - 98167287-8297-40e7-8354-c4ecab8b3787 + 7ab5f4f2-a03c-498e-b52e-ac3df962622c - FB_RS485_EASTRON_SDM220_MQTT + FB_OUTPUT_BISTABLE_MQTT -1 False - 49f1ae77-1980-43b6-84f7-f34c3c47b446 - 98167287-8297-40e7-8354-c4ecab8b3787 - InitRS485 + 7edb92de-841b-432e-a92d-7e51a09fe507 + 7ab5f4f2-a03c-498e-b52e-ac3df962622c + InitMqttDiscoveryAsLock @@ -18889,7 +18569,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326558020197 + 638133836332808001 @@ -18898,67 +18578,107 @@ 3 - THIS^.timerData1.PT := Data1PollingInterval; + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - THIS^.timerData2.PT := Data2PollingInterval; + 5 - THIS^.timerData3.PT := Data3PollingInterval; + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - THIS^.Data1RtuQuery.DeviceId := DeviceAddress; + ELSE 8 - THIS^.Data2RtuQuery.DeviceId := DeviceAddress; + id := overruleId; // 'MY_PH_GND_HALL_01' 9 - THIS^.Data3RtuQuery.DeviceId := DeviceAddress; + END_IF 10 - + 11 - THIS^.timerData1.IN := TRUE; + Device^.CreateLockEntity( 12 - THIS^.timerData2.IN := TRUE; + Name := name, 13 - THIS^.timerData3.IN := TRUE; + Id := id, 14 + Meta := meta, + + + 15 + + CommandTopic := THIS^.MQTTSubscribeTopic, + + + 16 + + PayloadLock := BOOL_TO_STRING(NOT(Invert)), + + + 17 + + PayloadUnlock := BOOL_TO_STRING(Invert), + + + 18 + + StateTopic := THIS^.MQTTPublishTopic, + + + 19 + + StateUnlocked := BOOL_TO_STRING(Invert), + + + 20 + + StateLocked := BOOL_TO_STRING(NOT(Invert))); + + + 21 + + + 22 + + initMqttDiscoveryDone := TRUE; + 2 - THIS^.InitRS485Done := TRUE; + END_IF @@ -18967,37 +18687,57 @@ - 15 + 23 - METHOD InitRS485 + METHOD InitMqttDiscoveryAsLock - 16 + 24 VAR_INPUT - 17 + 25 - Data1PollingInterval: TIME; + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - 18 + 26 - Data2PollingInterval: TIME; + Name: STRING(255); - 19 + 27 - Data3PollingInterval: TIME; + overruleId: STRING(255) := ''; - 20 + 28 - DeviceAddress: BYTE; + meta: STRING(255) := ''; - 21 + 29 + + Invert: BOOL := FALSE; + + + 30 + + END_VAR + + + 31 + + VAR + + + 32 + + id: STRING(255); + + + 33 END_VAR @@ -19010,18 +18750,18 @@ - 98167287-8297-40e7-8354-c4ecab8b3787 + 7ab5f4f2-a03c-498e-b52e-ac3df962622c - FB_RS485_EASTRON_SDM220_MQTT + FB_OUTPUT_BISTABLE_MQTT -1 False - 3a56402d-d2dc-4680-b04d-d8167fb5c466 - 98167287-8297-40e7-8354-c4ecab8b3787 - ProcessDataArray + 5458037e-216a-4f29-8f1d-1acb792138ad + 7ab5f4f2-a03c-498e-b52e-ac3df962622c + InitMqttDiscoveryAsSiren @@ -19045,7 +18785,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326558409549 + 638133836332438013 @@ -19054,262 +18794,172 @@ 3 - IF Error^ THEN + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - PubMqttMessage(Suffix := '/availability', Data := 'offline'); + 5 - ELSE + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - PubMqttMessage(Suffix := '/availability', Data := 'online'); + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - END_IF + ELSE 8 - + id := overruleId; // 'MY_PH_GND_HALL_01' 9 - IF ActiveRtuQuery = 1 THEN + END_IF 10 - THIS^.Error1 := Error^; + 11 - THIS^.timerData1.IN := TRUE; + Device^.CreateSirenEntity( 12 - IF NOT Error^ THEN + Name := name, 13 - THIS^.VOLTAGE := SwapWordsToReal(Data^[0], Data^[1]); + Id := id, 14 - THIS^.CURRENT := SwapWordsToReal(Data^[6], Data^[7]); + Meta := meta, 15 - THIS^.ACTIVEPOWER := SwapWordsToReal(Data^[12], Data^[13]); + CommandTopic := THIS^.MQTTSubscribeTopic, 16 - THIS^.APPARENT_POWER := SwapWordsToReal(Data^[18], Data^[19]); + PayloadOn := BOOL_TO_STRING(NOT(Invert)), 17 - THIS^.REACTIVE_POWER := SwapWordsToReal(Data^[24], Data^[25]); + PayloadOff := BOOL_TO_STRING(Invert), 18 - THIS^.POWER_FACTOR := SwapWordsToReal(Data^[30], Data^[31]); + StateTopic := THIS^.MQTTPublishTopic, 19 - THIS^.PHASE_ANGLE := SwapWordsToReal(Data^[36], Data^[37]); + StateOnPayload := BOOL_TO_STRING(NOT(Invert)), 20 - THIS^.Update1 := TRUE; + StateOffPayload := BOOL_TO_STRING(Invert) 21 - END_IF + ); 22 - ELSIF ActiveRtuQuery = 2 THEN + 23 - THIS^.Error2:= Error^; + initMqttDiscoveryDone := TRUE; + + 2 + + END_IF + + + + + + + 24 - THIS^.timerData2.IN := TRUE; + METHOD InitMqttDiscoveryAsSiren 25 - IF NOT Error^ THEN + VAR_INPUT 26 - THIS^.FREQUENCY := SwapWordsToReal(Data^[0], Data^[1]); + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; 27 - THIS^.IMPORT_ACTIVE_ENERGY := SwapWordsToReal(Data^[2], Data^[3]); + Name: STRING(255); 28 - THIS^.EXPORT_ACTIVE_ENERGY := SwapWordsToReal(Data^[4], Data^[5]); + overruleId: STRING(255) := ''; 29 - THIS^.IMPORT_REACTIVE_ENERGY := SwapWordsToReal(Data^[6], Data^[7]); + meta: STRING(255) := ''; 30 - THIS^.EXPORT_REACTIVE_ENERGY := SwapWordsToReal(Data^[8], Data^[9]); + Invert: BOOL := FALSE; 31 - THIS^.Update2 := TRUE; + END_VAR 32 - END_IF + VAR 33 - ELSIF ActiveRtuQuery = 3 THEN + id: STRING(255); 34 - THIS^.Error3 := Error^; - - - 35 - - THIS^.timerData3.IN := TRUE; - - - 36 - - IF NOT Error^ THEN - - - 37 - - THIS^.TOTAL_ACTIVE_ENERGY := SwapWordsToReal(Data^[0], Data^[1]); - - - 38 - - THIS^.TOTAL_REACTIVE_ENERGY := SwapWordsToReal(Data^[2], Data^[3]); - - - 39 - - THIS^.Update3 := TRUE; - - - 40 - - END_IF - - - 41 - - END_IF - - - 42 - - - - - 43 - - ActiveRtuQuery := 0; - - - 44 - - ActiveDevice := FALSE; - - - 45 - - - - - 46 - - - - - 47 - - - - - 2 - - - - - - - - - - - 48 - - METHOD ProcessDataArray - - - 49 - - VAR_INPUT - - - 50 - - Error: POINTER TO BOOL; - - - 51 - - Data: POINTER TO ARRAY[0..124] OF WORD; - - - 52 - END_VAR @@ -19321,18 +18971,18 @@ - 98167287-8297-40e7-8354-c4ecab8b3787 + 7ab5f4f2-a03c-498e-b52e-ac3df962622c - FB_RS485_EASTRON_SDM220_MQTT + FB_OUTPUT_BISTABLE_MQTT -1 False - 08adb491-aa8b-4186-8b2d-ca29e654144e - 98167287-8297-40e7-8354-c4ecab8b3787 - PubMqttMessage + 093e60e6-20ca-4487-ac0d-483abb782562 + 7ab5f4f2-a03c-498e-b52e-ac3df962622c + InitMqttDiscoveryAsSwitch @@ -19356,7 +19006,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326556688501 + 638133836330988029 @@ -19365,158 +19015,112 @@ 3 - IF InitMqttDone THEN + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - pMqttPublishQueue^.AddMessage( + 5 - Payload := Data, + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - Topic := CONCAT(CONCAT(MqttPublishTopicPrefix^, MqttPublishTopicSuffix), Suffix ), + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - Qos := MQTT.QoS.ExactlyOnce, + ELSE 8 - MqttRetain := FALSE + id := overruleId; // 'MY_PH_GND_HALL_01' 9 - ); + END_IF - 2 + 10 - END_IF - - - - - - - - - 10 - - METHOD PubMqttMessage + 11 - VAR_INPUT + Device^.CreateSwitchEntity( 12 - Suffix: STRING(100); + Name := name, 13 - Data: STRING(100); + Id := id, 14 - END_VAR + Meta := meta, - 1 + 15 - + CommandTopic := THIS^.MQTTSubscribeTopic, - - - - - 98167287-8297-40e7-8354-c4ecab8b3787 - - FB_RS485_EASTRON_SDM220_MQTT - - -1 - - - False - - 0adc2936-dc0e-49ef-a6e0-71608dca83d8 - 98167287-8297-40e7-8354-c4ecab8b3787 - RequestBusTime - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 16 + + PayloadOn := BOOL_TO_STRING(NOT(Invert)), - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638103326557296851 - - - - - - 3 + 17 - IF NOT InitRS485Done THEN + PayloadOff := BOOL_TO_STRING(Invert), - 4 + 18 - RequestBusTime := FALSE; + StateTopic := THIS^.MQTTPublishTopic, - 5 + 19 - ELSIF timerData1.Q OR timerData2.Q OR timerData3.Q THEN + StateOnPayload := BOOL_TO_STRING(NOT(Invert)), - 6 + 20 - RequestBusTime := TRUE; + StateOffPayload := BOOL_TO_STRING(Invert), - 7 + 21 - ELSE + DeviceClass := DeviceClass); - 8 + 22 - RequestBusTime := FALSE; + + + + 23 + + initMqttDiscoveryDone := TRUE; 2 - END_IF + END_IF @@ -19525,113 +19129,62 @@ - 9 + 24 - METHOD RequestBusTime : BOOL + METHOD InitMqttDiscoveryAsSwitch - 1 + 25 - - - - - - - 98167287-8297-40e7-8354-c4ecab8b3787 - - FB_RS485_EASTRON_SDM220_MQTT - - -1 - - - False - - 7b0676a2-9810-4121-b9d6-24902c186aa9 - c15e7142-c256-438c-b11e-9d0e3b37e53c - EnableOwd - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + VAR_INPUT - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638103326559292346 - - - - - - 3 + 26 - THIS^.OwdDevices[OwdNumber].InitOwd( + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - 4 + 27 - DeviceAddress := THIS^.DeviceAddress, + Name: STRING(255); - 5 + 28 - OwdNumber := OwdNumber, + DeviceClass: STRING(100) := 'outlet'; - 6 + 29 - DataPollingInterval := DataPollingInterval + overruleId: STRING(255) := ''; - 2 + 30 - ); + meta: STRING(255) := ''; - - - - - - - 7 + 31 - METHOD EnableOwd : BOOL + Invert: BOOL := FALSE; - 8 + 32 - VAR_INPUT + END_VAR - 9 + 33 - OwdNumber: UINT; + VAR - 10 + 34 - DataPollingInterval: TIME; + id: STRING(255); - 11 + 35 END_VAR @@ -19644,18 +19197,18 @@ - c15e7142-c256-438c-b11e-9d0e3b37e53c + 7ab5f4f2-a03c-498e-b52e-ac3df962622c - FB_RS485_ESERA_1WIRE_GATEWAY_MQTT + FB_OUTPUT_BISTABLE_MQTT -1 False - 0856600a-7f45-4285-bb29-6e9efc3545ab - c15e7142-c256-438c-b11e-9d0e3b37e53c - GetRtuQuery + 696ea1d5-94e6-4b86-8800-ca912c6b644d + 7ab5f4f2-a03c-498e-b52e-ac3df962622c + PublishReceived @@ -19679,7 +19232,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326561038294 + 638133836331648012 @@ -19688,172 +19241,131 @@ 3 - IF timerData.Q THEN + //first check if Mqtt is initialized, otherwise do nothing 4 - THIS^.timerData.IN := FALSE; + IF NOT(InitMqttDone) THEN 5 - GetRtuQuery := THIS^.OwdDevices[ActiveOwd].GetRtuQuery(); + //mark the interface call from the collector as done - 2 + 6 - END_IF + PublishReceived := TRUE; - - - - - - - 6 + 7 - METHOD GetRtuQuery : RS485_RtuQuery + //check if the packet is for this FB - 1 + 8 - + ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN - - - - - c15e7142-c256-438c-b11e-9d0e3b37e53c - - FB_RS485_ESERA_1WIRE_GATEWAY_MQTT - - -1 - - - False - - 3ce96a37-22ea-45e4-89b6-c39dd2524835 - c15e7142-c256-438c-b11e-9d0e3b37e53c - InitMqtt - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 9 + + //mark the interface call from the collector as done - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638103326559596741 - - - - - - 3 + 10 - InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(THIS^.InstanceName)) + 1; + PublishReceived := TRUE; - 4 + 11 - + //now process the data - 5 + 12 - FOR loopCounter := 1 TO 30 DO + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('TRUE')) THEN - 6 + 13 - OwdDevices[loopCounter].InitMqtt( + MqttHighRequest := TRUE; - 7 + 14 - MQTTPublishPrefix := MQTTPublishPrefix, + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN - 8 + 15 - MqttPublishTopicSuffix := InstanceNamePt^, + MqttLowRequest := TRUE; - 9 + 16 - pMqttPublishQueue := pMqttPublishQueue + // Siren sends out a JSON - 10 + 17 - ); + ELSIF FIND(Data.PayloadString^, 'TRUE') > 0 THEN - 2 + 18 - END_FOR + MqttHighRequest := TRUE; - - - - - - - 11 + 19 - METHOD InitMqtt + ELSIF FIND(Data.PayloadString^, 'FALSE') > 0 THEN - 12 + 20 - VAR_INPUT + MqttLowRequest := TRUE; - 13 + 21 - MQTTPublishPrefix: POINTER TO STRING; + END_IF - 14 + 2 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + END_IF + + + + + + - 15 + 22 - END_VAR + METHOD PublishReceived : BOOL - 16 + 23 - VAR + VAR_INPUT - 17 + 24 - InstanceNamePt: POINTER TO STRING; + ///Collection of recived Data - 18 + 25 + + Data: MQTT.CALLBACK_DATA; + + + 26 END_VAR @@ -19866,18 +19378,18 @@ - c15e7142-c256-438c-b11e-9d0e3b37e53c + 7ab5f4f2-a03c-498e-b52e-ac3df962622c - FB_RS485_ESERA_1WIRE_GATEWAY_MQTT + FB_OUTPUT_BISTABLE_MQTT -1 False - 10298b50-6428-498d-8112-32867d4ed647 - c15e7142-c256-438c-b11e-9d0e3b37e53c - InitRS485 + 1bf75fcd-baec-4e6b-99a5-eac88b92fc98 + a78cae3d-77db-4556-bb78-ee45b5903249 + ConfigureFunctionBlock @@ -19901,7 +19413,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326559915889 + 638115483684817847 @@ -19910,22 +19422,12 @@ 3 - THIS^.DeviceAddress := DeviceAddress; - - - 4 - - THIS^.timerData.PT := T#250MS; - - - 5 - - THIS^.timerData.IN := TRUE; + THIS^.T_LOCKOUT:=T_LOCKOUT; 2 - THIS^.InitRS485Done := TRUE; + THIS^.T_UD:=T_UD; @@ -19934,22 +19436,27 @@ - 6 + 4 - METHOD InitRS485 + METHOD ConfigureFunctionBlock : BOOL - 7 + 5 VAR_INPUT - 8 + 6 - DeviceAddress: BYTE; + T_LOCKOUT: TIME; - 9 + 7 + + T_UD: TIME; + + + 8 END_VAR @@ -19962,18 +19469,18 @@ - c15e7142-c256-438c-b11e-9d0e3b37e53c + a78cae3d-77db-4556-bb78-ee45b5903249 - FB_RS485_ESERA_1WIRE_GATEWAY_MQTT + FB_OUTPUT_COVER_MQTT -1 False - fe3be894-5278-47fa-832e-b328d4129c95 - c15e7142-c256-438c-b11e-9d0e3b37e53c - ProcessDataArray + d7ec667b-b145-4daa-9ed9-dc4af7254830 + a78cae3d-77db-4556-bb78-ee45b5903249 + InitMqtt @@ -19997,7 +19504,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326560739083 + 638115483684158237 @@ -20006,32 +19513,52 @@ 3 - THIS^.OwdDevices[ActiveOwd].ProcessDataArray( + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important 4 - Data := Data, + 5 - Error := Error + (*pass trough*) 6 - ); + THIS^.pMqttPublishQueue := pMqttPublishQueue; 7 - THIS^.ActiveOwd := 0; + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + + + 8 + + THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; + + + 9 + + THIS^.pMqttPublishQueue:=pMqttPublishQueue; + + + 10 + + + + + 11 + + SUPER^.InitBaseMqtt(); 2 - THIS^.timerData.IN := TRUE; + pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received @@ -20040,27 +19567,52 @@ - 8 + 12 - METHOD ProcessDataArray + METHOD InitMqtt - 9 + 13 VAR_INPUT - 10 + 14 - Error: POINTER TO BOOL; + MQTTPublishPrefix: POINTER TO STRING; - 11 + 15 - Data: POINTER TO ARRAY[0..124] OF WORD; + MQTTSubscribePrefix: POINTER TO STRING; - 12 + 16 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 17 + + pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + + + 18 + + END_VAR + + + 19 + + VAR + + + 20 + + InstanceNamePt: POINTER TO STRING; + + + 21 END_VAR @@ -20073,18 +19625,18 @@ - c15e7142-c256-438c-b11e-9d0e3b37e53c + a78cae3d-77db-4556-bb78-ee45b5903249 - FB_RS485_ESERA_1WIRE_GATEWAY_MQTT + FB_OUTPUT_COVER_MQTT -1 False - d7d7dd9c-7520-42fb-b2aa-d2e6b17e41a6 - c15e7142-c256-438c-b11e-9d0e3b37e53c - RequestBusTime + 742b01b6-131d-448e-a18f-8de8995e02d6 + a78cae3d-77db-4556-bb78-ee45b5903249 + InitMqttDiscovery @@ -20108,7 +19660,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326560435031 + 638115483685217844 @@ -20117,219 +19669,122 @@ 3 - IF NOT InitRS485Done OR NOT timerData.Q THEN + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN 4 - RequestBusTime := FALSE; + 5 - ELSE + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - FOR loopCounter := 1 TO 30 DO + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - IF OwdDevices[loopCounter].RequestBusTime() AND RequestBusTime = FALSE THEN + ELSE 8 - THIS^.ActiveOwd := loopCounter; + id := overruleId; // 'MY_PH_GND_HALL_01' 9 - RequestBusTime := TRUE; + END_IF 10 - END_IF + 11 - END_FOR + Device^.CreateCoverEntity( - 2 + 12 - END_IF + Name := name, - - - - - - - 12 + 13 - METHOD RequestBusTime : BOOL + Id := id, - 1 + 14 - - - - - - - c15e7142-c256-438c-b11e-9d0e3b37e53c - - FB_RS485_ESERA_1WIRE_GATEWAY_MQTT - - -1 - - - False - - 125cd1a1-e4a7-4a9c-b461-8d489a6c7555 - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - GetRtuQuery - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + Meta := meta, - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638103326563013438 - - - - - - 3 + 15 - IF timerData.Q THEN + CommandTopic := THIS^.MQTTSubscribeTopic, - 4 + 16 - THIS^.timerData.IN := FALSE; + PayloadOpen := 'OPEN', - 5 + 17 - GetRtuQuery := THIS^.RtuQuery; + PayloadClose := 'CLOSE', - 2 + 18 - END_IF + PayloadStop := 'STOP', - - - - - - - 6 + 19 - METHOD GetRtuQuery : RS485_RtuQuery + StateTopic := THIS^.MQTTPublishTopic, - 1 + 20 - - - - - - - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - - FB_RS485_ESERA_OWD_MQTT - - -1 - - - False - - 55a394b4-67ce-4a17-ab8f-9c31c5283299 - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - InitMqtt - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + StateOpen := 'OPEN', - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638103326565363788 - - - - - - 3 + 21 - THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; + StateClosed := 'CLOSED', - 4 + 22 - THIS^.MqttPublishTopicSuffix := MqttPublishTopicSuffix; + DeviceClass := DeviceClass - 5 + 23 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + ); - 6 + 24 + + 25 + + initMqttDiscoveryDone := TRUE; + 2 - THIS^.InitMqttDone := TRUE; + END_IF @@ -20338,32 +19793,57 @@ - 7 + 26 - METHOD InitMqtt + METHOD InitMqttDiscovery - 8 + 27 VAR_INPUT - 9 + 28 - MQTTPublishPrefix: POINTER TO STRING; + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - 10 + 29 - MqttPublishTopicSuffix: STRING(255); + Name: STRING(255); - 11 + 30 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + overruleId: STRING(255) := ''; - 12 + 31 + + meta: STRING(255) := ''; + + + 32 + + DeviceClass: STRING(50) := 'shutter'; + + + 33 + + END_VAR + + + 34 + + VAR + + + 35 + + id: STRING(255); + + + 36 END_VAR @@ -20376,18 +19856,18 @@ - bb58f587-9f45-44a1-8ab8-a2a557be2a09 + a78cae3d-77db-4556-bb78-ee45b5903249 - FB_RS485_ESERA_OWD_MQTT + FB_OUTPUT_COVER_MQTT -1 False - fcd9e993-4d76-42d3-bf14-28b914b97012 - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - InitOwd + cb2a9447-21b5-4579-addb-f9df7cecaa34 + a78cae3d-77db-4556-bb78-ee45b5903249 + PublishReceived @@ -20411,7 +19891,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326565670896 + 638115483684517851 @@ -20420,138 +19900,92 @@ 3 - THIS^.RtuQuery.DeviceId := DeviceAddress; + //first check if Mqtt is initialized, otherwise do nothing 4 - THIS^.RtuQuery.ReadAddress := OwdNumber * 100; + IF NOT(InitMqttDone) THEN 5 - THIS^.timerData.PT := DataPollingInterval; + //mark the interface call from the collector as done 6 - THIS^.OwdNumber := OwdNumber; + PublishReceived := TRUE; 7 - + //check if the packet is for this FB 8 - THIS^.timerData.IN := TRUE; + ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN 9 - - - - 2 - - THIS^.InitOwdDone := TRUE; + //mark the interface call from the collector as done - - - - - - 10 - METHOD InitOwd + PublishReceived := TRUE; 11 - VAR_INPUT + //now process the data 12 - DeviceAddress: BYTE; + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('STOP')) THEN 13 - OwdNumber: UINT; + THIS^.MqttRequestStop:=TRUE; 14 - DataPollingInterval: TIME; + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('OPEN')) THEN 15 - END_VAR + THIS^.MqttRequestOpen:=TRUE; - 1 + 16 - + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('CLOSE')) THEN - - - - - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - - FB_RS485_ESERA_OWD_MQTT - - -1 - - - False - - cff06864-4642-47d5-9c82-c5d5ed2296f0 - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - ProcessAirQuality - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 17 + + THIS^.MqttRequestClose:=TRUE; - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638103326563402432 - - - - - - 3 + 18 - THIS^.AIR_QUALITY := WORD_TO_REAL(Data) / 100; + END_IF + + + 19 + + 2 - PubMqttMessage(Suffix := '/AIRQ', Data := REAL_TO_STRING(AIR_QUALITY)); + END_IF @@ -20560,22 +19994,27 @@ - 4 + 20 - METHOD ProcessAirQuality + METHOD PublishReceived : BOOL - 5 + 21 VAR_INPUT - 6 + 22 - Data: WORD; + ///Collection of recived Data - 7 + 23 + + Data: MQTT.CALLBACK_DATA; + + + 24 END_VAR @@ -20588,18 +20027,18 @@ - bb58f587-9f45-44a1-8ab8-a2a557be2a09 + a78cae3d-77db-4556-bb78-ee45b5903249 - FB_RS485_ESERA_OWD_MQTT + FB_OUTPUT_COVER_MQTT -1 False - 06c71a77-eb2e-4d37-9195-781eecfb0184 - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - ProcessBrigthness + f8dd8d24-fdd6-4d76-9b04-0c2a3bdd2731 + f1306b9c-42ee-45fa-892a-f187063e8d39 + ConfigureFunctionBlock @@ -20623,7 +20062,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326561990965 + 638115483686667844 @@ -20632,12 +20071,57 @@ 3 - THIS^.BRIGHTNESS := WORD_TO_REAL(Data) / 100; + THIS^.T_Debounce:=T_Debounce; + + + 4 + + THIS^.T_Reconfig:=T_Reconfig; + + + 5 + + THIS^.T_On_Max:=T_On_Max; + + + 6 + + THIS^.T_Dimm_Start:=T_Dimm_Start; + + + 7 + + THIS^.T_Dimm:=T_Dimm; + + + 8 + + THIS^.Min_On:=Min_On; + + + 9 + + THIS^.Max_On:=Max_On; + + + 10 + + THIS^.Soft_Dimm:=Soft_Dimm; + + + 11 + + THIS^.Rst_Out:=Rst_Out; + + + 12 + + THIS^.OUT_LinearScaleMin:=OUT_LinearScaleMin; 2 - PubMqttMessage(Suffix := '/BNESS', Data := REAL_TO_STRING(BRIGHTNESS)); + THIS^.OUT_LinearScaleMax:=OUT_LinearScaleMax; @@ -20646,22 +20130,77 @@ - 4 + 13 - METHOD ProcessBrigthness + METHOD ConfigureFunctionBlock - 5 + 14 VAR_INPUT - 6 + 15 - Data: WORD; + /// Default values for dimmer, can be overwritten by method call - 7 + 16 + + T_Debounce: TIME := TIME#10ms; + + + 17 + + T_Reconfig: TIME := TIME#10s0ms; + + + 18 + + T_On_Max: TIME := TIME#0ms; + + + 19 + + T_Dimm_Start: TIME := TIME#400ms; + + + 20 + + T_Dimm: TIME := TIME#3s0ms; + + + 21 + + Min_On: BYTE := 50; + + + 22 + + Max_On: BYTE := 255; + + + 23 + + Soft_Dimm: BOOL := TRUE; + + + 24 + + Rst_Out: BOOL := FALSE; + + + 25 + + OUT_LinearScaleMin: INT := 0; + + + 26 + + OUT_LinearScaleMax: INT := 32767; + + + 27 END_VAR @@ -20674,18 +20213,18 @@ - bb58f587-9f45-44a1-8ab8-a2a557be2a09 + f1306b9c-42ee-45fa-892a-f187063e8d39 - FB_RS485_ESERA_OWD_MQTT + FB_OUTPUT_DIMMER_MQTT -1 False - 63a3c0cc-3577-4959-b57e-a8f337569c73 - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - ProcessDataArray + 06c245c1-2220-4230-98c9-4adcfafaf41b + f1306b9c-42ee-45fa-892a-f187063e8d39 + initDMX @@ -20709,7 +20248,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326562694290 + 638115483687357849 @@ -20718,172 +20257,228 @@ 3 - THIS^.timerData.IN := TRUE; + 4 - + IF NOT THIS^.InitDmxDone THEN 5 - IF WORD_TO_INT(Data^[12]) <> 0 OR Error^ THEN + THIS^.DmxChannel := DmxChannel; 6 - THIS^.Error := TRUE; + THIS^.pDmxValues := pDmxValues; 7 - PubMqttMessage(Suffix := '/availability', Data := 'offline'); + THIS^.DmxWidth := DmxWidth; 8 - ELSE + THIS^.InitDmxDone := TRUE; 9 - THIS^.Error := FALSE; + 10 - THIS^.DataAvailable := TRUE; + THIS^.InitDmxDone := TRUE; + + + 2 + + END_IF + + + + + + 11 - PubMqttMessage(Suffix := '/availability', Data := 'online'); + METHOD initDMX 12 - END_IF + VAR_INPUT 13 - + DmxChannel: INT; 14 - // Data handling + DmxWidth: INT := 1; 15 - IF NOT Error^ AND WORD_TO_INT(Data^[12]) = 0 THEN + DmxUniverse: INT := 1; 16 - IF Data^[16] = 11151 OR Data^[16] = 11152 THEN // Temperature, humidity & air quality + pDmxValues: POINTER TO oscat_network.NETWORK_BUFFER_SHORT; 17 - ProcessTemperature(Data^[0]); + END_VAR - 18 + 1 - ProcessOwdVoltage(Data^[2]); + + + + + + + f1306b9c-42ee-45fa-892a-f187063e8d39 + + FB_OUTPUT_DIMMER_MQTT + + -1 + + + False + + b5055521-50eb-4976-b6d8-a46b1e71804c + f1306b9c-42ee-45fa-892a-f187063e8d39 + 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 + + 638115483687008233 + + + + + - 19 + 3 - ProcessHumidity(Data^[4]); + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important - 20 + 4 - ProcessDewPoint(Data^[6]); + - 21 + 5 - ProcessAirQuality(Data^[8]); + (*pass trough*) - 22 + 6 - ELSIF Data^[16] = 11102 OR Data^[16] = 11113 OR Data^[16] = 11120 OR Data^[16] = 11148 OR Data^[16] = 11150 OR Data^[16] = 11160 THEN // Temperature, humidity + THIS^.pMqttPublishQueue := pMqttPublishQueue; - 23 + 7 - ProcessTemperature(Data^[0]); + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; - 24 + 8 - ProcessOwdVoltage(Data^[2]); + THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; - 25 + 9 - ProcessHumidity(Data^[4]); + THIS^.pMqttPublishQueue:=pMqttPublishQueue; - 26 + 10 - ProcessDewPoint(Data^[6]); + - 27 + 11 - ELSIF Data^[16] = 11121 OR Data^[16] = 11132 OR Data^[16] = 11134 OR Data^[16] = 11135 THEN // Temperature, humidity, brightness + // Dimmer specific - 28 + 12 - ProcessTemperature(Data^[0]); + THIS^.OutputDimmer:=OutputDimmer; - 29 + 13 - ProcessOwdVoltage(Data^[2]); + THIS^.Qos_Dimm:=Qos_Dimm; - 30 + 14 - ProcessHumidity(Data^[4]); + THIS^.Delta_Dimm:=Delta_Dimm; - 31 + 15 - ProcessDewPoint(Data^[6]); + - 32 + 16 - ProcessBrigthness(Data^[8]); + - 33 + 17 - ELSIF Data^[16] = 1820 THEN // Temperature DS18B20 + SUPER^.InitBaseMqtt(); - 34 + 18 - ProcessTemperature(Data^[0]); + pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received - 35 + 19 - END_IF + 2 - END_IF + @@ -20892,27 +20487,57 @@ - 36 + 20 - METHOD ProcessDataArray + METHOD InitMqtt - 37 + 21 VAR_INPUT - 38 + 22 - Error: POINTER TO BOOL; + MQTTPublishPrefix: POINTER TO STRING; - 39 + 23 - Data: POINTER TO ARRAY[0..124] OF WORD; + MQTTSubscribePrefix: POINTER TO STRING; - 40 + 24 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 25 + + pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + + + 26 + + /// Dimmer specific + + + 27 + + OutputDimmer: BOOL; + + + 28 + + Qos_Dimm: MQTT.QoS; + + + 29 + + Delta_Dimm: INT; + + + 30 END_VAR @@ -20925,18 +20550,18 @@ - bb58f587-9f45-44a1-8ab8-a2a557be2a09 + f1306b9c-42ee-45fa-892a-f187063e8d39 - FB_RS485_ESERA_OWD_MQTT + FB_OUTPUT_DIMMER_MQTT -1 False - 8c8f2813-2f4a-4df1-95dc-59dc19ab5ad2 - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - ProcessDewPoint + 3374cc16-98f5-4f93-97c9-86ddbebe87ac + f1306b9c-42ee-45fa-892a-f187063e8d39 + InitMqttDiscovery @@ -20960,7 +20585,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326563717081 + 638115483687667845 @@ -20969,270 +20594,127 @@ 3 - THIS^.DEW_POINT := WORD_TO_REAL(Data) / 100; - - - 2 - - PubMqttMessage(Suffix := '/DEWP', Data := REAL_TO_STRING(DEW_POINT)); + IF InitMqttDone AND NOT initMqttDiscoveryDone THEN - - - - - - 4 - METHOD ProcessDewPoint + 5 - VAR_INPUT + IF CommonTypesAndFunctions.StrEquals(str1:= ADR(overruleId), str2:= ADR('')) THEN 6 - Data: WORD; + id := CONCAT(CONCAT(THIS^.DeviceName,'_'), THIS^.InstanceNamePt^); // 'FB_DI_PB_003' 7 - END_VAR + ELSE - 1 + 8 - + id := overruleId; // 'MY_PH_GND_HALL_01' - - - - - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - - FB_RS485_ESERA_OWD_MQTT - - -1 - - - False - - 5702621d-7d5f-4a48-854d-4968f2efcdb2 - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - ProcessHumidity - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 9 + + END_IF - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638103326564016301 - - - - - - 3 + 10 - THIS^.HUMIDITY := WORD_TO_REAL(Data) / 100; + - 2 + 11 - PubMqttMessage(Suffix := '/HUM', Data := REAL_TO_STRING(HUMIDITY)); + Device^.CreateLightDimmerEntity( - - - - - - - 4 + 12 - METHOD ProcessHumidity + Name := name, - 5 + 13 - VAR_INPUT + Id := Id, - 6 + 14 - Data: WORD; + Meta := meta, - 7 + 15 - END_VAR + CommandTopic := CONCAT(THIS^.MQTTSubscribeTopic,'/Q'), - 1 + 16 - + PayloadOn := 'TRUE', - - - - - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - - FB_RS485_ESERA_OWD_MQTT - - -1 - - - False - - b3097b74-e2b0-4c73-8487-3877a0e4876f - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - ProcessOwdVoltage - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 17 + + PayloadOff := 'FALSE', - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638103326564385326 - - - - - - 3 + 18 - THIS^.OWD_VOLTAGE := WORD_TO_REAL(Data) / 100; + StateTopic := CONCAT(THIS^.MQTTPublishTopic,'/Q'), - 2 + 19 - PubMqttMessage(Suffix := '/OWDV', Data := REAL_TO_STRING(OWD_VOLTAGE)); + BrightnessCommandTopic := CONCAT(THIS^.MQTTSubscribeTopic,'/OUT'), - - - - - - - 4 + 20 - METHOD ProcessOwdVoltage + BrightnessStateTopic := CONCAT(THIS^.MQTTPublishTopic,'/OUT'), - 5 + 21 - VAR_INPUT + BrightnessScale := 255, - 6 + 22 - Data: WORD; + DmxChannel := THIS^.DmxChannel, - 7 + 23 - END_VAR + DmxWidth := THIS^.DmxWidth, - 1 + 24 - + DmxUniverse := THIS^.DmxUniverse); - - - - - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - - FB_RS485_ESERA_OWD_MQTT - - -1 - - - False - - c1b68752-979e-4788-9004-48b10ba95341 - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - ProcessTemperature - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 25 + + - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638103326564689709 - - - - - - 3 + 26 - THIS^.TEMPERATURE := WORD_TO_REAL(Data) / 100; + initMqttDiscoveryDone := TRUE; 2 - PubMqttMessage(Suffix := '/TEMP', Data := REAL_TO_STRING(TEMPERATURE)); + END_IF @@ -21241,22 +20723,52 @@ - 4 + 27 - METHOD ProcessTemperature + METHOD InitMqttDiscovery - 5 + 28 VAR_INPUT - 6 + 29 - Data: WORD; + Device: POINTER TO FB_PLC_MQTT_DISCOVERY_DEVICE; - 7 + 30 + + Name: STRING(255); + + + 31 + + overruleId: STRING(255) := ''; + + + 32 + + meta: STRING(255) := ''; + + + 33 + + END_VAR + + + 34 + + VAR + + + 35 + + id: STRING(255); + + + 36 END_VAR @@ -21269,18 +20781,18 @@ - bb58f587-9f45-44a1-8ab8-a2a557be2a09 + f1306b9c-42ee-45fa-892a-f187063e8d39 - FB_RS485_ESERA_OWD_MQTT + FB_OUTPUT_DIMMER_MQTT -1 False - 4e0a7d55-976c-4313-8409-76258001bc03 - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - PubMqttMessage + 503a6124-4e59-42e8-9059-2d7d5153fa01 + f1306b9c-42ee-45fa-892a-f187063e8d39 + PublishReceived @@ -21304,7 +20816,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638103326564994739 + 638115483686338242 @@ -21313,355 +20825,167 @@ 3 - IF InitMqttDone THEN + //first check if Mqtt is initialized, otherwise do nothing 4 - pMqttPublishQueue^.AddMessage( + IF NOT(InitMqttDone) THEN 5 - Payload := Data, + //mark the interface call from the collector as done 6 - Topic := CONCAT(CONCAT(CONCAT(CONCAT(MqttPublishTopicPrefix^, MqttPublishTopicSuffix), '/OWD/'), UINT_TO_STRING(OwdNumber)), Suffix ), + PublishReceived := TRUE; 7 - Qos := MQTT.QoS.ExactlyOnce, + //check if the packet is for this FB 8 - MqttRetain := FALSE + ELSIF CONCAT(MQTTSubscribeTopic,'/Q') = Data.TopicOut^ THEN 9 - ); - - - 2 - - END_IF + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('TRUE')) THEN - - - - - - 10 - METHOD PubMqttMessage + MqttHighRequest := TRUE; 11 - VAR_INPUT + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN 12 - Suffix: STRING(100); + MqttLowRequest := TRUE; 13 - Data: STRING(100); + END_IF; 14 - END_VAR - - - 1 - - - - - - - - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - - FB_RS485_ESERA_OWD_MQTT - - -1 - - - False - - 10464a34-9abe-4168-80d1-f7c2fe7383fd - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - RequestBusTime - - - - 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 - - 638103326562369983 - - - - - - - 3 - - IF NOT InitOwdDone THEN - - - 4 - - RequestBusTime := FALSE; - - - 5 - - ELSIF timerData.Q THEN - - - 6 - - RequestBusTime := TRUE; - - - 7 - - ELSE + - 8 + 15 - RequestBusTime := FALSE; + ELSIF CONCAT(MQTTSubscribeTopic,'/OUT') = Data.TopicOut^ THEN - 2 + 16 - END_IF + IF OSCAT_BASIC.IS_CC(str:= Data.PayloadString^,cmp:='0123456789.') AND THIS^.PRIO_HIGH = FALSE THEN - - - - - - - 9 + 17 - METHOD RequestBusTime : BOOL + THIS^.OUT_Target:=STRING_TO_BYTE(Data.PayloadString^); - 1 + 18 - - - - - - - bb58f587-9f45-44a1-8ab8-a2a557be2a09 - - FB_RS485_ESERA_OWD_MQTT - - -1 - - - False - - 1cbcfa4b-0748-4841-b663-0be0f4ae9e27 - 2d8d4e52-d630-40a2-99dd-1affee9ab859 - ConfigureFunctionBlockAsVirtualInput - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + THIS^.SoftDimToValue:=TRUE; - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483690068247 - - - - - - 3 + 19 - THIS^.DefaultValue:=DefaultValue; + END_IF - 4 + 20 - THIS^.SetDefaultValueStartup:=SetDefaultValueStartup; + - 5 + 21 - THIS^.PublishAtStartup:=PublishAtStartup; + - 6 + 22 - THIS^.UsePersistentAtStartup:=UsePersistentAtStartup; + // Legacy! backwards compatiably with /+ topics instead of /# - 7 + 23 - THIS^.ConfirmReceival:=ConfirmReceival; + ELSIF CommonTypesAndFunctions.StrEqualsAtStart(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN - 2 + 24 - THIS^.VirtualMode:=VIRTUAL_MODES.Input; + //mark the interface call from the collector as done - - - - - - - 8 + 25 - METHOD ConfigureFunctionBlockAsVirtualInput : BOOL + PublishReceived := TRUE; - 9 + 26 - VAR_INPUT + //now process the data - 10 + 27 - DefaultValue: BOOL; + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('TRUE')) THEN - 11 + 28 - SetDefaultValueStartup: BOOL; + MqttHighRequest := TRUE; - 12 + 29 - PublishAtStartup: BOOL; + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN - 13 + 30 - UsePersistentAtStartup: BOOL; + MqttLowRequest := TRUE; - 14 + 31 - ConfirmReceival: BOOL; + ELSIF OSCAT_BASIC.IS_CC(str:= Data.PayloadString^,cmp:='0123456789.') AND THIS^.PRIO_HIGH = FALSE THEN - 15 + 32 - END_VAR + THIS^.OUT_Target:=STRING_TO_BYTE(Data.PayloadString^); - 1 + 33 - - - - - - - 2d8d4e52-d630-40a2-99dd-1affee9ab859 - - FB_VIRTUAL_BOOL_MQTT - - -1 - - - False - - 28f15bea-ce5e-4422-8ca7-dc55f08bf0d0 - 2d8d4e52-d630-40a2-99dd-1affee9ab859 - ConfigureFunctionBlockAsVirtualOutput - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + THIS^.SoftDimToValue:=TRUE; - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483690767867 - - - - - - 3 + 34 - THIS^.PublishAtStartup:=PublishAtStartup; + END_IF 2 - THIS^.VirtualMode:=VIRTUAL_MODES.Output; + END_IF @@ -21670,22 +20994,27 @@ - 4 + 35 - METHOD ConfigureFunctionBlockAsVirtualOutput : BOOL + METHOD PublishReceived : BOOL - 5 + 36 VAR_INPUT - 6 + 37 - PublishAtStartup: BOOL; + ///Collection of recived Data - 7 + 38 + + Data: MQTT.CALLBACK_DATA; + + + 39 END_VAR @@ -21698,18 +21027,18 @@ - 2d8d4e52-d630-40a2-99dd-1affee9ab859 + f1306b9c-42ee-45fa-892a-f187063e8d39 - FB_VIRTUAL_BOOL_MQTT + FB_OUTPUT_DIMMER_MQTT -1 False - 1f27fc21-de67-4840-b246-a472251873ea - 2d8d4e52-d630-40a2-99dd-1affee9ab859 - InitMqtt + 9ad45f22-ef76-4c21-a580-a796b04d8554 + 20eaf0ea-fc95-467c-9beb-a3212b0f3e69 + GetIpAddress @@ -21733,7 +21062,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115483689357848 + 638133836334607983 @@ -21742,87 +21071,92 @@ 3 - InitMqttDone := TRUE; + xFirstAdapter := TRUE; 4 - + rResult := 0; 5 - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important + WHILE rResult = 0 DO 6 - + IF xFirstAdapter THEN 7 - (*pass trough*) + hAdapter := SysSockGetFirstAdapterInfo(ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); 8 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + ELSE 9 - THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + hAdapter := SysSockGetNextAdapterInfo(hAdapter, ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); 10 - THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; + END_IF 11 - THIS^.pMqttPublishQueue:=pMqttPublishQueue; + IF rResult = 0 THEN 12 - THIS^.MqttQos:=MqttQos; + GetIpAddress := Standard.CONCAT(BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b1),'.'); 13 - THIS^.MqttRetain:=MqttRetain; + GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b2)); 14 - + GetIpAddress := Standard.CONCAT(GetIpAddress,'.'); 15 - + GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b3)); 16 - SUPER^.InitBaseMqtt(); + GetIpAddress := Standard.CONCAT(GetIpAddress,'.'); 17 - pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b4)); 18 - + END_IF + + + 19 + + xFirstAdapter := FALSE; 2 - + END_WHILE @@ -21830,45 +21164,40 @@ - - 19 - - METHOD InitMqtt - 20 - VAR_INPUT + METHOD PRIVATE GetIpAddress : STRING(15) 21 - MQTTPublishPrefix: POINTER TO STRING; + VAR 22 - MQTTSubscribePrefix: POINTER TO STRING; + AdapterInfo: SOCK_ADAPTER_INFORMATION; 23 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + hAdapter: RTS_IEC_HANDLE; 24 - pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + udiStructSize: UDINT := SIZEOF(AdapterInfo); 25 - MqttQos: MQTT.QoS; + rResult: RTS_IEC_RESULT; 26 - MqttRetain: BOOL; + xFirstAdapter: BOOL; 27 @@ -21884,18 +21213,18 @@ - 2d8d4e52-d630-40a2-99dd-1affee9ab859 + 20eaf0ea-fc95-467c-9beb-a3212b0f3e69 - FB_VIRTUAL_BOOL_MQTT + FB_PLC_MQTT_DISCOVERY_DEVICE -1 False - 6b5db92a-fafb-4ea0-be0c-f0badeeb249b - 2d8d4e52-d630-40a2-99dd-1affee9ab859 - PublishReceived + 72f4c76c-9f8a-4bc8-baf3-b78d2848d2ab + 20eaf0ea-fc95-467c-9beb-a3212b0f3e69 + GetMac @@ -21919,7 +21248,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115483689688262 + 638133836335017979 @@ -21928,207 +21257,156 @@ 3 - //first check if Mqtt is initialized and FB in input mode, otherwise do nothing + xFirstAdapter := TRUE; 4 - IF NOT(InitMqttDone) AND VirtualMode <> VIRTUAL_MODES.Input THEN + rResult := 0; 5 - //mark the interface call from the collector as done + WHILE rResult = 0 DO 6 - PublishReceived := TRUE; + IF xFirstAdapter THEN 7 - //check if the packet is for this FB + hAdapter := SysSockGetFirstAdapterInfo(ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); 8 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN + ELSE 9 - //mark the interface call from the collector as done + hAdapter := SysSockGetNextAdapterInfo(hAdapter, ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); 10 - PublishReceived := TRUE; + END_IF 11 - //process the data + IF rResult = 0 THEN 12 - IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('TRUE')) THEN + GetMac := Standard.CONCAT(SM0.Byte_To_HexString(AdapterInfo.abyMac[0]),'-'); 13 - THIS^.OUT := TRUE; + GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[1])); 14 - MqttMessageReceived := TRUE; + GetMac := Standard.CONCAT(GetMac,'-'); 15 - END_IF + GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[2])); 16 - IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN + GetMac := Standard.CONCAT(GetMac,'-'); 17 - THIS^.OUT := FALSE; + GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[3])); 18 - MqttMessageReceived := TRUE; + GetMac := Standard.CONCAT(GetMac,'-'); 19 - END_IF - - - 2 - - END_IF + GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[4])); - - - - - - 20 - METHOD PublishReceived : BOOL + GetMac := Standard.CONCAT(GetMac,'-'); 21 - VAR_INPUT + GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[5])); 22 - ///Collection of recived Data + END_IF 23 - Data: MQTT.CALLBACK_DATA; - - - 24 - - END_VAR + xFirstAdapter := FALSE; - 1 + 2 - + END_WHILE - - 2d8d4e52-d630-40a2-99dd-1affee9ab859 - - FB_VIRTUAL_BOOL_MQTT - - -1 - - - False - - d4794c50-191d-409c-b4f5-b59aa920dbbc - 2d8d4e52-d630-40a2-99dd-1affee9ab859 - SetValue - - - - 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 - - 638115483690357939 - - - + - 3 + 24 - THIS^.OUT:=Value; + METHOD PRIVATE GetMac : STRING(17) - 2 + 25 - THIS^.UpdateFlag:=TRUE; + VAR - - - - - - - 4 + 26 - METHOD SetValue : BOOL + AdapterInfo: SOCK_ADAPTER_INFORMATION; - 5 + 27 - VAR_INPUT + hAdapter: RTS_IEC_HANDLE; - 6 + 28 - Value: BOOL; + udiStructSize: UDINT := SIZEOF(AdapterInfo); - 7 + 29 + + rResult: RTS_IEC_RESULT; + + + 30 + + xFirstAdapter: BOOL; + + + 31 END_VAR @@ -22141,18 +21419,18 @@ - 2d8d4e52-d630-40a2-99dd-1affee9ab859 + 20eaf0ea-fc95-467c-9beb-a3212b0f3e69 - FB_VIRTUAL_BOOL_MQTT + FB_PLC_MQTT_DISCOVERY_DEVICE -1 False - bbba49e9-c9a9-48ed-9c5b-1bcd8f194594 - dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 - ConfigureFunctionBlockAsVirtualInput + 7aeea78f-ae82-41be-8b32-40ecde7688b2 + 20eaf0ea-fc95-467c-9beb-a3212b0f3e69 + initPlcDevice @@ -22176,7 +21454,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115483693168259 + 638133836334188378 @@ -22185,1811 +21463,467 @@ 3 - THIS^.DefaultValue:=DefaultValue; + IF xInit THEN 4 - THIS^.SetDefaultValueStartup:=SetDefaultValueStartup; + xInit := FALSE; 5 - THIS^.PublishAtStartup:=PublishAtStartup; + 6 - THIS^.UsePersistentAtStartup:=UsePersistentAtStartup; + (* get the appname first *) 7 - THIS^.ConfirmReceival:=ConfirmReceival; + sAppName := PRO_JSON.GPL_JSON.ApplicationName; - - 2 - - THIS^.VirtualMode:=VIRTUAL_MODES.Input; - - - - - - - 8 - METHOD ConfigureFunctionBlockAsVirtualInput : BOOL + 9 - VAR_INPUT + (* IP address and MAC *) 10 - DefaultValue: INT; + sIpAddr := GetIpAddress(); 11 - SetDefaultValueStartup: BOOL; + sMacAddr := GetMac(); 12 - PublishAtStartup: BOOL; - - - 13 - - UsePersistentAtStartup: BOOL; - - - 14 - - ConfirmReceival: BOOL; - - - 15 - - END_VAR - - - 1 - - - - - - - - dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 - - FB_VIRTUAL_INT_MQTT - - -1 - - - False - - 51f5340a-511a-47c2-ad02-701f4f4d4dd9 - dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 - ConfigureFunctionBlockAsVirtualOutput - - - - 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 - - 638115483691797844 - - - - - - - 3 - - THIS^.PublishAtStartup:=PublishAtStartup; - - - 2 - - THIS^.VirtualMode:=VIRTUAL_MODES.Output; - - - - - - - - - 4 - - METHOD ConfigureFunctionBlockAsVirtualOutput : BOOL - - - 5 - - VAR_INPUT - - - 6 - - PublishAtStartup: BOOL; - - - 7 - - END_VAR - - - 1 - - - - - - - - dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 - - FB_VIRTUAL_INT_MQTT - - -1 - - - False - - 34587e6d-f03a-47e6-8dbe-293e2d6af718 - dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 - 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 - - 638115483692278228 - - - - - - - 3 - - InitMqttDone := TRUE; - - - 4 - - - - - 5 - - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important - - - 6 - - - 7 - - (*pass trough*) - - - 8 - - THIS^.pMqttPublishQueue := pMqttPublishQueue; - - - 9 - - THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; - - - 10 - - THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; - - - 11 - - THIS^.pMqttPublishQueue:=pMqttPublishQueue; - - - 12 - - THIS^.MqttQos:=MqttQos; - 13 - THIS^.MqttRetain:=MqttRetain; + (* manufacturer *) 14 - + iecResult := SysTarget.SysTargetGetVendorName(pwszName := ADR(manufacturer), pnMaxLength := ADR(manufacturerSize)); 15 - + (* model *) 16 - SUPER^.InitBaseMqtt(); + iecResult := SysTarget.SysTargetGetDeviceName(pwszName := ADR(model), pnMaxLength := ADR(modelSize)); 17 - pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + (* serial number *) 18 - - - - 2 - - + iecResult := SysTarget.SysTargetGetSerialNumber(ppsSerialNumber := ADR(psSerialNumber), pnMaxLen := ADR(diSerialNumber)); - - - - - - 19 - METHOD InitMqtt + 20 - VAR_INPUT + (* device name *) 21 - MQTTPublishPrefix: POINTER TO STRING; + pApp := AppFindApplicationByName(pszString := sAppName, pResult := ADR(iecResult)); 22 - MQTTSubscribePrefix: POINTER TO STRING; + pstAppInfo := AppGetApplicationInfo(pApp := pApp, pResult := ADR(iecResult)); 23 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + iSplitLocation := COL.Stu.StrFindA( 24 - pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + pst1:= ADR(THIS^.InstanceName), 25 - MqttQos: MQTT.QoS; + pst2:= ADR('.'), 26 - MqttRetain: BOOL; + uiSearchStart:= 1 27 - END_VAR - - - 1 - - - - - - - - dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 - - FB_VIRTUAL_INT_MQTT - - -1 - - - False - - d4933a30-8b1d-464c-95e0-2321ba9c9029 - dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 - 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 - - 638115483692697820 - - - - - - - 3 - - //first check if Mqtt is initialized and FB in input mode, otherwise do nothing - - - 4 - - IF NOT(InitMqttDone) AND VirtualMode <> VIRTUAL_MODES.Input 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 + ) - 1; - 10 + 28 - PublishReceived := TRUE; + - 11 + 29 - //process the data + (* sw version *) - 12 + 30 - IF OSCAT_BASIC.IS_NUM(str:= Data.PayloadString^) THEN + CompilerVersion := __SYSTEM.Constants.CompilerVersion; - 13 + 31 - THIS^.OUT := STRING_TO_INT(Data.PayloadString^); + SCompilerVersion := CONCAT(UINT_TO_STRING(CompilerVersion.uiMajor), '.'); - 14 + 32 - MqttMessageReceived := TRUE; + SCompilerVersion := CONCAT(SCompilerVersion, UINT_TO_STRING(CompilerVersion.uiMinor)); - 15 + 33 - END_IF + SCompilerVersion := CONCAT(SCompilerVersion, '.'); - 2 + 34 - END_IF + SCompilerVersion := CONCAT(SCompilerVersion, UINT_TO_STRING(CompilerVersion.uiServicePack)); - - - - - - - 16 + 35 - METHOD PublishReceived : BOOL + SCompilerVersion := CONCAT(SCompilerVersion, '.'); - 17 + 36 - VAR_INPUT + SCompilerVersion := CONCAT(SCompilerVersion, UINT_TO_STRING(CompilerVersion.uiPatch)); - 18 + 37 - ///Collection of recived Data + - 19 + 38 - Data: MQTT.CALLBACK_DATA; + (* url *) - 20 + 39 - END_VAR + IF CommonTypesAndFunctions.StrEquals(ADR(url), ADR('')) THEN - 1 + 40 - - - - - - - dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 - - FB_VIRTUAL_INT_MQTT - - -1 - - - False - - 6d062eee-2aad-4e3a-999e-f1cf9b80ed1b - dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 - SetValue - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + LocalUrl := CONCAT('https://', sIpAddr); - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483693597854 - - - - - - 3 + 41 - THIS^.OUT:=Value; + ELSE - 2 + 42 - THIS^.UpdateFlag:=TRUE; + LocalUrl := url; - - - - - - - 4 + 43 - METHOD SetValue : BOOL + END_IF - 5 + 44 - VAR_INPUT + - 6 + 45 - Value: INT; + SUPER^.initBaseDevice( - 7 + 46 - END_VAR + Name := LEFT(THIS^.InstanceName,iSplitLocation), - 1 - - - - - - - - dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 - - FB_VIRTUAL_INT_MQTT - - -1 - - - False - - 8207c67f-9eb3-4ffc-8674-7a2fa6b2a79f - a358b58e-8bfc-4426-9a93-064a10d81a04 - ConfigureFunctionBlockAsVirtualInput - - - - 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 - - 638115483696877868 - - - - - - - 3 - - THIS^.DefaultValue:=DefaultValue; - - - 4 - - THIS^.SetDefaultValueStartup:=SetDefaultValueStartup; - - - 5 - - THIS^.PublishAtStartup:=PublishAtStartup; - - - 6 - - THIS^.UsePersistentAtStartup:=UsePersistentAtStartup; - - - 7 - - THIS^.ConfirmReceival:=ConfirmReceival; - - - 2 - - THIS^.VirtualMode:=VIRTUAL_MODES.Input; - - - - - - - - - 8 - - METHOD ConfigureFunctionBlockAsVirtualInput : BOOL - - - 9 - - VAR_INPUT - - - 10 - - DefaultValue: REAL; - - - 11 - - SetDefaultValueStartup: BOOL; - - - 12 - - PublishAtStartup: BOOL; - - - 13 - - UsePersistentAtStartup: BOOL; - - - 14 - - ConfirmReceival: BOOL; - - - 15 - - END_VAR - - - 1 - - - - - - - - a358b58e-8bfc-4426-9a93-064a10d81a04 - - FB_VIRTUAL_REAL_MQTT - - -1 - - - False - - 1d91458c-a2c5-4790-a876-fa308386076d - a358b58e-8bfc-4426-9a93-064a10d81a04 - ConfigureFunctionBlockAsVirtualOutput - - - - 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 - - 638115483695707869 - - - - - - - 3 - - THIS^.PublishAtStartup:=PublishAtStartup; - - - 2 - - THIS^.VirtualMode:=VIRTUAL_MODES.Output; - - - - - - - - - 4 - - METHOD ConfigureFunctionBlockAsVirtualOutput : BOOL - - - 5 - - VAR_INPUT - - - 6 - - PublishAtStartup: BOOL; - - - 7 - - END_VAR - - - 1 - - - - - - - - a358b58e-8bfc-4426-9a93-064a10d81a04 - - FB_VIRTUAL_REAL_MQTT - - -1 - - - False - - 1b0b743d-e33a-46a5-994f-c178f35fee4c - a358b58e-8bfc-4426-9a93-064a10d81a04 - 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 - - 638115483696128239 - - - - - - - 3 - - InitMqttDone := TRUE; - - - 4 - - - - - 5 - - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important - - - 6 - - - - - 7 - - (*pass trough*) - - - 8 - - THIS^.pMqttPublishQueue := pMqttPublishQueue; - - - 9 - - THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; - - - 10 - - THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; - - - 11 - - THIS^.pMqttPublishQueue:=pMqttPublishQueue; - - - 12 - - THIS^.MqttQos:=MqttQos; - - - 13 - - THIS^.MqttRetain:=MqttRetain; - - - 14 - - - - - 15 - - - - - 16 - - SUPER^.InitBaseMqtt(); - - - 17 - - pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received - - - 18 - - - - - 2 - - - - - - - - - - - 19 - - METHOD InitMqtt - - - 20 - - VAR_INPUT - - - 21 - - MQTTPublishPrefix: POINTER TO STRING; - - - 22 - - MQTTSubscribePrefix: POINTER TO STRING; - - - 23 - - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; - - - 24 - - pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; - - - 25 - - MqttQos: MQTT.QoS; - - - 26 - - MqttRetain: BOOL; - - - 27 - - END_VAR - - - 1 - - - - - - - - a358b58e-8bfc-4426-9a93-064a10d81a04 - - FB_VIRTUAL_REAL_MQTT - - -1 - - - False - - ff86ca41-7669-4336-8757-e7c27720e57b - a358b58e-8bfc-4426-9a93-064a10d81a04 - 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 - - 638115483696507837 - - - - - - - 3 - - //first check if Mqtt is initialized and FB in input mode, otherwise do nothing - - - 4 - - IF NOT(InitMqttDone) AND VirtualMode <> VIRTUAL_MODES.Input 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 - - //process the data - - - 12 - - THIS^.OUT := STRING_TO_REAL(Data.PayloadString^); - - - 13 - - MqttMessageReceived := TRUE; - - - 2 - - END_IF - - - - - - - - - 14 - - METHOD PublishReceived : BOOL - - - 15 - - VAR_INPUT - - - 16 - - ///Collection of recived Data - - - 17 - - Data: MQTT.CALLBACK_DATA; - - - 18 - - END_VAR - - - 1 - - - - - - - - a358b58e-8bfc-4426-9a93-064a10d81a04 - - FB_VIRTUAL_REAL_MQTT - - -1 - - - False - - 8c3ea5f3-3fee-4da2-bdd9-d8e7f8d9a703 - a358b58e-8bfc-4426-9a93-064a10d81a04 - SetValue - - - - 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 - - 638115483697167850 - - - - - - - 3 - - THIS^.OUT:=Value; - - - 2 - - THIS^.UpdateFlag:=TRUE; - - - - - - - - - 4 - - METHOD SetValue : BOOL - - - 5 - - VAR_INPUT - - - 6 - - Value: REAL; - - - 7 - - END_VAR - - - 1 - - - - - - - - a358b58e-8bfc-4426-9a93-064a10d81a04 - - FB_VIRTUAL_REAL_MQTT - - -1 - - - False - - f2511d62-705b-40cb-8de4-d61fc6409bfe - 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb - ConfigureFunctionBlockAsVirtualInput - - - - 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 - - 638115483698747847 - - - - - - - 3 - - THIS^.DefaultValue:=DefaultValue; - - - 4 - - THIS^.SetDefaultValueStartup:=SetDefaultValueStartup; - - - 5 - - THIS^.PublishAtStartup:=PublishAtStartup; - - - 6 - - THIS^.UsePersistentAtStartup:=UsePersistentAtStartup; - - - 7 - - THIS^.ConfirmReceival:=ConfirmReceival; - - - 2 - - THIS^.VirtualMode:=VIRTUAL_MODES.Input; - - - - - - - - - 8 - - METHOD ConfigureFunctionBlockAsVirtualInput : BOOL - - - 9 - - VAR_INPUT - - - 10 - - DefaultValue: STRING; - - - 11 - - SetDefaultValueStartup: BOOL; - - - 12 - - PublishAtStartup: BOOL; - - - 13 - - UsePersistentAtStartup: BOOL; - - - 14 - - ConfirmReceival: BOOL; - - - 15 - - END_VAR - - - 1 - - - - - - - - 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb - - FB_VIRTUAL_STRING_MQTT - - -1 - - - False - - cd8070a9-0b16-4a71-bb37-7a04025d94af - 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb - ConfigureFunctionBlockAsVirtualOutput - - - - 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 - - 638115483699447842 - - - - - - - 3 - - THIS^.PublishAtStartup:=PublishAtStartup; - - - 2 - - THIS^.VirtualMode:=VIRTUAL_MODES.Output; - - - - - - - - - 4 - - METHOD ConfigureFunctionBlockAsVirtualOutput : BOOL - - - 5 - - VAR_INPUT - - - 6 - - PublishAtStartup: BOOL; - - - 7 - - END_VAR - - - 1 - - - - - - - - 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb - - FB_VIRTUAL_STRING_MQTT - - -1 - - - False - - 90629d9d-c71d-42ea-b678-23deb210a23f - 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb - 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 - - 638115483698027859 - - - - - - - 3 + 47 - InitMqttDone := TRUE; + ConfigurationUrl := LocalUrl, - 4 + 48 - + Identifiers := psSerialNumber^, - 5 + 49 - SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important + Manufacturer := WSTRING_TO_STRING(manufacturer), - 6 + 50 - + Model := WSTRING_TO_STRING(model), - 7 + 51 - (*pass trough*) + SoftwareVersion := SCompilerVersion, - 8 + 52 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + HardwareVersion := DT_TO_STRING(pstAppInfo^.dtLastChanges), - 9 + 53 - THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; + IpAddress := sIpAddr, - 10 + 54 - THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; + MacAddress := sMacAddr, - 11 + 55 - THIS^.pMqttPublishQueue:=pMqttPublishQueue; + availabilityTopic := availabilityTopic, - 12 + 56 - THIS^.MqttQos:=MqttQos; + availabilityOnline := availabilityOnline, - 13 + 57 - THIS^.MqttRetain:=MqttRetain; + availabilityOffline := availabilityOffline, - 14 + 58 - + MqttDiscoveryPrefix := MqttDiscoveryPrefix, - 15 + 59 - + MqttDiagnosticTopic := MqttDiagnosticTopic, - 16 + 60 - SUPER^.InitBaseMqtt(); + pMqttPublishQueue := pMqttPublishQueue); - 17 + 61 - pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received + - 18 + 62 - + // Serial number diagnostic - 2 + 63 - + CreateSensorEntityWithCategory( - - - - - - - 19 + 64 - METHOD InitMqtt + Name := 'Serial number', - 20 + 65 - VAR_INPUT + Id := CONCAT(THIS^.Name,'_diag_sn'), - 21 + 66 - MQTTPublishPrefix: POINTER TO STRING; + Meta := '', - 22 + 67 - MQTTSubscribePrefix: POINTER TO STRING; + StateTopic := CONCAT(MqttDiagnosticTopic, '/SN'), - 23 + 68 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + StateValue := psSerialNumber^, - 24 + 69 - pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + EntityCategory := 'diagnostic'); - 25 + 70 - MqttQos: MQTT.QoS; + - 26 + 71 - MqttRetain: BOOL; + // Serial number diagnostic - 27 + 72 - END_VAR + CreateSensorEntityWithCategory( - 1 + 73 - + Name := 'Serial number', - - - - - 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb - - FB_VIRTUAL_STRING_MQTT - - -1 - - - False - - d1d0e806-b356-4767-8b35-9b640e963245 - 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb - PublishReceived - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 74 + + Id := CONCAT(THIS^.Name,'_diag_sn'), - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483698448189 - - - - - - 3 + 75 - //first check if Mqtt is initialized and FB in input mode, otherwise do nothing + Meta := '', - 4 + 76 - IF NOT(InitMqttDone) AND VirtualMode <> VIRTUAL_MODES.Input THEN + StateTopic := CONCAT(MqttDiagnosticTopic, '/SN'), - 5 + 77 - //mark the interface call from the collector as done + StateValue := psSerialNumber^, - 6 + 78 - PublishReceived := TRUE; + EntityCategory := 'diagnostic'); - 7 + 79 - //check if the packet is for this FB + - 8 + 80 - ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN + // IP address diagnostic, initial publish. done cyclic as well - 9 + 81 - //mark the interface call from the collector as done + THIS^.MqttDiagnosticTopicIP := CONCAT(MqttDiagnosticTopic, '/IP'); - 10 + 82 - PublishReceived := TRUE; + MqttRefreshIP(ENQ:=TRUE, PTH:=T#0S, PTL:=T#1M); - 11 + 83 - //process the data + CreateSensorEntityWithCategory( - 12 + 84 - THIS^.OUT := Data.PayloadString^; + Name := 'IP', - 13 + 85 - MqttMessageReceived := TRUE; + Id := CONCAT(THIS^.Name,'_diag_ip'), - 2 + 86 - END_IF + Meta := '', - - - - - - - 14 + 87 - METHOD PublishReceived : BOOL + StateTopic := THIS^.MqttDiagnosticTopicIP, - 15 + 88 - VAR_INPUT + StateValue := sIpAddr, - 16 + 89 - ///Collection of recived Data + EntityCategory := 'diagnostic'); - 17 + 90 - Data: MQTT.CALLBACK_DATA; + - 18 + 91 - END_VAR + END_IF - 1 + 92 - - - - - 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb - - FB_VIRTUAL_STRING_MQTT - - -1 - - - False - - 159c061a-ec5c-40ae-99df-f862def91982 - 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb - SetValue - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 93 + + - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115483699047969 - - - - - - 3 + 94 - THIS^.OUT:=Value; + 2 - THIS^.UpdateFlag:=TRUE; + @@ -23998,163 +21932,157 @@ - 4 + 95 - METHOD SetValue : BOOL + METHOD initPlcDevice - 5 + 96 VAR_INPUT - 6 + 97 - Value: STRING; + url: STRING := ''; - 7 + 98 + + availabilityTopic: STRING; + + + 99 + + availabilityOnline: STRING; + + + 100 + + availabilityOffline: STRING; + + + 101 + + MqttDiscoveryPrefix: STRING; + + + 102 + + MqttDiagnosticTopic: STRING; + + + 103 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 104 END_VAR - 1 + 105 - + VAR - - - - - 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb - - FB_VIRTUAL_STRING_MQTT - - -1 - - - False - - e85afafb-0938-4f3e-a924-0f54fbabdc99 - e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 - AddMessage - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - + + 106 + + LocalUrl: STRING; - - - - f8a58466-d7f6-439f-bbb8-d4600e41d099 - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - - 638115485064636336 - - - - - - 3 + 107 - IF NOT FULL THEN + iSplitLocation: INT; - 4 + 108 - localMessage.Payload := Payload; + iecResult: SysTypes.RTS_IEC_RESULT; - 5 + 109 - localMessage.Topic := Topic; + /// must identic to the name in the device tree - 6 + 110 - localMessage.Qos := Qos; + sAppName: STRING; - 7 + 111 - localMessage.MqttRetain := MqttRetain; + pApp: POINTER TO CmpApp.APPLICATION; - 8 + 112 - fifo[pw] := localMessage; + stAppInfo: CmpApp.APPLICATION_INFO; - 9 + 113 - pw := OSCAT_BASIC.INC1(pw,n); + pstAppInfo: POINTER TO CmpApp.APPLICATION_INFO := ADR(stAppInfo); - 10 + 114 - FULL := pw = pr; + sIpAddr: STRING(15); - 11 + 115 - EMPTY := FALSE; + sMacAddr: STRING(17); - 2 + 116 - END_IF; + manufacturer: WSTRING; - - - - - - - 12 + 117 - METHOD AddMessage + manufacturerSize: UDINT := SIZEOF(manufacturer); - 13 + 118 - VAR_INPUT + model: WSTRING; - 14 + 119 - Payload: STRING(1500); + modelSize: DINT := SIZEOF(model); - 15 + 120 - Topic: STRING(128); + sSerialNumber: STRING; - 16 + 121 - Qos: MQTT.QoS; + psSerialNumber: POINTER TO STRING := ADR(sSerialNumber); - 17 + 122 - MqttRetain: BOOL; + diSerialNumber: DINT := SIZEOF(sSerialNumber); - 18 + 123 + + CompilerVersion: Version; + + + 124 + + SCompilerVersion: STRING; + + + 125 END_VAR @@ -24167,19 +22095,18 @@ - e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 + 20eaf0ea-fc95-467c-9beb-a3212b0f3e69 - Mqtt - FB_MqttPublishQueue + FB_PLC_MQTT_DISCOVERY_DEVICE -1 False - 2aca44d9-e20c-4d8f-9ac8-5cab1f548638 - e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 - GetMessage + 984fa948-b007-4cb3-9e0f-2d63e7f44db7 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + AddNode @@ -24203,7 +22130,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115485064616826 + 638103389528346545 @@ -24212,32 +22139,37 @@ 3 - IF NOT EMPTY THEN + THIS^.Nodes[NodePointer].InitNode( 4 - GetMessage := fifo[pr]; + DeviceAddress := THIS^.ReadMasterUnitQuery.DeviceId, 5 - pr := OSCAT_BASIC.INC1(pr,n); + NodeNumber := NodePointer -1, 6 - EMPTY := pr = pw; + DataPollingInterval := DataPollingInterval 7 - FULL := FALSE; + ); + + + 8 + + 2 - END_IF; + NodePointer := NodePointer + 1; @@ -24246,9 +22178,24 @@ - 8 + 9 + + METHOD AddNode : BOOL + + + 10 + + VAR_INPUT + + + 11 + + DataPollingInterval: TIME; + + + 12 - METHOD GetMessage : MQTT_MESSAGE + END_VAR 1 @@ -24259,19 +22206,18 @@ - e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - Mqtt - FB_MqttPublishQueue + FB_RS485_DUCO_DUCOBOX_MQTT -1 False - f24e2080-1319-4991-b6a7-fb17a1ccf8a1 - e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 - Reset + ea4a3060-cbd7-4ff9-940d-93b4781abc91 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + GetRtuQuery @@ -24295,7 +22241,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115485064646791 + 638103389527486540 @@ -24304,17 +22250,57 @@ 3 - pw := pr; + IF WriteQueryReady THEN 4 - FULL := FALSE; + GetRtuQuery := THIS^.WriteQuery; + + + 5 + + WriteQueryBeingExecuted := TRUE; + + + 6 + + // master + + + 7 + + ELSIF ActiveNode = 1 THEN + + + 8 + + THIS^.timerData.IN := FALSE; + + + 9 + + GetRtuQuery := THIS^.ReadMasterUnitQuery; + + + 10 + + // other nodes + + + 11 + + ELSIF ActiveNode > 1 THEN + + + 12 + + GetRtuQuery := THIS^.Nodes[ActiveNode].GetRtuQuery(); 2 - EMPTY := TRUE; + END_IF @@ -24323,9 +22309,9 @@ - 5 + 13 - METHOD Reset + METHOD GetRtuQuery : RS485_RtuQuery 1 @@ -24336,19 +22322,18 @@ - e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - Mqtt - FB_MqttPublishQueue + FB_RS485_DUCO_DUCOBOX_MQTT -1 False - a51ccb6a-0e41-4a8f-8043-1f5e0819cdbd - 15a50ac1-2e79-43de-b5c8-cf7e3b869577 - Init + 372d5ec1-4c34-43e7-a93a-115a801b0a96 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + InitMqtt @@ -24372,7 +22357,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115485064396775 + 638103389526927034 @@ -24381,28 +22366,103 @@ 3 - publish.SetMqttInOut(MQTT_IN_OUT := inputMQTT_IN_OUT^); + THIS^.pMqttPublishQueue := pMqttPublishQueue; 4 - + THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; 5 - InitDone := TRUE; + 6 - SendDone := TRUE; + InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(THIS^.InstanceName)) + 1; - 2 + 7 + + THIS^.MqttPublishTopicSuffix := InstanceNamePt^; + + + 8 + + THIS^.MQTTSubscribeTopic := CONCAT(MQTTSubscribePrefix^ ,THIS^.MqttPublishTopicSuffix); + + + 9 + + + + + 10 + + // register the FB agains the collector so mqtt events can be received + + + 11 + + pMqttCallbackCollector^.put(instance:= THIS^); + + + 12 + + + + + 13 + + + + + 14 + + FOR loopCounter := 2 TO 30 DO + + + 15 + + Nodes[loopCounter].InitMqtt( + + + 16 + + MQTTPublishPrefix := MQTTPublishPrefix, + + + 17 + + MqttPublishTopicSuffix := InstanceNamePt^, + + + 18 + + pMqttPublishQueue := pMqttPublishQueue + + + 19 + + ); + + + 20 + + END_FOR + + + 21 + + 2 + + InitMqttDone := TRUE; + @@ -24410,27 +22470,52 @@ - 7 + 22 - METHOD Init + METHOD InitMqtt - 8 + 23 VAR_INPUT - 9 + 24 - ///Pointer MQTTT exchange strucure + MQTTPublishPrefix: POINTER TO STRING; - 10 + 25 - inputMQTT_IN_OUT: POINTER TO MQTT.MQTT_IN_OUT; + MQTTSubscribePrefix: POINTER TO STRING; - 11 + 26 + + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + + + 27 + + pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; + + + 28 + + END_VAR + + + 29 + + VAR + + + 30 + + InstanceNamePt: POINTER TO STRING; + + + 31 END_VAR @@ -24443,19 +22528,18 @@ - 15a50ac1-2e79-43de-b5c8-cf7e3b869577 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - Mqtt - FB_MqttPublishWorker + FB_RS485_DUCO_DUCOBOX_MQTT -1 False - 8bf6165e-c19d-4c89-a9d0-84528bf38968 - 15a50ac1-2e79-43de-b5c8-cf7e3b869577 - PublishMessage + 723bccfa-a813-453d-a7fb-6bb45f91344e + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + InitRS485 @@ -24479,7 +22563,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638115485064416342 + 638103389526576970 @@ -24488,137 +22572,63 @@ 3 - LocalMqttMessage := MqttMessage; + THIS^.timerData.PT := DataPollingInterval; 4 - - - - 2 - - RequestToSend:=TRUE; + THIS^.ReadMasterUnitQuery.DeviceId := DeviceAddress; - - - - - - 5 - METHOD PublishMessage + THIS^.WriteQuery.DeviceId := DeviceAddress; 6 - VAR_INPUT + THIS^.timerData.IN := TRUE; 7 - MqttMessage: MQTT_MESSAGE; - - - 8 - - END_VAR + - 1 + 2 - + THIS^.InitRS485Done := TRUE; - - 15a50ac1-2e79-43de-b5c8-cf7e3b869577 - - Mqtt - FB_MqttPublishWorker - - -1 - - - False - - fcd96465-7e19-4f81-836c-09c3f3ef8312 - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_AVTY_T - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - - - - - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - - 638119892248617219 - - - 2 + 8 - TYPE MQTT_DISCOVERY_AVTY_T : + METHOD InitRS485 - 3 + 9 - STRUCT + VAR_INPUT - 4 + 10 - topic: JSONVAR; + DataPollingInterval: TIME; - 5 + 11 - END_STRUCT + DeviceAddress: BYTE; - 6 + 12 - END_TYPE + END_VAR 1 @@ -24628,21 +22638,19 @@ - 6 - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - MqttDiscovery - Messages + FB_RS485_DUCO_DUCOBOX_MQTT -1 False - a6b584f2-9095-4c45-acf1-91c47a7506e1 - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_BASE + 7e3a8fa6-6437-43f2-8c12-65ca0de644c9 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + ProcessDataArray @@ -24660,380 +22668,223 @@ - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc + f8a58466-d7f6-439f-bbb8-d4600e41d099 a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119892248797248 + 638103389526296862 - - + + - - 2 - - TYPE MQTT_DISCOVERY_BASE : - 3 - STRUCT + THIS^.Error := Error^; 4 - name: JSONVAR; + 5 - /// object_id + IF Error^ AND NOT WriteQueryBeingExecuted THEN 6 - obj_id: JSONVAR; + PubMqttMessage(Suffix := '/availability', Data := 'offline'); 7 - ///unique_id + ELSE 8 - uniq_id: JSONVAR; + PubMqttMessage(Suffix := '/availability', Data := 'online'); 9 - /// availability + END_IF 10 - avty: ARRAY[1..2] OF MQTT_DISCOVERY_AVTY_T; + 11 - /// availability mode + IF WriteQueryBeingExecuted THEN 12 - avty_mode: JSONVAR; + WriteQueryReady := FALSE; 13 - ///payload_available + WriteQueryBeingExecuted := FALSE; 14 - pl_avail: JSONVAR; + IF NOT Error^ THEN 15 - /// payload_not_available + PubMqttMessage(Suffix := CONCAT('/', WriteQuerySuffix), Data := WriteQueryPayload); 16 - pl_not_avail: JSONVAR; + END_IF 17 - /// device + // data for master unit (= main node) 18 - dev: MQTT_DISCOVERY_DEVICE; + ELSIF THIS^.ActiveNode = 1 THEN 19 - /// mqtt qos + THIS^.timerData.IN := TRUE; 20 - qos: JSONVAR; + THIS^.ActiveNode := 0; 21 - /// extra metadata + 22 - meta: JSONVAR; + IF NOT Error^ THEN 23 - END_STRUCT + PubMqttMessage(Suffix := '/1/read/0', Data := WORD_TO_STRING(Data^[0])); 24 - END_TYPE - - - 1 - - - - - - - 24 - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - MqttDiscovery - Messages - - -1 - - - False - - 28c781b2-bbbc-4bb1-b7a1-8da3fd48145f - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_BINARY_SENSOR - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - - - - - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - + PubMqttMessage(Suffix := '/1/read/1', Data := WORD_TO_STRING(Data^[1])); - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - - 638119892249017209 - - - - - - 2 + 25 - TYPE MQTT_DISCOVERY_BINARY_SENSOR EXTENDS MQTT_DISCOVERY_BASE : + PubMqttMessage(Suffix := '/1/read/2', Data := WORD_TO_STRING(Data^[2])); - 3 + 26 - STRUCT + PubMqttMessage(Suffix := '/1/read/3', Data := WORD_TO_STRING(Data^[3])); - 4 + 27 - ///state_topic + PubMqttMessage(Suffix := '/1/read/4', Data := WORD_TO_STRING(Data^[4])); - 5 + 28 - stat_t: JSONVAR; + PubMqttMessage(Suffix := '/1/read/5', Data := WORD_TO_STRING(Data^[5])); - 6 + 29 - ///payload_on + END_IF - 7 + 30 - pl_on: JSONVAR; + // data for nodes - 8 + 31 - ///payload_off + ELSIF THIS^.ActiveNode > 1 THEN - 9 + 32 - pl_off: JSONVAR; + THIS^.Nodes[ActiveNode].ProcessDataArray( - 10 + 33 - /// device class + Data := Data, - 11 + 34 - dev_cla: JSONVAR; + Error := Error - 12 + 35 - END_STRUCT + ); - 13 + 36 - END_TYPE + THIS^.ActiveNode := 0; - 1 + 2 - + END_IF - 13 - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - MqttDiscovery - Messages - - -1 - - - False - - 9459113e-7fe9-4c2b-acb8-6f4c482d9a59 - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_BINARY_SENSOR_ENT_CAT - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - - - - - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - - 638119892249176761 - - - 2 - - TYPE MQTT_DISCOVERY_BINARY_SENSOR_ENT_CAT EXTENDS MQTT_DISCOVERY_BINARY_SENSOR : - - - 3 + 37 - STRUCT + METHOD ProcessDataArray - 4 + 38 - /// entity category + VAR_INPUT - 5 + 39 - ent_cat: JSONVAR; + Error: POINTER TO BOOL; - 6 + 40 - END_STRUCT + Data: POINTER TO ARRAY[0..124] OF WORD; - 7 + 41 - END_TYPE + END_VAR 1 @@ -25043,21 +22894,19 @@ - 7 - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - MqttDiscovery - Messages + FB_RS485_DUCO_DUCOBOX_MQTT -1 False - 9f7614bb-75e9-429a-9de8-272e6045d67a - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_COVER + eaa441be-86d1-44ee-a353-eaca63e8d47e + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + PublishReceived @@ -25075,145 +22924,193 @@ - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc + f8a58466-d7f6-439f-bbb8-d4600e41d099 a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119892249377283 + 638103389528026550 - - + + - - 2 - - TYPE MQTT_DISCOVERY_COVER EXTENDS MQTT_DISCOVERY_BASE : - 3 - STRUCT + //first check if Mqtt is initialized, otherwise do nothing 4 - ///command_topic + IF NOT(InitMqttDone) THEN 5 - cmd_t: JSONVAR; + //mark the interface call from the collector as done 6 - /// payload open + PublishReceived := TRUE; 7 - pl_open: JSONVAR; + //check if the packet is for this FB 8 - /// payload_close + ELSIF MQTTSubscribeTopic = LEFT(Data.TopicOut^, LEN(MQTTSubscribeTopic)) THEN 9 - pl_cls: JSONVAR; + //mark the interface call from the collector as done 10 - /// payload_stop + PublishReceived := TRUE; 11 - pl_stop: JSONVAR; + // process the data 12 - /// state topic + SubTopic := RIGHT(Data.TopicOut^, 9); // 2/write/9 -> 10 chars 13 - stat_t: JSONVAR; + NodeNumber := LEFT(SubTopic, 1); 14 - /// state open + NodeRegister := RIGHT(SubTopic, 1); 15 - stat_open: JSONVAR; + 16 - /// state closed + IF FIND(SubTopic, 'write') > 0 AND 17 - stat_clsd: JSONVAR; + OSCAT_BASIC.IS_NUM(NodeNumber) AND 18 - /// optimistic + OSCAT_BASIC.IS_NUM(NodeRegister) AND 19 - opt: JSONVAR; + OSCAT_BASIC.IS_NUM(Data.PayloadString^) THEN 20 - /// device class + WriteQuery.WriteAddress := (STRING_TO_UINT(NodeNumber) * 10) + STRING_TO_UINT(NodeRegister); 21 - dev_cla: JSONVAR; + WriteQuery.WriteData[0] := STRING_TO_WORD(Data.PayloadString^); 22 - END_STRUCT + WriteQuerySuffix := SubTopic; 23 - END_TYPE + WriteQueryPayload := Data.PayloadString^; + + + 24 + + WriteQueryReady := TRUE; + + + 25 + + END_IF + + + 2 + + END_IF + + + + + + + + + 26 + + METHOD PublishReceived : BOOL + + + 27 + + VAR_INPUT + + + 28 + + ///Collection of recived Data + + + 29 + + Data: MQTT.CALLBACK_DATA; + + + 30 + + END_VAR + + + 31 + + VAR + + + 32 + + SubTopic: STRING; + + + 33 + + NodeNumber: STRING; + + + 34 + + NodeRegister: STRING; + + + 35 + + END_VAR 1 @@ -25223,21 +23120,19 @@ - 23 - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - MqttDiscovery - Messages + FB_RS485_DUCO_DUCOBOX_MQTT -1 False - cc7e28be-62c5-46bf-a211-17aae04d4917 - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_DEVICE + 04d3b380-14c7-4633-b3eb-30e8fb76c702 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + PubMqttMessage @@ -25255,120 +23150,88 @@ - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc + f8a58466-d7f6-439f-bbb8-d4600e41d099 a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119892249577247 + 638103389527756959 - - + + - - 2 - - TYPE MQTT_DISCOVERY_DEVICE : - 3 - STRUCT + IF InitMqttDone THEN 4 - name: JSONVAR; + pMqttPublishQueue^.AddMessage( 5 - ///configuration_url + Payload := Data, 6 - cu: JSONVAR; + Topic := CONCAT(CONCAT(MqttPublishTopicPrefix^, MqttPublishTopicSuffix), Suffix ), 7 - ///identifiers + Qos := MQTT.QoS.ExactlyOnce, 8 - ids: JSONVAR; + MqttRetain := FALSE 9 - ///manufacturer + ); + + + 2 + + END_IF + + + + + + 10 - mf: JSONVAR; + METHOD PubMqttMessage 11 - ///model + VAR_INPUT 12 - mdl: JSONVAR; + Suffix: STRING(100); 13 - ///sw_version + Data: STRING(100); 14 - sw: JSONVAR; - - - 15 - - ///hw_version - - - 16 - - hw: JSONVAR; - - - 17 - - END_STRUCT - - - 18 - - END_TYPE + END_VAR 1 @@ -25378,21 +23241,19 @@ - 18 - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 - MqttDiscovery - Messages + FB_RS485_DUCO_DUCOBOX_MQTT -1 False - d74686d1-5acc-4bc7-8861-6668c13d9c0c - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_LIGHT + 284fb9e1-88e7-4941-bc27-4f35fb4e92ce + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + RequestBusTime @@ -25410,105 +23271,199 @@ - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc + f8a58466-d7f6-439f-bbb8-d4600e41d099 a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119892249747235 + 638103389527206545 - - + + - - 2 - - TYPE MQTT_DISCOVERY_LIGHT EXTENDS MQTT_DISCOVERY_BASE : - 3 - STRUCT + IF NOT InitRS485Done THEN 4 - ///command_topic + RequestBusTime := FALSE; 5 - cmd_t: JSONVAR; + ELSIF WriteQueryReady THEN 6 - /// payload_on + RequestBusTime := TRUE; 7 - pl_on: JSONVAR; + ELSIF timerData.Q THEN // Master node 8 - /// payload_off + RequestBusTime := TRUE; 9 - pl_off: JSONVAR; + THIS^.ActiveNode := 1; 10 - /// state_topic + ELSIF NodePointer > 2 THEN// other nodes, if configured + + + 11 + + FOR loopCounter := 2 TO 30 DO + + + 12 + + IF Nodes[loopCounter].RequestBusTime() AND RequestBusTime = FALSE THEN + + + 13 + + THIS^.ActiveNode := loopCounter; + + + 14 + + RequestBusTime := TRUE; + + + 15 + + END_IF + + + 16 + + END_FOR + + + 17 + + ELSE + + + 18 + + RequestBusTime := FALSE; + + + 19 + + END_IF + + + 2 + + + + + + + + + + + 20 + + METHOD RequestBusTime : BOOL + + + 1 + + + + + + + + 2a1e90c2-80fd-4b12-94e1-317f72bf5184 + + FB_RS485_DUCO_DUCOBOX_MQTT + + -1 + + + False + + 33a50ff3-9c75-4b75-a3db-042629418278 + 6da195a7-86d2-4618-bcdb-49518274d9f3 + GetRtuQuery + + + + 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 + + 638103389529006952 + + + + + - 11 + 3 - stat_t: JSONVAR; + IF timerData.Q THEN - 12 + 4 - /// optimistic + THIS^.timerData.IN := FALSE; - 13 + 5 - opt: JSONVAR; + GetRtuQuery := THIS^.RtuQueryRead; - 14 + 2 - END_STRUCT + END_IF + + + + + + - 15 + 6 - END_TYPE + METHOD GetRtuQuery : RS485_RtuQuery 1 @@ -25518,21 +23473,19 @@ - 15 - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + 6da195a7-86d2-4618-bcdb-49518274d9f3 - MqttDiscovery - Messages + FB_RS485_DUCO_DUCOBOX_NODE_MQTT -1 False - 37d06121-3988-4895-88e6-9b917acf5c9a - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_LIGHT_DIMMER + 57422230-b02b-47fd-883e-95a351732463 + 6da195a7-86d2-4618-bcdb-49518274d9f3 + InitMqtt @@ -25550,115 +23503,78 @@ - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc + f8a58466-d7f6-439f-bbb8-d4600e41d099 a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119892250137259 + 638103389530166534 - - + + - - 2 - - TYPE MQTT_DISCOVERY_LIGHT_DIMMER EXTENDS MQTT_DISCOVERY_LIGHT : - 3 - STRUCT + THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; 4 - ///brightness state topic + THIS^.MqttPublishTopicSuffix := MqttPublishTopicSuffix; 5 - bri_stat_t: JSONVAR; + THIS^.pMqttPublishQueue := pMqttPublishQueue; 6 - /// brightness command topic + + + + 2 + + THIS^.InitMqttDone := TRUE; + + + + + + 7 - bri_cmd_t: JSONVAR; + METHOD InitMqtt 8 - /// brightness scale + VAR_INPUT 9 - bri_scl: JSONVAR; + MQTTPublishPrefix: POINTER TO STRING; 10 - /// on command type + MqttPublishTopicSuffix: STRING(255); 11 - on_cmd_type: JSONVAR; + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; 12 - /// DMX - - - 13 - - dmxChannel: JSONVAR; - - - 14 - - dmxWidth: JSONVAR; - - - 15 - - dmxUniverse: JSONVAR; - - - 16 - - END_STRUCT - - - 17 - - END_TYPE + END_VAR 1 @@ -25668,21 +23584,19 @@ - 17 - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + 6da195a7-86d2-4618-bcdb-49518274d9f3 - MqttDiscovery - Messages + FB_RS485_DUCO_DUCOBOX_NODE_MQTT -1 False - 57224119-342d-42e1-aac8-e9f601972e75 - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_LOCK + e8f2e620-c121-4dd7-ae15-57589c9c150e + 6da195a7-86d2-4618-bcdb-49518274d9f3 + InitNode @@ -25700,125 +23614,98 @@ - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc + f8a58466-d7f6-439f-bbb8-d4600e41d099 a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119892249937254 + 638103389529876572 - - + + - - 2 - - TYPE MQTT_DISCOVERY_LOCK EXTENDS MQTT_DISCOVERY_BASE : - 3 - STRUCT + THIS^.RtuQueryRead.DeviceId := DeviceAddress; 4 - ///command_topic + THIS^.RtuQueryRead.ReadAddress := (NodeNumber * 10) + 10; 5 - cmd_t: JSONVAR; + 6 - /// payload lock + THIS^.timerData.PT := DataPollingInterval; 7 - pl_lock: JSONVAR; + THIS^.NodeNumber := NodeNumber + 1; 8 - /// payload unlock + 9 - pl_unlk: JSONVAR; + THIS^.timerData.IN := TRUE; 10 - /// state_topic + + + + 2 + + THIS^.NodeInitialized := TRUE; + + + + + + 11 - stat_t: JSONVAR; + METHOD InitNode 12 - /// state locked + VAR_INPUT 13 - stat_locked: JSONVAR; + DeviceAddress: BYTE; 14 - /// state unlocked + NodeNumber: UINT; 15 - stat_unlocked: JSONVAR; + DataPollingInterval: TIME; 16 - /// optimistic - - - 17 - - opt: JSONVAR; - - - 18 - - END_STRUCT - - - 19 - - END_TYPE + END_VAR 1 @@ -25828,21 +23715,19 @@ - 19 - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + 6da195a7-86d2-4618-bcdb-49518274d9f3 - MqttDiscovery - Messages + FB_RS485_DUCO_DUCOBOX_NODE_MQTT -1 False - 58ffd74c-08b2-425f-9cd5-1cd6f4bec61c - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_SENSOR + 98b35e54-97b2-4227-bca4-337378a9d265 + 6da195a7-86d2-4618-bcdb-49518274d9f3 + ProcessDataArray @@ -25860,175 +23745,98 @@ - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc + f8a58466-d7f6-439f-bbb8-d4600e41d099 a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119892250296735 + 638103389529316913 - - + + - - 2 - - TYPE MQTT_DISCOVERY_SENSOR EXTENDS MQTT_DISCOVERY_BASE : - 3 - STRUCT + THIS^.timerData.IN := TRUE; 4 - ///state_topic + 5 - stat_t: JSONVAR; + IF NOT Error^ THEN 6 - ///expire after + PubMqttMessage(Suffix := '/read/0', Data := WORD_TO_STRING(Data^[0])); 7 - exp_aft: JSONVAR; + PubMqttMessage(Suffix := '/read/1', Data := WORD_TO_STRING(Data^[1])); 8 - END_STRUCT + PubMqttMessage(Suffix := '/read/2', Data := WORD_TO_STRING(Data^[2])); 9 - END_TYPE + PubMqttMessage(Suffix := '/read/3', Data := WORD_TO_STRING(Data^[3])); - 1 + 10 - + PubMqttMessage(Suffix := '/read/4', Data := WORD_TO_STRING(Data^[4])); + + + 11 + + PubMqttMessage(Suffix := '/read/5', Data := WORD_TO_STRING(Data^[5])); + + + 2 + + END_IF - 9 - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - MqttDiscovery - Messages - - -1 - - - False - - 9e7721c2-c711-4bee-a683-6d9823e692a9 - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_SENSOR_ENT_CAT - - - - 24568a24-c491-472c-a21f-ee5d33859fab - - - - 0 - False - False - False - - False - - - - - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc - - a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - - 638119892250487276 - - - 2 - - TYPE MQTT_DISCOVERY_SENSOR_ENT_CAT EXTENDS MQTT_DISCOVERY_SENSOR : - - - 3 + 12 - STRUCT + METHOD ProcessDataArray - 4 + 13 - /// entity category + VAR_INPUT - 5 + 14 - ent_cat: JSONVAR; + Error: POINTER TO BOOL; - 6 + 15 - END_STRUCT + Data: POINTER TO ARRAY[0..124] OF WORD; - 7 + 16 - END_TYPE + END_VAR 1 @@ -26038,21 +23846,19 @@ - 7 - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + 6da195a7-86d2-4618-bcdb-49518274d9f3 - MqttDiscovery - Messages + FB_RS485_DUCO_DUCOBOX_NODE_MQTT -1 False - a690381c-2055-480f-9ab3-f9abf5a6fc40 - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_SIREN + 816a26ad-fa61-4c29-b284-8d41f2463f2e + 6da195a7-86d2-4618-bcdb-49518274d9f3 + PubMqttMessage @@ -26070,125 +23876,88 @@ - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc + f8a58466-d7f6-439f-bbb8-d4600e41d099 a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119892250697276 + 638103389530446540 - - + + - - 2 - - TYPE MQTT_DISCOVERY_SIREN EXTENDS MQTT_DISCOVERY_BASE : - 3 - STRUCT + IF InitMqttDone THEN 4 - ///command_topic + pMqttPublishQueue^.AddMessage( 5 - cmd_t: JSONVAR; + Payload := Data, 6 - /// payload_on + Topic := CONCAT(CONCAT(CONCAT(CONCAT(MqttPublishTopicPrefix^, MqttPublishTopicSuffix), '/'), UINT_TO_STRING(NodeNumber)), Suffix ), 7 - pl_on: JSONVAR; + Qos := MQTT.QoS.ExactlyOnce, 8 - /// payload_off + MqttRetain := FALSE 9 - pl_off: JSONVAR; - - - 10 - - /// state_topic - - - 11 - - stat_t: JSONVAR; - - - 12 - - /// state on - - - 13 - - stat_on: JSONVAR; + ); - 14 + 2 - /// state off + END_IF + + + + + + - 15 + 10 - stat_off: JSONVAR; + METHOD PubMqttMessage - 16 + 11 - /// optimistic + VAR_INPUT - 17 + 12 - opt: JSONVAR; + Suffix: STRING(100); - 18 + 13 - END_STRUCT + Data: STRING(100); - 19 + 14 - END_TYPE + END_VAR 1 @@ -26198,21 +23967,19 @@ - 19 - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + 6da195a7-86d2-4618-bcdb-49518274d9f3 - MqttDiscovery - Messages + FB_RS485_DUCO_DUCOBOX_NODE_MQTT -1 False - 89e23349-328d-4437-a909-95a772caa4aa - 00000000-0000-0000-0000-000000000000 - MQTT_DISCOVERY_SWITCH + 6f3af5be-1a1b-4474-af9f-b3b4961b2598 + 6da195a7-86d2-4618-bcdb-49518274d9f3 + RequestBusTime @@ -26230,135 +23997,169 @@ - - - 829a18f2-c514-4f6e-9634-1df173429203 - - - - - - - 21af5390-2942-461a-bf89-951aaf6999f1 - - - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 - - - - - - - 2db5746d-d284-4425-9f7f-2663a34b0ebc + f8a58466-d7f6-439f-bbb8-d4600e41d099 a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119892250877250 + 638103389529596961 - - + + - - 2 - - TYPE MQTT_DISCOVERY_SWITCH EXTENDS MQTT_DISCOVERY_BASE : - 3 - STRUCT + IF NOT NodeInitialized THEN 4 - ///command_topic + RequestBusTime := FALSE; 5 - cmd_t: JSONVAR; + ELSIF timerData.Q THEN 6 - /// payload_on + RequestBusTime := TRUE; 7 - pl_on: JSONVAR; + ELSE 8 - /// payload_off + RequestBusTime := FALSE; - 9 + 2 - pl_off: JSONVAR; + END_IF + + + + + + - 10 + 9 - /// state_topic + METHOD RequestBusTime : BOOL - 11 + 1 - stat_t: JSONVAR; + + + + + + + 6da195a7-86d2-4618-bcdb-49518274d9f3 + + FB_RS485_DUCO_DUCOBOX_NODE_MQTT + + -1 + + + False + + 333dbf37-ebcd-46b9-be3b-adc8ad3216f3 + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + GetRtuQuery + + + + 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 + + 638103326551448711 + + + + + - 12 + 3 - /// state on + IF timerData.Q THEN - 13 + 4 - stat_on: JSONVAR; + THIS^.timerData.IN := FALSE; - 14 + 5 - /// state off + IF DeviceType = RS485_EASTRON_SDM_Devices.SDM120 OR DeviceType = RS485_EASTRON_SDM_Devices.SDM220 THEN - 15 + 6 - stat_off: JSONVAR; + GetRtuQuery := THIS^.SDM120AndSDM220RtuQuery; - 16 + 7 - /// optimistic + END_IF - 17 + 8 - opt: JSONVAR; + IF DeviceType = RS485_EASTRON_SDM_Devices.SDM630 THEN - 18 + 9 - /// device class + GetRtuQuery := THIS^.SDM630RtuQuery; - 19 + 10 - dev_cla: JSONVAR; + END_IF - 20 + 2 - END_STRUCT + END_IF + + + + + + - 21 + 11 - END_TYPE + METHOD GetRtuQuery : RS485_RtuQuery 1 @@ -26368,21 +24169,19 @@ - 21 - 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 - MqttDiscovery - Messages + FB_RS485_EASTRON_SDM_POWER_MQTT -1 False - 15ef830f-d40e-4914-9df5-2bcaf523565c - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - CreateBinarySensorEntity + dbf3b033-3fa0-4bef-ae08-ea325660b4dc + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + InitMqtt @@ -26406,7 +24205,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891893882957 + 638103326552160124 @@ -26415,12 +24214,12 @@ 3 - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + THIS^.pMqttPublishQueue := pMqttPublishQueue; 4 - + THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; 5 @@ -26430,376 +24229,363 @@ 6 - // Entity related: Basis + InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(THIS^.InstanceName)) + 1; 7 - MqttDiscMsgBinSens.name.CharString := name; // friendly name + THIS^.MqttPublishTopicSuffix := InstanceNamePt^; 8 - MqttDiscMsgBinSens.obj_id.CharString := Id; + + + + 2 + + THIS^.InitMqttDone := TRUE; + + + + + + 9 - MqttDiscMsgBinSens.uniq_id.CharString := Id; + METHOD InitMqtt 10 - + VAR_INPUT 11 - // Entity related: Specific + MQTTPublishPrefix: POINTER TO STRING; 12 - MqttDiscMsgBinSens.stat_t.CharString := StateTopic; + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; 13 - MqttDiscMsgBinSens.pl_on.CharString := PayloadOn; + END_VAR 14 - MqttDiscMsgBinSens.pl_off.CharString := PayloadOff; + VAR 15 - MqttDiscMsgBinSens.dev_cla.CharString := DeviceClass; + InstanceNamePt: POINTER TO STRING; 16 - - - - 17 - - // Availabilty related - - - 18 - - MqttDiscMsgBinSens.avty[1].topic.CharString := THIS^.availabilityTopic1; - - - 19 - - MqttDiscMsgBinSens.avty[2].topic.CharString := THIS^.availabilityTopic2; - - - 20 - - MqttDiscMsgBinSens.avty_mode.CharString := 'all'; - - - 21 - - MqttDiscMsgBinSens.pl_avail.CharString := THIS^.availabilityOnline; - - - 22 - - MqttDiscMsgBinSens.pl_not_avail.CharString := THIS^.availabilityOffline; - - - 23 - - MqttDiscMsgBinSens.qos.Integer := 2; + END_VAR - 24 + 1 - - 25 - - // Device related - - - 26 - - MqttDiscMsgBinSens.dev.cu.CharString := THIS^.cu; - - - 27 - - MqttDiscMsgBinSens.dev.name.CharString := THIS^.name; - - - 28 - - MqttDiscMsgBinSens.dev.hw.CharString := THIS^.hw; - - - 29 - - MqttDiscMsgBinSens.dev.ids.CharString := THIS^.ids; - - - 30 - - MqttDiscMsgBinSens.dev.sw.CharString := THIS^.sw; - - - 31 - - MqttDiscMsgBinSens.dev.mdl.CharString := THIS^.mdl; - - - 32 - - MqttDiscMsgBinSens.dev.mf.CharString := THIS^.mf; + + + + + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + + FB_RS485_EASTRON_SDM_POWER_MQTT + + -1 + + + False + + 1dfb6296-ec83-451a-8f4a-b952d2f4c484 + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + InitRS485 + + + + 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 + + 638103326552503645 + + + + + - 33 + 3 - + THIS^.timerData.PT := DataPollingInterval; - 34 + 4 - // Extra meta-data + THIS^.SDM120AndSDM220RtuQuery.DeviceId := DeviceAddress; - 35 + 5 - IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN + THIS^.SDM630RtuQuery.DeviceId := DeviceAddress; - 36 + 6 - MqttDiscMsgBinSens.meta.CharString := meta; + THIS^.timerData.IN := TRUE; - 37 + 7 - END_IF + THIS^.DeviceType := DeviceType; - 38 + 8 - 39 - - ComposeJSON( - - - 40 - - JSONString:= ADR(MqttJSON), - - - 41 + 2 - JSONStringSize:= SIZEOF(MqttJSON), + THIS^.InitRS485Done := TRUE; + + + + + + - 42 + 9 - JSONVars:= ADR(MqttDiscMsgBinSens), + METHOD InitRS485 - 43 + 10 - NumberOfVars:= SIZEOF(MqttDiscMsgBinSens) / SIZEOF(JSONVAR), + VAR_INPUT - 44 + 11 - MaxLevel := 1, + DataPollingInterval: TIME; - 45 + 12 - ); + DeviceAddress: BYTE; - 46 + 13 - ComposeJSON.Execute := TRUE; + DeviceType: RS485_EASTRON_SDM_Devices; - 47 + 14 - ComposeJSON(); + END_VAR - 48 + 1 - - 49 - - IF MqttJSON = '' THEN - - - 50 - - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); - - - 51 - - ELSIF NOT (MqttJSON = '') THEN - - - 52 - - pMqttPublishQueue^.AddMessage( - - - 53 - - Payload:= MqttJSON, - - - 54 - - Topic := MqttTopic, - - - 55 - - Qos := MQTT.QoS.ExactlyOnce, - - - 56 - - MqttRetain := TRUE, + + + + + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + + FB_RS485_EASTRON_SDM_POWER_MQTT + + -1 + + + False + + 1a4d1912-d02c-4e04-92e8-871ffaac1da6 + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + ProcessDataArray + + + + 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 + + 638103326552872370 + + + + + - 57 + 3 - ); + THIS^.Error := Error^; - 58 + 4 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + THIS^.timerData.IN := TRUE; - 59 + 5 - END_IF + - 2 + 6 - + IF Error^ THEN - - - - - - - 60 + 7 - {attribute 'reflection' := ''} + PubMqttMessage(Suffix := '/availability', Data := 'offline'); - 61 + 8 - METHOD CreateBinarySensorEntity + ELSE - 62 + 9 - VAR_INPUT + PubMqttMessage(Suffix := '/availability', Data := 'online'); - 63 + 10 - /// default + END_IF - 64 + 11 - Name: STRING; + - 65 + 12 - Id: STRING; + IF NOT Error^ THEN - 66 + 13 - Meta: STRING; + THIS^.ACTIVEPOWER := SwapWordsToReal(Data^[0], Data^[1]); - 67 + 14 - /// entity specific + THIS^.isDataUpdated := TRUE; - 68 + 15 - StateTopic: STRING; + END_IF - 69 + 16 - PayloadOn: STRING; + - 70 + 17 - PayloadOff: STRING; + ActiveDevice := FALSE; - 71 + 18 - DeviceClass: STRING; + - 72 + 19 - END_VAR + - 73 + 20 - VAR + - 74 + 2 - EntityId: STRING(25) := 'binary_sensor'; + + + + + + + + + + 21 + + METHOD ProcessDataArray - 75 + 22 - ComposeJSON: STRUCT_TO_JSON; + VAR_INPUT - 76 + 23 - MqttJSON: STRING(1500); + Error: POINTER TO BOOL; - 77 + 24 - MqttTopic: STRING(100); + Data: POINTER TO ARRAY[0..124] OF WORD; - 78 + 25 END_VAR @@ -26812,19 +24598,18 @@ - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 - MqttDiscovery - FB_BASE_MQTT_DISCOVERY_DEVICE + FB_RS485_EASTRON_SDM_POWER_MQTT -1 False - 84a05479-d9f3-44bb-95ff-594f6df7e337 - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - CreateBinarySensorEntityWithCategory + 236983d6-b20a-4991-811a-245d9ab2ffdb + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + PubMqttMessage @@ -26848,7 +24633,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891897672949 + 638103326551139504 @@ -26857,406 +24642,580 @@ 3 - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + IF InitMqttDone THEN 4 - + pMqttPublishQueue^.AddMessage( 5 - + Payload := Data, 6 - // Entity related: Basis + Topic := CONCAT(CONCAT(MqttPublishTopicPrefix^, MqttPublishTopicSuffix), Suffix ), 7 - MqttDiscMsgBinSensWCat.name.CharString := name; // friendly name + Qos := MQTT.QoS.ExactlyOnce, 8 - MqttDiscMsgBinSensWCat.obj_id.CharString := Id; + MqttRetain := FALSE 9 - MqttDiscMsgBinSensWCat.uniq_id.CharString := Id; + ); + + + 2 + + END_IF + + + + + + 10 - + METHOD PubMqttMessage 11 - // Entity related: Specific + VAR_INPUT 12 - MqttDiscMsgBinSensWCat.stat_t.CharString := StateTopic; + Suffix: STRING(100); 13 - MqttDiscMsgBinSensWCat.pl_on.CharString := PayloadOn; + Data: STRING(100); 14 - MqttDiscMsgBinSensWCat.pl_off.CharString := PayloadOff; + END_VAR - 15 + 1 - MqttDiscMsgBinSensWCat.dev_cla.CharString := DeviceClass; + - - 16 - - MqttDiscMsgBinSensWCat.ent_cat.CharString := EntityCategory; + + + + + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + + FB_RS485_EASTRON_SDM_POWER_MQTT + + -1 + + + False + + bb158147-189d-4cd6-829c-e3f886d74bf4 + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + RequestBusTime + + + + 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 + + 638103326551850643 + + + + + - 17 + 3 - + IF NOT InitRS485Done THEN - 18 + 4 - // Availabilty related + RequestBusTime := FALSE; - 19 + 5 - MqttDiscMsgBinSensWCat.avty[1].topic.CharString := THIS^.availabilityTopic1; + ELSIF timerData.Q THEN - 20 + 6 - MqttDiscMsgBinSensWCat.avty[2].topic.CharString := THIS^.availabilityTopic2; + RequestBusTime := TRUE; - 21 + 7 - MqttDiscMsgBinSensWCat.avty_mode.CharString := 'all'; + ELSE - 22 + 8 - MqttDiscMsgBinSensWCat.pl_avail.CharString := THIS^.availabilityOnline; + RequestBusTime := FALSE; - 23 + 2 - MqttDiscMsgBinSensWCat.pl_not_avail.CharString := THIS^.availabilityOffline; + END_IF + + + + + + - 24 + 9 - MqttDiscMsgBinSensWCat.qos.Integer := 2; + METHOD RequestBusTime : BOOL - 25 + 1 - - 26 - - // Device related - - - 27 - - MqttDiscMsgBinSensWCat.dev.cu.CharString := THIS^.cu; + + + + + b24bc2f9-2e7c-4fd5-9ba9-b49bb0e46e91 + + FB_RS485_EASTRON_SDM_POWER_MQTT + + -1 + + + False + + c2816008-578a-495d-aa59-42fedf1bc654 + 98167287-8297-40e7-8354-c4ecab8b3787 + GetRtuQuery + + + + 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 + + 638103326556987689 + + + + + - 28 + 3 - MqttDiscMsgBinSensWCat.dev.name.CharString := THIS^.name; + IF timerData1.Q THEN - 29 + 4 - MqttDiscMsgBinSensWCat.dev.hw.CharString := THIS^.hw; + THIS^.timerData1.IN := FALSE; - 30 + 5 - MqttDiscMsgBinSensWCat.dev.ids.CharString := THIS^.ids; + THIS^.ActiveRtuQuery := 1; - 31 + 6 - MqttDiscMsgBinSensWCat.dev.sw.CharString := THIS^.sw; + GetRtuQuery := THIS^.Data1RtuQuery; - 32 + 7 - MqttDiscMsgBinSensWCat.dev.mdl.CharString := THIS^.mdl; + ELSIF timerData2.Q THEN - 33 + 8 - MqttDiscMsgBinSensWCat.dev.mf.CharString := THIS^.mf; + THIS^.timerData2.IN := FALSE; - 34 + 9 - + THIS^.ActiveRtuQuery := 2; - 35 + 10 - // Extra meta-data + GetRtuQuery := THIS^.Data2RtuQuery; - 36 + 11 - IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN + ELSIF timerData3.Q THEN - 37 + 12 - MqttDiscMsgBinSensWCat.meta.CharString := meta; + THIS^.timerData3.IN := FALSE; - 38 + 13 - END_IF + THIS^.ActiveRtuQuery := 3; - 39 + 14 - + GetRtuQuery := THIS^.Data3RtuQuery; - 40 + 2 - ComposeJSON( + END_IF + + + + + + - 41 + 15 - JSONString:= ADR(MqttJSON), + METHOD GetRtuQuery : RS485_RtuQuery - 42 + 1 - JSONStringSize:= SIZEOF(MqttJSON), + - - 43 - - JSONVars:= ADR(MqttDiscMsgBinSensWCat), + + + + + 98167287-8297-40e7-8354-c4ecab8b3787 + + FB_RS485_EASTRON_SDM220_MQTT + + -1 + + + False + + 58603822-6916-4088-ad30-98dcf6b9779b + 98167287-8297-40e7-8354-c4ecab8b3787 + 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 + + 638103326557711312 + + + + + - 44 + 3 - NumberOfVars:= SIZEOF(MqttDiscMsgBinSensWCat) / SIZEOF(JSONVAR), + THIS^.pMqttPublishQueue := pMqttPublishQueue; - 45 + 4 - MaxLevel := 1, + THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; - 46 + 5 - ); + - 47 + 6 - ComposeJSON.Execute := TRUE; + InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(THIS^.InstanceName)) + 1; - 48 + 7 - ComposeJSON(); + THIS^.MqttPublishTopicSuffix := InstanceNamePt^; - 49 + 8 - 50 - - IF MqttJSON = '' THEN - - - 51 - - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); - - - 52 + 2 - ELSIF NOT (MqttJSON = '') THEN + THIS^.InitMqttDone := TRUE; + + + + + + - 53 + 9 - pMqttPublishQueue^.AddMessage( + METHOD InitMqtt - 54 + 10 - Payload:= MqttJSON, + VAR_INPUT - 55 + 11 - Topic := MqttTopic, + MQTTPublishPrefix: POINTER TO STRING; - 56 + 12 - Qos := MQTT.QoS.ExactlyOnce, + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; - 57 + 13 - MqttRetain := TRUE, + END_VAR - 58 + 14 - ); + VAR - 59 + 15 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + InstanceNamePt: POINTER TO STRING; - 60 + 16 - END_IF + END_VAR - 2 + 1 - + + 98167287-8297-40e7-8354-c4ecab8b3787 + + FB_RS485_EASTRON_SDM220_MQTT + + -1 + + + False + + 49f1ae77-1980-43b6-84f7-f34c3c47b446 + 98167287-8297-40e7-8354-c4ecab8b3787 + InitRS485 + + + + 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 + + 638103326558020197 + + + - 61 - - {attribute 'reflection' := ''} - - - 62 + 3 - METHOD CreateBinarySensorEntityWithCategory + THIS^.timerData1.PT := Data1PollingInterval; - 63 + 4 - VAR_INPUT + THIS^.timerData2.PT := Data2PollingInterval; - 64 + 5 - /// default + THIS^.timerData3.PT := Data3PollingInterval; - 65 + 6 - Name: STRING; + - 66 + 7 - Id: STRING; + THIS^.Data1RtuQuery.DeviceId := DeviceAddress; - 67 + 8 - Meta: STRING; + THIS^.Data2RtuQuery.DeviceId := DeviceAddress; - 68 + 9 - /// entity specific + THIS^.Data3RtuQuery.DeviceId := DeviceAddress; - 69 + 10 - StateTopic: STRING; + - 70 + 11 - PayloadOn: STRING; + THIS^.timerData1.IN := TRUE; - 71 + 12 - PayloadOff: STRING; + THIS^.timerData2.IN := TRUE; - 72 + 13 - DeviceClass: STRING; + THIS^.timerData3.IN := TRUE; - 73 + 14 - /// config or diagnostic + - 74 + 2 - EntityCategory: STRING; + THIS^.InitRS485Done := TRUE; + + + + + + - 75 + 15 - END_VAR + METHOD InitRS485 - 76 + 16 - VAR + VAR_INPUT - 77 + 17 - EntityId: STRING(25) := 'binary_sensor'; + Data1PollingInterval: TIME; - 78 + 18 - ComposeJSON: STRUCT_TO_JSON; + Data2PollingInterval: TIME; - 79 + 19 - MqttJSON: STRING(1500); + Data3PollingInterval: TIME; - 80 + 20 - MqttTopic: STRING(100); + DeviceAddress: BYTE; - 81 + 21 END_VAR @@ -27269,19 +25228,18 @@ - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 + 98167287-8297-40e7-8354-c4ecab8b3787 - MqttDiscovery - FB_BASE_MQTT_DISCOVERY_DEVICE + FB_RS485_EASTRON_SDM220_MQTT -1 False - 383d091c-3a64-4a06-bd90-0330831349bf - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - CreateCoverEntity + 3a56402d-d2dc-4680-b04d-d8167fb5c466 + 98167287-8297-40e7-8354-c4ecab8b3787 + ProcessDataArray @@ -27305,7 +25263,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891894312977 + 638103326558409549 @@ -27314,192 +25272,192 @@ 3 - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + IF Error^ THEN 4 - + PubMqttMessage(Suffix := '/availability', Data := 'offline'); 5 - // Entity related: Basis + ELSE 6 - MqttDiscMsgCover.name.CharString := name; // friendly name + PubMqttMessage(Suffix := '/availability', Data := 'online'); 7 - MqttDiscMsgCover.obj_id.CharString := Id; + END_IF 8 - MqttDiscMsgCover.uniq_id.CharString := Id; + 9 - + IF ActiveRtuQuery = 1 THEN 10 - // Entity related: Specific + THIS^.Error1 := Error^; 11 - MqttDiscMsgCover.cmd_t.CharString := CommandTopic; + THIS^.timerData1.IN := TRUE; 12 - MqttDiscMsgCover.pl_open.CharString := PayloadOpen; + IF NOT Error^ THEN 13 - MqttDiscMsgCover.pl_cls.CharString := PayloadClose; + THIS^.VOLTAGE := SwapWordsToReal(Data^[0], Data^[1]); 14 - MqttDiscMsgCover.pl_stop.CharString := PayloadStop; + THIS^.CURRENT := SwapWordsToReal(Data^[6], Data^[7]); 15 - MqttDiscMsgCover.stat_t.CharString := StateTopic; + THIS^.ACTIVEPOWER := SwapWordsToReal(Data^[12], Data^[13]); 16 - MqttDiscMsgCover.stat_open.CharString := StateOpen; + THIS^.APPARENT_POWER := SwapWordsToReal(Data^[18], Data^[19]); 17 - MqttDiscMsgCover.stat_clsd.CharString := StateClosed; + THIS^.REACTIVE_POWER := SwapWordsToReal(Data^[24], Data^[25]); 18 - MqttDiscMsgCover.opt.Boolean := FALSE; + THIS^.POWER_FACTOR := SwapWordsToReal(Data^[30], Data^[31]); 19 - MqttDiscMsgCover.dev_cla.CharString := Deviceclass; + THIS^.PHASE_ANGLE := SwapWordsToReal(Data^[36], Data^[37]); 20 - + THIS^.Update1 := TRUE; 21 - // Availabilty related + END_IF 22 - MqttDiscMsgCover.avty[1].topic.CharString := THIS^.availabilityTopic1; + ELSIF ActiveRtuQuery = 2 THEN 23 - MqttDiscMsgCover.avty[2].topic.CharString := THIS^.availabilityTopic2; + THIS^.Error2:= Error^; 24 - MqttDiscMsgCover.avty_mode.CharString := 'all'; + THIS^.timerData2.IN := TRUE; 25 - MqttDiscMsgCover.pl_avail.CharString := THIS^.availabilityOnline; + IF NOT Error^ THEN 26 - MqttDiscMsgCover.pl_not_avail.CharString := THIS^.availabilityOffline; + THIS^.FREQUENCY := SwapWordsToReal(Data^[0], Data^[1]); 27 - MqttDiscMsgCover.qos.Integer := 2; + THIS^.IMPORT_ACTIVE_ENERGY := SwapWordsToReal(Data^[2], Data^[3]); 28 - + THIS^.EXPORT_ACTIVE_ENERGY := SwapWordsToReal(Data^[4], Data^[5]); 29 - // Device related + THIS^.IMPORT_REACTIVE_ENERGY := SwapWordsToReal(Data^[6], Data^[7]); 30 - MqttDiscMsgCover.dev.cu.CharString := THIS^.cu; + THIS^.EXPORT_REACTIVE_ENERGY := SwapWordsToReal(Data^[8], Data^[9]); 31 - MqttDiscMsgCover.dev.name.CharString := THIS^.name; + THIS^.Update2 := TRUE; 32 - MqttDiscMsgCover.dev.hw.CharString := THIS^.hw; + END_IF 33 - MqttDiscMsgCover.dev.ids.CharString := THIS^.ids; + ELSIF ActiveRtuQuery = 3 THEN 34 - MqttDiscMsgCover.dev.sw.CharString := THIS^.sw; + THIS^.Error3 := Error^; 35 - MqttDiscMsgCover.dev.mdl.CharString := THIS^.mdl; + THIS^.timerData3.IN := TRUE; 36 - MqttDiscMsgCover.dev.mf.CharString := THIS^.mf; + IF NOT Error^ THEN 37 - + THIS^.TOTAL_ACTIVE_ENERGY := SwapWordsToReal(Data^[0], Data^[1]); 38 - // Extra meta-data + THIS^.TOTAL_REACTIVE_ENERGY := SwapWordsToReal(Data^[2], Data^[3]); 39 - IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN + THIS^.Update3 := TRUE; 40 - MqttDiscMsgCover.meta.CharString := meta; + END_IF 41 @@ -27514,228 +25472,467 @@ 43 - ComposeJSON( + ActiveRtuQuery := 0; 44 - JSONString:= ADR(MqttJSON), + ActiveDevice := FALSE; 45 - JSONStringSize:= SIZEOF(MqttJSON), + 46 - JSONVars:= ADR(MqttDiscMsgCover), + 47 - NumberOfVars:= SIZEOF(MqttDiscMsgCover) / SIZEOF(JSONVAR), + + + + 2 + + + + + + + + 48 - MaxLevel := 1, + METHOD ProcessDataArray 49 - ); + VAR_INPUT 50 - ComposeJSON.Execute := TRUE; + Error: POINTER TO BOOL; 51 - ComposeJSON(); + Data: POINTER TO ARRAY[0..124] OF WORD; 52 + END_VAR + + + 1 + + + + + + 98167287-8297-40e7-8354-c4ecab8b3787 + + FB_RS485_EASTRON_SDM220_MQTT + + -1 + + + False + + 08adb491-aa8b-4186-8b2d-ca29e654144e + 98167287-8297-40e7-8354-c4ecab8b3787 + PubMqttMessage + + + + 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 + + 638103326556688501 + + + + + - 53 + 3 - IF MqttJSON = '' THEN + IF InitMqttDone THEN - 54 + 4 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + pMqttPublishQueue^.AddMessage( - 55 + 5 - ELSIF NOT (MqttJSON = '') THEN + Payload := Data, - 56 + 6 - pMqttPublishQueue^.AddMessage( + Topic := CONCAT(CONCAT(MqttPublishTopicPrefix^, MqttPublishTopicSuffix), Suffix ), - 57 + 7 - Payload:= MqttJSON, + Qos := MQTT.QoS.ExactlyOnce, - 58 + 8 - Topic := MqttTopic, + MqttRetain := FALSE - 59 + 9 - Qos := MQTT.QoS.ExactlyOnce, + ); - 60 + 2 - MqttRetain := TRUE, + END_IF + + + + + + - 61 + 10 - ); + METHOD PubMqttMessage - 62 + 11 + + VAR_INPUT + + + 12 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + Suffix: STRING(100); - 63 + 13 - END_IF + Data: STRING(100); - 2 + 14 + + END_VAR + + + 1 - + + 98167287-8297-40e7-8354-c4ecab8b3787 + + FB_RS485_EASTRON_SDM220_MQTT + + -1 + + + False + + 0adc2936-dc0e-49ef-a6e0-71608dca83d8 + 98167287-8297-40e7-8354-c4ecab8b3787 + RequestBusTime + + + + 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 + + 638103326557296851 + + + - 64 + 3 - METHOD CreateCoverEntity + IF NOT InitRS485Done THEN - 65 + 4 - VAR_INPUT + RequestBusTime := FALSE; - 66 + 5 - /// default + ELSIF timerData1.Q OR timerData2.Q OR timerData3.Q THEN - 67 + 6 - Name: STRING; + RequestBusTime := TRUE; - 68 + 7 - Id: STRING; + ELSE - 69 + 8 - Meta: STRING; + RequestBusTime := FALSE; - 70 + 2 - /// entity specific + END_IF + + + + + + - 71 + 9 - CommandTopic: STRING; + METHOD RequestBusTime : BOOL - 72 + 1 - PayloadOpen: STRING; + + + + + + + 98167287-8297-40e7-8354-c4ecab8b3787 + + FB_RS485_EASTRON_SDM220_MQTT + + -1 + + + False + + 7b0676a2-9810-4121-b9d6-24902c186aa9 + c15e7142-c256-438c-b11e-9d0e3b37e53c + EnableOwd + + + + 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 + + 638103326559292346 + + + + + - 73 + 3 - PayloadClose: STRING; + THIS^.OwdDevices[OwdNumber].InitOwd( - 74 + 4 - PayloadStop: STRING; + DeviceAddress := THIS^.DeviceAddress, - 75 + 5 - StateTopic: STRING; + OwdNumber := OwdNumber, - 76 + 6 - StateOpen: STRING; + DataPollingInterval := DataPollingInterval - 77 + 2 - StateClosed: STRING; + ); + + + + + + - 78 + 7 - Deviceclass: STRING; + METHOD EnableOwd : BOOL - 79 + 8 + + VAR_INPUT + + + 9 + + OwdNumber: UINT; + + + 10 + + DataPollingInterval: TIME; + + + 11 END_VAR - 80 + 1 - VAR + + + + + + + c15e7142-c256-438c-b11e-9d0e3b37e53c + + FB_RS485_ESERA_1WIRE_GATEWAY_MQTT + + -1 + + + False + + 0856600a-7f45-4285-bb29-6e9efc3545ab + c15e7142-c256-438c-b11e-9d0e3b37e53c + GetRtuQuery + + + + 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 + + 638103326561038294 + + + + + - 81 + 3 - EntityId: STRING(25) := 'cover'; + IF timerData.Q THEN - 82 + 4 - ComposeJSON: STRUCT_TO_JSON; + THIS^.timerData.IN := FALSE; - 83 + 5 - MqttJSON: STRING(1500); + GetRtuQuery := THIS^.OwdDevices[ActiveOwd].GetRtuQuery(); - 84 + 2 - MqttTopic: STRING(100); + END_IF + + + + + + - 85 + 6 - END_VAR + METHOD GetRtuQuery : RS485_RtuQuery 1 @@ -27746,19 +25943,18 @@ - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 + c15e7142-c256-438c-b11e-9d0e3b37e53c - MqttDiscovery - FB_BASE_MQTT_DISCOVERY_DEVICE + FB_RS485_ESERA_1WIRE_GATEWAY_MQTT -1 False - b61fd448-3e18-4e0a-9cc3-be64bb51a2b4 - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - CreateLightDimmerEntity + 3ce96a37-22ea-45e4-89b6-c39dd2524835 + c15e7142-c256-438c-b11e-9d0e3b37e53c + InitMqtt @@ -27782,7 +25978,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891896802956 + 638103326559596741 @@ -27791,7 +25987,7 @@ 3 - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + InstanceNamePt := CommonTypesAndFunctions.FindLastDot(ADR(THIS^.InstanceName)) + 1; 4 @@ -27801,327 +25997,390 @@ 5 - // Entity related: Basis + FOR loopCounter := 1 TO 30 DO 6 - MqttDiscMsgLightDim.name.CharString := name; // friendly name + OwdDevices[loopCounter].InitMqtt( 7 - MqttDiscMsgLightDim.obj_id.CharString := Id; + MQTTPublishPrefix := MQTTPublishPrefix, 8 - MqttDiscMsgLightDim.uniq_id.CharString := Id; + MqttPublishTopicSuffix := InstanceNamePt^, 9 - + pMqttPublishQueue := pMqttPublishQueue 10 - // Entity related: Specific + ); + + + 2 + + END_FOR + + + + + + 11 - MqttDiscMsgLightDim.cmd_t.CharString := CommandTopic; + METHOD InitMqtt 12 - MqttDiscMsgLightDim.pl_on.CharString := PayloadOn; + VAR_INPUT 13 - MqttDiscMsgLightDim.pl_off.CharString := PayloadOff; + MQTTPublishPrefix: POINTER TO STRING; 14 - MqttDiscMsgLightDim.stat_t.CharString := StateTopic; + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; 15 - MqttDiscMsgLightDim.opt.Boolean := FALSE; + END_VAR 16 - + VAR 17 - MqttDiscMsgLightDim.bri_cmd_t.CharString := BrightnessCommandTopic; + InstanceNamePt: POINTER TO STRING; 18 - MqttDiscMsgLightDim.bri_stat_t.CharString := BrightnessStateTopic; - - - 19 - - MqttDiscMsgLightDim.bri_scl.Integer := BrightnessScale; - - - 20 - - MqttDiscMsgLightDim.on_cmd_type.CharString := 'last'; + END_VAR - 21 + 1 - - 22 - - MqttDiscMsgLightDim.dmxChannel.Integer := DmxChannel; - - - 23 - - MqttDiscMsgLightDim.dmxWidth.Integer := DmxWidth; - - - 24 - - MqttDiscMsgLightDim.dmxUniverse.Integer := DmxUniverse; + + + + + c15e7142-c256-438c-b11e-9d0e3b37e53c + + FB_RS485_ESERA_1WIRE_GATEWAY_MQTT + + -1 + + + False + + 10298b50-6428-498d-8112-32867d4ed647 + c15e7142-c256-438c-b11e-9d0e3b37e53c + InitRS485 + + + + 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 + + 638103326559915889 + + + + + - 25 + 3 - + THIS^.DeviceAddress := DeviceAddress; - 26 + 4 - // Availabilty related + THIS^.timerData.PT := T#250MS; - 27 + 5 - MqttDiscMsgLightDim.avty[1].topic.CharString := THIS^.availabilityTopic1; + THIS^.timerData.IN := TRUE; - 28 + 2 - MqttDiscMsgLightDim.avty[2].topic.CharString := THIS^.availabilityTopic2; + THIS^.InitRS485Done := TRUE; + + + + + + - 29 + 6 - MqttDiscMsgLightDim.avty_mode.CharString := 'all'; + METHOD InitRS485 - 30 + 7 - MqttDiscMsgLightDim.pl_avail.CharString := THIS^.availabilityOnline; + VAR_INPUT - 31 + 8 - MqttDiscMsgLightDim.pl_not_avail.CharString := THIS^.availabilityOffline; + DeviceAddress: BYTE; - 32 + 9 - MqttDiscMsgLightDim.qos.Integer := 2; + END_VAR - 33 + 1 - - 34 - - // Device related - - - 35 - - MqttDiscMsgLightDim.dev.cu.CharString := THIS^.cu; - - - 36 - - MqttDiscMsgLightDim.dev.name.CharString := THIS^.name; - - - 37 - - MqttDiscMsgLightDim.dev.hw.CharString := THIS^.hw; - - - 38 - - MqttDiscMsgLightDim.dev.ids.CharString := THIS^.ids; - - - 39 - - MqttDiscMsgLightDim.dev.sw.CharString := THIS^.sw; - - - 40 - - MqttDiscMsgLightDim.dev.mdl.CharString := THIS^.mdl; - - - 41 - - MqttDiscMsgLightDim.dev.mf.CharString := THIS^.mf; - - - 42 - - - - - 43 - - // Extra meta-data - - - 44 - - IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - - - 45 - - MqttDiscMsgLightDim.meta.CharString := meta; + + + + + c15e7142-c256-438c-b11e-9d0e3b37e53c + + FB_RS485_ESERA_1WIRE_GATEWAY_MQTT + + -1 + + + False + + fe3be894-5278-47fa-832e-b328d4129c95 + c15e7142-c256-438c-b11e-9d0e3b37e53c + ProcessDataArray + + + + 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 + + 638103326560739083 + + + + + - 46 + 3 - END_IF + THIS^.OwdDevices[ActiveOwd].ProcessDataArray( - 47 + 4 - + Data := Data, - 48 + 5 - ComposeJSON( + Error := Error - 49 + 6 - JSONString:= ADR(MqttJSON), + ); - 50 + 7 - JSONStringSize:= SIZEOF(MqttJSON), + THIS^.ActiveOwd := 0; - 51 + 2 - JSONVars:= ADR(MqttDiscMsgLightDim), + THIS^.timerData.IN := TRUE; + + + + + + - 52 + 8 - NumberOfVars:= SIZEOF(MqttDiscMsgLightDim) / SIZEOF(JSONVAR), + METHOD ProcessDataArray - 53 + 9 - MaxLevel := 1, + VAR_INPUT - 54 + 10 - ); + Error: POINTER TO BOOL; - 55 + 11 - ComposeJSON.Execute := TRUE; + Data: POINTER TO ARRAY[0..124] OF WORD; - 56 + 12 - ComposeJSON(); + END_VAR - 57 + 1 - - 58 - - IF MqttJSON = '' THEN - - - 59 - - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + + + + + c15e7142-c256-438c-b11e-9d0e3b37e53c + + FB_RS485_ESERA_1WIRE_GATEWAY_MQTT + + -1 + + + False + + d7d7dd9c-7520-42fb-b2aa-d2e6b17e41a6 + c15e7142-c256-438c-b11e-9d0e3b37e53c + RequestBusTime + + + + 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 + + 638103326560435031 + + + + + - 60 + 3 - ELSIF NOT (MqttJSON = '') THEN + IF NOT InitRS485Done OR NOT timerData.Q THEN - 61 + 4 - pMqttPublishQueue^.AddMessage( + RequestBusTime := FALSE; - 62 + 5 - Payload:= MqttJSON, + ELSE - 63 + 6 - Topic := MqttTopic, + FOR loopCounter := 1 TO 30 DO - 64 + 7 - Qos := MQTT.QoS.ExactlyOnce, + IF OwdDevices[loopCounter].RequestBusTime() AND RequestBusTime = FALSE THEN - 65 + 8 - MqttRetain := TRUE, + THIS^.ActiveOwd := loopCounter; - 66 + 9 - ); + RequestBusTime := TRUE; - 67 + 10 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + END_IF - 68 + 11 - END_IF + END_FOR 2 - + END_IF @@ -28130,127 +26389,199 @@ - 69 - - METHOD CreateLightDimmerEntity - - - 70 - - VAR_INPUT - - - 71 - - /// default - - - 72 - - Name: STRING; - - - 73 + 12 - Id: STRING; + METHOD RequestBusTime : BOOL - 74 + 1 - Meta: STRING; + - - 75 - - /// entity specific + + + + + c15e7142-c256-438c-b11e-9d0e3b37e53c + + FB_RS485_ESERA_1WIRE_GATEWAY_MQTT + + -1 + + + False + + 125cd1a1-e4a7-4a9c-b461-8d489a6c7555 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + GetRtuQuery + + + + 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 + + 638103326563013438 + + + + + - 76 + 3 - CommandTopic: STRING; + IF timerData.Q THEN - 77 + 4 - PayloadOn: STRING; + THIS^.timerData.IN := FALSE; - 78 + 5 - PayloadOff: STRING; + GetRtuQuery := THIS^.RtuQuery; - 79 + 2 - StateTopic: STRING; + END_IF + + + + + + - 80 + 6 - BrightnessCommandTopic: STRING; + METHOD GetRtuQuery : RS485_RtuQuery - 81 + 1 - BrightnessStateTopic: STRING; + - - 82 - - BrightnessScale: INT; + + + + + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + + FB_RS485_ESERA_OWD_MQTT + + -1 + + + False + + 55a394b4-67ce-4a17-ab8f-9c31c5283299 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + 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 + + 638103326565363788 + + + + + - 83 + 3 - /// dmx specific + THIS^.MqttPublishTopicPrefix := MQTTPublishPrefix; - 84 + 4 - DmxChannel: INT := 0; + THIS^.MqttPublishTopicSuffix := MqttPublishTopicSuffix; - 85 + 5 - DmxWidth: INT := 0; + THIS^.pMqttPublishQueue := pMqttPublishQueue; - 86 + 6 - DmxUniverse: INT := 0; + - 87 + 2 - END_VAR + THIS^.InitMqttDone := TRUE; + + + + + + - 88 + 7 - VAR + METHOD InitMqtt - 89 + 8 - EntityId: STRING(25) := 'light'; + VAR_INPUT - 90 + 9 - ComposeJSON: STRUCT_TO_JSON; + MQTTPublishPrefix: POINTER TO STRING; - 91 + 10 - MqttJSON: STRING(1500); + MqttPublishTopicSuffix: STRING(255); - 92 + 11 - MqttTopic: STRING(100); + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; - 93 + 12 END_VAR @@ -28263,19 +26594,18 @@ - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 - MqttDiscovery - FB_BASE_MQTT_DISCOVERY_DEVICE + FB_RS485_ESERA_OWD_MQTT -1 False - 39603b45-af9c-4d9e-ba72-a5d348be402d - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - CreateLightEntity + fcd9e993-4d76-42d3-bf14-28b914b97012 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + InitOwd @@ -28299,7 +26629,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891895122984 + 638103326565670896 @@ -28308,386 +26638,499 @@ 3 - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + THIS^.RtuQuery.DeviceId := DeviceAddress; 4 - + THIS^.RtuQuery.ReadAddress := OwdNumber * 100; 5 - // Entity related: Basis + THIS^.timerData.PT := DataPollingInterval; 6 - MqttDiscMsgLight.name.CharString := name; // friendly name + THIS^.OwdNumber := OwdNumber; 7 - MqttDiscMsgLight.obj_id.CharString := Id; + 8 - MqttDiscMsgLight.uniq_id.CharString := Id; + THIS^.timerData.IN := TRUE; 9 + + 2 + + THIS^.InitOwdDone := TRUE; + + + + + + + 10 - // Entity related: Specific + METHOD InitOwd 11 - MqttDiscMsgLight.cmd_t.CharString := CommandTopic; + VAR_INPUT 12 - MqttDiscMsgLight.pl_on.CharString := PayloadOn; + DeviceAddress: BYTE; 13 - MqttDiscMsgLight.pl_off.CharString := PayloadOff; + OwdNumber: UINT; 14 - MqttDiscMsgLight.stat_t.CharString := StateTopic; + DataPollingInterval: TIME; 15 - MqttDiscMsgLight.opt.Boolean := FALSE; + END_VAR - 16 + 1 - - 17 - - // Availabilty related + + + + + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + + FB_RS485_ESERA_OWD_MQTT + + -1 + + + False + + cff06864-4642-47d5-9c82-c5d5ed2296f0 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + ProcessAirQuality + + + + 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 + + 638103326563402432 + + + + + - 18 + 3 - MqttDiscMsgLight.avty[1].topic.CharString := THIS^.availabilityTopic1; + THIS^.AIR_QUALITY := WORD_TO_REAL(Data) / 100; - 19 + 2 - MqttDiscMsgLight.avty[2].topic.CharString := THIS^.availabilityTopic2; + PubMqttMessage(Suffix := '/AIRQ', Data := REAL_TO_STRING(AIR_QUALITY)); + + + + + + - 20 + 4 - MqttDiscMsgLight.avty_mode.CharString := 'all'; + METHOD ProcessAirQuality - 21 + 5 - MqttDiscMsgLight.pl_avail.CharString := THIS^.availabilityOnline; + VAR_INPUT - 22 + 6 - MqttDiscMsgLight.pl_not_avail.CharString := THIS^.availabilityOffline; + Data: WORD; - 23 + 7 - MqttDiscMsgLight.qos.Integer := 2; + END_VAR - 24 + 1 - - 25 - - // Device related - - - 26 - - MqttDiscMsgLight.dev.cu.CharString := THIS^.cu; - - - 27 - - MqttDiscMsgLight.dev.name.CharString := THIS^.name; - - - 28 - - MqttDiscMsgLight.dev.hw.CharString := THIS^.hw; + + + + + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + + FB_RS485_ESERA_OWD_MQTT + + -1 + + + False + + 06c71a77-eb2e-4d37-9195-781eecfb0184 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + ProcessBrigthness + + + + 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 + + 638103326561990965 + + + + + - 29 + 3 - MqttDiscMsgLight.dev.ids.CharString := THIS^.ids; + THIS^.BRIGHTNESS := WORD_TO_REAL(Data) / 100; - 30 + 2 - MqttDiscMsgLight.dev.sw.CharString := THIS^.sw; + PubMqttMessage(Suffix := '/BNESS', Data := REAL_TO_STRING(BRIGHTNESS)); + + + + + + - 31 + 4 - MqttDiscMsgLight.dev.mdl.CharString := THIS^.mdl; + METHOD ProcessBrigthness - 32 + 5 - MqttDiscMsgLight.dev.mf.CharString := THIS^.mf; + VAR_INPUT - 33 + 6 - + Data: WORD; - 34 + 7 - // Extra meta-data + END_VAR - 35 + 1 - IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN + - - 36 - - MqttDiscMsgLight.meta.CharString := meta; + + + + + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + + FB_RS485_ESERA_OWD_MQTT + + -1 + + + False + + 63a3c0cc-3577-4959-b57e-a8f337569c73 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + ProcessDataArray + + + + 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 + + 638103326562694290 + + + + + - 37 + 3 - END_IF + THIS^.timerData.IN := TRUE; - 38 + 4 - 39 - - ComposeJSON( - - - 40 + 5 - JSONString:= ADR(MqttJSON), + IF WORD_TO_INT(Data^[12]) <> 0 OR Error^ THEN - 41 + 6 - JSONStringSize:= SIZEOF(MqttJSON), + THIS^.Error := TRUE; - 42 + 7 - JSONVars:= ADR(MqttDiscMsgLight), + PubMqttMessage(Suffix := '/availability', Data := 'offline'); - 43 + 8 - NumberOfVars:= SIZEOF(MqttDiscMsgLight) / SIZEOF(JSONVAR), + ELSE - 44 + 9 - MaxLevel := 1, + THIS^.Error := FALSE; - 45 + 10 - ); + THIS^.DataAvailable := TRUE; - 46 + 11 - ComposeJSON.Execute := TRUE; + PubMqttMessage(Suffix := '/availability', Data := 'online'); - 47 + 12 - ComposeJSON(); + END_IF - 48 + 13 - 49 - - IF MqttJSON = '' THEN - - - 50 - - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); - - - 51 + 14 - ELSIF NOT (MqttJSON = '') THEN + // Data handling - 52 + 15 - pMqttPublishQueue^.AddMessage( + IF NOT Error^ AND WORD_TO_INT(Data^[12]) = 0 THEN - 53 + 16 - Payload:= MqttJSON, + IF Data^[16] = 11151 OR Data^[16] = 11152 THEN // Temperature, humidity & air quality - 54 + 17 - Topic := MqttTopic, + ProcessTemperature(Data^[0]); - 55 + 18 - Qos := MQTT.QoS.ExactlyOnce, + ProcessOwdVoltage(Data^[2]); - 56 + 19 - MqttRetain := TRUE, + ProcessHumidity(Data^[4]); - 57 + 20 - ); + ProcessDewPoint(Data^[6]); - 58 + 21 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + ProcessAirQuality(Data^[8]); - 59 + 22 - END_IF + ELSIF Data^[16] = 11102 OR Data^[16] = 11113 OR Data^[16] = 11120 OR Data^[16] = 11148 OR Data^[16] = 11150 OR Data^[16] = 11160 THEN // Temperature, humidity - 2 + 23 - + ProcessTemperature(Data^[0]); - - - - - - - 60 + 24 - METHOD CreateLightEntity + ProcessOwdVoltage(Data^[2]); - 61 + 25 - VAR_INPUT + ProcessHumidity(Data^[4]); - 62 + 26 - /// default + ProcessDewPoint(Data^[6]); - 63 + 27 - Name: STRING; + ELSIF Data^[16] = 11121 OR Data^[16] = 11132 OR Data^[16] = 11134 OR Data^[16] = 11135 THEN // Temperature, humidity, brightness - 64 + 28 - Id: STRING; + ProcessTemperature(Data^[0]); - 65 + 29 - Meta: STRING; + ProcessOwdVoltage(Data^[2]); - 66 + 30 - /// entity specific + ProcessHumidity(Data^[4]); - 67 + 31 - CommandTopic: STRING; + ProcessDewPoint(Data^[6]); - 68 + 32 - PayloadOn: STRING; + ProcessBrigthness(Data^[8]); - 69 + 33 - PayloadOff: STRING; + ELSIF Data^[16] = 1820 THEN // Temperature DS18B20 - 70 + 34 - StateTopic: STRING; + ProcessTemperature(Data^[0]); - 71 + 35 - END_VAR + END_IF - 72 + 2 - VAR + END_IF + + + + + + - 73 + 36 - EntityId: STRING(25) := 'light'; + METHOD ProcessDataArray - 74 + 37 - ComposeJSON: STRUCT_TO_JSON; + VAR_INPUT - 75 + 38 - MqttJSON: STRING(1500); + Error: POINTER TO BOOL; - 76 + 39 - MqttTopic: STRING(100); + Data: POINTER TO ARRAY[0..124] OF WORD; - 77 + 40 END_VAR @@ -28700,19 +27143,18 @@ - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 - MqttDiscovery - FB_BASE_MQTT_DISCOVERY_DEVICE + FB_RS485_ESERA_OWD_MQTT -1 False - c1828dc1-8bf3-4c1d-a131-457242b7b799 - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - CreateLockEntity + 8c8f2813-2f4a-4df1-95dc-59dc19ab5ad2 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + ProcessDewPoint @@ -28736,7 +27178,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891895493371 + 638103326563717081 @@ -28745,406 +27187,723 @@ 3 - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + THIS^.DEW_POINT := WORD_TO_REAL(Data) / 100; + + + 2 + + PubMqttMessage(Suffix := '/DEWP', Data := REAL_TO_STRING(DEW_POINT)); + + + + + + 4 - + METHOD ProcessDewPoint 5 - // Entity related: Basis + VAR_INPUT 6 - MqttDiscMsgLock.name.CharString := name; // friendly name + Data: WORD; 7 - MqttDiscMsgLock.obj_id.CharString := Id; - - - 8 - - MqttDiscMsgLock.uniq_id.CharString := Id; + END_VAR - 9 + 1 - - 10 - - // Entity related: Specific - - - 11 - - MqttDiscMsgLock.cmd_t.CharString := CommandTopic; + + + + + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + + FB_RS485_ESERA_OWD_MQTT + + -1 + + + False + + 5702621d-7d5f-4a48-854d-4968f2efcdb2 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + ProcessHumidity + + + + 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 + + 638103326564016301 + + + + + - 12 + 3 - MqttDiscMsgLock.pl_lock.CharString := PayloadLock; + THIS^.HUMIDITY := WORD_TO_REAL(Data) / 100; - 13 + 2 - MqttDiscMsgLock.pl_unlk.CharString := PayloadUnlock; + PubMqttMessage(Suffix := '/HUM', Data := REAL_TO_STRING(HUMIDITY)); + + + + + + - 14 + 4 - MqttDiscMsgLock.stat_t.CharString := StateTopic; + METHOD ProcessHumidity - 15 + 5 - MqttDiscMsgLock.stat_locked.CharString := StateLocked; + VAR_INPUT - 16 + 6 - MqttDiscMsgLock.stat_unlocked.CharString := StateUnlocked; + Data: WORD; - 17 + 7 - MqttDiscMsgLock.opt.Boolean := FALSE; + END_VAR - 18 + 1 - - 19 - - // Availabilty related + + + + + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + + FB_RS485_ESERA_OWD_MQTT + + -1 + + + False + + b3097b74-e2b0-4c73-8487-3877a0e4876f + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + ProcessOwdVoltage + + + + 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 + + 638103326564385326 + + + + + - 20 + 3 - MqttDiscMsgLock.avty[1].topic.CharString := THIS^.availabilityTopic1; + THIS^.OWD_VOLTAGE := WORD_TO_REAL(Data) / 100; - 21 + 2 - MqttDiscMsgLock.avty[2].topic.CharString := THIS^.availabilityTopic2; + PubMqttMessage(Suffix := '/OWDV', Data := REAL_TO_STRING(OWD_VOLTAGE)); + + + + + + - 22 + 4 - MqttDiscMsgLock.avty_mode.CharString := 'all'; + METHOD ProcessOwdVoltage - 23 + 5 - MqttDiscMsgLock.pl_avail.CharString := THIS^.availabilityOnline; + VAR_INPUT - 24 + 6 - MqttDiscMsgLock.pl_not_avail.CharString := THIS^.availabilityOffline; + Data: WORD; - 25 + 7 - MqttDiscMsgLock.qos.Integer := 2; + END_VAR - 26 + 1 - - 27 - - // Device related - - - 28 - - MqttDiscMsgLock.dev.cu.CharString := THIS^.cu; + + + + + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + + FB_RS485_ESERA_OWD_MQTT + + -1 + + + False + + c1b68752-979e-4788-9004-48b10ba95341 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + ProcessTemperature + + + + 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 + + 638103326564689709 + + + + + - 29 + 3 - MqttDiscMsgLock.dev.name.CharString := THIS^.name; + THIS^.TEMPERATURE := WORD_TO_REAL(Data) / 100; - 30 + 2 - MqttDiscMsgLock.dev.hw.CharString := THIS^.hw; + PubMqttMessage(Suffix := '/TEMP', Data := REAL_TO_STRING(TEMPERATURE)); + + + + + + - 31 + 4 - MqttDiscMsgLock.dev.ids.CharString := THIS^.ids; + METHOD ProcessTemperature - 32 + 5 - MqttDiscMsgLock.dev.sw.CharString := THIS^.sw; + VAR_INPUT - 33 + 6 - MqttDiscMsgLock.dev.mdl.CharString := THIS^.mdl; + Data: WORD; - 34 + 7 - MqttDiscMsgLock.dev.mf.CharString := THIS^.mf; + END_VAR - 35 + 1 - + - - 36 - - // Extra meta-data + + + + + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + + FB_RS485_ESERA_OWD_MQTT + + -1 + + + False + + 4e0a7d55-976c-4313-8409-76258001bc03 + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + PubMqttMessage + + + + 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 + + 638103326564994739 + + + + + - 37 + 3 - IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN + IF InitMqttDone THEN - 38 + 4 - MqttDiscMsgLock.meta.CharString := meta; + pMqttPublishQueue^.AddMessage( - 39 + 5 - END_IF + Payload := Data, - 40 + 6 - + Topic := CONCAT(CONCAT(CONCAT(CONCAT(MqttPublishTopicPrefix^, MqttPublishTopicSuffix), '/OWD/'), UINT_TO_STRING(OwdNumber)), Suffix ), - 41 + 7 - ComposeJSON( + Qos := MQTT.QoS.ExactlyOnce, - 42 + 8 - JSONString:= ADR(MqttJSON), + MqttRetain := FALSE - 43 + 9 - JSONStringSize:= SIZEOF(MqttJSON), + ); - 44 + 2 - JSONVars:= ADR(MqttDiscMsgLock), + END_IF + + + + + + - 45 + 10 - NumberOfVars:= SIZEOF(MqttDiscMsgLock) / SIZEOF(JSONVAR), + METHOD PubMqttMessage - 46 + 11 - MaxLevel := 1, + VAR_INPUT - 47 + 12 - ); + Suffix: STRING(100); - 48 + 13 - ComposeJSON.Execute := TRUE; + Data: STRING(100); - 49 + 14 - ComposeJSON(); + END_VAR - 50 + 1 - - 51 - - IF MqttJSON = '' THEN - - - 52 - - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); - - - 53 - - ELSIF NOT (MqttJSON = '') THEN + + + + + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + + FB_RS485_ESERA_OWD_MQTT + + -1 + + + False + + 10464a34-9abe-4168-80d1-f7c2fe7383fd + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + RequestBusTime + + + + 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 + + 638103326562369983 + + + + + - 54 + 3 - pMqttPublishQueue^.AddMessage( + IF NOT InitOwdDone THEN - 55 + 4 - Payload:= MqttJSON, + RequestBusTime := FALSE; - 56 + 5 - Topic := MqttTopic, + ELSIF timerData.Q THEN - 57 + 6 - Qos := MQTT.QoS.ExactlyOnce, + RequestBusTime := TRUE; - 58 + 7 - MqttRetain := TRUE, + ELSE - 59 + 8 - ); + RequestBusTime := FALSE; - 60 + 2 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + END_IF + + + + + + - 61 + 9 - END_IF + METHOD RequestBusTime : BOOL - 2 + 1 - + + bb58f587-9f45-44a1-8ab8-a2a557be2a09 + + FB_RS485_ESERA_OWD_MQTT + + -1 + + + False + + 1cbcfa4b-0748-4841-b663-0be0f4ae9e27 + 2d8d4e52-d630-40a2-99dd-1affee9ab859 + ConfigureFunctionBlockAsVirtualInput + + + + 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 + + 638115483690068247 + + + - 62 + 3 - METHOD CreateLockEntity + THIS^.DefaultValue:=DefaultValue; - 63 + 4 - VAR_INPUT + THIS^.SetDefaultValueStartup:=SetDefaultValueStartup; - 64 + 5 - /// default + THIS^.PublishAtStartup:=PublishAtStartup; - 65 + 6 - Name: STRING; + THIS^.UsePersistentAtStartup:=UsePersistentAtStartup; - 66 + 7 - Id: STRING; + THIS^.ConfirmReceival:=ConfirmReceival; - 67 + 2 - Meta: STRING; + THIS^.VirtualMode:=VIRTUAL_MODES.Input; + + + + + + - 68 + 8 - /// entity specific + METHOD ConfigureFunctionBlockAsVirtualInput : BOOL - 69 + 9 - CommandTopic: STRING; + VAR_INPUT - 70 + 10 - PayloadLock: STRING; + DefaultValue: BOOL; - 71 + 11 - PayloadUnlock: STRING; + SetDefaultValueStartup: BOOL; - 72 + 12 - StateTopic: STRING; + PublishAtStartup: BOOL; - 73 + 13 - StateLocked: STRING; + UsePersistentAtStartup: BOOL; - 74 + 14 - StateUnlocked: STRING; + ConfirmReceival: BOOL; - 75 + 15 END_VAR - 76 + 1 - VAR + + + + + + + 2d8d4e52-d630-40a2-99dd-1affee9ab859 + + FB_VIRTUAL_BOOL_MQTT + + -1 + + + False + + 28f15bea-ce5e-4422-8ca7-dc55f08bf0d0 + 2d8d4e52-d630-40a2-99dd-1affee9ab859 + ConfigureFunctionBlockAsVirtualOutput + + + + 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 + + 638115483690767867 + + + + + + + 3 + + THIS^.PublishAtStartup:=PublishAtStartup; - 77 + 2 - EntityId: STRING(25) := 'lock'; + THIS^.VirtualMode:=VIRTUAL_MODES.Output; + + + + + + - 78 + 4 - ComposeJSON: STRUCT_TO_JSON; + METHOD ConfigureFunctionBlockAsVirtualOutput : BOOL - 79 + 5 - MqttJSON: STRING(1500); + VAR_INPUT - 80 + 6 - MqttTopic: STRING(100); + PublishAtStartup: BOOL; - 81 + 7 END_VAR @@ -29157,19 +27916,18 @@ - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 + 2d8d4e52-d630-40a2-99dd-1affee9ab859 - MqttDiscovery - FB_BASE_MQTT_DISCOVERY_DEVICE + FB_VIRTUAL_BOOL_MQTT -1 False - 3c3b221f-dabf-4f9a-856a-a70a9a72a556 - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - CreateSensorEntity + 1f27fc21-de67-4840-b246-a472251873ea + 2d8d4e52-d630-40a2-99dd-1affee9ab859 + InitMqtt @@ -29193,7 +27951,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891896393375 + 638115483689357848 @@ -29202,7 +27960,7 @@ 3 - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + InitMqttDone := TRUE; 4 @@ -29212,47 +27970,47 @@ 5 - // Entity related: Basis + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important 6 - MqttDiscMsgSensor.name.CharString := name; // friendly name + 7 - MqttDiscMsgSensor.obj_id.CharString := Id; + (*pass trough*) 8 - MqttDiscMsgSensor.uniq_id.CharString := Id; + THIS^.pMqttPublishQueue := pMqttPublishQueue; 9 - + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; 10 - // Entity related: Specific + THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; 11 - //MqttDiscoverySensorMessage.ic.CharString := Icon; + THIS^.pMqttPublishQueue:=pMqttPublishQueue; 12 - MqttDiscMsgSensor.stat_t.CharString := StateTopic; + THIS^.MqttQos:=MqttQos; 13 - MqttDiscMsgSensor.exp_aft.Integer := ExpiryAfter; + THIS^.MqttRetain:=MqttRetain; 14 @@ -29262,222 +28020,415 @@ 15 - // Availabilty related + 16 - MqttDiscMsgSensor.avty[1].topic.CharString := THIS^.availabilityTopic1; + SUPER^.InitBaseMqtt(); 17 - MqttDiscMsgSensor.avty[2].topic.CharString := THIS^.availabilityTopic2; + pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received 18 - MqttDiscMsgSensor.avty_mode.CharString := 'all'; + + + + 2 + + + + + + + + 19 - MqttDiscMsgSensor.pl_avail.CharString := THIS^.availabilityOnline; + METHOD InitMqtt 20 - MqttDiscMsgSensor.pl_not_avail.CharString := THIS^.availabilityOffline; + VAR_INPUT 21 - MqttDiscMsgSensor.qos.Integer := 2; + MQTTPublishPrefix: POINTER TO STRING; 22 - + MQTTSubscribePrefix: POINTER TO STRING; 23 - // Device related + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; 24 - MqttDiscMsgSensor.dev.cu.CharString := THIS^.cu; + pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; 25 - MqttDiscMsgSensor.dev.name.CharString := THIS^.name; + MqttQos: MQTT.QoS; 26 - MqttDiscMsgSensor.dev.hw.CharString := THIS^.hw; + MqttRetain: BOOL; 27 - MqttDiscMsgSensor.dev.ids.CharString := THIS^.ids; + END_VAR - 28 + 1 - MqttDiscMsgSensor.dev.sw.CharString := THIS^.sw; + + + + + + + 2d8d4e52-d630-40a2-99dd-1affee9ab859 + + FB_VIRTUAL_BOOL_MQTT + + -1 + + + False + + 6b5db92a-fafb-4ea0-be0c-f0badeeb249b + 2d8d4e52-d630-40a2-99dd-1affee9ab859 + 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 + + 638115483689688262 + + + + + - 29 + 3 - MqttDiscMsgSensor.dev.mdl.CharString := THIS^.mdl; + //first check if Mqtt is initialized and FB in input mode, otherwise do nothing - 30 + 4 - MqttDiscMsgSensor.dev.mf.CharString := THIS^.mf; + IF NOT(InitMqttDone) AND VirtualMode <> VIRTUAL_MODES.Input THEN - 31 + 5 - + //mark the interface call from the collector as done - 32 + 6 - // Extra meta-data + PublishReceived := TRUE; - 33 + 7 - IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN + //check if the packet is for this FB - 34 + 8 - MqttDiscMsgSensor.meta.CharString := meta; + ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN - 35 + 9 - END_IF + //mark the interface call from the collector as done - 36 + 10 - + PublishReceived := TRUE; - 37 + 11 - ComposeJSON( + //process the data - 38 + 12 - JSONString:= ADR(MqttJSON), + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('TRUE')) THEN - 39 + 13 - JSONStringSize:= SIZEOF(MqttJSON), + THIS^.OUT := TRUE; - 40 + 14 - JSONVars:= ADR(MqttDiscMsgSensor), + MqttMessageReceived := TRUE; - 41 + 15 - NumberOfVars:= SIZEOF(MqttDiscMsgSensor) / SIZEOF(JSONVAR), + END_IF - 42 + 16 - MaxLevel := 1, + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN - 43 + 17 - ); + THIS^.OUT := FALSE; - 44 + 18 - ComposeJSON.Execute := TRUE; + MqttMessageReceived := TRUE; - 45 + 19 - ComposeJSON(); + END_IF - 46 + 2 + + END_IF + + + + + + + + + 20 + + METHOD PublishReceived : BOOL + + + 21 + + VAR_INPUT + + + 22 + + ///Collection of recived Data + + + 23 + + Data: MQTT.CALLBACK_DATA; + + + 24 + + END_VAR + + + 1 + + + + + 2d8d4e52-d630-40a2-99dd-1affee9ab859 + + FB_VIRTUAL_BOOL_MQTT + + -1 + + + False + + d4794c50-191d-409c-b4f5-b59aa920dbbc + 2d8d4e52-d630-40a2-99dd-1affee9ab859 + SetValue + + + + 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 + + 638115483690357939 + + + + + + + 3 + + THIS^.OUT:=Value; + + + 2 + + THIS^.UpdateFlag:=TRUE; + + + + + + + - 47 + 4 - IF MqttJSON = '' THEN + METHOD SetValue : BOOL - 48 + 5 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + VAR_INPUT - 49 + 6 - ELSIF NOT (MqttJSON = '') THEN + Value: BOOL; - 50 + 7 - pMqttPublishQueue^.AddMessage( + END_VAR - 51 + 1 - Payload:= MqttJSON, + - - 52 - - Topic := MqttTopic, + + + + + 2d8d4e52-d630-40a2-99dd-1affee9ab859 + + FB_VIRTUAL_BOOL_MQTT + + -1 + + + False + + bbba49e9-c9a9-48ed-9c5b-1bcd8f194594 + dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 + ConfigureFunctionBlockAsVirtualInput + + + + 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 + + 638115483693168259 + + + + + - 53 + 3 - Qos := MQTT.QoS.ExactlyOnce, + THIS^.DefaultValue:=DefaultValue; - 54 + 4 - MqttRetain := TRUE, + THIS^.SetDefaultValueStartup:=SetDefaultValueStartup; - 55 + 5 - ); + THIS^.PublishAtStartup:=PublishAtStartup; - 56 + 6 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + THIS^.UsePersistentAtStartup:=UsePersistentAtStartup; - 57 + 7 - END_IF + THIS^.ConfirmReceival:=ConfirmReceival; 2 - + THIS^.VirtualMode:=VIRTUAL_MODES.Input; @@ -29486,82 +28437,128 @@ - 58 + 8 - METHOD CreateSensorEntity + METHOD ConfigureFunctionBlockAsVirtualInput : BOOL - 59 + 9 VAR_INPUT - 60 + 10 - /// default + DefaultValue: INT; - 61 + 11 - Name: STRING; + SetDefaultValueStartup: BOOL; - 62 + 12 - Id: STRING; + PublishAtStartup: BOOL; - 63 + 13 - Meta: STRING; + UsePersistentAtStartup: BOOL; - 64 + 14 - /// entity specific + ConfirmReceival: BOOL; - 65 + 15 - StateTopic: STRING; + END_VAR - 66 + 1 - ExpiryAfter: INT := 0; + - - 67 - - END_VAR + + + + + dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 + + FB_VIRTUAL_INT_MQTT + + -1 + + + False + + 51f5340a-511a-47c2-ad02-701f4f4d4dd9 + dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 + ConfigureFunctionBlockAsVirtualOutput + + + + 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 + + 638115483691797844 + + + + + - 68 + 3 - VAR + THIS^.PublishAtStartup:=PublishAtStartup; - 69 + 2 - EntityId: STRING(25) := 'sensor'; + THIS^.VirtualMode:=VIRTUAL_MODES.Output; + + + + + + - 70 + 4 - ComposeJSON: STRUCT_TO_JSON; + METHOD ConfigureFunctionBlockAsVirtualOutput : BOOL - 71 + 5 - MqttJSON: STRING(1500); + VAR_INPUT - 72 + 6 - MqttTopic: STRING(100); + PublishAtStartup: BOOL; - 73 + 7 END_VAR @@ -29574,19 +28571,18 @@ - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 + dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 - MqttDiscovery - FB_BASE_MQTT_DISCOVERY_DEVICE + FB_VIRTUAL_INT_MQTT -1 False - 838e0445-8f4c-4cd1-b721-cd5515c3ea76 - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - CreateSensorEntityWithCategory + 34587e6d-f03a-47e6-8dbe-293e2d6af718 + dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 + InitMqtt @@ -29610,7 +28606,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891898032989 + 638115483692278228 @@ -29619,7 +28615,7 @@ 3 - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + InitMqttDone := TRUE; 4 @@ -29629,52 +28625,52 @@ 5 - // Entity related: Basis + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important 6 - MqttDiscMsgSensorWCat.name.CharString := name; // friendly name + 7 - MqttDiscMsgSensorWCat.obj_id.CharString := Id; + (*pass trough*) 8 - MqttDiscMsgSensorWCat.uniq_id.CharString := Id; + THIS^.pMqttPublishQueue := pMqttPublishQueue; 9 - + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; 10 - // Entity related: Specific + THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; 11 - //MqttDiscoverySensorMessage.ic.CharString := Icon; + THIS^.pMqttPublishQueue:=pMqttPublishQueue; 12 - MqttDiscMsgSensorWCat.stat_t.CharString := StateTopic; + THIS^.MqttQos:=MqttQos; 13 - MqttDiscMsgSensorWCat.exp_aft.Integer := ExpiryAfter; + THIS^.MqttRetain:=MqttRetain; 14 - MqttDiscMsgSensorWCat.ent_cat.CharString := EntityCategory; + 15 @@ -29684,267 +28680,390 @@ 16 - // Availabilty related + SUPER^.InitBaseMqtt(); 17 - MqttDiscMsgSensorWCat.avty[1].topic.CharString := THIS^.availabilityTopic1; + pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received 18 - MqttDiscMsgSensorWCat.avty[2].topic.CharString := THIS^.availabilityTopic2; + + + + 2 + + + + + + + + 19 - MqttDiscMsgSensorWCat.avty_mode.CharString := 'all'; + METHOD InitMqtt 20 - MqttDiscMsgSensorWCat.pl_avail.CharString := THIS^.availabilityOnline; + VAR_INPUT 21 - MqttDiscMsgSensorWCat.pl_not_avail.CharString := THIS^.availabilityOffline; + MQTTPublishPrefix: POINTER TO STRING; 22 - MqttDiscMsgSensorWCat.qos.Integer := 2; + MQTTSubscribePrefix: POINTER TO STRING; 23 - + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; 24 - // Device related + pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; 25 - MqttDiscMsgSensorWCat.dev.cu.CharString := THIS^.cu; + MqttQos: MQTT.QoS; 26 - MqttDiscMsgSensorWCat.dev.name.CharString := THIS^.name; + MqttRetain: BOOL; 27 - MqttDiscMsgSensorWCat.dev.hw.CharString := THIS^.hw; - - - 28 - - MqttDiscMsgSensorWCat.dev.ids.CharString := THIS^.ids; - - - 29 - - MqttDiscMsgSensorWCat.dev.sw.CharString := THIS^.sw; - - - 30 - - MqttDiscMsgSensorWCat.dev.mdl.CharString := THIS^.mdl; - - - 31 - - MqttDiscMsgSensorWCat.dev.mf.CharString := THIS^.mf; + END_VAR - 32 + 1 - + - - 33 - - // Extra meta-data + + + + + dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 + + FB_VIRTUAL_INT_MQTT + + -1 + + + False + + d4933a30-8b1d-464c-95e0-2321ba9c9029 + dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 + 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 + + 638115483692697820 + + + + + - 34 + 3 - IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN + //first check if Mqtt is initialized and FB in input mode, otherwise do nothing - 35 + 4 - MqttDiscMsgSensorWCat.meta.CharString := meta; + IF NOT(InitMqttDone) AND VirtualMode <> VIRTUAL_MODES.Input THEN - 36 + 5 - END_IF + //mark the interface call from the collector as done - 37 + 6 - + PublishReceived := TRUE; - 38 + 7 - ComposeJSON( + //check if the packet is for this FB - 39 + 8 - JSONString:= ADR(MqttJSON), + ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN - 40 + 9 - JSONStringSize:= SIZEOF(MqttJSON), + //mark the interface call from the collector as done - 41 + 10 - JSONVars:= ADR(MqttDiscMsgSensorWCat), + PublishReceived := TRUE; - 42 + 11 - NumberOfVars:= SIZEOF(MqttDiscMsgSensorWCat) / SIZEOF(JSONVAR), + //process the data - 43 + 12 - MaxLevel := 1, + IF OSCAT_BASIC.IS_NUM(str:= Data.PayloadString^) THEN - 44 + 13 - ); + THIS^.OUT := STRING_TO_INT(Data.PayloadString^); - 45 + 14 - ComposeJSON.Execute := TRUE; + MqttMessageReceived := TRUE; - 46 + 15 - ComposeJSON(); + END_IF - 47 + 2 - + END_IF + + + + + + - 48 + 16 - IF MqttJSON = '' THEN + METHOD PublishReceived : BOOL - 49 + 17 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + VAR_INPUT - 50 + 18 - ELSIF NOT (MqttJSON = '') THEN + ///Collection of recived Data - 51 + 19 - pMqttPublishQueue^.AddMessage( + Data: MQTT.CALLBACK_DATA; - 52 + 20 - Payload:= MqttJSON, + END_VAR - 53 + 1 - Topic := MqttTopic, + - - 54 - - Qos := MQTT.QoS.ExactlyOnce, + + + + + dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 + + FB_VIRTUAL_INT_MQTT + + -1 + + + False + + 6d062eee-2aad-4e3a-999e-f1cf9b80ed1b + dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 + SetValue + + + + 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 + + 638115483693597854 + + + + + - 55 + 3 - MqttRetain := TRUE, + THIS^.OUT:=Value; - 56 + 2 - ); + THIS^.UpdateFlag:=TRUE; + + + + + + - 57 + 4 - IF NOT (StateValue = '') THEN + METHOD SetValue : BOOL - 58 + 5 - pMqttPublishQueue^.AddMessage( + VAR_INPUT - 59 + 6 - Payload:= StateValue, + Value: INT; - 60 + 7 - Topic := StateTopic, + END_VAR - 61 + 1 - Qos := MQTT.QoS.ExactlyOnce, + - - 62 - - MqttRetain := TRUE, + + + + + dd2dc9c5-fe6d-48de-83e9-c8fa44707c85 + + FB_VIRTUAL_INT_MQTT + + -1 + + + False + + 8207c67f-9eb3-4ffc-8674-7a2fa6b2a79f + a358b58e-8bfc-4426-9a93-064a10d81a04 + ConfigureFunctionBlockAsVirtualInput + + + + 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 + + 638115483696877868 + + + + + - 63 + 3 - ); + THIS^.DefaultValue:=DefaultValue; - 64 + 4 - END_IF + THIS^.SetDefaultValueStartup:=SetDefaultValueStartup; - 65 + 5 - + THIS^.PublishAtStartup:=PublishAtStartup; - 66 + 6 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + THIS^.UsePersistentAtStartup:=UsePersistentAtStartup; - 67 + 7 - END_IF + THIS^.ConfirmReceival:=ConfirmReceival; 2 - + THIS^.VirtualMode:=VIRTUAL_MODES.Input; @@ -29953,97 +29072,128 @@ - 68 + 8 - METHOD CreateSensorEntityWithCategory + METHOD ConfigureFunctionBlockAsVirtualInput : BOOL - 69 + 9 VAR_INPUT - 70 - - /// default - - - 71 - - Name: STRING; - - - 72 - - Id: STRING; - - - 73 + 10 - Meta: STRING; + DefaultValue: REAL; - 74 + 11 - /// entity specific + SetDefaultValueStartup: BOOL; - 75 + 12 - StateTopic: STRING; + PublishAtStartup: BOOL; - 76 + 13 - StateValue: STRING := ''; + UsePersistentAtStartup: BOOL; - 77 + 14 - /// config or diagnostic + ConfirmReceival: BOOL; - 78 + 15 - EntityCategory: STRING; + END_VAR - 79 + 1 - ExpiryAfter: INT := 0; + - - 80 - - END_VAR + + + + + a358b58e-8bfc-4426-9a93-064a10d81a04 + + FB_VIRTUAL_REAL_MQTT + + -1 + + + False + + 1d91458c-a2c5-4790-a876-fa308386076d + a358b58e-8bfc-4426-9a93-064a10d81a04 + ConfigureFunctionBlockAsVirtualOutput + + + + 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 + + 638115483695707869 + + + + + - 81 + 3 - VAR + THIS^.PublishAtStartup:=PublishAtStartup; - 82 + 2 - EntityId: STRING(25) := 'sensor'; + THIS^.VirtualMode:=VIRTUAL_MODES.Output; + + + + + + - 83 + 4 - ComposeJSON: STRUCT_TO_JSON; + METHOD ConfigureFunctionBlockAsVirtualOutput : BOOL - 84 + 5 - MqttJSON: STRING(1500); + VAR_INPUT - 85 + 6 - MqttTopic: STRING(100); + PublishAtStartup: BOOL; - 86 + 7 END_VAR @@ -30056,19 +29206,18 @@ - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 + a358b58e-8bfc-4426-9a93-064a10d81a04 - MqttDiscovery - FB_BASE_MQTT_DISCOVERY_DEVICE + FB_VIRTUAL_REAL_MQTT -1 False - 793e7a44-13cb-4f55-8ebd-12db39302e12 - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - CreateSirenEntity + 1b0b743d-e33a-46a5-994f-c178f35fee4c + a358b58e-8bfc-4426-9a93-064a10d81a04 + InitMqtt @@ -30092,7 +29241,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891895922949 + 638115483696128239 @@ -30101,7 +29250,7 @@ 3 - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + InitMqttDone := TRUE; 4 @@ -30111,297 +29260,435 @@ 5 - // Entity related: Basis + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important 6 - MqttDiscMsgSiren.name.CharString := name; // friendly name + 7 - MqttDiscMsgSiren.obj_id.CharString := Id; + (*pass trough*) 8 - MqttDiscMsgSiren.uniq_id.CharString := Id; + THIS^.pMqttPublishQueue := pMqttPublishQueue; 9 - + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; 10 - // Entity related: Specific + THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; 11 - MqttDiscMsgSiren.cmd_t.CharString := CommandTopic; + THIS^.pMqttPublishQueue:=pMqttPublishQueue; 12 - MqttDiscMsgSiren.pl_on.CharString := PayloadOn; + THIS^.MqttQos:=MqttQos; 13 - MqttDiscMsgSiren.pl_off.CharString := PayloadOff; + THIS^.MqttRetain:=MqttRetain; 14 - MqttDiscMsgSiren.stat_t.CharString := StateTopic; + 15 - MqttDiscMsgSiren.stat_on.CharString := StateOnPayload; + 16 - MqttDiscMsgSiren.stat_off.CharString := StateOffPayload; + SUPER^.InitBaseMqtt(); 17 - MqttDiscMsgSiren.opt.Boolean := FALSE; + pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received 18 + + 2 + + + + + + + + + 19 - // Availabilty related + METHOD InitMqtt 20 - MqttDiscMsgSiren.avty[1].topic.CharString := THIS^.availabilityTopic1; + VAR_INPUT 21 - MqttDiscMsgSiren.avty[2].topic.CharString := THIS^.availabilityTopic2; + MQTTPublishPrefix: POINTER TO STRING; 22 - MqttDiscMsgSiren.avty_mode.CharString := 'all'; + MQTTSubscribePrefix: POINTER TO STRING; 23 - MqttDiscMsgSiren.pl_avail.CharString := THIS^.availabilityOnline; + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; 24 - MqttDiscMsgSiren.pl_not_avail.CharString := THIS^.availabilityOffline; + pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; 25 - MqttDiscMsgSiren.qos.Integer := 2; + MqttQos: MQTT.QoS; 26 - + MqttRetain: BOOL; 27 - - - - 28 - - // Device related + END_VAR - 29 + 1 - MqttDiscMsgSiren.dev.cu.CharString := THIS^.cu; + - - 30 - - MqttDiscMsgSiren.dev.name.CharString := THIS^.name; + + + + + a358b58e-8bfc-4426-9a93-064a10d81a04 + + FB_VIRTUAL_REAL_MQTT + + -1 + + + False + + ff86ca41-7669-4336-8757-e7c27720e57b + a358b58e-8bfc-4426-9a93-064a10d81a04 + 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 + + 638115483696507837 + + + + + - 31 + 3 - MqttDiscMsgSiren.dev.hw.CharString := THIS^.hw; + //first check if Mqtt is initialized and FB in input mode, otherwise do nothing - 32 + 4 - MqttDiscMsgSiren.dev.ids.CharString := THIS^.ids; + IF NOT(InitMqttDone) AND VirtualMode <> VIRTUAL_MODES.Input THEN - 33 + 5 - MqttDiscMsgSiren.dev.sw.CharString := THIS^.sw; + //mark the interface call from the collector as done - 34 + 6 - MqttDiscMsgSiren.dev.mdl.CharString := THIS^.mdl; + PublishReceived := TRUE; - 35 + 7 - MqttDiscMsgSiren.dev.mf.CharString := THIS^.mf; + //check if the packet is for this FB - 36 + 8 - + ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN - 37 + 9 - // Extra meta-data + //mark the interface call from the collector as done - 38 + 10 - IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN + PublishReceived := TRUE; - 39 + 11 - MqttDiscMsgSiren.meta.CharString := meta; + //process the data - 40 + 12 - END_IF + THIS^.OUT := STRING_TO_REAL(Data.PayloadString^); - 41 + 13 - + MqttMessageReceived := TRUE; - 42 + 2 - ComposeJSON( + END_IF + + + + + + - 43 + 14 - JSONString:= ADR(MqttJSON), + METHOD PublishReceived : BOOL - 44 + 15 - JSONStringSize:= SIZEOF(MqttJSON), + VAR_INPUT - 45 + 16 - JSONVars:= ADR(MqttDiscMsgSiren), + ///Collection of recived Data - 46 + 17 - NumberOfVars:= SIZEOF(MqttDiscMsgSiren) / SIZEOF(JSONVAR), + Data: MQTT.CALLBACK_DATA; - 47 + 18 - MaxLevel := 1, + END_VAR - 48 + 1 - ); + - - 49 - - ComposeJSON.Execute := TRUE; + + + + + a358b58e-8bfc-4426-9a93-064a10d81a04 + + FB_VIRTUAL_REAL_MQTT + + -1 + + + False + + 8c3ea5f3-3fee-4da2-bdd9-d8e7f8d9a703 + a358b58e-8bfc-4426-9a93-064a10d81a04 + SetValue + + + + 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 + + 638115483697167850 + + + + + - 50 + 3 - ComposeJSON(); + THIS^.OUT:=Value; - 51 + 2 - + THIS^.UpdateFlag:=TRUE; + + + + + + - 52 + 4 - IF MqttJSON = '' THEN + METHOD SetValue : BOOL - 53 + 5 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + VAR_INPUT - 54 + 6 - ELSIF NOT (MqttJSON = '') THEN + Value: REAL; - 55 + 7 - pMqttPublishQueue^.AddMessage( + END_VAR - 56 + 1 - Payload:= MqttJSON, + - - 57 - - Topic := MqttTopic, + + + + + a358b58e-8bfc-4426-9a93-064a10d81a04 + + FB_VIRTUAL_REAL_MQTT + + -1 + + + False + + f2511d62-705b-40cb-8de4-d61fc6409bfe + 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb + ConfigureFunctionBlockAsVirtualInput + + + + 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 + + 638115483698747847 + + + + + - 58 + 3 - Qos := MQTT.QoS.ExactlyOnce, + THIS^.DefaultValue:=DefaultValue; - 59 + 4 - MqttRetain := TRUE, + THIS^.SetDefaultValueStartup:=SetDefaultValueStartup; - 60 + 5 - ); + THIS^.PublishAtStartup:=PublishAtStartup; - 61 + 6 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + THIS^.UsePersistentAtStartup:=UsePersistentAtStartup; - 62 + 7 - END_IF + THIS^.ConfirmReceival:=ConfirmReceival; 2 - + THIS^.VirtualMode:=VIRTUAL_MODES.Input; @@ -30410,102 +29697,128 @@ - 63 + 8 - METHOD CreateSirenEntity + METHOD ConfigureFunctionBlockAsVirtualInput : BOOL - 64 + 9 VAR_INPUT - 65 - - /// default - - - 66 - - Name: STRING; - - - 67 - - Id: STRING; - - - 68 - - Meta: STRING; - - - 69 + 10 - /// entity specific + DefaultValue: STRING; - 70 + 11 - CommandTopic: STRING; + SetDefaultValueStartup: BOOL; - 71 + 12 - PayloadOn: STRING; + PublishAtStartup: BOOL; - 72 + 13 - PayloadOff: STRING; + UsePersistentAtStartup: BOOL; - 73 + 14 - StateTopic: STRING; + ConfirmReceival: BOOL; - 74 + 15 - StateOnPayload: STRING; + END_VAR - 75 + 1 - StateOffPayload: STRING; + - - 76 - - END_VAR + + + + + 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb + + FB_VIRTUAL_STRING_MQTT + + -1 + + + False + + cd8070a9-0b16-4a71-bb37-7a04025d94af + 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb + ConfigureFunctionBlockAsVirtualOutput + + + + 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 + + 638115483699447842 + + + + + - 77 + 3 - VAR + THIS^.PublishAtStartup:=PublishAtStartup; - 78 + 2 - EntityId: STRING(25) := 'siren'; + THIS^.VirtualMode:=VIRTUAL_MODES.Output; + + + + + + - 79 + 4 - ComposeJSON: STRUCT_TO_JSON; + METHOD ConfigureFunctionBlockAsVirtualOutput : BOOL - 80 + 5 - MqttJSON: STRING(1500); + VAR_INPUT - 81 + 6 - MqttTopic: STRING(100); + PublishAtStartup: BOOL; - 82 + 7 END_VAR @@ -30518,19 +29831,18 @@ - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 + 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb - MqttDiscovery - FB_BASE_MQTT_DISCOVERY_DEVICE + FB_VIRTUAL_STRING_MQTT -1 False - 75c455ae-a692-49d9-b87e-bebb86330594 - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - CreateSwitchEntity + 90629d9d-c71d-42ea-b678-23deb210a23f + 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb + InitMqtt @@ -30554,7 +29866,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891897272991 + 638115483698027859 @@ -30563,7 +29875,7 @@ 3 - MqttTopic := CONCAT(CONCAT(CONCAT(CONCAT(THIS^.MqttDiscoveryPrefix, EntityId),'/'), Id),'/config' ); + InitMqttDone := TRUE; 4 @@ -30573,297 +29885,329 @@ 5 - // Entity related: Basis + SUPER^._InstancePath := THIS^.InstancePath; // Due to reflection its location is important 6 - MqttDiscMsgSwitch.name.CharString := name; // friendly name + 7 - MqttDiscMsgSwitch.obj_id.CharString := Id; + (*pass trough*) 8 - MqttDiscMsgSwitch.uniq_id.CharString := Id; + THIS^.pMqttPublishQueue := pMqttPublishQueue; 9 - + THIS^.MqttPublishTopicPrefix:=MQTTPublishPrefix; 10 - // Entity related: Specific + THIS^.MQTTSubscribeTopicPrefix:=MQTTSubscribePrefix; 11 - MqttDiscMsgSwitch.cmd_t.CharString := CommandTopic; + THIS^.pMqttPublishQueue:=pMqttPublishQueue; 12 - MqttDiscMsgSwitch.pl_on.CharString := PayloadOn; + THIS^.MqttQos:=MqttQos; 13 - MqttDiscMsgSwitch.pl_off.CharString := PayloadOff; + THIS^.MqttRetain:=MqttRetain; 14 - MqttDiscMsgSwitch.stat_t.CharString := StateTopic; + 15 - MqttDiscMsgSwitch.stat_on.CharString := StateOnPayload; + 16 - MqttDiscMsgSwitch.stat_off.CharString := StateOffPayload; + SUPER^.InitBaseMqtt(); 17 - MqttDiscMsgSwitch.opt.Boolean := FALSE; + pMqttCallbackCollector^.put(instance:= THIS^); // register the FB agains the collector so mqtt events can be received 18 - MqttDiscMsgSwitch.dev_cla.CharString := DeviceClass; + - 19 + 2 + + + + + + + + 19 + + METHOD InitMqtt + 20 - // Availabilty related + VAR_INPUT 21 - MqttDiscMsgSwitch.avty[1].topic.CharString := THIS^.availabilityTopic1; + MQTTPublishPrefix: POINTER TO STRING; 22 - MqttDiscMsgSwitch.avty[2].topic.CharString := THIS^.availabilityTopic2; + MQTTSubscribePrefix: POINTER TO STRING; 23 - MqttDiscMsgSwitch.avty_mode.CharString := 'all'; + pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; 24 - MqttDiscMsgSwitch.pl_avail.CharString := THIS^.availabilityOnline; + pMqttCallbackCollector: POINTER TO MQTT.CallbackCollector; 25 - MqttDiscMsgSwitch.pl_not_avail.CharString := THIS^.availabilityOffline; + MqttQos: MQTT.QoS; 26 - MqttDiscMsgSwitch.qos.Integer := 2; + MqttRetain: BOOL; 27 - - - - 28 - - // Device related - - - 29 - - MqttDiscMsgSwitch.dev.cu.CharString := THIS^.cu; - - - 30 - - MqttDiscMsgSwitch.dev.name.CharString := THIS^.name; - - - 31 - - MqttDiscMsgSwitch.dev.hw.CharString := THIS^.hw; - - - 32 - - MqttDiscMsgSwitch.dev.ids.CharString := THIS^.ids; - - - 33 - - MqttDiscMsgSwitch.dev.sw.CharString := THIS^.sw; - - - 34 - - MqttDiscMsgSwitch.dev.mdl.CharString := THIS^.mdl; - - - 35 - - MqttDiscMsgSwitch.dev.mf.CharString := THIS^.mf; - - - 36 - - - - - 37 - - // Extra meta-data - - - 38 - - IF NOT CommonTypesAndFunctions.StrEquals(str1:= ADR(meta), str2:= ADR('')) THEN - - - 39 - - MqttDiscMsgSwitch.meta.CharString := meta; - - - 40 - - END_IF + END_VAR - 41 + 1 - - 42 - - ComposeJSON( + + + + + 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb + + FB_VIRTUAL_STRING_MQTT + + -1 + + + False + + d1d0e806-b356-4767-8b35-9b640e963245 + 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb + 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 + + 638115483698448189 + + + + + - 43 + 3 - JSONString:= ADR(MqttJSON), + //first check if Mqtt is initialized and FB in input mode, otherwise do nothing - 44 + 4 - JSONStringSize:= SIZEOF(MqttJSON), + IF NOT(InitMqttDone) AND VirtualMode <> VIRTUAL_MODES.Input THEN - 45 + 5 - JSONVars:= ADR(MqttDiscMsgSwitch), + //mark the interface call from the collector as done - 46 + 6 - NumberOfVars:= SIZEOF(MqttDiscMsgSwitch) / SIZEOF(JSONVAR), + PublishReceived := TRUE; - 47 + 7 - MaxLevel := 1, + //check if the packet is for this FB - 48 + 8 - ); + ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= Data.TopicOut) THEN - 49 + 9 - ComposeJSON.Execute := TRUE; + //mark the interface call from the collector as done - 50 + 10 - ComposeJSON(); + PublishReceived := TRUE; - 51 + 11 - + //process the data - 52 + 12 - IF MqttJSON = '' THEN + THIS^.OUT := Data.PayloadString^; - 53 + 13 - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + MqttMessageReceived := TRUE; - 54 + 2 - ELSIF NOT (MqttJSON = '') THEN + END_IF + + + + + + - 55 + 14 - pMqttPublishQueue^.AddMessage( + METHOD PublishReceived : BOOL - 56 + 15 - Payload:= MqttJSON, + VAR_INPUT - 57 + 16 - Topic := MqttTopic, + ///Collection of recived Data - 58 + 17 - Qos := MQTT.QoS.ExactlyOnce, + Data: MQTT.CALLBACK_DATA; - 59 + 18 - MqttRetain := TRUE, + END_VAR - 60 + 1 - ); + - - 61 - - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + + + + + 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb + + FB_VIRTUAL_STRING_MQTT + + -1 + + + False + + 159c061a-ec5c-40ae-99df-f862def91982 + 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb + SetValue + + + + 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 + + 638115483699047969 + + + + + - 62 + 3 - END_IF + THIS^.OUT:=Value; 2 - + THIS^.UpdateFlag:=TRUE; @@ -30872,107 +30216,163 @@ - 63 + 4 - METHOD CreateSwitchEntity + METHOD SetValue : BOOL - 64 + 5 VAR_INPUT - 65 + 6 - /// default + Value: STRING; - 66 + 7 - Name: STRING; + END_VAR + + + 1 + + + + + + + + 027fbd88-aa8f-4914-bfbe-ed314a3b9fcb + + FB_VIRTUAL_STRING_MQTT + + -1 + + + False + + e85afafb-0938-4f3e-a924-0f54fbabdc99 + e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 + AddMessage + + + + 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 + + 638115485064636336 + + + + + - 67 + 3 - Id: STRING; + IF NOT FULL THEN - 68 + 4 - Meta: STRING; + localMessage.Payload := Payload; - 69 + 5 - /// entity specific + localMessage.Topic := Topic; - 70 + 6 - CommandTopic: STRING; + localMessage.Qos := Qos; - 71 + 7 - PayloadOn: STRING; + localMessage.MqttRetain := MqttRetain; - 72 + 8 - PayloadOff: STRING; + fifo[pw] := localMessage; - 73 + 9 - StateTopic: STRING; + pw := OSCAT_BASIC.INC1(pw,n); - 74 + 10 - StateOnPayload: STRING; + FULL := pw = pr; - 75 + 11 - StateOffPayload: STRING; + EMPTY := FALSE; - 76 + 2 - DeviceClass: STRING; + END_IF; + + + + + + - 77 + 12 - END_VAR + METHOD AddMessage - 78 + 13 - VAR + VAR_INPUT - 79 + 14 - EntityId: STRING(25) := 'switch'; + Payload: STRING(1500); - 80 + 15 - ComposeJSON: STRUCT_TO_JSON; + Topic: STRING(128); - 81 + 16 - MqttJSON: STRING(1500); + Qos: MQTT.QoS; - 82 + 17 - MqttTopic: STRING(100); + MqttRetain: BOOL; - 83 + 18 END_VAR @@ -30985,19 +30385,19 @@ - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 + e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 - MqttDiscovery - FB_BASE_MQTT_DISCOVERY_DEVICE + Mqtt + FB_MqttPublishQueue -1 False - ba3ff3ed-9fe2-4fd0-920f-1b102db3373c - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 - initBaseDevice + 2aca44d9-e20c-4d8f-9ac8-5cab1f548638 + e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 + GetMessage @@ -31021,7 +30421,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891894742971 + 638115485064616826 @@ -31030,343 +30430,598 @@ 3 - THIS^.availabilityTopic1 := availabilityTopic; + IF NOT EMPTY THEN 4 - + GetMessage := fifo[pr]; 5 - IF CommonTypesAndFunctions.StrEquals(str1:= ADR(availabilityTopic2), str2:= ADR('')) THEN + pr := OSCAT_BASIC.INC1(pr,n); 6 - THIS^.availabilityTopic2 := availabilityTopic; + EMPTY := pr = pw; 7 - ELSE + FULL := FALSE; - 8 + 2 - THIS^.availabilityTopic2 := availabilityTopic2; + END_IF; + + + + + + - 9 + 8 - END_IF + METHOD GetMessage : MQTT_MESSAGE - 10 + 1 - - 11 - - THIS^.availabilityOnline := availabilityOnline; + + + + + e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 + + Mqtt + FB_MqttPublishQueue + + -1 + + + False + + f24e2080-1319-4991-b6a7-fb17a1ccf8a1 + e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 + Reset + + + + 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 + + 638115485064646791 + + + + + - 12 + 3 - THIS^.availabilityOffline := availabilityOffline; + pw := pr; - 13 + 4 - THIS^.pMqttPublishQueue := pMqttPublishQueue; + FULL := FALSE; - 14 + 2 - THIS^.MqttDiscoveryPrefix := MqttDiscoveryPrefix; + EMPTY := TRUE; + + + + + + - 15 + 5 - THIS^.MqttDiagnosticTopic := MqttDiagnosticTopic; + METHOD Reset - 16 + 1 - - 17 - - THIS^.name := Name; + + + + + e6d71da6-bd8d-47cb-8009-aa2e3c6860c1 + + Mqtt + FB_MqttPublishQueue + + -1 + + + False + + a51ccb6a-0e41-4a8f-8043-1f5e0819cdbd + 15a50ac1-2e79-43de-b5c8-cf7e3b869577 + Init + + + + 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 + + 638115485064396775 + + + + + - 18 + 3 - THIS^.cu:= ConfigurationUrl; + publish.SetMqttInOut(MQTT_IN_OUT := inputMQTT_IN_OUT^); - 19 + 4 - THIS^.ids:= Identifiers; + - 20 + 5 - THIS^.mf:= Manufacturer; + InitDone := TRUE; - 21 + 6 - THIS^.mdl:= Model; + SendDone := TRUE; - 22 + 2 - THIS^.hw:= HardwareVersion; + + + + + + + - 23 + 7 - THIS^.sw:= SoftwareVersion; + METHOD Init - 24 + 8 - THIS^.ip := IpAddress; + VAR_INPUT - 25 + 9 - THIS^.mac := MacAddress; + ///Pointer MQTTT exchange strucure - 26 + 10 - + inputMQTT_IN_OUT: POINTER TO MQTT.MQTT_IN_OUT; - 27 + 11 - //Create a diagnostics availability binary sensor + END_VAR - 28 + 1 - CreateBinarySensorEntityWithCategory( + - - 29 - - Name := 'Availability', + + + + + 15a50ac1-2e79-43de-b5c8-cf7e3b869577 + + Mqtt + FB_MqttPublishWorker + + -1 + + + False + + 8bf6165e-c19d-4c89-a9d0-84528bf38968 + 15a50ac1-2e79-43de-b5c8-cf7e3b869577 + PublishMessage + + + + 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 + + 638115485064416342 + + + + + - 30 + 3 - Id := CONCAT(THIS^.Name,'_diag_availability'), + LocalMqttMessage := MqttMessage; - 31 + 4 - Meta := '', + - 32 + 2 - StateTopic := availabilityTopic, + RequestToSend:=TRUE; + + + + + + - 33 + 5 - PayloadOn := availabilityOnline, + METHOD PublishMessage - 34 + 6 - PayloadOff := availabilityOffline, + VAR_INPUT - 35 + 7 - DeviceClass := 'CONNECTIVITY', + MqttMessage: MQTT_MESSAGE; - 36 + 8 - EntityCategory := 'diagnostic'); + END_VAR - 37 + 1 - + - - 38 - - // MAC address + + + + + 15a50ac1-2e79-43de-b5c8-cf7e3b869577 + + Mqtt + FB_MqttPublishWorker + + -1 + + + False + + fcd96465-7e19-4f81-836c-09c3f3ef8312 + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_AVTY_T + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + - - 39 - - IF NOT(MacAddress = '') THEN + + + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + + 2db5746d-d284-4425-9f7f-2663a34b0ebc + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + + 638119892248617219 + + + + + - 40 + 2 - CreateSensorEntityWithCategory( + TYPE MQTT_DISCOVERY_AVTY_T : - 41 + 3 - Name := 'MAC', + STRUCT - 42 + 4 - Id := CONCAT(THIS^.Name,'_diag_mac'), + topic: JSONVAR; - 43 + 5 - Meta := '', + END_STRUCT - 44 + 6 - StateTopic := CONCAT(MqttDiagnosticTopic, '/MAC'), + END_TYPE - 45 + 1 - StateValue := MacAddress, + + + + + + 6 + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + MqttDiscovery + Messages + + -1 + + + False + + a6b584f2-9095-4c45-acf1-91c47a7506e1 + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_BASE + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + - - 46 - - EntityCategory := 'diagnostic'); + + + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + + 2db5746d-d284-4425-9f7f-2663a34b0ebc + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + + 638119892248797248 + + + + + - 47 + 2 - END_IF + TYPE MQTT_DISCOVERY_BASE : - 48 + 3 - + STRUCT - 49 + 4 - + name: JSONVAR; - 2 + 5 - + /// object_id - - - - - - - 50 + 6 - METHOD initBaseDevice + obj_id: JSONVAR; - 51 + 7 - VAR_INPUT + ///unique_id - 52 + 8 - Name: STRING; + uniq_id: JSONVAR; - 53 + 9 - ConfigurationUrl: STRING; + /// availability - 54 + 10 - Identifiers: STRING; + avty: ARRAY[1..2] OF MQTT_DISCOVERY_AVTY_T; - 55 + 11 - Manufacturer: STRING; + /// availability mode - 56 + 12 - Model: STRING; + avty_mode: JSONVAR; - 57 + 13 - SoftwareVersion: STRING; + ///payload_available - 58 + 14 - HardwareVersion: STRING; + pl_avail: JSONVAR; - 59 + 15 - IpAddress: STRING := ''; + /// payload_not_available - 60 + 16 - MacAddress: STRING := ''; + pl_not_avail: JSONVAR; - 61 + 17 - availabilityTopic: STRING; + /// device - 62 + 18 - availabilityTopic2: STRING := ''; + dev: MQTT_DISCOVERY_DEVICE; - 63 + 19 - availabilityOnline: STRING; + /// mqtt qos - 64 + 20 - availabilityOffline: STRING; + qos: JSONVAR; - 65 + 21 - MqttDiscoveryPrefix: STRING; + /// extra metadata - 66 + 22 - MqttDiagnosticTopic: STRING; + meta: JSONVAR; - 67 + 23 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + END_STRUCT - 68 + 24 - END_VAR + END_TYPE 1 @@ -31376,20 +31031,21 @@ + 24 - a07dedee-1ed2-4ec8-b7b9-5d61346fba49 + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 MqttDiscovery - FB_BASE_MQTT_DISCOVERY_DEVICE + Messages -1 False - 5bf70d9e-202d-4116-8eeb-6e58fbbcd9d3 - 4ce5d04c-d166-4f84-8f14-40dee7843ab7 - GetIpAddress + 28c781b2-bbbc-4bb1-b7a1-8da3fd48145f + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_BINARY_SENSOR @@ -31407,153 +31063,195 @@ + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + - f8a58466-d7f6-439f-bbb8-d4600e41d099 + 2db5746d-d284-4425-9f7f-2663a34b0ebc a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891902783276 + 638119892249017209 - - + + + + 2 + + TYPE MQTT_DISCOVERY_BINARY_SENSOR EXTENDS MQTT_DISCOVERY_BASE : + 3 - xFirstAdapter := TRUE; + STRUCT 4 - rResult := 0; + ///state_topic 5 - WHILE rResult = 0 DO + stat_t: JSONVAR; 6 - IF xFirstAdapter THEN + ///payload_on 7 - hAdapter := SysSockGetFirstAdapterInfo(ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); + pl_on: JSONVAR; 8 - ELSE + ///payload_off 9 - hAdapter := SysSockGetNextAdapterInfo(hAdapter, ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); + pl_off: JSONVAR; 10 - END_IF + /// device class 11 - IF rResult = 0 THEN + dev_cla: JSONVAR; 12 - GetIpAddress := Standard.CONCAT(BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b1),'.'); + END_STRUCT 13 - GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b2)); - - - 14 - - GetIpAddress := Standard.CONCAT(GetIpAddress,'.'); - - - 15 - - GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b3)); - - - 16 - - GetIpAddress := Standard.CONCAT(GetIpAddress,'.'); - - - 17 - - GetIpAddress := Standard.CONCAT(GetIpAddress,BYTE_TO_STRING(AdapterInfo.IpAddr.S_un_b.s_b4)); - - - 18 - - END_IF - - - 19 - - xFirstAdapter := FALSE; + END_TYPE - 2 + 1 - END_WHILE + + 13 + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + MqttDiscovery + Messages + + -1 + + + False + + 9459113e-7fe9-4c2b-acb8-6f4c482d9a59 + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_BINARY_SENSOR_ENT_CAT + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + + + + + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + + + 2db5746d-d284-4425-9f7f-2663a34b0ebc + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + + 638119892249176761 + + - 20 - - METHOD PRIVATE GetIpAddress : STRING(15) - - - 21 - - VAR - - - 22 + 2 - AdapterInfo: SOCK_ADAPTER_INFORMATION; + TYPE MQTT_DISCOVERY_BINARY_SENSOR_ENT_CAT EXTENDS MQTT_DISCOVERY_BINARY_SENSOR : - 23 + 3 - hAdapter: RTS_IEC_HANDLE; + STRUCT - 24 + 4 - udiStructSize: UDINT := SIZEOF(AdapterInfo); + /// entity category - 25 + 5 - rResult: RTS_IEC_RESULT; + ent_cat: JSONVAR; - 26 + 6 - xFirstAdapter: BOOL; + END_STRUCT - 27 + 7 - END_VAR + END_TYPE 1 @@ -31563,20 +31261,21 @@ + 7 - 4ce5d04c-d166-4f84-8f14-40dee7843ab7 + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 MqttDiscovery - FB_PLC_MQTT_DISCOVERY_DEVICE + Messages -1 False - 8a5008f5-86c0-45e0-8bb8-56d69e51d414 - 4ce5d04c-d166-4f84-8f14-40dee7843ab7 - GetMac + 9f7614bb-75e9-429a-9de8-272e6045d67a + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_COVER @@ -31594,173 +31293,300 @@ + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + - f8a58466-d7f6-439f-bbb8-d4600e41d099 + 2db5746d-d284-4425-9f7f-2663a34b0ebc a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891903192962 + 638119892249377283 - - + + + + 2 + + TYPE MQTT_DISCOVERY_COVER EXTENDS MQTT_DISCOVERY_BASE : + 3 - xFirstAdapter := TRUE; + STRUCT 4 - rResult := 0; + ///command_topic 5 - WHILE rResult = 0 DO + cmd_t: JSONVAR; 6 - IF xFirstAdapter THEN + /// payload open 7 - hAdapter := SysSockGetFirstAdapterInfo(ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); + pl_open: JSONVAR; 8 - ELSE + /// payload_close 9 - hAdapter := SysSockGetNextAdapterInfo(hAdapter, ADR(AdapterInfo), ADR(udiStructSize), ADR(rResult)); + pl_cls: JSONVAR; 10 - END_IF + /// payload_stop 11 - IF rResult = 0 THEN + pl_stop: JSONVAR; 12 - GetMac := Standard.CONCAT(SM0.Byte_To_HexString(AdapterInfo.abyMac[0]),'-'); + /// state topic 13 - GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[1])); + stat_t: JSONVAR; 14 - GetMac := Standard.CONCAT(GetMac,'-'); + /// state open 15 - GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[2])); + stat_open: JSONVAR; 16 - GetMac := Standard.CONCAT(GetMac,'-'); + /// state closed 17 - GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[3])); + stat_clsd: JSONVAR; 18 - GetMac := Standard.CONCAT(GetMac,'-'); + /// optimistic 19 - GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[4])); + opt: JSONVAR; 20 - GetMac := Standard.CONCAT(GetMac,'-'); + /// device class 21 - GetMac := Standard.CONCAT(GetMac,SM0.Byte_To_HexString(AdapterInfo.abyMac[5])); + dev_cla: JSONVAR; 22 - END_IF + END_STRUCT 23 - xFirstAdapter := FALSE; + END_TYPE - 2 + 1 - END_WHILE + + 23 + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + MqttDiscovery + Messages + + -1 + + + False + + cc7e28be-62c5-46bf-a211-17aae04d4917 + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_DEVICE + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + + + + + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + + + 2db5746d-d284-4425-9f7f-2663a34b0ebc + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + + 638119892249577247 + + - 24 + 2 + + TYPE MQTT_DISCOVERY_DEVICE : + + + 3 + + STRUCT + + + 4 + + name: JSONVAR; + + + 5 + + ///configuration_url + + + 6 + + cu: JSONVAR; + + + 7 + + ///identifiers + + + 8 + + ids: JSONVAR; + + + 9 + + ///manufacturer + + + 10 + + mf: JSONVAR; + + + 11 - METHOD PRIVATE GetMac : STRING(17) + ///model - 25 + 12 - VAR + mdl: JSONVAR; - 26 + 13 - AdapterInfo: SOCK_ADAPTER_INFORMATION; + ///sw_version - 27 + 14 - hAdapter: RTS_IEC_HANDLE; + sw: JSONVAR; - 28 + 15 - udiStructSize: UDINT := SIZEOF(AdapterInfo); + ///hw_version - 29 + 16 - rResult: RTS_IEC_RESULT; + hw: JSONVAR; - 30 + 17 - xFirstAdapter: BOOL; + END_STRUCT - 31 + 18 - END_VAR + END_TYPE 1 @@ -31770,20 +31596,21 @@ + 18 - 4ce5d04c-d166-4f84-8f14-40dee7843ab7 + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 MqttDiscovery - FB_PLC_MQTT_DISCOVERY_DEVICE + Messages -1 False - c66e3b7f-1836-4252-9313-a1357d25b36b - 4ce5d04c-d166-4f84-8f14-40dee7843ab7 - initPlcDevice + d74686d1-5acc-4bc7-8861-6668c13d9c0c + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_LIGHT @@ -31801,643 +31628,955 @@ + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + - f8a58466-d7f6-439f-bbb8-d4600e41d099 + 2db5746d-d284-4425-9f7f-2663a34b0ebc a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119891902372969 + 638119892249747235 - - + + + + 2 + + TYPE MQTT_DISCOVERY_LIGHT EXTENDS MQTT_DISCOVERY_BASE : + 3 - IF xInit THEN + STRUCT 4 - xInit := FALSE; + ///command_topic 5 - + cmd_t: JSONVAR; 6 - (* get the appname first *) + /// payload_on 7 - sAppName := PRO_JSON.GPL_JSON.ApplicationName; + pl_on: JSONVAR; 8 - + /// payload_off 9 - (* IP address and MAC *) + pl_off: JSONVAR; 10 - sIpAddr := GetIpAddress(); + /// state_topic 11 - sMacAddr := GetMac(); + stat_t: JSONVAR; 12 - + /// optimistic 13 - (* manufacturer *) + opt: JSONVAR; 14 - iecResult := SysTarget.SysTargetGetVendorName(pwszName := ADR(manufacturer), pnMaxLength := ADR(manufacturerSize)); + END_STRUCT 15 - (* model *) - - - 16 - - iecResult := SysTarget.SysTargetGetDeviceName(pwszName := ADR(model), pnMaxLength := ADR(modelSize)); - - - 17 - - (* serial number *) - - - 18 - - iecResult := SysTarget.SysTargetGetSerialNumber(ppsSerialNumber := ADR(psSerialNumber), pnMaxLen := ADR(diSerialNumber)); + END_TYPE - 19 + 1 - - 20 - - (* device name *) - - - 21 - - pApp := AppFindApplicationByName(pszString := sAppName, pResult := ADR(iecResult)); - - - 22 - - pstAppInfo := AppGetApplicationInfo(pApp := pApp, pResult := ADR(iecResult)); - - - 23 - - iSplitLocation := COL.Stu.StrFindA( - - - 24 - - pst1:= ADR(THIS^.InstanceName), - - - 25 - - pst2:= ADR('.'), - - - 26 - - uiSearchStart:= 1 - - - 27 - - ) - 1; - - - 28 - - + + + + 15 + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + MqttDiscovery + Messages + + -1 + + + False + + 37d06121-3988-4895-88e6-9b917acf5c9a + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_LIGHT_DIMMER + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + - - 29 - - (* sw version *) + + + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + + 2db5746d-d284-4425-9f7f-2663a34b0ebc + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + + 638119892250137259 + + + + + - 30 + 2 - CompilerVersion := __SYSTEM.Constants.CompilerVersion; + TYPE MQTT_DISCOVERY_LIGHT_DIMMER EXTENDS MQTT_DISCOVERY_LIGHT : - 31 + 3 - SCompilerVersion := CONCAT(UINT_TO_STRING(CompilerVersion.uiMajor), '.'); + STRUCT - 32 + 4 - SCompilerVersion := CONCAT(SCompilerVersion, UINT_TO_STRING(CompilerVersion.uiMinor)); + ///brightness state topic - 33 + 5 - SCompilerVersion := CONCAT(SCompilerVersion, '.'); + bri_stat_t: JSONVAR; - 34 + 6 - SCompilerVersion := CONCAT(SCompilerVersion, UINT_TO_STRING(CompilerVersion.uiServicePack)); + /// brightness command topic - 35 + 7 - SCompilerVersion := CONCAT(SCompilerVersion, '.'); + bri_cmd_t: JSONVAR; - 36 + 8 - SCompilerVersion := CONCAT(SCompilerVersion, UINT_TO_STRING(CompilerVersion.uiPatch)); + /// brightness scale - 37 + 9 - + bri_scl: JSONVAR; - 38 + 10 - (* url *) + /// on command type - 39 + 11 - IF CommonTypesAndFunctions.StrEquals(ADR(url), ADR('')) THEN + on_cmd_type: JSONVAR; - 40 + 12 - LocalUrl := CONCAT('https://', sIpAddr); + /// DMX - 41 + 13 - ELSE + dmxChannel: JSONVAR; - 42 + 14 - LocalUrl := url; + dmxWidth: JSONVAR; - 43 + 15 - END_IF + dmxUniverse: JSONVAR; - 44 + 16 - + END_STRUCT - 45 + 17 - SUPER^.initBaseDevice( + END_TYPE - 46 + 1 - Name := LEFT(THIS^.InstanceName,iSplitLocation), + - - 47 - - ConfigurationUrl := LocalUrl, + + + + 17 + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + MqttDiscovery + Messages + + -1 + + + False + + 57224119-342d-42e1-aac8-e9f601972e75 + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_LOCK + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + - - 48 - - Identifiers := psSerialNumber^, + + + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + + 2db5746d-d284-4425-9f7f-2663a34b0ebc + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + + 638119892249937254 + + + + + - 49 + 2 - Manufacturer := WSTRING_TO_STRING(manufacturer), + TYPE MQTT_DISCOVERY_LOCK EXTENDS MQTT_DISCOVERY_BASE : - 50 + 3 - Model := WSTRING_TO_STRING(model), + STRUCT - 51 + 4 - SoftwareVersion := SCompilerVersion, + ///command_topic - 52 + 5 - HardwareVersion := DT_TO_STRING(pstAppInfo^.dtLastChanges), + cmd_t: JSONVAR; - 53 + 6 - IpAddress := sIpAddr, + /// payload lock - 54 + 7 - MacAddress := sMacAddr, + pl_lock: JSONVAR; - 55 + 8 - availabilityTopic := availabilityTopic, + /// payload unlock - 56 + 9 - availabilityOnline := availabilityOnline, + pl_unlk: JSONVAR; - 57 + 10 - availabilityOffline := availabilityOffline, + /// state_topic - 58 + 11 - MqttDiscoveryPrefix := MqttDiscoveryPrefix, + stat_t: JSONVAR; - 59 + 12 - MqttDiagnosticTopic := MqttDiagnosticTopic, + /// state locked - 60 + 13 - pMqttPublishQueue := pMqttPublishQueue); + stat_locked: JSONVAR; - 61 + 14 - + /// state unlocked - 62 + 15 - // Serial number diagnostic + stat_unlocked: JSONVAR; - 63 + 16 - CreateSensorEntityWithCategory( + /// optimistic - 64 + 17 - Name := 'Serial number', + opt: JSONVAR; - 65 + 18 - Id := CONCAT(THIS^.Name,'_diag_sn'), + END_STRUCT - 66 + 19 - Meta := '', + END_TYPE - 67 + 1 - StateTopic := CONCAT(MqttDiagnosticTopic, '/SN'), + - - 68 - - StateValue := psSerialNumber^, + + + + 19 + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + MqttDiscovery + Messages + + -1 + + + False + + 58ffd74c-08b2-425f-9cd5-1cd6f4bec61c + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_SENSOR + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + - - 69 - - EntityCategory := 'diagnostic'); + + + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + + 2db5746d-d284-4425-9f7f-2663a34b0ebc + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + + 638119892250296735 + + + + + - 70 + 2 - + TYPE MQTT_DISCOVERY_SENSOR EXTENDS MQTT_DISCOVERY_BASE : - 71 + 3 - // Serial number diagnostic + STRUCT - 72 + 4 - CreateSensorEntityWithCategory( + ///state_topic - 73 + 5 - Name := 'Serial number', + stat_t: JSONVAR; - 74 + 6 - Id := CONCAT(THIS^.Name,'_diag_sn'), + ///expire after - 75 + 7 - Meta := '', + exp_aft: JSONVAR; - 76 + 8 - StateTopic := CONCAT(MqttDiagnosticTopic, '/SN'), + END_STRUCT - 77 + 9 - StateValue := psSerialNumber^, + END_TYPE - 78 + 1 - EntityCategory := 'diagnostic'); + - - 79 - - + + + + 9 + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + MqttDiscovery + Messages + + -1 + + + False + + 9e7721c2-c711-4bee-a683-6d9823e692a9 + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_SENSOR_ENT_CAT + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + - - 80 - - // IP address diagnostic, initial publish. done cyclic as well + + + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + + 2db5746d-d284-4425-9f7f-2663a34b0ebc + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + + 638119892250487276 + + + + + - 81 + 2 - THIS^.MqttDiagnosticTopicIP := CONCAT(MqttDiagnosticTopic, '/IP'); + TYPE MQTT_DISCOVERY_SENSOR_ENT_CAT EXTENDS MQTT_DISCOVERY_SENSOR : - 82 + 3 - MqttRefreshIP(ENQ:=TRUE, PTH:=T#0S, PTL:=T#1M); + STRUCT - 83 + 4 - CreateSensorEntityWithCategory( + /// entity category - 84 + 5 - Name := 'IP', + ent_cat: JSONVAR; - 85 + 6 - Id := CONCAT(THIS^.Name,'_diag_ip'), + END_STRUCT - 86 + 7 - Meta := '', + END_TYPE - 87 + 1 - StateTopic := THIS^.MqttDiagnosticTopicIP, + + + + + + 7 + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + MqttDiscovery + Messages + + -1 + + + False + + a690381c-2055-480f-9ab3-f9abf5a6fc40 + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_SIREN + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + + + + + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + + 2db5746d-d284-4425-9f7f-2663a34b0ebc + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + + 638119892250697276 + + + + + - 88 + 2 - StateValue := sIpAddr, + TYPE MQTT_DISCOVERY_SIREN EXTENDS MQTT_DISCOVERY_BASE : - 89 + 3 - EntityCategory := 'diagnostic'); + STRUCT - 90 + 4 - + ///command_topic - 91 + 5 - END_IF + cmd_t: JSONVAR; - 92 + 6 - + /// payload_on - 93 + 7 - + pl_on: JSONVAR; - 94 + 8 - + /// payload_off - 2 + 9 - + pl_off: JSONVAR; - - - - - - - 95 + 10 - METHOD initPlcDevice + /// state_topic - 96 + 11 - VAR_INPUT + stat_t: JSONVAR; - 97 + 12 - url: STRING := ''; + /// state on - 98 + 13 - availabilityTopic: STRING; + stat_on: JSONVAR; - 99 + 14 - availabilityOnline: STRING; + /// state off - 100 + 15 - availabilityOffline: STRING; + stat_off: JSONVAR; - 101 + 16 - MqttDiscoveryPrefix: STRING; + /// optimistic - 102 + 17 - MqttDiagnosticTopic: STRING; + opt: JSONVAR; - 103 + 18 - pMqttPublishQueue: POINTER TO FB_MqttPublishQueue; + END_STRUCT - 104 + 19 - END_VAR + END_TYPE - 105 + 1 - VAR + + + + + + 19 + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + MqttDiscovery + Messages + + -1 + + + False + + 89e23349-328d-4437-a909-95a772caa4aa + 00000000-0000-0000-0000-000000000000 + MQTT_DISCOVERY_SWITCH + + + + 24568a24-c491-472c-a21f-ee5d33859fab + + + + 0 + False + False + False + + False + + + + + + + 829a18f2-c514-4f6e-9634-1df173429203 + + + + + + + 21af5390-2942-461a-bf89-951aaf6999f1 + + + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 + + + + + + + 2db5746d-d284-4425-9f7f-2663a34b0ebc + + a9ed5b7e-75c5-4651-af16-d2c27e98cb94 + + 638119892250877250 + + + + + - 106 + 2 - LocalUrl: STRING; + TYPE MQTT_DISCOVERY_SWITCH EXTENDS MQTT_DISCOVERY_BASE : - 107 + 3 - iSplitLocation: INT; + STRUCT - 108 + 4 - iecResult: SysTypes.RTS_IEC_RESULT; + ///command_topic - 109 + 5 - /// must identic to the name in the device tree + cmd_t: JSONVAR; - 110 + 6 - sAppName: STRING; + /// payload_on - 111 + 7 - pApp: POINTER TO CmpApp.APPLICATION; + pl_on: JSONVAR; - 112 + 8 - stAppInfo: CmpApp.APPLICATION_INFO; + /// payload_off - 113 + 9 - pstAppInfo: POINTER TO CmpApp.APPLICATION_INFO := ADR(stAppInfo); + pl_off: JSONVAR; - 114 + 10 - sIpAddr: STRING(15); + /// state_topic - 115 + 11 - sMacAddr: STRING(17); + stat_t: JSONVAR; - 116 + 12 - manufacturer: WSTRING; + /// state on - 117 + 13 - manufacturerSize: UDINT := SIZEOF(manufacturer); + stat_on: JSONVAR; - 118 + 14 - model: WSTRING; + /// state off - 119 + 15 - modelSize: DINT := SIZEOF(model); + stat_off: JSONVAR; - 120 + 16 - sSerialNumber: STRING; + /// optimistic - 121 + 17 - psSerialNumber: POINTER TO STRING := ADR(sSerialNumber); + opt: JSONVAR; - 122 + 18 - diSerialNumber: DINT := SIZEOF(sSerialNumber); + /// device class - 123 + 19 - CompilerVersion: Version; + dev_cla: JSONVAR; - 124 + 20 - SCompilerVersion: STRING; + END_STRUCT - 125 + 21 - END_VAR + END_TYPE 1 @@ -32447,11 +32586,12 @@ + 21 - 4ce5d04c-d166-4f84-8f14-40dee7843ab7 + 8a03c49a-4a2c-4182-a32d-4447ec4dd7c0 MqttDiscovery - FB_PLC_MQTT_DISCOVERY_DEVICE + Messages -1 @@ -33033,7 +33173,7 @@ - AAEAAAD/////AQAAAAAAAAAMAgAAADxDb3JlLCBWZXJzaW9uPTMuNS4xNy4yLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAACNfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuUHJvZmlsZQMAAAAeX3BsdWdJbkd1aWRUb1ZlcnNpb25Db25zdHJhaW50Fl9wbHVnSW5HdWlkVG9FeHRlbnNpb24aX3BsdWdJbkd1aWRUb0V4dGVuc2lvbkxpc3QEBAQ9XzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb1ZlcnNpb25Db25zdHJhaW50RGljdGlvbmFyeQIAAAAwXzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb0Jvb2xEaWN0aW9uYXJ5AgAAAEBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvUHJvZmlsZUV4dGVuc2lvbkxpc3REaWN0aW9uYXJ5AgAAAAIAAAAJAwAAAAkEAAAACQUAAAAFAwAAAD1fM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvVmVyc2lvbkNvbnN0cmFpbnREaWN0aW9uYXJ5AQAAABhEaWN0aW9uYXJ5QmFzZStoYXNodGFibGUDHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUCAAAACQYAAAAFBAAAADBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvQm9vbERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJBwAAAAUFAAAAQF8zUy5Db0RlU3lzLkNvcmUuQ29tcG9uZW50cy5HdWlkVG9Qcm9maWxlRXh0ZW5zaW9uTGlzdERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJCAAAAAQGAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUHAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhh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AAAAAAAAAWsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFsAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABbQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAW4BAABhAQAAAwAAAAUAAAAOAAAACgAAAAFvAQAAYQEAAAMAAAAFAAAADgAAAB4AAAABcAEAAGEBAAADAAAABQAAAA4AAAAKAAAAAXEBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFyAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXQBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF1AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABdgEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF4AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABeQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXoBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAF7AQAAYQEAAAMAAAAFAAAADgAAAAoAAAABfAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAX0BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF+AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABfwEAAGEBAAADAAAABQAAAA4AAAAeAAAAAYABAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGBAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABggEAAGEBAAADAAAABQAAAA4AAAAKAAAAAYMBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGEAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABhQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYYBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGHAQAAYQEAAAMAAAAFAAAADgAAABQAAAABiAEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYkBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGKAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYwBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGNAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABjgEAAGEBAAADAAAABQAAAA4A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AAAAAAAAAdcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHYAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB2QEAAGEBAAADAAAABQAAAA4AAAAAAAAAAdoBAABhAQAAAwAAAAUAAAAOAAAAHgAAAAHbAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB3AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAd0BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHeAQAAYQEAAAMAAAAFAAAADgAAAB4AAAAB3wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAeABAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHhAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB4gEAAGEBAAADAAAABQAAAA4AAAAAAAAAAeMBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHkAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB5QEAAGEBAAADAAAABQAAAA4AAAAeAAAAAeYBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHnAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB6AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAekBAABhAQAAAwAAAAUAAAAOAAAACgAAAAHqAQAAYQEAAAMAAAAFAAAADgAAABQAAAAB6wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAewBAABhAQAAAwAAAAUAAAAOAAAAFAAAAAHtAQAAYQEAAAMAAAAFAAAADgAAABQAAAAB7gEAAGEBAAADAAAABQAAAA4AAAAAAAAAAe8BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAHwAQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB8QEAAGEBAAADAAAABQAAAA4AAAAUAAAAAfIBAABhAQAAAwAAAAUAAAAOAAAAFAAAAAHzAQAAYQEAAAMAAAAFAAAADgAAAAoAAAAB9AEAAGEBAAADAAAABQAAAA4AAAAAAAAAAfUBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAH2AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB9wEAAGEBAAADAAAABQAAAA4AAAAKAAAAAfgBAABhAQAAAwAAAAUAAAAOAAAACgAAAAH5AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB+gEAAGEBAAADAAAABQAAAA4AAAAKAAAAAfsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAH8AQAAYQEAAAMAAAAFAAAADgAAAAAAAAAB/QEAAGEBAAADAAAABQAAAA4AAAAAAAAAAf4BAABhAQAAAwAAAAUAAAAOAAAAHgAAAAH/AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABAAIAAGEBAAADAAAABQAAAA4AAAAAAAAAAQECAABhAQAAAwAAAAUAAAAOAAAAAAAAAAECAgAAYQEAAAMAAAAFAAAADgAAAAAAAAABAwIAAGEBAAADAAAABQAAAA4AAAAeAAAAAQQCAABhAQAAAwAAAAUAAAAOAAAAFAAAAAEFAgAAYQEAAAMAAAAFAAAADgAAAAAAAAAL + AAEAAAD/////AQAAAAAAAAAMAgAAADxDb3JlLCBWZXJzaW9uPTMuNS4xNy4yLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPW51bGwFAQAAACNfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuUHJvZmlsZQMAAAAeX3BsdWdJbkd1aWRUb1ZlcnNpb25Db25zdHJhaW50Fl9wbHVnSW5HdWlkVG9FeHRlbnNpb24aX3BsdWdJbkd1aWRUb0V4dGVuc2lvbkxpc3QEBAQ9XzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb1ZlcnNpb25Db25zdHJhaW50RGljdGlvbmFyeQIAAAAwXzNTLkNvRGVTeXMuQ29yZS5Db21wb25lbnRzLkd1aWRUb0Jvb2xEaWN0aW9uYXJ5AgAAAEBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvUHJvZmlsZUV4dGVuc2lvbkxpc3REaWN0aW9uYXJ5AgAAAAIAAAAJAwAAAAkEAAAACQUAAAAFAwAAAD1fM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvVmVyc2lvbkNvbnN0cmFpbnREaWN0aW9uYXJ5AQAAABhEaWN0aW9uYXJ5QmFzZStoYXNodGFibGUDHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUCAAAACQYAAAAFBAAAADBfM1MuQ29EZVN5cy5Db3JlLkNvbXBvbmVudHMuR3VpZFRvQm9vbERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJBwAAAAUFAAAAQF8zUy5Db0RlU3lzLkNvcmUuQ29tcG9uZW50cy5HdWlkVG9Qcm9maWxlRXh0ZW5zaW9uTGlzdERpY3Rpb25hcnkBAAAAGERpY3Rpb25hcnlCYXNlK2hhc2h0YWJsZQMcU3lzdGVtLkNvbGxlY3Rpb25zLkhhc2h0YWJsZQIAAAAJCAAAAAQGAAAAHFN5c3RlbS5Db2xsZWN0aW9ucy5IYXNodGFibGUHAAAACkxvYWRGYWN0b3IHVmVyc2lvbghDb21wYXJlchBIYXNoQ29kZVByb3ZpZGVyCEhh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AAAeAAAAAWsBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFsAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABbQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAW4BAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFvAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcAEAAGEBAAADAAAABQAAAA4AAAAeAAAAAXEBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAFyAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABcwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXQBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF1AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABdgEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXcBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF4AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABeQEAAGEBAAADAAAABQAAAA4AAAAAAAAAAXoBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAF7AQAAYQEAAAMAAAAFAAAADgAAAB4AAAABfAEAAGEBAAADAAAABQAAAA4AAAAKAAAAAX0BAABhAQAAAwAAAAUAAAAOAAAAHgAAAAF+AQAAYQEAAAMAAAAFAAAADgAAAAAAAAABfwEAAGEBAAADAAAABQAAAA4AAAAeAAAAAYABAABhAQAAAwAAAAUAAAAOAAAAHgAAAAGBAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABggEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYMBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGEAQAAYQEAAAMAAAAFAAAADgAAAAoAAAABhQEAAGEBAAADAAAABQAAAA4AAAAKAAAAAYYBAABhAQAAAwAAAAUAAAAOAAAACgAAAAGHAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiAEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYkBAABhAQAAAwAAAAUAAAAOAAAAFAAAAAGKAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABiwEAAGEBAAADAAAABQAAAA4AAAAAAAAAAYwBAABhAQAAAwAAAAUAAAAOAAAAAAAAAAGNAQAAYQEAAAMAAAAFAAAADgAAAAAAAAABjgEAAGEBAAADAAAABQAAAA4A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 True @@ -33221,7 +33361,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 - 638119892597176709 + 638133837499546749 @@ -33290,12 +33430,7 @@ 132 - (* Shared Variables for MQTT subscribe communication *) - - - 171 - - + (* Shared Variables for MQTT subscribe communication *) 133 @@ -33327,11 +33462,6 @@ collector_FB_RS485_MQTT :MQTT.CallbackCollector; - - 138 - - MQTT_logger :FB_MQTT_LOG; - 139 @@ -33352,9 +33482,24 @@ + + 188 + + + + + 189 + + (* HOME ASSISTANT DISCOVERY VIA MQTT*) + 143 + PLC_Device :FB_PLC_MQTT_DISCOVERY_DEVICE; + + + 190 + @@ -33412,11 +33557,6 @@ MQTTAvailabilityHartbeatTime :TIME:=T#5S; - - 151 - - MqttPubLogPrefix :STRING(100) := CONCAT(MqttBaseTopic,'logger/'); - 152 @@ -34949,7 +35089,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638101084165271366 + 638133837659440721 None @@ -35369,7 +35509,7 @@ 188 - MqttVariables.MQTT_logger.send(CONCAT('ERROR|DMX has a connection error ', DWORD_TO_STRING(IP_C.ERROR))); + MqttVariables.PLC_Device.SendLogMessage(CONCAT('ERROR|DMX has a connection error ', DWORD_TO_STRING(IP_C.ERROR))); 189 @@ -35794,7 +35934,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 74f81948-1328-492c-b6c1-a9ea72048b28 - 638115492311744379 + 638133838537199548 None @@ -36894,27 +37034,7 @@ 183 - VAR - - - 309 - - - - - 313 - - (* HOME ASSISTANT DISCOVERY VIA MQTT*) - - - 318 - - PLC_Device :FB_PLC_MQTT_DISCOVERY_DEVICE; - - - 316 - - + VAR 184 @@ -39859,7 +39979,7 @@ a9ed5b7e-75c5-4651-af16-d2c27e98cb94 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638101078147745696 + 638133838499801557 None @@ -39909,7 +40029,7 @@ 26 - MqttVariables.MQTT_logger.send('DMX ping Error'); + MqttVariables.PLC_Device.SendLogMessage('DMX ping Error'); 2 @@ -40217,7 +40337,7 @@ 3b83b776-fb25-43b8-99f2-3c507c9143fc - 638119892787222841 + 638133838359628321 @@ -40231,7 +40351,7 @@ 556 - PLC_Device.initPlcDevice( + MqttVariables.PLC_Device.initPlcDevice( 739 @@ -40268,61 +40388,6 @@ ); - - 560 - - - - - 561 - - (* MQTT logger*) - - - 562 - - MqttVariables.MQTT_logger.InitMqtt( - - - 563 - - MQTTPublishPrefix:= ADR(MqttVariables.MqttPubLogPrefix), - - - 564 - - pMqttPublishQueue := ADR(MqttVariables.fbMqttPublishQueue), - - - 565 - - MqttQos:=MQTT.QoS.ExactlyOnce, - - - 566 - - MqttRetain:=FALSE - - - 567 - - ); - - - 568 - - MqttVariables.MQTT_logger.InitMqttDiscovery( - - - 570 - - Device := ADR(PLC_Device), (* The device show in Home Assistant *) - - - 571 - - ); - 506 @@ -40376,7 +40441,7 @@ 583 - Device := ADR(PLC_Device), (* The device show in Home Assistant *) + Device := ADR(MqttVariables.PLC_Device), (* The device show in Home Assistant *) 314 @@ -40566,7 +40631,7 @@ 627 - Device := ADR(PLC_Device), (* The device show in Home Assistant *) + Device := ADR(MqttVariables.PLC_Device), (* The device show in Home Assistant *) 453 @@ -40636,7 +40701,7 @@ 640 - Device := ADR(PLC_Device), (* The device show in Home Assistant *) + Device := ADR(MqttVariables.PLC_Device), (* The device show in Home Assistant *) 540 @@ -40696,7 +40761,7 @@ 757 - Device := ADR(PLC_Device), (* The device show in Home Assistant *) + Device := ADR(MqttVariables.PLC_Device), (* The device show in Home Assistant *) 366 @@ -40756,7 +40821,7 @@ 654 - device := ADR(PLC_Device), (* the device show in home assistant *) + device := ADR(MqttVariables.PLC_Device), (* the device show in home assistant *) 655 @@ -41021,7 +41086,7 @@ 735 - MqttVariables.MQTT_logger.send('Init finished', 'MAIN_INIT'); + MqttVariables.PLC_Device.SendLogMessage('Init finished', 'MAIN_INIT'); 736 diff --git a/src/Exports/PLCopen.xml b/src/Exports/PLCopen.xml index 9bbc657..da10c9f 100644 --- a/src/Exports/PLCopen.xml +++ b/src/Exports/PLCopen.xml @@ -1,7 +1,7 @@  - - + + @@ -991,6 +991,11 @@ + + + + + @@ -1225,7 +1230,7 @@ ComposeJSON.Execute := TRUE; ComposeJSON(); IF MqttJSON = '' THEN - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); ELSIF NOT (MqttJSON = '') THEN pMqttPublishQueue^.AddMessage( Payload:= MqttJSON, @@ -1233,7 +1238,7 @@ ELSIF NOT (MqttJSON = '') THEN Qos := MQTT.QoS.ExactlyOnce, MqttRetain := TRUE, ); - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -1413,7 +1418,7 @@ ComposeJSON.Execute := TRUE; ComposeJSON(); IF MqttJSON = '' THEN - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); ELSIF NOT (MqttJSON = '') THEN pMqttPublishQueue^.AddMessage( Payload:= MqttJSON, @@ -1421,7 +1426,7 @@ ELSIF NOT (MqttJSON = '') THEN Qos := MQTT.QoS.ExactlyOnce, MqttRetain := TRUE, ); - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -1541,7 +1546,7 @@ ComposeJSON.Execute := TRUE; ComposeJSON(); IF MqttJSON = '' THEN - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); ELSIF NOT (MqttJSON = '') THEN pMqttPublishQueue^.AddMessage( Payload:= MqttJSON, @@ -1549,7 +1554,7 @@ ELSIF NOT (MqttJSON = '') THEN Qos := MQTT.QoS.ExactlyOnce, MqttRetain := TRUE, ); - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -1691,7 +1696,7 @@ ComposeJSON.Execute := TRUE; ComposeJSON(); IF MqttJSON = '' THEN - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); ELSIF NOT (MqttJSON = '') THEN pMqttPublishQueue^.AddMessage( Payload:= MqttJSON, @@ -1699,7 +1704,7 @@ ELSIF NOT (MqttJSON = '') THEN Qos := MQTT.QoS.ExactlyOnce, MqttRetain := TRUE, ); - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -1840,7 +1845,7 @@ ComposeJSON.Execute := TRUE; ComposeJSON(); IF MqttJSON = '' THEN - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); ELSIF NOT (MqttJSON = '') THEN pMqttPublishQueue^.AddMessage( Payload:= MqttJSON, @@ -1848,7 +1853,7 @@ ELSIF NOT (MqttJSON = '') THEN Qos := MQTT.QoS.ExactlyOnce, MqttRetain := TRUE, ); - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -1977,7 +1982,7 @@ ComposeJSON.Execute := TRUE; ComposeJSON(); IF MqttJSON = '' THEN - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); ELSIF NOT (MqttJSON = '') THEN pMqttPublishQueue^.AddMessage( Payload:= MqttJSON, @@ -1985,7 +1990,7 @@ ELSIF NOT (MqttJSON = '') THEN Qos := MQTT.QoS.ExactlyOnce, MqttRetain := TRUE, ); - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -2129,6 +2134,14 @@ CreateBinarySensorEntityWithCategory( DeviceClass := 'CONNECTIVITY', EntityCategory := 'diagnostic'); +//Logger +CreateSensorEntityWithCategory( + Name := 'Log', + Id := CONCAT(THIS^.Name,'_diag_log'), + Meta := '', + StateTopic := CONCAT(MqttDiagnosticTopic, '/Log'), + EntityCategory := 'diagnostic'); + // MAC address IF NOT(MacAddress = '') THEN CreateSensorEntityWithCategory( @@ -2292,7 +2305,7 @@ ComposeJSON.Execute := TRUE; ComposeJSON(); IF MqttJSON = '' THEN - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); ELSIF NOT (MqttJSON = '') THEN pMqttPublishQueue^.AddMessage( Payload:= MqttJSON, @@ -2300,7 +2313,7 @@ ELSIF NOT (MqttJSON = '') THEN Qos := MQTT.QoS.ExactlyOnce, MqttRetain := TRUE, ); - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -2436,7 +2449,7 @@ ComposeJSON.Execute := TRUE; ComposeJSON(); IF MqttJSON = '' THEN - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); ELSIF NOT (MqttJSON = '') THEN pMqttPublishQueue^.AddMessage( Payload:= MqttJSON, @@ -2444,7 +2457,7 @@ ELSIF NOT (MqttJSON = '') THEN Qos := MQTT.QoS.ExactlyOnce, MqttRetain := TRUE, ); - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -2589,7 +2602,7 @@ ComposeJSON.Execute := TRUE; ComposeJSON(); IF MqttJSON = '' THEN - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); ELSIF NOT (MqttJSON = '') THEN pMqttPublishQueue^.AddMessage( Payload:= MqttJSON, @@ -2597,7 +2610,7 @@ ELSIF NOT (MqttJSON = '') THEN Qos := MQTT.QoS.ExactlyOnce, MqttRetain := TRUE, ); - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -2734,7 +2747,7 @@ ComposeJSON.Execute := TRUE; ComposeJSON(); IF MqttJSON = '' THEN - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('ERROR ',Id), ' had empty MqttJSON'), instance := InstanceName); ELSIF NOT (MqttJSON = '') THEN pMqttPublishQueue^.AddMessage( Payload:= MqttJSON, @@ -2751,7 +2764,7 @@ ELSIF NOT (MqttJSON = '') THEN ); END_IF - Mqttvariables.MQTT_logger.send(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := 'bla'); + SendLogMessage(str:=CONCAT(CONCAT('Added ',Id), ' as MQTT dicovery'), instance := InstanceName); END_IF @@ -2759,6 +2772,41 @@ END_IF + + + + + + + + + + + + + + + + + + + + + + + + + pMqttPublishQueue^.AddMessage( + Payload:= CONCAT(CONCAT(instance,' | '),str), + Topic := CONCAT(MqttDiagnosticTopic, '/Log'), + Qos := 1, + MqttRetain := TRUE +); + + + + + @@ -4727,10 +4775,14 @@ ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= D //mark the interface call from the collector as done PublishReceived := TRUE; //now process the data - IF FIND(Data.PayloadString^, 'TRUE') > 0 THEN + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('TRUE')) THEN MqttHighRequest := TRUE; - END_IF - IF FIND(Data.PayloadString^, 'FALSE') > 0 THEN + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN + MqttLowRequest := TRUE; + // Siren sends out a JSON + ELSIF FIND(Data.PayloadString^, 'TRUE') > 0 THEN + MqttHighRequest := TRUE; + ELSIF FIND(Data.PayloadString^, 'FALSE') > 0 THEN MqttLowRequest := TRUE; END_IF END_IF @@ -5380,10 +5432,14 @@ ELSIF CommonTypesAndFunctions.StrEquals(str1:= ADR(MQTTSubscribeTopic), str2:= D //mark the interface call from the collector as done PublishReceived := TRUE; //now process the data - IF FIND(Data.PayloadString^, 'TRUE') > 0 THEN + IF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('TRUE')) THEN MqttHighRequest := TRUE; - END_IF - IF FIND(Data.PayloadString^, 'FALSE') > 0 THEN + ELSIF CommonTypesAndFunctions.StrEquals(str1:= Data.PayloadString, str2:= ADR('FALSE')) THEN + MqttLowRequest := TRUE; + // Siren sends out a JSON + ELSIF FIND(Data.PayloadString^, 'TRUE') > 0 THEN + MqttHighRequest := TRUE; + ELSIF FIND(Data.PayloadString^, 'FALSE') > 0 THEN MqttLowRequest := TRUE; END_IF END_IF @@ -12230,11 +12286,6 @@ SwapWordsToReal := pt_REAL^; - - - - - @@ -12246,6 +12297,14 @@ SwapWordsToReal := pt_REAL^; QOS Constants + + + + + + HOME ASSISTANT DISCOVERY VIA MQTT + + @@ -12324,14 +12383,6 @@ SwapWordsToReal := pt_REAL^; - - - - - - - - @@ -12525,14 +12576,6 @@ SwapWordsToReal := pt_REAL^; - - - - - - HOME ASSISTANT DISCOVERY VIA MQTT - - @@ -12642,7 +12685,7 @@ FB_DO_BISTABLE_001(); (* MQTT Discovery device*) -PLC_Device.initPlcDevice( +MqttVariables.PLC_Device.initPlcDevice( MqttDiscoveryPrefix := MqttVariables.MqttHADiscoveryPrefix, pMqttPublishQueue := ADR(MqttVariables.fbMqttPublishQueue), availabilityTopic := MqttVariables.MqttAvailabilityTopic, @@ -12651,17 +12694,6 @@ PLC_Device.initPlcDevice( MqttDiagnosticTopic := MqttVariables.MqttDiagnosticTopic ); -(* MQTT logger*) -MqttVariables.MQTT_logger.InitMqtt( - MQTTPublishPrefix:= ADR(MqttVariables.MqttPubLogPrefix), - pMqttPublishQueue := ADR(MqttVariables.fbMqttPublishQueue), - MqttQos:=MQTT.QoS.ExactlyOnce, - MqttRetain:=FALSE -); -MqttVariables.MQTT_logger.InitMqttDiscovery( - Device := ADR(PLC_Device), (* The device show in Home Assistant *) -); - (* INIT DIGITAL INPUT STUFF *) FB_DI_PB_001.InitMqtt( @@ -12671,7 +12703,7 @@ FB_DI_PB_001.InitMqtt( FB_DI_PB_001.InitMqttDiscovery( name := 'Button number 001', (* The name show in Home Assistant frond-end*) - Device := ADR(PLC_Device), (* The device show in Home Assistant *) + Device := ADR(MqttVariables.PLC_Device), (* The device show in Home Assistant *) ); FB_DI_PB_002.InitMqtt( @@ -12709,7 +12741,7 @@ FB_AO_DIMMER_001.InitDmx( (* INIT HOME ASSISTANT DISCOVERTY*) FB_AO_DIMMER_001.InitMqttDiscovery( name := '001. Office strip cold', (* The name show in Home Assistant frond-end*) - Device := ADR(PLC_Device), (* The device show in Home Assistant *) + Device := ADR(MqttVariables.PLC_Device), (* The device show in Home Assistant *) ); @@ -12723,7 +12755,7 @@ FB_DO_BISTABLE_001.InitMqtt( FB_DO_BISTABLE_001.InitMqttDiscoveryAsLight( name := 'light number 1', (* The name show in Home Assistant frond-end*) - Device := ADR(PLC_Device), (* The device show in Home Assistant *) + Device := ADR(MqttVariables.PLC_Device), (* The device show in Home Assistant *) ); FB_DO_BIN_001.InitMqtt( @@ -12735,7 +12767,7 @@ FB_DO_BIN_001.InitMqtt( FB_DO_BIN_001.InitMqttDiscoveryAsLight( name := 'light number 2', (* The name show in Home Assistant frond-end*) - Device := ADR(PLC_Device), (* The device show in Home Assistant *) + Device := ADR(MqttVariables.PLC_Device), (* The device show in Home Assistant *) ); (* INIT COVERS STUFF *) @@ -12747,7 +12779,7 @@ FB_DO_COVER_001.InitMqtt(MQTTPublishPrefix:= ADR(MqttVariables.MqttPubCoverPrefi FB_DO_COVER_001.initmqttdiscovery( (*see dimmer for full example *) name := 'cover number 001', (* the name show in home assistant frond-end*) - device := ADR(PLC_Device), (* the device show in home assistant *) + device := ADR(MqttVariables.PLC_Device), (* the device show in home assistant *) ); FB_DO_COVER_001.ConfigureFunctionBlock( @@ -12800,7 +12832,7 @@ FB_VIRTUAL_REAL_001.ConfigureFunctionBlockAsVirtualInput(DefaultValue:=0.1,SetDe -MqttVariables.MQTT_logger.send('Init finished', 'MAIN_INIT'); +MqttVariables.PLC_Device.SendLogMessage('Init finished', 'MAIN_INIT'); @@ -14159,7 +14191,7 @@ CASE Step OF LED_1_BrokerStatus(eID:=eLedID.AppLED_1, xOpen:=TRUE ); LED_1_BrokerStatus.SetFlash(T#2S,eLedColor.Red, eLedColor.Off); IF IP_C.ERROR = 33554432 THEN - MqttVariables.MQTT_logger.send(CONCAT('ERROR|DMX has a connection error ', DWORD_TO_STRING(IP_C.ERROR))); + MqttVariables.PLC_Device.SendLogMessage(CONCAT('ERROR|DMX has a connection error ', DWORD_TO_STRING(IP_C.ERROR))); END_IF; @@ -14219,7 +14251,7 @@ IF DMXnodeReachable = 0 THEN // MqttVariables.MQTT_logger.send('DMX ping OK'); ELSIF DMXnodeReachable = 5 THEN LED_1_BrokerStatus.SetFlash(T#1S,eLedColor.Red, eLedColor.Off); - MqttVariables.MQTT_logger.send('DMX ping Error'); + MqttVariables.PLC_Device.SendLogMessage('DMX ping Error'); END_IF diff --git a/src/HomeAutomation.ecp b/src/HomeAutomation.ecp index 294a018..6c6daef 100644 Binary files a/src/HomeAutomation.ecp and b/src/HomeAutomation.ecp differ