{"id":61,"date":"2026-08-24T22:22:14","date_gmt":"2026-08-24T18:52:14","guid":{"rendered":"https:\/\/abedi-energy.ir\/?page_id=61"},"modified":"2026-10-30T00:39:40","modified_gmt":"2026-10-29T21:09:40","slug":"%d9%be%d8%a7%db%8c%d8%b4-%d8%a7%d9%86%d8%b1%da%98%db%8c","status":"publish","type":"page","link":"https:\/\/abedi-energy.ir\/","title":{"rendered":"\u067e\u0627\u06cc\u0634 \u0627\u0646\u0631\u0698\u06cc"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"61\" class=\"elementor elementor-61\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-6e6391e elementor-section-boxed elementor-section-height-default elementor-section-height-default wd-section-disabled\" data-id=\"6e6391e\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-1e0de05\" data-id=\"1e0de05\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-3889a94 elementor-widget elementor-widget-shortcode\" data-id=\"3889a94\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">    <style>\n        .ws-pro-panel {\n            font-family: 'IRANYekan', 'IRANSans', 'Vazirmatn', Tahoma, sans-serif;\n            max-width: 850px;\n            margin: 25px auto;\n            background: #ffffff;\n            border-radius: 16px;\n            box-shadow: 0 14px 35px rgba(0, 0, 0, 0.08);\n            border: 1px solid #e2e8f0;\n            overflow: hidden;\n            direction: rtl;\n            text-align: right;\n        }\n        .ws-pro-head {\n            background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);\n            color: #ffffff;\n            padding: 18px 24px;\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            flex-wrap: wrap;\n            gap: 12px;\n        }\n        .ws-pro-title {\n            font-size: 15px;\n            font-weight: bold;\n            color: #ffffff !important;\n            margin: 0 !important;\n            display: flex;\n            align-items: center;\n            gap: 8px;\n        }\n        .ws-live-dot {\n            width: 10px;\n            height: 10px;\n            background: #64748b;\n            border-radius: 50%;\n            display: inline-block;\n        }\n        .ws-live-dot.connected {\n            background: #10b981;\n            box-shadow: 0 0 10px #10b981;\n            animation: wsPulse 1.5s infinite;\n        }\n        @keyframes wsPulse {\n            0% { transform: scale(0.95); opacity: 0.8; }\n            50% { transform: scale(1.2); opacity: 1; }\n            100% { transform: scale(0.95); opacity: 0.8; }\n        }\n        .ws-pro-btn {\n            background: #10b981;\n            color: #ffffff;\n            border: none;\n            padding: 10px 20px;\n            border-radius: 8px;\n            font-family: inherit;\n            font-size: 13px;\n            font-weight: bold;\n            cursor: pointer;\n            transition: all 0.2s ease;\n        }\n        .ws-pro-btn:hover { background: #059669; }\n        .ws-pro-btn.disconnect { background: #ef4444; }\n        .ws-pro-body { padding: 24px; }\n\n        \/* \u06a9\u0627\u0631\u062a\u200c\u0647\u0627\u06cc \u0646\u0645\u0627\u06cc\u0634 \u0645\u0642\u0627\u062f\u06cc\u0631 \u0632\u0646\u062f\u0647 *\/\n        .ws-cards-row {\n            display: grid;\n            grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));\n            gap: 16px;\n            margin-bottom: 20px;\n        }\n        .ws-sensor-card {\n            background: #f8fafc;\n            border: 2px solid #e2e8f0;\n            border-radius: 14px;\n            padding: 18px;\n            text-align: center;\n            transition: all 0.2s ease;\n        }\n        .ws-sensor-card.active-turn {\n            border-color: #3b82f6;\n            background: #eff6ff;\n        }\n        .ws-sensor-title {\n            font-size: 13.5px;\n            font-weight: bold;\n            color: #475569;\n            margin-bottom: 10px;\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            gap: 6px;\n        }\n        .ws-sensor-val {\n            font-size: 32px;\n            font-weight: 800;\n            color: #0f172a;\n            direction: ltr;\n            font-family: Consolas, monospace;\n            margin-bottom: 12px;\n        }\n        .ws-reg-row {\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            gap: 6px;\n            font-size: 12px;\n            color: #64748b;\n            background: #ffffff;\n            padding: 6px 10px;\n            border-radius: 8px;\n            border: 1px solid #e2e8f0;\n        }\n        .ws-input-num {\n            width: 65px;\n            font-family: Consolas, monospace;\n            font-size: 12.5px;\n            font-weight: bold;\n            text-align: center;\n            border: 1px solid #cbd5e1;\n            border-radius: 5px;\n            padding: 3px;\n            direction: ltr;\n            color: #0f172a;\n        }\n        .ws-check {\n            cursor: pointer;\n            width: 15px;\n            height: 15px;\n            accent-color: #10b981;\n        }\n\n        \/* \u0646\u0648\u0627\u0631 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u0627\u0631\u062a\u0628\u0627\u0637\u06cc *\/\n        .ws-config-bar {\n            background: #f1f5f9;\n            padding: 12px 16px;\n            border-radius: 10px;\n            margin-bottom: 18px;\n            display: flex;\n            align-items: center;\n            justify-content: space-between;\n            flex-wrap: wrap;\n            gap: 12px;\n            font-size: 12.5px;\n            color: #334155;\n        }\n        .ws-select-box {\n            font-family: Consolas, Tahoma, monospace;\n            padding: 5px 10px;\n            border-radius: 6px;\n            border: 1px solid #cbd5e1;\n            background: #ffffff;\n            color: #0f172a;\n            direction: ltr;\n            font-size: 12px;\n        }\n\n        \/* \u0644\u0627\u06af \u0641\u0646\u06cc \u067e\u0627\u06cc\u06cc\u0646 \u067e\u0646\u0644 *\/\n        .ws-log-grid {\n            display: grid;\n            grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n            gap: 12px;\n        }\n        .ws-log-box {\n            background: #f8fafc;\n            border: 1px solid #e2e8f0;\n            padding: 10px 14px;\n            border-radius: 8px;\n        }\n        .ws-log-lbl { font-size: 11.5px; color: #64748b; display: block; margin-bottom: 4px; }\n        .ws-log-code {\n            font-family: Consolas, monospace;\n            font-size: 13px;\n            font-weight: bold;\n            color: #1e293b;\n            direction: ltr;\n            text-align: left;\n            display: block;\n            word-break: break-all;\n        }\n    <\/style>\n\n    <div class=\"ws-pro-panel\">\n        <div class=\"ws-pro-head\">\n            <div class=\"ws-pro-title\">\n                <span id=\"ws-dot\" class=\"ws-live-dot\"><\/span>\n                <span>\u062e\u0648\u0627\u0646\u0634 \u0645\u0633\u062a\u0642\u06cc\u0645 \u0645\u0631\u0648\u0631\u06af\u0631 \u0627\u0632 \u0633\u062e\u062a\u200c\u0627\u0641\u0632\u0627\u0631 (Web Serial API)<\/span>\n            <\/div>\n            <button id=\"ws-btn-connect\" class=\"ws-pro-btn\" onclick=\"wsToggleConnection()\">\ud83d\udd0c \u0627\u0646\u062a\u062e\u0627\u0628 \u067e\u0648\u0631\u062a COM \u0648 \u0634\u0631\u0648\u0639 \u062e\u0648\u0627\u0646\u0634<\/button>\n        <\/div>\n\n        <div class=\"ws-pro-body\">\n            <!-- \u06a9\u0627\u0631\u062a\u200c\u0647\u0627\u06cc \u0648\u0644\u062a\u0627\u0698\u060c \u062c\u0631\u06cc\u0627\u0646 \u0648 \u0641\u0631\u06a9\u0627\u0646\u0633 -->\n            <div class=\"ws-cards-row\">\n                <!-- \u06f1. \u0648\u0644\u062a\u0627\u0698 -->\n                <div id=\"box-volt\" class=\"ws-sensor-card\">\n                    <div class=\"ws-sensor-title\">\n                        <input type=\"checkbox\" id=\"en-volt\" class=\"ws-check\" checked title=\"\u0641\u0639\u0627\u0644\/\u063a\u06cc\u0631\u0641\u0639\u0627\u0644 \u06a9\u0631\u062f\u0646 \u062e\u0648\u0627\u0646\u0634 \u0648\u0644\u062a\u0627\u0698\">\n                        <span>\u26a1 \u0648\u0644\u062a\u0627\u0698 (Voltage)<\/span>\n                    <\/div>\n                    <div class=\"ws-sensor-val\">\n                        <span id=\"out-volt\">---<\/span> <span style=\"font-size:17px;color:#10b981;\">V<\/span>\n                    <\/div>\n                    <div class=\"ws-reg-row\">\n                        <span>\u0631\u062c\u06cc\u0633\u062a\u0631 (Dec):<\/span>\n                        <input type=\"number\" id=\"reg-volt\" class=\"ws-input-num\" value=\"3028\">\n                    <\/div>\n                <\/div>\n\n                <!-- \u06f2. \u062c\u0631\u06cc\u0627\u0646 -->\n                <div id=\"box-curr\" class=\"ws-sensor-card\">\n                    <div class=\"ws-sensor-title\">\n                        <input type=\"checkbox\" id=\"en-curr\" class=\"ws-check\" checked title=\"\u0641\u0639\u0627\u0644\/\u063a\u06cc\u0631\u0641\u0639\u0627\u0644 \u06a9\u0631\u062f\u0646 \u062e\u0648\u0627\u0646\u0634 \u062c\u0631\u06cc\u0627\u0646\">\n                        <span>\ud83d\udd0c \u062c\u0631\u06cc\u0627\u0646 (Current)<\/span>\n                    <\/div>\n                    <div class=\"ws-sensor-val\">\n                        <span id=\"out-curr\">---<\/span> <span style=\"font-size:17px;color:#f59e0b;\">A<\/span>\n                    <\/div>\n                    <div class=\"ws-reg-row\">\n                        <span>\u0631\u062c\u06cc\u0633\u062a\u0631 (Dec):<\/span>\n                        <input type=\"number\" id=\"reg-curr\" class=\"ws-input-num\" value=\"2998\">\n                    <\/div>\n                <\/div>\n\n                <!-- \u06f3. \u0641\u0631\u06a9\u0627\u0646\u0633 -->\n                <div id=\"box-freq\" class=\"ws-sensor-card\">\n                    <div class=\"ws-sensor-title\">\n                        <input type=\"checkbox\" id=\"en-freq\" class=\"ws-check\" checked title=\"\u0641\u0639\u0627\u0644\/\u063a\u06cc\u0631\u0641\u0639\u0627\u0644 \u06a9\u0631\u062f\u0646 \u062e\u0648\u0627\u0646\u0634 \u0641\u0631\u06a9\u0627\u0646\u0633\">\n                        <span>\u3030\ufe0f \u0641\u0631\u06a9\u0627\u0646\u0633 (Frequency)<\/span>\n                    <\/div>\n                    <div class=\"ws-sensor-val\">\n                        <span id=\"out-freq\">---<\/span> <span style=\"font-size:17px;color:#6366f1;\">Hz<\/span>\n                    <\/div>\n                    <div class=\"ws-reg-row\">\n                        <span>\u0631\u062c\u06cc\u0633\u062a\u0631 (Dec):<\/span>\n                        <input type=\"number\" id=\"reg-freq\" class=\"ws-input-num\" value=\"3109\">\n                    <\/div>\n                <\/div>\n            <\/div>\n\n            <!-- \u0646\u0648\u0627\u0631 \u062a\u0646\u0638\u06cc\u0645\u0627\u062a \u067e\u0648\u0631\u062a \u0648 \u0641\u0631\u0645\u062a -->\n            <div class=\"ws-config-bar\">\n                <div style=\"display:flex; align-items:center; gap:8px;\">\n                    <span>\ud83c\udd94 Slave ID:<\/span>\n                    <input type=\"number\" id=\"ws-slave\" class=\"ws-input-num\" value=\"1\" style=\"width:48px;\">\n                <\/div>\n                <div style=\"display:flex; align-items:center; gap:8px;\">\n                    <span>\ud83d\ude80 Baud Rate:<\/span>\n                    <select id=\"ws-baud\" class=\"ws-select-box\">\n                        <option value=\"9600\" selected>9600<\/option>\n                        <option value=\"19200\">19200<\/option>\n                        <option value=\"38400\">38400<\/option>\n                        <option value=\"115200\">115200<\/option>\n                    <\/select>\n                <\/div>\n                <div style=\"display:flex; align-items:center; gap:8px;\">\n                    <span>\u2699\ufe0f \u0641\u0631\u0645\u062a Float:<\/span>\n                    <select id=\"ws-endian\" class=\"ws-select-box\">\n                        <option value=\"ABCD\" selected>Big Endian (ABCD - \u0627\u0633\u062a\u0627\u0646\u062f\u0627\u0631\u062f)<\/option>\n                        <option value=\"CDAB\">Word Swapped (CDAB)<\/option>\n                        <option value=\"BADC\">Byte Swapped (BADC)<\/option>\n                        <option value=\"DCBA\">Little Endian (DCBA)<\/option>\n                    <\/select>\n                <\/div>\n            <\/div>\n\n            <!-- \u0645\u0627\u0646\u06cc\u062a\u0648\u0631\u06cc\u0646\u06af \u0628\u0633\u062a\u0647 \u0647\u0627\u06cc \u0627\u0631\u0633\u0627\u0644\u06cc \u0648 \u062f\u0631\u06cc\u0627\u0641\u062a\u06cc -->\n            <div class=\"ws-log-grid\">\n                <div class=\"ws-log-box\">\n                    <span class=\"ws-log-lbl\">\ud83d\udd0c \u0648\u0636\u0639\u06cc\u062a \u0627\u062a\u0635\u0627\u0644 \u0645\u0631\u0648\u0631\u06af\u0631:<\/span>\n                    <span id=\"ws-stat-txt\" class=\"ws-log-code\" style=\"color:#d97706;\">\u0622\u0645\u0627\u062f\u0647 \u0627\u062a\u0635\u0627\u0644 \u0628\u0647 \u067e\u0648\u0631\u062a USB<\/span>\n                <\/div>\n                <div class=\"ws-log-box\">\n                    <span class=\"ws-log-lbl\">\ud83d\udce5 \u0648\u0636\u0639\u06cc\u062a \u0641\u0631\u06cc\u0645 \u0648 CRC:<\/span>\n                    <span id=\"ws-crc-txt\" class=\"ws-log-code\">---<\/span>\n                <\/div>\n                <div class=\"ws-log-box\">\n                    <span class=\"ws-log-lbl\">\ud83d\udce4 \u062f\u0633\u062a\u0648\u0631 \u0627\u0631\u0633\u0627\u0644\u06cc (TX Hex):<\/span>\n                    <span id=\"ws-tx-txt\" class=\"ws-log-code\" style=\"color:#0284c7;\">---<\/span>\n                <\/div>\n                <div class=\"ws-log-box\">\n                    <span class=\"ws-log-lbl\">\ud83d\udce5 \u067e\u0627\u0633\u062e \u062f\u0631\u06cc\u0627\u0641\u062a\u06cc (RX Hex):<\/span>\n                    <span id=\"ws-rx-txt\" class=\"ws-log-code\" style=\"color:#7c3aed;\">---<\/span>\n                <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <script>\n    let serialPort = null;\n    let serialReader = null;\n    let isPolling = false;\n    let incomingBytes = [];\n\n    \/\/ \u06f1. \u0633\u0627\u062e\u062a \u0641\u0631\u06cc\u0645 \u0627\u0633\u062a\u0627\u0646\u062f\u0627\u0631\u062f Modbus RTU \u0628\u0647 \u0647\u0645\u0631\u0627\u0647 \u0645\u062d\u0627\u0633\u0628\u0647 \u062f\u0642\u06cc\u0642 CRC16\n    function createModbusRTUFrame(slave, func, regAddr, regCount) {\n        const frame = new Uint8Array(8);\n        frame[0] = slave & 0xFF;\n        frame[1] = func & 0xFF;\n        frame[2] = (regAddr >> 8) & 0xFF;\n        frame[3] = regAddr & 0xFF;\n        frame[4] = (regCount >> 8) & 0xFF;\n        frame[5] = regCount & 0xFF;\n\n        let crc = 0xFFFF;\n        for (let pos = 0; pos < 6; pos++) {\n            crc ^= frame[pos];\n            for (let i = 0; i < 8; i++) {\n                if ((crc & 0x0001) !== 0) {\n                    crc = (crc >> 1) ^ 0xA001;\n                } else {\n                    crc >>= 1;\n                }\n            }\n        }\n        frame[6] = crc & 0xFF;        \/\/ CRC Low Byte\n        frame[7] = (crc >> 8) & 0xFF; \/\/ CRC High Byte\n        return frame;\n    }\n\n    \/\/ \u06f2. \u0627\u0639\u062a\u0628\u0627\u0631\u0633\u0646\u062c\u06cc CRC16 \u0628\u0631\u0627\u06cc \u06f9 \u0628\u0627\u06cc\u062a \u062f\u0631\u06cc\u0627\u0641\u062a\u06cc \u0627\u0632 \u062f\u0633\u062a\u06af\u0627\u0647\n    function verifyCRC16(response) {\n        if (response.length !== 9) return false;\n        let crc = 0xFFFF;\n        for (let pos = 0; pos < 7; pos++) {\n            crc ^= response[pos];\n            for (let i = 0; i < 8; i++) {\n                if ((crc & 0x0001) !== 0) {\n                    crc = (crc >> 1) ^ 0xA001;\n                } else {\n                    crc >>= 1;\n                }\n            }\n        }\n        return (response[7] === (crc & 0xFF) && response[8] === ((crc >> 8) & 0xFF));\n    }\n\n    \/\/ \u06f3. \u062a\u0628\u062f\u06cc\u0644 \u06f4 \u0628\u0627\u06cc\u062a \u0647\u06af\u0632 \u0628\u0647 \u0639\u062f\u062f \u0627\u0639\u0634\u0627\u0631\u06cc IEEE 754 Float\n    function bytesToFloat32(b0, b1, b2, b3, format) {\n        const buffer = new ArrayBuffer(4);\n        const view = new DataView(buffer);\n        if (format === \"ABCD\") {\n            view.setUint8(0, b0); view.setUint8(1, b1); view.setUint8(2, b2); view.setUint8(3, b3);\n        } else if (format === \"CDAB\") {\n            view.setUint8(0, b2); view.setUint8(1, b3); view.setUint8(2, b0); view.setUint8(3, b1);\n        } else if (format === \"BADC\") {\n            view.setUint8(0, b1); view.setUint8(1, b0); view.setUint8(2, b3); view.setUint8(3, b2);\n        } else if (format === \"DCBA\") {\n            view.setUint8(0, b3); view.setUint8(1, b2); view.setUint8(2, b1); view.setUint8(3, b0);\n        }\n        return view.getFloat32(0, false); \/\/ Big-Endian \u062f\u0631 \u0633\u0637\u062d DataView\n    }\n\n    \/\/ \u06f4. \u062d\u0644\u0642\u0647 \u062f\u0627\u0626\u0645\u06cc \u0634\u0646\u0648\u062f \u067e\u0648\u0631\u062a \u0633\u0631\u06cc\u0627\u0644 \u062f\u0631 \u067e\u0633\u200c\u0632\u0645\u06cc\u0646\u0647 \u0645\u0631\u0648\u0631\u06af\u0631\n    async function startBackgroundReader() {\n        try {\n            serialReader = serialPort.readable.getReader();\n            while (isPolling) {\n                const { value, done } = await serialReader.read();\n                if (done) break;\n                if (value && value.length > 0) {\n                    incomingBytes.push(...value);\n                }\n            }\n        } catch (err) {\n            console.error(\"Reader Error:\", err);\n        } finally {\n            if (serialReader) {\n                try { serialReader.releaseLock(); } catch (e) {}\n                serialReader = null;\n            }\n        }\n    }\n\n    \/\/ \u06f5. \u0645\u062f\u06cc\u0631\u06cc\u062a \u0627\u062a\u0635\u0627\u0644 \u0648 \u0642\u0637\u0639 \u0627\u062a\u0635\u0627\u0644 Web Serial API\n    async function wsToggleConnection() {\n        const btn = document.getElementById(\"ws-btn-connect\");\n        const statTxt = document.getElementById(\"ws-stat-txt\");\n        const dot = document.getElementById(\"ws-dot\");\n\n        if (!(\"serial\" in navigator)) {\n            alert(\"\u0645\u0631\u0648\u0631\u06af\u0631 \u0634\u0645\u0627 \u0627\u0632 \u0642\u0627\u0628\u0644\u06cc\u062a Web Serial API \u067e\u0634\u062a\u06cc\u0628\u0627\u0646\u06cc \u0646\u0645\u06cc\u200c\u06a9\u0646\u062f. \u0644\u0637\u0641\u0627\u064b \u0635\u0641\u062d\u0647 \u0631\u0627 \u0628\u0627 Google Chrome \u06cc\u0627 Microsoft Edge \u062f\u0631 \u06a9\u0627\u0645\u067e\u06cc\u0648\u062a\u0631 \u0628\u0627\u0632 \u06a9\u0646\u06cc\u062f.\");\n            return;\n        }\n\n        \/\/ \u062f\u0631 \u0635\u0648\u0631\u062a \u0645\u062a\u0635\u0644 \u0628\u0648\u062f\u0646 -> \u0642\u0637\u0639 \u0627\u062a\u0635\u0627\u0644\n        if (serialPort) {\n            isPolling = false;\n            if (serialReader) {\n                try { await serialReader.cancel(); } catch (e) {}\n            }\n            setTimeout(async () => {\n                try { await serialPort.close(); } catch (e) {}\n                serialPort = null;\n                btn.innerText = \"\ud83d\udd0c \u0627\u0646\u062a\u062e\u0627\u0628 \u067e\u0648\u0631\u062a COM \u0648 \u0634\u0631\u0648\u0639 \u062e\u0648\u0627\u0646\u0634\";\n                btn.classList.remove(\"disconnect\");\n                dot.classList.remove(\"connected\");\n                statTxt.innerText = \"\ud83d\udd12 \u0627\u062a\u0635\u0627\u0644 \u0628\u0633\u062a\u0647 \u0634\u062f.\";\n                statTxt.style.color = \"#64748b\";\n            }, 200);\n            return;\n        }\n\n        \/\/ \u0634\u0631\u0648\u0639 \u0627\u062a\u0635\u0627\u0644 \u062c\u062f\u06cc\u062f \u0628\u0647 \u067e\u0648\u0631\u062a COM\n        try {\n            const baud = parseInt(document.getElementById(\"ws-baud\").value) || 9600;\n            serialPort = await navigator.serial.requestPort();\n            await serialPort.open({\n                baudRate: baud,\n                dataBits: 8,\n                stopBits: 1,\n                parity: \"none\",\n                bufferSize: 1024\n            });\n\n            btn.innerText = \"\u274c \u0642\u0637\u0639 \u0627\u062a\u0635\u0627\u0644 \u0627\u0632 \u067e\u0648\u0631\u062a\";\n            btn.classList.add(\"disconnect\");\n            dot.classList.add(\"connected\");\n            statTxt.innerText = \"\u2705 \u0645\u062a\u0635\u0644 \u0628\u0647 \u067e\u0648\u0631\u062a (\" + baud + \" 8N1)\";\n            statTxt.style.color = \"#059669\";\n\n            isPolling = true;\n            startBackgroundReader(); \/\/ \u0641\u0639\u0627\u0644\u200c\u0633\u0627\u0632\u06cc \u0634\u0646\u0648\u062f \u062f\u0627\u0626\u0645\u06cc\n            runModbusPollingLoop();  \/\/ \u0634\u0631\u0648\u0639 \u0627\u0631\u0633\u0627\u0644 \u0646\u0648\u0628\u062a\u06cc \u062f\u0633\u062a\u0648\u0631\u0627\u062a\n        } catch (err) {\n            statTxt.innerText = \"\u274c \u062e\u0637\u0627: \u067e\u0648\u0631\u062a \u0627\u0646\u062a\u062e\u0627\u0628 \u0646\u0634\u062f \u06cc\u0627 \u062f\u0631 \u0628\u0631\u0646\u0627\u0645\u0647 \u062f\u06cc\u06af\u0631\u06cc \u0628\u0627\u0632 \u0627\u0633\u062a!\";\n            statTxt.style.color = \"#ef4444\";\n            serialPort = null;\n        }\n    }\n\n    \/\/ \u06f6. \u0627\u0631\u0633\u0627\u0644 \u062f\u0633\u062a\u0648\u0631 \u0648 \u0627\u0633\u062a\u062e\u0631\u0627\u062c \u0641\u0631\u06cc\u0645 \u06f9 \u0628\u0627\u06cc\u062a\u06cc \u0645\u0639\u062a\u0628\u0631\n    async function queryModbusParameter(slaveId, regAddress) {\n        incomingBytes = []; \/\/ \u067e\u0627\u06a9\u0633\u0627\u0632\u06cc \u0628\u0627\u0641\u0631 \u0642\u0628\u0644 \u0627\u0632 \u0627\u0631\u0633\u0627\u0644 \u062f\u0631\u062e\u0648\u0627\u0633\u062a \u062c\u062f\u06cc\u062f\n        const txPacket = createModbusRTUFrame(slaveId, 3, regAddress, 2);\n\n        const txHex = Array.from(txPacket).map(b => b.toString(16).padStart(2, \"0\").toUpperCase()).join(\"\");\n        document.getElementById(\"ws-tx-txt\").innerText = txHex;\n\n        \/\/ \u0627\u0631\u0633\u0627\u0644 \u0631\u0648\u06cc \u067e\u0648\u0631\u062a USB\n        const writer = serialPort.writable.getWriter();\n        await writer.write(txPacket);\n        writer.releaseLock();\n\n        \/\/ \u0627\u0646\u062a\u0638\u0627\u0631 \u0647\u0648\u0634\u0645\u0646\u062f \u062a\u0627 \u06f5\u06f0\u06f0 \u0645\u06cc\u0644\u06cc\u200c\u062b\u0627\u0646\u06cc\u0647 \u0628\u0631\u0627\u06cc \u062f\u0631\u06cc\u0627\u0641\u062a \u06a9\u0627\u0645\u0644 \u06f9 \u0628\u0627\u06cc\u062a \u067e\u0627\u0633\u062e\n        const startWait = Date.now();\n        while (Date.now() - startWait < 500) {\n            await new Promise(r => setTimeout(r, 40));\n\n            if (incomingBytes.length >= 9) {\n                \/\/ \u062c\u0633\u062a\u062c\u0648\u06cc \u0647\u062f\u0631 \u067e\u0627\u0633\u062e \u0627\u0633\u062a\u0627\u0646\u062f\u0627\u0631\u062f: [SlaveID, 0x03, 0x04]\n                for (let i = 0; i <= incomingBytes.length - 9; i++) {\n                    if (incomingBytes[i] === slaveId && incomingBytes[i+1] === 0x03 && incomingBytes[i+2] === 0x04) {\n                        const candidate = incomingBytes.slice(i, i + 9);\n                        if (verifyCRC16(candidate)) {\n                            return { valid: true, frame: candidate };\n                        }\n                    }\n                }\n            }\n        }\n        return { valid: false, frame: incomingBytes.slice() };\n    }\n\n    \/\/ \u06f7. \u062d\u0644\u0642\u0647 \u0627\u0635\u0644\u06cc \u0686\u0631\u062e\u0634 \u0628\u06cc\u0646 \u0648\u0644\u062a\u0627\u0698\u060c \u062c\u0631\u06cc\u0627\u0646 \u0648 \u0641\u0631\u06a9\u0627\u0646\u0633\n    async function runModbusPollingLoop() {\n        const sensors = [\n            { enableId: \"en-volt\", regId: \"reg-volt\", outId: \"out-volt\", boxId: \"box-volt\", decimals: 4 },\n            { enableId: \"en-curr\", regId: \"reg-curr\", outId: \"out-curr\", boxId: \"box-curr\", decimals: 3 },\n            { enableId: \"en-freq\", regId: \"reg-freq\", outId: \"out-freq\", boxId: \"box-freq\", decimals: 2 }\n        ];\n\n        while (isPolling && serialPort) {\n            let anyEnabled = false;\n\n            for (const item of sensors) {\n                if (!isPolling) break;\n\n                const isEnabled = document.getElementById(item.enableId).checked;\n                if (!isEnabled) continue;\n                anyEnabled = true;\n\n                const slaveId = parseInt(document.getElementById(\"ws-slave\").value) || 1;\n                const regAddr = parseInt(document.getElementById(item.regId).value) || 0;\n                const endian  = document.getElementById(\"ws-endian\").value;\n                const boxEl   = document.getElementById(item.boxId);\n\n                boxEl.classList.add(\"active-turn\");\n\n                try {\n                    const result = await queryModbusParameter(slaveId, regAddr);\n\n                    if (result.valid) {\n                        const rxHex = result.frame.map(b => b.toString(16).padStart(2, \"0\").toUpperCase()).join(\"\");\n                        document.getElementById(\"ws-rx-txt\").innerText = rxHex;\n                        document.getElementById(\"ws-crc-txt\").innerText = \"9 Bytes (CRC16 OK \u2705)\";\n                        document.getElementById(\"ws-crc-txt\").style.color = \"#059669\";\n\n                        const floatVal = bytesToFloat32(\n                            result.frame[3],\n                            result.frame[4],\n                            result.frame[5],\n                            result.frame[6],\n                            endian\n                        );\n\n                        if (!isNaN(floatVal) && isFinite(floatVal)) {\n                            document.getElementById(item.outId).innerText = floatVal.toFixed(item.decimals);\n                        }\n                    } else if (result.frame.length > 0) {\n                        const rawHex = result.frame.map(b => b.toString(16).padStart(2, \"0\").toUpperCase()).join(\"\");\n                        document.getElementById(\"ws-rx-txt\").innerText = rawHex;\n                        document.getElementById(\"ws-crc-txt\").innerText = result.frame.length + \" Bytes (\u0628\u0633\u062a\u0647 \u0646\u0627\u0642\u0635 \u26a0\ufe0f)\";\n                        document.getElementById(\"ws-crc-txt\").style.color = \"#d97706\";\n                    } else {\n                        document.getElementById(\"ws-crc-txt\").innerText = \"\u0628\u062f\u0648\u0646 \u067e\u0627\u0633\u062e (Timeout \u23f3)\";\n                        document.getElementById(\"ws-crc-txt\").style.color = \"#ef4444\";\n                    }\n                } catch (e) {\n                    console.error(\"Polling Error:\", e);\n                }\n\n                boxEl.classList.remove(\"active-turn\");\n                \/\/ \u0645\u06a9\u062b \u06f3\u06f0\u06f0 \u0645\u06cc\u0644\u06cc\u200c\u062b\u0627\u0646\u06cc\u0647\u200c\u0627\u06cc \u0628\u06cc\u0646 \u0647\u0631 \u0633\u0646\u0633\u0648\u0631 \u0628\u0631\u0627\u06cc \u0622\u0631\u0627\u0645\u0634 \u062e\u0637 RS-485\n                await new Promise(r => setTimeout(r, 300));\n            }\n\n            if (!anyEnabled) {\n                await new Promise(r => setTimeout(r, 500));\n            }\n        }\n    }\n    <\/script>\n    <\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-15e606e elementor-section-boxed elementor-section-height-default elementor-section-height-default wd-section-disabled\" data-id=\"15e606e\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-9757847\" data-id=\"9757847\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-0ba22a5 elementor-widget__width-initial elementor-widget elementor-widget-html\" data-id=\"0ba22a5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<style>\r\n  .energy-table-wrapper {\r\n    background: #f9fafb;\r\n    padding: 20px 15px 15px 15px;\r\n    border-radius: 12px;\r\n    box-shadow: 0 2px 8px rgba(0,0,0,0.06);\r\n    border-top: 4px solid #27ae60;\r\n    direction: rtl;\r\n    margin-top: 20px;\r\n  }\r\n  .energy-table-wrapper .table-title {\r\n    text-align: center;\r\n    font-size: 18px;\r\n    font-weight: 700;\r\n    color: #1A237E;\r\n    margin-bottom: 12px;\r\n  }\r\n  .energy-table {\r\n    width: 100%;\r\n    border-collapse: collapse;\r\n    font-family: Vazir, sans-serif;\r\n    font-size: 13px; \/* \u06a9\u0648\u0686\u06cc\u06a9\u200c\u062a\u0631 *\/\r\n  }\r\n  .energy-table thead tr {\r\n    background-color: #27ae60;\r\n    color: #ffffff;\r\n  }\r\n  .energy-table th {\r\n    padding: 8px 10px;\r\n    text-align: center;\r\n    border: 1px solid #e2e8f0;\r\n    font-weight: 600;\r\n  }\r\n  .energy-table td {\r\n    padding: 6px 10px;\r\n    text-align: center;\r\n    border: 1px solid #e2e8f0;\r\n    color: #2D3748;\r\n    font-size: 13px;\r\n  }\r\n  .energy-table tbody tr:nth-child(even) {\r\n    background-color: #f0f4f0;\r\n  }\r\n  .energy-table tbody tr:hover {\r\n    background-color: #e6f0e6;\r\n    transition: 0.2s;\r\n  }\r\n  .phase-1-badge {\r\n    display: inline-block;\r\n    background: #2196F3;\r\n    color: #fff;\r\n    padding: 1px 8px;\r\n    border-radius: 20px;\r\n    font-size: 11px;\r\n  }\r\n  .phase-2-badge {\r\n    display: inline-block;\r\n    background: #2ecc71;\r\n    color: #fff;\r\n    padding: 1px 8px;\r\n    border-radius: 20px;\r\n    font-size: 11px;\r\n  }\r\n  .phase-3-badge {\r\n    display: inline-block;\r\n    background: #F44336;\r\n    color: #fff;\r\n    padding: 1px 8px;\r\n    border-radius: 20px;\r\n    font-size: 11px;\r\n  }\r\n  @media (max-width: 600px) {\r\n    .energy-table th, .energy-table td {\r\n      padding: 4px 6px;\r\n      font-size: 11px;\r\n    }\r\n    .energy-table-wrapper .table-title {\r\n      font-size: 15px;\r\n    }\r\n  }\r\n<\/style>\r\n\r\n<div class=\"energy-table-wrapper\">\r\n  <div class=\"table-title\">\ud83d\udcca \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0644\u062d\u0638\u0647\u200c\u0627\u06cc \u067e\u0627\u06cc\u0634 \u0627\u0646\u0631\u0698\u06cc \u0633\u0647\u200c\u0641\u0627\u0632<\/div>\r\n\r\n  <table class=\"energy-table\">\r\n    <thead>\r\n      <tr>\r\n        <th>\u067e\u0627\u0631\u0627\u0645\u062a\u0631<\/th>\r\n        <th>\u0641\u0627\u0632 \u06f1 <span class=\"phase-1-badge\">L1<\/span><\/th>\r\n        <th>\u0641\u0627\u0632 \u06f2 <span class=\"phase-2-badge\">L2<\/span><\/th>\r\n        <th>\u0641\u0627\u0632 \u06f3 <span class=\"phase-3-badge\">L3<\/span><\/th>\r\n      <\/tr>\r\n    <\/thead>\r\n    <tbody>\r\n      <tr>\r\n        <td><strong>\u0648\u0644\u062a\u0627\u0698 (V)<\/strong><\/td>\r\n        <td style=\"color:#2196F3; font-weight:600;\">225<\/td>\r\n        <td style=\"color:#2ecc71; font-weight:600;\">218<\/td>\r\n        <td style=\"color:#F44336; font-weight:600;\">231<\/td>\r\n      <\/tr>\r\n      <tr>\r\n        <td><strong>\u062c\u0631\u06cc\u0627\u0646 (A)<\/strong><\/td>\r\n        <td style=\"color:#2196F3; font-weight:600;\">12.5<\/td>\r\n        <td style=\"color:#2ecc71; font-weight:600;\">11.8<\/td>\r\n        <td style=\"color:#F44336; font-weight:600;\">13.2<\/td>\r\n      <\/tr>\r\n      <tr>\r\n        <td><strong>\u062a\u0648\u0627\u0646 \u0627\u06a9\u062a\u06cc\u0648 (W)<\/strong><\/td>\r\n        <td style=\"color:#2196F3; font-weight:600;\">2800<\/td>\r\n        <td style=\"color:#2ecc71; font-weight:600;\">2600<\/td>\r\n        <td style=\"color:#F44336; font-weight:600;\">2900<\/td>\r\n      <\/tr>\r\n      <tr>\r\n        <td><strong>\u062a\u0648\u0627\u0646 \u0631\u0627\u06a9\u062a\u06cc\u0648 (VAR)<\/strong><\/td>\r\n        <td style=\"color:#2196F3; font-weight:600;\">1200<\/td>\r\n        <td style=\"color:#2ecc71; font-weight:600;\">1100<\/td>\r\n        <td style=\"color:#F44336; font-weight:600;\">1300<\/td>\r\n      <\/tr>\r\n      <tr>\r\n        <td><strong>\u062a\u0648\u0627\u0646 \u0638\u0627\u0647\u0631\u06cc (VA)<\/strong><\/td>\r\n        <td style=\"color:#2196F3; font-weight:600;\">3100<\/td>\r\n        <td style=\"color:#2ecc71; font-weight:600;\">2800<\/td>\r\n        <td style=\"color:#F44336; font-weight:600;\">3200<\/td>\r\n      <\/tr>\r\n      <tr>\r\n        <td><strong>\u067e\u0627\u0648\u0631\u0641\u06a9\u062a\u0648\u0631<\/strong><\/td>\r\n        <td style=\"color:#2196F3; font-weight:600;\">0.85<\/td>\r\n        <td style=\"color:#2ecc71; font-weight:600;\">0.87<\/td>\r\n        <td style=\"color:#F44336; font-weight:600;\">0.83<\/td>\r\n      <\/tr>\r\n    <\/tbody>\r\n  <\/table>\r\n<\/div>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-373e0d8 elementor-section-boxed elementor-section-height-default elementor-section-height-default wd-section-disabled\" data-id=\"373e0d8\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-3ae35cb\" data-id=\"3ae35cb\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-2795d10 elementor-widget elementor-widget-html\" data-id=\"2795d10\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<style>\r\n  .chart-row {\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n    gap: 20px;\r\n    justify-content: center;\r\n    direction: rtl;\r\n    margin-top: 30px;\r\n  }\r\n  .chart-item {\r\n    flex: 1;\r\n    min-width: 250px;\r\n    max-width: 32%;\r\n    background: #f9fafb;\r\n    padding: 16px 12px 12px 12px;\r\n    border-radius: 12px;\r\n    box-shadow: 0 2px 8px rgba(0,0,0,0.06);\r\n    border-top: 4px solid #27ae60;\r\n  }\r\n  .chart-item h4 {\r\n    text-align: center;\r\n    font-size: 15px;\r\n    font-weight: 700;\r\n    margin: 0 0 8px 0;\r\n  }\r\n  .chart-item.l1 h4 { color: #2196F3; }\r\n  .chart-item.l2 h4 { color: #2ecc71; }\r\n  .chart-item.l3 h4 { color: #F44336; }\r\n  .chart-main-title {\r\n    text-align: center;\r\n    font-size: 20px;\r\n    font-weight: 700;\r\n    color: #1A237E;\r\n    margin: 30px 0 10px 0;\r\n  }\r\n  @media (max-width: 700px) {\r\n    .chart-item { min-width: 100%; max-width: 100%; }\r\n  }\r\n<\/style>\r\n\r\n<div class=\"chart-main-title\">\ud83d\udcc8 \u062a\u063a\u06cc\u06cc\u0631\u0627\u062a \u0648\u0644\u062a\u0627\u0698 \u0633\u0647\u200c\u0641\u0627\u0632 \u0628\u0631 \u062d\u0633\u0628 \u0632\u0645\u0627\u0646<\/div>\r\n\r\n<div class=\"chart-row\">\r\n\r\n  <div class=\"chart-item l1\">\r\n    <h4>\ud83d\udd35 \u0641\u0627\u0632 \u06f1 (L1)<\/h4>\r\n    <canvas id=\"chart1\" width=\"300\" height=\"150\"><\/canvas>\r\n  <\/div>\r\n\r\n  <div class=\"chart-item l2\">\r\n    <h4>\ud83d\udfe2 \u0641\u0627\u0632 \u06f2 (L2)<\/h4>\r\n    <canvas id=\"chart2\" width=\"300\" height=\"150\"><\/canvas>\r\n  <\/div>\r\n\r\n  <div class=\"chart-item l3\">\r\n    <h4>\ud83d\udd34 \u0641\u0627\u0632 \u06f3 (L3)<\/h4>\r\n    <canvas id=\"chart3\" width=\"300\" height=\"150\"><\/canvas>\r\n  <\/div>\r\n\r\n<\/div>\r\n\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js\"><\/script>\r\n<script>\r\nconst labels = ['10:00', '10:15', '10:30', '10:45', '11:00'];\r\n\r\n\/\/ \u0641\u0627\u0632 \u06f1\r\nnew Chart(document.getElementById('chart1'), {\r\n  type: 'line',\r\n  data: {\r\n    labels: labels,\r\n    datasets: [{\r\n      data: [225, 218, 231, 220, 228],\r\n      borderColor: '#2196F3',\r\n      backgroundColor: 'rgba(33,150,243,0.08)',\r\n      borderWidth: 3,\r\n      pointRadius: 4,\r\n      pointBackgroundColor: '#2196F3',\r\n      fill: true,\r\n      tension: 0.2\r\n    }]\r\n  },\r\n  options: {\r\n    responsive: true,\r\n    plugins: { legend: { display: false } },\r\n    scales: { y: { beginAtZero: false, min: 200, max: 245 } }\r\n  }\r\n});\r\n\r\n\/\/ \u0641\u0627\u0632 \u06f2\r\nnew Chart(document.getElementById('chart2'), {\r\n  type: 'line',\r\n  data: {\r\n    labels: labels,\r\n    datasets: [{\r\n      data: [218, 215, 222, 210, 225],\r\n      borderColor: '#2ecc71',\r\n      backgroundColor: 'rgba(46,204,113,0.08)',\r\n      borderWidth: 3,\r\n      pointRadius: 4,\r\n      pointBackgroundColor: '#2ecc71',\r\n      fill: true,\r\n      tension: 0.2\r\n    }]\r\n  },\r\n  options: {\r\n    responsive: true,\r\n    plugins: { legend: { display: false } },\r\n    scales: { y: { beginAtZero: false, min: 200, max: 245 } }\r\n  }\r\n});\r\n\r\n\/\/ \u0641\u0627\u0632 \u06f3\r\nnew Chart(document.getElementById('chart3'), {\r\n  type: 'line',\r\n  data: {\r\n    labels: labels,\r\n    datasets: [{\r\n      data: [231, 225, 235, 222, 230],\r\n      borderColor: '#F44336',\r\n      backgroundColor: 'rgba(244,67,54,0.08)',\r\n      borderWidth: 3,\r\n      pointRadius: 4,\r\n      pointBackgroundColor: '#F44336',\r\n      fill: true,\r\n      tension: 0.2\r\n    }]\r\n  },\r\n  options: {\r\n    responsive: true,\r\n    plugins: { legend: { display: false } },\r\n    scales: { y: { beginAtZero: false, min: 200, max: 245 } }\r\n  }\r\n});\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>\ud83d\udcca \u062f\u0627\u062f\u0647\u200c\u0647\u0627\u06cc \u0644\u062d\u0638\u0647\u200c\u0627\u06cc \u067e\u0627\u06cc\u0634 \u0627\u0646\u0631\u0698\u06cc \u0633\u0647\u200c\u0641\u0627\u0632 \u067e\u0627\u0631\u0627\u0645\u062a\u0631 \u0641\u0627\u0632 \u06f1 L1 \u0641\u0627\u0632 \u06f2 L2 \u0641\u0627\u0632 \u06f3 L3 \u0648\u0644\u062a\u0627\u0698 (V) 225 218<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-61","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/abedi-energy.ir\/index.php?rest_route=\/wp\/v2\/pages\/61","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/abedi-energy.ir\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/abedi-energy.ir\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/abedi-energy.ir\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/abedi-energy.ir\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=61"}],"version-history":[{"count":31,"href":"https:\/\/abedi-energy.ir\/index.php?rest_route=\/wp\/v2\/pages\/61\/revisions"}],"predecessor-version":[{"id":253,"href":"https:\/\/abedi-energy.ir\/index.php?rest_route=\/wp\/v2\/pages\/61\/revisions\/253"}],"wp:attachment":[{"href":"https:\/\/abedi-energy.ir\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=61"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}