Skip to content

Event detail endpoint is obsolete #486

Closed

Description

@fhewitt

Hi dear community,

Context

Today, we (the Hilo team) added the deprecation header on the event details endpoints : /GDService/v1/api/locations/{locationId}/events/{eventId}.

This endpoint is not used anymore inside the Hilo application, but we kept it up and functional for Home Assistant.

That being said, it's not tested so much anymore and it will, at some point, be removed or just stop working properly.

New Approach

You should be able to achieve the same result through websocket/signalR :
https://api.hiloenergie.com/ChallengeHub

Request Message: SubscribeToChallenge with a { eventId: long, locationId: long } payload

Which will trigger these 2 events in response

ChallengeDetailsInitialValuesReceived

      {
        "required": [
          "progress",
          "isParticipating",
          "isConfigurable",
          "id",
          "period",
          "phases"
        ],
        "type": "object",
        "properties": {
          "progress": {
            "enum": [
              "none",
              "scheduled",
              "inProgress",
              "completed"
            ],
            "type": "string",
            "default": "none"
          },
          "isParticipating": {
            "type": "boolean"
          },
          "isConfigurable": {
            "type": "boolean"
          },
          "currentPhase": {
            "enum": [
              "none",
              "preheat",
              "reduction",
              "recovery"
            ],
            "type": "string",
            "default": "none",
            "nullable": true
          },
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "period": {
            "enum": [
              "none",
              "am",
              "pm"
            ],
            "type": "string",
            "default": "none"
          },
          "phases": {
            "$ref": "#/components/schemas/eventPhases"
          }
        }
      },

ChallengeConsumptionUpdatedValuesReceived

     {
        "required": [
          "generatedTimeUTC"
        ],
        "type": "object",
        "properties": {
          "currentWh": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "baselineWh": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "estimatedReward": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "generatedTimeUTC": {
            "minLength": 1,
            "type": "string",
            "format": "date-time"
          },
          "cumulativeBaselinePoints": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/cumulativeConsumptionPoints"
            }
          },
          "cumulativeConsumptionPoints": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/cumulativeConsumptionPoints"
            }
          }
        }
      },

"cumulativeConsumptionPoints": {
        "required": [
          "timeUTC",
          "wh"
        ],
        "type": "object",
        "properties": {
          "timeUTC": {
            "minLength": 1,
            "type": "string",
            "format": "date-time"
          },
          "wh": {
            "type": "number",
            "format": "double"
          }
        }
      },

Obviously, these format could change in the future (probably not for this season).

Sorry that I can't be a lot more helpful, especially in this time of the year.

Activity

  1. changed the title [-]Event detail endpoint is deprecated[/-] [+]Event detail endpoint is obsolete[/+] on Oct 24, 2024
  2. ic-dev21 commented on Oct 25, 2024

    @ic-dev21
    Collaborator

    @fhewitt un gars s'essaye, y a-t-il un espoir de pull request de ta part?

  3. fhewitt commented on Oct 25, 2024

    @fhewitt
    Author

    Non, je ne connais pas le projet du tout, ni Python d'ailleurs. Je ne peux pas m'avancer concernant mes collègues, mais là tout de suite, ça ne sera pas priorisé.

    Par contre, je m'engage à repasser ici si on s'apprête à l'arracher et que le ticket est toujours ouvert, pour te dire que tu n'a plus le choix. Et ça ne sera certainement pas avant Q1 2025. D'ici là, l'espoir reste permis.

  4. ic-dev21 commented on Oct 26, 2024

    @ic-dev21
    Collaborator

    @fhewitt je suis pas une brute (c'est pas mon code, je l'apprends sur le tas), je vois que l'on utilise cet endpoint dans cette fonction-là:

    events = await self._hilo._api.get_gd_events(self._hilo.devices.location_id)

    Qui par la suite appelle celle-ci:

    https://github.com/dvd-dev/python-hilo/blob/99c73b76b74b8539672e68bbdd8942f63ba347e7/pyhilo/api.py#L531-L600

    Je comprends vite quand on m'explique longtemps.

    Est-ce que l'on souhaite obtenir que l'URL passe de:

    /GDService/v1/api/locations/{locationId}/events/{eventId}
    

    À

    /ChallengeHub/v1/api/locations/{locationId}/events/{eventId}
    

    Ou bien j'ai mal saisi l'information? Si j'ai bien saisi, ça me retourne une erreur 404 ici dans mon test en local.

    J'ai pas nécessairement besoin d'aide côté Python en tant que tel, plus ma compréhension de ce qui doit changer.

  5. valleedelisle commented on Oct 26, 2024

    @valleedelisle
    Contributor

    Ce code ne marchera plus. Il va falloir passer par le websocket et subscribe à ce nouvel url. Je suis aussi un noob avec tout ce qui est async et websocket.

    Je crois qu'on va avoir besoin de deux instances de WebsocketClient. Faut faire de quoi avec ce hack la qui hardcode le DeviceHub dans la methode de connexion. À moins qu'on puisse subscribe à plusieurs endpoints avec la même instance?

    Donc cette instance est créée dans le _post_init, je crois qu'on pourrait en créé une deuxième à cet endroit à moins qu'on puisse utilisé la même pour les deux endpoint, je ne suis pas assez familier avec tout ça.

    Ensuite, tout dépendemment si on utilise une ou deux instances de websocket client, on va devoir adapter tout le code ici pour supporter ces deux connexions. Tant qu'à le faire pour deux, on s'arrange pour que ça soit dynamique et pouvoir subscribe à une liste de websocket. Faudrait aussi ajuster le callback pour qui soit dynamique tant qu'à ça.

    C'est une pas pire job tout ça, surtout pour des noobs comme nous qui ont codé ça instinctivement en snoopant le traffic de l'app. Q1 2025 arrive très vite. C'est vraiment sympathique d'Hilo d'avoir supporté le REST API pour les events pour nous aussi longtemps mais ça serait aussi bien que Hilo puisse engagé un consultant afin de migrer vers la nouvelle infra. Un professionnel python devrait pouvoir comprendre et coder ça en pas trop long à mon avis.

  6. Leicas commented on Nov 12, 2024

    @Leicas
    Contributor

    @fhewitt , en essayant d’implémenter je me frotte à une erreur 401 sur la négociation avec https://api.hiloenergie.com/ChallengeHub, est-ce que le bearer token ne serrait pas un token général ?

    En utilisant le token obtenu par Oauth ça veut vraiment pas, alors je me demandais si ce n'était pas un token générique ou à obtenir via une autre méthode.
    Merci :)

  7. ic-dev21 commented on Nov 16, 2024

    @ic-dev21
    Collaborator

    Salut gang,

    @Leicas @valleedelisle @elafontaine
    J'ai eu un peu de temps pour discuter avec @nlz242 car j'avais pas mal de trouble à établir un POST pour obtenir mon URL Websocket de mon côté en dev.

    Au final, le token qui doit être utilisé pour la connexion initiale au websocket du ChallengeHub est ici:

    https://github.com/dvd-dev/python-hilo/blob/39cc8e28bbf9bbac9636f052f78b1045eda3e7b2/pyhilo/api.py#L130-L135

    Pour fins de connexion avec POSTMAN j'ai modifié le code ainsi pour obtenir mon token et confirmer que j'avais la bonne affaire:

        async def async_get_access_token(self) -> str:
            """Return a valid access token."""
            if not self._oauth_session.valid_token:
                await self._oauth_session.async_ensure_token_valid()
    
            access_token = str(self._oauth_session.token["access_token"])
            LOG.debug(f"ic-dev21 {access_token}")
            return str(self._oauth_session.token["access_token"])
    

    Résultat:
    image

    Donc il est possible d'obtenir notre WSS URL à partir de là!

    Je suis pas allé plus loin encore car je suis pas mal moins à l'aise avec cette portion là du code mais je voulais informer n'importe qui qui veut s'essayer de son côté comment obtenir le bon chemin!

  8. Leicas commented on Nov 16, 2024

    @Leicas
    Contributor

    Un peu de progrès, j’ai partagé ça sur dvd-dev/python-hilo#223 pour aider les autres qui travaille dessus, c’est pas très loin encore, mais la partie négo du WS avec les tokens fonctionne chez moi maintenant.

    La partie qui voulait vraiment pas et qui m’a tourné le crane c’est https://github.com/dvd-dev/python-hilo/pull/223/files#diff-9ee2958872aa7ec04a975bc72c01bd591c0babd6cdabed3344be35f80fff180dR234 .

  9. valleedelisle commented on Nov 20, 2024

    @valleedelisle
    Contributor

    Nice job! Merci pour ta contribution. Idéalement, il faudrait que ça soit dynamique au lieu de faire un websocket2. Peut-être un autre classe pour englober le tout? Je manque énormément de temps ces temps-ci, si Hilo pouvait faire des journées de 32h ça m'aiderait. Mais bon, si ça fonctionne comme ça, j'ai pas de problème à merger ce code et j'essaierai d'optimiser éventuellement.

  10. added a commit that references this issue on Nov 26, 2024
    f4b24ef
  11. ic-dev21 commented on Dec 18, 2024

    @ic-dev21
    Collaborator

    Manager class est faite dans pyhilo, voir dvd-dev/python-hilo#224, c'est pas mergé encore d'un coup que j'me sois planté mais ici en test c'est fonctionnel.

    #505 est un bon premier pas, merci beaucoup à @Leicas, je vais continuer à jouer avec pendant le temps des fêtes.

    Toute contribution ou essai de contribution sera apprécié

  12. sm-Fifteen commented on Dec 21, 2024

    @sm-Fifteen

    @fhewitt: Les structures de données JSON Schema, c'est copié d'une source de données publiquement accessible ou est-ce que c'est juste un cadeau? C'est généralement assez commode d'avoir les définitions d'API pour pouvoir mock ce que l'API renverrait ou même juste pour être certain que les modèles de données sont bons.

  13. ic-dev21 commented on Dec 21, 2024

    @ic-dev21
    Collaborator

    @fhewitt: Les structures de données JSON Schema, c'est copié d'une source de données publiquement accessible ou est-ce que c'est juste un cadeau? C'est généralement assez commode d'avoir les définitions d'API pour pouvoir mock ce que l'API renverrait ou même juste pour être certain que les modèles de données sont bons.

    @sm-Fifteen passes nous voir sur discord quand tu auras un moment, je peux au moins te faire un topo d’où c’est rendu

    https://discord.gg/d94yGKnz

  14. 1 remaining item

  15. ic-dev21 commented on Dec 26, 2024

    @ic-dev21
    Collaborator

    Info supplémentaire:

    SubscribeToChallengeList({long LocationId})
    

    retourne la liste des défi en cours/prévu

    UnsubscribeFromChallengeList({long LocationId})
    
    SubscribeToChallenge({long LocationId, long EventId})
    
    UnsubscribeFromChallenge({long LocationId, long EventId})
    
    RequestChallengeConsumptionUpdate({long LocationId, long EventId})
    
  16. ic-dev21 commented on Dec 27, 2024

    @ic-dev21
    Collaborator

    Ajouts dans #505, si on le roule avec dvd-dev/python-hilo#224 on a quelque chose de fonctionnel

  17. ic-dev21 commented on Dec 30, 2024

    @ic-dev21
    Collaborator

    Plus d'info:
    Le data de tous nos websockets ouverts nous reviens ici:
    https://github.com/dvd-dev/python-hilo/blob/0c9fca95f7fa7cfff5ee966d57699230fc36f89b/pyhilo/api.py#L246-L259

    Il va falloir remodeler
    https://github.com/dvd-dev/python-hilo/blob/0c9fca95f7fa7cfff5ee966d57699230fc36f89b/pyhilo/api.py#L543-L637

    Pour digérer l'info des défis je pense... Je ne sais pas si on va pas avoir besoin d'une méthode ou autre pour envoyer l'info aux bonnes places...

  18. ic-dev21 commented on Dec 30, 2024

    @ic-dev21
    Collaborator

    Ce qui revient par le /Challengehub:

    {
        "type": 1,
        "target": "ChallengeDetailsInitialValuesReceived",
        "arguments": [
            {
                "currentPhase": null,
                "parameters": {
                    "mode": "extreme",
                    "devices": [
                        {
                            "id": 454741,
                            "deviceUid": "BC33ACFFFE2BABDD",
                            "name": "Thermostat Cuisine",
                            "roomName": "Salon/Cuisine",
                            "optOut": false,
                            "preheat": true,
                            "deviceType": "Thermostat"
                        },
                        {
                            "id": 454744,
                            "deviceUid": "BC33ACFFFE21C79A",
                            "name": "Thermostat chambre des maîtres",
                            "roomName": "Chambre des maîtres",
                            "optOut": false,
                            "preheat": true,
                            "deviceType": "Thermostat"
                        },
                        {
                            "id": 454747,
                            "deviceUid": "5C0272FFFE823394",
                            "name": "Thermostat salle de bain",
                            "roomName": "Salle de bain en haut",
                            "optOut": true,
                            "preheat": false,
                            "deviceType": "Thermostat"
                        },
                        {
                            "id": 454750,
                            "deviceUid": "BC33ACFFFE296648",
                            "name": "Thermostat chambre XXX",
                            "roomName": "Chambre XXX",
                            "optOut": false,
                            "preheat": true,
                            "deviceType": "Thermostat"
                        },
                        {
                            "id": 454756,
                            "deviceUid": "BC33ACFFFE2BAD65",
                            "name": "Thermostat salle de jeux",
                            "roomName": "Salle de jeux",
                            "optOut": false,
                            "preheat": true,
                            "deviceType": "Thermostat"
                        },
                        {
                            "id": 454761,
                            "deviceUid": "5C0272FFFE8233C9",
                            "name": "Thermostat salle de bain en bas",
                            "roomName": "Salle de bain en bas",
                            "optOut": false,
                            "preheat": true,
                            "deviceType": "Thermostat"
                        },
                        {
                            "id": 454764,
                            "deviceUid": "BC33ACFFFE295E81",
                            "name": "Thermostat bureau",
                            "roomName": "Bureau",
                            "optOut": true,
                            "preheat": false,
                            "deviceType": "Thermostat"
                        },
                        {
                            "id": 454766,
                            "deviceUid": "BC33ACFFFE2B042D",
                            "name": "Thermostat chambre invité",
                            "roomName": "Chambre d'invités",
                            "optOut": true,
                            "preheat": false,
                            "deviceType": "Thermostat"
                        }
                    ]
                },
                "consumption": {
                    "currentWh": 4312.33349609375,
                    "baselineWh": 44751.55859375,
                    "estimatedReward": null,
                    "generatedTimeUTC": "2024-12-30T01:53:09.1207802+00:00",
                    "cumulativeBaselinePoints": [
                        {
                            "timeUTC": "2024-12-23T11:00:00+00:00",
                            "wh": 0.0
                        },
                        {
                            "timeUTC": "2024-12-23T12:00:00+00:00",
                            "wh": 14398.015625
                        },
                        {
                            "timeUTC": "2024-12-23T13:00:00+00:00",
                            "wh": 24935.7646484375
                        },
                        {
                            "timeUTC": "2024-12-23T14:00:00+00:00",
                            "wh": 34843.7255859375
                        },
                        {
                            "timeUTC": "2024-12-23T15:00:00+00:00",
                            "wh": 44751.5576171875
                        }
                    ],
                    "cumulativeConsumptionPoints": []
                },
                "isPreSeason": false,
                "report": {
                    "status": "Success",
                    "reward": 22.24,
                    "energySavingsWh": 40439.22509765625,
                    "calculatedReward": 22.24,
                    "isMissingBaseline": false,
                    "isMissingConsumption": false,
                    "adjustments": []
                },
                "generatedTimeUTC": "2024-12-30T01:53:09.1207802Z",
                "optOutDevices": [
                    {
                        "id": 454741,
                        "eventDateUtc": "2024-12-23T11:00:00.6549104Z",
                        "triggerTypeId": 3,
                        "triggerApplicationId": 1
                    },
                    {
                        "id": 454744,
                        "eventDateUtc": "2024-12-23T11:00:00.6593181Z",
                        "triggerTypeId": 3,
                        "triggerApplicationId": 1
                    },
                    {
                        "id": 454750,
                        "eventDateUtc": "2024-12-23T11:00:00.6460736Z",
                        "triggerTypeId": 3,
                        "triggerApplicationId": 1
                    },
                    {
                        "id": 454756,
                        "eventDateUtc": "2024-12-23T11:00:00.650514Z",
                        "triggerTypeId": 3,
                        "triggerApplicationId": 1
                    },
                    {
                        "id": 454761,
                        "eventDateUtc": "2024-12-23T11:00:00.6612074Z",
                        "triggerTypeId": 3,
                        "triggerApplicationId": 1
                    }
                ],
                "isEligibleForReward": true,
                "progress": "completed",
                "isParticipating": true,
                "isConfigurable": false,
                "id": 273,
                "period": "am",
                "phases": {
                    "settingsDeadlineUtc": "2024-12-23T05:00:00Z",
                    "preheatStartDateUTC": "2024-12-23T09:00:00Z",
                    "preheatEndDateUTC": "2024-12-23T11:00:00Z",
                    "reductionStartDateUTC": "2024-12-23T11:00:00Z",
                    "reductionEndDateUTC": "2024-12-23T15:00:00Z",
                    "recoveryStartDateUTC": "2024-12-23T15:00:00Z",
                    "recoveryEndDateUTC": "2024-12-23T16:00:00Z"
                }
            }
        ]
    }
    
  19. ic-dev21 commented on Dec 30, 2024

    @ic-dev21
    Collaborator
  20. ic-dev21 commented on Jan 5, 2025

    @ic-dev21
    Collaborator

    @sm-Fifteen @Leicas @valleedelisle

    #505 est à jour avec tous les messages qui sont rentrés à date dans le websocket du /ChallengeHub.

    Nécessite dvd-dev/python-hilo#224 pour rouler.

  21. ic-dev21 commented on Jan 6, 2025

    @ic-dev21
    Collaborator

    @sm-Fifteen @Leicas @valleedelisle

    Voici un debug log file épuré des premières phrases du défi de ce matin.
    Défi 2025-01-05.log

  22. ic-dev21 commented on Jan 7, 2025

    @ic-dev21
    Collaborator

    @sm-Fifteen @Leicas @valleedelisle

    Log épuré de sur un autre host, mais j'ai tous les messages websocket du 4 janvier au 6 au soir dedans
    Synology.log

  23. ic-dev21 commented on Jan 17, 2025

    @ic-dev21
    Collaborator

    New commit d'une solution partiellement fonctionnelle. J'ai créé temporairement une classe parallèle pour le sensor et la gestion d'event.

    Les attributs ne passent pas super bien. En attente de d'autres défis pour debug.

  24. ic-dev21 commented on Jan 28, 2025

    @ic-dev21
    Collaborator

    Salut gang, juste un petit update "public" pour expliquer où j'en suis avec tout ça.

    Avec le temps j'ai pu compiler des messages qui nous reviennent via le websocket et leur contenu JSON. J'ai créé un répertoire documentation dans python-hilo qui contient l'info, il peut être consulté ici:
    https://github.com/dvd-dev/python-hilo/tree/main/doc

    Ils n'y sont pas tous, mais je vais les ajouter prochainement.

    Entre temps, afin de pouvoir comparer des pommes avec des pommes j'ai créé localement un sensor défi parallèle qui lui marche en websocket:
    https://github.com/Leicas/hilo/blob/a2eade6152fb696a531ba951b9af16b353b42464/custom_components/hilo/sensor.py#L797-L984

    Qui dépend de la classe temporaire suivante:
    https://github.com/dvd-dev/python-hilo/blob/76781a738710b76b88c03340ea9f478c188b3524/pyhilo/event.py#L151-L293

    Problème qui me reste: bon update des attributs du sensor et gestion du mutlidéfi.

    J'avais un problème en fin de défi où les attributs restaient dans le sensor, exemple:

    next_events:
      - event_id: 284
        participating: true
        configurable: false
        period: am
        total_devices: 8
        opt_out_devices: 0
        pre_heat_devices: 0
        mode: extreme
        allowed_kWh: 0
        used_kWh: 0
        used_percentage: 0
        last_update: "2025-01-23T01:46:04.107790-05:00"
        phases:
          pre_cold_start: "2025-01-22T23:00:00-05:00"
          pre_cold_end: "2025-01-23T01:00:00-05:00"
          appreciation_start: "2025-01-23T01:00:00-05:00"
          appreciation_end: "2025-01-23T04:00:00-05:00"
          settings_deadline: "2025-01-23T00:00:00-05:00"
          preheat_start: "2025-01-23T04:00:00-05:00"
          preheat_end: "2025-01-23T06:00:00-05:00"
          reduction_start: "2025-01-23T06:00:00-05:00"
          reduction_end: "2025-01-23T10:00:00-05:00"
          recovery_start: "2025-01-23T10:00:00-05:00"
          recovery_end: "2025-01-23T11:00:00-05:00"
        state: "off"
    

    Comme ils ne s'éffaçaient pas et que l'état se fie au recovery_end:
    https://github.com/dvd-dev/python-hilo/blob/76781a738710b76b88c03340ea9f478c188b3524/pyhilo/event.py#L270-L293

    Je tombais correctement à off en fin de défi. Mais lorsqu'il y avait plus de 1 défi, je ne retombais pas en en scheduled car le premier recovery end faisait que la condition pour "off" était vraie.

    J'ai donc ajouté ceci pour flusher les attributs 5 minutes après un défi. Pourquoi 5 minutes? Pour garder l'état completed que certaines personnes utilisent:
    https://github.com/Leicas/hilo/blob/a2eade6152fb696a531ba951b9af16b353b42464/custom_components/hilo/sensor.py#L872-L881

    Les attributs:

        allowed_kWh: 0
        used_kWh: 0
    

    Ne s'updatent actuellement pas du tout sauf lors d'un reboot. Je ne m'y suis pas attardé encore car ça ne brise pas de fonctionalité, juste le calcul de récompenses anticipés ce qui est pas mal moins important que savoir qu'un défi est en cours.

    Sinon ben j'ai des beaux changements d'états aux bons moments:

    Image

    Image

    Image (les coches dans recovery c'est des reboot de testage de code)

    Image

    Voilà!

    @sm-Fifteen @Leicas @louim @valleedelisle

  25. ic-dev21 commented on Jan 30, 2025

    @ic-dev21
    Collaborator

    @sm-Fifteen @Leicas @louim @valleedelisle

    Je vais pousser du nouveau code ce fin PM/soir dans la branche du PR. J'ai commencé à dégraisser ce qui ne sert plus.

    Still needs attention: les attributs de consommation ne se remplissent pas à moins d'un reboot/reload

  26. added a commit that references this issue on Feb 2, 2025
  27. ic-dev21 commented on Feb 2, 2025

    @ic-dev21
    Collaborator

    PUlled into websocketdev branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions