[InfluxDB v1.8.x] Aller encore plus loin!

Il y a forcément un truc que je loupe car ce serait surprenant quand même, surtout pour une base de données orientée séries temporelles

Bon tu me croiras ou pas mais en voulant créer un topic sur le forum influxdb dédié à ce bug, je n’ai pas réussi à le reproduire…

C’est mieux comme ça :wink:

Je vais finir par croire que je deviens fou, heureusement que les impressions d’écrans sont là pour me prouver à moi même que j’ai vu ces comportements :face_with_head_bandage:

Quelles captures ? :rofl: :rofl:

Donc du coup, c’est un truc du package experimental qui manipule mal les TZ

1 « J'aime »

Je vais essayer de creuser en torturant un peu les manips et voir ce que « date.truncate » et « experimental.addDuration » donne. En tous cas d’après ce que j’ai lu dans la doc, cela est sensé bien fonctionner.

J’aime avancer petit à petit, doucement mais surement comme on dit. C’est une manière d’apprendre et un loisir pour moi :slight_smile:

Du coup je viens de faire un test réel :

  • Ecriture chaque minute de la température de mon jardin dans influxDB via nodered
  • Attente pendant 2 jours
  • Test du script ci-dessous qui fonctionne nikel !

import "date"
import "experimental"
TODAY = date.truncate(t: now(), unit: 1d )
YESTERDAY = experimental.addDuration(d: -1d, to: TODAY)
DATA = from(bucket: "DatabaseBaptisteV01")
  |> range(start: YESTERDAY, stop: TODAY)
  |> filter(fn: (r) => r["_measurement"] == "°C")
  |> filter(fn: (r) => r["_field"] == "value")
  |> filter(fn: (r) => r["instance"] == "Test")
  |> filter(fn: (r) => r["entity_id"] == "Jardin")
  |> filter(fn: (r) => r["city"] == "Lougres")
DATA
  |> mean()
  |> map(fn: (r) => ({r with _time: YESTERDAY}))
  |> set(key: "statistics", value: "mean")
  |> set(key: "source", value: "influxdb")
  |> to(bucket: "DatabaseBaptisteV02")
DATA
  |> min()
  |> map(fn: (r) => ({r with _time: YESTERDAY}))
  |> set(key: "statistics", value: "min")
  |> set(key: "source", value: "influxdb")
  |> to(bucket: "DatabaseBaptisteV02")
DATA
  |> max()
  |> map(fn: (r) => ({r with _time: YESTERDAY}))
  |> set(key: "statistics", value: "max")
  |> set(key: "source", value: "influxdb")
  |> to(bucket: "DatabaseBaptisteV02")

Le résultat :

CONCLUSION

Reste plus qu’à trouver une manière d’exécuter le script en automatique et surtout trouver un moyen pour que le script effectue ceci pour chaque variable sans devoir répliquer le code…

2 « J'aime »

Bien joué…
Pour l’équivalent du cron c’est facile

Donc 1 ligne de plus

Du coup je viens de créer une tache qui tournera tous les jours à 1h du matin (UTC je pense).

Le code :

import "date"
import "experimental"

option task = {name: "Daily_stat-v01", cron: "0 0 1 * * ?"}

TODAY = date.truncate(t: now(), unit: 1d)
YESTERDAY = experimental.addDuration(d: -1d, to: TODAY)
DATA = from(bucket: "DatabaseBaptisteV01")
	|> range(start: YESTERDAY, stop: TODAY)
	|> filter(fn: (r) =>
		(r["_measurement"] == "°C"))
	|> filter(fn: (r) =>
		(r["_field"] == "value"))
	|> filter(fn: (r) =>
		(r["instance"] == "Test"))
	|> filter(fn: (r) =>
		(r["entity_id"] == "Jardin"))
	|> filter(fn: (r) =>
		(r["city"] == "Lougres"))

DATA
	|> mean()
	|> map(fn: (r) =>
		({r with _time: YESTERDAY}))
	|> set(key: "statistics", value: "mean")
	|> set(key: "source", value: "influxdb")
	|> to(bucket: "DatabaseBaptisteV02")
DATA
	|> min()
	|> map(fn: (r) =>
		({r with _time: YESTERDAY}))
	|> set(key: "statistics", value: "min")
	|> set(key: "source", value: "influxdb")
	|> to(bucket: "DatabaseBaptisteV02")
DATA
	|> max()
	|> map(fn: (r) =>
		({r with _time: YESTERDAY}))
	|> set(key: "statistics", value: "max")
	|> set(key: "source", value: "influxdb")
	|> to(bucket: "DatabaseBaptisteV02")

Autre point aussi, stocker tout en UTC me va bien pour les valeurs brutes mais pour le traitement des données avec le changement d’heure je m’interroge. Je me demande s’il n’y a pas un truc à faire avec ceci :
https://www.influxdata.com/blog/time-zones-in-flux/

Tu es certain de l’impact ?
1 min, 1 mean, 1 max par jour que ce soit 0h utc ou 0h utc+1 on s’en fiche un peu, ça reste 1 valeur par jour

L’impact je ne pense pas qu’il y en ai vraiment un, surtout pour la température, mais pour l’élec je sais pas car on crée un offset d’une heure donc pour une intégrale…
Dans tous les cas j’aimerai savoir comment faire car déjà je suis un peu maniac et en plus cela me fera une compétence de plus. :slight_smile:

@Pulpy-Luke ,
As-tu trouvé une solution pour généraliser le script min/max/mean ?
En gros comment faire pour appliquer le script aux autres « entity_id » sans dupliquer le script autant de fois qu’il y a de capteurs ce qui deviendrait ingérable dans le temps.

J’ai crée un post à ce sujet :
https://community.influxdata.com/t/how-to-write-a-generic-task-for-all-table/23348

Pour l’instant non
J’ai dans l’idée de faire une requête pour faire la liste des entity_id… + une boucle de 3 fonctions (min/mean/max) par entity_id.
Mais je suis vraiment mauvais en base de données, pê des group_by à ajouter aussi

Comme ça: Use parameterized Flux queries | InfluxDB Cloud (TSM) Documentation

Apparemment il faut passer par l’API pour faire ça.
influxdb, c’est plutôt bien. Mais, je trouve ça très tordu comme approche. Là et en général…

Donc, tu gardes ta query du côté HA ou NR et avec les paramètre tu t’en sors.
Ca, c’est la théorie. Tu nous diras pour la pratique :slight_smile:

Je suis toujours en influxdb 1.x avec le vieux langage de requête. Je les construis (péniblement) dans grafana… Avec flux c’est du sans filet. Comme j’ai peur du vide, je reste au bord.

1 « J'aime »

Il y a le créateur pour filer un coup de main à la construction c’est pas mal pour générer la bonne syntaxe
influx

pour le reste effectivement c’est pas fluide

Salut @golfvert ,

Bon visiblement c’est beaucoup plus simple que prévu, il suffit de réduire le filtre de sélection pour prendre toute les tables et cela fait le calcul table par table, exactement ce que je voulais.

  • Par exemple si je sélectionne toute mes données, cela me donne 5 tables (entourés en rouge) qui chacune contient une série de donnée (flèche rouge).

  • Si maintenant j’applique par exemple le calcul de la moyenne sur ce résultat, j’obtiens bien une valeur par table correspondant à la moyenne. :slight_smile:

Du coup j’ai mis à jour ma « task » si cela intéresse quelqu’un :

  • Correction du CRON
  • Simplification des filtres pour prendre en compte l’ensemble des tables
  • Arrondi des valeurs min/mean/max à 1 chiffre après la virgule via math.round
import "date"
import "experimental"
import "math"

option task = {name: "Daily_stat-v01", cron: "0 1 * * *"}

TODAY = date.truncate(t: now(), unit: 1d)
YESTERDAY = experimental.addDuration(d: -1d, to: TODAY)
DATA = from(bucket: "DatabaseBaptisteV01")
	|> range(start: YESTERDAY, stop: TODAY)
	|> filter(fn: (r) =>
		(r["_measurement"] == "°C"))
	|> filter(fn: (r) =>
		(r["_field"] == "value"))

DATA
	|> mean()
	|> map(fn: (r) =>
		({r with _time: YESTERDAY}))
	|> set(key: "statistics", value: "mean")
	|> set(key: "source", value: "influxdb")
	|> map(fn: (r) =>
		({r with _value: math.round(x: r._value * 10.0) / 10.0}))
	|> to(bucket: "DatabaseBaptisteV02")
DATA
	|> min()
	|> map(fn: (r) =>
		({r with _time: YESTERDAY}))
	|> set(key: "statistics", value: "min")
	|> set(key: "source", value: "influxdb")
	|> to(bucket: "DatabaseBaptisteV02")
DATA
	|> max()
	|> map(fn: (r) =>
		({r with _time: YESTERDAY}))
	|> set(key: "statistics", value: "max")
	|> set(key: "source", value: "influxdb")
	|> to(bucket: "DatabaseBaptisteV02")

[EDIT] :

  • Le calcul a bien eu lieu à 1h00 ce matin pour l’ensemble de mes capteurs !
  • Plus qu’à exploiter le visuel sous grafana maintenant…
1 « J'aime »

Bien joué.
Du coup j’ai fait ça aussi à l’arrache et ça fonctionne.
Micro optimisation de mon côté, mettre les bd source et destination en variable.

Il doit y avoir moyen de faire une fonction pour faire les 3 opérations, je chercherai ce week-end

import "date"
import "experimental"
import "math"

option task = {
    name: "Downsample Températures",
    cron: "0 1 * * *",
}

TODAY = date.truncate(t: now(), unit: 1d)
YESTERDAY = experimental.addDuration(d: -1d, to: TODAY)
FROM_DB = "homeassistantDB"
TO_DB = "homeassistantDB2"

DATA = from(bucket: FROM_DB)
    |> range(start: YESTERDAY, stop: TODAY)
    |> filter(
        fn: (r) => r["_measurement"] == "°C",
    )
    |> filter(
        fn: (r) => r["_field"] == "value",
    )

DATA
    |> mean()
    |> map(
        fn: (r) => ({r with _time: YESTERDAY}),
    )
    |> set(key: "statistics", value: "mean")
    |> set(key: "source", value: "influxdb")
    |> map(
        fn: (r) => ({r with _value: math.round(x: r._value * 10.0) / 10.0}),
    )
    |> to(bucket: TO_DB)

DATA
    |> min()
    |> map(
        fn: (r) => ({r with _time: YESTERDAY}),
    )
    |> set(key: "statistics", value: "min")
    |> set(key: "source", value: "influxdb")
    |> to(bucket: TO_DB)

DATA
    |> max()
    |> map(
        fn: (r) => ({r with _time: YESTERDAY}),
    )
    |> set(key: "statistics", value: "max")
    |> set(key: "source", value: "influxdb")
    |> to(bucket: TO_DB)
1 « J'aime »

Hello !

Je partage ma tâche bricolé hier soir pour extraire ma consommation journalière d’électricité dans une seconde base :

Le code :

import "date"
import "experimental"
import "math"

option task = {
    name: "Daily_stat-v02",
    cron: "0 1 * * *",
}

TODAY = date.truncate(t: now(), unit: 1d)
YESTERDAY = experimental.addDuration(d: -1d, to: TODAY)

DATA = from(bucket: "DatabaseBaptisteV01")
    |> range(start: YESTERDAY, stop: TODAY)
    |> filter(fn: (r) => r["_measurement"] == "kWh")
    |> filter(fn: (r) => r["_field"] == "value")

DATA
    |> set(key: "source", value: "calculated")
    |> reduce(
        fn: (r, accumulator) => ({
            min: if r._value < accumulator.min then r._value else accumulator.min,
            max: if r._value > accumulator.max then r._value else accumulator.max,
            _time: r._time,
        }),
        identity: {min: 10000000000.0, max: -10000000000.0, _time: YESTERDAY},
    )
    |> map(fn: (r) => ({r with _time: YESTERDAY}))
    |> map(fn: (r) => ({r with _value: math.round(x: (r.max - r.min) * 100.0) / 100.0}))
    |> to(bucket: "DatabaseBaptisteV02")

Ce qui donne :