Skip to content
Merged
8 changes: 8 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# 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.

Expand Down
2 changes: 1 addition & 1 deletion library.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"maintainer": true
}
],
"version": "3.3.1",
"version": "3.4.0",
"frameworks": "arduino",
"platforms": [
"espressif8266",
Expand Down
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=SinricPro
version=3.3.1
version=3.4.0
author=Boris Jaeger <[email protected]>
maintainer=Boris Jaeger <[email protected]>
sentence=Library for https://sinric.pro - simple way to connect your device to alexa
Expand Down
82 changes: 82 additions & 0 deletions src/Capabilities/CameraController.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#pragma once

#include "../EventLimiter.h"
#include "../SinricProNamespace.h"
#include "../SinricProRequest.h"
#include "../SinricProStrings.h"
#include <HTTPClient.h>
#include <WiFiClientSecure.h>

namespace SINRICPRO_NAMESPACE {

FSTR(CAMERA, getSnapshot); // "getSnapshot"

using SnapshotCallback = std::function<bool(const String &)>;

template <typename T>
class CameraController {
public:
CameraController();
void onSnapshot(SnapshotCallback cb);
int sendSnapshot(uint8_t* buffer, size_t len);

protected:
bool handleCameraController(SinricProRequest &request);

private:
SnapshotCallback getSnapshotCallback = nullptr;
};

template <typename T>
CameraController<T>::CameraController() {
T *device = static_cast<T *>(this);
device->registerRequestHandler(std::bind(&CameraController<T>::handleCameraController, this, std::placeholders::_1));
}

template <typename T>
void CameraController<T>::onSnapshot(SnapshotCallback cb) {
getSnapshotCallback = cb;
}

template <typename T>
bool CameraController<T>::handleCameraController(SinricProRequest &request) {
T *device = static_cast<T *>(this);

bool success = false;

if (request.action == FSTR_CAMERA_getSnapshot) {
if (getSnapshotCallback) {
success = getSnapshotCallback(device->deviceId);
}
}

return success;
}

template <typename T>
int CameraController<T>::sendSnapshot(uint8_t* buffer, size_t len) {
T *device = static_cast<T *>(this);

if (!buffer) return -1;

WiFiClientSecure client;
client.setInsecure();

HTTPClient http;
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(FSTR_SINRICPRO_deviceId, deviceId);
http.addHeader(FSTR_SINRICPRO_timestamp, timestamp);
http.addHeader(FSTR_SINRICPRO_signature, signature);

int resCode = http.POST(buffer, len);
http.end();

return resCode;
}

} // namespace SINRICPRO_NAMESPACE
4 changes: 2 additions & 2 deletions src/Capabilities/ChannelController.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,13 @@ bool ChannelController<T>::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>()) {
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>()) {
String channelName("");
int channelNumber = request.request_value[FSTR_CHANNEL_channel][FSTR_CHANNEL_number];
success = changeChannelNumberCallback(device->deviceId, channelNumber, channelName);
Expand Down
2 changes: 1 addition & 1 deletion src/Capabilities/ThermostatController.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ bool ThermostatController<T>::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<Float>()) {
temperature = request.request_value[FSTR_THERMOSTAT_temperature];
} else {
temperature = 1;
Expand Down
75 changes: 40 additions & 35 deletions src/SinricPro.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
#include "SinricProDeviceInterface.h"
#include "SinricProInterface.h"
#include "SinricProMessageid.h"
#include "SinricProModuleCommandHandler.h"
#include "SinricProNamespace.h"
#include "SinricProQueue.h"
#include "SinricProSignature.h"
#include "SinricProStrings.h"
#include "SinricProUDP.h"
#include "SinricProWebsocket.h"
#include "Timestamp.h"
#include "SinricProModuleCommandHandler.h"
namespace SINRICPRO_NAMESPACE {

/**
Expand Down Expand Up @@ -57,7 +57,7 @@ using OTAUpdateCallbackHandler = std::function<bool(const String& url, int major
* @brief Function signature for setting a module setting.
*
* This callback is used to set a value for a specific setting identified by its ID.
*
*
* @param id The unique identifier of the setting to be set.
* @param value The new value to be assigned to the setting.
* @return bool Returns true if the setting was successfully updated, false otherwise.
Expand Down Expand Up @@ -93,20 +93,21 @@ class SinricProClass : public SinricProInterface {
class Proxy;

public:
void begin(String appKey, String appSecret, String serverURL = SINRICPRO_SERVER_URL);
void handle();
void stop();
bool isConnected();
void onConnected(ConnectedCallbackHandler cb);
void onDisconnected(DisconnectedCallbackHandler cb);
void onPong(PongCallback cb);
void restoreDeviceStates(bool flag);
void setResponseMessage(String&& message);
unsigned long getTimestamp() override;
Proxy operator[](const String deviceId);
void onOTAUpdate(OTAUpdateCallbackHandler cb);
void onSetSetting(SetSettingCallbackHandler cb);
void onReportHealth(ReportHealthCallbackHandler cb);
void begin(String appKey, String appSecret, String serverURL = SINRICPRO_SERVER_URL);
void handle();
void stop();
bool isConnected();
void onConnected(ConnectedCallbackHandler cb);
void onDisconnected(DisconnectedCallbackHandler cb);
void onPong(PongCallback cb);
void restoreDeviceStates(bool flag);
void setResponseMessage(String&& message);
unsigned long getTimestamp() override;
virtual String sign(const String& message);
Proxy operator[](const String deviceId);
void onOTAUpdate(OTAUpdateCallbackHandler cb);
void onSetSetting(SetSettingCallbackHandler cb);
void onReportHealth(ReportHealthCallbackHandler cb);

protected:
template <typename DeviceType>
Expand All @@ -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();
Expand Down Expand Up @@ -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>();
JsonObject header = requestMessage[FSTR_SINRICPRO_header].to<JsonObject>();
header[FSTR_SINRICPRO_payloadVersion] = 2;
header[FSTR_SINRICPRO_signatureVersion] = 1;

Expand Down Expand Up @@ -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 + "\"";
}
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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.
*
Expand All @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -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>();
JsonObject header = responseMessage[FSTR_SINRICPRO_header].to<JsonObject>();
header[FSTR_SINRICPRO_payloadVersion] = 2;
header[FSTR_SINRICPRO_signatureVersion] = 1;

Expand All @@ -680,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<String>()) 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;
Expand All @@ -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>();
JsonObject header = eventMessage[FSTR_SINRICPRO_header].to<JsonObject>();
header[FSTR_SINRICPRO_payloadVersion] = 2;
header[FSTR_SINRICPRO_signatureVersion] = 1;

Expand Down
5 changes: 4 additions & 1 deletion src/SinricProCamera.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -23,10 +24,12 @@ namespace SINRICPRO_NAMESPACE {
class SinricProCamera : public SinricProDevice,
public SettingController<SinricProCamera>,
public PushNotification<SinricProCamera>,
public PowerStateController<SinricProCamera> {
public PowerStateController<SinricProCamera>,
public CameraController<SinricProCamera> {
friend class SettingController<SinricProCamera>;
friend class PushNotification<SinricProCamera>;
friend class PowerStateController<SinricProCamera>;
friend class CameraController<SinricProCamera>;
public:
SinricProCamera(const String &deviceId) : SinricProDevice(deviceId, "CAMERA") {}
};
Expand Down
Loading
Loading