I think every computer language (well, most) has a random function, which usually returns a random-ish number between 0 and 1 as an inclusive interval.
To get this to a random number between say 0 and 255, we usually multiply by 255. However, this will generate a number that randomly spans between 0 and 255 exactly. Turning this into an integer becomes a problem, since we can round or floor or ceiling. Floor will return anything between 0 and 0.9999999 as 0. Anything between 1.0 and 1.9999999 as 1. OK so far.
The problem is 255, since the original random number goes from 0 to 1 inclusive, we end up with 255 as a (slim) possibility, but this will only be 255 when the base random function returns 1, hence 0 is generated from 0 … <1, and 1 from 1 … <2 and so on, but 255 occurs only for the miniscule span of 255 exactly. In practical terms, 255 will never occur. Hence we probably should multiply by 256 and trap 256, if it ever occurs, and throw it away (since 256 would be an error in this case) or multiply by 255.9999999999999999999999 and floor. Computers are crap at floating point computation, so this is unlikely to generate the correct interval.
You are entirely correct that floor is a better option than round, since round moves 0-0.5 to 0, and 0.5-1.5 to 1, which means integer 0 is half-represented. At the top end though integer 255 results from 254.5-255, which means that 1…254 is correctly represented by a full span, but 0, and 255 only get half a span each. The balance comes from 0 being half a span and 255 being half a span rather than almost no span at all. In practical terms I was lazy and opted for round as I would get 0 half as much as I should but 255 more often that it would be otherwise.
I think that all random number generators should have an option to return in the interval 0-0.999999999999999999 and not 0 to 1. My other approach is to generate 0-1 and throw the 1 away, or fold it back into the interval… which requires another random number to randomly fold ‘1’ back into the interval 0 … <1. Tough.
I am getting more experienced with coding and, on a good day, I refactor as I go along. Writing JSONata functions is easier than it may appear. Again the trick is to open a code block, which permits multiple statement lines as well as practical use of variables. Functions are defined and allocated to a ‘variable’ and can be called as required.
JSONata functions are closures, and it is possible to pass a function as a parameter to a function, as well as to call functions recursively. At that point I have to write it all out long-hand, and refactor one step at a time.
Anyway, hopefully this gives the OP some options!
Edit:
I checked the JSONata docs, and apparently the random is 0 <= n < 1 so excludes 1 (which does make it not a true random number but does make using it easier). So yes you are correct - should be
(
$rp:=function(){$floor($random()*256)};
$randcolor:=[$rp(), $rp(), $rp()];
{"rgb_color": $randcolor, "brightness": 100}
)
Edit 2:
Not using the Lodash functions myself, I had missed Kermit’s $randomNumber, which of course solves the problem very neatly and entirely [see below]
This function can only be used inside one of the HA WebSocket nodes, but with a bit of refactoring, the following code works as a single statement line.
{"rgb_color": [1..3].$randomNumber(0,255), "brightness": 100}