Skip to content

3.4.0 branch #409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Dec 9, 2024
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