@David_Piper Yes I can see the gas data in the Octopus app for today. There is a delay which can vary anything upto a few hours.
Below is the script I use to pull the data I wanted, but might give some pointers:
// --- User Configuration ---
const API_KEY = 'XXXXXXX';
// INTELLIGENT ELECTRICITY SETTINGS
const ELEC_RATE_PEAK = 29.2; // DAY rate (pence/kWh)
const ELEC_RATE_OFFPEAK = 7.0; // NIGHT rate (pence/kWh)
const ELEC_STANDING_CHARGE = 47.7; // Daily standing charge (pence)
// Off-Peak Window (23:30 to 05:30)
const OFFPEAK_START_HOUR = 23;
const OFFPEAK_START_MIN = 30;
const OFFPEAK_END_HOUR = 5;
const OFFPEAK_END_MIN = 30;
// GAS SETTINGS
const GAS_PRICE_PER_KWH = 6.22;
const GAS_STANDING_CHARGE = 32.71;
const GAS_CALORIFIC_VALUE = 39.3;
// SYSTEM
const GRAPHQL_ENDPOINT = 'https://api.octopus.energy/v1/graphql/';
async function run() {
console.log('--- Starting Octopus Intelligent Tariff Fetch ---');
try {
const token = await getKrakenToken(API_KEY);
const accountNumber = await getAccountNumber(token);
const now = new Date();
const startOfDay = new Date(now);
startOfDay.setHours(0, 0, 0, 0);
// --- ELECTRICITY ---
console.log('\n--- Electricity ---');
const elecDeviceId = await getDeviceId(token, accountNumber, 'electricity');
if (elecDeviceId) {
// Live Power (Watts is already correct, no division needed)
const oneMinuteAgo = new Date(now.getTime() - 60 * 1000);
const liveData = await getLiveTelemetry(token, elecDeviceId, oneMinuteAgo.toISOString(), now.toISOString());
if (liveData && liveData.length > 0) {
const latest = liveData[liveData.length - 1];
const watts = parseInt(latest.demand) || 0;
console.log(`Live Demand: ${watts} W`);
await tag('Octopus Live Power', watts);
}
// Daily Cost
const dailyData = await getHalfHourlyTelemetry(token, elecDeviceId, startOfDay.toISOString(), now.toISOString());
let totalElecKwh = 0;
let totalElecCostPence = ELEC_STANDING_CHARGE;
if (dailyData) {
for (const slot of dailyData) {
// FIX: Divide by 1000 to convert Wh to kWh
const kwh = (parseFloat(slot.consumptionDelta) || 0) / 1000;
const readTime = new Date(slot.readAt);
totalElecKwh += kwh;
if (isOffPeak(readTime)) {
totalElecCostPence += (kwh * ELEC_RATE_OFFPEAK);
} else {
totalElecCostPence += (kwh * ELEC_RATE_PEAK);
}
}
}
const elecCostPounds = totalElecCostPence / 100;
console.log(`Daily Usage: ${totalElecKwh.toFixed(2)} kWh`);
console.log(`Daily Cost (Est): ÂŁ${elecCostPounds.toFixed(2)}`);
await tag('Octopus Elec Daily kWh', parseFloat(totalElecKwh.toFixed(2)));
await tag('Octopus Elec Daily Cost', parseFloat(elecCostPounds.toFixed(2)));
}
// --- GAS ---
console.log('\n--- Gas ---');
const gasDeviceId = await getDeviceId(token, accountNumber, 'gas');
if (gasDeviceId) {
const dailyGasData = await getHalfHourlyTelemetry(token, gasDeviceId, startOfDay.toISOString(), now.toISOString());
let totalGasVolume = 0;
if (dailyGasData) {
// FIX: Divide by 10000 to convert Raw Units (Liters) to m3
totalGasVolume = dailyGasData.reduce((acc, cur) => acc + ((parseFloat(cur.consumptionDelta) || 0) / 10000), 0);
}
const totalGasKwh = (totalGasVolume * GAS_CALORIFIC_VALUE * 1.02264) / 3.6;
const gasCostPence = (totalGasKwh * GAS_PRICE_PER_KWH) + GAS_STANDING_CHARGE;
const gasCostPounds = gasCostPence / 100;
console.log(`Daily Usage: ${totalGasKwh.toFixed(2)} kWh`);
console.log(`Daily Cost: ÂŁ${gasCostPounds.toFixed(2)}`);
await tag('Octopus Gas Daily kWh', parseFloat(totalGasKwh.toFixed(2)));
await tag('Octopus Gas Daily Cost', parseFloat(gasCostPounds.toFixed(2)));
}
console.log('--- Script Finished Successfully ---');
} catch (error) {
console.error('SCRIPT FAILED:', error.message);
}
}
// --- Helper Functions ---
function isOffPeak(dateObj) {
const h = dateObj.getHours();
const m = dateObj.getMinutes();
const timeVal = h + (m / 60);
const startVal = OFFPEAK_START_HOUR + (OFFPEAK_START_MIN / 60);
const endVal = OFFPEAK_END_HOUR + (OFFPEAK_END_MIN / 60);
if (startVal > endVal) {
return (timeVal >= startVal) || (timeVal < endVal);
} else {
return (timeVal >= startVal) && (timeVal < endVal);
}
}
async function fetchGraphQL(token, query, variables = {}) {
const headers = { 'Content-Type': 'application/json' };
if (token) headers['Authorization'] = token;
const response = await fetch(GRAPHQL_ENDPOINT, {
method: 'POST',
headers: headers,
body: JSON.stringify({ query, variables }),
});
if (!response.ok) {
const txt = await response.text();
throw new Error(`HTTP Error: ${response.status} - ${txt}`);
}
const json = await response.json();
if (json.errors) throw new Error(`GraphQL Error: ${JSON.stringify(json.errors)}`);
return json.data;
}
async function getKrakenToken(apiKey) {
const query = `mutation ObtainToken($apiKey: String!) { obtainKrakenToken(input: {APIKey: $apiKey}) { token } }`;
const data = await fetchGraphQL(null, query, { apiKey });
return data.obtainKrakenToken.token;
}
async function getAccountNumber(token) {
const query = `query { viewer { accounts { number } } }`;
const data = await fetchGraphQL(token, query);
if (data.viewer.accounts && data.viewer.accounts.length > 0) return data.viewer.accounts[0].number;
throw new Error('Could not discover account number.');
}
async function getDeviceId(token, accountNumber, fuelType) {
const fieldName = fuelType === 'electricity' ? 'electricityAgreements' : 'gasAgreements';
const query = `query GetAccount($accountNumber: String!) { account(accountNumber: $accountNumber) { ${fieldName}(active: true) { meterPoint { meters(includeInactive: false) { smartDevices { deviceId } } } } } }`;
const data = await fetchGraphQL(token, query, { accountNumber });
const agreements = data.account[fieldName];
if (!agreements) return null;
for (const agreement of agreements) {
if (agreement.meterPoint && agreement.meterPoint.meters) {
for (const meter of agreement.meterPoint.meters) {
if (meter.smartDevices && meter.smartDevices.length > 0) return meter.smartDevices[0].deviceId;
}
}
}
return null;
}
async function getLiveTelemetry(token, deviceId, start, end) {
const query = `query LiveTelemetry($deviceId: String!, $start: DateTime!, $end: DateTime!) { smartMeterTelemetry(deviceId: $deviceId, grouping: TEN_SECONDS, start: $start, end: $end) { readAt, demand, consumptionDelta } }`;
const data = await fetchGraphQL(token, query, { deviceId, start, end });
return data.smartMeterTelemetry;
}
async function getHalfHourlyTelemetry(token, deviceId, start, end) {
const query = `query HistoryTelemetry($deviceId: String!, $start: DateTime!, $end: DateTime!) { smartMeterTelemetry(deviceId: $deviceId, grouping: HALF_HOURLY, start: $start, end: $end) { readAt, consumptionDelta } }`;
const data = await fetchGraphQL(token, query, { deviceId, start, end });
return data.smartMeterTelemetry;
}
await run();