Sensor
/** * Payload Encoder * * Copyright 2025 Milesight IoT * * @product UC100 v2 */ var RAW_VALUE = 0x00; /* eslint no-redeclare: "off" */ /* eslint-disable */ // Chirpstack v4 function encodeDownlink(input) { var encoded = milesightDeviceEncode(input.data); return { bytes: encoded }; } // Chirpstack v3 function Encode(fPort, obj) { return milesightDeviceEncode(obj); } // The Things Network function Encoder(obj, port) { return milesightDeviceEncode(obj); } /* eslint-enable */ function milesightDeviceEncode(payload) { var encoded = []; if ("reboot" in payload) { encoded = encoded.concat(reboot(payload.reboot)); } if ("report_status" in payload) { encoded = encoded.concat(reportStatus(payload.report_status)); } if ("sync_time" in payload) { encoded = encoded.concat(syncTime(payload.sync_time)); } if ("report_interval" in payload) { encoded = encoded.concat(setReportInterval(payload.report_interval)); } if ("confirm_mode_enable" in payload) { encoded = encoded.concat(setConfirmModeEnable(payload.confirm_mode_enable)); } if ("time_zone" in payload) { encoded = encoded.concat(setTimeZone(payload.time_zone)); } if ("dst_config" in payload) { encoded = encoded.concat(setDaylightSavingTime(payload.dst_config)); } if ("modbus_serial_port_config" in payload) { encoded = encoded.concat(setModbusSerialPortConfig(payload.modbus_serial_port_config)); } if ("modbus_config" in payload) { encoded = encoded.concat(setModbusConfig(payload.modbus_config)); } if ("query_modbus_serial_port_config" in payload) { encoded = encoded.concat(queryModbusSerialPortConfig(payload.query_modbus_serial_port_config)); } if ("query_modbus_config" in payload) { encoded = encoded.concat(queryModbusConfig(payload.query_modbus_config)); } if ("modbus_channels" in payload) { for (var i = 0; i < payload.modbus_channels.length; i++) { encoded = encoded.concat(setModbusChannel(payload.modbus_channels[i])); } } if ("modbus_channels_name" in payload) { for (var i = 0; i < payload.modbus_channels_name.length; i++) { encoded = encoded.concat(setModbusChannelName(payload.modbus_channels_name[i])); } } if ("remove_modbus_channels" in payload) { for (var i = 0; i < payload.remove_modbus_channels.length; i++) { encoded = encoded.concat(removeModbusChannel(payload.remove_modbus_channels[i])); } } if ("retransmit_config" in payload) { encoded = encoded.concat(setRetransmitConfig(payload.retransmit_config)); } if ("resend_interval" in payload) { encoded = encoded.concat(setResendInterval(payload.resend_interval)); } if ("retransmit_enable" in payload) { encoded = encoded.concat(setRetransmitEnable(payload.retransmit_enable)); } if ("history_enable" in payload) { encoded = encoded.concat(setHistoryEnable(payload.history_enable)); } if ("fetch_history" in payload) { encoded = encoded.concat(fetchHistory(payload.fetch_history)); } if ("clear_history" in payload) { encoded = encoded.concat(clearHistory(payload.clear_history)); } if ("batch_enable_rules" in payload) { encoded = encoded.concat(setBatchEnableRules(payload.batch_enable_rules)); } if ("batch_disable_rules" in payload) { encoded = encoded.concat(setBatchDisableRules(payload.batch_disable_rules)); } if ("batch_remove_rules" in payload) { encoded = encoded.concat(setBatchRemoveRules(payload.batch_remove_rules)); } if ("query_rule_config" in payload) { encoded = encoded.concat(queryRuleConfig(payload.query_rule_config)); } if ("rule_config" in payload) { for (var i = 0; i < payload.rule_config.length; i++) { encoded = encoded.concat(setRuleConfig(payload.rule_config[i])); } } return encoded; } /** * reboot device * @param {number} reboot values: (0: no, 1: yes) * @example { "reboot": 1 } */ function reboot(reboot) { var yes_no_map = { 0: "no", 1: "yes" }; var yes_no_values = getValues(yes_no_map); if (yes_no_values.indexOf(reboot) === -1) { throw new Error("reboot must be one of " + yes_no_values.join(", ")); } if (getValue(yes_no_map, reboot) === 0) { return []; } return [0xff, 0x10, 0xff]; } /** * report device status * @since v2.0 * @param {number} report_status values: (0: no, 1: yes) * @example { "report_status": 1 } */ function reportStatus(report_status) { var yes_no_map = { 0: "no", 1: "yes" }; var yes_no_values = getValues(yes_no_map); if (yes_no_values.indexOf(report_status) === -1) { throw new Error("report_status must be one of " + yes_no_values.join(", ")); } if (getValue(yes_no_map, report_status) === 0) { return []; } return [0xff, 0x28, 0xff]; } /** * sync time * @since v2.0 * @param {number} sync_time values: (0: no, 1: yes) * @example { "sync_time": 1 } */ function syncTime(sync_time) { var yes_no_map = { 0: "no", 1: "yes" }; var yes_no_values = getValues(yes_no_map); if (yes_no_values.indexOf(sync_time) === -1) { throw new Error("sync_time must be one of " + yes_no_values.join(", ")); } if (getValue(yes_no_map, sync_time) === 0) { return []; } return [0xff, 0x4a, 0x00]; } /** * set report interval * @param {number} report_interval unit: second * @example { "report_interval": 600 } */ function setReportInterval(report_interval) { if (typeof report_interval !== "number") { throw new Error("report_interval must be a number"); } if (report_interval < 0) { throw new Error("report_interval must be greater than 0"); } var buffer = new Buffer(4); buffer.writeUInt8(0xff); buffer.writeUInt8(0x03); buffer.writeUInt16LE(report_interval); return buffer.toBytes(); } /** * confirm mode enable * @param {number} confirm_mode_enable values: (0: disable, 1: enable) * @example { "confirm_mode_enable": 1 } */ function setConfirmModeEnable(confirm_mode_enable) { var enable_map = { 0: "disable", 1: "enable" }; var enable_values = getValues(enable_map); if (enable_values.indexOf(confirm_mode_enable) === -1) { throw new Error("confirm_mode_enable must be one of " + enable_values.join(", ")); } var buffer = new Buffer(3); buffer.writeUInt8(0xff); buffer.writeUInt8(0x04); buffer.writeUInt8(getValue(enable_map, confirm_mode_enable)); return buffer.toBytes(); } /** * set time zone * @param {number} time_zone unit: minute, convert: "hh:mm" -> "hh * 60 + mm", values: ( -720: UTC-12, -660: UTC-11, -600: UTC-10, -570: UTC-9:30, -540: UTC-9, -480: UTC-8, -420: UTC-7, -360: UTC-6, -300: UTC-5, -240: UTC-4, -210: UTC-3:30, -180: UTC-3, -120: UTC-2, -60: UTC-1, 0: UTC, 60: UTC+1, 120: UTC+2, 180: UTC+3, 240: UTC+4, 300: UTC+5, 360: UTC+6, 420: UTC+7, 480: UTC+8, 540: UTC+9, 570: UTC+9:30, 600: UTC+10, 660: UTC+11, 720: UTC+12, 765: UTC+12:45, 780: UTC+13, 840: UTC+14 ) * @example { "time_zone": 480 } * @example { "time_zone": -240 } */ function setTimeZone(time_zone) { var timezone_map = { "-720": "UTC-12", "-660": "UTC-11", "-600": "UTC-10", "-570": "UTC-9:30", "-540": "UTC-9", "-480": "UTC-8", "-420": "UTC-7", "-360": "UTC-6", "-300": "UTC-5", "-240": "UTC-4", "-210": "UTC-3:30", "-180": "UTC-3", "-120": "UTC-2", "-60": "UTC-1", 0: "UTC", 60: "UTC+1", 120: "UTC+2", 180: "UTC+3", 210: "UTC+3:30", 240: "UTC+4", 270: "UTC+4:30", 300: "UTC+5", 330: "UTC+5:30", 345: "UTC+5:45", 360: "UTC+6", 390: "UTC+6:30", 420: "UTC+7", 480: "UTC+8", 540: "UTC+9", 570: "UTC+9:30", 600: "UTC+10", 630: "UTC+10:30", 660: "UTC+11", 720: "UTC+12", 765: "UTC+12:45", 780: "UTC+13", 840: "UTC+14" }; var timezone_values = getValues(timezone_map); if (timezone_values.indexOf(time_zone) === -1) { throw new Error("time_zone must be one of " + timezone_values.join(", ")); } var buffer = new Buffer(4); buffer.writeUInt8(0xff); buffer.writeUInt8(0xbd); buffer.writeInt16LE(getValue(timezone_map, time_zone)); return buffer.toBytes(); } /** * set daylight saving time * @since v2.0 * @param {object} dst_config * @param {number} dst_config.enable values: (0: disable, 1: enable) * @param {number} dst_config.offset, unit: minute * @param {number} dst_config.start_month, values: (1: January, 2: February, 3: March, 4: April, 5: May, 6: June, 7: July, 8: August, 9: September, 10: October, 11: November, 12: December) * @param {number} dst_config.start_week_num, range: [1, 5] * @param {number} dst_config.start_week_day, range: [1, 7] * @param {number} dst_config.start_time, unit: minute, convert: "hh:mm" -> "hh * 60 + mm" * @param {number} dst_config.end_month, values: (1: January, 2: February, 3: March, 4: April, 5: May, 6: June, 7: July, 8: August, 9: September, 10: October, 11: November, 12: December) * @param {number} dst_config.end_week_num, range: [1, 5] * @param {number} dst_config.end_week_day, range: [1, 7] * @param {number} dst_config.end_time, unit: minute, convert: "hh:mm" -> "hh * 60 + mm" * @example { "dst_config": { "enable": 1, "offset": 60, "start_month": 3, "start_week_num": 2, "start_week_day": 7, "start_time": 120, "end_month": 1, "end_week_num": 4, "end_week_day": 1, "end_time": 180 } } output: FFBA013C032778000141B400 */ function setDaylightSavingTime(dst_config) { var enable = dst_config.enable; var offset = dst_config.offset; var start_month = dst_config.start_month; var start_week_num = dst_config.start_week_num; var start_week_day = dst_config.start_week_day; var start_time = dst_config.start_time; var end_month = dst_config.end_month; var end_week_num = dst_config.end_week_num; var end_week_day = dst_config.end_week_day; var end_time = dst_config.end_time; var enable_map = { 0: "disable", 1: "enable" }; var enable_values = getValues(enable_map); if (enable_values.indexOf(enable) === -1) { throw new Error("dst_config.enable must be one of " + enable_values.join(", ")); } var week_values = [1, 2, 3, 4, 5, 6, 7]; var month_values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; var enable_value = getValue(enable_map, enable); if (enable_value && month_values.indexOf(start_month) === -1) { throw new Error("dst_config.start_month must be one of " + month_values.join(", ")); } if (enable_value && month_values.indexOf(end_month) === -1) { throw new Error("dst_config.end_month must be one of " + month_values.join(", ")); } if (enable_value && week_values.indexOf(start_week_day) === -1) { throw new Error("dst_config.start_week_day must be one of " + week_values.join(", ")); } if (enable_value && week_values.indexOf(end_week_day) === -1) { throw new Error("dst_config.end_week_day must be one of " + week_values.join(", ")); } var data = 0x00; data |= getValue(enable_map, enable) << 7; data |= offset; var buffer = new Buffer(11); buffer.writeUInt8(0xf9); buffer.writeUInt8(0x72); buffer.writeUInt8(data); buffer.writeUInt8(enable_value && start_month); buffer.writeUInt8(enable_value && (start_week_num << 4) | start_week_day); buffer.writeUInt16LE(enable_value && start_time); buffer.writeUInt8(enable_value && end_month); buffer.writeUInt8(enable_value && (end_week_num << 4) | end_week_day); buffer.writeUInt16LE(enable_value && end_time); return buffer.toBytes(); } /** * Set modbus serial port config * @since v2.0 * @param {object} modbus_serial_port_config * @param {number} modbus_serial_port_config.baud_rate values: (1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200) * @param {number} modbus_serial_port_config.data_bits values: (7, 8, 9) * @param {number} modbus_serial_port_config.stop_bits values: (1, 2, 3) * @param {number} modbus_serial_port_config.parity values: (0: none, 1: odd, 2: even) * @example { "modbus_serial_port_config": { "baud_rate": 9600, "data_bits": 8, "stop_bits": 1, "parity": 0 } } */ function setModbusSerialPortConfig(modbus_serial_port_config) { var baud_rate = modbus_serial_port_config.baud_rate; var data_bits = modbus_serial_port_config.data_bits; var stop_bits = modbus_serial_port_config.stop_bits; var parity = modbus_serial_port_config.parity; var baud_rate_values = [1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]; if (baud_rate_values.indexOf(baud_rate) === -1) { throw new Error("modbus_serial_port_config.baud_rate must be one of " + baud_rate_values.join(", ")); } var data_bits_values = [7, 8, 9]; if (data_bits_values.indexOf(data_bits) === -1) { throw new Error("modbus_serial_port_config.data_bits must be one of " + data_bits_values.join(", ")); } var stop_bits_values = [1, 2, 3]; if (stop_bits_values.indexOf(stop_bits) === -1) { throw new Error("modbus_serial_port_config.stop_bits must be one of " + stop_bits_values.join(", ")); } var parity_map = { 0: "none", 1: "odd", 2: "even" }; var parity_values = getValues(parity_map); if (parity_values.indexOf(parity) === -1) { throw new Error("modbus_serial_port_config.parity must be one of " + parity_values.join(", ")); } var buffer = new Buffer(9); buffer.writeUInt8(0xf9); buffer.writeUInt8(0x78); buffer.writeUInt32LE(baud_rate); buffer.writeUInt8(data_bits); buffer.writeUInt8(stop_bits); buffer.writeUInt8(getValue(parity_map, parity)); return buffer.toBytes(); } /** * Set modbus config * @since v2.0 * @param {object} modbus_config * @param {number} modbus_config.exec_interval range: [100, 65535] * @param {number} modbus_config.max_response_time range: [100, 65535] * @param {number} modbus_config.retry_times range: [0, 255] * @param {number} modbus_config.pass_through_enable values: (0: disable, 1: enable) * @param {number} modbus_config.pass_through_direct values: (0: active, 1: bidirectional) * @param {number} modbus_config.pass_through_port range: [2, 223] * @example { "modbus_config": { "exec_interval": 1000, "max_response_time": 1000, "retry_times": 3, "pass_through_enable": 1, "pass_through_direct": 1, "pass_through_port": 52 } } */ function setModbusConfig(modbus_config) { var exec_interval = modbus_config.exec_interval; var max_response_time = modbus_config.max_response_time; var retry_times = modbus_config.retry_times; var pass_through_enable = modbus_config.pass_through_enable; var pass_through_direct = modbus_config.pass_through_direct; var pass_through_port = modbus_config.pass_through_port; var enable_map = { 0: "disable", 1: "enable" }; var enable_values = getValues(enable_map); if (enable_values.indexOf(pass_through_enable) === -1) { throw new Error("modbus_config.pass_through_enable must be one of " + enable_values.join(", ")); } var mode_map = { 0: "active", 1: "bidirectional" }; var mode_values = getValues(mode_map); if (mode_values.indexOf(pass_through_direct) === -1) { throw new Error("modbus_config.pass_through_direct must be one of " + mode_values.join(", ")); } if (pass_through_port < 2 || pass_through_port > 223) { throw new Error("modbus_config.pass_through_port must be between 2 and 223"); } var data = 0x00; data |= getValue(enable_map, pass_through_enable) << 4; data |= getValue(mode_map, pass_through_direct); var buffer = new Buffer(9); buffer.writeUInt8(0xf9); buffer.writeUInt8(0x79); buffer.writeUInt16LE(exec_interval); buffer.writeUInt16LE(max_response_time); buffer.writeUInt8(retry_times); buffer.writeUInt8(data); buffer.writeUInt8(pass_through_port); return buffer.toBytes(); } /** * Query modbus serial port config * @param {number} query_modbus_serial_port_config values: (0: no, 1: yes) * @example { "query_modbus_serial_port_config": 1 } */ function queryModbusSerialPortConfig(query_modbus_serial_port_config) { var yes_no_map = { 0: "no", 1: "yes" }; var yes_no_values = getValues(yes_no_map); if (yes_no_values.indexOf(query_modbus_serial_port_config) === -1) { throw new Error("query_modbus_serial_port_config must be one of " + yes_no_values.join(", ")); } if (getValue(yes_no_map, query_modbus_serial_port_config) === 0) { return []; } return [0xf9, 0x7a, 0x00]; } /** * Query modbus config * @param {number} query_modbus_config values: (0: no, 1: yes) * @example { "query_modbus_config": 1 } */ function queryModbusConfig(query_modbus_config) { var yes_no_map = { 0: "no", 1: "yes" }; var yes_no_values = getValues(yes_no_map); if (yes_no_values.indexOf(query_modbus_config) === -1) { throw new Error("query_modbus_config must be one of " + yes_no_values.join(", ")); } if (getValue(yes_no_map, query_modbus_config) === 0) { return []; } return [0xf9, 0x7a, 0x01]; } /** * Set modbus channel config * @param {object} modbus_channels * @param {number} modbus_channels._item.channel_id range: [1, 32] * @param {number} modbus_channels._item.slave_id range: [1, 255] * @param {number} modbus_channels._item.register_address range: [0, 65535] * @param {number} modbus_channels._item.register_type values: ( * 0: MB_REG_COIL, 1: MB_REG_DIS, * 2: MB_REG_INPUT_AB, 3: MB_REG_INPUT_BA, * 4: MB_REG_INPUT_INT32_ABCD, 5: MB_REG_INPUT_INT32_BADC, 6: MB_REG_INPUT_INT32_CDAB, 7: MB_REG_INPUT_INT32_DCBA, * 8: MB_REG_INPUT_INT32_AB, 9: MB_REG_INPUT_INT32_CD, * 10: MB_REG_INPUT_FLOAT_ABCD, 11: MB_REG_INPUT_FLOAT_BADC, 12: MB_REG_INPUT_FLOAT_CDAB, 13: MB_REG_INPUT_FLOAT_DCBA, * 14: MB_REG_HOLD_INT16_AB, 15: MB_REG_HOLD_INT16_BA, * 16: MB_REG_HOLD_INT32_ABCD, 17: MB_REG_HOLD_INT32_BADC, 18: MB_REG_HOLD_INT32_CDAB, 19: MB_REG_HOLD_INT32_DCBA, * 20: MB_REG_HOLD_INT32_AB, 21: MB_REG_HOLD_INT32_CD, * 22: MB_REG_HOLD_FLOAT_ABCD, 23: MB_REG_HOLD_FLOAT_BADC, 24: MB_REG_HOLD_FLOAT_CDAB, 25: MB_REG_HOLD_FLOAT_DCBA, * 26: MB_REG_INPUT_DOUBLE_ABCDEFGH, 27: MB_REG_INPUT_DOUBLE_GHEFCDAB, 28: MB_REG_INPUT_DOUBLE_BADCFEHG, 29: MB_REG_INPUT_DOUBLE_HGFEDCBA, * 30: MB_REG_INPUT_INT64_ABCDEFGH, 31: MB_REG_INPUT_INT64_GHEFCDAB, 32: MB_REG_INPUT_INT64_BADCFEHG, 33: MB_REG_INPUT_INT64_HGFEDCBA, * 34: MB_REG_HOLD_DOUBLE_ABCDEFGH, 35: MB_REG_HOLD_DOUBLE_GHEFCDAB, 36: MB_REG_HOLD_DOUBLE_BADCFEHG, 37: MB_REG_HOLD_DOUBLE_HGFEDCBA, * 38: MB_REG_HOLD_INT64_ABCDEFGH, 39: MB_REG_HOLD_INT64_GHEFCDAB, 40: MB_REG_HOLD_INT64_BADCFEHG, 41: MB_REG_HOLD_INT64_HGFEDCBA, * ) * @param {number} modbus_channels._item.quantity range: [1, 16] * @param {number} modbus_channels._item.sign values: (0: unsigned, 1: signed) * @example { "modbus_channels": [ { "channel_id": 1, "slave_id": 1, "register_address": 1, "quantity": 1, "register_type": 1, "sign": 1 } ] } */ function setModbusChannel(modbus_channels) { var channel_id = modbus_channels.channel_id; var slave_id = modbus_channels.slave_id; var register_address = modbus_channels.register_address; var quantity = modbus_channels.quantity; var register_type = modbus_channels.register_type; var sign = modbus_channels.sign; if (channel_id < 1 || channel_id > 32) { throw new Error("modbus_channels._item.channel_id must be between 1 and 32"); } if (slave_id < 1 || slave_id > 255) { throw new Error("modbus_channels._item.slave_id must be between 1 and 255"); } if (register_address < 0 || register_address > 65535) { throw new Error("modbus_channels._item.address must be between 0 and 65535"); } if (quantity < 1 || quantity > 16) { throw new Error("modbus_channels._item.quantity must be between 1 and 16"); } var register_type_map = { 0: "MB_REG_COIL", 1: "MB_REG_DIS", 2: "MB_REG_INPUT_AB", 3: "MB_REG_INPUT_BA", 4: "MB_REG_INPUT_INT32_ABCD", 5: "MB_REG_INPUT_INT32_BADC", 6: "MB_REG_INPUT_INT32_CDAB", 7: "MB_REG_INPUT_INT32_DCBA", 8: "MB_REG_INPUT_INT32_AB", 9: "MB_REG_INPUT_INT32_CD", 10: "MB_REG_INPUT_FLOAT_ABCD", 11: "MB_REG_INPUT_FLOAT_BADC", 12: "MB_REG_INPUT_FLOAT_CDAB", 13: "MB_REG_INPUT_FLOAT_DCBA", 14: "MB_REG_HOLD_INT16_AB", 15: "MB_REG_HOLD_INT16_BA", 16: "MB_REG_HOLD_INT32_ABCD", 17: "MB_REG_HOLD_INT32_BADC", 18: "MB_REG_HOLD_INT32_CDAB", 19: "MB_REG_HOLD_INT32_DCBA", 20: "MB_REG_HOLD_INT32_AB", 21: "MB_REG_HOLD_INT32_CD", 22: "MB_REG_HOLD_FLOAT_ABCD", 23: "MB_REG_HOLD_FLOAT_BADC", 24: "MB_REG_HOLD_FLOAT_CDAB", 25: "MB_REG_HOLD_FLOAT_DCBA", 26: "MB_REG_INPUT_DOUBLE_ABCDEFGH", 27: "MB_REG_INPUT_DOUBLE_GHEFCDAB", 28: "MB_REG_INPUT_DOUBLE_BADCFEHG", 29: "MB_REG_INPUT_DOUBLE_HGFEDCBA", 30: "MB_REG_INPUT_INT64_ABCDEFGH", 31: "MB_REG_INPUT_INT64_GHEFCDAB", 32: "MB_REG_INPUT_INT64_BADCFEHG", 33: "MB_REG_INPUT_INT64_HGFEDCBA", 34: "MB_REG_HOLD_DOUBLE_ABCDEFGH", 35: "MB_REG_HOLD_DOUBLE_GHEFCDAB", 36: "MB_REG_HOLD_DOUBLE_BADCFEHG", 37: "MB_REG_HOLD_DOUBLE_HGFEDCBA", 38: "MB_REG_HOLD_INT64_ABCDEFGH", 39: "MB_REG_HOLD_INT64_GHEFCDAB", 40: "MB_REG_HOLD_INT64_BADCFEHG", 41: "MB_REG_HOLD_INT64_HGFEDCBA", }; var register_type_values = getValues(register_type_map); if (register_type_values.indexOf(register_type) === -1) { throw new Error("modbus_channels._item.register_type must be one of " + register_type_values.join(", ")); } var sign_map = { 0: "unsigned", 1: "signed" }; var sign_values = getValues(sign_map); if (sign_values.indexOf(sign) === -1) { throw new Error("modbus_channels._item.sign must be one of " + sign_values.join(", ")); } var quantity_values = [1, 2]; if (quantity_values.indexOf(quantity) === -1) { throw new Error("modbus_channels._item.quantity must be one of " + quantity_values.join(", ")); } var data = 0x00; data |= getValue(sign_map, sign) << 4; data |= quantity; var buffer = new Buffer(9); buffer.writeUInt8(0xff); buffer.writeUInt8(0xef); buffer.writeUInt8(0x01); // config modbus channel buffer.writeUInt8(channel_id); buffer.writeUInt8(slave_id); buffer.writeUInt16LE(register_address); buffer.writeUInt8(getValue(register_type_map, register_type)); buffer.writeUInt8(data); return buffer.toBytes(); } /** * set modbus channel name * @param {object} modbus_channels_name * @param {number} modbus_channels_name._item.channel_id range: [1, 32] * @param {string} modbus_channels_name._item.name * @example { "modbus_channels_name": [ { "channel_id": 1, "name": "modbus_channel_1" } ] } */ function setModbusChannelName(modbus_channels_name) { var channel_id = modbus_channels_name.channel_id; var name = modbus_channels_name.name; var buffer = new Buffer(5 + name.length); buffer.writeUInt8(0xff); buffer.writeUInt8(0xef); buffer.writeUInt8(0x02); // config modbus channel name buffer.writeUInt8(channel_id); buffer.writeUInt8(name.length); buffer.writeASCII(name); return buffer.toBytes(); } /** * remove modbus channel * @param {object} remove_modbus_channels * @param {number} remove_modbus_channels._item.channel_id range: [1, 32] * @example { "remove_modbus_channels": [ { "channel_id": 1 } ] } */ function removeModbusChannel(remove_modbus_channels) { var channel_id = remove_modbus_channels.channel_id; if (channel_id < 1 || channel_id > 32) { throw new Error("remove_modbus_channels._item.channel_id must be between 1 and 32"); } var buffer = new Buffer(4); buffer.writeUInt8(0xff); buffer.writeUInt8(0xef); buffer.writeUInt8(0x00); // remove modbus channel buffer.writeUInt8(channel_id); return buffer.toBytes(); } /** * set retransmit config * @since v2.0 * @param {object} retransmit_config * @param {number} retransmit_config.enable values: (0: disable, 1: enable) * @param {number} retransmit_config.interval range: [30, 1200], unit: seconds * @example { "retransmit_config": { "enable": 1, "interval": 60 } } */ function setRetransmitConfig(retransmit_config) { var enable = retransmit_config.enable; var interval = retransmit_config.interval; var enable_map = { 0: "disable", 1: "enable" }; var enable_values = getValues(enable_map); if (enable_values.indexOf(enable) === -1) { throw new Error("retransmit_config.enable must be one of " + enable_values.join(", ")); } if (typeof interval !== "number") { throw new Error("retransmit_config.interval must be a number"); } if (interval < 30 || interval > 1200) { throw new Error("retransmit_config.interval must be in range [30, 1200]"); } var buffer = new Buffer(5); buffer.writeUInt8(0xf9); buffer.writeUInt8(0x0d); buffer.writeUInt8(getValue(enable_map, enable)); buffer.writeUInt16LE(interval); return buffer.toBytes(); } /** * set resend interval * @since v2.0 * @param {number} resend_interval unit: second, range: [30, 1200] * @example { "resend_interval": 60 } */ function setResendInterval(resend_interval) { if (typeof resend_interval !== "number") { throw new Error("resend_interval must be a number"); } if (resend_interval < 30 || resend_interval > 1200) { throw new Error("resend_interval must be in range [30, 1200]"); } var buffer = new Buffer(4); buffer.writeUInt8(0xf9); buffer.writeUInt8(0x0e); buffer.writeUInt16LE(resend_interval); return buffer.toBytes(); } /** * set retransmit enable * @param {number} retransmit_enable values: (0: disable, 1: enable) * @example { "retransmit_enable": 1 } */ function setRetransmitEnable(retransmit_enable) { var enable_map = { 0: "disable", 1: "enable" }; var enable_values = getValues(enable_map); if (enable_values.indexOf(retransmit_enable) === -1) { throw new Error("retransmit_enable must be one of " + enable_values.join(", ")); } var buffer = new Buffer(3); buffer.writeUInt8(0xff); buffer.writeUInt8(0x69); buffer.writeUInt8(getValue(enable_map, retransmit_enable)); return buffer.toBytes(); } /** * history enable * @param {number} history_enable values: (0: disable, 1: enable) * @example { "history_enable": 1 } */ function setHistoryEnable(history_enable) { var enable_map = { 0: "disable", 1: "enable" }; var enable_values = getValues(enable_map); if (enable_values.indexOf(history_enable) === -1) { throw new Error("history_enable must be one of " + enable_values.join(", ")); } var buffer = new Buffer(3); buffer.writeUInt8(0xff); buffer.writeUInt8(0x68); buffer.writeUInt8(getValue(enable_map, history_enable)); return buffer.toBytes(); } /** * fetch history * @since v2.0 * @param {object} fetch_history * @param {number} fetch_history.start_time * @param {number} fetch_history.end_time * @example { "fetch_history": { "start_time": 1609459200, "end_time": 1609545600 } } */ function fetchHistory(fetch_history) { var start_time = fetch_history.start_time; var end_time = fetch_history.end_time || 0; if (typeof start_time !== "number") { throw new Error("fetch_history.start_time must be a number"); } if (end_time && typeof end_time !== "number") { throw new Error("fetch_history.end_time must be a number"); } if (end_time && start_time > end_time) { throw new Error("fetch_history.start_time must be less than fetch_history.end_time"); } var buffer; if (end_time === 0) { buffer = new Buffer(6); buffer.writeUInt8(0xfd); buffer.writeUInt8(0x6b); buffer.writeUInt32LE(start_time); } else { buffer = new Buffer(10); buffer.writeUInt8(0xfd); buffer.writeUInt8(0x6c); buffer.writeUInt32LE(start_time); buffer.writeUInt32LE(end_time); } return buffer.toBytes(); } /** * clear history * @param {number} clear_history values: (0: no, 1: yes) * @example { "clear_history": 1 } */ function clearHistory(clear_history) { var yes_no_map = { 0: "no", 1: "yes" }; var yes_no_values = getValues(yes_no_map); if (yes_no_values.indexOf(clear_history) === -1) { throw new Error("clear_history must be one of " + yes_no_values.join(", ")); } if (getValue(yes_no_map, clear_history) === 0) { return []; } return [0xff, 0x27, 0x01]; } /** * set batch enable rules * @param {object} batch_enable_rules * @param {number} batch_enable_rules.rule_1 values: (0: no, 1: yes) * @param {number} batch_enable_rules.rule_x values: (0: no, 1: yes) * @param {number} batch_enable_rules.rule_16 values: (0: no, 1: yes) * @example { "batch_enable_rules": { "rule_1": 1, "rule_15": 1, "rule_16": 1 } } */ function setBatchEnableRules(batch_enable_rules) { var yes_no_map = { 0: "no", 1: "yes" }; var yes_no_values = getValues(yes_no_map); var rules_offset = { rule_1: 0, rule_2: 1, rule_3: 2, rule_4: 3, rule_5: 4, rule_6: 5, rule_7: 6, rule_8: 7, rule_9: 8, rule_10: 9, rule_11: 10, rule_12: 11, rule_13: 12, rule_14: 13, rule_15: 14, rule_16: 15 }; var data = 0x00; for (var key in rules_offset) { if (key in batch_enable_rules) { if (yes_no_values.indexOf(batch_enable_rules[key]) === -1) { throw new Error("batch_enable_rules." + key + " must be one of " + yes_no_values.join(", ")); } data |= getValue(yes_no_map, batch_enable_rules[key]) << rules_offset[key]; } } var buffer = new Buffer(5); buffer.writeUInt8(0xf9); buffer.writeUInt8(0x76); buffer.writeUInt16LE(data); buffer.writeUInt8(0x01); return buffer.toBytes(); } /** * set batch disable rules * @param {object} batch_disable_rules * @param {number} batch_disable_rules.rule_1 values: (0: no, 1: yes) * @param {number} batch_disable_rules.rule_x values: (0: no, 1: yes) * @param {number} batch_disable_rules.rule_16 values: (0: no, 1: yes) * @example { "batch_disable_rules": { "rule_1": 1, "rule_15": 1, "rule_16": 1 } } */ function setBatchDisableRules(batch_disable_rules) { var yes_no_map = { 0: "no", 1: "yes" }; var yes_no_values = getValues(yes_no_map); var rules_offset = { rule_1: 0, rule_2: 1, rule_3: 2, rule_4: 3, rule_5: 4, rule_6: 5, rule_7: 6, rule_8: 7, rule_9: 8, rule_10: 9, rule_11: 10, rule_12: 11, rule_13: 12, rule_14: 13, rule_15: 14, rule_16: 15 }; var data = 0x00; for (var key in rules_offset) { if (key in batch_disable_rules) { if (yes_no_values.indexOf(batch_disable_rules[key]) === -1) { throw new Error("batch_disable_rules." + key + " must be one of " + yes_no_values.join(", ")); } data |= getValue(yes_no_map, batch_disable_rules[key]) << rules_offset[key]; } } var buffer = new Buffer(5); buffer.writeUInt8(0xf9); buffer.writeUInt8(0x76); buffer.writeUInt16LE(data); buffer.writeUInt8(0x02); return buffer.toBytes(); } /** * set batch remove rules * @param {object} batch_remove_rules * @param {number} batch_remove_rules.rule_1 values: (0: no, 1: yes) * @param {number} batch_remove_rules.rule_x values: (0: no, 1: yes) * @param {number} batch_remove_rules.rule_16 values: (0: no, 1: yes) * @example { "batch_remove_rules": { "rule_1": 1, "rule_15": 1, "rule_16": 1 } } */ function setBatchRemoveRules(batch_remove_rules) { var yes_no_map = { 0: "no", 1: "yes" }; var yes_no_values = getValues(yes_no_map); var rules_offset = { rule_1: 0, rule_2: 1, rule_3: 2, rule_4: 3, rule_5: 4, rule_6: 5, rule_7: 6, rule_8: 7, rule_9: 8, rule_10: 9, rule_11: 10, rule_12: 11, rule_13: 12, rule_14: 13, rule_15: 14, rule_16: 15 }; var data = 0x00; for (var key in rules_offset) { if (key in batch_remove_rules) { if (yes_no_values.indexOf(batch_remove_rules[key]) === -1) { throw new Error("batch_remove_rules." + key + " must be one of " + yes_no_values.join(", ")); } data |= getValue(yes_no_map, batch_remove_rules[key]) << rules_offset[key]; } } var buffer = new Buffer(5); buffer.writeUInt8(0xf9); buffer.writeUInt8(0x76); buffer.writeUInt16LE(data); buffer.writeUInt8(0x03); return buffer.toBytes(); } /** * query rule config * @param {number} query_rule_config range: [1, 16] * @example { "query_rule_config": 1 } */ function queryRuleConfig(query_rule_config) { if (typeof query_rule_config !== "number") { throw new Error("query_rule_config must be a number"); } if (query_rule_config < 1 || query_rule_config > 16) { throw new Error("query_rule_config must be in range [1, 16]"); } var buffer = new Buffer(3); buffer.writeUInt8(0xf9); buffer.writeUInt8(0x77); buffer.writeUInt8(query_rule_config); return buffer.toBytes(); } /** * set rule config * @param {object} rule_config * @param {number} rule_config._item.rule_id range: [1, 16] * @param {number} rule_config._item.enable values: (0: disable, 1: enable) * @param {object} rule_config._item.condition * @param {Array} rule_config._item.action * @example { "rule_config": [{ "rule_id": 1, "enable": 1, "condition": { "type": 1, "time_condition": { "mode": 0, "week_mask": 0, "day_mask": 0, "hour": 0, "minute": 0 } }, "action": [{ "type": 1, "message_action": { "message": "Hello, world!" } }, { "type": 1, "message_action": { "message": "Hello, world!" } }, { "type": 1, "message_action": { "message": "Hello, world!" } }] } }] } */ function setRuleConfig(rule_config) { var enable = rule_config.enable; var rule_id = rule_config.rule_id; var condition = rule_config.condition; var action = rule_config.action; var enable_map = { 0: "disable", 1: "enable" }; var enable_values = getValues(enable_map); if (enable_values.indexOf(enable) === -1) { throw new Error("rule_config._item.enable must be one of " + enable_values.join(", ")); } if (rule_id < 1 || rule_id > 16) { throw new Error("rule_config._item.rule_id must be in range [1, 16]"); } var chn_data = 0x00; chn_data |= getValue(enable_map, enable) << 7; chn_data |= rule_id; var encoded = []; if ("condition" in rule_config) { var data = writeCondition(condition); var buffer = new Buffer(3 + data.length); buffer.writeUInt8(0xf9); buffer.writeUInt8(0x7d); buffer.writeUInt8(chn_data); buffer.writeBytes(data); encoded = encoded.concat(buffer.toBytes()); } if ("action" in rule_config) { for (var i = 0; i < action.length; i++) { var data = writeAction(action[i]); var buffer = new Buffer(3 + data.length); buffer.writeUInt8(0xf9); buffer.writeUInt8(0x7d); buffer.writeUInt8(chn_data); buffer.writeBytes(data); encoded = encoded.concat(buffer.toBytes()); } } return encoded; } /** * encode condition * @param {object} condition * @param {number} condition.type values: (0: none, 1: time, 2: value, 3: modbus_cmd, 4: message, 5: d2d, 6: reboot) * @param {object} condition.time_condition * @param {object} condition.modbus_value_condition * @param {object} condition.modbus_cmd_condition * @param {object} condition.message_condition * @param {object} condition.d2d_condition * @param {object} condition.reboot_condition * @example { "condition": { "type": 1, "time_condition": { } } } */ function writeCondition(condition) { var condition_type = condition.type; var condition_map = { 0: "none", 1: "time", 2: "modbus_value", 3: "modbus_cmd", 4: "message", 5: "d2d", 6: "reboot" }; var condition_values = getValues(condition_map); if (condition_values.indexOf(condition_type) === -1) { throw new Error("condition.type must be one of " + condition_values.join(", ")); } var params_data = []; var condition_value = getValue(condition_map, condition_type); switch (condition_value) { case 0x00: // NONE CONDITION break; case 0x01: // TIME CONDITION params_data = writeTimeCondition(condition.time_condition); break; case 0x02: // MODBUS VALUE CONDITION params_data = writeModbusValueCondition(condition.modbus_value_condition); break; case 0x03: // MODBUS CMD CONDITION params_data = writeModbusCmdCondition(condition.modbus_cmd_condition); break; case 0x04: // MESSAGE CONDITION params_data = writeMessageCondition(condition.message_condition); break; case 0x05: // D2D CONDITION params_data = writeD2DCondition(condition.d2d_condition); break; case 0x06: // REBOOT CONDITION break; } var condition_data = 0x00; condition_data |= 0 << 7; // condition type condition_data |= 1 << 4; // condition id condition_data |= getValue(condition_map, condition_type); var buffer = new Buffer(1 + params_data.length); buffer.writeUInt8(condition_data); if (params_data.length > 0) { buffer.writeBytes(params_data); } return buffer.toBytes(); } /** * write time condition * @param {object} time_condition * @param {number} time_condition.mode values: (0: weekdays, 1: days) * @param {Array} time_condition.weekdays range: [1, 7] * @param {Array} time_condition.days range: [1, 31] * @param {number} time_condition.hour range: [0, 23] * @param {number} time_condition.minute range: [0, 59] * @example { "time_condition": { "mode": 0, "weekdays": [1, 2, 3, 4, 5], "days": [1, 2, 3, 4, 5], "hour": 8, "minute": 30 } } */ function writeTimeCondition(time_condition) { var mode = time_condition.mode; var weekdays = time_condition.weekdays; var days = time_condition.days; var hour = time_condition.hour; var minute = time_condition.minute; // validate values var cycle_mode_map = { 0: "weekdays", 1: "days" }; var cycle_mode_values = getValues(cycle_mode_map); if (cycle_mode_values.indexOf(mode) === -1) { throw new Error("rule_config._item.condition.time_condition.mode must be one of " + cycle_mode_values.join(", ")); } if ("weekdays" in time_condition) { for (var i = 0; i < weekdays.length; i++) { if (weekdays[i] < 1 || weekdays[i] > 7) { throw new Error("rule_config._item.condition.time_condition.weekdays must be in range [1, 7]"); } } } if ("days" in time_condition) { for (var i = 0; i < days.length; i++) { if (days[i] < 1 || days[i] > 31) { throw new Error("rule_config._item.condition.time_condition.days must be in range [1, 31]"); } } } if (hour < 0 || hour > 23) { throw new Error("rule_config._item.condition.time_condition.hour must be in range [0, 23]"); } if (minute < 0 || minute > 59) { throw new Error("rule_config._item.condition.time_condition.minute must be in range [0, 59]"); } // encode var mask = 0x00; if ("weekdays" in time_condition) { for (var i = 0; i < weekdays.length; i++) { mask |= 1 << (weekdays[i] - 1); } } else if ("days" in time_condition) { for (var i = 0; i < days.length; i++) { mask |= 1 << (days[i] - 1); } } var buffer = new Buffer(7); buffer.writeUInt8(getValue(cycle_mode_map, mode)); buffer.writeUInt32LE(mask); buffer.writeUInt8(hour); buffer.writeUInt8(minute); return buffer.toBytes(); } /** * write modbus value condition * @param {object} modbus_value_condition * @param {number} modbus_value_condition.channel_id * @param {number} modbus_value_condition.condition values: (0: false, 1: true, 2: below, 3: above, 4: between, 5: outside, 6: change_with_time, 7: change_without_time) * @param {number} modbus_value_condition.holding_mode values: (0: below, 1: above) * @param {number} modbus_value_condition.min * @param {number} modbus_value_condition.max * @param {number} modbus_value_condition.mutation * @param {number} modbus_value_condition.mutation_duration * @param {number} modbus_value_condition.continue_time * @param {number} modbus_value_condition.lock_time * @example { "modbus_value_condition": { "condition": 1, "min": 1, "max": 2, "mutation": 0 } } */ function writeModbusValueCondition(modbus_value_condition) { var channel_id = modbus_value_condition.channel_id; var condition = modbus_value_condition.condition; var holding_mode = modbus_value_condition.holding_mode; var threshold_min = modbus_value_condition.threshold_min || 0; var threshold_max = modbus_value_condition.threshold_max || 0; var mutation = modbus_value_condition.mutation || 0; var mutation_duration = modbus_value_condition.mutation_duration || 0; var continue_time = modbus_value_condition.continue_time || 0; var lock_time = modbus_value_condition.lock_time || 0; // validate values var condition_map = { 0: "false", 1: "true", 2: "below", 3: "above", 4: "between", 5: "outside", 6: "change_with_time", 7: "change_without_time" }; var condition_values = getValues(condition_map); if (condition_values.indexOf(condition) === -1) { throw new Error("rule_config._item.condition.modbus_value_condition.condition must be one of " + condition_values.join(", ")); } var condition_value = getValue(condition_map, condition); if (condition_value < 5) { var holding_mode_map = { 0: "below", 1: "above" }; var holding_mode_values = getValues(holding_mode_map); if (holding_mode_values.indexOf(holding_mode) === -1) { throw new Error("rule_config._item.condition.modbus_value_condition.holding_mode must be one of " + holding_mode_values.join(", ")); } } // value below condition (min, continue_time, lock_time) if (condition_value === 2 && !("min" in modbus_value_condition) && !("continue_time" in modbus_value_condition) && !("lock_time" in modbus_value_condition)) { throw new Error("rule_config._item.condition.modbus_value_condition.min and rule_config._item.condition.modbus_value_condition.continue_time are required"); } // value above condition (max, continue_time, lock_time) if (condition_value === 3 && !("max" in modbus_value_condition) && !("continue_time" in modbus_value_condition) && !("lock_time" in modbus_value_condition)) { throw new Error("rule_config._item.condition.modbus_value_condition.max and rule_config._item.condition.modbus_value_condition.continue_time are required"); } // value between condition (min, max, continue_time, lock_time) if (condition_value === 4 && !("min" in modbus_value_condition) && !("max" in modbus_value_condition) && !("continue_time" in modbus_value_condition) && !("lock_time" in modbus_value_condition)) { throw new Error("rule_config._item.condition.modbus_value_condition.min and rule_config._item.condition.modbus_value_condition.max are required"); } // value outside condition (min, max, continue_time, lock_time) if (condition_value === 5 && !("min" in modbus_value_condition) && !("max" in modbus_value_condition) && !("continue_time" in modbus_value_condition) && !("lock_time" in modbus_value_condition)) { throw new Error("rule_config._item.condition.modbus_value_condition.min and rule_config._item.condition.modbus_value_condition.max are required"); } // change with time condition (mutation, mutation_duration) if (condition_value === 6 && !("mutation" in modbus_value_condition) && !("mutation_duration" in modbus_value_condition)) { throw new Error("rule_config._item.condition.modbus_value_condition.mutation and rule_config._item.condition.modbus_value_condition.mutation_duration are required"); } // change without time condition if (condition_value === 7 && !("mutation" in modbus_value_condition)) { throw new Error("rule_config._item.condition.modbus_value_condition.mutation is required"); } var holding_mode_value = 0x00; if (condition_value < 5) { holding_mode_value = getValue(holding_mode_map, holding_mode); } // encode var condition_data = 0x00; condition_data |= getValue(condition_map, condition); condition_data |= holding_mode_value << 4; var value_1 = 0x00; var value_2 = 0x00; // condition(below, between) if (condition_value === 2 || condition_value === 4) { value_1 = threshold_min; } else if (condition_value === 3 || condition_value === 4) { value_2 = threshold_max; } else if (condition_value === 6 || condition_value === 7) { value_1 = mutation_duration; value_2 = mutation; } var buffer = new Buffer(18); buffer.writeUInt8(channel_id); buffer.writeUInt8(condition_data); buffer.writeUInt32LE(continue_time); buffer.writeUInt32LE(lock_time); buffer.writeFloatLE(value_1); buffer.writeFloatLE(value_2); return buffer.toBytes(); } /** * write modbus cmd condition * @param {object} modbus_cmd_condition * @param {string} modbus_cmd_condition.cmd * @example { "modbus_cmd_condition": { "cmd": "1234567890" } } */ function writeModbusCmdCondition(modbus_cmd_condition) { var cmd = modbus_cmd_condition.cmd; // validate values if (typeof cmd !== "string") { throw new Error("modbus_cmd_condition.cmd must be a string"); } if (cmd.length > 48) { throw new Error("modbus_cmd_condition.cmd must be less than 48 characters"); } if (!/^[0-9a-fA-F]+$/.test(cmd)) { throw new Error("modbus_cmd_condition.cmd must be hex string [0-9a-fA-F]"); } // encode var buffer = new Buffer(1 + cmd.length); buffer.writeUInt8(cmd.length); buffer.writeASCII(cmd); return buffer.toBytes(); } /** * write message condition * @param {object} message_condition * @param {string} message_condition.message * @example { "message_condition": { "message": "1234567890" } } */ function writeMessageCondition(message_condition) { var message = message_condition.message; // validate values if (typeof message !== "string") { throw new Error("message_condition.message must be a string"); } if (message.length > 48) { throw new Error("message_condition.message must be less than 48 characters"); } if (!/^[0-9a-zA-Z,.;:!? ]+$/.test(message)) { throw new Error("message_condition.message must be hex string [0-9a-zA-Z,.;:!? ]"); } // encode var buffer = new Buffer(1 + message.length); buffer.writeUInt8(message.length); buffer.writeASCII(message); return buffer.toBytes(); } /** * write d2d condition * @param {object} d2d_condition * @param {string} d2d_condition.d2d_cmd * @param {number} d2d_condition.d2d_status values: (0: any, 1: on, 2: off) * @example { "d2d_condition": { "d2d_cmd": "1234", "d2d_status": 0 } } */ function writeD2DCondition(d2d_condition) { var d2d_cmd = d2d_condition.d2d_cmd; var d2d_status = d2d_condition.d2d_status; // validate values var d2d_status_map = { 0: "any", 1: "on", 2: "off" }; var d2d_status_values = getValues(d2d_status_map); if (d2d_status_values.indexOf(d2d_status) === -1) { throw new Error("rule_config._item.condition.d2d_condition.d2d_status must be one of " + d2d_status_values.join(", ")); } // encode var buffer = new Buffer(3); buffer.writeD2DCommand(d2d_cmd, "0000"); buffer.writeUInt8(getValue(d2d_status_map, d2d_status)); return buffer.toBytes(); } /** * write action * @param {object} action * @param {number} action.index range: [1, 3] * @param {number} action.type values: (0: none, 1: message, 2: d2d, 3: modbus_cmd, 4: report_status, 5: report_alarm, 6: reboot) * @param {number} action.delay_time * @param {object} action.message_action * @param {object} action.d2d_action * @param {object} action.modbus_cmd_action * @param {object} action.report_status_action * @param {object} action.report_alarm_action * @param {object} action.reboot_action * @param {number} action.delay_time * @example { "action": { "type": 1, "delay_time": 1000, "message_action": { "message": "1234567890" } } } */ function writeAction(action) { var index = action.index; var type = action.type; var delay_time = action.delay_time; var action_map = { 0: "none", 1: "message", 2: "d2d", 3: "modbus_cmd", 4: "report_status", 5: "report_alarm", 6: "reboot" }; var action_values = getValues(action_map); if (action_values.indexOf(type) === -1) { throw new Error("rule_config._item.action.type must be one of " + action_values.join(", ")); } var action_type_value = getValue(action_map, type); var params_data = []; switch (action_type_value) { case 0x00: break; case 0x01: // MESSAGE ACTION params_data = writeMessageAction(action.message_action); break; case 0x02: // D2D ACTION params_data = writeD2DAction(action.d2d_action); break; case 0x03: // MODBUS CMD ACTION params_data = writeModbusAction(action.modbus_cmd_action); break; case 0x04: // REPORT STATUS ACTION break; case 0x05: // REPORT ALARM ACTION params_data = writeReportAlarmAction(action.report_alarm_action); break; case 0x06: // REBOOT ACTION break; default: throw new Error("rule_config._item.action.type must be one of " + action_values.join(", ")); } var action_data = 0x00; action_data |= 1 << 7; // action type action_data |= index << 4; // action id action_data |= action_type_value; var buffer = new Buffer(5 + params_data.length); buffer.writeUInt8(action_data); buffer.writeUInt32LE(delay_time); if (params_data.length > 0) { buffer.writeBytes(params_data); } return buffer.toBytes(); } /** * write message action * @param {object} message_action * @param {string} message_action.message range: [1, 48] * @example { "message_action": { "message": "1234567890" } } */ function writeMessageAction(message_action) { var message = message_action.message; // validate values if (typeof message !== "string") { throw new Error("message_action.message must be a string"); } if (message.length < 1 || message.length > 48) { throw new Error("message_action.message must be in range [1, 48]"); } if (!/^[0-9a-zA-Z,.;:!? ]+$/.test(message)) { throw new Error("message_action.message must be hex string [0-9a-zA-Z,.;:!? ]"); } // encode var buffer = new Buffer(1 + message.length); buffer.writeUInt8(message.length); buffer.writeASCII(message); return buffer.toBytes(); } /** * write d2d action * @param {object} d2d_action * @param {string} d2d_action.d2d_cmd * @example { "d2d_action": { "d2d_cmd": "1234567890" } } */ function writeD2DAction(d2d_action) { var d2d_cmd = d2d_action.d2d_cmd || ""; // validate values if (typeof d2d_cmd !== "string") { throw new Error("d2d_action.d2d_cmd must be a string"); } if (d2d_cmd.length > 48) { throw new Error("d2d_action.d2d_cmd must be less than 48 characters"); } if (!/^[0-9a-fA-F]+$/.test(d2d_cmd)) { throw new Error("d2d_action.d2d_cmd must be hex string [0-9a-fA-F]"); } // encode var buffer = new Buffer(2); buffer.writeD2DCommand(d2d_cmd, "0000"); return buffer.toBytes(); } /** * write modbus action * @param {object} modbus_cmd_action * @param {string} modbus_cmd_action.cmd * @example { "modbus_cmd_action": { "cmd": 1 } } */ function writeModbusAction(modbus_cmd_action) { var cmd = modbus_cmd_action.cmd; // validate values if (typeof cmd !== "string") { throw new Error("modbus_cmd_action.cmd must be a string"); } if (cmd.length > 48) { throw new Error("modbus_cmd_action.cmd must be less than 48 characters"); } if (!/^[0-9a-fA-F]+$/.test(cmd)) { throw new Error("modbus_cmd_action.cmd must be hex string [0-9a-fA-F]"); } // encode var buffer = new Buffer(1 + cmd.length); buffer.writeUInt8(cmd.length); buffer.writeASCII(cmd); return buffer.toBytes(); } /** * write report alarm action * @param {object} report_alarm_action * @param {number} report_alarm_action.release_enable values: (0: disable, 1: enable) * @example { "report_alarm_action": { "release_enable": 1 } } */ function writeReportAlarmAction(report_alarm_action) { var release_enable = report_alarm_action.release_enable; // validate values var enable_map = { 0: "disable", 1: "enable" }; var enable_values = getValues(enable_map); if (enable_values.indexOf(release_enable) === -1) { throw new Error("rule_config._item.action.report_alarm_action.release_enable must be one of " + enable_values.join(", ")); } // encode var buffer = new Buffer(1); buffer.writeUInt8(getValue(enable_map, release_enable)); return buffer.toBytes(); } function Buffer(size) { this.buffer = new Array(size); this.offset = 0; for (var i = 0; i < size; i++) { this.buffer[i] = 0; } } Buffer.prototype._write = function (value, byteLength, isLittleEndian) { for (var index = 0; index < byteLength; index++) { var shift = isLittleEndian ? index << 3 : (byteLength - 1 - index) << 3; this.buffer[this.offset + index] = (value & (0xff << shift)) >> shift; } }; Buffer.prototype.writeUInt8 = function (value) { this._write(value, 1, true); this.offset += 1; }; Buffer.prototype.writeInt8 = function (value) { this._write(value < 0 ? value + 0x100 : value, 1, true); this.offset += 1; }; Buffer.prototype.writeUInt16LE = function (value) { this._write(value, 2, true); this.offset += 2; }; Buffer.prototype.writeInt16LE = function (value) { this._write(value < 0 ? value + 0x10000 : value, 2, true); this.offset += 2; }; Buffer.prototype.writeUInt32LE = function (value) { this._write(value, 4, true); this.offset += 4; }; Buffer.prototype.writeInt32LE = function (value) { this._write(value < 0 ? value + 0x100000000 : value, 4, true); this.offset += 4; }; Buffer.prototype.writeFloatLE = function (value) { var sign = value < 0 ? 1 : 0; var absValue = Math.abs(value); if (absValue === 0) { this._write(0, 4, true); } else if (Number.isNaN(absValue)) { this._write(0x7fc00000, 4, true); } else if (absValue === Infinity) { this._write(0x7f800000, 4, true); } else { var exponent = Math.floor(Math.log(absValue) / Math.LN2); var mantissa = absValue / Math.pow(2, exponent) - 1; var biasedExponent = exponent + 127; // Bias var exponentBits = biasedExponent << 23; var mantissaBits = Math.round(mantissa * Math.pow(2, 23)); var floatBits = (sign << 31) | exponentBits | mantissaBits; this._write(floatBits, 4, true); } this.offset += 4; }; Buffer.prototype.writeASCII = function (value) { for (var i = 0; i < value.length; i++) { this.buffer[this.offset + i] = value.charCodeAt(i); } this.offset += value.length; }; Buffer.prototype.writeD2DCommand = function (value, defaultValue) { if (typeof value !== "string") { value = defaultValue; } if (value.length !== 4) { throw new Error("d2d_cmd length must be 4"); } this.buffer[this.offset] = parseInt(value.substr(2, 2), 16); this.buffer[this.offset + 1] = parseInt(value.substr(0, 2), 16); this.offset += 2; }; Buffer.prototype.writeBytes = function (bytes) { for (var i = 0; i < bytes.length; i++) { this.buffer[this.offset + i] = bytes[i]; } this.offset += bytes.length; }; Buffer.prototype.toBytes = function () { return this.buffer; }; function getValues(map) { var values = []; for (var key in map) { values.push(RAW_VALUE ? parseInt(key) : map[key]); } return values; } function getValue(map, value) { if (RAW_VALUE) return value; for (var key in map) { if (map[key] === value) { return parseInt(key); } } throw new Error("not match in " + JSON.stringify(map)); }
This codec is sourced from Milesight-IoT. All rights belong to Milesight-IoT.
This codec is licensed under the GNU General Public License v3 (GPL v3). Modifications, if any, are clearly marked. You are free to use, modify, and distribute the codec under the terms of GPL v3.