From ff423fc029f9ed96679d8f64275e2d50c73fc3fd Mon Sep 17 00:00:00 2001 From: rainer Date: Thu, 12 Feb 2026 12:30:39 +0100 Subject: [PATCH] added custom overrides, motion-sensors and more... --- handlers.lua | 47 +++++-- init.lua | 1 + mod.conf | 4 +- motion_sensor.lua | 123 +++++++++++++++++++ overrides.lua | 64 +++++++++- switch.lua | 4 +- textures/smart_light_panel_front_timer.png | Bin 0 -> 5611 bytes textures/smart_light_sensor_front.png | Bin 0 -> 248 bytes textures/smart_light_sensor_front_active.png | Bin 0 -> 248 bytes timer.lua.broken | 79 ++++++++++++ tools.lua | 52 ++++++-- 11 files changed, 348 insertions(+), 26 deletions(-) create mode 100644 motion_sensor.lua create mode 100644 textures/smart_light_panel_front_timer.png create mode 100644 textures/smart_light_sensor_front.png create mode 100644 textures/smart_light_sensor_front_active.png create mode 100644 timer.lua.broken diff --git a/handlers.lua b/handlers.lua index 4b38171..bcfe41c 100644 --- a/handlers.lua +++ b/handlers.lua @@ -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 .. "]" .. diff --git a/init.lua b/init.lua index 0964901..df33395 100644 --- a/init.lua +++ b/init.lua @@ -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") diff --git a/mod.conf b/mod.conf index 00b2838..416b18f 100644 --- a/mod.conf +++ b/mod.conf @@ -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 diff --git a/motion_sensor.lua b/motion_sensor.lua new file mode 100644 index 0000000..8a20456 --- /dev/null +++ b/motion_sensor.lua @@ -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, +}) diff --git a/overrides.lua b/overrides.lua index cf87fff..68f48b4 100644 --- a/overrides.lua +++ b/overrides.lua @@ -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) diff --git a/switch.lua b/switch.lua index e3a79df..e2efe5b 100644 --- a/switch.lua +++ b/switch.lua @@ -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, diff --git a/textures/smart_light_panel_front_timer.png b/textures/smart_light_panel_front_timer.png new file mode 100644 index 0000000000000000000000000000000000000000..a7bbecc9206a4e4c070079f588fb73b8ffa3095b GIT binary patch literal 5611 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 FV1h%%H?IHy literal 0 HcmV?d00001 diff --git a/textures/smart_light_sensor_front.png b/textures/smart_light_sensor_front.png new file mode 100644 index 0000000000000000000000000000000000000000..625511134247f83f189c9a3f3c5e1d5ce84c4027 GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@SkfJR9T^xl z_H+M9WCijSl0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP(mWW zC&U#<1A$Lw;l+y=pFDZ;|NsAz!a}2;p~u#&p8}L%ED7=pW^j0RBMr!L^>lFzi8%cB z!bUCz1rCP5gP;D}TP|9<=IF_m>K#=bN(>F}x3(8GzB|Ia>bFE=Q)6*8TSzlw@u9|O jzXaKMs|nv-7#zA7cNVa|tj=aH0om*6>gTe~DWM4fIuud; literal 0 HcmV?d00001 diff --git a/textures/smart_light_sensor_front_active.png b/textures/smart_light_sensor_front_active.png new file mode 100644 index 0000000000000000000000000000000000000000..1fd98e258509b0107747482acf3727cd9fc34abf GIT binary patch literal 248 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofvPP)Tsw@SkfJR9T^xl z_H+M9WCijSl0AZa85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP(mWW zC&U#<1A$Lw;l+y=pFDZ;|NsAz!oqV53`=-#tp`dlmIV0)GdMiEkp|?rdb&7zv5 z!H|zZfrG_SSmgizu_0Tt~GMgTfI8c0<;$)+w)SLH2sO`njxgN@xNAea%ZM literal 0 HcmV?d00001 diff --git a/timer.lua.broken b/timer.lua.broken new file mode 100644 index 0000000..c6a902d --- /dev/null +++ b/timer.lua.broken @@ -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, +}) diff --git a/tools.lua b/tools.lua index f7cbbf5..50b77ee 100644 --- a/tools.lua +++ b/tools.lua @@ -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 .. "]" ..