Всем привет! Я работаю в компании, которая разрабатывает оборудование для мониторинга нефтяных вышек, майнинговых ферм, ДГУ и прочих скучных вещей. Но в этот раз мы автоматизировали кое-что иное. Итак, встречайте: «Кукинатор 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 pressed\r», то при нажатии на кнопку устройство пошлет в UART: button pressed и символ переноса строки.

Нажмите для увеличения изображения

Описание и примеры кодов можно найти в документации к экрану. Для отладки можно воспользоваться функцией Debug. Данное окно позволяет протестировать все функции прошивки до заливки в сам экран.

Нажмите для увеличения изображения

Если всё в порядке, то можно подключить дисплей к компьютеру через переходник USB/UART и залить прошивку, нажав на кнопку «Upload».

Нажмите для увеличения изображения
Но как же нам теперь подружить экран с WB6?
Подключить экран можно либо через тот же переходник USB\UART в один из портов USB на контроллере, либо на прямую к одному из слотов расширения на плате контроллера.
Нас интересуют пины TX, RX, 5V и GND.

Нажмите для увеличения изображения

После подключения экрана к контроллеру мы будем получать данные о событиях прямо в Serial порт.

Для того, чтобы как-то реагировать на эти события, давайте напишем небольшой скрипт, который будет слать все данные о событиях в MQTT топик. Для начала создадим файл в корневой папке контроллера и назовём его serial.sh

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 (именно в него мы шлем данные с экрана) будут происходить некие действия. В данном случае при нажатии на экран мы увидим в отладочном окне веб интерфейса сообщение «Нажата кнопка»:

screen_button.js
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. Список и описание команд можно найти в документации к экрану.

Для определения конца команды экран ждёт три спец символа (\xff\xff\xff). Для упрощения задачи в будущем: создадим в корневой папке bash скрипт. Назовём его text.sh:

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\"\xff\xff\xff" > /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. Далее для определения монетки нам необходимо всего лишь посчитать импульсы. Для этого создадим в движке правил новый скрипт:

money.js
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:

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 ограничены лишь фантазией. Все файлы и скрипты можно найти по ссылке.

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


  1. Sly_tom_cat
    23.08.2018 10:45

    А почему контроллер то в корпус не спрятали?
    Крайне странное решение — все прикрыть а контроллер вывесить наружу.

    Нет, для отладки — понятно — нужно, но в законченном виде это планируется внутрь корпуса убрать или нет?


    1. alexey-m-ukolov
      23.08.2018 11:22
      +2

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


    1. Gryphon88
      23.08.2018 16:21
      +1

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


      1. Sly_tom_cat
        23.08.2018 17:21

        А что там искать:

        Спираль и привод были куплены в интернет магазине Б\У зап. частей для вендинговых аппаратов. Работает от блока питания 24v. Коммутируется через реле модуля расширения WBE2-DO-R6C-1.

        Коммутируй привод прямо на блок и только успевай печеньки ловить.


        1. fizikdaos
          23.08.2018 18:25

          Еще можно крышку поднять и все печенья забрать.
          А вообще можно как тест на собеседовании давать и смотреть каким способом взламывать будут :))


  1. GeMir
    23.08.2018 10:45

    если он видит MAC адрес устройства принадлежащего сотруднику
    Поощрение краж устройств у коллег?

    Killer feature осталась не реализованной :(
    image


    1. evocatus
      23.08.2018 11:40

      MAC-адрес очень легко клонировать, не нужно ничего красть. В Linux это делается одной командой:

      ip link set dev eth0 address AA:BB:CC:DD:EE:FF


      1. Demon_i
        23.08.2018 22:51

        Сколько разных кнопок нужно нажать. В винде можно сделать это 2 кнопками мыши.


  1. Karlson_rwa
    23.08.2018 12:22
    +2

    Отличная иллюстрация концепции работать за еду.


  1. denis-19
    23.08.2018 14:34

    Кукинатор 3000
    Почему 3000 ??

    Сколько пачек печенек помещается в корпус?
    Есть счетчик окончания пачек и сигнализирование типа «пустой контейнер скоро» будет?

    Что туда еще можно положить более интересное не думали, может шоколадки или зефирки?


    1. berezuev
      23.08.2018 16:11

      «пустой контейнер скоро» будет

      Эта фраза в уме читается голосом магистра Йоды :)


  1. GeMir
    23.08.2018 14:49

    Почему 3000
    Шутка. Отсылка к Pip-Boy 2000 и схожим названиям «инновационных» и «незаменимых» продуктов.
    Сколько пачек печенек помещается в корпус?
    Судя по спирали на фото — 6.


  1. snuk182
    24.08.2018 10:06

    Какой же Кукинатор без албибека?
    image


    1. FRAGIL3
      24.08.2018 10:11

      image


  1. mukoladerevlo
    24.08.2018 10:35

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


  1. MahmudS
    24.08.2018 10:35

    А почему 6/2*(2+1) не дает 9? Ведь операции умножения/деления равноценны, и идут по порядку?


    1. p_fox
      24.08.2018 18:01

      Наверно потому что уравнение записано неверно.
      Видя 6/2**(2+1) мы по-умолчанию читаем это как (6/2)*(2+1), а на самом деле там 6/(2*(2+1)).
      Либо надо рисовать нормальную вертикальную дробь, либо ставить недостающие скобки.


  1. igormwd
    24.08.2018 10:35

    } else if (countMoney == 2) {
        log("1 рубль")
    }
    


    Т.е. получается если накидать 10ть десятикопеечных (или вообще копеечных) монеток — можно купить печеньку?


    1. Munrexio Автор
      24.08.2018 10:37

      Нет, считаются не монетки, а импульсы, которые выдаёт монетоприёмник.
      Монетоприёмник сам определяет номинал монеты. И в зависимости от номинала выдаёт определённое количество импульсов контроллеру. Контроллер их считает и переводит в рубли.