I use session.custom to handle "global" variables for stuff that we use across many customers. Stuff like Hand/Off/Auto - some customers prefer different words, so session.custom is where I store those lookups, and everywhere that needs them just refers there. So 1 spot to change and it affects all the buttons/statuses etc.
Seriously consider scalability with all of your projects. You never know when something you did is going to be deployed dozens, if not hundreds of times.
One of my big projects I've worked on started out as a simple Panelview Plus > Ignition Edge update. I had heard rumors of a Cloud portion but at the time it wasn't part of my scope and we had a deadline. So I made quite a few decisions that weren't ideal at scale, but fine for a single-node Edge application running on a site by itself, providing visualization to a single PLC. Then it turned out my less-than-ideal Edge application had to scale, and run on a Cloud server, with potentially dozens and then hundreds of tenants. As it grew, the decisions I made came back to bite me, and they had to be streamlined and made scalable, especially as more and more features were asked for. Of course, with every job, I look back and have regrets and "if I knew then what I know now" moments, but it never hurts to have less of them!
At the same time, avoid the temptation to over-abstract and make everything reusable at first. I used to do this with embedded views or components for everything, components that were usable in a variety of contexts and situations, etc. And at some point I was just making more work for myself and producing a lower-performance front end. There is a balance to be sought.
The balance between YANGI and abstracting appropriately is one you only really get with experience and failure. Knowing too if the project is going to be deployed elsewhere does also help inform you on these decisions. Try to do things with best practices as best you can, keep your code readable, keep your layers separate (gui from business even in scripting) will help keep things testable and extensible for when the client says "oh wait acutally can we do this other thing way".
But experience really will be the best teacher here imo.
I don't think it has been mentioned here just yet...
When working with strings in any Jython scripts, if you ever have to format, concatenate, or involve any operation that might include a unicode codepoint, use unicode strings explicitly!
Instead of using snippets that look like this:
def my_awesome_string_tool(user_name, user_id):
# Unicode can come from anywhere, but string encoding depends on the DB!
notes = system.db.execScalar('getNotes', {'noteid':4})
# The returned string may be less than ideal to work with...
return "My user {} has these notes: {}".format(user_name, notes)
Instead, a single character change may improve outcomes:
def my_awesome_unicode_string_tool(user_name, user_id):
# Unicode can come from anywhere, but it doesn't matter because we use unicode strings!
notes = system.db.execScalar('getNotes', {'noteid':4})
# The returned string is now explicitly a unicode string, and won't hurt you!
return u"My user {} has these notes: {}".format(user_name, notes)
I've been bitten by taking unicode input and formatting it within a jython2.7 string. Don't be like me and use unicode strings!
I use that all the time for Spanish characters
A theme seems to be put everything into scripts (the script library instead of on components), but then there is also a theme of only using scripts where necessary, and focusing on property bindings and expressions because they're faster.
What are some instances where scripts are necessary, and what are instances where expressions are sufficient? At what point is the cutoff? Is it just the amount of complicated logic?
if you have to write to a property or tag you have to use a script, most things involving arrays and datasets will also require a script. a good rule of thumb is if you don't need to write results to anything other than the property the binding itself is on, use expressions.
Those two items are orthogonal. The latter is a recommendation to maximize maintainability, and leverage certain performance advantages, when you decide to use a script at all.
I strongly encourage you to NOT put everything into scripts. They are the least performant way to move information around. But most flexible. Use where needed.
A big chunk of my Integration Toolkit is devoted to making this untrue--enabling expressions for complex constructs from datasets and other repetitive data.
My confusion came from the fact that they are very different, where can I find your Toolkit?
If you need more than a single expression, you need something more than the expression language (by definition).
Note that Phil's toolkit is entirely optional. I can't argue with his performance gains, but there's a saying about premature optimization. Make your project(s) in the way that you and whoever comes after you can maintain them. In my opinion, only reach to the advanced functionality offer by Phil's module when
- You actually need the extra performance
- You are sufficiently comfortable in Ignition that you understand the cost/benefit analysis
Don't just blindly hear "scripts are slow, expressions are fast" and think Phil's module is a panacea for all possible problems you're going to face in Ignition, especially Perspective.
IMO the same thing applies to map transforms. I use map transforms a lot when I feel the performance impact is minimal because I feel like the system will be more intuitive to support down the road. I try to build everything so that anyone can support it so that anyone can support it.
I like this out-of-context quote. I may be a bit biased.