# Sauvegarder ou pas l'historique d'une fonctionnalités précise

**URL:** <https://community.gladysassistant.com/t/sauvegarder-ou-pas-lhistorique-dune-fonctionnalites-precise/7241>\
**Category:** Développement\
**Created:** [Mai 3, 2022, 4:51 UTC](https://community.gladysassistant.com/t/sauvegarder-ou-pas-lhistorique-dune-fonctionnalites-precise/7241 "2022-05-03T16:51:33Z")\
**Posts on this page:** 1\
**Showing post:** 9

<div class="post-metadata">

**Author:** ![Terdious](https://gladys-assistant-community.b-cdn.net/user_avatar/community.gladysassistant.com/terdious/32/6316_2.png) [@Terdious](https://community.gladysassistant.com/u/Terdious)\
**Post date:** [Mai 5, 2022, 7:33 UTC](https://community.gladysassistant.com/t/sauvegarder-ou-pas-lhistorique-dune-fonctionnalites-precise/7241/9 "2022-05-05T07:33:26Z")

</div>

@pierre-gilles, @AlexTrovato, @VonOx,  
Je me permet de relancer le sujet le considérant comme possiblement critique sur certaines instance un peu lourdes.  
Pour rappel les sujets du débat :

> [@Rétention uniquement des valeurs aggrégées](https://community.gladysassistant.com/t/retention-uniquement-des-valeurs-aggregees/7064):
>
> Je propose d’ajouter une option pour ne garder qu’uniquement les valeurs aggrégées par période et supprimer les valeurs brut passé 24h (seuil configurable). Actuellement mes prises connectées renvoient une valeur / minute, 24h / 24h depuis plus d’un an. Ma base de données atteint 3Gb, alors qu’elle pourrait être de quelques centaines de Mio.

> [@\[DB de 5Go\] Lenteurs au premier démarrage](https://community.gladysassistant.com/t/db-de-5go-lenteurs-au-premier-demarrage/7211):
>
> Salut à tous, salut @pierre-gilles, J’en parle sur le forum avant de définir ensemble ce que tu veux voir sur GitHub wink Ca fait un moment que je le ressent, mais j’ai pu le confirmer maintenant en enregistrant mon écran. Démarrage de Gladys Si le conteneur de Gladys est arrêté puis démarré à nouveau (après une MAJ par exemple), le premier chargement des graphiques prend énormément de temps. Cela est certainement dû en partie à la taille de la DB 4.5Go ! Mais pas que, puisque tu as expli…

> [@Case à cochée "Ne pas enregistrer les nouvelles valeurs identiques" + Choix de durée de backup indépendant pour chaque Device Features](https://community.gladysassistant.com/t/case-a-cochee-ne-pas-enregistrer-les-nouvelles-valeurs-identiques-choix-de-duree-de-backup-independant-pour-chaque-device-features/5963):
>
> Bonjour, Suite à un gros retour d’expérience concernant l’usage et la taille de DB, je propose cette nouvelle Feature Request et je pense qu’elle rapidement devenir urgente. Je m’explique : J’ai 92 Devices et 143 Devices Features composés de : 4 caméras (avec un poll compris entre 10s et 1 minutes - pour certaines il serait nécessaire d’avoir un temps réel voir toutes les 2 secondes de temps en temps, mais ce n’est pas possible : rend l’interface trop lente), 2 devices / 9 devices features…

Si on peut définir la feuille de route au complet ainsi que valider un cahier des charges, je veux bien m’en occuper autant que possible et sortir un premier jet rapidement.

Pour rappel également, la proposition que je faisais (modifié selon la proposition de Pierre-Gilles dans l’ordre) pour entamer la discussion :

- _ **1ère PR** _ :

- _ **2ème PR** _ :

> **Proposition de Code**
>
> ```auto
> const db = require('../../models');
> const logger = require('../../utils/logger');
> const { EVENTS, WEBSOCKET_MESSAGE_TYPES } = require('../../utils/constants');
> 
> /**
> * @description Save new device feature state in DB.
> * @param {Object} deviceFeature - A DeviceFeature object.
> * @example
> * saveLastValueChanged({
> * id: 'fc235c88-b10d-4706-8b59-fef92a7119b2',
> * selector: 'my-light'
> * });
> */
> async function saveLastStateChanged(deviceFeature) {
> // logger.debug(`device.saveLastStateChanged of deviceFeature ${deviceFeature.selector}`);
> const now = new Date();
> // save local state in RAM
> this.stateManager.setState('deviceFeature', deviceFeature.selector, {
> last_value_changed: now,
> });
> await db.sequelize.transaction(async (t) => {
> // update deviceFeature lastValue in DB
> await db.DeviceFeature.update(
> {
> last_value_changed: now,
> },
> {
> where: {
> id: deviceFeature.id,
> },
> },
> {
> transaction: t,
> },
> );
> });
> 
> // send websocket event
> this.eventManager.emit(EVENTS.WEBSOCKET.SEND_ALL, {
> type: WEBSOCKET_MESSAGE_TYPES.DEVICE.NEW_STATE_NO_CHANGED,
> payload: {
> device_feature_selector: deviceFeature.selector,
> last_value_changed: now,
> },
> });
> }
> 
> module.exports = {
> saveLastStateChanged,
> };
> 
> ```

- Lorsque la valeur change de nouveau, on repasse par la fonction du fichier server/lib/device/device.saveState.js qu’on doit modifier pour réenregistrer, avant la nouvelle valeur, l’ancienne valeur déjà en base, pour avoir une courbe ajustée :

> **Proposition de Code**
>
> ```auto
> const db = require('../../models');
> const logger = require('../../utils/logger');
> const { EVENTS, WEBSOCKET_MESSAGE_TYPES } = require('../../utils/constants');
> const { BadParameters } = require('../../utils/coreErrors');
> 
> const DEFAULT_OPTIONS = {
> skip: 0,
> order_dir: 'DESC',
> order_by: 'created_at',
> };
> 
> /**
> * @description Save new device feature state in DB.
> * @param {Object} deviceFeature - A DeviceFeature object.
> * @param {number} newValue - The new value of the deviceFeature to save.
> * @example
> * saveState({
> * id: 'fc235c88-b10d-4706-8b59-fef92a7119b2',
> * selector: 'my-light'
> * }, 12);
> */
> async function saveState(deviceFeature, newValue) {
> if (Number.isNaN(newValue)) {
> throw new BadParameters(`device.saveState of NaN value on ${deviceFeature.selector}`);
> }
> const optionsWithDefault = Object.assign({}, DEFAULT_OPTIONS);
> 
> // logger.debug(`device.saveState of deviceFeature ${deviceFeature.selector}`);
> const now = new Date();
> const previousDeviceFeature = this.stateManager.get('deviceFeature', deviceFeature.selector);
> const previousDeviceFeatureValue = previousDeviceFeature ? previousDeviceFeature.last_value : null;
> 
> const previousDeviceFeatureLastValueChanged = previousDeviceFeature ? previousDeviceFeature.last_value_changed : null;
> 
> const deviceFeaturesState = await db.DeviceFeatureState.findOne({
> attributes: ['device_feature_id', 'value', 'created_at'],
> order: [[optionsWithDefault.order_by, optionsWithDefault.order_dir]],
> where: {
> device_feature_id: deviceFeature.id,
> },
> });
> const previousDeviceFeatureStateLastValueChanged = deviceFeaturesState ? deviceFeaturesState.created_at : 0;
> 
> // save local state in RAM
> this.stateManager.setState('deviceFeature', deviceFeature.selector, {
> last_value: newValue,
> last_value_changed: now,
> });
> // update deviceFeature lastValue in DB
> await db.DeviceFeature.update(
> {
> last_value: newValue,
> last_value_changed: now,
> },
> {
> where: {
> id: deviceFeature.id,
> },
> },
> );
> // if the deviceFeature should keep history, we save a new deviceFeatureState
> if (deviceFeature.keep_history) {
> // if the previous created deviceFeatureState is different of deviceFeature
> // last value changed, we save a new deviceFeatureState of old state
> if (previousDeviceFeatureLastValueChanged - previousDeviceFeatureStateLastValueChanged > 0) {
> await db.DeviceFeatureState.create({
> device_feature_id: deviceFeature.id,
> value: previousDeviceFeatureValue,
> created_at: previousDeviceFeatureLastValueChanged,
> });
> }
> await db.DeviceFeatureState.create({
> device_feature_id: deviceFeature.id,
> value: newValue,
> });
> }
> // });
> 
> // send websocket event
> this.eventManager.emit(EVENTS.WEBSOCKET.SEND_ALL, {
> type: WEBSOCKET_MESSAGE_TYPES.DEVICE.NEW_STATE,
> payload: {
> device_feature_selector: deviceFeature.selector,
> last_value: newValue,
> last_value_changed: now,
> },
> });
> 
> // check if there is a trigger matching
> this.eventManager.emit(EVENTS.TRIGGERS.CHECK, {
> type: EVENTS.DEVICE.NEW_STATE,
> device_feature: deviceFeature.selector,
> previous_value: previousDeviceFeatureValue,
> last_value: newValue,
> last_value_changed: now,
> });
> }
> 
> module.exports = {
> saveState,
> };
> 
> ```

Exemple :

> **si on reçoit pour une puissance consommée**
>
> ```auto
> {
> value: 1014.7,
> created_at: 2022-04-19 04:20:13.277 +00:00
> },
> {
> value: 1014.9,
> created_at: 2022-04-19 04:30:13.277 +00:00
> },
> {
> value: 1014.9,
> created_at: 2022-04-19 04:40:13.277 +00:00
> },
> {
> value: 1014.9,
> created_at: 2022-04-19 04:50:13.277 +00:00
> },
> {
> value: 1014.9,
> created_at: 2022-04-19 05:00:13.277 +00:00
> },
> {
> value: 1014.9,
> created_at: 2022-04-19 05:10:13.277 +00:00
> },
> {
> value: 78.0,
> created_at: 2022-04-19 05:20:13.277 +00:00
> }
> 
> ```
> 
> On retrouvera en DB seulement
> 
> ```auto
> {
> value: 1014.7,
> created_at: 2022-04-19 04:20:13.277 +00:00
> },
> {
> value: 1014.9,
> created_at: 2022-04-19 04:30:13.277 +00:00
> },
> // ici on a pas sauvegardé les valeurs identiques
> {
> value: 1014.9,
> created_at: 2022-04-19 05:10:13.277 +00:00
> },
> // Après avoir écrit la valeur ci-dessous, on a renvoyé
> {
> value: 78.0,
> created_at: 2022-04-19 05:20:13.277 +00:00
> }
> 
> ```

_Question_ : Est-ce utile ou indispensable de voir quelque chose pour les données agrégées ? Je m’explique : suite à lecture du post de lmilcent (cité précédemment concernant la rétention), lors de la 1ère PR il faut tenir compte de cela pour ne pas casser l’agrégation des données si le keep\_history de la feature est réglé sur 1 jour. L’agrégation des 1 an devra tout de même conserver toutes ses données sauf si le keep\_history est réglé à «&nbsp;OFF&nbsp;», n’est ce pas ??

---

_[View the full topic](https://community.gladysassistant.com/t/sauvegarder-ou-pas-lhistorique-dune-fonctionnalites-precise/7241)._
