Ignition Extensions - Convenience utilities for advanced users

Meh. Public code that anyone can build and carry forward.

@Michael.Smith has made a similar comment about my EtherNet/IP module being a third party product, but at least that one was justified by its commercial status.

Modules developed outside IA's process do not have to follow IA's schedule, and do not have to set the minimum Ignition version to the latest release, and can therefore provide features for older Ignition versions with low risk. My current set of modules work in the entire v8.1.x line.

IA's rigid versioning inhibits one of the key advantages of a modular platform: small changes (module installs) for incremental gains.

3 Likes

Does IA do design review or QA of other modules that are available in the module showcase? I don't know what the vetting process is. Is Paul's module distinct in that?

No.

Good points but I still think it's a value add in the context that this module is a collection of potentially useful scripts and not an IA product that has gone through the QA process.

Sure, I'm not disputing that. Use it. Or don't.

I'm just amused by history repeating itself.

This sounds interesting. I guess I'm going to have to get caught up on those episodes.

I love a good spicy breakfast in the morning, thanks y'all :laughing:

So, for me, this module serves a few purposes; in no particular order:

  • It's a fun distraction. I like writing Kotlin much more than Python, and most of what's in this module at the moment are basically just nice-to-have utility methods, but packaged under the system namespace because modules are allowed to do this. Basically zero maintenance burden or risk, because they're just operating on the public contract of things like datasets.
  • It's an educational exercise; for me, and for the community. This is, as far as I know, the only publicly available example of a 'modern' CI stack for an Ignition module. It's even got automated releasing and signing via Github Actions. It's also a good opportunity to demonstrate a "real" module, rather than the closer to toy examples in the sdk-examples project.
  • It's an experimentation ground for me. Maybe I have an idea for a function (that could eventually end up in Ignition) but I have no idea what the API should be. Or if it's even going to be useful to folks. With no QA process, no guarantees of future compatibility, and a big scary warning every time you autocomplete the function, I figure risk of someone blindly relying on this "in the wild" is pretty minimal.
  • Most of these functions don't belong in the platform for every single end user. Sure, anyone familiar with Python or functional programming in general is going to grok system.dataset.filter/map pretty immediately. But many folks coming to Ignition have never programmed in anything besides ladder, or VBA, or Excel formulas. Trying to explain the idea of a 'pure' function to someone who can't yet distinguish expressions from scripts? Sounds like a bad time.
    • Similarly, nothing I'm doing here is anything you can't just do yourself from scripting, with sufficient motivation. It's a lot easier now, sure, but the only truly "unsafe" thing exposed here, in terms of deep reflection or reliance on non-public internals are system.project.save() and system.project.update().

It's also not just my project. I'm open to PRs from everyone, and I took steps to divorce it from my name/namespace on Github. If anyone wants to step up and maintain it going forward, or if I fall off the face of the earth... they can! No big deal.

I'm very aware of the birth (and ignoble death) of the IA labs concept (https://forum.inductiveautomation.com/t/useful-common-script-extensions/64538?u=pgriffith) - it was top of mind when I started this project. That's precisely why I made sure to make nothing about this 'special' to me, or blessed by IA in any official capacity. It's intended to be a community effort; it's just that so far nobody's stepped up to learn enough Kotlin to contribute :laughing:

11 Likes

I'm very aware of the birth (and ignoble death) of the IA labs concept (https://forum.inductiveautomation.com/t/useful-common-script-extensions/64538?u=pgriffith)

Link is broken fyi :slight_smile:

Not broken, it's just in the special 'Lounge' area the forum software hasn't decided you get to see yet. It's not very exciting, I promise.

6 Likes

I spend my spare time in embedded Rust programming. Seems like I saw you had written something in Rust :thinking:, I think I was browsing your Github profile a while back and stumbled upon it :grinning:

Ahh gotcha. Disregard then!

To be clear, I don't have anything against third party modules and I think that they serve a purpose where IA doesn't have the knowledge/expertise/willpower/desire to develop a product in line with their standards. My comment to you previously was more of a curiosity about how it achieves magnitudes better performance than the base driver.

I think many of these features probably do belong in ignition at a base level as they are within the scope of the base ignition platform, particularly the fromExcel function and Logic expression functions.

I wouldn't be so sure of this assumption, I would suspect a great deal of the user base are familiar with basic programming concepts. Many people coming to ignition have probably never touched SQL, but those features are available to all users.

Not trying to rain on anyone's parade, and the other points you raised are valid, but at some point I think it is worth checking and saying "Should ignition just do this already?"

Maybe I'm biased since I made the suggestion, but I definitely feel the isAvailable function should become part of the Ignition base. The alternative without it is so overly convoluted in the expression language if you're wanting to hide components based on the availability of tags (exist and not disabled). I install this module for all projects almost purely for this function alone! Although I do find many of the other python functions convenient as well, however as Paul said, these at least are replicable without the module. Expression functions however, aren't, and if I tell a newcomer that in order to hide a component, they have to use this expression below, they will look at me like I'm insane :slight_smile:

indexOf(toStr(qualityOf({tag})), 'Bad_NotFound') = -1 &&
indexOf(toStr(qualityOf({tag})), 'Bad_Disabled') = -1

I'm curious, why do you need the indexOf() and toStr() portions of that expression? I would have thought that the expression below would work, but I'm guessing I'm missing something important:

qualityOf({tag}) != 'Bad_NotFound' &&
qualityOf({tag}) != 'Bad_Disabled'
1 Like

You used to be able to use this, but now (as of something like 8.1.9?) the quality contains contextual info in it like "Bad_Error (Node address not found blah blah blah)" so you have to use indexof :confused: (or just use isAvailable :slight_smile: )

Has that maybe changed back to the original behavior? I just tested in 8.1.25 and it appears to be working.

Edit: Did a quick check. Seems like it's only when you use the toStr() that the contextual info comes into play - at least for 8.1.25. I wonder if that was a bug that has since been fixed?

1 Like

@PGriffith - This reminded me that an expression function that I would find useful is one that could mimic the python in operator for checking if a value is in a list. Basically the same as the case/switch functions, getting rid of the return arguments and instead returning true if there is a match. Pretty common to have to check the same value against multiple conditions in an expression. Would help declutter a bit.

2 Likes

Hmm, I seem to remember when I tried using qualityOf that it would return an object rather than a string and it wasn't comparable to a string :thinking:

Still, I'd much prefer not to have to use even that slightly smaller collection of functions and text comparisons when I need to do this many times throughout a project

I think it is still an object, but it handles the comparison automatically depending on what you are trying to compare it to. Far as I can tell you can compare it to either the string or int value for the respective quality code.

Agree with you here that isAvailable() is much nicer. My original question was for my own learning as I wanted to make sure I wasn't missing some key detail when it came to quality code comparisons that was going to come back and bite me in the future :sweat_smile: