2 This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
3 Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
4 Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
5 You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
9 TemperatureSwitch is an optional module that will automatically turn on or off a switch
10 based on a setpoint temperature. It is commonly used to turn on/off a cooling fan or water pump
11 to cool the hot end's cold zone. Specifically, it turns one of the small MOSFETs on or off.
13 Author: Michael Hackney, mhackney@eclecticangler.com
16 #include "TemperatureSwitch.h"
17 #include "libs/Module.h"
18 #include "libs/Kernel.h"
19 #include "modules/tools/temperaturecontrol/TemperatureControlPublicAccess.h"
20 #include "SwitchPublicAccess.h"
25 #include "ConfigValue.h"
26 #include "checksumm.h"
27 #include "PublicData.h"
28 #include "StreamOutputPool.h"
30 #define temperatureswitch_checksum CHECKSUM("temperatureswitch")
31 #define temperatureswitch_enable_checksum CHECKSUM("enable")
32 #define temperatureswitch_hotend_checksum CHECKSUM("hotend")
33 #define temperatureswitch_threshold_temp_checksum CHECKSUM("threshold_temp")
34 #define temperatureswitch_type_checksum CHECKSUM("type")
35 #define temperatureswitch_heatup_poll_checksum CHECKSUM("heatup_poll")
36 #define temperatureswitch_cooldown_poll_checksum CHECKSUM("cooldown_poll")
38 TemperatureSwitch::TemperatureSwitch()
43 void TemperatureSwitch::on_module_loaded()
45 // free up space if not loaded
46 if (!THEKERNEL
->config
->value(temperatureswitch_checksum
, temperatureswitch_hotend_checksum
, temperatureswitch_enable_checksum
)->by_default(false)->as_bool()) {
52 this->on_config_reload(this);
56 void TemperatureSwitch::on_config_reload(void *argument
)
58 // get the list of temperature controllers and remove any that fon't have designator == "T"
59 vector
<uint16_t> controller_list
;
60 THEKERNEL
->config
->get_module_list(&controller_list
, temperature_control_checksum
);
63 for (auto controller
: controller_list
) {
64 bool temp_ok
= PublicData::get_value(temperature_control_checksum
, controller
, current_temperature_checksum
, &returned_temp
);
66 struct pad_temperature temp
= *static_cast<struct pad_temperature
*>(returned_temp
);
67 // if the controller is a hotend (designator == "T") then keep it
68 if (temp
.designator
.substr(0, 1) == "T") {
69 temp_controllers
.push_back(controller
);
74 // if we don't have any controllers, free up space
75 if (temp_controllers
.empty()) {
80 // load settings from config file
81 this->temperatureswitch_state
= false;
82 this->temperatureswitch_type_cs
= get_checksum(THEKERNEL
->config
->value(temperatureswitch_checksum
, temperatureswitch_hotend_checksum
, temperatureswitch_type_checksum
)->by_default("")->as_string());
83 this->temperatureswitch_threshold_temp
= THEKERNEL
->config
->value(temperatureswitch_checksum
, temperatureswitch_hotend_checksum
, temperatureswitch_threshold_temp_checksum
)->by_default(50.0f
)->as_number();
85 // these are to tune the heatup and cooldown polling frequencies
86 this->temperatureswitch_heatup_poll
= THEKERNEL
->config
->value(temperatureswitch_checksum
, temperatureswitch_hotend_checksum
, temperatureswitch_heatup_poll_checksum
)->by_default(15)->as_number();
87 this->temperatureswitch_cooldown_poll
= THEKERNEL
->config
->value(temperatureswitch_checksum
, temperatureswitch_hotend_checksum
, temperatureswitch_cooldown_poll_checksum
)->by_default(60)->as_number();
90 current_delay
= this->temperatureswitch_heatup_poll
;
92 // Register for events
93 this->register_for_event(ON_SECOND_TICK
);
96 // Called once a second but we only need to service on the cooldown and heatup poll intervals
97 void TemperatureSwitch::on_second_tick(void *argument
)
100 if (second_counter
< current_delay
) {
104 float current_temp
= this->get_highest_temperature();
106 if (current_temp
>= this->temperatureswitch_threshold_temp
) {
107 // temp >= threshold temp, turn the cooler switch on if it isn't already
108 if (!temperatureswitch_state
) {
110 current_delay
= temperatureswitch_cooldown_poll
;
113 // temp < threshold temp, turn the cooler switch off if it isn't already
114 if (temperatureswitch_state
) {
116 current_delay
= temperatureswitch_heatup_poll
;
122 // Get the highest temperature from the set of temperature controllers
123 float TemperatureSwitch::get_highest_temperature()
126 float high_temp
= 0.0;
128 for (auto controller
: temp_controllers
) {
129 bool temp_ok
= PublicData::get_value(temperature_control_checksum
, controller
, current_temperature_checksum
, &returned_temp
);
131 struct pad_temperature temp
= *static_cast<struct pad_temperature
*>(returned_temp
);
132 // check if this controller's temp is the highest and save it if so
133 if (temp
.current_temperature
> high_temp
) {
134 high_temp
= temp
.current_temperature
;
141 // Turn the switch on (true) or off (false)
142 void TemperatureSwitch::set_switch(bool switch_state
)
144 this->temperatureswitch_state
= switch_state
;
145 bool ok
= PublicData::set_value(switch_checksum
, this->temperatureswitch_type_cs
, state_checksum
, &this->temperatureswitch_state
);
147 THEKERNEL
->streams
->printf("Failed changing switch state.\r\n");