Управление поворотным устройством для камеры видеонаблюдения

Вот реализация, проверьте пожалуйста

// Путь к RPC
var pathRPC = "/rpc/v1/wb-mqtt-serial/port/Load/";

/*
Из мануала:
Byte 1	Byte 2	Byte 3	Byte 4	Byte 5	Byte 6	Byte 7
Sync	Camera Address	Command 1	Command 2	Data 1	Data 2	Checksum
 

Byte 1 (Sync) - the synchronization byte, fixed to FF
Byte 2 (Camera Address) - logical address of the camera being controlled (Address 1 is 01)
Byte 3 & 4 (Command 1 and 2) are shown below
Byte 5 (Data 1) - pan speed, range from 00 (stop) to 3F (high speed) and FF for "turbo" speed (the maximum pan speed that the device can go)
Byte 6 (Data 2) - tilt speed, range from 00 (stop) to 3F (maximum speed)
Byte 7 (Checksum) - sum of bytes (excluding the synchronization byte), then modulo 100 (Decimal code: 256)

То есть длинfа посылки всегда 7 байт.
Первый - всегда 0xff
Второй - camID
3-4 команда
5 - скорость горизонталь
6 - скорость вертикаль
7 - crc. Вот его и реализуем в функции calcCRC
*/


// Вычисляет контрольную сумму CRC по протоколу Pelco-D
//На входе строка в которой каждый байт соответствует посылке. Если в строке есть 7 байт или больше они должны быть нулевыми.
function calcCRC(str) {
    // Сумма начинается с 0
    var sum = 0;

    // Проходим по строке, игнорируя первый символ (FF)
    for (i = 1; i < str.length; i++) {
        // Получаем числовое представление текущего символа (ASCII-код)
        var byteValue = str.charCodeAt(i);
        sum += byteValue;
    }

    // Возвращаем остаток от деления суммы на 256 
    //return (sum % 256).toString(16);
    return (sum % 256);
}

/*
//просто тест для CRC
var testStr = String.fromCharCode(0xff) +
                String.fromCharCode(0x10) +
                String.fromCharCode(0xf0) +
                String.fromCharCode(0x80) +
                String.fromCharCode(0x20) +
                String.fromCharCode(0x20) +
                String.fromCharCode(0x00);

log.info("calcCRC()", calcCRC(testStr)); //0xc0 норм
*/


function bytesToHexString(arr) {
    var result = '';
    for (var i = 0; i < arr.length; i++) {
        var hex = arr.charCodeAt(i).toString(16);
        //var hex = arr.charCodeAt(i);
      log.info("hex", i, "=", hex)
        if (hex.length < 2) {
            hex = '0' + hex;
        }
        result += hex;
    }
    return result;
}

function hexStringToBytes(hex) {
    var bytes = [];
    for (var i = 0; i < hex.length; i += 2) {
        bytes.push(parseInt(hex.substr(i, 2), 16));
    }
    return bytes;
}



function createCam(nameCam, portCam, speedportCam, parityCam, stopBitCam, camID) {
  //log.info ("nameCam=", nameCam )
  //log.info ("portCam=", portCam )
  //log.info ("speedportCam=", speedportCam )
  //log.info ("parityCam=", parityCam )
  //log.info ("stopBitCam=", stopBitCam )
  //log.info ("camID=", camID )
    // Создаем виртуальное устройство
    makeNewVirtualControl(nameCam, "panSpeed", { type: "range", value: 20, min: 0, max: 100, readonly: false });
    makeNewVirtualControl(nameCam, "Left", { type: "pushbutton", readonly: false });
    //makeNewVirtualControl(nameCam, "Up", { type: "pushbutton", readonly: false });
    //makeNewVirtualControl(nameCam, "Stop", { type: "pushbutton", readonly: false });
    //makeNewVirtualControl(nameCam, "Down", { type: "pushbutton", readonly: false });

    // Up
    defineRule(nameCam + "_rule", {
        whenChanged: nameCam + "/Left",
        then: function (newValue, devName, cellName) {
            log.info(nameCam + "RULE!", "cellName=", cellName);
            var req = camCommandMsg(camID, 0x00, 0x04, dev[nameCam+"/panSpeed"], 0x00);
            log.info("Left=", req);
            requestRPC(portCam, speedportCam, parityCam, stopBitCam, nameCam, 1, "HEX", req, 8);
        }
    });


/*
    // Position slider
    defineRule(nameCam + "_rule_position", {
        whenChanged: nameCam + "/Position",
        then: function (value) {
            var is_auto_set = positionSetAuto[camID];
            if (is_auto_set === 0) {
                //var val = (dev[nameCam] && dev[nameCam]["Position"] !== undefined) ? dev[nameCam]["Position"] : 0;
                //var req = camCommandMsg(camID, blindCh_L, blindCh_H, 0x03, 0x04, val);
                //requestRPC(portCam, speedportCam, parityCam, stopBitCam, nameCam, 1, "HEX", req, 8);
            } else {
                //positionSetAuto[camID] = 0;
            }
        }
    });
*/
  
    // MQTT reply tracking
    trackMqtt(pathRPC + nameCam + "/reply", function (message) {
        log.info("from " + nameCam + " name: {}, value: {}".format(message.topic, message.value));
        var replyObj;
        try {
            replyObj = JSON.parse(message.value);
        } catch (e) {
            log.error("JSON parse error: " + e);
            return;
        }
        if (replyObj && replyObj.error === null) {
            var hexStr = replyObj.result.response;
            log.info("from " + nameCam + " replyObj.result.response: {}".format(hexStr));
            }
        })
   
 
return 0;
}

function requestRPC(modbusPort, modbusSpeed, modbusParity, reqStopbit, clientID, requestID, messageType, message, responseSize) {
    // Формируем JSON запрос:
    var strJson = JSON.stringify({
        params: {
            response_size: responseSize,
            format: messageType,
            path: modbusPort,
            baud_rate: modbusSpeed,
            parity: modbusParity,
            data_bits: 8,
            stop_bits: reqStopbit,
            msg: message
        },
        id: requestID
    });
    publish(pathRPC + clientID, strJson, 2, false);
}

function camCommandMsg(camID, command1, command2, data1, data2) {
    // Сформируем набор байт команды строкой.
    var data = String.fromCharCode(0xFF, camID, command1, command2, data1, data2)
    log.info ("datalen=",data.length)

    var crc = calcCRC(data);//Рассчитаем CRC
    //log.info ("crc=",crc)
    //log.info ("dataHEX1=",data)
    data = data+String.fromCharCode(crc); //Добавим CRC к строке
    var bytesStr = bytesToHexString(data);
    //log.info ("dataHEX2=",data)
    return bytesStr;
}

function makeNewVirtualControl(vdName, nameControl, typeControl) {
    if (getDevice(vdName) === undefined) {
        log.info("Define new");
        defineVirtualDevice(vdName, {
            title: vdName,
            cells: {},
        });
    }
    // Проверим есть ли уже контрол и если нет - создадим.
    var devObj = getDevice(vdName);
    if (devObj && !devObj.isControlExists(nameControl)) {
        log.debug("Контрола " + nameControl + " нет, создаем.");
        devObj.addControl(nameControl, typeControl);
    }
}

// Создаем виртуальное устройство, с контролами для камеры
// ID делаем уникальным
// createCam(nameCam, portCam, speedportCam, parityCam, stopBitCam, camID)
//            имя               порт     bod parity stopbit  camID
createCam("Камера1", "/dev/ttyRS485-2", 9600, "N",    1,     0x01 );
1 лайк