Skip to content

Conversation

@roelbroersma
Copy link

@roelbroersma roelbroersma commented Nov 11, 2023

Hello,

I spent the previous weeks in creating this usermod which I use as a Christmas card :)
I have it compiled on a M5Stack Atom S3 Lite and bought 60 to give to my friends (along with a 60 LED Ring). When my friends receive their 'christmas card' and turn it on... scan a QR code (so they connect to it by Wifi), fill in their WiFi credentials... the WLED is on their WiFi.

Now it requests a URL every (30 seconds) to see which lights of the LED ring needs to be turned ON. My server gives a JSON answer with a number of LEDs. This number is all the people who requested this URL in the past 5 minutes. So you have a 'ring of thought'. You see LED burning for every friend who also has the LED ring on :)

This Usermod is great if you just DROP a WLED device somewhere and you do not have access to it. But the device is able to access internet. You don't have to forward ports.. set up a VPN.. It just pulls it's data every 30 seconds from a URL you give it.
So you local goverment can have their christmass stars in the shopping street all with this usermod :) and they control it remotely without any network hassle...

@blazoncek
Copy link
Collaborator

Thank you for your contribution. This seems like a great add-on.

Unfortunately I cannot find a reasoning for reinventing the JSON API. Why not just use existing JSON API? Parsing it would be as simple as calling deserializeState().

@roelbroersma
Copy link
Author

roelbroersma commented Nov 11, 2023

Thank you for your contribution. This seems like a great add-on.

Unfortunately I cannot find a reasoning for reinventing the JSON API. Why not just use existing JSON API? Parsing it would be as simple as calling deserializeState().

You mean just the de-serialization or the whole JSON structure?
In the current JSON structure, the one we built, which is pulled from a URL, it is possible to set only LED1 (only red), LED10(red+blue) and LED 25 (green) to ON, while at the same time setting an effect for another segment and the overall brightness to 100. We use the handleOverlayDraw function for that.
Do you mean we should you the same JSON structure as the API uses? (which means you can also set and remove segments).
We have thought about a sort of 'proxy' (pulling a remote host for JSON and have that response), then do a request with that response to http://localhost/json, but settings individual LEDs was not possible and that json api is way too large.

I did extensive testing to see if there where any memory leaks and had a few (from friends here, also engineers) code reviews. As you can see the code is well documented. Especially the AsyncTCP part and unfortunatelly it doesn't accept https because that's not in the library. We tried compiling several other clients which have https support, but were not successfull.

Or do you mean only this part:

  DEBUG_PRINTLN(F("Received response for handleResponse."));
  // Calculate a sufficient size for the JSON buffer
  size_t jsonSize = responseStr.length() * 3; // 3 times as much memory as the full content, that would be enough. It needs more for shifting and stuff
  DEBUG_PRINT(F("Calculated JSON buffer size: "));
  DEBUG_PRINTLN(jsonSize);
  DynamicJsonDocument doc(jsonSize);

  // Search for two linebreaks between headers and content
  int bodyPos = responseStr.indexOf("\r\n\r\n");
  if (bodyPos > 0) {
    String jsonStr = responseStr.substring(bodyPos + 4); // +4 Skip the two CRLFs
    jsonStr.trim();

    DEBUG_PRINTLN("Response: ");
    DEBUG_PRINTLN(jsonStr);

    // Attempt to deserialize the JSON response
    DeserializationError error = deserializeJson(doc, jsonStr);
    if (error) {
      // If there is an error in deserialization, exit the function
      DEBUG_PRINT(F("DeserializationError: "));
      DEBUG_PRINTLN(error.c_str());
      return;
    }
  } else {
    DEBUG_PRINTLN(F("No body found in the response"));
    return;
  }

because from there, our 'own' JSON structure begins, like this:

  JsonArray segments = doc["segments"];
  if (!segments) {
    // If the 'segments' key is not found, exit the function
    DEBUG_PRINTLN(F("No 'segments' key found in JSON."));
    return;
  }

BTW. We drop/free the JSON objects as soon as possible and set the data in a C array. So we save a lot of memory and possible conflicts. The C array is used in the drawOverlay function and in out setEffect function.

@blazoncek
Copy link
Collaborator

I have not yet thoroughly examined the code, I will in time, but on my first glance it is really inefficient by handling a separate set of JSON API (like "segments" you mention). Also using a dynamic JSON document may be inefficient as WLED already has a permanent JSON buffer large enough for handling the largest possible JSON structure.
You use it by calling requestJSONBufferLock(id) and release it by releaseJSONBufferLock(). Between those calls you just use global doc.
If you have custom enhancements (that do not clash with existing API) you can safely parse them after handling deserializeState() as WLED ignores any unknown JSON object.

I am proposing to modify your web server code (PHP?) to use existing WLED API and only do deserializeState() call in your usermod.

@blazoncek blazoncek changed the title Merged edits from usermod_v2_HttpPullLightControl Remote web server WLED control usermod Nov 12, 2023
@roelbroersma
Copy link
Author

I close this request because I am doing a new request for tbhe v0.0.3 which incorporates the WLED JSON API.

@roelbroersma
Copy link
Author

See the new pull request: #3523

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants