If you take away the requirement that the alert come exactly at 00 and 30 and make your requirement that it only report every 30 minutes it is below the threshold it becomes much simpler. I’ll use Design Pattern: Expire Binding Based Timers and Design Pattern: Separation of Behaviors.
rule "PVisland Voltage below 23V Alert - Notification"
when
Item PVislandVolt changed
then
// NULL isn't a value we can use in this rule
if(PVislandVolt.state == NULL) return;
// If the Timer is already running we have nothing to do
if(PVislandVolt_Timer.state == ON) return;
// Voltage is low, alert
if(PVislandVolt.state < 23) {
aAlert.sendCommand("PVisland | Battery Voltage Level Alert | " + PVislandVolt.state + "V", "--EOM--")
PVislandVolt_Timer.sendCommand(ON)
}
// Voltage is back above threshold, cancel alerts
else {
PVislandVolt_Timer.postUpdate(OFF)
}
end
rule "PVislandVol timer expired"
when
Item PVislandVolt_Timer received command OFF
then
// No more alerts if the voltage goes above the threshold
if(PVislandVolt.state == NULL || PVislandVolt.state >= 23) return;
// alert and reschedule the Timer for another 30 minutes while it remains below threshold
aAlert.sendCommand("PVisland | Battery Voltage Level Alert | " + PVislandVolt.state + "V", "--EOM--")
PVislandVolt_Timer.sendCommand(ON)
end
If you only want the one alert when it first goes below the threshold and not get repeats, which you stated is your ultimate goal, then Scott already provided that answer in post 4.
As you can see, minor changes in your requirements can result in drastically different solutions. And all things considered, implementing your ultimate goal is actually far easier than your stated compromise solution.