EnigmaIOT  0.9.8
Secure sensor and gateway platform based on ESP8266 and ESP32
GatewayAPI.cpp
Go to the documentation of this file.
1 
9 #include "GatewayAPI.h"
10 #include <functional>
11 
12 using namespace std;
13 using namespace placeholders;
14 
15 const char* getNodeNumberUri = "/api/gw/nodenumber";
16 const char* getMaxNodesUri = "/api/gw/maxnodes";
17 const char* getNodesUri = "/api/gw/nodes";
18 const char* getNodeUri = "/api/node/node";
19 const char* getGwInfoUri = "/api/gw/info";
20 const char* getGwRestartUri = "/api/gw/restart";
21 const char* getGwResettUri = "/api/gw/reset";
22 const char* getNodeRestartUri = "/api/node/restart";
23 const char* nodeIdParam = "nodeid";
24 const char* nodeNameParam = "nodename";
25 const char* nodeAddrParam = "nodeaddr";
26 const char* confirmParam = "confirm";
27 
29  //if (!gw) {
30  // return;
31  //}
32  //gateway = gw;
33  server = new AsyncWebServer (WEB_API_PORT);
34  server->on (getNodeNumberUri, HTTP_GET, std::bind (&GatewayAPI::getNodeNumber, this, _1));
35  server->on (getMaxNodesUri, HTTP_GET, std::bind (&GatewayAPI::getMaxNodes, this, _1));
36  server->on (getNodesUri, HTTP_GET, std::bind (&GatewayAPI::getNodes, this, _1));
37  server->on (getNodeUri, HTTP_GET | HTTP_DELETE, std::bind (&GatewayAPI::nodeOp, this, _1));
38  server->on (getGwInfoUri, HTTP_GET, std::bind (&GatewayAPI::getGwInfo, this, _1));
39  server->on (getGwRestartUri, HTTP_PUT, std::bind (&GatewayAPI::restartGw, this, _1));
40  server->on (getGwResettUri, HTTP_PUT, std::bind (&GatewayAPI::resetGw, this, _1));
41  server->on (getNodeRestartUri, HTTP_PUT, std::bind (&GatewayAPI::restartNode, this, _1));
42  server->onNotFound (std::bind (&GatewayAPI::onNotFound, this, _1));
43  server->begin ();
44 }
45 
46 void GatewayAPI::getNodeNumber (AsyncWebServerRequest* request) {
47  char response[25];
48 
49  snprintf (response, 25, "{\"nodeNumber\":%d}", EnigmaIOTGateway.getActiveNodesNumber ());
50  DEBUG_INFO ("Response: %s", response);
51  request->send (200, "application/json", response);
52 }
53 
54 char* GatewayAPI::buildGwInfo (char* gwInfo, size_t len) {
55  DEBUG_INFO ("Build Gateway Info");
56  //resultCode = 200;
57  //time_t currentMillis = millis ();
58  snprintf (gwInfo, len, "{\"version\":\"%d.%d.%d\",\"network\":\"%s\",\"addresses\":{\"AP\":\"%s\",\"STA\":\"%s\"},"
59  "\"channel\":%d,\"ap\":\"%s\",\"bssid\":\"%s\",\"rssi\":%d,"
60 #ifdef ESP32
61  "\"txpower\":%.1f,"
62 #endif
63  "\"dns\":\"%s\",\"mem\":%d}",
66  WiFi.macAddress ().c_str (), WiFi.softAPmacAddress ().c_str (),
67  WiFi.channel (), WiFi.SSID ().c_str (), WiFi.BSSIDstr ().c_str (), WiFi.RSSI (),
68 #ifdef ESP32
69  (float)(WiFi.getTxPower ()) / 4,
70 #endif
71  WiFi.dnsIP ().toString ().c_str (),
72  ESP.getFreeHeap ()
73  );
74  DEBUG_DBG ("GwInfo: %s", gwInfo);
75  return gwInfo;
76 }
77 
78 void GatewayAPI::getGwInfo (AsyncWebServerRequest* request) {
79  int resultCode = 404;
80  char response[RESPONSE_SIZE];
81  const char* strTemp = buildGwInfo (response, RESPONSE_SIZE);
82  if (strTemp) {
83  resultCode = 200;
84  }
85  if (resultCode == 404) {
86  snprintf (response, RESPONSE_SIZE, "{\"result\":\"not found\"}");
87  }
88  DEBUG_DBG ("Response: %d --> %s", resultCode, response);
89  request->send (resultCode, "application/json", response);
90 }
91 
92 Node* GatewayAPI::getNodeFromParam (AsyncWebServerRequest* request) {
93  Node* node = NULL;
94  int params = request->params ();
95  int nodeIndex = -1;
96 
97  for (int i = 0; i < params; i++) {
98  AsyncWebParameter* p = request->getParam (i);
99  if (p->name () == nodeIdParam) {
100  if (isNumber (p->value ())) {
101  nodeIndex = atoi (p->value ().c_str ());
102  DEBUG_INFO ("Node to process is %d", nodeIndex);
103  node = EnigmaIOTGateway.nodelist.getNodeFromID (nodeIndex);
104  break;
105  }
106  }
107  if (p->name () == nodeNameParam) {
108  if (strcmp (p->value ().c_str (), BROADCAST_NONE_NAME)) {
109  node = EnigmaIOTGateway.nodelist.getNodeFromName (p->value ().c_str ());
110  DEBUG_INFO ("Node to process is %s", node ? node->getNodeName () : "NULL");
111  } else {
112  DEBUG_INFO ("Wrong node name %s", p->value ().c_str ());
113  }
114  break;
115  }
116  if (p->name () == nodeAddrParam) {
117  uint8_t addr[ENIGMAIOT_ADDR_LEN];
118  uint8_t* addrResult = str2mac (p->value ().c_str (), addr);
119  if (addrResult) {
120  if (memcmp (addr, BROADCAST_ADDRESS, ENIGMAIOT_ADDR_LEN)) {
122  DEBUG_INFO ("Node to process is %s", p ? p->value ().c_str () : "NULL");
123  }
124  }
125  break;
126  }
127  DEBUG_DBG ("Parameter %s = %s", p->name ().c_str (), p ? p->value ().c_str () : "NULL");
128  }
129 
130  DEBUG_DBG ("NodeId = %d, node: %p", nodeIndex, node);
131 
132  if (node) {
133  if (node->isRegistered ()) {
134  return node;
135  }
136  }
137  return node;
138 }
139 
140 const char* GatewayAPI::deleteNode (Node* node, int& resultCode) {
141  if (node) {
142  DEBUG_DBG ("Node %d is %p", node->getNodeId (), node);
143  if (node->isRegistered ()) {
144  DEBUG_INFO ("Node %d is registered", node->getNodeId ());
145  resultCode = 200;
147  return "{\"result\":\"ok\"}";
148  } else {
149  DEBUG_INFO ("Node %d is not registered", node->getNodeId ());
150  }
151  }
152  return NULL;
153 }
154 
155 char* GatewayAPI::getNodeInfo (Node* node, int& resultCode, char* nodeInfo, size_t len) {
156  if (node) {
157  DEBUG_DBG ("Node %d is %p", node->getNodeId (), node);
158  if (node->isRegistered ()) {
159  DEBUG_INFO ("Node %d is registered", node->getNodeId ());
160  resultCode = 200;
161  time_t currentMillis = millis ();
162  uint8_t* version = node->getVersion ();
163  size_t index;
164  index = snprintf (nodeInfo, len,
165  "{\"version\":\"%d.%d.%d\",\"node_id\":%d,\"address\":\"" MACSTR "\","\
166  "\"keyValidSince\":%lld,\"lastMessageTime\":%lld,\"sleepy\":%s,"\
167  "\"Broadcast\":%s,\"TimeSync\":%s,\"rssi\":%d,\"packetsHour\":%f,\"per\":%f",
168  version[0], version[1], version[2],
169  node->getNodeId (),
170  MAC2STR (node->getMacAddress ()),
171  currentMillis - node->getKeyValidFrom (),
172  currentMillis - node->getLastMessageTime (),
173  node->getSleepy () ? "True" : "False",
174  node->broadcastIsEnabled () ? "True" : "False",
175  node->useTimeSync () ? "True" : "False",
176  node->getRSSI (),
177  node->packetsHour,
178  node->per
179  );
180  char* nodeName = node->getNodeName ();
181  if (nodeName && strlen (nodeName)) {
182  index = index + snprintf (nodeInfo + index, len - index, ",\"Name\":\"%s\"", nodeName);
183  }
184  snprintf (nodeInfo + index, len - index, "}");
185  DEBUG_DBG ("NodeInfo: %s", nodeInfo);
186  return nodeInfo;
187  } else {
188  DEBUG_INFO ("Node %d is not registered", node->getNodeId ());
189  }
190  }
191  return NULL;
192 }
193 
195  return EnigmaIOTGateway.sendDownstream (node->getMacAddress (), NULL, 0, RESTART_NODE);
196 }
197 
198 void GatewayAPI::restartNode (AsyncWebServerRequest* request) {
199  Node* node;
200  int resultCode = 404;
201  char response[RESPONSE_SIZE];
202 
203  node = getNodeFromParam (request);
204 
205  DEBUG_WARN ("Send restart command to node %p", node);
206 
207  bool result = restartNodeRequest (node);
208  if (result) {
209  snprintf (response, 30, "{\"node_restart\":\"processed\"}");
210  resultCode = 200;
211  }
212  if (resultCode == 404) {
213  snprintf (response, 25, "{\"result\":\"not found\"}");
214  }
215  DEBUG_WARN ("Response: %d --> %s", resultCode, response);
216  request->send (resultCode, "application/json", response);
217 }
218 
219 void GatewayAPI::nodeOp (AsyncWebServerRequest* request) {
220  Node* node;
221  int resultCode = 404;
222  char response[RESPONSE_SIZE];
223 
224  node = getNodeFromParam (request);
225 
226  WebRequestMethodComposite method = request->method ();
227  DEBUG_INFO ("Method: %s", methodToString (request->method ()).c_str ());
228 
229  if (method == HTTP_DELETE) {
230  DEBUG_INFO ("Delete node %p", node);
231  const char* strTemp = deleteNode (node, resultCode);
232  if (strTemp) {
233  strncpy (response, strTemp, RESPONSE_SIZE);
234  }
235  } else if (method == HTTP_GET) {
236  DEBUG_INFO ("Info node %p", node);
237  const char* strTemp = getNodeInfo (node, resultCode, response, RESPONSE_SIZE);
238  DEBUG_DBG ("strTemp = %p", strTemp);
239  if (!strTemp) {
240  //strncpy (response, strTemp, 200);
241  resultCode = 404;
242  }
243  }
244  if (resultCode == 404) {
245  snprintf (response, 25, "{\"result\":\"not found\"}");
246  }
247  DEBUG_DBG ("Response: %d --> %s", resultCode, response);
248  request->send (resultCode, "application/json", response);
249 }
250 
251 void GatewayAPI::getMaxNodes (AsyncWebServerRequest* request) {
252  char response[25];
253 
254  snprintf (response, 25, "{\"maxNodes\":%d}", NUM_NODES);
255  DEBUG_INFO ("Response: %s", response);
256  request->send (200, "application/json", response);
257 }
258 
259 void GatewayAPI::restartGw (AsyncWebServerRequest* request) {
260  char response[30];
261  bool confirm = false;
262  int resultCode = 404;
263 
264  int params = request->params ();
265 
266  for (int i = 0; i < params; i++) {
267  AsyncWebParameter* p = request->getParam (i);
268  if (p->name () == confirmParam) {
269  if (p->value () == "1") {
270  confirm = true;
271  resultCode = 200;
272  break;
273  }
274  }
275  }
276 
277  if (confirm) {
278  snprintf (response, 30, "{\"gw_restart\":\"processed\"}");
279  request->send (resultCode, "application/json", response);
280  } else {
281  snprintf (response, 25, "{\"gw_restart\":\"fail\"}");
282  request->send (resultCode, "application/json", response);
283  }
284 
285  DEBUG_INFO ("Response: %s", response);
286 
287  if (confirm && EnigmaIOTGateway.notifyRestartRequested) {
289  }
290 }
291 
292 void GatewayAPI::resetGw (AsyncWebServerRequest* request) {
293  char response[30];
294  bool confirm = false;
295  int resultCode = 404;
296 
297  int params = request->params ();
298 
299  for (int i = 0; i < params; i++) {
300  AsyncWebParameter* p = request->getParam (i);
301  if (p->name () == confirmParam) {
302  if (p->value () == "1") {
303  confirm = true;
304  resultCode = 200;
305  break;
306  }
307  }
308  }
309 
310  if (confirm) {
311  snprintf (response, 30, "{\"gw_reset\":\"processed\"}");
312  request->send (resultCode, "application/json", response);
313  } else {
314  snprintf (response, 25, "{\"gw_reset\":\"fail\"}");
315  request->send (resultCode, "application/json", response);
316  }
317 
318  DEBUG_INFO ("Response: %s", response);
319 
321 
322 }
323 
324 
325 void GatewayAPI::getNodes (AsyncWebServerRequest* request) {
326  Node* node = NULL;
327 
328  AsyncResponseStream* response = request->beginResponseStream ("application/json");
329  response->setCode (200);
330 
331  response->print ("{\"nodes\":[");
332  do {
333  bool first = (node == NULL);
335  if (node && !first) {
336  DEBUG_DBG ("First is %s, node is %p", first ? "true" : "false", node);
337  response->print (',');
338  }
339  if (node) {
340  DEBUG_DBG ("LastNode: %u, node: %p", node->getNodeId (), node);
341  }
342  if (node) {
343  DEBUG_DBG ("Got node. NodeId -> %u", node->getNodeId ());
344  response->printf ("{\"nodeId\":%u,\"address\":\"" MACSTR "\"",
345  node->getNodeId (),
346  MAC2STR (node->getMacAddress ()));
347  char* nodeName = node->getNodeName ();
348  if (nodeName && strlen (nodeName)) {
349  response->printf (", \"name\":\"%s\"", node->getNodeName ());
350  }
351  response->print ("}");
352  }
353  } while (node != NULL);
354  response->print ("]}");
355  request->send (response);
356 }
357 
358 String methodToString (WebRequestMethodComposite method) {
359  switch (method) {
360  case HTTP_GET:
361  return String ("GET");
362  case HTTP_POST:
363  return String ("POST");
364  case HTTP_DELETE:
365  return String ("DELETE");
366  case HTTP_PUT:
367  return String ("PUT");
368  case HTTP_PATCH:
369  return String ("PATCH");
370  case HTTP_HEAD:
371  return String ("HEAD");
372  case HTTP_OPTIONS:
373  return String ("OPTIONS");
374  }
375  return "";
376 }
377 
378 void GatewayAPI::onNotFound (AsyncWebServerRequest* request) {
379  DEBUG_WARN ("404 Not found: %s", request->url ().c_str ());
380  DEBUG_WARN ("Method: %s", methodToString (request->method ()).c_str ());
381  int params = request->params ();
382  for (int i = 0; i < params; i++) {
383 #if DEBUG_LEVEL >= INFO
384  AsyncWebParameter* p = request->getParam (i);
385  DEBUG_INFO ("Parameter %s = %s", p->name ().c_str (), p->value ().c_str ());
386 #endif
387  }
388  request->send (404, "text/plain", "Not Found");
389 }
390 
GatewayAPI::onNotFound
void onNotFound(AsyncWebServerRequest *request)
Processes unknown entry points or methods.
Definition: GatewayAPI.cpp:378
EnigmaIOTGatewayClass::getActiveNodesNumber
int getActiveNodesNumber()
Gets number of active nodes.
Definition: EnigmaIOTGateway.h:592
EnigmaIOTGatewayClass::invalidateKey
bool invalidateKey(Node *node, gwInvalidateReason_t reason)
Creates an InvalidateKey message and sned it. This trigger a new key agreement to start on related no...
Definition: EnigmaIOTGateway.cpp:1624
getGwRestartUri
const char * getGwRestartUri
Definition: GatewayAPI.cpp:20
EnigmaIOTGatewayClass::doResetConfig
static void doResetConfig(void)
Activates a flag that signals that configuration has to be saved.
Definition: EnigmaIOTGateway.cpp:47
RESTART_NODE
@ RESTART_NODE
Definition: NodeList.h:65
NodeList::getNodeFromName
Node * getNodeFromName(const char *name)
Gets node that correspond with given node name.
Definition: NodeList.cpp:174
nodeIdParam
const char * nodeIdParam
Definition: GatewayAPI.cpp:23
ENIGMAIOT_ADDR_LEN
static const size_t ENIGMAIOT_ADDR_LEN
Address size. Mac address = 6 bytes.
Definition: EnigmaIoTconfigAdvanced.h:23
GatewayAPI::getMaxNodes
void getMaxNodes(AsyncWebServerRequest *request)
Processes max node number request.
Definition: GatewayAPI.cpp:251
GatewayAPI
Definition: GatewayAPI.h:25
Node::getVersion
uint8_t * getVersion()
Gets node EnigmaIOT version.
Definition: NodeList.h:449
GwAPI
GatewayAPI GwAPI
API instance.
Definition: GatewayAPI.cpp:391
Node::broadcastIsEnabled
bool broadcastIsEnabled()
Returns if node broadcast mode is enabled. In that case, node is able to send and receive encrypted b...
Definition: NodeList.h:373
getGwInfoUri
const char * getGwInfoUri
Definition: GatewayAPI.cpp:19
str2mac
uint8_t * str2mac(const char *macAddrString, uint8_t *macBytes)
Debug helper function that creates MAC address byte array from text representation.
Definition: helperFunctions.cpp:104
NodeList::getNodeFromMAC
Node * getNodeFromMAC(const uint8_t *mac)
Gets node that correspond with given address.
Definition: NodeList.cpp:142
GatewayAPI::getNodeFromParam
Node * getNodeFromParam(AsyncWebServerRequest *request)
Gets node reference from request parameters.
Definition: GatewayAPI.cpp:92
GatewayAPI::resetGw
void resetGw(AsyncWebServerRequest *request)
Processes gateway configuration reset request.
Definition: GatewayAPI.cpp:292
ENIGMAIOT_PROT_VERS
static const uint8_t ENIGMAIOT_PROT_VERS[3]
EnitmaIoT Version.
Definition: EnigmaIoTconfig.h:16
EnigmaIOTGatewayClass::getNetworkName
char * getNetworkName()
Gets EnigmaIOT network name.
Definition: EnigmaIOTGateway.h:349
KICKED
@ KICKED
Definition: EnigmaIOTGateway.h:82
methodToString
String methodToString(WebRequestMethodComposite method)
Definition: GatewayAPI.cpp:358
GatewayAPI::restartNodeRequest
bool restartNodeRequest(Node *node)
Sends restart node message.
Definition: GatewayAPI.cpp:194
GatewayAPI::getNodes
void getNodes(AsyncWebServerRequest *request)
Processes node list request.
Definition: GatewayAPI.cpp:325
getGwResettUri
const char * getGwResettUri
Definition: GatewayAPI.cpp:21
nodeAddrParam
const char * nodeAddrParam
Definition: GatewayAPI.cpp:25
Node::getSleepy
bool getSleepy()
Gets node working mode regarding battery saving strategy. If node is sleepy it will turn into deep sl...
Definition: NodeList.h:363
EnigmaIOTGatewayClass::notifyRestartRequested
simpleEventHandler_t notifyRestartRequested
Callback function that will be invoked when a hardware restart is requested.
Definition: EnigmaIOTGateway.h:138
GatewayAPI::nodeOp
void nodeOp(AsyncWebServerRequest *request)
Processes node information request.
Definition: GatewayAPI.cpp:219
GatewayAPI.h
API web server to control EnigmaIOT Gateway.
Node::getNodeId
uint16_t getNodeId()
Gets Node identifier.
Definition: NodeList.h:136
Node::getLastMessageTime
time_t getLastMessageTime()
Gets last time that node sent a message.
Definition: NodeList.h:203
RESPONSE_SIZE
const size_t RESPONSE_SIZE
Maximum API response size.
Definition: GatewayAPI.h:21
confirmParam
const char * confirmParam
Definition: GatewayAPI.cpp:26
getNodesUri
const char * getNodesUri
Definition: GatewayAPI.cpp:17
GatewayAPI::begin
void begin()
Starts REST API web server.
Definition: GatewayAPI.cpp:28
Node::packetsHour
double packetsHour
Packet rate for a specific nope.
Definition: NodeList.h:472
GatewayAPI::getNodeNumber
void getNodeNumber(AsyncWebServerRequest *request)
Processes node number request.
Definition: GatewayAPI.cpp:46
NodeList::getNextActiveNode
Node * getNextActiveNode(uint16_t nodeId)
Gets next active node by nodeId.
Definition: NodeList.cpp:295
NUM_NODES
static const int NUM_NODES
Maximum number of nodes that this gateway can handle.
Definition: EnigmaIoTconfig.h:32
getMaxNodesUri
const char * getMaxNodesUri
Definition: GatewayAPI.cpp:16
GatewayAPI::getNodeInfo
char * getNodeInfo(Node *node, int &resultCode, char *nodeInfo, size_t len)
Builds node info.
Definition: GatewayAPI.cpp:155
GatewayAPI::restartNode
void restartNode(AsyncWebServerRequest *request)
Processes node information request.
Definition: GatewayAPI.cpp:198
GatewayAPI::deleteNode
const char * deleteNode(Node *node, int &resultCode)
Processes node deletion request.
Definition: GatewayAPI.cpp:140
EnigmaIOTGatewayClass::nodelist
NodeList nodelist
Node database that keeps status and shared keys.
Definition: EnigmaIOTGateway.h:126
EnigmaIOTGateway
EnigmaIOTGatewayClass EnigmaIOTGateway
Definition: EnigmaIOTGateway.cpp:2050
BROADCAST_NONE_NAME
static const char BROADCAST_NONE_NAME[]
Name to reference broadcast node.
Definition: EnigmaIoTconfigAdvanced.h:27
Node::getNodeName
char * getNodeName()
Gets Node name.
Definition: NodeList.h:152
BROADCAST_ADDRESS
static const uint8_t BROADCAST_ADDRESS[]
Broadcast address.
Definition: EnigmaIoTconfigAdvanced.h:26
MACSTR
#define MACSTR
Definition: helperFunctions.cpp:83
Node
Class definition for a single sensor Node.
Definition: NodeList.h:109
getNodeRestartUri
const char * getNodeRestartUri
Definition: GatewayAPI.cpp:22
Node::isRegistered
bool isRegistered()
Gets registration state of this node.
Definition: NodeList.h:292
Node::getMacAddress
uint8_t * getMacAddress()
Gets address from Node.
Definition: NodeList.h:128
Node::getKeyValidFrom
time_t getKeyValidFrom()
Gets last time that key was agreed with gateway.
Definition: NodeList.h:187
GatewayAPI::buildGwInfo
char * buildGwInfo(char *gwInfo, size_t len)
Builds gateway info.
Definition: GatewayAPI.cpp:54
WEB_API_PORT
const int WEB_API_PORT
TCP port where Web API will listen through.
Definition: EnigmaIoTconfigAdvanced.h:77
EnigmaIOTGatewayClass::sendDownstream
bool sendDownstream(uint8_t *mac, const uint8_t *data, size_t len, control_message_type_t controlData, gatewayPayloadEncoding_t payload_type=RAW, char *nodeName=NULL)
Starts a downstream data message transmission.
Definition: EnigmaIOTGateway.cpp:364
GatewayAPI::getGwInfo
void getGwInfo(AsyncWebServerRequest *request)
Processes gateway information request.
Definition: GatewayAPI.cpp:78
getNodeNumberUri
const char * getNodeNumberUri
Definition: GatewayAPI.cpp:15
Node::per
double per
Current packet error rate of a specific node.
Definition: NodeList.h:471
NodeList::getNodeFromID
Node * getNodeFromID(uint16_t nodeId)
Gets node that correspond with given nodeId.
Definition: NodeList.cpp:135
nodeNameParam
const char * nodeNameParam
Definition: GatewayAPI.cpp:24
GatewayAPI::restartGw
void restartGw(AsyncWebServerRequest *request)
Processes gateway restart request.
Definition: GatewayAPI.cpp:259
isNumber
bool isNumber(const char *input)
Checks if input string is numeric.
Definition: helperFunctions.cpp:169
Node::useTimeSync
bool useTimeSync()
Gets node info to check if it has requested time sync ever.
Definition: NodeList.h:434
Node::getRSSI
int8_t getRSSI()
Gets last RSSI measurement of Gateway.
Definition: NodeList.h:418
getNodeUri
const char * getNodeUri
Definition: GatewayAPI.cpp:18