Управление Реле по MQTT на Arduino

Otto
Offline
Зарегистрирован: 26.06.2016

Такая проблема, работаю над скетчем для 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();
}

 

Otto
Offline
Зарегистрирован: 26.06.2016

Переделал скетч, стали кнопки теперь работать, но вот как управлять по 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();

 
}

 

a5021
Offline
Зарегистрирован: 07.07.2013

Мало кому будет интересно копаться в длинных портянках, выискивая ваши ошибки. Если что-то не работает, локализуйте проблемный участок до нескольких строк, снабжайте код всеми необходимым пояснениями и только в таком виде формулируйте вопрос.

andreibabrou
Offline
Зарегистрирован: 16.09.2016

Тоже долго мучаюсь. Ты не закончил код? может поделишься ?

Otto
Offline
Зарегистрирован: 26.06.2016

Отбросил эту идею, т.к. это накладно обходится: ардуино + Ethernet шилд + тянуть везде по дому витую пару.
Решил сделать по Wi-Fi через ESP8266, это дешевле и удобнее.
Но некоторые проекты именно через Arduino решил сделать.

alexeko
Offline
Зарегистрирован: 03.01.2014

Доброго дня. Я пошел по иному пути. Вот Код.

// Реле подлкючен к 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
  }
}

 

alexeko
Offline
Зарегистрирован: 03.01.2014

Этими данными управляю и получаю на разных устройствах.

Otto
Offline
Зарегистрирован: 26.06.2016

Спасибо! Думаю этот код ещё мне пригодится для каких либо проектов. :)

Otto
Offline
Зарегистрирован: 26.06.2016

Не могли бы помочь разобраться в коде.

Переделал дешёвый вентилятор за 300 руб. Сделал и и отладил код отвечающий за включение любого из 3-х режимов скорости и авто отключения по таймеру через ИК пульт. Изменил механизм поворота вентилятора, сделал повороты через servo с ИК пульта. Реализовал функционал: при коротком нажатии на кнопку №1 пульта серво будет непрерывно медленно вращаться влево-вправо, при нажатии другой кнопки №2 servo остановится (Ваш код выше отлично справляется с этим). А вот добавить в него ещё одну возможность не получается: при долгом зажатии кнопки №3(влево) servo должен медленно вращаться до упора Влево или пока не отпустишь кнопку пульта, тоже самое в правую сторону....
 
Где то напутал в функции: void Update()
Вот сам полурабочий код:
#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(); // получаем следующие значения
  }
}

 

 

alexeko
Offline
Зарегистрирован: 03.01.2014

Я так понял: нет поддержки постоянного нажатия кнопки? 

Otto
Offline
Зарегистрирован: 26.06.2016

да, вот сейчас переделал код чутка в Классе 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);  // скорость Авто-вращения серво

 

alexeko
Offline
Зарегистрирован: 03.01.2014

Я бы сделал следующее: Отдельная функция проверяет нажатие кнопки (разовое или постоянное), учти, что по ИК идет не 1 постоянно, а поток знаков, которые надо делить на код или прописать как "0xFFC23D0xFFC23D0xFFC23D0xFFC23D.....". Я с таким сталкивался. В порт выведи инфу о приходе данных.

alexeko
Offline
Зарегистрирован: 03.01.2014

А почему именно ИК? Под такие задачи лучше RF/

Otto
Offline
Зарегистрирован: 26.06.2016

У меня рабочий, почти готовый проект управления напольным вентилятором. Всё работает супер, кроме поворотов и автоповоротов вентилятора.

alexeko
Offline
Зарегистрирован: 03.01.2014

Для таких целей, я купил Вот такой прибор. И под него сделал: старенький холодильник, мультиварку, свет в прихожей и увлажнитель воздуха. 

Есть готовый скрипт по проверке кнопок, могу выставить. Там дребезг (программно решен) и нажатие на удержание.

Zhenya88
Offline
Зарегистрирован: 02.10.2016

Добрый день.

Можете детально разжевать, как получать данные по mqtt? С отправкой проблем нет, а вот принять ничего не выходит.

например пишу "client.subscribe(relays_topic2);" и по идее теперь мне должны приходить сообщения, но куда? в какую переменную и в каком типе (char, int)?

подскажите пожалуйста на каком нибудь куске кода, буду благодарен.

alexeko
Offline
Зарегистрирован: 03.01.2014

Доброго дня. Вот простой, увлажнитель воздуха на 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
  }
}

 

Logik
Offline
Зарегистрирован: 05.08.2014

alexeko пишет:

 GPIO0 - подключет к реле, а реле к ПЛЮСУ +3,3В

Жестоко. У ESP выходной ток совсем малые (по памяти 6мА) а Вы к нему реле. Наверно и без обратного диода.

alexeko
Offline
Зарегистрирован: 03.01.2014

Да. И поверьте все работает. Нагружал до 60мА. Сейчас все работает в связке с 24В. Управление идет через 4N35 . Схема:Схема соединения

alexeko
Offline
Зарегистрирован: 03.01.2014

Реле подключал ssr-25da. Там по току и напряжению есть запас. Работает отлично - управляет: светом, вытяжкой, холодильником и т.д... :)

Сейчас брокер MQTT стоит на Orange Pi PC2

Logik
Offline
Зарегистрирован: 05.08.2014

Так судя по схеме не реле к GPIO0 а оптрон подключен. Без токоограничительного резистора 8) Мрак.

///Нагружал до 60мА. 

Кого Вы нагружали ;) По доке у ESP нет такого тока на выходах и близко.

alexeko
Offline
Зарегистрирован: 03.01.2014

Верю, Вы правы на все 100%. Для пробы и не жалости ESP,  5В реле от ардуино, просто эксепимент. А вот SSR-25 работает до сих пор, как дистанционное управление. AC-DC (3.3В) + SSR-25 +ESP01. 

Logik
Offline
Зарегистрирован: 05.08.2014

Так чего ж там SSR-25  не работало бы, у него входной ток 4мА при 3В. Оптрон кстати лишний во всех случаях. Для SSR-25 вобще, для  "5В реле от ардуино" (че за зверь такой - ХЗ, хрустальный шар говорит что электромагнитное) заменить на транзистор.

alexeko
Offline
Зарегистрирован: 03.01.2014

Все просто. SSR - коммутирует только 220В переменки. А мне надо 24В постоянки. Схемотехника, такая нежная штука, что приходится учитывать все нюансы как и человеческий фактор (женские ручки дома :) ). Но это не та тема. Сейчас все перевожу на полевики.

Logik
Offline
Зарегистрирован: 05.08.2014

alexeko пишет:

Все просто. SSR - коммутирует только 220В переменки. А мне надо 24В постоянки. 

Там какие хош есть.

Однофазные твердотельные реле серии SSR представлены несколькими типами:

  • SSR-××DA – реле DC-AC типа
  • SSR-××AA – реле AC-AC и DC-DC типа
  • SSR-××VA – реле VR-AC с регулировкой выходного напряжения
  • SSR-××LA – линейные реле с регулировкой выходного напряжения

alexeko пишет:

Схемотехника, такая нежная штука, что приходится учитывать все нюансы как и человеческий фактор (женские ручки дома :) ). Но это не та тема. Сейчас все перевожу на полевики.

Оптрон  на человеческий фактор  не влияет. Там нет гальваноразвязки изи за того, что обозначено как "DC-DC". Он сильно похож на импульсный понижающий стабилизатор из китая;) Там земля общая, что в целом даже хороше, но гальваноразвязки нет, а следовательно и оптрон нафиг не нужен.

alexeko
Offline
Зарегистрирован: 03.01.2014

Что было под рукой на том и собрал. А гльваника есть, там нет общего минуса. Давай не будем углубляться в философию «споделок».Все делается из подручных материалов. А вылизывание проекта, это уже дело времени и средств.

 

Logik
Offline
Зарегистрирован: 05.08.2014

alexeko пишет:

Что было под рукой на том и собрал. А гльваника есть, там нет общего минуса. 

Ага. Аж два раза )))

 
04cc41.jpg....



Схема проще не придумаешь:
 

8f0fdb.jpg

https://mysku.ru/blog/aliexpress/36460.html

Где гальваноразвязка?! С помощю тестера это легко проверяется, Вы и сами можете сделать.
 

alexeko пишет:

Давай не будем углубляться в философию «споделок».Все делается из подручных материалов. А вылизывание проекта, это уже дело времени и средств.

 

 

Причем тут философия. Просто я указал Вам на лишний элемент схемы на SSR (кстати у него внутри свой оптрон еще имеется). И на невозможность подключения электромагнитного реле напрямую к ESP за превышения тока. Здесь нужен транзисторный ключ.

 

alexeko
Offline
Зарегистрирован: 03.01.2014

Все правильно. Вы все верно написали. 

Почему я пытаюсь доказать, что есть развязка. логический "0" это не прямой "-3.3В". Подключение к GPIO0 идет через +3.3В. Если использовать подключение как GPIO0 == "1" , то модуль встает в программирование и ни какое сопротивление не спасет Вас от потенциала. Да, допускаю, что ключи формирования логических "0" и "1" - это практически минус и плюс напряжения питания. Тогда встает вопрос, откуда берется ограничение тока нагрузки, от ключей управления? Да. Ну, а дальше смотрим схему микросхемы 8266. 

Ладно, это лирика. MQTT - удобно и просто. С этого вопроса все и началось.

Logik
Offline
Зарегистрирован: 05.08.2014

Ох и бардак в мыслях )))

Забудьте "-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

ZhenyaRUS39
Offline
Зарегистрирован: 08.10.2015
#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);       

  

первая часть кода с отправкой работает (отправляет на сервер нормально), а то что закомментированана нет (не принимает с сервера), подскажите, что я не так делаю?

alexeko
Offline
Зарегистрирован: 03.01.2014

Может я с утра слеповат. А где сама функция по приему топика. В 16 топике посмотрите.

if (client.connect(MQTT::Connect("arduinoClient2")

По

void callback(const MQTT::Publish& pub){

ZhenyaRUS39
Offline
Зарегистрирован: 08.10.2015

Можете подробнее расписать?

я никак не пойму как устроена библиотека pubsubclient.h на получение данных.

Отправить данные проблем не возникает, но вот получить никак не выходит.

Помогите, пожалуйста.

вставляю этот Ваш код

// Функция получения данных от сервера
void callback(const MQTT::Publish& pub){
  Serial.print(pub.topic());   // выводим в сериал порт название топика
  Serial.print(" => ");
  Serial.print(pub.payload_string()); // выводим в сериал порт значение полученных данных
   
  String payload = pub.payload_string();
   }

и получаю море ошибок компиляции

alexeko
Offline
Зарегистрирован: 03.01.2014
Olegator607
Offline
Зарегистрирован: 26.09.2017

Добрый день. Помогите пожалуйста разобраться. Использую 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();
    
  } 
}
alexeko
Offline
Зарегистрирован: 03.01.2014

Делай разный топик.    Mytest/Myled - отправить  а Mytest/Myled1 - принять,   А так, у тебя цикл, время которого исчисляется запросом к брокеру.

Или, можно попробовать, без сохранения данных на брокере.

Olegator607
Offline
Зарегистрирован: 26.09.2017

Спасибо! сегодня вечером попробую.

P.S. попытался. получилось.Спасибо за помощь!

Charly_big
Offline
Зарегистрирован: 03.12.2017

ZhenyaRUS39, добрый день. Точно такая же проблема. Вам удалось ее побороть? Грешу на разные библиотеки pubsubclient.h.

Charly_big
Offline
Зарегистрирован: 03.12.2017

ZhenyaRUS39, добрый день. Точно такая же проблема. Вам удалось ее побороть? Грешу на разные библиотеки pubsubclient.h.

ZhenyaRUS39
Offline
Зарегистрирован: 08.10.2015
Такой мой код работает:

/* плата 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;
} // конец основного цикла

 

Charly_big
Offline
Зарегистрирован: 03.12.2017

А какую библиотеку pubsubclient использовали? Их существует две, причем разных версий. Ту, что через менеджер библиотек подключается?

b707
Offline
Зарегистрирован: 26.05.2017

Charly_big - не советую повторять код из предыдущего сообщения, он кривой и даже более - код опасен для контроллера.

ZhenyaRUS39 - в коде куча ошибок, не надо его никому советовать.

Вот это вообще феерично: в 96 строке вы читаете Number из ЕПРОМ. В строке 111 безальтернативно приравниваете его шести (спрашивается, зачем тогда читали из памяти?). В строке 173 прибавляете к Number единицу, записываете в ЕПРОМ (на каждом цикле? - офигели?!) но потом loop кончается и снова переходит к началу. И снова сначала читаем из ЕПРОМ, выкидываем это значение, выставляем Number = 6 и тд...

Евгений, Вы хоть чуть-чуть логику кода понимаете? или вы его тупо списали где-то в инете? Мало того, что в каждом прогоне loop у Вас Number всегда 6. так еще вы на каждом лупе пишете в его ЕПРОМ. Вы в курсе, что ресурс записи в ЕПРОМ совсем небольшой? Если прикинуть, что у вас проход основного цикла занимает около 4х секунд - значит при ресурсе ЕПРОМ 100 000 записей ваш ЕПРОМ может начать глючить уже на пятые сутки.

 

 

 

Charly_big
Offline
Зарегистрирован: 03.12.2017

Решил проблему. Дело было в библиотеке. Скачал рабочий скетч и библиотеку по ссылке под видео https://youtu.be/q36C4rYAKVA

alexeko
Offline
Зарегистрирован: 03.01.2014

Полностью согласен с b707 . Только загубит память еще быстрее, НА СТАДИИ ОТЛАДКИ :-) . Если и хранить данные, то есть 4 метра для этого. Создайте файлик текстовый, туда и звписывайте. А если в лом, то используя MQTT, можно и в самом брокере - но это извращение, но как пример - можно.  

ZhenyaRUS39
Offline
Зарегистрирован: 08.10.2015

Этот код сюда вставлен только для показа взаимодействия в области MQTT (вопрос был об этом).

Код не завершен. Запись в EPROM нужна т.к. это будет устройство, которое будет засыпать и просыпаться раз в 20 минут прогнять цикл и снова спать(а т.к. во время сна на контроллере не будет питания, то единственно место записи EPROM), и лишь на 6й цикл просыпания будет подключаться к Wi-fi для обмена данных сервером.

Создавать файл и записывать и читать с него я не умею.

 

ZhenyaRUS39
Offline
Зарегистрирован: 08.10.2015

Если есть примеры опысывающие, как записывать в файл в память, то прошу поделиться.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

ZhenyaRUS39 пишет:

Если есть примеры опысывающие, как записывать в файл в память, то прошу поделиться.

Примеры есть в примерах Arduino IDE - открываете среду, идёте в пункт меню "Примеры" и - там примеры!

b707
Offline
Зарегистрирован: 26.05.2017

ZhenyaRUS39 пишет:

Создавать файл и записывать и читать с него я не умею.

Читать-то вы, надеюсь, умеете? Прочитайте ЕЩЕ РАЗ то что я вам написал. Во-первых - в вашем коде ВСЕГДА шестой цикл. Во-вторых - я вам обяснил, почему НЕЛЬЗЯ постоянно писать в ЕЕПРОМ. Тем более, что вы пишете туда ошибочные данные. В=третьих и в четвертых - вы, видимо, вообще крайне слабо представляете себе, как пишутся программы на ардуино - при засыпании контроллера на нем остается питание и данные в еепром писать необязательно, и в ЕЕПРОМ не пишут файлы!!!!

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

b707 пишет:

...и в ЕЕПРОМ не пишут файлы!!!!

А вот интересно, почему?

А то у меня тут как раз появилсь идея создать в EEPROM простенькую файловую систему.

alexeko
Offline
Зарегистрирован: 03.01.2014

andriano пишет:

b707 пишет:

...и в ЕЕПРОМ не пишут файлы!!!!

А вот интересно, почему?

А то у меня тут как раз появилсь идея создать в EEPROM простенькую файловую систему.

Доброго дня. Можно конечно сделать всё. А как же ресурс железяки. Надо и даташит читать. Раз идет тема про MQTT, а следовательно о ESP8266 (пока), то к ней незря приклеили 4 метра памяти. На ней хранить можно и файловую систему делать, но посточнная запись (не чтение) то же убийственна. Один из долговечных инструментов - CD карточка. Но и она может через годик сдохнуть. (Есть опыт с SQL - постоянный опрос и запись данных).

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

alexeko пишет:

...ЕЕПРОМ...

Можно конечно сделать всё. А как же ресурс железяки... Один из долговечных инструментов - CD карточка. Но и она может через годик сдохнуть.

Вообщето ресурс EEPROM где-то на порядок больше ресурса flash. (если, конечно, имелась в виду SD, у CD ресурс еще меньше)

alexeko
Offline
Зарегистрирован: 03.01.2014

С учетом, что стоит 25q32fvsig, в даташите  - W25Q32: 32 Мбит/4 Мбайт (4,194,304) .... До 100 тыс. циклов стирания/записи

PS - хотя по ДАТАШИТ написано, что БОЛЕЕ "More than 100,000 erase/program cycles"