Изучение WebUSB API: подключение к USB-устройствам и печать с помощью TSPL/TSPL2
5 апреля 2023 г.Что такое WebUSB API?
WebUSB API предоставляет классы и методы, которые позволяют нам подключать устройства и отправлять или получать данные через USB в веб-браузерах.
Краткий обзор того, как использовать WebUSB
Мы используем метод USB.requestDevice()
, чтобы отобразить диалоговое окно сопряжения для пользователя. После того, как пользователь выбирает USB-устройство в диалоговом окне, он возвращает выбранное устройство как экземпляр USBDevice
.
Позже мы можем отправлять или получать данные с этого устройства. Чтобы получить список уже сопряженных устройств, мы можем использовать метод USB.getDevices()
.
Браузеры, поддерживаемые WebUSB
Не все браузеры могут поддерживать WebUSB API. На данный момент поддерживаются следующие браузеры: Google Chrome, Microsoft Edge, Opera, Samsung Internet и Baidu Browser. Вы можете проверить, какие браузеры поддерживают WebUSB.
Один из способов проверить, поддерживает ли браузер WebUSB с JavaScript:
if (!('usb' in navigator)) {
console.log('WebUSB API is not supported!');
}
WebUSB API доступен только в защищенных контекстах (HTTPS)
WebUSB API можно использовать только в защищенных контекстах, другими словами, он должен предоставляться по URL-адресам https://
или wss://
. р>
Однако вы все равно можете протестировать его на localhost
, поскольку, согласно веб-документам MDN, локальные ресурсы считаются доставленными безопасно:
Локально доставляемые ресурсы, такие как ресурсы с URL-адресами http://127.0.0.1, http://localhost и http://*.localhost (например, http://dev.whatever.localhost/) и URL-адреса file:// также считаются доставленными безопасно.
Включить или отключить WebUSB API
Если вы хотите отключить WebUSB API, вы можете добавить HTTP-заголовок Permissions-Policy: usb=()
и использовать атрибут allow
для iframe. Вот пример для Node.js:
res.setHeader('Permissions-Policy', 'usb=()');
Если вы попытаетесь использовать WebUSB API после его отключения, вы получите сообщение об ошибке: Нарушение политики разрешений: USB не разрешен в этом документе
. Подробнее см. Веб-документы MDN — Политика разрешений.
WebUSB API с примером
Давайте рассмотрим, как мы можем использовать WebUSB API, на пошаговых примерах.
Сопряжение и подключение к USB-устройству с помощью WebUSB
Мы можем использовать метод USB.requestDevice()
для сопряжения и получения доступа к USB-устройству. Этот метод открывает диалоговое окно в браузере, где мы можем выбрать USB-устройство, к которому мы хотим подключиться. В случае успеха возвращается экземпляр USBDevice
.
Если устройство не выбрано, выдается исключение: Не удалось выполнить «requestDevice» на «USB»: устройство не выбрано.
Этот метод можно вызвать только с помощью жестов пользователя, таких как клики. В противном случае выдается исключение: Не удалось выполнить requestDevice на USB-накопителе: должен обрабатываться жест пользователя для отображения запроса на разрешение.
Чтобы сбросить разрешение на USB-устройство, мы можем использовать device.forget()
.
Давайте напишем код. Добавьте простую кнопку, которая вызывает метод USB.requestDevice()
при нажатии:
<button onclick="requestDevice()">Request device</button>
…
async function requestDevice() {
try {
const device = await navigator.usb.requestDevice({ filters: [] });
console.log(device);
} catch (e) {
console.error(e);
}
}
Параметр filters
используется для указания списка объектов для возможных устройств, которые мы хотели бы связать. Если оставить пустым, возвращаются все USB-устройства. Объекты фильтра могут иметь такие свойства, как vendorId
, productId
, classCode
, subclassCode
, protocolCode
. и серийный номер
.
Например, если мы хотим получить только список устройств Apple, код должен выглядеть так:
navigator.usb.requestDevice({ filters: [{ vendorId: 0x05ac }] });
Вот список идентификаторов USB.
Получение списка уже сопряженных устройств
После сопряжения и получения разрешения мы можем получить все сопряженные устройства с помощью метода USB.getDevices()
. Нам нужно использовать метод USB.requestDevice()
только один раз, чтобы получить разрешение, после чего мы можем получить массив сопряженных устройств с помощью USB.getDevices()
.. р>
async function getDevices() {
const devices = await navigator.usb.getDevices();
devices.forEach((device) => {
console.log(`Name: ${device.productName}, Serial: ${device.serialNumber}`);
});
return devices;
}
Отправка данных на USB-устройство с помощью WebUSB API
Теперь, когда у нас есть разрешение на использование USB-устройства и мы можем получить список сопряженных устройств, давайте посмотрим, как мы можем отправить на него данные.
Вот простой код, который отправляет данные на подключенное устройство:
async function transferOutTest(device) {
await device.open();
await device.selectConfiguration(1);
await device.claimInterface(0);
await device.transferOut(
2,
new Uint8Array(
new TextEncoder().encode('Test valuen')
),
);
await device.close();
}
* open()
запускает сеанс устройства.
* selectConfiguration()
выбирает конфигурацию для конкретного устройства.
* claimInterface()
запрашивает монопольный доступ к специфичному для устройства интерфейсу.
* transferOut()
отправляет данные на USB-устройство.
* close()
освобождает интерфейсы и завершает сеанс устройства.
Пример печати этикеток с помощью WebUSB API
Я создал простой пример печати этикеток с помощью TSPL и WebUSB API. Вы можете получить его с GitHub, но вот более короткая версия:
<button onclick="requestDevice()">Request device</button><br><br>
<button id="device"></button>
<script>
async function requestDevice() {
try {
const device = await navigator.usb.requestDevice({ filters: [] });
const elem = document.querySelector('#device');
elem.textContent = `Print with '${device.productName}'`;
elem.onclick = () => testPrint(device);
} catch (e) {
console.error(e);
}
}
async function testPrint(device) {
const cmds = [
'SIZE 48 mm,25 mm',
'CLS',
'TEXT 30,10,"4",0,1,1,"HackerNoon"',
'TEXT 30,50,"2",0,1,1,"WebUSB API"',
'BARCODE 30,80,"128",70,1,0,2,2,"altospos.com"',
'PRINT 1',
'END',
];
await device.open();
await device.selectConfiguration(1);
await device.claimInterface(0);
await device.transferOut(
device.configuration.interfaces[0].alternate.endpoints.find(obj => obj.direction === 'out').endpointNumber,
new Uint8Array(
new TextEncoder().encode(cmds.join('rn'))
),
);
await device.close();
}
</script>
И результат выглядит так:
Если вам интересно узнать больше о TSPL/TSPL2, я написал несколько статей, которые могут быть вам полезны. Они охватывают такие темы, как печать этикеток и изображений, а также печать квитанций с использованием TSPL и JavaScript.
Я написал эти статьи после добавления поддержки печати в Alto POS & Inventory, надеясь, что они будут полезны кому-то в похожей ситуации.
* Как печатать этикетки с помощью TSPL и JavaScript * Как печатать ИЗОБРАЖЕНИЯ с помощью TSPL и JavaScript * Как печатать квитанции с помощью TSPL и JavaScript
Несколько полезных инструментов:
chrome://device-log/
— используйте это, чтобы получить сведения об устройстве и создать тестовое устройство.chrome://device-log/
— показывает журналы, связанные с устройствами.- Zadig — общие драйверы USB для Windows — вам может потребоваться установить драйвер в Windows.
Не было войны! ✋🏽
Оригинал