Продолжение. Предыдущая часть.


Оглавление:



Центральный блок. Программное обеспечение


Наконец мы подошли к самой трудной части для любого программиста — описать по-человечески что он там наваял.


Исходный код для сервера составляет около 1300 строк, включая отступы, но это не должно вас пугать. Исходный текст снабжен подробными комментариями, в этом плане я не ошибусь, если скажу, что мои исходники описаны лучше чем любые другие которые вы только сможете найти. В комментариях прямо в исходном тексте вы найдете всю распиновку для подключения модулей и все необходимые ссылки на внешнюю документацию. Секрет прост — я писал комментарии для себя постоянно, «по ходу пьесы», поэтому никаких трудностей с документированием не испытал.


Как я уже писал вы можете начать и не имея всех модулей под рукой. Например, можно начать не имея радиомодуля или ESP8266. Датчик барометрического давления BMP180 также может отсутствовать. Добавите потом. Правда в этом случае вам (возможно) придется самостоятельно закомментировать в скетче те участки кода, которые отвечают за взаимодействие с отсутствующими блоками, но скорее всего этого не потребуется. Главное, чтобы хоть что-то собралось и заработало, тогда веселее продолжать.


Конкретно сейчас, в данном месте повествования, у нас пока ещё не собран заоконный (внешний) модуль и нет своего веб-сервера с базой данных, то нам пока не нужны (но если есть — подключите сразу, чтобы потом не копаться):


  • радиомодуль nRF24L01+
  • WiFi модуль ESP8266.

И всё таки я начну, пожалуй, с ESP8266, как самого проблемного в программировании и эксплуатации модуля. Причина кроется в разнообразии исполнения самих модулей и их прошивок.


Как я уже писал стандартные AT-прошивки для него имеют ряд недостатков:


  • они всё ещё сыроваты (по состоянию на 2016)
  • мне не удалось найти нормальную библиотеку для Arduino для управления модулем ESP8266 с помощью AT команд, пришлось «колхозить» самому.

Код для ESP8266 я не оформлял в отдельную библиотеку, а просто написал необходимые функции, поэтому скетч вышел таким длинным. Причём я реализовал только нужный мне функционал. Всё программирование для ESP с помощью AT команд сводится в итоге к парсингу строк и настройке задержек между командами.


Исходный код для сервера (центрального модуля) server.ino вы можете найти и скачать здесь.


Рядом я положил прошивку для ESP8266 в файле firmware/AT23-SDK101-nocloud.bin и в том же каталоге находится документация для любознательных. Прошив указанную прошивку вы можете быть уверены, что мой скетч у вас заработает с WiFi так как было задумано. С другими AT прошивками я не экспериментировал. Дело в том, что мне удалось таки отыскать «продвинутую» не AT прошивку, и даже немного поучаствовать в её создании, которая как нельзя лучше подходит для наших целей (вот она esp-link). Однако, как это часто случается, всё произошло уже после завершения работы над текущей версии метеостанции, поэтому решено было оставить всё так как есть.


Итак, в самом начале вам придётся прошить указанную AT прошивку. Сложного тут ничего нет, но и простого тоже. Как это сделать описано много где в сети — ESP8266 — подключение и обновление прошивки.


Поскольку у моего USB-TTL конвертора не хватило мощности по току и USB порт постоянно отваливался (вот это поворот!), то электрически я подключил модуль для его прошивки способом «Arduino в качестве простого USB-to-Serial TTL конвертора».


Так как я работаю в Linux, то и прошивал с помощью esptool.py. Для удобства прошивки я «наколхозил» небольшую вспомогательную плату с переключателями (здесь не описана).


После прошивки нужно установить скорость порта 57600 (так как для SoftSerial скорость порта в 115200 является большой и не гарантирует стабильную работу) командой


AT+UART_DEF=57600,8,1,0,0

Далее нужно слегка изменить стандартные библиотеки Arduino IDE, а именно в файле arduino/hardware/arduino/avr/libraries/SoftwareSerial/SoftwareSerial.h изменить соответствующую строку на


#define _SS_MAX_RX_BUFF 128 // RX buffer size

в файле arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h изменить соответствующие строки на


#define SERIAL_TX_BUFFER_SIZE 128
#define SERIAL_RX_BUFFER_SIZE 128

и в файле arduino/hardware/arduino/avr/cores/arduino/USBAPI.h изменить соответствующую строку на


#define SERIAL_BUFFER_SIZE 128

Строго говоря это неправильно, т.к. при обновлении Arduino SDK эти файлы скорее всего будут перезаписаны и придется повторить все исправления заново. По науке мы должны изобрести свою библиотеку, которая манипулирует указанными значениями (если получится), но это на любителя.


Так или иначе предварительные манипуляции закончены.


Теперь переходим непосредственно к коду центрального блока (серверу) server.ino


В первых же строках вы должны изменить настройки доступа к вашей точке WiFi


const String SSID = "...";
const String PASSWORD = "...";

работу с веб сервером подробно рассмотрим позже.


Далее идут (закомментированные) отладочные определения:


//#define DEBUG
//#define DEBUG_RF
//#define DEBUG_ESP
//#define DEBUG_LOG_SD

Если что-то пойдёт не так вы всегда можете их раскомментировать, перекомпилировать и перезалить скетч и получить больше отладочной информации в консоли или записать её в файл на SD карту. Причем вы можете раскомментировать только то, что вам нужно. Например, барахлит модуль nRF24L01+? Тогда раскоментируем только DEBUG_RF, и т.д.


Далее идут обширные комментарии с распиновкой, инициализацией и подробным описанием всей периферии.


Здесь вы можете изменить номер радиоканала для nRF24L01+


#define RF_CHANNEL  73

Далее идёт void setup(), что там делается понятно из подробных комментариев. Ну и затем void loop(), код работы с веб-сервером пока не рассматриваем.


После заливки скетча, ваш центральный блок оживёт и что-то вам покажет, но не сразу, а спустя 10 минут — значение DELAY_LOCAL_SENSOR. Можете его изменить конечно же.
На дисплее должны отобразиться: комнатная температура и влажность (данные поступят от датчика DHT11) и барометрическое давление (от BMP180).


За отображение на дисплее LCD 16?4 отвечают функции:


void lcdClearRow(int row)

// Печатает на экране показания удалённых, уличных датчиков
void lcdPrintOutdoor(int temperature, int humidity, float voltage)

// Печатает на экране показания внутренних, домашних датчиков
void lcdPrintHome(int temperature, int humidity, int pressure)

void lcdPrintInfo(char info[LCD_MAX_COLS])
void lcdPrintStatus()
void lcdPrintLastSensorTime()

Дизайн дисплея LCD1604 следующий.


Дизайн дисплея LCD1604


В первой (верхней) строке печатается стилизованная иконка (идущий человечек) призванная обозначить погоду на улице (вышел на улицу, идёт по улице). Иконку придумывал сам, поэтому, если у вас есть лучшая идея (умещающаяся в 5х8 пикселов), можете указать в комментариях (в виде byte-массива). Поупражняться в пиксель-арте можно здесь Custom Character Generator for HD44780 LCD Modules. В этой же строке печатается напряжение питания заоконного модуля.


Во второй строке печатается «погода в доме» и атмосферное давление. Иконка дома стандартная, всем понятная.


В третьей строке lcdPrintLastSensorTime() печатает сколько прошло времени (в сек) со момента снятия последних показаний датчиков, соответственно уличного и, через запятую, домашнего. Пригодится чтобы точно знать, что метеостанция не показывает погоду за вчера. По сути это отладочная информация и её можно убрать в финальной версии.


И в последней четвёртой строке экрана с помощью функции lcdPrintStatus() печатается статусная информация, где


  • s — это локальный датчик давления
  • e — это модуль ESP8266
  • i — это подключение к WiFi
  • w — это доступность web сервера
  • l — лог-файл на SD карте

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


Возвращаясь к вопросу выбора железа, поясню про преимущества выбора текстового LCD1604 дисплея перед графическим. Дело в том, что модули LCD1604 купленные у различных продавцов в большинстве случаев будут одинаковыми и предсказуемыми в подключении и просты в программировании. Чего нельзя сказать о графических дисплеях, хотя нарисовать и показать на них можно гораздо больше. Разборчивость изображения с расстояния в несколько метров опять же лучше у текстового дисплея, таки да, на графическом дисплее можно сделать шрифт побольше, но тогда много ли можно на нём уместить?


Далее. Как только вы зальете скетч и убедитесь, что все работает как надо, то можете переподключить «материнскую» плату Arduino Mega к внешнему источнику питания. Или оставить как есть, подключённым к USB компьютера, чтобы посматривать на всю эту красоту в отладочной консоли.


Если у вас не все блоки в сборе, то вы можете закомментировать ненужный код. Хотя, повторюсь, должно работать и так, просто будете получать сообщения об ошибках в консоли. Как это обойти?


Например, вы ещё не приобрели датчик атмосферного давления BMP180. В скетче server.ino ищем строки, отвечающие за подключение соответствующих библиотек, в нашем случае это


#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h>

Комментируем этот блок.


Далее в Arduino IDE запускаем компиляцию кода (не прошивку) и смотрим на какие строки ругается компилятор. Комментируем эти строки. Операцию повторяем до тех пор, пока код не будет собираться нормально, без ошибок. Хорошей практикой будет перед редактированием создать копию скетча, чтобы, когда из солнечного Китая приедет нужный датчик, не повторять все операции обратно.


Ссылки на используемые библиотеки даны в исходном коде. Если такой ссылки нет, то использовалась стандартная библиотека Arduino IDE.


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


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

Комментарии (15)


  1. mosidze
    10.10.2018 15:38

    Комментируем эти строки. Операцию повторяем до тех пор, пока код не будет собираться нормально, без ошибок.

    Я все…


    1. siryoshka
      10.10.2018 15:55

      Была бы возможность + поставить, да ума видимо нет, так и буду в машинном коде лазить, оптимизацию искать.
      Но мне сам подход нравится, сразу школьная пора вспомнилась


      1. mosidze
        10.10.2018 16:33

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


        1. Alexeyslav
          11.10.2018 10:14

          Можно было обернуть в условную компиляцию, а в главном файле только дефайны определять которые будут включать или исключать нужные инклуды. Но закомментировать и правда проще… теми же директивами можно в лог компиляции слать сообщения о выбранной конфигурации, вызывать ошибки при «неправильной конфигурации» и т.д.


    1. tim4dev Автор
      11.10.2018 18:41

      Не ну а чо.
      Пробовал условной компиляцией, но происходит путаница.
      Так проще.


      1. iig
        12.10.2018 11:18

        Изобретать свой собственный способ езды на велосипеде? Ну ок.


      1. Alexeyslav
        12.10.2018 13:15

        Путаница происходит только из-за непродуманности. Конечно, в таких случаях проще топором…


  1. Alyoshka1976
    10.10.2018 18:43

    Вы не пробовали использовать MQTT-протокол?


  1. iig
    10.10.2018 23:34

    Непонятно, зачем отключать куски кода методом комментирования? Ошибки в консоли. — они кому-то мешают разве? Размер программы большое — так в любом случае в память помещается.
    Если предусмотрено отключение куска кода — есть для этого ifdef.
    И, это… любая система контроля версий здорово упрощает жизнь. Особенно при программировании методом тыка (сначала в несколько и ераций добиваемся, чтобы компилилось, а потом — чтобы работало. А потом чтобы работало правильно)


    1. Alexeyslav
      11.10.2018 10:18

      боюсь СКВ в данном случае будет только мешать, забъётся многочисленными непонятными изменениями и только ещё больше запутает падавана при попытке отследить изменения и «раскрутить обратно». Обычный бэкап для этих целей гораздо лучше, темболее что его можно делать частично — отдельно по логическим модулям.


      1. iig
        11.10.2018 10:45
        +1

        Комментирование кода не учит ничему полезному, а использование СКВ — наоборот. А если файликов с backup'ами будет пару десятков, в них не то что падаван, магистр не разберется, в каком из них что сломалось а что починилось ;)
        А в применении к метеостанции — отсутствие датчика == отказ датчика, штатная ситуация, которая должна решаться внутри прошивки, а не перекомпиляцией кода.


    1. tim4dev Автор
      11.10.2018 12:14

      Можно и так. СКВ отдельно надо изучать, а кто знает тот так и делает.


  1. bulaev
    11.10.2018 11:54

    Почему не используете планировщик? Код гораздо лаконичнее и предсказуемый, если разбить его на отдельные задачи планировщиком. Неплохой вариант в плане потребления ресурсов, например, TaskSheduler


  1. alfaterra
    11.10.2018 12:16

    Как я уже писал вы можете начать и не имея всех модулей под рукой. Например, можно начать не имея радиомодуля или ESP8266. Датчик барометрического давления BMP180 также может отсутствовать. Добавите потом. Правда в этом случае вам (возможно) придется самостоятельно закомментировать в скетче те участки кода, которые отвечают за взаимодействие с отсутствующими блоками

    Вообще если такая потребность есть тогда правильно было автору использовать условное компилирование. Подобно:


    1. tim4dev Автор
      11.10.2018 12:20

      Всё верно.
      Это был копромисс.