#include <WiFi.h>
#include <WiFiClient.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <TimeLib.h>
#define numberRows 2
#define numberColumns 48
#define rTariff 0
#define rConsumption 1
HTTPClient octopusAPI;
String tariffAndConsumption [numberRows][numberColumns];
int iTariffCount;
int iConsumptionCount;
int colCounter = 0;
int HTTPstatusCode;
String Response = "";
String octopusTariffURL = "https://api.octopus.energy/v1/products/AGILE-24-04-03/electricity-tariffs/E-1R-AGILE-24-04-03-L/standard-unit-rates//?page_size=100&period_from=2024-08-!!T00:00&period_to=2024-08-!!T23:59";
String octopusConsumptionURL = "https://api.octopus.energy/v1/electricity-meter-points/2200040541020/meters/22M0405631/consumption/?period_from=2024-08-!!T00:00&period_to=2024-08-!!T23:30&page_size=1000";
String queryDay;
// remove for full code
const char* ntpServer = "pool.ntp.org";
void getNPTTime() {
configTime(0, 0, ntpServer);
time_t now;
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
}
time(&now);
setTime(now);
}
void setup() {
Serial.begin(9600);
Serial.print("Connecting to WiFi");
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print(".");
}
Serial.println(" Connected!");
// define day
queryDay = "22";
/*
getNPTTime();
queryDay = String(day() - 1);
if (queryDay.length() == 1) queryDay = "0" + queryDay;
*/
Serial.println("Query day = " + queryDay);
getConsumption();
Serial.println("Consumption Count = " + String(iConsumptionCount));
if (iConsumptionCount == 0 ) return;
getTariff();
calcAndDisplay();
}
void getTariff(){
//make no difference if use Z or not for time spec as it's always in GMT
Serial.println ("Getting Tariff.");
octopusTariffURL.replace("!!",queryDay);
octopusAPI.begin(octopusTariffURL.c_str());
// Send HTTP GET request
HTTPstatusCode = octopusAPI.GET();
Response = octopusAPI.getString();
octopusAPI.end();
JsonDocument tariff;
DeserializationError errorTariff = deserializeJson(tariff, Response);
if (errorTariff) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(errorTariff.f_str());
return;
}
iTariffCount = int(tariff["count"]);
if (iTariffCount == 0) {
Serial.println("No results: " + Response);
return;
}
int i = iTariffCount -1;
colCounter = 0;
for ( i ; i >= 0 ; --i){
tariffAndConsumption[rTariff][colCounter] = String(tariff["results"][i]["value_inc_vat"]);
// Serial.print(String(tariff["results"][i]["valid_from"]) + " " + String(tariff["results"][i]["value_inc_vat"]));
++colCounter;
}
}
void getConsumption(){
// in BST Use Z in time and returns data 1 hr later that in query when in BST
// in BST No Z and returns data starting from the hr specified in the query. So in BST this is best. check when returns to GMT
Serial.println ("Getting Consumption.");
octopusConsumptionURL.replace("!!",queryDay);
// Serial.println(octopusConsumptionURL);
octopusAPI.begin(octopusConsumptionURL.c_str());
octopusAPI.setAuthorization("sk_live_Vp9T9GmJFqHtaELcYXFgnici", "");
// Send HTTP GET request
HTTPstatusCode = octopusAPI.GET();
Response = octopusAPI.getString();
octopusAPI.end();
//Serial.println(Response);
JsonDocument consumption;
DeserializationError errorConsumption = deserializeJson(consumption, Response);
if (errorConsumption) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(errorConsumption.f_str());
return;
}
iConsumptionCount = int(consumption["count"]);
if (iConsumptionCount == 0) {
Serial.println("No results: " + Response);
return;
}
int i = iConsumptionCount - 1;
colCounter = 0;
for ( i ; i >= 0 ; --i){
String hour = String(consumption["results"][i]["interval_start"]).substring(11,13);
String minute = String(consumption["results"][i]["interval_start"]).substring(14,16);
colCounter = hour.toInt() * 2;
if (minute.toInt() == 30 ) colCounter = colCounter +1;
//Serial.println(hour + " " + minute + " colCounter=" + String(colCounter));
tariffAndConsumption[rConsumption][colCounter] = String(consumption["results"][i]["consumption"]);
// Serial.println(String(consumption["results"][i]["interval_start"]) + " " + String(consumption["results"][i]["consumption"]));
// ++colCounter;
}
}
void calcAndDisplay(){
float totalCost = 0;
float totalConsumption = 0;
int i = 0;
for ( i ; i < iTariffCount ; ++i){
float roundedConsumption = (round(tariffAndConsumption[rConsumption][i].toFloat()*100))/100;
Serial.println(tariffAndConsumption[rConsumption][i] + " " + String(roundedConsumption));
totalCost = totalCost + roundedConsumption * tariffAndConsumption[rTariff][i].toFloat();
totalConsumption = totalConsumption + roundedConsumption; //tariffAndConsumption[rConsumption][i].toFloat();
}
Serial.println("Cost = £" + String(totalCost/100));
Serial.println("Consumption = " + String(totalConsumption) + "kWh.");
Serial.println("average tariff = " + String(totalCost/totalConsumption) + "p/kWh");
}
void loop() {
delay(100); // TODO: Build something amazing!
}