MQTT Sparkplug via Cirruslink MQTT Engine

Hi all,

I'm trying to use the function "system.cirruslink.engine.publish()" to publish sparkplug messages back to a gateway.

The basic reason for this is that I'm using metadata properties on the tags for various things, and when these are updated on the gateway tags, it doesn't trigger a DCMD message the way changing the actual tag value would.

import sparkplug_b as sparkplug
from sparkplug_b import addMetric, MetricDataType

payload = sparkplug.getDdataPayload()
addMetric(payload, 'metric.meta', None, MetricDataType.Boolean, False)
topic='spBv1.0/...'
result = system.cirruslink.engine.publish('SERVER', topic, payload.SerializeToString(), 1, False)|

I've actually been running the script successfully for a while by importing the sparkplug libraries into Ignition and using the provided functions to encode the messages, but recent changes to the Ignition python binary removed the time.gmtime() function, which is in turn required by the google protobuf library, so that whole route is now no longer possible.

Traceback (most recent call last):
  File "<input>", line 7, in <module>
  File "/home/user/.ignition/cache/gwscada.example.com_8088/C1/pylib/sparkplug_b/__init__.py", line 13, in <module>
    import sparkplug_b_pb2
  File "/home/user/.ignition/cache/gwscada.example.com_8088/C1/pylib/sparkplug_b/sparkplug_b_pb2.py", line 8, in <module>
    from google.protobuf import reflection as _reflection
  File "/home/user/.ignition/cache/gwscada.example.com_8088/C1/pylib/google/protobuf/reflection.py", line 51, in <module>
    from google.protobuf import message_factory
  File "/home/user/.ignition/cache/gwscada.example.com_8088/C1/pylib/google/protobuf/message_factory.py", line 49, in <module>
    from google.protobuf.internal import python_message as message_impl
  File "/home/user/.ignition/cache/gwscada.example.com_8088/C1/pylib/google/protobuf/internal/python_message.py", line 70, in <module>
    from google.protobuf.internal import well_known_types
  File "/home/user/.ignition/cache/gwscada.example.com_8088/C1/pylib/google/protobuf/internal/well_known_types.py", line 99, in <module>
    _EPOCH_DATETIME = datetime.utcfromtimestamp(0)
  File "/home/user/.ignition/cache/gwscada.example.com_8088/C1/pylib/datetime.py", line 1623, in utcfromtimestamp
    y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t)
AttributeError: 'builtin_function_or_method' object has no attribute 'gmtime'

So what I'm trying to do is just get access to these encoding methods to convert my payload to sparkplug, which should already be present since that's what the driver does every time it sends a message.

I can use the function to send unencoded messages, but since the remote site is speaking in Sparkplug/Protobuf, these are not understood by the client.

Any ideas?

I was looking for something over on the Cirrus Link forum, and I spotted this parallel thread:

I don't know the answer, but since @wes0johnson referred this to us, I'm going to go ahead and bump this question.

Unfortunately, metric properties cannot be written to. They are intended to be static information to provide supporting context to the metric. Only the value of the metric can be updated via DCMD messages.

If the parameter is dynamic it will need to be broken out into it's own tag/metric. Typically, this is good use case for UDTs.

Hi TChenier,
I'm currently writing to metric properties from the field devices to Ignition without issue, and until the change to the built-in Time library, I was successfully writing properties back from Ignition to the field.

I suspect what you're saying is that the driver will not handle these write-backs for me, which is correct, and this is why I implemented my own publishing script.

The fact that I'm storing this information in metadata is not really core to the problem. I have a script that performs maintenance on tags at a low frequency and maintains relationships between tags that is specific to my project. Lets just assume for the moment that I need to be able to communicate custom commands or information back to the field using the existing MQTT/Sparkplug interface.

The only thing preventing me from doing this is that Ignition made a change to the built-in Python library that now prevents me from importing the Sparkplug libraries. I would load an alternative Time library, but I cannot find one written in Python. It's a core library written in C that is normally built into the Python executable itself.

I was hoping to gain access to the Cirruslink libraries, but as Wes explained, their codebase is in Java and cannot be exposed to users.

I'm not an expert on the Ignition stack, but I think the only solution here is to either convince Inductive Automation to include the full Time library in their Python executable again, or to somehow overload that library on my end.

I'm open to any other suggestions to try that could solve this problem!

We didn't change anything... when did this stop working for you? Versions?

import time

print time.gmtime(0)
Jython 2.7.2 (uncontrolled:000000000000, Jul 10 2023, 08:50:23)
[OpenJDK 64-Bit Server VM (Eclipse Adoptium)] on java11.0.20

>>> 
time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0)
>>> 

Hi!
Jacques, were you able to solve this problem? In my company we need to update several metrics of the same topic at the same time. By changing the value of the tags, only one metric can be sent at a time.

Best Regards.