{"id":1471,"date":"2026-04-14T02:57:44","date_gmt":"2026-04-14T02:57:44","guid":{"rendered":"https:\/\/envautomation.com\/?page_id=1471"},"modified":"2026-06-30T12:12:05","modified_gmt":"2026-06-30T12:12:05","slug":"wbgt-temperature-record","status":"publish","type":"page","link":"https:\/\/envautomation.com\/?page_id=1471","title":{"rendered":"WBGT -Temperature  Record"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"1471\" class=\"elementor elementor-1471\">\n\t\t\t\t<div class=\"elementor-element elementor-element-50d848b e-flex e-con-boxed e-con e-parent\" data-id=\"50d848b\" data-element_type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-220ccce elementor-widget elementor-widget-html\" data-id=\"220ccce\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!-- \u2705 WBGT 5-MINUTE READING PAGE - FULL CORRECTED WORKING CODE -->\r\n<link rel=\"stylesheet\" href=\"https:\/\/fonts.googleapis.com\/css2?family=Poppins:wght@300;400;500;600;700;800;900&display=swap\"\/>\r\n\r\n<style>\r\n:root{\r\n  --blue:#1573e6;\r\n  --cyan:#38bdf8;\r\n  --navy:#0b2a5a;\r\n  --line:#dbe7f3;\r\n  --text:#102033;\r\n  --muted:#64748b;\r\n  --shadow:0 18px 45px rgba(15,45,85,.13);\r\n  --soft:0 8px 24px rgba(15,45,85,.08);\r\n}\r\n\r\nbody{\r\n  font-family:Poppins,Arial,Helvetica,sans-serif;\r\n  margin:0;\r\n  background:#fff;\r\n  color:var(--text);\r\n}\r\n\r\n.premium-wbgt-page{\r\n  position:relative;\r\n  overflow:hidden;\r\n  min-height:100vh;\r\n  padding:26px 14px 42px;\r\n  background:\r\n    radial-gradient(circle at 18% 10%, rgba(56,189,248,.22), transparent 32%),\r\n    radial-gradient(circle at 82% 12%, rgba(21,115,230,.17), transparent 34%),\r\n    linear-gradient(180deg,#f7fbff 0%,#eef5ff 44%,#ffffff 100%);\r\n}\r\n\r\n.premium-wbgt-page *{\r\n  box-sizing:border-box;\r\n}\r\n\r\n.premium-shell{\r\n  position:relative;\r\n  max-width:1180px;\r\n  width:100%;\r\n  margin:0 auto;\r\n}\r\n\r\n.hero-card{\r\n  position:relative;\r\n  overflow:hidden;\r\n  border:1px solid rgba(255,255,255,.75);\r\n  border-radius:28px;\r\n  background:linear-gradient(135deg,rgba(255,255,255,.92),rgba(241,247,255,.82));\r\n  box-shadow:var(--shadow);\r\n  padding:22px;\r\n  margin-bottom:18px;\r\n  backdrop-filter:blur(16px);\r\n}\r\n\r\n.hero-inner{\r\n  display:grid;\r\n  grid-template-columns:1fr auto;\r\n  gap:18px;\r\n  align-items:center;\r\n}\r\n\r\n.brand-row{\r\n  display:flex;\r\n  gap:14px;\r\n  align-items:center;\r\n}\r\n\r\n.brand-icon{\r\n  width:58px;\r\n  height:58px;\r\n  border-radius:18px;\r\n  display:grid;\r\n  place-items:center;\r\n  color:#fff;\r\n  font-weight:900;\r\n  font-size:20px;\r\n  background:linear-gradient(135deg,var(--blue),var(--cyan));\r\n  box-shadow:0 16px 32px rgba(21,115,230,.28);\r\n  flex:0 0 auto;\r\n}\r\n\r\n.hero-title{\r\n  margin:0;\r\n  font-size:30px;\r\n  line-height:1.08;\r\n  font-weight:900;\r\n  color:var(--navy);\r\n}\r\n\r\n.hero-sub{\r\n  margin:7px 0 0;\r\n  color:var(--muted);\r\n  font-weight:700;\r\n  font-size:13px;\r\n}\r\n\r\n.live-pill{\r\n  display:inline-flex;\r\n  align-items:center;\r\n  gap:9px;\r\n  padding:10px 14px;\r\n  border-radius:999px;\r\n  background:rgba(255,255,255,.9);\r\n  border:1px solid var(--line);\r\n  box-shadow:var(--soft);\r\n  font-size:12px;\r\n  font-weight:900;\r\n  color:#30506c;\r\n  white-space:nowrap;\r\n}\r\n\r\n.live-dot{\r\n  width:9px;\r\n  height:9px;\r\n  border-radius:50%;\r\n  background:#22c55e;\r\n  box-shadow:0 0 0 7px rgba(34,197,94,.13);\r\n}\r\n\r\n.filter-card{\r\n  display:grid;\r\n  grid-template-columns:1fr 1fr auto auto;\r\n  gap:12px;\r\n  align-items:end;\r\n  border-radius:22px;\r\n  background:rgba(255,255,255,.88);\r\n  border:1px solid rgba(218,231,244,.9);\r\n  box-shadow:var(--soft);\r\n  padding:16px;\r\n  margin-top:18px;\r\n  width:100%;\r\n}\r\n\r\n.field{\r\n  display:flex;\r\n  flex-direction:column;\r\n  gap:7px;\r\n  min-width:0;\r\n  width:100%;\r\n}\r\n\r\n.label{\r\n  font-size:12px;\r\n  color:#244058;\r\n  font-weight:900;\r\n}\r\n\r\n.input{\r\n  height:44px;\r\n  padding:0 13px;\r\n  border:1px solid #cfdceb;\r\n  border-radius:12px;\r\n  background:#fff;\r\n  font-size:13px;\r\n  font-family:Poppins,Arial,sans-serif;\r\n  color:var(--text);\r\n  outline:none;\r\n  width:100%;\r\n}\r\n\r\n.btn{\r\n  height:44px;\r\n  padding:0 18px;\r\n  border:0;\r\n  border-radius:12px;\r\n  font-size:13px;\r\n  font-weight:900;\r\n  font-family:Poppins,Arial,sans-serif;\r\n  cursor:pointer;\r\n  white-space:nowrap;\r\n}\r\n\r\n.btn-search{\r\n  color:#fff;\r\n  background:linear-gradient(135deg,var(--blue),var(--cyan));\r\n  box-shadow:0 12px 26px rgba(21,115,230,.22);\r\n}\r\n\r\n.btn-download{\r\n  color:var(--blue);\r\n  background:#fff;\r\n  border:2px solid var(--blue);\r\n}\r\n\r\n.status-grid{\r\n  display:grid;\r\n  grid-template-columns:repeat(3,1fr);\r\n  gap:12px;\r\n  margin:18px 0;\r\n}\r\n\r\n.status-box{\r\n  border-radius:18px;\r\n  padding:15px 16px;\r\n  color:#fff;\r\n  box-shadow:var(--soft);\r\n}\r\n\r\n.status-box h3{\r\n  margin:0;\r\n  font-size:14px;\r\n  line-height:1.2;\r\n  font-weight:900;\r\n}\r\n\r\n.status-box p{\r\n  margin:5px 0 0;\r\n  font-size:12px;\r\n  font-weight:800;\r\n  opacity:.95;\r\n}\r\n\r\n.low{\r\n  background:linear-gradient(135deg,#16a34a,#64c955);\r\n}\r\n\r\n.mid{\r\n  background:linear-gradient(135deg,#f59e0b,#facc15);\r\n  color:#2c2200;\r\n}\r\n\r\n.high{\r\n  background:linear-gradient(135deg,#dc2626,#fb5b4c);\r\n}\r\n\r\n.chart-card{\r\n  display:block;\r\n  border-radius:26px;\r\n  background:rgba(255,255,255,.93);\r\n  border:1px solid rgba(218,231,244,.95);\r\n  box-shadow:var(--shadow);\r\n  padding:18px;\r\n  margin-bottom:18px;\r\n}\r\n\r\n.chart-head{\r\n  display:flex;\r\n  justify-content:space-between;\r\n  align-items:flex-start;\r\n  gap:12px;\r\n  flex-wrap:wrap;\r\n  margin-bottom:8px;\r\n}\r\n\r\n.chart-title{\r\n  margin:0;\r\n  font-size:20px;\r\n  color:var(--navy);\r\n  font-weight:900;\r\n}\r\n\r\n.chart-sub{\r\n  margin:4px 0 0;\r\n  font-size:12px;\r\n  color:var(--muted);\r\n  font-weight:700;\r\n}\r\n\r\n.chart-badge{\r\n  display:inline-flex;\r\n  align-items:center;\r\n  gap:8px;\r\n  padding:9px 12px;\r\n  border-radius:999px;\r\n  background:#f2f7ff;\r\n  color:#1b4f8d;\r\n  border:1px solid #d8e8ff;\r\n  font-size:12px;\r\n  font-weight:900;\r\n}\r\n\r\n.chart-box{\r\n  height:290px;\r\n  position:relative;\r\n}\r\n\r\n#wbgtChart{\r\n  width:100% !important;\r\n  height:100% !important;\r\n  display:block;\r\n}\r\n\r\n.meta-line{\r\n  display:flex;\r\n  flex-wrap:wrap;\r\n  gap:10px;\r\n  align-items:center;\r\n  margin:10px 0 14px;\r\n}\r\n\r\n.kv{\r\n  display:inline-flex;\r\n  align-items:center;\r\n  gap:6px;\r\n  padding:9px 11px;\r\n  border-radius:999px;\r\n  background:#fff;\r\n  border:1px solid var(--line);\r\n  box-shadow:0 5px 14px rgba(15,45,85,.05);\r\n  color:var(--muted);\r\n  font-size:12px;\r\n  font-weight:800;\r\n}\r\n\r\n.kv b{\r\n  color:#102033;\r\n  font-weight:900;\r\n}\r\n\r\n.table-card{\r\n  background:#fff;\r\n  border:1px solid var(--line);\r\n  border-radius:22px;\r\n  box-shadow:var(--shadow);\r\n  overflow:hidden;\r\n}\r\n\r\n.table-titlebar{\r\n  padding:14px 16px;\r\n  background:linear-gradient(135deg,#0b2a5a,#154d9c);\r\n  color:#fff;\r\n  display:flex;\r\n  justify-content:space-between;\r\n  gap:10px;\r\n  align-items:center;\r\n  flex-wrap:wrap;\r\n}\r\n\r\n.table-titlebar h3{\r\n  margin:0;\r\n  font-size:15px;\r\n  font-weight:900;\r\n  color:#ffffff !important;\r\n}\r\n\r\n.table-titlebar span{\r\n  font-size:12px;\r\n  font-weight:700;\r\n  opacity:.95;\r\n  color:#ffffff !important;\r\n}\r\n\r\n.table-scroller{\r\n  overflow:auto;\r\n  max-height:72vh;\r\n}\r\n\r\ntable{\r\n  border-collapse:separate;\r\n  border-spacing:0;\r\n  width:max-content;\r\n  min-width:100%;\r\n}\r\n\r\nthead th{\r\n  position:sticky;\r\n  top:0;\r\n  background:#f8fafc;\r\n  border-bottom:1px solid #e8eef6;\r\n  padding:11px 8px;\r\n  font-size:12px;\r\n  text-align:center;\r\n  z-index:2;\r\n  color:#1c2f45;\r\n  font-weight:900;\r\n}\r\n\r\ntbody td,\r\ntbody th{\r\n  border-bottom:1px solid #edf2f7;\r\n  border-right:1px solid #edf2f7;\r\n  padding:8px 7px;\r\n  font-size:11px;\r\n  text-align:center;\r\n  color:#223951;\r\n  font-weight:700;\r\n}\r\n\r\ntbody tr:hover td,\r\ntbody tr:hover th{\r\n  background:#f4f9ff;\r\n}\r\n\r\ntbody th.date{\r\n  position:sticky;\r\n  left:0;\r\n  background:#f8fafc;\r\n  border-right:1px solid var(--line);\r\n  z-index:1;\r\n}\r\n\r\ntbody th.time{\r\n  position:sticky;\r\n  left:90px;\r\n  background:#f8fafc;\r\n  border-right:1px solid var(--line);\r\n  z-index:1;\r\n}\r\n\r\n.col-date{\r\n  width:90px;\r\n  min-width:90px;\r\n}\r\n\r\n.col-time{\r\n  width:76px;\r\n  min-width:76px;\r\n}\r\n\r\n.col-min{\r\n  width:54px;\r\n  min-width:54px;\r\n}\r\n\r\n.col-max{\r\n  width:135px;\r\n  min-width:135px;\r\n  font-weight:900;\r\n}\r\n\r\n.g{\r\n  background:#e9f7ee !important;\r\n  color:#0f7a35 !important;\r\n}\r\n\r\n.y{\r\n  background:#fff3cf !important;\r\n  color:#8a5a00 !important;\r\n}\r\n\r\n.r{\r\n  background:#ffe1e1 !important;\r\n  color:#a31616 !important;\r\n}\r\n\r\n.api-error{\r\n  margin:12px 0;\r\n  padding:12px 14px;\r\n  border-radius:14px;\r\n  background:#fff4d6;\r\n  border:1px solid #ffd36b;\r\n  color:#6b4300;\r\n  font-size:12px;\r\n  font-weight:800;\r\n  display:none;\r\n}\r\n\r\n.footer-note{\r\n  text-align:center;\r\n  margin-top:18px;\r\n  color:#718096;\r\n  font-size:12px;\r\n  font-weight:800;\r\n}\r\n\r\n@media(max-width:980px){\r\n  .hero-inner{\r\n    grid-template-columns:1fr;\r\n  }\r\n\r\n  .filter-card{\r\n    grid-template-columns:1fr 1fr;\r\n  }\r\n\r\n  .filter-card button{\r\n    width:100%;\r\n  }\r\n\r\n  .status-grid{\r\n    grid-template-columns:1fr;\r\n  }\r\n\r\n  .chart-box{\r\n    height:230px;\r\n  }\r\n}\r\n\r\n@media(max-width:640px){\r\n  .premium-wbgt-page{\r\n    padding:16px 10px 34px;\r\n  }\r\n\r\n  .hero-card{\r\n    padding:16px;\r\n    border-radius:22px;\r\n  }\r\n\r\n  .hero-title{\r\n    font-size:22px;\r\n  }\r\n\r\n  .filter-card{\r\n    grid-template-columns:1fr;\r\n  }\r\n\r\n  .btn{\r\n    width:100%;\r\n  }\r\n}\r\n<\/style>\r\n\r\n<div class=\"premium-wbgt-page\">\r\n  <div class=\"premium-shell\">\r\n\r\n    <div class=\"hero-card\">\r\n      <div class=\"hero-inner\">\r\n        <div class=\"brand-row\">\r\n          <div class=\"brand-icon\">EA<\/div>\r\n          <div>\r\n            <h2 class=\"hero-title\">KIMLY CONSTRUCTION PTE LTD<\/h2>\r\n            <p class=\"hero-sub\">PROJECT : KBGC3<\/p>\r\n          <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"live-pill\">\r\n          <span class=\"live-dot\"><\/span>\r\n          Live Temperature\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <form id=\"kbFilterForm\" class=\"filter-card\" autocomplete=\"off\">\r\n        <div class=\"field\">\r\n          <label class=\"label\" for=\"kbFromDate\">From Date<\/label>\r\n          <input id=\"kbFromDate\" class=\"input\" type=\"date\" required\/>\r\n        <\/div>\r\n\r\n        <div class=\"field\">\r\n          <label class=\"label\" for=\"kbToDate\">To Date<\/label>\r\n          <input id=\"kbToDate\" class=\"input\" type=\"date\" required\/>\r\n        <\/div>\r\n\r\n        <button type=\"submit\" class=\"btn btn-search\">Search<\/button>\r\n        <button type=\"button\" id=\"kbBtnDownload\" class=\"btn btn-download\">Download PDF<\/button>\r\n      <\/form>\r\n    <\/div>\r\n\r\n    <div class=\"status-grid\">\r\n      <div class=\"status-box low\">\r\n        <h3>LOW HEAT STRESS<\/h3>\r\n        <p>WBGT below 31\u00b0C<\/p>\r\n      <\/div>\r\n      <div class=\"status-box mid\">\r\n        <h3>MODERATE HEAT STRESS<\/h3>\r\n        <p>31\u00b0C to below 33\u00b0C<\/p>\r\n      <\/div>\r\n      <div class=\"status-box high\">\r\n        <h3>HIGH HEAT STRESS<\/h3>\r\n        <p>WBGT 33\u00b0C and above<\/p>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div id=\"kbApiError\" class=\"api-error\"><\/div>\r\n\r\n    <div id=\"kbChartSection\" class=\"chart-card\">\r\n      <div class=\"chart-head\">\r\n        <div>\r\n          <h3 class=\"chart-title\">WBGT Heat Stress Reading<\/h3>\r\n          <p class=\"chart-sub\">Daily maximum WBGT trend with threshold lines<\/p>\r\n        <\/div>\r\n        <div class=\"chart-badge\">\u25cf 5-Minute Data Table<\/div>\r\n      <\/div>\r\n      <div class=\"chart-box\">\r\n        <canvas id=\"wbgtChart\"><\/canvas>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div id=\"kbReportWrap\">\r\n      <div class=\"meta-line\">\r\n        <span class=\"kv\">Project: <b id=\"kbMetaProj\">\u2014<\/b><\/span>\r\n        <span class=\"kv\">Label: <b id=\"kbMetaLabel\">WBGT-Heat Stress<\/b><\/span>\r\n        <span class=\"kv\">Metric: <b id=\"kbMetaMetric\">WBGT (\u00b0C)<\/b><\/span>\r\n        <span class=\"kv\">Range: <b id=\"kbMetaRange\">\u2014<\/b><\/span>\r\n        <span class=\"kv\">Records: <b id=\"kbMetaCount\">0<\/b><\/span>\r\n        <span class=\"kv\">Days: <b id=\"kbMetaDays\">0<\/b><\/span>\r\n        <span class=\"kv\">Last updated: <b id=\"kbMetaUpdated\">\u2014<\/b><\/span>\r\n      <\/div>\r\n\r\n      <div class=\"table-card\" id=\"kbPdfBlock\">\r\n        <div class=\"table-titlebar\">\r\n          <h3>WBGT 5-Minute Reading Table<\/h3>\r\n          <span>Auto colour based on heat stress level<\/span>\r\n        <\/div>\r\n\r\n        <div class=\"table-scroller\">\r\n          <table id=\"kbWbgtTable\"><\/table>\r\n        <\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"footer-note\">\r\n      Copyright \u00a9 2026 | ENV AUTOMATION PTE LTD\r\n    <\/div>\r\n\r\n  <\/div>\r\n<\/div>\r\n\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/chart.js@4.4.1\/dist\/chart.umd.min.js\"><\/script>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/html2canvas@1.4.1\/dist\/html2canvas.min.js\"><\/script>\r\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/jspdf@2.5.1\/dist\/jspdf.umd.min.js\"><\/script>\r\n\r\n<script>\r\n(function(){\r\n  \"use strict\";\r\n\r\n  var PROJECT_NAME = \"KIMLY KBGC3\";\r\n  var FIXED_LABEL  = \"WBGT-Heat Stress\";\r\n  var SENSOR_ID    = 1;\r\n\r\n  var API_BASE = \"https:\/\/cctv.envautomation.com\/dtu_ingest\/wbgt_kbgc3\/wbgt1_daily.php\";\r\n  var chartInstance = null;\r\n  var isLoading = false;\r\n\r\n  function el(id){ return document.getElementById(id); }\r\n  function pad(n){ return String(n).padStart(2, \"0\"); }\r\n\r\n  function ymdLocal(d){\r\n    return d.getFullYear() + \"-\" + pad(d.getMonth() + 1) + \"-\" + pad(d.getDate());\r\n  }\r\n\r\n  function todayLocal(){\r\n    var d = new Date();\r\n    return new Date(d.getFullYear(), d.getMonth(), d.getDate());\r\n  }\r\n\r\n  function addDays(d, n){\r\n    var x = new Date(d.getTime());\r\n    x.setDate(x.getDate() + n);\r\n    return x;\r\n  }\r\n\r\n  function labelFromYmd(ymd){\r\n    var p = ymd.split(\"-\");\r\n    return p[2] + \"\/\" + p[1] + \"\/\" + p[0];\r\n  }\r\n\r\n  function tableDateFromYmd(ymd){\r\n    var p = ymd.split(\"-\");\r\n    return p[2] + \"-\" + p[1] + \"-\" + p[0];\r\n  }\r\n\r\n  function toNumberOrNull(v){\r\n    if(v === null || typeof v === \"undefined\" || v === \"\") return null;\r\n    var n = parseFloat(v);\r\n    return isNaN(n) ? null : n;\r\n  }\r\n\r\n  function bandClassByWBGT(v){\r\n    v = toNumberOrNull(v);\r\n    if(v === null) return \"\";\r\n    if(v < 31) return \"g\";\r\n    if(v < 33) return \"y\";\r\n    return \"r\";\r\n  }\r\n\r\n  function emptyGrid(){\r\n    var map = {};\r\n    for(var h = 0; h < 24; h++){\r\n      for(var m = 0; m <= 55; m += 5){\r\n        map[pad(h) + \":\" + pad(m)] = null;\r\n      }\r\n    }\r\n    return map;\r\n  }\r\n\r\n  function showApiError(msg){\r\n    var box = el(\"kbApiError\");\r\n    if(!box) return;\r\n\r\n    if(msg){\r\n      box.style.display = \"block\";\r\n      box.textContent = msg;\r\n    }else{\r\n      box.style.display = \"none\";\r\n      box.textContent = \"\";\r\n    }\r\n  }\r\n\r\n  function dailyMaxFromGrid(grid){\r\n    var maxVal = null;\r\n\r\n    Object.keys(grid).forEach(function(k){\r\n      var v = toNumberOrNull(grid[k]);\r\n      if(v !== null){\r\n        if(maxVal === null || v > maxVal){\r\n          maxVal = v;\r\n        }\r\n      }\r\n    });\r\n\r\n    return maxVal;\r\n  }\r\n\r\n  function nearestFiveMinuteKey(timeText){\r\n    var match = String(timeText).match(\/(\\d{1,2}):(\\d{2})(?::(\\d{2}))?\/);\r\n    if(!match) return null;\r\n\r\n    var hh = parseInt(match[1], 10);\r\n    var mm = parseInt(match[2], 10);\r\n\r\n    if(isNaN(hh) || isNaN(mm)) return null;\r\n\r\n    var bucketMin = Math.round(mm \/ 5) * 5;\r\n\r\n    if(bucketMin === 60){\r\n      hh++;\r\n      bucketMin = 0;\r\n\r\n      if(hh >= 24){\r\n        hh = 23;\r\n        bucketMin = 55;\r\n      }\r\n    }\r\n\r\n    return pad(hh) + \":\" + pad(bucketMin);\r\n  }\r\n\r\n  function getBucketKey(r){\r\n    if(r.bucket_time){\r\n      return String(r.bucket_time).substring(0,5);\r\n    }\r\n\r\n    if(r.time){\r\n      return nearestFiveMinuteKey(r.time);\r\n    }\r\n\r\n    if(r.recorded_at){\r\n      return nearestFiveMinuteKey(r.recorded_at);\r\n    }\r\n\r\n    return null;\r\n  }\r\n\r\n  function normalizeDaily(json){\r\n    var grid = emptyGrid();\r\n    var latest = \"\u2014\";\r\n    var slotLatestTime = {};\r\n\r\n    if(!json || !(json.ok === true || json.ok === \"true\")){\r\n      return {\r\n        grid:grid,\r\n        count:0,\r\n        latest:latest,\r\n        max:null\r\n      };\r\n    }\r\n\r\n    var rows = [];\r\n\r\n    if(Array.isArray(json.readings)){\r\n      rows = json.readings;\r\n    }else if(Array.isArray(json.records)){\r\n      rows = json.records;\r\n    }else if(Array.isArray(json.data)){\r\n      rows = json.data;\r\n    }\r\n\r\n    rows.forEach(function(r){\r\n      if(!r) return;\r\n\r\n      var wbgt = toNumberOrNull(r.wbgt);\r\n      if(wbgt === null) return;\r\n\r\n      var key = getBucketKey(r);\r\n      if(!key) return;\r\n      if(!Object.prototype.hasOwnProperty.call(grid, key)) return;\r\n\r\n      var timeText = r.recorded_at || r.time || key;\r\n\r\n      if(!slotLatestTime[key] || String(timeText) >= String(slotLatestTime[key])){\r\n        grid[key] = wbgt;\r\n        slotLatestTime[key] = timeText;\r\n      }\r\n\r\n      latest = r.recorded_at || r.time || latest;\r\n    });\r\n\r\n    var total = Object.keys(grid).filter(function(k){\r\n      return grid[k] !== null;\r\n    }).length;\r\n\r\n    return {\r\n      grid:grid,\r\n      count:total,\r\n      latest:json.latest_recorded_at || latest,\r\n      max:dailyMaxFromGrid(grid)\r\n    };\r\n  }\r\n\r\n  function loadJsonp(dateStr, cb){\r\n    var callbackName = \"wbgtJsonp_\" + Date.now() + \"_\" + Math.floor(Math.random() * 100000);\r\n\r\n    window[callbackName] = function(json){\r\n      try{\r\n        cb(null, json);\r\n      }finally{\r\n        delete window[callbackName];\r\n        if(script && script.parentNode){\r\n          script.parentNode.removeChild(script);\r\n        }\r\n      }\r\n    };\r\n\r\n    var script = document.createElement(\"script\");\r\n\r\n    script.onerror = function(){\r\n      delete window[callbackName];\r\n\r\n      if(script && script.parentNode){\r\n        script.parentNode.removeChild(script);\r\n      }\r\n\r\n      cb(new Error(\"JSONP load failed\"), null);\r\n    };\r\n\r\n    script.src =\r\n      API_BASE +\r\n      \"?sensor_id=\" + encodeURIComponent(SENSOR_ID) +\r\n      \"&date=\" + encodeURIComponent(dateStr) +\r\n      \"&callback=\" + encodeURIComponent(callbackName) +\r\n      \"&nocache=\" + Date.now();\r\n\r\n    document.head.appendChild(script);\r\n  }\r\n\r\n  function renderWBGTTable(daysData){\r\n    var table = el(\"kbWbgtTable\");\r\n    if(!table) return;\r\n\r\n    var html = \"\";\r\n\r\n    html += \"<thead>\";\r\n    html += \"<tr>\";\r\n    html += \"<th class='col-date'>Date<\/th>\";\r\n    html += \"<th class='col-time'>Time<\/th>\";\r\n\r\n    for(var m = 0; m <= 55; m += 5){\r\n      html += \"<th class='col-min'>\" + pad(m) + \"<\/th>\";\r\n    }\r\n\r\n    html += \"<th class='col-max'>WBGT (Max) \u00b0C<\/th>\";\r\n    html += \"<\/tr>\";\r\n    html += \"<\/thead>\";\r\n\r\n    html += \"<tbody>\";\r\n\r\n    daysData.forEach(function(day){\r\n      var dateLabel = tableDateFromYmd(day.date);\r\n      var grid = day.grid || emptyGrid();\r\n\r\n      for(var h = 0; h < 24; h++){\r\n        var maxVal = null;\r\n\r\n        html += \"<tr>\";\r\n        html += \"<th class='date col-date'>\" + dateLabel + \"<\/th>\";\r\n        html += \"<th class='time col-time'>\" + pad(h) + \":00<\/th>\";\r\n\r\n        for(var m = 0; m <= 55; m += 5){\r\n          var key = pad(h) + \":\" + pad(m);\r\n          var val = toNumberOrNull(grid[key]);\r\n\r\n          if(val !== null){\r\n            if(maxVal === null || val > maxVal){\r\n              maxVal = val;\r\n            }\r\n          }\r\n\r\n          var cls = bandClassByWBGT(val);\r\n          html += \"<td class='col-min \" + cls + \"'>\" + (val === null ? \"\u2014\" : val.toFixed(1)) + \"<\/td>\";\r\n        }\r\n\r\n        var maxCls = bandClassByWBGT(maxVal);\r\n        html += \"<td class='col-max \" + maxCls + \"'>\" + (maxVal === null ? \"\u2014\" : maxVal.toFixed(1)) + \"<\/td>\";\r\n        html += \"<\/tr>\";\r\n      }\r\n    });\r\n\r\n    html += \"<\/tbody>\";\r\n    table.innerHTML = html;\r\n  }\r\n\r\n  function renderChart(labels, values){\r\n    var canvas = el(\"wbgtChart\");\r\n    if(!canvas || typeof Chart === \"undefined\") return;\r\n\r\n    var ctx = canvas.getContext(\"2d\");\r\n\r\n    if(chartInstance){\r\n      chartInstance.destroy();\r\n    }\r\n\r\n    chartInstance = new Chart(ctx, {\r\n      type:\"line\",\r\n      data:{\r\n        labels:labels,\r\n        datasets:[\r\n          {\r\n            label:\"WBGT (\u00b0C)\",\r\n            data:values,\r\n            borderColor:\"#0f172a\",\r\n            backgroundColor:\"#0f172a\",\r\n            pointRadius:5,\r\n            pointHoverRadius:7,\r\n            borderWidth:3,\r\n            tension:0.35,\r\n            spanGaps:true\r\n          },\r\n          {\r\n            label:\"31\u00b0C Green Line\",\r\n            data:labels.map(function(){ return 31; }),\r\n            borderColor:\"#16a34a\",\r\n            borderDash:[6,6],\r\n            borderWidth:2,\r\n            pointRadius:0\r\n          },\r\n          {\r\n            label:\"33\u00b0C Red Line\",\r\n            data:labels.map(function(){ return 33; }),\r\n            borderColor:\"#dc2626\",\r\n            borderDash:[6,6],\r\n            borderWidth:2,\r\n            pointRadius:0\r\n          }\r\n        ]\r\n      },\r\n      options:{\r\n        responsive:true,\r\n        maintainAspectRatio:false,\r\n        plugins:{\r\n          legend:{display:true, position:\"top\"}\r\n        },\r\n        scales:{\r\n          y:{\r\n            min:20,\r\n            max:40,\r\n            ticks:{stepSize:1},\r\n            title:{display:true, text:\"WBGT (\u00b0C)\"}\r\n          },\r\n          x:{\r\n            title:{display:true, text:\"Date\"}\r\n          }\r\n        }\r\n      }\r\n    });\r\n  }\r\n\r\n  function setText(id, value){\r\n    var a = el(id);\r\n    if(a) a.textContent = value;\r\n  }\r\n\r\n  function loadReport(){\r\n    if(isLoading) return;\r\n    isLoading = true;\r\n\r\n    var fromInput = el(\"kbFromDate\");\r\n    var toInput   = el(\"kbToDate\");\r\n\r\n    if(!fromInput || !toInput){\r\n      isLoading = false;\r\n      return;\r\n    }\r\n\r\n    var from = fromInput.value;\r\n    var to   = toInput.value;\r\n\r\n    if(!from || !to){\r\n      isLoading = false;\r\n      return;\r\n    }\r\n\r\n    if(from > to){\r\n      alert(\"From Date cannot be after To Date.\");\r\n      isLoading = false;\r\n      return;\r\n    }\r\n\r\n    showApiError(\"\");\r\n\r\n    setText(\"kbMetaProj\", PROJECT_NAME);\r\n    setText(\"kbMetaLabel\", FIXED_LABEL);\r\n    setText(\"kbMetaMetric\", \"WBGT (\u00b0C)\");\r\n    setText(\"kbMetaRange\", from + \" \u2192 \" + to);\r\n    setText(\"kbMetaCount\", \"Loading...\");\r\n    setText(\"kbMetaDays\", \"Loading...\");\r\n    setText(\"kbMetaUpdated\", \"Loading...\");\r\n\r\n    var start = new Date(from + \"T00:00:00\");\r\n    var end   = new Date(to + \"T00:00:00\");\r\n\r\n    var daysData = [];\r\n    var labels = [];\r\n    var chartValues = [];\r\n    var totalRecords = 0;\r\n    var latestTime = \"\u2014\";\r\n    var apiFailCount = 0;\r\n\r\n    function loadOneDay(d){\r\n      if(d > end){\r\n        renderWBGTTable(daysData);\r\n        renderChart(labels, chartValues);\r\n\r\n        setText(\"kbMetaCount\", String(totalRecords));\r\n        setText(\"kbMetaDays\", String(daysData.length));\r\n        setText(\"kbMetaUpdated\", latestTime);\r\n\r\n        if(apiFailCount > 0){\r\n          showApiError(\"Some daily API data failed to load. Please check wbgt1_daily.php JSONP callback.\");\r\n        }else if(totalRecords === 0){\r\n          showApiError(\"No readings found for selected date range.\");\r\n        }else{\r\n          showApiError(\"\");\r\n        }\r\n\r\n        isLoading = false;\r\n        return;\r\n      }\r\n\r\n      var ymd = ymdLocal(d);\r\n\r\n      loadJsonp(ymd, function(err, json){\r\n        if(err){\r\n          console.error(\"WBGT JSONP FAILED:\", err);\r\n          apiFailCount++;\r\n\r\n          daysData.push({\r\n            date:ymd,\r\n            grid:emptyGrid()\r\n          });\r\n\r\n          labels.push(labelFromYmd(ymd));\r\n          chartValues.push(null);\r\n\r\n          loadOneDay(addDays(d, 1));\r\n          return;\r\n        }\r\n\r\n        console.log(\"WBGT JSONP RESPONSE:\", json);\r\n\r\n        var normalized = normalizeDaily(json);\r\n\r\n        daysData.push({\r\n          date:ymd,\r\n          grid:normalized.grid\r\n        });\r\n\r\n        labels.push(labelFromYmd(ymd));\r\n        chartValues.push(normalized.max);\r\n\r\n        totalRecords += normalized.count;\r\n\r\n        if(normalized.latest !== \"\u2014\"){\r\n          latestTime = normalized.latest;\r\n        }\r\n\r\n        loadOneDay(addDays(d, 1));\r\n      });\r\n    }\r\n\r\n    loadOneDay(start);\r\n  }\r\n\r\n  function downloadPDF(){\r\n    var jsPDF = window.jspdf && window.jspdf.jsPDF;\r\n    if(!jsPDF){\r\n      alert(\"PDF library not loaded.\");\r\n      return;\r\n    }\r\n\r\n    var pdfBlock = el(\"kbPdfBlock\");\r\n    if(!pdfBlock) return;\r\n\r\n    html2canvas(pdfBlock, {\r\n      scale:1.5,\r\n      backgroundColor:\"#ffffff\",\r\n      useCORS:true\r\n    }).then(function(canvas){\r\n      var pdf = new jsPDF(\"l\", \"mm\", \"a4\");\r\n      var pageW = pdf.internal.pageSize.getWidth();\r\n      var pageH = pdf.internal.pageSize.getHeight();\r\n\r\n      var imgData = canvas.toDataURL(\"image\/png\");\r\n      var imgW = pageW - 20;\r\n      var imgH = canvas.height * imgW \/ canvas.width;\r\n\r\n      if(imgH > pageH - 20){\r\n        imgH = pageH - 20;\r\n      }\r\n\r\n      pdf.setFont(\"helvetica\", \"bold\");\r\n      pdf.setFontSize(14);\r\n      pdf.text(\"WBGT-HEAT STRESS RECORD - \" + PROJECT_NAME, 10, 10);\r\n\r\n      pdf.addImage(imgData, \"PNG\", 10, 18, imgW, imgH);\r\n      pdf.save(\"KIMLY_KBGC3_WBGT_5_MINUTE_REPORT.pdf\");\r\n    });\r\n  }\r\n\r\n  function initPage(){\r\n    var fromInput = el(\"kbFromDate\");\r\n    var toInput   = el(\"kbToDate\");\r\n    var form      = el(\"kbFilterForm\");\r\n    var btnPdf    = el(\"kbBtnDownload\");\r\n\r\n    if(!fromInput || !toInput || !form){\r\n      console.error(\"WBGT page input\/form not found\");\r\n      return;\r\n    }\r\n\r\n    var today = ymdLocal(todayLocal());\r\n\r\n    fromInput.value = today;\r\n    toInput.value   = today;\r\n\r\n    form.addEventListener(\"submit\", function(e){\r\n      e.preventDefault();\r\n      loadReport();\r\n    });\r\n\r\n    if(btnPdf){\r\n      btnPdf.addEventListener(\"click\", downloadPDF);\r\n    }\r\n\r\n    loadReport();\r\n\r\n    setInterval(loadReport, 5 * 60 * 1000);\r\n  }\r\n\r\n  if(document.readyState === \"loading\"){\r\n    document.addEventListener(\"DOMContentLoaded\", initPage);\r\n  }else{\r\n    initPage();\r\n  }\r\n\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>EA KIMLY CONSTRUCTION PTE LTD PROJECT : KBGC3 Live Temperature From Date To Date Search Download PDF LOW HEAT STRESS [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"","ast-site-content-layout":"full-width-container","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"disabled","ast-breadcrumbs-content":"","ast-featured-img":"disabled","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-1471","page","type-page","status-publish","hentry"],"brizy_media":[],"_links":{"self":[{"href":"https:\/\/envautomation.com\/index.php?rest_route=\/wp\/v2\/pages\/1471","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/envautomation.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/envautomation.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/envautomation.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/envautomation.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1471"}],"version-history":[{"count":5,"href":"https:\/\/envautomation.com\/index.php?rest_route=\/wp\/v2\/pages\/1471\/revisions"}],"predecessor-version":[{"id":2158,"href":"https:\/\/envautomation.com\/index.php?rest_route=\/wp\/v2\/pages\/1471\/revisions\/2158"}],"wp:attachment":[{"href":"https:\/\/envautomation.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1471"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}