{"id":409,"date":"2025-12-08T11:30:53","date_gmt":"2025-12-08T11:30:53","guid":{"rendered":"https:\/\/www.kitforward.co.th\/?page_id=409"},"modified":"2025-12-08T12:08:29","modified_gmt":"2025-12-08T12:08:29","slug":"dashboard","status":"publish","type":"page","link":"https:\/\/www.kitforward.co.th\/en_US\/dashboard\/","title":{"rendered":"Thailand&#8217;s Wolffia Data Portal"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"th\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Thailand&#8217;s Wolffia Data Portal<\/title>\n    <!-- Tailwind CSS CDN -->\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n    <!-- Chart.js CDN for interactive charts -->\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js@4.4.1\/dist\/chart.umd.min.js\"><\/script>\n    <!-- REQUIRED: Chart.js Plugin for displaying labels\/percentages on Donut Charts -->\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chartjs-plugin-datalabels@2.2.0\/dist\/chartjs-plugin-datalabels.min.js\"><\/script>\n    \n    <!-- Custom styles for a modern, dark theme look -->\n    <style>\n        body {\n            font-family: 'Inter', sans-serif;\n            background-color: #0d1117; \/* Dark background *\/\n        }\n        .card {\n            background-color: #161b22; \/* Slightly lighter dark card *\/\n            border-radius: 12px;\n            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);\n            padding: 1.5rem;\n        }\n        \/* Custom color function for the scatter plot *\/\n        .color-scale-legend {\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n            margin-top: 10px;\n            padding: 5px 0;\n            border-radius: 5px;\n            background: linear-gradient(to right, #9ca3af, #10b981); \/* Light Gray to Deep Green *\/\n            height: 15px;\n        }\n        .color-scale-legend span {\n            font-size: 0.75rem;\n            color: #0d1117;\n            font-weight: bold;\n            padding: 0 5px;\n        }\n\n        \/* --- Google Map Styles --- *\/\n        #geoMapContainer {\n            height: 500px; \/* Adjusted height for better map view *\/\n            width: 100%;\n            border-radius: 8px;\n            overflow: hidden;\n            background-color: #1e293b; \/* Fallback background *\/\n        }\n        \n        \/* Custom Legend Style *\/\n        .map-legend {\n            background: #1f2937;\n            padding: 10px;\n            margin-top: 10px;\n            border-radius: 6px;\n            border: 1px solid #4b5563;\n        }\n        .legend-item {\n            display: flex;\n            align-items: center;\n            margin-bottom: 5px;\n            font-size: 0.875rem;\n        }\n        .legend-color {\n            width: 15px;\n            height: 15px;\n            border-radius: 50%;\n            margin-right: 8px;\n        }\n    <\/style>\n<\/head>\n<body class=\"p-4 sm:p-8 text-gray-100\">\n\n    <header class=\"mb-8\">\n        <h1 class=\"text-4xl font-extrabold text-blue-400 mb-2\"> Thailand&#8217;s Wolffia Data Portal <\/h1>\n        <p class=\"text-gray-400\">\u0e01\u0e32\u0e23\u0e15\u0e34\u0e14\u0e15\u0e32\u0e21\u0e1c\u0e25\u0e1c\u0e25\u0e34\u0e15\u0e41\u0e25\u0e30\u0e2a\u0e20\u0e32\u0e1e\u0e41\u0e27\u0e14\u0e25\u0e49\u0e2d\u0e21\u0e1f\u0e32\u0e23\u0e4c\u0e21\u0e41\u0e1a\u0e1a\u0e40\u0e23\u0e35\u0e22\u0e25\u0e44\u0e17\u0e21\u0e4c (\u0e08\u0e33\u0e25\u0e2d\u0e07)<\/p>\n    <\/header>\n\n    <!-- 1. Geo Chart Section (Google Maps Integration) -->\n    <section id=\"map-section\" class=\"card mb-8\">\n        <h2 class=\"text-xl font-semibold mb-4 text-blue-300\">\u0e1e\u0e34\u0e01\u0e31\u0e14\u0e1f\u0e32\u0e23\u0e4c\u0e21\u0e41\u0e25\u0e30\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e32\u0e21\u0e32\u0e23\u0e16\u0e43\u0e19\u0e01\u0e32\u0e23\u0e1c\u0e25\u0e34\u0e15\u0e2a\u0e39\u0e07\u0e2a\u0e38\u0e14 (Max Capacity)<\/h2>\n        <p class=\"text-sm text-gray-500 mb-2\">\u0e41\u0e2a\u0e14\u0e07\u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e1f\u0e32\u0e23\u0e4c\u0e21\u0e1a\u0e19\u0e41\u0e1c\u0e19\u0e17\u0e35\u0e48 \u0e02\u0e19\u0e32\u0e14\u0e1f\u0e2d\u0e07\u0e2a\u0e1a\u0e39\u0e48\u0e41\u0e2a\u0e14\u0e07\u0e16\u0e36\u0e07 Max Capacity (\u0e01\u0e01.) \u0e41\u0e25\u0e30\u0e2a\u0e35\u0e41\u0e2a\u0e14\u0e07\u0e20\u0e39\u0e21\u0e34\u0e20\u0e32\u0e04<\/p>\n        <div id=\"geoMapContainer\">\n            <!-- Google Map will be initialized here -->\n        <\/div>\n\n        <!-- Map Legend -->\n        <div class=\"map-legend mt-4\">\n            <h3 class=\"text-base font-semibold mb-2 text-gray-300\">\u0e2a\u0e31\u0e0d\u0e25\u0e31\u0e01\u0e29\u0e13\u0e4c\u0e41\u0e1c\u0e19\u0e17\u0e35\u0e48<\/h3>\n            <div class=\"flex flex-wrap gap-4\">\n                <div class=\"legend-item\">\n                    <div class=\"legend-color bg-blue-500\"><\/div>\n                    Nonthaburi (\u0e19\u0e19\u0e17\u0e1a\u0e38\u0e23\u0e35) \/ Bangkok (\u0e01\u0e17\u0e21.)\n                <\/div>\n                <div class=\"legend-item\">\n                    <div class=\"legend-color bg-green-500\"><\/div>\n                    Kanchanaburi (\u0e01\u0e32\u0e0d\u0e08\u0e19\u0e1a\u0e38\u0e23\u0e35)\n                <\/div>\n                <div class=\"legend-item\">\n                    <div class=\"legend-color bg-red-500\"><\/div>\n                    Phetchaburi (\u0e40\u0e1e\u0e0a\u0e23\u0e1a\u0e38\u0e23\u0e35)\n                <\/div>\n                <div class=\"legend-item\">\n                    <div class=\"w-4 h-4 rounded-full border-2 border-gray-400\"><\/div>\n                    \u0e02\u0e19\u0e32\u0e14: 200 \u0e01\u0e01.\n                <\/div>\n                <div class=\"legend-item\">\n                    <div class=\"w-6 h-6 rounded-full border-2 border-gray-400\"><\/div>\n                    \u0e02\u0e19\u0e32\u0e14: 500 \u0e01\u0e01.\n                <\/div>\n                <div class=\"legend-item\">\n                    <div class=\"w-8 h-8 rounded-full border-2 border-gray-400\"><\/div>\n                    \u0e02\u0e19\u0e32\u0e14: 900 \u0e01\u0e01.\n                <\/div>\n            <\/div>\n        <\/div>\n    <\/section>\n\n     <!-- Alert Section (UNNUMBERED) - \u0e41\u0e2a\u0e14\u0e07\u0e40\u0e21\u0e37\u0e48\u0e2d\u0e21\u0e35\u0e04\u0e48\u0e32\u0e40\u0e01\u0e34\u0e19 Baseline -->\n    <section id=\"alert-section\" class=\"card bg-red-800\/20 border border-red-500\/50 mb-8 p-4 hidden\">\n        <h2 class=\"text-xl font-semibold mb-2 text-red-400 flex items-center\">\n            <!-- Alert Icon (Lucide: Alert Triangle) -->\n            <svg class=\"w-6 h-6 mr-2\" fill=\"none\" stroke=\"currentColor\" viewBox=\"0 0 24 24\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.332 17c-.77 1.333.192 3 1.732 3z\"><\/path><\/svg>\n            \u0e01\u0e32\u0e23\u0e41\u0e08\u0e49\u0e07\u0e40\u0e15\u0e37\u0e2d\u0e19\u0e1b\u0e31\u0e08\u0e08\u0e38\u0e1a\u0e31\u0e19 (<span id=\"alert-count\">0<\/span> \u0e23\u0e32\u0e22\u0e01\u0e32\u0e23)\n        <\/h2>\n        <ul id=\"active-alerts\" class=\"list-disc pl-5 text-red-300\">\n            <!-- Alerts will be listed here by JS -->\n        <\/ul>\n    <\/section>\n\n      <!-- 7. Environmental Data Section -->\n    <section id=\"environmental-section\" class=\"mb-8\">\n        <h2 class=\"text-xl font-semibold mb-4 text-blue-300\">\u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e2a\u0e20\u0e32\u0e1e\u0e41\u0e27\u0e14\u0e25\u0e49\u0e2d\u0e21\u0e41\u0e25\u0e30\u0e04\u0e38\u0e13\u0e20\u0e32\u0e1e (IoT Real-time )<\/h2>\n        \n        <!-- Environmental Scorecards -->\n        <div class=\"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-8 gap-4 mb-6\" id=\"env-scorecards\">\n            <!-- Scorecards will be populated by JS -->\n        <\/div>\n\n        <!-- Environmental Trend Chart with Filter -->\n        <div class=\"card\">\n            <!-- Title and Time Filter -->\n            <div class=\"flex justify-between items-center mb-4\">\n                <h2 class=\"text-xl font-semibold text-blue-300\" id=\"env-chart-title\">\u0e41\u0e19\u0e27\u0e42\u0e19\u0e49\u0e21 WT \u0e41\u0e25\u0e30 pH (24 \u0e0a\u0e31\u0e48\u0e27\u0e42\u0e21\u0e07\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14)<\/h2>\n                <select id=\"time-filter\" class=\"bg-gray-700 text-gray-200 rounded-lg p-2 text-sm border-gray-600 focus:ring-blue-500 focus:border-blue-500\">\n                    <option value=\"24h\">24 \u0e0a\u0e31\u0e48\u0e27\u0e42\u0e21\u0e07\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14<\/option>\n                    <option value=\"7d\">7 \u0e27\u0e31\u0e19\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14 (\u0e08\u0e33\u0e25\u0e2d\u0e07)<\/option>\n                    <option value=\"30d\">30 \u0e27\u0e31\u0e19\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14 (\u0e08\u0e33\u0e25\u0e2d\u0e07)<\/option>\n                <\/select>\n            <\/div>\n            <div class=\"h-64 md:h-96\">\n                <canvas id=\"envTrendChart\"><\/canvas>\n            <\/div>\n        <\/div>\n    <\/section>\n\n      <!-- 6. Time-Series Correlation Chart Section -->\n    <section id=\"correlation-chart-section\" class=\"card mb-8\">\n        <h2 class=\"text-xl font-semibold mb-4 text-blue-300\">\u0e2a\u0e20\u0e32\u0e1e\u0e41\u0e27\u0e14\u0e25\u0e49\u0e2d\u0e21 (EC, PAR) vs. \u0e04\u0e38\u0e13\u0e20\u0e32\u0e1e (\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 DW, FW) (24 \u0e0a\u0e31\u0e48\u0e27\u0e42\u0e21\u0e07\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14)<\/h2>\n        <div class=\"h-64 md:h-96\">\n            <canvas id=\"correlationChart\"><\/canvas>\n        <\/div>\n    <\/section>\n\n     <!-- 4. Scatter Plot for EC\/PAR\/Protein Relationship -->\n    <section id=\"scatter-plot-section\" class=\"card mb-8\">\n        <h2 class=\"text-xl font-semibold mb-4 text-blue-300\">\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e31\u0e21\u0e1e\u0e31\u0e19\u0e18\u0e4c\u0e23\u0e30\u0e2b\u0e27\u0e48\u0e32\u0e07 EC, PAR \u0e41\u0e25\u0e30\u0e04\u0e48\u0e32\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 (DW)<\/h2>\n        <p class=\"text-sm text-gray-500 mb-2\">\u0e02\u0e19\u0e32\u0e14\u0e41\u0e25\u0e30\u0e2a\u0e35\u0e02\u0e2d\u0e07\u0e08\u0e38\u0e14\u0e41\u0e2a\u0e14\u0e07\u0e23\u0e30\u0e14\u0e31\u0e1a\u0e40\u0e1b\u0e2d\u0e23\u0e4c\u0e40\u0e0b\u0e47\u0e19\u0e15\u0e4c\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 (\u0e2a\u0e35\u0e40\u0e02\u0e49\u0e21 = \u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19\u0e2a\u0e39\u0e07)<\/p>\n        <div class=\"color-scale-legend mb-4\">\n            <span>\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19\u0e15\u0e48\u0e33 (20% DW)<\/span>\n            <span>\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19\u0e2a\u0e39\u0e07 (60% DW)<\/span>\n        <\/div>\n        <div class=\"h-64 md:h-96\">\n            <canvas id=\"scatterPlotChart\"><\/canvas>\n        <\/div>\n    <\/section>\n\n    <!-- KPI Section (UNNUMBERED) -->\n    <section id=\"kpi-section\" class=\"grid grid-cols-1 md:grid-cols-3 gap-6 mb-8\">\n        <!-- 1. \u0e40\u0e1b\u0e49\u0e32\u0e2b\u0e21\u0e32\u0e22\u0e23\u0e32\u0e22\u0e40\u0e14\u0e37\u0e2d\u0e19 -->\n        <div class=\"card text-center transition duration-300 hover:shadow-blue-500\/50\">\n            <p class=\"text-lg text-gray-400 mb-2\">\u0e40\u0e1b\u0e49\u0e32\u0e2b\u0e21\u0e32\u0e22\u0e01\u0e32\u0e23\u0e40\u0e01\u0e47\u0e1a\u0e40\u0e01\u0e35\u0e48\u0e22\u0e27 (\u0e23\u0e32\u0e22\u0e40\u0e14\u0e37\u0e2d\u0e19)<\/p>\n            <p class=\"text-5xl font-bold text-green-400\">500 \u0e01\u0e01.<\/p>\n        <\/div>\n\n        <!-- 2. \u0e1c\u0e25\u0e1c\u0e25\u0e34\u0e15\u0e17\u0e35\u0e48\u0e04\u0e32\u0e14\u0e01\u0e32\u0e23\u0e13\u0e4c (30 \u0e27\u0e31\u0e19) -->\n        <div class=\"card text-center transition duration-300 hover:shadow-blue-500\/50\">\n            <p class=\"text-lg text-gray-400 mb-2\">\u0e1c\u0e25\u0e1c\u0e25\u0e34\u0e15\u0e17\u0e35\u0e48\u0e04\u0e32\u0e14\u0e01\u0e32\u0e23\u0e13\u0e4c (30 \u0e27\u0e31\u0e19)<\/p>\n            <p class=\"text-5xl font-bold text-yellow-400\" id=\"forecast-production\">350 \u0e01\u0e01.<\/p>\n        <\/div>\n\n        <!-- 3. \u0e2a\u0e16\u0e32\u0e19\u0e30\u0e04\u0e27\u0e32\u0e21\u0e04\u0e37\u0e1a\u0e2b\u0e19\u0e49\u0e32 (Progress) -->\n        <div class=\"card text-center transition duration-300 hover:shadow-blue-500\/50\">\n            <p class=\"text-lg text-gray-400 mb-2\">\u0e2a\u0e16\u0e32\u0e19\u0e30\u0e04\u0e27\u0e32\u0e21\u0e04\u0e37\u0e1a\u0e2b\u0e19\u0e49\u0e32 (30 \u0e27\u0e31\u0e19)<\/p>\n            <div class=\"flex items-center justify-center\">\n                <svg viewBox=\"0 0 36 36\" class=\"w-24 h-24\">\n                    <path class=\"text-gray-700\" d=\"M18 2.0845a15.9155 15.9155 0 0 1 0 31.831a15.9155 15.9155 0 0 1 0-31.831\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-dasharray=\"100, 100\" \/>\n                    <path class=\"text-blue-500\" id=\"progress-circle\" d=\"M18 2.0845a15.9155 15.9155 0 0 1 0 31.831a15.9155 15.9155 0 0 1 0-31.831\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-dasharray=\"70, 100\" \/>\n                <\/svg>\n                <span class=\"absolute text-3xl font-bold text-blue-400\" id=\"progress-percentage\">70%<\/span>\n            <\/div>\n        <\/div>\n    <\/section>\n    \n   \n\n    <!-- 2. Production Forecast Chart -->\n    <section id=\"production-chart-section\" class=\"card mb-8\">\n        <h2 class=\"text-xl font-semibold mb-4 text-blue-300\">\u0e01\u0e23\u0e32\u0e1f\u0e1c\u0e25\u0e1c\u0e25\u0e34\u0e15\u0e17\u0e35\u0e48\u0e04\u0e32\u0e14\u0e01\u0e32\u0e23\u0e13\u0e4c\u0e2a\u0e30\u0e2a\u0e21 (\u0e1e.\u0e22. 2568 &#8211; \u0e01.\u0e1e. 2569)<\/h2>\n        <div class=\"h-64 md:h-96\">\n            <canvas id=\"productionChart\"><\/canvas>\n        <\/div>\n    <\/section>\n\n    <!-- 3. Protein Trend Chart Section -->\n    <section id=\"protein-chart-section\" class=\"card mb-8\">\n        <div class=\"flex justify-between items-center mb-4\">\n            <h2 class=\"text-xl font-semibold text-blue-300\">\u0e41\u0e19\u0e27\u0e42\u0e19\u0e49\u0e21\u0e04\u0e48\u0e32\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 DW \u0e41\u0e25\u0e30 FW (\u0e01\u0e32\u0e23\u0e40\u0e01\u0e47\u0e1a\u0e40\u0e01\u0e35\u0e48\u0e22\u0e27\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14)<\/h2>\n            <select id=\"protein-cycle-filter\" class=\"bg-gray-700 text-gray-200 rounded-lg p-2 text-sm border-gray-600 focus:ring-blue-500 focus:border-blue-500\">\n                <option value=\"5\">5 \u0e23\u0e2d\u0e1a\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14<\/option>\n                <option value=\"7\" selected>7 \u0e23\u0e2d\u0e1a\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14<\/option>\n                <option value=\"10\">10 \u0e23\u0e2d\u0e1a\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14<\/option>\n            <\/select>\n        <\/div>\n        <div class=\"h-64 md:h-96\">\n            <canvas id=\"proteinTrendChart\"><\/canvas>\n        <\/div>\n    <\/section>\n\n    <!-- 5. Donut Charts for Composition -->\n    <section id=\"composition-chart-section\" class=\"card mb-8\">\n        <h2 class=\"text-xl font-semibold mb-4 text-blue-300\">\u0e2d\u0e07\u0e04\u0e4c\u0e1b\u0e23\u0e30\u0e01\u0e2d\u0e1a\u0e17\u0e32\u0e07\u0e0a\u0e35\u0e27\u0e20\u0e32\u0e1e: \u0e40\u0e1b\u0e2d\u0e23\u0e4c\u0e40\u0e0b\u0e47\u0e19\u0e15\u0e4c FW \u0e41\u0e25\u0e30 DW<\/h2>\n        <div class=\"grid grid-cols-1 md:grid-cols-2 gap-8\">\n            <div class=\"h-80 w-full\">\n                <canvas id=\"fwDonutChart\"><\/canvas>\n            <\/div>\n            <div class=\"h-80 w-full\">\n                <canvas id=\"dwDonutChart\"><\/canvas>\n            <\/div>\n            <div class=\"card text-center transition duration-300 hover:shadow-blue-500\/50\">\n            <p class=\"text-lg text-gray-400 mb-2\">\u0e04\u0e48\u0e32\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 FW<\/p>\n            <div class=\"flex items-center justify-center\">\n                <svg viewBox=\"0 0 36 36\" class=\"w-24 h-24\">\n                    <path class=\"text-gray-700\" d=\"M18 2.0845a15.9155 15.9155 0 0 1 0 31.831a15.9155 15.9155 0 0 1 0-31.831\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-dasharray=\"100, 100\" \/>\n                    <path class=\"text-blue-500\" id=\"progress-circle\" d=\"M18 2.0845a15.9155 15.9155 0 0 1 0 31.831a15.9155 15.9155 0 0 1 0-31.831\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-dasharray=\"70, 100\" \/>\n                <\/svg>\n                <span class=\"absolute text-3xl font-bold text-blue-400\" id=\"progress-percentage\">5.6%<\/span>\n            <\/div>\n        <\/div>\n        <div class=\"card text-center transition duration-300 hover:shadow-blue-500\/50\">\n            <p class=\"text-lg text-gray-400 mb-2\">\u0e04\u0e48\u0e32\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 DW<\/p>\n            <div class=\"flex items-center justify-center\">\n                <svg viewBox=\"0 0 36 36\" class=\"w-24 h-24\">\n                    <path class=\"text-gray-700\" d=\"M18 2.0845a15.9155 15.9155 0 0 1 0 31.831a15.9155 15.9155 0 0 1 0-31.831\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-dasharray=\"100, 100\" \/>\n                    <path class=\"text-blue-500\" id=\"progress-circle\" d=\"M18 2.0845a15.9155 15.9155 0 0 1 0 31.831a15.9155 15.9155 0 0 1 0-31.831\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-dasharray=\"70, 100\" \/>\n                <\/svg>\n                <span class=\"absolute text-3xl font-bold text-blue-400\" id=\"progress-percentage\">41%<\/span>\n            <\/div>\n        <\/div>\n        <\/div>\n        \n        \n        \n    <\/section>\n\n  \n\n  \n\n    <!-- Google Maps API Script: Removed the 'callback' to ensure charts initialize correctly -->\n    <script async defer src=\"https:\/\/maps.googleapis.com\/maps\/api\/js?key=\"><\/script>\n\n    <script type=\"module\">\n        \n        \/\/ New core initialization function\n        function initializeDashboard() {\n            console.log(\"Initializing Dashboard Components...\");\n\n            \/\/ 1. Setup Geo Chart (NEW SECTION 1) - Only run if Google Maps is loaded\n            if (typeof google !== 'undefined' && typeof google.maps !== 'undefined') {\n                initMap();\n            } else {\n                console.warn(\"Google Maps API is not loaded. Skipping map initialization.\");\n                \/\/ You might want to display a fallback message in #geoMapContainer here.\n            }\n\n            \/\/ 2. Setup Production Chart (Section 2)\n            setupProductionChart();\n\n            \/\/ 3. Setup Protein Trend Chart (Section 3)\n            updateProteinTrendChart(INITIAL_PROTEIN_VIEW_LENGTH);\n            setupProteinFilter(); \n            \n            \/\/ 4. Setup Scatter Plot (Section 4)\n            drawScatterPlot();\n\n            \/\/ 5. Setup Donut Charts (Section 5)\n            drawDonutChart('fwDonutChart', fwComposition, '\u0e2d\u0e07\u0e04\u0e4c\u0e1b\u0e23\u0e30\u0e01\u0e2d\u0e1a\u0e19\u0e49\u0e33\u0e2b\u0e19\u0e31\u0e01\u0e2a\u0e14 (Fresh Weight)');\n            drawDonutChart('dwDonutChart', dwComposition, '\u0e2d\u0e07\u0e04\u0e4c\u0e1b\u0e23\u0e30\u0e01\u0e2d\u0e1a\u0e19\u0e49\u0e33\u0e2b\u0e19\u0e31\u0e01\u0e41\u0e2b\u0e49\u0e07 (Dry Weight)');\n\n            \/\/ 6. Setup Correlation Chart (Time-Series) (Section 6)\n            setupCorrelationChart();\n\n            \/\/ 7. Update KPIs (Unnumbered)\n            updateKPIs();\n\n            \/\/ 8. Setup Environmental Trend Chart (WT & pH) (Section 7)\n            setupEnvTrendChart();\n            setupEnvFilters();\n\n\n            \/\/ 9. Initial data load and continuous simulation\n            simulateNewData(); \n            \n            \/\/ Set interval to simulate real-time IoT updates every 3 seconds\n            setInterval(simulateNewData, 3000); \n        }\n\n        \/\/ Attach the initialization function to the window load event\n        window.onload = initializeDashboard;\n\n\n        \/\/ -----------------------------------------------------\n        \/\/ 1. Static Data & Baselines\n        \/\/ -----------------------------------------------------\n        \n        const BASELINES = {\n            'WT': { value: 28.0, unit: '\u00b0C', label: '\u0e2d\u0e38\u0e13\u0e2b\u0e20\u0e39\u0e21\u0e34\u0e19\u0e49\u0e33', range: [27.0, 29.0], color: 'rgb(59, 130, 246)' },\n            'pH': { value: 5.5, unit: '', label: '\u0e04\u0e48\u0e32 pH', range: [5.0, 6.0], color: 'rgb(249, 115, 22)' },\n            'EC': { value: 400.0, unit: '\u00b5S\/cm', label: '\u0e04\u0e48\u0e32 EC', range: [350.0, 450.0], color: 'rgb(34, 197, 94)' },\n            'CO2': { value: 432.0, unit: 'ppm', label: '\u0e04\u0e48\u0e32 CO2', range: [400.0, 500.0], color: 'rgb(234, 179, 8)' },\n            'AirTemp': { value: 35.0, unit: '\u00b0C', label: '\u0e2d\u0e38\u0e13\u0e2b\u0e20\u0e39\u0e21\u0e34\u0e2d\u0e32\u0e01\u0e32\u0e28', range: [33.0, 37.0], color: 'rgb(239, 68, 68)' },\n            'Humidity': { value: 40.0, unit: '%RH', label: '\u0e04\u0e27\u0e32\u0e21\u0e0a\u0e37\u0e49\u0e19\u0e2d\u0e32\u0e01\u0e32\u0e28', range: [35.0, 45.0], color: 'rgb(139, 92, 246)' },\n            'PAR': { value: 100.0, unit: '\u00b5mol', label: '\u0e04\u0e48\u0e32 PAR', range: [80.0, 120.0], color: 'rgb(16, 185, 129)' },\n            \/\/ Quality Metrics\n            'Protein': { value: 41.0, unit: '%DW', label: '\u0e04\u0e48\u0e32\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 (DW)', range: [38.0, 44.0], color: 'rgb(245, 158, 11)' },\n            'DM': { value: 7.0, unit: '%DM', label: '\u0e19\u0e49\u0e33\u0e2b\u0e19\u0e31\u0e01\u0e41\u0e2b\u0e49\u0e07 (DM)', range: [6.5, 7.5], color: 'rgb(124, 58, 237)' },\n            'Protein_FW': { value: 2.87, unit: '%FW', label: '\u0e04\u0e48\u0e32\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 (FW)', range: [2.5, 3.5], color: 'rgb(251, 191, 36)' },\n        };\n\n        const MINIMUM_PROTEIN_DW_TARGET = 35.0; \n        const MAX_PROTEIN_HISTORY_LENGTH = 10; \n        const INITIAL_PROTEIN_VIEW_LENGTH = 7; \n\n        const PRODUCTION_PER_CYCLE = 50; \n        const MONTHLY_TARGET = 500;\n        const FORECAST_DAYS = 30; \n        const CYCLES_IN_30_DAYS = Math.floor(FORECAST_DAYS \/ 4);\n        const FORECAST_PRODUCTION = CYCLES_IN_30_DAYS * PRODUCTION_PER_CYCLE; \n        \n        let activeAlerts = []; \n        let updateCounter = 0; \n        const PROTEIN_UPDATE_SIMULATION_INTERVAL = 30; \n        \n        let proteinDataHistory = {\n            labels: Array.from({ length: MAX_PROTEIN_HISTORY_LENGTH }, (_, i) => `\u0e23\u0e2d\u0e1a\u0e17\u0e35\u0e48 ${i + 1}`), \n            Protein_DW: Array.from({ length: MAX_PROTEIN_HISTORY_LENGTH }, (v, i) => \n                BASELINES.Protein.value + (i - MAX_PROTEIN_HISTORY_LENGTH \/ 2) * 0.5 + (Math.random() * 2 - 1)\n            ), \n            Protein_FW: Array.from({ length: MAX_PROTEIN_HISTORY_LENGTH }, (v, i) => \n                BASELINES.Protein_FW.value + (i - MAX_PROTEIN_HISTORY_LENGTH \/ 2) * 0.05 + (Math.random() * 0.2 - 0.1)\n            ), \n        };\n        \n        const CORRELATION_HISTORY_LENGTH = 12;\n        const initialLabels = Array.from({ length: CORRELATION_HISTORY_LENGTH }, (_, i) => `${(i + 1) * 3} \u0e27\u0e34\u0e19\u0e32\u0e17\u0e35\u0e17\u0e35\u0e48\u0e41\u0e25\u0e49\u0e27`);\n        let correlationDataHistory = {\n            labels: initialLabels, \n            EC: Array.from({ length: CORRELATION_HISTORY_LENGTH }, () => BASELINES.EC.value + (Math.random() - 0.5) * 50),\n            PAR: Array.from({ length: CORRELATION_HISTORY_LENGTH }, () => BASELINES.PAR.value + (Math.random() - 0.5) * 20),\n            Protein_DW: Array.from({ length: CORRELATION_HISTORY_LENGTH }, () => BASELINES.Protein.value + (Math.random() - 0.5) * 3),\n            Protein_FW: Array.from({ length: CORRELATION_HISTORY_LENGTH }, () => BASELINES.Protein_FW.value + (Math.random() - 0.5) * 0.5),\n        };\n        let correlationChart;\n\n        \/\/ -----------------------------------------------------\n        \/\/ 2. Geo Chart Data and Logic (Google Maps)\n        \/\/ -----------------------------------------------------\n        let map; \n\n        \/\/ Farm Data with actual Lat\/Lon and Region for coloring\n        const farmLocationData = [\n            \/\/ { name, region, lat, lon, max_capacity, color, cultivation_system, certification } \/\/ Updated to include new fields\n            { name: 'Wolffia Vertical', region: 'Nonthaburi', lat: 13.868, lon: 100.528, capacity: 500, color: '#3b82f6', cultivation_system: 'Vertical Farm', certification: 'GAqP' }, \/\/ Blue\n            \/\/{ name: 'Wolffia Bangkok', region: 'Bangkok', lat: 13.750, lon: 100.520, capacity: 650, color: '#3b82f6', cultivation_system: 'Vertical Farm', certification: 'GAqP' }, \/\/ Blue\n            \/\/{ name: '\u0e1a\u0e49\u0e32\u0e19\u0e44\u0e02\u0e48\u0e19\u0e49\u0e33 by Thai Wolffia', region: 'Bangkok', lat: 13.780, lon: 100.550, capacity: 300, color: '#3b82f6', cultivation_system: 'Plastic Pond', certification: 'GAqP' }, \/\/ Blue\n            { name: '\u0e44\u0e23\u0e48\u0e41\u0e2a\u0e07\u0e2a\u0e01\u0e38\u0e25\u0e23\u0e38\u0e48\u0e07', region: 'Kanchanaburi', lat: 14.000, lon: 99.500, capacity: 200, color: '#10b981', cultivation_system: 'Open Pond', certification: 'GAqP' }, \/\/ Green\n            { name: '\u0e27\u0e34\u0e2a\u0e32\u0e2b\u0e01\u0e34\u0e08\u0e0a\u0e38\u0e21\u0e0a\u0e19\u0e1c\u0e33\u0e40\u0e1e\u0e0a\u0e23\u0e1a\u0e38\u0e23\u0e35', region: 'Phetchaburi', lat: 13.100, lon: 99.950, capacity: 900, color: '#ef4444', cultivation_system: 'Concrete Pond', certification: 'GAP' } \/\/ Red\n        ];\n        \n        \/\/ Function to map Max Capacity (200-900) to Google Maps Circle Radius (min 10000m to max 40000m)\n        function capacityToRadius(capacity) {\n            const minCap = 200;\n            const maxCap = 900;\n            const minRadius = 10000; \/\/ 10 km radius\n            const maxRadius = 40000; \/\/ 40 km radius\n            \n            \/\/ Linear scaling\n            const normalized = (capacity - minCap) \/ (maxCap - minCap);\n            return minRadius + normalized * (maxRadius - minRadius);\n        }\n\n        \/\/ Initialize and draw the Google Map\n        function initMap() {\n            \/\/ Check if google.maps is defined before proceeding\n            if (typeof google === 'undefined' || typeof google.maps === 'undefined') {\n                return;\n            }\n\n            const thaiCenter = { lat: 13.736717, lng: 100.523186 }; \/\/ Center near Bangkok (Siam Square)\n            const mapOptions = {\n                center: thaiCenter,\n                zoom: 8,\n                minZoom: 7, \n                maxZoom: 15,\n                streetViewControl: false,\n                mapTypeControl: false,\n                \/\/ Dark mode styling for the map\n                styles: [\n                    { elementType: \"geometry\", stylers: [{ color: \"#242f3e\" }] },\n                    { elementType: \"labels.text.stroke\", stylers: [{ color: \"#242f3e\" }] },\n                    { elementType: \"labels.text.fill\", stylers: [{ color: \"#746855\" }] },\n                    {\n                        featureType: \"administrative.locality\",\n                        elementType: \"labels.text.fill\",\n                        stylers: [{ color: \"#d59563\" }],\n                    },\n                    { featureType: \"poi\", elementType: \"labels.text.fill\", stylers: [{ color: \"#d59563\" }] },\n                    {\n                        featureType: \"poi.park\",\n                        elementType: \"geometry\",\n                        stylers: [{ color: \"#263c3f\" }],\n                    },\n                    {\n                        featureType: \"road\",\n                        elementType: \"geometry\",\n                        stylers: [{ color: \"#38414e\" }],\n                    },\n                    { featureType: \"water\", elementType: \"geometry\", stylers: [{ color: \"#17263c\" }] },\n                ],\n            };\n            \n            map = new google.maps.Map(document.getElementById('geoMapContainer'), mapOptions);\n            \n            farmLocationData.forEach(farm => {\n                const center = { lat: farm.lat, lng: farm.lon };\n                const radius = capacityToRadius(farm.capacity);\n                \n                \/\/ Create a Circle Marker (Bubble)\n                const cityCircle = new google.maps.Circle({\n                    strokeColor: farm.color,\n                    strokeOpacity: 0.8,\n                    strokeWeight: 2,\n                    fillColor: farm.color,\n                    fillOpacity: 0.35,\n                    map: map,\n                    center: center,\n                    radius: radius, \n                });\n\n                \/\/ Add InfoWindow for interactivity (Tooltip functionality)\n                const infoWindow = new google.maps.InfoWindow({\n                    content: `\n                        <div class=\"text-gray-800\">\n                            <h4 class=\"font-bold text-lg mb-1\">${farm.name}<\/h4>\n                            <p class=\"text-sm\"><strong>Region:<\/strong> ${farm.region}<\/p>\n                            <p class=\"text-sm\"><strong>Max Capacity:<\/strong> ${farm.capacity} \u0e01\u0e01.<\/p>\n                            <!-- NEW FIELDS ADDED HERE -->\n                            <p class=\"text-sm\"><strong>\u0e23\u0e30\u0e1a\u0e1a\u0e40\u0e1e\u0e32\u0e30\u0e40\u0e25\u0e35\u0e49\u0e22\u0e07:<\/strong> ${farm.cultivation_system}<\/p>\n                            <p class=\"text-sm\"><strong>\u0e01\u0e32\u0e23\u0e23\u0e31\u0e1a\u0e23\u0e2d\u0e07:<\/strong> ${farm.certification}<\/p>\n                        <\/div>\n                    `\n                });\n\n                \/\/ Event listener to open InfoWindow on click\n                cityCircle.addListener('click', () => {\n                    infoWindow.setPosition(center);\n                    infoWindow.open(map);\n                });\n            });\n        }\n\n\n        \/\/ -----------------------------------------------------\n        \/\/ 3. Production Chart Setup \n        \/\/ -----------------------------------------------------\n\n        function setupProductionChart() {\n            const weeks = Array.from({ length: 17 }, (_, i) => `\u0e2a\u0e31\u0e1b\u0e14\u0e32\u0e2b\u0e4c\u0e17\u0e35\u0e48 ${i + 1}`);\n            const cumulativeData = [];\n            let currentProduction = 0;\n\n            for (let i = 0; i < 17; i++) {\n                currentProduction += (7 \/ 4) * PRODUCTION_PER_CYCLE; \n                cumulativeData.push(Math.round(currentProduction));\n            }\n            \n            const cumulativeTarget = weeks.map((_, i) => (i + 1) * (MONTHLY_TARGET \/ 4));\n\n            const ctx = document.getElementById('productionChart').getContext('2d');\n            new Chart(ctx, {\n                type: 'line',\n                data: {\n                    labels: weeks,\n                    datasets: [\n                        {\n                            label: '\u0e1c\u0e25\u0e1c\u0e25\u0e34\u0e15\u0e17\u0e35\u0e48\u0e04\u0e32\u0e14\u0e01\u0e32\u0e23\u0e13\u0e4c\u0e2a\u0e30\u0e2a\u0e21 (\u0e01\u0e01.)',\n                            data: cumulativeData,\n                            backgroundColor: 'rgba(59, 130, 246, 0.5)',\n                            borderColor: 'rgb(59, 130, 246)',\n                            borderWidth: 2,\n                            tension: 0.4,\n                            fill: true,\n                        },\n                        {\n                            label: '\u0e40\u0e1b\u0e49\u0e32\u0e2b\u0e21\u0e32\u0e22\u0e2a\u0e30\u0e2a\u0e21\u0e23\u0e32\u0e22\u0e2a\u0e31\u0e1b\u0e14\u0e32\u0e2b\u0e4c (125 \u0e01\u0e01.\/\u0e2a\u0e31\u0e1b\u0e14\u0e32\u0e2b\u0e4c)',\n                            data: cumulativeTarget,\n                            borderColor: 'rgb(239, 68, 68)',\n                            borderWidth: 2,\n                            borderDash: [5, 5],\n                            pointRadius: 0,\n                            type: 'line',\n                            yAxisID: 'y'\n                        }\n                    ]\n                },\n                options: {\n                    responsive: true,\n                    maintainAspectRatio: false,\n                    plugins: {\n                        legend: { labels: { color: 'rgb(209, 213, 219)' } },\n                        title: { display: false }\n                    },\n                    scales: {\n                        x: {\n                            title: { display: true, text: '\u0e2a\u0e31\u0e1b\u0e14\u0e32\u0e2b\u0e4c', color: 'rgb(156, 163, 175)' },\n                            ticks: { color: 'rgb(156, 163, 175)' },\n                            grid: { color: 'rgba(55, 65, 81, 0.5)' }\n                        },\n                        y: {\n                            title: { display: true, text: '\u0e1c\u0e25\u0e1c\u0e25\u0e34\u0e15\u0e2a\u0e30\u0e2a\u0e21 (\u0e01\u0e01.)', color: 'rgb(156, 163, 175)' },\n                            ticks: { color: 'rgb(156, 163, 175)' },\n                            grid: { color: 'rgba(55, 65, 81, 0.5)' }\n                        }\n                    }\n                }\n            });\n        }\n\n        \/\/ -----------------------------------------------------\n        \/\/ 4. KPI & Scorecard Update \n        \/\/ -----------------------------------------------------\n\n        function updateKPIs() {\n            const progress = (FORECAST_PRODUCTION \/ MONTHLY_TARGET) * 100;\n            const progressDisplay = Math.round(progress);\n            \n            document.getElementById('forecast-production').textContent = `${FORECAST_PRODUCTION} \u0e01\u0e01.`;\n            document.getElementById('progress-percentage').textContent = `${progressDisplay}%`;\n            \n            document.getElementById('progress-circle').setAttribute('stroke-dasharray', `${progress}, 100`);\n            document.getElementById('progress-circle').setAttribute('class', `text-${progress >= 80 ? 'green' : (progress >= 60 ? 'yellow' : 'red')}-500`);\n        }\n        \n        \/\/ -----------------------------------------------------\n        \/\/ 5. Protein Trend Chart Setup\n        \/\/ -----------------------------------------------------\n\n        let proteinTrendChart;\n\n        function updateProteinTrendChart(cyclesToShow) {\n            if (proteinTrendChart) {\n                proteinTrendChart.destroy();\n            }\n\n            const dataLength = parseInt(cyclesToShow, 10);\n            \n            const slicedLabels = proteinDataHistory.labels.slice(MAX_PROTEIN_HISTORY_LENGTH - dataLength);\n            const slicedProteinDW = proteinDataHistory.Protein_DW.slice(MAX_PROTEIN_HISTORY_LENGTH - dataLength);\n            const slicedProteinFW = proteinDataHistory.Protein_FW.slice(MAX_PROTEIN_HISTORY_LENGTH - dataLength);\n            \n            const ctx = document.getElementById('proteinTrendChart').getContext('2d');\n            proteinTrendChart = new Chart(ctx, {\n                type: 'line',\n                data: {\n                    labels: slicedLabels,\n                    datasets: [\n                        {\n                            label: '\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 (%DW)',\n                            data: slicedProteinDW,\n                            borderColor: BASELINES.Protein.color,\n                            backgroundColor: 'rgba(245, 158, 11, 0.1)',\n                            fill: false,\n                            yAxisID: 'y-dw',\n                            tension: 0.2,\n                            pointRadius: 5,\n                            pointHoverRadius: 7,\n                        },\n                        {\n                            label: '\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 (%FW)',\n                            data: slicedProteinFW,\n                            borderColor: BASELINES.Protein_FW.color,\n                            backgroundColor: 'rgba(251, 191, 36, 0.1)',\n                            fill: false,\n                            yAxisID: 'y-fw',\n                            borderDash: [5, 2],\n                            tension: 0.2,\n                            pointRadius: 5,\n                            pointHoverRadius: 7,\n                        }\n                    ]\n                },\n                options: {\n                    responsive: true,\n                    maintainAspectRatio: false,\n                    plugins: { \n                        legend: { labels: { color: 'rgb(209, 213, 219)' } }\n                    },\n                    scales: {\n                        x: {\n                            title: { display: true, text: '\u0e23\u0e2d\u0e1a\u0e01\u0e32\u0e23\u0e40\u0e01\u0e47\u0e1a\u0e40\u0e01\u0e35\u0e48\u0e22\u0e27 (4 \u0e27\u0e31\u0e19)', color: 'rgb(156, 163, 175)' },\n                            ticks: { color: 'rgb(156, 163, 175)' },\n                            grid: { color: 'rgba(55, 65, 81, 0.5)' }\n                        },\n                        'y-dw': {\n                            type: 'linear',\n                            position: 'left',\n                            title: { display: true, text: '\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 (%DW)', color: BASELINES.Protein.color },\n                            ticks: { color: BASELINES.Protein.color },\n                            grid: { color: 'rgba(55, 65, 81, 0.5)' },\n                            min: 30, \n                            max: 50, \n                            afterBuildTicks: axis => {\n                                axis.ticks.push({ value: BASELINES.Protein.value, label: 'Optimal DW (41%)' });\n                                axis.ticks.push({ value: MINIMUM_PROTEIN_DW_TARGET, label: 'Min Target DW (35%)', major: true });\n                            }\n                        },\n                        'y-fw': {\n                            type: 'linear',\n                            position: 'right',\n                            title: { display: true, text: '\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 (%FW)', color: BASELINES.Protein_FW.color },\n                            ticks: { color: BASELINES.Protein_FW.color },\n                            grid: { drawOnChartArea: false },\n                            min: 2, \n                            max: 4, \n                            afterBuildTicks: axis => {\n                                axis.ticks.push({ value: BASELINES.Protein_FW.value, label: 'Optimal FW (2.87%)' });\n                            }\n                        }\n                    }\n                }\n            });\n        }\n        \n        \/\/ -----------------------------------------------------\n        \/\/ 6. Scatter Plot (EC vs PAR vs Protein)\n        \/\/ -----------------------------------------------------\n        const relationshipData = [\n            { x: 300, y: 150, p: 25 }, \n            { x: 450, y: 220, p: 32 },\n            { x: 500, y: 300, p: 40 },\n            { x: 550, y: 450, p: 55 }, \n            { x: 600, y: 500, p: 60 }, \n            { x: 650, y: 480, p: 58 },\n            { x: 700, y: 350, p: 50 },\n            { x: 750, y: 280, p: 45 },\n            { x: 800, y: 600, p: 52 }, \n            { x: 900, y: 180, p: 35 }, \n            { x: 400, y: 650, p: 48 }, \n        ];\n\n        function getProteinColor(protein) {\n            const minP = 20;\n            const maxP = 60;\n            const normalized = Math.max(0, Math.min(1, (protein - minP) \/ (maxP - minP)));\n            \n            const colorA = [156, 163, 175]; \n            const colorB = [16, 185, 129];  \n\n            const r = Math.round(colorA[0] + (colorB[0] - colorA[0]) * normalized);\n            const g = Math.round(colorA[1] + (colorB[1] - colorA[1]) * normalized);\n            const b = Math.round(colorA[2] + (colorB[2] - colorA[2]) * normalized);\n\n            return `rgb(${r}, ${g}, ${b})`;\n        }\n\n        function drawScatterPlot() {\n            const ctx = document.getElementById('scatterPlotChart').getContext('2d');\n            \n            const chartData = relationshipData.map(d => ({\n                x: d.x,\n                y: d.y,\n                r: d.p * 0.4, \n                protein: d.p \n            }));\n            \n            new Chart(ctx, {\n                type: 'scatter',\n                data: {\n                    datasets: [{\n                        label: 'EC, PAR \u0e41\u0e25\u0e30 Protein (%DW)',\n                        data: chartData,\n                        backgroundColor: chartData.map(d => getProteinColor(d.protein)),\n                        borderColor: 'rgba(255, 255, 255, 0.5)',\n                        borderWidth: 1,\n                        pointRadius: chartData.map(d => d.r), \n                        pointHoverRadius: chartData.map(d => d.r + 3),\n                    }]\n                },\n                options: {\n                    responsive: true,\n                    maintainAspectRatio: false,\n                    plugins: {\n                        legend: { display: false },\n                        tooltip: {\n                            callbacks: {\n                                label: function(context) {\n                                    const d = context.raw;\n                                    return [\n                                        `EC: ${d.x} \u00b5S\/cm`,\n                                        `PAR: ${d.y} \u00b5mol`,\n                                        `\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19: ${d.protein.toFixed(1)}% DW`\n                                    ];\n                                }\n                            }\n                        }\n                    },\n                    scales: {\n                        x: {\n                            type: 'linear',\n                            position: 'bottom',\n                            title: { display: true, text: 'EC (\u00b5S\/cm)', font: { size: 14 }, color: 'rgb(34, 197, 94)' },\n                            ticks: { color: 'rgb(156, 163, 175)' },\n                            grid: { color: 'rgba(55, 65, 81, 0.5)' }\n                        },\n                        y: {\n                            title: { display: true, text: 'PAR (\u00b5mol)', font: { size: 14 }, color: 'rgb(16, 185, 129)' },\n                            ticks: { color: 'rgb(156, 163, 175)' },\n                            grid: { color: 'rgba(55, 65, 81, 0.5)' }\n                        }\n                    }\n                }\n            });\n        }\n\n\n        \/\/ -----------------------------------------------------\n        \/\/ 7. Donut Charts (FW\/DW Composition)\n        \/\/ -----------------------------------------------------\n        const fwComposition = {\n            labels: ['\u0e19\u0e49\u0e33 (Water)', '\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 (Protein)', '\u0e04\u0e32\u0e23\u0e4c\u0e42\u0e1a\u0e44\u0e2e\u0e40\u0e14\u0e23\u0e15\/\u0e2d\u0e37\u0e48\u0e19\u0e46'],\n            data: [93, 3, 4], \n            colors: ['rgb(59, 130, 246)', 'rgb(251, 191, 36)', 'rgb(156, 163, 175)']\n        };\n\n        const dwComposition = {\n            labels: ['\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 (Protein)', '\u0e04\u0e32\u0e23\u0e4c\u0e42\u0e1a\u0e44\u0e2e\u0e40\u0e14\u0e23\u0e15 (Carbohydrates)', '\u0e44\u0e02\u0e21\u0e31\u0e19 (Lipids)', '\u0e40\u0e16\u0e49\u0e32\/\u0e41\u0e23\u0e48\u0e18\u0e32\u0e15\u0e38 (Ash\/Minerals)'],\n            data: [45, 30, 15, 10],\n            colors: ['rgb(245, 158, 11)', 'rgb(34, 197, 94)', 'rgb(239, 68, 68)', 'rgb(124, 58, 237)']\n        };\n\n        function drawDonutChart(elementId, composition, title) {\n            const ctx = document.getElementById(elementId).getContext('2d');\n            new Chart(ctx, {\n                type: 'doughnut',\n                data: {\n                    labels: composition.labels,\n                    datasets: [{\n                        data: composition.data,\n                        backgroundColor: composition.colors,\n                        hoverOffset: 10,\n                        borderColor: '#0d1117', \n                        borderWidth: 2,\n                    }]\n                },\n                options: {\n                    responsive: true,\n                    maintainAspectRatio: false,\n                    plugins: {\n                        legend: {\n                            position: 'bottom',\n                            labels: {\n                                padding: 15,\n                                color: 'rgb(209, 213, 219)',\n                                font: { size: 12 }\n                            }\n                        },\n                        title: {\n                            display: true,\n                            text: title,\n                            font: { size: 16, weight: 'bold' },\n                            color: 'rgb(59, 130, 246)'\n                        },\n                        datalabels: {\n                            formatter: (value) => {\n                                return value + '%';\n                            },\n                            color: '#fff',\n                            textShadowBlur: 4,\n                            textShadowColor: 'rgba(0, 0, 0, 0.6)',\n                            font: {\n                                weight: 'bold'\n                            }\n                        }\n                    }\n                },\n                plugins: [ChartDataLabels]\n            });\n        }\n\n        \/\/ -----------------------------------------------------\n        \/\/ 8. Time-Series Correlation Chart Setup \n        \/\/ -----------------------------------------------------\n\n        function setupCorrelationChart() {\n            const ctx = document.getElementById('correlationChart').getContext('2d');\n            correlationChart = new Chart(ctx, {\n                type: 'line',\n                data: {\n                    labels: correlationDataHistory.labels,\n                    datasets: [\n                        {\n                            label: 'EC (\u00b5S\/cm)',\n                            data: correlationDataHistory.EC,\n                            borderColor: BASELINES.EC.color,\n                            backgroundColor: 'rgba(34, 197, 94, 0.1)',\n                            fill: false,\n                            yAxisID: 'y-env',\n                            tension: 0.2\n                        },\n                        {\n                            label: 'PAR (\u00b5mol)',\n                            data: correlationDataHistory.PAR,\n                            borderColor: BASELINES.PAR.color,\n                            backgroundColor: 'rgba(16, 185, 129, 0.1)',\n                            fill: false,\n                            yAxisID: 'y-env',\n                            tension: 0.2\n                        },\n                        {\n                            label: '\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 DW (%)',\n                            data: correlationDataHistory.Protein_DW,\n                            borderColor: BASELINES.Protein.color,\n                            backgroundColor: 'rgba(245, 158, 11, 0.1)',\n                            fill: false,\n                            yAxisID: 'y-quality',\n                            borderDash: [5, 5],\n                            tension: 0.2\n                        },\n                        {\n                            label: '\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 FW (%)',\n                            data: correlationDataHistory.Protein_FW,\n                            borderColor: BASELINES.Protein_FW.color,\n                            backgroundColor: 'rgba(251, 191, 36, 0.1)',\n                            fill: false,\n                            yAxisID: 'y-quality',\n                            borderDash: [2, 2],\n                            tension: 0.2\n                        }\n                    ]\n                },\n                options: {\n                    responsive: true,\n                    maintainAspectRatio: false,\n                    plugins: { legend: { labels: { color: 'rgb(209, 213, 219)' } } },\n                    scales: {\n                        x: {\n                            title: { display: true, text: '\u0e40\u0e27\u0e25\u0e32 (\u0e27\u0e34\u0e19\u0e32\u0e17\u0e35)', color: 'rgb(156, 163, 175)' },\n                            ticks: { color: 'rgb(156, 163, 175)' },\n                            grid: { color: 'rgba(55, 65, 81, 0.5)' }\n                        },\n                        'y-env': {\n                            type: 'linear',\n                            position: 'left',\n                            title: { display: true, text: '\u0e2a\u0e20\u0e32\u0e1e\u0e41\u0e27\u0e14\u0e25\u0e49\u0e2d\u0e21 (EC, PAR)', color: 'rgb(34, 197, 94)' },\n                            ticks: { color: 'rgb(34, 197, 94)' },\n                            grid: { color: 'rgba(55, 65, 81, 0.5)' },\n                            min: 50, max: 500, \n                        },\n                        'y-quality': {\n                            type: 'linear',\n                            position: 'right',\n                            title: { display: true, text: '\u0e04\u0e38\u0e13\u0e20\u0e32\u0e1e (\u0e42\u0e1b\u0e23\u0e15\u0e35\u0e19 %)', color: BASELINES.Protein.color },\n                            ticks: { color: BASELINES.Protein.color },\n                            grid: { drawOnChartArea: false },\n                            min: 0, max: 50, \n                        }\n                    }\n                }\n            });\n        }\n\n        \/\/ -----------------------------------------------------\n        \/\/ 9. Alerts and Environmental Scorecard & Trend \n        \/\/ -----------------------------------------------------\n\n        function renderAlerts() {\n            const alertSection = document.getElementById('alert-section');\n            const alertList = document.getElementById('active-alerts');\n            const alertCount = document.getElementById('alert-count');\n            \n            alertList.innerHTML = '';\n            alertCount.textContent = activeAlerts.length;\n\n            if (activeAlerts.length > 0) {\n                alertSection.classList.remove('hidden');\n                activeAlerts.forEach(alert => {\n                    const listItem = document.createElement('li');\n                    listItem.textContent = alert;\n                    alertList.appendChild(listItem);\n                });\n            } else {\n                alertSection.classList.add('hidden');\n            }\n        }\n\n        function renderEnvScorecards(currentValues) {\n            const container = document.getElementById('env-scorecards');\n            container.innerHTML = '';\n            \n            Object.keys(BASELINES).forEach(key => {\n                const baseline = BASELINES[key];\n                const currentValue = currentValues[key];\n                \n                if (typeof currentValue === 'undefined') return;\n\n                const [min, max] = baseline.range;\n                \n                let status, color, icon;\n\n                if (currentValue >= min && currentValue <= max) {\n                    status = '\u0e1b\u0e01\u0e15\u0e34';\n                    color = 'text-green-400';\n                    icon = `<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-6 h-6\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M22 11.08V12a10 10 0 1 1-5.93-8.83\"><\/path><path d=\"M22 4L12 14.01l-3-3\"><\/path><\/svg>`;\n                } else {\n                    status = (currentValue > max) ? '\u0e2a\u0e39\u0e07\u0e40\u0e01\u0e34\u0e19\u0e44\u0e1b' : '\u0e15\u0e48\u0e33\u0e40\u0e01\u0e34\u0e19\u0e44\u0e1b';\n                    color = 'text-red-400';\n                    icon = `<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"w-6 h-6\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"><\/path><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"><\/line><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"><\/line><\/svg>`;\n                }\n                \n                const html = `\n                    <div class=\"card p-4 flex flex-col justify-between transition duration-300 ${color} hover:bg-gray-800\/50\">\n                        <div class=\"flex justify-between items-start mb-2\">\n                            <h3 class=\"text-sm font-medium text-gray-400\">${baseline.label}<\/h3>\n                            <span class=\"${color}\">${icon}<\/span>\n                        <\/div>\n                        <p class=\"text-3xl font-bold\">${currentValue.toFixed(2)} ${baseline.unit}<\/p>\n                        <p class=\"text-xs mt-1 text-gray-500\">Base: ${baseline.value.toFixed(1)} ${baseline.unit} (${status})<\/p>\n                    <\/div>\n                `;\n                container.innerHTML += html;\n            });\n        }\n\n        let envDataHistory = {\n            labels: Array.from({ length: 12 }, (_, i) => `${(i + 1) * 2} \u0e0a\u0e21.\u0e17\u0e35\u0e48\u0e41\u0e25\u0e49\u0e27`),\n            WT: Array.from({ length: 12 }, () => BASELINES.WT.value + (Math.random() - 0.5) * 2), \n            pH: Array.from({ length: 12 }, () => BASELINES.pH.value + (Math.random() - 0.5) * 0.5) \n        };\n\n        let envTrendChart;\n\n        function setupEnvTrendChart() {\n            const ctx = document.getElementById('envTrendChart').getContext('2d');\n            envTrendChart = new Chart(ctx, {\n                type: 'line',\n                data: {\n                    labels: envDataHistory.labels,\n                    datasets: [\n                        {\n                            label: '\u0e2d\u0e38\u0e13\u0e2b\u0e20\u0e39\u0e21\u0e34\u0e19\u0e49\u0e33 (WT)',\n                            data: envDataHistory.WT,\n                            borderColor: BASELINES.WT.color,\n                            backgroundColor: 'rgba(59, 130, 246, 0.1)',\n                            fill: false,\n                            yAxisID: 'y-wt',\n                            tension: 0.1\n                        },\n                        {\n                            label: '\u0e04\u0e48\u0e32 pH',\n                            data: envDataHistory.pH,\n                            borderColor: BASELINES.pH.color,\n                            backgroundColor: 'rgba(249, 115, 22, 0.1)',\n                            fill: false,\n                            yAxisID: 'y-ph',\n                            tension: 0.1\n                        }\n                    ]\n                },\n                options: {\n                    responsive: true,\n                    maintainAspectRatio: false,\n                    plugins: { legend: { labels: { color: 'rgb(209, 213, 219)' } } },\n                    scales: {\n                        x: {\n                            title: { display: true, text: '\u0e40\u0e27\u0e25\u0e32', color: 'rgb(156, 163, 175)' },\n                            ticks: { color: 'rgb(156, 163, 175)' },\n                            grid: { color: 'rgba(55, 65, 81, 0.5)' }\n                        },\n                        'y-wt': {\n                            type: 'linear',\n                            position: 'left',\n                            title: { display: true, text: 'WT (\u00b0C)', color: BASELINES.WT.color },\n                            ticks: { color: BASELINES.WT.color },\n                            grid: { color: 'rgba(55, 65, 81, 0.5)' },\n                            min: 25, max: 35,\n                            afterBuildTicks: axis => {\n                                axis.ticks.push({ value: BASELINES.WT.value, label: 'Baseline WT' });\n                            }\n                        },\n                        'y-ph': {\n                            type: 'linear',\n                            position: 'right',\n                            title: { display: true, text: 'pH', color: BASELINES.pH.color },\n                            ticks: { color: BASELINES.pH.color },\n                            grid: { drawOnChartArea: false },\n                            min: 4.0, max: 7.0,\n                            afterBuildTicks: axis => {\n                                axis.ticks.push({ value: BASELINES.pH.value, label: 'Baseline pH' });\n                            }\n                        }\n                    }\n                }\n            });\n        }\n\n        function simulateNewData() {\n            const currentValues = {};\n            activeAlerts = []; \n            \n            Object.keys(BASELINES).forEach(key => {\n                const baseline = BASELINES[key];\n                const rangeDiff = baseline.range[1] - baseline.range[0];\n                let randomDeviation;\n                \n                if (key === 'Protein') {\n                    randomDeviation = (Math.random() - 0.5) * 6.0; \n                    currentValues[key] = baseline.value + randomDeviation;\n                } else if (key === 'DM') {\n                    randomDeviation = (Math.random() - 0.5) * 1.0; \n                    currentValues[key] = baseline.value + randomDeviation;\n                } else if (key === 'Protein_FW') {\n                    return; \n                } else {\n                    randomDeviation = (Math.random() - 0.5) * rangeDiff * 1.5; \n                    currentValues[key] = baseline.value + randomDeviation;\n                }\n\n                const [min, max] = baseline.range;\n                if (currentValues[key] < min) {\n                    activeAlerts.push(`${baseline.label} \u0e15\u0e48\u0e33\u0e40\u0e01\u0e34\u0e19\u0e44\u0e1b: ${currentValues[key].toFixed(1)} ${baseline.unit} (Base Min: ${min} ${baseline.unit})`);\n                } else if (currentValues[key] > max) {\n                    activeAlerts.push(`${baseline.label} \u0e2a\u0e39\u0e07\u0e40\u0e01\u0e34\u0e19\u0e44\u0e1b: ${currentValues[key].toFixed(1)} ${baseline.unit} (Base Max: ${max} ${baseline.unit})`);\n                }\n            });\n\n            const proteinDW = currentValues.Protein;\n            const dryMatter = currentValues.DM;\n            const proteinFW = proteinDW * (dryMatter \/ 100);\n            currentValues.Protein_FW = proteinFW;\n\n            const fwBaseline = BASELINES.Protein_FW;\n            const [fwMin, fwMax] = fwBaseline.range;\n            if (proteinFW < fwMin) {\n                activeAlerts.push(`${fwBaseline.label} \u0e15\u0e48\u0e33\u0e40\u0e01\u0e34\u0e19\u0e44\u0e1b: ${proteinFW.toFixed(2)} ${fwBaseline.unit} (Base Min: ${fwMin} ${fwBaseline.unit})`);\n            } else if (proteinFW > fwMax) {\n                activeAlerts.push(`${fwBaseline.label} \u0e2a\u0e39\u0e07\u0e40\u0e01\u0e34\u0e19\u0e44\u0e1b: ${proteinFW.toFixed(2)} ${fwBaseline.unit} (Base Max: ${fwMax} ${fwBaseline.unit})`);\n            }\n            \n            envDataHistory.WT.shift();\n            envDataHistory.WT.push(currentValues.WT);\n            envDataHistory.pH.shift();\n            envDataHistory.pH.push(currentValues.pH);\n            \n            if (envTrendChart) {\n                envDataHistory.labels.shift();\n                envDataHistory.labels.push(new Date().toLocaleTimeString('th-TH', { hour: '2-digit', minute: '2-digit' }));\n\n                envTrendChart.data.datasets[0].data = envDataHistory.WT;\n                envTrendChart.data.datasets[1].data = envDataHistory.pH;\n                envTrendChart.data.labels = envDataHistory.labels;\n                envTrendChart.update();\n            }\n\n            correlationDataHistory.EC.shift();\n            correlationDataHistory.EC.push(currentValues.EC);\n            correlationDataHistory.PAR.shift();\n            correlationDataHistory.PAR.push(currentValues.PAR);\n            correlationDataHistory.Protein_DW.shift();\n            correlationDataHistory.Protein_DW.push(currentValues.Protein);\n            correlationDataHistory.Protein_FW.shift();\n            correlationDataHistory.Protein_FW.push(currentValues.Protein_FW);\n\n            if (correlationChart) {\n                correlationDataHistory.labels.shift();\n                correlationDataHistory.labels.push(`${CORRELATION_HISTORY_LENGTH * 3} \u0e27\u0e34\u0e19\u0e32\u0e17\u0e35\u0e17\u0e35\u0e48\u0e41\u0e25\u0e49\u0e27`); \n\n                correlationChart.data.datasets[0].data = correlationDataHistory.EC;\n                correlationChart.data.datasets[1].data = correlationDataHistory.PAR;\n                correlationChart.data.datasets[2].data = correlationDataHistory.Protein_DW;\n                correlationChart.data.datasets[3].data = correlationDataHistory.Protein_FW;\n                correlationChart.data.labels = correlationDataHistory.labels;\n                correlationChart.update();\n            }\n\n            updateCounter++;\n            if (updateCounter >= PROTEIN_UPDATE_SIMULATION_INTERVAL) {\n                updateCounter = 0;\n                \n                proteinDataHistory.Protein_DW.shift();\n                proteinDataHistory.Protein_DW.push(currentValues.Protein); \n                proteinDataHistory.Protein_FW.shift();\n                proteinDataHistory.Protein_FW.push(currentValues.Protein_FW); \n\n                const lastLabel = proteinDataHistory.labels.pop();\n                proteinDataHistory.labels.unshift(lastLabel);\n\n                const currentCycles = document.getElementById('protein-cycle-filter').value;\n                updateProteinTrendChart(currentCycles); \n            }\n\n            renderEnvScorecards(currentValues);\n            renderAlerts();\n        }\n\n        \/\/ Functionality for the Time Filter (Environmental Chart)\n        function setupEnvFilters() {\n            const filterSelect = document.getElementById('time-filter');\n            const chartTitle = document.getElementById('env-chart-title');\n            \n            filterSelect.addEventListener('change', (event) => {\n                const selected = event.target.value;\n                let titleText = '\u0e41\u0e19\u0e27\u0e42\u0e19\u0e49\u0e21 WT \u0e41\u0e25\u0e30 pH ';\n                \n                if (selected === '24h') {\n                    titleText += '(24 \u0e0a\u0e31\u0e48\u0e27\u0e42\u0e21\u0e07\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14)';\n                } else if (selected === '7d') {\n                    titleText += '(7 \u0e27\u0e31\u0e19\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14 - \u0e08\u0e33\u0e25\u0e2d\u0e07)';\n                } else if (selected === '30d') {\n                    titleText += '(30 \u0e27\u0e31\u0e19\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14 - \u0e08\u0e33\u0e25\u0e2d\u0e07)';\n                }\n                \n                chartTitle.textContent = titleText;\n            });\n        }\n        \n        \/\/ Functionality for the Protein Cycle Filter\n        function setupProteinFilter() {\n            const filterSelect = document.getElementById('protein-cycle-filter');\n            filterSelect.addEventListener('change', (event) => {\n                updateProteinTrendChart(event.target.value);\n            });\n        }\n\n    <\/script>\n    \n    <!-- Footer Section: Added as requested -->\n    <footer class=\"mt-12 py-6 text-center text-sm border-t border-gray-700\">\n        <p class=\"text-gray-500\">\n            &copy; 2025 Future Intelligence Nutritional Harvest &#8211; FINH. \n            Powered by <a href=\"https:\/\/www.kitforward.co.th\/en_US\/\" target=\"_blank\" class=\"text-blue-400 hover:text-blue-300 transition duration-150\">KITFORWARD<\/a>.\n        <\/p>\n    <\/footer>\n<\/body>\n<\/html>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Thailand&#8217;s Wolffia Data Portal Thailand&#8217;s Wolffia Data Portal \u0e01\u0e32\u0e23\u0e15\u0e34\u0e14\u0e15\u0e32\u0e21\u0e1c\u0e25\u0e1c\u0e25\u0e34\u0e15\u0e41\u0e25\u0e30\u0e2a\u0e20\u0e32\u0e1e\u0e41\u0e27\u0e14\u0e25\u0e49\u0e2d\u0e21\u0e1f\u0e32\u0e23\u0e4c\u0e21\u0e41\u0e1a\u0e1a\u0e40\u0e23\u0e35\u0e22\u0e25\u0e44\u0e17\u0e21\u0e4c (\u0e08\u0e33\u0e25\u0e2d\u0e07) \u0e1e\u0e34\u0e01\u0e31\u0e14\u0e1f\u0e32\u0e23\u0e4c\u0e21\u0e41\u0e25\u0e30\u0e04\u0e27\u0e32\u0e21\u0e2a\u0e32\u0e21\u0e32\u0e23\u0e16\u0e43\u0e19\u0e01\u0e32\u0e23\u0e1c\u0e25\u0e34\u0e15\u0e2a\u0e39\u0e07\u0e2a\u0e38\u0e14 (Max Capacity) \u0e41\u0e2a\u0e14\u0e07\u0e15\u0e33\u0e41\u0e2b\u0e19\u0e48\u0e07\u0e1f\u0e32\u0e23\u0e4c\u0e21\u0e1a\u0e19\u0e41\u0e1c\u0e19\u0e17\u0e35\u0e48 \u0e02\u0e19\u0e32\u0e14\u0e1f\u0e2d\u0e07\u0e2a\u0e1a\u0e39\u0e48\u0e41\u0e2a\u0e14\u0e07\u0e16\u0e36\u0e07 Max Capacity (\u0e01\u0e01.) \u0e41\u0e25\u0e30\u0e2a\u0e35\u0e41\u0e2a\u0e14\u0e07\u0e20\u0e39\u0e21\u0e34\u0e20\u0e32\u0e04 \u0e2a\u0e31\u0e0d\u0e25\u0e31\u0e01\u0e29\u0e13\u0e4c\u0e41\u0e1c\u0e19\u0e17\u0e35\u0e48 Nonthaburi (\u0e19\u0e19\u0e17\u0e1a\u0e38\u0e23\u0e35) \/ Bangkok (\u0e01\u0e17\u0e21.) Kanchanaburi (\u0e01\u0e32\u0e0d\u0e08\u0e19\u0e1a\u0e38\u0e23\u0e35) Phetchaburi (\u0e40\u0e1e\u0e0a\u0e23\u0e1a\u0e38\u0e23\u0e35) \u0e02\u0e19\u0e32\u0e14: 200 \u0e01\u0e01. \u0e02\u0e19\u0e32\u0e14: 500 \u0e01\u0e01. \u0e02\u0e19\u0e32\u0e14: 900 \u0e01\u0e01. \u0e01\u0e32\u0e23\u0e41\u0e08\u0e49\u0e07\u0e40\u0e15\u0e37\u0e2d\u0e19\u0e1b\u0e31\u0e08\u0e08\u0e38\u0e1a\u0e31\u0e19 (0 \u0e23\u0e32\u0e22\u0e01\u0e32\u0e23) \u0e02\u0e49\u0e2d\u0e21\u0e39\u0e25\u0e2a\u0e20\u0e32\u0e1e\u0e41\u0e27\u0e14\u0e25\u0e49\u0e2d\u0e21\u0e41\u0e25\u0e30\u0e04\u0e38\u0e13\u0e20\u0e32\u0e1e (IoT Real-time ) \u0e41\u0e19\u0e27\u0e42\u0e19\u0e49\u0e21 WT \u0e41\u0e25\u0e30 pH (24 \u0e0a\u0e31\u0e48\u0e27\u0e42\u0e21\u0e07\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14) 24 \u0e0a\u0e31\u0e48\u0e27\u0e42\u0e21\u0e07\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e147 \u0e27\u0e31\u0e19\u0e25\u0e48\u0e32\u0e2a\u0e38\u0e14 (\u0e08\u0e33\u0e25\u0e2d\u0e07)30&#8230;<\/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-409","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.kitforward.co.th\/en_US\/wp-json\/wp\/v2\/pages\/409","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.kitforward.co.th\/en_US\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.kitforward.co.th\/en_US\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.kitforward.co.th\/en_US\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kitforward.co.th\/en_US\/wp-json\/wp\/v2\/comments?post=409"}],"version-history":[{"count":6,"href":"https:\/\/www.kitforward.co.th\/en_US\/wp-json\/wp\/v2\/pages\/409\/revisions"}],"predecessor-version":[{"id":415,"href":"https:\/\/www.kitforward.co.th\/en_US\/wp-json\/wp\/v2\/pages\/409\/revisions\/415"}],"wp:attachment":[{"href":"https:\/\/www.kitforward.co.th\/en_US\/wp-json\/wp\/v2\/media?parent=409"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}