I am trying to convert a hex value to an ascii value. Any help would be appreciated.
hexIn = '4a6f7264616e20697320612067656e69757321204a75737420646f6e27742061736b2068697320776966652e'
print hexIn.decode('hex')
To be more specific I am trying to change a tag value from an float to a hex value then from hex to ascii value. the issue I am having is the tag binding script window doesn’t accept some of the characters in the code you provided. and I am not sure where I should put the code to affect my tag value?
Are you trying to convert the float to a string? or the float as some type of encoding that can be converted to ASCII?
You could create a new expression tag that converts the float to string and bind the new tag for you application.
I want to convert from float to an ascii value(the name of the device). i used the component binding window to convert from float to hex and now I want to go from hex to ascii.
Okay. The more information you can provide, the better the answers become. Stating what you are trying to do with an example of input and expected output helps too.
Just so I’m on the same page, do you want a string representation of the float, or a string representation of the hex?
@JordanCClark the device gives me a float value. according to manufacturer I should be able to convert the float to a hex value then from a hex value to an ascii value and that will give me the name of the device.
As suggested by @JordanCClark can you post an example of the float value and how it should look like in ASCII?
A float is just 32 bits, while an ASCII character is 8 bits.
So if you try to convert a float to ASCII without any other information (lookup tables of some kind), you can only get 4 characters out of it.
Sorry, Amos, I misread your previous post.
Some information that will help:
- Make and model of the device, or, link to the documentation.
- An example of what data is coming in.
- What you expect the output to be.
What we will do as a final solution would be to create a shared script for you to use, Then we can use runScript in your expression to get the string you need. There is no way to do this directly in expression language.
The name is probably stored in a float32 because the device does not have a string dataype. I think you need to do a c language memcpy(*floatval, stringval,4) with no translation. Sorry, I do not know how to do that in Python.
If this is Modbus device just read the 2 registers of the float value as a string. Modbus does not enforce datatypes.
Consider using system.tag.readAll for more efficient tag reads (all in one read), something like the script below (requires renaming your first tag to end in " 0" to make a consistent tag name pattern):
def HexToText():
tags = ['TemperatureReader/name %s' %i for i in range(0,7)]
hexValues = [hex(int(x.value))[2:] for x in system.tag.readAll(tags)]
return = ''.join(hexValues).decode('hex')
The above version also eliminates repetitive code for easier changes and less opportunity to introduce bugs.
At the cost of less people understanding it...
List comprehensions aren't such a standard feature in programming languages.
IMHO, it's best to stick to features you can write yourself. It becomes hard enough to figure out what's going wrong even when you wrote it yourself.
Don't get me wrong, it's a nice and clean solution for a team of advanced programmers, but it takes quite a bit of time to understand what's going wrong when you get an error. And it can scare novice programmers.
Some intermediate way, that still uses the readAll
function, and probably easier to understand, would be to use for-loops. Something like this (code untested):
def HexToText():
tags = []
for i in range(7):
tags.append('TemperatureReader/name %s' %i)
tagValues = system.tag.readAll(tags)
hexValues = []
for qualifiedValue in tagValues:
hexValues.append(hex(int(qualifiedValue.value))[2:])
fullEpc = ''
for hexValue in hexValues:
fullEpc += hexValue.decode('hex')
return fullEpc
No, this is really basic python. Learn list comprehensions and use them. A one-liner, as long as its not too long to see on the screen, is far more maintainable than an expanded loop. And runs faster.
I have to disagree on this one.
When using for loops, you usually have to name a few more variables (which gives them som meaning), it's also a lot easier to see from where errors are coming, to add debug print statements, to add breakpoints (if the environment allows it), ...
Also when extending the functionality, adding an if-statement, a break, or a continue in a loop is easy. But not in a list comprehension. If makes the list comprehension a lot uglier, and usually really needs a conversion to a for loop after all.
I've found myself very often writing beautiful list comprehensions, only to realise I needed to add this check to cover None values, and another check, and it became a mess that had to be turned into a for loop.
I do still use list comprehensions, but I only ever do one thing in such a comprehension. Certainly not getting the data, and converting it through 2 functions before returning it.
In the example given, how would you add a check that tests whether the tags have a good quality? And add a test to see if they aren't control characters? It seems pretty trivial to me in the for loop. But the list comprehension becomes quite long when doing that.
I think we'll just have to disagree. Many of your cases would trigger my long-line rule, so I don't think we are really that far apart. But I do use the if
clause to filter comprehensions efficiently. And I nest them, too. Most commonly with tag reads. This is a typical pattern in a script module:
udtParts = ['Start', 'Stop', 'Jog', 'Auto', 'Permissive', 'Run']
def computeRun(udtpath):
start, stop, jog, auto, permit, run = [x.value for x in system.tag.readAll([udtpath+'/'+y for y in udtParts])]
return (not stop) and permit and ((auto and (start or run)) or (jog and not auto))
While I agree in principle, everyone starts somewhere. Until you're comfortable with them, it's better to break it down to bite-size pieces, as Amos did.
Is it efficient? No. But, sometimes you need to have something that works first, then optimize it after.
Regardless of which you use: document, document, document. I've been as guilty as anyone of not properly documenting a routine, only to go back later and wonder what the heck it was that I did.
I now try to put comments in, even for routines that are 'self-documenting', because if I can confuse myself, I know I can confuse the guy behind me.
I don’t really have a horse in this race, since I have a significantly different workload, but one thing people under-utilize in list comprehensions is indentation. It’s not directly usable within Ignition, but I’m a dedicated convert to the strict formatter black. I use it on “real” Python code I write, and it makes some decisions that (in my opinion) really help legibility. You could certainly run it as a post-processing step manually on any “complicated” methods you write inside Ignition.
filters = {
k: v
for k, v in {
"state": args.get("state", "open"),
"sort": args.get("sort", "created"),
"direction": args.get("direction", "desc"),
"head": args.get("head"),
"base": args.get("base"),
}.items()
if v is not None
}
prs = git.get_pull_requests(filters)
return {
"prs": [
{
"id": pr.number,
"title": pr.title,
"cases": [
{"id": case.id, "title": case.title}
for case in config.fogbugz.unfurler.objects(pr.title, pr.body)
],
}
for pr in prs
]
}
That, and I wanted to show off
Absolutely--while expanding what you can write yourself. The first time I saw a list comprehension example here, I took a few minutes to read up on them. Since then I've used them routinely and would suggest anyone using Python would benefit from taking a few minutes to understand them.
Thanks for adding an intermediate example above; it'll be helpful to someone. Those comfortable with list comprehensions could likely read and understand the three lines of code more quickly than the multiple for loops, but they're both good ways of getting it done. When adding more logic, adjust the code as required to make it easy to follow--including moving to a for loop if needed. I probably would not include the checks you note inside the list comprehension in the example given above, but I'd still almost certainly use list comprehensions in the solution including those checks.
In the above case--without adding any more logic to that originally supplied--the basic steps from a high level perspective (not getting into what instructions are necessary/available to accomplish them) are:
- List tags.
- Get hex characters from tags.
- Return string from hex characters.
Those could be comment lines for inline documentation.
We could write the entire function on one line under the def
line, but we all likely agree that would be silly. The general rules I follow are:
- Break the code down into the logical steps of the task (from a high-level human perspective, not necessarily each code step), using variables for these steps (makes code more self-documenting). For more complex operations I'll often write the comment lines (high-level steps) first, then fill in the code under them.
- Keep code and comment lines short enough to read without horizontal scrolling as @pturmel notes.
I find these rules make code easy to comprehend quickly. I also find it helpful to view as much of the code as possible at once, which is why I've gradually developed a preference for structured text over ladder logic for most PLC code (now I'm asking for punishment!). Large monitors are great, as are efficient constructs like list comprehensions.
I don't know that I'd qualify as new to Python, but I only began learning it (from scratch) when I started working with Ignition (version 7.something), so I've been grateful for all examples (simple and advanced) shared by others here and elsewhere.
TLDR: I suggest using a single tag read to get all the data at once and eliminating repetitive code. Your example does a great job of these too. Use what works best for your team, and consider encouraging anyone writing Python code to get comfortable with list comprehensions.