Welcome to Tesla Motors Club
Discuss Tesla's Model S, Model 3, Model X, Model Y, Cybertruck, Roadster and More.
Register

Wiki Everything you wanted to know about Intelligent Octopus But Were Afraid To Ask

This site may earn commission on affiliate links.
Why write this post?
A lot of people are starting to get interested in IO. I don't think Octopus do a very good job of spelling out the benefits in their website. They have some FAQs, but the same questions keep coming up over and over on the forums.

What is it?
In a nutshell, IO is a split tariff that gives you a cheap off-peak rate for charging your EV and other electrical items in the household, including home batteries.

Isn’t that the same as Octopus Go or Go Faster?
The principle is the same, but in exchange for some benefits which we’ll explain, you allow Octopus to control the timing of your EV charge, so they can choose low carbon intensity and/or cheap wholesale priced time slots.

So I’m not in control of my charge? I don’t like the sound of that!
Well yes…and no. You’re in control of how much to charge and when you want the car to be ready, just like you would be normally. Within those parameters, you’re allowing Octopus to control which half-hour slots the car chooses to get to that target % charge. And you can always override IO if you want to “bump charge” through the day.

OK, but what are the benefits you mentioned for this trade off?
First of all, you get a larger guaranteed off-peak window for using household appliances and charging home batteries, etc. It’s six hours between 23:30-05:30. Go, for example, is a fixed 4 hour window.
In addition, when IO schedules your EV charging slots it sometimes creates schedules that fall outside of the fixed, six hour window. If that happens your EV charging and all your household use in these extra-slots is also charged at off-peak rates.
I have frequently had schedules give me seven or more hours of off-peak rates. On one occasion, I had a total of ten hours of off-peak rates.

Am I eligible?
You need a smart meter and a compatible car and/or charger. Since you’re reading this here, I assume you’ve got or are thinking of getting a Tesla. IO works with the Tesla API to create the charging schedules. The advantage of this is that IO will work with any* home charger. If you have a charger with smart features, you need to disable them so that the charger acts as a dumb switch. IO will control everything via Tesla’s API to start and stop your charging.
*Even your granny charger - but you need to tell IO what the max throughput is when you go through setup so that it can work out your schedules properly.

Some of this sounds too good to be true.
Phantom drain caused by having smart charging enabled in the Octopus app has been fixed as of 30th August 2022. One small side effect appears to be that schedules sometimes take longer to appear in the app after plugging in.

Further questions (to be updated in the main thread body once the edit timer on this post expires)

I have two EVs, can I charge the other while on IO?

Not with IO scheduling the charging, but you can charge any other car in the fixed 23:30-05:30 off peak window or at any other time at peak prices.

What are the rates etc?
Octopus do a decent job of explaining the peak and off-peak rates along with contracts etc. Head over to their pages to discover that.

I asked for a target % of x, but I got less than x.
There are two or three reasons for this.

The first, most common reason, is that Tesla reports battery % differently depending on where you look. The API (that IO uses) reports the gross battery %. This is generally fixed but can fluctuate very slightly. The Tesla app shows usable %. Apps like Teslamate and Teslafi can display both. Quite often, there is a delta of 2-3% which may be down to battery temp or other factors. This usable % will often be recovered as the battery warms up during a drive.

Some users have reported charging % being way off, perhaps 10% or more. This could be down to an error in the onboarding process. Some of the charger database entries incorrectly assume the charger you are onboarding is the 11kW version, without actually saying so in the charger description. The Andersen A2 was an early example of this. If you suspect this may be the case, the easiest thing to do is go through the on-boarding again and choose "Generic 7.4kW charger". It won't affect your functionality on IO in any way.

Lastly, it has to be mentioned that occasionally IO just craps out. It may be down to a comms error, a server error at Octopus' end, or just reasons. IO is a beta product and it's wise to expect one or two quirks from time to time
 
Last edited by a moderator:
Two overnight charges done on IO now. Absolutely no issues so far, and find the extra slots can be very handy too. Happy days :)

As ever, threads like this are so useful and full of info 👍
I’m interested to know what sort of interaction you’ve got between the Tesla and the IO app… have you got any charge target or schedule set on the Tesla side or is it all being controlled by IO?
 
I’m interested to know what sort of interaction you’ve got between the Tesla and the IO app… have you got any charge target or schedule set on the Tesla side or is it all being controlled by IO?
Let only IO control everything and it will work, it's very simple.

Set the Tesla app to the same target SOC as the Octopus app.
Choose 'ready by' time in the Octopus app.
Stop the initial plug-in charge via the Tesla app a few seconds after the charging starts.
 
  • Like
Reactions: Yuff
Sometimes I have to wake the car and force close/reopen the octopus app to get it to show the schedule. It still makes one, it just doesn't show it until I do that.
This.

If all else fails, disable smart charging in the Octopus app. Wait about a minute then re-enable smart charging.

This will force the Octopus app to poll the Tesla API and you should get a schedule a minute or two later.
 
I would like clarification of the operation of the IO tariff.
I use “Time-Based” Control in my App and assumed this would cause charging from the grid only during the assigned charging schedule, however it uses a significant amount of battery power from my Powerwall during (usually) the last two scheduled times.
Sometimes it would be useful to do a top-up charge from surplus battery power using “Self Powered” option at a lower current to limit output. Would this work?
Another issue I have is the charging level. If I set the car or App to 90% and Octopus to 85% it charges to 90%. - Why?
My Octopus settings: Ready by time 05:30, Charge limit 85%.
Tesla settings: Depart by 05:30. Charge limit 90%.
Comments, suggestions welcome.
 
Its taken a couple of weeks but IO is now enabled on my account, thanks all for the help getting here.

Next stage is getting my battery working with IO. I can happily pull historical data, and tomorrow's agile pricing is in the public api, but how do I get -my- IO slots for tomorrow?

I think I've found a node red integration (GitHub - boysie123/octopus) I can *cough* adjust from agile to work with this if I can work out where to get the data from. Advantage here is that the victron based battery system has node-red integrated and can issue proper controls

Or there is an HA IO integration that looks great (GitHub - megakid/ha_octopus_intelligent), but the HA integration for victron is pretty limited in it can't set charge schedules for the battery, just IMPORT, EXPORT or BALANCE commands. HA can also take some control over the heat pump to take advantage of any extra slots.

hmmm. Anyone any thoughts/ideas? I am slightly concerned that I'm going to fry something at some point - I re-use, adjust and borrow code, I am not a coder in any way shape or form these days. I retrieve my solcast data using excel and a couple of pivot tables :(.
 
Its taken a couple of weeks but IO is now enabled on my account, thanks all for the help getting here.

Next stage is getting my battery working with IO. I can happily pull historical data, and tomorrow's agile pricing is in the public api, but how do I get -my- IO slots for tomorrow?

I think I've found a node red integration (GitHub - boysie123/octopus) I can *cough* adjust from agile to work with this if I can work out where to get the data from. Advantage here is that the victron based battery system has node-red integrated and can issue proper controls

Or there is an HA IO integration that looks great (GitHub - megakid/ha_octopus_intelligent), but the HA integration for victron is pretty limited in it can't set charge schedules for the battery, just IMPORT, EXPORT or BALANCE commands. HA can also take some control over the heat pump to take advantage of any extra slots.

hmmm. Anyone any thoughts/ideas? I am slightly concerned that I'm going to fry something at some point - I re-use, adjust and borrow code, I am not a coder in any way shape or form these days. I retrieve my solcast data using excel and a couple of pivot tables :(.
Nodered reads the kraken data for me which I then use to control the battery charging
I wrote my own js for kraken
 
Nodered reads the kraken data for me which I then use to control the battery charging
I wrote my own js for kraken
Is kraken just the agile API?

Also, this evening's slots are set, but I'm only needing 75-90%. It's given me
Screenshot_2023-08-09-23-23-25-08_903d05fe1ae9780ffdf8ae337b6c882e.jpg

But realistically it's going to start around 11:30, and finish in an hour or 2 - if the car doesn't need the 6-6:30 slot, I won't get it will I? Just working out rules for running the heat pump as in winter that 6am slot would be very advantageous!
 
I’m interested to know what sort of interaction you’ve got between the Tesla and the IO app… have you got any charge target or schedule set on the Tesla side or is it all being controlled by IO?
I’ve put the charge limit in the car to 100%, so I can just set the actual limit in Octopus to what I need. Usually charge to 90% as the car advises. Then just leave it to IO. The only other thing I do is manually stop the initial charge via the Tesla app after plugging in

A few people have mentioned disabling the smart charge setting in the Octopus app - where and how do you do this? I’ve looked and couldn’t see any such option.

Edit: found it :)
 
Is kraken just the agile API?

Also, this evening's slots are set, but I'm only needing 75-90%. It's given me
View attachment 963593
But realistically it's going to start around 11:30, and finish in an hour or 2 - if the car doesn't need the 6-6:30 slot, I won't get it will I? Just working out rules for running the heat pump as in winter that 6am slot would be very advantageous!
No, IO sits on its own API - kraken

I check the API at the start of every 30 minute period to make sure the slots haven't changed

Here's the hard part of the JS using Axios:
Code:
//see what SLOTS are on my account
//Intelligent Octopus
//https://api.octopus.energy/v1/graphql

//OP1 - Something to process
//OP2 - get a new token
//OP3 - back round in 10s

//msg.IntelliCommand = "IntelliSlots" "IntelliPercent" "IntelliEnable" "IntelliDisable"


require = global.get('require');
const axios = require('axios')
var TeslaCharge = global.get('TargetSoC')


var AxiosResponse, OctopusID, authToken, DateNow, CurrentTime, CurrentHour, CurrentMinute, DPTime
var CurrentRate, KrakenURL, KrakenQuery, KrakenQueryHeader, ElectricRate, input, targetTime

OctopusID = global.get("OctopusID") //account ID A-xxxx
//OctopusID = Buffer.from(OctopusID).toString('base64')

var KrakenInstruction = msg.IntelliCommand

console.log("KrakenInstruction", KrakenInstruction)

authToken = flow.get("KrakenToken")

var ReadyBy = global.get('ReadyBy') || 2359
if (ReadyBy !== 2359) {
    //var targetTime = ReadyBy.substring(0, 1) + ":" + ReadyBy.substring(2, 3)
    var ReadyHour = Math.round(ReadyBy/100)
    var ReadyMinute = ReadyBy - (ReadyHour *100)
    if (ReadyMinute === 0) {
        ReadyMinute = "00"
    }
    if (ReadyBy < 1000) {
        targetTime = "0" + ReadyHour + ":" + ReadyMinute
    } else {
        targetTime = ReadyHour + ":" + ReadyMinute
    }
    global.set("ReadyByChange", false)
    //console.log("targetTime", targetTime)
} else {
    targetTime = "09:00"
}

//targetTime = "09:00"
var targetSocPercent = TeslaCharge


KrakenURL = "https://api.octopus.energy/v1/graphql/"


if (KrakenInstruction === "IntelliSlots") {
    KrakenQuery = {
        "query": `query AnyOldName($accountNumber: String!) {
                vehicleChargingPreferences(accountNumber: $accountNumber) {
                    weekdayTargetTime,
                    weekdayTargetSoc,
                    weekendTargetTime,
                    weekendTargetSoc
                }
                registeredKrakenflexDevice(accountNumber: $accountNumber) {
                    krakenflexDeviceId
                    provider
                    vehicleMake
                    vehicleModel
                    vehicleBatterySizeInKwh
                    chargePointMake
                    chargePointModel
                    chargePointPowerInKw
                    status
                    suspended
                    hasToken
                    createdAt
                }
                plannedDispatches(accountNumber: $accountNumber) {
                    startDtUtc: startDt
                    endDtUtc: endDt
                    chargeKwh: delta
                    meta {
                        source
                        location
                    }
                }
            }` ,
        "variables": { "accountNumber": OctopusID }
    }
} else if (KrakenInstruction === "IntelliPercent") {
    console.log("Updating the Kraken charge %age")
    KrakenQuery = {
        "query": `mutation setVehicleChargePreferences($accountNumber: String!, $targetTime: String!, $targetSocPercent: Int!) {
            setVehicleChargePreferences(input: { accountNumber: $accountNumber, weekdayTargetTime: $targetTime, weekendTargetTime: $targetTime, weekdayTargetSoc: $targetSocPercent, weekendTargetSoc: $targetSocPercent }) {
              krakenflexDevice {
                    krakenflexDeviceId
                }
            }
        }` , //this one stays
        "variables": { "accountNumber": OctopusID, "targetTime": targetTime, "targetSocPercent": targetSocPercent },
    }
} else if (KrakenInstruction === "IntelliEnable") {
    KrakenQuery = {
        "query": `mutation resumeControl($accountNumber: String!) {
            resumeControl(input: { accountNumber: $accountNumber }) {
              krakenflexDevice {
                krakenflexDeviceId
                }
            }
        }` , //this one stays
        "variables": { "accountNumber": OctopusID },
    }
} else if (KrakenInstruction === "IntelliDisable") {
    KrakenQuery = {
        "query": `mutation suspendControl($accountNumber: String!) {
            suspendControl(input: { accountNumber: $accountNumber }) {
              krakenflexDevice {
                krakenflexDeviceId
                }
            }
        }` , //this one stays
        "variables": { "accountNumber": OctopusID },
    }
} else {
    console.log("Unknown KrakenInstruction", KrakenInstruction)
    return
}

var basicAuth = authToken

KrakenQueryHeader = basicAuth

axios.defaults.headers.post['Authorization'] = `JWT ${KrakenQueryHeader}`  // for POST requests

input = await axiosTest(KrakenURL, KrakenQuery)

return

//async function axiosTest(KrakenURL, KrakenQuery, KrakenQueryHeader) {
async function axiosTest(KrakenURL, KrakenQuery) {
    axios.post(KrakenURL, KrakenQuery)
        .then(function (result) {
            AxiosResponse = result
            //flow.set("EarlyQueryResult", AxiosResponse.data.data)
            //flow.set("EarlyQueryResult", AxiosResponse)
            if (AxiosResponse.data.errors !== undefined) { //we have some error to process
                if (AxiosResponse.data.errors[0].message === "Signature of the JWT has expired.") {
                    node.send([[null], [msg]]) //need a new token
                    //console.log("Getting a token")
                    return
                }
                else {  //not a real error
                    console.log("Not a real error") //ValidAnswer(AxiosResponse)
                    return
                    //flow.set("KrakenToken",result.data.data.obtainKrakenToken.token)
                }
                return
            }
            else {
                msg.ValidAnswer = AxiosResponse
                node.send([[msg], [null]]) //off to processing
                return
            }
            return
        })
        .catch(function (error) {
            if (error.response) {
                // Request made and server responded
                var AxiosError = error.response
                if (error.response.status === 408) {
                    console.log("408 sleeping")
                    node.send([[null], [msg]])
                    //return (error)
                }
                else if (error.status = 500) {
                        console.log("500 Internal Server Error")
                        node.send([[null], [null], [msg]])
                    }
                
                else {
                    console.log("Some other error")
                    flow.set(KrakenInstruction + "-error", AxiosError)
                    //return (error)
                }
            } else if (error.request) {
                // The request was made but no response was received
                console.log("The request was made but no response was received");
                node.send([[null], [null], [msg]])
                flow.set(KrakenInstruction + "-request", AxiosError)
                //return (error)
            } else {
                // Something happened in setting up the request that triggered an Error
                console.log("Something happened in setting up the request that triggered an Error", AxiosError);
                flow.set(KrakenInstruction + "-other", AxiosError)
                //return (error)
            }
            //return
        }) //end of catch
    return
}
 
  • Like
Reactions: Avendit
No, IO sits on its own API - kraken

I check the API at the start of every 30 minute period to make sure the slots haven't changed

Here's the hard part of the JS using Axios:
Code:
//see what SLOTS are on my account
//Intelligent Octopus
//https://api.octopus.energy/v1/graphql

//OP1 - Something to process
//OP2 - get a new token
//OP3 - back round in 10s

//msg.IntelliCommand = "IntelliSlots" "IntelliPercent" "IntelliEnable" "IntelliDisable"


require = global.get('require');
const axios = require('axios')
var TeslaCharge = global.get('TargetSoC')


var AxiosResponse, OctopusID, authToken, DateNow, CurrentTime, CurrentHour, CurrentMinute, DPTime
var CurrentRate, KrakenURL, KrakenQuery, KrakenQueryHeader, ElectricRate, input, targetTime

OctopusID = global.get("OctopusID") //account ID A-xxxx
//OctopusID = Buffer.from(OctopusID).toString('base64')

var KrakenInstruction = msg.IntelliCommand

console.log("KrakenInstruction", KrakenInstruction)

authToken = flow.get("KrakenToken")

var ReadyBy = global.get('ReadyBy') || 2359
if (ReadyBy !== 2359) {
    //var targetTime = ReadyBy.substring(0, 1) + ":" + ReadyBy.substring(2, 3)
    var ReadyHour = Math.round(ReadyBy/100)
    var ReadyMinute = ReadyBy - (ReadyHour *100)
    if (ReadyMinute === 0) {
        ReadyMinute = "00"
    }
    if (ReadyBy < 1000) {
        targetTime = "0" + ReadyHour + ":" + ReadyMinute
    } else {
        targetTime = ReadyHour + ":" + ReadyMinute
    }
    global.set("ReadyByChange", false)
    //console.log("targetTime", targetTime)
} else {
    targetTime = "09:00"
}

//targetTime = "09:00"
var targetSocPercent = TeslaCharge


KrakenURL = "https://api.octopus.energy/v1/graphql/"


if (KrakenInstruction === "IntelliSlots") {
    KrakenQuery = {
        "query": `query AnyOldName($accountNumber: String!) {
                vehicleChargingPreferences(accountNumber: $accountNumber) {
                    weekdayTargetTime,
                    weekdayTargetSoc,
                    weekendTargetTime,
                    weekendTargetSoc
                }
                registeredKrakenflexDevice(accountNumber: $accountNumber) {
                    krakenflexDeviceId
                    provider
                    vehicleMake
                    vehicleModel
                    vehicleBatterySizeInKwh
                    chargePointMake
                    chargePointModel
                    chargePointPowerInKw
                    status
                    suspended
                    hasToken
                    createdAt
                }
                plannedDispatches(accountNumber: $accountNumber) {
                    startDtUtc: startDt
                    endDtUtc: endDt
                    chargeKwh: delta
                    meta {
                        source
                        location
                    }
                }
            }` ,
        "variables": { "accountNumber": OctopusID }
    }
} else if (KrakenInstruction === "IntelliPercent") {
    console.log("Updating the Kraken charge %age")
    KrakenQuery = {
        "query": `mutation setVehicleChargePreferences($accountNumber: String!, $targetTime: String!, $targetSocPercent: Int!) {
            setVehicleChargePreferences(input: { accountNumber: $accountNumber, weekdayTargetTime: $targetTime, weekendTargetTime: $targetTime, weekdayTargetSoc: $targetSocPercent, weekendTargetSoc: $targetSocPercent }) {
              krakenflexDevice {
                    krakenflexDeviceId
                }
            }
        }` , //this one stays
        "variables": { "accountNumber": OctopusID, "targetTime": targetTime, "targetSocPercent": targetSocPercent },
    }
} else if (KrakenInstruction === "IntelliEnable") {
    KrakenQuery = {
        "query": `mutation resumeControl($accountNumber: String!) {
            resumeControl(input: { accountNumber: $accountNumber }) {
              krakenflexDevice {
                krakenflexDeviceId
                }
            }
        }` , //this one stays
        "variables": { "accountNumber": OctopusID },
    }
} else if (KrakenInstruction === "IntelliDisable") {
    KrakenQuery = {
        "query": `mutation suspendControl($accountNumber: String!) {
            suspendControl(input: { accountNumber: $accountNumber }) {
              krakenflexDevice {
                krakenflexDeviceId
                }
            }
        }` , //this one stays
        "variables": { "accountNumber": OctopusID },
    }
} else {
    console.log("Unknown KrakenInstruction", KrakenInstruction)
    return
}

var basicAuth = authToken

KrakenQueryHeader = basicAuth

axios.defaults.headers.post['Authorization'] = `JWT ${KrakenQueryHeader}`  // for POST requests

input = await axiosTest(KrakenURL, KrakenQuery)

return

//async function axiosTest(KrakenURL, KrakenQuery, KrakenQueryHeader) {
async function axiosTest(KrakenURL, KrakenQuery) {
    axios.post(KrakenURL, KrakenQuery)
        .then(function (result) {
            AxiosResponse = result
            //flow.set("EarlyQueryResult", AxiosResponse.data.data)
            //flow.set("EarlyQueryResult", AxiosResponse)
            if (AxiosResponse.data.errors !== undefined) { //we have some error to process
                if (AxiosResponse.data.errors[0].message === "Signature of the JWT has expired.") {
                    node.send([[null], [msg]]) //need a new token
                    //console.log("Getting a token")
                    return
                }
                else {  //not a real error
                    console.log("Not a real error") //ValidAnswer(AxiosResponse)
                    return
                    //flow.set("KrakenToken",result.data.data.obtainKrakenToken.token)
                }
                return
            }
            else {
                msg.ValidAnswer = AxiosResponse
                node.send([[msg], [null]]) //off to processing
                return
            }
            return
        })
        .catch(function (error) {
            if (error.response) {
                // Request made and server responded
                var AxiosError = error.response
                if (error.response.status === 408) {
                    console.log("408 sleeping")
                    node.send([[null], [msg]])
                    //return (error)
                }
                else if (error.status = 500) {
                        console.log("500 Internal Server Error")
                        node.send([[null], [null], [msg]])
                    }
               
                else {
                    console.log("Some other error")
                    flow.set(KrakenInstruction + "-error", AxiosError)
                    //return (error)
                }
            } else if (error.request) {
                // The request was made but no response was received
                console.log("The request was made but no response was received");
                node.send([[null], [null], [msg]])
                flow.set(KrakenInstruction + "-request", AxiosError)
                //return (error)
            } else {
                // Something happened in setting up the request that triggered an Error
                console.log("Something happened in setting up the request that triggered an Error", AxiosError);
                flow.set(KrakenInstruction + "-other", AxiosError)
                //return (error)
            }
            //return
        }) //end of catch
    return
}

Making a token (needed first time, only last for about 60 mins)

JavaScript:
//Intelligent Octopus
//https://api.octopus.energy/v1/graphql

require = global.get('require');
const axios = require('axios')

const OctoAccount = global.get("OctopusID") //api ID A-xxxx
const OctoKey = global.get("OctopusKey") //api key

var OctoAuth = {
  auth: {
    "username": OctoKey,
    //password: pass
  }
}

var FirstURL = `https://api.octopus.energy/v1/graphql/`

var FirstData = {
    "query": `mutation krakenTokenAuthentication($api: String!) {
        obtainKrakenToken(input: {APIKey: $api}) {
            token
        }
        }`,
    "variables": {'api': OctoKey}
}

console.log("Making a kraken token")

function axiosTest(FirstURL, FirstData) {
    const response = axios.post(FirstURL,FirstData)
    .then(function (result) {
        var AxiosResponse = result
        //flow.set("KrakenResult",result)
        flow.set("KrakenToken",result.data.data.obtainKrakenToken.token)
        node.send ([msg])
        return
    })
    .catch (function (error) {
        flow.set("KrakenTokenError",error)
        return error
    })
    return response
}


//input =  await axiosTest(FirstURL,FirstHeaders, FirstData)
var input =  axiosTest(FirstURL, FirstData)
//console.log(input)
//flow.set('input',input)
 
Does anyone know how (or even if) I can change my charging vehicle on IO? I've got a home Podpoint charger which I use with the IO app to charge my model Y overnight. However the Y is currently at Tesla for repairs so i've got a loaner for a few weeks (probably).

Can I set it to still schedule overnight charges on the loaner vehicle as it does my own, or do I just have to manually plug it in after 23:30 every night for the cheap stuff?!
 
Does anyone know how (or even if) I can change my charging vehicle on IO? I've got a home Podpoint charger which I use with the IO app to charge my model Y overnight. However the Y is currently at Tesla for repairs so i've got a loaner for a few weeks (probably).

Can I set it to still schedule overnight charges on the loaner vehicle as it does my own, or do I just have to manually plug it in after 23:30 every night for the cheap stuff?!
Yes, just remove your current vehicle and do the onboarding with the loaner. Settings > Devices > Intelligent Octopus > Disconnect Device
 
Last edited:
  • Like
Reactions: rowedav and EyUpLad
Is kraken just the agile API?

Also, this evening's slots are set, but I'm only needing 75-90%. It's given me
View attachment 963593
But realistically it's going to start around 11:30, and finish in an hour or 2 - if the car doesn't need the 6-6:30 slot, I won't get it will I? Just working out rules for running the heat pump as in winter that 6am slot would be very advantageous!
The beauty of IO is it’s flexibilty as you can chose when you want your schedule, so if you want a schedule in the morning just request a schedule early morning and the time you want to leave, eg 8am And you should get a schedule until 8am.
You don’t have to charge during the off peak hours, as long as you let octopus control the charging you’ll get the extra slots
 
Someone said that you can't be on a high export tariff with IO.
I came back from holiday yesterday abd that's exactly what happened. I was on IO till April, them switched to Flux fir the high export rates.
I plugged the M3 in yesterday to give it a solar charge, having arrived home at 10%. IO created a charging cycle in the app.
The car was plugged into the Zappi, which I have never used for IO, I have a dumb charger for that.
My problem is now that IO has kept the car awake all night and I now only have 2% .. not enough to go shopping even.
I've posed the question to Octopus, asking how I can be smart charging and be on Flux at the same time.. IO still wants to control my solar charging by not charging on eco+ mode so I'll have to find a work around. I'm away again, without the car for a few weeks and was hoping as usual to leave the car plugged in and slowly top it up from solar.. but I'm not sure I can take the risk of IO depleting the battery.
Any quick solutions/ suggestions as I leave on Wed morning? Apart from leaving the car unplugged.