How build sigfox message?
-
Hi all
I'm coming from c++ and python is not my best ability right now. Finally, I read the sensors and now I have the values to be sent to Sigfox.
s.send(bytes([1.89, 2.90, 3.67, 4.87, 5.77, 6.44,0,0,0,12.7]))
I have some values with float or decimal format, but I have to convert. In C I use c function to convert to Uint, how do you do in python? and how do you decode them in Sigfox?Thank's
-
@ecabanas In many cases, it's actually not necessary to send floats. Either just convert to integers (if the decimal part is not useful), or multiply by a power of 10 before doing so. Adding an offset may also help
For instance, if you have values between 0.00 and 2.00 and need 2 decimals, then multiply by 100, you'll get an integer between 0 and 200 which you can encode as a single byte.
If you have values between 20.0 and 40.0 and only need one decimal, subtract 20 and multiply by 10, you'll again be able to send that as a single byte.
Given the limitations of Sigfox packet sizes, every byte (and even every bit) counts! Don't waste bits on precision or exponents you don't need. Try to find out for each value the possible range and how much precision you need, and use the smallest number of bits which can accommodate that.
-
@ecabanas I do not know a lot about python, and I dont know the syntaxis you use here. But you will not be able to compress 11 floats into 12 bytes, it is just too much information loss. Remember 1 byte is just able to store 0..255. Using float16 or a similar representation you might be able to include 6 floats at reduced precision, but I'd guess that that's about as far as you can go.
-
@claus said in How build sigfox message?:
which I linked yo
Hi @claus
If I reduce "aulity" of data from list below, could we reach it? In C I convert all data to Uint8 and was the solution correct, is it possible to do the same in python?
little_en1=struct.pack('<f', sbatt) int little_en2=struct.pack('<f', stemp) float one decimal little_en3=struct.pack('<f', shum) float one decimal little_en4=struct.pack('<f', spress) int little_en5=struct.pack('<f', caphum21) int little_en6=struct.pack('<f', caphum22) 0 little_en7=struct.pack('<f', caphum23) 0 little_en8=struct.pack('<f', rain) 0 little_en9=struct.pack('<f', vane) 0 little_en10=struct.pack('<f', wind) 0 little_en11=struct.pack('<f', gust) 0
What is your opinion? thanks again
Eduard
-
@ecabanas You can pack at most 3 "normal" floats in one sigfox message. "normal" meaning 4 bytes, or float32. If you do the trick with the float16 which I linked you can pack 6 floats into one message, but you loose precision with respect to float32. You have to carefully check if this is ok with your data. It might be ok for battery voltage (only the first few digits are of interest) but it might not be for high precision gps position. I would say you'll get around 3-4 valid digits with float16 for a number around 1.
-
@claus said in How build sigfox message?:
num1=1.23
num2=2.34
little_en1=struct.pack('<f', num1)
little_en2=struct.pack('<f', num2)
ba=bytearray(little_en1+little_en2)
print(ba)
bytearray(b'\xa4p\x9d?\x8f\xc2\x15@')len(ba)
8struct.unpack('<ff',ba)
Hi @claus
Thank's for your help, it is very very usufull.
My message is like this:
# unicode string sbatt=voltage stemp=bme280temp shum=bme280hum spress=0 captemp21=temp_moist caphum21=0 caphum22=0 caphum23=0 rain=0 vane=0 wind=0 gust=0 little_en1=struct.pack('<f', sbatt) little_en2=struct.pack('<f', stemp) little_en3=struct.pack('<f', shum) little_en4=struct.pack('<f', spress) little_en5=struct.pack('<f', caphum21) little_en6=struct.pack('<f', caphum22) little_en7=struct.pack('<f', caphum23) little_en8=struct.pack('<f', rain) little_en9=struct.pack('<f', vane) little_en10=struct.pack('<f', wind) little_en11=struct.pack('<f', gust) ba=bytearray(little_en1+little_en2+little_en3+little_en4+little_en5+little_en6+little_en7+little_en8+little_en9+little_en10+little_en11) print(ba) print(len(ba))
And the array is like this:
bytearray(b'\x00P\x12ER\xb8\xaeA\x9a\x99kB\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
but the len is 44 and if I'm not wrong, the limit is 12, how could I reduce it?
Thanks in advance
...and sorry but this part of the code is always a nightmare for me
Eduard
-
@ecabanas You just need to convert the data to a known (little or big endian) binary representation. I use bytearrays more or less like this
>>> import struct >>> num1=1.23 >>> num2=2.34 >>> little_en1=struct.pack('<f', num1) >>> little_en2=struct.pack('<f', num2) >>> ba=bytearray(little_en1+little_en2) >>> print(ba) bytearray(b'\xa4p\x9d?\x8f\xc2\x15@') >>> len(ba) 8 >>> struct.unpack('<ff',ba) (1.23, 2.34)
You see however that one sigfox message only permits for 3 floats (4 bytes each). If your data does not require high precision, you could think about a 16bit float representation, as shown here https://davidejones.com/blog/python-precision-floating-point/ for example.
-
Hi @Gijs
First of all, thank's for your comments and help.
I did the following but it doen's work:
import struct def binary(num): return ''.join(bin(ord(c)).replace('0b', '').rjust(8, '0') for c in struct.pack('!f', num)) Test = 0.25 binTest = binary(Test) print(binTest)
But I received the following error:
File "main.py", line 23, in binary File "main.py", line 23, in <genexpr> TypeError: can't convert 'int' object to str implicitly
and another question, how could I do with negative values? this is a temp sensor that send info to sigfox.
Could you help to me with this? thank you very very much,Eduard
-
I had some issues with this in the beginning as well (so much easier working with actual datatypes than this guessing of what it actually is :) )
What you need to do is convert a float to a bytearray (with for example thebytes(...)
function, apparently, in Python you would use astruct
for that:https://docs.python.org/3/library/struct.html
Have a look at this, we have it in micropython as well and it works the same!
Let me know if that helps you
Gijs