Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 92 additions & 0 deletions doc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Hilo API reference payloads

Captured responses from Hilo's services, grouped by transport to mirror the library modules.
IDs, URNs and serial numbers in the payload files are anonymized.

| Folder | Transport | Library module | Contents |
|---|---|---|---|
| [`rest/`](rest/) | HTTPS REST | `pyhilo/api.py` | Automation (`/Locations`, `/Weather`) and challenge season endpoints |
| [`graphql/`](graphql/) | GraphQL subscription | `pyhilo/graphql.py` | `onAnyDeviceUpdated` payloads per device type |
| [`signalr/devicehub/`](signalr/devicehub/) | SignalR WebSocket | `pyhilo/signalr.py` | DeviceHub messages |
| [`signalr/challengehub/`](signalr/challengehub/) | SignalR WebSocket | `pyhilo/signalr.py` | ChallengeHub messages, 2025-26 season onward (CH = Winter Credits, Flex = Flex D) |
| [`signalr/challengehub/legacy-pre-2025/`](signalr/challengehub/legacy-pre-2025/) | SignalR WebSocket | — | Challenge messages before the CH/Flex split; kept for reference |
| [`postman/`](postman/) | — | — | Postman collection and environment for manual testing |

## Adding a payload

1. Strip tokens, location URNs, serial numbers and personal data before committing.
2. Name REST files after the endpoint (`season_events_ch_2025.json`) and SignalR/GraphQL files after the message target (`EventCHDetailsInitialValuesReceived.json`).
3. Add a short suffix for variants (`-during-event`, `-empty`, `-meter`).

# Using Postman to query Hilo

Import [`postman/hilo.postman_collection.json`](postman/hilo.postman_collection.json) and [`postman/hilo-prod.postman_environment.json`](postman/hilo-prod.postman_environment.json), then select the **Hilo Prod** environment.

## Authentication

The collection uses OAuth 2.0 at the collection level. Open the collection's **Authorization** tab, click **Get New Access Token**, log in with your Hilo credentials in the browser window, then click **Use Token**. Every request in the collection inherits that token.

Tokens are short-lived and contain personally identifiable information. Do not share them or commit an exported environment that contains them.

## REST requests

With the access token set, the REST requests (`1-Get Locations`, `Get SeasonsSummary`, `Get CHEvents`, `Get FlexEvents`, ...) can be sent directly.

## Connecting to a hub

Each hub folder (`DeviceHub`, `ChallengeHub`) contains two negotiate requests. Send them in order:

1. `1-API Hilo ... Hub Negotiate` stores the hub URL and hub access token in the environment (`_deviceHubUrl` / `_deviceHubAccessToken`, or `_challengeHubUrl` / `_challengeHubAccessToken`).
2. `2-... Hub Negotiate` stores the connection token (`_deviceHubConnectionToken` or `_challengeHubConnectionToken`).

Then open a new WebSocket request in Postman:

1. Use the hub URL from the environment (`{{_deviceHubUrl}}` or `{{_challengeHubUrl}}`).
2. In **Headers**, add `Authorization` with the value `Bearer {{_deviceHubAccessToken}}` (or `Bearer {{_challengeHubAccessToken}}`).
3. Connect, then send the handshake below. The trailing record separator character `chr(30)` is required after every message.

```
{
"protocol": "json",
"version": 1
}
```

### DeviceHub

Invoke `SubscribeToLocation` with your location ID to get your device information:

```
{
"arguments": [
69420
],
"invocationId": "0",
"target": "SubscribeToLocation",
"type": 1
}
```

You should receive a [`DeviceListInitialValuesReceived`](signalr/devicehub/DeviceListInitialValuesReceived.json) message back.

### ChallengeHub

Since the 2025-2026 season and the addition of Flex D, messages are split between Winter Credits (Crédit Hivernal) and Flex D. Winter Credits targets contain `CH` and Flex D targets contain `Flex`. Each rate has its own event ID; for example, event 337 was for Winter Credits and event 338 for Flex D, both at the same time. You only have access to the one matching your rate.

#### SubscribeToEventCH or SubscribeToEventFlex

```
{
"arguments": [
{
"locationHiloId": "urn:YOUR-URN",
"eventId": ID(numeric)
}
],
"invocationId": "1",
"target": "SubscribeToEventCH",
"type": 1
}
```

Returns [`EventCHDetailsInitialValuesReceived`](signalr/challengehub/EventCHDetailsInitialValuesReceived.json) or [`EventFlexDetailsInitialValuesReceived`](signalr/challengehub/EventFlexDetailsInitialValuesReceived.json).
111 changes: 0 additions & 111 deletions doc/Readme.md

This file was deleted.

33 changes: 33 additions & 0 deletions doc/graphql/onAnyDeviceUpdated-cee.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"data": {
"onAnyDeviceUpdated": {
"deviceType": "cee",
"locationHiloId": "urn:hilo:crm:00000-abcdef:0",
"transmissionTime": "2026-10-24T19:46:35.207Z",
"operationId": "00000000-0000-0000-0000-000000000002",
"status": "REPORT",
"device": {
"deviceType": "cee",
"hiloId": "urn:hilo:philo:4a5b6c7d8e9f0001:0",
"physicalAddress": "4A5B6C7D8E9F0001",
"connectionStatus": "CONNECTED",
"gDState": "EXCLUDED",
"version": "45",
"probeTemp": {
"value": 54,
"kind": "DEGREE_CELSIUS"
},
"zigbeeVersion": "45",
"state": "ON",
"ccrType": "WATER_HEATER",
"alerts": [
"0"
],
"power": {
"value": 0,
"kind": "WATT"
}
}
}
}
}
22 changes: 22 additions & 0 deletions doc/graphql/onAnyDeviceUpdated-meter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"data": {
"onAnyDeviceUpdated": {
"deviceType": "meter",
"locationHiloId": "urn:hilo:crm:00000-abcdef:0",
"transmissionTime": "2026-10-24T19:48:54.966Z",
"operationId": "00000000-0000-0000-0000-000000000001",
"status": "REPORT",
"device": {
"deviceType": "meter",
"hiloId": "urn:hilo:philo:0x006baa0000000001-smart_meter:0",
"physicalAddress": "0x006BAA0000000001-smart_meter",
"connectionStatus": "CONNECTED",
"zigBeeChannel": 24,
"power": {
"value": 0.572,
"kind": "KILOWATT"
}
}
}
}
}
7 changes: 7 additions & 0 deletions doc/rest/location_weather.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"temperature": 10.0,
"time": "0001-01-01T00:00:00Z",
"condition": "Clear",
"icon": 0,
"humidity": 72.0
}
42 changes: 42 additions & 0 deletions doc/rest/season_events_ch_2025.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"season": 2025,
"events": [
{
"id": 378,
"startDateUtc": "2026-03-18T08:00:00+00:00",
"period": "AM",
"reward": 11.68,
"energySavingsWh": 20570,
"status": "Success",
"isPreseasonEvent": false,
"isCredited": true,
"isFlatRate": false,
"isInsufficientReduction": false
},
{
"id": 377,
"startDateUtc": "2026-03-03T09:00:00+00:00",
"period": "AM",
"reward": 17.95,
"energySavingsWh": 31620,
"status": "Success",
"isPreseasonEvent": false,
"isCredited": true,
"isFlatRate": false,
"isInsufficientReduction": false
},
{
"id": 373,
"startDateUtc": "2026-02-08T09:00:00+00:00",
"period": "AM",
"reward": 20.56,
"energySavingsWh": 36220,
"status": "Success",
"isPreseasonEvent": false,
"isCredited": true,
"isFlatRate": false,
"isInsufficientReduction": false
}
],
"periodId": "Q0h8dXJuOmhpbG86Y3JtOjAwMDAwLWFiY2RlZjowfDIwMjUtMTEtMDFUMTM6MDE6MTcuODA4Nzc4NVo="
}
5 changes: 5 additions & 0 deletions doc/rest/season_events_ch_2026_empty.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"season": 2026,
"events": [],
"periodId": "Q0h8dXJuOmhpbG86Y3JtOjAwMDAwLWFiY2RlZjowfDIwMjUtMTEtMDFUMTM6MDE6MTcuODA4Nzc4NVo="
}
36 changes: 36 additions & 0 deletions doc/rest/season_events_hilo_2024.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"season": 2024,
"events": [
{
"id": 303,
"startDateUtc": "2025-03-03T09:00:00+00:00",
"period": "AM",
"reportId": 1000000,
"reward": 20.39,
"energySavingsWh": 37081.6845703125,
"status": "Success",
"isPreseasonEvent": false
},
{
"id": 302,
"startDateUtc": "2025-02-19T09:00:00+00:00",
"period": "AM",
"reportId": 1000001,
"reward": 21.85,
"energySavingsWh": 39730.3349609375,
"status": "Success",
"isPreseasonEvent": false
},
{
"id": 301,
"startDateUtc": "2025-02-18T09:00:00+00:00",
"period": "AM",
"reportId": 1000002,
"reward": 23.91,
"energySavingsWh": 43477.09521484375,
"status": "Success",
"isPreseasonEvent": false
}
],
"periodId": "SGlsb3x1cm46aGlsbzpjcm06MDAwMDAtYWJjZGVmOjB8MjAyMi0wNi0yMlQxOTo1MDozOC4wMDAwMDAwWg=="
}
27 changes: 27 additions & 0 deletions doc/rest/seasons_summary.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[
{
"season": 2026,
"ratePlan": "CH",
"periodId": "Q0h8dXJuOmhpbG86Y3JtOjAwMDAwLWFiY2RlZjowfDIwMjUtMTEtMDFUMTM6MDE6MTcuODA4Nzc4NVo="
},
{
"season": 2025,
"ratePlan": "CH",
"periodId": "Q0h8dXJuOmhpbG86Y3JtOjAwMDAwLWFiY2RlZjowfDIwMjUtMTEtMDFUMTM6MDE6MTcuODA4Nzc4NVo="
},
{
"season": 2024,
"ratePlan": "Hilo",
"periodId": "SGlsb3x1cm46aGlsbzpjcm06MDAwMDAtYWJjZGVmOjB8MjAyMi0wNi0yMlQxOTo1MDozOC4wMDAwMDAwWg=="
},
{
"season": 2023,
"ratePlan": "Hilo",
"periodId": "SGlsb3x1cm46aGlsbzpjcm06MDAwMDAtYWJjZGVmOjB8MjAyMi0wNi0yMlQxOTo1MDozOC4wMDAwMDAwWg=="
},
{
"season": 2022,
"ratePlan": "Hilo",
"periodId": "SGlsb3x1cm46aGlsbzpjcm06MDAwMDAtYWJjZGVmOjB8MjAyMi0wNi0yMlQxOTo1MDozOC4wMDAwMDAwWg=="
}
]
Loading