Posted on

How to connect the Tentacle Mini to a Raspberry Pi

No Arduino needed!

What you need:

Enable I2C on the Pi

  1. Run
    sudo aspi-config.
  2. Navigate to
    Advanced Options-> I2C.
  3. Select yes when it asks you to enable I2C
  4. Select yes when it tasks about automatically loading the kernel module.
  5. Apply settings and reboot
  6. After reboot, type ls /dev/*i2c*
    The Pi should list its I2C bus(es), e.g.
  7. Install the I2C utilities:
    sudo apt-get install -y i2c-tools

Enable I2C on the Atlas Scientific EZO circuits

Manually switch each of your EZO circuits to I2C. Step-by-step tutorial for this is here. TL;DR Use your breadboard, a 5V DC power supply and some jumper wires to short PGND and TX before powering the circuit with 5V. Each power cycle with shorted PGND/TX will switch from UART to I2C and back.

Connect the Tentacle Mini and the Raspberry Pi

Pins to connect are 5V, IOREF, GND, SDA, SCL. In case you don’t intend to use your Tentacle Mini with an Arduino at all, you should consider ordering the Kit version. It comes without the Arduino headers pre-soldered and you can mount your own custom connector just for the required pins.

  •  Tentacle 5V -> RPi 5V
    (used to power the 2 isolated power circuits on the Tentacle)
  • Tentacle IOREF -> RPi 3.3V
    (used to power the isolated I2C communications – the Pi wants 3.3V on the I/O, so we apply 3.3V)
  • Tentacle GND -> RPi GND
  • Tentacle SCL -> RPi SCL
  • Tentacle SDA -> RPi SDA

Once the two boards are connected, plug the EZO circuits into the Tentacle Mini and power up the Pi

Talking to the sensors

You can verify the circuits work with the i2cdetect utility: i2cdetect -y 1

pi@raspberrypi:~/$ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- 61 -- 63 -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

In this example, a pH and a DO circuit are plugged in. Te factory settings for the EZO circuits are as follows:

  • DO: 0x60 (97)
  • ORP: 0x61 (98)
  • pH: 0x63 (99)
  • EC: 0x64 (100)
  • RTD: 0x66 (102)

If you’re using multiple of the same type of EZO circuit (e.g. 2x pH), both will have the address 0x63. I2C must be unique. You’ll want to connect only one of the circuits at first and change it’s address. You can do this in the interactive example code below by typing i2c,105. This will give this circuit the address of 0x69 (105). You can now plug in the next circuit of the same type.

The following code is provided by Atlas Scientific. You can download it here.


import io # used to create file streams
import fcntl # used to access I2C parameters like addresses

import time # used for sleep delay and timestamps
import string # helps parse strings

class atlas_i2c:
    long_timeout = 1.5 # the timeout needed to query readings and 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 = 99 # the default address for the pH 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 ="/dev/i2c-"+str(bus), "rb", buffering = 0)
        self.file_write ="/dev/i2c-"+str(bus), "wb", buffering = 0)
        # initializes I2C to either a user specified or default 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"
    def read(self, num_of_bytes = 31):
        # reads a specified number of bytes from I2C, then parses and displays the result
        res = # read from the board
        response = filter(lambda x: x != '\x00', res) # remove the null characters to get the response
        if(ord(response[0]) == 1): # if the response isnt an error
            char_list = map(lambda x: chr(ord(x) & ~0x80), list(response[1:])) # change MSB to 0 for all received characters except the first and get a list of characters 
            # NOTE: having to change the MSB to 0 is a glitch in the raspberry pi, and you shouldn't have to do this!
            return "Command succeeded " + ''.join(char_list) # convert the char list to a string and returns it
            return "Error " + str(ord(response[0]))
    def query(self, string):
        # write a command to the board, wait the correct timeout, and read the response
        # the read and calibration commands require a longer timeout
        if((string.upper().startswith("R")) or 
            return "sleep mode"
    def close(self):

def main():
    device = atlas_i2c() # creates the I2C port object, specify the address or bus if necessary
    print(">> Atlas Scientific sample code")
    print(">> Any commands entered are passed to the board via I2C except:")
    print(">> Address,xx changes the I2C address the Raspberry Pi communicates with.") 
    print(">> Poll,xx.x command continuously polls the board every xx.x seconds")
    print(" where xx.x is longer than the %0.2f second timeout." %  atlas_i2c.long_timeout)
    print(" Pressing ctrl-c will stop the polling")
    # main loop
    while True:
        input = raw_input("Enter command: ")
        # address command lets you change which address the Raspberry Pi will poll
            addr = int(string.split(input, ',')[1])
            print("I2C address set to " + str(addr))
        # contiuous polling command automatically polls the board
            delaytime = float(string.split(input, ',')[1])
            # check for polling time being too short, change it to the minimum timeout if too short
            if(delaytime < atlas_i2c.long_timeout):
                print("Polling time is shorter than timeout, setting polling time to %0.2f" %  atlas_i2c.long_timeout)
                delaytime =  atlas_i2c.long_timeout

            # get the information of the board you're polling
            info = string.split(device.query("I"), ",")[1]
            print("Polling %s sensor every %0.2f seconds, press ctrl-c to stop polling" % (info, delaytime))
                while True:
                    time.sleep(delaytime - atlas_i2c.long_timeout)
            except KeyboardInterrupt: # catches the ctrl-c command, which breaks the loop above
                print("Continuous polling stopped")
        # if not a special keyword, pass commands straight to board
            except IOError:
                print("Query failed")
if __name__ == '__main__':

Run the code above and you’ll be presented with an interactive prompt. You can use this to setup and configure your circuits and to read values from the sensors:
>> Atlas Scientific sample code
>> Any commands entered are passed to the board via I2C except:
>> Address,xx changes the I2C address the Raspberry Pi communicates with.
>> Poll,xx.x command continuously polls the board every xx.x seconds
where xx.x is longer than the 1.50 second timeout.
Pressing ctrl-c will stop the polling
Enter command:

To connect to a circuit, use the command Address,xx. xx is address of the circuit in decimal form. For the ph circuit with address 0x63, that’s 99.
Enter command: Address,99
I2C address set to 99

Use r to read the current sensor reading
Enter command: r
Command succeeded 6.997

Check out the datasheet of your respective type of EZO circuit for a list of all commands. To find out what type of circuit you have attached, use the command i
>Enter command: i
Command succeeded ?I,pH,1.0
Posted on

We’re hiring!

Electronics Engineer for Embedded Systems

We’re hiring an electronics engineer to help us further develop our Watermelon Embedded Linux system.

Node.js Developer / Software Engineer

We’re hiring a Node.js Developer to help us developing the software stack of our ooctopus, the open microhabitat controller.

Reef / Saltwater Aquarium Specialist

We’re hiring a saltwater aquarium specialist to help us setting up several reef aquaria to test our ooctopus controller on.

Find out more about the job descriptions and how to apply on our Jobs page.

Posted on

End-of-summer news

It’s been a long and rainy summer here in central Europe – plenty of time to make some good progress with our products. We’ve had lots of achievements, read on to learn about the most important ones:

Watermelon IoT development board

We received prototypes of the watermelon. We’ve been testing it throughly during the last weeks. There’s still work todo, we’re not quite happy with the component layout yet. However the watermelon board performs well and runs very stable.
Hardware development progress 75%
[progress percentage=”75″ type=”progress” style=”progress-bar-info”]

Software development progress 50%
[progress percentage=”50″ type=”progress” style=”progress-bar-info”]

We’ve created a new juicy page for the Watermelon, it contains lots of fresh information about the board, be sure to check it out!

Tentacle Shield for Arduino

First of all, we renamed the shield – we’ve reworked our products naming altogether. Here comes the tentacle! We’ve had a setback with the quality of isolation on our prototypes and went back to the drawing board. A new batch of prototypes are being soldered as I type. We were able to reduce the shield by 20% compared to the first version. We’ve also created some gorgeous new silkscreen graphics for the production batch, have a look:

Tentacle Shield Silkscreen front
Tentacle Shield Silkscreen back


Hardware development progress 90%
[progress percentage=”90″ type=”progress”]

Software development progress 50%
[progress percentage=”50″ type=”progress”]

Check out all the fresh information on the new Tentacle page!

ooctopus the open micro-climate controller

The product concept formerly called “Aqua Libre” has moved into development stage and is now called ooctopus (open octopus)! We’ve finished our research, tested a lot of competitors products and now have a clear picture of what the ooctopus will be. We’ve started software development, and we’re soon ready for some beta-testers. We’ve also created a strategy for enclosure design and production – super hacking-friendly semi-soft silicone… You’ll love this! We’ll create some Arduino and PI versions of this enclosure too – but more on this early next year.

Hardware development progress 50%
[progress percentage=”50″ type=”progress” style=”progress-bar-info”]

Software development progress 10%
[progress percentage=”10″ type=”progress” style=”progress-bar-info”]

There’s a huge amount of new information about the ooctopus – of course we created a new page for it too!

New Website – again

Last but not least, we’ve created a new website, again! We hope you like it – feel free to leave your opinion as a comment.

Posted on

Atlas circuit isolation, noise & crosstalk tests

For the development of our Tentacle Shield for Arduino we analyzed the Atlas Scientific sensor circuits for noise and probe crosstalk.

To be answered:

  • What are normal base values, range of error during normal operation?
  • What is the effect of touching the circuits on these readings?
  • What is the effect of noise on sensor system?
  • Is there cross talk between probes?
  • If so does probe cross talk effect measurements?
  • Is there cross talk between circuits?
  • If so does circuit cross talk effect measurements?

Continue reading Atlas circuit isolation, noise & crosstalk tests