Дисплей Nextion: азы. Arduino, ESP8266.

Тема в разделе "Глядите, что я сделал", создана пользователем ИгорьК, 9 авг 2016.

Метки:
  1. ИгорьК

    ИгорьК Гуру

    Код с openhab - это один код. ESP-8266 должен его "переработать" в код, понятный дисплею.
    Мне сложно понять что там у Вас происходит, но похоже ESP прямиком отправляет код на дисплей.
    Дисплей должен получить код t0.txt="12.34"0xff0xff0xff , тогда он изменит свое состояние.
    Этот код и ищите в ESP-8266.
    Кусочек кода модуля, который перерабатывает опенхабовские данные, я привёл.
    Выложу чуть позже весь работающий дисплей, что у меня не фото. Но он ещё сильно бета - сейчас занимаюсь другими делами, а выкладывать недоделки не привык.

    Да, и здесь я объясняю как работать с дисплеем и даю только кусочки кода. То есть это не проект, не готовое устройство, а узелок на память. Его нельзя повторить по моим записям.
     
    Последнее редактирование: 24 сен 2016
  2. Артем_Р

    Артем_Р Нуб

    Игорь, спасибо, разобрался, все работает!
     
  3. woow

    woow Гик

    ИгорьК, вредно для моего кошелька и личного времени, читать ваши посты ;) С начало скептический отнёсся к этому Nextion экранчику, почитав ваши сообщения рискнул и прикупил сей девайс. Интересная игрушка, вот только с рисованиям у меня не ахти, может быть встречали какие ресурсы по иконкам, вообще мне много и не надо термометр, кнопка одна другая и т.п.
    И ещё вопрос а этот Nextion признаёт *.gif формат я бы хотел например из трёх картинок сделать икону крутящегося вентилятора или насоса.
     
  4. ИгорьК

    ИгорьК Гуру

    Формат признает но анимацию не делает. Вопрос можно решить путем последовательного показа двух-трех картинок по таймеру.
    Каждое изображение имеет свойство видимости. Ничто не мешает последовательно сменять картинки.
     
    woow нравится это.
  5. woow

    woow Гик

    Всё спасибо за подсказку, "пламя горит", "вентилятор крутится". Не нашёл как сделать прозрачную картинку *.png, хотел крутящемся вентилятор сделать иконку без фона, но nextion конвертер всё испоганил
     
  6. ИгорьК

    ИгорьК Гуру

    4.0. Ардуино, однако.
    "Человек предполагает..." Не собирался я работать с Nextion на Ардуино, а пришлось.
    Итак, работать с Nextion просто: надо отправлять на него данные и принимать оные взад. Работать будем без библиотек: они скорее ограничивают чем помогают.
    Для Ардуино есть ОГРОМНАЯ библиотека/примеры: https://github.com/itead/ITEADLIB_Arduino_Nextion
    ИМХО, открывший ее впервые просто обязан вспотеть: "и что теперь делать, ...ь".
    Ок. Начнем распутывать ситуацию.
    Перед этим предлагаю изучить первую станицу этой ветки в части того, что написано о Nextion, пропустив все что говорится о ESP-8266. Там я раскрыл основные моменты программирования дисплея.

    Отправка данных.
    Данные (не вникал на счет waveform) на Nextion должны быть отправлены в формате:
    • имя страницы
    • знак "."
    • название принимающего элемента
    • знак "."
    • название поля принимающего элемента
    • знак "="
    • данные, причем если это String, то в кавычках, а если это цифровая информация, то четыре байта данных
    • три байта 0xff
    Только в этой структуре дисплей поймет и выполнит команду.
    Полагаю, что с передачей цифровой информации (еще раз - не касается waveform) заморачиваться не стоит: если вы захотите передать температуру 22.7 градуса в цифровом виде - вам это не удастся. Nextion не работает с float. Значит все равно - String!
    Как же организовать его вывод?
    Вот функция.
    Код (C++):

    // Функция принимает три параметра, первый - указатель на String с данными
    // второй - наименование элемента на странице, третий - номер страницы как String,
    // причем по умолчанию это нулевая страница
    void printNextion(const char* data, String top, String page = "0"){
        String spage = "page"+page+"."+top+".txt=\"";
        Serial.print(spage);
        Serial.print(data);
        Serial.print("\"");
        Serial.write(0xFF);
        Serial.write(0xFF);
        Serial.write(0xFF);
    }
    А как вызвать эту функцию? Вот так:
    Код (C++):
    String forNext = "Tra-la-la!";
    // forNext.c_str() - возвращает указатель на стринг, точнее на массив char из наших буковок
    // t2 - название элемента на странице
    // 4 - номер страницы
    printNextion(forNext.c_str(),"t2","4");
    Ясный перец - я работаю с Serial, обычным железным Serial, что дергает 0 и 1 ноги Arduino.
    При программировании Uno - Nextion, или хотя бы его питание, надо отключать, иначе не получится прошить ардуино.
    Софтверный сериал тоже будет работать, но зачем, если только не подключается еще одно UART устройство?
    Напомню, что связку Arduino - Nextion очень удобно тестировать на эмуляторе Nextion. Как это делать - смотреть на первой странице.

    Это все, колеги, что касается отправки данных.
     
    Последнее редактирование: 14 ноя 2016
    Un_ka и 9xA59kK нравится это.
  7. ИгорьК

    ИгорьК Гуру

    4.1. Ардуино, о приеме данных с Nextion.
    В отличие от приема с Ардуино, сам дисплей позволяет отправлять данные любым образом, ничем себя не ограничивая.
    Можно воспользоваться галочкой, чтобы, например, кнопка отправила свой id, когда по ней щелкнут:
    Ashampoo_Snap_2016.11.08_16h21m37s_005_.jpg
    Затем принять и дешифровать эту отправку.
    Однако я, полагаю, требуется более системнй подход для удобной работы.
    Предлагаю поступить так:
    • каждое сообщение от Nextion начинается с "#"
    • за ним следует буква-идентификатор, которая "привязывается" к необходимому от Ардуино действию
    • за буквой, при необходимости, стринг с данными;
    • все завершается ";"

    Вот пример:
    Ashampoo_Snap_2016.11.08_16h22m33s_006_.jpg
    В данном случае нам интересна строка
    Код (C++):
    print "#m0;"
    // # - признак начала сообщения
    // m - устанавливается режим работы устройства, в данном случае
    // 0 - сам режим
    // ; - признак конца команды
    В лупе будем отлавливать сообщения и отправлять их на переплавку (заметим, что этот способ не блокирует выполнение программы, а побайтно работает с приходящими данными):
    Код (C++):
    // Сначала объявим кое-что, заранее:
    String inStr = ""; // Это будет приемник информации от Nextion
    bool serialReadFlag = false; // А это гаец-регулировщик.

    /******************************************************************/
    // Располагаем в loop следующее
    if (Serial.available()) {
            uint8_t inn = Serial.read(); // читаем один байт
            if(serialReadFlag) { // Если установлен флаг приема - действуем
                if(inn == 59){     // ASCII : ";" // Находим конец передачи ";"
                    if(inStr.length() > 0) { // Проверяем длину сообщения и отправляем в "переработку"
                        checkCommand(inStr); // В этой функции будем парсить сообщение
                    }
                    serialReadFlag = false; // Сбрасываем флаг приема
                }
                else { // А это нормальный прием
                    inStr += (char)inn; // Создаем String от Nextion
                    inStr.trim();  // Это можно удалить, просто для ручной настройки,
                                 // а там возникает перевод строки
                }
            }
            else { // А здесь отлавливается начало передачи от Nextion
                if(inn == 35) { // ASCII : "#"
                    serialReadFlag = true; // После # начинаем чтение при следующем заходе
                    inStr = ""; // Но до этого очистим стринг приема
            }
        }
    }
     
    Последнее редактирование: 14 ноя 2016
    Un_ka, Никита1, Jendos77 и 2 другим нравится это.
  8. ИгорьК

    ИгорьК Гуру

    4.2 Небольшая часть парсинга строки:
    Эта функция вызывается из предыдущего сообщения.
    Код (C++):
    void checkCommand(String ins) {
        // У нас информация от Nextion состоит из двух частей,
        // первая буква - идентификатор действия
        // ловим его:
        String first = ins.substring(0,1);
        // А все остальное - данные:
        String last = ins.substring(1);

        //Например "t" - идентификатор установки температуры
        if(first == "t") { // 't'  ASCII Value: 116
            // Значит остальное парсим на float:
            float ttt = last.toFloat();
            // И проверяем  на допустимость (возможный диапазон)
            // переменная target была объявлена заранее, ее и устанавливаем, если
            // в пределах допустимого:
            ((ttt > 15.0) && (ttt < 28.5)) ? target = ttt : 1==1;
        }
        // А это как раз для установки режима, все аналогично,
        // только устанавливаем mode:
        else if(first == "m") { // 'm'  ASCII Value: 109
        uint8_t mm = (uint8_t)last.toInt();
            ((mm >= 0) && (mm <3)) ? mode = mm : 1 == 1;
        }
        // ... И так далее...
    }
     
    Удачи при пайке и растворении в спирте... (канифоли) :)
     
    Последнее редактирование: 9 ноя 2016
    Jendos77 и 9xA59kK нравится это.
  9. Securbond

    Securbond Гуру

    Игорь, а можно примерчик скрипта для LUA, для вывода информации, а то что то не выходит каменный цветок.
    пробовал ваш кусок кода вставлять
    Код (Java):
    m:on("message", function(conn, topic, data)
        topic = topic..'.txt='..'\"'..data..'\"'..'\255\255\255'
        uart.write(0,topic)
    end)
    но то ли не туда вставляю, то ли туплю, но никак данные в UART не идут...
    Туго у меня с LUA ...:(
     
  10. ИгорьК

    ИгорьК Гуру

    1. Дайте скриншот из редактора Nextion в какой компонент Вы хотите вывести информацию.
    2. Дайте скриншот из ESplorer по результатам работы этого скрипта.
     
  11. Securbond

    Securbond Гуру

    Доползу до дома, сброшу.
    Уверен что у меня скрипт Lua не правильный. После его загрузки байты в uart никакие не идут. Давно ничего не программировал, совсем забыл как с брокером общаться и функции в скрипте вызывать ((
     
  12. ИгорьК

    ИгорьК Гуру

    Тогда весь скрипт - посмотрим.
     
  13. Securbond

    Securbond Гуру

    Код (Java):
    Broker="192.168.0.100"
    port=1883
    myClient="Nextion"
    iogin=""
    pass=""
    m = mqtt.Client( myClient, 120, login, pass)
    m:lwt("nextion/", "By!", 0, 0)

    function run_main_prog()
      m:on("message", function(conn, topic, data)
        topic = topic..'.txt='..'\"'..data..'\"'..'\255\255\255'
        uart.setup(0,9600,8,uart.PARITY_NONE,uart.STOPBITS_1,1)
        uart.write(0,topic)
        print ("Ok")
    end)
    end

    tmr.alarm(0, 1000, 1, function()
      if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
      tmr.stop(0)
      m:connect(Broker, port, 0, function(conn)
      print("Mqtt Connected to: " .. Broker)
      run_main_prog()
      end)
      end
    end)
    Вот скрипт... чувствую чего-то в нем не хватает.:confused:
     
  14. Securbond

    Securbond Гуру

    подправил..
    Код (C++):
    Broker="192.168.0.100"
    port=1883
    myClient="Nextion"
    iogin=""
    pass=""
    m = mqtt.Client( myClient, 120, login, pass)
    m:lwt("nextion/", "By!", 0, 0)

    function run_main_prog()

      m:on("message", function(conn, topic, data)
        topic = topic..'.txt='..'\"'..data..'\"'..'\255\255\255'
        uart.write(0,topic)

    end)
    end

    tmr.alarm(0, 1000, 1, function()
      if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
      tmr.stop(0)
      m:connect(Broker, port, 0, function(conn)
      print("Mqtt Connected to: " .. Broker)
      m:subscribe("t0/#",0, function(conn)
      run_main_prog()
      end)
      end)
      end
    end)
    с таким скриптом сообщения приходят, и тут же начинается какой то бесконечный процесс прёма байт
    афсл.JPG
    А если смотреть в ESPlorer, то вроде бы всё норм
    11.JPG
     
  15. Securbond

    Securbond Гуру

    Наверное глюк был.... Сейчас всё работает. Теперь осталось понять как принимать и отправлять не одно, а много значений...
    Видимо нужно создавать топик nextion/
    в него кидать значения, например nextion/t1, nextion/t2 .....
    и потом делать условие - если топик nextion/t1, то кинуть в порт нужную строку и.т.д
    только вот нужно как то отбросить nextion/ и оставить только t1, что бы добавить к нему topic = topic..'.txt='..'\"'..data..'\"'..'\255\255\255'
    :oops:
     
    Последнее редактирование: 14 ноя 2016
  16. ИгорьК

    ИгорьК Гуру

    Тепло... :) Доберусь до компа - скину код.
     
  17. ИгорьК

    ИгорьК Гуру

    Вот код. Пока нет возможности закомментировать:
    Код (Lua):

    uart.setup(0,9600,8,uart.PARITY_NONE,uart.STOPBITS_1,1)
    ------------
    m:on("message", function(conn, topic, data)
        -- print(topic)
        -- print(data)
        if (string.find(topic, "state")) == nil then
             local top = string.gsub(topic, mClnt.."/","")
            if top == "dim" then
                top = top..'='..data..'\255\255\255'
            else
                data = string.sub(data, 1, 5) -- удаляем лишние цифры
                local snd = ''
                local thd = ''
                snd = string.sub(top,2,2)
                thd = string.sub(top,3,3)
                top ='page'..snd..'.'..string.sub(top,3)
                if thd == 't' or thd == 'v' then
                    top = top..'.txt='
                    top = top..'\"'..data..'\"'..'\255\255\255'
                --
                else
                    top = top..'.val='
                    top = top..data..'\255\255\255'
                end
             --]]
            --------------------------------------------------
            end
            uart.write(0,top)
        end
        collectgarbage()
    end)
    Или вообще полный код:
    Код (Lua):
    uart.setup(0,9600,8,uart.PARITY_NONE,uart.STOPBITS_1,1)
    str = ""
    count = 0
    Broker="my.mqtt.org"
    port=1883
    mClnt="next01"
    pass="pass"
    publish = false

    lt = false

    m = mqtt.Client(mClnt, 180, mClnt, pass)
    m:lwt("/lwt", mClnt, 0, 0)
    function connecting()
        function getConnect()
           if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
                 m:connect(Broker, port, 0, 0,
                    function(conn)
                        tmr.stop(6)
                         publish = true
                        m:subscribe(mClnt.."/#",0, function(conn)
                        end)
                end)
            end
        end
        getConnect()
        tmr.alarm(6, 90000, 1, function()
            getConnect()
        end)
    end

    m:on("offline", function(con)
        publish = false
        connecting()
    end)

    m:on("message", function(conn, topic, data)
        -- print(topic)
        -- print(data)
        if (string.find(topic, "state")) == nil then
             local top = string.gsub(topic, mClnt.."/","")
            if top == "dim" then
                top = top..'='..data..'\255\255\255'
            else
                data = string.sub(data, 1, 5) -- удаляем лишние цифры
                local snd = ''
                local thd = ''
                snd = string.sub(top,2,2)
                thd = string.sub(top,3,3)
                top ='page'..snd..'.'..string.sub(top,3)
                if thd == 't' or thd == 'v' then
                    top = top..'.txt='
                    top = top..'\"'..data..'\"'..'\255\255\255'
                --
                else
                    top = top..'.val='
                    top = top..data..'\255\255\255'
                end
             --]]
            --------------------------------------------------
            end
            uart.write(0,top)
        end
        collectgarbage()
    end)

    uart.on("data",1,
        function(dt)
        if lt then
            if dt == "\255" then
                count = count + 1
                if count == 3 then
                    count = 0
                    local publ
                    publ = str
                    str = ""
                    lt = false
                    pub(publ)
                end
            else
                str = str..dt
                if #str > 20 then str = ""; count = 0 end
            end
        end
        if str == "" and dt == "\112" then
            lt = true
        end
    end, 0)
    -------------------------------------------------------------
    function pub(pu)
        local topic
        local info
        topic, info = string.match(pu, "(%w+):(%w+)")
        if topic ~= nil and info ~= nil then
            m:publish(mClnt.."/"..topic.."/state",info,0,0)
        end
        collectgarbage()
    end
    ---------------------------------------------------------------
    connecting()
     
    Последнее редактирование: 14 ноя 2016
    Securbond нравится это.
  18. Securbond

    Securbond Гуру

    хмммм.....
    а я сделал так -
    Код (Java):
    Broker="192.168.0.100"
    port=1883
    myClient="Nextion"
    iogin=""
    pass=""
    m = mqtt.Client( myClient, 120, login, pass)
    m:lwt("nextion/", "By!", 0, 0)

    function run_main_prog()
      m:on("message", function(conn, topic, data)
         if topic == "nextion/t0" then
        topic = string.sub(topic, 9)
        topic = topic..'.txt='..'\"'..data..'\"'..'\255\255\255'
        uart.write(0,topic)
        end
    end)
    end

    tmr.alarm(0, 1000, 1, function()
      if wifi.sta.status() == 5 and wifi.sta.getip() ~= nil then
      tmr.stop(0)
      m:connect(Broker, port, 0, function(conn)
      print("Mqtt Connected to: " .. Broker)
      m:subscribe("nextion/#",0, function(conn)
      run_main_prog()
      end)
      end)
      end
    end)
    То же все работает ))
     
  19. ИгорьК

    ИгорьК Гуру

    Тут все зависит от задачи. Полная команда на Nextion должна выглядеть как указание номера страницы, название топика и данные для него: page2.t4.txt="text"\255\255\255
    Соответственно, мой код разбирает название топика на части, а топик (mqtt) должен выглядеть как "p2t4" - страница 2, топик t4.
    Когда страниц несколько, команду на Nextion надо формировать именно так.
     
    Последнее редактирование: 14 ноя 2016
    Securbond нравится это.
  20. Securbond

    Securbond Гуру

    Спасибо, понял.
    Попробую разобрать ваш код и понять структуру и как все работает...