@@ -22,6 +22,8 @@ namespace emsesp {
22
22
23
23
uuid::log::Logger Shower::logger_{F_ (shower), uuid::log ::Facility::CONSOLE};
24
24
25
+ static bool force_coldshot = false ;
26
+
25
27
void Shower::start () {
26
28
EMSESP::webSettingsService.read ([&](WebSettings & settings) {
27
29
shower_timer_ = settings.shower_timer ;
@@ -30,7 +32,27 @@ void Shower::start() {
30
32
shower_alert_coldshot_ = settings.shower_alert_coldshot * 1000 ; // convert from seconds
31
33
});
32
34
33
- set_shower_state (false , true ); // turns shower to off and creates HA topic if not already done
35
+ Command::add (
36
+ EMSdevice::DeviceType::BOILER,
37
+ F_ (coldshot),
38
+ [&](const char * value, const int8_t id, JsonObject & output) {
39
+ LOG_INFO (" Forcing coldshot..." );
40
+ if (shower_state_) {
41
+ output[" message" ] = " OK" ;
42
+ force_coldshot = true ;
43
+ } else {
44
+ output[" message" ] = " Coldshot failed. Shower not active" ;
45
+ LOG_WARNING (" Coldshot failed. Shower not active" );
46
+ force_coldshot = false ;
47
+ }
48
+ return true ;
49
+ },
50
+ FL_ (coldshot_cmd),
51
+ CommandFlag::ADMIN_ONLY);
52
+
53
+ if (shower_timer_) {
54
+ set_shower_state (false , true ); // turns shower to off and creates HA topic if not already done
55
+ }
34
56
}
35
57
36
58
void Shower::loop () {
@@ -57,10 +79,10 @@ void Shower::loop() {
57
79
// first check to see if hot water has been on long enough to be recognized as a Shower/Bath
58
80
if (!shower_state_ && (time_now - timer_start_) > SHOWER_MIN_DURATION) {
59
81
set_shower_state (true );
60
- LOG_DEBUG (" [Shower] hot water still running, starting shower timer" );
82
+ LOG_DEBUG (" hot water still running, starting shower timer" );
61
83
}
62
84
// check if the shower has been on too long
63
- else if ((time_now - timer_start_) > shower_alert_trigger_) {
85
+ else if ((shower_alert_ && (( time_now - timer_start_) > shower_alert_trigger_)) || force_coldshot ) {
64
86
shower_alert_start ();
65
87
}
66
88
}
@@ -79,11 +101,11 @@ void Shower::loop() {
79
101
if (duration_ > SHOWER_MIN_DURATION) {
80
102
StaticJsonDocument<EMSESP_JSON_SIZE_SMALL> doc;
81
103
82
- char s[50 ];
83
- snprintf (s, 50 , " %d minutes and %d seconds " , (uint8_t )(duration_ / 60000 ), (uint8_t )((duration_ / 1000 ) % 60 ));
84
- doc[" duration" ] = s;
104
+ // char s[50];
105
+ // snprintf(s, 50, "%02u:%02u:%02u", (uint8_t)(duration_ / 3600000UL) , (uint8_t)(duration_ / 60000UL ), (uint8_t)((duration_ / 1000UL ) % 60));
106
+ doc[" duration" ] = ( uint8_t )(duration_ / 1000UL ); // seconds
85
107
Mqtt::queue_publish (" shower_data" , doc.as <JsonObject>());
86
- LOG_DEBUG ( " [Shower] finished with duration %d" , duration_);
108
+ LOG_INFO ( " finished with duration %d" , duration_);
87
109
}
88
110
}
89
111
@@ -106,37 +128,34 @@ void Shower::loop() {
106
128
}
107
129
}
108
130
131
+ // turn off hot water to send a shot of cold
132
+ void Shower::shower_alert_start () {
133
+ LOG_DEBUG (" Shower Alert started" );
134
+ (void )Command::call (EMSdevice::DeviceType::BOILER, " wwtapactivated" , " false" );
135
+ doing_cold_shot_ = true ;
136
+ force_coldshot = false ;
137
+ alert_timer_start_ = uuid::get_uptime (); // timer starts now
138
+ }
139
+
109
140
// turn back on the hot water for the shower
110
141
void Shower::shower_alert_stop () {
111
142
if (doing_cold_shot_) {
112
143
LOG_DEBUG (" Shower Alert stopped" );
113
144
(void )Command::call (EMSdevice::DeviceType::BOILER, " wwtapactivated" , " true" );
114
145
doing_cold_shot_ = false ;
115
- }
116
- }
117
- // turn off hot water to send a shot of cold
118
- void Shower::shower_alert_start () {
119
- if (shower_alert_) {
120
- LOG_DEBUG (" Shower Alert started" );
121
- (void )Command::call (EMSdevice::DeviceType::BOILER, " wwtapactivated" , " false" );
122
- doing_cold_shot_ = true ;
123
- alert_timer_start_ = uuid::get_uptime (); // timer starts now
146
+ force_coldshot = false ;
124
147
}
125
148
}
126
149
127
150
// send status of shower to MQTT topic called shower_active - which is determined by the state parameter
128
151
// and creates the HA config topic if HA enabled
129
152
// force is used by EMSESP::publish_all_loop()
130
153
void Shower::set_shower_state (bool state, bool force) {
131
- if (!shower_timer_ && !shower_alert_) {
132
- return ;
133
- }
134
-
135
154
// sets the state
136
155
shower_state_ = state;
137
156
138
157
// only publish if that state has changed
139
- static bool old_shower_state_;
158
+ static bool old_shower_state_ = false ;
140
159
if ((shower_state_ == old_shower_state_) && !force) {
141
160
return ;
142
161
}
@@ -149,10 +168,15 @@ void Shower::set_shower_state(bool state, bool force) {
149
168
// send out HA MQTT Discovery config topic
150
169
if ((Mqtt::ha_enabled ()) && (!ha_configdone_ || force)) {
151
170
StaticJsonDocument<EMSESP_JSON_SIZE_LARGE> doc;
171
+ char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
172
+ char str[70 ];
173
+ char stat_t [50 ];
152
174
175
+ //
176
+ // shower_active topic
177
+ //
153
178
doc[" name" ] = " Shower Active" ;
154
179
155
- char str[70 ];
156
180
if (Mqtt::entity_format () == Mqtt::entityFormat::MULTI_SHORT) {
157
181
snprintf (str, sizeof (str), " %s_shower_active" , Mqtt::basename ().c_str ());
158
182
} else {
@@ -161,7 +185,6 @@ void Shower::set_shower_state(bool state, bool force) {
161
185
doc[" uniq_id" ] = str;
162
186
doc[" object_id" ] = str;
163
187
164
- char stat_t [50 ];
165
188
snprintf (stat_t , sizeof (stat_t ), " %s/shower_active" , Mqtt::basename ().c_str ());
166
189
doc[" stat_t" ] = stat_t ;
167
190
@@ -181,13 +204,39 @@ void Shower::set_shower_state(bool state, bool force) {
181
204
JsonArray ids = dev.createNestedArray (" ids" );
182
205
ids.add (Mqtt::basename ());
183
206
184
- // add "availability" section
185
- Mqtt::add_avty_to_doc (stat_t , doc.as <JsonObject>());
207
+ Mqtt::add_avty_to_doc (stat_t , doc.as <JsonObject>()); // add "availability" section
186
208
187
- char topic[Mqtt::MQTT_TOPIC_MAX_SIZE];
188
209
snprintf (topic, sizeof (topic), " binary_sensor/%s/shower_active/config" , Mqtt::basename ().c_str ());
189
-
190
210
ha_configdone_ = Mqtt::queue_ha (topic, doc.as <JsonObject>()); // publish the config payload with retain flag
211
+
212
+ //
213
+ // shower_duaration topic
214
+ //
215
+ doc.clear ();
216
+
217
+ snprintf (str, sizeof (str), " %s_shower_duration" , Mqtt::basename ().c_str ());
218
+
219
+ doc[" uniq_id" ] = str;
220
+ doc[" object_id" ] = str;
221
+
222
+ snprintf (stat_t , sizeof (stat_t ), " %s/shower_data" , Mqtt::basename ().c_str ());
223
+ doc[" stat_t" ] = stat_t ;
224
+
225
+ doc[" name" ] = " Shower Duration" ;
226
+ doc[" val_tpl" ] = " {{value_json.duration if value_json.duration is defined else 0}}" ;
227
+ doc[" unit_of_meas" ] = " s" ;
228
+ doc[" stat_cla" ] = " measurement" ;
229
+ doc[" dev_cla" ] = " duration" ;
230
+ doc[" ent_cat" ] = " diagnostic" ;
231
+
232
+ JsonObject dev2 = doc.createNestedObject (" dev" );
233
+ JsonArray ids2 = dev2.createNestedArray (" ids" );
234
+ ids2.add (Mqtt::basename ());
235
+
236
+ Mqtt::add_avty_to_doc (stat_t , doc.as <JsonObject>(), " value_json.duration is defined" ); // add "availability" section
237
+
238
+ snprintf (topic, sizeof (topic), " sensor/%s/shower_duration/config" , Mqtt::basename ().c_str ());
239
+ Mqtt::queue_ha (topic, doc.as <JsonObject>()); // publish the config payload with retain flag
191
240
}
192
241
}
193
242
0 commit comments