Atlas Scientific PT-1000 (-200C to +850C) temp

About This Project

The gist is that we need to be able to monitor both -100Celsius freezers that contain genetic samples and specialist biological samples and also liquid nitrogen dewers (-184Celsius). The first step is to start with just the temperature monitoring since adding such monitoring systems to existing freezers can cost upwards of several thousand dollars and require you use proprietary monitoring software. We wanted something that isn’t going to cost us a lot of money, was cloud based so we didn’t have to spin up additional virtual machines, and also didn’t require a programming team to maintain it.

The next iteration of this project will add an I2C mux so that we can add current monitors that will track power usage of the fridge since that trend is what we would track to see if the compressor is starting to go bad.

What’s Connected

  • Raspberry Pi 3B+ running Raspbian Stretch
  • Atlas Scientific PT-1000 temperature probe setup for I2C
  • POE daughter board (Navolabs POE for RasPi 3B+)

Triggers & Alerts

The goal is to add notification triggers once business rules are developed to set minimally acceptable upper and lower temperature thresholds.

Scheduling

(Did you use the Scheduling feature?)

Dashboard Screenshots

Photos of the Project

(Take some pictures of your project functioning in the wild!)

Video

(Upload a YouTube video showcasing your project in action!)

2 Likes

Main python2 code:

#!/usr/bin/env python
import cayenne.client
import time
import io # used to create file streams
import fcntl # used to access I2C parameters like addresses

# Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
# setup for Brian Chee Cayenne account
MQTT_USERNAME  = "Insert MQTT_USERNAME HERE"
MQTT_PASSWORD  = "Insert MQTT_PASSWORD HERE"
MQTT_CLIENT_ID = "Insert MQTT_CLIENT_ID HERE"

delay=5

client = cayenne.client.CayenneMQTTClient()
client.begin(MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID)
# For a secure connection use port 8883 when calling client.begin:
# client.begin(MQTT_USERNAME, MQTT_PASSWORD, MQTT_CLIENT_ID, port=8883)

class atlas_i2c:
    long_timeout = 1.5  # the timeout needed to query readings & calibrations
    short_timeout = .5  # timeout for regular commands
    default_bus = 1  # the default bus for I2C on the newer Raspberry Pis,
                     # certain older boards use bus 0
    default_address = 102  # the default address for the Temperature sensor

    def __init__(self, address=default_address, bus=default_bus):
        # open two file streams, one for reading and one for writing
        # the specific I2C channel is selected with bus
        # it is usually 1, except for older revisions where its 0
        # wb and rb indicate binary read and write
        self.file_read = io.open("/dev/i2c-" + str(bus), "rb", buffering=0)
        self.file_write = io.open("/dev/i2c-" + str(bus), "wb", buffering=0)

        # initializes I2C to either a user specified or default address
        self.set_i2c_address(address)

    def set_i2c_address(self, addr):
        # set the I2C communications to the slave specified by the address
        # The commands for I2C dev using the ioctl functions are specified in
        # the i2c-dev.h file from i2c-tools
        I2C_SLAVE = 0x703
        fcntl.ioctl(self.file_read, I2C_SLAVE, addr)
        fcntl.ioctl(self.file_write, I2C_SLAVE, addr)

    def write(self, string):
        # appends the null character and sends the string over I2C
        string += "\00"
        self.file_write.write(string)

    def read(self, num_of_bytes=31):
        # reads a specified number of bytes from I2C,
        # then parses and displays the result
        res = self.file_read.read(num_of_bytes)  # read from the board
        # remove the null characters to get the response
        response = filter(lambda x: x != '\x00', res)
        if(ord(response[0]) == 1):  # if the response isnt an error
            # change MSB to 0 for all received characters except the first
            # and get a list of characters
            char_list = map(lambda x: chr(ord(x) & ~0x80), list(response[1:]))
            # NOTE: having to change the MSB to 0 is a glitch in the
            # raspberry pi, and you shouldn't have to do this!
            # convert the char list to a string and returns it
            return ''.join(char_list)
        else:
            return "Error " + str(ord(response[0]))

    def query(self, string):
        # write a command to the board, wait the correct timeout,
        # and read the response
        self.write(string)

        # the read and calibration commands require a longer timeout
        if((string.upper().startswith("R")) or
           (string.upper().startswith("CAL"))):
            time.sleep(self.long_timeout)
        elif((string.upper().startswith("SLEEP"))):
            return "sleep mode"
        else:
            time.sleep(self.short_timeout)

        return self.read()

    def close(self):
        self.file_read.close()
        self.file_write.close()
        
def main():
    device = atlas_i2c(102)  # creates the I2C port object, specify the address
                          # or bus if necessary
    i=0
    timestamp = 0
 
    while True:
        client.celsiusWrite(1,device.query("R"))
        client.loop()
        time.sleep(delay)
       

if __name__ == '__main__':
    main()
1 Like

Added this line to the /etc/rc.local file:
/home/pi/start-atlas.sh &

start-atlas.sh is this:
#!/bin/sh
sleep 10
sudo /usr/bin/python2 /home/pi/minimal.py &

This then starts up the python2 script that harvests the temperature (-200C to +850C) off the I2C interface and then pushes the result every five seconds to the MQTT Cayenne gateway.

1 Like

Awesome project @chee and thanks for sharing it. would love to see some pics/video of this in wild.