From f9524177a291fd721e1002e1232bed63b89c82c1 Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Mon, 25 Nov 2024 05:23:57 +0100 Subject: [PATCH 01/17] fixed missing includes --- src/SinricProModuleCommandHandler.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/SinricProModuleCommandHandler.h b/src/SinricProModuleCommandHandler.h index fd0d3479..fecfce33 100644 --- a/src/SinricProModuleCommandHandler.h +++ b/src/SinricProModuleCommandHandler.h @@ -8,8 +8,10 @@ #pragma once #include "SinricProRequest.h" - +#include "SinricProStrings.h" #include "SinricProNamespace.h" +#include "SinricProDebug.h" + namespace SINRICPRO_NAMESPACE { FSTR(OTA, otaUpdateAvailable); // "otaUpdateAvailable" From cb5e66efb2c75633a18e103998459afa47af1464 Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Mon, 25 Nov 2024 05:29:41 +0100 Subject: [PATCH 02/17] implemented signature function for devices --- src/SinricPro.h | 73 +++++++++++++++++++++------------------- src/SinricProDevice.h | 7 +++- src/SinricProInterface.h | 1 + 3 files changed, 46 insertions(+), 35 deletions(-) diff --git a/src/SinricPro.h b/src/SinricPro.h index 567da203..2e3e1690 100644 --- a/src/SinricPro.h +++ b/src/SinricPro.h @@ -10,6 +10,7 @@ #include "SinricProDeviceInterface.h" #include "SinricProInterface.h" #include "SinricProMessageid.h" +#include "SinricProModuleCommandHandler.h" #include "SinricProNamespace.h" #include "SinricProQueue.h" #include "SinricProSignature.h" @@ -17,7 +18,6 @@ #include "SinricProUDP.h" #include "SinricProWebsocket.h" #include "Timestamp.h" -#include "SinricProModuleCommandHandler.h" namespace SINRICPRO_NAMESPACE { /** @@ -57,7 +57,7 @@ using OTAUpdateCallbackHandler = std::function @@ -117,7 +118,7 @@ class SinricProClass : public SinricProInterface { JsonDocument prepareResponse(JsonDocument& requestMessage); JsonDocument prepareEvent(String deviceId, const char* action, const char* cause) override; - void sendMessage(JsonDocument& jsonMessage) override; + void sendMessage(JsonDocument& jsonMessage) override; private: void handleReceiveQueue(); @@ -301,7 +302,7 @@ void SinricProClass::handle() { JsonDocument SinricProClass::prepareRequest(String deviceId, const char* action) { JsonDocument requestMessage; - JsonObject header = requestMessage[FSTR_SINRICPRO_header].to(); + JsonObject header = requestMessage[FSTR_SINRICPRO_header].to(); header[FSTR_SINRICPRO_payloadVersion] = 2; header[FSTR_SINRICPRO_signatureVersion] = 1; @@ -332,20 +333,20 @@ void SinricProClass::handleModuleRequest(JsonDocument& requestMessage, interface #endif JsonDocument responseMessage = prepareResponse(requestMessage); - - String action = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_action] | ""; - JsonObject request_value = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value]; - JsonObject response_value = responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value]; - SinricProRequest request{ action, "", request_value, response_value}; + + String action = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_action] | ""; + JsonObject request_value = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value]; + JsonObject response_value = responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_value]; + SinricProRequest request{action, "", request_value, response_value}; bool success = _moduleCommandHandler.handleRequest(request); - + responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_success] = success; responseMessage[FSTR_SINRICPRO_payload].remove(FSTR_SINRICPRO_deviceId); if (!success) { if (responseMessageStr.length() > 0) { responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = responseMessageStr; - responseMessageStr = ""; + responseMessageStr = ""; } else { responseMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_message] = "Module did not handle \"" + action + "\""; } @@ -424,13 +425,13 @@ void SinricProClass::handleReceiveQueue() { DEBUG_SINRIC("[SinricPro.handleReceiveQueue()]: Signature is valid. Processing message...\r\n"); extractTimestamp(jsonMessage); if (messageType == FSTR_SINRICPRO_response) handleResponse(jsonMessage); - if (messageType == FSTR_SINRICPRO_request) { + if (messageType == FSTR_SINRICPRO_request) { String scope = jsonMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_scope] | FSTR_SINRICPRO_device; if (strcmp(FSTR_SINRICPRO_module, scope.c_str()) == 0) { handleModuleRequest(jsonMessage, rawMessage->getInterface()); } else { handleDeviceRequest(jsonMessage, rawMessage->getInterface()); - } + } }; } else { DEBUG_SINRIC("[SinricPro.handleReceiveQueue()]: Signature is invalid! \r\n"); @@ -505,7 +506,7 @@ bool SinricProClass::isConnected() { /** * @brief Set callback function for OTA (Over-The-Air) updates. - * + * * This method registers a callback function that will be called when an OTA update is available. * The callback should handle the process of downloading and applying the update. * @@ -519,7 +520,7 @@ void SinricProClass::onOTAUpdate(OTAUpdateCallbackHandler cb) { /** * @brief Set callback function for setting a module setting. - * + * * This method registers a callback function that will be called when a request to change * a module setting is received. * @return void @@ -538,7 +539,7 @@ void SinricProClass::onSetSetting(SetSettingCallbackHandler cb) { * when the SinricPro system needs to report the device's health status. * * @param cb A function pointer of type ReportHealthCallbackHandler. - * This callback should populate a String with health information and return a boolean + * This callback should populate a String with health information and return a boolean * indicating success or failure of the health reporting process. * @return void * @see ReportHealthCallbackHandler for the definition of the callback function type. @@ -660,17 +661,21 @@ void SinricProClass::setResponseMessage(String&& message) { } /** - * @brief Get the current timestamp + * @brief * - * @return unsigned long current timestamp (unix epoch time) + * return unsigned long current timestamp(unix epoch time) * / */ unsigned long SinricProClass::getTimestamp() { return timestamp.getTimestamp(); } +String SinricProClass::sign(const String& message) { + return HMACbase64(message, appSecret); +} + JsonDocument SinricProClass::prepareResponse(JsonDocument& requestMessage) { JsonDocument responseMessage; - JsonObject header = responseMessage[FSTR_SINRICPRO_header].to(); + JsonObject header = responseMessage[FSTR_SINRICPRO_header].to(); header[FSTR_SINRICPRO_payloadVersion] = 2; header[FSTR_SINRICPRO_signatureVersion] = 1; @@ -691,7 +696,7 @@ JsonDocument SinricProClass::prepareResponse(JsonDocument& requestMessage) { JsonDocument SinricProClass::prepareEvent(String deviceId, const char* action, const char* cause) { JsonDocument eventMessage; - JsonObject header = eventMessage[FSTR_SINRICPRO_header].to(); + JsonObject header = eventMessage[FSTR_SINRICPRO_header].to(); header[FSTR_SINRICPRO_payloadVersion] = 2; header[FSTR_SINRICPRO_signatureVersion] = 1; diff --git a/src/SinricProDevice.h b/src/SinricProDevice.h index 04995624..6678f81f 100644 --- a/src/SinricProDevice.h +++ b/src/SinricProDevice.h @@ -33,8 +33,9 @@ class SinricProDevice : public SinricProDeviceInterface { void registerRequestHandler(const SinricProRequestHandler &requestHandler); unsigned long getTimestamp(); + String sign(const String& message); virtual bool sendEvent(JsonDocument &event); - virtual JsonDocument prepareEvent(const char *action, const char *cause); + virtual JsonDocument prepareEvent(const char *action, const char *cause); virtual String getProductType(); virtual void begin(SinricProInterface *eventSender); @@ -74,6 +75,10 @@ JsonDocument SinricProDevice::prepareEvent(const char* action, const char* cause return JsonDocument(); } +String SinricProDevice::sign(const String& message) { + if (eventSender) return eventSender->sign(message); + return ""; +} bool SinricProDevice::sendEvent(JsonDocument& event) { if (!SinricPro.isConnected()) { diff --git a/src/SinricProInterface.h b/src/SinricProInterface.h index 2de9216b..c5ea60c6 100644 --- a/src/SinricProInterface.h +++ b/src/SinricProInterface.h @@ -17,6 +17,7 @@ class SinricProInterface { friend class SinricProDevice; protected: virtual void sendMessage(JsonDocument& jsonEvent); + virtual String sign(const String& message); virtual JsonDocument prepareEvent(String deviceId, const char* action, const char* cause); virtual unsigned long getTimestamp(); virtual bool isConnected(); From 40a0d699d5e429e83cacbff675635f7614b1a69f Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Mon, 25 Nov 2024 05:30:48 +0100 Subject: [PATCH 03/17] added SINRICPRO_CAMERA_URL --- src/SinricProConfig.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/SinricProConfig.h b/src/SinricProConfig.h index 646db763..8a8aca33 100644 --- a/src/SinricProConfig.h +++ b/src/SinricProConfig.h @@ -25,13 +25,30 @@ #define WEBSOCKET_SSL #endif +#ifndef SINRICPRO_SERVER_URL #define SINRICPRO_SERVER_URL "ws.sinric.pro" +#endif + +#ifndef SINRICPRO_SERVER_PORT #define SINRICPRO_SERVER_PORT 80 +#endif + +#ifndef SINRICPRO_SERVER_SSL_PORT #define SINRICPRO_SERVER_SSL_PORT 443 +#endif + +#ifndef SINRICPRO_CAMERA_URL +#define SINRICPRO_CAMERA_URL "camera.sinric.pro" +#endif // UDP Configuration +#ifndef UDP_MUTLICAST_IP #define UDP_MULTICAST_IP IPAddress(224,9,9,9) +#endif + +#ifndef UDP_MULTICAST_PORT #define UDP_MULTICAST_PORT 3333 +#endif // WebSocket Configuration #ifdef DEBUG_WIFI_ISSUE @@ -43,6 +60,14 @@ #define WEBSOCKET_RETRY_COUNT 2 // EventLimiter Configuration +#ifndef EVENT_LIMIT_STATE #define EVENT_LIMIT_STATE 1000 +#endif + +#ifndef EVENT_LIMIT_SENSOR_STATE #define EVENT_LIMIT_SENSOR_STATE EVENT_LIMIT_STATE +#endif + +#ifndef EVENT_LIMIT_SENSOR_VALUE #define EVENT_LIMIT_SENSOR_VALUE 60000 +#endif From f44b034db07e3601a2d83bef8c51d8cc090cb7de Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Mon, 25 Nov 2024 05:31:21 +0100 Subject: [PATCH 04/17] Implemented CameraController --- src/Capabilities/CameraController.h | 83 +++++++++++++++++++++++++++++ src/SinricProCamera.h | 5 +- 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 src/Capabilities/CameraController.h diff --git a/src/Capabilities/CameraController.h b/src/Capabilities/CameraController.h new file mode 100644 index 00000000..a69fbf6e --- /dev/null +++ b/src/Capabilities/CameraController.h @@ -0,0 +1,83 @@ +#pragma once + +#include "../EventLimiter.h" +#include "../SinricProNamespace.h" +#include "../SinricProRequest.h" +#include "../SinricProStrings.h" +#include +#include + +namespace SINRICPRO_NAMESPACE { + +FSTR(CAMERA, getSnapshot); // "getSnapshot" + +using SnapshotCallback = std::function; + +template +class CameraController { + public: + CameraController(); + void onSnapshot(SnapshotCallback cb); + int uploadImage(uint8_t* buffer, size_t len); + + protected: + bool handleCameraController(SinricProRequest &request); + + private: + SnapshotCallback getSnapshotCallback = nullptr; +}; + +template +CameraController::CameraController() { + T *device = static_cast(this); + device->registerRequestHandler(std::bind(&CameraController::handleCameraController, this, std::placeholders::_1)); +} + +template +void CameraController::onSnapshot(SnapshotCallback cb) { + getSnapshotCallback = cb; +} + +template +bool CameraController::handleCameraController(SinricProRequest &request) { + T *device = static_cast(this); + + bool success = false; + + if (request.action == FSTR_CAMERA_getSnapshot) { + if (getSnapshotCallback) { + success = getSnapshotCallback(device->deviceId); + } + } + + return success; +} + +template +int CameraController::uploadImage(uint8_t* buffer, size_t len) { + T *device = static_cast(this); + + if (!buffer) return -1; + + WiFiClientSecure client; + client.setInsecure(); + + HTTPClient http; + if (!http.begin(client, SINRICPRO_CAMERA_URL, 443, "/snapshot", true)) return -1; + + const String& deviceId = device->getDeviceId(); + String timestamp = String(device->getTimestamp()); + String signature = device->sign(deviceId+timestamp); + + http.addHeader("deviceid", deviceId); + http.addHeader("timestamp", timestamp); + http.addHeader("signature", signature); + + int resCode = http.POST(buffer, len); + http.PUT(buffer, len); + http.end(); + + return resCode; +} + +} // namespace SINRICPRO_NAMESPACE \ No newline at end of file diff --git a/src/SinricProCamera.h b/src/SinricProCamera.h index af87fd12..cc854941 100644 --- a/src/SinricProCamera.h +++ b/src/SinricProCamera.h @@ -11,6 +11,7 @@ #include "Capabilities/SettingController.h" #include "Capabilities/PushNotification.h" #include "Capabilities/PowerStateController.h" +#include "Capabilities/CameraController.h" #include "SinricProNamespace.h" namespace SINRICPRO_NAMESPACE { @@ -23,10 +24,12 @@ namespace SINRICPRO_NAMESPACE { class SinricProCamera : public SinricProDevice, public SettingController, public PushNotification, - public PowerStateController { + public PowerStateController, + public CameraController { friend class SettingController; friend class PushNotification; friend class PowerStateController; + friend class CameraController; public: SinricProCamera(const String &deviceId) : SinricProDevice(deviceId, "CAMERA") {} }; From 473040358979a4e478bb88e2a945b36ab6f99bc7 Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Mon, 25 Nov 2024 05:32:46 +0100 Subject: [PATCH 05/17] Bump version to 3.4.0 --- changelog.md | 3 +++ library.json | 2 +- library.properties | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/changelog.md b/changelog.md index de046570..47bd0b38 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,8 @@ # Changelog +## Version 3.4.0 + - Support Image upload on camera devices + ## Version 3.3.1 - Support SmartButton. diff --git a/library.json b/library.json index 8e5b45c9..d03ce870 100644 --- a/library.json +++ b/library.json @@ -13,7 +13,7 @@ "maintainer": true } ], - "version": "3.3.1", + "version": "3.4.0", "frameworks": "arduino", "platforms": [ "espressif8266", diff --git a/library.properties b/library.properties index 5bf00481..223c1eeb 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SinricPro -version=3.3.1 +version=3.4.0 author=Boris Jaeger maintainer=Boris Jaeger sentence=Library for https://sinric.pro - simple way to connect your device to alexa From 5c640e50c5efda2ffd983e81fb6344db0c7060c7 Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Tue, 26 Nov 2024 05:19:04 +0100 Subject: [PATCH 06/17] removed unnecessary http.PUT --- src/Capabilities/CameraController.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Capabilities/CameraController.h b/src/Capabilities/CameraController.h index a69fbf6e..97f093a5 100644 --- a/src/Capabilities/CameraController.h +++ b/src/Capabilities/CameraController.h @@ -74,7 +74,6 @@ int CameraController::uploadImage(uint8_t* buffer, size_t len) { http.addHeader("signature", signature); int resCode = http.POST(buffer, len); - http.PUT(buffer, len); http.end(); return resCode; From 7712e8239630c1df70e823dd84938587f0b1caba Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Tue, 26 Nov 2024 05:22:25 +0100 Subject: [PATCH 07/17] renamed upladImage to sendSnapshot --- src/Capabilities/CameraController.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Capabilities/CameraController.h b/src/Capabilities/CameraController.h index 97f093a5..a02c9174 100644 --- a/src/Capabilities/CameraController.h +++ b/src/Capabilities/CameraController.h @@ -18,7 +18,7 @@ class CameraController { public: CameraController(); void onSnapshot(SnapshotCallback cb); - int uploadImage(uint8_t* buffer, size_t len); + int sendSnapshot(uint8_t* buffer, size_t len); protected: bool handleCameraController(SinricProRequest &request); @@ -54,7 +54,7 @@ bool CameraController::handleCameraController(SinricProRequest &request) { } template -int CameraController::uploadImage(uint8_t* buffer, size_t len) { +int CameraController::sendSnapshot(uint8_t* buffer, size_t len) { T *device = static_cast(this); if (!buffer) return -1; From 3a6d562818d92f467827bbfc3e14df794a436ab6 Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Thu, 28 Nov 2024 06:46:50 +0100 Subject: [PATCH 08/17] fixed: version --- src/SinricProVersion.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SinricProVersion.h b/src/SinricProVersion.h index 59024ce8..60f49f78 100644 --- a/src/SinricProVersion.h +++ b/src/SinricProVersion.h @@ -5,8 +5,8 @@ // Version Configuration #define SINRICPRO_VERSION_MAJOR 3 -#define SINRICPRO_VERSION_MINOR 3 -#define SINRICPRO_VERSION_REVISION 1 +#define SINRICPRO_VERSION_MINOR 4 +#define SINRICPRO_VERSION_REVISION 0 #define SINRICPRO_VERSION STR(SINRICPRO_VERSION_MAJOR) "." STR(SINRICPRO_VERSION_MINOR) "." STR(SINRICPRO_VERSION_REVISION) #define SINRICPRO_VERSION_STR "SinricPro (v" SINRICPRO_VERSION ")" #define SINRICPRO_VERISON_INT SINRICPRO_VERSION_MAJOR * 1000000 + SINRICPRO_VERSION_MINOR * 1000 + SINRICPRO_VERSION_REVISION \ No newline at end of file From 536ec6cc01604ba1f497bc7eb32679ae09d7d93b Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Thu, 28 Nov 2024 06:47:17 +0100 Subject: [PATCH 09/17] fixed interface classes --- src/SinricProDeviceInterface.h | 18 +++++++++--------- src/SinricProInterface.h | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/SinricProDeviceInterface.h b/src/SinricProDeviceInterface.h index 25740c23..0eba94f4 100644 --- a/src/SinricProDeviceInterface.h +++ b/src/SinricProDeviceInterface.h @@ -1,19 +1,19 @@ #pragma once #include "SinricProInterface.h" -#include "SinricProRequest.h" - #include "SinricProNamespace.h" +#include "SinricProRequest.h" namespace SINRICPRO_NAMESPACE { class SinricProDeviceInterface { - friend class SinricProClass; + friend class SinricProClass; + protected: - virtual bool handleRequest(SinricProRequest &request) = 0; - virtual String getDeviceId() = 0; - virtual String getProductType() = 0; - virtual void begin(SinricProInterface* eventSender) = 0; - virtual unsigned long getTimestamp(); + virtual bool handleRequest(SinricProRequest& request) = 0; + virtual String getDeviceId() = 0; + virtual String getProductType() = 0; + virtual void begin(SinricProInterface* eventSender) = 0; + virtual unsigned long getTimestamp() = 0; }; -} // SINRICPRO_NAMESPACE \ No newline at end of file +} // namespace SINRICPRO_NAMESPACE \ No newline at end of file diff --git a/src/SinricProInterface.h b/src/SinricProInterface.h index c5ea60c6..38436e50 100644 --- a/src/SinricProInterface.h +++ b/src/SinricProInterface.h @@ -8,19 +8,19 @@ #pragma once #include "ArduinoJson.h" -#include "SinricProQueue.h" - #include "SinricProNamespace.h" +#include "SinricProQueue.h" namespace SINRICPRO_NAMESPACE { class SinricProInterface { - friend class SinricProDevice; + friend class SinricProDevice; + protected: - virtual void sendMessage(JsonDocument& jsonEvent); - virtual String sign(const String& message); - virtual JsonDocument prepareEvent(String deviceId, const char* action, const char* cause); - virtual unsigned long getTimestamp(); - virtual bool isConnected(); + virtual void sendMessage(JsonDocument& jsonEvent) = 0; + virtual String sign(const String& message) = 0; + virtual JsonDocument prepareEvent(String deviceId, const char* action, const char* cause) = 0; + virtual unsigned long getTimestamp() = 0; + virtual bool isConnected() = 0; }; -} // SINRICPRO_NAMESPACE \ No newline at end of file +} // namespace SINRICPRO_NAMESPACE \ No newline at end of file From 7e1e13e0261eb3fa893601e5bdffac01efe868b7 Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Fri, 29 Nov 2024 05:28:30 +0100 Subject: [PATCH 10/17] removed containsKey() containsKey() is deprecated since ArduinoJson 7.2 --- src/Capabilities/ChannelController.h | 4 ++-- src/Capabilities/ThermostatController.h | 2 +- src/SinricPro.h | 2 +- src/SinricProSignature.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Capabilities/ChannelController.h b/src/Capabilities/ChannelController.h index 96bafbc2..847906c9 100644 --- a/src/Capabilities/ChannelController.h +++ b/src/Capabilities/ChannelController.h @@ -157,13 +157,13 @@ bool ChannelController::handleChannelController(SinricProRequest &request) { if (request.action == FSTR_CHANNEL_changeChannel) { - if (changeChannelCallback && request.request_value[FSTR_CHANNEL_channel].containsKey(FSTR_CHANNEL_name)) { + if (changeChannelCallback && request.request_value[FSTR_CHANNEL_channel][FSTR_CHANNEL_name].is()) { String channelName = request.request_value[FSTR_CHANNEL_channel][FSTR_CHANNEL_name] | ""; success = changeChannelCallback(device->deviceId, channelName); request.response_value[FSTR_CHANNEL_channel][FSTR_CHANNEL_name] = channelName; } - if (changeChannelNumberCallback && request.request_value[FSTR_CHANNEL_channel].containsKey(FSTR_CHANNEL_number)) { + if (changeChannelNumberCallback && request.request_value[FSTR_CHANNEL_channel][FSTR_CHANNEL_number].is()) { String channelName(""); int channelNumber = request.request_value[FSTR_CHANNEL_channel][FSTR_CHANNEL_number]; success = changeChannelNumberCallback(device->deviceId, channelNumber, channelName); diff --git a/src/Capabilities/ThermostatController.h b/src/Capabilities/ThermostatController.h index c7e8da7a..6ac5b44c 100644 --- a/src/Capabilities/ThermostatController.h +++ b/src/Capabilities/ThermostatController.h @@ -181,7 +181,7 @@ bool ThermostatController::handleThermostatController(SinricProRequest &reque if (request.action == FSTR_THERMOSTAT_targetTemperature && targetTemperatureCallback) { float temperature; - if (request.request_value.containsKey(FSTR_THERMOSTAT_temperature)) { + if (request.request_value[FSTR_THERMOSTAT_temperature].is()) { temperature = request.request_value[FSTR_THERMOSTAT_temperature]; } else { temperature = 1; diff --git a/src/SinricPro.h b/src/SinricPro.h index 2e3e1690..9cb567a2 100644 --- a/src/SinricPro.h +++ b/src/SinricPro.h @@ -685,7 +685,7 @@ JsonDocument SinricProClass::prepareResponse(JsonDocument& requestMessage) { payload[FSTR_SINRICPRO_scope] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_scope]; payload[FSTR_SINRICPRO_createdAt] = 0; payload[FSTR_SINRICPRO_deviceId] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_deviceId]; - if (requestMessage[FSTR_SINRICPRO_payload].containsKey(FSTR_SINRICPRO_instanceId)) payload[FSTR_SINRICPRO_instanceId] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_instanceId]; + if (requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_instanceId].is()) payload[FSTR_SINRICPRO_instanceId] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_instanceId]; payload[FSTR_SINRICPRO_message] = FSTR_SINRICPRO_OK; payload[FSTR_SINRICPRO_replyToken] = requestMessage[FSTR_SINRICPRO_payload][FSTR_SINRICPRO_replyToken]; payload[FSTR_SINRICPRO_success] = false; diff --git a/src/SinricProSignature.cpp b/src/SinricProSignature.cpp index be8d06d4..3d2bc0ad 100644 --- a/src/SinricProSignature.cpp +++ b/src/SinricProSignature.cpp @@ -71,7 +71,7 @@ String calculateSignature(const char* key, String payload) { } String signMessage(String key, JsonDocument &jsonMessage) { - if (!jsonMessage.containsKey("signature")) jsonMessage["signature"].to(); + if (!jsonMessage["signature"].is()) jsonMessage["signature"].to(); jsonMessage["signature"]["HMAC"] = calculateSignature(key.c_str(), jsonMessage["payload"]); String signedMessageString; serializeJson(jsonMessage, signedMessageString); From 30035b42cfc9da95115ce7e7a3e9920f76884bfa Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Fri, 29 Nov 2024 05:36:28 +0100 Subject: [PATCH 11/17] Update changelog --- changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog.md b/changelog.md index 47bd0b38..d5216b89 100644 --- a/changelog.md +++ b/changelog.md @@ -1,7 +1,12 @@ # Changelog ## Version 3.4.0 + New: - Support Image upload on camera devices + + Fixed: + - Removed calls to `containsKey` - deprecated since ArduinoJSON 7.2 + - Missing includes ## Version 3.3.1 - Support SmartButton. From f5f32acf19a90beb10b5b2b8ec66048fe8b67472 Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Fri, 29 Nov 2024 06:01:20 +0100 Subject: [PATCH 12/17] Added definition for camera upload path --- src/SinricProConfig.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/SinricProConfig.h b/src/SinricProConfig.h index 8a8aca33..c50d0051 100644 --- a/src/SinricProConfig.h +++ b/src/SinricProConfig.h @@ -41,6 +41,10 @@ #define SINRICPRO_CAMERA_URL "camera.sinric.pro" #endif +#ifndef SINRICPRO_CAMERA_PATH +#define SINRICPRO_CAMERA_PATH "/snapshot" +#endif + // UDP Configuration #ifndef UDP_MUTLICAST_IP #define UDP_MULTICAST_IP IPAddress(224,9,9,9) From 444d0b4e96b9e42b4b780514924e50d18877917d Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Fri, 29 Nov 2024 06:02:00 +0100 Subject: [PATCH 13/17] Changed: CameraController is now using defined Strings from SinricProStrings.h --- src/Capabilities/CameraController.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Capabilities/CameraController.h b/src/Capabilities/CameraController.h index a02c9174..bda02886 100644 --- a/src/Capabilities/CameraController.h +++ b/src/Capabilities/CameraController.h @@ -63,15 +63,15 @@ int CameraController::sendSnapshot(uint8_t* buffer, size_t len) { client.setInsecure(); HTTPClient http; - if (!http.begin(client, SINRICPRO_CAMERA_URL, 443, "/snapshot", true)) return -1; + if (!http.begin(client, SINRICPRO_CAMERA_URL, 443, SINRICPRO_CAMERA_PATH, true)) return -1; const String& deviceId = device->getDeviceId(); String timestamp = String(device->getTimestamp()); String signature = device->sign(deviceId+timestamp); - http.addHeader("deviceid", deviceId); - http.addHeader("timestamp", timestamp); - http.addHeader("signature", signature); + http.addHeader(FSTR_SINRICPRO_deviceId, deviceId); + http.addHeader(FSTR_SINRICPRO_timestamp, timestamp); + http.addHeader(FSTR_SINRICPRO_signature, signature); int resCode = http.POST(buffer, len); http.end(); From 92ae55c1c5e52c59e25fd3e29dc2d16af57056c4 Mon Sep 17 00:00:00 2001 From: sivar2311 Date: Tue, 10 Dec 2024 05:13:14 +0100 Subject: [PATCH 14/17] changed "timestamp" -> "createdAt" --- src/Capabilities/CameraController.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Capabilities/CameraController.h b/src/Capabilities/CameraController.h index bda02886..296e228d 100644 --- a/src/Capabilities/CameraController.h +++ b/src/Capabilities/CameraController.h @@ -66,11 +66,11 @@ int CameraController::sendSnapshot(uint8_t* buffer, size_t len) { if (!http.begin(client, SINRICPRO_CAMERA_URL, 443, SINRICPRO_CAMERA_PATH, true)) return -1; const String& deviceId = device->getDeviceId(); - String timestamp = String(device->getTimestamp()); - String signature = device->sign(deviceId+timestamp); + String createdAt = String(device->getTimestamp()); + String signature = device->sign(deviceId+createdAt); http.addHeader(FSTR_SINRICPRO_deviceId, deviceId); - http.addHeader(FSTR_SINRICPRO_timestamp, timestamp); + http.addHeader(FSTR_SINRICPRO_createdAt, createdAt); http.addHeader(FSTR_SINRICPRO_signature, signature); int resCode = http.POST(buffer, len); From 7171300f37aad8cbf01469ab2c2296db52e322a1 Mon Sep 17 00:00:00 2001 From: Aruna Tennakoon Date: Sat, 14 Dec 2024 12:11:01 +0700 Subject: [PATCH 15/17] feat: snapshot camera example --- examples/Camera/snapshot-camera/camera_pins.h | 272 ++++++++++++++++++ .../snapshot-camera/snapshot-camera.ino | 161 +++++++++++ 2 files changed, 433 insertions(+) create mode 100644 examples/Camera/snapshot-camera/camera_pins.h create mode 100644 examples/Camera/snapshot-camera/snapshot-camera.ino diff --git a/examples/Camera/snapshot-camera/camera_pins.h b/examples/Camera/snapshot-camera/camera_pins.h new file mode 100644 index 00000000..89eca49f --- /dev/null +++ b/examples/Camera/snapshot-camera/camera_pins.h @@ -0,0 +1,272 @@ +#if defined(CAMERA_MODEL_WROVER_KIT) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 21 +#define SIOD_GPIO_NUM 26 +#define SIOC_GPIO_NUM 27 + +#define Y9_GPIO_NUM 35 +#define Y8_GPIO_NUM 34 +#define Y7_GPIO_NUM 39 +#define Y6_GPIO_NUM 36 +#define Y5_GPIO_NUM 19 +#define Y4_GPIO_NUM 18 +#define Y3_GPIO_NUM 5 +#define Y2_GPIO_NUM 4 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 23 +#define PCLK_GPIO_NUM 22 + +#elif defined(CAMERA_MODEL_ESP_EYE) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 4 +#define SIOD_GPIO_NUM 18 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 36 +#define Y8_GPIO_NUM 37 +#define Y7_GPIO_NUM 38 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 35 +#define Y4_GPIO_NUM 14 +#define Y3_GPIO_NUM 13 +#define Y2_GPIO_NUM 34 +#define VSYNC_GPIO_NUM 5 +#define HREF_GPIO_NUM 27 +#define PCLK_GPIO_NUM 25 + +#elif defined(CAMERA_MODEL_M5STACK_PSRAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_M5STACK_V2_PSRAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 22 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_M5STACK_WIDE) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 22 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_M5STACK_ESP32CAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 17 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_M5STACK_UNITCAM) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 32 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + +#elif defined(CAMERA_MODEL_AI_THINKER) +#define PWDN_GPIO_NUM 32 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 0 +#define SIOD_GPIO_NUM 26 +#define SIOC_GPIO_NUM 27 + +#define Y9_GPIO_NUM 35 +#define Y8_GPIO_NUM 34 +#define Y7_GPIO_NUM 39 +#define Y6_GPIO_NUM 36 +#define Y5_GPIO_NUM 21 +#define Y4_GPIO_NUM 19 +#define Y3_GPIO_NUM 18 +#define Y2_GPIO_NUM 5 +#define VSYNC_GPIO_NUM 25 +#define HREF_GPIO_NUM 23 +#define PCLK_GPIO_NUM 22 + +#elif defined(CAMERA_MODEL_TTGO_T_JOURNAL) +#define PWDN_GPIO_NUM 0 +#define RESET_GPIO_NUM 15 +#define XCLK_GPIO_NUM 27 +#define SIOD_GPIO_NUM 25 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 19 +#define Y8_GPIO_NUM 36 +#define Y7_GPIO_NUM 18 +#define Y6_GPIO_NUM 39 +#define Y5_GPIO_NUM 5 +#define Y4_GPIO_NUM 34 +#define Y3_GPIO_NUM 35 +#define Y2_GPIO_NUM 17 +#define VSYNC_GPIO_NUM 22 +#define HREF_GPIO_NUM 26 +#define PCLK_GPIO_NUM 21 + + +#elif defined(CAMERA_MODEL_ESP32_CAM_BOARD) +// The 18 pin header on the board has Y5 and Y3 swapped +#define USE_BOARD_HEADER 0 +#define PWDN_GPIO_NUM 32 +#define RESET_GPIO_NUM 33 +#define XCLK_GPIO_NUM 4 +#define SIOD_GPIO_NUM 18 +#define SIOC_GPIO_NUM 23 + +#define Y9_GPIO_NUM 36 +#define Y8_GPIO_NUM 19 +#define Y7_GPIO_NUM 21 +#define Y6_GPIO_NUM 39 +#if USE_BOARD_HEADER +#define Y5_GPIO_NUM 13 +#else +#define Y5_GPIO_NUM 35 +#endif +#define Y4_GPIO_NUM 14 +#if USE_BOARD_HEADER +#define Y3_GPIO_NUM 35 +#else +#define Y3_GPIO_NUM 13 +#endif +#define Y2_GPIO_NUM 34 +#define VSYNC_GPIO_NUM 5 +#define HREF_GPIO_NUM 27 +#define PCLK_GPIO_NUM 25 + +#elif defined(CAMERA_MODEL_ESP32S3_CAM_LCD) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 40 +#define SIOD_GPIO_NUM 17 +#define SIOC_GPIO_NUM 18 + +#define Y9_GPIO_NUM 39 +#define Y8_GPIO_NUM 41 +#define Y7_GPIO_NUM 42 +#define Y6_GPIO_NUM 12 +#define Y5_GPIO_NUM 3 +#define Y4_GPIO_NUM 14 +#define Y3_GPIO_NUM 47 +#define Y2_GPIO_NUM 13 +#define VSYNC_GPIO_NUM 21 +#define HREF_GPIO_NUM 38 +#define PCLK_GPIO_NUM 11 + +#elif defined(CAMERA_MODEL_ESP32S2_CAM_BOARD) +// The 18 pin header on the board has Y5 and Y3 swapped +#define USE_BOARD_HEADER 0 +#define PWDN_GPIO_NUM 1 +#define RESET_GPIO_NUM 2 +#define XCLK_GPIO_NUM 42 +#define SIOD_GPIO_NUM 41 +#define SIOC_GPIO_NUM 18 + +#define Y9_GPIO_NUM 16 +#define Y8_GPIO_NUM 39 +#define Y7_GPIO_NUM 40 +#define Y6_GPIO_NUM 15 +#if USE_BOARD_HEADER +#define Y5_GPIO_NUM 12 +#else +#define Y5_GPIO_NUM 13 +#endif +#define Y4_GPIO_NUM 5 +#if USE_BOARD_HEADER +#define Y3_GPIO_NUM 13 +#else +#define Y3_GPIO_NUM 12 +#endif +#define Y2_GPIO_NUM 14 +#define VSYNC_GPIO_NUM 38 +#define HREF_GPIO_NUM 4 +#define PCLK_GPIO_NUM 3 + +#elif defined(CAMERA_MODEL_ESP32S3_EYE) +#define PWDN_GPIO_NUM -1 +#define RESET_GPIO_NUM -1 +#define XCLK_GPIO_NUM 15 +#define SIOD_GPIO_NUM 4 +#define SIOC_GPIO_NUM 5 + +#define Y2_GPIO_NUM 11 +#define Y3_GPIO_NUM 9 +#define Y4_GPIO_NUM 8 +#define Y5_GPIO_NUM 10 +#define Y6_GPIO_NUM 12 +#define Y7_GPIO_NUM 18 +#define Y8_GPIO_NUM 17 +#define Y9_GPIO_NUM 16 + +#define VSYNC_GPIO_NUM 6 +#define HREF_GPIO_NUM 7 +#define PCLK_GPIO_NUM 13 + +#else +#error "Camera model not selected" +#endif diff --git a/examples/Camera/snapshot-camera/snapshot-camera.ino b/examples/Camera/snapshot-camera/snapshot-camera.ino new file mode 100644 index 00000000..5eb9cf86 --- /dev/null +++ b/examples/Camera/snapshot-camera/snapshot-camera.ino @@ -0,0 +1,161 @@ +/* + * Example for how to use SinricPro Camera device: + * - Create a ESP32 Camera device from portal. + * - Copy the secrets below. + * + * If you encounter any issues: + * - check the readme.md at https://github.com/sinricpro/esp8266-esp32-sdk/blob/master/README.md + * - ensure all dependent libraries are installed + * - see https://github.com/sinricpro/esp8266-esp32-sdk/blob/master/README.md#arduinoide + * - see https://github.com/sinricpro/esp8266-esp32-sdk/blob/master/README.md#dependencies + * - open serial monitor and check whats happening + * - check full user documentation at https://sinricpro.github.io/esp8266-esp32-sdk + * - visit https://github.com/sinricpro/esp8266-esp32-sdk/issues and check for existing issues or open a new one + */ + +// Uncomment the following line to enable serial debug output +//#define ENABLE_DEBUG + +#include +#include +#include +#include + +#include + +// Select camera model +//#define CAMERA_MODEL_WROVER_KIT +//#define CAMERA_MODEL_ESP_EYE +//#define CAMERA_MODEL_M5STACK_PSRAM +//#define CAMERA_MODEL_M5STACK_V2_PSRAM +//#define CAMERA_MODEL_M5STACK_WIDE +//#define CAMERA_MODEL_M5STACK_ESP32CAM +//#define CAMERA_MODEL_M5STACK_UNITCAM +//#define CAMERA_MODEL_AI_THINKER +//#define CAMERA_MODEL_TTGO_T_JOURNAL +//#define CAMERA_MODEL_ESP32_CAM_BOARD +//#define CAMERA_MODEL_ESP32S3_CAM_LCD +//#define CAMERA_MODEL_ESP32S2_CAM_BOARD +//#define CAMERA_MODEL_ESP32S3_EYE + +#include "camera_pins.h" + +#define WIFI_SSID "YOUR-WIFI-SSID" +#define WIFI_PASS "YOUR-WIFI-PASSWORD" +#define APP_KEY "YOUR-APP-KEY" // Should look like "de0bxxxx-1x3x-4x3x-ax2x-5dabxxxxxxxx" +#define APP_SECRET "YOUR-APP-SECRET" // Should look like "5f36xxxx-x3x7-4x3x-xexe-e86724a9xxxx-4c4axxxx-3x3x-x5xe-x9x3-333d65xxxxxx" +#define CAMERA_ID "YOUR-ESP32-CAMERA-ID" // Should look like "5dc1564130xxxxxxxxxxxxxx" +#define BAUD_RATE 115200 // Change baudrate to your need + +bool onSnapshot(const String& deviceId) { + camera_fb_t* fb = esp_camera_fb_get(); + + if (!fb) { + Serial.println("Failed to grab image"); + return false; + } + + SinricProCamera& myCamera = SinricPro[deviceId]; + int result = myCamera.sendSnapshot(fb->buf, fb->len); + esp_camera_fb_return(fb); + + return result == 200; +} + +bool onPowerState(const String& deviceId, bool& state) { + return true; +} + +// setup function for WiFi connection +void setupWiFi() { + Serial.printf("\r\n[Wifi]: Connecting"); + + WiFi.setSleep(false); + WiFi.setAutoReconnect(true); + + WiFi.begin(WIFI_SSID, WIFI_PASS); + + while (WiFi.status() != WL_CONNECTED) { + Serial.printf("."); + delay(250); + } + Serial.printf("connected!\r\n[WiFi]: IP-Address is %s\r\n", WiFi.localIP().toString().c_str()); +} + +void setupSinricPro() { + SinricProCamera& myCamera = SinricPro[CAMERA_ID]; + myCamera.onPowerState(onPowerState); + myCamera.onSnapshot(onSnapshot); + SinricPro.onConnected([]() { Serial.printf("Connected to SinricPro\r\n"); }); + SinricPro.onDisconnected([]() { Serial.printf("Disconnected from SinricPro\r\n"); }); + + SinricPro.begin(APP_KEY, APP_SECRET); +} + +esp_err_t setupCamera() { + camera_config_t config; + config.ledc_channel = LEDC_CHANNEL_0; + config.ledc_timer = LEDC_TIMER_0; + config.pin_d0 = Y2_GPIO_NUM; + config.pin_d1 = Y3_GPIO_NUM; + config.pin_d2 = Y4_GPIO_NUM; + config.pin_d3 = Y5_GPIO_NUM; + config.pin_d4 = Y6_GPIO_NUM; + config.pin_d5 = Y7_GPIO_NUM; + config.pin_d6 = Y8_GPIO_NUM; + config.pin_d7 = Y9_GPIO_NUM; + config.pin_xclk = XCLK_GPIO_NUM; + config.pin_pclk = PCLK_GPIO_NUM; + config.pin_vsync = VSYNC_GPIO_NUM; + config.pin_href = HREF_GPIO_NUM; + config.pin_sccb_sda = SIOD_GPIO_NUM; + config.pin_sccb_scl = SIOC_GPIO_NUM; + config.pin_pwdn = PWDN_GPIO_NUM; + config.pin_reset = RESET_GPIO_NUM; + config.xclk_freq_hz = 20000000; + config.frame_size = FRAMESIZE_XGA; + config.pixel_format = PIXFORMAT_JPEG; + config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; + config.fb_location = CAMERA_FB_IN_PSRAM; + config.jpeg_quality = 12; + config.fb_count = 1; + + // if PSRAM IC present, init with UXGA resolution and higher JPEG quality + // for larger pre-allocated frame buffer. + if (psramFound()) { + config.jpeg_quality = 10; + config.fb_count = 2; + config.grab_mode = CAMERA_GRAB_LATEST; + } else { + // Limit the frame size when PSRAM is not available + config.frame_size = FRAMESIZE_SVGA; + config.fb_location = CAMERA_FB_IN_DRAM; + } + + // camera init + esp_err_t err = esp_camera_init(&config); + if (err != ESP_OK) { + return err; + } + + sensor_t* s = esp_camera_sensor_get(); + // initial sensors are flipped vertically and colors are a bit saturated + s->set_vflip(s, 1); // flip it back + s->set_brightness(s, 1); // up the brightness just a bit + s->set_saturation(s, 0); // lower the saturation + + return ESP_OK; +} + +void setup() { + Serial.begin(BAUD_RATE); Serial.printf("\r\n\r\n"); + setupWiFi(); + setupSinricPro(); + setupCamera(); +} + +void loop() { + SinricPro.handle(); +} + + From 341c5cc93476e856a29e0f5252f24b98e95eb728 Mon Sep 17 00:00:00 2001 From: Aruna Tennakoon Date: Sat, 14 Dec 2024 12:11:37 +0700 Subject: [PATCH 16/17] feat: comments + http/https support. --- src/Capabilities/CameraController.h | 67 ++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 11 deletions(-) diff --git a/src/Capabilities/CameraController.h b/src/Capabilities/CameraController.h index 296e228d..1d989e63 100644 --- a/src/Capabilities/CameraController.h +++ b/src/Capabilities/CameraController.h @@ -1,11 +1,15 @@ #pragma once +// Required header includes #include "../EventLimiter.h" #include "../SinricProNamespace.h" #include "../SinricProRequest.h" #include "../SinricProStrings.h" #include -#include + +#if defined(ESP32) + #include +#endif namespace SINRICPRO_NAMESPACE { @@ -13,17 +17,39 @@ FSTR(CAMERA, getSnapshot); // "getSnapshot" using SnapshotCallback = std::function; +/** + * @brief Camera + * @ingroup Capabilities + **/ template class CameraController { public: CameraController(); + + /** + * @brief Sets the callback function for snapshot requests + * @param cb Callback function to handle snapshot requests + */ void onSnapshot(SnapshotCallback cb); + + /** + * @brief Sends a camera snapshot to the SinricPro server + * @param buffer Pointer to the image data buffer + * @param len Length of the image data in bytes + * @return HTTP response code + */ int sendSnapshot(uint8_t* buffer, size_t len); protected: + /** + * @brief Handles incoming camera control requests + * @param request The incoming request object + * @return true if request was handled successfully, false otherwise + */ bool handleCameraController(SinricProRequest &request); private: + // Callback handler for snapshot requests SnapshotCallback getSnapshotCallback = nullptr; }; @@ -41,29 +67,47 @@ void CameraController::onSnapshot(SnapshotCallback cb) { template bool CameraController::handleCameraController(SinricProRequest &request) { T *device = static_cast(this); - bool success = false; + // Handle getSnapshot action if (request.action == FSTR_CAMERA_getSnapshot) { if (getSnapshotCallback) { success = getSnapshotCallback(device->deviceId); } } - return success; } template int CameraController::sendSnapshot(uint8_t* buffer, size_t len) { - T *device = static_cast(this); - - if (!buffer) return -1; + int resCode = -1; - WiFiClientSecure client; - client.setInsecure(); +#if defined(ESP32) + T *device = static_cast(this); + + // Validate input buffer + if (!buffer) return resCode; HTTPClient http; - if (!http.begin(client, SINRICPRO_CAMERA_URL, 443, SINRICPRO_CAMERA_PATH, true)) return -1; + bool beginSuccess = false; + + #ifdef SINRICPRO_NOSSL + WiFiClient *client = new WiFiClient(); + if (!client) return resCode; + + beginSuccess = http.begin(*client, SINRICPRO_CAMERA_URL, 80, SINRICPRO_CAMERA_PATH, false); + #else + WiFiClientSecure *secureClient = new WiFiClientSecure(); + if (!secureClient) return resCode; + + secureClient->setInsecure(); // Skip certificate validation + beginSuccess = http.begin(*secureClient, SINRICPRO_CAMERA_URL, 443, SINRICPRO_CAMERA_PATH, true); + #endif + + if (!beginSuccess) { + http.end(); + return resCode; + } const String& deviceId = device->getDeviceId(); String createdAt = String(device->getTimestamp()); @@ -73,9 +117,10 @@ int CameraController::sendSnapshot(uint8_t* buffer, size_t len) { http.addHeader(FSTR_SINRICPRO_createdAt, createdAt); http.addHeader(FSTR_SINRICPRO_signature, signature); - int resCode = http.POST(buffer, len); + resCode = http.POST(buffer, len); http.end(); - +#endif + return resCode; } From 421f0d215f26a7855dc687c78884461ac30f79fa Mon Sep 17 00:00:00 2001 From: Aruna Tennakoon Date: Sat, 14 Dec 2024 12:18:06 +0700 Subject: [PATCH 17/17] fix: change Float to float --- src/Capabilities/ThermostatController.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Capabilities/ThermostatController.h b/src/Capabilities/ThermostatController.h index 6ac5b44c..edc60bae 100644 --- a/src/Capabilities/ThermostatController.h +++ b/src/Capabilities/ThermostatController.h @@ -181,7 +181,7 @@ bool ThermostatController::handleThermostatController(SinricProRequest &reque if (request.action == FSTR_THERMOSTAT_targetTemperature && targetTemperatureCallback) { float temperature; - if (request.request_value[FSTR_THERMOSTAT_temperature].is()) { + if (request.request_value[FSTR_THERMOSTAT_temperature].is()) { temperature = request.request_value[FSTR_THERMOSTAT_temperature]; } else { temperature = 1;