FOR TIPS, gUIDES & TUTORIALS

subscribe to our Youtube

GO TO YOUTUBE

14455 questions

17168 answers

28195 comments

0 members

We are migrating to our new platform at https://community.teltonika.lt. Moving forward, you can continue discussions on this new platform. This current platform will be temporarily maintained for reference purposes.
0 votes
616 views 5 comments
by anonymous
I kludged together some code to measure the period of a digital input (dio2 at present)

it just runs as a brute-force polling task looking for a transition and taking the date +"%s" timestamps of the transitions

and massaging appropriately.  I notice the system load seems to increase without bound ;-)

I noticed that IOJuggler alleges that it can do event-oid processing

I'm confused by the configuration of the action...  There is a randomly ordered hodge-podge of parameters which can apparently be supplied as arguments to the user-defined script.  By default the arguments are:      -T %ut and -i %si

Of course neither of those parameters are defined anywhere...  my official guess would be -T %ut means UnixTimestamp
I notice that there is a Digital Input(1) - %g3  parameter.  I notice elsewhere that din1 is on the 4-pin connector and assume that digital input is not available here - this is din2.  My guess is that I can configure the action such that when the input rises the rising-edge script can be executed... however in contrast to my current application in which shell variables are all available in the current context, the rising and falling edge scripts would be totally independent.

 Is there any approach less-ugly than echo $blahblah > /tmp/blahblah for each variable needed for cross communication ? I'm thinking the timestamp and the averaged-pulsewidths would be the main ones...  Are there any shell-level interrupt-commands ? Is the digital input edge-detection available in Python ?    Any cool, interesting, tweaked, funky trickeries ?

As far as arguments go, I assume I can just not have any, and I assume that the %g3 parameter will always be 1 for a rising edge
( or more likely {(( "value":"high" ))} or maybe the whole pile of stuff that ubus call ioman...... puts out ;-)
by anonymous

OK, I managed to (b)ash together two skeletons for doing the flow measurement/totalizing

the first is a bit of a CPU-pig since it runs flat out looking for transitions
 

The second run uses the IOJuggler edge-trigger capability to measure/average pulse-widths/period and total
The only way I know to maintain  "global" variables is just using simple /tmp files
perhaps this can be optimized by some clever techniques

The challenge now is to figure out how to put this data into the /tmp/regfile ...
The default methodology seems horrendously hyper-ugly
Using some random non-SI illogical ugly ASCII-ified date-stamp at its head ???!!!
 

flowpulse:

#!/bin/sh

#flowpulse returns a simple civilized [0,1] for digital input state - instead of that giant ubus mess

ubus call ioman.gpio.din2 status | grep value | sed s/[^01]//g

flow:

#!/bin/sh

#flow calculates averaged low/high pulsewidths and period and totalized flow from digital input

avg_on=100

avg_off=100

dur=0

total=0

tick=`./flowpulse`

end=`date +"%s"`

echo dur $dur  avg_off $avg_off avg_on $avg_on  total $total

ticklast=`./flowpulse`

start=`date +"%s"`

while [ 0 -lt 1 ]

do

  #echo "tick"

  #read tick

  tick=`./flowpulse`

  #end=`date +"%s"`

  #echo $tick $ticklast

  if [ "$tick" != "$ticklast" ]

  then

    if [ "$tick" == 1 ]

    then

        total=`echo "$(( $total + 1))"`

        end=`date +"%s"`

        dur=`echo "$(( ( $end - $start) * 10 ))"`

        avg_off=`echo "$(( ( $avg_off * 9 + $dur ) / 10 ))"`

    fi

    if [ "$tick" == 0 ]

    then

        #total=`echo "$(( $total + 1))"`

        end=`date +"%s"`

        dur=`echo "$(( ( $end - $start) * 10 ))"`

        avg_on=`echo "$(( ( $avg_on * 9 + $dur ) / 10 ))"`

    fi

    avg_period=`echo "$(( $avg_off + $avg_on ))"`

    echo -e dur $dur  avg_off $avg_off avg on $avg_on avg_period $avg_period total $total

  fi

  start=`echo $end`

  ticklast=`echo $tick`

done

The above code works, but is pretty CPU intensive since Rust Never Sleeps while polling for DI transitions

I discovered that the IOJuggler can generate triggers on din2 input rise/fall transitions

So I surgically split and reworked the above code to get rid of the transition detection and use

/tmp/flow* files to store relevant calculated data...

I still want to explore more efficient mechanisms - perhaps concentrate stuff into fewer files - or maybe it's not worth the effort ?

flowrise:

#!/bin/sh

#flowrise flow pulse-off width averager and period and totalizer using /tmp/flow*

flowavg_on=`cat /tmp/flowavg_on`

flowavg_off=`cat /tmp/flowavg_off`

flowtotal=`cat /tmp/flowtotal`

start=`cat /tmp/flow_fall`

end=`date +"%s"`

echo $end > /tmp/flow_rise

flowtotal=`echo "$(( $flowtotal + 1))"`

dur=`echo "$(( ( $end - $start) * 10 ))"`

flowavg_off=`echo "$(( ( $flowavg_off * 9 + $dur ) / 10 ))"`

avg_period=`echo "$(( $flowavg_off + $flowavg_on ))"`

echo $avg_period>/tmp/flow_period

echo -e dur $dur  avg_off $flowavg_off avg on $flowavg_on avg_period $avg_period total $flowtotal

flowfall:

#!/bin/sh

#flowrise flow pulse-on width averager and period using /tmp/flow*

flowavg_on=`cat /tmp/flowavg_on`

flowavg_off=`cat /tmp/flowavg_off`

flowtotal=`cat /tmp/flowtotal`

start=`cat /tmp/flow_rise`

end=`date +"%s"`

echo $end > /tmp/flow_fall

flowtotal=`echo "$(( $flowtotal + 1))"`

dur=`echo "$(( ( $end - $start) * 10 ))"`

flowavg_on=`echo "$(( ( $flowavg_on * 9 + $dur ) / 10 ))"`

avg_period=`echo "$(( $flowavg_off + $flowavg_on ))"`

echo $avg_period>/tmp/flow_period

echo -e dur $dur  avg_off $flowavg_off avg on $flowavg_on avg_period $avg_period total $flowtotal

1 Answer

0 votes
by anonymous

Hi,

I suppose you want to use Modbus since you are looking for a way to write data into /tmp/regfile. There is a wiki article (available HERE) that provides information regarding writing the data into a custom Modbus register. 

Also, since you are writing a script and using Modbus, for Modbus TCP there is a 'modbus_tcp_test'  command which might be useful if you want to write/read data to/from the registers of slave devices. It is possible to use this command for Modbus RTU too, but you will need to configure a Modbus gateway which would allow you to translate TCP requests to RTU. You can find more about this command in this thread.

It is possible to put the variables into a single file, but this would require searching for the values within the file and then updating them. While it would be fewer files, I do not think that this would reduce the overhead much. This would bloat the script as well, making it bigger and more complex, which is unnecessary in my opinion. I cannot help much with the optimization of the script.

Kind Regards,

Andzej

by anonymous

You write 

"It is possible to use this command for Modbus RTU too, but you will need to configure a Modbus gateway which would allow you to translate TCP requests to RTU"
does that mean the the 955 cannot read registers from an RTU device and then push them to the cloud ?
I've got the internal 955 registers reading and pushing OK plus the Custom modbus reading from /tmp/regfile OK
(although the custom mysteriously stopped working, and just as mysteriously resumed working while I was

monkeying around attempting to get the RTU device reading...
WTH is the 485 configuration for if it doesn't actually gateway the data ?
I have tried configuring the 485 as a client and a server and bidirectional and as modbus Gateway.
It seemed to break the existing modbus traffic...  I attempted to just use a non-standard port 503

If I were to scrap the connection to the 955 modbus and custom modbus and only read from the RTU and push that up to the cloud is that possible ?

by anonymous

Hi,

Regarding the following:

"It is possible to use this command for Modbus RTU too, but you will need to configure a Modbus gateway which would allow you to translate TCP requests to RTU"

I was refering to the command itself ( 'modbus_tcp_test' ).

Could you please tell me what exactly are you trying to achieve?

First of all, the serial can be active only in one service. For example, you cannot configure your RS485 and have both, 'Modbus RTU' and 'serial over IP' services active.

You can gather data from the Modbus Slave either using TCP or RTU (done by configuring Modbus TCP / RTU Master, respectively). Then you can send the data to the cloud / server using 'Data to Server' functionality (selecting 'modbus data' as the source). If you are writing data to custom modbus registers on your RUT, then you will need to configure RUT as a TCP/RTU slave too, and read Modbus data from it too (treat it like another TCP/RTU slave). (more info here )

If you want to be able to request Modbus data from a remote Modbus Master (some external server running Modbus Master TCP), then you can configure Modbus Gateway. This way you can send Modbus TCP requests from Modbus Master to your router using a public IP (or VPN) and the router will pass the request to RTU slave. Basically, you will be able to query your RTU slave remotely. (example here, info here).

The serial over IP functionality allows you to connect to the router (from LAN or WAN remotely) and access the device that is connected to the router via serial cable.

Kind Regards,

Andzej

by anonymous

What I want to do:
1. monitor the operation of the Teltonika itself and its location and transmit data to the thingsboard portal. 
Already done.
2. monitor the operation of a flowmeter with pulse output and calculate the flowrate and the total flow. 

Already done using shell scripts and working on polishing, filtering, robustifying my code

3. monitor the operation of the flowmeter at a higher level using 4-20mA signal to show flowrate and calculate total flow

4. monitor the operation of the flowmeter at a higher level yet and use modbus RTU via rs485 direct hardwired connection to retrieve (and potentially modify) the flowmeter configuration and operating registers.

re: 3. My impression at this point is that the RUT 955 4-20mA input is "broken" or "needs help".
I connected the loop powered 4-20mA output of the flowmeter to the Analog input and I do get a reading but it is non-sensical.
In 4-20mA mode the 955 display shows 8mA (25%). The voltage across the input is 9.6VDC.
When I switch the dropdown box on Ain from 4-20mA to Voltage, the reading is 9.9V (not very accurate - tolerable)
What I notice which tells me that something is missing or broken is that a current reading is inherently a low-input-impedance measurement while a voltage reading is inherently a high-impedance measurement.  The 955 remains in high-impedance mode.

It is impossible that there is simultaneously 9.9V and 8mA from a 12V supply.
My assessment is that an external resistor is required across the analog input. Maybe 100 ohm or 250 ohm. Perhaps it was designed into the hardware, but the software/firmware does not correctly engage this resistor.
My question is: What is the required resistance to be externally connected to provide correct readings ?
I could play musical resistors and figure something out, but I prefer that you know about the problem and correct it - maybe in firmware - and tell me what the specified behaviour is supposed to be.

re 4: The modbus RTU support seems to be a bit of a mess too. local/internal Modbus TCP has been fine.
I was trying various permutations of the RS485 modbus support.
I first tried Serial Type: Over IP - both as slave and as server
Traffic was relayed over the 485 link but there was a bunch of extra junk at the head of each Tx poll packet.
I then switched to Gateway pointing to 192.168.1.1 - but with non-standard port 503 in order to segregate the RTU traffic from all the other TCP traffic..

I noticed that I was getting traffic on the 485, but there was less extra junk in the packets ahead of the actual modbus request.

My assumption was that the modbus gateway would strip out the extraneous junk when it made the RTU packet for the 485link

Apparently not.  I didn't look closely - it is possible that the ID field was being overwritten with the user-defined ID.


I then decided to switch the Slave ID configuration type from "user-defined" to "obtained from TCP".
Immediately I could see the Rx packets returning from the flowmeter in response to the Tx polls.
I can see that the TCP header stuff is being stripped out and only the RTU request packet is being sent

However, there is still a loose screw in there somewhere.
Even though the query is being received and responded to, the RuT955 is doing something dumb with the data it is requesting.

When I go into the modbus master configuration for the local 955 registers and for the custom modbus registers, and then the requests configuration and enter the queries for each piece of data I need. I can then slide down and find that new request and click Test and I will see the new data associated with that request.
However, in the case of the query for the external flowmeter queries via rs485, they all return "read: unexpected response length"

It should at least indicate the length in bytes/words which it is receiving which would be very useful to track down the culprit.


I always use ModbusPoll to get a definitive hold on the correct comm-stream.
I will post some of the logs in a separate message.
I hope we don't have to buy a proper Vlinx or other Modbus TCP/RTU gateway to actually gateway this data correctly.

by anonymous

ModbusPoll communications logfile of proper Modbus RTU comms between a USB RS485 adapter and the target flowmeter
 

Tx:000000-0B 03 17 70 00 08 40 C9 

Rx:000001-0B 03 10 31 32 32 32 30 35 32 37 00 00 00 00 00 00 00 00 10 D9 

Tx:000002-0B 03 17 80 00 08 40 FA 

Rx:000003-0B 03 10 43 50 2D 31 34 34 35 33 5F 31 30 2E 30 31 00 00 ED C6 

Tx:000004-0B 03 17 88 00 08 C1 38 

Rx:000005-0B 03 10 43 50 2D 31 34 32 37 36 5F 30 34 2E 31 31 00 00 7D 6C 

Tx:000006-0B 03 17 78 00 08 C1 0B 

Rx:000007-0B 03 10 49 4D 41 47 34 37 30 30 50 2D 32 30 30 00 00 00 02 F8 

Tx:000008-0B 03 1B 58 00 0C C2 52 

Rx:000009-0B 03 18 00 00 00 00 43 C8 00 00 41 20 00 00 43 66 61 09 42 70 76 E7 3B F6 42 D2 63 0E 

Here is a ModbusSlave communications logfile of the traffic between the RUT955 in various configurations and the target flowmeter :
 

I think this is when the RS485 was configured as OverIP server:
Green is modbusSlave request#

Yellow is some kind of TCP overhead stuff

Orange is the actual modbus request

Rx:004341-06 54 00 00 00 06 0B 03 1B 5E 00 02 

Rx:004342-06 55 00 00 00 06 0B 03 03 E8 00 02 

Rx:004343-06 56 00 00 00 06 0B 03 1B 5D 00 02 

Rx:004344-06 57 00 00 00 06 0B 03 1B 5E 00 02 

Rx:004345-06 58 00 00 00 06 0B 03 03 E8 00 02 

Rx:004346-06 FD 00 00 00 06 0B 03 03 E8 00 02 

Rx:004347-06 FE 00 00 00 06 0B 03 1B 5D 00 02 

Rx:004348-07 C1 00 00 00 06 0B 03 1B 5E 00 02 

Rx:004349-07 C2 00 00 00 06 0B 03 03 E8 00 02 

Rx:004350-07 C3 00 00 00 06 0B 03 1B 5D 00 02 

This is where I switched RS485 request config to ModbusGateway  user-defined ID was 1

Rx:004351-01 03 1B 5E 00 02 A3 3D 

Rx:004352-01 03 03 E8 00 02 44 7B 

Rx:004353-01 03 1B 5D 00 02 53 3D 

here is where I switched user-defined  ID as 11 (0x0B)  I just now noticed that some replies (Tx) were being generated

Rx:004354-0B 03 03 E8 00 02 44 D1 

Tx:004355-0B 03 04 00 00 00 00 50 33 

Rx:004356-0B 03 1B 5D 00 02 53 97 

Tx:004357-0B 03 04 00 00 42 F6 E0 D5 

Rx:004358-0B 03 04 00 10 00 05 91 F5 
I think this is where I  switched RS485 request config to ModbusGateway  obtained from TCP
I assume that extra TCP data was stripped out... I also wonder about the code 83 03

Tx:004359-0B 83 03 21 33 

Rx:004360-0B 83 01 A0 F2 

Tx:004361-0B 03 01 C1 32 

Rx:004362-0B 83 03 21 33 

Tx:004363-0B 03 01 C1 32 

Rx:004364-0B 83 03 21 33 

Tx:004365-0B 03 01 C1 32 

Rx:004366-0B 83 03 21 33 

Tx:004367-0B 03 01 C1 32 

I guess for clarity I should strip it down to just 1 record