Как добавить дополнительный датчик температуры (EZO RTD от Atlas Scientific) в базовый комплект Wi-Fi для пула Atlas Scientific?

Обзор проблемы

Когда я изменил I2C-адрес датчика (EZO RTD) на другой адрес (например, 50 или 100) вместо адреса по умолчанию (102), он не работал на моем базовом WiFi-комплекте Atlas Scientific для гидропоники.

Конкретное описание

Я попытался добавить датчик температуры (EZO RTD) в базовый WiFi-комплект гидропоники Atlas Scientific, в котором уже есть датчик pH (EZO pH) и датчик температуры (EZO RTD) на порте pH и порте температуры, соответственно. Поскольку в предоставленном руководстве по настройке Atlas Scientific говорится, что каждый датчик в комплекте должен иметь другой адрес I2C, когда на нем используется несколько датчиков. Поэтому я присвоил I2C-адрес "50" к дополнительному датчику, а затем добавил его к порту AUX (и попробовал порт температуры), но он вообще не работал. Между тем, датчик температуры с адресом I2C по умолчанию 102) очень хорошо работает как с портами температуры, так и с портами AUX. Я предполагаю, что это может быть связано с проблемой кодирования. Код, предоставленный Atlas Scientific, выглядит следующим образом: КОД УДАЛЕН МНОЙ

Спасибо, что прочитали мою проблему.

Джейджей

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Я решил эту проблему на основе ответа, за который проголосовал.

Я сделал следующий код:

#include <iot_cmd.h>
#include <ESP8266WiFi.h>                                         // включаем библиотеку Wi-Fi esp8266
#include "ThingSpeak.h"                                          //подключаем библиотеку ThingsSpeak
#include <sequencer4.h>                                          //импортирует 4-х функциональный секвенсор
#include <sequencer1.h>                                          //импортирует 1-функциональный секвенсор
#include <Ezo_i2c_util.h>                                        // вводит общие операторы печати
#include <Ezo_i2c.h> //включаем библиотеку EZO I2C с https://github.com/Atlas-Scientific/Ezo_I2c_lib
#include <Wire.h>    //включаем библиотеку ардуино i2c

WiFiClient client;                                              //объявляем, что это устройство подключается к сети Wi-Fi, создаем подключение к указанному IP-адресу в Интернете

//----------------Заполните свои учетные данные Wi-Fi / ThingSpeak-------
const String ssid = "WIFI NAME";                                 //Имя сети Wi-Fi, к которой вы подключаетесь
const String pass = "WIFI PASSWORD";                             //Ваш пароль от сети Wi-Fi
const long myChannelNumber = ;                            //Номер вашего канала Thingspeak
const char * myWriteAPIKey = "";                 //Ваш ключ API записи ThingSpeak
//------------------------------------------------ ------------------


Ezo_board PH = Ezo_board(99, "PH");       //создаем объект схемы PH, адрес которого 99 и имя "PH";
Ezo_board EC = Ezo_board(100, "EC");      // создаем объект цепи EC с адресом 100 и именем "EC"
Ezo_board RTD = Ezo_board(102, "RTD");    // создаем объект цепи RTD с адресом 102 и именем "RTD";
Ezo_board RTD2 = Ezo_board(50, "RTD2");   // создаем объект цепи RTD с адресом 50 и именем "RTD2";
Ezo_board PMP = Ezo_board(103, "PMP");    // создаем объект схемы PMP с адресом 103 и именем "PMP"

Ezo_board device_list[] = {   //массив плат, используемый для отправки команд всем или определенным платам
  PH,
  EC,
  RTD,
  RTD2,
  PMP
};

Ezo_board* default_board = &device_list[0]; //используется для хранения платы, с которой разговаривали

// автоматически получает длину массива, поэтому нам не нужно менять число каждый раз, когда мы добавляем новые платы
const uint8_t device_list_len = sizeof(device_list) / sizeof(device_list[0]);

//включаем пины для каждой цепи
const int EN_PH = 14;
const int EN_EC = 12;
const int EN_RTD = 15;
const int EN_AUX = 13;

const unsigned long reading_delay = 1000;                 //сколько мы ждем ответа, в миллисекундах
const unsigned long thingspeak_delay = 15000;             // как долго мы ждем, чтобы отправить значения в ThingsSpeak, в миллисекундах

unsigned int poll_delay = 2000 - reading_delay * 2 - 300; //сколько ждать между опросами после учета времени, необходимого для отправки показаний

//параметры для настройки производительности насоса
#define PUMP_BOARD        PMP       //насос, который будет производить вывод (если их несколько)
#define PUMP_DOSE         -0.5      //доза, которую выдает помпа, в миллилитрах
#define EZO_BOARD         EC        //схема, которая будет объектом сравнения
#define IS_GREATER_THAN   true      //true означает, что показание схемы должно быть больше значения сравнения, false означает, что оно должно быть меньше
#define COMPARISON_VALUE  1000      //порог, выше или ниже которого включается помпа

float k_val = 0;                                          //содержит значение k для определения того, что печатать в меню справки

bool polling  = true;                                     //переменная для определения того, опрашивались ли каналы
bool send_to_thingspeak = true;                           //переменная, чтобы определить, отправляли ли данные в ThingsSpeak или нет

bool wifi_isconnected(){                            //функция для проверки подключения к Wi-Fi
  return (WiFi.status() == WL_CONNECTED);
}

void reconnect_wifi(){                                    //функция для повторного подключения Wi-Fi, если он не подключен
  if(!wifi_isconnected()){
    WiFi.begin(ssid, pass);
    Serial.println("connecting to wifi");
  }
}

void thingspeak_send(){
  if (send_to_thingspeak == true) {                                                    // если мы записываем данные
    if(wifi_isconnected()){
      int return_code = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey); 
      if (return_code == 200) {                                                          //код успешной передачи
          Serial.println("sent to thingspeak");
      }else{
        Serial.println("couldnt send to thingspeak");
      }
    }
  }
}

void step1();      //передаем объявления функций, чтобы использовать их в секвенсоре перед их определением
void step2();
void step3();
void step4();
Sequencer4 Seq(&step1, reading_delay,   //вызывает шаги последовательно с интервалом между ними
               &step2, 300, 
               &step3, reading_delay,
               &step4, poll_delay);

Sequencer1 Wifi_Seq(&reconnect_wifi, 10000);  // вызывает функцию переподключения Wi-Fi каждые 10 секунд

Sequencer1 Thingspeak_seq(&thingspeak_send, thingspeak_delay); // отправляет данные в ThingsSpeak со временем, определяемым задержкой ThingsSpeak

void setup() {

  pinMode(EN_PH, OUTPUT);                                                         //установить разрешающие контакты как выходы
  pinMode(EN_EC, OUTPUT);
  pinMode(EN_RTD, OUTPUT);
  pinMode(EN_AUX, OUTPUT);
  digitalWrite(EN_PH, LOW);                                                       //установить разрешающие контакты для включения цепей
  digitalWrite(EN_EC, LOW);
  digitalWrite(EN_RTD, HIGH);
  digitalWrite(EN_AUX, LOW);

  Wire.begin();                           //запускаем I2C
  Serial.begin(9600);                     //запуск последовательной связи с компьютером

  WiFi.mode(WIFI_STA);                    // устанавливаем режим ESP8266 в качестве станции для подключения к сети Wi-Fi
  ThingSpeak.begin(client);               // включаем соединение ThingSpeak
  Wifi_Seq.reset();                       // инициализируем секвенсоры
  Seq.reset();
  Thingspeak_seq.reset();
}

void loop() {
 String cmd;                            //переменная для хранения команд, которые мы отправляем в комплект

  Wifi_Seq.run();                        // запускаем секвенсер для опроса
  
  if (receive_command(cmd)) {            //если мы отправили набору команду, она помещается в переменную cmd
    polling = false;                     //останавливаем опрос
    send_to_thingspeak = false;          //и отправка данных в ThingsSpeak
    if(!process_coms(cmd)){              //затем мы оцениваем cmd для конкретных команд комплекта
      process_command(cmd, device_list, device_list_len, default_board);    //тогда, если это не зависит от комплекта, передайте cmd функции обработки команд IOT
    }
  }
  
  if (polling == true) {                 //если опрос включен, запускаем секвенсор
    Seq.run();
    Thingspeak_seq.run();
  }
}
  
//функция, управляющая включением и выходом насосов
void pump_function(Ezo_board &pump, Ezo_board &sensor, float value, float dose, bool greater_than){
 if (sensor.get_error() == Ezo_board::SUCCESS) {                    //убедитесь, что у нас есть правильное чтение, прежде чем принимать какие-либо решения
    bool comparison = false;                                        //переменная для хранения результата сравнения
    if(greater_than){                                               // мы делаем разные сравнения в зависимости от того, что хочет пользователь
      comparison = (sensor.get_last_received_reading() >= value);   //сравните показания цепи со значением сравнения, чтобы определить, активируем ли мы насос
    }else{
      comparison = (sensor.get_last_received_reading() <= value);
    }
    if (comparison) {                                               //если результат сравнения означает, что мы должны активировать насос
      pump.send_cmd_with_num("d,", dose);                           //выдаем дозу
      delay(100);                                                   //подождите несколько миллисекунд перед получением результатов помпы
      Serial.print(pump.get_name());                                // получаем данные помпы, чтобы сообщить пользователю, успешно ли получена команда
      Serial.print(" ");
      char response[20]; 
      if(pump.receive_cmd(response, 20) == Ezo_board::SUCCESS){
        Serial.print("pump dispensed ");
      }else{
        Serial.print("pump error ");
      }
      Serial.println(response);
    }else {
      pump.send_cmd("x");                                          //если мы не должны разливать, останавливаем помпу
    }
  }
}

void step1() {
  // отправляем команду чтения. мы используем эту команду вместо RTD.send_cmd("R");
  //чтобы сообщить библиотеке, что нужно разобрать чтение
  RTD.send_read_cmd();
  RTD2.send_read_cmd();
}

void step2() {
  receive_and_print_reading(RTD);             // получаем показания из цепи RTD
    if ((RTD.get_error() == Ezo_board::SUCCESS) && (RTD.get_last_received_reading() > -1000.0)) { //если показания температуры получены и они достоверны
    PH.send_cmd_with_num("T,", RTD.get_last_received_reading());
    EC.send_cmd_with_num("T,", RTD.get_last_received_reading());
    ThingSpeak.setField(2, String(RTD.get_last_received_reading(), 2));                 //назначаем показания температуры третьему столбцу канала ThingsSpeak
  } else {                                                                                      //если показания температуры недействительны
    PH.send_cmd_with_num("T,", 25.0);
    EC.send_cmd_with_num("T,", 25.0);                                                          // отправляем температуру по умолчанию = 25 градусов C на датчик EC
    ThingSpeak.setField(2, String(25.0, 2));                 //назначаем показания температуры третьему столбцу канала ThingsSpeak
  }

  Serial.print(" ");
  receive_and_print_reading(RTD2);
  if ((RTD2.get_error() == Ezo_board::SUCCESS) && (RTD2.get_last_received_reading() > -1000.0)) { //если показания температуры получены и они достоверны
    PH.send_cmd_with_num("T,", RTD2.get_last_received_reading());
    EC.send_cmd_with_num("T,", RTD2.get_last_received_reading());
    ThingSpeak.setField(3, String(RTD2.get_last_received_reading(), 2));                 //назначаем показания температуры третьему столбцу канала ThingsSpeak
  } else {                                                                                      //если показания температуры недействительны
    PH.send_cmd_with_num("T,", 25.0);
    EC.send_cmd_with_num("T,", 25.0);                                                          // отправляем температуру по умолчанию = 25 градусов C на датчик EC
    ThingSpeak.setField(3, String(25.0, 2));                 //назначаем показания температуры третьему столбцу канала ThingsSpeak
  }

}


void step3() {
  // отправляем команду чтения. мы используем эту команду вместо PH.send_cmd("R");
  //чтобы сообщить библиотеке, что нужно разобрать чтение
  PH.send_read_cmd();
  EC.send_read_cmd();
}

void step4() {
  receive_and_print_reading(PH);             // получаем показания из цепи PH
  if (PH.get_error() == Ezo_board::SUCCESS) {                                          //если чтение PH прошло успешно (назад к шагу 1)
     ThingSpeak.setField(1, String(PH.get_last_received_reading(), 2));                 //назначаем показания PH первому столбцу канала ThingsSpeak
  }
  Serial.print("  ");
  receive_and_print_reading(EC);             //получить показания из цепи EC
  if (EC.get_error() == Ezo_board::SUCCESS) {                                          //если чтение EC прошло успешно (назад к шагу 1)
     ThingSpeak.setField(2, String(EC.get_last_received_reading(), 0));                 //назначаем показания EC второму столбцу канала ThingsSpeak
  }

  Serial.println();
  pump_function(PUMP_BOARD, EZO_BOARD, COMPARISON_VALUE, PUMP_DOSE, IS_GREATER_THAN);
}



void start_datalogging() {
  polling = true;                                                 //установите для опроса значение true, чтобы запустить цикл опроса
  send_to_thingspeak = true;
  Thingspeak_seq.reset();
}

bool process_coms(const String &string_buffer) {      //функция для обработки команд, управляющих глобальными переменными и специфичных для определенных наборов
  if (string_buffer == "HELP") {
    print_help();
    return true;
  }
  else if (string_buffer.startsWith("DATALOG")) {
     start_datalogging();
    return true;
  }
  else if (string_buffer.startsWith("POLL")) {
    polling = true;  
    Seq.reset();
    
    int16_t index = string_buffer.indexOf(',');                    //проверяем, не передавался ли параметр задержки опроса
    if (index != -1) {                                              //если есть задержка опроса
      float new_delay = string_buffer.substring(index + 1).toFloat(); // превращаем его в число с плавающей запятой

      float mintime = reading_delay*2 + 300;
      if (new_delay >= (mintime/1000.0)) {                                       // убедитесь, что оно больше нашего минимального времени
        Seq.set_step4_time((new_delay * 1000.0) - mintime);          // конвертируем в миллисекунды и убираем задержку чтения из нашего ожидания
      } else {
        Serial.println("delay too short");                          //выводим ошибку, если время опроса неверно
      }
    }
    return true;
  }
  return false;                         // возвращаем false, если команды нет в списке, поэтому мы можем просканировать другой список или передать его в схему
}

void get_ec_k_value(){                                    //функция для запроса значения цепи ec
  char rx_buf[10];                                        //буфер для хранения строки, которую мы получаем от схемы
  EC.send_cmd("k,?");                                     // запрашиваем значение k
  delay(300);
  if(EC.receive_cmd(rx_buf, 10) == Ezo_board::SUCCESS){   //если чтение прошло успешно
    k_val = String(rx_buf).substring(3).toFloat();        //разбираем чтение в число с плавающей запятой
  }
}

void print_help() {
  get_ec_k_value();
  Serial.println(F("Atlas Scientific I2C hydroponics kit                                       "));
  Serial.println(F("Commands:                                                                  "));
  Serial.println(F("datalog      Takes readings of all sensors every 15 sec send to thingspeak "));
  Serial.println(F("             Entering any commands stops datalog mode.                     "));
  Serial.println(F("poll         Takes readings continuously of all sensors                    "));
  Serial.println(F("                                                                           "));
  Serial.println(F("ph:cal,mid,7     calibrate to pH 7                                         "));
  Serial.println(F("ph:cal,low,4     calibrate to pH 4                                         "));
  Serial.println(F("ph:cal,high,10   calibrate to pH 10                                        "));
  Serial.println(F("ph:cal,clear     clear calibration                                         "));
  Serial.println(F("                                                                           "));
  Serial.println(F("ec:cal,dry           calibrate a dry EC probe                              "));
  Serial.println(F("ec:k,[n]             used to switch K values, standard probes values are 0.1, 1, and 10 "));
  Serial.println(F("ec:cal,clear         clear calibration                                     "));

  if(k_val > 9){
     Serial.println(F("For K10 probes, these are the recommended calibration values:            "));
     Serial.println(F("  ec:cal,low,12880     calibrate EC probe to 12,880us                    "));
     Serial.println(F("  ec:cal,high,150000   calibrate EC probe to 150,000us                   "));
  }
  else if(k_val > .9){
     Serial.println(F("For K1 probes, these are the recommended calibration values:             "));
     Serial.println(F("  ec:cal,low,12880     calibrate EC probe to 12,880us                    "));
     Serial.println(F("  ec:cal,high,80000    calibrate EC probe to 80,000us                    "));
  }
  else if(k_val > .09){
     Serial.println(F("For K0.1 probes, these are the recommended calibration values:           "));
     Serial.println(F("  ec:cal,low,84        calibrate EC probe to 84us                        "));
     Serial.println(F("  ec:cal,high,1413     calibrate EC probe to 1413us                      "));
  }
  
  Serial.println(F("                                                                           ")); 
  Serial.println(F("rtd:cal,t            calibrate the temp probe to any temp value            "));
  Serial.println(F("                     t= the temperature you have chosen                    "));
  Serial.println(F("rtd:cal,clear        clear calibration                                     "));
 }

, 👍1

Обсуждение

Определите «изменен адрес I2C» — самой плате датчика необходимо изменить адрес I2C — как именно вы изменили адрес I2C?, @Dave Newton

@DaveNewton Спасибо за ваш вопрос. Я использовал Arduino UNO и выдал команду «I2C, 50» в Arduino IDE., @JayJay Lee


1 ответ


Лучший ответ:

0

Вы обновили код выше, чтобы добавить свой новый датчик?

Беглый взгляд на сайт Atlas и их страницу Github не нашел очевидной инструкции делать то, что вы пытаетесь сделать, так что это первое, что я бы попробовал, если вы еще этого не сделали. В разделе Учетные данные Thinkspeak добавьте новое устройство в определения устройств I2C, а затем добавьте его имя в массив доступных устройств. В приведенном ниже примере я назвал новый датчик температуры RTD2, но вы, вероятно, могли бы назвать его чем-то более описательным для его функции или размещения. Похоже, что в каждом определении есть строка имени, которая (я предполагаю) будет отображаться в данных Thingspeak и будет хорошим местом для краткого описания.

        Ezo_board PH = Ezo_board(99, "PH");       //создайте объект PH circuit, адрес которого равен 99, а имя - "PH".
        Ezo_board EC = Ezo_board(100, "EC");      //создать объект схемы EC, адрес которого равен 100, а имя - "EC".
        Ezo_board RTD = Ezo_board(102, "RTD");    //создайте объект схемы RTD, адрес которого равен 102, а имя - "RTD".;
        Ezo_board RTD2 = Ezo_board(50, "RTD2");   //создайте объект RTD circuit, адрес которого равен 50, а имя - "RTD2".
        Ezo_board PMP = Ezo_board(103, "PMP");    //создайте объект схемы PMP, адрес которого равен 103, а имя - "PMP".
        
        Ezo_board device_list[] = {   //массив плат, используемых для отправки команд на все или определенные платы
          PH,
          EC,
          RTD,
          RTD2,
          PMP
        };

Обновление:

При просмотре, похоже, вам нужно будет определить вывод Arduino, чтобы включить новое устройство (в //enable pins для каждой секции схемы) и включить его в начале setup (), где контакты других устройств установлены в режим вывода, и установить этот вывод ВЫСОКИМ (предполагая, что ваш новый RTD будет идентичен вашему текущему):

//включить контакты для каждой схемы
const int EN_PH = 14;
const int EN_EC = 12;
const int EN_RTD = 15;
const int EN_RTD2 =    <some available pin# here> ;
const int EN_AUX = 13;

И в setup():


 pinMode(EN_RTD2, OUTPUT);

  ...

 digitalWrite(EN_RTD2, HIGH);

Обновление 2:

Я думаю, что то, что мы сделали выше, приведет к тому, что ваши новые данные датчика будут записаны в Thingspeak, так как я вижу сообщение, ссылающееся на "режим журнала данных" в print_help(). Если вы ожидаете, что процесс управления каким-то образом будет воздействовать на ваши новые данные датчика, вам нужно будет понять, что он делает сейчас и что вы хотите, чтобы он делал по-другому на основе вновь доступных данных. Но я бы все равно сделал так, чтобы система просто регистрировала новые данные в качестве первого шага.

,

Спасибо за ваш ответ. Я нашел способ решить эту проблему, следуя части вашего ответа. Я отредактировал свой код только на основе первого абзаца вашего ответа, но не всего остального. Вернее, я редактировал void. шаг 1 и недействительный шаг 2., @JayJay Lee