Всем привет! Я работаю в компании, которая разрабатывает оборудование для мониторинга нефтяных вышек, майнинговых ферм, ДГУ и прочих скучных вещей. Но в этот раз мы автоматизировали кое-что иное. Итак, встречайте: «Кукинатор 3000» — аппарат по выдаче печенья лучшим сотрудникам.
Аппарат представляет из себя конструкцию из ПВХ и некоторых деталей:
Спираль c приводом (служит для подачи товара), экран, монетоприемник, и мозг всей конструкции — контроллер Wiren Board 6.
Экран
В качестве экрана для WB6 я использую экранный модуль Nextion (NEXTION ENHANCED NX4832K035).
Модуль оснащён AVR-процессором. Имеет 3.5» TFT дисплей с разрешением 480 * 320, 32Mb встроенной памяти, 1024 byte EEPROM, 8192 byte RAM.
Данное устройство хранит и отображает графику, анимирует элементы интерфейса и обрабатывает нажатия. На контроллер по UART передаются только коды событий, что позволяет легко настраивать интерфейсы различной сложности.
Для загрузки необходимых настроек и графики в экранный модуль предусмотрен визуальный редактор интерфейсов «Nextion Editor». Скачать его можно на официальном сайте itead.
При создании нового проекта необходимо указать модель, положение экрана и кодировку символов. Для корректного отображения кириллицы нужно выбрать iso-8859-5.
Слева расположена панель инструментов. Здесь можно найти самые необходимые элементы для создания интерфейса.
Давайте нажмем на Button. В поле редактирования появится условная кнопка. Растянем её, отредактируем текст и название. Для отображения текста необходимо добавить шрифт. Воспользуемся инструментом «Font Creator» во вкладке tools. В поле «Event» необходимо написать код, который будет воспроизводиться по событиям.
На пример если во вкладке «Touch press event» прописать print «button pressedr», то при нажатии на кнопку устройство пошлет в UART: button pressed и символ переноса строки.
Описание и примеры кодов можно найти в документации к экрану. Для отладки можно воспользоваться функцией Debug. Данное окно позволяет протестировать все функции прошивки до заливки в сам экран.
Если всё в порядке, то можно подключить дисплей к компьютеру через переходник USB/UART и залить прошивку, нажав на кнопку «Upload».
Но как же нам теперь подружить экран с WB6?
Подключить экран можно либо через тот же переходник USBUART в один из портов USB на контроллере, либо на прямую к одному из слотов расширения на плате контроллера.
Нас интересуют пины TX, RX, 5V и GND.
После подключения экрана к контроллеру мы будем получать данные о событиях прямо в Serial порт.
Для того, чтобы как-то реагировать на эти события, давайте напишем небольшой скрипт, который будет слать все данные о событиях в MQTT топик. Для начала создадим файл в корневой папке контроллера и назовём его serial.sh
#!/bin/bash #Инициализируем порт /dev/ttyMOD3 stty -F /dev/ttyMOD3 ospeed 9600 ispeed 9600 raw clocal -parenb -echo cs8 CR="$(echo -e 'r')" exec 4<> /dev/ttyMOD3 cat <&4 | while : do IFS="$CR" read -r line case "$line" in quit*) break ;; *) if [[ -n "$line" ]]; then echo $line #Полученные строки шлём в MQTT mosquitto_pub -t /devices/screen/controls/raw/meta/type -r -m text mosquitto_pub -t /devices/screen/controls/raw/on -r -m "$line" fi ;; esac done
Если вы всё сделали правильно, то после запуска скрипта при нажатии на кнопку — в веб интерфейсе контроллера вы увидите топик с данными, которые посылает экранный модуль.
На контроллерах Wiren Board предусмотрена система правил — wb-rules. Правила создаются через веб-интерфейс и пишутся на простом Javascript-подобном языке.
В веб интерфейсе WB6 зайдите во вкладку Scripts и создайте новый скрипт, нажав на кнопку «New…», назовите его «screen_button.js» или как-нибудь еще. Далее напишем правило: При изменении топика screen/raw (именно в него мы шлем данные с экрана) будут происходить некие действия. В данном случае при нажатии на экран мы увидим в отладочном окне веб интерфейса сообщение «Нажата кнопка»:
defineVirtualDevice("screen", { // создаем виртуальный девайс title: "nextion screen", cells: { raw: { type: "text", value: "" }, } }); defineRule("screen_button", { whenChanged: "screen/raw", then: function(newValue, devName, cellName) { log(newValue); if (newValue == "button pressed") { //Если получили текст от экрана «button pressed» log("Нажата кнопка"); //Тут описываем наши действия на событие. } else if (newValue == "button released") { log("Не нажата кнопка"); } dev["screen"]["raw"] = ""; //Очищаем топик. } });
Отлично. С тем как обрабатывать нажатия на экране мы разобрались. Теперь поговорим о том, как нам управлять экраном с WB6. Например изменить текст кнопки. Экран принимает команды по UART. Список и описание команд можно найти в документации к экрану.
Для определения конца команды экран ждёт три спец символа (xffxffxff). Для упрощения задачи в будущем: создадим в корневой папке bash скрипт. Назовём его text.sh:
#!/bin/bash TEXT=""; UNIT=""; while [ -n "$1" ] do case "$1" in -a) UNIT=$2;; -b) TEXT=$2;; esac shift done echo -en "$UNIT.txt="$TEXT"xffxffxff" > /dev/ttyMOD3 exit 0
Теперь для того, чтобы изменить текст кнопки нам достаточно вызвать скрипт с аргументами:bash /mnt/data/root/text.sh -a b0 -b ‘Some Text’
Где b0 – это имя кнопки на экране, а Some Text – желаемый текст.
Пример использования в движке правил WB6:
var txt1 = "some text"; runShellCommand("bash /mnt/data/root/text.sh -a b0 -b '" + txt1+ "'");
Подобным образом можно изменять отображаемую на данный момент страницу на экране, текст на различных элементах, переменные и другие параметры. Не буду расписывать тут весь функционал экранного модуля. Для нашего проекта вполне достаточно уже написанной выше информации.
Монетоприемник
В качестве монетоприемника я использую китайский вариант, найденный на просторах Aliexpress рублей за 400.
С подключением всё просто. +12v и импульсный выход, который нужно подключить к модулю расширения «Сухой контакт» WBE2-DI-DR-3. Далее для определения монетки нам необходимо всего лишь посчитать импульсы. Для этого создадим в движке правил новый скрипт:
var timeout_ms = 1 * 200; var timer_id = null; var timerTime = Date.now(); var timerLast = 0; var countMoney = 0; defineRule("money", { whenChanged: "wb-gpio/MOD1_IN2", then: function(newValue, devName, cellName) { if (newValue) { timerLast = Date.now() if ((timerLast - timerTime) >= 500) { //первый импульс? timerTime = Date.now(); countMoney = 1; } else { timerTime = Date.now(); // второй и последующие импульсы countMoney++; } if (timer_id) { clearTimeout(timer_id); } timer_id = setTimeout(function() { // через определенное время смотрим что получилось if (countMoney == 5) { log("10 рублей") } else if (countMoney == 4) { log("5 рублей") } else if (countMoney == 3) { log("2 рубля") } else if (countMoney == 2) { log("1 рубль") } timer_id = null; }, timeout_ms); } } });
Довольно простое правило. Возможно не самое точное.
Bitrix24
Теперь наверное самое интересное. Попробуем разобраться, как воплотить фразу «Молодец. Возьми с полки пирожок печеньку». В нашей компании в качестве CRM используется система Bitrix24. Идея заключается в том, чтобы за каждое выполненное задание (Задачу) в битриксе сотрудник получал некие электронные баллы. Эти самые баллы можно использовать как валюту для нашего аппарата. Давайте разберемся, как подключиться к Bitrix24 и следить за успехами сотрудников.
За основу мы возьмём bitrix24-python-sdk.
Устанавливаем SDK на контроллер командой pip install bitrix24-python-sdk
Далее создадим python скрипт в корневой папке, назовём его bitrix.py:
#!/usr/bin/python3 import pprint from bitrix24 import bitrix24 import sys import subprocess b24_webhook_key = 'some_key' #Сюда вписать свой ключ, созданный в админке битрикса. b24_webhook_user = 1 #Вписать ID пользователя - того кто создал ключ. b24_domain = 'some_domain' #Вписать домен компании. page = 1 user_id = [16, 10, 6, 55, 8, 14, 67, 20] # список пользователей, за которыми собираемся следить ord_status = 5 # 5 - завершенные задачи order_list = 0 total_orders = 0 bx24 = bitrix24.Bitrix24(b24_domain, webhook_key=b24_webhook_key, webhook_user=b24_webhook_user) def get_order_list_len(_user_id): result_ = bx24.call( 'task.item.list', {'ORDER': {'DEADLINE': 'desc'}}, {'FILTER': {'RESPONSIBLE_ID': _user_id,'REAL_STATUS': ord_status}}, {'PARAMS': {'NAV_PARAMS': {'nPageSize': 50, 'iNumPage': page}}} ) if result_: return (len(result_['result'])) for user in user_id: while True: order_list = get_order_list_len(user) total_orders = total_orders + order_list page = page + 1 if(order_list < 50): subprocess.call("mosquitto_pub -t /devices/%s/controls/orders_finished/on -r -m %s" % (user, total_orders), shell=True) # Отправляем всё в MQTT. page = 1 total_orders = 0 break
Данный скрипт запрашивает все завершенные задачи заданного списка юзеров, считает их и посылает количество в mqtt топики. Далее нам остаётся только сравнить полученное количество с предыдущими значениями и если новые данные больше, то добавить баллы сотруднику за проделанную работу.
Bluetooth
Для сканирования BLE устройств я использую Bluez. Программа уже установлена на контроллер. Для того чтобы сканировать ble устройства достаточно ввести несколько команд в консоль: hciconfig hci0 up
hcitool lescan --duplicates
Однако нам этого не достаточно. Желательно видеть уровень сигнала. Для этого установим дополнительную утилиту hcidump:
apt-get install bluez-hcidump
И дополним нашу команду:
hciconfig hci0 up
hcitool lescan --duplicates | hcidump -a | grep -E 'bdaddr|RSSI'
На выходе получим MAC адреса и RSSI bluetooth (ble) устройств поблизости.
Эти две строки можно красиво обернуть в bash скрипт, а вывод отправлять в MQTT.
Второй способ- скрипт aioblescan
Для его работы требуется Python 3, желательно 3.5. Плюс этого скрипта в том, то что можно следить за конкретными MAC адресами, а не за всеми мимо проходящими за окном умными часами и смартфонами. Вывод скрипта так же перенаправляем в MQTT, для удобства работы с движком правил.
Теперь мы знаем как взаимодействовать с WB6 при помощи экранного модуля, умеем считать монеты, следить за успехами сотрудников в Битриксе, сканировать ble устройства и их уровень сигнала. Осталось собрать это в одну кучу и прописать какую-то логику. Я не буду расписывать все скрипты данного проекта. Всё будет доступно по ссылке в свободном доступе. Возможно кто-то из вас найдёт для этого всего более полезное и умное применение.
Корпус
Корпус сделан из 10mm вспененного ПВХ. Продаётся такой пластик листами. Умеренно мягкий. Резать можно ножовкой, либо обычным канцелярским ножом по линейке.
В качестве крепежа использовался детский набор металлических деталей «Конструктор» и короткие саморезы. В этом наборе нашлось практически всё необходимое для сборки корпуса.
Привод
Спираль и привод были куплены в интернет магазине БУ зап. частей для вендинговых аппаратов. Работает от блока питания 24v. Коммутируется через реле модуля расширения WBE2-DO-R6C-1.
Функционал
Функционально похож на обычный вендинговый аппарат. Выдаёт печенье за деньги и не только.
При запуске аппарата экран показывает заставку с логотипом, за тем перекидывает на главный экран, где нам предлагается либо купить печенье, либо сыграть в игру.
Игра для пользователя — бесплатная, но можно установить небольшую цену, для мотивации. Правила просты. Игроку предлагают решить три простые задачки. Если он дает три правильных ответа, то получает приз в виде печенья. Пожалуй это всё что нужно знать об этом пункте. Давайте вернёмся в главное меню и нажмём «Купить печенье».
Далее система предложит выбрать способ оплаты. При выборе способа оплаты «За деньги» на экране появляется окно с ценой и оплаченной суммой, которая увеличивается при внесении денег в монетоприемник.
Как только сумма будет достаточна для совершения покупки, аппарат автоматически закроет это окно и выдаст товар.
Но, как я рассказывал ранее, предусмотрена и другая валюта – это баллы, полученные за успехи сотрудников в системе Bitrix24. Если сотрудник закрывает поставленную ему задачу – ему начисляются баллы. Также баллы может начислить начальник за особенно хорошие результаты.
Чтобы расплатиться баллами, сотруднику нужно выбрать пункт «Купить за баллы», Затем аппарат попытается определить кто перед ним стоит. Для этого он сканирует Bluetooth устройства вокруг себя и если он видит MAC адрес устройства принадлежащего сотруднику и занесенного в базу данных, а также уровень сигнала достаточно мощный, что бы полагать, что он стоит рядом, то на экране появятся данные о состоянии счета сотрудника, его имя и предложение оплатить печенье баллами.
Если же системе не удалось определить ни одного знакомого устройства, то он выдаст предупреждение и предложит выбрать своё имя из списка и затем ввести свой пин-код.
В случае верного ввода откроется то самое окно с данными о состоянии счета пользователя и стоимости продукта. При подтверждении покупки со счета пользователя списывается необходимая сумма баллов и аппарат выдает товар.
На этом всё. Данный проект создан исключительно в образовательных целях, и чтобы показать, что области применения контроллера Wiren Board ограничены лишь фантазией. Все файлы и скрипты можно найти по ссылке.
Источник