Arduino+ SHT15 Help

I inherited this project from someone who’s left the company I work for and until a few months ago was very unfamiliar with Arduino. My knowledge is still pretty sparse. However I’ve wrapped my head around this project and have a good idea of what’s going on.

I am using an Arduino Uno, several SHT15 Breakout Board from Sparkfun, and Breadboard Power Supply Stick 3.3V-5V from Sparkfun.

The code used for the Arduino looks to be modified from this: http://wiring.org.co/learning/basics/hu … sht15.html. See below for the code I am using on the Arduino. I also have some Python code I inherited from this project. I will also post it below.

Currently I have one Arduino Uno hooked up to two SHT15 workinging as intended. This was by the previous employee. I’ve taken the code he used and have adapted it to work with six SHT15. With short runs of about 8 inches I was able to make four SHT15 work as intended. I didn’t purchase any extra SHT15 to test all six but the code was set up to loop and should work. The SHT15 were to be set up in different locations in the building. The distances from the Arduino and SHT15 ranged from 60 to 120 feet or so. I wasn’t sure if it would even work but I was pressed to try anyway.

It seemed that over these distances the SHT15 drew to much power from the board and it wouldn’t show up in the device manager anymore. My idea was to power the SHT15 externally and just use the digital pins to take readings. That is where the Breadboard Power Supply Stick came in. I decided to take everything down and run with just one SHT15 over a 100 foot CAT6 cable all at my workstation. We have two SHT15 running off a single 80 foot CAT6 run that is working so I didn’t see this as to much of a stretch.

When running on a short cable it works directly connected to the Arduino as expected. Using the Breadboard Power Supply I get an error “ACK error 0”. Using the 100 foot run with Arduino power I get an error “ACK error 1”. Using the Breadboard Power Supply I get the “ACK error 0” again. I understand that the errors are built into the Arduino code, but I don’t know what they mean. I thought that someone here may be able to help.

Arduino Code:

int temperatureCommand  = B00000011;  // command used to read temperature
int humidityCommand = B00000101;  // command used to read humidity

//int clockPin2 = 9;  // pin used for clock
//int dataPin2  = 8;  // pin used for data

int ack;  // track acknowledgment for errors
int val;

//Assembly 1 Pins 2 and 3
float tempC;
float tempF;
float humidity;
char tempbuff[10];
char humbuff[10];

void setup() {
  Serial.begin(9600); // open serial at 9600 bps
}

void loop() { 
 int clockPin = 3 ;  // pin used for clock
 int dataPin  = 2;  // pin used for data
 // read the temperature and convert it to centigrades 
 sendCommandSHT(temperatureCommand, dataPin, clockPin);
 waitForResultSHT(dataPin);
 val = getData16SHT(dataPin, clockPin);
 skipCrcSHT(dataPin, clockPin);
 tempC= -40.1 + 0.01 * (float)val ;
 tempF = ((9.0/5.0)*tempC) + 32;

 // read the humidity
 sendCommandSHT(humidityCommand, dataPin, clockPin);
 waitForResultSHT(dataPin);
 val = getData16SHT(dataPin, clockPin);
 skipCrcSHT(dataPin, clockPin);
 humidity = -2.0468 + 0.0367 * val + -0.0000015955 * val * val;
 humidity=humidity-2.09;
  
  dtostrf(tempF,5,2,tempbuff);
  dtostrf(humidity,5,2,humbuff);


  delay(600);


char monitor2[30];
sprintf(monitor2,"%s,%s",tempbuff,humbuff);
Serial.println(monitor2);


 delay(60000); // wait for 200 milliseconds for next reading
}

// commands for reading/sending data to a SHTx sensor

// send a command to the SHTx sensor
void sendCommandSHT(int command, int dataPin, int clockPin)

{
  int ack;

  // transmission start
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  digitalWrite(dataPin, HIGH);
  digitalWrite(clockPin, HIGH);
  digitalWrite(dataPin, LOW);
  digitalWrite(clockPin, LOW);
  digitalWrite(clockPin, HIGH);
  digitalWrite(dataPin, HIGH);
  digitalWrite(clockPin, LOW);
  


  // shift out the command (the 3 MSB are address and must be 000, the last 5 bits are the command)
  shiftOut(dataPin, clockPin, MSBFIRST, command);
  

  // verify we get the right ACK
 
  
  digitalWrite(clockPin, HIGH);
  pinMode(dataPin, INPUT);
  ack = digitalRead(dataPin);
  if (ack != LOW)
    Serial.println("ACK error 0");
  digitalWrite(clockPin, LOW);
  ack = digitalRead(dataPin);
  if (ack != HIGH)
    Serial.println("ACK error 1");

}

// wait for the SHTx answer
void waitForResultSHT(int dataPin)
{
  int ack;

  pinMode(dataPin, INPUT);
  for (int i = 0; i < 100; ++i)
  {
    delay(20);
    ack = digitalRead(dataPin);
    if (ack == LOW)
      break;
  }
  if (ack == HIGH)
    Serial.println("ACK error 2");

}
// get data from the SHTx sensor
int getData16SHT(int dataPin, int clockPin)
{
  int val;

  // get the MSB (most significant bits)
  pinMode(dataPin, INPUT);
  pinMode(clockPin, OUTPUT);
  val = shiftIn(dataPin, clockPin, MSBFIRST);
  val *= 256; // this is equivalent to val << 8;

  // send the required ACK
  pinMode(dataPin, OUTPUT);
  digitalWrite(dataPin, HIGH);
  digitalWrite(dataPin, LOW);
  digitalWrite(clockPin, HIGH);
  digitalWrite(clockPin, LOW);

  // get the LSB (less significant bits)
  pinMode(dataPin, INPUT);
  val |= shiftIn(dataPin, clockPin, MSBFIRST);
  return val;
}

// skip CRC data from the SHTx sensor
void skipCrcSHT(int dataPin, int clockPin)
{
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  digitalWrite(dataPin, HIGH);
  digitalWrite(clockPin, HIGH);
  digitalWrite(clockPin, LOW);
}

Python Code:

# -*- coding: utf-8 -*-
'''
Python Script to read and report data from SHT15 Sensors attached to Arudio UNO. 

See Change Log for list of changes. 
'''
##### Import libraries ##### 
import csv							#read comma separated variable data
import pylab						# plotting and math library
from pytz import timezone			#time zones and time converting library
import serial						# reading from serial port library
import os							# Linux-type command line commands

# opens COM port 9. None=wait forever for signals   
ser=serial.Serial(port='\\.\COM9', baudrate=9600, timeout=None)

print ("Open COM Port.")

import time							# import time library
from time import strftime 
    
tnow=strftime("%m_%Y")				#Define Time as current month and Year

txtfile=open('//SERVER/Quality/Quality/Temp/LogFiles/' + tnow + '.txt','a')    #open SHT15-1 txt file and append data to it. 
sensorlog=open('//SERVER/Quality/Quality/Temp/LogFiles/' + tnow + '.txt','r')   #open SHT15-1 to read data for analysis.

print ("Read text file.")
            
S=ser.readline()    #read most recent line from the serial port

print ("Read serial port.")

txtfile.write("%d,%s"%(int(time.time()),S))         #write the most recent line from serial port to file
txtfile.close()         #close file.

print ("Write text file.")

reader=csv.reader(sensorlog)    #use csv.reader to import data.
Time,Temperature1,humidity1=zip(*reader) #read data in txt file and separated into variable columns. 

Temp1=[float(i) for i in Temperature1]
hum1=[float(i) for i in humidity1]


#Define a list of variables to be used.
unix=[]    
month=[]
year=[]
day=[]
hour=[]
minute=[]
d=[]
t=[] 
data=[]
diff=[]
#Isolate the last value from the variables. To be displayed in the html file.
dispTemp1=str(Temp1[-1])    
dispHum1=str(hum1[-1])


#################################################################################
###     Email if condition is met                                             ###
#################################################################################
emailSent = 0
if Temp1[-1] > 120: #check the most recent value for temp in freezer. #should be temp6
	import smtplib

	from email.mime.multipart import MIMEMultipart
	from email.mime.text import MIMEText
	
	# me == my email address
	# you == recipient's email address
	me = "email@email.com"
	you = ['email@email.com','email@email.com'] # needs to be a list.
	
	# Create message container - the correct MIME type is multipart/alternative.
	msg = MIMEMultipart('alternative')
	msg['Subject'] = "Freezer Tempeture Is To High"
	msg['From'] = me
	msg['To'] = ", ".join(you)
	
	# Create the body of the message (a plain-text and an HTML version).
	text = "Warning! The current freezer temperature is above 32 degrees Fahrenheit."
	html = """\
	<html>
		<head></head>
		<body>
			<p>Warning! The current freezer temperature is above 32 degrees Fahrenheit.


			From the network, you can monitor the current data here:  "file://///SERVER/Quality/Quality/Temp/current.html"


			Sent by an automated process.
			</p>
		</body>
	</html>"""
	emailSent = 1
else:
	print ("Temp in range. No warning to send.")

# Email once per day between 12:00 and 12:10 to verify the program is running.
import time
from time import strftime
filetestH=time.strftime("%H") 
filetestM=int(time.strftime("%M"))

if  filetestH=="12" and filetestM<=10:
	import smtplib

	from email.mime.multipart import MIMEMultipart
	from email.mime.text import MIMEText
	
	me = "email@email.com"
	you = ['email@email.com','email@email.com'] # needs to be a list.
	
	msg = MIMEMultipart('alternative')
	msg['Subject'] = "Temperature and Humidity Sensors"
	msg['From'] = me
	msg['To'] = ", ".join(you)
	
	text = "Temperature and Humidity Sensors are working correctly."
	html = """\
	<html>
		<head></head>
		<body>
			<p>Temperature and Humidity Sensors are working correctly.


			From the network, you can monitor the current data here:  "file://///SERVER/Quality/Quality/Temp/current.html"


			Sent by an automated process.
			</p>
		</body>
	</html>"""
	emailSent = 1
else:
	print ("It's not yet time.")

if emailSent == 1:
	# Record the MIME types of both parts - text/plain and text/html.
	part1 = MIMEText(text, 'plain')
	part2 = MIMEText(html, 'html')
	
	# Attach parts into message container.
	# According to RFC 2046, the last part of a multipart message, in this case
	# the HTML message, is best and preferred.
	msg.attach(part1)
	msg.attach(part2)
	# Send the message via local SMTP server.
	mail = smtplib.SMTP('smtp.gmail.com', 587)
	mail.ehlo()
	mail.starttls()
	mail.login('email@email.com', 'password')
	mail.sendmail(me, you, msg.as_string())
	mail.quit()
	print ("Email successfully sent.")
	
#################################################################################
###     End Email                                                             ###
#################################################################################

# define times for each line of data in YYMMDDHHMM format from Unix time stamp
from datetime import datetime, date, time
for i in range(0,len(Time)):
    x=Time[i]
    utctime=datetime.fromtimestamp(int(x),timezone('UTC'))
    centtime=utctime.astimezone(timezone('US/Central'))
    unix.append(centtime.strftime('%Y,%m,%d,%H,%M'))
    month.append(int(unix[i][5:7]))
    day.append(int(unix[i][8:10]))
    year.append(int(unix[i][0:4]))
    hour.append(int(unix[i][11:13]))
    minute.append(int(unix[i][14:16]))
    
   # create variables combining the time.     
    d.append(date(year[i],month[i],day[i]))
    t.append(time(hour[i],minute[i]))    
    data.append(datetime.combine(d[i],t[i]))   
    
# convert date to datenum for plotting
dates=pylab.matplotlib.dates.date2num(data)

#################################################################################
###     Plotting Block                                                        ###
#################################################################################

count = 1
print ('Sensor Number: %s') % count
pylab.plt.close('all') # close any open plots if any
f,ax=pylab.plt.subplots(2,sharex=True)  #define sub-plot with 2 plots sharing x axis. 
# give each sub-plot a title 
ax[0].plot_date(dates[-144:],Temp1[-144:],'-',color='r')		#Plot the last 144 values, gives a better scale on y axis then max and min of the whole set.
ax[1].plot_date(dates[-144:],humidity1[-144:],'-',color='b')
ax[0].set_title('Assembly 1 Temp (deg F)')
ax[1].set_title('Assembly 1 Humidity (%)')

ax[0].grid(True,linestyle="--",color="0.75")
ax[1].grid(True,linestyle="--",color="0.75")
	
#get current axis (x) and display on the most recent 24 hours at 3hr interval tick marks and format.
ax = pylab.gca() 
pylab.plt.xlim(dates[-1]-1,dates[-1])  
ax.xaxis.set_major_locator(
	pylab.matplotlib.dates.HourLocator(byhour=range(24),interval=3)
)
ax.xaxis.set_major_formatter(
	pylab.matplotlib.dates.DateFormatter('%H:%M\n %m/%d')
) 

# get the current time for a check.
import time
from time import strftime
filetestH=time.strftime("%H") 
filetestM=int(time.strftime("%M")) 

#first reading after midnight. 
if  filetestH=="00" and filetestM<=10:
	fnow=strftime('%m%d%Y%H%M') #get time now

	filename='//SERVER/Quality/Quality/Temp/Assy1/%d/%d/' % (year[-1],month[-1]) #define a path to store the images
	dirPath = '//SERVER/Quality/Quality/Temp/Assy1/temp/'
	
	if not os.path.exists(filename): os.makedirs(filename)   # if it exists great if not create 
	filea= filename +"%s.png" % (fnow)  # create file name for images as time now
	pylab.savefig(filea, bbox_inches=0) #save figure
	fileList = os.listdir(dirPath)
	#for first reading after midnight, delete the files stored in the temp folder and store 1 24hr images in a permanent location. 
	for fileName in fileList:
		os.remove(dirPath+"/"+fileName)
	
		#if not directly after midnight, save file to temp folder
	else:
		fnow=strftime('%m%d%Y%H%M')
		filename='//E2_SERVER/Quality/Quality/Temp/Assy1/temp/'

	if not os.path.exists(filename): os.makedirs(filename)    
	filea= filename +"%s.png" % (fnow) 
	pylab.savefig(filea, bbox_inches=0)
	pylab.close()
	count += 1

#################################################################################
###     End Plotting                                                          ###
#################################################################################
#################################################################################
###     HTML Block                                                            ###
#################################################################################
from time import strftime
timenow=strftime('%H:%M')
if os.path.exists('//SERVER/Quality/Quality/Temp/current.html'):os.remove('//SERVER/Quality/Quality/Temp/current.html') #delete hmtl if exists 
webpg=open('//SERVER/Quality/Quality/Temp/current.html','w') # create new html file


if os.path.exists("//SERVER/Quality/Quality/Temp/Assy1/temp/Thumbs.db"): os.remove("//SERVER/Quality/Quality/Temp/Assy1/temp/Thumbs.db")  # remove thumb file

list1=os.listdir("//SERVER/Quality/Quality/Temp/Assy1/temp")

try:
    htmlcode="""
    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="refresh" content="30" />
    <title>Area Temp/Humidity</title>
    </head>

    <body>
	<p style="font-size: 40pt; color:#808080; position:absolute; top:-40px; left:40px;">Last Sensor Reading:</p>
	<p style="font-size: 40pt; color:#40FF00; position:absolute; top:-40px; left:520px;"> %s </p>
	
	<p style="font-size: 20pt; color:#808080; position:absolute; top:90px; left:10px;"> Assembly 1 Temp (F): 

	<p style="font-size: 96pt; color:#ff0000; position:absolute; top:20px; left:10px;"> %s 

	<p style="font-size: 20pt; color:#808080; position:absolute; top:310px; left:10px;"> Assembly 1 Humidity (%%): 

	<p style="font-size: 96pt; color:#0000FF; position:absolute; top:240px; left:10px;"> %s 

	</p></p></p></p>
    <div style="position: absolute; left: 270px; top: 75px; z-index: -20;">
	<img src="file:\\\\//SERVER/Quality\\Quality\\Temp\\Assy1\\temp\\%s" width="600" height="450">
    </div>

	</body>
    </html>""" % (timenow,dispTemp1,dispHum1,list1[-1]) 
    webpg.write("%s"%(htmlcode))
    webpg.close()
#################################################################################
###     End HTML                                                              ###
#################################################################################    
##if any indexing errors display message
except IndexError:
    print ("We will get it next time!")

print ("That's All Folks.")
#close open file
sensorlog.close()
#close open serial port    
ser.close()