Options to pass exported variables to the PB

My latest lighting project which is Electronic Minora
(just in case, here is a latest PB code):

// Variables for External Control
export var nCandles   = 3

// Internal Constants
var matriWwidth       = 32
var matrixHeight      = 8

var candlesMaxNumber  = 8

// Pre-defined Candle Base Width
var candleBaseWidth =
[
  [3, 0, 0, 0, 0, 0, 0, 0],
  [3, 3, 0, 0, 0, 0, 0, 0],
  [3, 3, 3, 0, 0, 0, 0, 0],
  [3, 3, 3, 3, 0, 0, 0, 0],
  [3, 3, 3, 3, 3, 0, 0, 0],
  [3, 3, 3, 3, 3, 3, 0, 0],
  [3, 3, 3, 3, 3, 3, 3, 0],
  [3, 3, 3, 3, 3, 3, 3, 3]
]

// Pre-defined Candle Base Height
var candleBaseHeight =
[
  [3, 0, 0, 0, 0, 0, 0, 0],
  [3, 3, 0, 0, 0, 0, 0, 0],
  [2, 3, 2, 0, 0, 0, 0, 0],
  [2, 3, 3, 2, 0, 0, 0, 0],
  [2, 3, 4, 3, 2, 0, 0, 0],
  [1, 2, 3, 3, 2, 1, 0, 0],
  [1, 2, 3, 4, 3, 2, 1, 0],
  [1, 2, 3, 4, 4, 3, 2, 1]
]

// Pre-defined Candle Flame Offset
// -1 : Candle Flame is narrowed by 2 vs Candle Base
//  0 : Candle Flame is equal to Candle Bas
// +1 : Candle Flame is widened by 2 vs Candle Base
var candleFlameOffset =
[
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 0, 0, 0]
]

// Pre-defined Candle Flame Height
// -x increases Candle Flame
// +x reduces Candle Flame
var candleFireHeight =
[
  [-0.1,    0,    0,    0,    0,    0,    0,    0],
  [-0.1, -0.1,    0,    0,    0,    0,    0,    0],
  [ 0.1, -0.1,  0.1,    0,    0,    0,    0,    0],
  [ 0.1, -0.1, -0.1,  0.1,    0,    0,    0,    0],
  [ 0.2,  0.1, -0.1,  0.1,  0.2,    0,    0,    0],
  [ 0.4,  0.2, -0.1, -0.1,  0.2,  0.4,    0,    0],
  [ 0.5,  0.4,  0.2, -0.1,  0.2,  0.4,  0.5,    0],
  [ 0.6,  0.4,  0.2, -0.1, -0.1,  0.2,  0.4,  0.6]
]

// Predefined Candle's Offsets
// Defines a location for the First Base Pixel
var candleOffset =
[
  // X - Candle Offset per Candle
  // Y - Candle Numbers
  [15,  0,  0,  0,  0,  0,  0,  0],
  [ 9, 20,  0,  0,  0,  0,  0,  0],
  [ 6, 15, 24,  0,  0,  0,  0,  0],
  [ 4, 11, 18, 25,  0,  0,  0,  0],
  [ 3,  9, 15, 21, 27,  0,  0,  0],
  [ 2,  7, 12, 17, 22, 27,  0,  0],
  [ 1,  5, 10, 14, 19, 23, 28,  0],
  [ 0,  4,  8, 12, 16, 20, 24, 28]
]

// Candle's Base Brightness and Color
var vBase = 0.08
var hBase = 0.65
var sBase = 0.1

// Candle's Fire Brightness and Color
var vFire = 1
var hFire = 0.05
var sFire = 1

// Calculated Parameters
var t1    = 0;

export function beforeRender(delta)
{
  // Build a timer using accumulated milliseconds
  // Denominator controls speed of noise field traversal (flicker speed)
  // The % 256 is used to keep values in a reasonable range for
  // input to noise function.
  t1 = (t1 + delta/2000) % 256;
}

export function render2D(index, x, y)
{
  X = floor(x * matriWwidth)
  Y = floor(y * matrixHeight)

  candleNumber = floor(X / (matriWwidth / nCandles))

  candleStartX = candleOffset[nCandles - 1][candleNumber]
  
  if (Y >= (matrixHeight - candleBaseHeight[nCandles - 1][candleNumber]))
  {
    candleStartX = candleOffset[nCandles - 1][candleNumber]
    candleStopX  = (candleStartX + candleBaseWidth[nCandles - 1][candleNumber])
  }
  else
  {
    candleStartX = candleOffset[nCandles - 1][candleNumber] - candleFlameOffset[nCandles - 1][candleNumber]
    candleStopX  = (candleStartX + candleBaseWidth[nCandles - 1][candleNumber]) + (2 * candleFlameOffset[nCandles - 1][candleNumber])
  }

  if  ((X >= candleStartX) && (X < candleStopX))
  {
    if (Y >= (matrixHeight - candleBaseHeight[nCandles - 1][candleNumber]))
    {
      v = vBase
      h = hBase
      s = sBase
    }
    else
    {
      // generate positive perlin noise value for current coordinates, offset by timer
      // this will be used both for pixel brightness and to determine the maximum
      // height of the current candle ()
      v = abs(perlin(Y+t1, X-t1, 0.5, PI))

      // if pixel is above max flame height, turn it off.  Otherwise
      // set it to perlin noise value.
      v = (y >= (vFire * v) + candleFireHeight[nCandles - 1][candleNumber]) ? v : 0;
      h = hFire
      s = sFire
    }
  }
  else
  {
    v = 0
  }

  hsv(h, s, v)
}

got a lot of attention from our friends with a request to build one for them.
All my PB projects are designed to be controlled by Hubitat Elevation home automation controller with excellent driver designed by @zranger1
The problem is - nobody of our friends have anything like this.
I did search forum and net for the options how to control a PBs remotely but so far did not find any reasonably simple simple solutions. (Yes, I can use something to toggle PBs GPIO pins but this required extra hardware).
My question is - is it possible to create something in the Web Browser (http post?) for updating exported PB variables?
For this Minore project all what I need is an ability to update nCandles exported variable and turn On/Off the entire thing (set built-in brightness variable to 0/1).
I am sure, it is possible to write a relatively simple Android (and/or Apple) app to send these commands to PB but is well beyond my capabilities.
Any ideas are very welcome.

PS. Installing any extra SW such as Python, etc. unfortunately not an option.

That’s what ui controls are for. It’s a few lines, a handler function that takes the data. pB creates the interface for these automatically by detecting exported functions with certain magic prefix naming.

OK, I understand how to format a message for the PB. In my case this should be something like this:

{"setVars":{"nCandles":A, "brightness":B}}

where A and B the desired values.

But my question is:
How do I send this to the PB from plane web browsers such as Chrome and/or Safari without installing anything else?
Is this possible?
If “yes” could you please provide an example?
I did search everything what I could but unfortunately did not find any simple answer.

You could do this via the fetch API, for example:

My point is that Pixelblaze already has a fairly good interface to control patterns and settings. I’m curious in which ways the PB interface wouldn’t accomplish what you are looking for for your friends?

I personally, do not have any problems how to control PB(s). Any PB Pattern which requires some external controls has number of exported variables. However all main automations are driven by HE (Hubitat Elevation) and BIG Thanks to the @zranger1 excellent driver for the HE the HE-PB integration is very easy going. But this is my case.
My friends, who expressed big interest on few my PB based lighting projects (Fireplace/Waterfall, Fire Torch and this recent Electronic Minora) do not have anything other than Android/Apple phones and/or tablets. And they do not want to install any sort of extra sw except maybe for the very specific app which does not exist. That is a reason why I am locking for a simplest as possible solution how to control a PB(s) just by plain web browser. I can add some logic to the PB patterns in order to create very minor automations but this will be very limited controls. Something like a Push Button connected to the GPIO could provide very minor external control(s) but ideally some sort of very simple script for the browser is more preferable. But unfortunately my sw skills are very limited. Maybe everything is already in place and I simply not understanding how to use things.

UPDATE

After thinking about how to solve this little problem I decided to add a Push Button to the GPIO pin. This way a PB will not depend on anything external. Every button push will simply cycle nCandles variable through 0 to 8 and value of 0 will turn it Off.

UPDATE-2

Just in case here is a Push Button processing PB code (debugged and tested):

// Push Button Input Pin
var PB_IN_PIN = 26
pinMode(PB_IN_PIN, INPUT_PULLUP)
var digitalIn

var pushBtnCounter    = 0
var pushBtnCounterMax = 8

var debounceDone      = 0
var debounceTimer     = 0
// Set Debounsing Timeout in mS
var debounceTimeout   = 100

// Push Button Debouncing and Processing
// For each Button Push 
// Variable "pushBtnCounter" cycles though
// 0 to "pushBtnCounterMax" values
function PushButton(delta)
{
  digitalIn = digitalRead(PB_IN_PIN)

  if (0 == digitalIn)
  {
    if (0 == debounceDone)
    {
      debounceTimer += delta
  
      if (debounceTimer >= debounceTimeout)
      {
        debounceTimer = 0
        debounceDone  = 1

        if (pushBtnCounter < pushBtnCounterMax)
        {
          pushBtnCounter++
        }
        else
        {
          pushBtnCounter = 0
        }
      }
    }
  }
  else
  {
    debounceTimer = 0
    debounceDone  = 0
  }
}

export function beforeRender(delta)
{
  PushButton(delta)

  t1 = time(.1)
}

export function render(index) {
  h = t1 + index/pixelCount
  s = 1
  
  if (0 == pushBtnCounter)
  {
    v = 0
  }
  else
  {
    v = 1
  }
  
  hsv(h, s, v)
}

This version simply debounces Push Button input and cycles variable “pushBtnCounter” between 0 and “pushBtnCounterMax” variable.

1 Like

I’m glad you have something working for you, but I’m still a bit confused as to why the built-in Pixelblaze app isn’t suitable given you wanted a remote, web based, user interface with no external dependencies or apps to install which works on Android and Apple phones.

And with UI controls, its easy to add number inputs, buttons, toggles, and sliders to a pattern to allow customization later with a few clicks/taps.

Are you talking about pointing browser to the PB IP or am I missing something very important?

Yes, I (or whoever else) can point any web browser to the PB IP (actually need to know what it is) and open a PB Web UI (BTW, very nice Web UI)
But now one will need to navigate to the Active Pattern, open it in the Editor and sure, can change any variable or whatever else (may or may not to save changes). This could be OK for myself but absolutely is NO GO for the Grandma persons.
Is this a case we are discussing or am I missing something extremely important for the case(s) like this?

Seems like a good ‘easy for the end user to use’ solution for the use case to toggle the pattern configuration.

you could use 8 patterns and just switch between them using the on-board button on GP0 whatever it is to switch between them, (saves the extra button maybe) but you end up making the config across duplicate patterns.

The real problem is the user support. i get it. just set them up as their own network (AP MODE) then if you are in line of site you can find it connect and do something. otherwise, the “USER” gets plug this in to the wall and here, and use this button to change patterns… (and hopefully thats all it ever is…) otherwise the basic networking, is a support incident. … in this case they might get two buttons if its this pattern then this other button does something… pretty cool.

just not a use case for the PB… it is but the networking aspects kill it for mortals…

I keep thinking i have use case for bypassing the network interface. I know i can for example write a client to send messages to the PB to configure a pattern. (say display a scrolling message or configure a specific pattern to run or configure variables exported in a pattern this is great) and would love to do it all without the network. alternative i have considered is just using something like the expander connected to a MCU but that makes the end result (pixel matrix) much more USE specific than i would like. (i always like to build some specific function but then still use the base and community patterns as they work)

Specific use case for example, select which pattern to run without a network.
as is: This could be done by using 1 pattern with a variable input that does for example 8 different things. much like in vitaliy’s minora example.

But to be able to have an interface to the PB would be what is desired.
This i would envision is passing something in via TX/RX pins.

Specifically, i have a vision to use a MCU to control a Pixelblaze. Most specifically the MCU (leonardo) built into the LattePanda boards. i want to control the PB directly from that MCU without a network. This is possible via network and sockets but trying to figure out how to get two devices doing it vs network interface. the intent is to be able to push a specific pattern active from the MCU, much like you can do with a network socket interface.

but best workaround i am considering now is some kind of input from a pin to determine what a single pattern does. seems like the best current approach and would love to learn or consider anything new.