/* PHASE//VOID - Loxone Program16 source, version 1. This is custom Program block source, NOT a factory/native PHASE//VOID block. Paste into a Program16 object in Loxone Config. Real Loxone Config / Miniserver acceptance (including the Etxt error output and Virtual Output edge behavior) is required before commissioning. Native C stub tests are not PicoC acceptance. Official API reference: https://updatefiles.loxone.com/KnowledgeBase/Online/Common/Documents/CustomScriptProgramming.pdf getinput / setoutput use ZERO-BASED indices; sleep takes MILLISECONDS. This top-level loop follows the official PicoC program example, without main(). Inputs (analogue inputs of Program16): I1 Mode: exactly 0 = stop, 1 = ambient, 2 = party, 3 = techno; invalid = 0. I2 Brightness: 0..100, clamped and rounded to a whole percent; NaN = 0. I3 Blackout: >0.5 is true. I4 Freeze: >0.5 is true. I5 Enabled: >0.5 is true; deliberate user enable, not an auto-start signal. I6 Ready: LAN status ONLINE AND ARMED; >0.5 is true. I7 Stop: >0.5 is true; only the rising edge requests stop. I8..I16 unused. Outputs (connect to bridge Virtual Output commands; no network in this block): O1 Ambient, O2 Party, O3 Techno: 100 ms pulses, ON command only, no OFF action. O4 Brightness: analogue whole percent, transmit on change. O5 Blackout, O6 Freeze: level; configure BOTH ON=true and OFF=false commands. O7 Stop: 100 ms pulse, ON command only, no OFF action. O8 RequestedMode: normalized current I1 for UI ONLY, not acknowledged/live state. O9..O16 unused. Never connect O8 to a command. Obtain actual state from status. Boot initializes O1..O7 to zero and samples inputs without issuing a command. Configure Virtual Outputs so initialization cannot start a show. Ready rising alone, or input changes in the same poll as Ready rising, do not send commands. Changes while disabled/not ready are consumed, never queued or replayed. A deliberate Enabled rising edge MAY request the current mode, only if Ready. Brightness/Blackout/Freeze then need a fresh input change on a later ready poll. Stop rising or Enabled falling wins over EVERY other action in that poll, even when not ready (best effort stop). Held Stop does not repeatedly issue commands. Mode 0 stops once on selection; reselect the same mode via 0 to request it again. Accepted brightness/blackout/freeze levels persist through stop/disconnection; use fresh changes to set them again. Virtual Outputs must not replay commands on reconnection. The LAN bridge must also reject commands while not armed. */ int initialized = 0; int mode = 0; int brightness = 0; int blackout = 0; int freeze = 0; int enabled = 0; int ready = 0; int stop = 0; int previousMode = 0; int previousBrightness = 0; int previousBlackout = 0; int previousFreeze = 0; int previousEnabled = 0; int previousReady = 0; int previousStop = 0; int requestMode = 0; float modeInput = 0; float brightnessInput = 0; setoutput(0, 0); setoutput(1, 0); setoutput(2, 0); setoutput(3, 0); setoutput(4, 0); setoutput(5, 0); setoutput(6, 0); setoutput(7, 0); while (1) { modeInput = getinput(0); mode = 0; if (modeInput == 1) mode = 1; if (modeInput == 2) mode = 2; if (modeInput == 3) mode = 3; brightnessInput = getinput(1); if (brightnessInput != brightnessInput) brightnessInput = 0; if (brightnessInput < 0) brightnessInput = 0; if (brightnessInput > 100) brightnessInput = 100; brightness = (int)(brightnessInput + 0.5); blackout = getinput(2) > 0.5; freeze = getinput(3) > 0.5; enabled = getinput(4) > 0.5; ready = getinput(5) > 0.5; stop = getinput(6) > 0.5; /* Reset one-poll pulses; level outputs change only after accepted actions. */ setoutput(0, 0); setoutput(1, 0); setoutput(2, 0); setoutput(6, 0); setoutput(7, mode); requestMode = 0; if (initialized) { if ((stop && !previousStop) || (!enabled && previousEnabled)) { setoutput(6, 1); } else if (enabled && ready) { if (!previousEnabled) { requestMode = 1; } else if (previousReady) { if (mode != previousMode) requestMode = 1; if (brightness != previousBrightness) setoutput(3, brightness); if (blackout != previousBlackout) setoutput(4, blackout); if (freeze != previousFreeze) setoutput(5, freeze); } if (requestMode) { if (mode == 0) setoutput(6, 1); if (mode == 1) setoutput(0, 1); if (mode == 2) setoutput(1, 1); if (mode == 3) setoutput(2, 1); } } } /* Always consume inputs, including blocked changes and priority losers. */ previousMode = mode; previousBrightness = brightness; previousBlackout = blackout; previousFreeze = freeze; previousEnabled = enabled; previousReady = ready; previousStop = stop; initialized = 1; sleep(100); }