edouard@3979: # mqtt/client.py edouard@3979: edouard@3979: from __future__ import absolute_import edouard@3979: edouard@3979: import os edouard@4005: import re edouard@4023: import wx edouard@3979: edouard@3979: from editors.ConfTreeNodeEditor import ConfTreeNodeEditor edouard@3979: from PLCControler import LOCATION_CONFNODE, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT edouard@3979: from .mqtt_client_gen import MQTTClientPanel, MQTTClientModel, MQTT_IEC_types, authParams edouard@3979: edouard@3979: import util.paths as paths edouard@3979: edouard@3984: edouard@3984: # assumes that "build" directory was created in paho.mqtt.c source directory, edouard@3984: # and cmake build was invoked from this directory edouard@3984: PahoMqttCLibraryPath = paths.ThirdPartyPath("paho.mqtt.c", "build", "src") edouard@3984: edouard@4012: frozen_path = paths.ThirdPartyPath("frozen") edouard@4012: edouard@4012: MqttCIncludePaths = [ edouard@3984: paths.ThirdPartyPath("paho.mqtt.c", "build"), # VersionInfo.h edouard@4012: paths.ThirdPartyPath("paho.mqtt.c", "src"), edouard@4012: frozen_path edouard@3984: ] edouard@3979: edouard@3979: class MQTTClientEditor(ConfTreeNodeEditor): edouard@3979: CONFNODEEDITOR_TABS = [ edouard@4023: (_("MQTT Client"), "CreateMQTTClient_UI"), edouard@4023: (_("Info"), "CreateInfo_UI")] edouard@3979: edouard@4014: MQTTClient_UI = None edouard@4023: Info_UI = None edouard@4014: edouard@3979: def Log(self, msg): edouard@3979: self.Controler.GetCTRoot().logger.write(msg) edouard@3979: edouard@3979: def CreateMQTTClient_UI(self, parent): edouard@4014: self.MQTTClient_UI = MQTTClientPanel( edouard@4010: parent, edouard@4010: self.Controler.GetModelData(), edouard@4010: self.Log, edouard@4010: self.Controler.GetTypes) edouard@4014: return self.MQTTClient_UI edouard@4014: edouard@4023: def CreateInfo_UI(self, parent): edouard@4023: location_str = "_".join(map(str, self.Controler.GetCurrentLocation())) edouard@4023: information=("Connection status GLOBAL VAR is:\n\n\tMQTT_STATUS_"+location_str edouard@4023: +", of type INT.\n\t" edouard@4023: +"0 is disconnected\n\t" edouard@4023: +"1 is connected\n") edouard@4023: self.Info_UI = wx.StaticText(parent, label = information) edouard@4023: return self.Info_UI edouard@4023: edouard@4014: def RefreshView(self): edouard@4014: if(self.MQTTClient_UI): edouard@4014: self.MQTTClient_UI.RefreshView() edouard@4014: return ConfTreeNodeEditor.RefreshView(self) edouard@4014: edouard@3979: edouard@3979: class MQTTClient(object): edouard@3979: XSD = """ edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@4005: edouard@4005: edouard@4005: edouard@4005: edouard@4005: edouard@4005: edouard@4005: edouard@4005: edouard@4005: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3979: edouard@3986: edouard@3979: edouard@3980: edouard@3979: edouard@3979: edouard@3979: edouard@3979: """ edouard@3979: edouard@3979: EditorType = MQTTClientEditor edouard@3979: edouard@3979: def __init__(self): edouard@3979: self.modeldata = MQTTClientModel(self.Log, self.CTNMarkModified) edouard@3979: edouard@3979: filepath = self.GetFileName() edouard@3979: if os.path.isfile(filepath): edouard@3979: self.modeldata.LoadCSV(filepath) edouard@3979: edouard@3979: def Log(self, msg): edouard@3979: self.GetCTRoot().logger.write(msg) edouard@3979: edouard@3979: def GetModelData(self): edouard@3979: return self.modeldata edouard@3979: edouard@4010: def GetTypes(self): edouard@4022: datatype_candidates = self.GetCTRoot().GetDataTypes(basetypes=False, only_locatables=True) edouard@4010: return datatype_candidates edouard@4010: edouard@4012: def GetDataTypeInfos(self, typename): edouard@4012: tagname = "D::"+typename edouard@4012: return self.GetCTRoot().GetDataTypeInfos(tagname) edouard@4012: edouard@3979: def GetConfig(self): edouard@3979: def cfg(path): edouard@3979: try: edouard@3979: attr=self.GetParamsAttributes("MQTTClient."+path) edouard@3979: except ValueError: edouard@3979: return None edouard@3979: return attr["value"] edouard@3979: edouard@3979: AuthType = cfg("AuthType") edouard@3986: res = dict( edouard@3986: URI=cfg("Broker_URI"), edouard@3986: AuthType=AuthType, edouard@3986: clientID=cfg("Client_ID"), edouard@3986: UseMQTT5=cfg("Use_MQTT_5")) edouard@3979: edouard@3979: paramList = authParams.get(AuthType, None) edouard@3979: if paramList: edouard@3979: for name,default in paramList: edouard@4005: edouard@4005: # Translate internal config naming into user config naming edouard@4005: displayed_name = {"KeyStore" : "Client_certificate", edouard@4005: "TrustStore" : "Broker_certificate", edouard@4005: "Verify" : "Verify_hostname"}.get(name, name) edouard@4005: edouard@4005: value = cfg("AuthType." + displayed_name) edouard@3979: if value == "" or value is None: edouard@3979: value = default edouard@4005: edouard@4005: if value is not None: edouard@4005: # cryptomaterial is expected to be in project's user provided file directory edouard@4005: edouard@4005: # User input may contain char incompatible with C string literal escaping edouard@4005: if name in ["User","Password","TrustStore","KeyStore","Broker_URI","Client_ID"]: edouard@4005: value = re.sub(r'([\"\\])', r'\\\1', value) edouard@4005: edouard@3979: res[name] = value edouard@3979: edouard@3979: return res edouard@3979: edouard@3979: def GetFileName(self): edouard@3979: return os.path.join(self.CTNPath(), 'selected.csv') edouard@3979: edouard@3979: def OnCTNSave(self, from_project_path=None): edouard@3979: self.modeldata.SaveCSV(self.GetFileName()) edouard@3979: return True edouard@3979: edouard@3979: def CTNGenerate_C(self, buildpath, locations): edouard@3979: current_location = self.GetCurrentLocation() edouard@3979: locstr = "_".join(map(str, current_location)) edouard@3979: c_path = os.path.join(buildpath, "mqtt_client__%s.c" % locstr) edouard@3979: edouard@3984: c_code = """ edouard@3984: #include "iec_types_all.h" edouard@3984: #include "beremiz.h" edouard@3984: """ edouard@4001: config = self.GetConfig() edouard@4012: c_code += self.modeldata.GenerateC(c_path, locstr, config, self.GetDataTypeInfos) edouard@3979: edouard@3979: with open(c_path, 'w') as c_file: edouard@3979: c_file.write(c_code) edouard@3979: edouard@4001: if config["AuthType"] == "x509": edouard@4001: static_lib = "libpaho-mqtt3cs.a" edouard@4001: libs = ['-lssl', '-lcrypto'] edouard@4001: else: edouard@4001: static_lib = "libpaho-mqtt3c.a" edouard@4001: libs = [] edouard@4001: edouard@4001: LDFLAGS = [' "' + os.path.join(PahoMqttCLibraryPath, static_lib) + '"'] + libs edouard@3979: edouard@4012: CFLAGS = ' '.join(['-I"' + path + '"' for path in MqttCIncludePaths]) edouard@4012: edouard@4012: # TODO: add frozen only if using JSON edouard@4012: frozen_c_path = os.path.join(frozen_path, "frozen.c") edouard@4012: edouard@4012: return [(c_path, CFLAGS), (frozen_c_path, CFLAGS)], LDFLAGS, True edouard@3979: edouard@3979: def GetVariableLocationTree(self): edouard@3979: current_location = self.GetCurrentLocation() edouard@3979: locstr = "_".join(map(str, current_location)) edouard@3979: name = self.BaseParams.getName() edouard@3991: edouard@3979: entries = [] edouard@3991: children = [] edouard@3991: edouard@3991: for row in self.modeldata["output"]: edouard@3991: Topic, QoS, _Retained, iec_type, iec_number = row edouard@3991: entries.append((Topic, QoS, iec_type, iec_number, "Q", LOCATION_VAR_OUTPUT)) edouard@3991: edouard@3991: for row in self.modeldata["input"]: edouard@3991: Topic, QoS, iec_type, iec_number = row edouard@3991: entries.append((Topic, QoS, iec_type, iec_number, "I", LOCATION_VAR_INPUT)) edouard@3991: edouard@3991: for Topic, QoS, iec_type, iec_number, iec_dir_prefix, loc_type in entries: edouard@4009: _C_type, iec_size_prefix = MQTT_IEC_types.get(iec_type,(None,"")) edouard@3991: c_loc_name = "__" + iec_dir_prefix + iec_size_prefix + locstr + "_" + str(iec_number) edouard@3991: children.append({ edouard@3991: "name": Topic, edouard@3991: "type": loc_type, edouard@4009: "size": {"X":1, "B":8, "W":16, "D":32, "L":64, "":None}[iec_size_prefix], edouard@3991: "IEC_type": iec_type, edouard@3991: "var_name": c_loc_name, edouard@3991: "location": "%" + iec_dir_prefix + iec_size_prefix + ".".join([str(i) for i in current_location]) + "." + str(iec_number), edouard@3991: "description": "", edouard@3991: "children": []}) edouard@3991: edouard@3979: return {"name": name, edouard@3979: "type": LOCATION_CONFNODE, edouard@3979: "location": ".".join([str(i) for i in current_location]) + ".x", edouard@3991: "children": children} edouard@3979: edouard@4010: edouard@4010: def CTNGlobalInstances(self): edouard@4010: location_str = "_".join(map(str, self.GetCurrentLocation())) edouard@4023: return [("MQTT_STATUS_"+location_str, "INT", ""), edouard@4023: ] edouard@4023: edouard@4023: