// POWERNET SENSOR // // Last Change 31.12.2014 by Atlantis // // Powernet sensors are devices which relay information about connected powernet. This information may be relayed // via two procs. Proc return_reading_text will return fully HTML styled string which contains all information. This // may be used in PDAs or similar applications. Second proc, return_reading_data will return list containing needed data. // This is used in NanoUI, for example. /obj/machinery/power/sensor name = "Powernet Sensor" desc = "Small machine which transmits data about specific powernet" anchored = TRUE density = FALSE layer = ABOVE_UTILITY icon = 'icons/obj/objects.dmi' icon_state = "floor_beacon" // If anyone wants to make better sprite, feel free to do so without asking me. var/name_tag = "#UNKN#" // ID tag displayed in list of powernet sensors. Each sensor should have it's own tag! var/long_range = 0 // If 1, sensor reading will show on all computers, regardless of Zlevel var/list/history = list() var/record_size = 60 var/record_interval = 50 var/next_record = 0 var/is_secret_monitor = FALSE // Proc: New() // Parameters: None // Description: Automatically assigns name according to ID tag. /obj/machinery/power/sensor/New() ..() auto_set_name() /obj/machinery/power/sensor/Initialize() . = ..() history["supply"] = list() history["demand"] = list() // Proc: auto_set_name() // Parameters: None // Description: Sets name of this sensor according to the ID tag. /obj/machinery/power/sensor/proc/auto_set_name() name = "[name_tag] - Powernet Sensor" /obj/machinery/power/sensor/Destroy() . = ..() // TODO - Switch power_monitor to register deletion events instead of this. for(var/obj/machinery/computer/power_monitor/PM in machines) if(PM.power_monitor) PM.power_monitor.refresh_sensors() history.Cut() history = null // Proc: check_grid_warning() // Parameters: None // Description: Checks connected powernet for warnings. If warning is found returns 1 /obj/machinery/power/sensor/proc/check_grid_warning() connect_to_network() if(powernet) if(powernet.problem) return 1 return 0 // Proc: process() // Parameters: None // Description: This tracks historical usage, for TGUI power monitors /obj/machinery/power/sensor/process() if(!powernet) use_power = USE_POWER_IDLE connect_to_network() else use_power = USE_POWER_ACTIVE record() return 1 // This tracks historical usage, for TGUI power monitors /obj/machinery/power/sensor/proc/record() if(world.time >= next_record) next_record = world.time + record_interval var/datum/powernet/connected_powernet = powernet var/list/supply = history["supply"] if(connected_powernet) supply += connected_powernet.viewavail if(supply.len > record_size) supply.Cut(1, 2) var/list/demand = history["demand"] if(connected_powernet) demand += connected_powernet.viewload if(demand.len > record_size) demand.Cut(1, 2) /obj/machinery/power/sensor/tgui_data() var/list/data = list() data["name"] = name_tag data["stored"] = record_size data["interval"] = record_interval / 10 data["attached"] = !!powernet data["history"] = history data["areas"] = list() if(powernet) for(var/obj/machinery/power/terminal/term in powernet.nodes) if(istype(term.master, /obj/machinery/power/apc)) var/obj/machinery/power/apc/A = term.master if(istype(A)) var/cell_charge if(!A.cell) cell_charge = 0 else cell_charge = A.cell.percent() data["areas"] += list(list( "name" = A.area.name, "charge" = cell_charge, "load" = DisplayPower(A.lastused_total), "charging" = A.charging, "eqp" = A.equipment, "lgt" = A.lighting, "env" = A.environ, )) return data // Proc: reading_to_text() // Parameters: 1 (amount - Power in Watts to be converted to W, kW or MW) // Description: Helper proc that converts reading in Watts to kW or MW (returns string version of amount parameter) /obj/machinery/power/sensor/proc/reading_to_text(var/amount = 0) var/units = "" // 10kW and less - Watts if(amount < 10000) units = "W" // 10MW and less - KiloWatts else if(amount < 10000000) units = "kW" amount = (round(amount/100) / 10) // More than 10MW - MegaWatts else units = "MW" amount = (round(amount/10000) / 100) if (units == "W") return "[amount] W" else return "~[amount] [units]" //kW and MW are only approximate readings, therefore add "~" // Proc: find_apcs() // Parameters: None // Description: Searches powernet for APCs and returns them in a list. /obj/machinery/power/sensor/proc/find_apcs() if(!powernet) return var/list/L = list() for(var/obj/machinery/power/terminal/term in powernet.nodes) if(istype(term.master, /obj/machinery/power/apc)) var/obj/machinery/power/apc/A = term.master L += A return L // Proc: return_reading_text() // Parameters: None // Description: Generates string which contains HTML table with reading data. /obj/machinery/power/sensor/proc/return_reading_text() // No powernet. Try to connect to one first. if(!powernet) connect_to_network() var/out = "" if(!powernet) // No powernet. out = "# SYSTEM ERROR - NO POWERNET #" return out var/list/L = find_apcs() var/total_apc_load = 0 if(L.len <= 0) // No APCs found. out = "No APCs located in connected powernet!" else // APCs found. Create very ugly (but working!) HTML table. out += "
| Name | EQUIP | LIGHT | ENVIRON | CELL | LOAD" // These lists are used as replacement for number based APC settings var/list/S = list("M-OFF","A-OFF","M-ON", "A-ON") var/list/chg = list("N","C","F") // Split to multiple lines to make it more readable for(var/obj/machinery/power/apc/A in L) out += " | |
|---|---|---|---|---|---|---|
| \The [A.area]" // Add area name out += " | [S[A.equipment+1]] | [S[A.lighting+1]] | [S[A.environ+1]]" // Show status of channels if(A.cell) out += " | [round(A.cell.percent())]% - [chg[A.charging+1]]" else out += " | NO CELL" var/load = A.lastused_total // Load. total_apc_load += load load = reading_to_text(load) out += " | [load]"
out += " TOTAL AVAILABLE: [reading_to_text(powernet.avail)]" out += " APC LOAD: [reading_to_text(total_apc_load)]" out += " OTHER LOAD: [reading_to_text(max(powernet.load - total_apc_load, 0))]" out += " TOTAL GRID LOAD: [reading_to_text(powernet.viewload)] ([round((powernet.load / powernet.avail) * 100)]%)" if(powernet.problem) out += " WARNING: Abnormal grid activity detected!" return out // Proc: return_reading_data() // Parameters: None // Description: Generates list containing all powernet data. Optimised for usage with NanoUI /obj/machinery/power/sensor/proc/return_reading_data() // No powernet. Try to connect to one first. if(!powernet) connect_to_network() var/list/data = list() data["name"] = name_tag if(!powernet) data["error"] = "# SYSTEM ERROR - NO POWERNET #" data["alarm"] = 0 // Runtime Prevention return data var/list/L = find_apcs() var/total_apc_load = 0 var/list/APC_data = list() if(L.len > 0) // These lists are used as replacement for number based APC settings var/list/S = list("M-OFF","A-OFF","M-ON", "A-ON") var/list/chg = list("N","C","F") for(var/obj/machinery/power/apc/A in L) var/list/APC_entry = list() // Channel Statuses APC_entry["s_equipment"] = S[A.equipment+1] APC_entry["s_lighting"] = S[A.lighting+1] APC_entry["s_environment"] = S[A.environ+1] // Cell Status APC_entry["cell_charge"] = A.cell ? round(A.cell.percent()) : "NO CELL" APC_entry["cell_status"] = A.cell ? chg[A.charging+1] : "N" // Location APC_entry["x"] = A.x APC_entry["y"] = A.y APC_entry["z"] = A.z // Other info APC_entry["total_load"] = reading_to_text(A.lastused_total) // Hopefully removes those goddamn \improper s which are screwing up the UI var/N = A.area.name if(findtext(N, "�")) N = copytext(N, 3) APC_entry["name"] = N // Add data into main list of APC data. APC_data += list(APC_entry) // Add load of this APC to total APC load calculation total_apc_load += A.lastused_total data["apc_data"] = APC_data data["total_avail"] = reading_to_text(max(powernet.avail, 0)) data["total_used_apc"] = reading_to_text(max(total_apc_load, 0)) data["total_used_other"] = reading_to_text(max(powernet.viewload - total_apc_load, 0)) data["total_used_all"] = reading_to_text(max(powernet.viewload, 0)) // Prevents runtimes when avail is 0 (division by zero) if(powernet.avail) data["load_percentage"] = round((powernet.viewload / powernet.avail) * 100) else data["load_percentage"] = 100 data["alarm"] = powernet.problem ? 1 : 0 return data |