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.
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").
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()
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