Создание плагина
Теперь, когда мы выделили наши RGB-данные, можно приступать к созданию плагина.
Для начала откройте текстовый редактор и вставьте приведённый ниже текст.
export function Name() { return ""; }export function VendorId() { return ; }export function ProductId() { return ; }export function Publisher() { return ""; }export function Documentation(){ return "troubleshooting/brand"; }export function Size() { return [1,1]; }export function ControllableParameters() { return [ {"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"009bde"}, {"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"}, {"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"}, ];}
export function Initialize() {
}
var vLedNames = [ "Led 1" ];var vLedPositions = [ [0,0] ];
export function LedNames() {
}
export function LedPositions() {
}
export function Render() {
}
export function Shutdown() {
}
function hexToRgb(hex) { let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); let colors = []; colors[0] = parseInt(result[1], 16); colors[1] = parseInt(result[2], 16); colors[2] = parseInt(result[3], 16);
return colors;}
export function Validate(endpoint) { return endpoint.interface === 0 && endpoint.usage === 0 && endpoint.usage_page === 0;}
export function ImageUrl() { return "";}Приведённый выше текст — базовая структура плагина устройства.
Начнём с заполнения полей в верхней части плагина информацией об устройстве.
Заполним поле name именем устройства.
Поиск Vendor ID и Product ID
Заголовок раздела «Поиск Vendor ID и Product ID»Для поиска Vendor ID и Product ID необходимо сначала открыть меню настроек SignalRGB с помощью значка шестерёнки в нижнем левом углу.

Теперь перейдите на страницу «Информация об устройстве».

Нам нужны VendorID и ProductID для реализуемого устройства. В данном случае это Corsair Scimitar Pro. Vendor ID Scimitar — 0x1b1c, его Product ID — 0x1b3e.

Теперь, когда мы нашли Vendor ID и Product ID, заполним эти поля в плагине.
В поле Publisher можно указать своё имя!
На данный момент мы заполнили все поля, которые можем.
Вот наш пример для Scimitar Pro с заполненными полями.

Создание RGB-пакета
Заголовок раздела «Создание RGB-пакета»Далее необходимо создать функцию для отправки цветовых данных на устройство. Начнём с простой функции:
function sendColors(shutdown = false){ let packet = [];}Теперь нужно начать заполнять пакет данными, используя данные из одного из помеченных RGB-пакетов.
- ПРИМЕЧАНИЕ: Это устройство использует нулевое дополнение. Это означает, что все байты нужно сдвинуть на 1 позицию. Узнайте о нулевом дополнении здесь.

function sendColors(shutdown = false){ let packet = []; packet[0] = 0x00; packet[1] = 0x07; packet[2] = 0x22; packet[3] = 0x05; packet[4] = 0x01;
}Заполняем данные заголовка пакета, как показано выше. Останавливаемся на позиции 4, так как позиция 5 — первый байт RGB-данных.
Определение типа пакета
Заголовок раздела «Определение типа пакета»Далее нужно создать систему заполнения цветов. Существует несколько способов её реализации, и метод зависит от структуры пакета устройства. Вот несколько различных примеров цветовых пакетов:
function sendZone(zone, shutdown = false){ let packet = []; packet[0] = LongMessage; packet[1] = ConnectionMode; packet[2] = RGBFeatureID; packet[3] = 0x30; packet[4] = zone; packet[5] = 0x01;
var iX = vLedPositions[zone][0]; var iY = vLedPositions[zone][1]; var color; if(shutdown) { color = hexToRgb(shutdownColor); } else if (LightingMode == "Forced") { color = hexToRgb(forcedColor); } else { color = device.color(iX, iY); } packet[6] = color[0]; packet[7] = color[1]; packet[8] = color[2]; packet[9] = 0x02;
device.write(packet, 120);}
function SendPacket(shutdown = false){ let packet = []; packet[0] = 0x00; packet[1] = 0x00; packet[2] = 0x1F; packet[3] = 0x00; packet[4] = 0x00; packet[5] = 0x00; packet[6] = 0x41; packet[7] = 0x0F; packet[8] = 0x03; packet[13] = 0x13;
for(let iIdx = 0; iIdx < vLedPositions.length; iIdx++) {
let iPxX = vLedPositions[iIdx][0]; let iPxY = vLedPositions[iIdx][1]; var color;
if(shutdown) { color = hexToRgb(shutdownColor); } else if (LightingMode === "Forced") { color = hexToRgb(forcedColor); } else { color = device.color(iPxX, iPxY); }
let iLedIdx = (iIdx*3) + 14; packet[iLedIdx] = color[0]; packet[iLedIdx+1] = color[1]; packet[iLedIdx+2] = color[2]; } device.write(packet, 120);}
function sendColors(shutdown = false){
let packet = []; packet[0x00] = 0x00; packet[0x01] = 0x08; packet[0x02] = 0x12; packet[0x03] = 0x05; packet[0x04] = 0x01;
let zoneId = [1, 2, 3, 4, 5];
for(let zone_idx = 0; zone_idx < vLedPositions.length; zone_idx++) { let iX = vLedPositions[zone_idx][0]; let iY = vLedPositions[zone_idx][1]; var col;
if(shutdown){ col = hexToRgb(shutdownColor); }else if (LightingMode === "Forced") { col = hexToRgb(forcedColor); }else{ col = device.color(iX, iY); }
packet[(zone_idx * 4) + 2] = zoneId[zone_idx]; packet[(zone_idx * 4) + 3] = col[0]; packet[(zone_idx * 4) + 4] = col[1]; packet[(zone_idx * 4) + 5] = col[2]; }
device.write(packet, 120);}Три приведённых выше примера подходят для разных структур пакетов. Функция sendZone хороша для устройств, использующих отдельный пакет для каждого светодиода. Функция SendPacket больше подходит для устройств, отправляющих несколько светодиодов подряд в одном пакете. Функция sendColors подходит для устройств с несколькими светодиодами в пакете, но не идущими подряд. В нашем случае мы будем использовать функцию sendColors.
function sendColors(shutdown = false){ let packet = [];
packet[0] = 0x00; packet[1] = 0x07; packet[2] = 0x22; packet[3] = 0x05; packet[4] = 0x01;
let zoneId = [2, 4, 5, 1, 3];
for(let zone_idx = 0; zone_idx < vLedPositions.length; zone_idx++) { let iX = vLedPositions[zone_idx][0]; let iY = vLedPositions[zone_idx][1]; var col;
if(shutdown){ col = hexToRgb(shutdownColor); }else if (LightingMode === "Forced") { col = hexToRgb(forcedColor); }else{ col = device.color(iX, iY); }
packet[(zone_idx * 1) + 2] = zoneId[zone_idx]; packet[(zone_idx * 1) + 3] = col[0]; packet[(zone_idx * 1) + 4] = col[1]; packet[(zone_idx * 1) + 5] = col[2]; }
packet[21] = 0xff; packet[22] = 0xff; packet[23] = 0xff;
device.write(packet, 120);}Для правильной настройки функции sendColors необходимо выяснить Zone ID устройства. Снова глядя на захват пакетов, видим, что порядок зон — 2, 4, 5, 1, 3, как показано ниже. Заметим, что мы добавили 5-ю зону: похоже, мы также можем адресовать светодиод DPI.

Определив Zone ID, необходимо выяснить смещения для zone_idx. Первая зона находится в packet[4], вторая — в packet[8]. Это означает, что zone_idx нужно умножать на 4 при каждом переходе к новому светодиоду. Также нужно выяснить смещение RGB-данных. Поскольку первая зона находится в packet[5], просто нужно сместить пакет на 5 байт, как показано ниже.
function sendColors(shutdown = false){ let packet = []; packet[0] = 0x00; packet[1] = 0x07; packet[2] = 0x22; packet[3] = 0x05; packet[4] = 0x01;
let zoneId = [2, 4, 5, 1, 3];
for(let zone_idx = 0; zone_idx < vLedPositions.length; zone_idx++) { let iX = vLedPositions[zone_idx][0]; let iY = vLedPositions[zone_idx][1]; var col;
if(shutdown){ col = hexToRgb(shutdownColor); }else if (LightingMode === "Forced") { col = hexToRgb(forcedColor); }else{ col = device.color(iX, iY); }
packet[(zone_idx * 4) + 5] = zoneId[zone_idx]; packet[(zone_idx * 4) + 6] = col[0]; packet[(zone_idx * 4) + 7] = col[1]; packet[(zone_idx * 4) + 8] = col[2]; }
device.write(packet, 120);}Добавив всё необходимое в пакет, нужно найти его длину. Просто посмотрите на длину данных в Wireshark. В нашем примере длина данных — 64 байта.
- ПРИМЕЧАНИЕ: Это устройство использует нулевое дополнение, поэтому длина записи должна быть на единицу больше, чем в захвате Wireshark.

Зная длину данных, устанавливаем длину device.write в 65 байт, как показано ниже.
function sendColors(shutdown = false){ let packet = []; packet[0] = 0x00; packet[1] = 0x07; packet[2] = 0x22; packet[3] = 0x05; packet[4] = 0x01;
let zoneId = [2, 4, 5, 1, 3];
for(let zone_idx = 0; zone_idx < vLedPositions.length; zone_idx++) { let iX = vLedPositions[zone_idx][0]; let iY = vLedPositions[zone_idx][1]; var col;
if(shutdown){ col = hexToRgb(shutdownColor); }else if (LightingMode === "Forced") { col = hexToRgb(forcedColor); }else{ col = device.color(iX, iY); }
packet[(zone_idx * 4) + 5] = zoneId[zone_idx]; packet[(zone_idx * 4) + 6] = col[0]; packet[(zone_idx * 4) + 7] = col[1]; packet[(zone_idx * 4) + 8] = col[2]; }
device.write(packet, 65);}Теперь, когда RGB-пакет настроен, нужно настроить светодиоды и выбрать конечные точки устройства.
Базовая настройка светодиодов
Заголовок раздела «Базовая настройка светодиодов»Для настройки светодиодов необходимо добавить правильное количество светодиодов в vLedNames и vLedPositions. В нашем случае нужно добавить ещё четыре светодиода к каждому, как показано ниже.
var vLedNames = [ "Led 1", "Led 2", "Led 3", "Led 4", "Led 5" ];var vLedPositions = [ [0,0], [1,0], [2,0], [3,0], [4,0] ];На данный момент даём этим четырём светодиодам базовые привязки, так как не знаем, где эти светодиоды физически расположены на устройстве относительно их позиций в SignalRGB.
Теперь, когда светодиоды нанесены на карту, нужно установить размер устройства. Размер устройства должен быть на единицу больше дальнейшего светодиода в обоих направлениях. В нашем случае размер должен быть [5,1], так как дальнейший светодиод находится в [4,0].
export function Name() { return "Corsair Scimitar Pro"; }export function VendorId() { return 0x1b1c; }export function ProductId() { return 0x1B3E; }export function Publisher() { return "WhirlwindFX"; }export function Documentation(){ return "troubleshooting/corsair"; }export function Size() { return [5,1]; }Следующее — выяснить конечную точку устройства.