Multi-segment UDP sync via IR remote

Hello,

My issue is similar to this question. I’m currently using v0.13.1, and as discussed @ here, “multi-segment UDP sync” should work as of v0.13.

When the following is set in cfg.json

"if":{"recv":{...,"seg":true,"sb":true}

(i.e. receiveSegmentOptions and receiveSegmentBounds, resp.) things such as multi-segment colors and smooth palette transitions to work on the receiver side – but only for playlists. Attempts to UDP sync individual presets fail! For example, if a sync’d playlist is in progress, and an attempt to sync to a new individual preset is made, the receiver does not change to this new preset command – regardless of whether the preset is single- or multi-segment. Rather, the receiver will just stop the playlist at its active preset, and render it indefinitely until another playlist sync command is sent.

I suspect this has something to do with the length of the presets vs. playlist JSON? Maybe something to do with packetSize in

void handleNotifications()
{
    ...
    // API over UDP
    udpIn[packetSize] = '\0';
    ...

in udp.cpp?

Here is a typical single-segment preset JSON (I probably could get rid of the unused {"stop":0} segment objects, but this has sometimes caused problems):

{"n":"SingleSegPreset","on":true,"bri":255,"transition":7,"mainseg":0,"seg":[{"id":0,"start":0,"stop":600,"grp":1,"spc":0,"of":0,"on":true,"frz":false,"bri":250,"cct":127,"col":[[255,0,255],[0,0,0],[0,0,0]],"fx":49,"sx":210,"ix":30,"pal":47,"sel":true,"rev":false,"mi":false},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0}]}

… a two-segment preset JSON:

{"n":"TwoSegPreset","on":true,"bri":255,"transition":7,"mainseg":0,"seg":[{"id":0,"start":0,"stop":300,"grp":1,"spc":0,"of":0,"on":true,"frz":false,"bri":250,"cct":127,"col":[[255,0,255],[0,0,0],[0,0,0]],"fx":4,"sx":150,"ix":20,"pal":2,"sel":true,"rev":false,"mi":false},{"id":1,"start":300,"stop":600,"grp":1,"spc":0,"of":0,"on":true,"frz":false,"bri":250,"cct":127,"col":[[8,255,0],[0,0,0],[0,0,0]],"fx":4,"sx":6,"ix":55,"pal":2,"sel":true,"rev":true,"mi":false},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0}]}

… and here is a typical playlist JSON:

{"playlist":{"ps":[5,6,7,8],"dur":[200,100,100,100],"transition":[7,7,7,7],"repeat":0,"r":true},"on":true,"n":"Playlist0"}"

Any ideas?

Sorry guys,

Actually sync’ing individual presets works… this is how I achieved this already! It must have slipped my mind as I did it quite some time ago… I’m re-inventing the wheel and I just have to figure out what I’ve messed up in this new implementation…

Regards,
Gbd

I think I’ve identified the issue. But since I haven’t yet fully analyzed the pertinent WLED internals, I’ll leave the final say to the maestros.

When a preset change is due to UI, or API over HTTP, or API over serial communication, callMode == CALL_MODE_DIRECT_CHANGE (notifyDirect == true). This call mode works OK with multi-segment UDP sync notification; and that’s why the sound-reactive setup (which employed WLED JSON API over serial communications) worked without issues in the multi-segment UDP sync mode configuration (for multi-panel control).

However, the current project I’m working on involves manual selection of multi-segment presets via IR remote to a WLED “master” in UDP sync mode. Apparently, when preset change is due to IR or button press, callMode == CALL_MODE_BUTTON_PRESET (notifyButton == true). I see this call mode does not (yet) work well with multi-segment UDP sync notification; from ir.cpp – and note the comment JSON object (TODO: currently will not handle irApplyToAllSelected correctly):

void decodeIRJson(uint32_t code) 
{
  ...
  cmdStr = fdo["cmd"].as<String>();
  jsonCmdObj = fdo["cmd"]; //object
  if (jsonCmdObj.isNull())  // we could also use: fdo["cmd"].is<String>()
  {
    ...
  } else {
    // command is JSON object (TODO: currently will not handle irApplyToAllSelected correctly)
    if (jsonCmdObj[F("psave")].isNull()) {
      deserializeState(jsonCmdObj, CALL_MODE_BUTTON_PRESET);
    } 
  }
}

Nevertheless, selecting playlists via IR (or button press) works w/o issues; Is this because playlist selection results in an internal automation which sets callMode == CALL_MODE_DIRECT_CHANGE (rather than callMode == CALL_MODE_BUTTON_PRESS) for each of the playlist’s preset notifications?

One more thing:

It seems that with UDP sync, it’s best not to omit the {"stop":0} segment objects when sending preset JSON API. While omitting these objects – in the interests of more compact data transfers – may not cause problems when remotely updating the state of a “stand-alone” WLED instance, it seems to cause strange issues in UDP (multi-segment) sync setups.

Thanks for posting this info. @gbd - I’m wondering if you have any pointers for me on firing UDP packets at WLED to control individual segments. I can control basic stuff like brightness and FX, but it only seems to apply whatever the selected segments are, rather than being assignable through the UDP packets. I think I’m just sending the wrong packet structure. Thanks for any tips.

@beatKeeper Do you mean explicitly packing WLED multi-segment preset JSON into a UDP message from a custom/stand-alone program (just like udp.cpp::notify() does), and then sending this to a WLED instance?

Would it be heresy to simply replace CALL_MODE_BUTTON_PRESS with CALL_MODE_DIRECT_CHANGE? As in:

void decodeIRJson(uint32_t code) 
{
  ...
  cmdStr = fdo["cmd"].as<String>();
  jsonCmdObj = fdo["cmd"]; //object
  if (jsonCmdObj.isNull())  // we could also use: fdo["cmd"].is<String>()
  {
    ...
  } else {
    // command is JSON object (TODO: currently will not handle irApplyToAllSelected correctly)
    if (jsonCmdObj[F("psave")].isNull()) {
      deserializeState(jsonCmdObj, CALL_MODE_DIRECT_CHANGE); // formerly CALL_MODE_BUTTON_PRESS
    } 
  }
}

This naïve hack seems to allow multi-segment preset JSON sent from IR “context” to work as anticipated – but I’m probably breaking some design principle in the overall WLED architecture.

I probably should be banned from this forum! The issue actually lied in my cfg.json settings –
I was directly editing the file (rather than using the browser’s Sync Interface), and it turns out that I had overlooked the "btn":true requirement for the sender! None of the naïve hackery I proposed in the previous posts was necessary at all! Don’t do it! It’s heresy!

Bottom line… multi-segment UDP sync works like a CHAMP with v0.13.1 … just get your Sync Interface settings right! Here are mine:

  • Sender cfg.json settings

    "if":{
      "sync":{
        "port0":21324,"port1":65506,
        ...
       "send":{
         "dir":true,"btn":true,"va":false,"hue":true,"macro":false,"twice":true,"grp":1
       }
     },
    

    … you may ignore the Philips Hue setting…

  • Receiver cfg.json setings

    "if":{
      "sync":{
        "port0":21324,"port1":65506,
        "recv":{
          "bri":true,"col":true,"fx":true,"grp":1,"seg":true,"sb":true
        },
        ...
      },
    
  • For illustration, the combined web interface settings for receiver (red) and sender (green)

I’m currently running “stress” tests, but I think this issue should be closed…

1 Like

Basically, yes. I’m using a Python script to fire UDP packets at a WLED instance. Until I figure out what I’m doing, I’m putting this at the byte level, manually creating the data payload to make sure I know what I’m changing. So in that sense I’m pretending that I’m another instance of WLED notifying the strip that I’ve changed.

This is working pretty well so far, but I can’t control the segments individually without changing the selected segment in the UI or JSON API. I’m clearly missing some piece of the puzzle. I’m using Wireshark to examine the notifier packets WLED is sending out in response to my packets and they’re 44 bytes long - largely matching up with the udp.cpp code on GitHub. But something is off in my settings or I’m just fuzzy on the bytes I should be sending to tell the instance to do different things with it’s different segments.

Really appreciate your time and thoughts!

@beatKeeper What version of WLED are you using? Multi-segment UDP sync support was introduced in 0.13. However, you should be using at least v0.13.1 (since v0.13.0 is not recommended – has a “critical” bug w/ presets creation)…

@gbd 0.13.1 - thanks

@gbd - Just want to be clear. I can make this work firing JSON at the WLED - controlling individual segements. Just trying to figure out how to get the same result through a UDP packet so it’s faster.

@beatKeeper, Yes sir. That’s what I understood. The UDP sync mechanism is quite intricate. Let’s see if we can hack it … or, hopefully, someone with a greater understanding will chime in.

@beatKeeper, It’s probably better to move your issue to a separate thread – something like “Multi-segment UDP Sync via stand-alone program”. I would like to rename this thread “Multi-segment UDP sync via IR” and mark it as solved. What you think?

@gbd - Nice. I’ll be hammering on the packets trying to dissect what’s happening. If I get a breakthrough I’ll pass it along.

@gbd - yeah - I’ll post as a separate thread. Your issue was the closest I could find to what I’m after. Thanks!

@beatKeeper, you opened an issue already? We could continue the discussion…

Just got it posted: