mirror of
https://github.com/RWejlgaard/octopus_exporter.git
synced 2026-07-04 13:56:17 +00:00
112 lines
3.3 KiB
Go
112 lines
3.3 KiB
Go
package main
|
|
|
|
import "time"
|
|
|
|
type tariffRates struct {
|
|
ElectricityUnitRate float64
|
|
ElectricityStandingCharge float64
|
|
ElectricityProductCode string
|
|
ElectricityTariffCode string
|
|
ElectricityIsAgile bool
|
|
GasUnitRate float64
|
|
GasStandingCharge float64
|
|
SolarExportRate float64
|
|
SolarHasExport bool
|
|
}
|
|
|
|
func getRates(token string) (*tariffRates, error) {
|
|
result, err := doGraphQL(gqlRequest{
|
|
Query: `{ viewer { accounts { ... on AccountType { properties {
|
|
electricityMeterPoints {
|
|
direction
|
|
agreements { validFrom validTo tariff {
|
|
... on StandardTariff { unitRate standingCharge productCode tariffCode }
|
|
... on HalfHourlyTariff { standingCharge productCode tariffCode }
|
|
... on PrepayTariff { unitRate standingCharge productCode tariffCode }
|
|
} }
|
|
}
|
|
gasMeterPoints {
|
|
agreements { validFrom validTo tariff { unitRate standingCharge } }
|
|
}
|
|
} } } } }`,
|
|
}, token)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
rates := &tariffRates{}
|
|
|
|
data, _ := result["data"].(map[string]any)
|
|
viewer, _ := data["viewer"].(map[string]any)
|
|
accounts, _ := viewer["accounts"].([]any)
|
|
for _, a := range accounts {
|
|
props, _ := a.(map[string]any)["properties"].([]any)
|
|
for _, p := range props {
|
|
pm, ok := p.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
for _, mp := range toSlice(pm["electricityMeterPoints"]) {
|
|
tariff := activeAgreementTariff(mp)
|
|
if tariff == nil {
|
|
continue
|
|
}
|
|
mpm, _ := mp.(map[string]any)
|
|
if dir, _ := mpm["direction"].(string); dir == "EXPORT" {
|
|
rates.SolarExportRate, _ = tariff["unitRate"].(float64)
|
|
rates.SolarHasExport = true
|
|
continue
|
|
}
|
|
rates.ElectricityUnitRate, _ = tariff["unitRate"].(float64)
|
|
rates.ElectricityStandingCharge, _ = tariff["standingCharge"].(float64)
|
|
rates.ElectricityProductCode, _ = tariff["productCode"].(string)
|
|
rates.ElectricityTariffCode, _ = tariff["tariffCode"].(string)
|
|
// HalfHourlyTariff has no unitRate field — detect Agile by absence.
|
|
if _, hasUnit := tariff["unitRate"]; !hasUnit {
|
|
rates.ElectricityIsAgile = true
|
|
}
|
|
}
|
|
|
|
for _, mp := range toSlice(pm["gasMeterPoints"]) {
|
|
if tariff := activeAgreementTariff(mp); tariff != nil {
|
|
rates.GasUnitRate, _ = tariff["unitRate"].(float64)
|
|
rates.GasStandingCharge, _ = tariff["standingCharge"].(float64)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return rates, nil
|
|
}
|
|
|
|
// activeAgreementTariff returns the tariff for the agreement in effect now:
|
|
// validFrom in the past (or absent) and validTo null or in the future. Fixed-term
|
|
// tariffs carry a future validTo (their contract end), so matching only validTo==null
|
|
// would miss them.
|
|
func activeAgreementTariff(meterPoint any) map[string]any {
|
|
mp, ok := meterPoint.(map[string]any)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
now := time.Now()
|
|
for _, ag := range toSlice(mp["agreements"]) {
|
|
agm, ok := ag.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if from, ok := agm["validFrom"].(string); ok {
|
|
if t, err := time.Parse(time.RFC3339, from); err == nil && t.After(now) {
|
|
continue // not started yet
|
|
}
|
|
}
|
|
if to, ok := agm["validTo"].(string); ok {
|
|
if t, err := time.Parse(time.RFC3339, to); err == nil && !t.After(now) {
|
|
continue // already ended
|
|
}
|
|
}
|
|
tariff, _ := agm["tariff"].(map[string]any)
|
|
return tariff
|
|
}
|
|
return nil
|
|
}
|