Community discussions

MikroTik App
 
kp3928
just joined
Topic Author
Posts: 20
Joined: Tue Jul 06, 2021 3:47 pm

FLOAT datatype

Wed May 18, 2022 2:19 pm

I try to decode the temperature value of the TG-BT5-OUT bluetooth tag.

Hex value is (signed) 0x19a1
Real temperature is (0x19a1)/256 = 25.6 degrees Celcius.

I want to push the real temperature directly into an MQTT message body.

As far as I can see there is only TONUM() available for this type of operations, but that is integer only, so that will report 26 degrees.

Any suggestion or trick to mimic a TOFLOAT() function ?
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11968
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: FLOAT datatype

Wed May 18, 2022 3:17 pm

Hmmm.....

....

See the new function than consider also the negative values:
viewtopic.php?p=934123#p934123
Last edited by rextended on Fri Nov 18, 2022 11:56 am, edited 1 time in total.
 
kp3928
just joined
Topic Author
Posts: 20
Joined: Tue Jul 06, 2021 3:47 pm

Re: FLOAT datatype : TG-BT5-OUT decode

Wed May 18, 2022 6:15 pm

Wow, impressive trick, I will try tonight and let you know.
 
kp3928
just joined
Topic Author
Posts: 20
Joined: Tue Jul 06, 2021 3:47 pm

Re: FLOAT datatype

Thu May 19, 2022 10:26 am

Thank you, that works fine indeed, will adapt for temps below 0 and share here.
At least it allows me to push the temp data of the TG-BT5-OUT to MQTT without any client hassle.
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11968
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: FLOAT datatype  [SOLVED]

Thu May 19, 2022 2:05 pm

This function is for you, the 2nd parameter is the wanted decimals (obviously from 0 to 3):

This is for float 8bit.8bit
Expected input value are on big-endian ("0x" . #15 . #14)

The input values can be any between 0x0 and 0xffff

test for positive temperature:(0x19a1)/256 = 25.628 C

test for negative temperature: (0xe65f)/256 = -25.628 C

:global float2deg do={
    :local float [:tonum $1]
    :local decimalsign "," ; # in Italy it is "," in other countries can be "."
    :local sign        ""  ; # if wanted can be "+"
    :if ($float > 32767) do={:set float (($float - 65536) * -1); :set sign "-"}
    :local forthousand ($float * 1000)
    :local forthousand ($forthousand / 256) ; # MikroTik offset
    :local ftstring "00$[:tostr $forthousand]"
    :local pickpos  ([:len $ftstring] - 3)
    :local decimals [:pick $ftstring $pickpos ($pickpos + [:tonum $2])]
    :local celsius  ($forthousand/1000)
    :if ([:tonum $2] > 0) do={:set celsius "$celsius$decimalsign$decimals" }
    :return "$sign$celsius"
}

terminal code

[rex@tended] > :global float2deg do={
{...     :local float [:tonum $1]
{...     :local decimalsign "," ; # in Italy it is "," in other countries can be "."
{...     :local sign        ""  ; # if wanted can be "+"
{...     :if ($float > 32767) do={:set float (($float - 65536) * -1); :set sign "-"}
{...     :local forthousand ($float * 1000)
{...     :local forthousand ($forthousand / 256) ; # MikroTik offset
{...     :local ftstring "00$[:tostr $forthousand]"
{...     :local pickpos  ([:len $ftstring] - 3)
{...     :local decimals [:pick $ftstring $pickpos ($pickpos + [:tonum $2])]
{...     :local celsius  ($forthousand/1000)
{...     :if ([:tonum $2] > 0) do={:set celsius "$celsius$decimalsign$decimals" }
{...     :return "$sign$celsius"
{... }
[rex@tended] > :put [$float2deg 0x19a1 0]
25
[rex@tended] > :put [$float2deg 0x19a1 1]
25,6
[rex@tended] > :put [$float2deg 0x19a1 2]
25,62
[rex@tended] > :put [$float2deg 0x19a1 3]
25,628
[rex@tended] > :put [$float2deg 0xe65f 0]
-25
[rex@tended] > :put [$float2deg 0xe65f 1]
-25,6
[rex@tended] > :put [$float2deg 0xe65f 2]
-25,628
[rex@tended] > :put [$float2deg 0xe65f 3]
-25,628
 
User avatar
Larsa
Forum Guru
Forum Guru
Posts: 1025
Joined: Sat Aug 29, 2015 7:40 pm
Location: The North Pole, Santa's Workshop

Re: FLOAT datatype

Thu May 19, 2022 4:57 pm

@Rextended, the wizard of scripts! Nice work, it's a keeper!
 
kp3928
just joined
Topic Author
Posts: 20
Joined: Tue Jul 06, 2021 3:47 pm

Re: FLOAT datatype

Sat May 21, 2022 7:52 pm

@rextended blazing fast, thank you, I did about the same but you were first!
I should visit the forum more often ;)
 
germarsh
just joined
Posts: 16
Joined: Fri Jun 24, 2022 4:53 pm

Re: FLOAT datatype

Wed Jul 13, 2022 11:08 am

Thank you for this. I came across a similar problem in attempting to send a floating value via MQTT from the LTE1 interface.

This is my "noddy" solution:
	:if ($rsrqLen > 2) do {
		:set $intpart ($rsrq/10)
		:set $decpart ($rsrq%10*-1)
		:set $rsrqvalue ($intpart . "." . $decpart)
		} else={ :set $rsrqvalue $rsrq} 
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11968
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: FLOAT datatype

Wed Jul 13, 2022 12:21 pm

Thanks for sharing, but is "another" problem.
On OP case, is a HEX Float value to be converted on decimal (string)

On your case, you have a integer, than rapresent 10 times the value???
and you want convert it on float (string)???
Is not clear how to use that fragment, because is out of the contest where is used.
 
kreload
just joined
Posts: 20
Joined: Tue Sep 15, 2020 10:18 am

Re: FLOAT datatype

Fri Mar 31, 2023 2:35 pm

Any script for 32 bit float that will work with sensors where the value is based on 2 word length?

Ex

{:local output [/iot modbus read-holding-registers slave-id=0x21 num-regs=0x2 reg-addr=0x1000 as-value once];:put [($output->"values")]}
80500;31200
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11968
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: FLOAT datatype

Fri Mar 31, 2023 5:21 pm

I do not understand what you mean, give example on single value and corresponding true value.

2 word = 2 distinct DWORD on one array?

80500 = ?
31200 = ?
Last edited by rextended on Fri Mar 31, 2023 5:27 pm, edited 1 time in total.
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3169
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: FLOAT datatype

Fri Mar 31, 2023 5:25 pm

You can get to the modbus float to string with a script I suspect. But you do run into the problem you can NOT compare or do math on them, unless you convert to integer - since there are no "real" floats.

So what your hoping to do with these floats becomes important ;)
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3169
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: FLOAT datatype

Sat Apr 01, 2023 12:01 am

Any script for 32 bit float that will work with sensors where the value is based on 2 word length?
You'd also have to know the byte-order, e.g. big endian or little endian, to convert to anything.
 
kreload
just joined
Posts: 20
Joined: Tue Sep 15, 2020 10:18 am

Re: FLOAT datatype

Mon Apr 03, 2023 4:50 pm

I do not understand what you mean, give example on single value and corresponding true value.

2 word = 2 distinct DWORD on one array?

80500 = ?
31200 = ?
I'm new to modbus stuff so forgive me if i can't explant very good. I also writed wrong 80500 on the first result.

I have multiple energy meters where every value is stored according the the manufactures on 2 registers if i use IEEE values table and starting from 0x1000 or 4 registers starting from 0x0000.
So, to read System Voltage i interogate 0x1000 (or 44097) with a length of 2 (or 4 for the alternative table). I used length of 2 because i thought it will be simplier.

With Mikrotik i get this result: 18630;49152 . These values, in hex, are actually 0x48C6;0xC000

If you convert 0x48C6C000 on a IEEE 754 converter to decimal you get 402,944 which are mW according to the manual or 402.9 V.

So FFS, how do i transform 18630;49152 to 402944 directly on Mikrotik? :)
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11968
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: FLOAT datatype

Tue Apr 04, 2023 12:24 am

0x48C6C000 from IEEE 754 to decimal is 407040, probably is 407,04 mW (why V ???)

402944 is 0x48c4c000 and probably is 402,944 mW???


So FFS, how do i transform 18630;49152 to 402944 directly on Mikrotik?
Step 1, convert the value from array of integer to one hex value.
{
:local output {18630;49152} ; # simulate the reading
# a = 18630 = 0x48C6
# b = 49152 = 0xC000
# (a * 0x1000) + b = (0x48C6 * 0x10000) + 0xC000 = 0x48C60000 + 0xC0000 = 0x48C6C000 = 1220984832
:local fullvalue ((($output->0) * 0x10000) + ($output->1))
:put $fullvalue
}

output code

1220984832
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 11968
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: FLOAT datatype

Tue Apr 04, 2023 12:24 am

search tag # rextended ieee754toint IEEE754 DWORD FLOAT to number

Functions to convert DWORD FLOAT as IEEE754 to number

This feature is not complete.
RouterOS does not support numbers larger than 9223372036854775807 or smaller than -9223372036854775808, and it also does not support decimal division.
So we can only have an approximation, because the float type go from
(+/-)0,(put 45 zeros here)140129846432481707092372958328991613128026194187651577175706828388979108268586060148663818836212158203125
to
(+/-)340282346638528859811704183484516925440
and is impossible to represent correctly on RouterOS.

So this function, in extreme cases, could produce an incorrect value.
:global ieee754toint do={
    :local input    [:tonum "$1"]
    :local hack     0x3B9ACA00 ; # Hack, RouterOS do not support decimal numbers...
    :local isneg    ($input >> 31)
    :local exponent (($input >> 23) & 0xFF)
    :local powerof2 1
    :for x from=1 to=($exponent - 0x7F) step=1 do={:set powerof2 ($powerof2 * 2)}
    :set   exponent $powerof2
    :local mantissa ($input & 0x7FFFFF)
    :set   powerof2 $hack
    :local temp     $hack
    :for x from=22 to=5 step=-1 do={ ; # is 5 and not 0 because missing support for decimals on RouterOS
        :set powerof2 ($powerof2 / 2)
        :if ((($mantissa >> $x) & 1) = 1) do={
            :set temp ($temp + $powerof2)
        }
    }
    :set   mantissa $temp
    :local total    (($exponent * $mantissa) / $hack)
    :local decimal  (($exponent * $mantissa) % $hack)
    :if ($decimal > 444444444) do={:set total ($total +1)}
    :if ($isneg = 1) do={:set total ($total * -1)}
    :return $total
}

example code

{
:local output {18630;49152} ; # simulate the read
# a = 18630 = 0x48C6
# b = 49152 = 0xC000
# (a * 0x1000) + b = (0x48C6 * 0x10000) + 0xC000 = 0x48C60000 + 0xC0000 = 0x48C6C000 = 1220984832
:local fullvalue ((($output->0) * 0x10000) + ($output->1))
:set fullvalue [$ieee754toint $fullvalue]
:local intmw ($fullvalue / 1000)
:local decmw "00$($fullvalue % 1000)" ; :set decmw [:pick $decmw ([:len $decmw] - 3) [:len $decmw]]
:put "$intmw,$"decmw"mW"
}

result code

407,040mW

next convert 407040,0 to it's intended value:
407040,0 / 1000 = 407,040 mW

Who is online

Users browsing this forum: Ahrefs [Bot], rextended and 33 guests