Overview

Simple Ohaus scale with Ethernet and we need the data!
Our scale, an Ohaus Valor 7000 gets its IP via DHCP so we have our DHCP server assigning 192.168.4.179. The TCP port for sending and receiving data is 9761.

Ohaus scale, demo box

To get data from our scale sending ‘P\r\n’ seems to work. If you’re not familiar with that notation \r = carriage return and \n = new line.

adamd@pop-os:~$ nc 192.168.4.179 9761
P
     2.0135    lb      
P
     3.0865    lb ?    
P
    12.6450    lb 

Points of note:

  • I used netcat or nc on Linux to connect directly to the scale for testing. Other options would be telnet or putty. Very valuable to test it in a simple terminal before trying to get it working via socket programming.
  • Unstable readings have a ? at the end.
  • The whole number part can be one or two digits.
  • There are spaces present before our number.

Function block ‘ScaleGetData’

While not complete this code is getting the job done. Missing is error handling, dealing with different units, etc. Also since we start our exponent at -4 and don’t properly look for a decimal point this only works because this device always sends 4 places after the decimal.

There are many ways to accomplish this task. Another, potentially better way, is to use the buf_to_real function after capturing the section containing our value from the returned string.

Variables:

Group,Name,DataType,Usage,IsTranslate,Comment,InitValue,AccessSpecifier,IsRetain,IsConstant,IsOpc,IsHmi,IsProficloud,Address
,sIpAddr,STRING,Input,False,,,None,False,False,False,False,False,
,uiPort,UINT,Input,False,,,None,False,False,False,False,False,
,SockScale,TLS_SOCKET_2,Local,False,,,None,False,False,False,False,False,
,bConnect,BOOL,Input,False,,,None,False,False,False,False,False,
,dwScaleHandle,DWORD,Local,False,,,None,False,False,False,False,False,
,baOutBuf,ByteArray35,Local,False,,,None,False,False,False,False,False,
,SockScaleSend,TLS_SEND_2,Local,False,,,None,False,False,False,False,False,
,bRequestData,BOOL,Input,False,,,None,False,False,False,False,False,
,SockScaleRec,TLS_RECEIVE_2,Local,False,,,None,False,False,False,False,False,
,bEnableReceive,BOOL,Local,False,,,None,False,False,False,False,False,
,baInBuf,ByteArray35,Local,False,,,None,False,False,False,False,False,
,bGetData,BOOL,Local,False,,,None,False,False,False,False,False,
,iBytesAvailable,INT,Local,False,,,None,False,False,False,False,False,
,x,INT,Local,False,,,None,False,False,False,False,False,
,rTemp,REAL,Local,False,,,None,False,False,False,False,False,
,iExponent,INT,Local,False,,,None,False,False,False,False,False,
,bStable,BOOL,Output,False,,,None,False,False,False,False,False,
,rThisDigit,REAL,Local,False,,,None,False,False,False,False,False,
,rValueOut,REAL,Output,False,,,None,False,False,False,False,False,
,bNewRead,BOOL,Output,False,,,None,False,False,False,False,False,
,bConnectedOk,BOOL,Output,False,,,None,False,False,False,False,False,

Code:

SockScale(ACTIVATE := bConnect, DEST_IP := sIpAddr, DEST_PORT := uiPort, HANDLE => dwScaleHandle);
bConnectedOK := SockScale.ACTIVE;


baOutBuf[0] := 80; // 'P'
baOutBuf[1] := 13; // 'Carriage Return'
baOutBuf[2] := 10; // 'Line Feed'

SockScaleSend(REQ := bRequestData, HANDLE := dwScaleHandle, DATA_CNT := udint#3, DATA := baOutBuf);

// ******************************************************************************************
// *****************************************************************************************

SockScaleRec(EN_R := bEnableReceive, HANDLE := dwScaleHandle, EXP_DATA_CNT := SIZEOF(baInBuf),DATA := baInBuf);

(* Receiving data tricks *)
(* Set ExpectedDataCount = buffer size. This will make DATA_CNT actually give values up to max buffer size *)
(* Toggle EnableReceive off, then on again to reset DATA_CNT to zero *)
If bGetData or SockScaleRec.DATA_CNT > 1 THEN  //Is there any data?
    iBytesAvailable := to_int(SockScaleRec.DATA_CNT);  //How many bytes to loop through
    bEnableReceive := False; //need to toggle to reset DATA_CNT
    rTemp := 0.0;
    iExponent := -4; // Start with -4 or 10**-4 which is 0.0001 and work up
    bStable := True;
    for x := (iBytesAvailable - 1) to 0 BY -1 DO
        // ASCII numbers are 0x30 to 0x39, we capture all ASCII numbers
        IF baInBuf[x] >= 16#30 and baInBuf[x] <= 16#39 THEN
            rThisDigit := to_real(TO_DINT(baInBuf[x]) - 16#30); // Trick for ASCII to value conversion
            rTemp := rTemp + (rThisDigit * (10.0**iExponent));
            iExponent := iExponent + 1;
        End_if;
        If baInBuf[x] = byte#63 then  //Is there a ? in the string?
            bStable := False;
        End_if;   
    End_For;
    rValueOut := rTemp; //pass out the final anser
    bGetData := false;
    bNewRead := True;
ELSE
    //If we are connected keep receive on
    bEnableReceive := SockScale.ACTIVE;
End_if;

If NOT(bRequestData) THEN
    rValueOut := 0.0;
    bNewRead := False;
End_if;
    

Implemented in code

ScaleGetData1(sIpAddr := '192.168.4.179', uiPort := 9761, bConnect := bDoIt, bRequestData := bGetData, 
bStable => bGoodValue, 
rValueOut => rTheValue, 
bNewRead => bNewData,
bConnectedOk => bConnectSuccess);

What it looks like when monitoring online

Monitoring the implementation in structured text code.