SinricPro Library
SinricProWebsocket.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 
9 #ifndef _SINRICPRO_WEBSOCKET_H__
10 #define _SINRICPRO_WEBSOCKET_H__
11 
12 #if defined ESP8266
13  #include <ESP8266WiFi.h>
14 #endif
15 #if defined ESP32
16  #include <WiFi.h>
17 #endif
18 
19 #include <WebSocketsClient.h>
20 #include <ArduinoJson.h>
21 #include "SinricProDebug.h"
22 #include "SinricProConfig.h"
23 #include "SinricProQueue.h"
24 #include "SinricProInterface.h"
25 
26 class websocketListener
27 {
28  public:
29  typedef std::function<void(void)> wsConnectedCallback;
30  typedef std::function<void(void)> wsDisconnectedCallback;
31 
32  websocketListener();
33  ~websocketListener();
34 
35  void begin(String server, String socketAuthToken, String deviceIds, SinricProQueue_t* receiveQueue);
36  void handle();
37  void stop();
38  bool isConnected() { return _isConnected; }
39  void setRestoreDeviceStates(bool flag) { this->restoreDeviceStates = flag; };
40 
41  void sendMessage(String &message);
42 
43  void onConnected(wsConnectedCallback callback) { _wsConnectedCb = callback; }
44  void onDisconnected(wsDisconnectedCallback callback) { _wsDisconnectedCb = callback; }
45 
46  void disconnect() { webSocket.disconnect(); }
47  private:
48  bool _begin = false;
49  bool _isConnected = false;
50  bool restoreDeviceStates = false;
51 
52  WebSocketsClient webSocket;
53 
54  wsConnectedCallback _wsConnectedCb;
55  wsDisconnectedCallback _wsDisconnectedCb;
56 
57  void webSocketEvent(WStype_t type, uint8_t * payload, size_t length);
58  void setExtraHeaders();
59  SinricProQueue_t* receiveQueue;
60  String deviceIds;
61  String socketAuthToken;
62 };
63 
64 void websocketListener::setExtraHeaders() {
65  String headers = "appkey:" + socketAuthToken + "\r\n";
66  headers += "deviceids:" + deviceIds + "\r\n";
67  headers += "restoredevicestates:" + String(restoreDeviceStates?"true":"false") + "\r\n";
68  #ifdef ESP8266
69  headers += "platform:ESP8266\r\n";
70  #endif
71  #ifdef ESP32
72  headers += "platform:ESP32\r\n";
73  #endif
74  headers += "version:" + String(SINRICPRO_VERSION);
75  DEBUG_SINRIC("[SinricPro:Websocket]: headers: \r\n%s\r\n", headers.c_str());
76  webSocket.setExtraHeaders(headers.c_str());
77 }
78 
79 websocketListener::websocketListener() : _isConnected(false) {}
80 
81 websocketListener::~websocketListener() {
82  stop();
83 }
84 
85 void websocketListener::begin(String server, String socketAuthToken, String deviceIds, SinricProQueue_t* receiveQueue) {
86  if (_begin) return;
87  _begin = true;
88 
89  this->receiveQueue = receiveQueue;
90  this->socketAuthToken = socketAuthToken;
91  this->deviceIds = deviceIds;
92 
93 #ifdef WEBSOCKET_SSL
94  DEBUG_SINRIC("[SinricPro:Websocket]: Connecting to WebSocket Server using SSL (%s)\r\n", server.c_str());
95 #else
96  DEBUG_SINRIC("[SinricPro:Websocket]: Connecting to WebSocket Server (%s)\r\n", server.c_str());
97 #endif
98 
99  if (_isConnected) {
100  stop();
101  }
102  setExtraHeaders();
103  webSocket.onEvent([&](WStype_t type, uint8_t * payload, size_t length) { webSocketEvent(type, payload, length); });
104  webSocket.enableHeartbeat(WEBSOCKET_PING_INTERVAL, WEBSOCKET_PING_TIMEOUT, WEBSOCKET_RETRY_COUNT);
105 #ifdef WEBSOCKET_SSL
106  // To get this working, WebSocketsClient.h needs to be fixed. See https://github.com/Links2004/arduinoWebSockets/issues/492
107  webSocket.beginSSL(server, SINRICPRO_SERVER_SSL_PORT, "/");
108 #else
109  webSocket.begin(server, SINRICPRO_SERVER_PORT, "/"); // server address, port and URL
110 #endif
111 }
112 
113 void websocketListener::handle() {
114  webSocket.loop();
115 }
116 
117 void websocketListener::stop() {
118  if (_isConnected) {
119  webSocket.disconnect();
120  }
121  _begin = false;
122 }
123 
124 void websocketListener::sendMessage(String &message) {
125  webSocket.sendTXT(message);
126 }
127 
128 
129 void websocketListener::webSocketEvent(WStype_t type, uint8_t * payload, size_t length)
130 {
131  switch (type) {
132  case WStype_DISCONNECTED:
133  if (_isConnected) {
134  DEBUG_SINRIC("[SinricPro:Websocket]: disconnected\r\n");
135  if (_wsDisconnectedCb) _wsDisconnectedCb();
136  _isConnected = false;
137  }
138  break;
139  case WStype_CONNECTED:
140  _isConnected = true;
141  DEBUG_SINRIC("[SinricPro:Websocket]: connected\r\n");
142  if (_wsConnectedCb) _wsConnectedCb();
143  if (restoreDeviceStates) {
144  restoreDeviceStates=false;
145  setExtraHeaders();
146  }
147  break;
148  case WStype_TEXT: {
149  SinricProMessage* request = new SinricProMessage(IF_WEBSOCKET, (char*)payload);
150  DEBUG_SINRIC("[SinricPro:Websocket]: receiving data\r\n");
151  receiveQueue->push(request);
152  break;
153  }
154  default: break;
155  }
156 }
157 
158 #endif