Closed rkoshak closed 4 years ago
@rkoshak Fan's previous state is not restored when AUTO ends like when temperature is reached during heating/cooling, so fan always 'returns' to ON. Can I also say that I timed a boot and it is really improved!!! I think we got the LCD UI (but empty) after 10 minutes and fully functional (relays, LCD UI, Web UI and phone App) after about 15-18 minutes (in total!). From 25-28 minutes that it used to be, this is HUGE and I have to thank you @rkoshak for this enormous interest and help over the last month or so (that I haven't been able to keep up with). On the other hand the rules are much harder for me to follow now :) but I haven't got the chance to spend enough time with them due to my other non-coding commitments with the project.
@rkoshak Fan's previous state is not restored when AUTO ends like when temperature is reached during heating/cooling, so fan always 'returns' to ON.
That's how it was in the original code too. When the heat or cooling turns on, the Fan mode goes to AUTO and the fan turns ON. When heating/cooling ends, the Fan mode turns OFF too:
rule "FanControl"
when
Item HeatingPin changed or
Item CoolingPin changed or
Item FanMode changed
then
if (FanMode.state == "AUTO") {
if ((HeatingPin.state == ON) || (CoolingPin.state == ON)) {
FanPin.sendCommand(ON)
}
else {
FanPin.sendCommand(OFF)
}
} else if (FanMode.state == "ON") {
FanPin.sendCommand(ON)
} else { //FanMode.state == "OFF"
FanPin.sendCommand(OFF)
}
end
FanMode will be AUTO when the HeatingPin or CoolingPin turn OFF so FanPin is set to OFF.
If someone happened to change the FanMode to ON or OFF while the heating was running, which shouldn't have been allowed per previous issues with trying to run the heating or cooling without the fan than it would remain ON or turn OFF.
With the new code, the Fan cannot be changed while heating or cooling is running.
I can easily add code to restore the fan to the previous mode after heating or cooling ends, which really only is meaningful if the FanMode was ON before heating/cooling started. It will make the logic a little more challenging though.
I'm really happy to hear I've made that much of a difference in the boot time. It felt like I've made progress but I failed to take a before measurement to compare against. I mostly restart OH instead of rebooting the whole machine (who wants to wait around that long?). I bet I can shave at least another 5 minutes or so from that boot time.
The limiting factor appears to be CPU so anything we can do to reduce the CPU load like switching to JSONDB should have a significant improvement.
I am happy to answer any questions you may have on the Rules. It might help to review some of the design pattern postings on the OH forum which I applied in order to make the Rules more generic.
I use HashMaps to store key/value pairs a lot. These store default values (DEFAULTS), mappings between the PinItems and the GPIO Pin Items since they are different when in HVAC mode and EU mode, timers and the lambdas which are the functions called from various Rules.
I based access to defaults, values, timers, and the lambdas on Item names. This lets me write the Rules generically and pick the right value, Item, lambda, etc. based on the name of the Item that triggered the Rule.
The lambdas come in pairs, one (DECIDE_LAMBDAS) is responsible for determining whether to turn on or off a device. The second (CTRL_LAMBDAS) is responsible for actually turning on or off the devices. Hopefully the code in the lambdas is self explanatory. The ctrl lambda is passed into the decide lambda because global lambdas cannot see each other.
The Initialization Rule goes through all of the setting Items. If the Item is NULL or UNDEF, the Item is set to it's default (defined in DEFAULTS). If it does have a value, it was restored from the database and we keep that value, restoring the thermostat to what ever state it was in before it restarted. Because there is more than one line of code needed for each Item, I defined some lambdas to call at the top of the Rule to reduce duplicated code. The network/system status Items get initialized from the scripts every time. Once everything is initialized, we cancel any Boost modes that were active before OH started. Finally, we activate any devices that need to be activated now that everything is initialized. There is a boolean defined to prevent rules from running as the sensors report new readings while it is still initializing.
Temp Proxy Sync and Pin changed are simple rules that sync the proxy Items with each other. There is a check in "Pin changed" to make sure the Fan turns when heating or cooling turns on. The mapping between, for example, HeatingPin and Pin12 is stored in the map discussed previously.
"Process Sensor Changes" gets triggered whenever a sensor reading comes in. It's completely generic, using the same code for Temperature, Humidity, and Pressure. It uses the Associated Item Design Pattern to generate the "PreviousXReading" Item name from the name of the Item that triggered the Rule. As with the previous set of rules, triggering the Rule that decided whether or not to turn on/off a device is done by commanding the PreviousReading Item. This Item too is obtained using the Associated Item DP. The hysteresis used to avoid changing the PreviousReading Item for too small a change is in the DEFAULTS map. Since the sensor readings can't cause anything to happen until everything is initialized, we don't need to check for initialization in here.
"Temp or setpoint changed" is where the sensor readings and setpoints actually drive the temp devices. It's a very simple rule now. It just needs to figure out what device we need to control and call the proper decide lambda. "Humidity or setpoint changed" is the humidity equivalent.
"Mode Changed" is triggered when any one of the Mode Items. It works the same for all the devices, even the Fan. Based on the name of the Mode Item that triggered the Rule, we obtain the right lambdas from the Map and then call them with the right arguments based on the new Mode. the lambda takes it from there.
"Heating2 turned OFF" get's called when second stage heating turns off. See the heating lambdas for how heating2 is turned ON using a timer.
"MainSwitch OFF" turns all the Modes Items to OFF. the Mode Changed Rule and lambdas will get called in turn to ultimately turn off the devices.
The way "Boost" works has changed significantly. Instead of running two Timers side by side, one to count down and the other to turn off Boost mode, we have just the one Timer. When a device's Mode changes to Boost the "Boost" Rule triggers. This Rule records the previousState and calls the lambda to decide whether to turn on/off the device. Then we command the "[device]RemBoostTime" with the number stored in "[device]BoostTime". This triggers the "RemBoostTimeChanged" Rule. This Rule looks to see how much time is left on the RemBoostTime Item. If there is more than 0, it sets a Timer for one minute. The Timer subtracts one from the RemBoostTime Item which triggers the Rule again. When it get's down to 0, turn off Boost mode and return to the previous mode. I had to create the new RemBoostTime Items and link those to the MQTT topics that drive the LCD.
The rest of the Rules are straight forward and pretty close to what was in the originals. But I did consolidate a lot of the rules that were the same code with different Items, added some logging, and cleaned up a little bit.
For some background see:
PR #36 addresses the FanMode issue mentioned above as well as a bug with the BoostTime Items.
That's how it was in the original code too. When the heat or cooling turns on, the Fan mode goes to AUTO and the fan turns ON.
It switched to AUTO only if it was OFF. If it was ON the FanMode would stay unchanged.
if (FanMode.state == "OFF") FanMode.sendCommand("AUTO");
When heating/cooling ends, the Fan mode turns OFF too:
When heating/cooling ends, HeatingPin or CoolingPin would change triggering this rule that would force FanPin to follow HeatingPin or CoolingPin if (FanMode.state == "AUTO")
otherwise FanPin
would follow FanMode
.
rule "FanControl"
when
Item HeatingPin changed or
Item CoolingPin changed or
Item FanMode changed
then
if (FanMode.state == "AUTO") {
if ((HeatingPin.state == ON) || (CoolingPin.state == ON)) {
FanPin.sendCommand(ON)
}
else {
FanPin.sendCommand(OFF)
}
} else if (FanMode.state == "ON") {
FanPin.sendCommand(ON)
} else { //FanMode.state == "OFF"
FanPin.sendCommand(OFF)
}
end
merging #36 as it seems to produce the same result...
Added controls to prevent the fan from being turned off if heating or cooling is on.
Added a FanCtrl Item used to hide/show the fan controls on BasicUI only when heating or cooling is not ON.
Added code in Rules to turn on the Fan first, wait a second and then turn on Heating or Cooling. When turning off, turn off Heating or Cooling first and then wait a second to turn off the Fan. When in heating or cooling, disable the ability to control the Fan on the sitemap by sending OFF to FanCtrl.
In initialization, only call the lambdas if the mode is not OFF. Otherwise the heating, cooling, or humidity will turn on if the setpoint and sensor value says to even if the mode is OFF.
As a last bit of protection, even if FanPin receives a command to turn OFF, if Heating or Cooling is ON ignore the command and return FanPin to ON, FanMode to AUTO and FanCtrl to OFF.
Changed debug log level to Debug for changes to the WAN IP changes.
Signed-off-by: Richard Koshak rlkoshak@gmail.com