Цикл, пока не придет новое сообщение

secret_py

✩✩✩✩✩✩✩
12 Окт 2021
10
0
Добрый день! Новый вопрос: у меня есть проект, который будет управляться через телеграм. Для этого на базе wemos d1 mini подключена библиотека UniversalTelegramBot. Я написал бота, для приема сообщений и тд. Теперь у меня вопрос: мне нужно, чтобы при определенном слове, полученном ботом, у меня запускался цикл, который будет выполнять функцию до тех пор, пока не придет новое сообщение. Я пробовал использовать do while, заранее сохраняя айди сообщения и проверяя в цикле, не пришло ли новое в момент работы цикла. Однако если делать проверку вне функции обработки сообщения, то код не видит айди и возвращает ноль, также как и внутри самого цикла, так как код уже не видит его. Знает ли кто-нибудь как решить мою проблему? Если нужно, то готов перейти на другую библиотеку. Главное, чтобы при определенном сообщении в цикле запускался функция, пока не будет иной команды, метод реализации не важен.

В цикле лежит функция для матрицы, чтобы эффект работал не один раз и останавливался, А постоянно, пока не будет иная команда на смену режима.
 

bort707

★★★★★★✩
21 Сен 2020
3,062
912
проблема непонятна. Определите глобальную переменную для ID - и она будет видна и внутри функции обработки. и снаружи
 

secret_py

✩✩✩✩✩✩✩
12 Окт 2021
10
0
@bort707,смотри, когда я начинаю запрос обновления нового сообщения и получения его id, то это становится невозможным, так как по библиотеке можно получить id iтого сообщения, в цикле for это переменная i, но как только я начинаю цикл после обработки сообщения, то переменная начинает равняться нули, хоть данная команда не была выполнена, а значит и не получиться получить нужный эффект. А я пока сидел, возник вопрос, что если написать функцию и запихнуть ее в loop. И если будет сообщение нужно, то менять переменную, это увидит функция и запустит цикл. Можно ли сделать так?
 

Lumenjer

★★★✩✩✩✩
10 Дек 2020
220
112
так как по библиотеке можно получить id iтого сообщения, в цикле for это переменная i, но как только я начинаю цикл после обработки сообщения, то переменная начинает равняться нули, хоть данная команда не была выполнена, а значит и не получиться получить нужный эффект.
Почему вы так решили? Как "i" может быть ID?)

Пример FastLED:
void loop()
{
  if (millis() - bot_lasttime > BOT_MTBS)  // Периодично проверяем на обновления
  {
    int numNewMessages = bot.getUpdates(bot.last_message_received + 1);  // Метод getUpdates возвращает количество новых сообщений

    while (numNewMessages)   // Если есть новые сообщения
    {
      Serial.println("got response");
      handleNewMessages(numNewMessages);  // Обрабатываем все сообщения
      numNewMessages = bot.getUpdates(bot.last_message_received + 1); // проверяем, не пришло ли ничего нового, пока обрабатывали сообщения, если ничего, то 0 и выходим из цикла
    }

    bot_lasttime = millis();
  }
}
Какой вывод из этого можем сделать?
ID сообщения можно получить в цикле for в методе "handleNewMessages".
id = bot.last_message_received - (numNewMessages-1) + i;
Можем ли мы это хранить в глобальной переменной? Да запросто, только что вы с этим дальше будете делать - это уже другой вопрос, я даже сомневаюсь, что для ваших задач вам вообще нужно знать ID

А "i" это никаким образом не ID, это всего лишь индекс нового сообщения, которое хранится в оперативной памяти МК на данный момент (в массиве новых сообщений). По умолчанию библиотека хранит в памяти максимум 1 сообщение #define HANDLE_MESSAGES 1.

Мой вам совет, если пришло сообщение c тем вашим определенным словом, просто включите какой-то глобальный bool flag при обработке этой команды, а дальше в лупе меняйте поведение по этому флагу, и уже с последующим новым сообщением просто выключите этот флаг в начале функции "handleNewMessages"
 

secret_py

✩✩✩✩✩✩✩
12 Окт 2021
10
0
@Lumenjer, I в цикле for функции обработки сообщений должна входить в команду bot.getUpdates(messages.message_id). Сделал я такой вывод, потому что что если по логике библиотеки нам нужно сделать тоже самое, но прописан text, чтобы получить текст сообщения. Да и я работаю с телеграм ботами на пилоне более 2 лет, поэтому несмотря на другой язык, все выглядит интуитивно понятным именно в определенных вещах
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,969
632
44
Скорее всего автору проще сделать через конечный автомат (state machine).
Абстрактный код примерно такой:
Код:
int state = 0;

void loop() {
    
    if (state == 0) {
        doSomething0();
        if (conditionOk) state++;
    }

    if (state == 1) {
        doSomething1();
        if (conditionOk) state++;
    }

    if (state == 2) {
        doSomething2();
        if (conditionOk) state=0;
    }

}
Либо я не правильно понял проблему топикстартера. =)
 

secret_py

✩✩✩✩✩✩✩
12 Окт 2021
10
0
@Lumenjer, пробывал только что, даже так все равно 0 выдает. Значит буду через флаги работать пробовать
 

secret_py

✩✩✩✩✩✩✩
12 Окт 2021
10
0
@bort707,так он предложил флаг. Глобальная переменная - не работает. У данной библиотеки проблемы с получением айди сообщения. Даже если без айди работать и ввести свою переменную, то при каждом рестарте платы все будет идти сначала. Я могу скинуть код, чтобы вы убедились, что не работает значение id
 

bort707

★★★★★★✩
21 Сен 2020
3,062
912

@secret_py, я вам уже в прошлой в теме писал, что вам надо С++ учить, а не полагаться на опыт в питоне. При всей общности алгоритмов разница между Си и скриптовыми языками огромная.

Теперь по сути - флаг это и есть глобальная переменная. И "не работать" она не может. Так что первая фраза в вашем ответе - чушь. А чтобы оно работало, переменную надо описывать не в библиотеке, а в своем коде. И, возможно, саму библиотеку придется немного поправить.
 

secret_py

✩✩✩✩✩✩✩
12 Окт 2021
10
0
@bort707, вы не поняли. Он изначально говорил про метод id, а не флаги. Он написал пример кода(получения новых сообщений) и предложил как получить нужный мне айди. Я не говорил, что флаги не работают. Я сказал, что код с получением айди всегда дает ноль, это не только у меня. Флаги он написал в конце ответа, как совет по изменению ситуации. Прочитайте еще раз. Я не полагаюсь на питон, я просто изучаю язык и вижу сходности в алгоритмах
 

bort707

★★★★★★✩
21 Сен 2020
3,062
912
Эта библиотека не может вернуться параметр сообщения, так как макс значение может равняться 1
тебе уже
@Lumenjer написал, что для решения твоей задачи это не нужно.

Давай по другому - ты же можешь понять, что пришло сообщение с нужным тебе текстом? - значит в этот момент ты можешь запомнить ид сообщения или его номер или выставить флаг - это все одно и то же. Суть в том, что тебе надо зафиксировать факт прихода нужного текста. А что до того, что библиотека это не умеет - так на то ты и автор программы. И, кстати, библиотеки пишут такие же люди как ты и я - и при необходимости в библиотеку можно и добавить недостающие функции.

А обижаться не надо
 

Lumenjer

★★★✩✩✩✩
10 Дек 2020
220
112
Я сказал, что код с получением айди всегда дает ноль, это не только у меня.
Я более чем уверен, что вы неправильно получаете айди. Глянул библиотеку поближе, возьмем все тот же пример FlashLED и начало функции "handleNewMessages"

FlashLED:
int id = 0;      // Объявляем глобальную int переменную id
void handleNewMessages(int numNewMessages)
{
  Serial.print("handleNewMessages ");
  Serial.println(numNewMessages);

  for (int i = 0; i < numNewMessages; i++)
  {
    String chat_id = bot.messages[i].chat_id;
    String text = bot.messages[i].text;
    Serial.print("Message ID =");
    Serial.println(bot.messages[i].message_id);
    Serial.print("Update ID =");
    Serial.println(bot.messages[i].update_id);
    id = bot.messages[i].message_id;   // пихаем ID в глобальную переменную, "Вы великолепны © "
Не поленился расчехлить какого-то своего бота и собственно вот пруфы

1635937735268.png
Глобальная id будет доступна везде, и она будет равна 0 только до получения каких либо новых сообщений.


FlashLED:
/*******************************************************************
    A telegram bot for your ESP8266 that controls the
    onboard LED. The LED in this example is active low.

    Parts:
    D1 Mini ESP8266 * - http://s.click.aliexpress.com/e/uzFUnIe
    (or any ESP8266 board)

      = Affilate

    If you find what I do useful and would like to support me,
    please consider becoming a sponsor on Github
    https://github.com/sponsors/witnessmenow/


    Written by Brian Lough
    YouTube: https://www.youtube.com/brianlough
    Tindie: https://www.tindie.com/stores/brianlough/
    Twitter: https://twitter.com/witnessmenow
 *******************************************************************/

#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
#include <UniversalTelegramBot.h>

// Wifi network station credentials
#define WIFI_SSID "SSID"
#define WIFI_PASSWORD "PASSWORD"
// Telegram BOT Token (Get from Botfather)
#define BOT_TOKEN "XXXXXXXXX:XXXXXXXXXXXXXXXXXXX"

const unsigned long BOT_MTBS = 1000; // mean time between scan messages

X509List cert(TELEGRAM_CERTIFICATE_ROOT);
WiFiClientSecure secured_client;
UniversalTelegramBot bot(BOT_TOKEN, secured_client);
unsigned long bot_lasttime; // last time messages' scan has been done

const int ledPin = LED_BUILTIN;
int ledStatus = 0;
int id = 0;

void handleNewMessages(int numNewMessages)
{
  Serial.print("handleNewMessages ");
  Serial.println(numNewMessages);

  for (int i = 0; i < numNewMessages; i++)
  {
    String chat_id = bot.messages[i].chat_id;
    String text = bot.messages[i].text;
    Serial.print("Message ID = ");
    Serial.println(bot.messages[i].message_id);
    Serial.print("Update ID = ");
    Serial.println(bot.messages[i].update_id);
    id = bot.messages[i].message_id;

    String from_name = bot.messages[i].from_name;
    if (from_name == "")
      from_name = "Guest";

    if (text == "/ledon")
    {
      digitalWrite(ledPin, LOW); // turn the LED on (HIGH is the voltage level)
      ledStatus = 1;
      bot.sendMessage(chat_id, "Led is ON", "");
    }

    if (text == "/ledoff")
    {
      ledStatus = 0;
      digitalWrite(ledPin, HIGH); // turn the LED off (LOW is the voltage level)
      bot.sendMessage(chat_id, "Led is OFF", "");
    }

    if (text == "/status")
    {
      if (ledStatus)
      {
        bot.sendMessage(chat_id, "Led is ON", "");
      }
      else
      {
        bot.sendMessage(chat_id, "Led is OFF", "");
      }
    }

    if (text == "/start")
    {
      String welcome = "Welcome to Universal Arduino Telegram Bot library, " + from_name + ".\n";
      welcome += "This is Flash Led Bot example.\n\n";
      welcome += "/ledon : to switch the Led ON\n";
      welcome += "/ledoff : to switch the Led OFF\n";
      welcome += "/status : Returns current status of LED\n";
      bot.sendMessage(chat_id, welcome, "Markdown");
    }
  }
}


void setup()
{
  Serial.begin(115200);
  Serial.println();

  pinMode(ledPin, OUTPUT); // initialize digital ledPin as an output.
  delay(10);
  digitalWrite(ledPin, HIGH); // initialize pin as off (active LOW)

  // attempt to connect to Wifi network:
  configTime(0, 0, "pool.ntp.org");      // get UTC time via NTP
  secured_client.setTrustAnchors(&cert); // Add root certificate for api.telegram.org
  Serial.print("Connecting to Wifi SSID ");
  Serial.print(WIFI_SSID);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.print(".");
    delay(500);
  }
  Serial.print("\nWiFi connected. IP address: ");
  Serial.println(WiFi.localIP());

  // Check NTP/Time, usually it is instantaneous and you can delete the code below.
  Serial.print("Retrieving time: ");
  time_t now = time(nullptr);
  while (now < 24 * 3600)
  {
    Serial.print(".");
    delay(100);
    now = time(nullptr);
  }
  Serial.println(now);
}

void loop()
{
  if (millis() - bot_lasttime > BOT_MTBS)
  {
    int numNewMessages = bot.getUpdates(bot.last_message_received + 1);

    while (numNewMessages)
    {
      Serial.println("got response");
      handleNewMessages(numNewMessages);
      numNewMessages = bot.getUpdates(bot.last_message_received + 1);
    }
    Serial.print("Printing ID from loop() - ID = ");
    Serial.println(id);
    bot_lasttime = millis();
  }
}
 

Вложения