local tv = get_trigger_variable(1) if tv == nil then return end local lux = tv.integer if lux == nil then return end if lux < 0 then lux = 0 end if lux > 200000 then lux = 200000 end lux_value = lux if lux_link_on == nil then lux_link_on = true end if not lux_link_on then return end if lux_poll_s == nil then lux_poll_s = 1 end local okt, now = pcall(function() return os.time() end) if okt and now ~= nil then if lux_last_adj ~= nil and now - lux_last_adj < lux_poll_s then return end lux_last_adj = now else lux_tick = (lux_tick or 0) + 1 if lux_tick % lux_poll_s ~= 0 then return end end if lux_fade == nil then lux_fade = 1.0 end if lux_deadband == nil then lux_deadband = 1 end if lux_target == nil then lux_target = 500 end local TARGET_LUX = lux_target local DEADBAND = lux_deadband local MIN_LEVEL = 0.05 local MAX_LEVEL = 1.0 local STEP_MAX = 0.20 local K_DEFAULT = 3000 local ok, grp = pcall(get_group, 0) if not ok or grp == nil then ok, grp = pcall(get_group, 'All Fixtures') end if not ok or grp == nil then return end local err = TARGET_LUX - lux if lux_prev_cmd ~= nil and lux_prev_cur ~= nil and lux_prev_lux ~= nil and lux_prev_band ~= nil then local dl = lux_prev_cmd - lux_prev_cur local clamped = (lux_prev_cmd <= MIN_LEVEL + 0.001) or (lux_prev_cmd >= MAX_LEVEL - 0.001) if math.abs(dl) > 0.005 and not clamped then local ki = (lux - lux_prev_lux) / dl if ki > 100 and ki < 10000 and math.abs(lux - lux_prev_lux) >= 3 then lux_kb = lux_kb or {} local kb = lux_kb[lux_prev_band] if kb == nil then lux_kb[lux_prev_band] = ki elseif ki > kb then lux_kb[lux_prev_band] = 0.5 * kb + 0.5 * ki else lux_kb[lux_prev_band] = 0.9 * kb + 0.1 * ki end end end lux_prev_cmd = nil end if err >= -DEADBAND and err <= DEADBAND then lux_last_err = err return end local lv = grp.master_intensity_level local hw if lv ~= nil and lv.range ~= nil and lv.range > 0 then hw = lv.integer / lv.range end local cur = lux_cur_level if cur == nil or (hw ~= nil and math.abs(hw - cur) > 0.05) then cur = hw or 0.5 end local band = math.floor(cur * 4.999) + 1 local k = (lux_kb ~= nil and lux_kb[band]) or K_DEFAULT lux_agg = lux_agg or 0.7 local delta if lux_last_err ~= nil and (err > 0) ~= (lux_last_err > 0) then lux_agg = lux_agg * 0.5 if math.abs(err) > 3 and lux_kb ~= nil and lux_prev_band ~= nil and lux_kb[lux_prev_band] ~= nil then lux_kb[lux_prev_band] = math.min(lux_kb[lux_prev_band] * 1.3, 10000) end else lux_agg = math.min(lux_agg * 1.15, 0.9) end delta = err / k * lux_agg if math.abs(err) < 30 then delta = delta * 0.5 end lux_last_err = err if delta > STEP_MAX then delta = STEP_MAX end if delta < -STEP_MAX then delta = -STEP_MAX end local new = cur + delta if new < MIN_LEVEL then new = MIN_LEVEL end if new > MAX_LEVEL then new = MAX_LEVEL end lux_prev_cur = cur lux_prev_cmd = new lux_prev_lux = lux lux_prev_band = band lux_cur_level = new grp:set_master_intensity(new, lux_fade)