> 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/fr/example-queries/leasing.md).

# Crédit-bail

Modèles de requêtes SQL pour l'analyse bancaire et de crédit-bail, couvrant le cycle de vie des actifs, la conformité contractuelle, l'ordonnancement de l'entretien et le suivi des limites d'utilisation

{% hint style="warning" %}
Activer **IoT Query** avant d'utiliser les données pour élaborer des analyses complètes. Si vous ne l'avez pas encore, contactez-nous pour connaître les détails d'activation - <iotquery@navixy.com>
{% endhint %}

Les sociétés de leasing (en particulier les banques et les fournisseurs de leasing de Flotte) conservent la propriété du véhicule ou de l'équipement tandis que le client n'en loue que l'usage, de sorte qu'elles supportent le risque lié à l'Actif pendant toute la durée du contrat. 

Pour protéger la valeur résiduelle, imposer des limites contractuelles (kilometrage, géographie, Entretien) et simplifier les obligations de service complet, elles s'appuient sur Navixy. Les données GPS en temps réel, les diagnostics basés sur des capteurs et les analyses comportementales leur permettent de vérifier les conditions d'utilisation, d'automatiser l'Ordonnancement des entretiens, de détecter tôt les problèmes mécaniques, de calculer des pénalités ou des frais de kilometrage excédentaire et, si nécessaire, d'immobiliser ou de récupérer l'Actif — autant d'éléments qui sécurisent leur investissement, réduisent les coûts opérationnels et renforcent la transparence client tout au long du cycle de vie du contrat de location.

Navixy **IoT Query** vous aidera à organiser tout type d'analytique à chaque étape du contrat de leasing. Un contrat de leasing traverse plusieurs phases prévisibles : Intégration et configuration de l'Actif → Phase opérationnelle → Surveillance des risques et de la conformité

Les recettes SQL suivantes de votre livre surveillent conjointement chaque étape critique de ce cycle de vie :

| Phase du cycle de vie                                    | Objectifs et étapes clés                                                                                                                                     | Cas d’usage couverts / Recettes                                                                                                                                                                                                                                           |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Intégration & configuration de l’Actif                   | • Enregistrer le véhicule, activer l’Assurance et les identifiants du Conducteur. • Importer l’Actif dans le portail client avec la visibilité correcte.     | Règles d’alertes d’expiration pour l’Assurance – les dates de référence sont capturées. Expiration du permis du Conducteur – valide les Conducteurs avant la mise en circulation.                                                                                         |
| Planification de l’Entretien préventif                   | • Mettre en place des calendriers d’entretien récurrents, basés sur le kilometrage et sur le temps. • Garantir les changements saisonniers de pneus.         | Inspections de routine par intervalle – Missions déclenchées par le calendrier. Entretien selon le seuil de kilometrage – règles d’entretien mineur/majeur déclenchées par les km. Surveillance des heures moteur – entretien déclenché par les heures pour les machines. |
| Limites d’utilisation liées au contrat                   | • Faire respecter les allocations de kilometrage et les plafonds financiers. • Détecter tôt les surutilisations pour éviter les surprises en fin de contrat. | Plafond de kilometrage et pénalités – surveillance annuelle / du kilometrage total du contrat.                                                                                                                                                                            |
| Comportement en temps réel des Conducteurs et des Actifs | • Protégez la valeur de l’Actif ; accompagnez les Conducteurs. • Repérez les usages abusifs qui annulent la couverture « full-service ».                     | Freinage brutal. Accélération brutale. Virages brusques / prise de virage brusque.                                                                                                                                                                                        |
| Supervision des risques et de la conformité              | • Gardez les Actifs à l’intérieur des limites géographiques et contractuelles. • Conservez le droit de désactiver ou de récupérer.                           | Sortie de la zone géographique (frontière nationale) – alerte instantanée en cas de violation du territoire. Détection du Contact et du ralenti – Suivi du gaspillage de Carburant / de l’utilisation abusive.                                                            |

### Modèle de tableau de bord

Bien que les recettes SQL ci-dessous offrent un contrôle complet sur l’analyse du leasing, vous pouvez commencer plus rapidement avec un tableau de bord préconfiguré qui visualise les indicateurs critiques tout au long du cycle de vie du bail. Le modèle élimine la création de requêtes et de visualisations à partir de zéro. Importez-le, ajustez les paramètres et commencez immédiatement à surveiller la conformité, les risques et la protection des Actifs.

Le modèle couvre les principaux flux de travail du leasing : le suivi des enregistrements et de l’expiration de l’Assurance, la surveillance du permis de Conducteur, la détection du Freinage brutal et de l’accélération brutale avec des classifications de gravité, l’analyse du temps de ralenti et la surveillance de l’activité des appareils.

<figure><img src="https://2191335748-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>

Importez la configuration dans [Studio de tableau de bord](https://marketplace.navixy.com/shop/dashboard-studio/), ajustez les seuils pour vos contrats (plafonds de kilometrage, niveaux de gravité des comportements, paramètres de détection d'inactivité) et déployez un espace de travail de surveillance complet. Cela fonctionne bien lorsque les équipes ont besoin de tableaux de bord opérationnels pour la conformité au quotidien et la supervision des risques, sans écrire de SQL.

**Prérequis :**

* IoT Query activé dans votre environnement
* Dashboard Studio installé et accessible
* Au moins 72 heures de données de Suivi
* Tables du schéma standard renseignées : `suivi_data_core`, `états`, `objets`, `Véhicules`, `employés`

**Configuration après importation :**

Après avoir importé le modèle, adaptez-le à vos contrats de location spécifiques et à vos seuils opérationnels :

1. Vérifiez la plage horaire par défaut de 72 heures et ajustez-la si la disponibilité de vos données diffère.
2. Définissez les seuils de gravité pour les événements d’Eco conduite dans les paramètres de requête (par défaut : 60+ km/h/s pour les avertissements, 80+ km/h/s pour les Règles d’alertes critiques).
3. Configurez les paramètres de détection d’immobilité (par défaut : vitesse inférieure à 5 km/h, durée minimale de 5 minutes).
4. Mettez à jour les libellés de Zone géographique dans la requête de passage de frontière si vous surveillez des restrictions territoriales.
5. Utilisez le sélecteur de période global pour analyser des périodes historiques ou vous concentrer sur l’activité récente.

**JSON du modèle :**

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

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

```json
{
  "id": null,
  "uid": "bonjour-le-monde",
  "Mots clés": [
    "exemple",
    "prise-en-main"
  ],
  "time": {
    "to": "now",
    "from": "now-72h"
  },
  "links": [],
  "style": "sombre",
  "title": "Tableau de bord de leasing",
  "panels": [
    {
      "id": 10,
      "type": "texte",
      "title": "Contact et détection du ralenti",
      "gridPos": {
        "h": 4,
        "w": 24,
        "x": 0,
        "y": 158
      },
      "options": {
        "mode": "markdown",
        "contenu": " "
      },
      "x-navixy": {
        "sql": {
          "instruction": ""
        },
        "jeu de données": {
          "forme": "table",
          "colonnes": {}
        }
      }
    },
    {
      "id": 11,
      "type": "diagramme circulaire",
      "title": "Conducteurs avec les dates d'expiration les plus proches",
      "gridPos": {
        "h": 12,
        "w": 12,
        "x": 12,
        "y": 0
      },
      "options": {
        "pieType": "donut"
      },
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "instruction": "SELECT \r\n    CASE \r\n        WHEN (DATE(e.driver_license_valid_till) - CURRENT_DATE)::INTEGER < 0 THEN 'Expiré'\r\n        ELSE 'Autres'\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"
        },
        "vérifier": {
          "lignes_max": 1000
        },
        "jeu de données": {
          "forme": "camembert",
          "colonnes": {
            "valeur": {
              "type": "entier"
            },
            "catégorie": {
              "type": "chaîne"
            }
          }
        }
      }
    },
    {
      "id": 12,
      "type": "diagramme circulaire",
      "titre": "Véhicules avec les dates d'expiration les plus proches",
      "gridPos": {
        "h": 12,
        "w": 12,
        "x": 0,
        "y": 0
      },
      "options": {
        "pieType": "donut"
      },
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "instruction": "WITH expiry_data AS (\r\n    SELECT \r\n        CASE \r\n            WHEN v.free_assurance_valid_till_date IS NOT NULL\r\n                AND (v.liability_assurance_valid_till IS NULL \r\n                      OR v.free_assurance_valid_till_date <= v.liability_assurance_valid_till)\r\n                THEN v.free_assurance_valid_till_date\r\n            WHEN v.liability_assurance_valid_till IS NOT NULL\r\n                THEN v.liability_assurance_valid_till\r\n            ELSE NULL\r\n        END AS nearest_expiry_date\r\n    FROM raw_business_data.Véhicules 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 'Expiré'\r\n            WHEN (DATE(nearest_expiry_date) - CURRENT_DATE)::INTEGER >= 0 \r\n                  AND (DATE(nearest_expiry_date) - CURRENT_DATE)::INTEGER < 30 THEN 'Expire dans les 30 jours'\r\n            ELSE 'Autres'\r\n        END AS catégorie\r\n    FROM expiry_data\r\n    WHERE nearest_expiry_date IS NOT NULL\r\n)\r\nSELECT \r\n    catégorie,\r\n    COUNT(*) AS valeur\r\nFROM categorized_data\r\nGROUP BY catégorie\r\nORDER BY \r\n    CASE catégorie\r\n        WHEN 'Expiré' THEN 1\r\n        WHEN 'Expire dans les 30 jours' THEN 2\r\n        WHEN 'Autres' THEN 3\r\n    END"
        },
        "vérifier": {
          "lignes_max": 1000
        },
        "jeu de données": {
          "forme": "camembert",
          "colonnes": {
            "valeur": {
              "type": "entier"
            },
            "catégorie": {
              "type": "chaîne"
            }
          }
        }
      }
    },
    {
      "id": 13,
      "type": "diagramme à barres",
      "title": "Événements de Freinage brutal",
      "gridPos": {
        "h": 11,
        "w": 24,
        "x": 0,
        "y": 12
      },
      "options": {
        "textMode": "auto"
      },
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "déclaration": "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 'Critique'\r\n              WHEN d.decel_kmh_per_sec >= 60 THEN 'Avertissement'\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"
        },
        "vérifier": {
          "lignes_max": 1000
        },
        "jeu de données": {
          "forme": "valeur_de_catégorie",
          "colonnes": {
            "valeur": {
              "type": "entier"
            },
            "série": {
              "type": "chaîne"
            },
            "catégorie": {
              "type": "date"
            }
          }
        },
        "visualisation": {
          "sortOrder": "aucun",
          "colorPalette": "vif"
        }
      }
    },
    {
      "id": 14,
      "type": "diagramme à barres",
      "title": "Événements d'Accélération brutale",
      "gridPos": {
        "h": 17,
        "w": 24,
        "x": 0,
        "y": 41
      },
      "options": {
        "orientation": "vertical"
      },
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "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        ),\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          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(a.device_time) AS category,\r\n            CASE \r\n              WHEN a.accel_kmh_per_sec >= 80 THEN 'Critique'\r\n              WHEN a.accel_kmh_per_sec >= 60 THEN 'Avertissement'\r\n              ELSE 'Normal'\r\n            END AS series\r\n          FROM accels a\r\n          WHERE a.accel_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"
        },
        "vérifier": {
          "lignes_max": 1000
        },
        "jeu de données": {
          "forme": "valeur_de_catégorie",
          "colonnes": {
            "valeur": {
              "type": "entier"
            },
            "série": {
              "type": "chaîne"
            },
            "catégorie": {
              "type": "date"
            }
          }
        },
        "visualisation": {
          "colorPalette": "vif"
        }
      }
    },
    {
      "id": 15,
      "type": "diagramme à barres",
      "title": "Virages brusques / Prise de virage",
      "gridPos": {
        "h": 13,
        "w": 24,
        "x": 0,
        "y": 23
      },
      "options": {
        "orientation": "vertical"
      },
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "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 'Critique'\r\n              WHEN ABS(b.heading_change) >= 30 AND b.kmh >= 30 THEN 'Avertissement'\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"
        },
        "vérifier": {
          "lignes_max": 1000
        },
        "jeu de données": {
          "forme": "valeur_de_catégorie",
          "colonnes": {
            "valeur": {
              "type": "entier"
            },
            "série": {
              "type": "chaîne"
            },
            "catégorie": {
              "type": "date"
            }
          }
        },
        "visualisation": {
          "empilement": "pourcentage",
          "colorPalette": "classique"
        }
      }
    },
    {
      "id": 16,
      "type": "stat",
      "title": "Événements d'inactivité totaux",
      "gridPos": {
        "h": 5,
        "w": 8,
        "x": 0,
        "y": 36
      },
      "options": {
        "textMode": "auto"
      },
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "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 = 'Contact'\r\n        ),\r\n        spd AS (\r\n          SELECT device_id, device_time, speed/100.0 AS kmh\r\n          FROM raw_telematics_data.Suivi_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"
        },
        "vérifier": {
          "lignes_max": 1000
        },
        "jeu de données": {
          "shape": "kpi",
          "colonnes": {}
        }
      }
    },
    {
      "id": 9,
      "type": "série chronologique",
      "title": "Messages au fil du temps",
      "gridPos": {
        "h": 13,
        "w": 24,
        "x": 0,
        "y": 83
      },
      "options": {
        "legend": {
          "calcs": [],
          "placement": "bas",
          "showLegend": true,
          "displayMode": "liste"
        },
        "info-bulle": {
          "mode": "simple",
          "sort": "aucun"
        }
      },
      "cibles": [],
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "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 messages, 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 -- décommentez et définissez si vous souhaitez un client spécifique\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.messages, 0) AS messages, COALESCE(c.unique_devices, 0) AS unique_devices\nFROM hours h LEFT\n    JOIN counts c USING (bucket)\nORDER BY time;"
        },
        "vérifier": {
          "lignes_max": 1000
        },
        "jeu de données": {
          "forme": "valeur_de_temps",
          "colonnes": {}
        },
        "visualisation": {
          "lineStyle": "continu",
          "colorPalette": "moderne",
          "interpolation": "fluide",
          "legendPosition": "haut"
        }
      },
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "unit": "court",
          "color": {
            "mode": "palette-classique"
          },
          "custom": {"}
            "empilement": {
              "mode": "aucun",
              "Groupe": "A"
            },
            "style de tracé": "ligne",
            "largeur de ligne": 1,
            "étendre les valeurs nulles": false,
            "afficher les points": "auto",
            "opacité de remplissage": 10,
            "mode de dégradé": "aucun",
            "placement de l'axe": "auto",
            "interpolationDeLigne": "linéaire"
          },
          "mappages": [],
          "seuils": {
            "mode": "absolu",
            "étapes": [
              {
                "couleur": "vert",
                "valeur": null
              }
            ]
          }
        },
        "surcharges": []
      }
    },
    {
      "id": 1,
      "type": "KPI",
      "titre": "Nombre d'échantillons",
      "gridPos": {
        "h": 5,
        "w": 6,
        "x": 18,
        "y": 128
      },
      "options": {
        "modeTexte": "auto",
        "modeCouleur": "valeur",
        "modeGraphique": "aucun",
        "modeJustification": "auto",
        "orientation": "auto"
      },
      "cibles": [],
      "x-navixy": {
        "sql": {
          "paramètres": {
            "tenant_id": {
              "type": "uuid"
            }
          },
          "instruction" : "SELECT *\nFROM raw_telematics_data.Suivi_data_core LIMIT 10;"
        },
        "vérifier": {
          "max_rows": 1
        },
        "jeu de données": {
          "shape": "kpi",
          "colonnes": {
            "valeur": {
              "type": "nombre"
            }
          }
        }
      },
      "datasource": null,
      "description": ",
      "fieldConfig": {
        "defaults": {
          "unit": "court",
          "color": {
            "mode": "seuils"
          },
          "seuils": {
            "mode": "absolu",
            "étapes": [
              {
                "couleur": "vert",
                "valeur": null
              }
            ]
          }
        },
        "surcharges": []
      }
    },
    {
      "id": 2,
      "type": "diagramme à barres",
      "title": "Données d'exemple par catégorie",
      "gridPos": {
        "h": 15,
        "w": 18,
        "x": 0,
        "y": 130
      },
      "options": {
        "valueMode": "couleur",
        "displayMode": "dégradé",
        "orientation": "horizontal",
        "showUnfilled": true
      },
      "cibles": [],
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "statement": "SELECT o.Traceur_label, COUNT(*) AS msgs_24h\nFROM raw_telematics_data.Suivi_data_core AS t\n    JOIN raw_business_data.Traceurs AS o\n  ON o.device_id = t.device_id\nWHERE t.device_time >= NOW() - INTERVAL '24 hours'\nGROUP BY o.client_id, o.Traceur_label, t.device_id\nORDER BY msgs_24h DESC LIMIT 20;"
        },
        "vérifier": {
          "max_rows": 10
        },
        "jeu de données": {
          "forme": "valeur_de_catégorie",
          "colonnes": {}
        },
        "visualisation": {
          "orientation": "vertical"
        }
      },
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "unit": "court",
          "color": {
            "mode": "palette-classique"
          },
          "custom": {"}
            "hideFrom": {
              "viz": false,
              "legend": false,
              "tooltip": false
            }
          },
          "mappages": [],
          "seuils": {
            "mode": "absolu",
            "étapes": [
              {
                "couleur": "vert",
                "valeur": null
              }
            ]
          }
        },
        "surcharges": []
      }
    },
    {
      "id": 3,
      "type": "table",
      "title": "Messages par jour",
      "gridPos": {
        "h": 9,
        "w": 12,
        "x": 4,
        "y": 148
      },
      "options": {
        "sortBy": [],
        "showHeader": true
      },
      "cibles": [],
      "x-navixy": {
        "sql": {
          "paramètres": {
            "__to": null,
            "__from": null
          },
          "statement": "SELECT TO_CHAR(date_trunc('day', t.device_time), 'Mon DD, YYYY') AS \"Date\", \n       COUNT(*) AS \"Messages\"\nFROM raw_telematics_data.Suivi_data_core AS t\nWHERE t.device_time >= ${__from}\n  AND t.device_time < ${__to}\nGROUP BY 1\nORDER BY 1;"
        },
        "vérifier": {
          "max_rows": 10
        },
        "jeu de données": {
          "forme": "table",
          "colonnes": {}
        },
        "visualisation": {
          "pageSize": 5
        }
      },
      "datasource": null,
      "fieldConfig": {
        "defaults": {
          "custom": {"}
            "align": "auto",
            "displayMode": "auto"
          },
          "mappages": [],
          "seuils": {
            "mode": "absolu",
            "étapes": [
              {
                "couleur": "vert",
                "valeur": null
              }
            ]
          }
        },
        "surcharges": []
      }
    },
    {
      "id": 6,
      "type": "KPI",
      "title": "Temps total d'inactivité",
      "gridPos": {
        "h": 5,
        "w": 8,
        "x": 8,
        "y": 36
      },
      "options": {
        "textMode": "auto"
      },
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "statement": "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 = 'Contact'\n  ),\n  spd AS (\n    SELECT device_id, device_time, speed/100 AS kmh\n    FROM raw_telematics_data.Suivi_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"
        },
        "vérifier": {
          "lignes_max": 1000
        },
        "jeu de données": {
          "shape": "kpi",
          "colonnes": {
            "valeur": {
              "type": "nombre"
            }
          }
        }
      }
    },
    {
      "id": 7,
      "type": "diagramme circulaire",
      "title": "Appareils les plus actifs au cours des dernières 24 h",
      "gridPos": {
        "h": 9,
        "w": 12,
        "x": 0,
        "y": 121
      },
      "options": {
        "pieType": "donut"
      },
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "statement": "SELECT o.Traceur_label, COUNT(*) AS msgs_24h\nFROM raw_telematics_data.Suivi_data_core AS t\n    JOIN raw_business_data.Traceurs AS o\n  ON o.device_id = t.device_id\nWHERE t.device_time >= NOW() - INTERVAL '24 hours'\nGROUP BY o.client_id, o.Traceur_label, t.device_id\nORDER BY msgs_24h DESC LIMIT 20;"
        },
        "vérifier": {
          "lignes_max": 1000
        },
        "jeu de données": {
          "forme": "camembert",
          "colonnes": {}
        }
      }
    },
    {
      "id": 8,
      "type": "table",
      "title": "Mouvements récents des véhicules",
      "gridPos": {
        "h": 25,
        "w": 24,
        "x": 0,
        "y": 96
      },
      "options": {
        "showHeader": true
      },
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "statement": "SELECT\n  to_char(t.device_time, 'YYYY-MM-DD HH24:MI:SS TZ') AS \"Horodatage\",\n  t.device_id                                       AS \"ID de l'appareil\",\n  t.speed                                           AS \"Vitesse\",\n  round(t.latitude::numeric  / 10000000, 6)         AS \"Latitude (°)\",\n  round(t.longitude::numeric / 10000000, 6)         AS \"Longitude (°)\"\nFROM raw_telematics_data.Suivi_data_core t\nWHERE t.device_time >= NOW() - INTERVAL '3 days'\n  AND t.speed > 0\nORDER BY t.device_time DESC;"
        },
        "vérifier": {
          "max_rows": 3
        },
        "jeu de données": {
          "forme": "table",
          "colonnes": {
            "Speed": {
              "type": "entier"
            },
            "Device ID": {
              "type": "entier"
            },
            "Timestamp": {
              "type": "chaîne"
            },
            "Latitude (°)": {
              "type": "nombre"
            },
            "Longitude (°)": {
              "type": "nombre"
            }
          }
        },
        "visualisation": {
          "pageSize": 25,
          "sortable": true,
          "showHeader": true,
          "showTotals": false,
          "rowHighlighting": "survol"
        }
      }
    },
    {
      "id": 19,
      "type": "stat",
      "title": "Durée moyenne d'inactivité",
      "gridPos": {
        "h": 5,
        "w": 8,
        "x": 16,
        "y": 36
      },
      "options": {
        "textMode": "auto"
      },
      "x-navixy": {
        "sql": {
          "paramètres": {},
          "déclaration": "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 = 'ignition'\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"
        },
        "vérifier": {
          "lignes_max": 1000
        },
        "jeu de données": {
          "shape": "kpi",
          "colonnes": {}
        }
      }
    }
  ],
  "actualisation": "30s",
  "version": 1,
  "modifiable": true,
  "timezone": "navigateur",
  "x-navixy": {
    "exécution": {
      "dialecte": "postgresql",
      "point de terminaison": "/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": "Locataire",
        "query": "demo-tenant-id",
        "current": {
          "text": "Locataire de démonstration",
          "value": "demo-tenant-id"
        },
        "options": [
          {
            "text": "Locataire de démonstration",
            "valeur": "demo-tenant-id",
            "sélectionné": true
          }
        ]
      }
    ],
    "activé": true
  },
  "sélecteur d'heure": {
    "maintenant": true,
    "activé": true,
    "masqué": false,
    "replié": false,
    "options de temps": [
      "5m",
      "15m",
      "1h",
      "6h",
      "12h",
      "24h"
    ],
    "intervalles_de_rafraîchissement": [
      "5s",
      "10s",
      "30s",
      "1m",
      "5m",
      "15m",
      "30m",
      "1h"
    ]
  },
  "annotations": {
    "list": [
      {
        "hide": true,
        "name": "Annotations & Règles d’alertes",
        "type": "dashboard",
        "activé": true,
        "target": {
          "mots clés": [],
          "type": "dashboard",
          "limit": 100,
          "matchAny": false
        },
        "builtIn": 1,
        "iconColor": "rgba(0, 211, 255, 1)",
        "datasource": {
          "uid": "-- Tableau de bord --",
          "type": "dashboard"
        }
      }
    ]
  },
  "description": "Tableau de bord d'exemple simple pour démarrer",
  "graphTooltip": 1,
  "schemaVersion": 38
}
```

{% endcode %}

Pour en savoir plus sur l’application de tableau de bord d’IoT Querie, voir [Studio de tableau de bord](/docs/analytics/fr/dashboard-studio.md).

Pour obtenir de l’assistance à la configuration, contactez <iotquery@navixy.com>.

## **Règles d’alertes d’expiration d’immatriculation / d’Assurance**

Les banques doivent suivre les prochaines échéances d’immatriculation et d’Assurance, car elles sont responsables des contrôles techniques, de l’immatriculation et de l’Assurance. Des Règles d’alertes émises à temps évitent les amendes et l’immobilisation des Véhicules.

{% code expandable="true" %}

```sql
Sélectionner 
    v.vehicle_id,
    v.vehicle_label,
    v.registration_number,
    v.free_Assurance_valid_till_date,
    v.liability_Assurance_valid_till
FROM raw_business_data.Véhicules v
WHERE v.free_Assurance_valid_till_date BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '30 days'
    OR v.liability_Assurance_valid_till BETWEEN CURRENT_DATE AND CURRENT_DATE + INTERVAL '30 days';
```

{% endcode %}

## **Expiration du permis de Conducteur**

Bien que ce ne soit pas toujours obligatoire, proposer des Règles d’alertes proactives d’expiration de licence est un service à valeur ajoutée. Des avertissements précoces permettent aux clients de renouveler leurs licences avant leur expiration. Veuillez noter que vous

{% code expandable="true" %}

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

{% endcode %}

## Sortie de la zone géographique (Frontière du pays) <a href="#geofence-exit-country-border" id="geofence-exit-country-border"></a>

Les contrats peuvent restreindre le Mouvement du véhicule à un territoire spécifique (par exemple, la Serbie). Quitter cette zone devrait alerter instantanément la banque afin qu’elle puisse agir (par exemple, contacter le client, immobiliser l’Actif).

Cette requête SQL est conçue pour surveiller et identifier quand un appareil quitte une zone géographique prédéfinie nommée « Tallaght Garage Geofences. » Le processus commence par la collecte et l’ordre des points géographiques qui définissent la frontière de la zone. Pour s’assurer que la frontière forme un polygone valide, le premier point est ajouté à la fin de la liste, ce qui ferme effectivement la forme. Cet ensemble fermé de points est ensuite utilisé pour créer un polygone représentant la zone géographique, qui est converti en un objet de géographie pour l’analyse spatiale.

La requête récupère ensuite les données de Suivi des appareils dans une plage de temps spécifiée, en convertissant les valeurs brutes de latitude et de longitude en points géographiques. Elle calcule si chaque point de l’appareil se trouve à l’intérieur ou à l’extérieur de la zone prédéfinie à l’aide de la fonction ST\_Contains, qui vérifie la containment spatiale. Le paramètre calculé pos indique « inside » si le point se trouve dans la zone et « outside » sinon. Enfin, la requête filtre ces résultats pour détecter les transitions où un appareil passe de l’intérieur de la zone à l’extérieur, en utilisant une fonction fenêtre pour comparer la position actuelle avec la précédente. Cette logique aide à surveiller les déplacements des appareils et à détecter les événements de sortie de zones géographiques spécifiques. Assurez-vous d’ajouter la valeur correcte pour le paramètre : `z.zone_label = 'votre_zone_label'.`

{% 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
  JOINDRE raw_business_data.Zone géographique_points g SUR g.zone_id = z.zone_id
  WHERE z.zone_label = 'votre_libellé_de_zone'
  Groupe BY z.zone_id
),
pts AS (
  SELECT device_id,
         heure de l'appareil,
         ST_SetSRID(ST_MakePoint(longitude/1e7::numeric, latitude/1e7::numeric), 4326)::geography AS geog
  DE raw_telematics_data.Suivi_data_core
  OÙ device_time ENTRE '2025-07-27 00:00:00' ET '2025-07-28 23:59:59'
),
states AS (
  SELECT p.*,
         CASE WHEN ST_Contains(z.geog::geometry, p.geog::geometry) THEN 'à l''intérieur' ELSE 'à l''extérieur' END AS pos
  FROM pts p CROSS JOIN zone z
),
filtered_states AS (
  Sélectionner
    device_id,
    heure de l'appareil,
    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 %}

## **Inspections de routine par intervalle de temps**

Certaines Missions d’Entretien reviennent selon des calendriers fixes. Le système devrait signaler les Véhicules dont la prochaine inspection/vérification est due dans un intervalle défini.

{% code expandable="true" %}

```sql
AVEC t AS (
    Sélectionner
        id_véhicule,
        description,
        date de début,
        intervalle de répétition de la date,
        make_interval(days => date_repeat_interval) AS repeat_interval
    DEPUIS raw_business_data.vehicle_service_tasks
    OÙ date_repeat_interval N'EST PAS NULL
)
Sélectionner
    id_véhicule,
    description,
    date de début,
    intervalle de répétition de la date,
    date_de_début
        + repeat_interval
            * floor(
                extract(epoch from (current_date::timestamp - start_date))
                / extract(epoch from repeat_interval)
              ) AS last_due,
    date_de_début
        + repeat_interval
            * (
                floor(
                    extract(epoch from (current_date::timestamp - start_date))
                    / extract(epoch from repeat_interval)
                ) + 1
              ) AS next_due
FROM t
WHERE (
        date_de_début
            + 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 %}

## **Service par seuil de kilometrage (mineur/majeur)**

Les services mineurs et majeurs sont déclenchés par le kilometrage depuis le dernier événement d'entretien. Lorsque les kilomètres cumulés dépassent le seuil, le service approprié doit être planifié.

Veuillez noter le `Le champ vst.description doit contenir des commentaires / une description pertinents pour l'utiliser dans les filtres du code SQL ci-dessous.`

{% code expandable="true" %}

```sql
Sélectionner
  v.vehicle_id,
  v.vehicle_label,
  km.km_since_service,
  vst.kilometrage_limit
FROM
  raw_business_data.Véhicules v
  JOIN LATERAL (
    SELECT MAX(vst.completion_date) AS date_dernier_service
    FROM raw_business_data.vehicle_service_Missions vst
    WHERE vst.vehicle_id = v.vehicle_id
      AND (vst.description ILIKE '%mineur%' OR vst.description ILIKE '%majeur%')
      AND vst.completion_date IS NOT NULL
  ) ls ON TRUE
  JOIN raw_business_data.Traceurs o ON o.Traceur_id = v.vehicle_id
  JOIN LATERAL (
    SELECT SUM(t.Voyage_distance_meters) / 1000.0 AS km_since_service
    FROM processed_common_data.Trajets t
    WHERE t.device_id = o.device_id
      AND t.Voyage_start_time > ls.last_service_date
  ) km ON VRAI
  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 '%mineur%' OR vst.description ILIKE '%majeur%')

```

{% endcode %}

## **Plafond de kilometrage et pénalités**

Les contrats de leasing plafonnent souvent le kilometrage (par ex. 25 000 km/an). Si la limite est dépassée, des clauses de pénalité s'appliquent. Le système doit comparer le kilometrage réel sur la durée du contrat avec la limite convenue et calculer les frais.

{% code expandable="true" %}

```sql
WITH driven AS (
  Sélectionner
    o.traceur_id,
    DATE_TRUNC('year', t.voyage_start_time) AS year,
    SUM(t.Voyage_distance_meters) / 1000.0 AS km_year
  FROM
    processed_common_data.Trajets t
    JOIN raw_business_data.Traceur o ON o.device_id = t.device_id
  OÙ
    t.Voyage_start_time >= '2023-01-01'::date
    ET t.Voyage_start_time < '2024-01-01'::date
  Groupe par
    o.Traceur_id, DATE_TRUNC('year', t.Voyage_start_time)
),
limites AS (
  Sélectionner
    Traceur_id,
    10000 AS km_limit,
    0.5 AS taux_de_pénalité
  FROM
    raw_business_data.objects
)
Sélectionner
  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 montant_de_pénalité
FROM
  entraîné d
  JOIN limits l ON d.object_id = l.object_id;
```

{% endcode %}

## **Surveillance des Heures moteur**

Pour les machines et les équipements agricoles, ce sont les heures de fonctionnement — et non le kilometrage — qui déterminent l'Entretien et la facturation. Les données d'heures moteur (p. ex. via CAN-Bus) doivent être surveillées et résumées.

{% code expandable="true" %}

```sql
AVEC last_service AS (
  Sélectionner
    vst.vehicle_id,
    MAX(vst.completion_date) AS date_du_dernier_service,
    MAX(vst.completion_engine_hours) AS heures_moteur_du_dernier_service
  FROM
    raw_business_data.vehicle_service_missions vst
  Groupe par
    vst.vehicle_id
),
heures_moteur_depuis_entretien AS (
  Sélectionner
    v.vehicle_id,
    SUM(t.voyage_duration_seconds) / 3600.0 AS heures_moteur_depuis_service
  FROM
    raw_business_data.Véhicules v
    JOIN raw_business_data.objects o ON o.object_id = v.object_id
    JOIN processed_common_data.trajets t ON t.device_id = o.device_id
    JOIN last_service ls ON ls.vehicle_id = v.vehicle_id
  OÙ
    t.trip_start_time > ls.last_service_date
  Groupe par
    v.vehicle_id
)
Sélectionner
  v.vehicle_id,
  v.vehicle_label,
  ls.last_service_engine_hours,
  ehs.heures_moteur_depuis_entretien,
  (COALESCE(ehs.engine_hours_since_service,0) + COALESCE(ls.last_service_engine_hours,0)) AS heures_moteur_actuelles,
  vst.engine_hours_limit
FROM
  raw_business_data.Véhicules 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 %}

## **Événements de Freinage brutal**

Le comportement lié à Eco conduite influe sur l'usure et le respect du contrat. Détecter un Freinage brutal aide la banque à attribuer l'usure prématurée des freins/pneus à un usage abusif par le Conducteur et, si nécessaire, à transférer les coûts.

La requête SQL ci-dessous calcule d'abord la vitesse en kilomètres par heure et l'écart de temps entre des points de données consécutifs pour chaque appareil. À partir de ces informations, elle calcule ensuite le taux de décélération en kilomètres par heure par seconde. Enfin, elle filtre et renvoie les enregistrements où le taux de décélération est de 20 km/h par seconde ou plus, indiquant des événements de décélération significatifs.

{% code expandable="true" %}

```sql
WITH spd AS (
  Sélectionner
    device_id,
    heure de l'appareil,
    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
  FROM
    raw_telematics_data.Suivi_data_core
  OÙ
    device_time BETWEEN '2025-07-24 00:00:00' AND '2025-07-24 23:59:59'
),
decels AS (
  Sélectionner
    device_id,
    heure de l'appareil,
    (prev_kmh - kmh) / NULLIF(dt_sec, 0) AS decel_kmh_per_sec
  FROM
    spd
  OÙ
    prev_kmh IS NOT NULL
)
SELECT *
FROM decels
WHERE decel_kmh_per_sec >= 20;
```

{% endcode %}

## **Événements d’Accélération brutale**

Une accélération agressive augmente l’usure des pneus, des transmissions, des groupes motopropulseurs et des supports moteur. L’identification de ces événements permet d’appuyer le coaching et un éventuel recouvrement des coûts.

La requête SQL ci-dessous est conçue pour identifier des événements d’accélération significatifs à partir d’un ensemble de données de Suivi. Elle calcule d’abord la vitesse en kilomètres par heure et la différence de temps entre des points de données consécutifs pour chaque appareil. À partir de ces informations, elle calcule ensuite le taux d’accélération en kilomètres par heure par seconde. Enfin, elle filtre et renvoie les enregistrements dont le taux d’accélération atteint ou dépasse un seuil spécifié, indiquant des événements d’accélération significatifs.

{% code expandable="true" %}

```sql
WITH spd AS (
  Sélectionner
    device_id,
    heure de l'appareil,
    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
  FROM
    raw_telematics_data.Suivi_data_core
  OÙ
    device_time BETWEEN '2025-07-28 00:00:00' AND '2025-07-28 23:59:59'
)
Sélectionner
  device_id,
  heure de l'appareil,
  (kmh - prev_kmh) / NULLIF(dt_sec, 0) AS accel_kmh_per_sec
FROM
  spd
OÙ
  prev_kmh IS NOT NULL
  AND (kmh - prev_kmh) / NULLIF(dt_sec, 0) >= 20;
```

{% endcode %}

## **Virages brusques / prise de virage**

Les virages serrés combinés à des changements brusques de vitesse indiquent une Eco conduite risquée. Le Suivi de ce comportement aide à détecter une utilisation inappropriée du véhicule.

Cette requête SQL est conçue pour identifier des changements significatifs de direction et de vitesse à partir de données de Suivi sur une période donnée. Elle convertit d’abord les valeurs brutes de latitude et de longitude en degrés décimaux et calcule la vitesse en kilomètres par heure. À l’aide de la fonction LAG, elle récupère les données précédentes de localisation et de vitesse pour chaque appareil, ce qui permet de calculer les changements au fil du temps. La requête calcule ensuite la variation de cap en degrés à l’aide de fonctions trigonométriques afin de déterminer le relèvement entre des points consécutifs. Elle calcule également la variation de vitesse entre ces points. Enfin, la requête filtre les résultats pour n’inclure que les enregistrements où la variation absolue du cap est d’au moins 10 degrés et la variation absolue de la vitesse d’au moins 5 km/h, identifiant ainsi des manœuvres ou événements significatifs dans les données de Suivi.

{% code expandable="true" %}

```sql
WITH pts AS (
  Sélectionner
    device_id,
    heure de l'appareil,
    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
  FROM
    raw_telematics_data.Suivi_data_core
  OÙ
    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 *
À partir du cap
WHERE abs(heading_change) >= 10
  AND abs(delta_speed) >= 5;

```

{% endcode %}

## **Détection du Contact et du ralenti**

Mesurer le temps au ralenti (contact activé, vitesse faible/nulle) aide à réduire le gaspillage de Carburant et à identifier une utilisation abusive. Les longues périodes au ralenti doivent être signalées et gérées.

{% hint style="info" %}
[Studio de tableau de bord](/docs/analytics/fr/dashboard-studio.md) et les outils similaires ne prennent pas en charge la substitution de variables (`:variable` syntaxe). Remplacez tous les paramètres par des valeurs littérales avant d'exécuter cette requête. Voir l'exemple ci-dessous pour le format correct.
{% endhint %}

{% code expandable="true" %}

```sql
WITH ign AS (
    Sélectionner
        device_id,
        heure de l'appareil,
        value::int AS ign_on
    FROM raw_telematics_data.states
    WHERE state_name = 'Contact'
      AND device_time BETWEEN :from_ts::timestamptz AND :to_ts::timestamptz
      -- Pour Dashboard Studio, remplacez :from_ts et :to_ts par des horodatages littéraux :
      -- TIMESTAMPTZ '2024-01-01 00:00:00+00' AND TIMESTAMPTZ '2024-01-07 00:00:00+00'
),
spd AS (
    Sélectionner
        device_id,
        heure de l'appareil,
        speed / 100.0 AS kmh
    DE raw_telematics_data.Suivi_data_core
    WHERE device_time BETWEEN :from_ts AND :to_ts
    -- Pour Dashboard Studio, remplacez :from_ts et :to_ts par des horodatages littéraux :
    -- TIMESTAMPTZ '2024-01-01 00:00:00+00' AND TIMESTAMPTZ '2024-01-07 00:00:00+00'
),
merged AS (
    Sélectionner
        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)
)
Sélectionner
    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
  -- Pour Dashboard Studio, remplacez :idle_speed par une valeur numérique, par exemple 5
  AND next_time IS NOT NULL
  AND (next_time - device_time) >= (:idle_min::int * INTERVAL '1 minute');
  -- Pour Dashboard Studio, remplacez :idle_min par une valeur numérique, par exemple (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/fr/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.
