Kotlin, 74 bytes
{it.stream().reduce(1){r,v->if(r*25>r*v)1 else(r*if(v<30)2 else 6)%864}<1}
(-1 byte thanks Lynn: replaced r>0&&v<25 with r25>rv)
{it.stream().reduce(1){r,v->if(r>0&&v<25)1 else(r*if(v<30)2 else 6)%864}<1}
This lambda expression takes a List and returns true for a heatwave or false else.
Thanks to the magic number 864 and to Udo Borkowski and Mathis for their ideas.
How does if work? Each sequence of numbers is iterated with a reduce operation starting at the reduce value 1. If a number >= 25 is seen the reduce is multiplied by 2. If a number >= 30 is seen the reduce is multiplied by 2 and by 3 = 6. If a number < 25 is seen the reduce starts again at 1. If the reduce is divisible by 864=2222233*3 then a heatwave is found, and the result of the modulo operation is 0 which results in a reduce value of 0 and in a return value of true.