Управление Реле по MQTT на Arduino
- Войдите на сайт для отправки комментариев
Пнд, 25/07/2016 - 12:41
Такая проблема, работаю над скетчем для Arduino UNO + Ethernet Shild W5100, который будет управлять реле по протоколу MQTT программно через систему автоматизации Умного дома MajorDoMo, или вручную с выключателей-кнопок + отображать в системе MajorDoMo состояние реле (Вкл./Выкл., 0 или 1) для каждой релюшки. Только пока не могу понять как сделать управление Вкл./Выкл. с отправкой статуса о реле через топики по MQTT и выключателей.
Уже долго мучаюсь над кодом, помогите пожалуйста.
/*
Скетч для управления Реле через кнопку-выключатель, либо через MajorDoMo
по MQTT с обратной связью и сохранением статуса реле при откл. питания...
*/
#include <SPI.h> // Библиотека SPI шины
#include <Ethernet.h> // Ethernet библиотека
#include <PubSubClient.h> // Библиотека MQTT
#include <EEPROM.h> // Библиотека EEPROM
#define Relay1 2 // Реле №1
#define Relay2 3 // Реле №2
#define Relay3 4 // Реле №3
#define Relay4 5 // Реле №4
#define BUTTON_1 6 // Кнопка-выключатель №1
#define BUTTON_2 7 // Кнопка-выключатель №1
#define BUTTON_3 8 // Кнопка-выключатель №1
#define BUTTON_4 9 // Кнопка-выключатель №1
boolean StatusRelay1 = true; // Статус Реле №1
boolean btnPress1 = false; // Объявляем что кнопка №1 не нажата 0
boolean LastBtnStat1 = false; // Временная переменная для хранения статуса
boolean StatusRelay2 = true; // Статус Реле №2
boolean btnPress2 = false; // Объявляем что кнопка №2 не нажата 0
boolean LastBtnStat2 = false; // Временная переменная для хранения статуса
boolean StatusRelay3 = true; // Статус Реле №3
boolean btnPress3 = false; // Объявляем что кнопка №3 не нажата 0
boolean LastBtnStat3 = false; // Временная переменная для хранения статуса
boolean StatusRelay4 = true; // Статус Реле №4
boolean btnPress4 = false; // Объявляем что кнопка №4 не нажата 0
boolean LastBtnStat4 = false; // Временная переменная для хранения статуса
int REL1; // Переменные для вычислений с Реле...
int REL2;
int REL3;
int REL4;
int Address1 = 0; // Адреса EEPROM для хранения значений
int Address2 = 2;
int Address3 = 4;
int Address4 = 6;
// Задаём mac и ip адреса в Локальной сети
byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip{192, 168, 1, 74}; //ip Адрес Ethernet Shild'a Arduino
IPAddress server{192, 168, 1, 70}; //ip Адрес для MQTT Брокера
// Шапка Функции Callback для объявления и Инициализации PubSubClient
void callback(char* topic, byte* payload, unsigned int length);
EthernetClient ethClient; // Инициализируем Ethernet клиент
PubSubClient client(server, 1883, callback, ethClient); // Инициализируем MQTT клиент
// Функция Callback
void callback(char* topic, byte* payload, unsigned int length)
{
payload[length] = '\0';
Serial.print(topic);
Serial.print(" ");
String strTopic = String(topic);
String strPayload = String((char*)payload);
Serial.println(strPayload);
if (strTopic == "home/data/status/Relay/1") {
if (strPayload == "ON") {
REL1 = 1;
}
else if (strPayload == "OFF") {
REL1 = 0;
}
Serial.print("REL1 = ");
Serial.println(REL1);
}
else if (strTopic == "home/data/status/Relay/2") {
if (strPayload == "ON") {
REL2 = 1;
}
else if (strPayload == "OFF") {
REL2 = 0;
}
Serial.print("REL2 = ");
Serial.println(REL2);
}
else if (strTopic == "home/data/status/Relay/3") {
if (strPayload == "ON") {
REL3 = 1;
}
else if (strPayload == "OFF") {
REL3 = 0;
}
Serial.print("REL3 = ");
Serial.println(REL3);
}
else if (strTopic == "home/data/status/Relay/4") {
if (strPayload == "ON") {
REL4 = 1;
}
else if (strPayload == "OFF") {
REL4 = 0;
}
Serial.print("REL4 = ");
Serial.println(REL4);
}
}
void setup()
{
pinMode(Relay1, OUTPUT); // Задаём Реле №1 как Выход
pinMode(BUTTON_1, INPUT); // Задаём кнопку №1 как Вход
pinMode(Relay2, OUTPUT);
pinMode(BUTTON_2, INPUT);
pinMode(Relay3, OUTPUT);
pinMode(BUTTON_3, INPUT);
pinMode(Relay4, OUTPUT);
pinMode(BUTTON_4, INPUT);
Ethernet.begin(mac, ip); // Инициализируем mac, ip
Serial.begin(9600); // Задаём скорость порта в БОД'ах.
Serial.println(F("Relay Test!")); /* Тестовое сообщ. при откр. Монитора порта.
Так же обёртываем сообщения
в макрос F() для экономии ОЗУ */
//цикл считывания значения из EEPROM для реле №1
if ( EEPROM.read(Address1) ) {
digitalWrite(Relay1, HIGH);
} else {
digitalWrite(Relay1, LOW);
}
//цикл считывания значения из EEPROM для реле №2
if ( EEPROM.read(Address2) ) {
digitalWrite(Relay2, HIGH);
} else {
digitalWrite(Relay2, LOW);
}
//цикл считывания значения из EEPROM для реле №3
if ( EEPROM.read(Address3) ) {
digitalWrite(Relay3, HIGH);
} else {
digitalWrite(Relay3, LOW);
}
//цикл считывания значения из EEPROM для реле №4
if ( EEPROM.read(Address4) ) {
digitalWrite(Relay4, HIGH);
} else {
digitalWrite(Relay4, LOW);
}
if (client.connect("RelayClient")) {
Serial.println("Online");
// client.publish("home/data/status/Relay/1", "OFF");
// client.publish("home/data/status/Relay/2", "OFF");
client.subscribe("home/data/status/Relay/#");
}
}
// Функция для кнопки №1
void Button1() {
btnPress1 = digitalRead(BUTTON_1);
StatusRelay1 = digitalRead(Relay1);
if (btnPress1 && LastBtnStat1) {
delay(35); // Задержка для защиты от дребезга
btnPress1 = digitalRead(BUTTON_1);
}
LastBtnStat1 = btnPress1;
}
// Функция для кнопки №2
void Button2() {
btnPress2 = digitalRead(BUTTON_2);
StatusRelay2 = digitalRead(Relay2);
if (btnPress2 && LastBtnStat2) {
delay(35); // Задержка для защиты от дребезга
btnPress2 = digitalRead(BUTTON_2);
}
LastBtnStat2 = btnPress2;
}
// Функция для кнопки №3
void Button3() {
btnPress3 = digitalRead(BUTTON_3);
StatusRelay3 = digitalRead(Relay3);
if (btnPress3 && LastBtnStat3) {
delay(35); // Задержка для защиты от дребезга
btnPress3 = digitalRead(BUTTON_3);
}
LastBtnStat3 = btnPress3;
}
// Функция для кнопки №4
void Button4() {
btnPress4 = digitalRead(BUTTON_4);
StatusRelay4 = digitalRead(Relay4);
if (btnPress4 && LastBtnStat4) {
delay(35); // Задержка для защиты от дребезга
btnPress4 = digitalRead(BUTTON_4);
}
LastBtnStat4 = btnPress4;
}
// Функция для переподключения соединения с Брокером
void reconnect() {
// Повторяем, пока не переподключимся...
while (!client.connected()) { // Логическое НЕ "!" - Проверяем, если клиент не Законнектен....
// Попытка подключиться
if (client.connect("RelayClient")) { // Если DHTClient клиент подключен...
Serial.println(F("Connected!")); // Выводим сообщ., что подключено!
} else {
Serial.print(F("Failed connected - ")); // Ощибка соединения
Serial.println(F("Jdem 5 seconds")); // Ждём 5 секунд
delay(5000);
}
}
}
void loop() {
if (!client.connect("RelayClient")) { // Если DHTClient клиент НЕ подключен...
reconnect(); // Запускаем функцию переподключения
}
Button1();
Button2();
Button3();
Button4();
//Реле 1
if (REL1 == 0) {
digitalWrite(Relay1, LOW);
Serial.println(F("Relay1 - off"));
EEPROM.write(Address1, 0); //сохраняем как Off
client.publish("home/data/status/Relay/1", "0");
} else if (REL1 == 1) {
digitalWrite(Relay1, HIGH);
Serial.println(F("Relay1 - on"));
EEPROM.write(Address1, 1); //сохраняем как On
client.publish("home/data/status/Relay/1", "1");
}
delay(900);
//Реле 2
if (REL2 == 0) {
digitalWrite(Relay2, LOW);
Serial.println(F("Relay2 - off"));
EEPROM.write(Address2, 0); //сохраняем как Off
client.publish("home/data/status/Relay/2", "0");
} else if (REL2 == 1) {
digitalWrite(Relay2, HIGH);
Serial.println(F("Relay2 - on"));
EEPROM.write(Address2, 1); //сохраняем как On
client.publish("home/data/status/Relay/2", "1");
}
delay(900);
//Реле 3
if (REL3 == 0) {
digitalWrite(Relay3, LOW);
Serial.println(F("Relay3 - off"));
EEPROM.write(Address3, 0); //сохраняем как Off
client.publish("home/data/status/Relay/3", "0");
} else if (REL3 == 1) {
digitalWrite(Relay3, HIGH);
Serial.println(F("Relay3 - on"));
EEPROM.write(Address3, 1); //сохраняем как On
client.publish("home/data/status/Relay/3", "1");
}
delay(900);
//Реле 4
if (REL4 == 0) {
digitalWrite(Relay4, LOW);
Serial.println(F("Relay4 - off"));
EEPROM.write(Address4, 0); //сохраняем как Off
client.publish("home/data/status/Relay/4", "0");
} else if (REL4 == 1) {
digitalWrite(Relay4, HIGH);
Serial.println(F("Relay4 - on"));
EEPROM.write(Address4, 1); //сохраняем как On
client.publish("home/data/status/Relay/4", "1");
}
delay(900);
client.loop();
}
Переделал скетч, стали кнопки теперь работать, но вот как управлять по MQTT, не могу погнать.
/* Переделываю скетч для реле */ #include <SPI.h> // Библиотека SPI шины #include <Ethernet.h> // Ethernet библиотека #include <PubSubClient.h> // Библиотека MQTT #include <EEPROM.h> // Библиотека EEPROM #define Relay1 2 // Реле №1 #define Relay2 3 // Реле №2 #define relays_topic1 "home/data/status/Relay/1" //публикуемый топик #define BUTTON_1 6 // Кнопка-выключатель №1 #define BUTTON_2 7 // Кнопка-выключатель №2 #define relays_topic2 "home/data/status/Relay/2" //публикуемый топик #define UNUSED(expr) do { (void)(expr); } while (0) /*Безсмысленный цикл для callback убирающий предупреждение с компилятора*/ long last_mls3 = millis(); //функция времени для отправки топиков bool stateRelay1 = false; // Состояние Реле №1 bool wasButtonDown1 = false; // Состояние 1-й кнопки bool stateRelay2 = true; // Статус Реле №2 bool wasButtonDown2 = false; // Объявляем что кнопка №2 не нажата 0 int Address1 = 0; // Адреса EEPROM для хранения значений int Address2 = 2; // Задаём mac и ip адреса в Локальной сети byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; IPAddress ip{192, 168, 1, 74}; //ip Адрес Ethernet Shild'a Arduino IPAddress server{192, 168, 1, 70}; //ip Адрес для MQTT Брокера // Шапка Функции Callback для объявления и Инициализации PubSubClient void callback(char* topic, byte* payload, unsigned int length); EthernetClient ethClient; // Инициализируем Ethernet клиент PubSubClient client(server, 1883, callback, ethClient); // Инициализируем MQTT клиент // Функция Callback void callback(char* topic, byte* payload, unsigned int length) { //Используем идентификатор UNUSED для устранения Warning'а при компиляции UNUSED(topic); client.publish("home/data/status/Relay", payload, length); } void setup() { pinMode(Relay1, OUTPUT); // Задаём Реле №1 как Выход pinMode(BUTTON_1, INPUT); // Задаём кнопку №1 как Вход pinMode(Relay2, OUTPUT); pinMode(BUTTON_2, INPUT); Serial.begin(9600); // Задаём скорость порта в БОД'ах. Serial.println(F("Relay test!")); /* Тестовое сообщ. при откр. Монитора порта. Так же обёртываем сообщения в макрос F() для экономии ОЗУ */ Ethernet.begin(mac, ip); // Инициализируем mac, ip delay(100); //ждем 100 милисекунд client.connect("RelayClient"); //конектимся с брокером как клиент client.subscribe(relays_topic1); //подписываемся на топик client.subscribe(relays_topic2); //подписываемся на топик //цикл считывания значения из EEPROM для реле №1 if ( EEPROM.read(Address1) ) { digitalWrite(Relay1, HIGH); } else { digitalWrite(Relay1, LOW); } //цикл считывания значения из EEPROM для реле №2 if ( EEPROM.read(Address2) ) { digitalWrite(Relay2, HIGH); } else { digitalWrite(Relay2, LOW); } } // Функция для переподключения соединения с Брокером void reconnect() { // Повторяем, пока не переподключимся... while (!client.connected()) { // Логическое НЕ "!" - Проверяем, если клиент не Законнектен.... // Попытка подключиться if (client.connect("RelayClient")) { // Если RelayClient клиент подключен... Serial.println(F("Connected!")); // Выводим сообщ., что подключено! } else { Serial.print(F("failed connected - ")); // Ощибка соединения Serial.println(F("Jdem 5 seconds")); // Ждём 5 секунд delay(5000); } } } // Функция для кнопки №1 (функция для сенсорной кнопки) void Button1() { byte sensButtonVal = digitalRead(BUTTON_1); // Читаем значение с сенсорной кнопки bool isButtonDown1 = sensButtonVal; if (isButtonDown1 && !wasButtonDown1) { stateRelay1 = !stateRelay1; //delay(10); // Для сенсорной кнопки защита от дребезга некчему } wasButtonDown1 = isButtonDown1; digitalWrite(Relay1, stateRelay1); } // Функция для кнопки №2 (функция для механической кнопки) void Button2() { bool isButtonDown2 = digitalRead(BUTTON_2); if (isButtonDown2 && !wasButtonDown2) { stateRelay2 = !stateRelay2; delay(10); // Защита от дребезга } wasButtonDown2 = isButtonDown2; digitalWrite(Relay2, stateRelay2); } void loop() { if (!client.connect("RelayClient")) { // Если RelayClient клиент НЕ подключен... reconnect(); // Запускаем функцию переподключения } client.loop(); Button1(); Button2(); }Мало кому будет интересно копаться в длинных портянках, выискивая ваши ошибки. Если что-то не работает, локализуйте проблемный участок до нескольких строк, снабжайте код всеми необходимым пояснениями и только в таком виде формулируйте вопрос.
Тоже долго мучаюсь. Ты не закончил код? может поделишься ?
Отбросил эту идею, т.к. это накладно обходится: ардуино + Ethernet шилд + тянуть везде по дому витую пару.
Решил сделать по Wi-Fi через ESP8266, это дешевле и удобнее.
Но некоторые проекты именно через Arduino решил сделать.
Доброго дня. Я пошел по иному пути. Вот Код.
// Реле подлкючен к 0 пину и к +3.3v инверсия!!! // Датчик температуры DHT11 к 2 пину #include <ESP8266WiFi.h> #include <PubSubClient.h> #include <DHT.h> #define DHTPIN 2 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); const char *ssid = "555555"; // Имя вайфай точки доступа const char *pass = "1111111111"; // Пароль от точки доступа const char *mqtt_server = "m13.cloudmqtt.com"; // Имя сервера MQTT const int mqtt_port = *******; // Порт для подключения к серверу MQTT const char *mqtt_user = "efgerghj"; // Логи от сервер const char *mqtt_pass = "JkljIiGJTiUTR"; // Пароль от сервера #define BUFFER_SIZE 100 bool LedState = false; int tm=300; int tmvrem=300; // по умолчанию int tm1=300; int autom=1; //если 0 - то ручное, если 1 - то автоматическое int hum_min = 45; //минимальная влажность int hum_max = 65; //максимальная влажность float temp=0; float h,t; // Функция получения данных от сервера void callback(const MQTT::Publish& pub){ Serial.print(pub.topic()); // выводим в сериал порт название топика Serial.print(" => "); Serial.print(pub.payload_string()); // выводим в сериал порт значение полученных данных String payload = pub.payload_string(); if(autom == 0){ if(String(pub.topic()) == "test/led") // проверяем из нужного ли нам топика пришли данные { int stled = payload.toInt(); // преобразуем полученные данные в тип integer digitalWrite(0,stled); // включаем или выключаем светодиод в зависимоти от полученных значений данных } } if(String(pub.topic()) == "test/aut1") // проверяем из нужного ли нам топика пришли данные { autom = payload.toInt(); // преобразуем полученные данные в тип integer } if(String(pub.topic()) == "test/hmin1") // проверяем из нужного ли нам топика пришли данные { hum_min = payload.toInt(); // преобразуем полученные данные в тип integer } if(String(pub.topic()) == "test/hmax1") // проверяем из нужного ли нам топика пришли данные { hum_max = payload.toInt(); // преобразуем полученные данные в тип integer } if(String(pub.topic()) == "test/vrem") // проверяем из нужного ли нам топика пришли данные { tmvrem = payload.toInt(); // преобразуем полученные данные в тип integer } } WiFiClient wclient; PubSubClient client(wclient, mqtt_server, mqtt_port); void setup() { Serial.begin(115200); delay(10); Serial.println(); Serial.println(); pinMode(0, OUTPUT); // отмечаем, что порт будет ВЫХОДОМ dht.begin(); // запускаем библиотеку датчика } void loop() { TempHum(); // показания с датчиков delay(10); if(autom == 1){ RunProg(); } // подключаемся к wi-fi if (WiFi.status() != WL_CONNECTED) { Serial.print("Connecting to "); Serial.print(ssid); Serial.println("..."); WiFi.begin(ssid, pass); if (WiFi.waitForConnectResult() != WL_CONNECTED) return; Serial.println("WiFi connected"); } // подключаемся к MQTT серверу if (WiFi.status() == WL_CONNECTED) { if (!client.connected()) { Serial.println("Connecting to MQTT server"); if (client.connect(MQTT::Connect("arduinoClient2") .set_auth(mqtt_user, mqtt_pass))) { Serial.println("Connected to MQTT server"); client.set_callback(callback); client.subscribe("test/led"); // подписывааемся по топик с данными для светодиода client.subscribe("test/aut1"); client.subscribe("test/hmin1"); client.subscribe("test/hmax1"); client.subscribe("test/vrem"); } else { Serial.println("Could not connect to MQTT server"); } } if (client.connected()){ // если есть соединение client.loop(); TempSend(); // Функция отправки показаний с термодатчика } } } // конец основного цикла // Функция отправки показаний с термодатчика void TempSend(){ if (tm==0) { h = dht.readHumidity(); t = dht.readTemperature(); // Read temperature as Celsius (the default) client.publish("test/temp",String(t)); // отправляем в топик для термодатчика значение температуры Serial.println(t); client.publish("test/hum",String(h)); // отправляем в топик для термодатчика значение влажности Serial.println(h); if(autom == 1){ client.publish("test/aut","Включена"); } if(autom == 0){ client.publish("test/aut","Выключена"); } Serial.println(autom); tm = tmvrem; // пауза меду отправками значений } tm--; delay(10); } // чтение данных с датчика, раз в 3с. void TempHum(){ if (tm1==0) { h = dht.readHumidity(); t = dht.readTemperature(); tm1 = 300; } tm1--; delay(10); } // работа по уставкам void RunProg(){ if(h >= hum_max){ digitalWrite(0,1); // выключаем 1 GPIO 0 } if(h <= hum_min){ digitalWrite(0,0); // включаем 0 GPIO 0 } }Этими данными управляю и получаю на разных устройствах.
Спасибо! Думаю этот код ещё мне пригодится для каких либо проектов. :)
Не могли бы помочь разобраться в коде.
#include <Servo.h> // Библиотека для Servo-Мотора с регулировкой скорости #include <IRremote.h> // Библиотека для ИК приёмника byte RECV_PIN = 11; // вход ИК приемника IRrecv irrecv(RECV_PIN); // Объект ИК decode_results results; // переменные для контроля за процессом поворотов Servo bool Right_Pin_1 = false; //для ручного поворота вправо при зажатии кнопки bool Left_Pin_1 = false; //для ручного поворота влево при зажатии кнопки bool Auto_Povorot = false; //для Автоповорота при кратковременном нажатии class Sweeper { Servo servoAutoPovorot; // сервопривод int pos; // текущее положение сервы int increment; // увеличиваем перемещение на каждом шаге int updateInterval; // промежуток времени между обновлениями unsigned long lastUpdate; // последнее обновление положения public: Sweeper (int interval) { updateInterval = interval; increment = 2; // шаг приращения положения сервы pos = 90; // устанавливаем серву в среднее положение servoAutoPovorot.write(pos); } void Attach(int pin) { servoAutoPovorot.attach(pin); } void Detach() { servoAutoPovorot.detach(); } void Update() { if (((millis() - lastUpdate) > updateInterval) && (Right_Pin_1 == true)) { Left_Pin_1 = false; Auto_Povorot = false; // если время обновлять и нажата кнопка на пине 2 - увеличиваем положение сервы lastUpdate = millis(); if (pos <= 130) { pos += increment; servoAutoPovorot.write(pos); } } else if (((millis() - lastUpdate) > updateInterval) && (Left_Pin_1 == true)) { Right_Pin_1 = false; Auto_Povorot = false; // если время обновлять и нажата кнопка на пине 3 - уменьшаем положение сервы lastUpdate = millis(); if (pos >= 0) { pos -= increment; servoAutoPovorot.write(pos); } } else if ((millis() - lastUpdate) > updateInterval && (Auto_Povorot == true)) // время обновлять { Left_Pin_1 = false; Right_Pin_1 = false; lastUpdate = millis(); pos += increment; servoAutoPovorot.write(pos); if ((pos >= 130) || (pos <= 0)) // конец вращения { // обратное направление increment = -increment; } } } }; Sweeper servoAutoPovorot(35); // скорость Авто-вращения серво void setup() { irrecv.enableIRIn(); // включить ИК приёмник servoAutoPovorot.Attach(9); // для автоповоротов класса Sweeper } void loop() { servoAutoPovorot.Update(); if (irrecv.decode(&results)) { // 2 Команды с пульта отвечающие за ручные повороты Серво. if (results.value == 0xFFC23D) Right_Pin_1 = true; // Поворот Вправо if (results.value == 0xFF22DD) Left_Pin_1 = true; // Поворот Влуво if (results.value == 0xFF629D) Auto_Povorot = true; //Автоповорот вкл. if (results.value == 0xFFA857) Auto_Povorot = false; //Автоповорот откл. irrecv.resume(); // получаем следующие значения } }Я так понял: нет поддержки постоянного нажатия кнопки?
да, вот сейчас переделал код чутка в Классе Sweeper по другому. Но чёт не то всё же....
class Sweeper { VarSpeedServo servoAutoPovorot; // сервопривод int L = 0; int pos1; int pos; // текущее положение сервы int increment; // увеличиваем перемещение на каждом шаге int updateInterval; // промежуток времени между обновлениями unsigned long lastUpdate; // последнее обновление положения public: Sweeper (int interval) { updateInterval = interval; increment = 1; // шаг приращения положения сервы pos = 90; // устанавливаем серву в среднее положение servoAutoPovorot.write(pos); } void Attach(int pin) { servoAutoPovorot.attach(pin); } void Detach() { servoAutoPovorot.detach(); } void Update() { if ((millis() - lastUpdate) > updateInterval && (Auto_Povorot == true)) // время обновлять { lastUpdate = millis(); pos += increment; servoAutoPovorot.write(pos); if ((pos >= 130) || (pos <= 0)) // конец вращения { // обратное направление increment = -increment; } } if (digitalRead(RECV_PIN) == LOW) lastUpdate = millis(); if (millis() - lastUpdate > 100) (Right_Pin_1 = false), (Left_Pin_1 = false); if (Right_Pin_1 == true && L < 20000 ) L = L + increment; if (Left_Pin_1 == true && L > 0 ) L = L - increment; pos1 = L; pos1 = map(pos, 0, 20000, 1, 130); // Задаём диапазон скорости и поворота Серво (углы поворота от 1 до 130 градусов) servoAutoPovorot.write(pos1); // Положение Серво в соответствии с val_1. } }; Sweeper servoAutoPovorot(35); // скорость Авто-вращения сервоЯ бы сделал следующее: Отдельная функция проверяет нажатие кнопки (разовое или постоянное), учти, что по ИК идет не 1 постоянно, а поток знаков, которые надо делить на код или прописать как "0xFFC23D0xFFC23D0xFFC23D0xFFC23D.....". Я с таким сталкивался. В порт выведи инфу о приходе данных.
А почему именно ИК? Под такие задачи лучше RF/
У меня рабочий, почти готовый проект управления напольным вентилятором. Всё работает супер, кроме поворотов и автоповоротов вентилятора.
Для таких целей, я купил Вот такой прибор. И под него сделал: старенький холодильник, мультиварку, свет в прихожей и увлажнитель воздуха.
Есть готовый скрипт по проверке кнопок, могу выставить. Там дребезг (программно решен) и нажатие на удержание.
Добрый день.
Можете детально разжевать, как получать данные по mqtt? С отправкой проблем нет, а вот принять ничего не выходит.
например пишу "client.subscribe(relays_topic2);" и по идее теперь мне должны приходить сообщения, но куда? в какую переменную и в каком типе (char, int)?подскажите пожалуйста на каком нибудь куске кода, буду благодарен.Доброго дня. Вот простой, увлажнитель воздуха на MQTT, Но! Как показала практика, можно и в один топик кидать, лишь бы ЭХО не было. Забыл, допишу, что GPIO0 - подключет к реле, а реле к ПЛЮСУ +3,3В, если стандартно, через МИНУС, то модуль входит в режим программирования, ОН видит любой потенциал!!
// Реле подлкючен к 0 пину и к +3.3v инверсия!!! // Датчик температуры DHT11 к 2 пину #include <ESP8266WiFi.h> #include <PubSubClient.h> #include <DHT.h> #define DHTPIN 2 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); const char *ssid = "+++++"; // Имя вайфай точки доступа const char *pass = "+++++++"; // Пароль от точки доступа const char *mqtt_server = "192.198.155.155"; // Имя сервера MQTT const int mqtt_port = 16835; // Порт для подключения к серверу MQTT const char *mqtt_user = "у меня нет"; // Логи от сервер const char *mqtt_pass = "у меня нет"; // Пароль от сервера #define BUFFER_SIZE 100 bool LedState = false; int tm=300; int tmvrem=300; // минута по умолчанию int tm1=300; int autom=1; //если 0 - то ручное, если 1 - то автоматическое int hum_min = 45; //минимальная влажность int hum_max = 65; //максимальная влажность float temp=0; float h,t; // Функция получения данных от сервера void callback(const MQTT::Publish& pub){ Serial.print(pub.topic()); // выводим в сериал порт название топика Serial.print(" => "); Serial.print(pub.payload_string()); // выводим в сериал порт значение полученных данных String payload = pub.payload_string(); if(autom == 0){ if(String(pub.topic()) == "test/led") // проверяем из нужного ли нам топика пришли данные { int stled = payload.toInt(); // преобразуем полученные данные в тип integer digitalWrite(0,stled); // включаем или выключаем светодиод в зависимоти от полученных значений данных } } if(String(pub.topic()) == "test/aut1") // проверяем из нужного ли нам топика пришли данные { autom = payload.toInt(); // преобразуем полученные данные в тип integer } if(String(pub.topic()) == "test/hmin1") // проверяем из нужного ли нам топика пришли данные { hum_min = payload.toInt(); // преобразуем полученные данные в тип integer } if(String(pub.topic()) == "test/hmax1") // проверяем из нужного ли нам топика пришли данные { hum_max = payload.toInt(); // преобразуем полученные данные в тип integer } if(String(pub.topic()) == "test/vrem") // проверяем из нужного ли нам топика пришли данные { tmvrem = payload.toInt(); // преобразуем полученные данные в тип integer } } WiFiClient wclient; PubSubClient client(wclient, mqtt_server, mqtt_port); void setup() { Serial.begin(115200); delay(10); Serial.println(); Serial.println(); pinMode(0, OUTPUT); // отмечаем, что порт будет ВЫХОДОМ dht.begin(); // запускаем библиотеку датчика } void loop() { TempHum(); // показания с датчиков delay(10); if(autom == 1){ RunProg(); } // подключаемся к wi-fi if (WiFi.status() != WL_CONNECTED) { Serial.print("Connecting to "); Serial.print(ssid); Serial.println("..."); WiFi.begin(ssid, pass); if (WiFi.waitForConnectResult() != WL_CONNECTED) return; Serial.println("WiFi connected"); } // подключаемся к MQTT серверу if (WiFi.status() == WL_CONNECTED) { if (!client.connected()) { Serial.println("Connecting to MQTT server"); if (client.connect(MQTT::Connect("arduinoClient2") .set_auth(mqtt_user, mqtt_pass))) { Serial.println("Connected to MQTT server"); client.set_callback(callback); client.subscribe("test/led"); // подписывааемся по топик с данными для светодиода client.subscribe("test/aut1"); client.subscribe("test/hmin1"); client.subscribe("test/hmax1"); client.subscribe("test/vrem"); } else { Serial.println("Could not connect to MQTT server"); } } if (client.connected()){ // если есть соединение client.loop(); TempSend(); // Функция отправки показаний с термодатчика } } } // конец основного цикла // Функция отправки показаний с термодатчика void TempSend(){ if (tm==0) { h = dht.readHumidity(); t = dht.readTemperature(); // Read temperature as Celsius (the default) client.publish("test/temp",String(t)); // отправляем в топик для термодатчика значение температуры Serial.println(t); client.publish("test/hum",String(h)); // отправляем в топик для термодатчика значение влажности Serial.println(h); if(autom == 1){ client.publish("test/aut","Включена"); } if(autom == 0){ client.publish("test/aut","Выключена"); } Serial.println(autom); tm = tmvrem; // пауза меду отправками значений } tm--; delay(10); } // чтение данных с датчика, раз в 3с. void TempHum(){ if (tm1==0) { h = dht.readHumidity(); t = dht.readTemperature(); tm1 = 300; } tm1--; delay(10); } // работа по уставкам void RunProg(){ if(h >= hum_max){ digitalWrite(0,1); // выключаем 1 GPIO 0 } if(h <= hum_min){ digitalWrite(0,0); // включаем 0 GPIO 0 } }GPIO0 - подключет к реле, а реле к ПЛЮСУ +3,3В
Жестоко. У ESP выходной ток совсем малые (по памяти 6мА) а Вы к нему реле. Наверно и без обратного диода.
Да. И поверьте все работает. Нагружал до 60мА. Сейчас все работает в связке с 24В. Управление идет через 4N35 . Схема:
Реле подключал ssr-25da. Там по току и напряжению есть запас. Работает отлично - управляет: светом, вытяжкой, холодильником и т.д... :)
Сейчас брокер MQTT стоит на Orange Pi PC2
Так судя по схеме не реле к GPIO0 а оптрон подключен. Без токоограничительного резистора 8) Мрак.
///Нагружал до 60мА.
Кого Вы нагружали ;) По доке у ESP нет такого тока на выходах и близко.
Верю, Вы правы на все 100%. Для пробы и не жалости ESP, 5В реле от ардуино, просто эксепимент. А вот SSR-25 работает до сих пор, как дистанционное управление. AC-DC (3.3В) + SSR-25 +ESP01.
Так чего ж там SSR-25 не работало бы, у него входной ток 4мА при 3В. Оптрон кстати лишний во всех случаях. Для SSR-25 вобще, для "5В реле от ардуино" (че за зверь такой - ХЗ, хрустальный шар говорит что электромагнитное) заменить на транзистор.
Все просто. SSR - коммутирует только 220В переменки. А мне надо 24В постоянки. Схемотехника, такая нежная штука, что приходится учитывать все нюансы как и человеческий фактор (женские ручки дома :) ). Но это не та тема. Сейчас все перевожу на полевики.
Все просто. SSR - коммутирует только 220В переменки. А мне надо 24В постоянки.
Однофазные твердотельные реле серии SSR представлены несколькими типами:
Схемотехника, такая нежная штука, что приходится учитывать все нюансы как и человеческий фактор (женские ручки дома :) ). Но это не та тема. Сейчас все перевожу на полевики.
Что было под рукой на том и собрал. А гльваника есть, там нет общего минуса. Давай не будем углубляться в философию «споделок».Все делается из подручных материалов. А вылизывание проекта, это уже дело времени и средств.
Что было под рукой на том и собрал. А гльваника есть, там нет общего минуса.
Ага. Аж два раза )))
Схема проще не придумаешь:
https://mysku.ru/blog/aliexpress/36460.html
Давай не будем углубляться в философию «споделок».Все делается из подручных материалов. А вылизывание проекта, это уже дело времени и средств.
Причем тут философия. Просто я указал Вам на лишний элемент схемы на SSR (кстати у него внутри свой оптрон еще имеется). И на невозможность подключения электромагнитного реле напрямую к ESP за превышения тока. Здесь нужен транзисторный ключ.
Все правильно. Вы все верно написали.
Почему я пытаюсь доказать, что есть развязка. логический "0" это не прямой "-3.3В". Подключение к GPIO0 идет через +3.3В. Если использовать подключение как GPIO0 == "1" , то модуль встает в программирование и ни какое сопротивление не спасет Вас от потенциала. Да, допускаю, что ключи формирования логических "0" и "1" - это практически минус и плюс напряжения питания. Тогда встает вопрос, откуда берется ограничение тока нагрузки, от ключей управления? Да. Ну, а дальше смотрим схему микросхемы 8266.
Ладно, это лирика. MQTT - удобно и просто. С этого вопроса все и началось.
Ох и бардак в мыслях )))
Забудьте "-3.3В." их в этой схеме нет, та точка которая у Вас так названа - это 0. Она ж и логический ноль. Если бы было -3.3В то вольтмер между -3.3 и +3.3 показал бы 6.6В, это не наш случай, такое бывает называется двухполярным питанием.
И "Подключение к GPIO0 идет через +3.3В. " тоже забудьте...
Я к счастю знаком с этой проблемой не по наслышке (например http://arduino.ru/forum/apparatnye-voprosy/polzuet-li-kto-wifi-moduli-esp8266-podelites-vpechatleniyami?page=20#comment-260721 ), потому понимаю что вы стараетесь сказать.
А именно, при старте модуля необходима подтяжка GPIO0 (и GPIO2 тоже) к 1, потому чтоб управляемое устройство не срабатывало при старте из-за подтяжки оно должно быть активным по 0. Может это кому и непревычно, но вполне нормально.
ПС. заодно и тут глянте http://arduino.ru/forum/apparatnye-voprosy/polzuet-li-kto-wifi-moduli-esp8266-podelites-vpechatleniyami?page=20#comment-260968
#include <ESP8266WiFi.h> // соединяем на плате gpio16 и reset для возмоности глубокого сна(DeepSleep) #include <EEPROM.h> #include <PubSubClient.h> ///////////////настриваемые параметры////////////////////// #define Sensor 1 // номер сенсора (меняет в коде всё под этот номер) IPAddress ip(192, 168, 1, 101); // статический IP (необходимо указать для быстрого подключения к Wi-fi), меняем последнюю цифру const char *ssid = "Evgenii"; // имя домашней wi-fi сети const char *password = "66666666"; // пароль домашней wi-fi сети const char *mqtt_server = "192.168.1.100"; // адрес брокера /////////////////////////////////////////////////////////// #define SignalOut 4 // порт выходного сигнала #define SignalInput 5 // порт входного сигнала byte Number; // номер цикла byte NumberMax; // максимальный номер цикла byte NumberMaxOld; // промежуточное, для проверки изменения состояния, максимальный номер цикла long TimeSleepMicro; // протяженность сна в микросекундах (1 000 000) = 1 секунда, (небходимо для работы таймера) int TimeSleep; // протяженность сна в секундах (необходимо для передачи данных между устройствами) int TimeSleepOld; // промежуточное, для проверки изменения состояния int status = WL_IDLE_STATUS; IPAddress gateway(192, 168, 0, 1); IPAddress subnet(255, 255, 255, 0); WiFiClient espClient; PubSubClient client(espClient); //long lastMsg = 0; //char msg[50]; //int value = 0; void setup() { TimeSleep = 5; // таймер сна в секундах Number = 1; NumberMax = 1; pinMode(12, OUTPUT); // светодиод (12-зеленый) pinMode(13, OUTPUT); // светодиод (13-синий) pinMode(15, OUTPUT); // светодиод (15-красный) TimeSleepMicro = TimeSleep * 1000000; // перевод в микросекунды из секунд } void loop() { digitalWrite(13, LOW); // выключить светодиод EEPROM.begin(256); Number = EEPROM.read(1); // читаем номер цикла из энергонезависимой памяти NumberMax = EEPROM.read(2); // максимальное количестов циклов (после сбрасывается до первого) NumberMaxOld = NumberMax; // промежуточное, для проверки изменения if (NumberMax == 0) // для первого старта с длительностью сна в 1 секунду { NumberMax = 10; } TimeSleep = EEPROM.read(3); // читаем протяженность сна из энергонезависимой памяти TimeSleepOld = TimeSleep; // промежуточное, для проверки изменения if (TimeSleep == 0) // для первого старта с длительностью сна в 1 секунду { TimeSleep = 1; } NumberMax = 6; // максимальное количестов циклов (после сбрасывается до первого) Serial.begin(115200); delay(10); Serial.print("Number = "); Serial.print(Number); Serial.print("/"); Serial.println(NumberMax); //Serial.end(); digitalWrite(SignalOut, HIGH); // отправляем сигнал digitalRead(SignalInput); // принимаем сигнал if (SignalInput == HIGH || Number == 1) // если есть сигнал на контактах или если подошла очередь по циклам { //--------для визуализации, что начался цикл без сна-----------// digitalWrite(13, HIGH); // включить синий светодиод //-------------------------------------------------------------// delay(10); Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.config(ip, gateway, subnet); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } //--------для визуализации, что подключились к Wi-Fi-----------// digitalWrite(13, LOW); // выключить синий светодиод digitalWrite(12, HIGH); // включить зеленый светодиод, если подключились //-------------------------------------------------------------// Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); //--------------MQTT-------------------------------------------// client.setServer(mqtt_server, 1883); // подключение по MQTT while (!client.connected()) // если не подключились, то повторяем каждые 2 секунды { Serial.print("Attempting MQTT connection..."); // String clientId = "Sensor-1"; String clientId = "Sensor-"; clientId += Sensor; // присвоение ID для клиента MQTT*/ /* String clientId = "ESP8266Client-"; clientId += String(random(0xffff), HEX); // присвоение случайного ID для клиента MQTT*/ if (client.connect(clientId.c_str())) { Serial.println("connected"); char char_Number[10]; // Переменная для перевода из в char dtostrf(Number, 3, 0, char_Number); // Перевод в char client.publish("/Sensor1", char_Number); // отправка по MQTT сообщения // char Input; // client.subscribe("/Sensor1/NumberMax", Input ); // проверка входящих по MQTT сообщений // Serial.print("Input"); // Serial.println(Input); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 2 seconds"); delay(2000); } } //-----------------------------------// delay(3000); WiFi.disconnect(); // отключаем Wi-fi } //------------Работа с циклами-----------------// Number = Number + 1; // увеличиваем цикл на 1 if (Number > NumberMax) // если номер цикла стал выше чем максимальный, то сбрасываем цикл до первого { Number = 1; } EEPROM.write(1, Number); // записываем номер цикла в энергонезависимую память //EEPROM.commit(); //EEPROM.end(); if (NumberMax != NumberMaxOld) // если значение максимального номера цикла сменилось, то записываем новое значение в память (необходимо для работы смены дистанционно) { EEPROM.write(2, NumberMax); //EEPROM.commit(); //EEPROM.end(); } if (TimeSleep != TimeSleepOld) // если значение таймера сна сменились с начала цикла, то записываем новое значение в память (необходимо для работы смены дистанционно) { EEPROM.write(3, TimeSleep); //EEPROM.commit(); //EEPROM.end(); } EEPROM.commit(); EEPROM.end(); //--------Визуализация, что конец цикла----// digitalWrite(12, LOW); // выключить зеленый светодиод digitalWrite(15, HIGH); // включить красный светодиод //-----------------------------------------// delay(1000); digitalWrite(15, LOW); // выключить красный светодиод //ESP.deepSleep(TimeSleepMicro); //уснуть на величину таймера сна (в микросекундах) (1 000 000) = 1 секунда, }В строках:
if (client.connect(clientId.c_str())) { Serial.println("connected"); char char_Number[10]; // Переменная для перевода из в char dtostrf(Number, 3, 0, char_Number); // Перевод в char client.publish("/Sensor1", char_Number); // отправка по MQTT сообщения // char Input; // client.subscribe("/Sensor1/NumberMax", Input ); // проверка входящих по MQTT сообщений // Serial.print("Input"); // Serial.println(Input);первая часть кода с отправкой работает (отправляет на сервер нормально), а то что закомментированана нет (не принимает с сервера), подскажите, что я не так делаю?
Может я с утра слеповат. А где сама функция по приему топика. В 16 топике посмотрите.
if (client.connect(MQTT::Connect("arduinoClient2")По
voidcallback(constMQTT::Publish& pub){Можете подробнее расписать?
я никак не пойму как устроена библиотека pubsubclient.h на получение данных.
Отправить данные проблем не возникает, но вот получить никак не выходит.
Помогите, пожалуйста.
вставляю этот Ваш код
// Функция получения данных от сервера void callback(const MQTT::Publish& pub){ Serial.print(pub.topic()); // выводим в сериал порт название топика Serial.print(" => "); Serial.print(pub.payload_string()); // выводим в сериал порт значение полученных данных String payload = pub.payload_string(); }и получаю море ошибок компиляции
Вот тут есть видео, можно посмотреть и сразу все понять.
Добрый день. Помогите пожалуйста разобраться. Использую gprs модем А6 и uno. Хочу включать и выключать светодиод через mqtt клиент. Соединение настраиваю, подключаюсь к нету, к mqtt серверу - тут проблем нет. Но когда отправляю "1" происходит постоянное включение-выключение светодиода (моргает), в клиенте на телефоне отображается постоянное переключение с"1" на "0". Прошу помощи! Вторую неделю бьюсь, а результата нет.
#define TINY_GSM_MODEM_A6 #include <TinyGsmClient.h> #include <PubSubClient.h> // Your GPRS credentials // Leave empty, if missing user or pass const char apn[] = "***"; const char user[] = "***"; const char pass[] = "***"; #include <SoftwareSerial.h> SoftwareSerial SerialAT(2, 3); // RX, TX const char* mqtt_server = "***"; const int mqtt_port = ***; // Порт для подключения к серверу MQTT const char *mqtt_user = "***"; // Логин от сервер const char *mqtt_pass = "***"; // Пароль const char* id = "Mytest"; const char* topicMyled = "Mytest/Myled"; #define BUFFER_SIZE 100 const uint8_t LED_PIN = 12; int ledStatus = LOW; TinyGsm modem(SerialAT); TinyGsmClient client(modem); PubSubClient mqtt(client); void setup() { Serial.begin(9600); delay(10); Serial.println(); Serial.println(); pinMode(12, OUTPUT); // Set console baud rate Serial.begin(9600); delay(10); // Set GSM module baud rate SerialAT.begin(9600); delay(3000); // Restart takes quite some time // To skip it, call init() instead of restart() Serial.println("Initializing modem..."); modem.restart(); String modemInfo = modem.getModemInfo(); Serial.print("Modem: "); Serial.println(modemInfo); // Unlock your SIM card with a PIN //modem.simUnlock("1234"); Serial.print("Waiting for network..."); if (!modem.waitForNetwork()) { Serial.println(" fail"); modem.restart(); while (true); } Serial.println(" OK"); Serial.print("Connecting to "); Serial.print(apn); if (!modem.gprsConnect(apn, user, pass)) { Serial.println(" fail"); while (true); } Serial.println(" OK"); // MQTT Broker setup mqtt.setServer(mqtt_server, mqtt_port); mqtt.setCallback(mqttCallback); if (!mqtt.connect(id, mqtt_user, mqtt_pass)) { Serial.println(" fail"); return false; } Serial.println(" OK"); mqtt.subscribe(topicMyled ); return mqtt.connected(); if (!mqtt.connect("Mytest")) { Serial.println("Connected to MQTT server"); mqtt.setCallback(mqttCallback); mqtt.subscribe("Mytest/Myled"); // подписывааемся по топик с данными для светодиода } else { Serial.println("Could not connect to MQTT server"); } } //Функция получения данных от сервера void mqttCallback(char* topic, byte* payload, unsigned int len) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("]: "); Serial.write(payload, len); Serial.println(); // управляем диодом if (mqtt.publish(topicMyled, ledStatus = "1")) { digitalWrite(LED_PIN, HIGH); } if (mqtt.publish(topicMyled, ledStatus = "0")) { digitalWrite(LED_PIN, LOW); } } void loop() { if (mqtt.connected()) { mqtt.loop(); } }Делай разный топик. Mytest/Myled - отправить а Mytest/Myled1 - принять, А так, у тебя цикл, время которого исчисляется запросом к брокеру.
Или, можно попробовать, без сохранения данных на брокере.
Спасибо! сегодня вечером попробую.
P.S. попытался. получилось.Спасибо за помощь!
ZhenyaRUS39, добрый день. Точно такая же проблема. Вам удалось ее побороть? Грешу на разные библиотеки pubsubclient.h.
ZhenyaRUS39, добрый день. Точно такая же проблема. Вам удалось ее побороть? Грешу на разные библиотеки pubsubclient.h.
Такой мой код работает: /* плата ESP8266 "Witty Cloud" Заставляем плату "спать" и просыпаться раз в заданный период времени (TimeSleep). Пускаем сигнал по однойму порту и пытаемся его принять на другом: а) если сигнала нет, то засыпаем снова. б) если количество циклов сна (Number) достигло выставленного значения (NumberMax, но по факту первого), то подключаемся по Wi-Fi к домашней сети и по MQTT отправляем своё состояние и заряд батареи на сервер, и принимаем с записью в EEPROM (если изменились) значения для NumberMax, TimeSleep. . в) если сигнал есть, то подключаемся по Wi-Fi к домашней сети и по MQTT отправляем своё состояние и заряд батареи на сервер и проверяем значения для NumberMax, TimeSleep. */ #include <ESP8266WiFi.h> #include <PubSubClient.h> #include <EEPROM.h> //IPAddress ip(192, 168, 1, 101); // статический IP (необходимо указать для быстрого подключения к Wi-fi), меняем последнюю цифру const char *ssid = "Evgenii"; // Имя вайфай точки доступа const char *pass = "66666666"; // Пароль от точки доступа const char *mqtt_server = "192.168.1.218"; // Имя сервера MQTT const int mqtt_port = 1883; // Порт для подключения к серверу MQTT const char *mqtt_user = ""; // Логин от сервер const char *mqtt_pass = ""; // Пароль от сервера #define SignalOut 4 // порт выходного сигнала #define SignalInput 5 // порт входного сигнала byte Number; // номер цикла byte NumberMax; // максимальный номер цикла byte NumberMaxOld; // промежуточное, для проверки изменения состояния, максимальный номер цикла long TimeSleepMicro; // протяженность сна в микросекундах (1 000 000) = 1 секунда, (небходимо для работы таймера) int TimeSleep; // протяженность сна в секундах (необходимо для передачи данных между устройствами) int TimeSleepOld; // промежуточное, для проверки изменения состояния int status = WL_IDLE_STATUS; int STATUS_WORK = 0; // промежуточное, для проверки изменения состояния (что настал рабочий цикл) int stledG; // Переменные для MQTT int payloadG; int stledR; int payloadR; int stledB; int payloadB; // Функция получения данных от сервера void callback(const MQTT::Publish& pub) { Serial.print(pub.topic()); // выводим в сериал порт название топика Serial.print(" => "); Serial.println(pub.payload_string()); // выводим в сериал порт значение полученных данных String payloadG = pub.payload_string(); // записываем в переменную полученные из MQTT значения String payloadR = pub.payload_string(); String payloadB = pub.payload_string(); if (String(pub.topic()) == "/test/ledG") // проверяем из нужного ли нам топика пришли данные { int stledG = payloadG.toInt(); // преобразуем полученные данные в тип integer digitalWrite(12, stledG); // включаем или выключаем светодиод в зависимоти от полученных значений данных } if (String(pub.topic()) == "/test/ledR") // проверяем из нужного ли нам топика пришли данные { int stledR = payloadR.toInt(); // преобразуем полученные данные в тип integer digitalWrite(15, stledR); // включаем или выключаем светодиод в зависимоти от полученных значений данных } if (String(pub.topic()) == "/test/ledB") // проверяем из нужного ли нам топика пришли данные { int stledB = payloadB.toInt(); // преобразуем полученные данные в тип integer digitalWrite(13, stledB); // включаем или выключаем светодиод в зависимоти от полученных значений данных } } WiFiClient wclient; PubSubClient client(wclient, mqtt_server, mqtt_port); void setup() { Serial.begin(115200); delay(10); Serial.println(); Serial.println(); pinMode(12, OUTPUT); // светодиод (12-зеленый) pinMode(13, OUTPUT); // светодиод (13-синий) pinMode(15, OUTPUT); // светодиод (15-красный) } void loop() { EEPROM.begin(256); Number = EEPROM.read(1); // читаем номер цикла из энергонезависимой памяти NumberMax = EEPROM.read(2); // максимальное количестов циклов (после сбрасывается до первого) NumberMaxOld = NumberMax; // промежуточное, для проверки изменения if (NumberMax == 0) // для первого старта с длительностью сна в 1 секунду { NumberMax = 10; } TimeSleep = EEPROM.read(3); // читаем протяженность сна из энергонезависимой памяти TimeSleepOld = TimeSleep; // промежуточное, для проверки изменения if (TimeSleep == 0) // для первого старта с длительностью сна в 1 секунду { TimeSleep = 1; } NumberMax = 6; // максимальное количестов циклов (после сбрасывается до первого) delay(10); Serial.print("Number = "); Serial.print(Number); Serial.print("/"); Serial.println(NumberMax); // выводим в мониторинг максимальное количестов циклов (после сбрасывается до первого) if (SignalInput == HIGH || Number == 1) // если есть сигнал на контактах или если подошла очередь по циклам { // STATUS_WORK = 1; // if (STATUS_WORK == 1) // если есть сигнал на контактах или если подошла очередь по циклам // подключаемся к wi-fi if (WiFi.status() != WL_CONNECTED) { Serial.print("Connecting to "); Serial.print(ssid); Serial.println("..."); WiFi.begin(ssid, pass); if (WiFi.waitForConnectResult() != WL_CONNECTED) return; Serial.println("WiFi connected"); } // подключаемся к MQTT серверу if (WiFi.status() == WL_CONNECTED) { if (!client.connected()) { Serial.println("Connecting to MQTT server"); if (client.connect(MQTT::Connect("arduinoClient2") .set_auth(mqtt_user, mqtt_pass))) { Serial.println("Connected to MQTT server"); client.publish("/Sensor1", "1"); // отправка по MQTT сообщения Serial.print("Send:"); Serial.println("1"); client.set_callback(callback); client.subscribe("test/ledG"); // подписывааемся по топик с данными для светодиода client.subscribe("test/ledR"); // подписывааемся по топик с данными для светодиода client.subscribe("test/ledB"); // подписывааемся по топик с данными для светодиода client.loop(); } else { Serial.println("Could not connect to MQTT server"); } } delay(3000); WiFi.disconnect(); // отключаем Wi-fi if (client.connected()) { client.loop(); } } } Number = Number + 1; // увеличиваем цикл на 1 if (Number > NumberMax) // если номер цикла стал выше чем максимальный, то сбрасываем цикл до первого { Number = 1; } EEPROM.write(1, Number); // записываем номер цикла в энергонезависимую память //EEPROM.commit(); //EEPROM.end(); if (NumberMax != NumberMaxOld) // если значение максимального номера цикла сменилось, то записываем новое значение в память (необходимо для работы смены дистанционно) { EEPROM.write(2, NumberMax); //EEPROM.commit(); //EEPROM.end(); } if (TimeSleep != TimeSleepOld) // если значение таймера сна сменились с начала цикла, то записываем новое значение в память (необходимо для работы смены дистанционно) { EEPROM.write(3, TimeSleep); //EEPROM.commit(); //EEPROM.end(); } EEPROM.commit(); EEPROM.end(); delay(1000); STATUS_WORK = 0; } // конец основного циклаА какую библиотеку pubsubclient использовали? Их существует две, причем разных версий. Ту, что через менеджер библиотек подключается?
Charly_big - не советую повторять код из предыдущего сообщения, он кривой и даже более - код опасен для контроллера.
ZhenyaRUS39 - в коде куча ошибок, не надо его никому советовать.
Вот это вообще феерично: в 96 строке вы читаете Number из ЕПРОМ. В строке 111 безальтернативно приравниваете его шести (спрашивается, зачем тогда читали из памяти?). В строке 173 прибавляете к Number единицу, записываете в ЕПРОМ (на каждом цикле? - офигели?!) но потом loop кончается и снова переходит к началу. И снова сначала читаем из ЕПРОМ, выкидываем это значение, выставляем Number = 6 и тд...
Евгений, Вы хоть чуть-чуть логику кода понимаете? или вы его тупо списали где-то в инете? Мало того, что в каждом прогоне loop у Вас Number всегда 6. так еще вы на каждом лупе пишете в его ЕПРОМ. Вы в курсе, что ресурс записи в ЕПРОМ совсем небольшой? Если прикинуть, что у вас проход основного цикла занимает около 4х секунд - значит при ресурсе ЕПРОМ 100 000 записей ваш ЕПРОМ может начать глючить уже на пятые сутки.
Решил проблему. Дело было в библиотеке. Скачал рабочий скетч и библиотеку по ссылке под видео https://youtu.be/q36C4rYAKVA
Полностью согласен с b707 . Только загубит память еще быстрее, НА СТАДИИ ОТЛАДКИ :-) . Если и хранить данные, то есть 4 метра для этого. Создайте файлик текстовый, туда и звписывайте. А если в лом, то используя MQTT, можно и в самом брокере - но это извращение, но как пример - можно.
Этот код сюда вставлен только для показа взаимодействия в области MQTT (вопрос был об этом).
Код не завершен. Запись в EPROM нужна т.к. это будет устройство, которое будет засыпать и просыпаться раз в 20 минут прогнять цикл и снова спать(а т.к. во время сна на контроллере не будет питания, то единственно место записи EPROM), и лишь на 6й цикл просыпания будет подключаться к Wi-fi для обмена данных сервером.
Создавать файл и записывать и читать с него я не умею.
Если есть примеры опысывающие, как записывать в файл в память, то прошу поделиться.
Если есть примеры опысывающие, как записывать в файл в память, то прошу поделиться.
Примеры есть в примерах Arduino IDE - открываете среду, идёте в пункт меню "Примеры" и - там примеры!
Создавать файл и записывать и читать с него я не умею.
Читать-то вы, надеюсь, умеете? Прочитайте ЕЩЕ РАЗ то что я вам написал. Во-первых - в вашем коде ВСЕГДА шестой цикл. Во-вторых - я вам обяснил, почему НЕЛЬЗЯ постоянно писать в ЕЕПРОМ. Тем более, что вы пишете туда ошибочные данные. В=третьих и в четвертых - вы, видимо, вообще крайне слабо представляете себе, как пишутся программы на ардуино - при засыпании контроллера на нем остается питание и данные в еепром писать необязательно, и в ЕЕПРОМ не пишут файлы!!!!
...и в ЕЕПРОМ не пишут файлы!!!!
А вот интересно, почему?
А то у меня тут как раз появилсь идея создать в EEPROM простенькую файловую систему.
...и в ЕЕПРОМ не пишут файлы!!!!
А вот интересно, почему?
А то у меня тут как раз появилсь идея создать в EEPROM простенькую файловую систему.
Доброго дня. Можно конечно сделать всё. А как же ресурс железяки. Надо и даташит читать. Раз идет тема про MQTT, а следовательно о ESP8266 (пока), то к ней незря приклеили 4 метра памяти. На ней хранить можно и файловую систему делать, но посточнная запись (не чтение) то же убийственна. Один из долговечных инструментов - CD карточка. Но и она может через годик сдохнуть. (Есть опыт с SQL - постоянный опрос и запись данных).
...ЕЕПРОМ...
Можно конечно сделать всё. А как же ресурс железяки... Один из долговечных инструментов - CD карточка. Но и она может через годик сдохнуть.
Вообщето ресурс EEPROM где-то на порядок больше ресурса flash. (если, конечно, имелась в виду SD, у CD ресурс еще меньше)
С учетом, что стоит 25q32fvsig, в даташите - W25Q32: 32 Мбит/4 Мбайт (4,194,304) .... До 100 тыс. циклов стирания/записи
PS - хотя по ДАТАШИТ написано, что БОЛЕЕ "More than 100,000 erase/program cycles"