Kilometrage : Jeep lue par Uconnect (releve a chaque trajet, niveau au branchement), saisie a la seconde

This commit is contained in:
Tallagrand Thierry
2026-10-04 15:01:44 +02:00
parent 74415080d2
commit a1ff5633db
3 changed files with 111 additions and 3 deletions

View File

@@ -245,7 +245,9 @@ const rejetsJournalises = new Set();
export async function ingererNiveauSaisi(sql, st) {
// L'attribut `timestamp` d'un input_datetime est en secondes epoch : pas de
// fuseau a deviner (l'etat, lui, est une heure locale sans decalage).
const at = Number(st.get(NIVEAU_AT_ENTITY)?.attributes?.timestamp) * 1000;
// A la SECONDE : un redemarrage de HA restaure l'horodatage sans ses
// millisecondes, et la meme saisie revenait en double (04/10).
const at = Math.floor(Number(st.get(NIVEAU_AT_ENTITY)?.attributes?.timestamp)) * 1000;
const niveau = Number(st.get(NIVEAU_ENTITY)?.state);
const ref = Number(st.get(NIVEAU_REF_ENTITY)?.state);
if (!Number.isFinite(at) || !Number.isInteger(niveau) || !Number.isFinite(ref) || ref <= 0) return 0;
@@ -254,3 +256,70 @@ export async function ingererNiveauSaisi(sql, st) {
[new Date(at), niveau, ref]);
return r?.rowCount || 0;
}
// ---------------------------------------------------------------------
// JEEP LUE DIRECTEMENT (04/10/2026) : integration HACS hass-uconnect (API
// Stellantis non officielle, compte du proprietaire, intervalle 15 min, sans
// PIN ni entites de commande). La voiture publie un etat a chaque evenement
// (arret, branchement) : `last_info_update_at` date les valeurs.
// - RELEVE : un par changement d'odometre (fin de trajet), date de la mise a
// jour, avec le niveau HV a cet instant. Le compteur immobile ne produit rien.
// - NIVEAU AU BRANCHEMENT : la premiere mise a jour dans les 30 min apres le
// branchement de la borne, si la Jeep se dit branchee -> niveau_saisi
// (source uconnect). Une saisie humaine posterieure reste prioritaire (la
// vue prend la derniere saisie du branchement).
// ---------------------------------------------------------------------
export const JEEP = {
odometre: 'sensor.jeep_renegade_phev_odometer',
niveau: 'sensor.jeep_renegade_phev_hvbattery_charge',
majA: 'sensor.jeep_renegade_phev_last_info_update_at',
branchee: 'binary_sensor.jeep_renegade_phev_ev_charger',
};
export async function ingererJeep(sql, lire, st, journaliser) {
const km = Number(st.get(JEEP.odometre)?.state);
const niv = Number(st.get(JEEP.niveau)?.state);
const t = Date.parse(st.get(JEEP.majA)?.state ?? '');
if (!Number.isFinite(t) || !Number.isInteger(km) || km <= 0) return 0;
const niveau = Number.isFinite(niv) && niv >= 0 && niv <= 100 ? Math.round(niv) : null;
const ts = new Date(t);
let n = 0;
const { rows: der } = await lire(
"SELECT km, ts FROM releve_km WHERE vehicule = 'JEEP' ORDER BY ts DESC LIMIT 1", []);
if (!der.length || (Number(der[0].km) !== km && ts > der[0].ts)) {
if (der.length && km < Number(der[0].km)) return 0; // compteur en baisse : on ne croit pas
const cap = Number(st.get('input_number.victron_evcs_capacity_jeep_kwh')?.state);
const auto = Number(st.get('input_number.victron_evcs_autonomie_jeep_km')?.state);
const r = await sql(
`INSERT INTO releve_km (vehicule, ts, km, niveau_pct, source, capacite_kwh, autonomie_ref_km, tout_electrique)
VALUES ('JEEP',$1,$2,$3,'uconnect',$4,$5,false) ON CONFLICT DO NOTHING`,
[ts, km, niveau, cap > 0 ? cap : null, auto > 0 ? auto : null]);
if (r?.rowCount) {
n++;
await journaliser(sql, 'vehicule', `Releve km JEEP ${km} km` + (niveau === null ? '' : `, niveau ${niveau} %`) + ' (lu par Uconnect)',
{ vehicule: 'JEEP', km, niveau, ts: ts.toISOString(), source: 'uconnect' });
}
}
if (niveau !== null && st.get(JEEP.branchee)?.state === 'on'
&& st.get('binary_sensor.victron_evcs_vehicle_connected')?.state === 'on') {
const { rows: b } = await lire(
`SELECT max(ts) AS t FROM evenement WHERE genre = 'vehicule'
AND detail->>'entite' = 'binary_sensor.victron_evcs_vehicle_connected' AND detail->>'apres' = 'on'`, []);
const branche = b[0]?.t;
if (branche && ts >= new Date(branche.getTime() - 5 * 60000) && ts <= new Date(branche.getTime() + 30 * 60000)) {
const { rows: deja } = await lire(
"SELECT 1 FROM niveau_saisi WHERE source = 'uconnect' AND saisi_a >= $1", [new Date(branche.getTime() - 5 * 60000)]);
if (!deja.length) {
const r = await sql(
"INSERT INTO niveau_saisi (saisi_a, niveau_pct, ref_kwh, source) VALUES ($1,$2,NULL,'uconnect') ON CONFLICT DO NOTHING",
[ts, niveau]);
if (r?.rowCount) {
n++;
await journaliser(sql, 'vehicule', `Niveau JEEP au branchement : ${niveau} % (lu par Uconnect)`,
{ niveau, ts: ts.toISOString(), branchement: branche.toISOString() });
}
}
}
}
return n;
}