11    #include <ESP8266WiFi.h> 
   12#elif defined(ESP32) || defined(ARDUINO_ARCH_RP2040) 
   16#include <ArduinoJson.h> 
   17#include <WebSocketsClient.h> 
   19#include "SinricProConfig.h" 
   20#include "SinricProDebug.h" 
   21#include "SinricProInterface.h" 
   22#include "SinricProNamespace.h" 
   23#include "SinricProQueue.h" 
   24namespace SINRICPRO_NAMESPACE {
 
   26enum class ConnectionState {
 
   32#if !defined(WEBSOCKETS_VERSION_INT) || (WEBSOCKETS_VERSION_INT < 2003005) 
   33#error "Wrong WebSockets Version! Minimum Version is 2.3.5!!!" 
   36using wsConnectedCallback    = std::function<void(
void)>;
 
   37using wsDisconnectedCallback = std::function<void(
void)>;
 
   38using wsPongCallback         = std::function<void(uint32_t)>;
 
   40class WebsocketListener : 
protected WebSocketsClient {
 
   45    void begin(String server, String appKey, String deviceIds, SinricProQueue_t* receiveQueue);
 
   48    void setRestoreDeviceStates(
bool flag);
 
   50    void sendMessage(String& message);
 
   52    void onConnected(wsConnectedCallback callback);
 
   53    void onDisconnected(wsDisconnectedCallback callback);
 
   54    void onPong(wsPongCallback callback);
 
   56    using WebSocketsClient::disconnect;
 
   57    using WebSocketsClient::isConnected;
 
   61    bool restoreDeviceStates;
 
   62    ConnectionState connectionState;
 
   64    wsConnectedCallback    _wsConnectedCb;
 
   65    wsDisconnectedCallback _wsDisconnectedCb;
 
   66    wsPongCallback         _wsPongCb;
 
   68    virtual void runCbEvent(WStype_t type, uint8_t* payload, 
size_t length) 
override;
 
   70    void              setExtraHeaders();
 
   71    SinricProQueue_t* receiveQueue;
 
   76WebsocketListener::WebsocketListener()
 
   78    , restoreDeviceStates(false)
 
   79    , connectionState(ConnectionState::disconnected)
 
   80    , _wsConnectedCb(nullptr)
 
   81    , _wsDisconnectedCb(nullptr)
 
   82    , _wsPongCb(nullptr) {}
 
   84WebsocketListener::~WebsocketListener() {
 
   88void WebsocketListener::setExtraHeaders() {
 
   90    const char* platform = 
"ESP8266";
 
   92    const char* platform = 
"ESP32";
 
   93#elif defined(ARDUINO_ARCH_RP2040) 
   94    const char* platform = 
"RP2040";
 
   97    String headers = 
"appkey:" + appKey;
 
   98    headers += 
"\r\ndeviceids:" + deviceIds;
 
   99    headers += 
"\r\nrestoredevicestates:" + String(restoreDeviceStates ? 
"true" : 
"false");
 
  100    headers += 
"\r\nip:" + WiFi.localIP().toString();
 
  101    headers += 
"\r\nmac:" + WiFi.macAddress();
 
  102    headers += 
"\r\nplatform:" + String(platform);
 
  103    headers += 
"\r\nSDKVersion:" + String(SINRICPRO_VERSION);
 
  105#ifdef FIRMWARE_VERSION 
  106    headers += 
"\r\nfirmwareVersion:" + String(FIRMWARE_VERSION);
 
  109    DEBUG_SINRIC(
"[SinricPro:Websocket]: headers: \r\n%s\r\n", headers.c_str());
 
  110    WebSocketsClient::setExtraHeaders(headers.c_str());
 
  113void WebsocketListener::begin(String server, String appKey, String deviceIds, SinricProQueue_t* receiveQueue) {
 
  116    connectionState = ConnectionState::connecting;
 
  118    this->receiveQueue = receiveQueue;
 
  119    this->appKey       = appKey;
 
  120    this->deviceIds    = deviceIds;
 
  123    DEBUG_SINRIC(
"[SinricPro:Websocket]: Connecting to WebSocket Server using SSL (%s)\r\n", server.c_str());
 
  125    DEBUG_SINRIC(
"[SinricPro:Websocket]: Connecting to WebSocket Server (%s)\r\n", server.c_str());
 
  128    if (isConnected()) stop();
 
  130    enableHeartbeat(WEBSOCKET_PING_INTERVAL, WEBSOCKET_PING_TIMEOUT, WEBSOCKET_RETRY_COUNT);
 
  132    WebSocketsClient::beginSSL(server.c_str(), SINRICPRO_SERVER_SSL_PORT, 
"/");
 
  134    WebSocketsClient::begin(server.c_str(), SINRICPRO_SERVER_PORT, 
"/");  
 
  138void WebsocketListener::handle() {
 
  142void WebsocketListener::stop() {
 
  145    connectionState = ConnectionState::disconnected;
 
  148void WebsocketListener::setRestoreDeviceStates(
bool flag) {
 
  149    this->restoreDeviceStates = flag;
 
  152void WebsocketListener::sendMessage(String& message) {
 
  156void WebsocketListener::onConnected(wsConnectedCallback callback) {
 
  157    _wsConnectedCb = callback;
 
  160void WebsocketListener::onDisconnected(wsDisconnectedCallback callback) {
 
  161    _wsDisconnectedCb = callback;
 
  164void WebsocketListener::onPong(wsPongCallback callback) {
 
  165    _wsPongCb = callback;
 
  168void WebsocketListener::runCbEvent(WStype_t type, uint8_t* payload, 
size_t length) {
 
  172        case WStype_DISCONNECTED: {
 
  173                DEBUG_SINRIC(
"[SinricPro:Websocket]: disconnected\r\n");
 
  174                if (connectionState == ConnectionState::connected && _wsDisconnectedCb) _wsDisconnectedCb();
 
  175                connectionState = ConnectionState::disconnected;
 
  179        case WStype_CONNECTED:
 
  180            DEBUG_SINRIC(
"[SinricPro:Websocket]: connected\r\n");
 
  181            if (_wsConnectedCb) _wsConnectedCb();
 
  182            if (restoreDeviceStates) {
 
  183                restoreDeviceStates = 
false;
 
  186            connectionState = ConnectionState::connected;
 
  190            SinricProMessage* request = 
new SinricProMessage(IF_WEBSOCKET, (
char*)payload);
 
  191            DEBUG_SINRIC(
"[SinricPro:Websocket]: receiving data\r\n");
 
  192            receiveQueue->push(request);
 
  197            if (_wsPongCb) _wsPongCb(millis() - _client.lastPing);