> For the complete documentation index, see [llms.txt](https://navixy.com/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://navixy.com/docs/analytics/id/example-queries/leasing.md).

# Leasing

Templat kueri SQL untuk analitik perbankan dan leasing, mencakup siklus hidup aset, kepatuhan kontrak, penjadwalan pemeliharaan, dan pelacakan batas penggunaan

{% hint style="warning" %}
Aktifkan **IoT Query** sebelum memanfaatkan data untuk membangun analitik komprehensif. Jika Anda belum memilikinya, hubungi kami untuk detail aktivasi - <iotquery@navixy.com>
{% endhint %}

Perusahaan leasing (terutama bank dan penyedia leasing armada) mempertahankan kepemilikan kendaraan atau peralatan sementara klien hanya menyewa penggunaannya, sehingga mereka menanggung risiko terkait aset sepanjang kontrak. 

Untuk melindungi nilai sisa, menegakkan batasan kontraktual (jarak tempuh, geografi, pemeliharaan), dan menyederhanakan kewajiban layanan penuh, mereka mengandalkan Navixy. Data GPS waktu nyata, diagnostik berbasis sensor, dan analitik perilaku memungkinkan mereka memverifikasi kondisi penggunaan, mengotomatiskan penjadwalan layanan, mendeteksi masalah mekanis sejak dini, menghitung penalti atau biaya kelebihan kilometer, dan, bila perlu, melumpuhkan atau mengambil kembali aset—yang semuanya mengamankan investasi mereka, mengurangi biaya operasional, dan meningkatkan transparansi pelanggan sepanjang seluruh siklus hidup sewa.

Navixy **IoT Query** akan membantu mengorganisasi berbagai jenis analitik pada setiap tahap kontrak leasing. Kontrak leasing melewati beberapa fase yang dapat diprediksi: Onboarding & Penyiapan aset → Fase operasional → Pengawasan risiko & kepatuhan

Resep SQL berikut dalam buku Anda secara kolektif memantau setiap tonggak kritis di sepanjang siklus hidup tersebut:

| Fase siklus hidup                  | Tujuan & tonggak                                                                                                                             | Kasus penggunaan / resep yang dicakup                                                                                                                                                                      |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Onboarding & penyiapan Aset        | • Daftarkan kendaraan, aktifkan Asuransi dan kredensial Supir. • Impor Aset ke portal klien dengan visibilitas yang tepat.                   | Aturan peringatan kedaluwarsa registrasi/asuransi – tanggal dasar dicatat. Kedaluwarsa lisensi Supir – memvalidasi Supir sebelum dilepas.                                                                  |
| Perencanaan pemeliharaan preventif | • Tetapkan jadwal servis berulang, berbasis Jarak tempuh, dan berbasis waktu. • Pastikan penggantian ban musiman.                            | Pemeriksaan rutin berdasarkan interval – Tugas berbasis kalender. Servis berdasarkan ambang Jarak tempuh – aturan servis ringan/berat berbasis km. Pemantauan Jam mesin – servis berbasis jam untuk mesin. |
| Batas penggunaan terikat kontrak   | • Tegakkan jatah Jarak tempuh dan batas finansial. • Deteksi penggunaan berlebih sejak awal untuk menghindari kejutan di akhir masa kontrak. | Batas Jarak tempuh & penalti – pengawasan kilometer total tahunan / total kontrak.                                                                                                                         |
| Perilaku Supir & Aset waktu nyata  | • Lindungi nilai Aset; bimbing Supir. • Deteksi penyalahgunaan yang membatalkan cakupan “full-service”.                                      | Pengereman keras. Akselerasi keras. Belokan/tikungan mendadak.                                                                                                                                             |
| Pengawasan risiko dan kepatuhan    | • Jaga aset tetap berada di dalam batas geografis dan kontraktual. • Pertahankan hak untuk menonaktifkan atau mengambil kembali.             | Keluar geofence (batas negara) – peringatan instan atas pelanggaran wilayah. Pengapian & deteksi idle – pemborosan bahan bakar / pelacakan penyalahgunaan.                                                 |

### Templat dasbor

Sementara resep SQL di bawah ini memberikan kontrol penuh atas analitik leasing, Anda dapat memulai lebih cepat dengan dasbor siap pakai yang memvisualisasikan metrik penting di seluruh siklus sewa. Templat ini menghilangkan kebutuhan untuk membuat kueri dan visualisasi dari nol. Impor, sesuaikan parameter, dan segera mulai memantau kepatuhan, risiko, dan perlindungan Aset.

Template ini mencakup alur kerja utama penyewaan: pelacakan pendaftaran dan kedaluwarsa Asuransi, pemantauan lisensi Supir, deteksi Pengemudian kasar dan akselerasi dengan klasifikasi tingkat keparahan, analisis waktu menganggur, dan pemantauan aktivitas perangkat.

<figure><img src="https://1696125515-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoFNFEIINiGFbhi3Px3dE%2Fuploads%2Fgit-blob-64ef38d2255e595e6b5ee405e94ff208302d8131%2Fimage%20(16).png?alt=media" alt=""><figcaption></figcaption></figure>

Impor konfigurasi ke [Studio Dasbor](https://marketplace.navixy.com/shop/dashboard-studio/), sesuaikan ambang batas untuk kontrak Anda (batas Jarak tempuh, tingkat keparahan perilaku, parameter deteksi diam), dan terapkan ruang kerja pemantauan yang lengkap. Ini cocok saat tim memerlukan dasbor operasional untuk kepatuhan harian dan pengawasan risiko tanpa menulis SQL.

**Prasyarat:**

* IoT Query diaktifkan di lingkungan Anda
* Dashboard Studio terinstal dan dapat diakses
* Setidaknya 72 jam data pelacakan
* Tabel skema standar terisi: `tracking_data_core`, `states`, `objects`, `Kendaraan`, `Karyawan`

**Konfigurasi setelah impor:**

Setelah mengimpor templat, sesuaikan templat tersebut dengan kontrak sewa dan ambang batas operasional spesifik Anda:

1. Tinjau rentang waktu default 72 jam dan sesuaikan jika ketersediaan data Anda berbeda.
2. Tetapkan ambang batas tingkat keparahan untuk peristiwa Mengemudi dalam parameter kueri (default: 60+ km/h/s untuk peringatan, 80+ km/h/s untuk Aturan peringatan kritis).
3. Konfigurasikan parameter deteksi idle (default: kecepatan di bawah 5 km/h, durasi minimum 5 menit).
4. Perbarui label zona Perimeter dalam kueri penyeberangan perbatasan jika memantau pembatasan wilayah.
5. Gunakan pemilih waktu global untuk menganalisis periode historis atau memfokuskan pada aktivitas terbaru.

**JSON templat:**

{% file src="/files/fcff24dc3c4aea7396b836aa46b76e150579321b" %}

{% code lineNumbers="true" expandable="true" %}

```json
{
  "id": null,
  "uid": "halo-dunia",
  "Tagar": [
    "contoh",
    "memulai"
  ],
  "waktu": {
    "ke": "sekarang",
    "dari": "sekarang-72h"
  },
  "tautan": [],
  "gaya": "gelap",
  "title": "Dasbor leasing",
  "panels": [
    {
      "id": 10,
      "type": "text",
      "title": "Deteksi pengapian & idle",
      "gridPos": {
        "h": 4,
        "w": 24,
        "x": 0,
        "y": 158
      },
      "opsi": {
        "mode": "markdown",
        "konten": " "
      },
      "x-Navixy": {
        "sql": {
          "pernyataan": ""
        },
        "set data": {
          "bentuk": "tabel",
          "kolom": {}
        }
      }
    },
    {
      "id": 11,
      "type": "diagram pai",
      "title": "Supir dengan tanggal kedaluwarsa terdekat",
      "gridPos": {
        "h": 12,
        "w": 12,
        "x": 12,
        "y": 0
      },
      "opsi": {
        "pieType": "donut"
      },
      "x-Navixy": {
        "sql": {
          "params": {},
          "statement": "SELECT \r\n    CASE \r\n        WHEN (DATE(e.driver_license_valid_till) - CURRENT_DATE)::INTEGER < 0 THEN 'Kadaluwarsa'\r\n        ELSE 'Lainnya'\r\n    END AS category,\r\n    COUNT(*) AS value\r\nFROM raw_business_data.employees e\r\nWHERE e.driver_license_valid_till IS NOT NULL\r\nGROUP BY category\r\nORDER BY category"
        },
        "verify": {
          "max_rows": 1000
        },
        "set data": {
          "shape": "pie",
          "columns": {
            "value": {
              "type": "integer"
            },
            "kategori": {
              "type": "string"
            }
          }
        }
      }
    },
    {
      "id": 12,
      "type": "diagram pai",
      "title": "Kendaraan dengan tanggal kedaluwarsa terdekat",
      "gridPos": {
        "h": 12,
        "w": 12,
        "x": 0,
        "y": 0
      },
      "opsi": {
        "pieType": "donut"
      },
      "x-Navixy": {
        "sql": {
          "params": {},
          "statement": "WITH expiry_data AS (\r\n    SELECT \r\n        CASE \r\n            WHEN v.free_insurance_valid_till_date IS NOT NULL\r\n                AND (v.liability_insurance_valid_till IS NULL \r\n                      OR v.free_insurance_valid_till_date <= v.liability_insurance_valid_till)\r\n                THEN v.free_insurance_valid_till_date\r\n            WHEN v.liability_insurance_valid_till IS NOT NULL\r\n                THEN v.liability_insurance_valid_till\r\n            ELSE NULL\r\n        END AS nearest_expiry_date\r\n    FROM raw_business_data.vehicles v\r\n),\r\ncategorized_data AS (\r\n    SELECT \r\n        CASE \r\n            WHEN (DATE(nearest_expiry_date) - CURRENT_DATE)::INTEGER < 0 THEN 'Kedaluwarsa'\r\n            WHEN (DATE(nearest_expiry_date) - CURRENT_DATE)::INTEGER >= 0 \r\n                  AND (DATE(nearest_expiry_date) - CURRENT_DATE)::INTEGER < 30 THEN 'Kedaluwarsa dalam 30 hari'\r\n            ELSE 'Lainnya'\r\n        END AS category\r\n    FROM expiry_data\r\n    WHERE nearest_expiry_date IS NOT NULL\r\n)\r\nSELECT \r\n    category,\r\n    COUNT(*) AS value\r\nFROM categorized_data\r\nGROUP BY category\r\nORDER BY \r\n    CASE category\r\n        WHEN 'Kedaluwarsa' THEN 1\r\n        WHEN 'Kedaluwarsa dalam 30 hari' THEN 2\r\n        WHEN 'Lainnya' THEN 3\r\n    END"
        },
        "verify": {
          "max_rows": 1000
        },
        "set data": {
          "shape": "pie",
          "columns": {
            "value": {
              "type": "integer"
            },
            "kategori": {
              "type": "string"
            }
          }
        }
      }
    },
    {
      "id": 13,
      "type": "barchart",
      "title": "Peristiwa Pengemudian kasar",
      "gridPos": {
        "h": 11,
        "w": 24,
        "x": 0,
        "y": 12
      },
      "opsi": {
        "textMode": "auto"
      },
      "x-Navixy": {
        "sql": {
          "params": {},
          "statement": "WITH spd AS (\r\n          SELECT\r\n            device_id,\r\n            device_time,\r\n            speed/100.0 AS kmh,\r\n            LAG(speed/100.0) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_kmh,\r\n            EXTRACT(EPOCH FROM (device_time - LAG(device_time) OVER (PARTITION BY device_id ORDER BY device_time))) AS dt_sec\r\n          FROM\r\n            raw_telematics_data.tracking_data_core\r\n          WHERE 1=1\r\n        ),\r\n        decels AS (\r\n          SELECT\r\n            device_id,\r\n            device_time,\r\n            (prev_kmh - kmh) / NULLIF(dt_sec, 0) AS decel_kmh_per_sec\r\n          FROM\r\n            spd\r\n          WHERE\r\n            prev_kmh IS NOT NULL\r\n        ),\r\n        events_with_severity AS (\r\n          SELECT \r\n            DATE(d.device_time) AS category,\r\n            CASE \r\n              WHEN d.decel_kmh_per_sec >= 80 THEN 'Kritis'\r\n              WHEN d.decel_kmh_per_sec >= 60 THEN 'Peringatan'\r\n              ELSE 'Normal'\r\n            END AS series\r\n          FROM decels d\r\n          WHERE d.decel_kmh_per_sec >= 60\r\n        )\r\n        SELECT \r\n          category,\r\n          COUNT(*) AS value,\r\n          series\r\n        FROM events_with_severity\r\n        GROUP BY category, series\r\n        ORDER BY series"
        },
        "verify": {
          "max_rows": 1000
        },
        "set data": {
          "shape": "category_value",
          "columns": {
            "value": {
              "type": "integer"
            },
            "series": {
              "type": "string"
            },
            "kategori": {
              "type": "date"
            }
          }
        },
        "visualisasi": {
          "sortOrder": "none",
          "colorPalette": "vibrant"
        }
      }
    },
    {
      "id": 14,
      "type": "barchart",
      "title": "Peristiwa Percepatan kasar",
      "gridPos": {
        "h": 17,
        "w": 24,
        "x": 0,
        "y": 41
      },
      "opsi": {
        "orientation": "vertical"
      },
      "x-Navixy": {
        "sql": {
          "params": {},
          "statement": "DENGAN spd AS (\r\n          PILIH\r\n            device_id,\r\n            device_time,\r\n            speed/100.0 AS kmh,\r\n            LAG(speed/100.0) OVER (PARTISI BY device_id URUTKAN device_time) AS prev_kmh,\r\n            EXTRACT(EPOCH FROM (device_time - LAG(device_time) OVER (PARTISI BY device_id URUTKAN device_time))) AS dt_sec\r\n          DARI\r\n            raw_telematics_data.tracking_data_core\r\n        ),\r\n        accels AS (\r\n          SELECT\r\n            device_id,\r\n            device_time,\r\n            (kmh - prev_kmh) / NULLIF(dt_sec, 0) AS accel_kmh_per_sec\r\n          DARI\r\n            spd\r\n          DI MANA\r\n            prev_kmh IS NOT NULL\r\n        ),\r\n        events_with_severity AS (\r\n          SELECT \r\n            DATE(a.device_time) AS category,\r\n            CASE \r\n              KETIKA a.accel_kmh_per_sec >= 80 MAKA 'Kritis'\r\n              KETIKA a.accel_kmh_per_sec >= 60 MAKA 'Peringatan'\r\n              LAIN 'Normal'\r\n            END AS series\r\n          DARI accels a\r\n          DI MANA a.accel_kmh_per_sec >= 60\r\n        )\r\n        PILIH \r\n          category,\r\n          COUNT(*) AS value,\r\n          series\r\n        DARI events_with_severity\r\n        GROUP BY category, series\r\n        ORDER BY series"
        },
        "verify": {
          "max_rows": 1000
        },
        "set data": {
          "shape": "category_value",
          "columns": {
            "value": {
              "type": "integer"
            },
            "series": {
              "type": "string"
            },
            "kategori": {
              "type": "date"
            }
          }
        },
        "visualisasi": {
          "colorPalette": "vibrant"
        }
      }
    },
    {
      "id": 15,
      "type": "barchart",
      "title": "Belokan mendadak / menikung",
      "gridPos": {
        "h": 13,
        "w": 24,
        "x": 0,
        "y": 23
      },
      "opsi": {
        "orientation": "vertical"
      },
      "x-Navixy": {
        "sql": {
          "params": {},
          "statement": "WITH pts AS (\r\n          SELECT\r\n            device_id,\r\n            device_time,\r\n            latitude/1e7::numeric AS lat,\r\n            longitude/1e7::numeric AS lon,\r\n            LAG(latitude/1e7::numeric) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_lat,\r\n            LAG(longitude/1e7::numeric) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_lon,\r\n            speed/100.0 AS kmh,\r\n            LAG(speed/100.0) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_kmh\r\n          FROM\r\n            raw_telematics_data.tracking_data_core\r\n        ),\r\n        bearing AS (\r\n          SELECT *,\r\n                 atan2(\r\n                   sin(radians(lon-prev_lon))*cos(radians(lat)),\r\n                   cos(radians(prev_lat))*sin(radians(lat)) -\r\n                   sin(radians(prev_lat))*cos(radians(lat))*cos(radians(lon-prev_lon))\r\n                 ) * 180/pi() AS heading_change\r\n          FROM pts\r\n          WHERE prev_lat IS NOT NULL AND prev_lon IS NOT NULL\r\n        ),\r\n        events_with_severity AS (\r\n          SELECT \r\n            DATE(b.device_time) AS category,\r\n            CASE \r\n              WHEN ABS(b.heading_change) >= 50 AND b.kmh >= 30 THEN 'Kritis'\r\n              WHEN ABS(b.heading_change) >= 30 AND b.kmh >= 30 THEN 'Peringatan'\r\n              ELSE 'Normal'\r\n            END AS series\r\n          FROM bearing b\r\n        )\r\n        SELECT \r\n          category,\r\n          COUNT(*) AS value,\r\n          series\r\n        FROM events_with_severity\r\n        GROUP BY category, series\r\n        ORDER BY category, series"
        },
        "verify": {
          "max_rows": 1000
        },
        "set data": {
          "shape": "category_value",
          "columns": {
            "value": {
              "type": "integer"
            },
            "series": {
              "type": "string"
            },
            "kategori": {
              "type": "date"
            }
          }
        },
        "visualisasi": {
          "penumpukan": "persen",
          "colorPalette": "classic"
        }
      }
    },
    {
      "id": 16,
      "type": "stat",
      "title": "Total kejadian idle",
      "gridPos": {
        "h": 5,
        "w": 8,
        "x": 0,
        "y": 36
      },
      "opsi": {
        "textMode": "auto"
      },
      "x-Navixy": {
        "sql": {
          "params": {},
          "statement": "WITH ign AS (\r\n          SELECT device_id,\r\n                 device_time,\r\n                 value::int AS ign_on\r\n          FROM raw_telematics_data.states\r\n          WHERE state_name = 'Pengapian'\r\n        ),\r\n        spd AS (\r\n          SELECT device_id, device_time, speed/100.0 AS kmh\r\n          FROM raw_telematics_data.tracking_data_core\r\n        ),\r\n        merged AS (\r\n          SELECT i.device_id,\r\n                 i.device_time,\r\n                 i.ign_on,\r\n                 s.kmh,\r\n                 LEAD(i.device_time) OVER (PARTITION BY i.device_id ORDER BY i.device_time) AS next_time\r\n          FROM ign i\r\n          LEFT JOIN spd s ON s.device_id = i.device_id AND s.device_time = i.device_time\r\n        )\r\n        SELECT COUNT(*) AS value\r\n        FROM merged m\r\n        WHERE m.ign_on = 1 \r\n          AND (m.kmh IS NULL OR m.kmh < 5) \r\n          AND m.next_time IS NOT NULL\r\n          AND EXTRACT(EPOCH FROM (m.next_time - m.device_time))/60 >= 5"
        },
        "verify": {
          "max_rows": 1000
        },
        "set data": {
          "shape": "kpi",
          "kolom": {}
        }
      }
    },
    {
      "id": 9,
      "type": "timeseries",
      "title": "Pesan dari Waktu ke Waktu",
      "gridPos": {
        "h": 13,
        "w": 24,
        "x": 0,
        "y": 83
      },
      "opsi": {
        "legenda": {
          "calcs": [],
          "placement": "bawah",
          "showLegend": true,
          "displayMode": "list"
        },
        "tooltip": {
          "mode": "single",
          "sort": "none"
        }
      },
      "targets": [],
      "x-Navixy": {
        "sql": {
          "params": {},
          "statement": "WITH bounds AS (\nSELECT date_trunc('hour', NOW() - INTERVAL '24 hours') AS start_ts, date_trunc('hour', NOW()) AS end_ts ), hours AS (\nSELECT generate_series( (\nSELECT start_ts\nFROM bounds), (\nSELECT end_ts\nFROM bounds), INTERVAL '1 hour' ) AS bucket ), counts AS (\nSELECT date_trunc('hour', t.device_time) AS bucket, COUNT(*) AS Pesan, COUNT(DISTINCT t.device_id) AS unique_devices\nFROM raw_telematics_data.tracking_data_core t --\n    JOIN raw_business_data.objects o\n  ON o.device_id = t.device_id --\n  AND o.client_id = 398286 -- batalkan komentar & atur jika Anda menginginkan klien tertentu\nWHERE t.device_time >= (\nSELECT start_ts\nFROM bounds)\n  AND t.device_time < (\nSELECT end_ts\nFROM bounds) + INTERVAL '1 hour'\nGROUP BY 1 )\nSELECT h.bucket AS time, COALESCE(c.Pesan, 0) AS Pesan, COALESCE(c.unique_devices, 0) AS unique_devices\nFROM hours h LEFT\n    JOIN counts c USING (bucket)\nORDER BY time;"
        },
        "verify": {
          "max_rows": 1000
        },
        "set data": {
          "shape": "time_value",
          "kolom": {}
        },
        "visualisasi": {
          "lineStyle": "solid",
          "colorPalette": "modern",
          "interpolation": "halus",
          "legendPosition": "atas"
        }
      },
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "unit": "singkat",
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "stacking": {
              "mode": "none",
              "kelompok": "A"
            },
            "drawStyle": "line",
            "lineWidth": 1,
            "spanNulls": false,
            "showPoints": "auto",
            "fillOpacity": 10,
            "gradientMode": "none",
            "axisPlacement": "auto",
            "lineInterpolation": "linear"
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      }
    },
    {
      "id": 1,
      "type": "kpi",
      "title": "Jumlah sampel",
      "gridPos": {
        "h": 5,
        "w": 6,
        "x": 18,
        "y": 128
      },
      "opsi": {
        "textMode": "auto",
        "colorMode": "value",
        "graphMode": "none",
        "justifyMode": "auto",
        "orientation": "auto"
      },
      "targets": [],
      "x-Navixy": {
        "sql": {
          "params": {
            "tenant_id": {
              "type": "uuid"
            }
          },
          "statement": "SELECT *\nFROM raw_telematics_data.tracking_data_core LIMIT 10;"
        },
        "verify": {
          "max_rows": 1
        },
        "set data": {
          "shape": "kpi",
          "columns": {
            "value": {
              "type": "number"
            }
          }
        }
      },
      "datasource": null,
      "description": "",
      "fieldConfig": {
        "defaults": {
          "unit": "singkat",
          "color": {
            "mode": "thresholds"
          },
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      }
    },
    {
      "id": 2,
      "type": "barchart",
      "title": "Contoh data berdasarkan kategori",
      "gridPos": {
        "h": 15,
        "w": 18,
        "x": 0,
        "y": 130
      },
      "opsi": {
        "valueMode": "warna",
        "displayMode": "gradient",
        "orientation": "horizontal",
        "showUnfilled": true
      },
      "targets": [],
      "x-Navixy": {
        "sql": {
          "params": {},
          "statement": "SELECT o.object_label, COUNT(*) AS msgs_24h\nFROM raw_telematics_data.tracking_data_core AS t\n    JOIN raw_business_data.objects AS o\n  ON o.device_id = t.device_id\nWHERE t.device_time >= NOW() - INTERVAL '24 hours'\nGROUP BY o.client_id, o.object_label, t.device_id\nORDER BY msgs_24h DESC LIMIT 20;"
        },
        "verify": {
          "max_rows": 10
        },
        "set data": {
          "shape": "category_value",
          "kolom": {}
        },
        "visualisasi": {
          "orientation": "vertical"
        }
      },
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "unit": "singkat",
          "color": {
            "mode": "palette-classic"
          },
          "custom": {
            "hideFrom": {
              "viz": false,
              "legend": false,
              "tooltip": false
            }
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      }
    },
    {
      "id": 3,
      "type": "table",
      "title": "Pesan per hari",
      "gridPos": {
        "h": 9,
        "w": 12,
        "x": 4,
        "y": 148
      },
      "opsi": {
        "sortBy": [],
        "showHeader": true
      },
      "targets": [],
      "x-Navixy": {
        "sql": {
          "params": {
            "__to": null,
            "__from": null
          },
          "statement": "SELECT TO_CHAR(date_trunc('day', t.device_time), 'Mon DD, YYYY') AS \"Tanggal\", \n       COUNT(*) AS \"Pesan\"\nFROM raw_telematics_data.tracking_data_core AS t\nWHERE t.device_time >= ${__from}\n  AND t.device_time < ${__to}\nGROUP BY 1\nORDER BY 1;"
        },
        "verify": {
          "max_rows": 10
        },
        "set data": {
          "bentuk": "tabel",
          "kolom": {}
        },
        "visualisasi": {
          "pageSize": 5
        }
      },
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "custom": {
            "align": "auto",
            "displayMode": "auto"
          },
          "mappings": [],
          "thresholds": {
            "mode": "absolute",
            "steps": [
              {
                "color": "green",
                "value": null
              }
            ]
          }
        },
        "overrides": []
      }
    },
    {
      "id": 6,
      "type": "kpi",
      "title": "Total waktu idle",
      "gridPos": {
        "h": 5,
        "w": 8,
        "x": 8,
        "y": 36
      },
      "opsi": {
        "textMode": "auto"
      },
      "x-Navixy": {
        "sql": {
          "params": {},
          "pernyataan": "WITH ign AS (\n    SELECT device_id,\n            device_time,\n            value::int AS ign_on\n    FROM raw_telematics_data.states\n    WHERE state_name = 'Pengapian'\n  ),\n  spd AS (\n    SELECT device_id, device_time, speed/100 AS kmh\n    FROM raw_telematics_data.tracking_data_core\n  ),\n  merged AS (\n    SELECT i.device_id,\n            i.device_time,\n            i.ign_on,\n            s.kmh,\n            LEAD(i.device_time) OVER (PARTITION BY i.device_id ORDER BY i.device_time) AS next_time\n    FROM ign i\n    LEFT JOIN spd s ON s.device_id = i.device_id AND s.device_time = i.device_time\n  )\n  SELECT round(COALESCE(SUM(EXTRACT(EPOCH FROM (m.next_time - m.device_time))/60), 0), 0) AS value\n  FROM merged m\n  WHERE m.ign_on = 1 \n    AND (m.kmh IS NULL OR m.kmh < 5) \n    AND m.next_time IS NOT NULL\n    AND EXTRACT(EPOCH FROM (m.next_time - m.device_time))/60 >= 5"
        },
        "verify": {
          "max_rows": 1000
        },
        "set data": {
          "shape": "kpi",
          "columns": {
            "value": {
              "type": "number"
            }
          }
        }
      }
    },
    {
      "id": 7,
      "type": "diagram pai",
      "title": "Perangkat aktif teratas dalam 24 jam terakhir",
      "gridPos": {
        "h": 9,
        "w": 12,
        "x": 0,
        "y": 121
      },
      "opsi": {
        "pieType": "donut"
      },
      "x-Navixy": {
        "sql": {
          "params": {},
          "statement": "SELECT o.object_label, COUNT(*) AS msgs_24h\nFROM raw_telematics_data.tracking_data_core AS t\n    JOIN raw_business_data.objects AS o\n  ON o.device_id = t.device_id\nWHERE t.device_time >= NOW() - INTERVAL '24 hours'\nGROUP BY o.client_id, o.object_label, t.device_id\nORDER BY msgs_24h DESC LIMIT 20;"
        },
        "verify": {
          "max_rows": 1000
        },
        "set data": {
          "shape": "pie",
          "kolom": {}
        }
      }
    },
    {
      "id": 8,
      "type": "table",
      "title": "Pergerakan kendaraan terbaru",
      "gridPos": {
        "h": 25,
        "w": 24,
        "x": 0,
        "y": 96
      },
      "opsi": {
        "showHeader": true
      },
      "x-Navixy": {
        "sql": {
          "params": {},
          "statement": "SELECT\n  to_char(t.device_time, 'YYYY-MM-DD HH24:MI:SS TZ') AS \"Stempel waktu\",\n  t.device_id                                       AS \"ID perangkat\",\n  t.speed                                           AS \"Kecepatan\",\n  round(t.latitude::numeric  / 10000000, 6)         AS \"Lintang (°)\",\n  round(t.longitude::numeric / 10000000, 6)         AS \"Bujur (°)\"\nFROM raw_telematics_data.tracking_data_core t\nWHERE t.device_time >= NOW() - INTERVAL '3 days'\n  AND t.speed > 0\nORDER BY t.device_time DESC;"
        },
        "verify": {
          "max_rows": 3
        },
        "set data": {
          "bentuk": "tabel",
          "columns": {
            "Kecepatan": {
              "type": "integer"
            },
            "ID perangkat": {
              "type": "integer"
            },
            "Stempel waktu": {
              "type": "string"
            },
            "Lintang (°)": {
              "type": "number"
            },
            "Bujur (°)": {
              "type": "number"
            }
          }
        },
        "visualisasi": {
          "pageSize": 25,
          "sortable": true,
          "showHeader": true,
          "showTotals": false,
          "rowHighlighting": "hover"
        }
      }
    },
    {
      "id": 19,
      "type": "stat",
      "title": "Durasi menganggur rata-rata",
      "gridPos": {
        "h": 5,
        "w": 8,
        "x": 16,
        "y": 36
      },
      "opsi": {
        "textMode": "auto"
      },
      "x-Navixy": {
        "sql": {
          "params": {},
          "statement": "WITH ign AS (\r\n          SELECT device_id,\r\n                 device_time,\r\n                 value::int AS ign_on\r\n          FROM raw_telematics_data.states\r\n          WHERE state_name = 'pengapian'\r\n        ),\r\n        spd AS (\r\n          SELECT device_id, device_time, speed/100.0 AS kmh\r\n          FROM raw_telematics_data.tracking_data_core\r\n        ),\r\n        merged AS (\r\n          SELECT i.device_id,\r\n                 i.device_time,\r\n                 i.ign_on,\r\n                 s.kmh,\r\n                 LEAD(i.device_time) OVER (PARTITION BY i.device_id ORDER BY i.device_time) AS next_time\r\n          FROM ign i\r\n          LEFT JOIN spd s ON s.device_id = i.device_id AND s.device_time = i.device_time\r\n        )\r\n        SELECT round(COALESCE(AVG(EXTRACT(EPOCH FROM (m.next_time - m.device_time))/60), 0),0) AS value\r\n        FROM merged m\r\n        WHERE m.ign_on = 1 \r\n          AND (m.kmh IS NULL OR m.kmh < 5) \r\n          AND m.next_time IS NOT NULL\r\n          AND EXTRACT(EPOCH FROM (m.next_time - m.device_time))/60 >= 5"
        },
        "verify": {
          "max_rows": 1000
        },
        "set data": {
          "shape": "kpi",
          "kolom": {}
        }
      }
    }
  ],
  "refresh": "30s",
  "version": 1,
  "editable": true,
  "timezone": "browser",
  "x-Navixy": {
    "execution": {
      "dialect": "postgresql",
      "endpoint": "/api/v1/sql/run",
      "max_rows": 1000,
      "read_only": true,
      "timeout_ms": 5000,
      "allowed_schemas": [
        "demo_data"
      ]
    },
    "parameters": {
      "bindings": {
        "to": "${__to}",
        "from": "${__from}",
        "tenant_id": "${var_tenant}"
      }
    },
    "schemaVersion": "1.0.0"
  },
  "templating": {
    "list": [
      {
        "name": "var_tenant",
        "type": "constant",
        "label": "Penyewa",
        "query": "demo-tenant-id",
        "current": {
          "text": "Penyewa demo",
          "value": "demo-tenant-id"
        },
        "options": [
          {
            "text": "Penyewa demo",
            "value": "demo-tenant-id",
            "selected": true
          }
        ]
      }
    ],
    "enable": true
  },
  "timepicker": {
    "now": true,
    "enable": true,
    "hidden": false,
    "collapse": false,
    "time_options": [
      "5m",
      "15m",
      "1h",
      "6h",
      "12h",
      "24h"
    ],
    "refresh_intervals": [
      "5s",
      "10s",
      "30s",
      "1m",
      "5m",
      "15m",
      "30m",
      "1 jam"
    ]
  },
  "annotations": {
    "list": [
      {
        "hide": true,
        "name": "Anotasi & Aturan peringatan",
        "type": "dashboard",
        "enable": true,
        "target": {
          "Tagar": [],
          "type": "dashboard",
          "limit": 100,
          "matchAny": false
        },
        "builtIn": 1,
        "iconColor": "rgba(0, 211, 255, 1)",
        "datasource": {
          "uid": "-- Dashboard --",
          "type": "dashboard"
        }
      }
    ]
  },
  "description": "Contoh dasbor sederhana untuk memulai",
  "graphTooltip": 1,
  "schemaVersion": 38
}
```

{% endcode %}

Untuk mempelajari lebih lanjut tentang aplikasi dasbor IoT Query, lihat [Studio Dasbor](/docs/analytics/id/dashboard-studio.md).

Untuk bantuan pengaturan, hubungi <iotquery@navixy.com>.

## **Pendaftaran / Aturan peringatan kedaluwarsa Asuransi**

Bank harus melacak kedaluwarsa registrasi dan Asuransi yang akan datang karena mereka bertanggung jawab atas inspeksi teknis, registrasi, dan Asuransi. Aturan peringatan yang tepat waktu mencegah denda dan waktu henti kendaraan.

{% code expandable="true" %}

```sql
SELECT 
    v.vehicle_id,
    v.vehicle_label,
    v.nomor registrasi,
    v.free_asuransi_valid_till_date,
    v. Asuransi tanggung jawab berlaku hingga
DARI raw_business_data.kendaraan v
WHERE v.free_insurance_valid_till_date BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '30 days'
    OR v.liability_insurance_valid_till BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '30 days';
```

{% endcode %}

## **Masa berlaku lisensi Supir**

Meskipun tidak selalu wajib, menawarkan layanan tambahan berupa aturan peringatan kedaluwarsa lisensi yang proaktif adalah nilai tambah. Peringatan dini memungkinkan klien memperbarui lisensi sebelum kedaluwarsa. Harap diperhatikan Anda

{% code expandable="true" %}

```sql
SELECT e.employee_id,
       e.first_name || ' ' || e.last_name AS nama_supir,
       e.nomor_lisensi_Supir,
       e.izin_mengemudi_berlaku_hingga
FROM raw_business_data.employees e
WHERE e.driver_license_valid_till BETWEEN CURRENT_DATE AND CURRENT_DATE + (30 * INTERVAL '1 day');
```

{% endcode %}

## Keluar geofence (Perbatasan negara) <a href="#geofence-exit-country-border" id="geofence-exit-country-border"></a>

Kontrak dapat membatasi gerakan kendaraan ke wilayah tertentu (misalnya, Serbia). Keluar dari zona tersebut harus segera memberi peringatan kepada bank agar dapat bertindak (misalnya, menghubungi klien, melumpuhkan Aset).

Kueri SQL ini dirancang untuk memantau dan mengidentifikasi kapan sebuah perangkat keluar dari zona geografis yang telah ditentukan sebelumnya berlabel "Geofence Depo Tallaght". Prosesnya dimulai dengan mengumpulkan dan mengurutkan titik-titik geografis yang mendefinisikan batas zona tersebut. Untuk memastikan batas tersebut membentuk poligon yang valid, titik pertama ditambahkan ke akhir daftar, sehingga bentuknya tertutup. Kumpulan titik yang tertutup ini kemudian digunakan untuk membuat poligon yang merepresentasikan zona geografis, yang dikonversi menjadi objek geografi untuk analisis spasial.

Query kemudian mengambil data pelacakan perangkat dalam rentang waktu yang ditentukan, mengonversi nilai lintang dan bujur mentah menjadi titik geografis. Query menghitung apakah setiap titik perangkat berada di dalam atau di luar zona yang telah ditentukan menggunakan fungsi ST\_Contains, yang memeriksa ketercakupan spasial. Parameter yang dihitung, pos, menunjukkan 'inside' jika titik berada di dalam zona dan 'outside' jika sebaliknya. Terakhir, query memfilter hasil ini untuk mendeteksi transisi saat perangkat bergerak dari dalam zona ke luar, menggunakan fungsi jendela untuk membandingkan posisi saat ini dengan posisi sebelumnya. Logika ini membantu memantau pergerakan perangkat dan mendeteksi peristiwa keluar dari area geografis tertentu. Pastikan Anda menambahkan nilai yang benar untuk parameter: `z.zone_label = 'label_zona_Anda'.`

{% code expandable="true" %}

```sql
WITH zone AS (
  SELECT z.zone_id,
         ST_MakePolygon(ST_MakeLine(ARRAY_AGG(ST_MakePoint(g.longitude, g.latitude) ORDER BY g.number)))::geography AS geog
  FROM raw_business_data.zones z
  JOIN raw_business_data.geofence_points g ON g.zone_id = z.zone_id
  WHERE z.zone_label = 'your_zone_label'
  Kelompok berdasarkan z.zone_id
),
poin AS (
  SELECT device_id,
         waktu perangkat,
         ST_SetSRID(ST_MakePoint(longitude/1e7::numeric, latitude/1e7::numeric), 4326)::geography AS geog
  DARI raw_telematics_data.tracking_data_core
  WHERE device_time BETWEEN '2025-07-27 00:00:00' AND '2025-07-28 23:59:59'
),
states AS (
  SELECT p.*,
         CASE WHEN ST_Contains(z.geog::geometry, p.geog::geometry) THEN 'inside' ELSE 'outside' END AS pos
  FROM pts p CROSS JOIN zone z
),
filtered_states AS (
  SELECT
    device_id,
    waktu perangkat,
    pos,
    LAG(pos) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_pos
  FROM states
)
SELECT device_id, device_time, pos
FROM filtered_states
WHERE prev_pos = 'inside' AND pos = 'outside';

```

{% endcode %}

## **Inspeksi rutin berdasarkan interval waktu**

Beberapa Tugas Pemeliharaan berulang pada jadwal waktu tetap. Sistem harus menandai Kendaraan yang inspeksi/pemeriksaan berikutnya jatuh tempo dalam interval yang ditentukan.

{% code expandable="true" %}

```sql
WITH t AS (
    SELECT
        vehicle_id,
        deskripsi,
        start_date,
        interval pengulangan tanggal,
        make_interval(days => date_repeat_interval) AS repeat_interval
    DARI raw_business_data.vehicle_service_tasks
    WHERE date_repeat_interval IS NOT NULL
)
SELECT
    vehicle_id,
    deskripsi,
    start_date,
    interval pengulangan tanggal,
    start_date
        + repeat_interval
            * floor(
                extract(epoch from (current_date::timestamp - start_date))
                / extract(epoch from repeat_interval)
              ) AS last_due,
    start_date
        + repeat_interval
            * (
                floor(
                    extract(epoch from (current_date::timestamp - start_date))
                    / extract(epoch from repeat_interval)
                ) + 1
              ) AS next_due
FROM t
WHERE (
        start_date
            + repeat_interval
                * (
                    floor(
                        extract(epoch from (current_date::timestamp - start_date))
                        / extract(epoch from repeat_interval)
                    ) + 1
                  )
      ) BETWEEN current_date
          AND (current_date + interval '30 days');
```

{% endcode %}

## **Servis berdasarkan ambang batas jarak tempuh (Minor/Major)**

Servis minor dan servis besar dipicu oleh Jarak tempuh sejak kejadian servis terakhir. Ketika kilometer yang terakumulasi melebihi ambang batas, servis yang sesuai harus dijadwalkan.

Harap perhatikan `Field vst.description harus memiliki komentar/deskripsi yang relevan agar dapat digunakan untuk filter dalam kode SQL di bawah ini.`

{% code expandable="true" %}

```sql
SELECT
  v.vehicle_id,
  v.vehicle_label,
  km.km_since_service,
  vst.batas_jarak_tempuh
DARI
  raw_business_data.Kendaraan v
  JOIN LATERAL (
    SELECT MAX(vst.completion_date) AS last_service_date
    DARI raw_business_data.vehicle_service_Tugas vst
    WHERE vst.vehicle_id = v.vehicle_id
      AND (vst.description ILIKE '%minor%' OR vst.description ILIKE '%major%')
      AND vst.completion_date IS NOT NULL
  ) ls ON TRUE
  JOIN raw_business_data.objects o ON o.object_id = v.vehicle_id
  JOIN LATERAL (
    SELECT SUM(t.trip_distance_meters) / 1000.0 AS km_since_service
    FROM processed_common_data.Perjalanan t
    WHERE t.device_id = o.device_id
      AND t.trip_start_time > ls.last_service_date
  ) km AKTIF BENAR
  JOIN raw_business_data.vehicle_service_tasks vst
    ON vst.vehicle_id = v.vehicle_id
    AND vst.completion_date = ls.last_service_date
    AND (vst.description ILIKE '%minor%' OR vst.description ILIKE '%major%')

```

{% endcode %}

## **Batas Jarak tempuh & Penalti**

Kontrak leasing sering membatasi Jarak tempuh (misalnya, 25.000 km/tahun). Jika batas terlampaui, klausul penalti berlaku. Sistem harus membandingkan Jarak tempuh aktual selama periode kontrak dengan batas yang disepakati dan menghitung biaya.

{% code expandable="true" %}

```sql
WITH driven AS (
  SELECT
    o.pelacak_id,
    DATE_TRUNC('year', t.trip_start_time) AS year,
    SUM(t.trip_distance_meters) / 1000.0 AS km_year
  DARI
    processed_common_data.Perjalanan t
    JOIN raw_business_data.objects o ON o.device_id = t.device_id
  WHERE
    t.trip_start_time >= '2023-01-01'::date
    AND t.trip_start_time < '2024-01-01'::date
  Kelompok berdasarkan
    o.object_id, DATE_TRUNC('year', t.trip_start_time)
),
limits AS (
  SELECT
    object_id,
    10000 AS km_limit,
    0,5 AS tarif penalti
  DARI
    raw_business_data.objects
)
SELECT
  d.object_id,
  d.year,
  d.km_year,
  l.km_limit,
  GREATEST(d.km_year - l.km_limit, 0) AS km_over,
  GREATEST(d.km_year - l.km_limit, 0) * l.penalty_rate AS penalty_amount
DARI
  digerakkan d
  JOIN limits l ON d.object_id = l.object_id;
```

{% endcode %}

## **Pemantauan Mesin jam**

Bagi mesin dan peralatan pertanian, jam operasional—bukan Jarak tempuh—menentukan Pemeliharaan dan penagihan. Data jam mesin (misalnya dari CAN-Bus) harus dipantau dan diringkas.

{% code expandable="true" %}

```sql
WITH last_service AS (
  SELECT
    vst.vehicle_id,
    MAX(vst.completion_date) AS last_service_date,
    MAX(vst.completion_engine_hours) AS last_service_engine_hours
  DARI
    raw_business_data.vehicle_service_tugas vst
  Kelompok berdasarkan
    vst.vehicle_id
),
engine_hours_since_service AS (
  SELECT
    v.vehicle_id,
    SUM(t.trip_duration_seconds) / 3600.0 AS engine_hours_since_service
  DARI
    raw_business_data.Kendaraan v
    JOIN raw_business_data.objects o ON o.object_id = v.object_id
    JOIN processed_common_data.Perjalanan t ON t.device_id = o.device_id
    JOIN last_service ls ON ls.vehicle_id = v.vehicle_id
  WHERE
    t.trip_start_time > ls.last_service_date
  Kelompok berdasarkan
    v.vehicle_id
)
SELECT
  v.vehicle_id,
  v.vehicle_label,
  ls.last_service_engine_hours,
  ehs.engine_hours_since_service,
  (COALESCE(ehs.engine_hours_since_service,0) + COALESCE(ls.last_service_engine_hours,0)) AS current_engine_hours,
  vst.engine_hours_limit
DARI
  raw_business_data.Kendaraan v
  JOIN last_service ls ON ls.vehicle_id = v.vehicle_id
  LEFT JOIN engine_hours_since_service ehs ON ehs.vehicle_id = v.vehicle_id
  JOIN raw_business_data.vehicle_service_tasks vst
    ON vst.vehicle_id = v.vehicle_id
    AND vst.completion_date = ls.last_service_date
```

{% endcode %}

## **Peristiwa pengemudian kasar**

Perilaku mengemudi memengaruhi keausan dan kepatuhan kontrak. Mendeteksi pengemudian kasar membantu bank menisbatkan keausan dini rem/ban kepada penyalahgunaan oleh supir dan, jika perlu, mengalihkan biaya.

Kueri SQL di bawah pertama-tama menghitung kecepatan dalam kilometer per jam dan selisih waktu antara titik data berurutan untuk setiap perangkat. Dengan menggunakan informasi ini, kueri kemudian menghitung laju perlambatan dalam kilometer per jam per detik. Terakhir, kueri memfilter dan mengembalikan catatan yang laju perlambatannya 20 km/jam per detik atau lebih, yang menunjukkan peristiwa perlambatan signifikan.

{% code expandable="true" %}

```sql
WITH spd AS (
  SELECT
    device_id,
    waktu perangkat,
    speed/100.0 AS kmh,
    LAG(speed/100.0) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_kmh,
    EXTRACT(EPOCH FROM (device_time - LAG(device_time) OVER (PARTITION BY device_id ORDER BY device_time))) AS dt_sec
  DARI
    raw_telematics_data.tracking_data_core
  WHERE
    device_time BETWEEN '2025-07-24 00:00:00' AND '2025-07-24 23:59:59'
),
decels AS (
  SELECT
    device_id,
    waktu perangkat,
    (prev_kmh - kmh) / NULLIF(dt_sec, 0) AS decel_kmh_per_sec
  DARI
    spd
  WHERE
    prev_kmh IS NOT NULL
)
SELECT *
FROM decels
WHERE decel_kmh_per_sec >= 20;
```

{% endcode %}

## **Peristiwa percepatan kasar**

Akselerasi agresif meningkatkan keausan pada ban, transmisi, drivetrain, dan dudukan mesin. Mengidentifikasi peristiwa ini mendukung pembinaan dan potensi pemulihan biaya.

Kueri SQL di bawah dirancang untuk mengidentifikasi peristiwa akselerasi signifikan dari sekumpulan data pelacakan. Kueri ini pertama-tama menghitung kecepatan dalam kilometer per jam dan selisih waktu antara titik data berurutan untuk setiap perangkat. Dengan menggunakan informasi ini, kueri kemudian menghitung laju akselerasi dalam kilometer per jam per detik. Terakhir, kueri memfilter dan mengembalikan catatan yang laju akselerasinya mencapai atau melebihi ambang batas yang ditentukan, yang menunjukkan peristiwa akselerasi signifikan.

{% code expandable="true" %}

```sql
WITH spd AS (
  SELECT
    device_id,
    waktu perangkat,
    speed/100.0 AS kmh,
    LAG(speed/100.0) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_kmh,
    EXTRACT(EPOCH FROM (device_time - LAG(device_time) OVER (PARTITION BY device_id ORDER BY device_time))) AS dt_sec
  DARI
    raw_telematics_data.tracking_data_core
  WHERE
    device_time BETWEEN '2025-07-28 00:00:00' AND '2025-07-28 23:59:59'
)
SELECT
  device_id,
  waktu perangkat,
  (kmh - prev_kmh) / NULLIF(dt_sec, 0) AS accel_kmh_per_sec
DARI
  spd
WHERE
  prev_kmh IS NOT NULL
  AND (kmh - prev_kmh) / NULLIF(dt_sec, 0) >= 20;
```

{% endcode %}

## **Belokan mendadak / menikung**

Belokan tajam yang dikombinasikan dengan perubahan kecepatan yang tiba-tiba menunjukkan mengemudi berisiko. Melacak perilaku seperti ini membantu mendeteksi penggunaan kendaraan yang tidak semestinya.

Kueri SQL ini dirancang untuk mengidentifikasi perubahan signifikan dalam arah dan kecepatan dari data pelacakan selama periode waktu yang ditentukan. Kueri ini pertama-tama mengonversi nilai lintang dan bujur mentah menjadi derajat desimal dan menghitung kecepatan dalam kilometer per jam. Dengan menggunakan fungsi LAG, kueri ini mengambil data lokasi dan kecepatan sebelumnya untuk setiap perangkat, sehingga memungkinkan perhitungan perubahan dari waktu ke waktu. Kueri kemudian menghitung perubahan arah dalam derajat menggunakan fungsi trigonometri untuk menentukan azimut antara titik-titik berurutan. Kueri ini juga menghitung perubahan kecepatan antara titik-titik tersebut. Terakhir, kueri memfilter hasil untuk hanya menyertakan catatan yang perubahan absolut arah sebesar 10 derajat atau lebih dan perubahan absolut kecepatan sebesar 5 km/jam atau lebih, sehingga mengidentifikasi manuver atau peristiwa signifikan dalam data pelacakan.

{% code expandable="true" %}

```sql
WITH pts AS (
  SELECT
    device_id,
    waktu perangkat,
    latitude/1e7::numeric AS lat,
    longitude/1e7::numeric AS lon,
    LAG(latitude/1e7::numeric) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_lat,
    LAG(longitude/1e7::numeric) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_lon,
    speed/100.0 AS kmh,
    LAG(speed/100.0) OVER (PARTITION BY device_id ORDER BY device_time) AS prev_kmh
  DARI
    raw_telematics_data.tracking_data_core
  WHERE
    device_time BETWEEN '2025-07-28 00:00:00' AND '2025-07-28 23:59:59'
),
bearing AS (
  SELECT *,
         atan2(
           sin(radians(lon-prev_lon))*cos(radians(lat)),
           cos(radians(prev_lat))*sin(radians(lat)) -
           sin(radians(prev_lat))*cos(radians(lat))*cos(radians(lon-prev_lon))
         ) * 180/pi() AS heading_change,
         (kmh - prev_kmh) AS delta_speed
  FROM pts
)
SELECT *
FROM bearing
WHERE abs(heading_change) >= 10
  AND abs(delta_speed) >= 5;

```

{% endcode %}

## **Pengapian & deteksi diam**

Mengukur waktu idle (Pengapian aktif, kecepatan rendah/tidak ada) membantu mengurangi pemborosan Bahan bakar dan mengidentifikasi penyalahgunaan. Periode Idle yang panjang harus dilaporkan dan dikelola.

{% hint style="info" %}
[Studio Dasbor](/docs/analytics/id/dashboard-studio.md) dan alat serupa tidak mendukung substitusi variabel (`:variabel` Sintaks). Ganti semua parameter dengan nilai literal sebelum menjalankan kueri ini. Lihat contoh di bawah untuk format yang benar.
{% endhint %}

{% code expandable="true" %}

```sql
WITH ign AS (
    SELECT
        device_id,
        waktu perangkat,
        value::int AS ign_on
    FROM raw_telematics_data.states
    WHERE state_name = 'pengapian'
      AND device_time BETWEEN :from_ts::timestamptz AND :to_ts::timestamptz
      -- Untuk Dashboard Studio, ganti :from_ts dan :to_ts dengan stempel waktu literal:
      -- TIMESTAMPTZ '2024-01-01 00:00:00+00' AND TIMESTAMPTZ '2024-01-07 00:00:00+00'
),
spd AS (
    SELECT
        device_id,
        waktu perangkat,
        speed / 100.0 AS kmh
    DARI raw_telematics_data.tracking_data_core
    WHERE device_time BETWEEN :from_ts AND :to_ts
    -- Untuk Dashboard Studio, ganti :from_ts dan :to_ts dengan stempel waktu literal:
    -- TIMESTAMPTZ '2024-01-01 00:00:00+00' AND TIMESTAMPTZ '2024-01-07 00:00:00+00'
),
merged AS (
    SELECT
        i.device_id,
        i.device_time,
        i.ign_on,
        s.kmh,
        LEAD(i.device_time) OVER (
            PARTITION BY i.device_id
            ORDER BY i.device_time
        ) AS next_time
    FROM ign i
    LEFT JOIN spd s USING (device_id, device_time)
)
SELECT
    device_id,
    device_time AS idle_start,
    next_time   AS idle_end,
    EXTRACT(EPOCH FROM (next_time - device_time)) / 60.0 AS idle_minutes
FROM merged
WHERE ign_on = 1
  AND kmh < :idle_speed
  -- Untuk Dashboard Studio, ganti :idle_speed dengan nilai numerik, misalnya 5
  AND next_time IS NOT NULL
  AND (next_time - device_time) >= (:idle_min::int * INTERVAL '1 minute');
  -- Untuk Dashboard Studio, ganti :idle_min dengan nilai numerik, misalnya (5 * INTERVAL '1 minute')
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://navixy.com/docs/analytics/id/example-queries/leasing.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
