3

I am trying to write a simple Python script that connects to a number of Fluke Thermo-Hygrometers (DewK 1620A) and write the temperature and humidity readings to a file I can then ingest into Splunk. This is the first time I've ever tried anything with Python and I'm really close, but can't seem to nail down how to get the data via a TCP socket.

Overview

The script reads a list of devices from an external JSON and then opens a connection to each device, sends a command to get the current readings, and then writes those readings to a file.

In my first iteration, I simply made a single "data = s.recv(64)" call, but the devices were inconsistent in returning a full result. Sometimes I'd get the full result (ie. "69.64,45.9,0,0") and other times I'd only get part of the reading (ie. "69.64,4").

While True Loop

After doing some research, I began to see recommendations for using a while True loop to get the "rest" of the data in a second (or third) pass. I changed out my simple s.recv call with the following:

while True:
     data = s.recv(64)           # Retrieve data from device
     if not data:                # If no data exists, break loop
          continue
     f.write(data.decode())      # Write data to logfile

Unfortunately, now the script will not finish. I suspect the loop is not exiting, but the response should never be more than 24 bytes. I'm not sure how else to test and exit the loop. I tried adding a timeout, but that kills the whole script.

connectDeviceTCP.py

import datetime
import json
import socket

# the command to be passed to the device
command = "read?\r"

# open the deviceLocation.json file for reading
jsonFile = open("devices.json", "r", encoding="utf-8")

# load the contents of the json file into 
locationFile = json.load(jsonFile)
jsonFile.close()

# for each device, connect & retrieve device readings
for device in locationFile["devices"]:

    location = device["location"]
    host = device["host"]
    portStr = device["port"]

    # convert the portStr variable from string to integer
    port = int(portStr)
    
    # open log file for appending.
    f = open("log/" + location + ".log", "a")

    try:

        # create a socket on client using TCP/IP
        s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
        
        # set socket timeout to 3 seconds
        s.settimeout(10)
        
        # connect to host and port
        s.connect((host, port))

    except TimeoutError:

        # write to the log file if the host cannot be reached
        f.write(('\n{:%Y-%m-%d %H:%M:%S} - '.format(datetime.datetime.now())) + location + " - Error: " + host + ":" + portStr + " does not respond.")

    else:

        # send the command to the device
        s.sendall(command.encode())

        # write the timestamp and location to the log
        f.write(('{:%Y-%m-%d %H:%M:%S} - '.format(datetime.datetime.now())) + location + " - ")

        while True:
            data = s.recv(64)           # Retrieve data from device
            if not data:                # If no data exists, break loop
                break
            f.write(data.decode())      # Write data to logfile
        
        # --- The following work except the device doesn't always spit out all the data.
        # receive message string from device
        #data = s.recv(64)

        # write returned values to log file.
        #f.write(data.decode())

    finally:

        # disconnect the client
        s.close()      

        # close log file
        f.close()
5
  • 1
    if not data: continue should be if not data: break if you want to leave the loop. continue there will just cause the call to write to be skipped. Commented May 12, 2021 at 17:58
  • It was "break" initially and then I changed it to give it a shot before posting. It still doesn't exit. Commented May 12, 2021 at 18:16
  • If the loop never exits, then if not data must never be true. Double check what data is (put a print in there). Commented May 12, 2021 at 18:18
  • So that is where I'm confused. If I connect with netcat, I can send commands and receive responses. There is no stream of data. When I change the write out for a print, I get my results like the following: b'76' and b'.84,38.4,70.11,49.3\r' on new lines and then nothing. It just hangs there like it is waiting for data that isn't coming. Commented May 12, 2021 at 18:39
  • It's understandable that more data isn't coming, because for that to happen another read command has to be sent to the device. Commented May 13, 2021 at 15:45

1 Answer 1

1

The devices communicate line-oriented with lines terminated by \r, so just read a whole line - replace the while True loop with

        data = s.makefile(newline='\r').readline()
        f.write(data)      # Write data to logfile
Sign up to request clarification or add additional context in comments.

4 Comments

Unfortunately, that didn't work either. It still hangs and never writes the data. I added a print(data) call before the write and it never displays anything coming back. I tried explicitly setting the makefile mode to read and setting the bytes for readline, but neither seemed to have any impact.
Ah, I just read in the Users Guide: Responses are terminated with a carriage return (the serial interface can be configured to also send a new line character). That explains why readline() (which waits for a NL) didn't work.
I adjusted the answer.
That definitely seemed to do the trick. I've run it numerous times and the output is exactly as I expected. I saw that in the user's guide as well, but other than putting it in the command, I had no idea how to make the read operation terminate. Thank you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.