MQTT WIP: intermediate state, implementing MQTT client C code generator.
authorEdouard Tisserant <edouard@beremiz.fr>
Fri, 14 Jun 2024 15:56:12 +0200
changeset 3980 96acfee19caf
parent 3979 76295adcf940
child 3981 74035ea6792c
MQTT WIP: intermediate state, implementing MQTT client C code generator.
mqtt/client.py
mqtt/mqtt_client_gen.py
--- a/mqtt/client.py	Wed Jun 12 11:45:09 2024 +0200
+++ b/mqtt/client.py	Fri Jun 14 15:56:12 2024 +0200
@@ -50,6 +50,7 @@
             </xsd:element>
           </xsd:sequence>
           <xsd:attribute name="Broker_URI" type="xsd:string" use="optional" default="ws://localhost:1883"/>
+          <xsd:attribute name="Client_ID" type="xsd:string" use="optional" default=""/>
         </xsd:complexType>
       </xsd:element>
     </xsd:schema>
@@ -79,7 +80,7 @@
             return attr["value"]
 
         AuthType = cfg("AuthType")
-        res = dict(URI=cfg("Broker_URI"), AuthType=AuthType)
+        res = dict(URI=cfg("Broker_URI"), AuthType=AuthType, clientID=cfg("Client_ID"))
 
         paramList = authParams.get(AuthType, None)
         if paramList:
--- a/mqtt/mqtt_client_gen.py	Wed Jun 12 11:45:09 2024 +0200
+++ b/mqtt/mqtt_client_gen.py	Fri Jun 14 15:56:12 2024 +0200
@@ -32,10 +32,16 @@
 """
 QoS_values = [0, 1, 2]
 
-lstcolnames  = [ "Topic",  "QoS", "Type", "Location"]
-lstcolwidths = [     100,     50,    100,         50]
-lstcoltypess = [     str,    int,    str,        int]
-lstcoldeflts = [ "a/b/c",    "1", "DINT",        "0"]
+def boolean(v):
+    if v in ["False","0"]:
+        return False
+    else:
+        return bool(v)
+
+lstcolnames  = [ "Topic",  "QoS",  "Retain", "Type", "Location"]
+lstcolwidths = [     100,     50,       100,    100,         50]
+lstcoltypess = [     str,    int,   boolean,    str,        int]
+lstcoldeflts = [ "a/b/c",    "1",     False, "DINT",        "0"]
 Location_column = lstcolnames.index("Location")
 
 directions = ["input", "output"]
@@ -48,7 +54,7 @@
         ("User", None),
         ("Password", None)]}
 
-class MQTTSubListModel(dv.PyDataViewIndexListModel):
+class MQTTTopicListModel(dv.PyDataViewIndexListModel):
     def __init__(self, data, log):
         dv.PyDataViewIndexListModel.__init__(self, len(data))
         self.data = data
@@ -121,7 +127,7 @@
     def ResetData(self):
         self.Reset(len(self.data))
 
-class MQTTSubListPanel(wx.Panel):
+class MQTTTopicListPanel(wx.Panel):
     def __init__(self, parent, log, model, direction):
         self.log = log
         wx.Panel.__init__(self, parent, -1)
@@ -188,8 +194,8 @@
         self.selected_splitter = wx.SplitterWindow(self, style=wx.SUNKEN_BORDER | wx.SP_3D)
 
         self.selected_datas = modeldata
-        self.selected_models = { direction:MQTTSubListModel(self.selected_datas[direction], log) for direction in directions }
-        self.selected_lists = { direction:MQTTSubListPanel(
+        self.selected_models = { direction:MQTTTopicListModel(self.selected_datas[direction], log) for direction in directions }
+        self.selected_lists = { direction:MQTTTopicListPanel(
                 self.selected_splitter, log, 
                 self.selected_models[direction], direction) 
             for direction in directions }
@@ -283,14 +289,8 @@
     def GenerateC(self, path, locstr, config):
         template = """/* code generated by beremiz MQTT extension */
 
-#include <open62541/client_config_default.h>
-#include <open62541/client_highlevel.h>
-#include <open62541/plugin/log_stdout.h>
-#include <open62541/plugin/securitypolicy.h>
-#include <open62541/plugin/securitypolicy_default.h>
-
-#include <open62541/types.h>
-#include <open62541/types_generated_handling.h>
+#include "MQTTAsync.h"
+#include "MQTTClientPersistence.h"
 
 #define _Log(level, ...)                                                                           \\
     {{                                                                                             \\
@@ -303,38 +303,40 @@
 #define LogError(...) _Log(LOG_CRITICAL, __VA_ARGS__);
 #define LogWarning(...) _Log(LOG_WARNING, __VA_ARGS__);
 
-static MQTT_INLINE MQTT_ByteString
-loadFile(const char *const path) {{
-    MQTT_ByteString fileContents = MQTT_STRING_NULL;
+static inline void* loadFile(const char *const path) {{
 
     FILE *fp = fopen(path, "rb");
     if(!fp) {{
         errno = 0;
-        LogError("OPC-MQTT could not open %s", path);
-        return fileContents;
+        LogError("MQTT could not open %s", path);
+        return NULL;
     }}
 
     fseek(fp, 0, SEEK_END);
-    fileContents.length = (size_t)ftell(fp);
-    fileContents.data = (MQTT_Byte *)MQTT_malloc(fileContents.length * sizeof(MQTT_Byte));
-    if(fileContents.data) {{
+    size_t length = (size_t)ftell(fp);
+    void* data = malloc(length);
+    if(data) {{
         fseek(fp, 0, SEEK_SET);
-        size_t read = fread(fileContents.data, sizeof(MQTT_Byte), fileContents.length, fp);
-        if(read != fileContents.length){{
-            MQTT_ByteString_clear(&fileContents);
-            LogError("OPC-MQTT could not read %s", path);
+        size_t read = fread(data, 1, fileContents.length, fp);
+        if(read != length){{
+            free(data);
+            LogError("MQTT could not read %s", path);
         }}
     }} else {{
-        fileContents.length = 0;
-        LogError("OPC-MQTT Not enough memoty to load %s", path);
+        LogError("MQTT Not enough memoty to load %s", path);
     }}
     fclose(fp);
 
-    return fileContents;
+    return data;
 }}
 
-static MQTT_Client *client;
-static MQTT_ClientConfig *cc;
+static MQTTClient client;
+static MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
+
+void trace_callback(enum MQTTASYNC_TRACE_LEVELS level, char* message)
+{
+	LogWarning("Paho MQTT Trace : %d, %s\n", level, message);
+}
 
 #define DECL_VAR(ua_type, C_type, c_loc_name)                                                       \\
 static MQTT_Variant c_loc_name##_variant;                                                             \\
@@ -350,13 +352,13 @@
 }}
 
 #define INIT_NoAuth()                                                                              \\
-    LogInfo("OPC-MQTT Init no auth");                                                                \\
+    LogInfo("MQTT Init no auth");                                                                \\
     MQTT_ClientConfig_setDefault(cc);                                                                \\
     retval = MQTT_Client_connect(client, uri);
 
 /* Note : Single policy is enforced here, by default open62541 client supports all policies */
 #define INIT_x509(Policy, UpperCaseMode, PrivateKey, Certificate)                                  \\
-    LogInfo("OPC-MQTT Init x509 %s,%s,%s,%s", #Policy, #UpperCaseMode, PrivateKey, Certificate);     \\
+    LogInfo("MQTT Init x509 %s,%s,%s,%s", #Policy, #UpperCaseMode, PrivateKey, Certificate);     \\
                                                                                                    \\
     MQTT_ByteString certificate = loadFile(Certificate);                                             \\
     MQTT_ByteString privateKey  = loadFile(PrivateKey);                                              \\
@@ -398,7 +400,7 @@
     MQTT_ByteString_clear(&privateKey);
 
 #define INIT_UserPassword(User, Password)                                                          \\
-    LogInfo("OPC-MQTT Init UserPassword %s,%s", User, Password);                                     \\
+    LogInfo("MQTT Init UserPassword %s,%s", User, Password);                                     \\
     MQTT_ClientConfig_setDefault(cc);                                                                \\
     retval = MQTT_Client_connectUsername(client, uri, User, Password);
 
@@ -410,14 +412,23 @@
 
 int __init_{locstr}(int argc,char **argv)
 {{
-    MQTT_StatusCode retval;
-    client = MQTT_Client_new();
-    cc = MQTT_Client_getConfig(client);
     char *uri = "{uri}";
+    char *clientID = "{clientID}";
+    int rc;
+    conn_opts = MQTTClient_connectOptions_initializer;
+
+    if ((rc = MQTTClient_create(&client, uri, clientID,
+        MQTTCLIENT_PERSISTENCE_NONE, NULL)) != MQTTCLIENT_SUCCESS)
+    {
+        printf("Failed to create client, return code %d\n", rc);
+        rc = EXIT_FAILURE;
+        goto exit;
+    }
+
 {init}
 
     if(retval != MQTT_STATUSCODE_GOOD) {{
-        LogError("OPC-MQTT Init Failed %d", retval);
+        LogError("MQTT Init Failed %d", retval);
         MQTT_Client_delete(client);
         return EXIT_FAILURE;
     }}
@@ -453,6 +464,7 @@
         formatdict = dict(
             locstr   = locstr,
             uri      = config["URI"],
+            clientID = config["clientID"],
             decl     = "",
             cleanup  = "",
             init     = "",
@@ -511,13 +523,14 @@
     argc = len(sys.argv)
 
     config={}
-    config["URI"] = sys.argv[1] if argc>1 else "opc.tcp://localhost:4840"
+    config["URI"] = sys.argv[1] if argc>1 else "tcp://localhost:1883"
+    config["clientID"] = sys.argv[2] if argc>2 else ""
     config["AuthType"] = None
 
-    if argc > 2:
-        AuthType = sys.argv[2]
+    if argc > 3:
+        AuthType = sys.argv[3]
         config["AuthType"] = AuthType
-        for (name, default), value in zip_longest(authParams[AuthType], sys.argv[3:]):
+        for (name, default), value in zip_longest(authParams[AuthType], sys.argv[4:]):
             if value is None:
                 if default is None:
                     raise Exception(name+" param expected")