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 "SinricProWebsocket.h"
19#include "Timestamp.h"
20#include "EventLimiter.h"
21#ifndef SINRICPRO_NO_LOCAL_CONTROL
22#include "SinricProUDP.h"
23#endif
24#include "SinricProMDNS.h"
25namespace SINRICPRO_NAMESPACE {
26
34using ConnectedCallbackHandler = std::function<void(void)>;
35
43using DisconnectedCallbackHandler = std::function<void(void)>;
44
58using OTAUpdateCallbackHandler = std::function<bool(const String& url, int major, int minor, int patch, bool enforce)>;
59
69using SetSettingCallbackHandler = std::function<bool(const String& id, SettingValue& value)>;
70
84using ReportHealthCallbackHandler = std::function<bool(String& healthReport)>;
85
86using PongCallback = std::function<void(uint32_t)>;
87
93class SinricProClass : public SinricProInterface {
94 friend class SinricProDevice;
95
96 public:
97 class Proxy;
98
99 public:
100 void begin(String appKey, String appSecret, String serverURL = SINRICPRO_SERVER_URL);
101 void handle();
102 void stop();
103 bool isConnected();
104 void onConnected(ConnectedCallbackHandler cb);
105 void onDisconnected(DisconnectedCallbackHandler cb);
106 void onPong(PongCallback cb);
107 void restoreDeviceStates(bool flag);
108 void setResponseMessage(String&& message);
109 unsigned long getTimestamp() override;
110 virtual String sign(const String& message);
111 Proxy operator[](const String deviceId);
112 void onOTAUpdate(OTAUpdateCallbackHandler cb);
113 void onSetSetting(SetSettingCallbackHandler cb);
114 void onReportHealth(ReportHealthCallbackHandler cb);
115 bool sendSettingEvent(String settingId, SettingValue settingValue, String cause = FSTR_SINRICPRO_PHYSICAL_INTERACTION);
116
117 protected:
118 template <typename DeviceType>
119 DeviceType& add(String deviceId);
120
121 void add(SinricProDeviceInterface& newDevice);
122 void add(SinricProDeviceInterface* newDevice);
123
124 JsonDocument prepareResponse(JsonDocument& requestMessage);
125 JsonDocument prepareEvent(String deviceId, const char* action, const char* cause) override;
126 void sendMessage(JsonDocument& jsonMessage) override;
127
128 private:
129 void handleReceiveQueue();
130 void handleSendQueue();
131
132 void handleDeviceRequest(JsonDocument& requestMessage, const SinricProMessage* origin);
133 void handleModuleRequest(JsonDocument& requestMessage, const SinricProMessage* origin);
134 void handleResponse(JsonDocument& responseMessage);
135 void handleInvalidSignatureRequest(JsonDocument& requestMessage, const SinricProMessage* origin);
136
137 JsonDocument prepareRequest(String deviceId, const char* action);
138
139 void connect();
140 void disconnect();
141 void reconnect();
142
143 void onConnect();
144 void onDisconnect();
145
146 void extractTimestamp(JsonDocument& message);
147
148 SinricProDeviceInterface* getDevice(String deviceId);
149
150 String joinDeviceIds(char separator);
151
152 template <typename DeviceType>
153 DeviceType& getDeviceInstance(String deviceId);
154
155 std::vector<SinricProDeviceInterface*> devices;
156
157 String appKey;
158 String appSecret;
159 String serverURL;
160
161 WebsocketListener _websocketListener;
162#ifndef SINRICPRO_NO_LOCAL_CONTROL
163 UdpListener _udpListener;
164#endif
165#ifdef SINRICPRO_MDNS_ENABLED
166 SinricProMDNS _mdnsListener;
167 size_t _mdnsDeviceCount = 0;
168#endif
169 SinricProQueue_t receiveQueue;
170 SinricProQueue_t sendQueue;
171
172 Timestamp timestamp;
173
174 bool _begin = false;
175 String responseMessageStr = "";
176
177 SinricProModuleCommandHandler _moduleCommandHandler;
178 EventLimiter _settingEventLimiter{EVENT_LIMIT_STATE};
179};
180
181class SinricProClass::Proxy {
182 public:
183 Proxy(SinricProClass* ptr, const String& deviceId);
184
185 template <typename DeviceType>
186 operator DeviceType&();
187
188 protected:
189 SinricProClass* ptr;
190 String deviceId;
191};
192
193SinricProClass::Proxy::Proxy(SinricProClass* ptr, const String& deviceId)
194 : ptr(ptr), deviceId(deviceId) {}
195
196template <typename DeviceType>
197SinricProClass::Proxy::operator DeviceType&() {
198 return ptr->getDeviceInstance<DeviceType>(deviceId);
199}
200
201SinricProDeviceInterface* SinricProClass::getDevice(String deviceId) {
202 for (auto& device : devices) {
203 if (deviceId == device->getDeviceId()) return device;
204 }
205 return nullptr;
206}
207
208template <typename DeviceType>
209DeviceType& SinricProClass::getDeviceInstance(String deviceId) {
210 DeviceType* tmp_device = (DeviceType*)getDevice(deviceId);
211 if (tmp_device) return *tmp_device;
212
213 DEBUG_SINRIC("[SinricPro]: Device \"%s\" does not exist in the internal device list. creating new device\r\n", deviceId.c_str());
214 DeviceType& tmp_deviceInstance = add<DeviceType>(deviceId);
215
216 if (isConnected()) {
217 DEBUG_SINRIC("[SinricPro]: Reconnecting to server.\r\n");
218 reconnect();
219 }
220
221 return tmp_deviceInstance;
222}
223
240void SinricProClass::begin(String appKey, String appSecret, String serverURL) {
241 bool success = true;
242
243 // Validate APP_KEY
244 // - Must be 36 characters
245 // - UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
246 if (appKey.length() != 36) {
247 Serial.printf("[SinricPro:begin()]: Invalid App Key '%s' detected (Length: %d; Expected: 36). Initialization aborted! Please check your SinricPro credentials.\r\n", appKey.c_str(), appKey.length());
248 success = false;
249 } else if (appKey.charAt(8) != '-' || appKey.charAt(13) != '-' || appKey.charAt(18) != '-' || appKey.charAt(23) != '-') {
250 Serial.printf("[SinricPro:begin()]: App Key '%s' is in an invalid format. Initialization aborted!\r\n", appKey.c_str());
251 success = false;
252 }
253
254 // Validate APP_SECRET (73 characters)
255 // - Must be 73 characters
256 // - Double UUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
257 if (appSecret.length() != 73) {
258 Serial.printf("[SinricPro:begin()]: Invalid App Secret '%s' detected (Length: %d; Expected: 73). Initialization aborted! Please check your SinricPro credentials.\r\n", appSecret.c_str(), appSecret.length());
259 success = false;
260 } else if (appSecret.charAt(8) != '-' || appSecret.charAt(13) != '-' || appSecret.charAt(18) != '-' || appSecret.charAt(23) != '-' ||
261 appSecret.charAt(36) != '-' || appSecret.charAt(45) != '-' || appSecret.charAt(50) != '-' || appSecret.charAt(55) != '-' || appSecret.charAt(60) != '-') {
262 Serial.printf("[SinricPro:begin()]: App Secret '%s' is in an invalid format. Initialization aborted!\r\n", appSecret.c_str());
263 success = false;
264 }
265
266 if (!success) {
267 _begin = false;
268 return;
269 }
270
271 this->appKey = appKey;
272 this->appSecret = appSecret;
273 this->serverURL = serverURL;
274 _begin = true;
275#ifndef SINRICPRO_NO_LOCAL_CONTROL
276 _udpListener.begin(&receiveQueue);
277#endif
278#ifdef SINRICPRO_MDNS_ENABLED
279 {
280 String hostName = "sinricpro-" + WiFi.macAddress();
281 hostName.replace(":", "");
282 hostName.toLowerCase();
283 _mdnsListener.begin(hostName, joinDeviceIds(',')); //mDNS TXT uses ',' (CSV).
284 _mdnsDeviceCount = devices.size();
285 }
286#endif
287}
288
289template <typename DeviceType>
290DeviceType& SinricProClass::add(String deviceId) {
291 // Validate DEVICE_ID
292 // - Must be 24 characters
293 // - Hexadecimal only (0-9, a-f, A-F)
294 // - Format: 695b4624f6e5944047661b8a
295 if (deviceId.length() != 24) {
296 Serial.printf("[SinricPro:add()]: Device Id \"%s\" is invalid (wrong length: expected 24, got %d)!! Please check your device-id!!\r\n", deviceId.c_str(), deviceId.length());
297 }
298
299 DeviceType* newDevice = new DeviceType(deviceId);
300 DEBUG_SINRIC("[SinricPro:add()]: Adding device with id \"%s\".\r\n", deviceId.c_str());
301 newDevice->begin(this);
302
303 devices.push_back(newDevice);
304 return *newDevice;
305}
306
307__attribute__((deprecated("Please use DeviceType& myDevice = SinricPro.add<DeviceType>(String);"))) void SinricProClass::add(SinricProDeviceInterface* newDevice) {
308 newDevice->begin(this);
309 devices.push_back(newDevice);
310}
311
312__attribute__((deprecated("Please use DeviceType& myDevice = SinricPro.add<DeviceType>(String);"))) void SinricProClass::add(SinricProDeviceInterface& newDevice) {
313 newDevice.begin(this);
314 devices.push_back(&newDevice);
315}
316
333 static bool begin_error = false;
334 if (!_begin) {
335 if (!begin_error) { // print this only once!
336 DEBUG_SINRIC("[SinricPro:handle()]: ERROR! SinricPro.begin() failed or was not called prior to event handler\r\n");
337 DEBUG_SINRIC("[SinricPro:handle()]: -Reasons include an invalid app-key, invalid app-secret or no valid deviceIds)\r\n");
338 DEBUG_SINRIC("[SinricPro:handle()]: -SinricPro is disabled! Check earlier log messages for details.\r\n");
339 begin_error = true;
340 }
341 return;
342 }
343
344 if (!isConnected()) connect();
345 _websocketListener.handle();
346#ifndef SINRICPRO_NO_LOCAL_CONTROL
347 _udpListener.handle();
348#endif
349#ifdef SINRICPRO_MDNS_ENABLED
350 _mdnsListener.handle();
351#endif
352
353 handleReceiveQueue();
354 handleSendQueue();
355}
356
357JsonDocument SinricProClass::prepareRequest(String deviceId, const char* action) {
362
367 payload[FSTR_SINRICPRO_replyToken] = MessageID().getID();
370 return requestMessage;
371}
372
373void SinricProClass::handleResponse(JsonDocument& responseMessage) {
374 (void)responseMessage;
375 DEBUG_SINRIC("[SinricPro.handleResponse()]:\r\n");
376
377#ifndef NODEBUG_SINRIC
378 serializeJsonPretty(responseMessage, DEBUG_ESP_PORT);
379 Serial.println();
380#endif
381}
382
383void SinricProClass::handleModuleRequest(JsonDocument& requestMessage, const SinricProMessage* origin) {
384 DEBUG_SINRIC("[SinricPro.handleModuleScopeRequest()]: handling module scope request\r\n");
385#ifndef NODEBUG_SINRIC
386 serializeJsonPretty(requestMessage, DEBUG_ESP_PORT);
387#endif
388
389 JsonDocument responseMessage = prepareResponse(requestMessage);
390
391 String action = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_action] | "";
392 JsonObject request_value = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value];
393 JsonObject response_value = responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value];
394 SinricProRequest request{action, "", request_value, response_value};
395
396 bool success = _moduleCommandHandler.handleRequest(request);
397
398 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_success] = success;
399 responseMessage[FSTR_SINRICPRO_payload].remove(FSTR_SINRICPRO_deviceId);
400 if (!success) {
401 if (responseMessageStr.length() > 0) {
402 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = responseMessageStr;
403 responseMessageStr = "";
404 } else {
405 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = "Module did not handle \"" + action + "\"";
406 }
407 }
408
409 String responseString;
410 serializeJson(responseMessage, responseString);
411 sendQueue.push(new SinricProMessage(origin->getInterface(), responseString.c_str(),
412 origin->getRemoteIP(), origin->getRemotePort()));
413}
414
415void SinricProClass::handleDeviceRequest(JsonDocument& requestMessage, const SinricProMessage* origin) {
416 DEBUG_SINRIC("[SinricPro.handleDeviceRequest()]: handling device sope request\r\n");
417#ifndef NODEBUG_SINRIC
418 serializeJsonPretty(requestMessage, DEBUG_ESP_PORT);
419#endif
420
421 JsonDocument responseMessage = prepareResponse(requestMessage);
422
423 // handle devices
424 bool success = false;
425 const char* deviceId = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_deviceId];
426 String action = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_action] | "";
427 String instance = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_instanceId] | "";
428 JsonObject request_value = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value];
429 JsonObject response_value = responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value];
430
431 bool deviceIsOurs = false;
432
433 for (auto& device : devices) {
434 if (device->getDeviceId() == deviceId && success == false) {
435 deviceIsOurs = true;
436 SinricProRequest request{
437 action,
438 instance,
439 request_value,
440 response_value};
441 success = device->handleRequest(request);
442 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_success] = success;
443 if (!success) {
444 if (responseMessageStr.length() > 0) {
445 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = responseMessageStr;
446 responseMessageStr = "";
447 } else {
448 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = "Device did not handle \"" + action + "\"";
449 }
450 }
451 }
452 }
453
454 if (!deviceIsOurs && origin->getInterface() == IF_UDP) {
455 DEBUG_SINRIC("[SinricPro.handleDeviceRequest()]: ignoring LAN request for unknown device \"%s\"\r\n", deviceId);
456 return;
457 }
458
459 String responseString;
460 serializeJson(responseMessage, responseString);
461 sendQueue.push(new SinricProMessage(origin->getInterface(), responseString.c_str(),
462 origin->getRemoteIP(), origin->getRemotePort()));
463}
464
465void SinricProClass::handleReceiveQueue() {
466 if (receiveQueue.size() == 0) return;
467
468 DEBUG_SINRIC("[SinricPro.handleReceiveQueue()]: %i message(s) in receiveQueue\r\n", receiveQueue.size());
469 while (receiveQueue.size() > 0) {
470 SinricProMessage* rawMessage = receiveQueue.front();
471 receiveQueue.pop();
472 JsonDocument jsonMessage;
473 deserializeJson(jsonMessage, rawMessage->getMessage());
474
475 bool sigMatch = false;
476
477 if (strncmp(rawMessage->getMessage(), "{\"timestamp\":", 13) == 0 && strlen(rawMessage->getMessage()) <= 26) {
478 sigMatch = true; // timestamp message has no signature...ignore sigMatch for this!
479 } else {
480 String signature = jsonMessage[FSTR_SINRICPRO_signature][FSTR_SINRICPRO_HMAC] | "";
481 String payload = extractPayload(rawMessage->getMessage());
482 String calculatedSignature = calculateSignature(appSecret.c_str(), payload);
483 sigMatch = (calculatedSignature == signature);
484 }
485
486 String messageType = jsonMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_type];
487
488 if (sigMatch) { // signature is valid process message
489 DEBUG_SINRIC("[SinricPro.handleReceiveQueue()]: Signature is valid. Processing message...\r\n");
490 extractTimestamp(jsonMessage);
491 if (messageType == FSTR_SINRICPRO_response) handleResponse(jsonMessage);
492 if (messageType == FSTR_SINRICPRO_request) {
493 String scope = jsonMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_scope] | FSTR_SINRICPRO_device;
494 if (strcmp(FSTR_SINRICPRO_module, scope.c_str()) == 0) {
495 handleModuleRequest(jsonMessage, rawMessage);
496 } else {
497 handleDeviceRequest(jsonMessage, rawMessage);
498 }
499 };
500 } else {
501 handleInvalidSignatureRequest(jsonMessage, rawMessage);
502 }
503 delete rawMessage;
504 }
505}
506
507void SinricProClass::handleInvalidSignatureRequest(JsonDocument& requestMessage, const SinricProMessage* origin) {
508 DEBUG_SINRIC("[SinricPro.handleInvalidSignatureRequest()]: Signature is invalid!\r\n");
509
510#ifndef NODEBUG_SINRIC
511 serializeJsonPretty(requestMessage, DEBUG_ESP_PORT);
512#endif
513
514 JsonDocument responseMessage = prepareResponse(requestMessage);
515 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_success] = false;
516 responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = "Signature is invalid";
517
518 String responseString;
519 serializeJson(responseMessage, responseString);
520 sendQueue.push(new SinricProMessage(origin->getInterface(), responseString.c_str(),
521 origin->getRemoteIP(), origin->getRemotePort()));
522}
523
524void SinricProClass::handleSendQueue() {
525 // Visit each pending message once so deferred cloud messages cannot block LAN replies.
526 size_t pending = sendQueue.size();
527 while (pending-- > 0) {
528 DEBUG_SINRIC("[SinricPro:handleSendQueue()]: %i message(s) in sendQueue\r\n", sendQueue.size());
529
530 SinricProMessage* rawMessage = sendQueue.front();
531
532 if (rawMessage->getInterface() == IF_WEBSOCKET &&
533 (!isConnected() || !timestamp.getTimestamp())) {
534 sendQueue.pop();
535 sendQueue.push(rawMessage);
536 continue;
537 }
538
539 DEBUG_SINRIC("[SinricPro:handleSendQueue()]: Sending message...\r\n");
540 sendQueue.pop();
541
542 JsonDocument jsonMessage;
543 deserializeJson(jsonMessage, rawMessage->getMessage());
544 jsonMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_createdAt] = timestamp.getTimestamp();
545 signMessage(appSecret, jsonMessage);
546
547 String messageStr;
548
549 serializeJson(jsonMessage, messageStr);
550#ifndef NODEBUG_SINRIC
551 serializeJsonPretty(jsonMessage, DEBUG_ESP_PORT);
552 Serial.println();
553#endif
554
555 switch (rawMessage->getInterface()) {
556 case IF_WEBSOCKET:
557 if (isConnected()) {
558 DEBUG_SINRIC("[SinricPro:handleSendQueue]: Sending to websocket\r\n");
559 _websocketListener.sendMessage(messageStr);
560 } else {
561 DEBUG_SINRIC("[SinricPro:handleSendQueue]: Dropping WS message — not connected\r\n");
562 }
563 break;
564 case IF_UDP:
565#ifndef SINRICPRO_NO_LOCAL_CONTROL
566 DEBUG_SINRIC("[SinricPro:handleSendQueue]: Sending to UDP\r\n");
567 _udpListener.sendMessage(messageStr, rawMessage->getRemoteIP(), rawMessage->getRemotePort());
568#endif
569 break;
570 default:
571 break;
572 }
573 delete rawMessage;
574 DEBUG_SINRIC("[SinricPro:handleSendQueue()]: message sent.\r\n");
575 }
576}
577
578String SinricProClass::joinDeviceIds(char separator) {
579 String out;
580 int i = 0;
581 for (auto& device : devices) {
582 if (i++ > 0) out += separator;
583 out += device->getDeviceId();
584 }
585 return out;
586}
587
588void SinricProClass::connect() {
589 _websocketListener.begin(serverURL, appKey, joinDeviceIds(';'), &receiveQueue);
590
591#ifdef SINRICPRO_MDNS_ENABLED
592 if (devices.size() != _mdnsDeviceCount) {
593 _mdnsDeviceCount = devices.size();
594 _mdnsListener.update(joinDeviceIds(','));
595 }
596#endif
597}
598
599void SinricProClass::stop() {
600 _begin = false;
601 DEBUG_SINRIC("[SinricPro:stop()\r\n");
602 _websocketListener.stop();
603}
604
605bool SinricProClass::isConnected() {
606 return _websocketListener.isConnected();
607};
608
620 _moduleCommandHandler.onOTAUpdate(cb);
621}
622
634 _moduleCommandHandler.onSetSetting(cb);
635}
636
650 _moduleCommandHandler.onReportHealth(cb);
651}
652
664 if (_settingEventLimiter) return false;
665
666 JsonDocument eventMessage = prepareEvent("", FSTR_SETTING_setSetting, cause.c_str());
668
671
674
675 if (std::holds_alternative<int>(settingValue)) {
677 } else if (std::holds_alternative<float>(settingValue)) {
678 event_value[FSTR_SETTING_value] = std::get<float>(settingValue);
679 } else if (std::holds_alternative<bool>(settingValue)) {
681 } else if (std::holds_alternative<String>(settingValue)) {
682 event_value[FSTR_SETTING_value] = std::get<String>(settingValue);
683 }
684
685 sendMessage(eventMessage);
686 return true;
687}
688
699 _websocketListener.onConnected(cb);
700}
701
712 _websocketListener.onDisconnected(cb);
713}
714
715void SinricProClass::onPong(PongCallback cb) {
716 _websocketListener.onPong(cb);
717}
718
719void SinricProClass::reconnect() {
720 DEBUG_SINRIC("SinricPro:reconnect(): disconnecting\r\n");
721 stop();
722 DEBUG_SINRIC("SinricPro:reconnect(): connecting\r\n");
723 connect();
724}
725
726void SinricProClass::onConnect() {
727 DEBUG_SINRIC("[SinricPro]: Connected to \"%s\"!]\r\n", serverURL.c_str());
728}
729
730void SinricProClass::onDisconnect() {
731 DEBUG_SINRIC("[SinricPro]: Disconnect\r\n");
732}
733
734void SinricProClass::extractTimestamp(JsonDocument& message) {
735 unsigned long tempTimestamp = 0;
736 // extract timestamp from timestamp message right after websocket connection is established
737 tempTimestamp = message["timestamp"] | 0;
738 if (tempTimestamp) {
739 timestamp.setTimestamp(tempTimestamp);
740 DEBUG_SINRIC("[SinricPro:extractTimestamp(): Got Timestamp %lu\r\n", tempTimestamp);
741 return;
742 }
743
744 // extract timestamp from request message
745 tempTimestamp = message[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_createdAt] | 0;
746 if (tempTimestamp) {
747 DEBUG_SINRIC("[SinricPro:extractTimestamp(): Got Timestamp %lu\r\n", tempTimestamp);
748 timestamp.setTimestamp(tempTimestamp);
749 return;
750 }
751}
752
753void SinricProClass::sendMessage(JsonDocument& jsonMessage) {
754 if (!isConnected()) {
755 DEBUG_SINRIC("[SinricPro:sendMessage()]: device is offline, message has been dropped\r\n");
756 return;
757 }
758 DEBUG_SINRIC("[SinricPro:sendMessage()]: pushing message into sendQueue\r\n");
759 String messageString;
760 serializeJson(jsonMessage, messageString);
761 sendQueue.push(new SinricProMessage(IF_WEBSOCKET, messageString.c_str()));
762}
763
775__attribute__((deprecated("Use SinricPro Portal: Edit Device > Other > 'Restore Device State When Connect' instead"))) void SinricProClass::restoreDeviceStates(bool flag) {
776 _websocketListener.setRestoreDeviceStates(flag);
777}
778
795SinricProClass::Proxy SinricProClass::operator[](const String deviceId) {
796 return Proxy(this, deviceId);
797}
798
799void SinricProClass::setResponseMessage(String&& message) {
800 responseMessageStr = message;
801}
802
809 return timestamp.getTimestamp();
810}
811
812String SinricProClass::sign(const String& message) {
813 return HMACbase64(message, appSecret);
814}
815
816JsonDocument SinricProClass::prepareResponse(JsonDocument& requestMessage) {
817 JsonDocument responseMessage;
818 JsonObject header = responseMessage[FSTR_SINRICPRO_header].to<JsonObject>();
819 header[FSTR_SINRICPRO_payloadVersion] = 2;
820 header[FSTR_SINRICPRO_signatureVersion] = 1;
821
822 JsonObject payload = responseMessage[FSTR_SINRICPRO_payload].to<JsonObject>();
823 payload[FSTR_SINRICPRO_action] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_action];
824 payload[FSTR_SINRICPRO_clientId] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_clientId];
825 payload[FSTR_SINRICPRO_scope] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_scope];
826 payload[FSTR_SINRICPRO_createdAt] = 0;
827 payload[FSTR_SINRICPRO_deviceId] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_deviceId];
828 if (requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_instanceId].is<String>()) payload[FSTR_SINRICPRO_instanceId] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_instanceId];
829 payload[FSTR_SINRICPRO_message] = FSTR_SINRICPRO_OK;
830 payload[FSTR_SINRICPRO_replyToken] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_replyToken];
831 payload[FSTR_SINRICPRO_success] = false;
832 payload[FSTR_SINRICPRO_type] = FSTR_SINRICPRO_response;
833 payload[FSTR_SINRICPRO_value].to<JsonObject>();
834 return responseMessage;
835}
836
837JsonDocument SinricProClass::prepareEvent(String deviceId, const char* action, const char* cause) {
838 JsonDocument eventMessage;
839 JsonObject header = eventMessage[FSTR_SINRICPRO_header].to<JsonObject>();
840 header[FSTR_SINRICPRO_payloadVersion] = 2;
841 header[FSTR_SINRICPRO_signatureVersion] = 1;
842
843 JsonObject payload = eventMessage[FSTR_SINRICPRO_payload].to<JsonObject>();
844 payload[FSTR_SINRICPRO_action] = action;
845 payload[FSTR_SINRICPRO_cause][FSTR_SINRICPRO_type].to<JsonObject>();
846 payload[FSTR_SINRICPRO_cause][FSTR_SINRICPRO_type] = cause;
847 payload[FSTR_SINRICPRO_createdAt] = 0;
848 payload[FSTR_SINRICPRO_deviceId] = deviceId;
849 payload[FSTR_SINRICPRO_replyToken] = MessageID().getID();
850 payload[FSTR_SINRICPRO_type] = FSTR_SINRICPRO_event;
851 payload[FSTR_SINRICPRO_value].to<JsonObject>();
852 return eventMessage;
853}
854
855} // namespace SINRICPRO_NAMESPACE
856
857SINRICPRO_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:93
void begin(String appKey, String appSecret, String serverURL="ws.sinric.pro")
Initializing SinricProClass to be able to connect to SinricPro Server.
Definition SinricPro.h:240
void handle()
Handles communication between device and SinricPro Server.
Definition SinricPro.h:332
void onDisconnected(DisconnectedCallbackHandler cb)
Set callback function for websocket disconnected event.
Definition SinricPro.h:711
void onSetSetting(SetSettingCallbackHandler cb)
Set callback function for setting a module setting.
Definition SinricPro.h:633
bool sendSettingEvent(String settingId, SettingValue settingValue, String cause=FSTR_SINRICPRO_PHYSICAL_INTERACTION)
Send setSetting event to SinricPro Server at module level.
Definition SinricPro.h:663
Proxy operator[](const String deviceId)
operator[] is used tor create a new device instance or get an existing device instance
Definition SinricPro.h:795
void onConnected(ConnectedCallbackHandler cb)
Set callback function for websocket connected event.
Definition SinricPro.h:698
void onOTAUpdate(OTAUpdateCallbackHandler cb)
Set callback function for OTA (Over-The-Air) updates.
Definition SinricPro.h:619
void onReportHealth(ReportHealthCallbackHandler cb)
Sets the callback function for reporting device health status.
Definition SinricPro.h:649
unsigned long getTimestamp() override
return unsigned long current timestamp(unix epoch time) * /
Definition SinricPro.h:808
Base class for all device types.
Definition SinricProDevice.h:24
Announces this device on the LAN via mDNS.
Definition SinricProMDNS.h:59
std::function< bool(const String &url, int major, int minor, int patch, bool enforce)> OTAUpdateCallbackHandler
Function signature for OTA update callback.
Definition SinricPro.h:58
std::function< bool(String &healthReport)> ReportHealthCallbackHandler
Defines a function type for reporting device health status.
Definition SinricPro.h:84
std::function< void(void)> DisconnectedCallbackHandler
Callback definition for onDisconnected function.
Definition SinricPro.h:43
std::function< void(void)> ConnectedCallbackHandler
Callback definition for onConnected function.
Definition SinricPro.h:34
std::variant< int, float, bool, String > SettingValue
Variant type for setting values that can hold int, float, bool, or String.
Definition SettingController.h:19
std::function< bool(const String &id, SettingValue &value)> SetSettingCallbackHandler
Function signature for setting a module setting.
Definition SinricPro.h:69