среда, декабря 28, 2016

Победа над SIP близка как никогда


Задача: операторы на телефонах (приём заказов) должны в момент ответа на звонок знать, с кем они говорят (или хотя бы не переспрашивать номер, если клиент новый).

Это было решено когда-то наколенными средствами, которые больше не годятся. Тем более что теперь имеется сервер, способный доставить звонок до операторских ноутбуков (они под Убунту).

Решение нашлось почти сразу: Linux-клиент SIP Twinkle, способный хорошо манипулировать с заголовками, а главное - поддерживающий скриптинг по событиям.

Опробовал у себя (Debian); работает. Написал крошечный скрипт на событие "call is answered":

#!/bin/bash

xdg-open http://host/callerid.php?$(echo ${SIP_FROM}  | cut -d '"' -f2 | cut -d '+' -f2) &
echo end

по частям:

xdg-open: выполнить дефолтное действие; для URL это открытие предпочитаемого браузера.

callerid.php: скрипт, ожидающий чего-то похожего на телефонный номер, приводящий его к нормальному виду (10 цифр) и выполняющий поиск в базе клиентов.

echo ${SIP_FROM}: сюда выводится переменная SIP_FROM, устанавливаемая в окружении скрипта Twinkle'ом. В начале её содержимого идёт номер в кавычках.
Первый cut разбивает строку по кавычкам, второе поле этого результата - телефонный номер с плюсом в начале; от плюса избавляет второй cut, результат идёт в http-запрос.

echo end: передать Twinkle, что скрипт закончил работу.

В момент ответа на звонок у оператора выскакивает браузер со страницей, где он видит телефон и имя клиента (если он повторный).

Дальше, как водится, был геморрой: в Убунту 14 Twinkle без GUI; после апгрейда до 16 выяснилось, что Twinkle тупо сегфолтит на звонке, что характерно, именно на Убунте (ох уж ейная самобытность, сколько крови выпила). Пришлось (благо на ноутах, кроме браузера и SIP-клиента, ничего нет) быстренько перескочить на Debian Stretch, после чего уже всё и заработало.


четверг, декабря 15, 2016

Linux -> Windows -> HP LaserJet

Потребовалось настроить печать из CUPS на HP LJ, зашаренный на Windows-машине. Пишу в том числе и для памяти: сколько раз приходилось повторно решать проблему, не сделав памятки.

1) На Linux должна быть установлена samba и HPLIP.

2) На Windows нужно зашарить принтер с удобным (коротким буквоцифровым) именем.

3) Проверяем, что Windows-хост виден Линуксу:

smbtree

Ниже информации о самом себе должен быть хост Windows, например:

\\DESKTOP-Q8VFISC

3) Проверяем, что принтер виден Линуксу. uname - имя пользователя на Windows-хосте:

smbclient -L \\DESKTOP-Q8VFISC -U uname

Sharename       Type      Comment
---------       ----      -------
ADMIN$          Disk      Удаленный Admin
C$              Disk      Стандартный общий ресурс
IPC$            IPC       Удаленный IPC
P2035           Printer   HP LaserJet P2035
print$          Disk      Драйверы принтеров

4) Открываем администрирование принтеров в CUPS, добавляем принтер, выбираем из сетевых принтеров опцию Windows Printer via SAMBA. Строка подключения:

smb://uname:pwd@host/printername

Если принтер зашарен без пароля, uname:pwd@ опустить. При повторных изменениях принтера имя-пароль будут сбрасываться!

5) Выбираем драйвер. Здесь 2 момента:

- Драйверы некоторых принтеров HPLIP требуют закрытого плагина (в имени драйвера указано requires proprietary plugin. Плагин устанавливается в консоли:

hp-plugin -i

- Всё готово, но в CUPS задание печати помечено Filter failed. В /var/log/cups/error.log написано:

Error: This module is designed to work with HP Printers only

У меня это решилось сменой драйвера с ZJS на PCL, т. е. даёт ошибку

HP LaserJet p2035 zjs, hpcups 3.16.11, requires proprietary plugin

но работает

HP LaserJet p2035 pcl3, hpcups 3.16.11, requires proprietary plugin

вторник, ноября 15, 2016

НЬЮЗЕНБЕРГИАДА, или Неожиданное путешествие по воздуху, суше и морю на ту сторону Курильской гряды и обратно


- У меня люди едут на Итуруп.

- Замечательное место, - заметил я. - Только летом там лучше.

Кончался октябрь.

- Там пароход сломался. Едет специалист, везёт запчасть.

- Ты сказал: люди.

- Ещё ты.

- ??!

- Помоги, он сам не доберётся. Ты местный.

- Я с Кунашира. Итуруп только с рейда видел.

- Какая, б***ь, разница? Все Курилы одинаковые.

- Запчасть тяжёлая?

- Килограмм десять-пятнадцать.

* * *

Это был пролог, а сейчас второе ноября, среда, мы с Родионом пьём лимонад из картонных стаканчиков с символикой авиакомпании «Аврора» на борту Bombardier Q-400 авиакомпании «Аврора», рейс 801 Южно-Сахалинск — Курильск. Стаканчики принесла девушка в форме авиакомпании «Аврора», та же самая девушка, что вчера приносила сэндвичи и апельсиновый сок на борту Bombardier Q-400 авиакомпании «Аврора», рейс из Владивостока в Южно-Сахалинск. Ещё за час до того, первого «Бомбардье», мы встретили в аэропорту рейс из Кореи, на котором некто Сергей привёз ту самую запчасть и вручил нам, как 11-килограммовую эстафетную палочку.

Родион — судомеханик. Запчасть — увесистая. Я — сопровождающий.


суббота, сентября 03, 2016

Лихтенштейновская женщина в Inkscape: паттерны - это просто

Нужно было картинку с девушкой в манере Роя Лихтенштейна. Сделать в Inkscape. Высотой 3 метра.

Сама девушка была подготовлена в Gimp и трассирована.




Теперь надо было сделать растр с точкой размером горошины. Очевидно, надо использовать паттерн. Это одна из возможностей Inkscape, которых я никогда или почти никогда не касался. А зря. Всё оказалось очень непринуждённо.

1) Надо сделать примерно 50% растр с круглой точкой. Рисуем квадрат, в нём  круг размером в 2 раза меньше, примерно так:


2) Круг делаем красным, квадрат - прозрачным. Выделяем и делаем Objects -> Pattern -> Objects to pattern.

3) Рисуем контур под заливку и заливаем своим паттерном. Берём инструмент Node. Контур должен быть активен. Пока он активен, операции над контролирующими точками оригинала будут влиять на заливку контура. Так очень легко получить нужную частоту и угол растра. 



Насыщенность "краски" растра в этом конкретном случае можно регулировать прозрачностью контура. Но в целом после создания паттерна с ним уже мало что можно сделать. Если вы унесёте оригинал паттерна в другое место рисунка, его контролирующие точки останутся там, где оригинал был создан. Можете вообще его удалить, это не повлияет ни на заливку, ни на местонахождение контролирующих точек.

Поскольку Inkscape рисует SVG, то заливка паттерном, думаю, внутренне реализована как background-image, параметры которого регулируются инструментом Node.

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









понедельник, августа 08, 2016

Ушёл на базу. Через шифрованную дырку.

С открытием второй пиццерии (с моей точки зрения - с развёртыванием второй системы управления производством) возникли вопросы взаимодействия:

Как дать возможность оператору отправить заказ на нужную пиццерию?

Как формировать консолидированные отчёты по двум точкам?

Как синхронизировать меню, цены, акции, дисконты, купоны - всё, что может измениться в любой момент?

Вариант master/slave в MySQL сразу не рассматривал, потому что схема должна быть такой, чтобы пережить атомную бомбардировку: уцелевшие пиццерии должны продолжить автономную работу несмотря на оборванные провода и исчезнувшие соединения.

Это можно сделать через REST: куча писанины и куча новых ошибок.

Либо обращаться к базе удалённо.

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

Немножко почитал интернеты и понял, что понадобится:

autossh - надстройка над ssh, поддерживающая соединение в рабочем состоянии, пока это возможно;


И всё.

К слову, Гугл по поиску autossh в третьей позиции даёт ветку под названием "Чтоб вы знали: autossh - полное дерьмо". Я её внимательно изучил. Она меня не убедила.

Ещё нужен скрипт для управления autossh как службой, он находится здесь и отлично встраивается в Debian.

Смотав это всё синей изолентой, получаем на сервере А новый порт MySQL, открытый в тьму внешн базу данных сервера Б, без создания новых дырок, через зашифрованное, автоматически устанавливающееся и магически восстанавливающееся соединение.

Дальше - с отвёрткой в зубах - в PHP-класс работы с SQL. Здесь делаем выбор параметров соединения из массива предопределённых вариантов. Важно: если сервером указывать localhost, запрос такого-то порта будет проигнорирован. Поэтому указываем 127.0.0.1. Вроде хрен и редька, а вот хрен.

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

Холишыт, это действительно работает!

Дальше так: в интерфейс операторов, принимающих заказы с доставкой, добавляем выбор пиццерии:


Чуть позже по умолчанию будет та, чей этот клиент географически.

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

Дальше надо поэкспериментировать и понять, как лучше строить консолидированные отчёты: federated table?

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

четверг, августа 04, 2016

Печать чеков на Posiflex Aura: траблшутинг

Как уже сообщалось, произошло обарывание принтера Posiflex Aura для печати из-под CUPS; как оказалось, не окончательное.

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

Надо думать. Теорию суперструн вон придумали, а ср@ные полоски на бумаге не осмыслим? Так не бывает.

Вот драйвер принтера переварил PDF и выдал растровую страницу. Вот она пошла в принтер. Может переполниться память? Если она есть, то может.

Посмотрел спецификацию принтера. Памяти страниц нет. Есть входной буфер размером 10К.

Значит, принтер не запоминает всё задание перед печатью. Выводит поток на ленту и тут же забывает. Логично: все нелазерные принтеры так работают.

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

Теперь смотрим на PDF, который мы печатаем. Начало.


Что, если жирный логотип сразу забивает буфер и не успевает утечь в дренаж? Buffer overrun. Скорее всего, часть данных будет потеряна; затем напечатается обрывок нижней части. Размер чека будет таким, будто всё напечатано правильно: скорее всего, он передаётся в задании.

Это именно то, что мы имеем.

Проверяем. Открываем шаблон PDF и комментим лого. Надо же - всё печатается хорошо.

Исправляем в стиле логотипа ширину: 40 мм вместо 70. Полёт нормальный.

Ставим 50 мм. Нормально.

Где-то между 50 и 70 находится критический размер, дающий битмап под 10К. Я не стал его выяснять: 5-сантиметровое лого ОК.

Если всё верно, теперь при любом размере чека печать будет происходить правильно. Для проверки лезем в базу данных:

select count(ID) as c, order_id 
from ########## 
group by order_id order by c desc limit 1

Получаем заказ из 52 позиций, это исторический максимум со среза базы в январе.

Печатаем его чек. Две 32-сантиметровые страницы, всё чётко. С логотипом.

Последнее: уменьшенный логотип имеет некрасивые края: dithering. Открываем Gimp, меняем печатный размер лого: 50 мм при разрешении 8 dpmm (из спецификации). Переводим в 1-битный битмап и сохраняем. О, печатается намного лучше!

Последнее. Открываем скрипт печати и переключаем вывод сокета TCP на очередь CUPS.

Трибуны беснуются.

пятница, июля 29, 2016

Траблшутинг: как модем перестал, а потом снова начал слать СМС


Жил-был в одной пиццерии модем, выполнявший единственную функцию: при оформлении онлайн-заказа слал на номер клиента число из диапазона 1000-9999. Слал-слал, да и перестал.

В error-логе Apache обнаружилось, что gsmsendsms заканчивается неудачей с ошибкой: неожиданный ответ: ^RSSI: 9.

RSSI - показатель силы сигнала. Чо к чему?

Полез к модему через minicom. Увидел, что модем регулярно шлёт RSSI: <цифра> и тип соединения. Очевидно, это и есть "неожиданный ответ". gsmsendsms ожидала на свою сентенцию что-то типа ОК, а получила, натурально, уровень сигнала зачем-то.

Выключил эти сообщения (есть такая АТ команда). Теперь gsmsendsms заканчивалась с ошибкой 500.

500 - это ошибка типа "ХЗ". Что-то не так, не технически, а вообще. Непорядок во внешней вселенной.

Вынул SIM-карту из модема, поставил в телефон. Она оказалась заполненной. Хранилище на 15 сообщений было полно предупреждениями МЧС о грядущих ненастьях.

Удалил сообщения и поставил карту назад в модем. Она стала отправлять сообщения.

Проблема была решена, но в ближайшей перспективе. МЧС ведь не остановится. Ненастья грядут.

Изучение AT команд открыло, что AT+CMGD=X удалит из хранилища сообщение номер X. А AT+CMGD=X,4 удалит всё, игнорируя значение X.

Также оказалось, что AT команды можно тупо слать в /dev/ttyUSBx, например, через echo -n.

Осталось вставить это в crontab рута.

Оставил на завтра: слишком много свершений за один день.

среда, июля 20, 2016

Pre-cut appliqué [Практическая машинная вышивка]



Этим стулом мастер Гамбс 
начинает новую партию стульев.

Аппликация - понятно - детский сад и клейстер. В машинной вышивке, как у бабочек, всё происходит примерно так же.

Аппликация бывает trimmed in position и pre-cut. Ушлые умы пусть догонят сами, а сейчас будет только про второе.

Предварительно вырезанная аппликация - это когда на изделие налагается нечто, натурально, вырезанное заблаговременно. Мне нужно было наложить триколоры на рукава рубашек-поло. Флажки были отшиты одним блоком на куске габардина, вырезаны (оно! Pre-cut!) и оплавлены весёлым пропановым огоньком.


Это детская аппликация: пришивается удобный прямоугольник. Весь (нехитрый) фокус в проектировании фиксирующей части. Она состоит минимум из трёх строчек. Я не знаю русской терминологии, поэтому будем пользоваться обозначениями placement, tackdown и covering. Вот они.


Placement line (зелёная) обозначает на изделии контур, очерчивающий аппликацию. Это просто для удобства оператора, никакого другого смысла в этой строчке нет.

Tackdown line (жёлтая) - зигзаг, начерно фиксирующий аппликацию на её месте. Намётка. Ширина зигзага - 2 мм или больше. Чем больше, тем более толстой строчкой придётся его укрывать: нехорошо. Меньше 2 мм - трудно будет попасть краем аппликации в этот зазор. 

Covering line - сатиновая строчка, минимум на 0,5 мм (лучше на 1) шире намётки. Окончательно всё фиксирует и прикрывает всю эту намёточную срамоту.

Всё это делается из одного контура: рисуется single run line, дублируется; дубликат преобразуется в satin line нужной толщины, минимальной плотности, без underlay - получился зигзаг, дублируется; дубликат делается шире  примерно на 1 мм, плотностью около 80%, underlay по желанию, но лучше - делать, edge run.

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

Растаращиваем наш рукав на подходящем хупе. Можно настроить паузу после первой строчки, можно делать паузу в процессе. Скорость лучше выставить минимальную. Машина рисует контур. Вкладываем в него аппликацию. Слегка прижимаем пальцами (подальше от иглы! Блокировка сработает только когда игла упрётся в кость!) и запускаем машину. Загзаг должен пристрелить аппликацию аккуратно, нигде не уйдя с неё. Если такое случилось, надо не полениться и проектировать новую covering line с учётом ошибки.



После удачной пристрелки запускаем верхнюю строчку и медитируем.


Фишки и типсы.

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

Если что-то пошло не так, простые контуры можно поправить на лету. Допустим, хорошо пристрелились белая сторона и ближний торец, а красная сторона и дальний торец зацепило плохо (даже с правильными контурами такое бывает, если слегка ошибиться в расположении аппликации или не удержать её при пристрелке).  Ведём covering line до последнего угла, где она хорошо ложится (на фото - красного). Стоп. Запоминаем номер стежка на машине. На машинном компьютере открываем редактирование и сдвигаем строчку на пару миллиметров в нужных направлениях. Возвращаемся к стежку, который запомнили. Поехали дальше. При известном глазомере и сообразительности вы продолжите безошибочно.

Аппликация - это круто. Простые контуры, минимум ниток: вы можете делать очень сложные рисунки на самых хлипких тканях. Рисунки будут чёткими, а ткань не поведёт.


вторник, июля 19, 2016

Чековый принтер Posiflex AURA 6900 + Linux

Более двух лет назад пришлось подключать чековые принтеры Posiflex 6900 к производственной системе, построенной на LAMP. Тогда я решил эту задачу минималистично: обнаружил, что принтер тупо выводит на ленту всё, что приходит на порт TCP 9100 (обнаружил случайно: попытался открыть порт 9100 браузером и увидел на ленте заголовки HTTP-запроса). Русские буквы выходили двухбайтными; установить, что встроенный шрифт использует codepage 866, было просто. Написал вывод текстовых чеков на порты нужных принтеров, и больше двух лет так и работало.

Сейчас возникло желание поиметь красивые чеки с картинками и шлюхами. Для этого надо подключить принтер через CUPS. Исследование инета показало. что: 1) драйверов для CUPS нет ни у производителя, ни у вендоров; 2) в инете есть 2 (две) релевантные темы на форумах, ни в одной нет решения. Но! В одной из тем топикстартер приложил файл 6800.zip. Внутри обнаружился PPD для этого типа принтеров и - бааааа! - файл rastertopp7, который, ясное дело, представляет собой принтер-специфический фильтр CUPS. Файл оказался 32-bit ELF binary. Система 64-битная. Хьюстон, у нас тово.

Положил фильтр в /usr/lib/cups/filter. Добавил принтер, подключение: socket://xxx.xxx.xxx.xxx:9100, скормил найденный PPD. Попробовал напечатать тестовую страницу, получил сообщение "Filter failed". Естественно: рыба-то пресноводная, а водоём-от солёный.

Я поискал исходники и почти нашёл. На тайваньском сервере. С китайским интерфейсом. За скачивание попросили 50 юаней. Я пожопился из-за отчётливого ощущения разводилова. Адрес пользователя, разместившего архив, был в mail.ru.

Остался план Б: мультиархитектура. Добавил архитектуру i386 в систему:

dpkg --add-architecture i386

добавил 32-битные библиотеки:

apt-get update

apt-get install ia32-libs

Повторил пробную печать. Filter failed. Недодавил где-то.

ldd /usr/lib/cups/filter/rastertopp7 | grep found

Выхватил сообщение о не найденной libcupsimage.so.2

apt-get install libcupsimage2:i386

Повторил печать. Из принтера вылезла пробная страница с пингвином.

Теперь всё просто:  1) чек рисуется в HTML; 2) пропускается через mPDF, получается PDF; 3) отправляем его на принтер, ждём несколько секунд и удаляем файл. Несколько уродски, но просто и работает, а простые фокусы - самые надёжные.




среда, февраля 10, 2016

2016 (16?? Да, всё верно: 16). Рестарт.

Вспомнил, что у меня есть блог. Жизнь стала краше.

Поиск по этому блогу