| | |
| | | -- SWITCHING STATION |
| | | -- The switching station is the center of all power distribution on an electric network. |
| | | -- |
| | | -- The station collects power from sources (PR), distributes it to sinks (RE), |
| | | -- and uses the excess/shortfall to charge and discharge batteries (BA). |
| | | -- |
| | | -- For now, all supply and demand values are expressed in kW. |
| | | -- |
| | | -- It works like this: |
| | | -- All PR,BA,RE nodes are indexed and tagged with the switching station. |
| | | -- The tagging is to allow more stations to be built without allowing a cheat |
| | | -- with duplicating power. |
| | | -- All the RE nodes are queried for their current EU demand. Those which are off |
| | | -- would require no or a small standby EU demand, while those which are on would |
| | | -- require more. |
| | | -- If the total demand is less than the available power they are all updated with the |
| | | -- demand number. |
| | | -- If any surplus exists from the PR nodes the batteries will be charged evenly with this. |
| | | -- If the total demand requires draw on the batteries they will be discharged evenly. |
| | | -- |
| | | -- If the total demand is more than the available power all RE nodes will be shut down. |
| | | -- We have a brown-out situation. |
| | | -- |
| | | -- Hence all the power distribution logic resides in this single node. |
| | | -- |
| | | -- Nodes connected to the network will have one or more of these parameters as meta data: |
| | | -- <LV|MV|HV>_EU_supply : Exists for PR and BA node types. This is the EU value supplied by the node. Output |
| | | -- <LV|MV|HV>_EU_demand : Exists for RE and BA node types. This is the EU value the node requires to run. Output |
| | | -- <LV|MV|HV>_EU_input : Exists for RE and BA node types. This is the actual EU value the network can give the node. Input |
| | | -- |
| | | -- The reason the LV|MV|HV type is prepended toe meta data is because some machine could require several supplies to work. |
| | | -- This way the supplies are separated per network. |
| | | -- See also technic/doc/api.md |
| | | |
| | | technic.networks = {} |
| | | technic.cables = {} |
| | | |
| | | local mesecons_path = minetest.get_modpath("mesecons") |
| | | local digilines_path = minetest.get_modpath("digilines") |
| | | |
| | | local S = technic.getter |
| | | |
| | | local cable_entry = "^technic_cable_connection_overlay.png" |
| | | |
| | | minetest.register_craft({ |
| | | output = "technic:switching_station", |
| | |
| | | } |
| | | }) |
| | | |
| | | local mesecon_def |
| | | if mesecons_path then |
| | | mesecon_def = {effector = { |
| | | rules = mesecon.rules.default, |
| | | }} |
| | | end |
| | | |
| | | minetest.register_node("technic:switching_station",{ |
| | | description = S("Switching Station"), |
| | | tiles = {"technic_water_mill_top_active.png", "technic_water_mill_top_active.png", |
| | | "technic_water_mill_top_active.png", "technic_water_mill_top_active.png", |
| | | "technic_water_mill_top_active.png", "technic_water_mill_top_active.png"}, |
| | | tiles = { |
| | | "technic_water_mill_top_active.png", |
| | | "technic_water_mill_top_active.png"..cable_entry, |
| | | "technic_water_mill_top_active.png", |
| | | "technic_water_mill_top_active.png", |
| | | "technic_water_mill_top_active.png", |
| | | "technic_water_mill_top_active.png"}, |
| | | groups = {snappy=2, choppy=2, oddly_breakable_by_hand=2, technic_all_tiers=1}, |
| | | connect_sides = {"bottom"}, |
| | | sounds = default.node_sound_wood_defaults(), |
| | |
| | | local meta = minetest.get_meta(pos) |
| | | meta:set_string("infotext", S("Switching Station")) |
| | | meta:set_string("active", 1) |
| | | meta:set_string("channel", "switching_station"..minetest.pos_to_string(pos)) |
| | | meta:set_string("formspec", "field[channel;Channel;${channel}]") |
| | | end, |
| | | after_dig_node = function(pos) |
| | | minetest.forceload_free_block(pos) |
| | | pos.y = pos.y - 1 |
| | | minetest.forceload_free_block(pos) |
| | | end, |
| | | on_receive_fields = function(pos, formname, fields, sender) |
| | | if not fields.channel then |
| | | return |
| | | end |
| | | local plname = sender:get_player_name() |
| | | if minetest.is_protected(pos, plname) then |
| | | minetest.record_protection_violation(pos, plname) |
| | | return |
| | | end |
| | | local meta = minetest.get_meta(pos) |
| | | meta:set_string("channel", fields.channel) |
| | | end, |
| | | mesecons = mesecon_def, |
| | | digiline = { |
| | | receptor = {action = function() end}, |
| | | effector = { |
| | | action = function(pos, node, channel, msg) |
| | | if msg ~= "GET" and msg ~= "get" then |
| | | return |
| | | end |
| | | local meta = minetest.get_meta(pos) |
| | | if channel ~= meta:get_string("channel") then |
| | | return |
| | | end |
| | | digilines.receptor_send(pos, digilines.rules.default, channel, { |
| | | supply = meta:get_int("supply"), |
| | | demand = meta:get_int("demand") |
| | | }) |
| | | end |
| | | }, |
| | | }, |
| | | }) |
| | | |
| | | -------------------------------------------------- |
| | |
| | | local BA_nodes |
| | | local RE_nodes |
| | | local machine_name = S("Switching Station") |
| | | |
| | | |
| | | -- Which kind of network are we on: |
| | | pos1 = {x=pos.x, y=pos.y-1, z=pos.z} |
| | | |
| | |
| | | minetest.forceload_free_block(pos1) |
| | | return |
| | | end |
| | | |
| | | |
| | | -- Run all the nodes |
| | | local function run_nodes(list, run_stage) |
| | | for _, pos2 in ipairs(list) do |
| | |
| | | end |
| | | end |
| | | end |
| | | |
| | | |
| | | run_nodes(PR_nodes, technic.producer) |
| | | run_nodes(RE_nodes, technic.receiver) |
| | | run_nodes(BA_nodes, technic.battery) |
| | |
| | | S("@1. Supply: @2 Demand: @3", |
| | | machine_name, technic.pretty_num(PR_eu_supply), technic.pretty_num(RE_eu_demand))) |
| | | |
| | | -- If mesecon signal and power supply or demand changed then |
| | | -- send them via digilines. |
| | | if mesecons_path and digilines_path and mesecon.is_powered(pos) then |
| | | if PR_eu_supply ~= meta:get_int("supply") or |
| | | RE_eu_demand ~= meta:get_int("demand") then |
| | | local channel = meta:get_string("channel") |
| | | digilines.receptor_send(pos, digilines.rules.default, channel, { |
| | | supply = PR_eu_supply, |
| | | demand = RE_eu_demand |
| | | }) |
| | | end |
| | | end |
| | | |
| | | -- Data that will be used by the power monitor |
| | | meta:set_int("supply",PR_eu_supply) |
| | | meta:set_int("demand",RE_eu_demand) |
| | |
| | | meta1 = minetest.get_meta(pos1) |
| | | meta1:set_int(eu_input_str, 0) |
| | | end |
| | | |
| | | |
| | | end, |
| | | }) |
| | | |
| | |
| | | end |
| | | end |
| | | minetest.register_abm({ |
| | | label = "Machines: timeout check", |
| | | nodenames = {"group:technic_machine"}, |
| | | interval = 1, |
| | | chance = 1, |
| | |
| | | |
| | | --Re-enable disabled switching station if necessary, similar to the timeout above |
| | | minetest.register_abm({ |
| | | label = "Machines: re-enable check", |
| | | nodenames = {"technic:switching_station"}, |
| | | interval = 1, |
| | | chance = 1, |