I’m in the process of writing an RNET plugin (my first attempt at this so I’m asking for patience) and I have the basic commands for a single keypad hammered out and working. My problem in getting this to work for multiple keypads is in the way that RNET generates the hex string to be sent. The command string contains a number of hex bytes that, among other things, include the keypad # and a calculated checksum byte. A shortened example of how I’m sending the command is:
How can I make one of the hex bytes a variable (the keypad number) pulled from the settings?
I need to make hex calculations to generate the checksum byte…that is adding hex numbers and then using the “AND” operator. Does anyone know how to do this or if it is even possible?
How can I make one of the hex bytes a variable (the keypad number) pulled from the settings?[/quote]
I had to make a lot assumptions here, but the general form will be:
[code] local RNET_SID = “urn: russound-com:serviceId:Config1”
<ACTION>
...
<RUN>
local keyPad = luup.variable_get(RNET_SID, "KeyPad", device) or "1"
-- keyPad will be a String, so you'll need to glue it into the right spot. It's very likely
-- you'll need to convert it into the right form also, depending upon how the Keypad
-- is represented in the string that you need to send -- ?? Details needed
</RUN>
</ACTION>
[/code]
2) I need to make hex calculations to generate the checksum byte....that is adding hex numbers and then using the "AND" operator. Does anyone know how to do this or if it is even possible?
You're need to be [i]much[/i] more specific about the algorithm used for computing the Checksum, and the form (byte, word, etc) it needs to be in order for it to be sent to the RNET device.
It’ll also be easier if you attach what you have so far. Otherwise folks helping you will have to guess the context of where you’re writing the code, and what you’ve already setup.
I need to make hex calculations to generate the checksum byte....that is adding hex numbers and then using the "AND" operator. Does anyone know how to do this or if it is even possible?
There are various ways that checksums can be calculated. In the simplest form, you just add all the bytes in the command together and then[i] and[/i] the result with 0xFF to leave just the least significant eight bits as the checksum. Other forms require the use of exclusive-or instead of add to get a [i]bitwise[/i] addition - in which case the checksum will usually not require the final [i]and[/i] operation.
Hex is just the format that we humans use to enter or display binary values. Internally, all numbers are in binary form anyway. It is only when converting numbers to or from string values that conversion to/from hex notation is required.
When a command string requires a calculated checksum, it is generally best to construct the command in a table or array as integer values. Once the constant and variable values have been entered into the table, the checksum is calculated by looping through the table adding (or Xor-ing) the elements. The calculated checksum is then appended as the last element in the table. The command can now be sent from the table - using string.format to convert it to hex notation if necessary.
If your commands are short and constants, you can always calculate the checksums like this:
guessed, having scoured these boards I had a feeling that it would be you coming in here to save me. Thanks for the reply. Hopefully this will give you the information you need:
Using this code to grab the setting, I’m stuck with a two character string in the range of “01” through “06”. I need to subtract one from this number (KeyPad - 1), then add a leading “0x” to have it recognized by RNET has a hex number. I then need to insert it into my luup.io.write command. An example being, where KP is “the KeyPad variable - 1”:
I’ve cut and pasted the calculation from Russound’s manual here:
Checksum Calculation Example:
Value (Hex)
F0 Start of Message Character
00
67
7C
F1
0F
59 Checksum
F7 End of Message Character
Step #1 - Add the HEX value of every byte in the message that precedes the Checksum:
Example - 0xF0 + 0x00 + 0x67 + 0x7C + 0xF1 + 0x0F = 0x02D3
Step #2 - Count the number of bytes which precede the Checksum and convert that value from
DEC to HEX (byte count). Add the byte count in HEX to the previously calculated sum of
bytes:
Example - 0x02D3 + 6 (6 = Decimal value byte count) = 0x02D9
Step #3 - This value is then AND-ed with the HEX value 0x007F (7F is the highest BIN value
for 7 bits = 1111111). The Checksum itself and the End of Message Character are not
included in the calculation. Only the low 7 bits are used so overflow is discarded:
Example - 0x02D9 AND 0x007F = 0x59 = Checksum
RexBeckett, thank you! I’m not going to have a chance to try this out tonight but I will tomorrow. It looks so much easier than what I was trying, I guess I was over thinking it. I’ll post back tomorrow with my progress.
Thanks for the correction, @futzle. You are right, of course. My excuse is that it is 01:15 over here and, after the wine ran out, I started on the Spanish brandy… Note to Self: Do not write code after brandy. ;D
Well I gave it a shot but I still can’t seem to get it to work. I’ve attached here what I have so far with the hopes that you guys can help. The “altid” I’m trying to grab is from a child device (keypad) so I’m not sure if I’m referencing it correctly. Any assistance would be appreciated.
You’ve made keyPad a string and it should be an integer. Try:
local keyPad = tonumber(luup.variable.get("urn:micasaverde-com:serviceId:RNET1", "altid", lul_device),10)
Also see my post above about using a function to construct the command string. It will be less prone to errors than having two sets of numbers that must be identical.
Also note that, in [tt]sendCommand[/tt], you’re referencing [tt]socket.gettime()[/tt], but you’re never initializing the variable “[tt]socket[/tt]” with anything.
You need a line (near the top, outside of a function) like:
[tt] local socket = require(“socket”)[/tt]
That’ll initialize it for you so you can call it’s methods.
PS: Sorry for not responding further y/day, got distracted with the 777 accident at SFO (nasty stuff, for those not watching the news)
Ok so I added the socket line and I made the change to raw protocol and my static commands still work but the ones generated with variables still do not. This is what I’ve changed the keyPad command to:
local keyPad = luup.variable.get("urn:micasaverde-com:serviceId:RNET1", "altid", lul_device) - 1
local keyPad = "0x" .. keyPad
What I’m uncertain of is:
Am I correctly referencing the keypad device and “altid” here?
How do I subtract 1 from the altid (which will be in the format of 01, 02, etc) then add a leading “0x” so the string sent sees it as a hex value?
Thanks again for the help. And I have been following the plane crash in the news…amazing only two people died.
My comments were secondary to those of @RexBeckett.
In Lua, [tt]0xFF[/tt] is a number (expressed in it’s Hex form) and [tt]“0xFF”[/tt] is a string.
The [tt]luup.variable_get[/tt] function will return a String representation of a number (“01”, "02, etc) and you’ll need to convert it to a number first before putting it into the middle of the byte sequence you’ve put together.
[tt] – Get the Keypad identifier, in string format.
local keyPad = luup.variable.get(“urn:micasaverde-com:serviceId:RNET1”, “altid”, lul_device)
– Convert it to a number, so we can put it into the byte sequence to deliver
keyPad = tonumber(keyPad) - 1[/tt]
Now it’ll be in the correct form for use inside of [tt]string.char[/tt], or your [numeric] checksum calc.
Ok, still not working but I trying to do some debugging. It looks like there is a failure in trying to get the keyPad variable. These are the log entries keeping in mind that device 67 is the serial port, 68 is the parent device, and 69 is the keypad (child device):
Yes, you’re asking it for the “[tt]altid[/tt]” State Variable, but it’s not being set anywhere so it’ll return a nil value.
In startup, you set two state variables:
[tt]ZoneIds[/tt]
[tt]UrtsiId[/tt]
So asking for any other value will return nil, since it doesn’t exist.
You may also want to declare a variable for:
local RNET_SID = “urn:micasaverde-com:serviceId:RNET1”
and use it everywhere you have that string, since it’ll make it easier to change to another value at a later stage (you’ll want to change it to “[tt]urn:russound-com:serviceId:Config1[/tt]” or something non Micasaverde based)
I’m going on the older code that you posted, so you might have changed things since then.
Ah, I thought the “luup.variable.get” command would pull it from the device I’m issuing the command from. I can’t set the keyPad value in startup because I need it to be specific to the child device that is issuing the command. Is this possible? Do I initialize the variable in startup then “get” it in the action?
There are a bunch of strategies for doing that. It might pay to tackle one problem at a time though and “hardcode” that for now so you can get the binary-transmission format sorted out.
Once that’s worked out correctly, you can move on to handling how to differentiate the child devices, and use that information to push out stuff in a child-specific manner.
Note that altid is an Attribute of a device, not a State Variable.
Attributes are retrieved by calling [tt]luup.attr_get[/tt] instead, but you have to know the right attribute name to use when making those calls. Sometimes the names are different than what you see in the UI.