Интернет вещей с RemoteXY: элементы управления

Очередная статья по сервису RemoteXY. В статье рассмотрены элементы управления кнопка, выключатель, переключатель и слайдер. Работа с каждым элементом рассмотрена на практическом примере простых для повторения новичками устройств.

Элементы управления

У всех интерактивных элементов интерфейса есть атрибут «имя переменной», по этому имени идет обращение к элементу в программе микроконтроллера

Рассмотрим пример интерфейса, содержащего переключатель. Имя переключателя по умолчанию «switch_1», при выделении элемента на рабочем поле над ним появляется его имя переменной. При добавлении элементов того же типа имя переменной остается тем же, но меняется его порядковый номер (switch_2, switch_3). Можно изменить имя переменной на произвольное, но в соответствии с правилами именования переменных в С++, а именно:

  • имя переменной не должно начинаться с цифры;
  • имя переменной не должно включать следующие символы: , / : * ? » < > |
  • имя переменной всегда должно начинаться с маленькой буквы и иметь «верблюжий» регистр (lightButton), но это скорее рекомендация соглашения об именовании.


Все имена переменных хранятся в структуре, которой присваивается имя RemoteXY. Структура – своего рода контейнер различных переменных, которому можно присвоить имя. Структура может содержать в себе переменные различного типа одновременно.

// конфигурация интерфейса  #pragma pack(push, 1)

uint8_t RemoteXY_CONF[] =

 { 1,0,17,0,6,5,0,2,0,34

 ,18,22,11,2,79,78,0,79,70,70

 ,0 }; //в этом массиве зашифрованы все элементы интерфейса, их размеры, местоположение, цвет и другие настройки. Ни в коем случае не меняйте содержимое.

// Все имена переменных хранятся в этой структуре в виде объектов структуры struct {

 // input variable

 uint8_t switch_1; // именно здесь указано имя переменной переключателя из примера выше

   // other variable

 uint8_t connect_flag; // =1 if wire connected, else =0

} RemoteXY; //здесь структуре присваивается имя структуры, по которому мы будем обращаться к объектам структуры

#pragma pack(pop)

 

Обращение к элементу (полю) структуры организовано по образцу «имя_структуры.имя_переменной», таким образом, что бы прочитать состояние переключателя switch_1 из структуры RemoteXY, необходимо обратиться к этому переключателю RemoteXY.switch_1

digitalWrite(PIN_SWITCH_1, (RemoteXY.switch_1==0)?LOW:HIGH);.

 

Кнопка

Элемент «кнопка» имитирует работу кнопки без фиксации. Имеет параметры: цвет, имя переменной (по умолчанию button), надпись на кнопке, отрисовка кнопки (круглая или прямоугольная) и привязка к выводу.

Кнопка принимает значение 1 если нажата, 0 если не нажата. Проверка состояния осуществляется простым сравнением RemoteXY.button_1= =0.

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

Объявление кнопки в структуре:

struct {   // input variable
  uint8_t button_1; // 0   // other variable
  uint8_t connect_flag;  // =1 if wire connected, else =0 } RemoteXY; 

​Если при создании интерфейса привязать кнопку к выводу, то генератор кода в функции loop() создает строку

digitalWrite(PIN_BUTTON_1, (RemoteXY.button_1==0)?LOW:HIGH);

Проект «кодового» замка

Закрепим полученные знания на практике, создав проект «кодового» замка. Слово «кодовый» недаром написано в кавычках, ведь вся секретность замка основана на пароле модуля связи.

Создадим подключение со следующей конфигурацией:

Для этого проекта я решил использовать NodeMCU. Конфигурация соединения – точка доступа Wi-Fi, таким образом, достигается независимость устройства от других сетей. Обратите внимание на пароль, именно он обеспечивает «секретность» замка, другой защиты не предусмотрено.

Внешний вид интерфейса.

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

Замок построен по следующей схеме.

Как известно выводы микроконтроллеров не могут дать достаточной силы тока для работы сильноточных устройств, поэтому я  предлагаю использовать микросхему ULN2003, которая представляет собой сборку из 7 мостов Дарлингтона с защитными диодами. Схема питается от сборки батарей типа АА подключенных последовательно, NodeMCU работает непосредственно от них через встроенный стабилизатор.

Отдельного внимания заслуживает рассмотрение работы микросхемы ULN2003. Вывод 8 – общий, 9 – подключается к источнику тока, от которого будет работать электромагнитный замок (в нашем случае это батарейки АА, общим напряжением 6 вольт). Большим плюсом этой микросхемы является то, что сигнал проходит «напрямую», от входа на выводе 1 на выход на выводе 16, от 2 к 15 и так далее, что облегчает создание печатных плат. Так же микросхема содержит защитные диоды на каждом канале и подходит для подключения индукционной нагрузки, которой является и электромагнитный замок. Один канал микросхемы может выдержать ток до 0,5 ампера, вся микросхема ток до 2 ампер на всех каналах. Если необходимо подключить нагрузку более 0,5 ампер можно использовать несколько каналов микросхемы параллельно. При прохождении через микросхему логический сигнал инвертируется.

Схема для любителей программы Fritizing.

Та же схема в классическом представлении (создана так же в Fritizing, и мне не нравится как коряво получаются принципиальные схемы в нем).

Рассмотрим сгенерированный он-лайн редактором исходный код.

//////////////////////////////////////////////
// RemoteXY include library //
//////////////////////////////////////////////

// определение режима соединения и подключение библиотеки RemoteXY
#define REMOTEXY_MODE__ESP8266WIFIPOINT_LIB
#include <ESP8266WiFi.h>

#include <RemoteXY.h>

// настройки соединения
#define REMOTEXY_WIFI_SSID «RemoteXY»
#define REMOTEXY_WIFI_PASSWORD «35673810» //Это пароль, который обеспечивает секрет-ность всего замка
#define REMOTEXY_SERVER_PORT 6377

// конфигурация интерфейса
#pragma pack(push, 1)
uint8_t RemoteXY_CONF[] =
{ 1,0,49,0,6,4,0,1,1,62
,18,24,24,2,208,158,208,186,0,129
,0,7,27,47,6,12,208,158,209,130
,208,186,209,128,209,139,209,130,209,140
,32,208,180,208,178,208,181,209,128,209
,140,58,0 };

// структура определяет все переменные вашего интерфейса управления
struct {

// input variable
uint8_t button_1; // 0

// other variable
uint8_t connect_flag; // =1 if wire connected, else =0

} RemoteXY;
#pragma pack(pop)

/////////////////////////////////////////////
// END RemoteXY include //
/////////////////////////////////////////////

#define PIN_BUTTON_1 D0//привязка кнопки к выводу D0,наименование вывода заменено константой

void setup()
{
RemoteXY_Init ();

pinMode (PIN_BUTTON_1, OUTPUT);//вывод к которому привязана кнопка сконфигурирован на выход

// TODO you setup code

}

void loop()
{
RemoteXY_Handler ();

digitalWrite(PIN_BUTTON_1, (RemoteXY.button_1==0)?LOW:HIGH);//этот код сгенерирован онлайн редактором автоматически,
//потому что была выбрана привязка к выводу D0

// TODO you loop code
// используйте структуру RemoteXY для передачи данных

}

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

Выключатель

Выключатель, название говорит само за себя. Имеет параметры цвет, имя переменной, надпись включения, надпись выключения и привязка к выводу.

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

Поле структуры принимает значение 0 в положении «выключено» и 1 в положении «включено». Проверить состояние выключателя можно простым сравнением поля структуры с 0 и 1 (например, RemoteXY.switch_1= =0). Так же состояние выключателя можно изменить в самой программе, просто присвоив полю структуры значение 0 или 1. Но если изменение значения произойдет в то время, когда смартфон подключен к контроллеру, то видимое переключение выключателя не произойдет, на экране выключатель останется в том же положении (хотя значение поля структуры изменится). Чтобы положение выключателя изменилось, надо отключиться от контроллера, а далее подключиться вновь.

Зачатки умного дома

У вас бывало такое, что вечером забравшись в теплую кровать, вы вспоминали, что забыли выключить свет, допустим в ванной. Вставать и идти выключать? Не наш метод. Предлагаю проект (который в последующем станет основой умного дома), в котором будет реализовано дистанционное управление освещением. Управление освещением со смартфона, с одной стороны удобно для управления издали, но не доставать же смартфон каждый раз, когда надо включить или выключить свет. Потому управление освещением будет продублировано, и со смартфона и обычной кнопкой, вместо стандартного выключателя. Лампочка (энергосберегающая, накаливания, светодиодная, не важно) как правило, подключается к сети переменного тока напряжением 220 вольт, поэтому подключать их следует через реле. Вы можете использовать готовые блоки реле или самостоятельно подключить реле к контроллеру, как это сделать смотрите в книге Рюмик С.М. 1000 и одна микроконтроллерная схема.

Конфигурация подключения и внешний вид интерфейса представлен на скриншотах.

Дальнейшие пояснения в комментариях к исходному коду.

//////////////////////////////////////////////

//   RemoteXY include library   //

//////////////////////////////////////////////

// определение режима соединения и подключение библиотеки RemoteXY #define REMOTEXY_MODE__HARDSERIAL

#include <RemoteXY.h>

// настройки соединения #define REMOTEXY_SERIAL Serial1

#define REMOTEXY_SERIAL_SPEED 9600

// конфигурация интерфейса  #pragma pack(push, 1)

uint8_t RemoteXY_CONF[] =

 { 1,0,53,0,6,4,1,2,0,39

 ,3,22,11,2,79,78,0,79,70,70

 ,0,129,0,4,6,32,4,0,208,161

 ,208,178,208,181,209,130,32,208,178,32

 ,208,186,208,190,209,128,208,184,208,180

 ,208,190,209,128,208,181,0 };

 // структура определяет все переменные вашего интерфейса управления struct {

 // input variable

 uint8_t switch_1; // этим выключателем будем включать и выключать реле, через которое подключено освещение

// other variable

 uint8_t connect_flag; // =1 if wire connected, else =0

} RemoteXY;

#pragma pack(pop)

/////////////////////////////////////////////

//   END RemoteXY include   //

/////////////////////////////////////////////

#define PIN_SWITCH_1 13 //к этому выводу подключено реле

#define PIN_SWITCH_2 12 //к этому выводу подключена кнопка включения/выключения освещения

void setup() {

 RemoteXY_Init ();   pinMode (PIN_SWITCH_1, OUTPUT); //вывод с подключенным реле настроен как выход

 pinMode (PIN_SWITCH_2, INPUT);  //вывод к которому подключена кнопка

 digitalWrite(PIN_SWITCH_2, HIGH); //включаем подтягивающие резисторы

  }

void loop() {  RemoteXY_Handler ();

 digitalWrite(PIN_SWITCH_1, (RemoteXY.switch_1==0)?LOW:HIGH); //если поле структуры RemoteXY.switch_1 равно нулю, то свет выключен, если 1, то включен

   if ((digitalRead(PIN_SWITCH_2)==LOW)&&(RemoteXY.switch_1==1)) { //если нажата кнопка и поле структуры RemoteXY.switch_1 равно 1,
//то выключаем освещение присвоив полю структуры RemoteXY.switch_1 значение 0

   RemoteXY.switch_1=0;

 }

 if ((digitalRead(PIN_SWITCH_2)==LOW)&&(RemoteXY.switch_1==0)) { //тут наоборот, если нажата кнопка, а реле выключено,
//то включаем реле посредством присваивания полю структуры RemoteXY.switch_1 значения 1

   RemoteXY.switch_1=1;

 }

}

Внимательные читатели наверняка заметили, что в коде нет никакой защиты от дребезга контактов. 

Переключатель

Переключатель может принимать одно из нескольких значений (от 2 до 10) и передает на микроконтроллер результат в виде числа от 0 до 9 (А=0, В=1 и так далее). Имеет параметры цвет, имя переменной (по умолчанию select), количество положений (от 2 до 10) и ориентация (горизонтальная или вертикальная). Значения переключателя всегда обозначаются буквами латинского алфавита, в отличие от кнопки и выключателя, редактировать текст на переключателе не возможно.

Проверять значение положения переключателя удобно при помощи функции switch

switch (RemoteXY.select_1) {   case 0:   /* текущее состояние A */   break;

   case 1:   /* текущее состояние B */   break;

   case 2:   /* текущее состояние C */   break;

   case 3:   /* текущее состояние D */   break;

 }

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

Генератор эффектов для гирлянды на 8 каналов

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

Дальнейшие пояснения в комментариях к исходному коду.

//////////////////////////////////////////////

//   RemoteXY include library   //

//////////////////////////////////////////////

// определение режима соединения и подключение библиотеки RemoteXY #define REMOTEXY_MODE__HARDSERIAL

#include <RemoteXY.h>

#include <relay8.h>//для управления реле я рекомендую использовать библиотеку relay8.h,
//кроме прямого управления реле в ней описаны функции для эффектов, которые я буду применять в этом проекте.
//Библиотека способна управлять до 8 реле одновременно, но не больше.

relay8 relay(0, 1, 2, 3, 4, 5, 6, 7); //здесь перечислены выводы, к котором подключены реле.

/*я буду подключать гирлянду через блок из 8 реле, поэтому я задействую все 8 возможных каналов.
Количество каналов можно убавить и подключить любую китайскую гирлянду (обычно в них 3 или 4 канала).*/

// настройки соединения.

#define REMOTEXY_SERIAL Serial1

#define REMOTEXY_SERIAL_SPEED 9600

// конфигурация интерфейса  #pragma pack(push, 1)

uint8_t RemoteXY_CONF[] =

 { 2,0,98,0,6,11,1,3,6,5

 ,3,17,93,1,2,0,31,82,22,11

 ,2,79,78,0,79,70,70,0,129,0

 ,28,8,29,6,0,208,147,208,184,209

 ,128,208,187,209,143,208,189,208,180,208

 ,176,0,129,0,25,16,35,6,0,54

 ,32,209,141,209,132,209,132,208,181,208

 ,186,209,130,208,190,208,178,0,129,0

 ,26,72,30,6,0,208,146,208,186,208

 ,187,209,142,209,135,208,184,209,130,209

 ,140,0 };

  // структура определяет все переменные вашего интерфейса управления struct {

   // input variable

 uint8_t select_1; // этим переключателем будем выбирать эффект

 uint8_t switch_1; // этим выключателем будем останавливать и запускать эффекты

   // other variable

 uint8_t connect_flag; // флаг соединения смартфона с контроллером нам тоже пригодится, но о нем позже

} RemoteXY;

#pragma pack(pop)

/////////////////////////////////////////////

//   END RemoteXY include   //

/////////////////////////////////////////////

void setup() {

 RemoteXY_Init ();   // TODO you setup code

  }

void loop() {  RemoteXY_Handler ();

//если соединение смартфона и контроллера установлено И если выключатель в положении ON, то входим в функцию выбора

 if ((RemoteXY.switch_1==1)&&(RemoteXY.connect_flag==1)) {

   switch (RemoteXY.select_1) {   case 0: //если выбран пункт А переключателя, то

   {relay.allOn(); //включаем все реле

   delay(200); //ждем 0,2 секунды

   relay.allOff(); //выключаем все реле

   delay(200); //снова ждем 0,2 секунды

   }

   break;

   case 1: //если в положении В, то выполняем этот эффект. Ну и так далее.

   {relay.cycleUp(50); //Описывать каждый эффект я не буду, лучше один раз увидеть.

   relay.cycleDown(50);

/*во всех функциях библиотеки relay8.h (кроме allOn и allOff) можно установить скорость эффекта
в миллисекундах (по умолчанию 250). Я ставлю большую скорость, потому что при скорости 250
соединение смартфона с контроллером обрывается (а мы же помним, что нельзя использовать паузы в
программах с использованием RemoteXY).*/

   }

   break;

   case 2:

   relay.cycleUp(50);

   break;

   case 3:   relay.cycleDown(50);

   break;

   case 4:   {relay.chaseUpOn(50);

   relay.chaseUpOff(50);

   }

   break;

   case 5: //всего библиотека relay8.h может обеспечить 6 эффектов

   {relay.chaseDownOn(50);

   relay.chaseDownOff(50);

   }

   break;

   }

 }

   if (RemoteXY.connect_flag==0) //если соединение смартфона и контроллера разорвалось, то

   {RemoteXY.switch_1=0; //устанавливаем выключатель в положение OFF.

   } //в этом случае при повторном соединении эффекты не запустятся самопроизвольно

}

В этом примере наглядно видно, к чему приводят функции типа delay в коде, где используется сервис RemoteXY. Команда, отданная со смартфона, доходит до контроллера лишь через 5-10 секунд.

 Слайдер

Слайдер позволяет передать в контроллер значение своего положения, значение лежит в диапазоне от 0 до 100 (или от -100 до 100). Значение поля структуры прямо пропорционально зависит от положения слайдера. Имеет параметры цвет, имя переменной (по умолчанию slider_1), ориентация (вертикально или горизонтально), позиция центра и авто центрирование.

Позиция центра (сверху, посредине или снизу в вертикальном положении слайдера и справа, посредине или слева для горизонтального положения слайдера) показывает, в каком положении слайдера поле структуры будет принимать значение 0. Следует обратить внимание на позицию центра «посредине», в этом случае диапазон значений поля структуры принимает значения от -100 до 100. Во всех остальных случаях от 0 до 100. Авто центрирование возвращает положение слайдера в 0 как лишь будет убран палец со слайдера.

Изначально положение слайдера можно задать, присвоив в функции setup полю структуры необходимое значение, которое должно лежать в диапазоне от 0 до 100 (или в диапазоне от -100 до 100 для положения центра посредине). Но если включено авто центрирование, то значение будет сбрасываться все равно в 0, независимо от того какое значение было задано изначально.

Диммер для светодиода

Конфигурация подключения произвольна (в моем случае соединение по Bluetooth, контроллер arduino mega2560, модуль связи HC-05, подключение модуля связи по Serial1 на скорости 9600). Ориентация экрана – вертикальная, цвета произвольны. На рабочем поле слайдер, высота слайдера по высоте экрана, слайдер расположен посредине экрана. Параметры слайдера по умолчанию. Назначение проекта – плавное регулирование свечения светодиода, установленного на плате arduino. Дальнейшие примечания к коду в комментариях.

//////////////////////////////////////////////

//   RemoteXY include library   //

//////////////////////////////////////////////

// определение режима соединения и подключение библиотеки RemoteXY #define REMOTEXY_MODE__HARDSERIAL

#define led 13 //светодиод подключен к выводу 13

#include <RemoteXY.h>

// настройки соединения #define REMOTEXY_SERIAL Serial1

#define REMOTEXY_SERIAL_SPEED 9600

// конфигурация интерфейса  #pragma pack(push, 1)

uint8_t RemoteXY_CONF[] =

 { 1,0,10,0,6,2,1,4,0,24

 ,4,11,89,2 };

  // структура определяет все переменные вашего интерфейса управления struct {

   // input variable

 int8_t slider_1; // =0..100 положение слайдера

   // other variable

 uint8_t connect_flag; // =1 if wire connected, else =0

} RemoteXY;

#pragma pack(pop)

/////////////////////////////////////////////

//   END RemoteXY include   //

/////////////////////////////////////////////

void setup() {

 RemoteXY_Init ();  pinMode(led, OUTPUT); //вывод 13 сконфигурирован на выход  }

void loop() {  RemoteXY_Handler ();

   analogWrite(led, map(RemoteXY.slider_1, 0, 100, 0, 255)); //используем ШИМ для изменения яркости светодиода.
//Поскольку значение слайдера ограничено диапазоном 0-100, то используем функцию map, что бы привести значение к диапазону 0-255

}

В следующей статье будут рассмотрены элементы джойстик, поле ввода и RGB круг.  

Прикрепленные файлы:

Добавить комментарий

Ваш адрес email не будет опубликован.