SinricPro Library
Loading...
Searching...
No Matches
SinricPro.h
1/*
2 * Copyright (c) 2019 Sinric. All rights reserved.
3 * Licensed under Creative Commons Attribution-Share Alike (CC BY-SA)
4 *
5 * This file is part of the Sinric Pro (https://github.com/sinricpro/)
6 */
7
8#pragma once
9
10#include "SinricProDeviceInterface.h"
11#include "SinricProInterface.h"
12#include "SinricProMessageid.h"
13#include "SinricProModuleCommandHandler.h"
14#include "SinricProNamespace.h"
15#include "SinricProQueue.h"
16#include "SinricProSignature.h"
17#include "SinricProStrings.h"
18#include "SinricProUDP.h"
19#include "SinricProWebsocket.h"
20#include "Timestamp.h"
21namespace SINRICPRO_NAMESPACE {
22
30using ConnectedCallbackHandler = std::function<void(void)>;
31
39using DisconnectedCallbackHandler = std::function<void(void)>;
40
54using OTAUpdateCallbackHandler = std::function<bool(const String& url, int major, int minor, int patch, bool enforce)>;
55
65using SetSettingCallbackHandler = std::function<bool(const String& id, const String& value)>;
66
80using ReportHealthCallbackHandler = std::function<bool(String& healthReport)>;
81
82using PongCallback = std::function<void(uint32_t)>;
83
89class SinricProClass : public SinricProInterface {
90 friend class SinricProDevice;
91
92 public:
93 class Proxy;
94
95 public:
96 void begin(String appKey, String appSecret, String serverURL = SINRICPRO_SERVER_URL);
97 void handle();
98 void stop();
99 bool isConnected();
100 void onConnected(ConnectedCallbackHandler cb);
101 void onDisconnected(DisconnectedCallbackHandler cb);
102 void onPong(PongCallback cb);
103 void restoreDeviceStates(bool flag);
104 void setResponseMessage(String&& message);
105 unsigned long getTimestamp() override;
106 virtual String sign(const String& message);
107 Proxy operator[](const String deviceId);
108 void onOTAUpdate(OTAUpdateCallbackHandler cb);
109 void onSetSetting(SetSettingCallbackHandler cb);
110 void onReportHealth(ReportHealthCallbackHandler cb);
111
112 protected:
113 template <typename DeviceType>
114 DeviceType& add(String deviceId);
115
116 void add(SinricProDeviceInterface& newDevice);
117 void add(SinricProDeviceInterface* newDevice);
118
119 JsonDocument prepareResponse(JsonDocument& requestMessage);
120 JsonDocument prepareEvent(String deviceId, const char* action, const char* cause) override;
121 void sendMessage(JsonDocument& jsonMessage) override;
122
123 private:
124 void handleReceiveQueue();
125 void handleSendQueue();
126
127 void handleDeviceRequest(JsonDocument& requestMessage, interface_t Interface);
128 void handleModuleRequest(JsonDocument& requestMessage, interface_t Interface);
129 void handleResponse(JsonDocument& responseMessage);
130 void handleInvalidSignatureRequest(JsonDocument& requestMessage, interface_t Interface);
131
132 JsonDocument prepareRequest(String deviceId, const char* action);
133
134 void connect();
135 void disconnect();
136 void reconnect();
137
138 void onConnect();
139 void onDisconnect();
140
141 void extractTimestamp(JsonDocument& message);
142
143 SinricProDeviceInterface* getDevice(String deviceId);
144
145 template <typename DeviceType>
146 DeviceType& getDeviceInstance(String deviceId);
147
148 std::vector<SinricProDeviceInterface*> devices;
149
150 String appKey;
151 String appSecret;
152 String serverURL;
153
154 WebsocketListener _websocketListener;
155 UdpListener _udpListener;
156 SinricProQueue_t receiveQueue;
157 SinricProQueue_t sendQueue;
158
159 Timestamp timestamp;
160
161 bool _begin = false;
162 String responseMessageStr = "";
163
164 SinricProModuleCommandHandler _moduleCommandHandler;
165};
166
167class SinricProClass::Proxy {
168 public:
169 Proxy(SinricProClass* ptr, const String& deviceId);
170
171 template <typename DeviceType>
172 operator DeviceType&();
173
174 protected:
175 SinricProClass* ptr;
176 String deviceId;
177};
178
179SinricProClass::Proxy::Proxy(SinricProClass* ptr, const String& deviceId)
180 : ptr(ptr), deviceId(deviceId) {}
181
182template <typename DeviceType>
183SinricProClass::Proxy::operator DeviceType&() {
184 return ptr->getDeviceInstance<DeviceType>(deviceId);
185}
186
187SinricProDeviceInterface* SinricProClass::getDevice(String deviceId) {
188 for (auto& device : devices) {
189 if (deviceId == device->getDeviceId()) return device;
190 }
191 return nullptr;
192}
193
194template <typename DeviceType>
195DeviceType& SinricProClass::getDeviceInstance(String deviceId) {
196 DeviceType* tmp_device = (DeviceType*)getDevice(deviceId);
197 if (tmp_device) return *tmp_device;
198
199 DEBUG_SINRIC("[SinricPro]: Device \"%s\" does not exist in the internal device list. creating new device\r\n", deviceId.c_str());
200 DeviceType& tmp_deviceInstance = add<DeviceType>(deviceId);
201
202 if (isConnected()) {
203 DEBUG_SINRIC("[SinricPro]: Reconnecting to server.\r\n");
204 reconnect();
205 }
206
207 return tmp_deviceInstance;
208}
209
226void SinricProClass::begin(String appKey, String appSecret, String serverURL) {
227 bool success = true;
228 if (!appKey.length()) {
229 DEBUG_SINRIC("[SinricPro:begin()]: App-Key \"%s\" is invalid!! Please check your app-key!! SinricPro will not work!\r\n", appKey.c_str());
230 success = false;
231 }
232 if (!appSecret.length()) {
233 DEBUG_SINRIC("[SinricPro:begin()]: App-Secret \"%s\" is invalid!! Please check your app-secret!! SinricPro will not work!\r\n", appSecret.c_str());
234 success = false;
235 }
236
237 if (!success) {
238 _begin = false;
239 return;
240 }
241
242 this->appKey = appKey;
243 this->appSecret = appSecret;
244 this->serverURL = serverURL;
245 _begin = true;
246 _udpListener.begin(&receiveQueue);
247}
248
249template <typename DeviceType>
250DeviceType& SinricProClass::add(String deviceId) {
251 DeviceType* newDevice = new DeviceType(deviceId);
252 DEBUG_SINRIC("[SinricPro:add()]: Adding device with id \"%s\".\r\n", deviceId.c_str());
253 newDevice->begin(this);
254
255 devices.push_back(newDevice);
256 return *newDevice;
257}
258
259__attribute__((deprecated("Please use DeviceType& myDevice = SinricPro.add<DeviceType>(String);"))) void SinricProClass::add(SinricProDeviceInterface* newDevice) {
260 newDevice->begin(this);
261 devices.push_back(newDevice);
262}
263
264__attribute__((deprecated("Please use DeviceType& myDevice = SinricPro.add<DeviceType>(String);"))) void SinricProClass::add(SinricProDeviceInterface& newDevice) {
265 newDevice.begin(this);
266 devices.push_back(&newDevice);
267}
268
285 static bool begin_error = false;
286 if (!_begin) {
287 if (!begin_error) { // print this only once!
288 DEBUG_SINRIC("[SinricPro:handle()]: ERROR! SinricPro.begin() failed or was not called prior to event handler\r\n");
289 DEBUG_SINRIC("[SinricPro:handle()]: -Reasons include an invalid app-key, invalid app-secret or no valid deviceIds)\r\n");
290 DEBUG_SINRIC("[SinricPro:handle()]: -SinricPro is disabled! Check earlier log messages for details.\r\n");
291 begin_error = true;
292 }
293 return;
294 }
295
296 if (!isConnected()) connect();
297 _websocketListener.handle();
298 _udpListener.handle();
299
300 handleReceiveQueue();
301 handleSendQueue();
302}
303
304JsonDocument SinricProClass::prepareRequest(String deviceId, const char* action) {
309
314 payload[FSTR_SINRICPRO_replyToken] = MessageID().getID();
317 return requestMessage;
318}
319
320void SinricProClass::handleResponse(JsonDocument& responseMessage) {
321 (void)responseMessage;
322 DEBUG_SINRIC("[SinricPro.handleResponse()]:\r\n");
323
324#ifndef NODEBUG_SINRIC
325 serializeJsonPretty(responseMessage, DEBUG_ESP_PORT);
326 Serial.println();
327#endif
328}
329
330void SinricProClass::handleModuleRequest(JsonDocument& requestMessage, interface_t Interface) {
331 DEBUG_SINRIC("[SinricPro.handleModuleScopeRequest()]: handling module scope request\r\n");
332#ifndef NODEBUG_SINRIC
333 serializeJsonPretty(requestMessage, DEBUG_ESP_PORT);
334#endif
335
336 JsonDocument responseMessage = prepareResponse(requestMessage);
337
338 String action = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_action] | "";
339 JsonObject request_value = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value];
340 JsonObject response_value = responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value];
341 SinricProRequest request{action, "", request_value, response_value};
342
343 bool success = _moduleCommandHandler.handleRequest(request);
344
345 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_success] = success;
346 responseMessage[FSTR_SINRICPRO_payload].remove(FSTR_SINRICPRO_deviceId);
347 if (!success) {
348 if (responseMessageStr.length() > 0) {
349 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = responseMessageStr;
350 responseMessageStr = "";
351 } else {
352 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = "Module did not handle \"" + action + "\"";
353 }
354 }
355
356 String responseString;
357 serializeJson(responseMessage, responseString);
358 sendQueue.push(new SinricProMessage(Interface, responseString.c_str()));
359}
360
361void SinricProClass::handleDeviceRequest(JsonDocument& requestMessage, interface_t Interface) {
362 DEBUG_SINRIC("[SinricPro.handleDeviceRequest()]: handling device sope request\r\n");
363#ifndef NODEBUG_SINRIC
364 serializeJsonPretty(requestMessage, DEBUG_ESP_PORT);
365#endif
366
367 JsonDocument responseMessage = prepareResponse(requestMessage);
368
369 // handle devices
370 bool success = false;
371 const char* deviceId = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_deviceId];
372 String action = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_action] | "";
373 String instance = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_instanceId] | "";
374 JsonObject request_value = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value];
375 JsonObject response_value = responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value];
376
377 for (auto& device : devices) {
378 if (device->getDeviceId() == deviceId && success == false) {
379 SinricProRequest request{
380 action,
381 instance,
382 request_value,
383 response_value};
384 success = device->handleRequest(request);
385 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_success] = success;
386 if (!success) {
387 if (responseMessageStr.length() > 0) {
388 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = responseMessageStr;
389 responseMessageStr = "";
390 } else {
391 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = "Device did not handle \"" + action + "\"";
392 }
393 }
394 }
395 }
396
397 String responseString;
398 serializeJson(responseMessage, responseString);
399 sendQueue.push(new SinricProMessage(Interface, responseString.c_str()));
400}
401
402void SinricProClass::handleReceiveQueue() {
403 if (receiveQueue.size() == 0) return;
404
405 DEBUG_SINRIC("[SinricPro.handleReceiveQueue()]: %i message(s) in receiveQueue\r\n", receiveQueue.size());
406 while (receiveQueue.size() > 0) {
407 SinricProMessage* rawMessage = receiveQueue.front();
408 receiveQueue.pop();
409 JsonDocument jsonMessage;
410 deserializeJson(jsonMessage, rawMessage->getMessage());
411
412 bool sigMatch = false;
413
414 if (strncmp(rawMessage->getMessage(), "{\"timestamp\":", 13) == 0 && strlen(rawMessage->getMessage()) <= 26) {
415 sigMatch = true; // timestamp message has no signature...ignore sigMatch for this!
416 } else {
417 String signature = jsonMessage[FSTR_SINRICPRO_signature][FSTR_SINRICPRO_HMAC] | "";
418 String payload = extractPayload(rawMessage->getMessage());
419 String calculatedSignature = calculateSignature(appSecret.c_str(), payload);
420 sigMatch = (calculatedSignature == signature);
421 }
422
423 String messageType = jsonMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_type];
424
425 if (sigMatch) { // signature is valid process message
426 DEBUG_SINRIC("[SinricPro.handleReceiveQueue()]: Signature is valid. Processing message...\r\n");
427 extractTimestamp(jsonMessage);
428 if (messageType == FSTR_SINRICPRO_response) handleResponse(jsonMessage);
429 if (messageType == FSTR_SINRICPRO_request) {
430 String scope = jsonMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_scope] | FSTR_SINRICPRO_device;
431 if (strcmp(FSTR_SINRICPRO_module, scope.c_str()) == 0) {
432 handleModuleRequest(jsonMessage, rawMessage->getInterface());
433 } else {
434 handleDeviceRequest(jsonMessage, rawMessage->getInterface());
435 }
436 };
437 } else {
438 handleInvalidSignatureRequest(jsonMessage, rawMessage->getInterface());
439 }
440 delete rawMessage;
441 }
442}
443
444void SinricProClass::handleInvalidSignatureRequest(JsonDocument& requestMessage, interface_t Interface) {
445 DEBUG_SINRIC("[SinricPro.handleInvalidSignatureRequest()]: Signature is invalid!\r\n");
446
447#ifndef NODEBUG_SINRIC
448 serializeJsonPretty(requestMessage, DEBUG_ESP_PORT);
449#endif
450
451 JsonDocument responseMessage = prepareResponse(requestMessage);
452 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_success] = false;
453 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = "Signature is invalid";
454
455 String responseString;
456 serializeJson(responseMessage, responseString);
457 sendQueue.push(new SinricProMessage(Interface, responseString.c_str()));
458}
459
460void SinricProClass::handleSendQueue() {
461 if (!isConnected()) return;
462 if (!timestamp.getTimestamp()) return;
463 while (sendQueue.size() > 0) {
464 DEBUG_SINRIC("[SinricPro:handleSendQueue()]: %i message(s) in sendQueue\r\n", sendQueue.size());
465 DEBUG_SINRIC("[SinricPro:handleSendQueue()]: Sending message...\r\n");
466
467 SinricProMessage* rawMessage = sendQueue.front();
468 sendQueue.pop();
469
470 JsonDocument jsonMessage;
471 deserializeJson(jsonMessage, rawMessage->getMessage());
472 jsonMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_createdAt] = timestamp.getTimestamp();
473 signMessage(appSecret, jsonMessage);
474
475 String messageStr;
476
477 serializeJson(jsonMessage, messageStr);
478#ifndef NODEBUG_SINRIC
479 serializeJsonPretty(jsonMessage, DEBUG_ESP_PORT);
480 Serial.println();
481#endif
482
483 switch (rawMessage->getInterface()) {
484 case IF_WEBSOCKET:
485 DEBUG_SINRIC("[SinricPro:handleSendQueue]: Sending to websocket\r\n");
486 _websocketListener.sendMessage(messageStr);
487 break;
488 case IF_UDP:
489 DEBUG_SINRIC("[SinricPro:handleSendQueue]: Sending to UDP\r\n");
490 _udpListener.sendMessage(messageStr);
491 break;
492 default:
493 break;
494 }
495 delete rawMessage;
496 DEBUG_SINRIC("[SinricPro:handleSendQueue()]: message sent.\r\n");
497 }
498}
499
500void SinricProClass::connect() {
501 String deviceList;
502 int i = 0;
503 for (auto& device : devices) {
504 String deviceId = device->getDeviceId();
505 if (i > 0) deviceList += ';';
506 deviceList += device->getDeviceId();
507 i++;
508 }
509
510 _websocketListener.begin(serverURL, appKey, deviceList, &receiveQueue);
511}
512
513void SinricProClass::stop() {
514 _begin = false;
515 DEBUG_SINRIC("[SinricPro:stop()\r\n");
516 _websocketListener.stop();
517}
518
519bool SinricProClass::isConnected() {
520 return _websocketListener.isConnected();
521};
522
534 _moduleCommandHandler.onOTAUpdate(cb);
535}
536
548 _moduleCommandHandler.onSetSetting(cb);
549}
550
564 _moduleCommandHandler.onReportHealth(cb);
565}
566
577 _websocketListener.onConnected(cb);
578}
579
590 _websocketListener.onDisconnected(cb);
591}
592
593void SinricProClass::onPong(PongCallback cb) {
594 _websocketListener.onPong(cb);
595}
596
597void SinricProClass::reconnect() {
598 DEBUG_SINRIC("SinricPro:reconnect(): disconnecting\r\n");
599 stop();
600 DEBUG_SINRIC("SinricPro:reconnect(): connecting\r\n");
601 connect();
602}
603
604void SinricProClass::onConnect() {
605 DEBUG_SINRIC("[SinricPro]: Connected to \"%s\"!]\r\n", serverURL.c_str());
606}
607
608void SinricProClass::onDisconnect() {
609 DEBUG_SINRIC("[SinricPro]: Disconnect\r\n");
610}
611
612void SinricProClass::extractTimestamp(JsonDocument& message) {
613 unsigned long tempTimestamp = 0;
614 // extract timestamp from timestamp message right after websocket connection is established
615 tempTimestamp = message["timestamp"] | 0;
616 if (tempTimestamp) {
617 timestamp.setTimestamp(tempTimestamp);
618 DEBUG_SINRIC("[SinricPro:extractTimestamp(): Got Timestamp %lu\r\n", tempTimestamp);
619 return;
620 }
621
622 // extract timestamp from request message
623 tempTimestamp = message[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_createdAt] | 0;
624 if (tempTimestamp) {
625 DEBUG_SINRIC("[SinricPro:extractTimestamp(): Got Timestamp %lu\r\n", tempTimestamp);
626 timestamp.setTimestamp(tempTimestamp);
627 return;
628 }
629}
630
631void SinricProClass::sendMessage(JsonDocument& jsonMessage) {
632 if (!isConnected()) {
633 DEBUG_SINRIC("[SinricPro:sendMessage()]: device is offline, message has been dropped\r\n");
634 return;
635 }
636 DEBUG_SINRIC("[SinricPro:sendMessage()]: pushing message into sendQueue\r\n");
637 String messageString;
638 serializeJson(jsonMessage, messageString);
639 sendQueue.push(new SinricProMessage(IF_WEBSOCKET, messageString.c_str()));
640}
641
652 _websocketListener.setRestoreDeviceStates(flag);
653}
654
671SinricProClass::Proxy SinricProClass::operator[](const String deviceId) {
672 return Proxy(this, deviceId);
673}
674
675void SinricProClass::setResponseMessage(String&& message) {
676 responseMessageStr = message;
677}
678
685 return timestamp.getTimestamp();
686}
687
688String SinricProClass::sign(const String& message) {
689 return HMACbase64(message, appSecret);
690}
691
692JsonDocument SinricProClass::prepareResponse(JsonDocument& requestMessage) {
693 JsonDocument responseMessage;
694 JsonObject header = responseMessage[FSTR_SINRICPRO_header].to<JsonObject>();
695 header[FSTR_SINRICPRO_payloadVersion] = 2;
696 header[FSTR_SINRICPRO_signatureVersion] = 1;
697
698 JsonObject payload = responseMessage[FSTR_SINRICPRO_payload].to<JsonObject>();
699 payload[FSTR_SINRICPRO_action] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_action];
700 payload[FSTR_SINRICPRO_clientId] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_clientId];
701 payload[FSTR_SINRICPRO_scope] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_scope];
702 payload[FSTR_SINRICPRO_createdAt] = 0;
703 payload[FSTR_SINRICPRO_deviceId] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_deviceId];
704 if (requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_instanceId].is<String>()) payload[FSTR_SINRICPRO_instanceId] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_instanceId];
705 payload[FSTR_SINRICPRO_message] = FSTR_SINRICPRO_OK;
706 payload[FSTR_SINRICPRO_replyToken] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_replyToken];
707 payload[FSTR_SINRICPRO_success] = false;
708 payload[FSTR_SINRICPRO_type] = FSTR_SINRICPRO_response;
709 payload[FSTR_SINRICPRO_value].to<JsonObject>();
710 return responseMessage;
711}
712
713JsonDocument SinricProClass::prepareEvent(String deviceId, const char* action, const char* cause) {
714 JsonDocument eventMessage;
715 JsonObject header = eventMessage[FSTR_SINRICPRO_header].to<JsonObject>();
716 header[FSTR_SINRICPRO_payloadVersion] = 2;
717 header[FSTR_SINRICPRO_signatureVersion] = 1;
718
719 JsonObject payload = eventMessage[FSTR_SINRICPRO_payload].to<JsonObject>();
720 payload[FSTR_SINRICPRO_action] = action;
721 payload[FSTR_SINRICPRO_cause][FSTR_SINRICPRO_type].to<JsonObject>();
722 payload[FSTR_SINRICPRO_cause][FSTR_SINRICPRO_type] = cause;
723 payload[FSTR_SINRICPRO_createdAt] = 0;
724 payload[FSTR_SINRICPRO_deviceId] = deviceId;
725 payload[FSTR_SINRICPRO_replyToken] = MessageID().getID();
726 payload[FSTR_SINRICPRO_type] = FSTR_SINRICPRO_event;
727 payload[FSTR_SINRICPRO_value].to<JsonObject>();
728 return eventMessage;
729}
730
731} // namespace SINRICPRO_NAMESPACE
732
733SINRICPRO_NAMESPACE::SinricProClass SinricPro;
AirQuality.
Definition AirQualitySensor.h:19
The main class of this library, handling communication between SinricPro Server and your devices.
Definition SinricPro.h:89
void begin(String appKey, String appSecret, String serverURL="ws.sinric.pro")
Initializing SinricProClass to be able to connect to SinricPro Server.
Definition SinricPro.h:226
void restoreDeviceStates(bool flag)
Enable / disable restore device states function.
Definition SinricPro.h:651
void handle()
Handles communication between device and SinricPro Server.
Definition SinricPro.h:284
void onDisconnected(DisconnectedCallbackHandler cb)
Set callback function for websocket disconnected event.
Definition SinricPro.h:589
void onSetSetting(SetSettingCallbackHandler cb)
Set callback function for setting a module setting.
Definition SinricPro.h:547
Proxy operator[](const String deviceId)
operator[] is used tor create a new device instance or get an existing device instance
Definition SinricPro.h:671
void onConnected(ConnectedCallbackHandler cb)
Set callback function for websocket connected event.
Definition SinricPro.h:576
void onOTAUpdate(OTAUpdateCallbackHandler cb)
Set callback function for OTA (Over-The-Air) updates.
Definition SinricPro.h:533
void onReportHealth(ReportHealthCallbackHandler cb)
Sets the callback function for reporting device health status.
Definition SinricPro.h:563
unsigned long getTimestamp() override
return unsigned long current timestamp(unix epoch time) * /
Definition SinricPro.h:684
Base class for all device types.
Definition SinricProDevice.h:24
std::function< bool(const String &url, int major, int minor, int patch, bool enforce)> OTAUpdateCallbackHandler
Function signature for OTA update callback.
Definition SinricPro.h:54
std::function< bool(String &healthReport)> ReportHealthCallbackHandler
Defines a function type for reporting device health status.
Definition SinricPro.h:80
std::function< void(void)> DisconnectedCallbackHandler
Callback definition for onDisconnected function.
Definition SinricPro.h:39
std::function< bool(const String &id, const String &value)> SetSettingCallbackHandler
Function signature for setting a module setting.
Definition SinricPro.h:65
std::function< void(void)> ConnectedCallbackHandler
Callback definition for onConnected function.
Definition SinricPro.h:30