Boron not talking to Atlas Scientific pH sensor


I’m using a Boron to connect to an Atlas Scientific pH sensor using the Tentacle 3 HAT board. All the connections are as per the specifications I found online but the Boron is unable to listen to the sensor. This is the code I’m running and I keep getting a -1 value for Please help!

String WebHookName = "SetWebhookParameter";
#define address 99
double ph = 0;

void setup() {
    if (!Wire.isEnabled())
    Particle.variable("pH", ph);

void loop() {
     char data[20];
  int i=0;
  String cmd = "R";
  Wire.requestFrom(address, 20);
  switch (val) {
    case 1:
    Particle.publish("Read", "Success");
    case 2:
      Particle.publish("Read", "Failed");
    case 254:
      Particle.publish("Read", "Pending");
    case 255:
      Particle.publish("Read", "No Data");
      String Publish = String::format("Invalid response:%d", val);
      Particle.publish("Read", Publish);

  while(Wire.available()) {
  String pH_data = data;
  if (isdigit(pH_data.charAt(0))) {
    float current = String(pH_data).toFloat();
    if((ph == 0))
      ph = current;
      ph = (ph + current) / 2;
    String DataPublish = String::format("{\"ph\":%f}",ph);
    Particle.publish("Data", DataPublish);

Whenever experiencing difficulties communicating with an I2C device it’s advisable to check the most basic communication with an I2C scanner application.

If this doesn’t find the device chances are that your are missing the pull-up resistors on the communication lines.

To exactly understand your HW setup it’s also,good practice to provide a schematic or at least a pin connection table and the exact types of the sensor and connection board (preferable with link).

1 Like

Were you able to resolve this issue?
My understanding is that the Tentacle 3 HAT is for connecting the sensors to a Raspberry Pi.
Please let us know what was the solution.

I helped on a ticket for this one - the HAT was indeed the problem. Using the sensor directly worked.

@no1089 Thanks for chiming in. I wish people who take the opportunity to tap into the vast knowledge of the experts here would also take the effort to provide feedback when their problem is solved.
I’m glad that this case was fairly straightforward.

1 Like

My pleasure - I’m part of the support team, so feel free to reach out if you need help.
Tentacle actually sells a breakout that is just for the PH sensor, so you can still use a reliable probe connector, and have the supporting circuits.

I’m currently using an Argon OS1.5 with a NCD ControlEverything breakout board, Gravity Atlas Scientific V2.1board, and a ph probe. Using the 5v and attaching via the A1 Pin. I have imported the DFRobot library for pH. I’m currently getting readings in the -51 to -54 on pH with storage solution:

temperature:25.0^C pH:-51.26

I have setup and tested an arduino uno and everything is working. I checked and have replaced the wires. I tried changing the voltage equation to voltage = analogRead(PH_PIN)/4096.0*5000; Which obviously increases but is still in the -1 area. Once I figure this out I’m also not understanding how to send messages like arduino and calibrate the probe.

My current code

#include "DFRobot_PH.h"
//#include "EEPROM.h" 

#define PH_PIN A1
float voltage,phValue,temperature = 25;
DFRobot_PH ph;

void setup()

void loop()
    static unsigned long timepoint = millis();
    if(millis()-timepoint>1000U){                  //time interval: 1s
        timepoint = millis();
        //temperature = readTemperature();         // read your temperature sensor to execute temperature compensation
        voltage = analogRead(PH_PIN)/1024.0*5000;  // read the voltage
        phValue = ph.readPH(voltage,temperature);  // convert voltage to pH with temperature compensation
        Serial.print("^C  pH:");
        //Particle.publish("phValue", String(phValue, 2));
        //Particle.publish("Temperature", String(temperature, 2));
    ph.calibration(voltage,temperature);           // calibration process by Serail CMD

float readTemperature()
  //add your code here to get the temperature from your temperature sensor

If you check

Note: All GPIOs are only rated at 3.3VDC max.

You will see the Argon pins are not rated for 5V, so your readings will be off.

And if your sensors should actually send up to 5V to the GPIOs you’ll most likely be grilling your ADCs (if not already happened).

Thanks. So I changed to 3.3v using pin A2, A3, or A4 in case the other 2 were fried. I’m still getting the same readings -51 as before.

Which version are you now running - the code block you posted still uses the wrong calculation (although you got a better one in your text).

It should be

  voltage = analogRead(PH_PIN) * 3300 / 4095.0;

BTW, you can simplify your print statemen this way

  Serial.printlnf("Temp: %.1f °C pH: %.2f %% Voltage: %.2f mV"
                 , temperature
                 , phValue
                 , voltage);

However, have you tried looking into the library how the voltage and temperature readings are converted into the pH reading? That might provide some clue about the origin of the issue.

Which version? DFRobot_PH library is V1.04

So your formula works. I’m still not sure why the test code supplied by the library is wrong though? It’s the same formula as the arduino code from what I can tell.

Also I’m having problems with it locating the EEPROM.h using VSCode

In file included from src/pHSensor1.ino:3:0:
lib/DFRobot_PH/src/DFRobot_PH.h:16:5: warning: "ARDUINO" is not defined [-Wundef]
 #if ARDUINO >= 100
src/pHSensor1.ino:4:21: fatal error: EEPROM.h: No such file or directory

I have changed my cpp_properties.json file to:

"browse": {
                "limitSymbolsToIncludedHeaders": false,
                "path": [

The EEPROM.h file is in the EEPROM folder.It should do a recursive search in the Java folder before that but nothing seems to point it correctly.

Probably because the examples were not ported to reflect the differences between target platforms. While it would be nice if they were, knowing the basic characterisitics of any given target platform should enable anybody to adapt the samples accordingly.

EEPROM.h is not required for Particle as it is baked into the device OS API.

This suggests that the library wasn’t ported properly.
For Particle ports you’d usually see something like this

#if defined(PARTICLE)
  #if ARDUINO >= 100

Or more recently a compatibility header Arduino.h has been added to the Particle framework. Instead of the above one can now add #include <Arduino.h>.

Thanks again @ScruffR! One more thing that I’m trying to understand is how to send messages to the device over serial to calibrate the pH Sensor. Is there a way to do this?

Can you specify that a bit more?
What do you want to send to the Boron and what should it do with the data?
Have you considered using the core features that makes Particle devices stand for - e.g. sending the data to the Boron not over USB but the cloud?

From the DFRobot_PH test script:

  • You can send commands in the serial monitor to execute the calibration.
  • Serial Commands:
  • enterph -> enter the calibration mode
  • calph -> calibrate with the standard buffer solution, two buffer solutions(4.0 and 7.0) will be automaticlly recognized
  • exitph -> save the calibrated parameters and exit from calibration mode

With Arduino you can send the commands via the serial monitor. I’ve tried calling the functions via the Particle CLI.

particle call <device> function calibration()

It gives me:


When I enter ‘enterph’ or the other commands nothing seems to happen. So I thought I’d check if I’m missing something before I try to create specific Particle cloud functions.

I haven’t had a look at the Arduino code for this device, but in order to forward any thing to the sensor you first need to catch it from somewhere (anywhere).
An Arduino does - out the box - not offer any means to receive data other than via serial.
However Particle devices do.

I’d start with something like this

const char cmdList[][16] =                                // list of all possible commands
{ "n/a"                                                   // for ease of use when parsing 
, "enterph"                                               
, "calph"
, "exitph"
, ...
const int maxCmd = sizeof(cmdList) / sizeof(cmdList[0]);  // number of defined commands
int newCmd = 0;

void setup() {
  Particle.function("sendCommand", sendCmd);             // hook-up function handler 

void loop() {
  switch(newCmd) {                                       // select command branches
    case 0:
      // do nothing
    case 1: // enterph
      // do what's needed
    case 2: // calph
      // do what's needed
    case 3: // exitph
      // do what's needed
      Log.warn("command '%d' not in list", newCmd);
  newCmd = 0;                                         // command has been treated - clear

int sendCmd(const char* cmd) {
  // find sent command in list
  for (newCmd = 0; strcmp(cmd, cmdList[newCmd]) && newCmd < maxCmd; newCmd++); 
  if (newCmd >= maxCmd) {
    newCmd = 0;
    Log.warn("command '%s' not in list", cmd);
  return newCmd;

Wow. I greatly appreciate your help once again in pointing me in the right direction!

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.