1+ #pragma once
2+
3+ #include " ../SinricProRequest.h"
4+ #include " ../EventLimiter.h"
5+ #include " ../SinricProStrings.h"
6+
7+ #include " ../SinricProNamespace.h"
8+ namespace SINRICPRO_NAMESPACE {
9+
10+ FSTR (OPEN_CLOSE, openPercent); // "openPercent"
11+ FSTR (OPEN_CLOSE, openRelativePercent); // "openRelativePercent"
12+ FSTR (OPEN_CLOSE, openDirection); // "openDirection"
13+ FSTR (OPEN_CLOSE, setOpenClose); // "setOpenClose"
14+ FSTR (OPEN_CLOSE, adjustOpenClose); // "adjustOpenClose"
15+
16+
17+ /* *
18+ * @brief Callback definition for onOpenClose callback
19+ *
20+ * Gets called when device receives a `setOpenClose` request
21+ * @param[in] deviceId String containing the ID of device
22+ * @param[in,out] openPercent Integer percentage (0-100) of how open the device should be set (0 = closed, 100 = fully open)
23+ * @return Success status of the request
24+ * @retval true Request handled successfully
25+ * @retval false Request handling failed
26+ *
27+ * @section OpenCloseCallback Example-Code
28+ * @snippet callbacks.cpp onSetOpenClose
29+ **/
30+ using OpenCloseCallback = std::function<bool (const String &, int &)>;
31+
32+ /* *
33+ * @brief Callback definition for onAdjustOpenClose callback
34+ *
35+ * Gets called when device receives an `adjustOpenClose` request
36+ * @param[in] deviceId String containing the ID of device
37+ * @param[in,out] openRelativePercent Integer value representing the relative percentage change to apply
38+ * On output, should contain the absolute percentage value the device has been set to
39+ * @return Success status of the request
40+ * @retval true Request handled successfully
41+ * @retval false Request handling failed
42+ *
43+ * @section AdjustOpenCloseCallback Example-Code
44+ * @snippet callbacks.cpp onAdjustOpenClose
45+ **/
46+ using AdjustOpenCloseCallback = std::function<bool (const String &, int &)>;
47+
48+ /* *
49+ * @brief Callback definition for onDirectionOpenClose callback
50+ *
51+ * Gets called when device receives a `setOpenClose` request with direction information
52+ * @param[in] deviceId String containing the ID of device
53+ * @param[in] openDirection String direction in which to open: `UP`, `DOWN`, `LEFT`, `RIGHT`, `IN`, `OUT`
54+ * @param[in,out] openPercent Integer percentage (0-100) of how open the device should be set
55+ * @return Success status of the request
56+ * @retval true Request handled successfully
57+ * @retval false Request handling failed
58+ *
59+ * @section DirectionOpenCloseCallback Example-Code
60+ * @snippet callbacks.cpp onDirectionOpenClose
61+ **/
62+ using DirectionOpenCloseCallback = std::function<bool (const String &, const String &, int &)>;
63+
64+ /* *
65+ * @brief Callback definition for onAdjustDirectionOpenClose callback
66+ *
67+ * Gets called when device receives an `adjustOpenClose` request with direction information
68+ * @param[in] deviceId String containing the ID of device
69+ * @param[in] openDirection String direction in which to open: `UP`, `DOWN`, `LEFT`, `RIGHT`, `IN`, `OUT`
70+ * @param[in,out] openRelativePercent Integer representing relative percentage change to apply
71+ * On output, should contain the absolute percentage value the device has been set to
72+ * @return Success status of the request
73+ * @retval true Request handled successfully
74+ * @retval false Request handling failed
75+ *
76+ * @section AdjustDirectionOpenCloseCallback Example-Code
77+ * @snippet callbacks.cpp onAdjustDirectionOpenClose
78+ **/
79+ using AdjustDirectionOpenCloseCallback = std::function<bool (const String &, const String &, int &)>;
80+
81+ /* *
82+ * @brief Controller class for devices with open/close functionality
83+ * @ingroup Capabilities
84+ * This controller handles open/close operations for devices that can be opened or closed by percentage and may supports multiple directions.
85+ *
86+ * @tparam T Device type that implements this controller
87+ */
88+ template <typename T>
89+ class OpenCloseController {
90+ public:
91+ OpenCloseController ();
92+
93+ /* *
94+ * @brief Set callback function for simple open/close operations
95+ *
96+ * @param cb Function pointer to a `OpenCloseCallback` function
97+ * @return void
98+ * @see OpenCloseCallback
99+ **/
100+ void onOpenClose (OpenCloseCallback cb);
101+
102+ /* *
103+ * @brief Set callback function for directional open/close operations
104+ *
105+ * @param cb Function pointer to a `DirectionOpenCloseCallback` function
106+ * @return void
107+ * @see DirectionOpenCloseCallback
108+ **/
109+ void onDirectionOpenClose (DirectionOpenCloseCallback cb);
110+
111+ /* *
112+ * @brief Set callback function for relative adjustments to open/close status
113+ *
114+ * @param cb Function pointer to a `AdjustOpenCloseCallback` function
115+ * @return void
116+ * @see AdjustOpenCloseCallback
117+ **/
118+ void onAdjustOpenClose (AdjustOpenCloseCallback cb);
119+
120+ /* *
121+ * @brief Set callback function for directional relative adjustments
122+ *
123+ * @param cb Function pointer to a `AdjustDirectionOpenCloseCallback` function
124+ * @return void
125+ * @see AdjustDirectionOpenCloseCallback
126+ **/
127+ void onAdjustDirectionOpenClose (AdjustDirectionOpenCloseCallback cb);
128+
129+ /* *
130+ * @brief Send an event to update the open/close status
131+ *
132+ * @param openPercent Current open percentage (0-100)
133+ * @param cause Cause of the event (default: physical interaction)
134+ * @return bool Whether the event was sent successfully
135+ **/
136+ bool sendOpenCloseEvent (int openPercent, String cause = FSTR_SINRICPRO_PHYSICAL_INTERACTION);
137+
138+ /* *
139+ * @brief Send an event to update the open/close status with direction
140+ *
141+ * @param openDirection Direction of opening (UP, DOWN, LEFT, RIGHT, IN, OUT)
142+ * @param openPercent Current open percentage (0-100)
143+ * @param cause Cause of the event (default: physical interaction)
144+ * @return bool Whether the event was sent successfully
145+ **/
146+ bool sendOpenCloseEvent (String openDirection, int openPercent, String cause = FSTR_SINRICPRO_PHYSICAL_INTERACTION);
147+
148+ protected:
149+ /* *
150+ * @brief Handle incoming open/close control requests
151+ *
152+ * @param request The incoming request to process
153+ * @return bool Whether the request was handled successfully
154+ **/
155+ bool handleOpenCloseController (SinricProRequest &request);
156+
157+ private:
158+ EventLimiter event_limiter;
159+ DirectionOpenCloseCallback directionOpenCloseCallback;
160+ OpenCloseCallback openCloseCallback;
161+ AdjustOpenCloseCallback adjustOpenCloseCallback;
162+ AdjustDirectionOpenCloseCallback adjustDirectionOpenCloseCallback;
163+ };
164+
165+ template <typename T>
166+ OpenCloseController<T>::OpenCloseController()
167+ :event_limiter(EVENT_LIMIT_STATE) {
168+ T* device = static_cast <T*>(this );
169+ device->registerRequestHandler (std::bind (&OpenCloseController<T>::handleOpenCloseController, this , std::placeholders::_1));
170+ }
171+
172+ template <typename T>
173+ void OpenCloseController<T>::onOpenClose(OpenCloseCallback cb) { openCloseCallback = cb; }
174+
175+ template <typename T>
176+ void OpenCloseController<T>::onDirectionOpenClose(DirectionOpenCloseCallback cb) { directionOpenCloseCallback = cb; }
177+
178+ template <typename T>
179+ void OpenCloseController<T>::onAdjustOpenClose(AdjustOpenCloseCallback cb) { adjustOpenCloseCallback = cb; }
180+
181+ template <typename T>
182+ void OpenCloseController<T>::onAdjustDirectionOpenClose(AdjustDirectionOpenCloseCallback cb) { adjustDirectionOpenCloseCallback = cb; }
183+
184+ /* *
185+ * @brief Send an event to update open/close status with open direction and precent and information
186+ *
187+ * Sends the current open/close status with direction to the Sinric Pro cloud.
188+ * The event will only be sent if the event rate limiter allows it.
189+ *
190+ * @param openDirection Direction in which the device is opening
191+ * @param openPercent Current open percentage (0-100)
192+ * @param cause Reason for the state change (default: physical interaction)
193+ * @return bool Whether the event was sent successfully
194+ */
195+ template <typename T>
196+ bool OpenCloseController<T>::sendOpenCloseEvent(String openDirection, int openPercent, String cause) {
197+ if (event_limiter) return false ;
198+ T* device = static_cast <T*>(this );
199+
200+ JsonDocument eventMessage = device->prepareEvent (FSTR_OPEN_CLOSE_setOpenClose, cause.c_str ());
201+ JsonObject event_value = eventMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value];
202+ event_value[FSTR_OPEN_CLOSE_openDirection] = openDirection;
203+ event_value[FSTR_OPEN_CLOSE_openPercent] = openPercent;
204+
205+ return device->sendEvent (eventMessage);
206+ }
207+
208+ /* *
209+ * @brief Send an event to update open/close status
210+ *
211+ * Sends the current open/close percentage to the Sinric Pro cloud.
212+ * The event will only be sent if the event rate limiter allows it.
213+ *
214+ * @param openPercent Current open percentage (0-100)
215+ * @param cause Reason for the state change (default: physical interaction)
216+ * @return bool Whether the event was sent successfully
217+ */
218+ template <typename T>
219+ bool OpenCloseController<T>::sendOpenCloseEvent(int openPercent, String cause) {
220+ if (event_limiter) return false ;
221+ T* device = static_cast <T*>(this );
222+
223+ JsonDocument eventMessage = device->prepareEvent (FSTR_OPEN_CLOSE_setOpenClose, cause.c_str ());
224+ JsonObject event_value = eventMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value];
225+ event_value[FSTR_OPEN_CLOSE_openPercent] = openPercent;
226+
227+ return device->sendEvent (eventMessage);
228+ }
229+
230+ /* *
231+ * @brief Handle incoming open/close requests
232+ *
233+ * Processes both setOpenClose and adjustOpenClose requests with or without direction information.
234+ * Delegates to the appropriate callback function based on the request type and parameters.
235+ *
236+ * @param request The incoming request containing action and parameters
237+ * @return bool Whether the request was handled successfully
238+ */
239+ template <typename T>
240+ bool OpenCloseController<T>::handleOpenCloseController(SinricProRequest &request) {
241+ T* device = static_cast <T*>(this );
242+
243+ bool success = false ;
244+
245+ if (request.action == FSTR_OPEN_CLOSE_setOpenClose) {
246+ bool hasOpenDirection = !request.request_value [FSTR_OPEN_CLOSE_openDirection].isNull ();
247+ int openPercent = request.request_value [FSTR_OPEN_CLOSE_openPercent];
248+
249+ if (hasOpenDirection && directionOpenCloseCallback) {
250+ String openDirection = request.request_value [FSTR_OPEN_CLOSE_openDirection];
251+ success = directionOpenCloseCallback (device->deviceId , openDirection, openPercent);
252+ request.response_value [FSTR_OPEN_CLOSE_openDirection] = openDirection;
253+ request.response_value [FSTR_OPEN_CLOSE_openPercent] = openPercent;
254+ } else if (!hasOpenDirection && openCloseCallback) {
255+ success = openCloseCallback (device->deviceId , openPercent);
256+ request.response_value [FSTR_OPEN_CLOSE_openPercent] = openPercent;
257+ }
258+
259+ return success;
260+ }
261+
262+ if (request.action == FSTR_OPEN_CLOSE_adjustOpenClose) {
263+ bool hasOpenDirection = !request.request_value [FSTR_OPEN_CLOSE_openDirection].isNull ();
264+ int openRelativePercent = request.request_value [FSTR_OPEN_CLOSE_openRelativePercent];
265+
266+ if (hasOpenDirection && adjustDirectionOpenCloseCallback) {
267+ String openDirection = request.request_value [FSTR_OPEN_CLOSE_openDirection];
268+ success = adjustDirectionOpenCloseCallback (device->deviceId , openDirection, openRelativePercent);
269+ request.response_value [FSTR_OPEN_CLOSE_openDirection] = openDirection;
270+ request.response_value [FSTR_OPEN_CLOSE_openPercent] = openRelativePercent;
271+ } else if (!hasOpenDirection && adjustOpenCloseCallback) {
272+ success = adjustOpenCloseCallback (device->deviceId , openRelativePercent);
273+ request.response_value [FSTR_OPEN_CLOSE_openPercent] = openRelativePercent;
274+ }
275+
276+ return success;
277+ }
278+
279+ return false ;
280+ }
281+
282+ } // SINRICPRO_NAMESPACE
283+
284+ template <typename T>
285+ using OpenCloseController = SINRICPRO_NAMESPACE::OpenCloseController<T>;
0 commit comments