added custom overrides, motion-sensors and more...

This commit is contained in:
Rainer 2026-02-12 12:30:39 +01:00
parent 53466eed17
commit ff423fc029
11 changed files with 348 additions and 26 deletions

View file

@ -65,19 +65,16 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local pos_str = formname:sub(21)
local pos = minetest.string_to_pos(pos_str)
if not pos then return end
if fields.save_switch then
local area, chan = fields.area_sel, fields.chan_sel
if area == "-- Bitte wählen --" or chan == "-- Bitte wählen --" then
minetest.chat_send_player(name, "FEHLER: Bitte Area UND Kanal auswählen!")
return
end
local meta = minetest.get_meta(pos)
meta:set_string("sl_area", area)
meta:set_string("sl_chan", chan)
meta:set_string("infotext", "Schalter: " .. area .. ":" .. chan)
if smart_light.registry.areas[area] and smart_light.registry.areas[area].channels[chan] then
smart_light.registry.areas[area].channels[chan].switches = smart_light.registry.areas[area].channels[chan].switches or {}
smart_light.registry.areas[area].channels[chan].switches[pos_str] = true
@ -88,13 +85,48 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
return
end
if fields.area_sel and fields.area_sel ~= "-- Bitte wählen --" then
minetest.get_meta(pos):set_string("sl_area", fields.area_sel)
minetest.registered_tools["smart_light:programmer"].on_place(player:get_wielded_item(), player, {type="node", under=pos})
end
end
-- --- NEU: BEWEGUNGSMELDER PROGRAMMIERER (Kanal-Zuweisung) ---
if formname:sub(1, 20) == "smart_light:prog_ms_" then
local pos_str = formname:sub(21)
local pos = minetest.string_to_pos(pos_str)
if not pos then return end
if fields.save_ms then
local area, chan = fields.area_sel, fields.chan_sel
if area == "-- Bitte wählen --" or chan == "-- Bitte wählen --" then
minetest.chat_send_player(name, "FEHLER: Bitte Area UND Kanal auswählen!")
return
end
local meta = minetest.get_meta(pos)
meta:set_string("sl_area", area)
meta:set_string("sl_chan", chan)
meta:set_string("infotext", "Bewegungsmelder: " .. area .. ":" .. chan)
minetest.get_node_timer(pos):start(1.5) -- Timer starten
minetest.chat_send_player(name, "Bewegungsmelder verknüpft!")
return
end
if fields.area_sel and fields.area_sel ~= "-- Bitte wählen --" then
minetest.get_meta(pos):set_string("sl_area", fields.area_sel)
minetest.registered_tools["smart_light:programmer"].on_place(player:get_wielded_item(), player, {type="node", under=pos})
end
end
-- --- NEU: BEWEGUNGSMELDER WERTE (Radius/Dauer) ---
if formname:sub(1, 19) == "smart_light:sensor_" then
if fields.save_sensor then
local pos = minetest.string_to_pos(formname:sub(20))
local meta = minetest.get_meta(pos)
meta:set_int("range", tonumber(fields.range) or 8)
meta:set_int("duration", tonumber(fields.duration) or 30)
minetest.chat_send_player(name, "Sensor-Parameter gespeichert.")
end
end
-- --- LICHT PROGRAMMIERER ---
if formname:sub(1, 17) == "smart_light:prog_" and formname:sub(1, 20) ~= "smart_light:prog_sw_" then
if fields.save then
@ -102,17 +134,14 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local pos = minetest.string_to_pos(pos_str)
local area, chan = fields.area_sel, fields.chan_in
if not area or area == "-- Bitte wählen --" or chan == "" then return end
minetest.get_meta(pos):set_string("sl_area", area)
minetest.get_meta(pos):set_string("sl_chan", chan)
local item = player:get_wielded_item()
local t_meta = item:get_meta()
t_meta:set_string("last_area", area)
t_meta:set_string("last_channel", chan)
t_meta:set_string("description", "Programmer Area: " .. area .. "\nChannel: " .. chan)
player:set_wielded_item(item)
smart_light.registry.areas[area] = smart_light.registry.areas[area] or { channels = {} }
smart_light.registry.areas[area].channels[chan] = smart_light.registry.areas[area].channels[chan] or { nodes = {}, last_level = "max", brightness = "max" }
smart_light.registry.areas[area].channels[chan].nodes[pos_str] = true
@ -126,7 +155,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local pos_str = formname:sub(18)
local pos = minetest.string_to_pos(pos_str)
local area = minetest.get_meta(pos):get_string("area_id")
if fields.all_off then
for c,_ in pairs(smart_light.registry.areas[area].channels) do smart_light.switch_channel(area, c, "off") end
minetest.registered_nodes["smart_light:controller"].on_rightclick(pos, nil, player)
@ -140,7 +168,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local count = smart_light.get_count(area, cid)
local status = smart_light.get_status_text(area, cid)
local last_lvl = smart_light.registry.areas[area].channels[cid].last_level or "max"
local subfs = "size[4,5.5]label[0.5,0.2;Channel: " .. cid .. "]" ..
"label[0.5,0.7;Anzahl Leuchten: " .. count .. "]" ..
"label[0.5,1.2;Status: " .. status .. "]" ..
@ -164,7 +191,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local meta = minetest.get_meta(pos)
local area = meta:get_string("area_id")
if area == "" then area = meta:get_string("sl_area") end
for k, _ in pairs(fields) do
local cid, action = k:match("^sub_(.+)_([%a%d]+)$")
if cid and action then
@ -172,7 +198,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local count = smart_light.get_count(area, cid)
local status = smart_light.get_status_text(area, cid)
local last_lvl = smart_light.registry.areas[area].channels[cid].last_level or "max"
local subfs = "size[4,5.5]label[0.5,0.2;Channel: " .. cid .. "]" ..
"label[0.5,0.7;Anzahl Leuchten: " .. count .. "]" ..
"label[0.5,1.2;Status: " .. status .. "]" ..

View file

@ -148,4 +148,5 @@ dofile(path .. "/tools.lua")
dofile(path .. "/panel.lua")
dofile(path .. "/handlers.lua")
dofile(path .. "/switch.lua")
dofile(path .. "/motion_sensor.lua")
dofile(path .. "/overrides.lua")

View file

@ -1,6 +1,4 @@
name = smart_light
description = Steuerung und Dimmen von Lichtern via Shadow-Nodes.
depends = default
optional_depends = areas, myschool, morelights_modern, morelights_vintage
author = Rage87
version = 1005
optional_depends = areas, ethereal, morelights_modern, morelights_vintage, myschool, mystreets, xnether

123
motion_sensor.lua Normal file
View file

@ -0,0 +1,123 @@
local sensor_box = { type = "fixed", fixed = { { -6/32, -6/32, 14/32, 6/32, 6/32, 16/32} } }
minetest.register_node("smart_light:motion_sensor", {
description = "Smart Light Bewegungsmelder",
tiles = {
"smart_light_case.png", "smart_light_case.png",
"smart_light_case.png", "smart_light_case.png",
"smart_light_case.png", "smart_light_case.png^smart_light_sensor_front.png",
},
drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir",
sunlight_propagates = true, groups = {cracky=2, crumbly=2},
node_box = sensor_box,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_int("range", 8)
meta:set_int("duration", 30)
meta:set_string("infotext", "Bewegungsmelder (nicht konfiguriert)")
end,
on_punch = function(pos, node, puncher)
if not puncher:get_player_control().sneak then return end
local meta = minetest.get_meta(pos)
local area = meta:get_string("sl_area")
local chan = meta:get_string("sl_chan")
if area == "" or chan == "" then
minetest.chat_send_player(puncher:get_player_name(), "Bitte zuerst mit dem Programmer verknüpfen!")
return
end
local range = meta:get_int("range")
local duration = meta:get_int("duration")
local fs = "size[5,5]label[0.5,0.2;Sensor Setup: " .. area .. ":" .. chan .. "]" ..
"field[0.8,1.5;4,1;range;Erfassungs-Radius (Blöcke);" .. range .. "]" ..
"field[0.8,3;4,1;duration;Leuchtdauer (Sekunden);" .. duration .. "]" ..
"button_exit[1,4.2;3,1;save_sensor;Einstellungen speichern]"
minetest.show_formspec(puncher:get_player_name(), "smart_light:sensor_" .. minetest.pos_to_string(pos), fs)
end,
on_timer = function(pos, elapsed)
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
local area_id = meta:get_string("sl_area")
local chan_id = meta:get_string("sl_chan")
if area_id == "" or chan_id == "" then return false end
-- Zugriff auf die Registry für diesen Channel
local chan_data = smart_light.registry.areas[area_id] and smart_light.registry.areas[area_id].channels[chan_id]
if not chan_data then return false end
local range = meta:get_int("range")
local duration = meta:get_int("duration")
local now = minetest.get_gametime()
-- 1. Lokale Erfassung
local found = false
local objs = minetest.get_objects_inside_radius(pos, range)
for _, obj in pairs(objs) do
if obj:is_player() then found = true break end
end
-- 2. Visuelles Feedback am Sensor (unabhängig vom Licht)
if found then
if node.name ~= "smart_light:motion_sensor_active" then
minetest.swap_node(pos, {name = "smart_light:motion_sensor_active", param2 = node.param2})
end
-- GLOBAL: Deadline in der Registry setzen/verlängern
chan_data.ms_deadline = now + duration
-- Licht einschalten, falls aus
if smart_light.get_status_text(area_id, chan_id) == "AUS" then
smart_light.switch_channel(area_id, chan_id, "on")
end
else
if node.name ~= "smart_light:motion_sensor" then
minetest.swap_node(pos, {name = "smart_light:motion_sensor", param2 = node.param2})
end
end
-- 3. Globale Licht-Logik (Prüfung durch jeden Sensor)
if smart_light.get_status_text(area_id, chan_id) == "AN" then
local deadline = chan_data.ms_deadline or 0
-- Nur wenn die globale Deadline abgelaufen ist, schalten wir aus
if now >= deadline then
smart_light.switch_channel(area_id, chan_id, "off")
end
end
return true
end,
after_dig_node = function(pos, oldnode, oldmetadata)
local area, chan = oldmetadata.fields.sl_area, oldmetadata.fields.sl_chan
if area and chan and smart_light.registry.areas[area] and smart_light.registry.areas[area].channels[chan] then
if smart_light.registry.areas[area].channels[chan].switches then
smart_light.registry.areas[area].channels[chan].switches[minetest.pos_to_string(pos)] = nil
smart_light.save()
end
end
end,
})
minetest.register_node("smart_light:motion_sensor_active", {
description = "Smart Light Bewegungsmelder (Aktiv)",
tiles = {
"smart_light_case.png", "smart_light_case.png",
"smart_light_case.png", "smart_light_case.png",
"smart_light_case.png", "smart_light_case.png^smart_light_sensor_front_active.png",
},
drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir",
groups = {cracky=2, crumbly=2, not_in_creative_inventory=1},
node_box = sensor_box,
drop = "smart_light:motion_sensor",
on_timer = minetest.registered_nodes["smart_light:motion_sensor"].on_timer,
on_punch = minetest.registered_nodes["smart_light:motion_sensor"].on_punch,
after_dig_node = minetest.registered_nodes["smart_light:motion_sensor"].after_dig_node,
})

View file

@ -1,4 +1,4 @@
-- Hier können beliebig viele Lampen registriert werden
--[[ Hier können beliebig viele Lampen registriert werden
minetest.register_on_mods_loaded(function()
smart_light.register_lamp_control("myschool:light")
smart_light.register_lamp_control("morelights_modern:walllamp")
@ -21,3 +21,65 @@ minetest.register_on_mods_loaded(function()
-- smart_light.register_lamp_control("andere_mod:lampe")
end)
--]]
-- 1. SPEZIFISCHE MUSTER (Präzise Filter)
local lamp_patterns = {
-- ["mod:specific_light"] = true, -- finds specific light
-- ["mod_pack:light.*"] = true, -- finds ex. light_normal, light_vintage, ...
-- ["mod_pack:light_."] = true, -- finds ex. light_a, light_b, ...
"default:mese_post_.*",
"ethereal:mese_post_.*",
"morelights_modern:walllamp",
"morelights_modern:ceilinglight",
"morelights_modern:block",
"morelights_modern:smallblock",
"morelights_modern:post_.", -- post_d, post_l
"morelights_modern:barlight_.", -- barlight_c, barlight_s
"morelights_modern:canlight_.", -- canlight_d, canlight_l
"morelights_modern:tablelamp_.", -- tablelamp_d, tablelamp_l
"morelights_modern:pathlight_.", -- pathlight_d, pathlight_l
"morelights_vintage:lantern_.", -- lantern_f, lantern_c, lantern_w
"morelights_vintage:hangingbulb",
"morelights_vintage:chandelier",
"myschool:light",
"mystreets:street_light",
"mystreets:street_dome_light",
"xnether:mese_post_.*",
}
-- 2. BLACKLIST
local blacklist = {
-- ["mod:specific_light"] = true, -- finds specific light
-- ["mod_pack:light.*"] = true, -- finds ex. light_normal, light_vintage, ...
-- ["mod_pack:light_."] = true, -- finds ex. light_a, light_b, ...
}
-- 3. AUTOMATISIERTE REGISTRIERUNG
minetest.register_on_mods_loaded(function()
local count = 0
-- Wir durchlaufen alle registrierten Nodes in der Engine
for node_name, _ in pairs(minetest.registered_nodes) do
-- A: Zuerst prüfen, ob der Node auf der Blacklist steht
if not blacklist[node_name] then
-- B: Dann prüfen, ob der Node zu einem der Muster passt
for _, pattern in ipairs(lamp_patterns) do
if node_name:find("^" .. pattern) then
-- C: Sicherheits-Check gegen Selbst-Registrierung
if not node_name:find("^smart_light:") then
smart_light.register_lamp_control(node_name)
count = count + 1
break -- Gefunden, nächster Node
end
end
end
end
end
minetest.log("action", "[smart_light] Automatisierung aktiv: " .. count .. " Lampen registriert.")
end)

View file

@ -7,7 +7,7 @@ minetest.register_node("smart_light:switch", {
"smart_light_case.png", "smart_light_case.png",
"smart_light_case.png", "smart_light_case.png^smart_light_button_off.png",
},
drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir",
drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir", light_source = 2,
sunlight_propagates = true, groups = {cracky=2, crumbly=2},
node_box = switch_box,
@ -61,7 +61,7 @@ minetest.register_node("smart_light:switch_active", {
"smart_light_case.png", "smart_light_case.png",
"smart_light_case.png", "smart_light_case.png^smart_light_button_on.png",
},
drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir",
drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir", light_source = 5,
sunlight_propagates = true, groups = {cracky=2, crumbly=2, not_in_creative_inventory=1},
node_box = switch_box, drop = "smart_light:switch",
on_punch = minetest.registered_nodes["smart_light:switch"].on_punch,

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

79
timer.lua.broken Normal file
View file

@ -0,0 +1,79 @@
local timer_box = { type = "fixed", fixed = {{-0.5, -0.5, 0.4, 0.5, 0.5, 0.5}} }
minetest.register_node("smart_light:timer", {
description = "Smart Light Zeitschaltuhr",
tiles = {
"smart_light_panel_sides.png", "smart_light_panel_sides.png",
"smart_light_panel_sides.png", "smart_light_panel_sides.png",
"smart_light_panel_sides.png", "smart_light_panel_front_timer.png"
},
drawtype = "nodebox", paramtype = "light", paramtype2 = "facedir",
groups = {cracky = 2, oddly_breakable_by_hand = 1},
node_box = timer_box,
on_construct = function(pos)
local meta = minetest.get_meta(pos)
meta:set_string("infotext", "Zeitschaltuhr (nicht konfiguriert)")
end,
on_rightclick = function(pos, node, clicker)
local meta = minetest.get_meta(pos)
local area = meta:get_string("area_id")
local name = clicker:get_player_name()
if area == "" then
minetest.chat_send_player(name, "Bitte zuerst Area mit dem Programmer zuweisen!")
return
end
local fs = "size[11,9]label[0.5,0.2;Zeitschaltuhr: " .. area:upper() .. "]"
local y, x, count, channels = 1.2, 0.5, 0, {}
if smart_light.registry.areas[area] and smart_light.registry.areas[area].channels then
for c_id, _ in pairs(smart_light.registry.areas[area].channels) do table.insert(channels, c_id) end
table.sort(channels)
for _, c_id in ipairs(channels) do
local c_data = smart_light.registry.areas[area].channels[c_id]
local t_status = (c_data.timer and c_data.timer.enabled) and "AN" or "AUS"
-- WICHTIG: Neues Kürzel tmr_m:
fs = fs .. "button["..x..","..y..";2.5,0.8;tmr_ch_"..c_id..";" .. c_id .. "\n(TIMER: "..t_status..")]"
x, count = x + 2.6, count + 1
if count % 4 == 0 then x, y = 0.5, y + 1 end
end
else
fs = fs .. "label[0.5,2;Keine Kanäle in dieser Area gefunden.]"
end
minetest.show_formspec(name, "tmr_m:" .. minetest.pos_to_string(pos), fs)
end,
on_timer = function(pos, elapsed)
local meta = minetest.get_meta(pos)
local area_id = meta:get_string("area_id")
if area_id == "" or not smart_light.registry.areas[area_id] then return true end
local time = minetest.get_timeofday() * 24
for c_id, c_data in pairs(smart_light.registry.areas[area_id].channels) do
if c_data.timer and c_data.timer.enabled then
local t = c_data.timer
local should_be_on = false
if t.start_h < t.end_h then
if time >= t.start_h and time < t.end_h then should_be_on = true end
else
if time >= t.start_h or time < t.end_h then should_be_on = true end
end
local current_status = smart_light.get_status_text(area_id, c_id)
if should_be_on and current_status == "AUS" then
smart_light.switch_channel(area_id, c_id, "on")
elseif not should_be_on and current_status == "AN" then
local now = minetest.get_gametime()
if not c_data.ms_deadline or now >= c_data.ms_deadline then
smart_light.switch_channel(area_id, c_id, "off")
end
end
end
end
return true
end,
})

View file

@ -23,7 +23,8 @@ minetest.register_tool("smart_light:programmer", {
-- LAMPE PASTEN
local original = smart_light.shadow_to_original[node.name] or node.name
if smart_light.original_to_shadows[original] then
smart_light.registry.areas[area].channels[chan] = smart_light.registry.areas[area].channels[chan] or { nodes = {}, last_level = "max" }
smart_light.registry.areas[area] = smart_light.registry.areas[area] or { channels = {} }
smart_light.registry.areas[area].channels[chan] = smart_light.registry.areas[area].channels[chan] or { nodes = {}, last_level = "max", brightness = "max" }
smart_light.registry.areas[area].channels[chan].nodes[pos_str] = true
smart_light.save()
local n_meta = minetest.get_meta(pos)
@ -50,6 +51,21 @@ minetest.register_tool("smart_light:programmer", {
minetest.chat_send_player(name, "PASTE (Schalter): " .. area .. ":" .. chan)
return itemstack
end
-- NEU: BEWEGUNGSMELDER PASTEN
if node.name:sub(1, 25) == "smart_light:motion_sensor" then
if not smart_light.registry.areas[area] or not smart_light.registry.areas[area].channels[chan] then
minetest.chat_send_player(name, "FEHLER: Ziel-Kanal existiert nicht!")
return
end
local n_meta = minetest.get_meta(pos)
n_meta:set_string("sl_area", area)
n_meta:set_string("sl_chan", chan)
n_meta:set_string("infotext", "Bewegungsmelder: " .. area .. ":" .. chan)
minetest.get_node_timer(pos):start(1.5) -- Logik-Timer starten
minetest.chat_send_player(name, "PASTE (Sensor): " .. area .. ":" .. chan)
return itemstack
end
end,
on_place = function(itemstack, user, pointed_thing)
@ -65,17 +81,14 @@ minetest.register_tool("smart_light:programmer", {
return itemstack
end
-- SCHALTER SETUP (Beide Dropdowns mit Platzhalter)
-- SCHALTER SETUP
if node.name:sub(1, 18) == "smart_light:switch" then
local n_meta = minetest.get_meta(pos)
local curr_area = n_meta:get_string("sl_area")
local areas_table = {"-- Bitte wählen --"}
for a_id, _ in pairs(smart_light.registry.areas) do table.insert(areas_table, a_id) end
local area_idx = 1
for i, v in ipairs(areas_table) do if v == curr_area then area_idx = i end end
local channels_table = {"-- Bitte wählen --"}
if curr_area ~= "" and curr_area ~= "-- Bitte wählen --" and smart_light.registry.areas[curr_area] then
local tmp = {}
@ -83,29 +96,50 @@ minetest.register_tool("smart_light:programmer", {
table.sort(tmp)
for _, c in ipairs(tmp) do table.insert(channels_table, c) end
end
local fs = "size[5,4.5]label[0.5,0.2;Schalter Programmierung]" ..
"dropdown[0.5,1.2;4,1;area_sel;" .. table.concat(areas_table, ",") .. ";" .. area_idx .. "]" ..
"label[0.5,2.2;Kanal auswählen:]" ..
"dropdown[0.5,2.7;4,1;chan_sel;" .. table.concat(channels_table, ",") .. ";1]" ..
"button[0.5,3.8;1.5,1;cancel;Abbruch]" ..
"button_exit[2.5,3.8;2,1;save_switch;Speichern]"
minetest.show_formspec(name, "smart_light:prog_sw_" .. minetest.pos_to_string(pos), fs)
return itemstack
end
-- NEU: BEWEGUNGSMELDER SETUP (Dropdown für Area/Kanal)
if node.name:sub(1, 25) == "smart_light:motion_sensor" then
local n_meta = minetest.get_meta(pos)
local curr_area = n_meta:get_string("sl_area")
local areas_table = {"-- Bitte wählen --"}
for a_id, _ in pairs(smart_light.registry.areas) do table.insert(areas_table, a_id) end
local area_idx = 1
for i, v in ipairs(areas_table) do if v == curr_area then area_idx = i end end
local channels_table = {"-- Bitte wählen --"}
if curr_area ~= "" and curr_area ~= "-- Bitte wählen --" and smart_light.registry.areas[curr_area] then
local tmp = {}
for c_id, _ in pairs(smart_light.registry.areas[curr_area].channels) do table.insert(tmp, c_id) end
table.sort(tmp)
for _, c in ipairs(tmp) do table.insert(channels_table, c) end
end
local fs = "size[5,4.5]label[0.5,0.2;Sensor Kanal-Setup]" ..
"dropdown[0.5,1.2;4,1;area_sel;" .. table.concat(areas_table, ",") .. ";" .. area_idx .. "]" ..
"label[0.5,2.2;Kanal auswählen:]" ..
"dropdown[0.5,2.7;4,1;chan_sel;" .. table.concat(channels_table, ",") .. ";1]" ..
"button[0.5,3.8;1.5,1;cancel;Abbruch]" ..
"button_exit[2.5,3.8;2,1;save_ms;Speichern]"
minetest.show_formspec(name, "smart_light:prog_ms_" .. minetest.pos_to_string(pos), fs)
return itemstack
end
-- LAMPEN SETUP
local original = smart_light.shadow_to_original[node.name] or node.name
if not smart_light.original_to_shadows[original] then return end
local n_meta = minetest.get_meta(pos)
local curr_area, curr_chan = n_meta:get_string("sl_area"), n_meta:get_string("sl_chan")
local areas_table = {"-- Bitte wählen --"}
for a_id, _ in pairs(smart_light.registry.areas) do table.insert(areas_table, a_id) end
local area_idx = 1
for i, v in ipairs(areas_table) do if v == curr_area then area_idx = i end end
local fs = "size[5,4.5]label[0.5,0.2;Licht Programmierung]" ..
"dropdown[0.5,1.2;4,1;area_sel;" .. table.concat(areas_table, ",") .. ";" .. area_idx .. "]" ..
"field[0.8,2.5;4,1;chan_in;Channel ID;" .. curr_chan .. "]" ..