Description

Milesight UG6X/UG56 gateway support build-in Node-red. This Node-Red example provides a solution for triggering SMS alarms using Node-Red. and takes an example of triggering an SMS alarm when the EM300 temperature exceeds 26°C.

 

 

Requirement

  • Milesight Gateway(with cellular module): UG56/UG65/UG67
  • LoRaWAN Sensor
  • SIM cards and Mobile Phone

 

Configuration

Step 1: Check Cellular Status

Insert the SIM in the gateway . Go to Network>Interface>Cellular, set the required parameters and fill in regional SMS center number of the SIM card inserted in the gateway (note: this is not the SIM card’s phone number). You can search online for the SMS center number of your current SIM card or contact your carrier to obtain it.


Keep cellular in the connected status.


Step 2: Connect the LoRaWAN Sensor to the Gateway

Please refer to this article about how to connect LoRaWAN nodes to milesight gateway: 

https://support.milesight-iot.com/support/solutions/articles/73000514280-how-to-connect-lorawan-nodes-to-milesight-gateway



Step 3: Launch Node-RED and Import Flow Example

1. Go to App > Node-RED page to enable Node-RED program and wait for a while to load the program, click Launch button to start Node-RED web GUI.

 

2. Log in the Node-RED web GUI. The account information is the same as gateway web GUI. 

 

 

3. Click Import to import the node-red flow example by pasting the content or import the json format file.


 

 

Step 4: Node-RED Configuration

Flow structure:


Content:

[{"id":"8208c83dd9c34e3a","type":"tab","label":"流程 1","disabled":false,"info":"","env":[]},{"id":"58aad37bb390d15b","type":"LoRa Input","z":"8208c83dd9c34e3a","name":"","devEUI":"","extendedField":"","x":80,"y":280,"wires":[["af99ce753bad9c95"]]},{"id":"af99ce753bad9c95","type":"Device Filter","z":"8208c83dd9c34e3a","name":"WT101","eui":"24E124714E287260","x":240,"y":280,"wires":[["59284890e5bab55e"]]},{"id":"1a4677d654fcebcf","type":"switch","z":"8208c83dd9c34e3a","name":"","property":"payload.temperature","propertyType":"msg","rules":[{"t":"gt","v":"25","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":630,"y":280,"wires":[["f761faf035fc7a79","6d682cc6c187654f"]]},{"id":"6d682cc6c187654f","type":"SMS Output","z":"8208c83dd9c34e3a","name":"China Mobile","phone":"+8615985913245","message":"The temperature exceeds the threshold. The value is {{payload.temperature}}","x":830,"y":320,"wires":[]},{"id":"f761faf035fc7a79","type":"debug","z":"8208c83dd9c34e3a","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":820,"y":180,"wires":[]},{"id":"59284890e5bab55e","type":"function","z":"8208c83dd9c34e3a","name":"WT101 decoder","func":"/**\n * Payload Decoder\n *\n * Copyright 2025 Milesight IoT\n *\n * @product WT101\n */\nvar RAW_VALUE = 0x00;\n\n/* eslint no-redeclare: \"off\" */\n/* eslint-disable */\n// Chirpstack v4\nfunction decodeUplink(input) {\n    var decoded = milesightDeviceDecode(input.bytes);\n    return { data: decoded };\n}\n\n// Chirpstack v3\nfunction Decode(fPort, bytes) {\n    return milesightDeviceDecode(bytes);\n}\n\n// The Things Network\nfunction Decoder(bytes, port) {\n    return milesightDeviceDecode(bytes);\n}\n/* eslint-enable */\n\nfunction milesightDeviceDecode(bytes) {\n    var decoded = {};\n\n    for (var i = 0; i < bytes.length;) {\n        var channel_id = bytes[i++];\n        var channel_type = bytes[i++];\n\n        // IPSO VERSION\n        if (channel_id === 0xff && channel_type === 0x01) {\n            decoded.ipso_version = readProtocolVersion(bytes[i]);\n            i += 1;\n        }\n        // HARDWARE VERSION\n        else if (channel_id === 0xff && channel_type === 0x09) {\n            decoded.hardware_version = readHardwareVersion(bytes.slice(i, i + 2));\n            i += 2;\n        }\n        // FIRMWARE VERSION\n        else if (channel_id === 0xff && channel_type === 0x0a) {\n            decoded.firmware_version = readFirmwareVersion(bytes.slice(i, i + 2));\n            i += 2;\n        }\n        // TSL VERSION\n        else if (channel_id === 0xff && channel_type === 0xff) {\n            decoded.tsl_version = readTslVersion(bytes.slice(i, i + 2));\n            i += 2;\n        }\n        // SERIAL NUMBER\n        else if (channel_id === 0xff && channel_type === 0x16) {\n            decoded.sn = readSerialNumber(bytes.slice(i, i + 8));\n            i += 8;\n        }\n        // LORAWAN CLASS TYPE\n        else if (channel_id === 0xff && channel_type === 0x0f) {\n            decoded.lorawan_class = readLoRaWANClass(bytes[i]);\n            i += 1;\n        }\n        // RESET EVENT\n        else if (channel_id === 0xff && channel_type === 0xfe) {\n            decoded.reset_event = readResetEvent(1);\n            i += 1;\n        }\n        // DEVICE STATUS\n        else if (channel_id === 0xff && channel_type === 0x0b) {\n            decoded.device_status = readDeviceStatus(1);\n            i += 1;\n        }\n        // BATTERY\n        else if (channel_id === 0x01 && channel_type === 0x75) {\n            decoded.battery = readUInt8(bytes[i]);\n            i += 1;\n        }\n        // TEMPERATURE\n        else if (channel_id === 0x03 && channel_type === 0x67) {\n            decoded.temperature = readInt16LE(bytes.slice(i, i + 2)) / 10;\n            i += 2;\n        }\n        // TARGET TEMPERATURE\n        else if (channel_id === 0x04 && channel_type === 0x67) {\n            decoded.target_temperature = readInt16LE(bytes.slice(i, i + 2)) / 10;\n            i += 2;\n        }\n        // VALVE OPENING\n        else if (channel_id === 0x05 && channel_type === 0x92) {\n            decoded.valve_opening = readUInt8(bytes[i]);\n            i += 1;\n        }\n        // TAMPER STATUS\n        else if (channel_id === 0x06 && channel_type === 0x00) {\n            decoded.tamper_status = readTamperStatus(bytes[i]);\n            i += 1;\n        }\n        // WINDOW DETECTION\n        else if (channel_id === 0x07 && channel_type === 0x00) {\n            decoded.window_detection = readWindowDetectionStatus(bytes[i]);\n            i += 1;\n        }\n        // MOTOR STROKE CALIBRATION RESULT\n        else if (channel_id === 0x08 && channel_type === 0xe5) {\n            decoded.motor_calibration_result = readMotorCalibrationResult(bytes[i]);\n            i += 1;\n        }\n        // MOTOR STROKE\n        else if (channel_id === 0x09 && channel_type === 0x90) {\n            decoded.motor_stroke = readUInt16LE(bytes.slice(i, i + 2));\n            i += 2;\n        }\n        // FREEZE PROTECTION\n        else if (channel_id === 0x0a && channel_type === 0x00) {\n            decoded.freeze_protection = readFreezeProtectionStatus(bytes[i]);\n            i += 1;\n        }\n        // MOTOR CURRENT POSITION\n        else if (channel_id === 0x0b && channel_type === 0x90) {\n            decoded.motor_position = readUInt16LE(bytes.slice(i, i + 2));\n            i += 2;\n        }\n        // HEATING DATE\n        else if (channel_id === 0xf9 && channel_type === 0x33) {\n            decoded.heating_date = readHeatingDate(bytes.slice(i, i + 7));\n            i += 7;\n        }\n        // HEATING SCHEDULE\n        else if (channel_id === 0xf9 && channel_type === 0x34) {\n            var heating_schedule = readHeatingSchedule(bytes.slice(i, i + 9));\n            decoded.heating_schedule = decoded.heating_schedule || [];\n            decoded.heating_schedule.push(heating_schedule);\n            i += 9;\n        }\n        // DOWNLINK RESPONSE\n        else if (channel_id === 0xfe || channel_id === 0xff) {\n            var result = handle_downlink_response(channel_type, bytes, i);\n            decoded = Object.assign(decoded, result.data);\n            i = result.offset;\n        }\n        // DOWNLINK RESPONSE\n        else if (channel_id === 0xf8 || channel_id === 0xf9) {\n            var result = handle_downlink_response_ext(channel_id, channel_type, bytes, i);\n            decoded = Object.assign(decoded, result.data);\n            i = result.offset;\n        } else {\n            break;\n        }\n    }\n\n    return decoded;\n}\n\nfunction handle_downlink_response(channel_type, bytes, offset) {\n    var decoded = {};\n\n    switch (channel_type) {\n        case 0x10:\n            decoded.reboot = readYesNoStatus(1);\n            offset += 1;\n            break;\n        case 0x17:\n            decoded.time_zone = readTimeZoneV1(readInt16LE(bytes.slice(offset, offset + 2)));\n            offset += 2;\n            break;\n        case 0x25:\n            decoded.child_lock_config = decoded.child_lock_config || {};\n            decoded.child_lock_config.enable = readEnableStatus(bytes[offset]);\n            offset += 1;\n            break;\n        case 0x28:\n            decoded.report_status = readYesNoStatus(1);\n            offset += 1;\n            break;\n        case 0x3b:\n            decoded.time_sync_enable = readTimeSyncEnable(bytes[offset]);\n            offset += 1;\n            break;\n        case 0x4a:\n            decoded.sync_time = readYesNoStatus(1);\n            offset += 1;\n            break;\n        case 0x57:\n            decoded.restore_open_window_detection = readYesNoStatus(1);\n            offset += 1;\n            break;\n        case 0x8e:\n            // ignore the first byte\n            decoded.report_interval = readUInt16LE(bytes.slice(offset + 1, offset + 3));\n            offset += 3;\n            break;\n        case 0xae:\n            decoded.temperature_control = decoded.temperature_control || {};\n            decoded.temperature_control.mode = readTemperatureControlMode(bytes[offset]);\n            offset += 1;\n            break;\n        case 0xab:\n            decoded.temperature_calibration_settings = {};\n            decoded.temperature_calibration_settings.enable = readEnableStatus(bytes[offset]);\n            decoded.temperature_calibration_settings.calibration_value = readInt16LE(bytes.slice(offset + 1, offset + 3)) / 10;\n            offset += 3;\n            break;\n        case 0xac:\n            decoded.valve_control_algorithm = readValveControlAlgorithm(bytes[offset]);\n            offset += 1;\n            break;\n        case 0xad:\n            decoded.valve_calibration = readYesNoStatus(1);\n            offset += 1;\n            break;\n        case 0xaf:\n            decoded.open_window_detection = decoded.open_window_detection || {};\n            decoded.open_window_detection.enable = readEnableStatus(bytes[offset]);\n            decoded.open_window_detection.temperature_threshold = readInt8(bytes[offset + 1]) / 10;\n            decoded.open_window_detection.time = readUInt16LE(bytes.slice(offset + 2, offset + 4));\n            offset += 4;\n            break;\n        case 0xb0:\n            decoded.freeze_protection_config = decoded.freeze_protection_config || {};\n            decoded.freeze_protection_config.enable = readEnableStatus(bytes[offset]);\n            decoded.freeze_protection_config.temperature = readInt16LE(bytes.slice(offset + 1, offset + 3)) / 10;\n            offset += 3;\n            break;\n        case 0xb1:\n            decoded.target_temperature = readInt8(bytes[offset]);\n            decoded.temperature_tolerance = readUInt16LE(bytes.slice(offset + 1, offset + 3)) / 10;\n            offset += 3;\n            break;\n        case 0xb3:\n            decoded.temperature_control = decoded.temperature_control || {};\n            decoded.temperature_control.enable = readEnableStatus(bytes[offset]);\n            offset += 1;\n            break;\n        case 0xb4:\n            decoded.valve_opening = readUInt8(bytes[offset]);\n            offset += 1;\n            break;\n        case 0xba:\n            decoded.dst_config = {};\n            decoded.dst_config.enable = readEnableStatus(bytes[offset]);\n            decoded.dst_config.offset = readInt8(bytes[offset + 1]);\n            decoded.dst_config.start_month = bytes[offset + 2];\n            decoded.dst_config.start_week_num = readUInt8(bytes[offset + 3]) >> 4;\n            decoded.dst_config.start_week_day = bytes[offset + 3] & 0x0f;\n            decoded.dst_config.start_time = readUInt16LE(bytes.slice(offset + 4, offset + 6));\n            decoded.dst_config.end_month = bytes[offset + 6];\n            decoded.dst_config.end_week_num = readUInt8(bytes[offset + 7]) >> 4;\n            decoded.dst_config.end_week_day = bytes[offset + 7] & 0x0f;\n            decoded.dst_config.end_time = readUInt16LE(bytes.slice(offset + 8, offset + 10));\n            offset += 10;\n            break;\n        case 0xbd:\n            decoded.time_zone = readTimeZone(readInt16LE(bytes.slice(offset, offset + 2)));\n            offset += 2;\n            break;\n        case 0xc4:\n            decoded.outside_temperature_control = {};\n            decoded.outside_temperature_control.enable = readEnableStatus(bytes[offset]);\n            decoded.outside_temperature_control.timeout = readUInt8(bytes[offset + 1]);\n            offset += 2;\n            break;\n        case 0xf8:\n            decoded.offline_control_mode = readOfflineControlMode(bytes[offset]);\n            offset += 1;\n            break;\n        default:\n            throw new Error(\"unknown downlink response\");\n    }\n\n    return { data: decoded, offset: offset };\n}\n\nfunction handle_downlink_response_ext(code, channel_type, bytes, offset) {\n    var decoded = {};\n\n    switch (channel_type) {\n        case 0x33:\n            decoded.heating_date = readHeatingDate(bytes.slice(offset, offset + 7));\n            offset += 7;\n            break;\n        case 0x34:\n            var heating_schedule = readHeatingSchedule(bytes.slice(offset, offset + 9));\n            decoded.heating_schedule = decoded.heating_schedule || [];\n            decoded.heating_schedule.push(heating_schedule);\n            offset += 9;\n            break;\n        case 0x35:\n            decoded.target_temperature_range = {};\n            decoded.target_temperature_range.min = readInt8(bytes[offset]);\n            decoded.target_temperature_range.max = readInt8(bytes[offset + 1]);\n            offset += 2;\n            break;\n        case 0x36:\n            decoded.display_ambient_temperature = readEnableStatus(bytes[offset]);\n            offset += 1;\n            break;\n        case 0x37:\n            decoded.window_detection_valve_strategy = readWindowDetectionValveStrategy(bytes[offset]);\n            offset += 1;\n            break;\n        case 0x38:\n            decoded.effective_stroke = {};\n            decoded.effective_stroke.enable = readEnableStatus(bytes[offset]);\n            decoded.effective_stroke.rate = readUInt8(bytes[offset + 1]);\n            offset += 2;\n            break;\n        case 0x3a:\n            decoded.change_report_enable = readEnableStatus(bytes[offset]);\n            offset += 1;\n            break;\n        default:\n            throw new Error(\"unknown downlink response\");\n    }\n\n    if (hasResultFlag(code)) {\n        var result_value = readUInt8(bytes[offset]);\n        offset += 1;\n\n        if (result_value !== 0) {\n            var request = decoded;\n            decoded = {};\n            decoded.device_response_result = {};\n            decoded.device_response_result.channel_type = channel_type;\n            decoded.device_response_result.result = readResultStatus(result_value);\n            decoded.device_response_result.request = request;\n        }\n    }\n\n    return { data: decoded, offset: offset };\n}\n\nfunction hasResultFlag(code) {\n    return code === 0xf8;\n}\n\nfunction readResultStatus(status) {\n    var status_map = { 0: \"success\", 1: \"forbidden\", 2: \"invalid parameter\" };\n    return getValue(status_map, status);\n}\n\nfunction readProtocolVersion(bytes) {\n    var major = (bytes & 0xf0) >> 4;\n    var minor = bytes & 0x0f;\n    return \"v\" + major + \".\" + minor;\n}\n\nfunction readHardwareVersion(bytes) {\n    var major = (bytes[0] & 0xff).toString(16);\n    var minor = (bytes[1] & 0xff) >> 4;\n    return \"v\" + major + \".\" + minor;\n}\n\nfunction readFirmwareVersion(bytes) {\n    var major = (bytes[0] & 0xff).toString(16);\n    var minor = (bytes[1] & 0xff).toString(16);\n    return \"v\" + major + \".\" + minor;\n}\n\nfunction readTslVersion(bytes) {\n    var major = bytes[0] & 0xff;\n    var minor = bytes[1] & 0xff;\n    return \"v\" + major + \".\" + minor;\n}\n\nfunction readSerialNumber(bytes) {\n    var temp = [];\n    for (var idx = 0; idx < bytes.length; idx++) {\n        temp.push((\"0\" + (bytes[idx] & 0xff).toString(16)).slice(-2));\n    }\n    return temp.join(\"\");\n}\n\nfunction readLoRaWANClass(type) {\n    var class_map = {\n        0: \"Class A\",\n        1: \"Class B\",\n        2: \"Class C\",\n        3: \"Class CtoB\",\n    };\n    return getValue(class_map, type);\n}\n\nfunction readResetEvent(status) {\n    var status_map = { 0: \"normal\", 1: \"reset\" };\n    return getValue(status_map, status);\n}\n\nfunction readDeviceStatus(status) {\n    var status_map = { 0: \"off\", 1: \"on\" };\n    return getValue(status_map, status);\n}\n\nfunction readTamperStatus(type) {\n    var tamper_status_map = { 0: \"installed\", 1: \"uninstalled\" };\n    return getValue(tamper_status_map, type);\n}\n\nfunction readWindowDetectionStatus(type) {\n    var window_detection_status_map = { 0: \"normal\", 1: \"open\" };\n    return getValue(window_detection_status_map, type);\n}\n\nfunction readMotorCalibrationResult(type) {\n    var motor_calibration_result_map = {\n        0: \"success\",\n        1: \"fail: out of range\",\n        2: \"fail: uninstalled\",\n        3: \"calibration cleared\",\n        4: \"temperature control disabled\",\n    };\n    return getValue(motor_calibration_result_map, type);\n}\n\nfunction readFreezeProtectionStatus(type) {\n    var freeze_protection_status_map = {\n        0: \"normal\",\n        1: \"triggered\",\n    };\n    return getValue(freeze_protection_status_map, type);\n}\n\nfunction readHeatingDate(bytes) {\n    var heating_date = {};\n    var offset = 0;\n    heating_date.enable = readEnableStatus(bytes[offset]);\n    heating_date.report_interval = readUInt16LE(bytes.slice(offset + 1, offset + 3));\n    heating_date.start_month = bytes[offset + 3];\n    heating_date.start_day = readUInt8(bytes[offset + 4]);\n    heating_date.end_month = bytes[offset + 5];\n    heating_date.end_day = readUInt8(bytes[offset + 6]);\n    return heating_date;\n}\n\nfunction readHeatingSchedule(bytes) {\n    var heating_schedule = {};\n    var offset = 0;\n    heating_schedule.index = readUInt8(bytes[offset]) + 1;\n    heating_schedule.enable = readEnableStatus(bytes[offset + 1]);\n    heating_schedule.temperature_control_mode = readTemperatureControlMode(bytes[offset + 2]);\n    heating_schedule.value = readUInt8(bytes[offset + 3]);\n    heating_schedule.report_interval = readUInt16LE(bytes.slice(offset + 4, offset + 6));\n    heating_schedule.execute_time = readUInt16LE(bytes.slice(offset + 6, offset + 8));\n    var day = readUInt8(bytes[offset + 8]);\n    heating_schedule.week_recycle = {};\n    var week_day_offset = { monday: 1, tuesday: 2, wednesday: 3, thursday: 4, friday: 5, saturday: 6, sunday: 7 };\n    for (var key in week_day_offset) {\n        heating_schedule.week_recycle[key] = readEnableStatus((day >>> week_day_offset[key]) & 0x01);\n    }\n\n    return heating_schedule;\n}\n\nfunction readYesNoStatus(type) {\n    var yes_no_map = { 0: \"no\", 1: \"yes\" };\n    return getValue(yes_no_map, type);\n}\n\nfunction readEnableStatus(type) {\n    var status_map = { 0: \"disable\", 1: \"enable\" };\n    return getValue(status_map, type);\n}\n\nfunction readTemperatureControlMode(type) {\n    var temperature_control_mode_map = { 0: \"auto\", 1: \"manual\" };\n    return getValue(temperature_control_mode_map, type);\n}\n\nfunction readTimeZoneV1(time_zone) {\n    var timezone_map = { \"-120\": \"UTC-12\", \"-110\": \"UTC-11\", \"-100\": \"UTC-10\", \"-95\": \"UTC-9:30\", \"-90\": \"UTC-9\", \"-80\": \"UTC-8\", \"-70\": \"UTC-7\", \"-60\": \"UTC-6\", \"-50\": \"UTC-5\", \"-40\": \"UTC-4\", \"-35\": \"UTC-3:30\", \"-30\": \"UTC-3\", \"-20\": \"UTC-2\", \"-10\": \"UTC-1\", 0: \"UTC\", 10: \"UTC+1\", 20: \"UTC+2\", 30: \"UTC+3\", 35: \"UTC+3:30\", 40: \"UTC+4\", 45: \"UTC+4:30\", 50: \"UTC+5\", 55: \"UTC+5:30\", 57: \"UTC+5:45\", 60: \"UTC+6\", 65: \"UTC+6:30\", 70: \"UTC+7\", 80: \"UTC+8\", 90: \"UTC+9\", 95: \"UTC+9:30\", 100: \"UTC+10\", 105: \"UTC+10:30\", 110: \"UTC+11\", 120: \"UTC+12\", 127: \"UTC+12:45\", 130: \"UTC+13\", 140: \"UTC+14\" };\n    return getValue(timezone_map, time_zone);\n}\n\nfunction readTimeZone(time_zone) {\n    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\" };\n    return getValue(timezone_map, time_zone);\n}\n\nfunction readTimeSyncEnable(type) {\n    var enable_map = { 0: \"disable\", 2: \"enable\" };\n    return getValue(enable_map, type);\n}\n\nfunction readValveControlAlgorithm(type) {\n    var valve_control_algorithm_map = { 0: \"rate\", 1: \"pid\" };\n    return getValue(valve_control_algorithm_map, type);\n}\n\nfunction readOfflineControlMode(type) {\n    var offline_control_mode_map = { 0: \"keep\", 1: \"embedded temperature control\", 2: \"off\" };\n    return getValue(offline_control_mode_map, type);\n}\n\nfunction readWindowDetectionValveStrategy(type) {\n    var window_detection_valve_strategy_map = { 0: \"keep\", 1: \"close\" };\n    return getValue(window_detection_valve_strategy_map, type);\n}\n\nfunction readUInt8(bytes) {\n    return bytes & 0xff;\n}\n\nfunction readInt8(bytes) {\n    var ref = readUInt8(bytes);\n    return ref > 0x7f ? ref - 0x100 : ref;\n}\n\nfunction readUInt16LE(bytes) {\n    var value = (bytes[1] << 8) + bytes[0];\n    return value & 0xffff;\n}\n\nfunction readInt16LE(bytes) {\n    var ref = readUInt16LE(bytes);\n    return ref > 0x7fff ? ref - 0x10000 : ref;\n}\n\nfunction getValue(map, key) {\n    if (RAW_VALUE) return key;\n\n    var value = map[key];\n    if (!value) value = \"unknown\";\n    return value;\n}\n\nif (!Object.assign) {\n    Object.defineProperty(Object, \"assign\", {\n        enumerable: false,\n        configurable: true,\n        writable: true,\n        value: function (target) {\n            \"use strict\";\n            if (target == null) {\n                throw new TypeError(\"Cannot convert first argument to object\");\n            }\n\n            var to = Object(target);\n            for (var i = 1; i < arguments.length; i++) {\n                var nextSource = arguments[i];\n                if (nextSource == null) {\n                    continue;\n                }\n                nextSource = Object(nextSource);\n\n                var keysArray = Object.keys(Object(nextSource));\n                for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {\n                    var nextKey = keysArray[nextIndex];\n                    var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);\n                    if (desc !== undefined && desc.enumerable) {\n                        // concat array\n                        if (Array.isArray(to[nextKey]) && Array.isArray(nextSource[nextKey])) {\n                            to[nextKey] = to[nextKey].concat(nextSource[nextKey]);\n                        } else {\n                            to[nextKey] = nextSource[nextKey];\n                        }\n                    }\n                }\n            }\n            return to;\n        },\n    });\n}\n\nvar buffer = Buffer.from(msg.payload, 'base64');\nvar aa = Decoder(buffer);\nmsg.payload = aa;\nmsg.buffer = buffer;\nreturn msg;","outputs":1,"noerr":49,"initialize":"","finalize":"","libs":[],"x":440,"y":280,"wires":[["1a4677d654fcebcf"]]}]

(1) LoRa Input: To get all uplink message from Sensor in network server.

(2) Device Filter: Filter device by Device EUI. Here we configure it to filter WT101 by their device EUI.


(3) Fuction node: Please convert the hex data reported by WT101 into readable JSON data according to the document below.

https://support.milesight-iot.com/support/solutions/articles/73000535734-how-to-use-decoder-on-node-red

https://github.com/Milesight-IoT/SensorDecoders/blob/main/wt-series/wt101/wt101-decoder.js

 


(4) Switch: Use to set up judgement condition(If…). 

More Milesight sensor parameter information in decoder code, get from https://github.com/Milesight-IoT/SensorDecoders 

The example setting is triggered when the temperature is higher than 25℃.


(5) Debug: Display selected message properties in the debug sidebar tab and optionally the runtime log. Here, we use it to see sensor uplink package content, keep Output as payload by default.


(6) SMS Output: This is the output setting for the text message.  You need to add the phone number that should receive alarm messages in "Phone Number", and the actual output value should be enclosed in {{}}.



Step 5: Deploy and Check Result

1. Click Deploy to save all node-red configurations.


2. Check SMS, gateway will send an SMS alarm when the specified threshold is exceeded.

 


Check SMS, gateway will send an SMS alarm when the specified threshold is exceeded.




-------END-----