Atlas Scientific PT1000 Temp sensor

So I have the two pieces working, the MQTT sample code can post bogus data to the dashboard (Example-01-SendData.py from the Cayenne GitHub page) and I can read the temperature off the I2C connected Atlas Scientific PT-1000 ultra low temp probe. However, I’m trying to slim it down and combine the two and I can read off the PT-1000 every 5 seconds just fine, but the posting of data to the MQTT gateway doesn’t seem to want to play. It thinks it’s posting for about a minute with the device “online” but then goes offline without ever displaying any data.

Here’s the Python 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  = "myusername"
MQTT_PASSWORD  = "mypassword"
MQTT_CLIENT_ID = "myclientID"

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 "Command succeeded " + ''.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

# put this in just to push some data to the dashboard, but it never arrives
    client.celsiusWrite(1,22.345)
    while True:
        i= device.query("R")
        client.celsiusWrite(1,i)
        print "My Temp in C: "+i
        time.sleep(delay)
    

if __name__ == '__main__':
    main()

you are missing client.loop()

SOrry to be dense but why didn’t the first datapoint post and do you have a link to documentation on how client.loop() works? I already have a while loop going and it’s mostly working since it reads from the I2C sensor every 5 seconds…why do I need the client.loop() if I have a while loop going?

Brian Chee

University of Hawaii SOEST

chee@hawaii.edu

you need to call client.loop() to ensure there is continues connection between the server and the device.
you can find more detail here Cayenne-MQTT-Python/client.py at master · myDevicesIoT/Cayenne-MQTT-Python · GitHub

Okie dokie…this seems to now work…gonna add a bit more to make it more bullet proof and add some code to display the temp on an LCD. Then this is going onto a -100C freezer.

#!/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()

Ok now one more question…when I look at the data stream…I get two observations for each period… where am I writing to the MQTT gateway twice? (ignore this question)…

How long does the data stick around? Is there a way to use something like WGET to grab the dataset and store it someplace that won’t go away?

was this issue solved? code seems to be sending only one data at a time.

you can download the data from the dashboard.

Ok hopefully the last on this thread before I share the code…now I’m trying to get the python code to autostart at boot…so far I’ve tried:

  • added “sudo /usr/bin/python2 /home/pi/minimal.py &” to my /etc/rc.local file
  • I’ve tried adding @reboot sudo /usr/bin/python2 /home/pi/minimal.py & to my crontab file
  • I’ve tried instructions I found to add it as a service to init.d
    Oh and I’ve changed it from GUI to CLI on boot…

So obviously I’m missing something to get it to autostart…Oh yeah, the permissions are 775 for the python script minimal.py in /home/pi

Ok found a workable solution:

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.

2 Likes