Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Period graphs #19

Merged
merged 2 commits into from
Apr 14, 2023
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
227 changes: 226 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,231 @@ logger:

## Lovelace examples

### Latest charges
### Period graphs

![Period Graphs](https://github.com/geertmeersman/nexxtmove/raw/main/images/screenshots/period_graphs.png)

<details><summary>Show markdown code</summary>

**Replace &lt;username&gt; by your Nexxtmove username**

```
type: custom:config-template-card
variables:
nexxtmove:
account: geertgerits
device_id: 1204969
entities:
- >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_cost"}
card:
type: vertical-stack
cards:
- type: custom:apexcharts-card
apex_config:
tooltip:
enabled: true
followCursor: true
x:
show: false
format: MMMM yyyy
'y':
show: true
graph_span: 1year
header:
standard_format: false
show: true
show_states: false
title: ${'Nexxtmove costs for the past year €'}
now:
show: true
series:
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_cost"}
name: Home
type: column
color: 73C56C
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].home];
});
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_cost"}
name: Work
type: column
color: ff8d00
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].work];
});
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_cost"}
name: Payment
type: column
color: 00a8ff
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].payment];
});
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_cost"}
name: Guest
type: column
color: d100a0
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].guest];
});
- type: custom:apexcharts-card
apex_config:
tooltip:
enabled: true
followCursor: true
x:
show: false
format: MMMM yyyy
'y':
show: true
graph_span: 1year
header:
standard_format: false
show: true
show_states: false
title: ${'Nexxtmove energy usage for the past year Wh'}
now:
show: true
series:
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_energy"}
name: Home
type: column
color: 73C56C
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].home];
});
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_energy"}
name: Work
type: column
color: ff8d00
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].work];
});
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_energy"}
name: Payment
type: column
color: 00a8ff
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].payment];
});
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_energy"}
name: Guest
type: column
color: d100a0
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].guest];
});
- type: custom:apexcharts-card
apex_config:
tooltip:
enabled: true
followCursor: true
x:
show: false
format: MMMM yyyy
'y':
show: true
graph_span: 1year
header:
standard_format: false
show: true
show_states: false
title: ${'Nexxtmove charges for the past year \#'}
now:
show: true
series:
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_charges"}
name: Home
type: column
color: 73C56C
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].home];
});
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_charges"}
name: Work
type: column
color: ff8d00
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].work];
});
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_charges"}
name: Payment
type: column
color: 00a8ff
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].payment];
});
- entity: >-
${"sensor.nexxtmove_"+nexxtmove.account+"_charging_device_"+nexxtmove.device_id+"_period_energy"}
name: Guest
type: column
color: d100a0
show:
legend_value: false
float_precision: 2
data_generator: |
return entity.attributes.dates.map((day, index) => {
return [new Date(day), entity.attributes.values[index].guest];
});

```

</details>

![Latest charges](https://github.com/geertmeersman/nexxtmove/raw/main/images/screenshots/latest_charges.png)

Expand Down Expand Up @@ -107,6 +331,7 @@ title: Latest charges

| Description | Screenshot |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| Period Graphs | ![Period Graphs](https://github.com/geertmeersman/nexxtmove/raw/main/images/screenshots/period_graphs.png) |
| Profile | ![Profile](https://github.com/geertmeersman/nexxtmove/raw/main/images/screenshots/profile.png) |
| Company | ![Company](https://github.com/geertmeersman/nexxtmove/raw/main/images/screenshots/company.png) |
| Nexxtender Mobile Black | ![Nexxtender Mobile Black](https://github.com/geertmeersman/nexxtmove/raw/main/images/screenshots/nexxtender_mobile_black.png) |
Expand Down
115 changes: 115 additions & 0 deletions custom_components/nexxtmove/client.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
"""Nexxtmove API Client."""
from __future__ import annotations

import datetime

from requests import (
Session,
)

from .const import BASE_HEADERS
from .const import CONNECTION_RETRY
from .const import DEFAULT_NEXXTMOVE_ENVIRONMENT
from .const import GRAPH_START_DATE
from .const import REQUEST_TIMEOUT
from .exceptions import BadCredentialsException
from .exceptions import NexxtmoveServiceException
Expand Down Expand Up @@ -240,6 +243,103 @@ def fetch_data(self):
extra_attributes=charging_device,
)

graph_data = self.charging_device_graph(
charging_device_id,
GRAPH_START_DATE,
datetime.datetime.now().strftime("%Y%m%d"),
)

suffix = "period reimbursed"
key = format_entity_name(
f"{self.username} charging device {charging_device_id} {suffix}"
)
data[key] = NexxtmoveItem(
name=f"{charging_device.get('name')} {suffix}",
key=key,
type="euro",
sensor_type="sensor",
device_key=device_key,
device_name=device_name,
device_model=device_model,
state=graph_data.get("totals").get("totalReimbursed"),
)
monthly_date = []
monthly_cost = []
monthly_energy = []
monthly_charges = []
period_energy = 0
for record in graph_data.get("records"):
period_energy += record.get("energyWh")
monthly_date.append(record.get("date"))
cost = {}
energy = {}
charges = {}
for category in ["home", "payment", "guest", "work"]:
cost |= {
category: record.get("detailsPerAccount")
.get(category.upper())
.get("cost")
}
energy |= {
category: record.get("detailsPerAccount")
.get(category.upper())
.get("energyWh")
}
charges |= {
category: record.get("detailsPerAccount")
.get(category.upper())
.get("charges")
}
monthly_cost.append(cost)
monthly_energy.append(energy)
monthly_charges.append(charges)

suffix = "period cost"
key = format_entity_name(
f"{self.username} charging device {charging_device_id} {suffix}"
)
data[key] = NexxtmoveItem(
name=f"{charging_device.get('name')} {suffix}",
key=key,
type="euro",
sensor_type="sensor",
device_key=device_key,
device_name=device_name,
device_model=device_model,
state=graph_data.get("totals").get("totalCost"),
extra_attributes={"dates": monthly_date, "values": monthly_cost},
)
suffix = "period energy"
key = format_entity_name(
f"{self.username} charging device {charging_device_id} {suffix}"
)
data[key] = NexxtmoveItem(
name=f"{charging_device.get('name')} {suffix}",
key=key,
type="consumption",
sensor_type="sensor",
device_key=device_key,
device_name=device_name,
device_model=device_model,
state=graph_data.get("totals").get("totalEnergyWh") / 1000,
extra_attributes={"dates": monthly_date, "values": monthly_energy},
)
suffix = "period charges"
key = format_entity_name(
f"{self.username} charging device {charging_device_id} {suffix}"
)
data[key] = NexxtmoveItem(
name=f"{charging_device.get('name')} {suffix}",
key=key,
type="counter",
sensor_type="sensor",
device_key=device_key,
device_name=device_name,
device_model=device_model,
state=0,
extra_attributes={"dates": monthly_date, "values": monthly_charges},
)

"""
tokens = self.charging_device_tokens(charging_device_id)
log_debug(f"Charging tokens: {tokens}", True)
Expand Down Expand Up @@ -410,6 +510,21 @@ def charging_device_tokens(self, device_id):
return False
return response.json()

def charging_device_graph(self, device_id, start_date, end_date):
"""Fetch Charging graph data."""
log_debug(
"[NexxtmoveClient|charging_device_graph] Fetching charging graph data from Nexxtmove"
)
response = self.request(
f"{self.environment.api_endpoint}/graph/graph/{device_id}?startDate={start_date}&endDate={end_date}",
"[NexxtmoveClient|charging_device_graph]",
None,
200,
)
if response is False:
return False
return response.json()

def charging_point(self, charging_point_id):
"""Fetch Charging point info."""
log_debug(
Expand Down
2 changes: 2 additions & 0 deletions custom_components/nexxtmove/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
"Content-Type": "application/json; charset=utf-8",
}

GRAPH_START_DATE = "20220101"

COORDINATOR_UPDATE_INTERVAL = timedelta(minutes=5)
CONNECTION_RETRY = 5
REQUEST_TIMEOUT = 20
Expand Down
Loading