Как добавить дополнительный датчик температуры (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 "));
}
@JayJay Lee, 👍1
Обсуждение1 ответ
Лучший ответ:
Вы обновили код выше, чтобы добавить свой новый датчик?
Беглый взгляд на сайт 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
- C++ против языка Arduino?
- avrdude ser_open() can't set com-state
- Как читать и записывать EEPROM в ESP8266
- Float печатается только 2 десятичных знака после запятой
- устаревшее преобразование из строковой константы в 'char*'
- Запрограммировать ATMega328P и использовать его без платы Arduino.
- Разница между print() и println()
- Как исправить: Invalid conversion from 'const char*' to 'char*' [-fpermissive]
Определите «изменен адрес I2C» — самой плате датчика необходимо изменить адрес I2C — как именно вы изменили адрес I2C?, @Dave Newton
@DaveNewton Спасибо за ваш вопрос. Я использовал Arduino UNO и выдал команду «I2C, 50» в Arduino IDE., @JayJay Lee