ioBroker: переменный топик

Rustzi50
Offline
Зарегистрирован: 14.01.2020

Братья по разуму! 

Можете помочь, не могу сделать переменный топик для ioBroker, (их у меня 28 шт. только для света)

//Функция обработки входящих соединений - прием данных по подписке
void callback(char* topic, byte* payload, unsigned int length)
{  //преобразуем тему(topic) и значение (payload) в строку
  payload[length] = '\0';
  String strTopic = String(topic);
  String strPayload = String((char*)payload);
  //Чтение статусов
  for (i = 0; i < 28; i++){   //цикл 1
      String Index= String(i, DEC); 
      String  Stsv = String("svet/stsv" +  Index);
   
      if (strTopic == Stsv)  {  // управление  светом
          stsv[i] = strPayload.toInt();
       digitalWrite(led[i], stsv[i]);
          tmr[i] = millis(); }
 
                        } // конец цикла                                                                                                                                                                                              
}//end void callback

выдает ошибку: invalid types 'byte {aka unsigned char}[byte {aka unsigned char}]' for array subscript

переменная i в начале скетча обозначена как байт

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Мда...

b707
Онлайн
Зарегистрирован: 26.05.2017

DetSimen пишет:

Мда...

эт точно. хотел что-то поумнее написать - но тут иначе и не скажешь :)

rkit
Offline
Зарегистрирован: 23.11.2016

Рядом с ошибкой обычно номер строки написан.

Rustzi50
Offline
Зарегистрирован: 14.01.2020

у меня 1.8 : показывает на строку 

digitalWrite(led[i], stsv[i]);

закомментил её,

показывает на предыдущую строку

 stsv[i] = strPayload.toInt(); и т.д.

 

b707
Онлайн
Зарегистрирован: 26.05.2017

Rustzi50 пишет:

у меня 1.8 : показывает на строку 

digitalWrite(led[i], stsv[i]);

закомментил её,

показывает на предыдущую строку

 stsv[i] = strPayload.toInt(); и т.д.

 

где и как описан массив stsv[] ?

Rustzi50
Offline
Зарегистрирован: 14.01.2020

Да, действительно - непростительная ошибка в определении массивов!

Идем дальше 

if (client.connect("svet1")) {
    // Once connected, publish an announcement...
  if (flags == 1) {
     for (i = 0; i < 4; i++){   //цикл 1
      String Index= String(i, DEC); 
      String  Stsv = String("svet1/stsv" +  Index);
      dtostrf(stsv[i], 1, 0, buff);
     client.publish(Stsv, buff);
                            }}

выдает:  no matching function for call to 'PubSubClient::publish(String&, char [20])'

курю библиотеку PubSubClient

b707
Онлайн
Зарегистрирован: 26.05.2017

Rustzi50 пишет:

курю библиотеку PubSubClient

вам не библиотеку надо курить, а книжку по С/С++ штудировать. Разберитесь в отличиях String и char* и в работе с массивами.

А потом подумайте - неужели преобразование числа в String, формирование из него имени топика. а потом поиск этого имени среди 28 одинаковых имен - это правильный метод поиска нужного топика в массиве? Я вам сразу скажу - это бредятина, а не алгоритм...

Rustzi50
Offline
Зарегистрирован: 14.01.2020

Предлагаете 

if (strTopic == "svet1/stsv0")
....
if (strTopic == "svet1/stsv28")
28 строк писать, 
циклы же для таких случаев придуманы
b707
Онлайн
Зарегистрирован: 26.05.2017

Rustzi50 пишет:

Предлагаете 

if (strTopic == "svet1/stsv0")
....
if (strTopic == "svet1/stsv28")
28 строк писать, 
циклы же для таких случаев придуманы

нет, предлагаю просто найти в строчке topic номер и использовать как индекс.

интересно, если бы у вас было 50000 вариантов -тоже в цикле сравнивали 50 тысяч строк??

Rustzi50
Offline
Зарегистрирован: 14.01.2020

да, согласен, спасибо! Свежий взгляд помог, а то мой замылился с этим иоброкером

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

Если имя топика в конце содержит цифры, и по ним надо ориентироваться, то просто ищем с конца первый символ - не цифру, а остальные справа - будут цифрами. Что-то типа этого:

void callback(char* topic, byte* payload, unsigned int length)
{
	const char* ptr = topic + strlen(topic);
	while(ptr >= topic && (*ptr >= '0' && *ptr <= '9'))
	{
		ptr--;
	}
	
	int idx = atoi(ptr);
}

Навскидку, не проверял, но там всё понятно по алгоритму, надеюсь: просто смотрим на конец имени топика, и перемещаемся влево, пока встретим символы, отличные от ['0'-'9'].

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Оно, конечно, по уже установившейся традиции, ТС скрыл свой суперскетч от нас, чтобы мы не стырили, потому, точно не скажешь, но, вот сдаётся мне в строке №4 выход за границу массива.

Logik
Онлайн
Зарегистрирован: 05.08.2014

Rustzi50 пишет:

у меня 1.8 : показывает на строку 

digitalWrite(led[i], stsv[i]);

закомментил её,

Подход верный, продолжайте так,  комментируйте все строки с ошибками. 

Rustzi50
Offline
Зарегистрирован: 14.01.2020

спасибо, парни, за тычки в нужную сторону, скетч  полностью могу выложить, когда он станет рабочим. думаю над ошибкой в посте 6

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

Rustzi50 пишет:

думаю над ошибкой в посте 6

Думать не надо, надо посмотреть объявления методов PubSubClient и понять, что String он не принимает в качестве параметра, а принимает - char*. Поэтому, вместо

client.publish(Stsv, buff);

достаточно написать:

client.publish(Stsv.c_str(), buff);

и учить основы языка - будет вовне необязательно, лишнее это, никому не нужное.

Rustzi50
Offline
Зарегистрирован: 14.01.2020

Ура! Заработало! 

ioBroker

Спасибо  DIYMan и b707!

На плане два светильника из 28.  Использую Mega+W5100.

Кнопки будут реализованы на PCF8574.

В скетче, для примера, использованы 4 кнопки, подключенные к Меге.

 
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>

 byte mac[] = { 0xDE, 0xAA, 0xBB, 0xFF, 0xEE, 0xDD }; 
 IPAddress ip(192, 168, 0, 210);  //вводим  IP
 IPAddress Server(192, 168, 0, 1);

 char buff[20]; 
 byte flag[4]; // флаг кнопок 
 byte flags= 0; // флаг отправки
 byte stsv[4];   // статус светодиодов 
 unsigned long tmr[4];   
 const long zad = 600000;       // задержка  60 мин
 const byte insvet[] = {43,45,47,49};     // номер  ноги кнопки на ноль
 const byte led[] = {22,24,26,28};    // номер ноги светодиода
 byte i,  val;

EthernetClient ethClient;
PubSubClient client(ethClient);

//Функция обработки входящих соединений - прием данных по подписке
void callback(char* topic, byte* payload, unsigned int length)
{ //преобразуем тему(topic) и значение (payload) в строку
  payload[length] = '\0';
  String strTopic = String(topic);
  String strPayload = String((char*)payload);
  //Чтение статусов
  for (i = 0; i < 4; i++){   //цикл1
      String Index= String(i, DEC); 
      String  Stsv = String("svet1/stsv" +  Index);
      if (strTopic ==Stsv.c_str())  {  // управление  светом
          stsv[i] = strPayload.toInt();
          digitalWrite(led[i], stsv[i]);
          tmr[i] = millis(); }
                        } // конец цикл1
}//end void callback

void setup() {
 client.setServer(Server, 1883);
 client.setCallback(callback); 
 Ethernet.begin (mac, ip);//запускаем сервер с указанными ранее MAC и  IP 
 // Serial.begin(9600);
 delay(790); //ждем  Ethernet.begin
 for (i = 0; i < 4; i++){   //цикл 2
      pinMode(insvet[i], INPUT);   //вывод-вход
      digitalWrite(insvet[i],HIGH); //включаем внутр. резистор
      pinMode(led[i], OUTPUT); //вывод-выход
      digitalWrite(led[i],0); //выключаем все
      tmr[i] = millis();
                        } //конец цикл2


  if (client.connect("svet1"))   { 
      for (i = 0; i < 4; i++){   //цикл3
      String Index= String(i, DEC); 
      String  Stsv = String("svet1/stsv" + Index);
       client.subscribe(Stsv.c_str());  //подписка на топики 
                             } //цикл3            
                                }//end client.connect

 } // конец setup

void loop() {
     for (i = 0; i < 4; i++){   //Ручное управление светом: цикл4
      val = !digitalRead(insvet[i]);
     if(val==1 && flag[i]==0)        //если кнопка нажата    
     { stsv[i] = !stsv[i];  flags = 1;  
       digitalWrite(led[i], stsv[i]);   flag[i]=1; 
       if (stsv[i] ==1) {tmr[i] = millis();} //установка времени вкл света
     }    
     if(val==0 && flag[i]==1)   //если кнопка НЕ нажата 
     {  flag[i] = 0;  }         //обнуляем переменную flag  
     if (stsv[i] ==1 && millis()-tmr[i] > zad) //время вышло?
     {stsv[i] = 0; digitalWrite(led[i], 0); flags = 1;}
                          }//конец цикл4

  if (flags == 1) { //если есть изменение статуса света
  if (client.connect("svet1")) { 
     for (i = 0; i < 4; i++){   //цикл 1
      String Index= String(i, DEC); 
      String  Stsv = String("svet1/stsv" +  Index);
      dtostrf(stsv[i], 1, 0, buff);
     client.publish(Stsv.c_str(), buff);
      flags = 0;  }
  
  }// end Client connected
  
  }// end if (flags == 1)
  client.loop();
 delay(1); 
 } // end void loop

 

 

Rustzi50
Offline
Зарегистрирован: 14.01.2020

Скетч оччень простой получился!

Есть конечно огрехи, будем вылизывать!