Ruby-Дайджест за неделю (24 янв — 31 янв)

Навигация:

Intern section

Данный раздел дайджеста предназначен для начинающих рубистов. Здесь можно будет найти различные мануалы/гайды, литературу.
Если ты хочешь пощупать и вкатиться в Ruby-разработку, то это будет отличной отправной точкой в столь интересном пути.

Мануалы/Гайды

Парсинг веб-страниц при помощи Ruby.

  • Язык: русский.

  • Сложность: легко.

  • Ссылка: статья на Хабре.

  • Данная статья является переводом Web Scraping with Ruby, призвана помочь начинающим программистам разобраться с парсингом на Ruby, при помощи таких гемов: open-uri, nokogiri.

В дополнение к этому материалу можно посоветовать данный видеоролик:

Он на английском языке, но тут по-путно можно научиться работать с прекрасным инстрментом byebug.

Byebug — это отладчик Ruby кода.

Поучаствуй в дайджесте.
Поучаствуй в дайджесте.

Литература

Путь Ruby.

  • Язык: русский/английский.

  • Страниц: 660.

  • Преимущество: более 400 примеров кода.

  • Недостаток: используется старая версия Ruby.

Рецензии/отзывы.

Альберт.

Отзыв с сайта Labirint.

Хоть руби не особо востребованный язык, но в этой книге он хорошо
расскрыт. Книга дороговата, даже очень. Но толк в ней есть. Покупать
только в крайней необходимости. Электронная версич есть в сети.

Игорь.

Отзыв с сайта Labirint.

Недавно заказал, сейчас в процессе изучения. На мой взгляд, эта книга достойна сравнения со всемирноизвестной «философией Java», только
для ruby, если говорить о русскоязычных изданиях. Подача материала и
качество перевода позволяют с интересом изучать эту книгу.

Небольшая статья о книге на Хабре.


Held section

Данный раздел дайджеста предназначен для уже состоявшихся рубистов. Здесь можно будет найти различные мануалы/гайды, обновления/появление гемов, конференции и вакансии рынка труда.

Обновление популярных гемов.

  • Появилась новая версия bundler (2.3.6)

  • Свое обновление так же получил i18n (1.9.1)

  • Новый релиз puma (5.6)

Краткие новости.

  • WebPacker в скором времени перестанет поддерживать Ruby.

  • В ближайшем будущем CRuby может содержать в себе код Rust. Matz одобрил.

  • Spree Commerce получил релиз 4.4. Система электронной коммерции Rails с открытым исходным кодом.

  • Sidekiq исполнилось 10 лет. Рассказ автора.

Ruby Habr

Как рутинное обновление гемов привело к созданию подписок на $73К
Читать на Хабре.


Работа Ruby-разработчиком.

Tripment Health

Описание вакансии:
Ищем FullStack разработчика (RoR+React), который отличает PUT от PATCH, понимает, зачем нужен webpacker, и знает, что значит сделать.

Зарплатная вилка:
2500 — 4500 USD (прямой контракт)

Тип работы:
Полный рабочий день

Тип занятости:
Удаленка

Перейти к вакансии.


Плейлист является открытым. Вы можете добавлять свои треки и работать в свое удовольствие.
Открыть на Spotify.

Друзья дайджеста.

На этом все, до следующего дайджеста.

Данила Кравченко

Ruby-разработчик / Ведущий RubyDigest на habr.com


ссылка на оригинал статьи https://habr.com/ru/post/648691/

«Из разработчика в девопс» — стажировка в Southbridge

В феврале мы запускаем в Southbridge новую программу стажировки — «Из разработчика в девопс». Участие бесплатное. Программа рассчитана на три с половиной месяца, выделять на обучение нужно примерно по четыре часа в день.

Под катом рассказываем, что в программе и как пройти отбор.

Программа стажировки

Что будем изучать в теории и отрабатывать на практике:

  • архитектуру Linux и администрирование Linux-серверов;

  • стек веб-технологий: Nginx, PHP-FPM/Apache, MySQL, Memcached;

  • технологии контейнеризации, работу с Docker;

  • принципы методологии девопс;

  • Git: возможность работать с локальными и удалёнными репозиториями;

  • работу с Kubernetes: настройку и обслуживание отказоустойчивого кластера, работу с сетевой безопасностью;

  • мониторинг и логирование в Kubernetes: работу с EFK, Prometheus, Loki, Grafana;

  • построение пайплайнов с Gitlab CI/CD, интеграцию с Kubernetes, проверку качества кода;

  • управление облачной инфраструктурой с Ansible и Terraform;

  • потренируем софт-скиллы: работу в команде, самостоятельное обучение, тайм-менеджмент.

Кого приглашаем

Ждём на стажировку разработчиков с опытом от двух лет, которые планируют развиваться в сторону девопс. Понадобятся знания базы Linux, отлично, если есть опыт в системном администрировании. Перед началом обучения — конкурсный отбор.

По результатам стажировки есть шанс присоединиться к команде Southbridge или командам наших партнёров.

Чтобы оставить заявку, отправьте резюме на почту: job@southbridge.ru

Почитать о прошедших стажировках Southbridge можно здесь:

Как проходит DevOps-стажировка в Southbridge

«Сайт падал на полторы минуты в сутки, но мы уже решили эту проблему». Итоги стажировки и онбординга нового инженера

Добро пожаловать в Зольни: как из стажировки Southbridge появилась новая компания


ссылка на оригинал статьи https://habr.com/ru/company/southbridge/blog/648817/

5 заблуждений про DevSecOps

Популярность DevSecOps, философии интеграции методов безопасности в DevOps, в последние годы набирает обороты. И чем больше людей проникается философией DevSecOps, тем больше мифов вырастает вокруг этого направления. Под катом мы разберем некоторые наиболее часто встречающиеся заблуждения.

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


Внедрение DevSecOps приводит бизнес к потере контроля над процессами разработки

Нетрудно догадаться, где скрыты корни этого заблуждения. В сообществе разработчиков нередко можно столкнуться с мнением, что любые меры безопасности продукта (сверх понятных и привычных) являются ничем иным, как препятствием свободе и творчеству. Вместе с тем, тимлидам, руководителям проектов и прочим сотрудникам старшего звена дополнительные меры контроля только на руку. Измеримость работы и темпа ее исполнения — это крайне полезные метрики, как с точки зрения time-to-market, так и с экономической.

Некоторые разработчики переживают, что из-за внедрения DevSecOps и сопутствующих инструментов автоматизации их роль в команде может потерять значимость. Этот страх продиктован тем, что классические, ручные процессы дают (чаще всего ложное) ощущение рабочего процесса и контроля над результатом.
Таким образом получается, что страх потерять контроль из-за внедрения DevSecOps возникает не у руководителей, а преимущественно у исполнителей.

Побороть это заблуждение можно традиционным методом: обучением команды новой методологии, объяснением ее полезности. Не лишней также будет демонстрация успешных кейсов внедрения DevSecOps.

DevSecOps — это некое решение, которое можно купить и развернуть у себя

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

Разумеется, это представление в корне ошибочно. DevSecOps — это, в первую очередь, описание подхода к разработке, методология. Ее применение может включать использование некоторых специализированных программ и иных инструментов, платных и бесплатных, однако в качестве отдельного продукта DevSecOps нигде не продается.

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

DevSecOps — это универсальная модель, подходящая всем «из коробки»

Согласитесь, было бы крайне удобно развернуть комфортную и безопасную среду разработки приложений, которая бы идеально подошла вашей организации, к тому же была бы не требовательна к обслуживанию и могла функционировать неограниченно долгое время. Увы, всё это не про DevSecOps.

Некоторые базовые концепции методологии применимы практически к любым организациям. Однако внедрение DevSecOps следует начинать максимально внимательно и осторожно, чтобы не навредить действующим в компании рабочим процессам. Каждая компания уникальна, обладает собственными корпоративной культурой, миссией и целями.

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

DevSecOps — это брат-близнец DevOps’а

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

Чтобы подходы DevSecOps работали, отделам безопасности, разработки и эксплуатации необходимо найти общий язык и наладить эффективную совместную работу. При этом методология не предусматривает главенство безопасности над всеми остальными процессами. Суть философии DevSecOps состоит в том, чтобы на стыке требований трех подразделений был найден оптимальный и подходящий вариант.

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

2 мифа в одном: DevSecOps — это только про технологии/это только про корпоративную культуру

Мы решили объединить два этих мифа под одним заголовком, поскольку они имеют общий корень. Представление о DevSecOps как об исключительно технологической методологии ошибочно, поскольку оно игнорирует людей как факторы рабочего процесса. В чем-то это заблуждение сходно с предыдущим.

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

Кстати, теме DevSecOps посвящен отдельный урок нашего бесплатного курса Cloud DevOps. Вести его будут эксперты #CloudMTS, VMware, Microsoft.

На курсе вы сможете:

  • узнать о стратегиях миграции с монолита на микросервисы;
  • изучить основы Kubernetes;
  • познакомиться с контейнерным подходом;
  • разобраться с тонкостями Kubernetes в продуктивной среде;
  • освоить инструменты автоматизации процессов, реализации CI/CD;
  • оценить возможности MLOps-платформы.

Ознакомиться с программой Cloud DevOps, экспертами и зарегистрироваться можно на странице курса. Удачи в освоении новых знаний!


ссылка на оригинал статьи https://habr.com/ru/company/cloud_mts/blog/648353/

Retrieval Transformer в картинках

Резюме: Новые языковые модели могут быть намного меньше GPT-3, но при этом достигать сравнимых результатов благодаря использованию запросов к базе данных или поиску информации в Интернете. Ключевая идея заключается в том, что построение все более и более крупных моделей — не единственный способ повысить качество.

Последние несколько лет ознаменовались появлением больших языковых моделей (Large Language Models, LLM) — моделей машинного обучения, которые способствовали быстрому развитию сферы машинной обработки и генерации естественного языка. Некоторые из основных вех развития области с 2017 года включают в себя:

  • Оригинальный Трансформер (Transformer) бьет предыдущие рекорды качества машинного перевода.
  • BERT популяризирует процесс предварительного обучения, а затем тонкой настройки, а также контекстуализированные эмбеддинги слов на основе Трансформера. В скором времени он начинает использоваться в Google Search и Bing Search.
  • GPT-2 демонстрирует способность компьютера достигать сравнимого с человеком качества написания текстов.
  • Сначала T5, а затем T0 раздвигают границы трансферного обучения (обучение модели на одной задаче, а затем ее успешное применение для смежных), представляя множество различных задач в виде задачи преобразования текста в текст.
  • GPT-3 показала, что массовое масштабирование генеративных моделей может привести к возникновению самых удивительных приложений (и индустрия продолжает обучать все более крупные модели, такие как Gopher, MT-NLG и т. д.).

Какое-то время казалось, что масштабирование все более и более крупных моделей является основным способом повышения производительности. Недавние разработки в этой области, такие как RETRO Transformer от DeepMind и WebGPT от OpenAI, обращают эту тенденцию вспять, показывая, что небольшие генеративные языковые модели могут работать наравне с большими, если мы дополняем их возможностью искать или запрашивать необходимую информацию.

В данной статье рассказывается о RETRO (Retrieval-Enhanced TRansfOrmer) от DeepMind и о том, как она работает. Модель показывает результаты, сравнимые с GPT-3, несмотря на то, что она составляет всего 4% от размера последней (7.5 миллиардов параметров против 185 миллиардов у GPT-3 Da Vinci).

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

RETRO была представлена в статье Improving Language Models by Retrieving from Trillions of Tokens, которая основывается и, в свою очередь, продолжает широкий спектр работ исследовательского сообщества, посвященных задаче извлечения информации. Однако данная статья посвящена объяснению работы самой модели, а не тому, что нового она привнесла в данную область исследований.

Почему это важно: отделение языковой информации от знаний о мире

Языковое моделирование обучает модели предсказывать следующее слово — по сути, заполнять пропуск в конце предложения.

Заполнение пропуска иногда требует знания фактической информации (такой как имена или даты). Например:

Затравка на входе: «Фильм Дюна был выпущен в …».

В других случаях знания языка достаточно, чтобы догадаться, что стоит на месте пропуска. Например:

Затравка на входе: «его популярность распространялась из уст в уста, чтобы позволить Герберту начать работать в полную …».

Это различие важно, потому что LLM закодировали все, что они знают, в своих параметрах. Хотя такая стратегия имеет смысл для языковой информации, она оказывается неэффективной для фактической информации и знании о мире.

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

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

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

Технически RETRO представляет собой модель энкодер-декодер, как и оригинальный Трансформер. Однако в RETRO входная последовательность дополняется извлеченной из базы данных информацией. Модель находит наиболее вероятные последовательности в базе данных и добавляет их на вход. Здесь происходит магия, и RETRO генерирует выходной прогноз.

RETRO использует базу данных для дополнения входной последовательности. Для извлечения необходимой информации из базы данных используется первоначальный текст на входе.

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

Исследование базы данных для извлечения информации RETRO

База данных — это хранилище ключей-значений.

Ключ представляет собой стандартный эмбеддинг предложения, полученный с помощью BERT’а.

Значение представляет собой текст, состоящий из двух частей:

  • «Сосед» (Neighbor), который используется для вычисления ключа;
  • «Завершение» (Completion), продолжение текста в исходном документе.

База данных RETRO содержит 2 триллиона многоязычных токенов на основе набора данных MassiveText. И «сосед», и «завершение» имеют длину не более 64 токенов.

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

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

Поиск в базе данных

Прежде чем идти на вход RETRO, входная последовательность проходит через BERT. Полученные контекстуализированные векторы затем усредняются для построения вектора эмбеддинга предложения. Этот вектор затем используется в качестве запроса к базе данных.

Обработка входной последовательности с помощью BERT’а создает контекстуализированные эмбеддинги токенов. Их усреднение дает эмбеддинг предложения.

Этот эмбеддинг предложения затем используется в приближенном поиске ближайшего соседа (https://github.com/google-research/google-research/tree/master/scann).

Извлекаются два ближайших соседа, и их текст становится частью входа в RETRO.

Эмбеддинг предложения из BERT’а используется для извлечения ближайших соседей из нейронной базы данных RETRO. Затем они добавляются к входным данным языковой модели.

Теперь это входные данные в RETRO. Входная последовательность и два её ближайших соседа из базы данных (и их продолжения).

Начиная с этого момента блоки Трансформера и RETRO включают в свою обработку фактическую информацию.

Полученные соседи добавляются на вход языковой модели. Однако внутри модели они обрабатываются немного по-другому.

Высокоуровневая архитектура RETRO

Архитектура RETRO представляет собой стек энкодера и стек декодера.

RETRO Трансформер состоит из стека энкодера (для обработки соседей) и стека декодера (для обработки входных данных).

Энкодер состоит из стандартных блоков энкодера Трансформера (внутреннее внимание (self-attention) + FFNN). Насколько можно судить, RETRO использует энкодер, состоящий из двух блоков энкодера Трансформера.

Стек декодера чередует два типа блоков декодера:

  • Стандартный блок декодера Трансформера (ATTN + FFNN)
  • Блок декодера RETRO (ATTN + Chunked Cross Attention (CCA) + FFNN)

Три типа блоков Трансформера, из которых состоит RETRO.

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

Стек энкодера обрабатывает извлеченные соседи, в результате чего получаются матрицы KEYS и VALUE.

Блоки декодера обрабатывают входной текст так же, как GPT. Он применяет внутреннее внимание к токену входа (каузально, поэтому обращает внимание только на предыдущие токены), затем пропускает его через слой FFNN.

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

Только достигнув декодера RETRO, мы начнем включать извлеченную фактическую информацию. Каждый третий блок, начиная с 9, является RETRO-блоком (что позволяет его входу обслуживать соседей). Итак, слои 9, 12, 15…32 — это блоки RETRO.

Входная последовательность достигает блока декодера RETRO, и начинается поиск информации в базе данных.

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

Блок декодера RETRO извлекает информацию из ближайших соседей с использованием Chunked Cross-Attention.

Предыдущие работы

Дополнение языковых моделей методами извлечения информации – активно развивающаяся область исследований. Некоторые из предыдущих работ в этой сфере включают:

Авторы


ссылка на оригинал статьи https://habr.com/ru/post/648705/

Kincony KC868-A4: ультимативный гайд. Часть 2. Программирование компонентов

Продолжаем ультимативный гайд по контроллеру Kincony KC868-A4, начатый в предыдущей статье. Сегодня мы подробно разберём распиновку KC868-A4 и познакомимся с принципами программирования компонентов (функциональных блоков) этого контроллера. Все примеры будут сопровождаться готовым рабочим кодом, который вы можете использовать в своих проектах.

Начнём мы с распиновки центрального модуля ESP32-S и разбора того, что и как подключено к нему инженерами компании Kincony.

▍ Распиновка KC868-A4

Микроконтроллер ESP32 всем хорош, но есть у него один врождённый недостаток — крайне малое число свободных GPIO контактов. И каждый, кто хочет спроектировать контроллер на ESP32 или хотя бы просто применить его в своём более-менее развитом проекте, вынужден каким-то образом решать эту проблему.

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

Инженеры компании Kincony так и сделали — постарались подобрать набор из, на их взгляд, наиболее востребованных компонентов (функциональных блоков), куда вошли:

  • 4 цифровых входа
  • 4 аналоговых входа
  • 2 аналоговых выхода
  • 4 реле
  • Датчик(и) температуры/влажности
  • Интерфейс RS232
  • Модули (R/T) 433 МГц
  • Инфракрасные (IR) модули (R/T)
  • Пищалка (buzzer)

Этот набор забрал все свободные GPIO контроллера ESP32, больше не осталось ни одного контакта, к которому вы могли бы подключить что-то своё. Например, индикатор, который не помешал бы любому контроллеру.

Но глядя на то, что инженеры Kincony установили на плату KC868-A4, можно сказать, что у них получилось довольно сбалансированное решение для небольших проектов и целей обучения программированию микроконтроллеров.

Проблема заключается в том, что если вы захотите подключить какую-то свою деталь или модуль к KC868-A4, то без паяльника и соответствующей квалификации у вас ничего не получится — свободных для подключения GPIO просто нет.

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

Итак, ниже представлено сочинение инженеров компании Kincony на тему «Как я распределил GPIO контакты ESP32», записанное мной в виде таблицы. В ближних к контроллеру столбцах указаны обозначения линий и подключений из принципиальной схемы (см. предыдущую статью), а в дальних — входы и выходы функциональных блоков контроллера KC868-A4.

В целом неплохо, основным достоинством такого расклада GPIO я бы назвал то, что всё это реально работает и не мешает друг другу.

Если бы проектированием Kincony KC868-A4 занимался я, то я бы в первую очередь избавился от подключения беспроводных модулей на 433 МГц, как архаичного, в пользу чего-нибудь более современного, типа nRF24 или LoRa, вывел бы контакты для подключения оборудования по I2C и SPI и повесил бы цифровые входы/выходы на расширители портов. А также добавил бы блок часов реального времени и вывел блок реле в отдельный модуль на DIN-рейку. Но тогда это был бы уже совсем другой контроллер, поэтому давайте спустимся с небес на землю и продолжим разбор Kincony KC868-A4.

С распределением GPIO контактов ESP32 всё более-менее понятно и теперь, вооружившись этой информацией, давайте приступим к собственно программированию отдельных функциональных блоков Kincony KC868-A4 и начнём мы с программной среды.

▍ Программная среда для KC868-A4

Программировать контроллер Kincony KC868-A4 можно в любой подходящей для этого среде — вы можете использовать для этого вашу любимую IDE, я же буду приводить примеры для среды Arduino 1.8.5. При этом предполагается, что вы обладаете необходимой квалификацией и знакомы с работой в Arduino IDE и умеете программировать микроконтроллер ESP32.

Для работы с Kincony KC868-A4, из всего списка поддерживаемых контроллеров вам нужно выбрать вариант «NodeMCU-32S». Это прозрачно намекает на то, что Kincony KC868-A4 является расширенной и дополненной различной периферией версией NodeMCU-32S.

Остальные настройки видны на скриншоте, вам нужно выставить у себя такие же (кроме номера порта, который у вас будет своим). Теперь переходим к разбору примеров программирования функциональных блоков контроллера Kincony KC868-A4.

▍ Программируем реле KC868-A4

Начнём мы конечно с управления реле, как с самого простого и востребованного функционала подобных контроллеров. Реле, как это видно на вышеприведённой схеме распиновки, подключены к GPIO 2, 15, 5, 4. Для примера управления реле контроллера Kincony KC868-A4 создадим скетч, который по очереди переключает реле, создавая эффект «бегущего огня».

/*   Kincony KC868-A4   Relays example */  byte pins[] = {2, 15, 5, 4}; byte pos = 0;  void setup() {   Serial.begin(115200);   Serial.println(F("Start Kincony KC868-A4 Relays example..."));    pinMode(pins[0], OUTPUT);   pinMode(pins[1], OUTPUT);   pinMode(pins[2], OUTPUT);   pinMode(pins[3], OUTPUT); }  void clear() {   digitalWrite(pins[0], LOW);   digitalWrite(pins[1], LOW);   digitalWrite(pins[2], LOW);   digitalWrite(pins[3], LOW); }  void change(byte n) {   clear();   digitalWrite(pins[n], HIGH); }  void loop() {   change(pos);   Serial.print(F("ON Relay #")); Serial.println(pos);   delay(10000);   pos++;   if (pos > 3) {pos = 0;} } 

Этого примера вполне достаточно, чтобы вы на его основе могли реализовать любую логику управления реле контроллера Kincony KC868-A4. Вот результат вывода в Serial нашего тестового скетча:

▍ Buzzer и Tone

Как я уже отметил ранее, плата Kincony KC868-A4 снабжена приятным дополнением в виде пьезоэлектрического излучателя. Он может помочь вам сделать удобное звуковое оповещение о различных состояниях (авария, какие-то события и т. д.) контроллера. Вот простой пример работы с пищалкой.

/*   Kincony KC868-A4   Buzzer example */  #define BUZZER_PIN 18  void setup() {   Serial.begin(115200);   Serial.println(F("Start Kincony KC868-A4 Buzzer example..."));        pinMode(BUZZER_PIN, OUTPUT); }  void loop() {   digitalWrite(BUZZER_PIN, HIGH); delay(500);   digitalWrite(BUZZER_PIN, LOW);  delay(500); } 

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

/*   Kincony KC868-A4   Buzzer Tone example */  #define BUZZER_PIN 18 const int TONE_PWM_CHANNEL = 0;  void setup() {   Serial.begin(115200);   Serial.println(F("Start Kincony KC868-A4 Buzzer Tone example..."));      ledcAttachPin(BUZZER_PIN, TONE_PWM_CHANNEL); }  void loop() {   ledcWriteNote(TONE_PWM_CHANNEL, NOTE_C, 4); delay(500);   ledcWriteNote(TONE_PWM_CHANNEL, NOTE_D, 4); delay(500);   ledcWriteNote(TONE_PWM_CHANNEL, NOTE_E, 4); delay(500);   ledcWriteNote(TONE_PWM_CHANNEL, NOTE_F, 4); delay(500);   ledcWriteNote(TONE_PWM_CHANNEL, NOTE_G, 4); delay(500);   ledcWriteNote(TONE_PWM_CHANNEL, NOTE_A, 4); delay(500);   ledcWriteNote(TONE_PWM_CHANNEL, NOTE_B, 4); delay(500);   ledcWriteNote(TONE_PWM_CHANNEL, NOTE_C, 5); delay(500); } 

▍ DAC

Kincony KC868-A4 снабжён двумя цифро-аналоговыми преобразователями (DAC), которые могут формировать напряжение в диапазоне от 0 до 10 вольт. Это может пригодиться для управления различным оборудованием. Ниже приведён пример генерации постоянного напряжения 5 вольт на выходе DAC1 контроллера.

/*   Kincony KC868-A4   DAC example */  #define DAC1 26 #define DAC2 25  void setup() {   Serial.begin(115200);   Serial.println(F("Start Kincony KC868-A4 DAC example..."));      int value = 127; // 255 = 10V   dacWrite(DAC1, value); }  void loop() {  } 

Понятно, что генерация постоянного напряжения — это только небольшая область применения DAC, в основном востребована динамическая генерация (периодических) сигналов. Далее вы можете видеть пример кода для генерации пилообразного сигнала на выходе DAC1.

/*   Kincony KC868-A4   DAC Saw example */  #define DAC1 26 #define DAC2 25  byte value = 0;  void setup() {   Serial.begin(115200);   Serial.println(F("Start Kincony KC868-A4 DAC Saw example...")); }  void saw() {   value++; }  void loop() {   dacWrite(DAC1, value);   saw(); } 

Небольшой модификацией этого кода вы можете добиться генерации сигналов контроллером Kincony KC868-A4 практически любой формы.

▍ Цифровые входы

Контроллер Kincony KC868-A4 имеет 4 опторазвязанных цифровых входа «сухой контакт», которые подключены на GPIO 36, 39, 27 и 14. Обслуживание этих входов предельно просто и осуществляется практически одной функцией digitalRead() — вы получаете текущее состояние любого из входов контроллера и далее используете его в коде по своему усмотрению.

/*   Kincony KC868-A4   Digital Input example */  #define INPUT_PIN1 36 #define INPUT_PIN2 39 #define INPUT_PIN3 27 #define INPUT_PIN4 14  void setup() {   Serial.begin(115200);   Serial.println(F("Start Kincony KC868-A4 Digital Input example..."));   pinMode(INPUT_PIN1, INPUT); }  void loop() {   Serial.println(digitalRead(INPUT_PIN1));   delay(10); } 

▍ Аналоговые входы

Kincony KC868-A4 имеет 4 «аналоговых» входа, которые подключены на GPIO 32, 33, 34 и 35. Как уже было отмечено в первой статье, формированием уровней для сигналов 0–5 В и 4-20 мА занимаются входные каскады, которые формируют 2 входа для напряжения (GPIO 32 и 33) и 2 входа для тока (GPI 34 и 35). В коде работа с обоими типами входных сигналов не различается, она осуществляется функцией analogRead() с разрешением 4096.

/*   Kincony KC868-A4   Analog Input example */  #define ANALOG_PIN1 32 // INA1 0-5V #define ANALOG_PIN2 33 // INA2 0-5V #define ANALOG_PIN3 34 // INA3 4-20 mA #define ANALOG_PIN4 35 // INA4 4-20 mA  int value1 = 0;  void setup() {   Serial.begin(115200);   Serial.println(F("Start Kincony KC868-A4 Analog Input example..."));   pinMode(ANALOG_PIN1, INPUT); }  void loop() {   value1 = analogRead(ANALOG_PIN1); // 0-4096   delay(1000);   Serial.printf("Value on pin %d = %d\n", ANALOG_PIN1, value1); } 

▍ Датчики температуры и влажности

Kincony KC868-A4 имеет колодку 3V, S, GND для подключения датчика температуры DS18B20. К этой колодке можно также подключить сеть из нескольких датчиков DS18B20, датчик влажности или любой другой датчик, подходящий по типу подключения. Нужно только помнить, что на плате уже установлена подтяжка линии данных к напряжению питания.

Для работы с датчиками температуры DS18B20 требуются библиотеки DS18B20 и OneWire. Ниже приведён код для одного датчика DS18B20, подключённого к плате KC868-A4.

/*   Kincony KC868-A4   DS18B20 example */  #include <DS18B20.h>  #define  LOW_ALARM 30 #define HIGH_ALARM 40  DS18B20 ds(13);  void setup() {   Serial.begin(115200);   Serial.println(F("Start Kincony KC868-A4 DS18B20 example..."));      ds.doConversion();   while (ds.selectNext()) {     ds.setAlarms(LOW_ALARM, HIGH_ALARM);   } }  void loop() {   ds.doConversion();    while (ds.selectNextAlarm()) {     Serial.print("Alarm Low: ");   Serial.print(ds.getAlarmLow());  Serial.println(" °C");     Serial.print("Alarm High: ");  Serial.print(ds.getAlarmHigh()); Serial.println(" °C");     Serial.print("Temperature: "); Serial.print(ds.getTempC());     Serial.println(" °C\n");   }    delay(2000); } 

В коде выставляются пороги срабатывания и, в случае выхода контролируемой температуры за определённые значения, в Serial выводится соответствующее сообщение.

Библиотека DS18B20 содержит множество примеров использования датчиков температуры DS18B20 на все случаи жизни — вы легко можете использовать их для своих проектов.

▍ Приёмник и передатчик на 433 МГц

Как вы уже знаете, в состав контроллера Kincony KC868-A4 входят модули приёмника и передатчика на 433 МГц. Эти модули могут быть использованы для управления различной техникой и приёма данных с датчиков, использующих диапазон 433 МГц для передачи своих сигналов.

Приёмник подключен на GPIO 19 контроллера, а передатчик на GPIO 21. Для работы с беспроводной передачей и приёмом данных используется популярная библиотека RC-Switch. Вот пример посылки данных и управляющих команд беспроводным модулем на 433 МГц контроллера Kincony KC868-A4.

/*   Kincony KC868-A4   433 Transmit example  */  #include <RCSwitch.h> RCSwitch mySwitch = RCSwitch();  #define DELAY_MS 500  void setup() {   Serial.begin(115200);   Serial.println(F("Start Kincony KC868-A4 433 Transmit example..."));      mySwitch.enableTransmit(digitalPinToInterrupt(21)); }  void loop() {   mySwitch.switchOn ("11111", "00010");      delay(DELAY_MS);   mySwitch.switchOff("11111", "00010");      delay(DELAY_MS);   mySwitch.send(5393, 24);                   delay(DELAY_MS);   mySwitch.send("000000000001010100010001"); delay(DELAY_MS);   mySwitch.sendTriState("00000FFF0F0F");     delay(DELAY_MS);  } 

Наглядная визуализация работы этого скетча в программе SDRSharp. Видны посылки в эфир данных контроллером каждые 500 миллисекунд.

Аналогичным образом вы можете использовать примеры приёма (GPIO 19) сигналов в диапазоне 433 МГц, идущие в составе библиотеки RC-Switch.

▍ Инфракрасные (IR) приёмник и передатчик

Завершим мы обзор программных модулей Kincony KC868-A4 примером работы с приёмником (GPIO 23, IRD) и излучателем (GPIO 22, IRS) инфракрасных сигналов. Используя эти приёмник и передатчик, вы можете организовать управление любой техникой, которая использует инфракрасные пульты для своей работы. Вы можете как записывать коды от ваших пультов управления, так и выдавать их (коды) в эфир для управления вашим оборудованием.

Для работы с инфракрасными приёмником и передатчиком используется библиотека Arduino-IRremote. Рассмотрим пример, созданный на её основе. В этом тестовом скетче мы будем принимать инфракрасный сигнал от бытового пульта управления, идентифицировать этот сигнал (производителя оборудования, частоту сигнала, протокол управления, и код нажатой клавиши), а также посылать в эфир записанный сигнал, нажимая на функциональную клавишу контроллера Kincony KC868-A4.

Исходные данные:

  • IR приёмник: GPIO 23
  • IR излучатель: GPIO 22
  • Функциональная кнопка: GPIO 0
  • STATUS_PIN используется в скетче для индикации событий, но поскольку в Kincony KC868-A4 задействованы практически все GPIO ESP32 (и также занят GPIO2), то встроенный светодиод (D2) переопределён на (условно) свободный пин D12.

Полный код скетча содержит 2 файла: основной (ir_example.ino) и файл с настройками (PinDefinitionsAndMore.h). В файле PinDefinitionsAndMore.h нужно изменить номера GPIO в соответствии с распиновкой контроллера Kincony KC868-A4 (строки с настройками помечены тремя восклицательными знаками).

#define LED_BUILTIN 12 // !!! #define IR_RECEIVE_PIN       23  // !!! #define IR_SEND_PIN          22  // !!! #define APPLICATION_PIN      0   // !!! 

Полный код файла PinDefinitionsAndMore.h

/*  *  PinDefinitionsAndMore.h  *  *  Contains pin definitions for IRremote examples for various platforms  *  as well as definitions for feedback LED and tone() and includes  *  *  Copyright (C) 2021  Armin Joachimsmeyer  *  armin.joachimsmeyer@gmail.com  *  *  This file is part of IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.  *  *  Arduino-IRremote is free software: you can redistribute it and/or modify  *  it under the terms of the GNU General Public License as published by  *  the Free Software Foundation, either version 3 of the License, or  *  (at your option) any later version.  *  *  This program is distributed in the hope that it will be useful,  *  but WITHOUT ANY WARRANTY; without even the implied warranty of  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  *  GNU General Public License for more details.  *  *  You should have received a copy of the GNU General Public License  *  along with this program.  If not, see <http://www.gnu.org/licenses/gpl.html>.  *  */  /*  * Pin mapping table for different platforms  *  * Platform     IR input    IR output   Tone  * -----------------------------------------  * DEFAULT/AVR  2           3           4  * ATtinyX5     0           4           3  * ATtiny167    9           8           5 // Digispark pro number schema  * ATtiny167    3           2           7  * ATtiny3217   10          11          3 // TinyCore schema  * ATtiny1604   2           PA5/3       %  * SAMD21       3           4           5  * ESP8266      14 // D5    12 // D6    %  * ESP32        15          4           27  * BluePill     PA6         PA7         PA3  * APOLLO3      11          12          5  */  #define LED_BUILTIN 12 // !!!   //#define _IR_MEASURE_TIMING // For debugging purposes. // #if defined(ESP8266) #define FEEDBACK_LED_IS_ACTIVE_LOW // The LED on my board (D4) is active LOW #define IR_RECEIVE_PIN          14 // D5 #define IR_RECEIVE_PIN_STRING   "D5" #define IR_SEND_PIN             12 // D6 - D4/pin 2 is internal LED #define IR_SEND_PIN_STRING      "D6" #define _IR_TIMING_TEST_PIN     13 // D7 #define APPLICATION_PIN          0 // D3  #define tone(...) void()      // tone() inhibits receive timer #define noTone(a) void() #define TONE_PIN                42 // Dummy for examples using it   #elif defined(ESP32) #include <Arduino.h> #define TONE_LEDC_CHANNEL        1  // Using channel 1 makes tone() independent of receiving timer -> No need to stop receiving timer. void tone(uint8_t _pin, unsigned int frequency){     ledcAttachPin(_pin, TONE_LEDC_CHANNEL);     ledcWriteTone(TONE_LEDC_CHANNEL, frequency); } void tone(uint8_t _pin, unsigned int frequency, unsigned long duration){     ledcAttachPin(_pin, TONE_LEDC_CHANNEL);     ledcWriteTone(TONE_LEDC_CHANNEL, frequency);     delay(duration);     ledcWriteTone(TONE_LEDC_CHANNEL, 0); } void noTone(uint8_t _pin){     ledcWriteTone(TONE_LEDC_CHANNEL, 0); } #define IR_RECEIVE_PIN       23  // !!! #define IR_SEND_PIN          22  // !!! #define TONE_PIN                27  // D27 25 & 26 are DAC0 and 1 #define APPLICATION_PIN      0   // !!!   #elif defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_STM32F1) // BluePill in 2 flavors // Timer 3 blocks PA6, PA7, PB0, PB1 for use by Servo or tone() #define IR_RECEIVE_PIN          PA6 #define IR_RECEIVE_PIN_STRING   "PA6" #define IR_SEND_PIN             PA7 #define IR_SEND_PIN_STRING      "PA7" #define TONE_PIN                PA3 #define _IR_TIMING_TEST_PIN      PA5 #define APPLICATION_PIN         PA2  #elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) #include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut". saves 370 bytes program space and 38 bytes RAM for digistump core #define IR_RECEIVE_PIN  0 #define IR_SEND_PIN     4 // Pin 2 is serial output with ATtinySerialOut. Pin 1 is internal LED and Pin3 is USB+ with pullup on Digispark board. #define TONE_PIN        3 #define _IR_TIMING_TEST_PIN 3  #elif defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__) #include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut" // For ATtiny167 Pins PB6 and PA3 are usable as interrupt source. #  if defined(ARDUINO_AVR_DIGISPARKPRO) #define IR_RECEIVE_PIN   9 // PA3 - on Digispark board labeled as pin 9 //#define IR_RECEIVE_PIN  14 // PB6 / INT0 is connected to USB+ on DigisparkPro boards #define IR_SEND_PIN      8 // PA2 - on Digispark board labeled as pin 8 #define TONE_PIN         5 // PA7 #define _IR_TIMING_TEST_PIN 10 // PA4 #  else #define IR_RECEIVE_PIN  3 #define IR_SEND_PIN     2 #define TONE_PIN        7 #  endif  #elif defined(__AVR_ATtiny88__) // MH-ET Tiny88 board #include "ATtinySerialOut.hpp" // Available as Arduino library "ATtinySerialOut". Saves 128 bytes program space // Pin 6 is TX pin 7 is RX #define IR_RECEIVE_PIN   3 // INT1 #define IR_SEND_PIN      4 #define TONE_PIN         9 #define _IR_TIMING_TEST_PIN 8  #elif defined(__AVR_ATtiny3217__) #define IR_RECEIVE_PIN  10 #define IR_SEND_PIN     11 #define TONE_PIN         3 #define APPLICATION_PIN  5  #elif defined(__AVR_ATtiny1604__) #define IR_RECEIVE_PIN   2 // To be compatible with interrupt example, pin 2 is chosen here. #define IR_SEND_PIN      3 #define APPLICATION_PIN  5  #define tone(...) void()      // Define as void, since TCB0_INT_vect is also used by tone() #define noTone(a) void() #define TONE_PIN        42 // Dummy for examples using it  #  elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) \ || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) \ || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega324A__) \ || defined(__AVR_ATmega324PA__) || defined(__AVR_ATmega164A__) \ || defined(__AVR_ATmega164P__) || defined(__AVR_ATmega32__) \ || defined(__AVR_ATmega16__) || defined(__AVR_ATmega8535__) \ || defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) \ || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) \ || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega162__) #define IR_RECEIVE_PIN      2 #define IR_SEND_PIN        13 #define TONE_PIN            4 #define APPLICATION_PIN     5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN  7  #elif defined(ARDUINO_ARCH_APOLLO3) #define IR_RECEIVE_PIN  11 #define IR_SEND_PIN     12 #define TONE_PIN         5  #elif defined(ARDUINO_ARCH_MBED) // Arduino Nano 33 BLE #define IR_RECEIVE_PIN      2 #define IR_SEND_PIN         3 #define TONE_PIN            4 #define APPLICATION_PIN     5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN  7  #elif defined(TEENSYDUINO) #define IR_RECEIVE_PIN      2 #define IR_SEND_PIN         3 #define TONE_PIN            4 #define APPLICATION_PIN     5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN  7  #elif defined(__AVR__) // Default as for ATmega328 like on Uno, Nano etc. #define IR_RECEIVE_PIN      2 // To be compatible with interrupt example, pin 2 is chosen here. #define IR_SEND_PIN         3 #define TONE_PIN            4 #define APPLICATION_PIN     5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN  7  #elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM) #define IR_RECEIVE_PIN      2 #define IR_SEND_PIN         3 #define TONE_PIN            4 #define APPLICATION_PIN     5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN  7  // On the Zero and others we switch explicitly to SerialUSB #define Serial SerialUSB  // Definitions for the Chinese SAMD21 M0-Mini clone, which has no led connected to D13/PA17. // Attention!!! D2 and D4 are switched on these boards!!! // If you connect the LED, it is on pin 24/PB11. In this case activate the next two lines. //#undef LED_BUILTIN //#define LED_BUILTIN 24 // PB11 // As an alternative you can choose pin 25, it is the RX-LED pin (PB03), but active low.In this case activate the next 3 lines. //#undef LED_BUILTIN //#define LED_BUILTIN 25 // PB03 //#define FEEDBACK_LED_IS_ACTIVE_LOW // The RX LED on the M0-Mini is active LOW  #elif defined (NRF51) // BBC micro:bit #define IR_RECEIVE_PIN      2 #define IR_SEND_PIN         3 #define APPLICATION_PIN     1 #define _IR_TIMING_TEST_PIN  4  #define tone(...) void()    // no tone() available #define noTone(a) void() #define TONE_PIN           42 // Dummy for examples using it  #else #warning Board / CPU is not detected using pre-processor symbols -> using default values, which may not fit. Please extend PinDefinitionsAndMore.h. // Default valued for unidentified boards #define IR_RECEIVE_PIN      2 #define IR_SEND_PIN         3 #define TONE_PIN            4 #define APPLICATION_PIN     5 #define ALTERNATIVE_IR_FEEDBACK_LED_PIN 6 // E.g. used for examples which use LED_BUILDIN for example output. #define _IR_TIMING_TEST_PIN  7 #endif // defined(ESP8266)  #if !defined (FLASHEND) #define FLASHEND 0xFFFF // Dummy value for platforms where FLASHEND is not defined #endif /*  * Helper macro for getting a macro definition as string  */ #define STR_HELPER(x) #x #define STR(x) STR_HELPER(x) 

Полный код файла ir_example.ino

/*   Kincony KC868-A4   IR example   * ReceiveAndSend.cpp  *   *  * Record and play back last received IR signal at button press.  * The logic is:  * If the button is pressed, send the IR code.  * If an IR code is received, record it.  *  * An example for simultaneous receiving and sending is in the UnitTest example.  *  * An IR detector/demodulator must be connected to the input IR_RECEIVE_PIN.  *  * A button must be connected between the input SEND_BUTTON_PIN and ground.  * A visible LED can be connected to STATUS_PIN to provide status.  *  * Initially coded 2009 Ken Shirriff http://www.righto.com  *  *  This file is part of Arduino-IRremote https://github.com/Arduino-IRremote/Arduino-IRremote.  *  */ #include <Arduino.h>  /*  * Define macros for input and output pin etc.  */ #include "PinDefinitionsAndMore.h"  //#define EXCLUDE_EXOTIC_PROTOCOLS // saves around 900 bytes program space  #include <IRremote.hpp>  int SEND_BUTTON_PIN = APPLICATION_PIN; int STATUS_PIN = LED_BUILTIN;  int DELAY_BETWEEN_REPEAT = 50;  // On the Zero and others we switch explicitly to SerialUSB #if defined(ARDUINO_ARCH_SAMD) #define Serial SerialUSB #endif  struct storedIRDataStruct { // Storage for the recorded code   IRData receivedIRData;   // extensions for sendRaw   uint8_t rawCode[RAW_BUFFER_LENGTH]; // durations if raw   uint8_t rawCodeLength;              // length of code } sStoredIRData;  int lastButtonState;  void storeCode(IRData *aIRReceivedData); void sendCode(storedIRDataStruct *aIRDataToSend);  void setup() {   Serial.begin(115200);   Serial.println(F("Start Kincony KC868-A4 IR example..."));      // Just to know which program is running on my Arduino   //Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));    IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK); // Start the receiver, enable feedback LED, take LED feedback pin from the internal boards definition   IrSender.begin(IR_SEND_PIN, ENABLE_LED_FEEDBACK); // Specify send pin and enable feedback LED at default feedback LED pin    pinMode(STATUS_PIN, OUTPUT);    /*   Serial.print(F("Ready to receive IR signals of protocols: "));   printActiveIRProtocols (&Serial);   Serial.print(F("at pin "));      #if defined(ARDUINO_ARCH_STM32) || defined(ESP8266)   Serial.println(IR_RECEIVE_PIN_STRING); #else   Serial.println(IR_RECEIVE_PIN); #endif    Serial.print(F("Ready to send IR signals at pin ")); #if defined(ARDUINO_ARCH_STM32) || defined(ESP8266)   Serial.println(IR_SEND_PIN_STRING); #else   Serial.print(IR_SEND_PIN); #endif        Serial.print(F(" on press of button at pin "));   Serial.println(SEND_BUTTON_PIN);    Serial.print(F("LED_BUILTIN: ")); Serial.println(LED_BUILTIN);   Serial.print(F("STATUS_PIN: ")); Serial.println(STATUS_PIN);   Serial.print(F("TONE_PIN: ")); Serial.println(TONE_PIN);   Serial.print(F("IR_RECEIVE_PIN: ")); Serial.println(IR_RECEIVE_PIN);   Serial.print(F("IR_SEND_PIN: ")); Serial.println(IR_SEND_PIN);   Serial.print(F("APPLICATION_PIN: ")); Serial.println(APPLICATION_PIN);   */  } // setup  // Stores the code for later playback in sStoredIRData  void storeCode(IRData *aIRReceivedData) {   if (aIRReceivedData->flags & IRDATA_FLAGS_IS_REPEAT)      {Serial.println(F("Ignore repeat")); return;}   if (aIRReceivedData->flags & IRDATA_FLAGS_IS_AUTO_REPEAT) {Serial.println(F("Ignore autorepeat")); return;}   if (aIRReceivedData->flags & IRDATA_FLAGS_PARITY_FAILED)  {Serial.println(F("Ignore parity error")); return;}    sStoredIRData.receivedIRData = *aIRReceivedData; // Copy decoded data    if (sStoredIRData.receivedIRData.protocol == UNKNOWN) {     Serial.print(F("Received unknown code and store "));     Serial.print(IrReceiver.decodedIRData.rawDataPtr->rawlen - 1);     Serial.println(F(" timing entries as raw "));          IrReceiver.printIRResultRawFormatted(&Serial, true); // output the results in RAW format          sStoredIRData.rawCodeLength = IrReceiver.decodedIRData.rawDataPtr->rawlen - 1;     IrReceiver.compensateAndStoreIRResultInArray(sStoredIRData.rawCode); // store current raw data in dedicated array for later usage   } else {     IrReceiver.printIRResultShort(&Serial);     sStoredIRData.receivedIRData.flags = 0; // clear flags -esp. repeat- for later sending     Serial.println();   } } // storeCode( )  void sendCode(storedIRDataStruct *aIRDataToSend) {   if (aIRDataToSend->receivedIRData.protocol == UNKNOWN) { // raw     IrSender.sendRaw(aIRDataToSend->rawCode, aIRDataToSend->rawCodeLength, 38); // 38 KHz     Serial.print(F("Sent raw "));     Serial.print(aIRDataToSend->rawCodeLength);     Serial.println(F(" marks or spaces"));   } else {     IrSender.write(&aIRDataToSend->receivedIRData, NO_REPEATS); // write func switch for different protocols     Serial.print(F("Sent: "));     printIRResultShort(&Serial, &aIRDataToSend->receivedIRData);   } }  void loop() {   int buttonState = digitalRead(SEND_BUTTON_PIN); // active LOW    if (lastButtonState == LOW && buttonState == HIGH) {     Serial.println(F("Button released"));     IrReceiver.start(); // re-enable receiver   }    // Check for static button state    if (buttonState == LOW) {     IrReceiver.stop();          // Button pressed send stored data or repeat     Serial.println(F("Button pressed, now sending"));     digitalWrite(STATUS_PIN, HIGH);     if (lastButtonState == buttonState) {       sStoredIRData.receivedIRData.flags = IRDATA_FLAGS_IS_REPEAT;     }     sendCode(&sStoredIRData);     digitalWrite(STATUS_PIN, LOW);     delay(DELAY_BETWEEN_REPEAT); // Wait a bit between retransmissions   } else if (IrReceiver.available()) { // Button is not pressed, check for incoming data     storeCode(IrReceiver.read());     IrReceiver.resume();   }    lastButtonState = buttonState; } // loop 

Результат работы скетча: сначала мы принимаем IR сигнал от пульта и декодируем его, а затем посылаем в эфир (дублируем), нажимая на кнопку «USER» контроллера Kincony KC868-A4.

▍ Заключение

Во второй статье цикла мы рассмотрели «атомарные» примеры программирования различных функциональных блоков контроллера Kincony KC868-A4. Используя эту информацию, вы можете легко начать программировать контроллер под свои задачи — всё расписано «от и до»: фото, схемы, распиновка, примеры кода, ссылки на библиотеки, скриншоты, пояснения и т. д.

В следующей статье мы рассмотрим более сложные примеры работы с KC868-A4, такие, как работа с беспроводной Wi-Fi частью и удалённое управление контроллером через интернет при помощи мессенджеров Telegram и/или Whatsapp.


ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/647119/