Skip to content
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

Bmp280 example #6

Merged
merged 13 commits into from
Aug 23, 2021
157 changes: 6 additions & 151 deletions ESPWebThingAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class WebThingAdapter {
}

MDNS.addService("webthing", "tcp", port);
MDNS.addServiceTxt("webthing", "tcp", "path", "/");
MDNS.addServiceTxt("webthing", "tcp", "path", "/.well-known/wot-thing-description");

DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods",
Expand All @@ -70,7 +70,7 @@ class WebThingAdapter {
this->server.on("/*", HTTP_OPTIONS,
std::bind(&WebThingAdapter::handleOptions, this,
std::placeholders::_1));
this->server.on("/", HTTP_GET,
this->server.on("/.well-known/wot-thing-description", HTTP_GET,
std::bind(&WebThingAdapter::handleThings, this,
std::placeholders::_1));

Expand Down Expand Up @@ -158,15 +158,6 @@ class WebThingAdapter {
void update() {
#ifdef ESP8266
MDNS.update();
#endif
#ifndef WITHOUT_WS
// * Send changed properties as defined in "4.5 propertyStatus message"
// Do this by looping over all devices and properties
ThingDevice *device = this->firstDevice;
while (device != nullptr) {
sendChangedProperties(device);
device = device->next;
}
#endif
}

Expand All @@ -178,19 +169,6 @@ class WebThingAdapter {
this->lastDevice->next = device;
this->lastDevice = device;
}

#ifndef WITHOUT_WS
// Initiate the websocket instance
AsyncWebSocket *ws = new AsyncWebSocket("/things/" + device->id);
device->ws = ws;
// AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType
// type, void * arg, uint8_t *data, size_t len, ThingDevice* device
ws->onEvent(std::bind(
&WebThingAdapter::handleWS, this, std::placeholders::_1,
std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,
std::placeholders::_5, std::placeholders::_6, device));
this->server.addHandler(ws);
#endif
}

private:
Expand Down Expand Up @@ -228,118 +206,6 @@ class WebThingAdapter {
return false;
}

#ifndef WITHOUT_WS
void sendErrorMsg(DynamicJsonDocument &prop, AsyncWebSocketClient &client,
int status, const char *msg) {
prop["error"] = msg;
prop["status"] = status;
String jsonStr;
serializeJson(prop, jsonStr);
client.text(jsonStr.c_str(), jsonStr.length());
}

void handleWS(AsyncWebSocket *server, AsyncWebSocketClient *client,
AwsEventType type, void *arg, const uint8_t *rawData,
size_t len, ThingDevice *device) {
if (type == WS_EVT_DISCONNECT || type == WS_EVT_ERROR) {
device->removeEventSubscriptions(client->id());
return;
}

// Ignore all others except data packets
if (type != WS_EVT_DATA)
return;

// Only consider non fragmented data
AwsFrameInfo *info = (AwsFrameInfo *)arg;
if (!info->final || info->index != 0 || info->len != len)
return;

// Web Thing only specifies text, not binary websocket transfers
if (info->opcode != WS_TEXT)
return;

// In theory we could just have one websocket for all Things and react on
// the server->url() to route data. Controllers will however establish a
// separate websocket connection for each Thing anyway as of in the spec.
// For now each Thing stores its own Websocket connection object therefore.

// Parse request
DynamicJsonDocument newProp(SMALL_JSON_DOCUMENT_SIZE);
auto error = deserializeJson(newProp, rawData, len);
if (error) {
sendErrorMsg(newProp, *client, 400, "Invalid json");
return;
}

String messageType = newProp["messageType"].as<String>();
JsonVariant dataVariant = newProp["data"];
if (!dataVariant.is<JsonObject>()) {
sendErrorMsg(newProp, *client, 400, "data must be an object");
return;
}

JsonObject data = dataVariant.as<JsonObject>();

if (messageType == "setProperty") {
for (JsonPair kv : data) {
device->setProperty(kv.key().c_str(), kv.value());
}
} else if (messageType == "requestAction") {
for (JsonPair kv : data) {
DynamicJsonDocument *actionRequest =
new DynamicJsonDocument(SMALL_JSON_DOCUMENT_SIZE);

JsonObject actionObj = actionRequest->to<JsonObject>();
JsonObject nested = actionObj.createNestedObject(kv.key());

for (JsonPair kvInner : kv.value().as<JsonObject>()) {
nested[kvInner.key()] = kvInner.value();
}

ThingActionObject *obj = device->requestAction(actionRequest);
if (obj != nullptr) {
obj->setNotifyFunction(std::bind(&ThingDevice::sendActionStatus,
device, std::placeholders::_1));
device->sendActionStatus(obj);

obj->start();
}
}
} else if (messageType == "addEventSubscription") {
for (JsonPair kv : data) {
ThingEvent *event = device->findEvent(kv.key().c_str());
if (event) {
device->addEventSubscription(client->id(), event->id);
}
}
}
}

void sendChangedProperties(ThingDevice *device) {
// Prepare one buffer per device
DynamicJsonDocument message(LARGE_JSON_DOCUMENT_SIZE);
message["messageType"] = "propertyStatus";
JsonObject prop = message.createNestedObject("data");
bool dataToSend = false;
ThingItem *item = device->firstProperty;
while (item != nullptr) {
ThingDataValue *value = item->changedValueOrNull();
if (value) {
dataToSend = true;
item->serializeValue(prop);
}
item = item->next;
}
if (dataToSend) {
String jsonStr;
serializeJson(message, jsonStr);
// Inform all connected ws clients of a Thing about changed properties
((AsyncWebSocket *)device->ws)->textAll(jsonStr);
}
}
#endif

void handleUnknown(AsyncWebServerRequest *request) {
if (!verifyHost(request)) {
return;
Expand All @@ -362,16 +228,15 @@ class WebThingAdapter {
request->beginResponseStream("application/json");

DynamicJsonDocument buf(LARGE_JSON_DOCUMENT_SIZE);
JsonArray things = buf.to<JsonArray>();
JsonObject thing = buf.to<JsonObject>();
ThingDevice *device = this->firstDevice;
while (device != nullptr) {
JsonObject descr = things.createNestedObject();
device->serialize(descr, ip, port);
descr["href"] = "/things/" + device->id;
device->serialize(thing, ip, port);
thing["href"] = "/things/" + device->id;
device = device->next;
}

serializeJson(things, *response);
serializeJson(thing, *response);
request->send(response);
}

Expand Down Expand Up @@ -513,11 +378,6 @@ class WebThingAdapter {
return;
}

#ifndef WITHOUT_WS
obj->setNotifyFunction(std::bind(&ThingDevice::sendActionStatus, device,
std::placeholders::_1));
#endif

DynamicJsonDocument respBuffer(SMALL_JSON_DOCUMENT_SIZE);
JsonObject item = respBuffer.to<JsonObject>();
obj->serialize(item, device->id);
Expand Down Expand Up @@ -624,11 +484,6 @@ class WebThingAdapter {
return;
}

#ifndef WITHOUT_WS
obj->setNotifyFunction(std::bind(&ThingDevice::sendActionStatus, device,
std::placeholders::_1));
#endif

DynamicJsonDocument respBuffer(SMALL_JSON_DOCUMENT_SIZE);
JsonObject item = respBuffer.to<JsonObject>();
obj->serialize(item, device->id);
Expand Down
Loading