--- a/ConfigTreeNode.py Wed Jan 22 22:05:08 2025 +0100
+++ b/ConfigTreeNode.py Sun Jan 26 14:58:13 2025 +0100
@@ -585,6 +585,8 @@
NewCTNName = self.FindNewName(CTNName)
# If dir have already be made, and file exist
if os.path.isdir(self.CTNPath(NewCTNName)): # and os.path.isfile(self.ConfNodeXmlFilePath(CTNName)):
+ # Make CTN aware that this configuration was loaded + self.new_config = False # Load the confnode.xml file into parameters members
self.LoadXMLParams(NewCTNName)
# Basic check. Better to fail immediately.
@@ -605,6 +607,8 @@
# just loaded, nothing to saved
self.ChangesToSave = False
+ # Make CTN aware that this is first time configuration # If confnode do not have corresponding file/dirs - they will be created on Save
--- a/mqtt/library.py Wed Jan 22 22:05:08 2025 +0100
+++ b/mqtt/library.py Sun Jan 26 14:58:13 2025 +0100
@@ -22,11 +22,14 @@
res = c_function(topic, payload, len(payload), QoS, Retained)
-# C per client CallBack type for __mqtt_python_subscribe_{name}
-c_cb_type = ctypes.CFUNCTYPE(ctypes.c_int, # return
- ctypes.c_char_p, # topic
- ctypes.POINTER(ctypes.c_char), # data
- ctypes.c_uint32) # data length
+# C per client CallBack type for __mqtt_python_onmsg_{name} +mqtt_c_cb_onmsg_type = ctypes.CFUNCTYPE(ctypes.c_int, # return + ctypes.c_char_p, # topic + ctypes.POINTER(ctypes.c_char), # data + ctypes.c_uint32) # data length +# C per client CallBack type for __mqtt_python_resub_{name} +mqtt_c_cb_resub_type = ctypes.CFUNCTYPE(ctypes.c_int) # return # - each call to MQTT_subscribe registers a callback
@@ -35,18 +38,21 @@
# - one callback registered to C side per client
-def per_client_cb_factory(client):
- def per_client_cb(topic, dataptr, datalen):
+def mqtt_per_client_cb_factory(clientname): + def per_client_onmsg_cb(topic, dataptr, datalen): payload = ctypes.string_at(dataptr, datalen)
- subscriber = MQTT_subscribers_cbs[client].get(topic, None)
+ subscriber,_Qos = MQTT_subscribers_cbs[clientname].get(topic, None) subscriber(topic, payload)
+ def per_client_resub_cb(): + for topic,(_cb,QoS) in MQTT_subscribers_cbs[clientname].items(): + _MQTT_subscribe(clientname, topic, QoS) + return per_client_onmsg_cb,per_client_resub_cb -def MQTT_subscribe(clientname, topic, cb, QoS = 1):
- global MQTT_client_cbs, MQTT_subscribers_cbs
+def _MQTT_subscribe(clientname, topic, QoS): c_function_name = "__mqtt_python_subscribe_" + clientname
c_function = getattr(PLCBinary, c_function_name)
c_function.restype = ctypes.c_int # error or 0
@@ -54,17 +60,24 @@
- MQTT_subscribers_cbs.setdefault(clientname, {})[topic] = cb
+ return c_function(topic, QoS) +def MQTT_subscribe(clientname, topic, cb, QoS = 1): + global MQTT_client_cbs, MQTT_subscribers_cbs + MQTT_subscribers_cbs.setdefault(clientname, {})[topic] = (cb, QoS) + res = _MQTT_subscribe(clientname, topic, QoS) - c_cb = MQTT_client_cbs.get(clientname, None)
- c_cb = c_cb_type(per_client_cb_factory(clientname))
- MQTT_client_cbs[clientname] = c_cb
+ c_cbs = MQTT_client_cbs.get(clientname, None) + cb_onmsg, cb_resub = mqtt_per_client_cb_factory(clientname) + c_cbs = (mqtt_c_cb_onmsg_type(cb_onmsg), + mqtt_c_cb_resub_type(cb_resub)) + MQTT_client_cbs[clientname] = c_cbs register_c_function = getattr(PLCBinary, "__mqtt_python_callback_setter_"+clientname )
- register_c_function.argtypes = [c_cb_type]
- register_c_function(c_cb)
+ register_c_function.argtypes = [mqtt_c_cb_onmsg_type, mqtt_c_cb_resub_type] + register_c_function(*c_cbs) - res = c_function(topic, QoS)
--- a/mqtt/mqtt_template.c Wed Jan 22 22:05:08 2025 +0100
+++ b/mqtt/mqtt_template.c Sun Jan 26 14:58:13 2025 +0100
@@ -260,8 +260,11 @@
-typedef int(*callback_fptr_t)(char* topic, char* data, uint32_t datalen);
-static callback_fptr_t __mqtt_python_callback_fptr_{name} = NULL;
+typedef int(*cb_onmsg_fptr_t)(char* topic, char* data, uint32_t datalen); +static cb_onmsg_fptr_t __mqtt_python_cb_onmsg_fptr_{name} = NULL; +typedef int(*cb_resub_fptr_t)(void); +static cb_resub_fptr_t __mqtt_python_cb_resub_fptr_{name} = NULL; static int messageArrived(void *context, char *topicName, int topicLen, MQTTClient_message *message)
@@ -309,8 +312,8 @@
// If we reach here, then the element was not present
- if(__mqtt_python_callback_fptr_{name} &&
- (*__mqtt_python_callback_fptr_{name})(topicName,
+ if(__mqtt_python_cb_onmsg_fptr_{name} && + (*__mqtt_python_cb_onmsg_fptr_{name})(topicName, message->payloadlen) == 0){{
// Topic was handled in python
@@ -405,7 +408,7 @@
#define PUBLISH_JSON(Topic, QoS, C_type, c_loc_name, Retained) \
int res = json_gen_##c_loc_name(&MQTT_##c_loc_name##_buf); \
- _PUBLISH(Topic, QoS, json_out_len, json_out_buf, Retained) \
+ _PUBLISH(#Topic, QoS, json_out_len, json_out_buf, Retained) \ #define INIT_PUBLICATION(encoding, Topic, QoS, C_type, c_loc_name, Retained) \
@@ -458,6 +461,10 @@
+ if(__mqtt_python_cb_resub_fptr_{name}){{ + (*__mqtt_python_cb_resub_fptr_{name})(); return MQTTCLIENT_SUCCESS;
@@ -630,8 +637,9 @@
-int __mqtt_python_callback_setter_{name}(callback_fptr_t cb)
+int __mqtt_python_callback_setter_{name}(cb_onmsg_fptr_t cb_onmsg, cb_resub_fptr_t cb_resub) - __mqtt_python_callback_fptr_{name} = cb;
+ __mqtt_python_cb_onmsg_fptr_{name} = cb_onmsg; + __mqtt_python_cb_resub_fptr_{name} = cb_resub; --- a/runtime/WampClient.py Wed Jan 22 22:05:08 2025 +0100
+++ b/runtime/WampClient.py Sun Jan 26 14:58:13 2025 +0100
@@ -241,7 +241,7 @@
def SetWampSecret(wampSecret):
- with open(os.path.realpath(_WampSecret), 'w') as f:
+ with open(os.path.realpath(_WampSecret), 'wb') as f: --- a/xmlclass/xmlclass.py Wed Jan 22 22:05:08 2025 +0100
+++ b/xmlclass/xmlclass.py Sun Jan 26 14:58:13 2025 +0100
@@ -575,7 +575,7 @@
-def GenerateTagInfos(infos):
+def GenerateTagInfos(factory, infos): raise ValueError("\"%s\" musn't have attributes!" % infos["name"])
@@ -593,15 +593,14 @@
- p = etree.Element(infos["name"])
+ return factory.Parser.CreateElement(infos["name"])
"check": lambda x: x is None or infos["minOccurs"] == 0 and x
@@ -659,7 +658,7 @@
if element_infos is not None:
sequence_element["elmt_type"] = element_infos
elif choice["elmt_type"] == "tag":
- choice["elmt_type"] = GenerateTagInfos(choice)
+ choice["elmt_type"] = GenerateTagInfos(factory, choice) factory.AddToLookupClass(choice["name"], name, DefaultElementClass)
choice_infos = factory.ExtractTypeInfos(choice["name"], name, choice["elmt_type"])
@@ -1147,7 +1146,7 @@
elmtname = element["name"]
if element["elmt_type"] == "tag":
- infos = GenerateTagInfos(element)
+ infos = GenerateTagInfos(self, element) self.AddToLookupClass(element["name"], name, DefaultElementClass)
infos = self.ExtractTypeInfos(element["name"], name, element["elmt_type"])
@@ -1489,8 +1488,7 @@
value = self.content.getLocalTag()
- if self.content is not None:
- children.extend(self.content.getElementInfos(value)["children"])
+ children.extend(self.content.getElementInfos(value)["children"]) elif element["elmt_type"]["type"] == SIMPLETYPE:
@@ -1736,7 +1734,14 @@
return NAMESPACE_PATTERN.sub("", etree.tostring(self, encoding='unicode'))
def getElementInfos(self, name, path=None, derived=False):
- return {"name": name, "type": TAG, "value": None, "use": None, "children": []}
+ raise ValueError("Simple element "+name+" accepts no path: "+path) class XMLElementClassLookUp(etree.PythonElementClassLookup):