I am trying to get some double values from my Lopy 4 into my PHP web-application. Based on some example scripts, I wrote the following code:
# Imports import ubinascii import pycom from network import LoRa import socket import struct # Set LoRa properties lora = LoRa(mode=LoRa.LORAWAN, region=LoRa.EU868) dev_addr = struct.unpack(">l", ubinascii.unhexlify('addr')) nwk_swkey = ubinascii.unhexlify('key') app_swkey = ubinascii.unhexlify('key') # Pack data buffer = bytearray() buffer.extend(struct.pack('d', 2.5)) buffer.extend(struct.pack('d', 3.6)) buffer.extend(struct.pack('d', 3.2)) buffer.extend(struct.pack('d', 8.1)) buffer.extend(struct.pack('d', 1.1)) # Send data lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, app_swkey)) s = socket.socket(socket.AF_LORA, socket.SOCK_RAW) s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5) s.setblocking(True) s.send(bytes(buffer)) s.setblocking(False)
My LoRa provider (KPN) receives the data, decrypts it and sends the payload to my webserver. The received payload-hex looks like this:
After trying many different approaches, I somehow can't manage to turn this hex back into the original double values. I've got two major questions:
- Is this a recommended way to pack the original data values? Am I doing something wrong here?
- What exact steps need to be taken in order to turn this payload-hex back into the original values?
I need to be able to do the decoding using PHP. However, if someone can tell me about the steps that need to be taken, I might be able to figure out the syntax myself.
Thanks in advance!
My apologies for the late response and any confusion I might have caused by switching to integers within the post. The big/little-endian format was indeed the issue. Adding a '>' sign in both the micropython and the php script solved the problem. This is what I ended up doing.
# Pack data data = struct.pack('>5i', 25, 36, 81, 11) # Send data print('Sending data') lora.join(activation=LoRa.ABP, auth=(dev_addr, nwk_swkey, app_swkey)) s = socket.socket(socket.AF_LORA, socket.SOCK_RAW) s.setsockopt(socket.SOL_LORA, socket.SO_DR, 5) s.setblocking(True) s.send(bytes(data)) s.setblocking(False)
$struct = new Struct(); $decoded_payload = $struct->unpack('>5i', hex2bin($decrypted_payload)); $data = [ 'var1' => $decoded_payload/10, 'var2' => $decoded_payload/10, 'var3' => $decoded_payload/10, 'var4' => $decoded_payload/10, 'var5' => $decoded_payload/10 ];
The PHP struct class I used in the PHP decoding script can be found here.
Thanks a lot for your help!
My guess is that the values are 5770,66,2,21,176 (5 x 32-bit ints in little-endian order).
mfalkvidd last edited by
1.1 should be 0xcdcc8c3f or 0x3f8ccccd depending on endianness. There is nothing similar in the decrypted message, so something seems to be way way off.
@mfalkvidd I believe the format was switched from d (double) to i (a 32-bit integer) between the two posts.
mfalkvidd last edited by mfalkvidd
@vicluijkx the decrypted hex is much shorter than the encrypted hex. That's strange. Could there be something wrong with the decryption?
To save space, you could use the "e" pack format, which only uses 2 bytes and still has about three digits precision.
@vicluijkx there may be an issue with big/little-endian format. Try adding > or < before the format.
Thanks @jcaron! After running some more tests I figured out that the hex string, as you mentioned, isn't decrypted at all. This is weird as the provider's documentation clearly states: "Messages are forwarded unencrypted. The developer portal already decrypts the LoRa data using the randomly generated AppSKey. No further decryption is necessary."
Anyway, I managed to decrypt the payload-hex which returns something like this:
I was able to get this string back into the original values using unhexlify and unpack in a micropython console.
>> import ubinascii >> import struct >> hex = 'A86100002400000020000000510000000B000000' >> unhex = ubinascii.unhexlify(hex) # Step 1 >> struct.unpack('5i', unhex) # Step 2
Now I'm trying to figure out how to do the same using PHP. I tried doing step 1 using the php hex2bin() function. This however, resulted into the following:
������@������@������ @���@33 @�������?
In order to do step 2, I tried using this php struct package. It was no surprise that this returned the same kind of characters:
If I try to do step 1 using micropython and step 2 using this php package, I get an array of 5 numbers which I can't seem to relate to the original numbers.
It would be great if someone could see what's going on here.
@vicluijkx Not sure what the actual format is. Are you sure this is the decrypted payload? Try using the same number twice and check if the 16 digits for those two numbers match. You can also log the buffer on the LoPy to see what it is supposed to contain.
In any case, I would recommend avoiding floats. The format can be implementation specific, and as you can see, that's a lot of data (8 bytes per double), so unless you really need to cover a very wide range of values, I would recommend switching to a shorter format based on integers.