2

I am currently trying to develop a script that will connect to a Fluke DewK 1620a Themo-Hygrometer and pull the current temperature and humidity readings from the device. While these devices have a network port on them, there does not appear to be a common protocol listening on the port. They simply accept a raw TCP connection. I can connect interactively via netcat and putty, pass commands, and receive output. I tried scripting this via netcat (See "Capturing data from a Fluke 1620a via netcat"), but simply could not make it work. Since then I've discovered that I can accomplish my mission using Bash's unique ability to open a file descriptor read/write on a TCP connection. While I am now able to capture the data into a file, I'm struggling with what I know are probably some pretty basic issues.

#!/bin/bash

$host=1.2.3.4
$port=10001
$location=lab1
$log=${location}_DewK.log
$datetime=$(date +%F_%T)

exec 3<>/dev/tcp/${host}/${port}
echo -e "read?" >&3                 # Sends the read? command to the Fluke.
printf ${datetime} >> ${log}        # Inserts a timestamp to the log.
cat <&3 | tee -a ${log} &           # Tee was the only way I could get it to log.
sleep 1 && pkill cat                # The cat just hangs out there & will not end.
exec 3<&-
exec 3>&-

I know its ugly, but I just cannot seem to figure out how to make it more efficient. My main issues are:

  1. The "cat <&3" causes all kinds of problems. There is no EOF so it just hangs there forever. I've tried a bunch of different approaches using read, but can't seem to get it to work. The "cat" seems to be the only way I can get the data pulled & written to a file, but have to use the 'pkill' just to keep it from tying up the sensor.
  2. I'd love to be able to read the results into a variable like $results, but can't seem to do that with a "cat". I suspect I'm missing something really simple, but can't seem to figure it out.
  3. The output from the Fluke comes back like "76.05,56.3,72.89,59.0^M". I know this is because it doesn't detect an EOL, but I don't know how to add a new line after the "cat <&3". The results is a log that looks like:

    2014-11-26_07:09:03

    75.75,56.4,72.53,59.7^M2014-11-26_07:09:05

    75.75,56.4,72.54,59.7^M2014-11-26_07:09:07

    75.75,56.4,72.53,59.7^M

  4. My goal is to write "${datetime} - ${results}" on a single line for each run to a log file, but I don't know how to combine the lines. I imagine the answer lies in getting the results into a variable I can use.

I appreciate any assistance I can get. I've been pouring through man pages, the bash documentation, blog posts, and this site of course. The information I've gleaned here is really the only reason I've come this far. I'm simply out of my depth and getting a crash course.

0

I'm not clear if you get one result per read?, or if you get a stream of results. I think you're saying one request -> one reply. And you never gave a hexdump or anything of the output, but it looks like the line endings are probably CR-only, not DOS CR-LF or unix LF. (That's why your prompt overwrites the output after netcat.)

I did find the manual: http://us.flukecal.com/literature/product-manuals/1620a-user%E2%80%99s-guide

It confirms that responses are terminated with a CR. This makes it a huge pain to work with in the shell, because tr '\r' '\n' has the same problem as cat: it won't stop after one line.

# read -d sets the delimiter.
#  $'' is a special type of quoting where \r expands to a literal carriage return.
get_temp () {  # io to fluke on FD 3
    echo "read?" >&3
    local resp
    IFS=  read resp -d $'\r' -u 3
    printf '%s\n' "$resp"
}

exec 3<>"/dev/tcp/$host/$port"
while true; do  # whole loop is redirected to log
    temp="$( get_temp )"
    printf '%s - %s\n'  "$(date +%F_%T)" "$temp"
    # or  echo -n "$(date) - "; get_temp
    sleep 1
done | tee -a "$log"
#  or just  >> "$log", and tail -f the log file when you want it on screen.

Or an implementation that lets tr deal with the CR -> LF translation:

exec 3<>"/dev/tcp/$host/$port"
(while echo 'read?';do sleep 1;done >&3) &

tr -d '\r' '\n' <&3 | IFS= while read temp; do
    printf '%s - %s\n' "$(date +%F_%T)" "$temp"
done >> "$log"

This puts a subshell in the background, writing a command every second. You still need a read loop to get the current time formatted into the received lines. IDK if ^C will kill the subshell or not.

Variables set inside the loop won't be present after it ends, because we piped into it, in case you were going to try that.

This is an old question, so I didn't actually run these. There may be syntax errors, or bugs. But the general idea is sound, I'm pretty sure.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.